LyoKICogQ09NIHN0dWIgKENTdGRTdHViQnVmZmVyKSBpbXBsZW1lbnRhdGlvbgogKgogKiBDb3B5cmlnaHQgMjAwMSBPdmUgS+V2ZW4sIFRyYW5zR2FtaW5nIFRlY2hub2xvZ2llcwogKgogKiBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yCiAqIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMKICogTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyCiAqIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLgogKgogKiBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwKICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YKICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlUKICogTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KICoKICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYwogKiBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlCiAqIEZvdW5kYXRpb24sIEluYy4sIDU5IFRlbXBsZSBQbGFjZSwgU3VpdGUgMzMwLCBCb3N0b24sIE1BICAwMjExMS0xMzA3ICBVU0EKICovCgojaW5jbHVkZSA8c3RkYXJnLmg+CgojZGVmaW5lIENPQkpNQUNST1MKCiNpbmNsdWRlICJ3aW5kZWYuaCIKI2luY2x1ZGUgIndpbmJhc2UuaCIKI2luY2x1ZGUgIndpbmVycm9yLmgiCgojaW5jbHVkZSAib2JqYmFzZS5oIgoKI2luY2x1ZGUgInJwY3Byb3h5LmgiCgojaW5jbHVkZSAid2luZS9kZWJ1Zy5oIgoKI2luY2x1ZGUgImNwc2YuaCIKCldJTkVfREVGQVVMVF9ERUJVR19DSEFOTkVMKG9sZSk7CgojZGVmaW5lIFNUVUJfSEVBREVSKFRoaXMpICgoKENJbnRlcmZhY2VTdHViSGVhZGVyKikoKFRoaXMpLT5scFZ0YmwpKVstMV0pCgpIUkVTVUxUIFdJTkFQSSBDU3RkU3R1YkJ1ZmZlcl9Db25zdHJ1Y3QoUkVGSUlEIHJpaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExQVU5LTk9XTiBwVW5rU2VydmVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQQ0ludGVyZmFjZU5hbWUgbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ0ludGVyZmFjZVN0dWJWdGJsICp2dGJsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMUFBTRkFDVE9SWUJVRkZFUiBwUFNGYWN0b3J5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMUFJQQ1NUVUJCVUZGRVIgKnBwU3R1YikKewogIENTdGRTdHViQnVmZmVyICpUaGlzOwoKICBUUkFDRSgiKCVwLCVwLCVwLCVwKSAlc1xuIiwgcFVua1NlcnZlciwgdnRibCwgcFBTRmFjdG9yeSwgcHBTdHViLCBuYW1lKTsKICBUUkFDRSgiaWlkPSVzXG4iLCBkZWJ1Z3N0cl9ndWlkKHZ0YmwtPmhlYWRlci5waWlkKSk7CiAgVFJBQ0UoInZ0Ymw9JXBcbiIsICZ2dGJsLT5WdGJsKTsKCiAgaWYgKCFJc0VxdWFsR1VJRCh2dGJsLT5oZWFkZXIucGlpZCwgcmlpZCkpIHsKICAgIEVSUigiSUlEIG1pc21hdGNoIGR1cmluZyBzdHViIGNyZWF0aW9uXG4iKTsKICAgIHJldHVybiBSUENfRV9VTkVYUEVDVEVEOwogIH0KCiAgVGhpcyA9IEhlYXBBbGxvYyhHZXRQcm9jZXNzSGVhcCgpLEhFQVBfWkVST19NRU1PUlksc2l6ZW9mKENTdGRTdHViQnVmZmVyKSk7CiAgaWYgKCFUaGlzKSByZXR1cm4gRV9PVVRPRk1FTU9SWTsKCiAgVGhpcy0+bHBWdGJsID0gJnZ0YmwtPlZ0Ymw7CiAgVGhpcy0+UmVmQ291bnQgPSAxOwogIFRoaXMtPnB2U2VydmVyT2JqZWN0ID0gcFVua1NlcnZlcjsKICBUaGlzLT5wUFNGYWN0b3J5ID0gcFBTRmFjdG9yeTsKICAqcHBTdHViID0gKExQUlBDU1RVQkJVRkZFUilUaGlzOwoKICBJVW5rbm93bl9BZGRSZWYoVGhpcy0+cHZTZXJ2ZXJPYmplY3QpOwogIElQU0ZhY3RvcnlCdWZmZXJfQWRkUmVmKHBQU0ZhY3RvcnkpOwogIHJldHVybiBTX09LOwp9CgpIUkVTVUxUIFdJTkFQSSBDU3RkU3R1YkJ1ZmZlcl9RdWVyeUludGVyZmFjZShMUFJQQ1NUVUJCVUZGRVIgaWZhY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUkVGSUlEIHJpaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTFBWT0lEICpvYmopCnsKICBDU3RkU3R1YkJ1ZmZlciAqVGhpcyA9IChDU3RkU3R1YkJ1ZmZlciAqKWlmYWNlOwogIFRSQUNFKCIoJXApLT5RdWVyeUludGVyZmFjZSglcywlcClcbiIsVGhpcyxkZWJ1Z3N0cl9ndWlkKHJpaWQpLG9iaik7CgogIGlmIChJc0VxdWFsR1VJRCgmSUlEX0lVbmtub3duLHJpaWQpIHx8CiAgICAgIElzRXF1YWxHVUlEKCZJSURfSVJwY1N0dWJCdWZmZXIscmlpZCkpIHsKICAgICpvYmogPSBUaGlzOwogICAgVGhpcy0+UmVmQ291bnQrKzsKICAgIHJldHVybiBTX09LOwogIH0KICByZXR1cm4gRV9OT0lOVEVSRkFDRTsKfQoKVUxPTkcgV0lOQVBJIENTdGRTdHViQnVmZmVyX0FkZFJlZihMUFJQQ1NUVUJCVUZGRVIgaWZhY2UpCnsKICBDU3RkU3R1YkJ1ZmZlciAqVGhpcyA9IChDU3RkU3R1YkJ1ZmZlciAqKWlmYWNlOwogIFRSQUNFKCIoJXApLT5BZGRSZWYoKVxuIixUaGlzKTsKICByZXR1cm4gKysoVGhpcy0+UmVmQ291bnQpOwp9CgpVTE9ORyBXSU5BUEkgTmRyQ1N0ZFN0dWJCdWZmZXJfUmVsZWFzZShMUFJQQ1NUVUJCVUZGRVIgaWZhY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTFBQU0ZBQ1RPUllCVUZGRVIgcFBTRikKewogIENTdGRTdHViQnVmZmVyICpUaGlzID0gKENTdGRTdHViQnVmZmVyICopaWZhY2U7CiAgVFJBQ0UoIiglcCktPlJlbGVhc2UoKVxuIixUaGlzKTsKCiAgaWYgKCEtLShUaGlzLT5SZWZDb3VudCkpIHsKICAgIElScGNTdHViQnVmZmVyX0Rpc2Nvbm5lY3QoaWZhY2UpOwogICAgaWYoVGhpcy0+cFBTRmFjdG9yeSkKICAgICAgICBJUFNGYWN0b3J5QnVmZmVyX1JlbGVhc2UoVGhpcy0+cFBTRmFjdG9yeSk7CiAgICBIZWFwRnJlZShHZXRQcm9jZXNzSGVhcCgpLDAsVGhpcyk7CiAgICByZXR1cm4gMDsKICB9CiAgcmV0dXJuIFRoaXMtPlJlZkNvdW50Owp9CgpVTE9ORyBXSU5BUEkgTmRyQ1N0ZFN0dWJCdWZmZXIyX1JlbGVhc2UoTFBSUENTVFVCQlVGRkVSIGlmYWNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTFBQU0ZBQ1RPUllCVUZGRVIgcFBTRikKewogICAgRklYTUUoIk5vdCBpbXBsZW1lbnRlZFxuIik7CiAgICByZXR1cm4gMDsKfQoKSFJFU1VMVCBXSU5BUEkgQ1N0ZFN0dWJCdWZmZXJfQ29ubmVjdChMUFJQQ1NUVUJCVUZGRVIgaWZhY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMUFVOS05PV04gbHBVbmtTZXJ2ZXIpCnsKICBDU3RkU3R1YkJ1ZmZlciAqVGhpcyA9IChDU3RkU3R1YkJ1ZmZlciAqKWlmYWNlOwogIFRSQUNFKCIoJXApLT5Db25uZWN0KCVwKVxuIixUaGlzLGxwVW5rU2VydmVyKTsKICBUaGlzLT5wdlNlcnZlck9iamVjdCA9IGxwVW5rU2VydmVyOwogIHJldHVybiBTX09LOwp9Cgp2b2lkIFdJTkFQSSBDU3RkU3R1YkJ1ZmZlcl9EaXNjb25uZWN0KExQUlBDU1RVQkJVRkZFUiBpZmFjZSkKewogIENTdGRTdHViQnVmZmVyICpUaGlzID0gKENTdGRTdHViQnVmZmVyICopaWZhY2U7CiAgVFJBQ0UoIiglcCktPkRpc2Nvbm5lY3QoKVxuIixUaGlzKTsKICBpZiAoVGhpcy0+cHZTZXJ2ZXJPYmplY3QpCiAgewogICAgSVVua25vd25fUmVsZWFzZShUaGlzLT5wdlNlcnZlck9iamVjdCk7CiAgICBUaGlzLT5wdlNlcnZlck9iamVjdCA9IE5VTEw7CiAgfQp9CgpIUkVTVUxUIFdJTkFQSSBDU3RkU3R1YkJ1ZmZlcl9JbnZva2UoTFBSUENTVFVCQlVGRkVSIGlmYWNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQUlBDT0xFTUVTU0FHRSBwTXNnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMUFJQQ0NIQU5ORUxCVUZGRVIgcENoYW5uZWwpCnsKICBDU3RkU3R1YkJ1ZmZlciAqVGhpcyA9IChDU3RkU3R1YkJ1ZmZlciAqKWlmYWNlOwogIERXT1JEIGR3UGhhc2UgPSBTVFVCX1VOTUFSU0hBTDsKICBUUkFDRSgiKCVwKS0+SW52b2tlKCVwLCVwKVxuIixUaGlzLHBNc2cscENoYW5uZWwpOwoKICBpZiAoU1RVQl9IRUFERVIoVGhpcykucERpc3BhdGNoVGFibGUpCiAgICBTVFVCX0hFQURFUihUaGlzKS5wRGlzcGF0Y2hUYWJsZVtwTXNnLT5pTWV0aG9kXShpZmFjZSwgcENoYW5uZWwsIChQUlBDX01FU1NBR0UpcE1zZywgJmR3UGhhc2UpOwogIGVsc2UgLyogcHVyZSBpbnRlcnByZXRlZCAqLwogICAgTmRyU3R1YkNhbGwyKGlmYWNlLCBwQ2hhbm5lbCwgKFBSUENfTUVTU0FHRSlwTXNnLCAmZHdQaGFzZSk7CiAgcmV0dXJuIFNfT0s7Cn0KCkxQUlBDU1RVQkJVRkZFUiBXSU5BUEkgQ1N0ZFN0dWJCdWZmZXJfSXNJSURTdXBwb3J0ZWQoTFBSUENTVFVCQlVGRkVSIGlmYWNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUkVGSUlEIHJpaWQpCnsKICBDU3RkU3R1YkJ1ZmZlciAqVGhpcyA9IChDU3RkU3R1YkJ1ZmZlciAqKWlmYWNlOwogIFRSQUNFKCIoJXApLT5Jc0lJRFN1cHBvcnRlZCglcylcbiIsVGhpcyxkZWJ1Z3N0cl9ndWlkKHJpaWQpKTsKICByZXR1cm4gSXNFcXVhbEdVSUQoU1RVQl9IRUFERVIoVGhpcykucGlpZCwgcmlpZCkgPyBpZmFjZSA6IE5VTEw7Cn0KClVMT05HIFdJTkFQSSBDU3RkU3R1YkJ1ZmZlcl9Db3VudFJlZnMoTFBSUENTVFVCQlVGRkVSIGlmYWNlKQp7CiAgQ1N0ZFN0dWJCdWZmZXIgKlRoaXMgPSAoQ1N0ZFN0dWJCdWZmZXIgKilpZmFjZTsKICBUUkFDRSgiKCVwKS0+Q291bnRSZWZzKClcbiIsVGhpcyk7CiAgcmV0dXJuIFRoaXMtPlJlZkNvdW50Owp9CgpIUkVTVUxUIFdJTkFQSSBDU3RkU3R1YkJ1ZmZlcl9EZWJ1Z1NlcnZlclF1ZXJ5SW50ZXJmYWNlKExQUlBDU1RVQkJVRkZFUiBpZmFjZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExQVk9JRCAqcHB2KQp7CiAgQ1N0ZFN0dWJCdWZmZXIgKlRoaXMgPSAoQ1N0ZFN0dWJCdWZmZXIgKilpZmFjZTsKICBUUkFDRSgiKCVwKS0+RGVidWdTZXJ2ZXJRdWVyeUludGVyZmFjZSglcClcbiIsVGhpcyxwcHYpOwogIHJldHVybiBTX09LOwp9Cgp2b2lkIFdJTkFQSSBDU3RkU3R1YkJ1ZmZlcl9EZWJ1Z1NlcnZlclJlbGVhc2UoTFBSUENTVFVCQlVGRkVSIGlmYWNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMUFZPSUQgcHYpCnsKICBDU3RkU3R1YkJ1ZmZlciAqVGhpcyA9IChDU3RkU3R1YkJ1ZmZlciAqKWlmYWNlOwogIFRSQUNFKCIoJXApLT5EZWJ1Z1NlcnZlclJlbGVhc2UoJXApXG4iLFRoaXMscHYpOwp9Cgpjb25zdCBJUnBjU3R1YkJ1ZmZlclZ0YmwgQ1N0ZFN0dWJCdWZmZXJfVnRibCA9CnsKICAgIENTdGRTdHViQnVmZmVyX1F1ZXJ5SW50ZXJmYWNlLAogICAgQ1N0ZFN0dWJCdWZmZXJfQWRkUmVmLAogICAgTlVMTCwKICAgIENTdGRTdHViQnVmZmVyX0Nvbm5lY3QsCiAgICBDU3RkU3R1YkJ1ZmZlcl9EaXNjb25uZWN0LAogICAgQ1N0ZFN0dWJCdWZmZXJfSW52b2tlLAogICAgQ1N0ZFN0dWJCdWZmZXJfSXNJSURTdXBwb3J0ZWQsCiAgICBDU3RkU3R1YkJ1ZmZlcl9Db3VudFJlZnMsCiAgICBDU3RkU3R1YkJ1ZmZlcl9EZWJ1Z1NlcnZlclF1ZXJ5SW50ZXJmYWNlLAogICAgQ1N0ZFN0dWJCdWZmZXJfRGVidWdTZXJ2ZXJSZWxlYXNlCn07Cgpjb25zdCBNSURMX1NFUlZFUl9JTkZPICpDU3RkU3R1YkJ1ZmZlcl9HZXRTZXJ2ZXJJbmZvKElScGNTdHViQnVmZmVyICppZmFjZSkKewogIENTdGRTdHViQnVmZmVyICpUaGlzID0gKENTdGRTdHViQnVmZmVyICopaWZhY2U7CiAgcmV0dXJuIFNUVUJfSEVBREVSKFRoaXMpLnBTZXJ2ZXJJbmZvOwp9Cg==