LyoKICogQ2xvY2sKICoKICogQ29weXJpZ2h0IDE5OTggTWFyY2VsIEJhdXIgPG1iYXVyQGcyNi5ldGh6LmNoPgogKiBDb3B5cmlnaHQgMTk5OCBLYXJsIEJhY2tzdHL2bSA8a2FybF9iQGdlb2NpdGllcy5jb20+CiAqLwoKI2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlICJ3aW5kb3dzLmgiCiNpbmNsdWRlICJtYWluLmgiCiNpbmNsdWRlICJsYW5ndWFnZS5oIgojaWZkZWYgV0lORUxJQgojaW5jbHVkZSAib3B0aW9ucy5oIgojZW5kaWYKCkNIQVIgU1RSSU5HX01FTlVfWHhbXSAgICAgID0gIk1FTlVfWHgiOwoKc3RhdGljIEJPT0wgTEFOR1VBR0VfTG9hZFN0cmluZ090aGVyKFVJTlQgbnVtLCBVSU5UIGlkcywgTFBTVFIgc3RyLCBVSU5UIGxlbikKewogIGlkcyAtPSBHbG9iYWxzLndTdHJpbmdUYWJsZU9mZnNldDsKICBpZHMgKz0gbnVtICogMHgxMDA7CiAgcmV0dXJuKExvYWRTdHJpbmcoR2xvYmFscy5oSW5zdGFuY2UsIGlkcywgc3RyLCBsZW4pKTsKfTsKClZPSUQgTEFOR1VBR0VfU2VsZWN0QnlOYW1lKExQQ1NUUiBsYW5nKQp7CiAgSU5UIGk7CiAgQ0hBUiBuZXdsYW5nWzNdOwoKICBmb3IgKGkgPSAwOyBpIDw9IE1BWF9MQU5HVUFHRV9OVU1CRVI7IGkrKykKICAgIGlmIChMQU5HVUFHRV9Mb2FkU3RyaW5nT3RoZXIoaSwgSURTX0xBTkdVQUdFX0lELCBuZXdsYW5nLCBzaXplb2YobmV3bGFuZykpICYmCgkhbHN0cmNtcChsYW5nLCBuZXdsYW5nKSkKICAgICAgewogICAgICAgIExBTkdVQUdFX1NlbGVjdEJ5TnVtYmVyKGkpOwoJcmV0dXJuOwogICAgICB9CgogIC8qIEZhbGxiYWNrICovCiAgICBmb3IgKGkgPSAwOyBpIDw9IE1BWF9MQU5HVUFHRV9OVU1CRVI7IGkrKykKICAgIGlmIChMQU5HVUFHRV9Mb2FkU3RyaW5nT3RoZXIoaSwgSURTX0xBTkdVQUdFX0lELCBuZXdsYW5nLCBzaXplb2YobmV3bGFuZykpKQogICAgICB7CglMQU5HVUFHRV9TZWxlY3RCeU51bWJlcihpKTsKCXJldHVybjsKICAgICAgfQoKICBNZXNzYWdlQm94KEdsb2JhbHMuaE1haW5XbmQsICJObyBsYW5ndWFnZSBmb3VuZCIsICJGQVRBTCBFUlJPUiIsIE1CX09LKTsKICBQb3N0UXVpdE1lc3NhZ2UoMSk7Cn0KClZPSUQgTEFOR1VBR0VfU2VsZWN0QnlOdW1iZXIoVUlOVCBudW0pCnsKICBJTlQgICAgaTsKICBDSEFSICAgbGFuZ1szXTsKICBDSEFSICAgY2FwdGlvbltNQVhfU1RSSU5HX0xFTl07CiAgQ0hBUiAgIGl0ZW1bTUFYX1NUUklOR19MRU5dOwogIEhNRU5VICBoTWFpbk1lbnU7CgogIC8qIFNlbGVjdCBzdHJpbmcgdGFibGUgKi8KICBHbG9iYWxzLndTdHJpbmdUYWJsZU9mZnNldCA9IG51bSAqIDB4MTAwOwoKICAvKiBHZXQgTGFuZ3VhZ2UgaWQgKi8KICBMb2FkU3RyaW5nKEdsb2JhbHMuaEluc3RhbmNlLCBJRFNfTEFOR1VBR0VfSUQsIGxhbmcsIHNpemVvZihsYW5nKSk7CiAgR2xvYmFscy5scHN6TGFuZ3VhZ2UgPSBsYW5nOwoKICAvKiBTZXQgZnJhbWUgY2FwdGlvbiAqLwogIExvYWRTdHJpbmcoR2xvYmFscy5oSW5zdGFuY2UsIElEU19DTE9DSywgY2FwdGlvbiwgc2l6ZW9mKGNhcHRpb24pKTsKICBTZXRXaW5kb3dUZXh0KEdsb2JhbHMuaE1haW5XbmQsIGNhcHRpb24pOwoKICAvKiBDaGFuZ2UgUmVzb3VyY2UgbmFtZXMgKi8KICBsc3RyY3B5bihTVFJJTkdfTUVOVV9YeCAgICArIHNpemVvZihTVFJJTkdfTUVOVV9YeCkgICAgLSAzLCBsYW5nLCAzKTsKCiAgLyogQ3JlYXRlIG1lbnUgKi8KICBoTWFpbk1lbnUgPSBMb2FkTWVudShHbG9iYWxzLmhJbnN0YW5jZSwgU1RSSU5HX01FTlVfWHgpOwogICAgR2xvYmFscy5oUHJvcGVydGllc01lbnUgICAgID0gR2V0U3ViTWVudShoTWFpbk1lbnUsIDApOwogICAgR2xvYmFscy5oTGFuZ3VhZ2VNZW51IAk9IEdldFN1Yk1lbnUoaE1haW5NZW51LCAxKTsKICAgIEdsb2JhbHMuaEluZm9NZW51ICAgICAJPSBHZXRTdWJNZW51KGhNYWluTWVudSwgMik7CgogIC8qIFJlbW92ZSBkdW1teSBpdGVtICovCiAgUmVtb3ZlTWVudShHbG9iYWxzLmhMYW5ndWFnZU1lbnUsIDAsIE1GX0JZUE9TSVRJT04pOwogIC8qIEFkZCBsYW5ndWFnZSBpdGVtcyAqLwogIGZvciAoaSA9IDA7IGkgPD0gTUFYX0xBTkdVQUdFX05VTUJFUjsgaSsrKQogICAgaWYgKExBTkdVQUdFX0xvYWRTdHJpbmdPdGhlcihpLCBJRFNfTEFOR1VBR0VfTUVOVV9JVEVNLCBpdGVtLCBzaXplb2YoaXRlbSkpKQogICAgICBBcHBlbmRNZW51KEdsb2JhbHMuaExhbmd1YWdlTWVudSwgTUZfU1RSSU5HIHwgTUZfQllDT01NQU5ELAoJCSBDTF9GSVJTVF9MQU5HVUFHRSArIGksIGl0ZW0pOwoKICBTZXRNZW51KEdsb2JhbHMuaE1haW5XbmQsIGhNYWluTWVudSk7CgogIC8qIERlc3Ryb3kgb2xkIG1lbnUgKi8KICBpZiAoR2xvYmFscy5oTWFpbk1lbnUpIERlc3Ryb3lNZW51KEdsb2JhbHMuaE1haW5NZW51KTsKICBHbG9iYWxzLmhNYWluTWVudSA9IGhNYWluTWVudTsKCiNpZmRlZiBXSU5FTElCCiAgLyogVXBkYXRlIHN5c3RlbSBtZW51cyAqLwogIGZvciAoaSA9IDA7IExhbmd1YWdlc1tpXS5uYW1lICYmIGxzdHJjbXAobGFuZywgTGFuZ3VhZ2VzW2ldLm5hbWUpOykgaSsrOwogIGlmIChMYW5ndWFnZXNbaV0ubmFtZSkgT3B0aW9ucy5sYW5ndWFnZSA9IGk7CgojZW5kaWYKCi8qIFNwZWNpZmljIGZvciBjbG9jayAqLwppZihHbG9iYWxzLmJBbmFsb2cgPT0gVFJVRSkgewoJQ2hlY2tNZW51SXRlbShHbG9iYWxzLmhQcm9wZXJ0aWVzTWVudSwgQ0xfQU5BTE9HLCBcCiAgICAgICAgICAgICAgICAgICAgICAgTUZfQllDT01NQU5EIHwgTUZfQ0hFQ0tFRCk7CiAgICAgICAgQ2hlY2tNZW51SXRlbShHbG9iYWxzLmhQcm9wZXJ0aWVzTWVudSwgQ0xfRElHSVRBTCwgXAogICAgICAgICAgICAgICAgICAgICAgIE1GX0JZQ09NTUFORCB8IE1GX1VOQ0hFQ0tFRCk7CglFbmFibGVNZW51SXRlbShHbG9iYWxzLmhQcm9wZXJ0aWVzTWVudSwgQ0xfRk9OVCwgXAogICAgICAgICAgICAgICAgICAgICAgIE1GX0JZQ09NTUFORCB8IE1GX0dSQVlFRCk7Cn0KZWxzZSB7CglDaGVja01lbnVJdGVtKEdsb2JhbHMuaFByb3BlcnRpZXNNZW51LCBDTF9BTkFMT0csIFwKICAgICAgICAgICAgICAgICAgICAgICBNRl9CWUNPTU1BTkQgfCBNRl9VTkNIRUNLRUQpOwogICAgICAgIENoZWNrTWVudUl0ZW0oR2xvYmFscy5oUHJvcGVydGllc01lbnUsIENMX0RJR0lUQUwsIFwKICAgICAgICAgICAgICAgICAgICAgICBNRl9CWUNPTU1BTkQgfCBNRl9DSEVDS0VEKTsKfQoJQ2hlY2tNZW51SXRlbShHbG9iYWxzLmhQcm9wZXJ0aWVzTWVudSwgQ0xfV0lUSE9VVF9USVRMRSwgTUZfQllDT01NQU5EIHwgXAoJICAgICAgICAgICAgICAgICAgICAgKEdsb2JhbHMuYldpdGhvdXRUaXRsZSA/IE1GX0NIRUNLRUQgOiBNRl9VTkNIRUNLRUQpKTsKCUNoZWNrTWVudUl0ZW0oR2xvYmFscy5oUHJvcGVydGllc01lbnUsIENMX09OX1RPUCwgTUZfQllDT01NQU5EIHwgXAoJICAgICAgICAgICAgICAgICAgICAgKEdsb2JhbHMuYkFsd2F5c09uVG9wID8gTUZfQ0hFQ0tFRCA6IE1GX1VOQ0hFQ0tFRCkpOwoJQ2hlY2tNZW51SXRlbShHbG9iYWxzLmhQcm9wZXJ0aWVzTWVudSwgQ0xfU0VDT05EUywgTUZfQllDT01NQU5EIHwgXAoJICAgICAgICAgICAgICAgICAgICAgKEdsb2JhbHMuYlNlY29uZHMgPyBNRl9DSEVDS0VEIDogTUZfVU5DSEVDS0VEKSk7CglDaGVja01lbnVJdGVtKEdsb2JhbHMuaFByb3BlcnRpZXNNZW51LCBDTF9EQVRFLCBNRl9CWUNPTU1BTkQgfCBcCgkgICAgICAgICAgICAgICAgICAgICAoR2xvYmFscy5iRGF0ZSA/IE1GX0NIRUNLRUQgOiBNRl9VTkNIRUNLRUQpKTsKfQoKVk9JRCBMQU5HVUFHRV9EZWZhdWx0SGFuZGxlKFdQQVJBTSB3UGFyYW0pCnsKICBpZiAoKHdQYXJhbSA+PUNMX0ZJUlNUX0xBTkdVQUdFKSAmJiAod1BhcmFtPD1DTF9MQVNUX0xBTkdVQUdFKSkKICAgICAgICAgIExBTkdVQUdFX1NlbGVjdEJ5TnVtYmVyKHdQYXJhbSAtIENMX0ZJUlNUX0xBTkdVQUdFKTsKICAgICBlbHNlIHByaW50ZigiVW5pbXBsZW1lbnRlZCBtZW51IGNvbW1hbmQgJWlcbiIsIHdQYXJhbSk7Cn0KClZPSUQgTEFOR1VBR0VfSW5pdChWT0lEKQp7CiAgI2lmZGVmIFdJTkVMSUIKICAgR2xvYmFscy5scHN6TGFuZ3VhZ2UgPSBMYW5ndWFnZXNbT3B0aW9ucy5sYW5ndWFnZV0ubmFtZTsKICAjZW5kaWYKLy8gICNlbHNlCiAgcHJpbnRmKCJHbG9iYWxzLmxwc3pMYW5ndWFnZSA9PSAlc1xuIiwgR2xvYmFscy5scHN6TGFuZ3VhZ2UpOwogIGlmIChHbG9iYWxzLmxwc3pMYW5ndWFnZSA9PSAiRW4iKSB7CiAgICBDSEFSIGJ1ZmZlcltNQVhfUEFUSE5BTUVfTEVOXSwgKnA7CiAgICBwcmludGYoIk11dVxuIik7CiAgICBQUk9GSUxFX0dldFdpbmVJbmlTdHJpbmcoInByb2dyYW1zIiwgImxhbmd1YWdlIiwgIkVuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnVmZmVyLCBzaXplb2YoYnVmZmVyKSk7CiAgR2xvYmFscy5scHN6TGFuZ3VhZ2UgPSBwID0gTG9jYWxMb2NrKExvY2FsQWxsb2MoTE1FTV9GSVhFRCwgbHN0cmxlbihidWZmZXIpKSk7CiAgaG1lbWNweShwLCBidWZmZXIsIDEgKyBsc3RybGVuKGJ1ZmZlcikpOyB9Ci8vICAjZW5kaWYKLy8gIGlmICghR2xvYmFscy5scHN6TGFuZ3VhZ2UpIEdsb2JhbHMubHBzekxhbmd1YWdlID0gIkVuIjsKfQoKLyogTG9jYWwgVmFyaWFibGVzOiAgICAqLwovKiBjLWZpbGUtc3R5bGU6ICJHTlUiICovCi8qIEVuZDogICAgICAgICAgICAgICAgKi8K