0x4774…5ac5

All memos sent from and to 0x4774…5ac5.

0x4774567d…5ac5·#25,346,651·0x5bfe9c6b…10f68c
Invalid NFT contractRrNothing to withdraw`hSeller does not own this tokenApprove this contract on BrokenL`DRmNo active sale`Send exactly the listed priceSeller no longer owns this token`DContract approval was revokedETH transfer to seller failedCancel sale before changing sell`DRmNo active sale`
0x4774567d…5ac5·#25,346,645·0x9ab91098…a169ba
RuInvalid QRCode address`P6V[P[PPPPPV[``_aABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789+/PPPPPV[u{"name":"broken link #`P","description":"broken link by `MyFi Studio","image":"data:image`6","attributes":[{"trait_type":"C`y"},{"trait_type":"Token ID","val"},{"trait_type":"Edition","valudata:application/json;base64,{"name":"Broken Link","description":"An interactive art piece ex` ploring the relationship between`@ analog static and digital conne``ctivity. Created by MyFi Studio.`","image":"data:image/svg+xml;ba`","external_link":"https://www.m`őyfi.studio/broken-link","seller_`fee_basis_points":500,"fee_recipa
ICBjb25zdCBjYW52YXMgPSB0aGlzLnN0YXRlLmNhbnZhczsKICAgICAgICBjb25zdCBkcHIgPSBNYXRoLm1pbih3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyB8fCAxLCAyKTsKICAgICAgICAKICAgICAgICAvLyBTZXQgZGlzcGxheSBzaXplIChDU1MgcGl4ZWxzKQogICAgICAgIGNhbnZhcy5zdHlsZS53aWR0aCA9IHdpbmRvdy5pbm5lcldpZHRoICsgJ3B4JzsKICAgICAgICBjYW52YXMuc3R5bGUuaGVpZ2h0ID0gd2luZG93LmlubmVySGVpZ2h0ICsgJ3B4JzsKICAgICAgICAKICAgICAgICAvLyBTZXQgYWN0dWFsIGNhbnZhcyByZXNvbHV0aW9uIChhY2NvdW50aW5nIGZvciBkZXZpY2UgcGl4ZWwgcmF0aW8pCiAgICAgICAgY2FudmFzLndpZHRoID0gd2luZG93LmlubmVyV2lkdGggKiBkcHI7CiAgICAgICAgY2FudmFzLmhlaWdodCA9IHdpbmRvdy5pbm5lckhlaWdodCAqIGRwcjsKICAgICAgICAKICAgICAgICBMb2dnZXIuZGVidWcoJ0FQUCcsIGBDYW52YXMgcmVzaXplZDogJHtjYW52YXMud2lkdGh9eCR7Y2FudmFzLmhlaWdodH0gKERQUjogJHtkcHJ9KWApOwogICAgfQogICAgCiAgICAvKioKICAgICAqIFNldHVwIHdpbmRvdyByZXNpemUgaGFuZGxlcgogICAgICovCiAgICBzZXR1cFJlc2l6ZUhhbmRsZXIoKSB7CiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsICgpID0+IHsKICAgICAgICAgICAgdGhpcy5yZXNpemVDYW52YXMoKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIE5vdGlmeSByZW5kZXJlciBvZiByZXNpemUgKHJlY3JlYXRlcyBpbnRlcm1lZGlhdGUgdGV4dHVyZXMpCiAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnJlbmRlcmVyKSB7CiAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLnJlbmRlcmVyLnJlc2l6ZSgKICAgICAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLmNhbnZhcy53aWR0aCwKICAgICAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLmNhbnZhcy5oZWlnaHQKICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgIH0KICAgICAgICB9KTsKICAgICAgICAKICAgICAgICBMb2dnZXIuZGVidWcoJ0FQUCcsICdSZXNpemUgaGFuZGxlciBzZXR1cCcpOwogICAgfQogICAgCiAgICAvKioKICAgICAqIFN0YXJ0IHJlbmRlciBsb29wCiAgICAgKi8KICAgIHN0YXJ0UmVuZGVyTG9vcCgpIHsKICAgICAgICBpZiAodGhpcy5zdGF0ZS5yZW5kZXJpbmcuaXNSdW5uaW5nKSB7CiAgICAgICAgICAgIExvZ2dlci53YXJuKCdBUFAnLCAnUmVuZGVyIGxvb3AgYWxyZWFkeSBydW5uaW5nJyk7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgdGhpcy5zdGF0ZS5yZW5kZXJpbmcuaXNSdW5uaW5nID0gdHJ1ZTsKICAgICAgICB0aGlzLnN0YXRlLnJlbmRlcmluZy5sYXN0RnJhbWVUaW1lID0gcGVyZm9ybWFuY2Uubm93KCk7CiAgICAgICAgdGhpcy5zdGF0ZS5yZW5kZXJpbmcuZnBzVXBkYXRlVGltZSA9IHBlcmZvcm1hbmNlLm5vdygpOwogICAgICAgIAogICAgICAgIExvZ2dlci5pbmZvKCdBUFAnLCAnUmVuZGVyIGxvb3Agc3RhcnRlZCcpOwogICAgICAgIAogICAgICAgIC8vIFN0YXJ0IGFuaW1hdGlvbiBsb29wCiAgICAgICAgdGhpcy5yZW5kZXIocGVyZm9ybWFuY2Uubm93KCkpOwogICAgfQogICAgCiAgICAvKioKICAgICAqIFN0b3AgcmVuZGVyIGxvb3AKICAgICAqLwogICAgc3RvcFJlbmRlckxvb3AoKSB7CiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnJlbmRlcmluZy5pc1J1bm5pbmcpIHJldHVybjsKICAgICAgICAKICAgICAgICB0aGlzLnN0YXRlLnJlbmRlcmluZy5pc1J1bm5pbmcgPSBmYWxzZTsKICAgICAgICAKICAgICAgICBpZiAodGhpcy5zdGF0ZS5yZW5kZXJpbmcuYW5pbWF0aW9uRnJhbWVJZCkgewogICAgICAgICAgICBjYW5jZWxBbmltYXRpb25GcmFtZSh0aGlzLnN0YXRlLnJlbmRlcmluZy5hbmltYXRpb25GcmFtZUlkKTsKICAgICAgICAgICAgdGhpcy5zdGF0ZS5yZW5kZXJpbmcuYW5pbWF0aW9uRnJhbWVJZCA9IG51bGw7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIExvZ2dlci5pbmZvKCdBUFAnLCAnUmVuZGVyIGxvb3Agc3RvcHBlZCcpOwogICAgfQogICAgCiAgICAvKioKICAgICAqIE1haW4gcmVuZGVyIGZ1bmN0aW9uIC0gUGhhc2UgQzogTXVsdGktcGFzcyByZW5kZXJpbmcgc3VwcG9ydAogICAgICovCiAgICByZW5kZXIodGltZXN0YW1wKSB7CiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnJlbmRlcmluZy5pc1J1bm5pbmcpIHJldHVybjsKICAgICAgICAKICAgICAgICB0cnkgewogICAgICAgICAgICAvLyBVcGRhdGUgRlBTIGNvdW50ZXIKICAgICAgICAgICAgdGhpcy51cGRhdGVGUFModGltZXN0YW1wKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIENoZWNrIGlmIHVzZXIgaXMgaW50ZXJhY3RpbmcKICAgICAgICAgICAgY29uc3QgaXNJbnRlcmFjdGluZyA9IHRoaXMuc3RhdGUuZWZmZWN0TWFuYWdlci5pc0ludGVyYWN0aW5nKCk7CiAgICAgICAgICAgIAogICAgICAgICAgICBpZiAoaXNJbnRlcmFjdGluZykgewogICAgICAgICAgICAgICAgLy8gUEhBU0UgQzogTXVsdGktcGFzcyByZW5kZXJpbmcgKFN0YXRpYyDihpIgUGl4ZWxpemF0aW9uKQogICAgICAgICAgICAgICAgdGhpcy5yZW5kZXJNdWx0aVBhc3ModGltZXN0YW1wKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIC8vIFBIQVNFIEI6IFNpbmdsZS1wYXNzIHJlbmRlcmluZyAoU3RhdGljIG9ubHkpCiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlclNpbmdsZVBhc3ModGltZXN0YW1wKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgLy8gVXBkYXRlIGZyYW1lIGNvdW50ZXIKICAgICAgICAgICAgdGhpcy5zdGF0ZS5yZW5kZXJpbmcuZnJhbWVDb3VudCsrOwogICAgICAgICAgICAKICAgICAgICB9IGNhdGNoIChlcnJvcikgewogICAgICAgICAgICBMb2dnZXIuZXJyb3IoJ0FQUCcsICdSZW5kZXIgZXJyb3I6JywgZXJyb3IpOwogICAgICAgICAgICB0aGlzLnN0b3BSZW5kZXJMb29wKCk7CiAgICAgICAgICAgIHRoaXMuc2hvd0Vycm9yKCdSZW5kZXJpbmcgZXJyb3Igb2NjdXJyZWQuIENoZWNrIGNvbnNvbGUgZm9yIGRldGFpbHMuJyk7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgLy8gUmVxdWVzdCBuZXh0IGZyYW1lCiAgICAgICAgdGhpcy5yZXF1ZXN0TmV4dEZyYW1lKCk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogU2luZ2xlLXBhc3MgcmVuZGVyaW5nOiBUViBTdGF0aWMgZGlyZWN0bHkgdG8gc2NyZWVuCiAgICAgKi8KICAgIHJlbmRlclNpbmdsZVBhc3ModGltZXN0YW1wKSB7CiAgICAgICAgY29uc3Qgc3RhdGljRWZmZWN0ID0gdGhpcy5zdGF0ZS5lZmZlY3RzLnN0YXRpY0VmZmVjdDsKICAgICAgICBpZiAoIXN0YXRpY0VmZmVjdCkgcmV0dXJuOwogICAgICAgIAogICAgICAgIC8vIFVwZGF0ZSBlZmZlY3QgdGltZQogICAgICAgIGNvbnN0IHRpbWVJblNlY29uZHMgPSAodGltZXN0YW1wIC0gdGhpcy5zdGF0ZS5hcHAuc3RhcnRUaW1lKSAvIDEwMDAuMDsKICAgICAgICBzdGF0aWNFZmZlY3QudXBkYXRlVGltZSh0aW1lSW5TZWNvbmRzKTsKICAgICAgICAKICAgICAgICAvLyBEZWxlZ2F0ZSB0byByZW5kZXJlciAoaGFuZGxlcyBXZWJHUFUgb3IgV2ViR0wpCiAgICAgICAgdGhpcy5zdGF0ZS5yZW5kZXJlci5yZW5kZXJTaW5nbGVQYXNzKAogICAgICAgICAgICBzdGF0aWNFZmZlY3QsCiAgICAgICAgICAgIHRpbWVzdGFtcCwKICAgICAgICAgICAgdGhpcy5zdGF0ZS5jYW52YXMud2lkdGgsCiAgICAgICAgICAgIHRoaXMuc3RhdGUuY2FudmFzLmhlaWdodAogICAgICAgICk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogTXVsdGktcGFzcyByZW5kZXJpbmc6IFRWIFN0YXRpYyDihpIgVGV4dHVyZSDihpIgUGl4ZWxpemF0aW9uIOKGkiBTY3JlZW4KICAgICAqLwogICAgcmVuZGVyTXVsdGlQYXNzKHRpbWVzdGFtcCkgewogICAgICAgIGNvbnN0IHN0YXRpY0VmZmVjdCA9IHRoaXMuc3RhdGUuZWZmZWN0cy5zdGF0aWNFZmZlY3Q7CiAgICAgICAgY29uc3QgcGl4ZWxpemF0aW9uRWZmZWN0ID0gdGhpcy5zdGF0ZS5lZmZlY3RzLnBpeGVsaXphdGlvbkVmZmVjdDsKICAgICAgICAKICAgICAgICBpZiAoIXN0YXRpY0VmZmVjdCB8fCAhcGl4ZWxpemF0aW9uRWZmZWN0KSByZXR1cm47CiAgICAgICAgCiAgICAgICAgLy8gVXBkYXRlIHRpbWUgZm9yIGJvdGggZWZmZWN0cwogICAgICAgIGNvbnN0IHRpbWVJblNlY29uZHMgPSAodGltZXN0YW1wIC0gdGhpcy5zdGF0ZS5hcHAuc3RhcnRUaW1lKSAvIDEwMDAuMDsKICAgICAgICBzdGF0aWNFZmZlY3QudXBkYXRlVGltZSh0aW1lSW5TZWNvbmRzKTsKICAgICAgICBwaXhlbGl6YXRpb25FZmZlY3QudXBkYXRlVGltZSh0aW1lSW5TZWNvbmRzKTsKICAgICAgICAKICAgICAgICAvLyBEZWJ1ZzogTG9nIHJlbmRlcmluZyBwYXJhbWV0ZXJzCiAgICAgICAgY29uc3QgcGl4ZWxQYXJhbXMgPSBwaXhlbGl6YXRpb25FZmZlY3QuZ2V0TWFwcGVkUGFyYW1ldGVycygpOwogICAgICAgIExvZ2dlci5kZWJ1ZygnQVBQJywgYFJlbmRlciBYPSR7cGl4ZWxpemF0aW9uRWZmZWN0LnN0YXRlLnBhcmFtZXRlcnMueC50b0ZpeGVkKDMpfSBZPSR7cGl4ZWxpemF0aW9uRWZmZWN0LnN0YXRlLnBhcmFtZXRlcnMueS50b0ZpeGVkKDMpfSDihpIgcGl4ZWxSb3dzPSR7cGl4ZWxQYXJhbXMucGl4ZWxSb3dzfSBibGVuZD0ke3BpeGVsUGFyYW1zLmJsZW5kRmFjdG9yLnRvRml4ZWQoMil9YCk7CiAgICAgICAgCiAgICAgICAgLy8gRGVsZWdhdGUgdG8gcmVuZGVyZXIgKGhhbmRsZXMgV2ViR1BVIG9yIFdlYkdMIG11bHRpLXBhc3MpCiAgICAgICAgdGhpcy5zdGF0ZS5yZW5kZXJlci5yZW5kZXJNdWx0aVBhc3MoCiAgICAgICAgICAgIHN0YXRpY0VmZmVjdCwKICAgICAgICAgICAgcGl4ZWxpemF0aW9uRWZmZWN0LAogICAgICAgICAgICB0aW1lc3RhbXAsCiAgICAgICAgICAgIHRoaXMuc3RhdGUuY2FudmFzLndpZHRoLAogICAgICAgICAgICB0aGlzLnN0YXRlLmNhbnZhcy5oZWlnaHQKICAgICAgICApOwogICAgfQogICAgCiAgICAvKioKICAgICAqIFJlcXVlc3QgbmV4dCBhbmltYXRpb24gZnJhbWUKICAgICAqLwogICAgcmVxdWVzdE5leHRGcmFtZSgpIHsKICAgICAgICB0aGlzLnN0YXRlLnJlbmRlcmluZy5hbmltYXRpb25GcmFtZUlkID0gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCh0KSA9PiB0aGlzLnJlbmRlcih0KSk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogVXBkYXRlIEZQUyBjb3VudGVyCiAgICAgKi8KICAgIHVwZGF0ZUZQUyh0aW1lc3RhbXApIHsKICAgICAgICBjb25zdCBkZWx0YVRpbWUgPSB0aW1lc3RhbXAgLSB0aGlzLnN0YXRlLnJlbmRlcmluZy5sYXN0RnJhbWVUaW1lOwogICAgICAgIHRoaXMuc3RhdGUucmVuZGVyaW5nLmxhc3RGcmFtZVRpbWUgPSB0aW1lc3RhbXA7CiAgICAgICAgCiAgICAgICAgLy8gVXBkYXRlIEZQUyBkaXNwbGF5IGV2ZXJ5IHNlY29uZAogICAgICAgIGlmICh0aW1lc3RhbXAgLSB0aGlzLnN0YXRlLnJlbmRlcmluZy5mcHNVcGRhdGVUaW1lID4gMTAwMCkgewogICAgICAgICAgICB0aGlzLnN0YXRlLnJlbmRlcmluZy5mcHMgPSBNYXRoLnJvdW5kKAogICAgICAgICAgICAgICAgMTAwMCAvIGRlbHRhVGltZQogICAgICAgICAgICApOwogICAgICAgICAgICB0aGlzLnN0YXRlLnJlbmRlcmluZy5mcHNVcGRhdGVUaW1lID0gdGltZXN0YW1wOwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gTG9nIEZQUyBwZXJpb2RpY2FsbHkgKGV2ZXJ5IDUgc2Vjb25kcykKICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUucmVuZGVyaW5nLmZyYW1lQ291bnQgJSAzMDAgPT09IDApIHsKICAgICAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnQVBQJywgYEZQUzogJHt0aGlzLnN0YXRlLnJlbmRlcmluZy5mcHN9YCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CiAgICAKICAgIC8qKgogICAgICogQXR0ZW1wdCB0byBsb2NrIHNjcmVlbiBvcmllbnRhdGlvbiB0byBsYW5kc2NhcGUgKG1vYmlsZSkKICAgICAqIE11c3QgYmUgY2FsbGVkIGFmdGVyIHVzZXIgaW50ZXJhY3Rpb24gZm9yIHBlcm1pc3Npb24KICAgICAqIE5vdGU6IEFuZHJvaWQgQ2hyb21lIHJlcXVpcmVzIGZ1bGxzY3JlZW4gbW9kZSBmb3Igb3JpZW50YXRpb24gbG9jayB0byB3b3JrCiAgICAgKi8KICAgIGFzeW5jIGxvY2tPcmllbnRhdGlvbigpIHsKICAgICAgICAvLyBTa2lwIGlmIGFscmVhZHkgbG9ja2VkIG9yIGF0dGVtcHRlZAogICAgICAgIGlmICh0aGlzLnN0YXRlLmFwcC5vcmllbnRhdGlvbkxvY2tlZCkgcmV0dXJuOwogICAgICAgIAogICAgICAgIHRyeSB7CiAgICAgICAgICAgIC8vIENoZWNrIGlmIFNjcmVlbiBPcmllbnRhdGlvbiBBUEkgaXMgYXZhaWxhYmxlCiAgICAgICAgICAgIGlmIChzY3JlZW4ub3JpZW50YXRpb24gJiYgc2NyZWVuLm9yaWVudGF0aW9uLmxvY2spIHsKICAgICAgICAgICAgICAgIC8vIFRyeSB0byBsb2NrIG9yaWVudGF0aW9uCiAgICAgICAgICAgICAgICBhd2FpdCBzY3JlZW4ub3JpZW50YXRpb24ubG9jaygnbGFuZHNjYXBlJyk7CiAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLmFwcC5vcmllbnRhdGlvbkxvY2tlZCA9IHRydWU7CiAgICAgICAgICAgICAgICBMb2dnZXIuaW5mbygnQVBQJywgJ1NjcmVlbiBvcmllbnRhdGlvbiBsb2NrZWQgdG8gbGFuZHNjYXBlJyk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBMb2dnZXIuZGVidWcoJ0FQUCcsICdTY3JlZW4gT3JpZW50YXRpb24gQVBJIG5vdCBhdmFpbGFibGUgKGRlc2t0b3Agb3IgdW5zdXBwb3J0ZWQgYnJvd3NlciknKTsKICAgICAgICAgICAgfQogICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgICAgICAgIC8vIE9yaWVudGF0aW9uIGxvY2sgZmFpbGVkIC0gdGhpcyBpcyBleHBlY3RlZCBvbiBBbmRyb2lkIHdpdGhvdXQgZnVsbHNjcmVlbgogICAgICAgICAgICAvLyBNYXJrIGFzIGF0dGVtcHRlZCBzbyB3ZSBkb24ndCBrZWVwIHRyeWluZwogICAgICAgICAgICB0aGlzLnN0YXRlLmFwcC5vcmllbnRhdGlvbkxvY2tlZCA9IHRydWU7CiAgICAgICAgICAgIAogICAgICAgICAgICBpZiAoZXJyb3IubmFtZSA9PT0gJ1NlY3VyaXR5RXJyb3InIHx8IGVycm9yLm1lc3NhZ2UuaW5jbHVkZXMoJ2Z1bGxzY3JlZW4nKSkgewogICAgICAgICAgICAgICAgTG9nZ2VyLmluZm8oJ0FQUCcsICdPcmllbnRhdGlvbiBsb2NrIHJlcXVpcmVzIGZ1bGxzY3JlZW4gb24gdGhpcyBkZXZpY2UgKEFuZHJvaWQpLiBBcHAgd29ya3MgZmluZSB3aXRob3V0IGl0LicpOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgTG9nZ2VyLmRlYnVnKCdBUFAnLCAnQ291bGQgbm90IGxvY2sgb3JpZW50YXRpb246JywgZXJyb3IubWVzc2FnZSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CiAgICAKICAgIC8qKgogICAgICogU2hvdyBlcnJvciBtZXNzYWdlIHRvIHVzZXIKICAgICAqLwogICAgc2hvd0Vycm9yKG1lc3NhZ2UpIHsKICAgICAgICAvLyBTaWxlbnRseSBsb2cgdG8gY29uc29sZSAtIG5vIHBvcHVwcwogICAgICAgIExvZ2dlci5lcnJvcignQVBQJywgbWVzc2FnZSk7CiAgICAgICAgLy8gVXNlciBzZWVzIHN0YXRpYyBldmVuIGlmIGVycm9ycyBvY2N1cgogICAgICAgIC8vIENoZWNrIGNvbnNvbGUgKEYxMikgZm9yIGRlYnVnZ2luZyBpbmZvCiAgICB9CiAgICAKICAgIC8qKgogICAgICogR2V0IGFwcGxpY2F0aW9uIHN0YXRlIGZvciBkZWJ1Z2dpbmcKICAgICAqLwogICAgZ2V0U3RhdGUoKSB7CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgaXNJbml0aWFsaXplZDogdGhpcy5zdGF0ZS5hcHAuaXNJbml0aWFsaXplZCwKICAgICAgICAgICAgaXNSZW5kZXJpbmc6IHRoaXMuc3RhdGUucmVuZGVyaW5nLmlzUnVubmluZywKICAgICAgICAgICAgZnBzOiB0aGlzLnN0YXRlLnJlbmRlcmluZy5mcHMsCiAgICAgICAgICAgIGZyYW1lQ291bnQ6IHRoaXMuc3RhdGUucmVuZGVyaW5nLmZyYW1lQ291bnQsCiAgICAgICAgICAgIHJlbmRlcmVyOiB0aGlzLnN0YXRlLnJlbmRlcmVyPy5nZXRUeXBlKCkgfHwgJ25vbmUnLAogICAgICAgICAgICBjYW52YXNTaXplOiB7CiAgICAgICAgICAgICAgICB3aWR0aDogdGhpcy5zdGF0ZS5jYW52YXM/LndpZHRoLAogICAgICAgICAgICAgICAgaGVpZ2h0OiB0aGlzLnN0YXRlLmNhbnZhcz8uaGVpZ2h0CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIGVmZmVjdE1hbmFnZXI6IHRoaXMuc3RhdGUuZWZmZWN0TWFuYWdlcj8uZ2V0U3RhdGUoKSwKICAgICAgICAgICAgaW5wdXRDb250cm9sbGVyOiB0aGlzLnN0YXRlLmlucHV0Q29udHJvbGxlcj8uZ2V0U3RhdGUoKSwKICAgICAgICAgICAgYXVkaW9Db250cm9sbGVyOiB0aGlzLnN0YXRlLmF1ZGlvQ29udHJvbGxlcj8uZ2V0U3RhdGUoKSwKICAgICAgICAgICAgaXNJbnRlcmFjdGluZzogdGhpcy5zdGF0ZS5lZmZlY3RNYW5hZ2VyPy5pc0ludGVyYWN0aW5nKCkKICAgICAgICB9OwogICAgfQogICAgCiAgICAvKioKICAgICAqIENsZWFuIHVwIHJlc291cmNlcwogICAgICovCiAgICBkZXN0cm95KCkgewogICAgICAgIExvZ2dlci5pbmZvKCdBUFAnLCAnRGVzdHJveWluZyBhcHBsaWNhdGlvbi4uLicpOwogICAgICAgIAogICAgICAgIHRoaXMuc3RvcFJlbmRlckxvb3AoKTsKICAgICAgICAKICAgICAgICBpZiAodGhpcy5zdGF0ZS5pbnB1dENvbnRyb2xsZXIpIHsKICAgICAgICAgICAgdGhpcy5zdGF0ZS5pbnB1dENvbnRyb2xsZXIuZGVzdHJveSgpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICBpZiAodGhpcy5zdGF0ZS5hdWRpb0NvbnRyb2xsZXIpIHsKICAgICAgICAgICAgdGhpcy5zdGF0ZS5hdWRpb0NvbnRyb2xsZXIuZGVzdHJveSgpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZmZlY3RNYW5hZ2VyKSB7CiAgICAgICAgICAgIHRoaXMuc3RhdGUuZWZmZWN0TWFuYWdlci5kZXN0cm95KCk7CiAgICAgICAgfQoKICAgICAgICBpZiAodGhpcy5zdGF0ZS5yZW5kZXJlcikgewogICAgICAgICAgICB0aGlzLnN0YXRlLnJlbmRlcmVyLmRlc3Ryb3koKTsKICAgICAgICB9CgogICAgICAgIExvZ2dlci5pbmZvKCdBUFAnLCAnQXBwbGljYXRpb24gZGVzdHJveWVkJyk7CiAgICB9Cn0KCi8vIEluaXRpYWxpemUgYW5kIHN0YXJ0IGFwcGxpY2F0aW9uIHdoZW4gRE9NIGlzIHJlYWR5CmFzeW5jIGZ1bmN0aW9uIG1haW4oKSB7CiAgICBMb2dnZXIuaW5mbygnTUFJTicsICdTdGFydGluZyBUViBTdGF0aWMgQXBwbGljYXRpb24uLi4nKTsKICAgIAogICAgdHJ5IHsKICAgICAgICAvLyBDcmVhdGUgYW5kIGluaXRpYWxpemUgYXBwCiAgICAgICAgY29uc3QgYXBwID0gbmV3IFRWU3RhdGljQXBwKCk7CiAgICAgICAgYXdhaXQgYXBwLmluaXRpYWxpemUoKTsKICAgICAgICAKICAgICAgICAvLyBNYWtlIGFwcCBnbG9iYWxseSBhY2Nlc3NpYmxlIGZvciBkZWJ1Z2dpbmcKICAgICAgICB3aW5kb3cudHZTdGF0aWNBcHAgPSBhcHA7CiAgICAgICAgCiAgICAgICAgTG9nZ2VyLmluZm8oJ01BSU4nLCAnQXBwbGljYXRpb24gc3RhcnRlZCBzdWNjZXNzZnVsbHkhJyk7CiAgICAgICAgTG9nZ2VyLmluZm8oJ01BSU4nLCAnRGVidWcgc2hvcnRjdXRzOiBDdHJsK1NoaWZ0K0QgKHRvZ2dsZSBvdmVybGF5KSwgQ3RybCtTaGlmdCtMIChkb3dubG9hZCBsb2dzKScpOwogICAgICAgIAogICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgICBMb2dnZXIuZXJyb3IoJ01BSU4nLCAnRmFpbGVkIHRvIHN0YXJ0IGFwcGxpY2F0aW9uOicsIGVycm9yKTsKICAgICAgICAvLyBTaWxlbnRseSBmYWlsIC0gY2hlY2sgY29uc29sZSBmb3IgZGV0YWlscwogICAgICAgIC8vIEFwcCB3aWxsIGdyYWNlZnVsbHkgZmFsbCBiYWNrIHRvIFdlYkdMIGlmIFdlYkdQVSB1bmF2YWlsYWJsZQogICAgfQp9CgovLyBTdGFydCB3aGVuIERPTSBpcyByZWFkeQppZiAoZG9jdW1lbnQucmVhZHlTdGF0ZSA9PT0gJ2xvYWRpbmcnKSB7CiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgbWFpbik7Cn0gZWxzZSB7CiAgICBtYWluKCk7Cn0KCgogICAgPC9zY3JpcHQ+CjwvYm9keT4KPC9odG1sPg==
XJzIHNldCB1cCcpOwogICAgfQoKICAgIC8qKgogICAgICogSGFuZGxlIG1vdXNlIGRvd24gZXZlbnRzCiAgICAgKi8KICAgIGhhbmRsZU1vdXNlRG93bihldmVudCkgewogICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IC8vIFByZXZlbnQgc2Nyb2xsaW5nCiAgICAgICAgCiAgICAgICAgY29uc3QgcG9zaXRpb24gPSB0aGlzLmdldE1vdXNlUG9zaXRpb24oZXZlbnQpOwogICAgICAgIAogICAgICAgIHRoaXMuc3RhdGUuaW50ZXJhY3Rpb24uaXNBY3RpdmUgPSB0cnVlOwogICAgICAgIHRoaXMuc3RhdGUuaW50ZXJhY3Rpb24udHlwZSA9ICdtb3VzZSc7CiAgICAgICAgdGhpcy5zdGF0ZS5pbnRlcmFjdGlvbi5wb3NpdGlvbiA9IHBvc2l0aW9uOwogICAgICAgIAogICAgICAgIC8vIFN0YXJ0IGF1ZGlvIG9uIGZpcnN0IGludGVyYWN0aW9uIChQaGFzZSBEKQogICAgICAgIGlmICh0aGlzLmF1ZGlvQ29udHJvbGxlcikgewogICAgICAgICAgICB0aGlzLmF1ZGlvQ29udHJvbGxlci5oYW5kbGVGaXJzdEludGVyYWN0aW9uKCk7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIC8vIExvY2sgc2NyZWVuIG9yaWVudGF0aW9uIG9uIGZpcnN0IGludGVyYWN0aW9uIChQaGFzZSBGIC0gTW9iaWxlKQogICAgICAgIGlmICh0aGlzLmFwcCAmJiB0aGlzLmFwcC5sb2NrT3JpZW50YXRpb24pIHsKICAgICAgICAgICAgdGhpcy5hcHAubG9ja09yaWVudGF0aW9uKCk7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIC8vIFVwZGF0ZSBlZmZlY3QgbWFuYWdlciAodmlzdWFsIGVmZmVjdHMpCiAgICAgICAgdGhpcy5lZmZlY3RNYW5hZ2VyLnVwZGF0ZUludGVyYWN0aW9uKHBvc2l0aW9uLngsIHBvc2l0aW9uLnksIHRydWUpOwogICAgICAgIAogICAgICAgIC8vIFVwZGF0ZSBhdWRpbyBjb250cm9sbGVyIChmaWx0ZXIgY29udHJvbCAtIFBoYXNlIEUpCiAgICAgICAgaWYgKHRoaXMuYXVkaW9Db250cm9sbGVyKSB7CiAgICAgICAgICAgIHRoaXMuYXVkaW9Db250cm9sbGVyLnVwZGF0ZUZpbHRlckZyb21JbnRlcmFjdGlvbihwb3NpdGlvbi55LCB0cnVlKTsKICAgICAgICAgICAgdGhpcy5hdWRpb0NvbnRyb2xsZXIudXBkYXRlUmh5dGhtRnJvbUludGVyYWN0aW9uKHBvc2l0aW9uLngsIHRydWUpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICBpZiAodGhpcy5zdGF0ZS5jb25maWcuZW5hYmxlTG9nZ2luZykgewogICAgICAgICAgICBMb2dnZXIuZGVidWcoJ0lOUFVUJywgYE1vdXNlIGRvd24gYXQgKCR7cG9zaXRpb24ueC50b0ZpeGVkKDMpfSwgJHtwb3NpdGlvbi55LnRvRml4ZWQoMyl9KWApOwogICAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIEhhbmRsZSBtb3VzZSBtb3ZlIGV2ZW50cwogICAgICovCiAgICBoYW5kbGVNb3VzZU1vdmUoZXZlbnQpIHsKICAgICAgICBpZiAoIXRoaXMuc3RhdGUuaW50ZXJhY3Rpb24uaXNBY3RpdmUgfHwgdGhpcy5zdGF0ZS5pbnRlcmFjdGlvbi50eXBlICE9PSAnbW91c2UnKSB7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTsKICAgICAgICAKICAgICAgICBjb25zdCBwb3NpdGlvbiA9IHRoaXMuZ2V0TW91c2VQb3NpdGlvbihldmVudCk7CiAgICAgICAgdGhpcy5zdGF0ZS5pbnRlcmFjdGlvbi5wb3NpdGlvbiA9IHBvc2l0aW9uOwogICAgICAgIAogICAgICAgIC8vIFVwZGF0ZSBlZmZlY3QgbWFuYWdlciAodmlzdWFsIGVmZmVjdHMpCiAgICAgICAgdGhpcy5lZmZlY3RNYW5hZ2VyLnVwZGF0ZUludGVyYWN0aW9uKHBvc2l0aW9uLngsIHBvc2l0aW9uLnksIHRydWUpOwogICAgICAgIAogICAgICAgIC8vIFVwZGF0ZSBhdWRpbyBjb250cm9sbGVyIChmaWx0ZXIgY29udHJvbCAtIFBoYXNlIEUpCiAgICAgICAgaWYgKHRoaXMuYXVkaW9Db250cm9sbGVyKSB7CiAgICAgICAgICAgIHRoaXMuYXVkaW9Db250cm9sbGVyLnVwZGF0ZUZpbHRlckZyb21JbnRlcmFjdGlvbihwb3NpdGlvbi55LCB0cnVlKTsKICAgICAgICAgICAgdGhpcy5hdWRpb0NvbnRyb2xsZXIudXBkYXRlUmh5dGhtRnJvbUludGVyYWN0aW9uKHBvc2l0aW9uLngsIHRydWUpOwogICAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIEhhbmRsZSBtb3VzZSB1cCBldmVudHMKICAgICAqLwogICAgaGFuZGxlTW91c2VVcChldmVudCkgewogICAgICAgIGlmICghdGhpcy5zdGF0ZS5pbnRlcmFjdGlvbi5pc0FjdGl2ZSkgcmV0dXJuOwogICAgICAgIAogICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7CiAgICAgICAgCiAgICAgICAgdGhpcy5lbmRJbnRlcmFjdGlvbigpOwogICAgfQoKCiAgICAvKioKICAgICAqIEhhbmRsZSB0b3VjaCBzdGFydCBldmVudHMKICAgICAqLwogICAgaGFuZGxlVG91Y2hTdGFydChldmVudCkgewogICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IC8vIFByZXZlbnQgc2Nyb2xsaW5nIQogICAgICAgIAogICAgICAgIC8vIENoZWNrIGZvciAzLWZpbmdlciB0b3VjaCBnZXN0dXJlIChkcm9uZSBtb2RlIHRvZ2dsZSkKICAgICAgICAvLyBPbmx5IHRvZ2dsZSBvbmNlIHdoZW4gdHJhbnNpdGlvbmluZyB0byAzIGZpbmdlcnMKICAgICAgICBpZiAoZXZlbnQudG91Y2hlcy5sZW5ndGggPT09IDMgJiYgIXRoaXMuc3RhdGUuZHJvbmVUb2dnbGUudGhyZWVGaW5nZXJBY3RpdmUpIHsKICAgICAgICAgICAgdGhpcy5zdGF0ZS5kcm9uZVRvZ2dsZS50aHJlZUZpbmdlckFjdGl2ZSA9IHRydWU7CiAgICAgICAgICAgIHRoaXMudG9nZ2xlRHJvbmVNb2RlKCk7CiAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnSU5QVVQnLCAnMy1maW5nZXIgdG91Y2ggZGV0ZWN0ZWQgLSB0b2dnbGluZyBkcm9uZSBtb2RlJyk7CiAgICAgICAgICAgIHJldHVybjsgLy8gRG9uJ3QgcHJvY2VzcyBhcyBub3JtYWwgaW50ZXJhY3Rpb24KICAgICAgICB9CiAgICAgICAgCiAgICAgICAgLy8gSWYgd2UgYWxyZWFkeSBoYXZlIHRoZSAzLWZpbmdlciBnZXN0dXJlIGFjdGl2ZSwgaWdub3JlIG90aGVyIHRvdWNoZXMKICAgICAgICBpZiAodGhpcy5zdGF0ZS5kcm9uZVRvZ2dsZS50aHJlZUZpbmdlckFjdGl2ZSkgewogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIAogICAgICAgIGlmICh0aGlzLnN0YXRlLmludGVyYWN0aW9uLmlzQWN0aXZlKSByZXR1cm47IC8vIEFscmVhZHkgdHJhY2tpbmcgYSB0b3VjaAogICAgICAgIAogICAgICAgIGNvbnN0IHRvdWNoID0gZXZlbnQuY2hhbmdlZFRvdWNoZXNbMF07CiAgICAgICAgdGhpcy5zdGF0ZS5pbnRlcmFjdGlvbi5pc0FjdGl2ZSA9IHRydWU7CiAgICAgICAgdGhpcy5zdGF0ZS5pbnRlcmFjdGlvbi50eXBlID0gJ3RvdWNoJzsKICAgICAgICB0aGlzLnN0YXRlLmludGVyYWN0aW9uLnRvdWNoSWQgPSB0b3VjaC5pZGVudGlmaWVyOwogICAgICAgIAogICAgICAgIGNvbnN0IHBvc2l0aW9uID0gdGhpcy5nZXRUb3VjaFBvc2l0aW9uKHRvdWNoKTsKICAgICAgICB0aGlzLnN0YXRlLmludGVyYWN0aW9uLnBvc2l0aW9uID0gcG9zaXRpb247CiAgICAgICAgCiAgICAgICAgLy8gU3RhcnQgYXVkaW8gb24gZmlyc3QgaW50ZXJhY3Rpb24gKFBoYXNlIEQpCiAgICAgICAgaWYgKHRoaXMuYXVkaW9Db250cm9sbGVyKSB7CiAgICAgICAgICAgIHRoaXMuYXVkaW9Db250cm9sbGVyLmhhbmRsZUZpcnN0SW50ZXJhY3Rpb24oKTsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgLy8gTG9jayBzY3JlZW4gb3JpZW50YXRpb24gb24gZmlyc3QgaW50ZXJhY3Rpb24gKFBoYXNlIEYgLSBNb2JpbGUpCiAgICAgICAgaWYgKHRoaXMuYXBwICYmIHRoaXMuYXBwLmxvY2tPcmllbnRhdGlvbikgewogICAgICAgICAgICB0aGlzLmFwcC5sb2NrT3JpZW50YXRpb24oKTsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgLy8gVXBkYXRlIGVmZmVjdCBtYW5hZ2VyICh2aXN1YWwgZWZmZWN0cykKICAgICAgICB0aGlzLmVmZmVjdE1hbmFnZXIudXBkYXRlSW50ZXJhY3Rpb24ocG9zaXRpb24ueCwgcG9zaXRpb24ueSwgdHJ1ZSk7CiAgICAgICAgCiAgICAgICAgLy8gVXBkYXRlIGF1ZGlvIGNvbnRyb2xsZXIgKGZpbHRlciBjb250cm9sIC0gUGhhc2UgRSkKICAgICAgICBpZiAodGhpcy5hdWRpb0NvbnRyb2xsZXIpIHsKICAgICAgICAgICAgdGhpcy5hdWRpb0NvbnRyb2xsZXIudXBkYXRlRmlsdGVyRnJvbUludGVyYWN0aW9uKHBvc2l0aW9uLnksIHRydWUpOwogICAgICAgICAgICB0aGlzLmF1ZGlvQ29udHJvbGxlci51cGRhdGVSaHl0aG1Gcm9tSW50ZXJhY3Rpb24ocG9zaXRpb24ueCwgdHJ1ZSk7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIGlmICh0aGlzLnN0YXRlLmNvbmZpZy5lbmFibGVMb2dnaW5nKSB7CiAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnSU5QVVQnLCBgVG91Y2ggc3RhcnQgYXQgKCR7cG9zaXRpb24ueC50b0ZpeGVkKDMpfSwgJHtwb3NpdGlvbi55LnRvRml4ZWQoMyl9KWApOwogICAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIEhhbmRsZSB0b3VjaCBtb3ZlIGV2ZW50cwogICAgICovCiAgICBoYW5kbGVUb3VjaE1vdmUoZXZlbnQpIHsKICAgICAgICAvLyBDaGVjayBmb3IgMy1maW5nZXIgdG91Y2ggZ2VzdHVyZSAoZHJvbmUgbW9kZSB0b2dnbGUpCiAgICAgICAgLy8gT25seSB0b2dnbGUgb25jZSB3aGVuIHRyYW5zaXRpb25pbmcgdG8gMyBmaW5nZXJzCiAgICAgICAgaWYgKGV2ZW50LnRvdWNoZXMubGVuZ3RoID09PSAzICYmICF0aGlzLnN0YXRlLmRyb25lVG9nZ2xlLnRocmVlRmluZ2VyQWN0aXZlKSB7CiAgICAgICAgICAgIHRoaXMuc3RhdGUuZHJvbmVUb2dnbGUudGhyZWVGaW5nZXJBY3RpdmUgPSB0cnVlOwogICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5pbnRlcmFjdGlvbi5pc0FjdGl2ZSkgewogICAgICAgICAgICAgICAgdGhpcy5lbmRJbnRlcmFjdGlvbigpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMudG9nZ2xlRHJvbmVNb2RlKCk7CiAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnSU5QVVQnLCAnMy1maW5nZXIgdG91Y2ggZGV0ZWN0ZWQgZHVyaW5nIG1vdmUgLSB0b2dnbGluZyBkcm9uZSBtb2RlJyk7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgLy8gSWYgd2UgYWxyZWFkeSBoYXZlIHRoZSAzLWZpbmdlciBnZXN0dXJlIGFjdGl2ZSwgaWdub3JlIG90aGVyIHRvdWNoZXMKICAgICAgICBpZiAodGhpcy5zdGF0ZS5kcm9uZVRvZ2dsZS50aHJlZUZpbmdlckFjdGl2ZSkgewogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIAogICAgICAgIGlmICghdGhpcy5zdGF0ZS5pbnRlcmFjdGlvbi5pc0FjdGl2ZSB8fCB0aGlzLnN0YXRlLmludGVyYWN0aW9uLnR5cGUgIT09ICd0b3VjaCcpIHsKICAgICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICAKICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpOwogICAgICAgIAogICAgICAgIC8vIEZpbmQgdGhlIHRvdWNoIHdlJ3JlIHRyYWNraW5nCiAgICAgICAgY29uc3QgdG91Y2ggPSBBcnJheS5mcm9tKGV2ZW50LmNoYW5nZWRUb3VjaGVzKS5maW5kKAogICAgICAgICAgICB0ID0+IHQuaWRlbnRpZmllciA9PT0gdGhpcy5zdGF0ZS5pbnRlcmFjdGlvbi50b3VjaElkCiAgICAgICAgKTsKICAgICAgICAKICAgICAgICBpZiAoIXRvdWNoKSByZXR1cm47CiAgICAgICAgCiAgICAgICAgY29uc3QgcG9zaXRpb24gPSB0aGlzLmdldFRvdWNoUG9zaXRpb24odG91Y2gpOwogICAgICAgIHRoaXMuc3RhdGUuaW50ZXJhY3Rpb24ucG9zaXRpb24gPSBwb3NpdGlvbjsKICAgICAgICAKICAgICAgICAvLyBVcGRhdGUgZWZmZWN0IG1hbmFnZXIgKHZpc3VhbCBlZmZlY3RzKQogICAgICAgIHRoaXMuZWZmZWN0TWFuYWdlci51cGRhdGVJbnRlcmFjdGlvbihwb3NpdGlvbi54LCBwb3NpdGlvbi55LCB0cnVlKTsKICAgICAgICAKICAgICAgICAvLyBVcGRhdGUgYXVkaW8gY29udHJvbGxlciAoZmlsdGVyIGNvbnRyb2wgLSBQaGFzZSBFKQogICAgICAgIGlmICh0aGlzLmF1ZGlvQ29udHJvbGxlcikgewogICAgICAgICAgICB0aGlzLmF1ZGlvQ29udHJvbGxlci51cGRhdGVGaWx0ZXJGcm9tSW50ZXJhY3Rpb24ocG9zaXRpb24ueSwgdHJ1ZSk7CiAgICAgICAgICAgIHRoaXMuYXVkaW9Db250cm9sbGVyLnVwZGF0ZVJoeXRobUZyb21JbnRlcmFjdGlvbihwb3NpdGlvbi54LCB0cnVlKTsKICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBIYW5kbGUgdG91Y2ggZW5kIGV2ZW50cwogICAgICovCiAgICBoYW5kbGVUb3VjaEVuZChldmVudCkgewogICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7CiAgICAgICAgCiAgICAgICAgLy8gUmVzZXQgMy1maW5nZXIgZ2VzdHVyZSBmbGFnIHdoZW4gZmluZ2VycyBnbyBiZWxvdyAzCiAgICAgICAgaWYgKGV2ZW50LnRvdWNoZXMubGVuZ3RoIDwgMykgewogICAgICAgICAgICB0aGlzLnN0YXRlLmRyb25lVG9nZ2xlLnRocmVlRmluZ2VyQWN0aXZlID0gZmFsc2U7CiAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnSU5QVVQnLCAnMy1maW5nZXIgZ2VzdHVyZSByZXNldCAoZmluZ2VycyBsaWZ0ZWQpJyk7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIGlmICghdGhpcy5zdGF0ZS5pbnRlcmFjdGlvbi5pc0FjdGl2ZSkgcmV0dXJuOwogICAgICAgIAogICAgICAgIC8vIENoZWNrIGlmIG91ciB0cmFja2VkIHRvdWNoIGVuZGVkCiAgICAgICAgY29uc3QgdG91Y2ggPSBBcnJheS5mcm9tKGV2ZW50LmNoYW5nZWRUb3VjaGVzKS5maW5kKAogICAgICAgICAgICB0ID0+IHQuaWRlbnRpZmllciA9PT0gdGhpcy5zdGF0ZS5pbnRlcmFjdGlvbi50b3VjaElkCiAgICAgICAgKTsKICAgICAgICAKICAgICAgICBpZiAodG91Y2gpIHsKICAgICAgICAgICAgdGhpcy5lbmRJbnRlcmFjdGlvbigpOwogICAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIEhhbmRsZSB0b3VjaCBjYW5jZWwgZXZlbnRzCiAgICAgKi8KICAgIGhhbmRsZVRvdWNoQ2FuY2VsKGV2ZW50KSB7CiAgICAgICAgLy8gUmVzZXQgMy1maW5nZXIgZ2VzdHVyZSBmbGFnCiAgICAgICAgdGhpcy5zdGF0ZS5kcm9uZVRvZ2dsZS50aHJlZUZpbmdlckFjdGl2ZSA9IGZhbHNlOwogICAgICAgIAogICAgICAgIGlmICh0aGlzLnN0YXRlLmludGVyYWN0aW9uLmlzQWN0aXZlICYmIHRoaXMuc3RhdGUuaW50ZXJhY3Rpb24udHlwZSA9PT0gJ3RvdWNoJykgewogICAgICAgICAgICB0aGlzLmVuZEludGVyYWN0aW9uKCk7CiAgICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogSGFuZGxlIGtleWJvYXJkIGV2ZW50cyAoc3BhY2UgYmFyIGZvciBkcm9uZSB0b2dnbGUpCiAgICAgKi8KICAgIGhhbmRsZUtleURvd24oZXZlbnQpIHsKICAgICAgICAvLyBTcGFjZSBiYXIgdG9nZ2xlcyBkcm9uZSBtb2RlCiAgICAgICAgaWYgKGV2ZW50LmNvZGUgPT09ICdTcGFjZScgfHwgZXZlbnQua2V5ID09PSAnICcpIHsKICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTsgLy8gUHJldmVudCBwYWdlIHNjcm9sbAogICAgICAgICAgICAKICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuaW50ZXJhY3Rpb24uaXNBY3RpdmUpIHsKICAgICAgICAgICAgICAgIC8vIEN1cnJlbnRseSBpbnRlcmFjdGluZyAtIHF1ZXVlIHRoZSB0b2dnbGUgZm9yIHdoZW4gaW50ZXJhY3Rpb24gZW5kcwogICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS5kcm9uZVRvZ2dsZS5wZW5kaW5nVG9nZ2xlID0gdHJ1ZTsKICAgICAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnSU5QVVQnLCAnRHJvbmUgdG9nZ2xlIHF1ZXVlZCAoaW50ZXJhY3Rpb24gYWN0aXZlKScpOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgLy8gTm90IGludGVyYWN0aW5nIC0gdG9nZ2xlIGltbWVkaWF0ZWx5CiAgICAgICAgICAgICAgICB0aGlzLnRvZ2dsZURyb25lTW9kZSgpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogVG9nZ2xlIGRyb25lIG1vZGUgKGJhY2tncm91bmQgbm9pc2Ugd2hlbiBub3QgY2xpY2tpbmcpCiAgICAgKi8KICAgIHRvZ2dsZURyb25lTW9kZSgpIHsKICAgICAgICBpZiAodGhpcy5hdWRpb0NvbnRyb2xsZXIpIHsKICAgICAgICAgICAgdGhpcy5hdWRpb0NvbnRyb2xsZXIudG9nZ2xlRHJvbmVNb2RlKCk7CiAgICAgICAgICAgIExvZ2dlci5pbmZvKCdJTlBVVCcsICdEcm9uZSBtb2RlIHRvZ2dsZWQnKTsKICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBFbmQgaW50ZXJhY3Rpb24gKHJldHVybiB0byByYXcgc3RhdGljKQogICAgICovCiAgICBlbmRJbnRlcmFjdGlvbigpIHsKICAgICAgICB0aGlzLnN0YXRlLmludGVyYWN0aW9uLmlzQWN0aXZlID0gZmFsc2U7CiAgICAgICAgdGhpcy5zdGF0ZS5pbnRlcmFjdGlvbi50b3VjaElkID0gbnVsbDsKICAgICAgICAKICAgICAgICAvLyBOb3RpZnkgZWZmZWN0IG1hbmFnZXIgKGluc3RhbnQgcmV0dXJuIHRvIHJhdyBzdGF0aWMpCiAgICAgICAgdGhpcy5lZmZlY3RNYW5hZ2VyLnVwZGF0ZUludGVyYWN0aW9uKDAsIDAsIGZhbHNlKTsKICAgICAgICAKICAgICAgICAvLyBSZXNldCBhdWRpbyBmaWx0ZXIgYW5kIHJoeXRobSAoYnlwYXNzIGZpbHRlciwgc3RvcCByaHl0aG0gLSBQaGFzZSBFKQogICAgICAgIGlmICh0aGlzLmF1ZGlvQ29udHJvbGxlcikgewogICAgICAgICAgICB0aGlzLmF1ZGlvQ29udHJvbGxlci51cGRhdGVGaWx0ZXJGcm9tSW50ZXJhY3Rpb24oMCwgZmFsc2UpOwogICAgICAgICAgICB0aGlzLmF1ZGlvQ29udHJvbGxlci51cGRhdGVSaHl0aG1Gcm9tSW50ZXJhY3Rpb24oMCwgZmFsc2UpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICAvLyBFeGVjdXRlIHBlbmRpbmcgZHJvbmUgdG9nZ2xlIGlmIHF1ZXVlZAogICAgICAgIGlmICh0aGlzLnN0YXRlLmRyb25lVG9nZ2xlLnBlbmRpbmdUb2dnbGUpIHsKICAgICAgICAgICAgdGhpcy5zdGF0ZS5kcm9uZVRvZ2dsZS5wZW5kaW5nVG9nZ2xlID0gZmFsc2U7CiAgICAgICAgICAgIHRoaXMudG9nZ2xlRHJvbmVNb2RlKCk7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIGlmICh0aGlzLnN0YXRlLmNvbmZpZy5lbmFibGVMb2dnaW5nKSB7CiAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnSU5QVVQnLCAnSW50ZXJhY3Rpb24gZW5kZWQnKTsKICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgbm9ybWFsaXplZCBtb3VzZSBwb3NpdGlvbiAoMC0xKQogICAgICovCiAgICBnZXRNb3VzZVBvc2l0aW9uKGV2ZW50KSB7CiAgICAgICAgY29uc3QgcmVjdCA9IHRoaXMuY2FudmFzLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOwogICAgICAgIAogICAgICAgIGxldCB4ID0gKGV2ZW50LmNsaWVudFggLSByZWN0LmxlZnQpIC8gcmVjdC53aWR0aDsKICAgICAgICBsZXQgeSA9IChldmVudC5jbGllbnRZIC0gcmVjdC50b3ApIC8gcmVjdC5oZWlnaHQ7CiAgICAgICAgCiAgICAgICAgLy8gQXBwbHkgWSBpbnZlcnNpb24gaWYgZW5hYmxlZAogICAgICAgIGlmICh0aGlzLnN0YXRlLmNvbmZpZy5pbnZlcnRZKSB7CiAgICAgICAgICAgIHkgPSAxLjAgLSB5OwogICAgICAgIH0KICAgICAgICAKICAgICAgICAvLyBDbGFtcCB0byAwLTEgcmFuZ2UKICAgICAgICB4ID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oMSwgeCkpOwogICAgICAgIHkgPSBNYXRoLm1heCgwLCBNYXRoLm1pbigxLCB5KSk7CiAgICAgICAgCiAgICAgICAgcmV0dXJuIHsgeCwgeSB9OwogICAgfQoKICAgIC8qKgogICAgICogR2V0IG5vcm1hbGl6ZWQgdG91Y2ggcG9zaXRpb24gKDAtMSkKICAgICAqLwogICAgZ2V0VG91Y2hQb3NpdGlvbih0b3VjaCkgewogICAgICAgIGNvbnN0IHJlY3QgPSB0aGlzLmNhbnZhcy5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTsKICAgICAgICAKICAgICAgICBsZXQgeCA9ICh0b3VjaC5jbGllbnRYIC0gcmVjdC5sZWZ0KSAvIHJlY3Qud2lkdGg7CiAgICAgICAgbGV0IHkgPSAodG91Y2guY2xpZW50WSAtIHJlY3QudG9wKSAvIHJlY3QuaGVpZ2h0OwogICAgICAgIAogICAgICAgIC8vIEFwcGx5IFkgaW52ZXJzaW9uIGlmIGVuYWJsZWQKICAgICAgICBpZiAodGhpcy5zdGF0ZS5jb25maWcuaW52ZXJ0WSkgewogICAgICAgICAgICB5ID0gMS4wIC0geTsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgLy8gQ2xhbXAgdG8gMC0xIHJhbmdlCiAgICAgICAgeCA9IE1hdGgubWF4KDAsIE1hdGgubWluKDEsIHgpKTsKICAgICAgICB5ID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oMSwgeSkpOwogICAgICAgIAogICAgICAgIHJldHVybiB7IHgsIHkgfTsKICAgIH0KCiAgICAvKioKICAgICAqIENvbmZpZ3VyZSBpbnB1dCBjb250cm9sbGVyCiAgICAgKi8KICAgIGNvbmZpZ3VyZShjb25maWcpIHsKICAgICAgICBpZiAoY29uZmlnLmludmVydFkgIT09IHVuZGVmaW5lZCkgewogICAgICAgICAgICB0aGlzLnN0YXRlLmNvbmZpZy5pbnZlcnRZID0gQm9vbGVhbihjb25maWcuaW52ZXJ0WSk7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIGlmIChjb25maWcuZW5hYmxlTG9nZ2luZyAhPT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICAgIHRoaXMuc3RhdGUuY29uZmlnLmVuYWJsZUxvZ2dpbmcgPSBCb29sZWFuKGNvbmZpZy5lbmFibGVMb2dnaW5nKTsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgTG9nZ2VyLmluZm8oJ0lOUFVUJywgJ0NvbmZpZ3VyYXRpb24gdXBkYXRlZDonLCB0aGlzLnN0YXRlLmNvbmZpZyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgaW5wdXQgY29udHJvbGxlciBzdGF0ZSBmb3IgZGVidWdnaW5nCiAgICAgKi8KICAgIGdldFN0YXRlKCkgewogICAgICAgIHJldHVybiB7CiAgICAgICAgICAgIGlzQWN0aXZlOiB0aGlzLnN0YXRlLmludGVyYWN0aW9uLmlzQWN0aXZlLAogICAgICAgICAgICB0eXBlOiB0aGlzLnN0YXRlLmludGVyYWN0aW9uLnR5cGUsCiAgICAgICAgICAgIHBvc2l0aW9uOiB7IC4uLnRoaXMuc3RhdGUuaW50ZXJhY3Rpb24ucG9zaXRpb24gfSwKICAgICAgICAgICAgY29uZmlnOiB7IC4uLnRoaXMuc3RhdGUuY29uZmlnIH0KICAgICAgICB9OwogICAgfQoKICAgIC8qKgogICAgICogQ2xlYW4gdXAgZXZlbnQgbGlzdGVuZXJzIGFuZCByZXNvdXJjZXMKICAgICAqLwogICAgZGVzdHJveSgpIHsKICAgICAgICAvLyBSZW1vdmUgZXZlbnQgbGlzdGVuZXJzCiAgICAgICAgdGhpcy5jYW52YXMucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgdGhpcy5oYW5kbGVNb3VzZURvd24pOwogICAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZW1vdmUnLCB0aGlzLmhhbmRsZU1vdXNlTW92ZSk7CiAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNldXAnLCB0aGlzLmhhbmRsZU1vdXNlVXApOwogICAgICAgIAogICAgICAgIHRoaXMuY2FudmFzLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNoc3RhcnQnLCB0aGlzLmhhbmRsZVRvdWNoU3RhcnQpOwogICAgICAgIHRoaXMuY2FudmFzLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNobW92ZScsIHRoaXMuaGFuZGxlVG91Y2hNb3ZlKTsKICAgICAgICB0aGlzLmNhbnZhcy5yZW1vdmVFdmVudExpc3RlbmVyKCd0b3VjaGVuZCcsIHRoaXMuaGFuZGxlVG91Y2hFbmQpOwogICAgICAgIHRoaXMuY2FudmFzLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNoY2FuY2VsJywgdGhpcy5oYW5kbGVUb3VjaENhbmNlbCk7CiAgICAgICAgCiAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2tleWRvd24nLCB0aGlzLmhhbmRsZUtleURvd24pOwogICAgICAgIAogICAgICAgIExvZ2dlci5pbmZvKCdJTlBVVCcsICdJbnB1dENvbnRyb2xsZXIgZGVzdHJveWVkJyk7CiAgICB9Cn0KCklucHV0Q29udHJvbGxlcjsKCgovLyBtYWluLmpzIC0gVFYgU3RhdGljIEFwcGxpY2F0aW9uIENvcmUKLy8gdjI6IER1YWwgcmVuZGVyZXIgc3VwcG9ydCAoV2ViR1BVICsgV2ViR0wgZmFsbGJhY2spCi8vIEhhbmRsZXMgcmVuZGVyZXIgaW5pdGlhbGl6YXRpb24sIGVmZmVjdCBtYW5hZ2VtZW50LCBhbmQgcmVuZGVyIGxvb3AKCmNsYXNzIFRWU3RhdGljQXBwIHsKICAgIGNvbnN0cnVjdG9yKCkgewogICAgICAgIC8vIFN0cnVjdHVyZWQgc3RhdGUKICAgICAgICB0aGlzLnN0YXRlID0gewogICAgICAgICAgICAvLyBDYW52YXMKICAgICAgICAgICAgY2FudmFzOiBudWxsLAogICAgICAgICAgICAKICAgICAgICAgICAgLy8gUmVuZGVyZXIgKFdlYkdQVSBvciBXZWJHTCAtIGF1dG8tc2VsZWN0ZWQpCiAgICAgICAgICAgIHJlbmRlcmVyOiBudWxsLAogICAgICAgICAgICAKICAgICAgICAgICAgLy8gUmVuZGVyaW5nIHN0YXRlCiAgICAgICAgICAgIHJlbmRlcmluZzogewogICAgICAgICAgICAgICAgYW5pbWF0aW9uRnJhbWVJZDogbnVsbCwKICAgICAgICAgICAgICAgIGlzUnVubmluZzogZmFsc2UsCiAgICAgICAgICAgICAgICBsYXN0RnJhbWVUaW1lOiAwLAogICAgICAgICAgICAgICAgZnJhbWVDb3VudDogMCwKICAgICAgICAgICAgICAgIGZwczogMCwKICAgICAgICAgICAgICAgIGZwc1VwZGF0ZVRpbWU6IDAKICAgICAgICAgICAgfSwKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIE1hbmFnZXJzCiAgICAgICAgICAgIGVmZmVjdE1hbmFnZXI6IG51bGwsCiAgICAgICAgICAgIGlucHV0Q29udHJvbGxlcjogbnVsbCwKICAgICAgICAgICAgYXVkaW9Db250cm9sbGVyOiBudWxsLAogICAgICAgICAgICAKICAgICAgICAgICAgLy8gRWZmZWN0cyAoc3RvcmVkIGZvciBlYXN5IGFjY2VzcykKICAgICAgICAgICAgZWZmZWN0czogewogICAgICAgICAgICAgICAgc3RhdGljRWZmZWN0OiBudWxsLAogICAgICAgICAgICAgICAgcGl4ZWxpemF0aW9uRWZmZWN0OiBudWxsCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBBcHAgc3RhdGUKICAgICAgICAgICAgYXBwOiB7CiAgICAgICAgICAgICAgICBpc0luaXRpYWxpemVkOiBmYWxzZSwKICAgICAgICAgICAgICAgIHN0YXJ0VGltZTogMCwKICAgICAgICAgICAgICAgIG9yaWVudGF0aW9uTG9ja2VkOiBmYWxzZQogICAgICAgICAgICB9CiAgICAgICAgfTsKICAgICAgICAKICAgICAgICBMb2dnZXIuaW5mbygnQVBQJywgJ1RWIFN0YXRpYyBBcHBsaWNhdGlvbiBjcmVhdGVkICh2MiAtIGR1YWwgcmVuZGVyZXIpJyk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogSW5pdGlhbGl6ZSB0aGUgYXBwbGljYXRpb24KICAgICAqLwogICAgYXN5bmMgaW5pdGlhbGl6ZSgpIHsKICAgICAgICB0cnkgewogICAgICAgICAgICBMb2dnZXIuaW5mbygnQVBQJywgJ1N0YXJ0aW5nIGluaXRpYWxpemF0aW9uLi4uJyk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyAxLiBTZXR1cCBjYW52YXMKICAgICAgICAgICAgdGhpcy5zZXR1cENhbnZhcygpOwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gMi4gSW5pdGlhbGl6ZSByZW5kZXJlciAoV2ViR1BVIG9yIFdlYkdMIC0gYXV0by1zZWxlY3RlZCkKICAgICAgICAgICAgYXdhaXQgdGhpcy5pbml0aWFsaXplUmVuZGVyZXIoKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIDMuIENyZWF0ZSBlZmZlY3QgbWFuYWdlcgogICAgICAgICAgICB0aGlzLnN0YXRlLmVmZmVjdE1hbmFnZXIgPSBuZXcgRWZmZWN0TWFuYWdlcih0aGlzLnN0YXRlLnJlbmRlcmVyKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIDQuIENyZWF0ZSBhbmQgcmVnaXN0ZXIgVFYgU3RhdGljIGVmZmVjdCAoSUQ6IDApCiAgICAgICAgICAgIGNvbnN0IHR2U3RhdGljRWZmZWN0ID0gbmV3IFRWU3RhdGljRWZmZWN0KCk7CiAgICAgICAgICAgIHRoaXMuc3RhdGUuZWZmZWN0cy5zdGF0aWNFZmZlY3QgPSB0dlN0YXRpY0VmZmVjdDsKICAgICAgICAgICAgYXdhaXQgdGhpcy5zdGF0ZS5lZmZlY3RNYW5hZ2VyLnJlZ2lzdGVyRWZmZWN0KHR2U3RhdGljRWZmZWN0KTsKICAgICAgICAgICAgYXdhaXQgdGhpcy5zdGF0ZS5lZmZlY3RNYW5hZ2VyLmNyZWF0ZVBpcGVsaW5lKAogICAgICAgICAgICAgICAgdHZTdGF0aWNFZmZlY3QsCiAgICAgICAgICAgICAgICBmYWxzZSAgLy8gbmVlZHNUZXh0dXJlSW5wdXQgPSBmYWxzZSAoZ2VuZXJhdGVzIGNvbnRlbnQpCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyA1LiBDcmVhdGUgYW5kIHJlZ2lzdGVyIFBpeGVsaXphdGlvbiBlZmZlY3QgKElEOiAxKQogICAgICAgICAgICBjb25zdCBwaXhlbGl6YXRpb25FZmZlY3QgPSBuZXcgUGl4ZWxpemF0aW9uRWZmZWN0KCk7CiAgICAgICAgICAgIHRoaXMuc3RhdGUuZWZmZWN0cy5waXhlbGl6YXRpb25FZmZlY3QgPSBwaXhlbGl6YXRpb25FZmZlY3Q7CiAgICAgICAgICAgIGF3YWl0IHRoaXMuc3RhdGUuZWZmZWN0TWFuYWdlci5yZWdpc3RlckVmZmVjdChwaXhlbGl6YXRpb25FZmZlY3QpOwogICAgICAgICAgICBhd2FpdCB0aGlzLnN0YXRlLmVmZmVjdE1hbmFnZXIuY3JlYXRlUGlwZWxpbmUoCiAgICAgICAgICAgICAgICBwaXhlbGl6YXRpb25FZmZlY3QsCiAgICAgICAgICAgICAgICB0cnVlICAvLyBuZWVkc1RleHR1cmVJbnB1dCA9IHRydWUgKHBvc3QtcHJvY2Vzc2luZyBlZmZlY3QpCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyA2LiBDcmVhdGUgaW50ZXJtZWRpYXRlIHRleHR1cmUgZm9yIG11bHRpLXBhc3MgcmVuZGVyaW5nCiAgICAgICAgICAgIHRoaXMuc3RhdGUucmVuZGVyZXIuY3JlYXRlSW50ZXJtZWRpYXRlVGV4dHVyZSgKICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUuY2FudmFzLndpZHRoLAogICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS5jYW52YXMuaGVpZ2h0CiAgICAgICAgICAgICk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyA3LiBDcmVhdGUgYXVkaW8gY29udHJvbGxlcgogICAgICAgICAgICB0aGlzLnN0YXRlLmF1ZGlvQ29udHJvbGxlciA9IG5ldyBBdWRpb0NvbnRyb2xsZXIoKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIDguIENyZWF0ZSBpbnB1dCBjb250cm9sbGVyIGZvciBtb3VzZS90b3VjaCBpbnRlcmFjdGlvbgogICAgICAgICAgICB0aGlzLnN0YXRlLmlucHV0Q29udHJvbGxlciA9IG5ldyBJbnB1dENvbnRyb2xsZXIoCiAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLmNhbnZhcywKICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUuZWZmZWN0TWFuYWdlciwKICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUuYXVkaW9Db250cm9sbGVyLAogICAgICAgICAgICAgICAgdGhpcyAgLy8gUGFzcyBhcHAgcmVmZXJlbmNlIGZvciBvcmllbnRhdGlvbiBsb2NrCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyA5LiBTZXR1cCB3aW5kb3cgcmVzaXplIGhhbmRsZXIKICAgICAgICAgICAgdGhpcy5zZXR1cFJlc2l6ZUhhbmRsZXIoKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIDEwLiBTdGFydCByZW5kZXIgbG9vcAogICAgICAgICAgICB0aGlzLnN0YXRlLmFwcC5pc0luaXRpYWxpemVkID0gdHJ1ZTsKICAgICAgICAgICAgdGhpcy5zdGF0ZS5hcHAuc3RhcnRUaW1lID0gcGVyZm9ybWFuY2Uubm93KCk7CiAgICAgICAgICAgIHRoaXMuc3RhcnRSZW5kZXJMb29wKCk7CiAgICAgICAgICAgIAogICAgICAgICAgICBMb2dnZXIuaW5mbygnQVBQJywgYEluaXRpYWxpemF0aW9uIGNvbXBsZXRlISBSZW5kZXJlcjogJHt0aGlzLnN0YXRlLnJlbmRlcmVyLmdldFR5cGUoKX1gKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIGlPUyBTYWZhcmkgV2ViR1BVIGZpeDogRm9yY2UgY2FudmFzIHJlcGFpbnQKICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUucmVuZGVyZXIuZ2V0VHlwZSgpID09PSAnd2ViZ3B1JykgewogICAgICAgICAgICAgICAgdGhpcy5mb3JjZUNhbnZhc1JlcGFpbnQoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICB9IGNhdGNoIChlcnJvcikgewogICAgICAgICAgICBMb2dnZXIuZXJyb3IoJ0FQUCcsICdJbml0aWFsaXphdGlvbiBmYWlsZWQ6JywgZXJyb3IpOwogICAgICAgICAgICB0aGlzLnNob3dFcnJvcignRmFpbGVkIHRvIGluaXRpYWxpemUgYXBwbGljYXRpb24uIENoZWNrIGNvbnNvbGUgZm9yIGRldGFpbHMuJyk7CiAgICAgICAgICAgIHRocm93IGVycm9yOwogICAgICAgIH0KICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBGb3JjZSBjYW52YXMgcmVwYWludCAoaU9TIFNhZmFyaSBXZWJHUFUgZml4KQogICAgICovCiAgICBmb3JjZUNhbnZhc1JlcGFpbnQoKSB7CiAgICAgICAgY29uc3QgY2FudmFzID0gdGhpcy5zdGF0ZS5jYW52YXM7CiAgICAgICAgCiAgICAgICAgLy8gVHJpZ2dlciBpT1MgY29tcG9zaXRvciBieSB0ZW1wb3JhcmlseSBtb2RpZnlpbmcgY2FudmFzCiAgICAgICAgY29uc3Qgb3JpZ2luYWxEaXNwbGF5ID0gY2FudmFzLnN0eWxlLmRpc3BsYXk7CiAgICAgICAgY2FudmFzLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7CiAgICAgICAgCiAgICAgICAgLy8gRm9yY2UgcmVmbG93CiAgICAgICAgdm9pZCBjYW52YXMub2Zmc2V0SGVpZ2h0OwogICAgICAgIAogICAgICAgIGNhbnZhcy5zdHlsZS5kaXNwbGF5ID0gb3JpZ2luYWxEaXNwbGF5OwogICAgICAgIAogICAgICAgIExvZ2dlci5kZWJ1ZygnQVBQJywgJ0ZvcmNlZCBjYW52YXMgcmVwYWludCBmb3IgaU9TIFdlYkdQVSBjb21wYXRpYmlsaXR5Jyk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogU2V0dXAgY2FudmFzIGVsZW1lbnQKICAgICAqLwogICAgc2V0dXBDYW52YXMoKSB7CiAgICAgICAgdGhpcy5zdGF0ZS5jYW52YXMgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc3RhdGljQ2FudmFzJyk7CiAgICAgICAgCiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLmNhbnZhcykgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NhbnZhcyBlbGVtZW50IG5vdCBmb3VuZCcpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICBpZiAoISh0aGlzLnN0YXRlLmNhbnZhcyBpbnN0YW5jZW9mIEhUTUxDYW52YXNFbGVtZW50KSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3N0YXRpY0NhbnZhcyBpcyBub3QgYSBjYW52YXMgZWxlbWVudCcpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICAvLyBpT1MgZGVidWdnaW5nCiAgICAgICAgY29uc3QgaXNJT1MgPSAvaVBhZHxpUGhvbmV8aVBvZC8udGVzdChuYXZpZ2F0b3IudXNlckFnZW50KTsKICAgICAgICBMb2dnZXIuaW5mbygnQVBQJywgYFBsYXRmb3JtOiAke2lzSU9TID8gJ2lPUycgOiAnT3RoZXInfSwgVXNlciBBZ2VudDogJHtuYXZpZ2F0b3IudXNlckFnZW50LnN1YnN0cmluZygwLCA1MCl9Li4uYCk7CiAgICAgICAgCiAgICAgICAgLy8gU2V0IGNhbnZhcyBzaXplIHRvIHdpbmRvdyBzaXplCiAgICAgICAgdGhpcy5yZXNpemVDYW52YXMoKTsKICAgICAgICAKICAgICAgICAvLyBpT1MgV2ViR1BVIGNhbnZhcyB2aXNpYmlsaXR5IGNoZWNrCiAgICAgICAgY29uc3QgY29tcHV0ZWRTdHlsZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKHRoaXMuc3RhdGUuY2FudmFzKTsKICAgICAgICBMb2dnZXIuaW5mbygnQVBQJywgYENhbnZhcyBzZXR1cCAtIERpbWVuc2lvbnM6ICR7dGhpcy5zdGF0ZS5jYW52YXMud2lkdGh9eCR7dGhpcy5zdGF0ZS5jYW52YXMuaGVpZ2h0fWApOwogICAgICAgIExvZ2dlci5pbmZvKCdBUFAnLCBgQ2FudmFzIGRpc3BsYXk6ICR7Y29tcHV0ZWRTdHlsZS5kaXNwbGF5fSwgdmlzaWJpbGl0eTogJHtjb21wdXRlZFN0eWxlLnZpc2liaWxpdHl9LCBvcGFjaXR5OiAke2NvbXB1dGVkU3R5bGUub3BhY2l0eX0sIHpJbmRleDogJHtjb21wdXRlZFN0eWxlLnpJbmRleH1gKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBJbml0aWFsaXplIHJlbmRlcmVyIHVzaW5nIGZhY3RvcnkgKGF1dG8tZGV0ZWN0cyBXZWJHUFUvV2ViR0wpCiAgICAgKi8KICAgIGFzeW5jIGluaXRpYWxpemVSZW5kZXJlcigpIHsKICAgICAgICB0cnkgewogICAgICAgICAgICBMb2dnZXIuaW5mbygnQVBQJywgJ0luaXRpYWxpemluZyByZW5kZXJlci4uLicpOwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gVXNlIGZhY3RvcnkgdG8gYXV0by1kZXRlY3QgYW5kIGNyZWF0ZSBiZXN0IGF2YWlsYWJsZSByZW5kZXJlcgogICAgICAgICAgICB0aGlzLnN0YXRlLnJlbmRlcmVyID0gYXdhaXQgUmVuZGVyZXJGYWN0b3J5LmNyZWF0ZVJlbmRlcmVyKHRoaXMuc3RhdGUuY2FudmFzKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIExvZ2dlci5pbmZvKCdBUFAnLCBgUmVuZGVyZXIgaW5pdGlhbGl6ZWQ6ICR7dGhpcy5zdGF0ZS5yZW5kZXJlci5nZXRUeXBlKCl9YCk7CiAgICAgICAgICAgIAogICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgICAgICAgIExvZ2dlci5lcnJvcignQVBQJywgJ1JlbmRlcmVyIGluaXRpYWxpemF0aW9uIGZhaWxlZDonLCBlcnJvcik7CiAgICAgICAgICAgIHRocm93IGVycm9yOwogICAgICAgIH0KICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBSZXNpemUgY2FudmFzIHRvIG1hdGNoIHdpbmRvdyBzaXplCiAgICAgKi8KICAgIHJlc2l6ZUNhbnZhcygpIHsKICAgICAg
AgICAgIHRoaXMuc3RhdGUucGxheWJhY2suaXNQbGF5aW5nID0gZmFsc2U7CiAgICAgICAgICAgIExvZ2dlci5pbmZvKCdBVURJTycsICdXaGl0ZSBub2lzZSBzdG9wcGVkJyk7CiAgICAgICAgICAgIAogICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgICAgICAgIExvZ2dlci5lcnJvcignQVVESU8nLCAnRmFpbGVkIHRvIHN0b3Agd2hpdGUgbm9pc2U6JywgZXJyb3IpOwogICAgICAgIH0KICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBVcGRhdGUgdm9sdW1lCiAgICAgKiBAcGFyYW0ge251bWJlcn0gdm9sdW1lIC0gVm9sdW1lIGxldmVsICgwLTEpCiAgICAgKi8KICAgIHNldFZvbHVtZSh2b2x1bWUpIHsKICAgICAgICBpZiAoIXRoaXMuc3RhdGUucGxheWJhY2suaXNJbml0aWFsaXplZCkgcmV0dXJuOwogICAgICAgIAogICAgICAgIHZvbHVtZSA9IE1hdGgubWF4KDAsIE1hdGgubWluKDEsIHZvbHVtZSkpOwogICAgICAgIHRoaXMuc3RhdGUucGFyYW1ldGVycy52b2x1bWUgPSB2b2x1bWU7CiAgICAgICAgCiAgICAgICAgaWYgKHRoaXMuc3RhdGUubm9kZXMuZ2Fpbk5vZGUpIHsKICAgICAgICAgICAgLy8gU21vb3RoIHJhbXAgdG8gYXZvaWQgY2xpY2tzCiAgICAgICAgICAgIGNvbnN0IG5vdyA9IHRoaXMuc3RhdGUuYXVkaW9Db250ZXh0LmN1cnJlbnRUaW1lOwogICAgICAgICAgICB0aGlzLnN0YXRlLm5vZGVzLmdhaW5Ob2RlLmdhaW4uc2V0VGFyZ2V0QXRUaW1lKHZvbHVtZSwgbm93LCAwLjAxKTsKICAgICAgICB9CiAgICB9CiAgICAKICAgIC8qKgogICAgICogVXBkYXRlIGxvdy1wYXNzIGZpbHRlciBmcmVxdWVuY3kgKFBoYXNlIEUgLSBZLWF4aXMgY29udHJvbCkKICAgICAqIEBwYXJhbSB7bnVtYmVyfSBmcmVxdWVuY3kgLSBDdXRvZmYgZnJlcXVlbmN5IGluIEh6ICgyMC0yMDAwMCkKICAgICAqLwogICAgc2V0RmlsdGVyRnJlcXVlbmN5KGZyZXF1ZW5jeSkgewogICAgICAgIGlmICghdGhpcy5zdGF0ZS5wbGF5YmFjay5pc0luaXRpYWxpemVkKSByZXR1cm47CiAgICAgICAgCiAgICAgICAgZnJlcXVlbmN5ID0gTWF0aC5tYXgoMjAsIE1hdGgubWluKDIwMDAwLCBmcmVxdWVuY3kpKTsKICAgICAgICB0aGlzLnN0YXRlLnBhcmFtZXRlcnMuZmlsdGVyRnJlcXVlbmN5ID0gZnJlcXVlbmN5OwogICAgICAgIAogICAgICAgIGlmICh0aGlzLnN0YXRlLm5vZGVzLmZpbHRlck5vZGUpIHsKICAgICAgICAgICAgY29uc3Qgbm93ID0gdGhpcy5zdGF0ZS5hdWRpb0NvbnRleHQuY3VycmVudFRpbWU7CiAgICAgICAgICAgIHRoaXMuc3RhdGUubm9kZXMuZmlsdGVyTm9kZS5mcmVxdWVuY3kuc2V0VGFyZ2V0QXRUaW1lKGZyZXF1ZW5jeSwgbm93LCAwLjAxKTsKICAgICAgICB9CiAgICB9CiAgICAKICAgIC8qKgogICAgICogVXBkYXRlIGZpbHRlciBiYXNlZCBvbiBpbnRlcmFjdGlvbiBZIHBhcmFtZXRlciAoMC0xKQogICAgICogQHBhcmFtIHtudW1iZXJ9IHkgLSBOb3JtYWxpemVkIFkgcG9zaXRpb24gKDAtMSkKICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gaXNBY3RpdmUgLSBXaGV0aGVyIGludGVyYWN0aW9uIGlzIGFjdGl2ZQogICAgICovCiAgICB1cGRhdGVGaWx0ZXJGcm9tSW50ZXJhY3Rpb24oeSwgaXNBY3RpdmUpIHsKICAgICAgICBpZiAoIXRoaXMuc3RhdGUucGxheWJhY2suaXNJbml0aWFsaXplZCkgcmV0dXJuOwogICAgICAgIAogICAgICAgIC8vIFVwZGF0ZSBpbnRlcmFjdGlvbiBzdGF0ZSBmb3IgZHJvbmUgY29udHJvbAogICAgICAgIHRoaXMuc3RhdGUuZHJvbmVNb2RlLmlzSW50ZXJhY3RpbmcgPSBpc0FjdGl2ZTsKICAgICAgICB0aGlzLnVwZGF0ZURyb25lR2FpbigpOwogICAgICAgIAogICAgICAgIGlmICghaXNBY3RpdmUpIHsKICAgICAgICAgICAgLy8gTm8gaW50ZXJhY3Rpb24gLSBieXBhc3MgZmlsdGVyIChzZXQgdG8gdmVyeSBoaWdoIGZyZXF1ZW5jeSkKICAgICAgICAgICAgdGhpcy5zZXRGaWx0ZXJGcmVxdWVuY3koNDkwMDApOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIAogICAgICAgIC8vIE1hcCBZIHBhcmFtZXRlciB0byBmaWx0ZXIgZnJlcXVlbmN5IHJhbmdlIHVzaW5nIExPR0FSSVRITUlDIHNjYWxpbmcKICAgICAgICAvLyBUaGlzIG1hdGNoZXMgaHVtYW4gcGVyY2VwdGlvbiBvZiBmcmVxdWVuY3kgKG9jdGF2ZXMgc291bmQgZXZlbikKICAgICAgICAvLyBZPTAgKGJvdHRvbSkgPSBtaW5GcmVxdWVuY3kgKG11ZmZsZWQpCiAgICAgICAgLy8gWT0xICh0b3ApID0gbWF4RnJlcXVlbmN5IChicmlnaHQpCiAgICAgICAgCiAgICAgICAgY29uc3QgbWluRnJlcSA9IHRoaXMuY29uZmlnLmZpbHRlci5taW5GcmVxdWVuY3k7CiAgICAgICAgY29uc3QgbWF4RnJlcSA9IHRoaXMuY29uZmlnLmZpbHRlci5tYXhGcmVxdWVuY3k7CiAgICAgICAgCiAgICAgICAgLy8gTG9nYXJpdGhtaWMgaW50ZXJwb2xhdGlvbjogZnJlcSA9IG1pbkZyZXEgKiAobWF4RnJlcS9taW5GcmVxKV55CiAgICAgICAgY29uc3QgZnJlcXVlbmN5ID0gbWluRnJlcSAqIE1hdGgucG93KG1heEZyZXEgLyBtaW5GcmVxLCB5KTsKICAgICAgICAKICAgICAgICB0aGlzLnNldEZpbHRlckZyZXF1ZW5jeShmcmVxdWVuY3kpOwogICAgfQogICAgCiAgICAvKioKICAgICAqIFNjaGVkdWxlIGEgc2luZ2xlIHB1bHNlIChBRFNSIGVudmVsb3BlKQogICAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXJ0VGltZSAtIFdoZW4gdG8gc3RhcnQgdGhlIHB1bHNlIChBdWRpb0NvbnRleHQgdGltZSkKICAgICAqLwogICAgc2NoZWR1bGVQdWxzZShzdGFydFRpbWUpIHsKICAgICAgICBpZiAoIXRoaXMuc3RhdGUucGxheWJhY2suaXNJbml0aWFsaXplZCB8fCAhdGhpcy5zdGF0ZS5ub2Rlcy5yaHl0aG1HYWluKSB7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgY29uc3QgZ2FpbiA9IHRoaXMuc3RhdGUubm9kZXMucmh5dGhtR2Fpbi5nYWluOwogICAgICAgIGNvbnN0IGNvbmZpZyA9IHRoaXMuY29uZmlnLnJoeXRobTsKICAgICAgICAKICAgICAgICAvLyBDYW5jZWwgYW55IHNjaGVkdWxlZCB2YWx1ZXMgYWZ0ZXIgc3RhcnRUaW1lCiAgICAgICAgZ2Fpbi5jYW5jZWxTY2hlZHVsZWRWYWx1ZXMoc3RhcnRUaW1lKTsKICAgICAgICAKICAgICAgICAvLyBBRFNSIEVudmVsb3BlCiAgICAgICAgY29uc3QgYXR0YWNrRW5kID0gc3RhcnRUaW1lICsgY29uZmlnLmF0dGFjazsKICAgICAgICBjb25zdCBkZWNheUVuZCA9IGF0dGFja0VuZCArIGNvbmZpZy5kZWNheTsKICAgICAgICBjb25zdCByZWxlYXNlU3RhcnQgPSBkZWNheUVuZDsgLy8gUmVsZWFzZSBzdGFydHMgaW1tZWRpYXRlbHkgYWZ0ZXIgZGVjYXkgKG5vIGhvbGQgcGhhc2UpCiAgICAgICAgY29uc3QgcmVsZWFzZUVuZCA9IHJlbGVhc2VTdGFydCArIGNvbmZpZy5yZWxlYXNlOwogICAgICAgIAogICAgICAgIC8vIEF0dGFjazogMCDihpIgMQogICAgICAgIGdhaW4uc2V0VmFsdWVBdFRpbWUoMCwgc3RhcnRUaW1lKTsKICAgICAgICBnYWluLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKDEuMCwgYXR0YWNrRW5kKTsKICAgICAgICAKICAgICAgICAvLyBEZWNheTogMSDihpIgc3VzdGFpbiBsZXZlbAogICAgICAgIGdhaW4ubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoY29uZmlnLnN1c3RhaW4sIGRlY2F5RW5kKTsKICAgICAgICAKICAgICAgICAvLyBSZWxlYXNlOiBzdXN0YWluIOKGkiAwCiAgICAgICAgZ2Fpbi5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSgwLCByZWxlYXNlRW5kKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBTdGFydCByaHl0aG0gc2NoZWR1bGluZyBsb29wCiAgICAgKi8KICAgIHN0YXJ0Umh5dGhtU2NoZWR1bGVyKCkgewogICAgICAgIGlmICh0aGlzLnN0YXRlLnJoeXRobS5zY2hlZHVsZXJUaW1lcikgewogICAgICAgICAgICByZXR1cm47IC8vIEFscmVhZHkgcnVubmluZwogICAgICAgIH0KICAgICAgICAKICAgICAgICAvLyBTY2hlZHVsZSBwdWxzZXMgcmVndWxhcmx5CiAgICAgICAgdGhpcy5zdGF0ZS5yaHl0aG0uc2NoZWR1bGVyVGltZXIgPSBzZXRJbnRlcnZhbCgoKSA9PiB7CiAgICAgICAgICAgIHRoaXMuc2NoZWR1bGVVcGNvbWluZ1B1bHNlcygpOwogICAgICAgIH0sIDUwKTsgLy8gQ2hlY2sgZXZlcnkgNTBtcwogICAgICAgIAogICAgICAgIExvZ2dlci5kZWJ1ZygnQVVESU8nLCAnUmh5dGhtIHNjaGVkdWxlciBzdGFydGVkJyk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogU3RvcCByaHl0aG0gc2NoZWR1bGluZyBsb29wCiAgICAgKi8KICAgIHN0b3BSaHl0aG1TY2hlZHVsZXIoKSB7CiAgICAgICAgaWYgKHRoaXMuc3RhdGUucmh5dGhtLnNjaGVkdWxlclRpbWVyKSB7CiAgICAgICAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5zdGF0ZS5yaHl0aG0uc2NoZWR1bGVyVGltZXIpOwogICAgICAgICAgICB0aGlzLnN0YXRlLnJoeXRobS5zY2hlZHVsZXJUaW1lciA9IG51bGw7CiAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnQVVESU8nLCAnUmh5dGhtIHNjaGVkdWxlciBzdG9wcGVkJyk7CiAgICAgICAgfQogICAgfQogICAgCiAgICAvKioKICAgICAqIFNjaGVkdWxlIHVwY29taW5nIHB1bHNlcyBiYXNlZCBvbiBjdXJyZW50IHJoeXRobSByYXRlCiAgICAgKi8KICAgIHNjaGVkdWxlVXBjb21pbmdQdWxzZXMoKSB7CiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnBsYXliYWNrLmlzSW5pdGlhbGl6ZWQgfHwgIXRoaXMuc3RhdGUucmh5dGhtLmlzQWN0aXZlKSB7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgY29uc3QgY3R4ID0gdGhpcy5zdGF0ZS5hdWRpb0NvbnRleHQ7CiAgICAgICAgY29uc3QgY3VycmVudFRpbWUgPSBjdHguY3VycmVudFRpbWU7CiAgICAgICAgY29uc3QgcmF0ZSA9IHRoaXMuc3RhdGUucmh5dGhtLmN1cnJlbnRSYXRlOwogICAgICAgIAogICAgICAgIGlmIChyYXRlIDw9IDApIHJldHVybjsKICAgICAgICAKICAgICAgICBjb25zdCBpbnRlcnZhbCA9IDEuMCAvIHJhdGU7IC8vIFRpbWUgYmV0d2VlbiBwdWxzZXMKICAgICAgICBjb25zdCBzY2hlZHVsZUFoZWFkID0gdGhpcy5jb25maWcucmh5dGhtLnNjaGVkdWxlQWhlYWQ7CiAgICAgICAgCiAgICAgICAgLy8gU2NoZWR1bGUgcHVsc2VzIHVwIHRvIHNjaGVkdWxlQWhlYWQgdGltZSBpbiB0aGUgZnV0dXJlCiAgICAgICAgd2hpbGUgKHRoaXMuc3RhdGUucmh5dGhtLm5leHRQdWxzZVRpbWUgPCBjdXJyZW50VGltZSArIHNjaGVkdWxlQWhlYWQpIHsKICAgICAgICAgICAgdGhpcy5zY2hlZHVsZVB1bHNlKHRoaXMuc3RhdGUucmh5dGhtLm5leHRQdWxzZVRpbWUpOwogICAgICAgICAgICB0aGlzLnN0YXRlLnJoeXRobS5uZXh0UHVsc2VUaW1lICs9IGludGVydmFsOwogICAgICAgIH0KICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBVcGRhdGUgcmh5dGhtIGJhc2VkIG9uIGludGVyYWN0aW9uIFggcGFyYW1ldGVyICgwLTEpCiAgICAgKiBAcGFyYW0ge251bWJlcn0geCAtIE5vcm1hbGl6ZWQgWCBwb3NpdGlvbiAoMC0xKQogICAgICogQHBhcmFtIHtib29sZWFufSBpc0FjdGl2ZSAtIFdoZXRoZXIgaW50ZXJhY3Rpb24gaXMgYWN0aXZlCiAgICAgKi8KICAgIHVwZGF0ZVJoeXRobUZyb21JbnRlcmFjdGlvbih4LCBpc0FjdGl2ZSkgewogICAgICAgIGlmICghdGhpcy5zdGF0ZS5wbGF5YmFjay5pc0luaXRpYWxpemVkKSByZXR1cm47CiAgICAgICAgCiAgICAgICAgY29uc3QgY3R4ID0gdGhpcy5zdGF0ZS5hdWRpb0NvbnRleHQ7CiAgICAgICAgY29uc3Qgbm93ID0gY3R4LmN1cnJlbnRUaW1lOwogICAgICAgIAogICAgICAgIGlmICghaXNBY3RpdmUpIHsKICAgICAgICAgICAgLy8gTm8gaW50ZXJhY3Rpb24gLSBjb250aW51b3VzIGRyb25lIChubyByaHl0aG0pCiAgICAgICAgICAgIHRoaXMuc3RvcFJoeXRobSgpOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIAogICAgICAgIC8vIFg9MCAobGVmdCkgPSBjb250aW51b3VzIGRyb25lIChubyByaHl0aG0pCiAgICAgICAgLy8gWD4wID0gcmh5dGhtaWMgcHVsc2VzIGF0IGluY3JlYXNpbmcgcmF0ZXMKICAgICAgICAKICAgICAgICBjb25zdCBtaW5SYXRlID0gdGhpcy5jb25maWcucmh5dGhtLm1pblJhdGU7CiAgICAgICAgY29uc3QgbWF4UmF0ZSA9IHRoaXMuY29uZmlnLnJoeXRobS5tYXhSYXRlOwogICAgICAgIAogICAgICAgIGlmICh4IDw9IDAuMDEpIHsKICAgICAgICAgICAgLy8gVmVyeSBjbG9zZSB0byBsZWZ0IGVkZ2UgLSBjb250aW51b3VzIGRyb25lCiAgICAgICAgICAgIHRoaXMuc3RvcFJoeXRobSgpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIC8vIENhbGN1bGF0ZSByYXRlIHVzaW5nIGV4cG9uZW50aWFsIHNjYWxpbmcgKGZlZWxzIG1vcmUgbmF0dXJhbCkKICAgICAgICAgICAgLy8geD0wLjAxIOKGkiBtaW5SYXRlLCB4PTEuMCDihpIgbWF4UmF0ZQogICAgICAgICAgICBjb25zdCBub3JtYWxpemVkWCA9ICh4IC0gMC4wMSkgLyAoMS4wIC0gMC4wMSk7IC8vIE5vcm1hbGl6ZSB0byAwLTEgYWZ0ZXIgdGhyZXNob2xkCiAgICAgICAgICAgIGNvbnN0IHJhdGUgPSBtaW5SYXRlICogTWF0aC5wb3cobWF4UmF0ZSAvIG1pblJhdGUsIG5vcm1hbGl6ZWRYKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIHRoaXMuc3RhcnRSaHl0aG0ocmF0ZSwgbm93KTsKICAgICAgICB9CiAgICB9CiAgICAKICAgIC8qKgogICAgICogU3RhcnQgb3IgdXBkYXRlIHJoeXRobSBhdCBzcGVjaWZpZWQgcmF0ZQogICAgICogQHBhcmFtIHtudW1iZXJ9IHJhdGUgLSBQdWxzZSByYXRlIGluIEh6CiAgICAgKiBAcGFyYW0ge251bWJlcn0gY3VycmVudFRpbWUgLSBDdXJyZW50IGF1ZGlvIGNvbnRleHQgdGltZQogICAgICovCiAgICBzdGFydFJoeXRobShyYXRlLCBjdXJyZW50VGltZSkgewogICAgICAgIHRoaXMuc3RhdGUucGFyYW1ldGVycy5yaHl0aG1SYXRlID0gcmF0ZTsKICAgICAgICAKICAgICAgICBjb25zdCB3YXNBY3RpdmUgPSB0aGlzLnN0YXRlLnJoeXRobS5pc0FjdGl2ZTsKICAgICAgICBjb25zdCByYXRlQ2hhbmdlZCA9IE1hdGguYWJzKHRoaXMuc3RhdGUucmh5dGhtLmN1cnJlbnRSYXRlIC0gcmF0ZSkgPiAwLjE7CiAgICAgICAgCiAgICAgICAgdGhpcy5zdGF0ZS5yaHl0aG0uaXNBY3RpdmUgPSB0cnVlOwogICAgICAgIHRoaXMuc3RhdGUucmh5dGhtLmN1cnJlbnRSYXRlID0gcmF0ZTsKICAgICAgICAKICAgICAgICBpZiAoIXdhc0FjdGl2ZSkgewogICAgICAgICAgICAvLyBTdGFydGluZyByaHl0aG0gZm9yIHRoZSBmaXJzdCB0aW1lCiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRHYWluID0gdGhpcy5zdGF0ZS5ub2Rlcy5yaHl0aG1HYWluPy5nYWluLnZhbHVlIHx8IDA7CiAgICAgICAgICAgIAogICAgICAgICAgICBpZiAoY3VycmVudEdhaW4gPiAwLjEpIHsKICAgICAgICAgICAgICAgIC8vIENvbWluZyBmcm9tIGNvbnRpbnVvdXMgZHJvbmUgbW9kZSAtIG5lZWQgdG8gcmFtcCBkb3duCiAgICAgICAgICAgICAgICAvLyBTbW9vdGhseSByYW1wIGRvd24gcmh5dGhtIGdhaW4gdG8gMCBiZWZvcmUgZmlyc3QgcHVsc2UKICAgICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLm5vZGVzLnJoeXRobUdhaW4pIHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBnYWluID0gdGhpcy5zdGF0ZS5ub2Rlcy5yaHl0aG1HYWluLmdhaW47CiAgICAgICAgICAgICAgICAgICAgZ2Fpbi5jYW5jZWxTY2hlZHVsZWRWYWx1ZXMoY3VycmVudFRpbWUpOwogICAgICAgICAgICAgICAgICAgIGdhaW4uc2V0VmFsdWVBdFRpbWUoY3VycmVudEdhaW4sIGN1cnJlbnRUaW1lKTsKICAgICAgICAgICAgICAgICAgICBnYWluLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKDAsIGN1cnJlbnRUaW1lICsgMC4wMDUpOyAvLyA1bXMgcmFtcCBkb3duCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAvLyBTY2hlZHVsZSBmaXJzdCBwdWxzZSBhZnRlciByYW1wIGNvbXBsZXRlcwogICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS5yaHl0aG0ubmV4dFB1bHNlVGltZSA9IGN1cnJlbnRUaW1lICsgMC4wMDY7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAvLyBBbHJlYWR5IGF0IDAgKGZyb20gZHJvbmUgbW9kZSBPRkYpCiAgICAgICAgICAgICAgICAvLyBEZWxheSBmaXJzdCBwdWxzZSB0byBzdGFydCBBRlRFUiBkcm9uZSBnYWluIHJhbXAgY29tcGxldGVzICgzbXMpCiAgICAgICAgICAgICAgICAvLyBUaGlzIHdheSB0aGUgYXR0YWNrIGhhcHBlbnMgYXQgZnVsbCB2b2x1bWUgaW5zdGVhZCBvZiBmYWRpbmcgaW4KICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUucmh5dGhtLm5leHRQdWxzZVRpbWUgPSBjdXJyZW50VGltZSArIDAuMDAzOwogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICB0aGlzLnN0YXJ0Umh5dGhtU2NoZWR1bGVyKCk7CiAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnQVVESU8nLCBgUmh5dGhtIHN0YXJ0ZWQgYXQgJHtyYXRlLnRvRml4ZWQoMil9IEh6YCk7CiAgICAgICAgfSBlbHNlIGlmIChyYXRlQ2hhbmdlZCkgewogICAgICAgICAgICAvLyBSYXRlIGNoYW5nZWQgc2lnbmlmaWNhbnRseSAtIHJlc3luYyBwdWxzZSB0aW1pbmcKICAgICAgICAgICAgY29uc3QgaW50ZXJ2YWwgPSAxLjAgLyByYXRlOwogICAgICAgICAgICAvLyBBbGlnbiBuZXh0IHB1bHNlIHRvIG5ldyBpbnRlcnZhbAogICAgICAgICAgICB0aGlzLnN0YXRlLnJoeXRobS5uZXh0UHVsc2VUaW1lID0gY3VycmVudFRpbWUgKyBpbnRlcnZhbDsKICAgICAgICB9CiAgICB9CiAgICAKICAgIC8qKgogICAgICogU3RvcCByaHl0aG0gKHJldHVybiB0byBjb250aW51b3VzIGRyb25lIG9yIHNpbGVuY2UpCiAgICAgKi8KICAgIHN0b3BSaHl0aG0oKSB7CiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnJoeXRobS5pc0FjdGl2ZSkgcmV0dXJuOwogICAgICAgIAogICAgICAgIHRoaXMuc3RhdGUucmh5dGhtLmlzQWN0aXZlID0gZmFsc2U7CiAgICAgICAgdGhpcy5zdGF0ZS5yaHl0aG0uY3VycmVudFJhdGUgPSAwOwogICAgICAgIHRoaXMuc3RhdGUucGFyYW1ldGVycy5yaHl0aG1SYXRlID0gMDsKICAgICAgICB0aGlzLnN0b3BSaHl0aG1TY2hlZHVsZXIoKTsKICAgICAgICAKICAgICAgICAvLyBTZXQgcmh5dGhtIGdhaW4gYmFzZWQgb24gaW50ZXJhY3Rpb24gc3RhdGUgYW5kIGRyb25lIG1vZGUKICAgICAgICAvLyBJZiBjdXJyZW50bHkgaW50ZXJhY3RpbmcgKGRyYWdnaW5nKTogYWx3YXlzIDEuMCAoY29udGludW91cyBkcm9uZSB3aGlsZSBob2xkaW5nKQogICAgICAgIC8vIElmIG5vdCBpbnRlcmFjdGluZzogZGVwZW5kcyBvbiBkcm9uZSBtb2RlICgxLjAgaWYgT04sIDAuMCBpZiBPRkYpCiAgICAgICAgaWYgKHRoaXMuc3RhdGUubm9kZXMucmh5dGhtR2FpbikgewogICAgICAgICAgICBjb25zdCBnYWluID0gdGhpcy5zdGF0ZS5ub2Rlcy5yaHl0aG1HYWluLmdhaW47CiAgICAgICAgICAgIGNvbnN0IG5vdyA9IHRoaXMuc3RhdGUuYXVkaW9Db250ZXh0LmN1cnJlbnRUaW1lOwogICAgICAgICAgICBnYWluLmNhbmNlbFNjaGVkdWxlZFZhbHVlcyhub3cpOwogICAgICAgICAgICAKICAgICAgICAgICAgY29uc3QgdGFyZ2V0R2FpbiA9IHRoaXMuc3RhdGUuZHJvbmVNb2RlLmlzSW50ZXJhY3RpbmcgPyAxLjAgOiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHRoaXMuc3RhdGUuZHJvbmVNb2RlLmVuYWJsZWQgPyAxLjAgOiAwLjApOwogICAgICAgICAgICBnYWluLnNldFRhcmdldEF0VGltZSh0YXJnZXRHYWluLCBub3csIDAuMDEpOyAvLyBTbW9vdGggdHJhbnNpdGlvbgogICAgICAgIH0KICAgICAgICAKICAgICAgICBMb2dnZXIuZGVidWcoJ0FVRElPJywgJ1JoeXRobSBzdG9wcGVkIChjb250aW51b3VzIGRyb25lKScpOwogICAgfQogICAgCiAgICAvKioKICAgICAqIFVwZGF0ZSBkcm9uZSBnYWluIGJhc2VkIG9uIGludGVyYWN0aW9uIHN0YXRlIGFuZCBkcm9uZSBtb2RlCiAgICAgKi8KICAgIHVwZGF0ZURyb25lR2FpbigpIHsKICAgICAgICBpZiAoIXRoaXMuc3RhdGUucGxheWJhY2suaXNJbml0aWFsaXplZCB8fCAhdGhpcy5zdGF0ZS5ub2Rlcy5kcm9uZUdhaW4pIHJldHVybjsKICAgICAgICAKICAgICAgICBjb25zdCBjdHggPSB0aGlzLnN0YXRlLmF1ZGlvQ29udGV4dDsKICAgICAgICBjb25zdCBub3cgPSBjdHguY3VycmVudFRpbWU7CiAgICAgICAgY29uc3QgZ2FpbiA9IHRoaXMuc3RhdGUubm9kZXMuZHJvbmVHYWluLmdhaW47CiAgICAgICAgCiAgICAgICAgLy8gV2hlbiBpbnRlcmFjdGluZzogYWx3YXlzIGZ1bGwgdm9sdW1lICgxLjApCiAgICAgICAgLy8gV2hlbiBub3QgaW50ZXJhY3Rpbmc6IGRlcGVuZHMgb24gZHJvbmUgbW9kZSAoMS4wIGlmIE9OLCAwLjAgaWYgT0ZGKQogICAgICAgIGNvbnN0IGN1cnJlbnRHYWluID0gZ2Fpbi52YWx1ZTsKICAgICAgICBjb25zdCB0YXJnZXRHYWluID0gdGhpcy5zdGF0ZS5kcm9uZU1vZGUuaXNJbnRlcmFjdGluZyA/IDEuMCA6IAogICAgICAgICAgICAgICAgICAgICAgICAgICh0aGlzLnN0YXRlLmRyb25lTW9kZS5lbmFibGVkID8gMS4wIDogMC4wKTsKICAgICAgICAKICAgICAgICAvLyBDYW5jZWwgYW55IHNjaGVkdWxlZCBjaGFuZ2VzCiAgICAgICAgZ2Fpbi5jYW5jZWxTY2hlZHVsZWRWYWx1ZXMobm93KTsKICAgICAgICAKICAgICAgICAvLyBVc2Ugc2hvcnQgZmFkZS1pbiB3aGVuIGdvaW5nIGZyb20gc2lsZW5jZSB0byBzb3VuZCAoMCDihpIgMSkKICAgICAgICAvLyBUaGlzIHByZXZlbnRzIGNsaWNrL3BvcCB3aGVuIHN0YXJ0aW5nIGludGVyYWN0aW9uIGluIGRyb25lIG1vZGUgT0ZGCiAgICAgICAgaWYgKGN1cnJlbnRHYWluID09PSAwLjAgJiYgdGFyZ2V0R2FpbiA9PT0gMS4wKSB7CiAgICAgICAgICAgIC8vIEZhc3QgM21zIGZhZGUtaW4gZm9yIHJlc3BvbnNpdmUgZmVlbAogICAgICAgICAgICAvLyBSaHl0aG0gZ2FpbiBpcyBhbHJlYWR5IGF0IDAgKG5vIHJhbXAgbmVlZGVkKSwgc28gd2UgY2FuIGJlIHF1aWNrCiAgICAgICAgICAgIGdhaW4uc2V0VmFsdWVBdFRpbWUoMC4wLCBub3cpOwogICAgICAgICAgICBnYWluLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKDEuMCwgbm93ICsgMC4wMDMpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIC8vIEltbWVkaWF0ZSBjaGFuZ2UgZm9yIGFsbCBvdGhlciB0cmFuc2l0aW9ucyAoaGFyZCBjdXQpCiAgICAgICAgICAgIC8vIFRoaXMgaW5jbHVkZXM6IDHihpIwIChzdG9wcGluZyksIDDihpIwIChzdGF5aW5nIHNpbGVudCksIDHihpIxIChzdGF5aW5nIGF1ZGlibGUpCiAgICAgICAgICAgIGdhaW4uc2V0VmFsdWVBdFRpbWUodGFyZ2V0R2Fpbiwgbm93KTsKICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBUb2dnbGUgZHJvbmUgbW9kZSAoc3BhY2UgYmFyKQogICAgICovCiAgICB0b2dnbGVEcm9uZU1vZGUoKSB7CiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnBsYXliYWNrLmlzSW5pdGlhbGl6ZWQpIHJldHVybjsKICAgICAgICAKICAgICAgICAvLyBUb2dnbGUgdGhlIG1vZGUKICAgICAgICB0aGlzLnN0YXRlLmRyb25lTW9kZS5lbmFibGVkID0gIXRoaXMuc3RhdGUuZHJvbmVNb2RlLmVuYWJsZWQ7CiAgICAgICAgCiAgICAgICAgLy8gVXBkYXRlIGRyb25lIGdhaW4gaW1tZWRpYXRlbHkKICAgICAgICB0aGlzLnVwZGF0ZURyb25lR2FpbigpOwogICAgICAgIAogICAgICAgIC8vIElmIG5vdCBjdXJyZW50bHkgaW50ZXJhY3RpbmcsIHVwZGF0ZSByaHl0aG0gZ2FpbiB0b28KICAgICAgICAvLyBEcm9uZSBPTjogcmh5dGhtIGdhaW4gc2hvdWxkIGJlIDEuMCAoY29udGludW91cykKICAgICAgICAvLyBEcm9uZSBPRkY6IHJoeXRobSBnYWluIHNob3VsZCBiZSAwLjAgKHJlYWR5IGZvciBpbnN0YW50IGZpcnN0IG5vdGUpCiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLmRyb25lTW9kZS5pc0ludGVyYWN0aW5nICYmICF0aGlzLnN0YXRlLnJoeXRobS5pc0FjdGl2ZSkgewogICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5ub2Rlcy5yaHl0aG1HYWluKSB7CiAgICAgICAgICAgICAgICBjb25zdCBnYWluID0gdGhpcy5zdGF0ZS5ub2Rlcy5yaHl0aG1HYWluLmdhaW47CiAgICAgICAgICAgICAgICBjb25zdCBub3cgPSB0aGlzLnN0YXRlLmF1ZGlvQ29udGV4dC5jdXJyZW50VGltZTsKICAgICAgICAgICAgICAgIGNvbnN0IHRhcmdldEdhaW4gPSB0aGlzLnN0YXRlLmRyb25lTW9kZS5lbmFibGVkID8gMS4wIDogMC4wOwogICAgICAgICAgICAgICAgZ2Fpbi5jYW5jZWxTY2hlZHVsZWRWYWx1ZXMobm93KTsKICAgICAgICAgICAgICAgIGdhaW4uc2V0VGFyZ2V0QXRUaW1lKHRhcmdldEdhaW4sIG5vdywgMC4wMSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgCiAgICAgICAgTG9nZ2VyLmluZm8oJ0FVRElPJywgYERyb25lIG1vZGU6ICR7dGhpcy5zdGF0ZS5kcm9uZU1vZGUuZW5hYmxlZCA/ICdPTicgOiAnT0ZGJ31gKTsKICAgIH0KCiAgICAvKioKICAgICAqIEhhbmRsZSBmaXJzdCB1c2VyIGludGVyYWN0aW9uIChzdGFydCBhdWRpbykKICAgICAqLwogICAgYXN5bmMgaGFuZGxlRmlyc3RJbnRlcmFjdGlvbigpIHsKICAgICAgICBpZiAoIXRoaXMuc3RhdGUucGxheWJhY2suaXNJbml0aWFsaXplZCkgewogICAgICAgICAgICBjb25zdCBzdWNjZXNzID0gYXdhaXQgdGhpcy5pbml0aWFsaXplKCk7CiAgICAgICAgICAgIGlmIChzdWNjZXNzKSB7CiAgICAgICAgICAgICAgICAvLyBGb3JjZSByZXN1bWUgb24gQW5kcm9pZCAoZXh0cmEgYWdncmVzc2l2ZSB1bmxvY2spCiAgICAgICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5hdWRpb0NvbnRleHQuc3RhdGUgPT09ICdzdXNwZW5kZWQnKSB7CiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLmluZm8oJ0FVRElPJywgJ0ZvcmNpbmcgQXVkaW9Db250ZXh0IHJlc3VtZSBvbiBmaXJzdCBpbnRlcmFjdGlvbi4uLicpOwogICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuc3RhdGUuYXVkaW9Db250ZXh0LnJlc3VtZSgpOwogICAgICAgICAgICAgICAgICAgIExvZ2dlci5pbmZvKCdBVURJTycsIGBBdWRpb0NvbnRleHQgc3RhdGUgYWZ0ZXIgcmVzdW1lOiAke3RoaXMuc3RhdGUuYXVkaW9Db250ZXh0LnN0YXRlfWApOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5zdGFydFdoaXRlTm9pc2UoKTsKICAgICAgICAgICAgfQogICAgICAgIH0gZWxzZSBpZiAoIXRoaXMuc3RhdGUucGxheWJhY2suaXNQbGF5aW5nKSB7CiAgICAgICAgICAgIC8vIEZvcmNlIHJlc3VtZSBvbiBBbmRyb2lkIChleHRyYSBhZ2dyZXNzaXZlIHVubG9jaykKICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuYXVkaW9Db250ZXh0LnN0YXRlID09PSAnc3VzcGVuZGVkJykgewogICAgICAgICAgICAgICAgTG9nZ2VyLmluZm8oJ0FVRElPJywgJ0ZvcmNpbmcgQXVkaW9Db250ZXh0IHJlc3VtZS4uLicpOwogICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5zdGF0ZS5hdWRpb0NvbnRleHQucmVzdW1lKCk7CiAgICAgICAgICAgICAgICBMb2dnZXIuaW5mbygnQVVESU8nLCBgQXVkaW9Db250ZXh0IHN0YXRlIGFmdGVyIHJlc3VtZTogJHt0aGlzLnN0YXRlLmF1ZGlvQ29udGV4dC5zdGF0ZX1gKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBhd2FpdCB0aGlzLnN0YXJ0V2hpdGVOb2lzZSgpOwogICAgICAgIH0KICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBHZXQgYXVkaW8gY29udHJvbGxlciBzdGF0ZSBmb3IgZGVidWdnaW5nCiAgICAgKi8KICAgIGdldFN0YXRlKCkgewogICAgICAgIHJldHVybiB7CiAgICAgICAgICAgIGlzSW5pdGlhbGl6ZWQ6IHRoaXMuc3RhdGUucGxheWJhY2suaXNJbml0aWFsaXplZCwKICAgICAgICAgICAgaXNQbGF5aW5nOiB0aGlzLnN0YXRlLnBsYXliYWNrLmlzUGxheWluZywKICAgICAgICAgICAgYXVkaW9Db250ZXh0U3RhdGU6IHRoaXMuc3RhdGUuYXVkaW9Db250ZXh0Py5zdGF0ZSB8fCAnbm90IGNyZWF0ZWQnLAogICAgICAgICAgICBwYXJhbWV0ZXJzOiB7IC4uLnRoaXMuc3RhdGUucGFyYW1ldGVycyB9LAogICAgICAgICAgICByaHl0aG06IHsKICAgICAgICAgICAgICAgIGlzQWN0aXZlOiB0aGlzLnN0YXRlLnJoeXRobS5pc0FjdGl2ZSwKICAgICAgICAgICAgICAgIGN1cnJlbnRSYXRlOiB0aGlzLnN0YXRlLnJoeXRobS5jdXJyZW50UmF0ZQogICAgICAgICAgICB9LAogICAgICAgICAgICBkcm9uZU1vZGU6IHsKICAgICAgICAgICAgICAgIGVuYWJsZWQ6IHRoaXMuc3RhdGUuZHJvbmVNb2RlLmVuYWJsZWQsCiAgICAgICAgICAgICAgICBpc0ludGVyYWN0aW5nOiB0aGlzLnN0YXRlLmRyb25lTW9kZS5pc0ludGVyYWN0aW5nCiAgICAgICAgICAgIH0KICAgICAgICB9OwogICAgfQogICAgCiAgICAvKioKICAgICAqIENsZWFuIHVwIGF1ZGlvIHJlc291cmNlcwogICAgICovCiAgICBkZXN0cm95KCkgewogICAgICAgIHRoaXMuc3RvcFJoeXRobVNjaGVkdWxlcigpOwogICAgICAgIHRoaXMuc3RvcFdoaXRlTm9pc2UoKTsKICAgICAgICAKICAgICAgICBpZiAodGhpcy5zdGF0ZS5hdWRpb0NvbnRleHQpIHsKICAgICAgICAgICAgdGhpcy5zdGF0ZS5hdWRpb0NvbnRleHQuY2xvc2UoKTsKICAgICAgICAgICAgdGhpcy5zdGF0ZS5hdWRpb0NvbnRleHQgPSBudWxsOwogICAgICAgIH0KICAgICAgICAKICAgICAgICBMb2dnZXIuaW5mbygnQVVESU8nLCAnQXVkaW9Db250cm9sbGVyIGRlc3Ryb3llZCcpOwogICAgfQp9CgpBdWRpb0NvbnRyb2xsZXI7CgoKLy8gSW5wdXRDb250cm9sbGVyIC0gTW91c2UgYW5kIHRvdWNoIGludGVyYWN0aW9uIGZvciBlZmZlY3QgcGFyYW1ldGVycwovLyBQaGFzZSBDOiBZLWF4aXMgcGl4ZWxpemF0aW9uIGNvbnRyb2wKLy8gQmFzZWQgb24gd2ViX0dQVV9taXhlciBYWVBhZENvbnRyb2xsZXIsIHNpbXBsaWZpZWQgZm9yIG91ciBuZWVkcwoKY2xhc3MgSW5wdXRDb250cm9sbGVyIHsKICAgIGNvbnN0cnVjdG9yKGNhbnZhcywgZWZmZWN0TWFuYWdlciwgYXVkaW9Db250cm9sbGVyID0gbnVsbCwgYXBwID0gbnVsbCkgewogICAgICAgIC8vIFZhbGlkYXRlIGRlcGVuZGVuY2llcwogICAgICAgIGlmICghY2FudmFzKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW5wdXRDb250cm9sbGVyIHJlcXVpcmVzIGNhbnZhcyBlbGVtZW50Jyk7CiAgICAgICAgfQogICAgICAgIGlmICghZWZmZWN0TWFuYWdlcikgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0lucHV0Q29udHJvbGxlciByZXF1aXJlcyBFZmZlY3RNYW5hZ2VyIGluc3RhbmNlJyk7CiAgICAgICAgfQoKICAgICAgICB0aGlzLmNhbnZhcyA9IGNhbnZhczsKICAgICAgICB0aGlzLmVmZmVjdE1hbmFnZXIgPSBlZmZlY3RNYW5hZ2VyOwogICAgICAgIHRoaXMuYXVkaW9Db250cm9sbGVyID0gYXVkaW9Db250cm9sbGVyOyAvLyBPcHRpb25hbCBhdWRpbyBjb250cm9sbGVyIChQaGFzZSBEKQogICAgICAgIHRoaXMuYXBwID0gYXBwOyAvLyBPcHRpb25hbCBhcHAgcmVmZXJlbmNlIGZvciBvcmllbnRhdGlvbiBsb2NrIChQaGFzZSBGKQogICAgICAgIAogICAgICAgIC8vIFN0cnVjdHVyZWQgc3RhdGUKICAgICAgICB0aGlzLnN0YXRlID0gewogICAgICAgICAgICAvLyBJbnRlcmFjdGlvbiBzdGF0ZQogICAgICAgICAgICBpbnRlcmFjdGlvbjogewogICAgICAgICAgICAgICAgaXNBY3RpdmU6IGZhbHNlLAogICAgICAgICAgICAgICAgdHlwZTogbnVsbCwgICAgICAgICAgICAgICAvLyAnbW91c2UnIG9yICd0b3VjaCcKICAgICAgICAgICAgICAgIHBvc2l0aW9uOiB7IHg6IDAuNSwgeTogMC41IH0sCiAgICAgICAgICAgICAgICB0b3VjaElkOiBudWxsICAgICAgICAgICAgIC8vIFRyYWNrIGZpcnN0IHRvdWNoIGZvciBtdWx0aS10b3VjaCBoYW5kbGluZwogICAgICAgICAgICB9LAogICAgICAgICAgICAKICAgICAgICAgICAgLy8gRHJvbmUgbW9kZSB0b2dnbGUgc3RhdGUgKHNwYWNlIGJhciBhbmQgMy1maW5nZXIgZ2VzdHVyZSkKICAgICAgICAgICAgZHJvbmVUb2dnbGU6IHsKICAgICAgICAgICAgICAgIHBlbmRpbmdUb2dnbGU6IGZhbHNlLCAgICAgLy8gUXVldWUgdG9nZ2xlIGlmIHNwYWNlIHByZXNzZWQgZHVyaW5nIGludGVyYWN0aW9uCiAgICAgICAgICAgICAgICB0aHJlZUZpbmdlckFjdGl2ZTogZmFsc2UgIC8vIFRyYWNrIGlmIDMtZmluZ2VyIGdlc3R1cmUgaXMgY3VycmVudGx5IGFjdGl2ZQogICAgICAgICAgICB9LAogICAgICAgICAgICAKICAgICAgICAgICAgLy8gQ29uZmlndXJhdGlvbgogICAgICAgICAgICBjb25maWc6IHsKICAgICAgICAgICAgICAgIGludmVydFk6IHRydWUsICAgICAgICAgICAgLy8gSW52ZXJ0IFkgYXhpcyAoc2NyZWVuIFkgaW5jcmVhc2VzIGRvd24sIHBhcmFtZXRlciBZIHNob3VsZCBpbmNyZWFzZSB1cCkKICAgICAgICAgICAgICAgIGVuYWJsZUxvZ2dpbmc6IGZhbHNlICAgICAgLy8gRW5hYmxlIGRldGFpbGVkIGxvZ2dpbmcgZm9yIGRlYnVnZ2luZwogICAgICAgICAgICB9CiAgICAgICAgfTsKCiAgICAgICAgLy8gQmluZCBldmVudCBoYW5kbGVycyB0byBtYWludGFpbiAndGhpcycgY29udGV4dAogICAgICAgIHRoaXMuaGFuZGxlTW91c2VEb3duID0gdGhpcy5oYW5kbGVNb3VzZURvd24uYmluZCh0aGlzKTsKICAgICAgICB0aGlzLmhhbmRsZU1vdXNlTW92ZSA9IHRoaXMuaGFuZGxlTW91c2VNb3ZlLmJpbmQodGhpcyk7CiAgICAgICAgdGhpcy5oYW5kbGVNb3VzZVVwID0gdGhpcy5oYW5kbGVNb3VzZVVwLmJpbmQodGhpcyk7CiAgICAgICAgCiAgICAgICAgdGhpcy5oYW5kbGVUb3VjaFN0YXJ0ID0gdGhpcy5oYW5kbGVUb3VjaFN0YXJ0LmJpbmQodGhpcyk7CiAgICAgICAgdGhpcy5oYW5kbGVUb3VjaE1vdmUgPSB0aGlzLmhhbmRsZVRvdWNoTW92ZS5iaW5kKHRoaXMpOwogICAgICAgIHRoaXMuaGFuZGxlVG91Y2hFbmQgPSB0aGlzLmhhbmRsZVRvdWNoRW5kLmJpbmQodGhpcyk7CiAgICAgICAgdGhpcy5oYW5kbGVUb3VjaENhbmNlbCA9IHRoaXMuaGFuZGxlVG91Y2hDYW5jZWwuYmluZCh0aGlzKTsKICAgICAgICAKICAgICAgICB0aGlzLmhhbmRsZUtleURvd24gPSB0aGlzLmhhbmRsZUtleURvd24uYmluZCh0aGlzKTsKCiAgICAgICAgdGhpcy5zZXR1cEV2ZW50TGlzdGVuZXJzKCk7CiAgICAgICAgCiAgICAgICAgTG9nZ2VyLmluZm8oJ0lOUFVUJywgJ0lucHV0Q29udHJvbGxlciBjcmVhdGVkJyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBTZXQgdXAgbW91c2UgYW5kIHRvdWNoIGV2ZW50IGxpc3RlbmVycyBvbiB0aGUgY2FudmFzCiAgICAgKi8KICAgIHNldHVwRXZlbnRMaXN0ZW5lcnMoKSB7CiAgICAgICAgLy8gTW91c2UgZXZlbnRzCiAgICAgICAgLy8gbW91c2Vkb3duIG9ubHkgb24gY2FudmFzICh0byBpbml0aWF0ZSBpbnRlcmFjdGlvbikKICAgICAgICB0aGlzLmNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCB0aGlzLmhhbmRsZU1vdXNlRG93biwgeyBwYXNzaXZlOiBmYWxzZSB9KTsKICAgICAgICAvLyBtb3VzZW1vdmUgYW5kIG1vdXNldXAgb24gd2luZG93ICh0byB0cmFjayBldmVuIHdoZW4gZHJhZ2dpbmcgb3V0c2lkZSBjYW52YXMpCiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbW92ZScsIHRoaXMuaGFuZGxlTW91c2VNb3ZlLCB7IHBhc3NpdmU6IGZhbHNlIH0pOwogICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgdGhpcy5oYW5kbGVNb3VzZVVwLCB7IHBhc3NpdmU6IGZhbHNlIH0pOwogICAgICAgIAogICAgICAgIC8vIFRvdWNoIGV2ZW50cyAobW9iaWxlKQogICAgICAgIHRoaXMuY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNoc3RhcnQnLCB0aGlzLmhhbmRsZVRvdWNoU3RhcnQsIHsgcGFzc2l2ZTogZmFsc2UgfSk7CiAgICAgICAgdGhpcy5jYW52YXMuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2htb3ZlJywgdGhpcy5oYW5kbGVUb3VjaE1vdmUsIHsgcGFzc2l2ZTogZmFsc2UgfSk7CiAgICAgICAgdGhpcy5jYW52YXMuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2hlbmQnLCB0aGlzLmhhbmRsZVRvdWNoRW5kLCB7IHBhc3NpdmU6IGZhbHNlIH0pOwogICAgICAgIHRoaXMuY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNoY2FuY2VsJywgdGhpcy5oYW5kbGVUb3VjaENhbmNlbCwgeyBwYXNzaXZlOiBmYWxzZSB9KTsKICAgICAgICAKICAgICAgICAvLyBLZXlib2FyZCBldmVudHMgKHNwYWNlIGJhciBmb3IgZHJvbmUgdG9nZ2xlKQogICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdrZXlkb3duJywgdGhpcy5oYW5kbGVLZXlEb3duLCB7IHBhc3NpdmU6IGZhbHNlIH0pOwogICAgICAgIAogICAgICAgIC8vIFByZXZlbnQgY29udGV4dCBtZW51IG9uIHJpZ2h0IGNsaWNrCiAgICAgICAgdGhpcy5jYW52YXMuYWRkRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCAoZSkgPT4gZS5wcmV2ZW50RGVmYXVsdCgpLCB7IHBhc3NpdmU6IGZhbHNlIH0pOwogICAgICAgIAogICAgICAgIExvZ2dlci5kZWJ1ZygnSU5QVVQnLCAnRXZlbnQgbGlzdGVuZ
gICAgICAgICB0aGlzLmxvZygnZGVidWcnLCBgVXBkYXRlZCBwaXhlbGl6YXRpb24gdW5pZm9ybXM6IHJvd3M9JHttYXBwZWRQYXJhbXMucGl4ZWxSb3dzfSwgY29scz0ke3BpeGVsQ29sc30sIGJsZW5kPSR7bWFwcGVkUGFyYW1zLmJsZW5kRmFjdG9yLnRvRml4ZWQoMil9YCk7CgogICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgICAgICAgIHRoaXMubG9nKCdlcnJvcicsICdGYWlsZWQgdG8gd3JpdGUgcGl4ZWxpemF0aW9uIHVuaWZvcm1zOicsIGVycm9yKTsKICAgICAgICAgICAgdGhyb3cgZXJyb3I7CiAgICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogVXBkYXRlIGNhbnZhcyBkaW1lbnNpb25zIGZvciBwcm9wZXIgYXNwZWN0IHJhdGlvIGNhbGN1bGF0aW9uCiAgICAgKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBDYW52YXMgd2lkdGggaW4gcGl4ZWxzCiAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gQ2FudmFzIGhlaWdodCBpbiBwaXhlbHMKICAgICAqLwogICAgdXBkYXRlQ2FudmFzRGltZW5zaW9ucyh3aWR0aCwgaGVpZ2h0KSB7CiAgICAgICAgdGhpcy5jYW52YXNXaWR0aCA9IHdpZHRoOwogICAgICAgIHRoaXMuY2FudmFzSGVpZ2h0ID0gaGVpZ2h0OwogICAgICAgIAogICAgICAgIC8vIE1hcmsgdW5pZm9ybXMgYXMgbmVlZGluZyB1cGRhdGUgd2l0aCBuZXcgZGltZW5zaW9ucwogICAgICAgIHRoaXMuc3RhdGUudW5pZm9ybXMubmVlZHNVcGRhdGUgPSB0cnVlOwogICAgICAgIAogICAgICAgIHRoaXMubG9nKCdkZWJ1ZycsIGBDYW52YXMgZGltZW5zaW9ucyB1cGRhdGVkOiAke3dpZHRofXgke2hlaWdodH1gKTsKICAgIH0KCiAgICAvKioKICAgICAqIEdldCBwaXhlbGl6YXRpb24tc3BlY2lmaWMgc3RhdGUgZm9yIGRlYnVnZ2luZwogICAgICogQHJldHVybnMge09iamVjdH0gRXh0ZW5kZWQgc3RhdGUgd2l0aCBwaXhlbGl6YXRpb24gaW5mbwogICAgICovCiAgICBnZXRFZmZlY3RTdGF0ZSgpIHsKICAgICAgICBjb25zdCBiYXNlU3RhdGUgPSBzdXBlci5nZXRFZmZlY3RTdGF0ZSgpOwogICAgICAgIGNvbnN0IG1hcHBlZFBhcmFtcyA9IHRoaXMuc3RhdGUubWV0YWRhdGEuaXNJbml0aWFsaXplZCA/IHRoaXMuZ2V0TWFwcGVkUGFyYW1ldGVycygpIDogbnVsbDsKICAgICAgICAKICAgICAgICByZXR1cm4gewogICAgICAgICAgICAuLi5iYXNlU3RhdGUsCiAgICAgICAgICAgIHBpeGVsaXphdGlvbkNvbmZpZzogdGhpcy5jb25maWcsCiAgICAgICAgICAgIGN1cnJlbnRQaXhlbGl6YXRpb246IG1hcHBlZFBhcmFtcyA/IHsKICAgICAgICAgICAgICAgIHBpeGVsUm93czogbWFwcGVkUGFyYW1zLnBpeGVsUm93cywKICAgICAgICAgICAgICAgIHBpeGVsQ29sczogbWFwcGVkUGFyYW1zLnBpeGVsQ29scywKICAgICAgICAgICAgICAgIGdyYW51bGFyaXR5UGVyY2VudDogTWF0aC5yb3VuZChtYXBwZWRQYXJhbXMuZ3JhbnVsYXJpdHkgKiAxMDApCiAgICAgICAgICAgIH0gOiBudWxsLAogICAgICAgICAgICBjYW52YXNEaW1lbnNpb25zOiB7CiAgICAgICAgICAgICAgICB3aWR0aDogdGhpcy5jYW52YXNXaWR0aCB8fCAndW5rbm93bicsCiAgICAgICAgICAgICAgICBoZWlnaHQ6IHRoaXMuY2FudmFzSGVpZ2h0IHx8ICd1bmtub3duJwogICAgICAgICAgICB9CiAgICAgICAgfTsKICAgIH0KCiAgICAvKioKICAgICAqIEhlbHBlciBtZXRob2QgZm9yIGxvZ2dpbmcKICAgICAqLwogICAgbG9nKGxldmVsLCBtZXNzYWdlLCBkYXRhID0gbnVsbCkgewogICAgICAgIGlmICh0eXBlb2YgTG9nZ2VyICE9PSAndW5kZWZpbmVkJykgewogICAgICAgICAgICBMb2dnZXJbbGV2ZWxdKCdQSVhFTElaQVRJT04nLCBtZXNzYWdlLCBkYXRhKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBjb25zb2xlLmxvZyhgW1BJWEVMSVpBVElPTl0gWyR7bGV2ZWwudG9VcHBlckNhc2UoKX1dICR7bWVzc2FnZX1gLCBkYXRhIHx8ICcnKTsKICAgICAgICB9CiAgICB9Cn0KClBpeGVsaXphdGlvbkVmZmVjdDsKCgovLyBFZmZlY3RNYW5hZ2VyIC0gTWFuYWdlcyBlZmZlY3QgbGlmZWN5Y2xlLCBwaXBlbGluZXMsIGFuZCByZW5kZXJpbmcKLy8gdjI6IFVzZXMgcmVuZGVyZXIgYWJzdHJhY3Rpb24gaW5zdGVhZCBvZiBkaXJlY3QgR1BVIGFjY2VzcwovLyBIYW5kbGVzIGVmZmVjdCByZWdpc3RyYXRpb24sIHBpcGVsaW5lIGNyZWF0aW9uLCBhbmQgcGFyYW1ldGVyIHVwZGF0ZXMKCmNsYXNzIEVmZmVjdE1hbmFnZXIgewogICAgY29uc3RydWN0b3IocmVuZGVyZXIpIHsKICAgICAgICBpZiAoIXJlbmRlcmVyKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignRWZmZWN0TWFuYWdlciByZXF1aXJlcyBhIHJlbmRlcmVyJyk7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIHRoaXMucmVuZGVyZXIgPSByZW5kZXJlcjsKICAgICAgICAKICAgICAgICAvLyBTdHJ1Y3R1cmVkIHN0YXRlCiAgICAgICAgdGhpcy5zdGF0ZSA9IHsKICAgICAgICAgICAgLy8gUmVnaXN0ZXJlZCBlZmZlY3RzCiAgICAgICAgICAgIGVmZmVjdHM6IHsKICAgICAgICAgICAgICAgIGxpc3Q6IFtdLCAgICAgICAgICAgICAgICAgICAgLy8gQXJyYXkgb2YgRWZmZWN0IGluc3RhbmNlcwogICAgICAgICAgICAgICAgYnlJZDogbmV3IE1hcCgpLCAgICAgICAgICAgICAvLyBNYXAgb2YgaWQgLT4gRWZmZWN0CiAgICAgICAgICAgICAgICBwaXBlbGluZXM6IG5ldyBNYXAoKSwgICAgICAgIC8vIE1hcCBvZiBpZCAtPiBHUFVSZW5kZXJQaXBlbGluZQogICAgICAgICAgICAgICAgY3VycmVudEVmZmVjdElkOiBudWxsICAgICAgICAvLyBDdXJyZW50bHkgYWN0aXZlIGVmZmVjdAogICAgICAgICAgICB9LAogICAgICAgICAgICAKICAgICAgICAgICAgLy8gSW50ZXJhY3Rpb24gc3RhdGUKICAgICAgICAgICAgaW50ZXJhY3Rpb246IHsKICAgICAgICAgICAgICAgIGlzQWN0aXZlOiBmYWxzZSwKICAgICAgICAgICAgICAgIHBvc2l0aW9uOiB7IHg6IDAuNSwgeTogMC41IH0sCiAgICAgICAgICAgICAgICB0aW1lc3RhbXA6IDAKICAgICAgICAgICAgfSwKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIE1ldGFkYXRhCiAgICAgICAgICAgIG1ldGFkYXRhOiB7CiAgICAgICAgICAgICAgICBpc0luaXRpYWxpemVkOiBmYWxzZSwKICAgICAgICAgICAgICAgIGVmZmVjdHNSZWdpc3RlcmVkOiAwLAogICAgICAgICAgICAgICAgcGlwZWxpbmVzQ3JlYXRlZDogMAogICAgICAgICAgICB9CiAgICAgICAgfTsKICAgICAgICAKICAgICAgICB0aGlzLmxvZygnaW5mbycsICdFZmZlY3RNYW5hZ2VyIGNyZWF0ZWQnKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBSZWdpc3RlciBhbiBlZmZlY3QgKGRlbGVnYXRlcyB0byByZW5kZXJlcikKICAgICAqIEBwYXJhbSB7RWZmZWN0fSBlZmZlY3QgLSBFZmZlY3QgaW5zdGFuY2UgdG8gcmVnaXN0ZXIKICAgICAqLwogICAgYXN5bmMgcmVnaXN0ZXJFZmZlY3QoZWZmZWN0KSB7CiAgICAgICAgaWYgKCFlZmZlY3QpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgcmVnaXN0ZXIgbnVsbCBlZmZlY3QnKTsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgLy8gQ2hlY2sgZm9yIGR1cGxpY2F0ZSBJRHMKICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZmZlY3RzLmJ5SWQuaGFzKGVmZmVjdC5pZCkpIHsKICAgICAgICAgICAgdGhpcy5sb2coJ3dhcm4nLCBgRWZmZWN0IElEICR7ZWZmZWN0LmlkfSBhbHJlYWR5IHJlZ2lzdGVyZWQsIHNraXBwaW5nYCk7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgdHJ5IHsKICAgICAgICAgICAgLy8gRGVsZWdhdGUgdG8gcmVuZGVyZXIgZm9yIEdQVSByZXNvdXJjZSBjcmVhdGlvbgogICAgICAgICAgICBhd2FpdCB0aGlzLnJlbmRlcmVyLnJlZ2lzdGVyRWZmZWN0KGVmZmVjdCk7CiAgICAgICAgICAgIGVmZmVjdC5zdGF0ZS5tZXRhZGF0YS5pc0luaXRpYWxpemVkID0gdHJ1ZTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIFN0b3JlIGVmZmVjdAogICAgICAgICAgICB0aGlzLnN0YXRlLmVmZmVjdHMubGlzdC5wdXNoKGVmZmVjdCk7CiAgICAgICAgICAgIHRoaXMuc3RhdGUuZWZmZWN0cy5ieUlkLnNldChlZmZlY3QuaWQsIGVmZmVjdCk7CiAgICAgICAgICAgIHRoaXMuc3RhdGUubWV0YWRhdGEuZWZmZWN0c1JlZ2lzdGVyZWQrKzsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIFNldCBhcyBjdXJyZW50IGlmIGZpcnN0IGVmZmVjdAogICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5lZmZlY3RzLmN1cnJlbnRFZmZlY3RJZCA9PT0gbnVsbCkgewogICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS5lZmZlY3RzLmN1cnJlbnRFZmZlY3RJZCA9IGVmZmVjdC5pZDsKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgdGhpcy5sb2coJ2luZm8nLCBgRWZmZWN0IHJlZ2lzdGVyZWQ6ICR7ZWZmZWN0Lm5hbWV9IChJRDogJHtlZmZlY3QuaWR9KWApOwogICAgICAgICAgICAKICAgICAgICB9IGNhdGNoIChlcnJvcikgewogICAgICAgICAgICB0aGlzLmxvZygnZXJyb3InLCBgRmFpbGVkIHRvIHJlZ2lzdGVyIGVmZmVjdCAke2VmZmVjdC5uYW1lfTpgLCBlcnJvcik7CiAgICAgICAgICAgIHRocm93IGVycm9yOwogICAgICAgIH0KICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBDcmVhdGUgcmVuZGVyIHBpcGVsaW5lIGZvciBhbiBlZmZlY3QgKGRlbGVnYXRlcyB0byByZW5kZXJlcikKICAgICAqIEBwYXJhbSB7RWZmZWN0fSBlZmZlY3QgLSBFZmZlY3QgdG8gY3JlYXRlIHBpcGVsaW5lIGZvcgogICAgICogQHBhcmFtIHtib29sZWFufSBuZWVkc1RleHR1cmVJbnB1dCAtIFdoZXRoZXIgZWZmZWN0IG5lZWRzIHRleHR1cmUgaW5wdXQgKGdyb3VwIDApCiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxhbnk+fSBDcmVhdGVkIHBpcGVsaW5lICh0eXBlIGRlcGVuZHMgb24gcmVuZGVyZXIpCiAgICAgKi8KICAgIGFzeW5jIGNyZWF0ZVBpcGVsaW5lKGVmZmVjdCwgbmVlZHNUZXh0dXJlSW5wdXQgPSBmYWxzZSkgewogICAgICAgIHRyeSB7CiAgICAgICAgICAgIHRoaXMubG9nKCdkZWJ1ZycsIGBDcmVhdGluZyBwaXBlbGluZSBmb3IgJHtlZmZlY3QubmFtZX1gKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIERlbGVnYXRlIHRvIHJlbmRlcmVyIGZvciBwaXBlbGluZSBjcmVhdGlvbgogICAgICAgICAgICBjb25zdCBwaXBlbGluZSA9IGF3YWl0IHRoaXMucmVuZGVyZXIuY3JlYXRlUGlwZWxpbmUoZWZmZWN0LCBuZWVkc1RleHR1cmVJbnB1dCk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBTdG9yZSBwaXBlbGluZSByZWZlcmVuY2UKICAgICAgICAgICAgdGhpcy5zdGF0ZS5lZmZlY3RzLnBpcGVsaW5lcy5zZXQoZWZmZWN0LmlkLCBwaXBlbGluZSk7CiAgICAgICAgICAgIHRoaXMuc3RhdGUubWV0YWRhdGEucGlwZWxpbmVzQ3JlYXRlZCsrOwogICAgICAgICAgICAKICAgICAgICAgICAgdGhpcy5sb2coJ2luZm8nLCBgUGlwZWxpbmUgY3JlYXRlZCBmb3IgJHtlZmZlY3QubmFtZX1gKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIHJldHVybiBwaXBlbGluZTsKICAgICAgICAgICAgCiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgICAgICAgdGhpcy5sb2coJ2Vycm9yJywgYEZhaWxlZCB0byBjcmVhdGUgcGlwZWxpbmUgZm9yICR7ZWZmZWN0Lm5hbWV9OmAsIGVycm9yKTsKICAgICAgICAgICAgdGhyb3cgZXJyb3I7CiAgICAgICAgfQogICAgfQogICAgCiAgICAvKioKICAgICAqIEdldCBjdXJyZW50IGVmZmVjdAogICAgICogQHJldHVybnMge0VmZmVjdHxudWxsfSBDdXJyZW50IGVmZmVjdCBvciBudWxsCiAgICAgKi8KICAgIGdldEN1cnJlbnRFZmZlY3QoKSB7CiAgICAgICAgaWYgKHRoaXMuc3RhdGUuZWZmZWN0cy5jdXJyZW50RWZmZWN0SWQgPT09IG51bGwpIHsKICAgICAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgICAgfQogICAgICAgIHJldHVybiB0aGlzLnN0YXRlLmVmZmVjdHMuYnlJZC5nZXQodGhpcy5zdGF0ZS5lZmZlY3RzLmN1cnJlbnRFZmZlY3RJZCk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogVXBkYXRlIGludGVyYWN0aW9uIHN0YXRlCiAgICAgKiBAcGFyYW0ge251bWJlcn0geCAtIE5vcm1hbGl6ZWQgWCBwb3NpdGlvbiAoMC0xKQogICAgICogQHBhcmFtIHtudW1iZXJ9IHkgLSBOb3JtYWxpemVkIFkgcG9zaXRpb24gKDAtMSkKICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gaXNBY3RpdmUgLSBXaGV0aGVyIGludGVyYWN0aW9uIGlzIGFjdGl2ZQogICAgICovCiAgICB1cGRhdGVJbnRlcmFjdGlvbih4LCB5LCBpc0FjdGl2ZSkgewogICAgICAgIHRoaXMuc3RhdGUuaW50ZXJhY3Rpb24gPSB7CiAgICAgICAgICAgIGlzQWN0aXZlLAogICAgICAgICAgICBwb3NpdGlvbjogeyB4LCB5IH0sCiAgICAgICAgICAgIHRpbWVzdGFtcDogcGVyZm9ybWFuY2Uubm93KCkKICAgICAgICB9OwogICAgICAgIAogICAgICAgIGlmIChpc0FjdGl2ZSkgewogICAgICAgICAgICAvLyBVcGRhdGUgcGl4ZWxpemF0aW9uIGVmZmVjdCAoSUQ6IDEpIHdpdGggWSBwYXJhbWV0ZXIKICAgICAgICAgICAgY29uc3QgcGl4ZWxpemF0aW9uRWZmZWN0ID0gdGhpcy5zdGF0ZS5lZmZlY3RzLmJ5SWQuZ2V0KDEpOwogICAgICAgICAgICBpZiAocGl4ZWxpemF0aW9uRWZmZWN0KSB7CiAgICAgICAgICAgICAgICBwaXhlbGl6YXRpb25FZmZlY3QudXBkYXRlUGFyYW1ldGVycyh4LCB5KTsKICAgICAgICAgICAgICAgIC8vIERlYnVnOiBMb2cgdGhlIHVwZGF0ZWQgcGFyYW1ldGVycwogICAgICAgICAgICAgICAgY29uc3QgbWFwcGVkUGFyYW1zID0gcGl4ZWxpemF0aW9uRWZmZWN0LmdldE1hcHBlZFBhcmFtZXRlcnMoKTsKICAgICAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnRUZGRUNUX01HUicsIGBJbnRlcmFjdGlvbiBZPSR7eS50b0ZpeGVkKDMpfSDihpIgcGl4ZWxSb3dzPSR7bWFwcGVkUGFyYW1zLnBpeGVsUm93c31gKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBDaGVjayBpZiBjdXJyZW50bHkgaW4gaW50ZXJhY3RpdmUgbW9kZQogICAgICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgaW50ZXJhY3RpbmcKICAgICAqLwogICAgaXNJbnRlcmFjdGluZygpIHsKICAgICAgICByZXR1cm4gdGhpcy5zdGF0ZS5pbnRlcmFjdGlvbi5pc0FjdGl2ZTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBHZXQgZWZmZWN0IG1hbmFnZXIgc3RhdGUgZm9yIGRlYnVnZ2luZwogICAgICogQHJldHVybnMge09iamVjdH0gQ3VycmVudCBzdGF0ZQogICAgICovCiAgICBnZXRTdGF0ZSgpIHsKICAgICAgICByZXR1cm4gewogICAgICAgICAgICBlZmZlY3RzUmVnaXN0ZXJlZDogdGhpcy5zdGF0ZS5tZXRhZGF0YS5lZmZlY3RzUmVnaXN0ZXJlZCwKICAgICAgICAgICAgcGlwZWxpbmVzQ3JlYXRlZDogdGhpcy5zdGF0ZS5tZXRhZGF0YS5waXBlbGluZXNDcmVhdGVkLAogICAgICAgICAgICBjdXJyZW50RWZmZWN0OiB0aGlzLmdldEN1cnJlbnRFZmZlY3QoKT8ubmFtZSB8fCAnbm9uZScsCiAgICAgICAgICAgIGVmZmVjdHNMaXN0OiB0aGlzLnN0YXRlLmVmZmVjdHMubGlzdC5tYXAoZSA9PiAoewogICAgICAgICAgICAgICAgaWQ6IGUuaWQsCiAgICAgICAgICAgICAgICBuYW1lOiBlLm5hbWUsCiAgICAgICAgICAgICAgICBpc0luaXRpYWxpemVkOiBlLmlzSW5pdGlhbGl6ZWQoKQogICAgICAgICAgICB9KSksCiAgICAgICAgICAgIGlzSW50ZXJhY3Rpbmc6IHRoaXMuc3RhdGUuaW50ZXJhY3Rpb24uaXNBY3RpdmUsCiAgICAgICAgICAgIGludGVyYWN0aW9uUG9zaXRpb246IHsgLi4udGhpcy5zdGF0ZS5pbnRlcmFjdGlvbi5wb3NpdGlvbiB9CiAgICAgICAgfTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBDbGVhbiB1cCBhbGwgcmVzb3VyY2VzCiAgICAgKi8KICAgIGRlc3Ryb3koKSB7CiAgICAgICAgLy8gRGVzdHJveSBhbGwgZWZmZWN0cwogICAgICAgIGZvciAoY29uc3QgZWZmZWN0IG9mIHRoaXMuc3RhdGUuZWZmZWN0cy5saXN0KSB7CiAgICAgICAgICAgIGVmZmVjdC5kZXN0cm95KCk7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIC8vIENsZWFyIHN0YXRlCiAgICAgICAgdGhpcy5zdGF0ZS5lZmZlY3RzLmxpc3QgPSBbXTsKICAgICAgICB0aGlzLnN0YXRlLmVmZmVjdHMuYnlJZC5jbGVhcigpOwogICAgICAgIHRoaXMuc3RhdGUuZWZmZWN0cy5waXBlbGluZXMuY2xlYXIoKTsKICAgICAgICB0aGlzLnN0YXRlLmVmZmVjdHMuY3VycmVudEVmZmVjdElkID0gbnVsbDsKICAgICAgICAKICAgICAgICB0aGlzLmxvZygnaW5mbycsICdFZmZlY3RNYW5hZ2VyIGRlc3Ryb3llZCcpOwogICAgfQogICAgCiAgICAvKioKICAgICAqIEhlbHBlciBtZXRob2QgZm9yIGxvZ2dpbmcKICAgICAqLwogICAgbG9nKGxldmVsLCBtZXNzYWdlLCBkYXRhID0gbnVsbCkgewogICAgICAgIExvZ2dlcltsZXZlbF0oJ0VGRkVDVF9NR1InLCBtZXNzYWdlLCBkYXRhKTsKICAgIH0KfQoKRWZmZWN0TWFuYWdlcjsKCgovKioKICogQXVkaW9Db250cm9sbGVyLmpzCiAqIE1hbmFnZXMgV2ViIEF1ZGlvIEFQSSBmb3IgVFYgc3RhdGljIHdoaXRlIG5vaXNlIGdlbmVyYXRpb24KICogUGhhc2UgRDogQ29udGludW91cyB3aGl0ZSBub2lzZSBwbGF5YmFjawogKiBQaGFzZSBFOiBJbnRlcmFjdGl2ZSBjb250cm9scyAoWS1heGlzOiBsb3ctcGFzcyBmaWx0ZXIsIFgtYXhpczogcmh5dGhtKQogKi8KCmNsYXNzIEF1ZGlvQ29udHJvbGxlciB7CiAgICBjb25zdHJ1Y3RvcigpIHsKICAgICAgICAvLyA9PT09PSBUVU5BQkxFIENPTkZJR1VSQVRJT04gPT09PT0KICAgICAgICAvLyBFYXN5IGFjY2VzcyBmb3IgYWRqdXN0aW5nIGF1ZGlvIHBhcmFtZXRlcnMKICAgICAgICB0aGlzLmNvbmZpZyA9IHsKICAgICAgICAgICAgLy8gTG93LXBhc3MgZmlsdGVyIHNldHRpbmdzIChZLWF4aXMgY29udHJvbCkKICAgICAgICAgICAgZmlsdGVyOiB7CiAgICAgICAgICAgICAgICBtaW5GcmVxdWVuY3k6IDE0NywgICAgIC8vIEJvdHRvbSBvZiBZLWF4aXMgKG1vc3QgbXVmZmxlZCkgLSBIegogICAgICAgICAgICAgICAgbWF4RnJlcXVlbmN5OiA0OTAwLCAgICAvLyBUb3Agb2YgWS1heGlzIChicmlnaHRlc3QpIC0gSHoKICAgICAgICAgICAgICAgIHJlc29uYW5jZTogNi4wICAgICAgICAgLy8gUSBmYWN0b3IgLSBoaWdoZXIgPSBtb3JlIHByb25vdW5jZWQgZmlsdGVyaW5nCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBSaHl0aG0gc2V0dGluZ3MgKFgtYXhpcyBjb250cm9sKQogICAgICAgICAgICByaHl0aG06IHsKICAgICAgICAgICAgICAgIG1pblJhdGU6IDMsICAgICAgICAgICAgLy8gTWluaW11bSBwdWxzZSByYXRlIChsZWZ0IHNpZGUpIC0gSHogKHB1bHNlcyBwZXIgc2Vjb25kKQogICAgICAgICAgICAgICAgbWF4UmF0ZTogMTMsICAgICAgICAgLy8gTWF4aW11bSBwdWxzZSByYXRlIChyaWdodCBzaWRlKSAtIEh6CiAgICAgICAgICAgICAgICAvLyBBRFNSIGVudmVsb3BlIGZvciBlYWNoIHB1bHNlIChpbiBzZWNvbmRzKQogICAgICAgICAgICAgICAgYXR0YWNrOiAwLjAwMDEsICAgICAgICAvLyBBdHRhY2sgdGltZSAtIGhvdyBmYXN0IGl0IGZhZGVzIGluCiAgICAgICAgICAgICAgICBkZWNheTogMC4wNywgICAgICAgICAgIC8vIERlY2F5IHRpbWUgLSBob3cgbG9uZyBpdCB0YWtlcyB0byBkZWNheSBhZnRlciBhdHRhY2sKICAgICAgICAgICAgICAgIHN1c3RhaW46IDAuMDAxLCAgICAgICAgLy8gU3VzdGFpbiBsZXZlbCAoMC0xKSAtIGxldmVsIGR1cmluZyBzdXN0YWluIHBoYXNlCiAgICAgICAgICAgICAgICByZWxlYXNlOiAwLjAyLCAgICAgICAgIC8vIFJlbGVhc2UgdGltZSAtIGhvdyBsb25nIHRvIGZhZGUgb3V0CiAgICAgICAgICAgICAgICBzY2hlZHVsZUFoZWFkOiAwLjIgICAgIC8vIEhvdyBmYXIgYWhlYWQgdG8gc2NoZWR1bGUgcHVsc2VzIChzZWNvbmRzKQogICAgICAgICAgICB9LAogICAgICAgICAgICAKICAgICAgICAgICAgLy8gTWFzdGVyIHZvbHVtZQogICAgICAgICAgICB2b2x1bWU6IDAuMywgICAgICAgICAgICAgICAvLyBWb2x1bWUgbGV2ZWwgKDAtMSkKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIEF1ZGlvIGVuZ2luZSBzZXR0aW5ncwogICAgICAgICAgICBzYW1wbGVSYXRlOiA0NDEwMCwgICAgICAgICAvLyBBdWRpbyBzYW1wbGUgcmF0ZQogICAgICAgICAgICBidWZmZXJTaXplOiAyLCAgICAgICAgICAgICAvLyBXaGl0ZSBub2lzZSBidWZmZXIgZHVyYXRpb24gaW4gc2Vjb25kcwogICAgICAgICAgICBlbmFibGVMb2dnaW5nOiB0cnVlICAgICAgICAvLyBEZWJ1ZyBsb2dnaW5nCiAgICAgICAgfTsKICAgICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQogICAgICAgIAogICAgICAgIHRoaXMuc3RhdGUgPSB7CiAgICAgICAgICAgIC8vIEF1ZGlvIGNvbnRleHQgYW5kIG5vZGVzCiAgICAgICAgICAgIGF1ZGlvQ29udGV4dDogbnVsbCwKICAgICAgICAgICAgbm9kZXM6IHsKICAgICAgICAgICAgICAgIHdoaXRlTm9pc2U6IG51bGwsICAgICAgLy8gV2hpdGUgbm9pc2UgYnVmZmVyIHNvdXJjZQogICAgICAgICAgICAgICAgZ2Fpbk5vZGU6IG51bGwsICAgICAgICAvLyBNYXN0ZXIgdm9sdW1lIGNvbnRyb2wKICAgICAgICAgICAgICAgIGZpbHRlck5vZGU6IG51bGwsICAgICAgLy8gTG93LXBhc3MgZmlsdGVyIChQaGFzZSBFIC0gWS1heGlzKQogICAgICAgICAgICAgICAgcmh5dGhtR2FpbjogbnVsbCwgICAgICAvLyBSaHl0aG0gZ2FpbiBmb3IgQURTUiBlbnZlbG9wZSAoUGhhc2UgRSAtIFgtYXhpcykKICAgICAgICAgICAgICAgIGRyb25lR2FpbjogbnVsbCwgICAgICAgLy8gRHJvbmUgZ2FpbiBmb3IgYmFja2dyb3VuZCBkcm9uZSBjb250cm9sIChzcGFjZSBiYXIgdG9nZ2xlKQogICAgICAgICAgICB9LAogICAgICAgICAgICAKICAgICAgICAgICAgLy8gUGxheWJhY2sgc3RhdGUKICAgICAgICAgICAgcGxheWJhY2s6IHsKICAgICAgICAgICAgICAgIGlzUGxheWluZzogZmFsc2UsCiAgICAgICAgICAgICAgICBpc0luaXRpYWxpemVkOiBmYWxzZSwKICAgICAgICAgICAgICAgIHN0YXJ0VGltZTogMAogICAgICAgICAgICB9LAogICAgICAgICAgICAKICAgICAgICAgICAgLy8gUmh5dGhtIGNvbnRyb2wgc3RhdGUKICAgICAgICAgICAgcmh5dGhtOiB7CiAgICAgICAgICAgICAgICBpc0FjdGl2ZTogZmFsc2UsICAgICAgIC8vIFdoZXRoZXIgcmh5dGhtIGlzIGFjdGl2ZSAoWCA+IDApCiAgICAgICAgICAgICAgICBjdXJyZW50UmF0ZTogMCwgICAgICAgIC8vIEN1cnJlbnQgcHVsc2UgcmF0ZSBpbiBIegogICAgICAgICAgICAgICAgbmV4dFB1bHNlVGltZTogMCwgICAgICAvLyBXaGVuIHRoZSBuZXh0IHB1bHNlIHNob3VsZCB0cmlnZ2VyCiAgICAgICAgICAgICAgICBzY2hlZHVsZXJUaW1lcjogbnVsbCAgIC8vIFRpbWVyIGZvciBwdWxzZSBzY2hlZHVsaW5nCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBEcm9uZSBtb2RlIHN0YXRlIChzcGFjZSBiYXIgdG9nZ2xlKQogICAgICAgICAgICBkcm9uZU1vZGU6IHsKICAgICAgICAgICAgICAgIGVuYWJsZWQ6IHRydWUsICAgICAgICAgLy8gU3RhcnQgaW4gZHJvbmUgbW9kZSBPTiAoZGVmYXVsdC9jdXJyZW50IGJlaGF2aW9yKQogICAgICAgICAgICAgICAgaXNJbnRlcmFjdGluZzogZmFsc2UgICAvLyBUcmFjayBpZiBjdXJyZW50bHkgY2xpY2tpbmcvZHJhZ2dpbmcKICAgICAgICAgICAgfSwKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIEN1cnJlbnQgYXVkaW8gcGFyYW1ldGVycwogICAgICAgICAgICBwYXJhbWV0ZXJzOiB7CiAgICAgICAgICAgICAgICB2b2x1bWU6IDAuMywgICAgICAgICAgIC8vIE1hc3RlciB2b2x1bWUgKDAtMSkKICAgICAgICAgICAgICAgIGZpbHRlckZyZXF1ZW5jeTogNDkwMCwgLy8gTG93LXBhc3MgZmlsdGVyIGN1dG9mZiAtIHN0YXJ0cyBhdCBtYXggKG5vIGZpbHRlcmluZykKICAgICAgICAgICAgICAgIHJoeXRobVJhdGU6IDAgICAgICAgICAgLy8gUmh5dGhtIHJhdGUgaW4gSHogKDAgPSBjb250aW51b3VzL2Ryb25lKQogICAgICAgICAgICB9CiAgICAgICAgfTsKICAgICAgICAKICAgICAgICBMb2dnZXIuaW5mbygnQVVESU8nLCAnQXVkaW9Db250cm9sbGVyIGNyZWF0ZWQnKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBJbml0aWFsaXplIFdlYiBBdWRpbyBBUEkgKG11c3QgYmUgY2FsbGVkIGFmdGVyIHVzZXIgaW50ZXJhY3Rpb24pCiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gVHJ1ZSBpZiBpbml0aWFsaXphdGlvbiBzdWNjZXNzZnVsCiAgICAgKi8KICAgIGFzeW5jIGluaXRpYWxpemUoKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUucGxheWJhY2suaXNJbml0aWFsaXplZCkgewogICAgICAgICAgICAgICAgTG9nZ2VyLndhcm4oJ0FVRElPJywgJ0FscmVhZHkgaW5pdGlhbGl6ZWQnKTsKICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICBMb2dnZXIuaW5mbygnQVVESU8nLCAnSW5pdGlhbGl6aW5nIFdlYiBBdWRpbyBBUEkuLi4nKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIENyZWF0ZSBhdWRpbyBjb250ZXh0CiAgICAgICAgICAgIGNvbnN0IEF1ZGlvQ29udGV4dENsYXNzID0gd2luZG93LkF1ZGlvQ29udGV4dCB8fCB3aW5kb3cud2Via2l0QXVkaW9Db250ZXh0OwogICAgICAgICAgICB0aGlzLnN0YXRlLmF1ZGlvQ29udGV4dCA9IG5ldyBBdWRpb0NvbnRleHRDbGFzcyh7CiAgICAgICAgICAgICAgICBzYW1wbGVSYXRlOiB0aGlzLmNvbmZpZy5zYW1wbGVSYXRlCiAgICAgICAgICAgIH0pOwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gQ3JlYXRlIGF1ZGlvIGdyYXBoCiAgICAgICAgICAgIGF3YWl0IHRoaXMuY3JlYXRlQXVkaW9HcmFwaCgpOwogICAgICAgICAgICAKICAgICAgICAgICAgdGhpcy5zdGF0ZS5wbGF5YmFjay5pc0luaXRpYWxpemVkID0gdHJ1ZTsKICAgICAgICAgICAgTG9nZ2VyLmluZm8oJ0FVRElPJywgYEF1ZGlvIGluaXRpYWxpemVkIChzYW1wbGUgcmF0ZTogJHt0aGlzLnN0YXRlLmF1ZGlvQ29udGV4dC5zYW1wbGVSYXRlfUh6KWApOwogICAgICAgICAgICAKICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICAgIAogICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgICAgICAgIExvZ2dlci5lcnJvcignQVVESU8nLCAnRmFpbGVkIHRvIGluaXRpYWxpemUgYXVkaW86JywgZXJyb3IpOwogICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgfQogICAgfQogICAgCiAgICAvKioKICAgICAqIENyZWF0ZSB0aGUgYXVkaW8gcHJvY2Vzc2luZyBncmFwaAogICAgICovCiAgICBhc3luYyBjcmVhdGVBdWRpb0dyYXBoKCkgewogICAgICAgIGNvbnN0IGN0eCA9IHRoaXMuc3RhdGUuYXVkaW9Db250ZXh0OwogICAgICAgIAogICAgICAgIC8vIENyZWF0ZSByaHl0aG0gZ2FpbiBub2RlIGZvciBBRFNSIGVudmVsb3BlIChQaGFzZSBFIC0gWC1heGlzIGNvbnRyb2wpCiAgICAgICAgdGhpcy5zdGF0ZS5ub2Rlcy5yaHl0aG1HYWluID0gY3R4LmNyZWF0ZUdhaW4oKTsKICAgICAgICAvLyBTdGFydCBhdCAxLjAgaWYgZHJvbmUgT04gKGNvbnRpbnVvdXMpLCAwLjAgaWYgZHJvbmUgT0ZGIChyZWFkeSBmb3IgaW5zdGFudCBmaXJzdCBub3RlKQogICAgICAgIHRoaXMuc3RhdGUubm9kZXMucmh5dGhtR2Fpbi5nYWluLnZhbHVlID0gdGhpcy5zdGF0ZS5kcm9uZU1vZGUuZW5hYmxlZCA/IDEuMCA6IDAuMDsKICAgICAgICAKICAgICAgICAvLyBDcmVhdGUgZHJvbmUgZ2FpbiBub2RlIGZvciBiYWNrZ3JvdW5kIGRyb25lIGNvbnRyb2wgKHNwYWNlIGJhciB0b2dnbGUpCiAgICAgICAgdGhpcy5zdGF0ZS5ub2Rlcy5kcm9uZUdhaW4gPSBjdHguY3JlYXRlR2FpbigpOwogICAgICAgIHRoaXMuc3RhdGUubm9kZXMuZHJvbmVHYWluLmdhaW4udmFsdWUgPSAxLjA7IC8vIFN0YXJ0IGF0IGZ1bGwgdm9sdW1lIChkcm9uZSBtb2RlIE9OKQogICAgICAgIAogICAgICAgIC8vIENyZWF0ZSBsb3ctcGFzcyBmaWx0ZXIgKFBoYXNlIEUgLSBZLWF4aXMgY29udHJvbCkKICAgICAgICB0aGlzLnN0YXRlLm5vZGVzLmZpbHRlck5vZGUgPSBjdHguY3JlYXRlQmlxdWFkRmlsdGVyKCk7CiAgICAgICAgdGhpcy5zdGF0ZS5ub2Rlcy5maWx0ZXJOb2RlLnR5cGUgPSAnbG93cGFzcyc7CiAgICAgICAgdGhpcy5zdGF0ZS5ub2Rlcy5maWx0ZXJOb2RlLmZyZXF1ZW5jeS52YWx1ZSA9IHRoaXMuY29uZmlnLmZpbHRlci5tYXhGcmVxdWVuY3k7IC8vIFN0YXJ0IGF0IG1heCAobm8gZmlsdGVyaW5nKQogICAgICAgIHRoaXMuc3RhdGUubm9kZXMuZmlsdGVyTm9kZS5RLnZhbHVlID0gdGhpcy5jb25maWcuZmlsdGVyLnJlc29uYW5jZTsgLy8gUmVzb25hbmNlL2NoYXJhY3RlcgogICAgICAgIAogICAgICAgIC8vIENyZWF0ZSBtYXN0ZXIgZ2FpbiBub2RlIGZvciB2b2x1bWUgY29udHJvbAogICAgICAgIHRoaXMuc3RhdGUubm9kZXMuZ2Fpbk5vZGUgPSBjdHguY3JlYXRlR2FpbigpOwogICAgICAgIHRoaXMuc3RhdGUubm9kZXMuZ2Fpbk5vZGUuZ2Fpbi52YWx1ZSA9IHRoaXMuY29uZmlnLnZvbHVtZTsKICAgICAgICAKICAgICAgICAvLyBDb25uZWN0OiBmaWx0ZXIg4oaSIHJoeXRobSBnYWluIOKGkiBkcm9uZSBnYWluIOKGkiBtYXN0ZXIgZ2FpbiDihpIgZGVzdGluYXRpb24KICAgICAgICB0aGlzLnN0YXRlLm5vZGVzLmZpbHRlck5vZGUuY29ubmVjdCh0aGlzLnN0YXRlLm5vZGVzLnJoeXRobUdhaW4pOwogICAgICAgIHRoaXMuc3RhdGUubm9kZXMucmh5dGhtR2Fpbi5jb25uZWN0KHRoaXMuc3RhdGUubm9kZXMuZHJvbmVHYWluKTsKICAgICAgICB0aGlzLnN0YXRlLm5vZGVzLmRyb25lR2Fpbi5jb25uZWN0KHRoaXMuc3RhdGUubm9kZXMuZ2Fpbk5vZGUpOwogICAgICAgIHRoaXMuc3RhdGUubm9kZXMuZ2Fpbk5vZGUuY29ubmVjdChjdHguZGVzdGluYXRpb24pOwogICAgICAgIAogICAgICAgIExvZ2dlci5pbmZvKCdBVURJTycsIGBBdWRpbyBncmFwaCBjcmVhdGVkIChmaWx0ZXI6ICR7dGhpcy5jb25maWcuZmlsdGVyLm1pbkZyZXF1ZW5jeX0tJHt0aGlzLmNvbmZpZy5maWx0ZXIubWF4RnJlcXVlbmN5fUh6LCBROiAke3RoaXMuY29uZmlnLmZpbHRlci5yZXNvbmFuY2V9LCByaHl0aG06ICR7dGhpcy5jb25maWcucmh5dGhtLm1pblJhdGV9LSR7dGhpcy5jb25maWcucmh5dGhtLm1heFJhdGV9SHosIGRyb25lOiAke3RoaXMuc3RhdGUuZHJvbmVNb2RlLmVuYWJsZWQgPyAnT04nIDogJ09GRid9KWApOwogICAgfQogICAgCiAgICAvKioKICAgICAqIEdlbmVyYXRlIHdoaXRlIG5vaXNlIGJ1ZmZlcgogICAgICogQHJldHVybnMge0F1ZGlvQnVmZmVyfSBCdWZmZXIgY29udGFpbmluZyB3aGl0ZSBub2lzZQogICAgICovCiAgICBnZW5lcmF0ZVdoaXRlTm9pc2VCdWZmZXIoKSB7CiAgICAgICAgY29uc3QgY3R4ID0gdGhpcy5zdGF0ZS5hdWRpb0NvbnRleHQ7CiAgICAgICAgY29uc3QgYnVmZmVyU2l6ZSA9IGN0eC5zYW1wbGVSYXRlICogdGhpcy5jb25maWcuYnVmZmVyU2l6ZTsKICAgICAgICBjb25zdCBidWZmZXIgPSBjdHguY3JlYXRlQnVmZmVyKDEsIGJ1ZmZlclNpemUsIGN0eC5zYW1wbGVSYXRlKTsKICAgICAgICBjb25zdCBvdXRwdXQgPSBidWZmZXIuZ2V0Q2hhbm5lbERhdGEoMCk7CiAgICAgICAgCiAgICAgICAgLy8gRmlsbCBidWZmZXIgd2l0aCByYW5kb20gdmFsdWVzICgtMSB0byAxKSBmb3Igd2hpdGUgbm9pc2UKICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGJ1ZmZlclNpemU7IGkrKykgewogICAgICAgICAgICBvdXRwdXRbaV0gPSBNYXRoLnJhbmRvbSgpICogMiAtIDE7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIExvZ2dlci5kZWJ1ZygnQVVESU8nLCBgV2hpdGUgbm9pc2UgYnVmZmVyIGdlbmVyYXRlZCAoJHtidWZmZXJTaXplfSBzYW1wbGVzKWApOwogICAgICAgIHJldHVybiBidWZmZXI7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogU3RhcnQgcGxheWluZyB3aGl0ZSBub2lzZSAoY29udGludW91c2x5IGxvb3BpbmcpCiAgICAgKi8KICAgIGFzeW5jIHN0YXJ0V2hpdGVOb2lzZSgpIHsKICAgICAgICBpZiAoIXRoaXMuc3RhdGUucGxheWJhY2suaXNJbml0aWFsaXplZCkgewogICAgICAgICAgICBMb2dnZXIuZXJyb3IoJ0FVRElPJywgJ0Nhbm5vdCBzdGFydCAtIG5vdCBpbml0aWFsaXplZCcpOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIAogICAgICAgIGlmICh0aGlzLnN0YXRlLnBsYXliYWNrLmlzUGxheWluZykgewogICAgICAgICAgICBMb2dnZXIud2FybignQVVESU8nLCAnQWxyZWFkeSBwbGF5aW5nJyk7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgdHJ5IHsKICAgICAgICAgICAgY29uc3QgY3R4ID0gdGhpcy5zdGF0ZS5hdWRpb0NvbnRleHQ7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBSZXN1bWUgYXVkaW8gY29udGV4dCBpZiBzdXNwZW5kZWQgKEFuZHJvaWQvU2FmYXJpIHJlcXVpcmVtZW50KQogICAgICAgICAgICAvLyBBbmRyb2lkIENocm9tZSBpcyBlc3BlY2lhbGx5IHN0cmljdCAtIE1VU1QgYXdhaXQgcmVzdW1lIGJlZm9yZSBzdGFydGluZwogICAgICAgICAgICBpZiAoY3R4LnN0YXRlID09PSAnc3VzcGVuZGVkJykgewogICAgICAgICAgICAgICAgTG9nZ2VyLmluZm8oJ0FVRElPJywgYEF1ZGlvQ29udGV4dCBzdXNwZW5kZWQgKCR7Y3R4LnN0YXRlfSksIHJlc3VtaW5nLi4uYCk7CiAgICAgICAgICAgICAgICBhd2FpdCBjdHgucmVzdW1lKCk7CiAgICAgICAgICAgICAgICBMb2dnZXIuaW5mbygnQVVESU8nLCBgQXVkaW9Db250ZXh0IHJlc3VtZWQsIHN0YXRlOiAke2N0eC5zdGF0ZX1gKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgLy8gVmVyaWZ5IGNvbnRleHQgaXMgcnVubmluZwogICAgICAgICAgICBpZiAoY3R4LnN0YXRlICE9PSAncnVubmluZycpIHsKICAgICAgICAgICAgICAgIExvZ2dlci5lcnJvcignQVVESU8nLCBgQXVkaW9Db250ZXh0IG5vdCBydW5uaW5nIChzdGF0ZTogJHtjdHguc3RhdGV9KSwgY2Fubm90IHN0YXJ0IGF1ZGlvYCk7CiAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIH0KICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIENyZWF0ZSBidWZmZXIgc291cmNlCiAgICAgICAgICAgIGNvbnN0IHdoaXRlTm9pc2VCdWZmZXIgPSB0aGlzLmdlbmVyYXRlV2hpdGVOb2lzZUJ1ZmZlcigpOwogICAgICAgICAgICB0aGlzLnN0YXRlLm5vZGVzLndoaXRlTm9pc2UgPSBjdHguY3JlYXRlQnVmZmVyU291cmNlKCk7CiAgICAgICAgICAgIHRoaXMuc3RhdGUubm9kZXMud2hpdGVOb2lzZS5idWZmZXIgPSB3aGl0ZU5vaXNlQnVmZmVyOwogICAgICAgICAgICB0aGlzLnN0YXRlLm5vZGVzLndoaXRlTm9pc2UubG9vcCA9IHRydWU7IC8vIExvb3AgY29udGludW91c2x5CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBDb25uZWN0IHRvIGF1ZGlvIGdyYXBoCiAgICAgICAgICAgIHRoaXMuc3RhdGUubm9kZXMud2hpdGVOb2lzZS5jb25uZWN0KHRoaXMuc3RhdGUubm9kZXMuZmlsdGVyTm9kZSk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBTdGFydCBwbGF5YmFjawogICAgICAgICAgICB0aGlzLnN0YXRlLm5vZGVzLndoaXRlTm9pc2Uuc3RhcnQoMCk7CiAgICAgICAgICAgIHRoaXMuc3RhdGUucGxheWJhY2suaXNQbGF5aW5nID0gdHJ1ZTsKICAgICAgICAgICAgdGhpcy5zdGF0ZS5wbGF5YmFjay5zdGFydFRpbWUgPSBjdHguY3VycmVudFRpbWU7CiAgICAgICAgICAgIAogICAgICAgICAgICBMb2dnZXIuaW5mbygnQVVESU8nLCAnV2hpdGUgbm9pc2Ugc3RhcnRlZCBzdWNjZXNzZnVsbHknKTsKICAgICAgICAgICAgCiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgICAgICAgTG9nZ2VyLmVycm9yKCdBVURJTycsICdGYWlsZWQgdG8gc3RhcnQgd2hpdGUgbm9pc2U6JywgZXJyb3IpOwogICAgICAgIH0KICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBTdG9wIHdoaXRlIG5vaXNlIHBsYXliYWNrCiAgICAgKi8KICAgIHN0b3BXaGl0ZU5vaXNlKCkgewogICAgICAgIGlmICghdGhpcy5zdGF0ZS5wbGF5YmFjay5pc1BsYXlpbmcpIHsKICAgICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICAKICAgICAgICB0cnkgewogICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5ub2Rlcy53aGl0ZU5vaXNlKSB7CiAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLm5vZGVzLndoaXRlTm9pc2Uuc3RvcCgpOwogICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS5ub2Rlcy53aGl0ZU5vaXNlLmRpc2Nvbm5lY3QoKTsKICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUubm9kZXMud2hpdGVOb2lzZSA9IG51bGw7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgCiAgICAgIC
IGVmZmVjdHMKICogU3ViY2xhc3NlcyBtdXN0IGltcGxlbWVudDoKICogLSBtYXBQYXJhbWV0ZXJzKHgsIHkpIC0gTWFwIG5vcm1hbGl6ZWQgaW5wdXQgdG8gZWZmZWN0LXNwZWNpZmljIHZhbHVlcwogKiAtIGNyZWF0ZVVuaWZvcm1zKGRldmljZSkgLSBDcmVhdGUgR1BVIHVuaWZvcm0gYnVmZmVycyBhbmQgYmluZCBncm91cHMKICogLSB3cml0ZVVuaWZvcm1zKGRldmljZSwgbWFwcGVkUGFyYW1zKSAtIFdyaXRlIHBhcmFtZXRlcnMgdG8gR1BVCiAqLwpjbGFzcyBFZmZlY3QgewogICAgY29uc3RydWN0b3IoaWQsIG5hbWUpIHsKICAgICAgICB0aGlzLmlkID0gaWQ7CiAgICAgICAgdGhpcy5uYW1lID0gbmFtZTsKICAgICAgICAKICAgICAgICAvLyBTdHJ1Y3R1cmVkIHN0YXRlIGZvbGxvd2luZyBhYnN0cmFjdGlvbiBydWxlcwogICAgICAgIHRoaXMuc3RhdGUgPSB7CiAgICAgICAgICAgIC8vIEVmZmVjdCBwYXJhbWV0ZXJzIChub3JtYWxpemVkIDAtMSkKICAgICAgICAgICAgcGFyYW1ldGVyczogewogICAgICAgICAgICAgICAgeDogMC41LAogICAgICAgICAgICAgICAgeTogMC41LAogICAgICAgICAgICAgICAgdGltZTogMC4wICAvLyBBbmltYXRpb24gdGltZQogICAgICAgICAgICB9LAogICAgICAgICAgICAKICAgICAgICAgICAgLy8gR1BVIHJlc291cmNlcwogICAgICAgICAgICB1bmlmb3JtczogewogICAgICAgICAgICAgICAgYnVmZmVyOiBudWxsLAogICAgICAgICAgICAgICAgYmluZEdyb3VwOiBudWxsLAogICAgICAgICAgICAgICAgbGF5b3V0OiBudWxsLAogICAgICAgICAgICAgICAgbmVlZHNVcGRhdGU6IHRydWUKICAgICAgICAgICAgfSwKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIEVmZmVjdCBtZXRhZGF0YQogICAgICAgICAgICBtZXRhZGF0YTogewogICAgICAgICAgICAgICAgaXNJbml0aWFsaXplZDogZmFsc2UsCiAgICAgICAgICAgICAgICBsYXN0VXBkYXRlVGltZTogMCwKICAgICAgICAgICAgICAgIHVwZGF0ZUNvdW50OiAwCiAgICAgICAgICAgIH0KICAgICAgICB9OwogICAgICAgIAogICAgICAgIC8vIEVmZmVjdC1zcGVjaWZpYyBjb25maWd1cmF0aW9uIChvdmVycmlkZSBpbiBzdWJjbGFzc2VzKQogICAgICAgIHRoaXMuY29uZmlnID0ge307CiAgICAgICAgCiAgICAgICAgdGhpcy5sb2coJ2RlYnVnJywgYEVmZmVjdCBjcmVhdGVkOiAke3RoaXMubmFtZX0gKElEOiAke3RoaXMuaWR9KWApOwogICAgfQogICAgCiAgICAvKioKICAgICAqIE1hcCBub3JtYWxpemVkIFhZIHBhcmFtZXRlcnMgKDAtMSkgdG8gZWZmZWN0LXNwZWNpZmljIHZhbHVlcwogICAgICogTXVzdCBiZSBpbXBsZW1lbnRlZCBieSBzdWJjbGFzc2VzCiAgICAgKiBAcGFyYW0ge251bWJlcn0geCAtIE5vcm1hbGl6ZWQgWCBwYXJhbWV0ZXIgKDAtMSkKICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5IC0gTm9ybWFsaXplZCBZIHBhcmFtZXRlciAoMC0xKQogICAgICogQHJldHVybnMge09iamVjdH0gRWZmZWN0LXNwZWNpZmljIHBhcmFtZXRlciB2YWx1ZXMKICAgICAqLwogICAgbWFwUGFyYW1ldGVycyh4LCB5KSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBtYXBQYXJhbWV0ZXJzKCkgbXVzdCBiZSBpbXBsZW1lbnRlZCBieSAke3RoaXMubmFtZX1gKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBDcmVhdGUgR1BVIHVuaWZvcm0gYnVmZmVycyBhbmQgYmluZCBncm91cCBsYXlvdXQKICAgICAqIE11c3QgYmUgaW1wbGVtZW50ZWQgYnkgc3ViY2xhc3NlcwogICAgICogQHBhcmFtIHtHUFVEZXZpY2V9IGRldmljZSAtIFdlYkdQVSBkZXZpY2UKICAgICAqLwogICAgYXN5bmMgY3JlYXRlVW5pZm9ybXMoZGV2aWNlKSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBjcmVhdGVVbmlmb3JtcygpIG11c3QgYmUgaW1wbGVtZW50ZWQgYnkgJHt0aGlzLm5hbWV9YCk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogV3JpdGUgcGFyYW1ldGVyIHZhbHVlcyB0byBHUFUgdW5pZm9ybSBidWZmZXIKICAgICAqIE11c3QgYmUgaW1wbGVtZW50ZWQgYnkgc3ViY2xhc3NlcwogICAgICogQHBhcmFtIHtHUFVEZXZpY2V9IGRldmljZSAtIFdlYkdQVSBkZXZpY2UKICAgICAqIEBwYXJhbSB7T2JqZWN0fSBtYXBwZWRQYXJhbXMgLSBFZmZlY3Qtc3BlY2lmaWMgcGFyYW1ldGVyIHZhbHVlcwogICAgICovCiAgICB3cml0ZVVuaWZvcm1zKGRldmljZSwgbWFwcGVkUGFyYW1zKSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGB3cml0ZVVuaWZvcm1zKCkgbXVzdCBiZSBpbXBsZW1lbnRlZCBieSAke3RoaXMubmFtZX1gKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBVcGRhdGUgZWZmZWN0IHBhcmFtZXRlcnMgKG5vcm1hbGl6ZWQgMC0xKQogICAgICogQHBhcmFtIHtudW1iZXJ9IHggLSBOb3JtYWxpemVkIFggcGFyYW1ldGVyICgwLTEpCiAgICAgKiBAcGFyYW0ge251bWJlcn0geSAtIE5vcm1hbGl6ZWQgWSBwYXJhbWV0ZXIgKDAtMSkKICAgICAqLwogICAgdXBkYXRlUGFyYW1ldGVycyh4LCB5KSB7CiAgICAgICAgdGhpcy5zdGF0ZS5wYXJhbWV0ZXJzLnggPSBNYXRoLm1heCgwLCBNYXRoLm1pbigxLCB4KSk7CiAgICAgICAgdGhpcy5zdGF0ZS5wYXJhbWV0ZXJzLnkgPSBNYXRoLm1heCgwLCBNYXRoLm1pbigxLCB5KSk7CiAgICAgICAgdGhpcy5zdGF0ZS51bmlmb3Jtcy5uZWVkc1VwZGF0ZSA9IHRydWU7CiAgICAgICAgdGhpcy5zdGF0ZS5tZXRhZGF0YS5sYXN0VXBkYXRlVGltZSA9IHBlcmZvcm1hbmNlLm5vdygpOwogICAgICAgIHRoaXMuc3RhdGUubWV0YWRhdGEudXBkYXRlQ291bnQrKzsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBVcGRhdGUgYW5pbWF0aW9uIHRpbWUKICAgICAqIEBwYXJhbSB7bnVtYmVyfSB0aW1lIC0gVGltZSBpbiBzZWNvbmRzCiAgICAgKi8KICAgIHVwZGF0ZVRpbWUodGltZSkgewogICAgICAgIHRoaXMuc3RhdGUucGFyYW1ldGVycy50aW1lID0gdGltZTsKICAgICAgICB0aGlzLnN0YXRlLnVuaWZvcm1zLm5lZWRzVXBkYXRlID0gdHJ1ZTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBHZXQgbWFwcGVkIHBhcmFtZXRlcnMgYmFzZWQgb24gY3VycmVudCBzdGF0ZQogICAgICogQHJldHVybnMge09iamVjdH0gTWFwcGVkIHBhcmFtZXRlciB2YWx1ZXMKICAgICAqLwogICAgZ2V0TWFwcGVkUGFyYW1ldGVycygpIHsKICAgICAgICByZXR1cm4gdGhpcy5tYXBQYXJhbWV0ZXJzKAogICAgICAgICAgICB0aGlzLnN0YXRlLnBhcmFtZXRlcnMueCwKICAgICAgICAgICAgdGhpcy5zdGF0ZS5wYXJhbWV0ZXJzLnkKICAgICAgICApOwogICAgfQogICAgCiAgICAvKioKICAgICAqIEdldCBiaW5kIGdyb3VwIGZvciByZW5kZXJpbmcKICAgICAqIEByZXR1cm5zIHtHUFVCaW5kR3JvdXB9IEJpbmQgZ3JvdXAgZm9yIHRoaXMgZWZmZWN0CiAgICAgKi8KICAgIGdldEJpbmRHcm91cCgpIHsKICAgICAgICByZXR1cm4gdGhpcy5zdGF0ZS51bmlmb3Jtcy5iaW5kR3JvdXA7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogR2V0IGJpbmQgZ3JvdXAgbGF5b3V0IGZvciBwaXBlbGluZSBjcmVhdGlvbgogICAgICogQHJldHVybnMge0dQVUJpbmRHcm91cExheW91dH0gQmluZCBncm91cCBsYXlvdXQKICAgICAqLwogICAgZ2V0QmluZEdyb3VwTGF5b3V0KCkgewogICAgICAgIHJldHVybiB0aGlzLnN0YXRlLnVuaWZvcm1zLmxheW91dDsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBDaGVjayBpZiBlZmZlY3QgaXMgaW5pdGlhbGl6ZWQKICAgICAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIGluaXRpYWxpemVkCiAgICAgKi8KICAgIGlzSW5pdGlhbGl6ZWQoKSB7CiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGUubWV0YWRhdGEuaXNJbml0aWFsaXplZDsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBHZXQgZWZmZWN0IHN0YXRlIGZvciBkZWJ1Z2dpbmcKICAgICAqIEByZXR1cm5zIHtPYmplY3R9IEN1cnJlbnQgZWZmZWN0IHN0YXRlCiAgICAgKi8KICAgIGdldEVmZmVjdFN0YXRlKCkgewogICAgICAgIHJldHVybiB7CiAgICAgICAgICAgIGlkOiB0aGlzLmlkLAogICAgICAgICAgICBuYW1lOiB0aGlzLm5hbWUsCiAgICAgICAgICAgIGlzSW5pdGlhbGl6ZWQ6IHRoaXMuc3RhdGUubWV0YWRhdGEuaXNJbml0aWFsaXplZCwKICAgICAgICAgICAgcGFyYW1ldGVyczogeyAuLi50aGlzLnN0YXRlLnBhcmFtZXRlcnMgfSwKICAgICAgICAgICAgbWFwcGVkUGFyYW1ldGVyczogdGhpcy5pc0luaXRpYWxpemVkKCkgPyB0aGlzLmdldE1hcHBlZFBhcmFtZXRlcnMoKSA6IG51bGwsCiAgICAgICAgICAgIHVwZGF0ZUNvdW50OiB0aGlzLnN0YXRlLm1ldGFkYXRhLnVwZGF0ZUNvdW50LAogICAgICAgICAgICBjb25maWc6IHsgLi4udGhpcy5jb25maWcgfQogICAgICAgIH07CiAgICB9CiAgICAKICAgIC8qKgogICAgICogQ2xlYW4gdXAgR1BVIHJlc291cmNlcwogICAgICovCiAgICBkZXN0cm95KCkgewogICAgICAgIGlmICh0aGlzLnN0YXRlLnVuaWZvcm1zLmJ1ZmZlcikgewogICAgICAgICAgICB0aGlzLnN0YXRlLnVuaWZvcm1zLmJ1ZmZlci5kZXN0cm95KCk7CiAgICAgICAgICAgIHRoaXMuc3RhdGUudW5pZm9ybXMuYnVmZmVyID0gbnVsbDsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgdGhpcy5zdGF0ZS51bmlmb3Jtcy5iaW5kR3JvdXAgPSBudWxsOwogICAgICAgIHRoaXMuc3RhdGUudW5pZm9ybXMubGF5b3V0ID0gbnVsbDsKICAgICAgICB0aGlzLnN0YXRlLm1ldGFkYXRhLmlzSW5pdGlhbGl6ZWQgPSBmYWxzZTsKICAgICAgICAKICAgICAgICB0aGlzLmxvZygnaW5mbycsIGBFZmZlY3QgZGVzdHJveWVkOiAke3RoaXMubmFtZX1gKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBIZWxwZXIgbWV0aG9kIGZvciBsb2dnaW5nCiAgICAgKi8KICAgIGxvZyhsZXZlbCwgbWVzc2FnZSwgZGF0YSA9IG51bGwpIHsKICAgICAgICBMb2dnZXJbbGV2ZWxdKCdFRkZFQ1QnLCBgWyR7dGhpcy5uYW1lfV0gJHttZXNzYWdlfWAsIGRhdGEpOwogICAgfQp9CgpFZmZlY3Q7CgoKLy8gVFZTdGF0aWNFZmZlY3QgLSBQcm9jZWR1cmFsbHkgZ2VuZXJhdGVkIFRWIHN0YXRpYyBzbm93Ci8vIFB1cmUgYmxhY2sgJiB3aGl0ZSBub2lzZSwgbm8gQ1JUIGFydGlmYWN0cywgb3B0aW1pemVkIGZvciA2MGZwcysKCmNsYXNzIFRWU3RhdGljRWZmZWN0IGV4dGVuZHMgRWZmZWN0IHsKICAgIGNvbnN0cnVjdG9yKCkgewogICAgICAgIHN1cGVyKDAsICdUViBTdGF0aWMnKTsKICAgICAgICAKICAgICAgICAvLyBFZmZlY3Qtc3BlY2lmaWMgY29uZmlndXJhdGlvbgogICAgICAgIHRoaXMuY29uZmlnID0gewogICAgICAgICAgICBpbnRlbnNpdHk6IDEuMCwgICAgICAgICAvLyBTdGF0aWMgaW50ZW5zaXR5ICgwLTEpCiAgICAgICAgICAgIHNwZWVkOiAxLjAsICAgICAgICAgICAgIC8vIEFuaW1hdGlvbiBzcGVlZCBtdWx0aXBsaWVyCiAgICAgICAgICAgIGNvbnRyYXN0OiAxLjUsICAgICAgICAgIC8vIENvbnRyYXN0IGJvb3N0IC0gcHVzaGVzIHRvIGJsYWNrL3doaXRlIGV4dHJlbWVzCiAgICAgICAgICAgIGJyaWdodG5lc3M6IDEuMCAgICAgICAgIC8vIE92ZXJhbGwgYnJpZ2h0bmVzcyAoMS4wID0gZnVsbCByYW5nZSkKICAgICAgICB9OwoKICAgICAgICAvLyBQcmUtYWxsb2NhdGVkIHVuaWZvcm0gYnVmZmVyIOKAlCByZXVzZWQgZXZlcnkgZnJhbWUgdG8gYXZvaWQgR0MgcHJlc3N1cmUKICAgICAgICB0aGlzLnVuaWZvcm1EYXRhID0gbmV3IEZsb2F0MzJBcnJheSgxMik7CiAgICAgICAgCiAgICAgICAgdGhpcy5sb2coJ2luZm8nLCAnVFZTdGF0aWNFZmZlY3QgY3JlYXRlZCB3aXRoIGNvbmZpZzonLCB0aGlzLmNvbmZpZyk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogTWFwIG5vcm1hbGl6ZWQgWFkgcGFyYW1ldGVycyB0byBzdGF0aWMtc3BlY2lmaWMgdmFsdWVzCiAgICAgKiBGb3IgUGhhc2UgQiwgWC9ZIGFyZSBub3QgdXNlZCAobm8gaW50ZXJhY3Rpb24geWV0KQogICAgICogVGltZSBpcyB0aGUgbWFpbiBwYXJhbWV0ZXIgZm9yIGFuaW1hdGlvbgogICAgICogQHBhcmFtIHtudW1iZXJ9IHggLSBOb3JtYWxpemVkIFggcGFyYW1ldGVyICgwLTEpIC0gdW51c2VkIGluIFBoYXNlIEIKICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5IC0gTm9ybWFsaXplZCBZIHBhcmFtZXRlciAoMC0xKSAtIHVudXNlZCBpbiBQaGFzZSBCCiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBTdGF0aWMtc3BlY2lmaWMgcGFyYW1ldGVyIHZhbHVlcwogICAgICovCiAgICBtYXBQYXJhbWV0ZXJzKHgsIHkpIHsKICAgICAgICByZXR1cm4gewogICAgICAgICAgICB0aW1lOiB0aGlzLnN0YXRlLnBhcmFtZXRlcnMudGltZSwKICAgICAgICAgICAgaW50ZW5zaXR5OiB0aGlzLmNvbmZpZy5pbnRlbnNpdHksCiAgICAgICAgICAgIHNwZWVkOiB0aGlzLmNvbmZpZy5zcGVlZCwKICAgICAgICAgICAgY29udHJhc3Q6IHRoaXMuY29uZmlnLmNvbnRyYXN0LAogICAgICAgICAgICBicmlnaHRuZXNzOiB0aGlzLmNvbmZpZy5icmlnaHRuZXNzLAogICAgICAgICAgICAvLyBSZXNvbHV0aW9uIHdpbGwgYmUgc2V0IGluIHdyaXRlVW5pZm9ybXMKICAgICAgICAgICAgcmVzb2x1dGlvblg6IDE5MjAsCiAgICAgICAgICAgIHJlc29sdXRpb25ZOiAxMDgwCiAgICAgICAgfTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBDcmVhdGUgR1BVIHVuaWZvcm0gYnVmZmVycyBmb3IgVFYgc3RhdGljIHBhcmFtZXRlcnMKICAgICAqIEBwYXJhbSB7R1BVRGV2aWNlfSBkZXZpY2UgLSBXZWJHUFUgZGV2aWNlCiAgICAgKi8KICAgIGFzeW5jIGNyZWF0ZVVuaWZvcm1zKGRldmljZSkgewogICAgICAgIHRyeSB7CiAgICAgICAgICAgIHRoaXMubG9nKCdkZWJ1ZycsICdDcmVhdGluZyBUViBzdGF0aWMgdW5pZm9ybSBidWZmZXJzLi4uJyk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBEZWZpbmUgdW5pZm9ybSBidWZmZXIgbGF5b3V0CiAgICAgICAgICAgIC8vIHN0cnVjdCBTdGF0aWNVbmlmb3JtcyB7CiAgICAgICAgICAgIC8vICAgICB0aW1lOiBmMzIsICAgICAgICAgICAvLyBDdXJyZW50IHRpbWUgZm9yIGFuaW1hdGlvbgogICAgICAgICAgICAvLyAgICAgaW50ZW5zaXR5OiBmMzIsICAgICAgLy8gU3RhdGljIGludGVuc2l0eQogICAgICAgICAgICAvLyAgICAgX3BhZDI6IGYzMiwgICAgICAgICAgLy8gcmVzZXJ2ZWQKICAgICAgICAgICAgLy8gICAgIHNwZWVkOiBmMzIsICAgICAgICAgIC8vIEFuaW1hdGlvbiBzcGVlZAogICAgICAgICAgICAvLyAgICAgY29udHJhc3Q6IGYzMiwgICAgICAgLy8gQ29udHJhc3QgbXVsdGlwbGllcgogICAgICAgICAgICAvLyAgICAgX3BhZDU6IGYzMiwgICAgICAgICAgLy8gcmVzZXJ2ZWQKICAgICAgICAgICAgLy8gICAgIGJyaWdodG5lc3M6IGYzMiwgICAgIC8vIE92ZXJhbGwgYnJpZ2h0bmVzcwogICAgICAgICAgICAvLyAgICAgcGFkZGluZzE6IGYzMiwgICAgICAgLy8gQWxpZ25tZW50IHBhZGRpbmcKICAgICAgICAgICAgLy8gICAgIHJlc29sdXRpb246IHZlYzI8ZjMyPiAvLyBTY3JlZW4gcmVzb2x1dGlvbiAoOCBieXRlcykKICAgICAgICAgICAgLy8gICAgIHBhZGRpbmcyOiB2ZWMyPGYzMj4gIC8vIEFsaWdubWVudCBwYWRkaW5nICg4IGJ5dGVzKQogICAgICAgICAgICAvLyB9CiAgICAgICAgICAgIC8vIFRvdGFsOiA0OCBieXRlcyAoYWxpZ25lZCB0byAxNikKICAgICAgICAgICAgY29uc3QgdW5pZm9ybUJ1ZmZlclNpemUgPSA0ODsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIENyZWF0ZSB1bmlmb3JtIGJ1ZmZlcgogICAgICAgICAgICB0aGlzLnN0YXRlLnVuaWZvcm1zLmJ1ZmZlciA9IGRldmljZS5jcmVhdGVCdWZmZXIoewogICAgICAgICAgICAgICAgc2l6ZTogdW5pZm9ybUJ1ZmZlclNpemUsCiAgICAgICAgICAgICAgICB1c2FnZTogR1BVQnVmZmVyVXNhZ2UuVU5JRk9STSB8IEdQVUJ1ZmZlclVzYWdlLkNPUFlfRFNULAogICAgICAgICAgICAgICAgbGFiZWw6ICdUViBTdGF0aWMgVW5pZm9ybXMnCiAgICAgICAgICAgIH0pOwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gQ3JlYXRlIGJpbmQgZ3JvdXAgbGF5b3V0IChncm91cCAwIGZvciB0aGlzIGVmZmVjdCkKICAgICAgICAgICAgdGhpcy5zdGF0ZS51bmlmb3Jtcy5sYXlvdXQgPSBkZXZpY2UuY3JlYXRlQmluZEdyb3VwTGF5b3V0KHsKICAgICAgICAgICAgICAgIGVudHJpZXM6IFt7CiAgICAgICAgICAgICAgICAgICAgYmluZGluZzogMCwKICAgICAgICAgICAgICAgICAgICB2aXNpYmlsaXR5OiBHUFVTaGFkZXJTdGFnZS5GUkFHTUVOVCB8IEdQVVNoYWRlclN0YWdlLlZFUlRFWCwKICAgICAgICAgICAgICAgICAgICBidWZmZXI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ3VuaWZvcm0nCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfV0sCiAgICAgICAgICAgICAgICBsYWJlbDogJ1RWIFN0YXRpYyBCaW5kIEdyb3VwIExheW91dCcKICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBDcmVhdGUgYmluZCBncm91cAogICAgICAgICAgICB0aGlzLnN0YXRlLnVuaWZvcm1zLmJpbmRHcm91cCA9IGRldmljZS5jcmVhdGVCaW5kR3JvdXAoewogICAgICAgICAgICAgICAgbGF5b3V0OiB0aGlzLnN0YXRlLnVuaWZvcm1zLmxheW91dCwKICAgICAgICAgICAgICAgIGVudHJpZXM6IFt7CiAgICAgICAgICAgICAgICAgICAgYmluZGluZzogMCwKICAgICAgICAgICAgICAgICAgICByZXNvdXJjZTogewogICAgICAgICAgICAgICAgICAgICAgICBidWZmZXI6IHRoaXMuc3RhdGUudW5pZm9ybXMuYnVmZmVyCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfV0sCiAgICAgICAgICAgICAgICBsYWJlbDogJ1RWIFN0YXRpYyBCaW5kIEdyb3VwJwogICAgICAgICAgICB9KTsKICAgICAgICAgICAgCiAgICAgICAgICAgIHRoaXMubG9nKCdpbmZvJywgJ1RWIHN0YXRpYyB1bmlmb3JtIGJ1ZmZlcnMgY3JlYXRlZCBzdWNjZXNzZnVsbHknKTsKICAgICAgICAgICAgCiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgICAgICAgdGhpcy5sb2coJ2Vycm9yJywgJ0ZhaWxlZCB0byBjcmVhdGUgVFYgc3RhdGljIHVuaWZvcm1zOicsIGVycm9yKTsKICAgICAgICAgICAgdGhyb3cgZXJyb3I7CiAgICAgICAgfQogICAgfQogICAgCiAgICAvKioKICAgICAqIFdyaXRlIHBhcmFtZXRlciB2YWx1ZXMgdG8gR1BVIHVuaWZvcm0gYnVmZmVyCiAgICAgKiBAcGFyYW0ge0dQVURldmljZX0gZGV2aWNlIC0gV2ViR1BVIGRldmljZQogICAgICogQHBhcmFtIHtPYmplY3R9IG1hcHBlZFBhcmFtcyAtIFN0YXRpYy1zcGVjaWZpYyBwYXJhbWV0ZXIgdmFsdWVzCiAgICAgKi8KICAgIHdyaXRlVW5pZm9ybXMoZGV2aWNlLCBtYXBwZWRQYXJhbXMpIHsKICAgICAgICB0cnkgewogICAgICAgICAgICAvLyBXcml0ZSBpbnRvIHByZS1hbGxvY2F0ZWQgYnVmZmVyIOKAlCBhdm9pZHMgcGVyLWZyYW1lIEZsb2F0MzJBcnJheSBhbGxvY2F0aW9uCiAgICAgICAgICAgIHRoaXMudW5pZm9ybURhdGFbMF0gID0gbWFwcGVkUGFyYW1zLnRpbWU7ICAgICAgICAgIC8vIHRpbWU6IGYzMgogICAgICAgICAgICB0aGlzLnVuaWZvcm1EYXRhWzFdICA9IG1hcHBlZFBhcmFtcy5pbnRlbnNpdHk7ICAgICAvLyBpbnRlbnNpdHk6IGYzMgogICAgICAgICAgICB0aGlzLnVuaWZvcm1EYXRhWzJdICA9IDAuMDsgICAgICAgICAgICAgICAgICAgICAgICAvLyBfcGFkMjogZjMyIChyZXNlcnZlZCkKICAgICAgICAgICAgdGhpcy51bmlmb3JtRGF0YVszXSAgPSBtYXBwZWRQYXJhbXMuc3BlZWQ7ICAgICAgICAgLy8gc3BlZWQ6IGYzMgogICAgICAgICAgICB0aGlzLnVuaWZvcm1EYXRhWzRdICA9IG1hcHBlZFBhcmFtcy5jb250cmFzdDsgICAgICAvLyBjb250cmFzdDogZjMyCiAgICAgICAgICAgIHRoaXMudW5pZm9ybURhdGFbNV0gID0gMC4wOyAgICAgICAgICAgICAgICAgICAgICAgIC8vIF9wYWQ1OiBmMzIgKHJlc2VydmVkKQogICAgICAgICAgICB0aGlzLnVuaWZvcm1EYXRhWzZdICA9IG1hcHBlZFBhcmFtcy5icmlnaHRuZXNzOyAgICAvLyBicmlnaHRuZXNzOiBmMzIKICAgICAgICAgICAgdGhpcy51bmlmb3JtRGF0YVs3XSAgPSAwLjA7ICAgICAgICAgICAgICAgICAgICAgICAgLy8gcGFkZGluZzE6IGYzMgogICAgICAgICAgICB0aGlzLnVuaWZvcm1EYXRhWzhdICA9IG1hcHBlZFBhcmFtcy5yZXNvbHV0aW9uWDsgICAvLyByZXNvbHV0aW9uLng6IGYzMgogICAgICAgICAgICB0aGlzLnVuaWZvcm1EYXRhWzldICA9IG1hcHBlZFBhcmFtcy5yZXNvbHV0aW9uWTsgICAvLyByZXNvbHV0aW9uLnk6IGYzMgogICAgICAgICAgICB0aGlzLnVuaWZvcm1EYXRhWzEwXSA9IDAuMDsgICAgICAgICAgICAgICAgICAgICAgICAvLyBwYWRkaW5nMi54OiBmMzIKICAgICAgICAgICAgdGhpcy51bmlmb3JtRGF0YVsxMV0gPSAwLjA7ICAgICAgICAgICAgICAgICAgICAgICAgLy8gcGFkZGluZzIueTogZjMyCiAgICAgICAgICAgIGNvbnN0IHVuaWZvcm1EYXRhID0gdGhpcy51bmlmb3JtRGF0YTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIFdyaXRlIHRvIEdQVSBidWZmZXIKICAgICAgICAgICAgZGV2aWNlLnF1ZXVlLndyaXRlQnVmZmVyKAogICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS51bmlmb3Jtcy5idWZmZXIsCiAgICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgICAgdW5pZm9ybURhdGEuYnVmZmVyCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIAogICAgICAgICAgICB0aGlzLnN0YXRlLnVuaWZvcm1zLm5lZWRzVXBkYXRlID0gZmFsc2U7CiAgICAgICAgICAgIAogICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgICAgICAgIHRoaXMubG9nKCdlcnJvcicsICdGYWlsZWQgdG8gd3JpdGUgVFYgc3RhdGljIHVuaWZvcm1zOicsIGVycm9yKTsKICAgICAgICAgICAgdGhyb3cgZXJyb3I7CiAgICAgICAgfQogICAgfQogICAgCiAgICAvKioKICAgICAqIEdldCBUViBzdGF0aWMtc3BlY2lmaWMgc3RhdGUgZm9yIGRlYnVnZ2luZwogICAgICogQHJldHVybnMge09iamVjdH0gRXh0ZW5kZWQgc3RhdGUgd2l0aCBzdGF0aWMgaW5mbwogICAgICovCiAgICBnZXRFZmZlY3RTdGF0ZSgpIHsKICAgICAgICBjb25zdCBiYXNlU3RhdGUgPSBzdXBlci5nZXRFZmZlY3RTdGF0ZSgpOwogICAgICAgIAogICAgICAgIHJldHVybiB7CiAgICAgICAgICAgIC4uLmJhc2VTdGF0ZSwKICAgICAgICAgICAgc3RhdGljQ29uZmlnOiB0aGlzLmNvbmZpZywKICAgICAgICAgICAgY3VycmVudFRpbWU6IHRoaXMuc3RhdGUucGFyYW1ldGVycy50aW1lLnRvRml4ZWQoMikKICAgICAgICB9OwogICAgfQp9CgpUVlN0YXRpY0VmZmVjdDsKCgovLyBQaXhlbGl6YXRpb25FZmZlY3QgLSBEeW5hbWljIHBpeGVsaXphdGlvbiBwb3N0LXByb2Nlc3NpbmcKLy8gWC1heGlzIGNvbnRyb2xzIHBpeGVsIGdyYW51bGFyaXR5ICh0dW5hYmxlIG1pbi9tYXggcm93cykKLy8gWS1heGlzIGNvbnRyb2xzIG9wYWNpdHkvYmxlbmQgKGJvdHRvbT1vcGFxdWUsIHRvcD10cmFuc3BhcmVudCkKLy8gQmFzZWQgb24gd2ViX0dQVV9taXhlci9lZmZlY3RzL2VmZmVjdHMvUGl4ZWxpemF0aW9uRWZmZWN0LmpzCgpjbGFzcyBQaXhlbGl6YXRpb25FZmZlY3QgZXh0ZW5kcyBFZmZlY3QgewogICAgY29uc3RydWN0b3IoKSB7CiAgICAgICAgc3VwZXIoMSwgJ1BpeGVsaXphdGlvbicpOwogICAgICAgIAogICAgICAgIC8vIEVmZmVjdC1zcGVjaWZpYyBtZXRhZGF0YQogICAgICAgIHRoaXMuc3RhdGUubWV0YWRhdGEgPSB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiAnRHluYW1pYyBwaXhlbGl6YXRpb24gd2l0aCBhZGp1c3RhYmxlIGdyaWQgc2l6ZScsCiAgICAgICAgICAgIHBhcmFtZXRlck5hbWVzOiB7IAogICAgICAgICAgICAgICAgeDogJ1BpeGVsIEdyYW51bGFyaXR5IChyb3dzKScsIAogICAgICAgICAgICAgICAgeTogJ09wYWNpdHkvQmxlbmQgKGJvdHRvbT1vcGFxdWUsIHRvcD10cmFuc3BhcmVudCknIAogICAgICAgICAgICB9LAogICAgICAgICAgICBpc0luaXRpYWxpemVkOiBmYWxzZSwKICAgICAgICAgICAgbGFzdFVwZGF0ZVRpbWU6IDAKICAgICAgICB9OwogICAgICAgIAogICAgICAgIC8vIFRVTkFCTEUgQ09ORklHVVJBVElPTgogICAgICAgIC8vIEFkanVzdCB0aGVzZSB2YWx1ZXMgdG8gY2hhbmdlIHBpeGVsaXphdGlvbiByYW5nZQogICAgICAgIHRoaXMuY29uZmlnID0gewogICAgICAgICAgICBtaW5QaXhlbFJvd3M6IDIsICAgICAgLy8gTGVmdCBvZiBYLWF4aXMgKHZlcnkgY2h1bmt5IC0gbGFyZ2UgcGl4ZWxzKQogICAgICAgICAgICBtYXhQaXhlbFJvd3M6IDExMSwgICAgIC8vIFJpZ2h0IG9mIFgtYXhpcyAoZmluZSAtIHNtYWxsIHBpeGVscykKICAgICAgICAgICAgZGVmYXVsdFBpeGVsUm93czogMjAgIC8vIFN0YXJ0aW5nIHZhbHVlIChtZWRpdW0gcGl4ZWxzKQogICAgICAgIH07CgogICAgICAgIC8vIFNldCBkZWZhdWx0IHBhcmFtZXRlcnMgdG8gY3JlYXRlIG1lZGl1bS1zaXplZCBwaXhlbHMgKFggY29udHJvbHMgZ3JhbnVsYXJpdHkgbm93KQogICAgICAgIGNvbnN0IGRlZmF1bHRYID0gKHRoaXMuY29uZmlnLmRlZmF1bHRQaXhlbFJvd3MgLSB0aGlzLmNvbmZpZy5taW5QaXhlbFJvd3MpIC8gCiAgICAgICAgICAgICAgICAgICAgICAgICh0aGlzLmNvbmZpZy5tYXhQaXhlbFJvd3MgLSB0aGlzLmNvbmZpZy5taW5QaXhlbFJvd3MpOwogICAgICAgIHRoaXMuc3RhdGUucGFyYW1ldGVycy54ID0gZGVmYXVsdFg7CiAgICAgICAgCiAgICAgICAgLy8gU2V0IGRlZmF1bHQgWSB0byBvcGFxdWUgKGJsZW5kIGZhY3RvciA9IDApCiAgICAgICAgdGhpcy5zdGF0ZS5wYXJhbWV0ZXJzLnkgPSAwOwoKICAgICAgICAvLyBQcmUtYWxsb2NhdGVkIHVuaWZvcm0gYnVmZmVyIOKAlCByZXVzZWQgZXZlcnkgZnJhbWUgdG8gYXZvaWQgR0MgcHJlc3N1cmUKICAgICAgICB0aGlzLnVuaWZvcm1EYXRhID0gbmV3IEZsb2F0MzJBcnJheSg4KTsKCiAgICAgICAgdGhpcy5sb2coJ2luZm8nLCBgQ3JlYXRlZCBQaXhlbGl6YXRpb25FZmZlY3Qgd2l0aCBjb25maWc6YCwgdGhpcy5jb25maWcpOwogICAgfQoKICAgIC8qKgogICAgICogTWFwIG5vcm1hbGl6ZWQgWFkgcGFyYW1ldGVycyB0byBwaXhlbGl6YXRpb24tc3BlY2lmaWMgdmFsdWVzCiAgICAgKiBAcGFyYW0ge251bWJlcn0geCAtIE5vcm1hbGl6ZWQgWCBwYXJhbWV0ZXIgKDAtMSkgLSBjb250cm9scyBwaXhlbCBncmFudWxhcml0eSAobGVmdD1jaHVua3ksIHJpZ2h0PWZpbmUpCiAgICAgKiBAcGFyYW0ge251bWJlcn0geSAtIE5vcm1hbGl6ZWQgWSBwYXJhbWV0ZXIgKDAtMSkgLSBjb250cm9scyBibGVuZC9vcGFjaXR5IChib3R0b209b3BhcXVlLCB0b3A9dHJhbnNwYXJlbnQpCiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBQaXhlbGl6YXRpb24tc3BlY2lmaWMgcGFyYW1ldGVyIHZhbHVlcwogICAgICovCiAgICBtYXBQYXJhbWV0ZXJzKHgsIHkpIHsKICAgICAgICAvLyBYIGNvbnRyb2xzIHBpeGVsIGdyYW51bGFyaXR5IHVzaW5nIExPR0FSSVRITUlDIHNjYWxpbmcgZm9yIG1vcmUgZ3JhZHVhbC9uYXR1cmFsIGZlZWwKICAgICAgICAvLyAwID0gbGFyZ2UgcGl4ZWxzIChtaW5QaXhlbFJvd3MpLCAxID0gc21hbGwgcGl4ZWxzIChtYXhQaXhlbFJvd3MpCiAgICAgICAgLy8gRm9ybXVsYTogcGl4ZWxSb3dzID0gbWluUGl4ZWxSb3dzICogKG1heFBpeGVsUm93cy9taW5QaXhlbFJvd3MpXngKICAgICAgICBjb25zdCBtaW5Sb3dzID0gdGhpcy5jb25maWcubWluUGl4ZWxSb3dzOwogICAgICAgIGNvbnN0IG1heFJvd3MgPSB0aGlzLmNvbmZpZy5tYXhQaXhlbFJvd3M7CiAgICAgICAgY29uc3QgcGl4ZWxSb3dzID0gbWluUm93cyAqIE1hdGgucG93KG1heFJvd3MgLyBtaW5Sb3dzLCB4KTsKICAgICAgICAKICAgICAgICAvLyBDYWxjdWxhdGUgcGl4ZWwgY29sdW1ucyB0byBtYWludGFpbiBzcXVhcmUgcGl4ZWxzIGJhc2VkIG9uIGNhbnZhcyBhc3BlY3QgcmF0aW8KICAgICAgICAvLyBUaGlzIHdpbGwgYmUgdXBkYXRlZCB3aGVuIHdlIGhhdmUgYWN0dWFsIGNhbnZhcyBkaW1lbnNpb25zCiAgICAgICAgY29uc3QgYXNwZWN0UmF0aW8gPSAxNiAvIDk7IC8vIERlZmF1bHQgYXNwZWN0IHJhdGlvLCB3aWxsIGJlIHVwZGF0ZWQgZnJvbSBjYW52YXMKICAgICAgICBjb25zdCBwaXhlbENvbHMgPSBNYXRoLnJvdW5kKHBpeGVsUm93cyAqIGFzcGVjdFJhdGlvKTsKICAgICAgICAKICAgICAgICAvLyBZIGNvbnRyb2xzIGJsZW5kIGZhY3RvcjogMCA9IHNvbGlkIG9wYXF1ZSBwaXhlbHMgKGJvdHRvbSksIDEgPSBmb2dneS90cmFuc3BhcmVudCAodG9wKQogICAgICAgIGNvbnN0IGJsZW5kRmFjdG9yID0geTsKICAgICAgICAKICAgICAgICByZXR1cm4gewogICAgICAgICAgICBwaXhlbFJvd3M6IE1hdGgucm91bmQocGl4ZWxSb3dzKSwKICAgICAgICAgICAgcGl4ZWxDb2xzOiBwaXhlbENvbHMsCiAgICAgICAgICAgIGJsZW5kRmFjdG9yOiBibGVuZEZhY3RvciwKICAgICAgICAgICAgZ3JhbnVsYXJpdHk6IHggLy8gTm9ybWFsaXplZCBncmFudWxhcml0eSBmb3IgZGVidWdnaW5nIChub3cgZnJvbSBYKQogICAgICAgIH07CiAgICB9CgogICAgLyoqCiAgICAgKiBDcmVhdGUgR1BVIHVuaWZvcm0gYnVmZmVycyBhbmQgYmluZCBncm91cCBsYXlvdXQgZm9yIHBpeGVsaXphdGlvbgogICAgICogQHBhcmFtIHtHUFVEZXZpY2V9IGRldmljZSAtIFdlYkdQVSBkZXZpY2UKICAgICAqLwogICAgYXN5bmMgY3JlYXRlVW5pZm9ybXMoZGV2aWNlKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgICAgdGhpcy5sb2coJ2RlYnVnJywgJ0NyZWF0aW5nIHBpeGVsaXphdGlvbiB1bmlmb3JtIGJ1ZmZlcnMuLi4nKTsKCiAgICAgICAgICAgIC8vIERlZmluZSB1bmlmb3JtIGJ1ZmZlciBsYXlvdXQgZm9yIHBpeGVsaXphdGlvbiBwYXJhbWV0ZXJzCiAgICAgICAgICAgIC8vIFN0cnVjdCBFZmZlY3RVbmlmb3JtcyB7CiAgICAgICAgICAgIC8vICAgICBwaXhlbFJvd3M6IGYzMiwKICAgICAgICAgICAgLy8gICAgIHBpeGVsQ29sczogZjMyLCAKICAgICAgICAgICAgLy8gICAgIGNhbnZhc1dpZHRoOiBmMzIsCiAgICAgICAgICAgIC8vICAgICBjYW52YXNIZWlnaHQ6IGYzMiwKICAgICAgICAgICAgLy8gICAgIGJsZW5kRmFjdG9yOiBmMzIsCiAgICAgICAgICAgIC8vICAgICB0aW1lOiBmMzIsCiAgICAgICAgICAgIC8vICAgICBfcGFkZGluZzE6IGYzMiwKICAgICAgICAgICAgLy8gICAgIF9wYWRkaW5nMjogZjMyLAogICAgICAgICAgICAvLyB9CiAgICAgICAgICAgIGNvbnN0IHVuaWZvcm1CdWZmZXJTaXplID0gOCAqIDQ7IC8vIDggZjMyIHZhbHVlcyAqIDQgYnl0ZXMgZWFjaCA9IDMyIGJ5dGVzCgogICAgICAgICAgICAvLyBDcmVhdGUgdW5pZm9ybSBidWZmZXIKICAgICAgICAgICAgdGhpcy5zdGF0ZS51bmlmb3Jtcy5idWZmZXIgPSBkZXZpY2UuY3JlYXRlQnVmZmVyKHsKICAgICAgICAgICAgICAgIHNpemU6IHVuaWZvcm1CdWZmZXJTaXplLAogICAgICAgICAgICAgICAgdXNhZ2U6IEdQVUJ1ZmZlclVzYWdlLlVOSUZPUk0gfCBHUFVCdWZmZXJVc2FnZS5DT1BZX0RTVCwKICAgICAgICAgICAgICAgIGxhYmVsOiAnUGl4ZWxpemF0aW9uIEVmZmVjdCBVbmlmb3JtcycKICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAvLyBDcmVhdGUgYmluZCBncm91cCBsYXlvdXQgZm9yIGVmZmVjdCB1bmlmb3JtcyAoZ3JvdXAgMSkKICAgICAgICAgICAgdGhpcy5zdGF0ZS51bmlmb3Jtcy5sYXlvdXQgPSBkZXZpY2UuY3JlYXRlQmluZEdyb3VwTGF5b3V0KHsKICAgICAgICAgICAgICAgIGVudHJpZXM6IFt7CiAgICAgICAgICAgICAgICAgICAgYmluZGluZzogMCwKICAgICAgICAgICAgICAgICAgICB2aXNpYmlsaXR5OiBHUFVTaGFkZXJTdGFnZS5GUkFHTUVOVCwKICAgICAgICAgICAgICAgICAgICBidWZmZXI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ3VuaWZvcm0nCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfV0sCiAgICAgICAgICAgICAgICBsYWJlbDogJ1BpeGVsaXphdGlvbiBFZmZlY3QgQmluZCBHcm91cCBMYXlvdXQnCiAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgLy8gQ3JlYXRlIGJpbmQgZ3JvdXAKICAgICAgICAgICAgdGhpcy5zdGF0ZS51bmlmb3Jtcy5iaW5kR3JvdXAgPSBkZXZpY2UuY3JlYXRlQmluZEdyb3VwKHsKICAgICAgICAgICAgICAgIGxheW91dDogdGhpcy5zdGF0ZS51bmlmb3Jtcy5sYXlvdXQsCiAgICAgICAgICAgICAgICBlbnRyaWVzOiBbewogICAgICAgICAgICAgICAgICAgIGJpbmRpbmc6IDAsCiAgICAgICAgICAgICAgICAgICAgcmVzb3VyY2U6IHsKICAgICAgICAgICAgICAgICAgICAgICAgYnVmZmVyOiB0aGlzLnN0YXRlLnVuaWZvcm1zLmJ1ZmZlcgogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH1dLAogICAgICAgICAgICAgICAgbGFiZWw6ICdQaXhlbGl6YXRpb24gRWZmZWN0IEJpbmQgR3JvdXAnCiAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgdGhpcy5sb2coJ2luZm8nLCAnUGl4ZWxpemF0aW9uIHVuaWZvcm0gYnVmZmVycyBjcmVhdGVkIHN1Y2Nlc3NmdWxseScpOwoKICAgICAgICB9IGNhdGNoIChlcnJvcikgewogICAgICAgICAgICB0aGlzLmxvZygnZXJyb3InLCAnRmFpbGVkIHRvIGNyZWF0ZSBwaXhlbGl6YXRpb24gdW5pZm9ybXM6JywgZXJyb3IpOwogICAgICAgICAgICB0aHJvdyBlcnJvcjsKICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBXcml0ZSBwYXJhbWV0ZXIgdmFsdWVzIHRvIEdQVSB1bmlmb3JtIGJ1ZmZlcgogICAgICogQHBhcmFtIHtHUFVEZXZpY2V9IGRldmljZSAtIFdlYkdQVSBkZXZpY2UKICAgICAqIEBwYXJhbSB7T2JqZWN0fSBtYXBwZWRQYXJhbXMgLSBQaXhlbGl6YXRpb24tc3BlY2lmaWMgcGFyYW1ldGVyIHZhbHVlcwogICAgICovCiAgICB3cml0ZVVuaWZvcm1zKGRldmljZSwgbWFwcGVkUGFyYW1zKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgICAgLy8gR2V0IGNhbnZhcyBkaW1lbnNpb25zICh3aWxsIGJlIHByb3ZpZGVkIGJ5IHJlbmRlcmVyKQogICAgICAgICAgICAvLyBGb3Igbm93LCB1c2UgZGVmYXVsdCBkaW1lbnNpb25zIC0gdGhpcyB3aWxsIGJlIHVwZGF0ZWQgd2hlbiBpbnRlZ3JhdGVkCiAgICAgICAgICAgIGNvbnN0IGNhbnZhc1dpZHRoID0gdGhpcy5jYW52YXNXaWR0aCB8fCAxOTIwOwogICAgICAgICAgICBjb25zdCBjYW52YXNIZWlnaHQgPSB0aGlzLmNhbnZhc0hlaWdodCB8fCAxMDgwOwoKICAgICAgICAgICAgLy8gUmVjYWxjdWxhdGUgcGl4ZWwgY29sdW1ucyBiYXNlZCBvbiBhY3R1YWwgY2FudmFzIGFzcGVjdCByYXRpbwogICAgICAgICAgICBjb25zdCBhc3BlY3RSYXRpbyA9IGNhbnZhc1dpZHRoIC8gY2FudmFzSGVpZ2h0OwogICAgICAgICAgICBjb25zdCBwaXhlbENvbHMgPSBNYXRoLnJvdW5kKG1hcHBlZFBhcmFtcy5waXhlbFJvd3MgKiBhc3BlY3RSYXRpbyk7CgogICAgICAgICAgICAvLyBXcml0ZSBpbnRvIHByZS1hbGxvY2F0ZWQgYnVmZmVyIOKAlCBhdm9pZHMgcGVyLWZyYW1lIEZsb2F0MzJBcnJheSBhbGxvY2F0aW9uCiAgICAgICAgICAgIHRoaXMudW5pZm9ybURhdGFbMF0gPSBtYXBwZWRQYXJhbXMucGl4ZWxSb3dzOyAgICAgIC8vIHBpeGVsUm93czogZjMyCiAgICAgICAgICAgIHRoaXMudW5pZm9ybURhdGFbMV0gPSBwaXhlbENvbHM7ICAgICAgICAgICAgICAgICAgIC8vIHBpeGVsQ29sczogZjMyCiAgICAgICAgICAgIHRoaXMudW5pZm9ybURhdGFbMl0gPSBjYW52YXNXaWR0aDsgICAgICAgICAgICAgICAgIC8vIGNhbnZhc1dpZHRoOiBmMzIKICAgICAgICAgICAgdGhpcy51bmlmb3JtRGF0YVszXSA9IGNhbnZhc0hlaWdodDsgICAgICAgICAgICAgICAgLy8gY2FudmFzSGVpZ2h0OiBmMzIKICAgICAgICAgICAgdGhpcy51bmlmb3JtRGF0YVs0XSA9IG1hcHBlZFBhcmFtcy5ibGVuZEZhY3RvcjsgICAgLy8gYmxlbmRGYWN0b3I6IGYzMiAoMD1zb2xpZCwgMT1mb2dneSkKICAgICAgICAgICAgdGhpcy51bmlmb3JtRGF0YVs1XSA9IHRoaXMuc3RhdGUucGFyYW1ldGVycy50aW1lOyAgLy8gdGltZTogZjMyCiAgICAgICAgICAgIHRoaXMudW5pZm9ybURhdGFbNl0gPSAwLjA7ICAgICAgICAgICAgICAgICAgICAgICAgIC8vIF9wYWRkaW5nMTogZjMyCiAgICAgICAgICAgIHRoaXMudW5pZm9ybURhdGFbN10gPSAwLjA7ICAgICAgICAgICAgICAgICAgICAgICAgIC8vIF9wYWRkaW5nMjogZjMyCiAgICAgICAgICAgIGNvbnN0IHVuaWZvcm1EYXRhID0gdGhpcy51bmlmb3JtRGF0YTsKCiAgICAgICAgICAgIC8vIFdyaXRlIHRvIEdQVSBidWZmZXIKICAgICAgICAgICAgZGV2aWNlLnF1ZXVlLndyaXRlQnVmZmVyKAogICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS51bmlmb3Jtcy5idWZmZXIsCiAgICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgICAgdW5pZm9ybURhdGEuYnVmZmVyCiAgICAgICAgICAgICk7CgogICA
XJyb3IpOwogICAgICAgICAgICB0aHJvdyBlcnJvcjsKICAgICAgICB9CiAgICB9CiAgICAKICAgIC8qKgogICAgICogQ29tcGlsZSBzaGFkZXIKICAgICAqIEBwYXJhbSB7V2ViR0wyUmVuZGVyaW5nQ29udGV4dH0gZ2wgLSBXZWJHTCBjb250ZXh0CiAgICAgKiBAcGFyYW0ge251bWJlcn0gdHlwZSAtIFNoYWRlciB0eXBlIChWRVJURVhfU0hBREVSIG9yIEZSQUdNRU5UX1NIQURFUikKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2UgLSBTaGFkZXIgc291cmNlIGNvZGUKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gU2hhZGVyIG5hbWUgZm9yIGRlYnVnZ2luZwogICAgICogQHJldHVybnMge1dlYkdMU2hhZGVyfSBDb21waWxlZCBzaGFkZXIKICAgICAqLwogICAgY29tcGlsZVNoYWRlcihnbCwgdHlwZSwgc291cmNlLCBuYW1lKSB7CiAgICAgICAgY29uc3Qgc2hhZGVyID0gZ2wuY3JlYXRlU2hhZGVyKHR5cGUpOwogICAgICAgIGdsLnNoYWRlclNvdXJjZShzaGFkZXIsIHNvdXJjZSk7CiAgICAgICAgZ2wuY29tcGlsZVNoYWRlcihzaGFkZXIpOwogICAgICAgIAogICAgICAgIGlmICghZ2wuZ2V0U2hhZGVyUGFyYW1ldGVyKHNoYWRlciwgZ2wuQ09NUElMRV9TVEFUVVMpKSB7CiAgICAgICAgICAgIGNvbnN0IGluZm8gPSBnbC5nZXRTaGFkZXJJbmZvTG9nKHNoYWRlcik7CiAgICAgICAgICAgIGdsLmRlbGV0ZVNoYWRlcihzaGFkZXIpOwogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7bmFtZX0gc2hhZGVyIGNvbXBpbGF0aW9uIGZhaWxlZDogJHtpbmZvfWApOwogICAgICAgIH0KICAgICAgICAKICAgICAgICByZXR1cm4gc2hhZGVyOwogICAgfQogICAgCiAgICAvKioKICAgICAqIEdldCBhbGwgdW5pZm9ybSBsb2NhdGlvbnMgZm9yIGEgcHJvZ3JhbQogICAgICogQHBhcmFtIHtXZWJHTDJSZW5kZXJpbmdDb250ZXh0fSBnbCAtIFdlYkdMIGNvbnRleHQKICAgICAqIEBwYXJhbSB7V2ViR0xQcm9ncmFtfSBwcm9ncmFtIC0gUHJvZ3JhbSB0byBnZXQgdW5pZm9ybXMgZnJvbQogICAgICogQHBhcmFtIHtFZmZlY3R9IGVmZmVjdCAtIEVmZmVjdCBpbnN0YW5jZQogICAgICogQHBhcmFtIHtib29sZWFufSBuZWVkc1RleHR1cmVJbnB1dCAtIFdoZXRoZXIgZWZmZWN0IG5lZWRzIHRleHR1cmUgaW5wdXQKICAgICAqIEByZXR1cm5zIHtPYmplY3R9IFVuaWZvcm0gbG9jYXRpb25zCiAgICAgKi8KICAgIGdldFVuaWZvcm1Mb2NhdGlvbnMoZ2wsIHByb2dyYW0sIGVmZmVjdCwgbmVlZHNUZXh0dXJlSW5wdXQpIHsKICAgICAgICBjb25zdCBsb2NhdGlvbnMgPSB7fTsKICAgICAgICAKICAgICAgICAvLyBHZXQgdW5pZm9ybSBjb3VudAogICAgICAgIGNvbnN0IG51bVVuaWZvcm1zID0gZ2wuZ2V0UHJvZ3JhbVBhcmFtZXRlcihwcm9ncmFtLCBnbC5BQ1RJVkVfVU5JRk9STVMpOwogICAgICAgIAogICAgICAgIC8vIEdldCBhbGwgdW5pZm9ybSBsb2NhdGlvbnMKICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG51bVVuaWZvcm1zOyBpKyspIHsKICAgICAgICAgICAgY29uc3QgaW5mbyA9IGdsLmdldEFjdGl2ZVVuaWZvcm0ocHJvZ3JhbSwgaSk7CiAgICAgICAgICAgIGlmIChpbmZvKSB7CiAgICAgICAgICAgICAgICBjb25zdCBsb2NhdGlvbiA9IGdsLmdldFVuaWZvcm1Mb2NhdGlvbihwcm9ncmFtLCBpbmZvLm5hbWUpOwogICAgICAgICAgICAgICAgbG9jYXRpb25zW2luZm8ubmFtZV0gPSBsb2NhdGlvbjsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAKICAgICAgICB0aGlzLmxvZygnZGVidWcnLCBgRm91bmQgJHtPYmplY3Qua2V5cyhsb2NhdGlvbnMpLmxlbmd0aH0gdW5pZm9ybXMgZm9yICR7ZWZmZWN0Lm5hbWV9YCk7CiAgICAgICAgCiAgICAgICAgcmV0dXJuIGxvY2F0aW9uczsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBDcmVhdGUgaW50ZXJtZWRpYXRlIHRleHR1cmUgZm9yIG11bHRpLXBhc3MgcmVuZGVyaW5nCiAgICAgKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBUZXh0dXJlIHdpZHRoCiAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gVGV4dHVyZSBoZWlnaHQKICAgICAqLwogICAgY3JlYXRlSW50ZXJtZWRpYXRlVGV4dHVyZSh3aWR0aCwgaGVpZ2h0KSB7CiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLmlzSW5pdGlhbGl6ZWQpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdSZW5kZXJlciBub3QgaW5pdGlhbGl6ZWQnKTsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgY29uc3QgZ2wgPSB0aGlzLnN0YXRlLmdsOwogICAgICAgIAogICAgICAgIC8vIERlbGV0ZSBleGlzdGluZyByZXNvdXJjZXMKICAgICAgICBpZiAodGhpcy5zdGF0ZS5tdWx0aXBhc3MuZnJhbWVidWZmZXIpIHsKICAgICAgICAgICAgZ2wuZGVsZXRlRnJhbWVidWZmZXIodGhpcy5zdGF0ZS5tdWx0aXBhc3MuZnJhbWVidWZmZXIpOwogICAgICAgICAgICBnbC5kZWxldGVUZXh0dXJlKHRoaXMuc3RhdGUubXVsdGlwYXNzLnRleHR1cmUpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICAvLyBDcmVhdGUgdGV4dHVyZQogICAgICAgIGNvbnN0IHRleHR1cmUgPSBnbC5jcmVhdGVUZXh0dXJlKCk7CiAgICAgICAgZ2wuYmluZFRleHR1cmUoZ2wuVEVYVFVSRV8yRCwgdGV4dHVyZSk7CiAgICAgICAgZ2wudGV4SW1hZ2UyRChnbC5URVhUVVJFXzJELCAwLCBnbC5SR0JBLCB3aWR0aCwgaGVpZ2h0LCAwLCBnbC5SR0JBLCBnbC5VTlNJR05FRF9CWVRFLCBudWxsKTsKICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfTUlOX0ZJTFRFUiwgZ2wuTElORUFSKTsKICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfTUFHX0ZJTFRFUiwgZ2wuTElORUFSKTsKICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfV1JBUF9TLCBnbC5DTEFNUF9UT19FREdFKTsKICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfV1JBUF9ULCBnbC5DTEFNUF9UT19FREdFKTsKICAgICAgICAKICAgICAgICAvLyBDcmVhdGUgZnJhbWVidWZmZXIKICAgICAgICBjb25zdCBmcmFtZWJ1ZmZlciA9IGdsLmNyZWF0ZUZyYW1lYnVmZmVyKCk7CiAgICAgICAgZ2wuYmluZEZyYW1lYnVmZmVyKGdsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlcik7CiAgICAgICAgZ2wuZnJhbWVidWZmZXJUZXh0dXJlMkQoZ2wuRlJBTUVCVUZGRVIsIGdsLkNPTE9SX0FUVEFDSE1FTlQwLCBnbC5URVhUVVJFXzJELCB0ZXh0dXJlLCAwKTsKICAgICAgICAKICAgICAgICAvLyBDaGVjayBmcmFtZWJ1ZmZlciBzdGF0dXMKICAgICAgICBjb25zdCBzdGF0dXMgPSBnbC5jaGVja0ZyYW1lYnVmZmVyU3RhdHVzKGdsLkZSQU1FQlVGRkVSKTsKICAgICAgICBpZiAoc3RhdHVzICE9PSBnbC5GUkFNRUJVRkZFUl9DT01QTEVURSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEZyYW1lYnVmZmVyIGluY29tcGxldGU6ICR7c3RhdHVzfWApOwogICAgICAgIH0KICAgICAgICAKICAgICAgICAvLyBVbmJpbmQKICAgICAgICBnbC5iaW5kRnJhbWVidWZmZXIoZ2wuRlJBTUVCVUZGRVIsIG51bGwpOwogICAgICAgIGdsLmJpbmRUZXh0dXJlKGdsLlRFWFRVUkVfMkQsIG51bGwpOwogICAgICAgIAogICAgICAgIC8vIFN0b3JlCiAgICAgICAgdGhpcy5zdGF0ZS5tdWx0aXBhc3MuZnJhbWVidWZmZXIgPSBmcmFtZWJ1ZmZlcjsKICAgICAgICB0aGlzLnN0YXRlLm11bHRpcGFzcy50ZXh0dXJlID0gdGV4dHVyZTsKICAgICAgICB0aGlzLnN0YXRlLm11bHRpcGFzcy53aWR0aCA9IHdpZHRoOwogICAgICAgIHRoaXMuc3RhdGUubXVsdGlwYXNzLmhlaWdodCA9IGhlaWdodDsKICAgICAgICAKICAgICAgICB0aGlzLmxvZygnaW5mbycsIGBJbnRlcm1lZGlhdGUgdGV4dHVyZSBjcmVhdGVkOiAke3dpZHRofXgke2hlaWdodH1gKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBTaW5nbGUtcGFzcyByZW5kZXJpbmc6IEVmZmVjdCBkaXJlY3RseSB0byBzY3JlZW4KICAgICAqIEBwYXJhbSB7RWZmZWN0fSBlZmZlY3QgLSBFZmZlY3QgdG8gcmVuZGVyCiAgICAgKiBAcGFyYW0ge251bWJlcn0gdGltZXN0YW1wIC0gQ3VycmVudCB0aW1lc3RhbXAKICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIENhbnZhcyB3aWR0aAogICAgICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIENhbnZhcyBoZWlnaHQKICAgICAqLwogICAgcmVuZGVyU2luZ2xlUGFzcyhlZmZlY3QsIHRpbWVzdGFtcCwgd2lkdGgsIGhlaWdodCkgewogICAgICAgIGNvbnN0IGdsID0gdGhpcy5zdGF0ZS5nbDsKICAgICAgICBjb25zdCBwcm9ncmFtSW5mbyA9IHRoaXMuc3RhdGUucHJvZ3JhbUluZm8uZ2V0KGVmZmVjdC5pZCk7CiAgICAgICAgCiAgICAgICAgaWYgKCFwcm9ncmFtSW5mbykgewogICAgICAgICAgICB0aGlzLmxvZygnd2FybicsIGBObyBwcm9ncmFtIGZvciBlZmZlY3QgJHtlZmZlY3QuaWR9YCk7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgLy8gVXNlIHByb2dyYW0KICAgICAgICBnbC51c2VQcm9ncmFtKHByb2dyYW1JbmZvLnByb2dyYW0pOwogICAgICAgIAogICAgICAgIC8vIFVwZGF0ZSB1bmlmb3JtcwogICAgICAgIGNvbnN0IG1hcHBlZFBhcmFtcyA9IGVmZmVjdC5nZXRNYXBwZWRQYXJhbWV0ZXJzKCk7CiAgICAgICAgbWFwcGVkUGFyYW1zLnJlc29sdXRpb25YID0gd2lkdGg7CiAgICAgICAgbWFwcGVkUGFyYW1zLnJlc29sdXRpb25ZID0gaGVpZ2h0OwogICAgICAgIAogICAgICAgIHRoaXMuc2V0VW5pZm9ybXMoZ2wsIHByb2dyYW1JbmZvLnVuaWZvcm1Mb2NhdGlvbnMsIG1hcHBlZFBhcmFtcywgZWZmZWN0KTsKICAgICAgICAKICAgICAgICAvLyBCaW5kIGZyYW1lYnVmZmVyIChudWxsID0gc2NyZWVuKQogICAgICAgIGdsLmJpbmRGcmFtZWJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgbnVsbCk7CiAgICAgICAgZ2wudmlld3BvcnQoMCwgMCwgd2lkdGgsIGhlaWdodCk7CiAgICAgICAgCiAgICAgICAgLy8gQ2xlYXIKICAgICAgICBnbC5jbGVhcihnbC5DT0xPUl9CVUZGRVJfQklUKTsKICAgICAgICAKICAgICAgICAvLyBEcmF3IGZ1bGxzY3JlZW4gdHJpYW5nbGUKICAgICAgICBnbC5iaW5kVmVydGV4QXJyYXkodGhpcy5zdGF0ZS5xdWFkLnZhbyk7CiAgICAgICAgZ2wuZHJhd0FycmF5cyhnbC5UUklBTkdMRVMsIDAsIDMpOwogICAgICAgIGdsLmJpbmRWZXJ0ZXhBcnJheShudWxsKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBNdWx0aS1wYXNzIHJlbmRlcmluZzogRmlyc3QgZWZmZWN0IOKGkiBUZXh0dXJlIOKGkiBTZWNvbmQgZWZmZWN0IOKGkiBTY3JlZW4KICAgICAqIEBwYXJhbSB7RWZmZWN0fSBmaXJzdEVmZmVjdCAtIEZpcnN0IGVmZmVjdCAoZS5nLiwgVFYgc3RhdGljKQogICAgICogQHBhcmFtIHtFZmZlY3R9IHNlY29uZEVmZmVjdCAtIFNlY29uZCBlZmZlY3QgKGUuZy4sIHBpeGVsaXphdGlvbikKICAgICAqIEBwYXJhbSB7bnVtYmVyfSB0aW1lc3RhbXAgLSBDdXJyZW50IHRpbWVzdGFtcAogICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gQ2FudmFzIHdpZHRoCiAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gQ2FudmFzIGhlaWdodAogICAgICovCiAgICByZW5kZXJNdWx0aVBhc3MoZmlyc3RFZmZlY3QsIHNlY29uZEVmZmVjdCwgdGltZXN0YW1wLCB3aWR0aCwgaGVpZ2h0KSB7CiAgICAgICAgY29uc3QgZ2wgPSB0aGlzLnN0YXRlLmdsOwogICAgICAgIAogICAgICAgIGNvbnN0IGZpcnN0UHJvZ3JhbUluZm8gPSB0aGlzLnN0YXRlLnByb2dyYW1JbmZvLmdldChmaXJzdEVmZmVjdC5pZCk7CiAgICAgICAgY29uc3Qgc2Vjb25kUHJvZ3JhbUluZm8gPSB0aGlzLnN0YXRlLnByb2dyYW1JbmZvLmdldChzZWNvbmRFZmZlY3QuaWQpOwogICAgICAgIAogICAgICAgIGlmICghZmlyc3RQcm9ncmFtSW5mbyB8fCAhc2Vjb25kUHJvZ3JhbUluZm8pIHsKICAgICAgICAgICAgdGhpcy5sb2coJ3dhcm4nLCAnTWlzc2luZyBwcm9ncmFtIGZvciBtdWx0aS1wYXNzIHJlbmRlcmluZycpOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIAogICAgICAgIC8vIFBBU1MgMTogUmVuZGVyIGZpcnN0IGVmZmVjdCB0byB0ZXh0dXJlCiAgICAgICAgewogICAgICAgICAgICBnbC51c2VQcm9ncmFtKGZpcnN0UHJvZ3JhbUluZm8ucHJvZ3JhbSk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBVcGRhdGUgdW5pZm9ybXMKICAgICAgICAgICAgY29uc3QgZmlyc3RQYXJhbXMgPSBmaXJzdEVmZmVjdC5nZXRNYXBwZWRQYXJhbWV0ZXJzKCk7CiAgICAgICAgICAgIGZpcnN0UGFyYW1zLnJlc29sdXRpb25YID0gd2lkdGg7CiAgICAgICAgICAgIGZpcnN0UGFyYW1zLnJlc29sdXRpb25ZID0gaGVpZ2h0OwogICAgICAgICAgICB0aGlzLnNldFVuaWZvcm1zKGdsLCBmaXJzdFByb2dyYW1JbmZvLnVuaWZvcm1Mb2NhdGlvbnMsIGZpcnN0UGFyYW1zLCBmaXJzdEVmZmVjdCk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBSZW5kZXIgdG8gZnJhbWVidWZmZXIKICAgICAgICAgICAgZ2wuYmluZEZyYW1lYnVmZmVyKGdsLkZSQU1FQlVGRkVSLCB0aGlzLnN0YXRlLm11bHRpcGFzcy5mcmFtZWJ1ZmZlcik7CiAgICAgICAgICAgIGdsLnZpZXdwb3J0KDAsIDAsIHdpZHRoLCBoZWlnaHQpOwogICAgICAgICAgICBnbC5jbGVhcihnbC5DT0xPUl9CVUZGRVJfQklUKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIERyYXcKICAgICAgICAgICAgZ2wuYmluZFZlcnRleEFycmF5KHRoaXMuc3RhdGUucXVhZC52YW8pOwogICAgICAgICAgICBnbC5kcmF3QXJyYXlzKGdsLlRSSUFOR0xFUywgMCwgMyk7CiAgICAgICAgICAgIGdsLmJpbmRWZXJ0ZXhBcnJheShudWxsKTsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgLy8gUEFTUyAyOiBSZW5kZXIgc2Vjb25kIGVmZmVjdCAod2l0aCB0ZXh0dXJlIGlucHV0KSB0byBzY3JlZW4KICAgICAgICB7CiAgICAgICAgICAgIGdsLnVzZVByb2dyYW0oc2Vjb25kUHJvZ3JhbUluZm8ucHJvZ3JhbSk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBCaW5kIGlucHV0IHRleHR1cmUKICAgICAgICAgICAgZ2wuYWN0aXZlVGV4dHVyZShnbC5URVhUVVJFMCk7CiAgICAgICAgICAgIGdsLmJpbmRUZXh0dXJlKGdsLlRFWFRVUkVfMkQsIHRoaXMuc3RhdGUubXVsdGlwYXNzLnRleHR1cmUpOwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gVXBkYXRlIHVuaWZvcm1zCiAgICAgICAgICAgIGNvbnN0IHNlY29uZFBhcmFtcyA9IHNlY29uZEVmZmVjdC5nZXRNYXBwZWRQYXJhbWV0ZXJzKCk7CiAgICAgICAgICAgIGlmIChzZWNvbmRFZmZlY3QudXBkYXRlQ2FudmFzRGltZW5zaW9ucykgewogICAgICAgICAgICAgICAgc2Vjb25kRWZmZWN0LnVwZGF0ZUNhbnZhc0RpbWVuc2lvbnMod2lkdGgsIGhlaWdodCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIFNldCB0ZXh0dXJlIHVuaWZvcm0KICAgICAgICAgICAgY29uc3QgaW5wdXRUZXh0dXJlTG9jYXRpb24gPSBzZWNvbmRQcm9ncmFtSW5mby51bmlmb3JtTG9jYXRpb25zWydpbnB1dFRleHR1cmUnXTsKICAgICAgICAgICAgaWYgKGlucHV0VGV4dHVyZUxvY2F0aW9uKSB7CiAgICAgICAgICAgICAgICBnbC51bmlmb3JtMWkoaW5wdXRUZXh0dXJlTG9jYXRpb24sIDApOwogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICB0aGlzLnNldFVuaWZvcm1zKGdsLCBzZWNvbmRQcm9ncmFtSW5mby51bmlmb3JtTG9jYXRpb25zLCBzZWNvbmRQYXJhbXMsIHNlY29uZEVmZmVjdCk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBSZW5kZXIgdG8gc2NyZWVuCiAgICAgICAgICAgIGdsLmJpbmRGcmFtZWJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgbnVsbCk7CiAgICAgICAgICAgIGdsLnZpZXdwb3J0KDAsIDAsIHdpZHRoLCBoZWlnaHQpOwogICAgICAgICAgICBnbC5jbGVhcihnbC5DT0xPUl9CVUZGRVJfQklUKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIERyYXcKICAgICAgICAgICAgZ2wuYmluZFZlcnRleEFycmF5KHRoaXMuc3RhdGUucXVhZC52YW8pOwogICAgICAgICAgICBnbC5kcmF3QXJyYXlzKGdsLlRSSUFOR0xFUywgMCwgMyk7CiAgICAgICAgICAgIGdsLmJpbmRWZXJ0ZXhBcnJheShudWxsKTsKICAgICAgICB9CiAgICB9CiAgICAKICAgIC8qKgogICAgICogU2V0IHVuaWZvcm1zIGZyb20gbWFwcGVkIHBhcmFtZXRlcnMKICAgICAqIEBwYXJhbSB7V2ViR0wyUmVuZGVyaW5nQ29udGV4dH0gZ2wgLSBXZWJHTCBjb250ZXh0CiAgICAgKiBAcGFyYW0ge09iamVjdH0gbG9jYXRpb25zIC0gVW5pZm9ybSBsb2NhdGlvbnMKICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwYXJhbXMgLSBQYXJhbWV0ZXIgdmFsdWVzCiAgICAgKiBAcGFyYW0ge0VmZmVjdH0gZWZmZWN0IC0gRWZmZWN0IGluc3RhbmNlIChmb3IgYWNjZXNzaW5nIGluc3RhbmNlIHZhcmlhYmxlcykKICAgICAqLwogICAgc2V0VW5pZm9ybXMoZ2wsIGxvY2F0aW9ucywgcGFyYW1zLCBlZmZlY3QgPSBudWxsKSB7CiAgICAgICAgZm9yIChjb25zdCBbbmFtZSwgbG9jYXRpb25dIG9mIE9iamVjdC5lbnRyaWVzKGxvY2F0aW9ucykpIHsKICAgICAgICAgICAgaWYgKCFsb2NhdGlvbikgY29udGludWU7CiAgICAgICAgICAgIAogICAgICAgICAgICBsZXQgdmFsdWUgPSBwYXJhbXNbbmFtZV07CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBIYW5kbGUgcmVzb2x1dGlvbiAoZm9yIFRWIHN0YXRpYyBlZmZlY3QpCiAgICAgICAgICAgIGlmIChuYW1lID09PSAncmVzb2x1dGlvbicgJiYgcGFyYW1zLnJlc29sdXRpb25YICE9PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0yZihsb2NhdGlvbiwgcGFyYW1zLnJlc29sdXRpb25YLCBwYXJhbXMucmVzb2x1dGlvblkpOwogICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIEhhbmRsZSBjYW52YXMgZGltZW5zaW9ucyBmcm9tIGVmZmVjdCBpbnN0YW5jZSAoZm9yIHBpeGVsaXphdGlvbikKICAgICAgICAgICAgaWYgKG5hbWUgPT09ICdjYW52YXNXaWR0aCcgJiYgZWZmZWN0ICYmIGVmZmVjdC5jYW52YXNXaWR0aCAhPT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICAgICAgICBnbC51bmlmb3JtMWYobG9jYXRpb24sIGVmZmVjdC5jYW52YXNXaWR0aCk7CiAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAobmFtZSA9PT0gJ2NhbnZhc0hlaWdodCcgJiYgZWZmZWN0ICYmIGVmZmVjdC5jYW52YXNIZWlnaHQgIT09IHVuZGVmaW5lZCkgewogICAgICAgICAgICAgICAgZ2wudW5pZm9ybTFmKGxvY2F0aW9uLCBlZmZlY3QuY2FudmFzSGVpZ2h0KTsKICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBIYW5kbGUgcGl4ZWxDb2xzIGNhbGN1bGF0aW9uIChmb3IgcGl4ZWxpemF0aW9uKQogICAgICAgICAgICBpZiAobmFtZSA9PT0gJ3BpeGVsQ29scycgJiYgZWZmZWN0ICYmIGVmZmVjdC5jYW52YXNXaWR0aCAmJiBlZmZlY3QuY2FudmFzSGVpZ2h0ICYmIHBhcmFtcy5waXhlbFJvd3MpIHsKICAgICAgICAgICAgICAgIGNvbnN0IGFzcGVjdFJhdGlvID0gZWZmZWN0LmNhbnZhc1dpZHRoIC8gZWZmZWN0LmNhbnZhc0hlaWdodDsKICAgICAgICAgICAgICAgIGNvbnN0IHBpeGVsQ29scyA9IE1hdGgucm91bmQocGFyYW1zLnBpeGVsUm93cyAqIGFzcGVjdFJhdGlvKTsKICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0xZihsb2NhdGlvbiwgcGl4ZWxDb2xzKTsKICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBIYW5kbGUgdGltZSBmcm9tIGVmZmVjdCBpbnN0YW5jZQogICAgICAgICAgICBpZiAobmFtZSA9PT0gJ3RpbWUnICYmIHZhbHVlID09PSB1bmRlZmluZWQgJiYgZWZmZWN0ICYmIGVmZmVjdC5zdGF0ZSAmJiBlZmZlY3Quc3RhdGUucGFyYW1ldGVycykgewogICAgICAgICAgICAgICAgdmFsdWUgPSBlZmZlY3Quc3RhdGUucGFyYW1ldGVycy50aW1lOwogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkgY29udGludWU7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBTZXQgdW5pZm9ybSBiYXNlZCBvbiB0eXBlCiAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSB7CiAgICAgICAgICAgICAgICBnbC51bmlmb3JtMWYobG9jYXRpb24sIHZhbHVlKTsKICAgICAgICAgICAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkgewogICAgICAgICAgICAgICAgaWYgKHZhbHVlLmxlbmd0aCA9PT0gMikgewogICAgICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0yZihsb2NhdGlvbiwgdmFsdWVbMF0sIHZhbHVlWzFdKTsKICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodmFsdWUubGVuZ3RoID09PSAzKSB7CiAgICAgICAgICAgICAgICAgICAgZ2wudW5pZm9ybTNmKGxvY2F0aW9uLCB2YWx1ZVswXSwgdmFsdWVbMV0sIHZhbHVlWzJdKTsKICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodmFsdWUubGVuZ3RoID09PSA0KSB7CiAgICAgICAgICAgICAgICAgICAgZ2wudW5pZm9ybTRmKGxvY2F0aW9uLCB2YWx1ZVswXSwgdmFsdWVbMV0sIHZhbHVlWzJdLCB2YWx1ZVszXSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0gZWxzZSBpZiAodmFsdWUubGVuZ3RoICE9PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgIC8vIEhhbmRsZSBhcnJheS1saWtlIG9iamVjdHMKICAgICAgICAgICAgICAgIGlmICh2YWx1ZS5sZW5ndGggPT09IDIpIHsKICAgICAgICAgICAgICAgICAgICBnbC51bmlmb3JtMmYobG9jYXRpb24sIHZhbHVlWzBdLCB2YWx1ZVsxXSk7CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlLmxlbmd0aCA9PT0gMykgewogICAgICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0zZihsb2NhdGlvbiwgdmFsdWVbMF0sIHZhbHVlWzFdLCB2YWx1ZVsyXSk7CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlLmxlbmd0aCA9PT0gNCkgewogICAgICAgICAgICAgICAgICAgIGdsLnVuaWZvcm00Zihsb2NhdGlvbiwgdmFsdWVbMF0sIHZhbHVlWzFdLCB2YWx1ZVsyXSwgdmFsdWVbM10pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQogICAgCiAgICAvKioKICAgICAqIEhhbmRsZSBjYW52YXMgcmVzaXplCiAgICAgKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBOZXcgd2lkdGgKICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBOZXcgaGVpZ2h0CiAgICAgKi8KICAgIHJlc2l6ZSh3aWR0aCwgaGVpZ2h0KSB7CiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLmlzSW5pdGlhbGl6ZWQpIHJldHVybjsKICAgICAgICAKICAgICAgICBjb25zdCBnbCA9IHRoaXMuc3RhdGUuZ2w7CiAgICAgICAgCiAgICAgICAgLy8gVXBkYXRlIHZpZXdwb3J0CiAgICAgICAgZ2wudmlld3BvcnQoMCwgMCwgd2lkdGgsIGhlaWdodCk7CiAgICAgICAgCiAgICAgICAgLy8gUmVjcmVhdGUgaW50ZXJtZWRpYXRlIHRleHR1cmUgd2l0aCBuZXcgc2l6ZQogICAgICAgIHRoaXMuY3JlYXRlSW50ZXJtZWRpYXRlVGV4dHVyZSh3aWR0aCwgaGVpZ2h0KTsKICAgICAgICAKICAgICAgICB0aGlzLmxvZygnZGVidWcnLCBgUmVzaXplZCB0byAke3dpZHRofXgke2hlaWdodH1gKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBHZXQgcmVuZGVyZXIgc3RhdGUgZm9yIGRlYnVnZ2luZwogICAgICogQHJldHVybnMge09iamVjdH0gQ3VycmVudCBzdGF0ZQogICAgICovCiAgICBnZXRTdGF0ZSgpIHsKICAgICAgICByZXR1cm4gewogICAgICAgICAgICAuLi5zdXBlci5nZXRTdGF0ZSgpLAogICAgICAgICAgICBwcm9ncmFtc0NyZWF0ZWQ6IHRoaXMuc3RhdGUucHJvZ3JhbXMuc2l6ZSwKICAgICAgICAgICAgZWZmZWN0c1JlZ2lzdGVyZWQ6IHRoaXMuc3RhdGUuZWZmZWN0cy5zaXplLAogICAgICAgICAgICBoYXNJbnRlcm1lZGlhdGVUZXh0dXJlOiB0aGlzLnN0YXRlLm11bHRpcGFzcy50ZXh0dXJlICE9PSBudWxsCiAgICAgICAgfTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBDbGVhbiB1cCBXZWJHTCByZXNvdXJjZXMKICAgICAqLwogICAgZGVzdHJveSgpIHsKICAgICAgICB0aGlzLmxvZygnaW5mbycsICdEZXN0cm95aW5nIFdlYkdMIHJlbmRlcmVyLi4uJyk7CiAgICAgICAgCiAgICAgICAgY29uc3QgZ2wgPSB0aGlzLnN0YXRlLmdsOwogICAgICAgIAogICAgICAgIGlmICghZ2wpIHJldHVybjsKICAgICAgICAKICAgICAgICAvLyBEZWxldGUgcHJvZ3JhbXMKICAgICAgICBmb3IgKGNvbnN0IHByb2dyYW0gb2YgdGhpcy5zdGF0ZS5wcm9ncmFtcy52YWx1ZXMoKSkgewogICAgICAgICAgICBnbC5kZWxldGVQcm9ncmFtKHByb2dyYW0pOwogICAgICAgIH0KICAgICAgICAKICAgICAgICAvLyBEZWxldGUgZnJhbWVidWZmZXIgYW5kIHRleHR1cmUKICAgICAgICBpZiAodGhpcy5zdGF0ZS5tdWx0aXBhc3MuZnJhbWVidWZmZXIpIHsKICAgICAgICAgICAgZ2wuZGVsZXRlRnJhbWVidWZmZXIodGhpcy5zdGF0ZS5tdWx0aXBhc3MuZnJhbWVidWZmZXIpOwogICAgICAgIH0KICAgICAgICBpZiAodGhpcy5zdGF0ZS5tdWx0aXBhc3MudGV4dHVyZSkgewogICAgICAgICAgICBnbC5kZWxldGVUZXh0dXJlKHRoaXMuc3RhdGUubXVsdGlwYXNzLnRleHR1cmUpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICAvLyBEZWxldGUgVkFPCiAgICAgICAgaWYgKHRoaXMuc3RhdGUucXVhZC52YW8pIHsKICAgICAgICAgICAgZ2wuZGVsZXRlVmVydGV4QXJyYXkodGhpcy5zdGF0ZS5xdWFkLnZhbyk7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIC8vIENsZWFyIHN0YXRlCiAgICAgICAgdGhpcy5zdGF0ZS5wcm9ncmFtcy5jbGVhcigpOwogICAgICAgIHRoaXMuc3RhdGUucHJvZ3JhbUluZm8uY2xlYXIoKTsKICAgICAgICB0aGlzLnN0YXRlLmVmZmVjdHMuY2xlYXIoKTsKICAgICAgICB0aGlzLnN0YXRlLmlzSW5pdGlhbGl6ZWQgPSBmYWxzZTsKICAgICAgICAKICAgICAgICB0aGlzLmxvZygnaW5mbycsICdXZWJHTCByZW5kZXJlciBkZXN0cm95ZWQnKTsKICAgIH0KfQoKV2ViR0xSZW5kZXJlcjsKCgovLyBSZW5kZXJlckZhY3RvcnkuanMgLSBBdXRvbWF0aWMgcmVuZGVyZXIgZGV0ZWN0aW9uIGFuZCBpbnN0YW50aWF0aW9uCi8vIERldGVjdHMgR1BVIGNhcGFiaWxpdGllcyBhbmQgY3JlYXRlcyB0aGUgYmVzdCBhdmFpbGFibGUgcmVuZGVyZXIKLy8gUHJpb3JpdHk6IFdlYkdQVSA+IFdlYkdMIDIuMCA+IEVycm9yCgpjbGFzcyBSZW5kZXJlckZhY3RvcnkgewogICAgLyoqCiAgICAgKiBEZXRlY3QgYmVzdCBhdmFpbGFibGUgcmVuZGVyZXIgYW5kIGNyZWF0ZSBpbnN0YW5jZQogICAgICogUHJpb3JpdHk6IFdlYkdQVSA+IFdlYkdMIDIuMAogICAgICogQHBhcmFtIHtIVE1MQ2FudmFzRWxlbWVudH0gY2FudmFzIC0gVGFyZ2V0IGNhbnZhcwogICAgICogQHJldHVybnMge1Byb21pc2U8SVJlbmRlcmVyPn0gSW5pdGlhbGl6ZWQgcmVuZGVyZXIKICAgICAqLwogICAgc3RhdGljIGFzeW5jIGNyZWF0ZVJlbmRlcmVyKGNhbnZhcykgewogICAgICAgIExvZ2dlci5pbmZvKCdSRU5ERVJFUicsICdEZXRlY3RpbmcgR1BVIGNhcGFiaWxpdGllcy4uLicpOwogICAgICAgIAogICAgICAgIC8vIEdldCBhdmFpbGFibGUgcmVuZGVyZXJzCiAgICAgICAgY29uc3QgYXZhaWxhYmxlID0gYXdhaXQgUmVuZGVyZXJGYWN0b3J5LmdldEF2YWlsYWJsZVJlbmRlcmVycyhjYW52YXMpOwogICAgICAgIExvZ2dlci5pbmZvKCdSRU5ERVJFUicsICdBdmFpbGFibGUgcmVuZGVyZXJzOicsIGF2YWlsYWJsZSk7CiAgICAgICAgCiAgICAgICAgLy8gVHJ5IFdlYkdQVSBmaXJzdCAoYmVzdCBwZXJmb3JtYW5jZSkKICAgICAgICBpZiAoYXZhaWxhYmxlLndlYmdwdSkgewogICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgICAgTG9nZ2VyLmluZm8oJ1JFTkRFUkVSJywgJ1dlYkdQVSBkZXRlY3RlZCAtIGF0dGVtcHRpbmcgdG8gaW5pdGlhbGl6ZSBXZWJHUFUgcmVuZGVyZXIuLi4nKTsKICAgICAgICAgICAgICAgIGNvbnN0IHJlbmRlcmVyID0gbmV3IFdlYkdQVVJlbmRlcmVyKCk7CiAgICAgICAgICAgICAgICAvLyBQYXNzIHRoZSBhbHJlYWR5LW9idGFpbmVkIGFkYXB0ZXIgdG8gYXZvaWQgYSBzZWNvbmQgcmVxdWVzdEFkYXB0ZXIoKSBjYWxsCiAgICAgICAgICAgICAgICBhd2FpdCByZW5kZXJlci5pbml0aWFsaXplKGNhbnZhcywgYXZhaWxhYmxlLndlYmdwdUFkYXB0ZXIpOwogICAgICAgICAgICAgICAgTG9nZ2VyLmluZm8oJ1JFTkRFUkVSJywgJ+KckyBXZWJHUFUgcmVuZGVyZXIgaW5pdGlhbGl6ZWQgc3VjY2Vzc2Z1bGx5Jyk7CiAgICAgICAgICAgICAgICByZXR1cm4gcmVuZGVyZXI7CiAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgICAgICAgICAgICBMb2dnZXIud2FybignUkVOREVSRVInLCAnV2ViR1BVIGluaXRpYWxpemF0aW9uIGZhaWxlZDonLCBlcnJvci5tZXNzYWdlKTsKICAgICAgICAgICAgICAgIExvZ2dlci5pbmZvKCdSRU5ERVJFUicsICdGYWxsaW5nIGJhY2sgdG8gV2ViR0wgMi4wLi4uJyk7CiAgICAgICAgICAgICAgICAvLyBDb250aW51ZSB0byBXZWJHTCBmYWxsYmFjayBiZWxvdwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIAogICAgICAgIC8vIEZhbGwgYmFjayB0byBXZWJHTCAyLjAKICAgICAgICBpZiAoYXZhaWxhYmxlLndlYmdsMikgewogICAgICAgICAgICBMb2dnZXIuaW5mbygnUkVOREVSRVInLCAnSW5pdGlhbGl6aW5nIFdlYkdMIDIuMCByZW5kZXJlci4uLicpOwogICAgICAgICAgICBjb25zdCByZW5kZXJlciA9IG5ldyBXZWJHTFJlbmRlcmVyKCk7CiAgICAgICAgICAgIGF3YWl0IHJlbmRlcmVyLmluaXRpYWxpemUoY2FudmFzKTsKICAgICAgICAgICAgTG9nZ2VyLmluZm8oJ1JFTkRFUkVSJywgJ+KckyBXZWJHTCAyLjAgcmVuZGVyZXIgaW5pdGlhbGl6ZWQgc3VjY2Vzc2Z1bGx5Jyk7CiAgICAgICAgICAgIHJldHVybiByZW5kZXJlcjsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgLy8gTm8gc3VwcG9ydGVkIHJlbmRlcmVyCiAgICAgICAgTG9nZ2VyLmVycm9yKCdSRU5ERVJFUicsICdOZWl0aGVyIFdlYkdQVSBub3IgV2ViR0wgMi4wIHN1cHBvcnRlZCcpOwogICAgICAgIHRocm93IG5ldyBFcnJvcignTmVpdGhlciBXZWJHUFUgbm9yIFdlYkdMIDIuMCBzdXBwb3J0ZWQgaW4gdGhpcyBicm93c2VyLiBQbGVhc2UgdXBkYXRlIHlvdXIgYnJvd3Nlci4nKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBDaGVjayBpZiBXZWJHUFUgaXMgYXZhaWxhYmxlIGFuZCB3b3JraW5nCiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gVHJ1ZSBpZiBXZWJHUFUgYXZhaWxhYmxlCiAgICAgKi8KICAgIC8qKgogICAgICogUmV0dXJucyB0aGUgbGl2ZSBHUFVBZGFwdGVyIGlmIFdlYkdQVSBpcyBhdmFpbGFibGUsIG9yIG51bGwgaWYgbm90LgogICAgICogS2VlcGluZyB0aGUgYWRhcHRlciBhbGl2ZSBhdm9pZHMgYSBzZWNvbmQgcmVxdWVzdEFkYXB0ZXIoKSBjYWxsIGluIHRoZSByZW5kZXJlci4KICAgICAqLwogICAgc3RhdGljIGFzeW5jIGdldFdlYkdQVUFkYXB0ZXIoKSB7CiAgICAgICAgaWYgKCFuYXZpZ2F0b3IuZ3B1KSB7CiAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnUkVOREVSRVInLCAnbmF2aWdhdG9yLmdwdSBub3QgZm91bmQgLSBXZWJHUFUgbm90IGF2YWlsYWJsZScpOwogICAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICB9CgogICAgICAgIHRyeSB7CiAgICAgICAgICAgIGNvbnN0IGFkYXB0ZXIgPSBhd2FpdCBuYXZpZ2F0b3IuZ3B1LnJlcXVlc3RBZGFwdGVyKHsKICAgICAgICAgICAgICAgIHBvd2VyUHJlZmVyZW5jZTogJ2hpZ2gtcGVyZm9ybWFuY2UnCiAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgaWYgKCFhZGFwdGVyKSB7CiAgICAgICAgICAgICAgICBMb2dnZXIuZGVidWcoJ1JFTkRFUkVSJywgJ05vIFdlYkdQVSBhZGFwdGVyIGZvdW5kJyk7CiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgTG9nZ2VyLmRlYnVnKCdSRU5ERVJFUicsICdXZWJHUFUgYWRhcHRlciBhY3F1aXJlZCBkdXJpbmcgZGV0ZWN0aW9uJyk7CiAgICAgICAgICAgIHJldHVybiBhZGFwdGVyOwoKICAgICAgICB9IGNhdGNoIChlcnJvcikgewogICAgICAgICAgICBMb2dnZXIud2FybignUkVOREVSRVInLCAnV2ViR1BVIGRldGVjdGlvbiBmYWlsZWQ6JywgZXJyb3IpOwogICAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICB9CiAgICB9CiAgICAKICAgIC8qKgogICAgICogQ2hlY2sgaWYgV2ViR0wgMi4wIGlzIGF2YWlsYWJsZQogICAgICogQ1JJVElDQUw6IFVzZXMgYSB0ZW1wb3JhcnkgY2FudmFzIHRvIGF2b2lkIGNvbnRhbWluYXRpbmcgdGhlIG1haW4gY2FudmFzIQogICAgICogT25jZSBhIGNhbnZhcyBnZXRzIEFOWSBjb250ZXh0IHR5cGUsIGl0IGNhbm5vdCBnZXQgYSBkaWZmZXJlbnQgY29udGV4dCB0eXBlLgogICAgICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgV2ViR0wgMi4wIGF2YWlsYWJsZQogICAgICovCiAgICBzdGF0aWMgaXNXZWJHTDJBdmFpbGFibGUoKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgICAgLy8gQ3JlYXRlIHRlbXBvcmFyeSBjYW52YXMgZm9yIHRlc3RpbmcgKGRvbid0IHVzZSB0aGUgcmVhbCBjYW52YXMhKQogICAgICAgICAgICBjb25zdCB0ZXN0Q2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7CiAgICAgICAgICAgIGNvbnN0IGdsID0gdGVzdENhbnZhcy5nZXRDb250ZXh0KCd3ZWJnbDInKTsKICAgICAgICAgICAgY29uc3QgYXZhaWxhYmxlID0gZ2wgIT09IG51bGw7CiAgICAgICAgICAgIAogICAgICAgICAgICBpZiAoYXZhaWxhYmxlKSB7CiAgICAgICAgICAgICAgICBMb2dnZXIuZGVidWcoJ1JFTkRFUkVSJywgJ1dlYkdMIDIuMCBhdmFpbGFibGUnKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIExvZ2dlci5kZWJ1ZygnUkVOREVSRVInLCAnV2ViR0wgMi4wIG5vdCBhdmFpbGFibGUnKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgcmV0dXJuIGF2YWlsYWJsZTsKICAgICAgICAgICAgCiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgICAgICAgTG9nZ2VyLndhcm4oJ1JFTkRFUkVSJywgJ1dlYkdMIDIuMCBkZXRlY3Rpb24gZmFpbGVkOicsIGVycm9yKTsKICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBHZXQgYWxsIGF2YWlsYWJsZSByZW5kZXJlciB0eXBlcwogICAgICogQHBhcmFtIHtIVE1MQ2FudmFzRWxlbWVudH0gY2FudmFzIC0gQ2FudmFzIChub3QgdXNlZCBmb3IgZGV0ZWN0aW9uIC0gc2VlIG5vdGUgYmVsb3cpCiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBdmFpbGFibGUgcmVuZGVyZXJzIGFuZCBwcmVmZXJyZWQgY2hvaWNlCiAgICAgKiAKICAgICAqIE5PVEU6IFdlIGRvbid0IHVzZSB0aGUgYWN0dWFsIGNhbnZhcyBmb3IgZGV0ZWN0aW9uIGJlY2F1c2UgZ2V0dGluZyBhbnkgY29udGV4dAogICAgICogb24gYSBjYW52YXMgcHJldmVudHMgZ2V0dGluZyBhIGRpZmZlcmVudCBjb250ZXh0IHR5cGUgbGF0ZXIhCiAgICAgKi8KICAgIHN0YXRpYyBhc3luYyBnZXRBdmFpbGFibGVSZW5kZXJlcnMoY2FudmFzKSB7CiAgICAgICAgY29uc3QgYWRhcHRlciA9IGF3YWl0IFJlbmRlcmVyRmFjdG9yeS5nZXRXZWJHUFVBZGFwdGVyKCk7CiAgICAgICAgY29uc3Qgd2ViZ2wyID0gUmVuZGVyZXJGYWN0b3J5LmlzV2ViR0wyQXZhaWxhYmxlKCk7IC8vIFVzZXMgdGVtcCBjYW52YXMgaW50ZXJuYWxseQoKICAgICAgICBjb25zdCBwcmVmZXJyZWQgPSBhZGFwdGVyID8gJ3dlYmdwdScgOiAod2ViZ2wyID8gJ3dlYmdsJyA6ICdub25lJyk7CgogICAgICAgIHJldHVybiB7CiAgICAgICAgICAgIHdlYmdwdTogISFhZGFwdGVyLAogICAgICAgICAgICB3ZWJncHVBZGFwdGVyOiBhZGFwdGVyLCAgIC8vIExpdmUgYWRhcHRlciDigJQgcGFzc2VkIHRvIFdlYkdQVVJlbmRlcmVyIHRvIHNraXAgc2Vjb25kIGluaXQKICAgICAgICAgICAgd2ViZ2wyLAogICAgICAgICAgICBwcmVmZXJyZWQKICAgICAgICB9OwogICAgfQp9CgpSZW5kZXJlckZhY3Rvcnk7CgoKLy8gRWZmZWN0IC0gQmFzZSBjbGFzcyBmb3IgYWxsIFdlYkdQVSBzaGFkZXIgZWZmZWN0cwovLyBQcm92aWRlcyBzdHJ1Y3R1cmVkIHN0YXRlIG1hbmFnZW1lbnQgYW5kIHVuaWZvcm0gYnVmZmVyIGhhbmRsaW5nCgovKioKICogQmFzZSBjbGFzcyBmb3IgYWxs
k7CiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChtZXNzYWdlLnR5cGUgPT09ICd3YXJuaW5nJykgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZygnd2FybicsIGBGcmFnbWVudCBzaGFkZXIgd2FybmluZzogJHttZXNzYWdlLm1lc3NhZ2V9YCk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBCdWlsZCBiaW5kIGdyb3VwIGxheW91dHMgYXJyYXkKICAgICAgICAgICAgY29uc3QgYmluZEdyb3VwTGF5b3V0cyA9IFtdOwogICAgICAgICAgICAKICAgICAgICAgICAgaWYgKG5lZWRzVGV4dHVyZUlucHV0KSB7CiAgICAgICAgICAgICAgICAvLyBHcm91cCAwOiBUZXh0dXJlIGlucHV0IChmb3IgcG9zdC1wcm9jZXNzaW5nIGVmZmVjdHMpCiAgICAgICAgICAgICAgICBjb25zdCB0ZXh0dXJlQmluZEdyb3VwTGF5b3V0ID0gdGhpcy5zdGF0ZS5kZXZpY2UuY3JlYXRlQmluZEdyb3VwTGF5b3V0KHsKICAgICAgICAgICAgICAgICAgICBlbnRyaWVzOiBbCiAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpbmRpbmc6IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aXNpYmlsaXR5OiBHUFVTaGFkZXJTdGFnZS5GUkFHTUVOVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHR1cmU6IHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVUeXBlOiAnZmxvYXQnCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpbmRpbmc6IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aXNpYmlsaXR5OiBHUFVTaGFkZXJTdGFnZS5GUkFHTUVOVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZXI6IHt9CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgIGxhYmVsOiBgJHtlZmZlY3QubmFtZX0gVGV4dHVyZSBCaW5kIEdyb3VwIExheW91dGAKICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgYmluZEdyb3VwTGF5b3V0cy5wdXNoKHRleHR1cmVCaW5kR3JvdXBMYXlvdXQpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBHcm91cCAxIChvciAwIGlmIG5vIHRleHR1cmUpOiBFZmZlY3QgcGFyYW1ldGVycwogICAgICAgICAgICBiaW5kR3JvdXBMYXlvdXRzLnB1c2goZWZmZWN0LmdldEJpbmRHcm91cExheW91dCgpKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIGNvbnN0IHBpcGVsaW5lTGF5b3V0ID0gdGhpcy5zdGF0ZS5kZXZpY2UuY3JlYXRlUGlwZWxpbmVMYXlvdXQoewogICAgICAgICAgICAgICAgYmluZEdyb3VwTGF5b3V0cywKICAgICAgICAgICAgICAgIGxhYmVsOiBgJHtlZmZlY3QubmFtZX0gUGlwZWxpbmUgTGF5b3V0YAogICAgICAgICAgICB9KTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIENyZWF0ZSByZW5kZXIgcGlwZWxpbmUKICAgICAgICAgICAgY29uc3QgcGlwZWxpbmUgPSB0aGlzLnN0YXRlLmRldmljZS5jcmVhdGVSZW5kZXJQaXBlbGluZSh7CiAgICAgICAgICAgICAgICBsYXlvdXQ6IHBpcGVsaW5lTGF5b3V0LAogICAgICAgICAgICAgICAgdmVydGV4OiB7CiAgICAgICAgICAgICAgICAgICAgbW9kdWxlOiB2ZXJ0ZXhNb2R1bGUsCiAgICAgICAgICAgICAgICAgICAgZW50cnlQb2ludDogJ3ZzX21haW4nCiAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgZnJhZ21lbnQ6IHsKICAgICAgICAgICAgICAgICAgICBtb2R1bGU6IGZyYWdtZW50TW9kdWxlLAogICAgICAgICAgICAgICAgICAgIGVudHJ5UG9pbnQ6ICdmc19tYWluJywKICAgICAgICAgICAgICAgICAgICB0YXJnZXRzOiBbewogICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXQ6IHRoaXMuc3RhdGUuZm9ybWF0CiAgICAgICAgICAgICAgICAgICAgfV0KICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICBwcmltaXRpdmU6IHsKICAgICAgICAgICAgICAgICAgICB0b3BvbG9neTogJ3RyaWFuZ2xlLWxpc3QnCiAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgbGFiZWw6IGAke2VmZmVjdC5uYW1lfSBQaXBlbGluZWAKICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBTdG9yZSBwaXBlbGluZQogICAgICAgICAgICB0aGlzLnN0YXRlLnBpcGVsaW5lcy5zZXQoZWZmZWN0LmlkLCBwaXBlbGluZSk7CiAgICAgICAgICAgIAogICAgICAgICAgICB0aGlzLmxvZygnaW5mbycsIGBQaXBlbGluZSBjcmVhdGVkIGZvciAke2VmZmVjdC5uYW1lfWApOwogICAgICAgICAgICAKICAgICAgICAgICAgcmV0dXJuIHBpcGVsaW5lOwogICAgICAgICAgICAKICAgICAgICB9IGNhdGNoIChlcnJvcikgewogICAgICAgICAgICB0aGlzLmxvZygnZXJyb3InLCBgRmFpbGVkIHRvIGNyZWF0ZSBwaXBlbGluZSBmb3IgJHtlZmZlY3QubmFtZX06YCwgZXJyb3IpOwogICAgICAgICAgICB0aHJvdyBlcnJvcjsKICAgICAgICB9CiAgICB9CiAgICAKICAgIC8qKgogICAgICogQ3JlYXRlIGludGVybWVkaWF0ZSB0ZXh0dXJlIGZvciBtdWx0aS1wYXNzIHJlbmRlcmluZwogICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gVGV4dHVyZSB3aWR0aAogICAgICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFRleHR1cmUgaGVpZ2h0CiAgICAgKi8KICAgIGNyZWF0ZUludGVybWVkaWF0ZVRleHR1cmUod2lkdGgsIGhlaWdodCkgewogICAgICAgIGlmICghdGhpcy5zdGF0ZS5pc0luaXRpYWxpemVkKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUmVuZGVyZXIgbm90IGluaXRpYWxpemVkJyk7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIC8vIERlc3Ryb3kgZXhpc3RpbmcgdGV4dHVyZSBpZiByZXNpemluZwogICAgICAgIGlmICh0aGlzLnN0YXRlLm11bHRpcGFzcy5pbnRlcm1lZGlhdGVUZXh0dXJlKSB7CiAgICAgICAgICAgIHRoaXMuc3RhdGUubXVsdGlwYXNzLmludGVybWVkaWF0ZVRleHR1cmUuZGVzdHJveSgpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICAvLyBDcmVhdGUgdGV4dHVyZSBmb3Igc3RvcmluZyBmaXJzdCBwYXNzIChUViBzdGF0aWMpCiAgICAgICAgdGhpcy5zdGF0ZS5tdWx0aXBhc3MuaW50ZXJtZWRpYXRlVGV4dHVyZSA9IHRoaXMuc3RhdGUuZGV2aWNlLmNyZWF0ZVRleHR1cmUoewogICAgICAgICAgICBzaXplOiB7IHdpZHRoLCBoZWlnaHQgfSwKICAgICAgICAgICAgZm9ybWF0OiB0aGlzLnN0YXRlLmZvcm1hdCwKICAgICAgICAgICAgdXNhZ2U6IEdQVVRleHR1cmVVc2FnZS5SRU5ERVJfQVRUQUNITUVOVCB8IEdQVVRleHR1cmVVc2FnZS5URVhUVVJFX0JJTkRJTkcKICAgICAgICB9KTsKICAgICAgICAKICAgICAgICAvLyBDcmVhdGUgdGV4dHVyZSB2aWV3CiAgICAgICAgdGhpcy5zdGF0ZS5tdWx0aXBhc3MuaW50ZXJtZWRpYXRlVGV4dHVyZVZpZXcgPSB0aGlzLnN0YXRlLm11bHRpcGFzcy5pbnRlcm1lZGlhdGVUZXh0dXJlLmNyZWF0ZVZpZXcoKTsKICAgICAgICAKICAgICAgICAvLyBDcmVhdGUgc2FtcGxlciBvbmNlIChyZXVzZWQgYWNyb3NzIHJlc2l6ZXMpCiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLm11bHRpcGFzcy5zYW1wbGVyKSB7CiAgICAgICAgICAgIHRoaXMuc3RhdGUubXVsdGlwYXNzLnNhbXBsZXIgPSB0aGlzLnN0YXRlLmRldmljZS5jcmVhdGVTYW1wbGVyKHsKICAgICAgICAgICAgICAgIG1hZ0ZpbHRlcjogJ2xpbmVhcicsCiAgICAgICAgICAgICAgICBtaW5GaWx0ZXI6ICdsaW5lYXInCiAgICAgICAgICAgIH0pOwogICAgICAgIH0KCiAgICAgICAgLy8gQ2FjaGUgdGhlIHRleHR1cmUgYmluZCBncm91cCDigJQgcmVidWlsdCBoZXJlIG9uIHJlc2l6ZSwgcmV1c2VkIGV2ZXJ5IGZyYW1lCiAgICAgICAgLy8gUmVxdWlyZXMgdGhlIHBpeGVsaXphdGlvbiBwaXBlbGluZSB0byBleGlzdDsgaWYgbm90IHlldCBjcmVhdGVkLCByZW5kZXJNdWx0aVBhc3MKICAgICAgICAvLyB3aWxsIGZhbGwgYmFjayB0byBidWlsZGluZyBpdCBvbiBmaXJzdCB1c2UuCiAgICAgICAgY29uc3QgcGl4ZWxpemF0aW9uUGlwZWxpbmUgPSB0aGlzLnN0YXRlLnBpcGVsaW5lcy5nZXQoMSk7CiAgICAgICAgaWYgKHBpeGVsaXphdGlvblBpcGVsaW5lKSB7CiAgICAgICAgICAgIHRoaXMuc3RhdGUubXVsdGlwYXNzLnRleHR1cmVCaW5kR3JvdXAgPSB0aGlzLnN0YXRlLmRldmljZS5jcmVhdGVCaW5kR3JvdXAoewogICAgICAgICAgICAgICAgbGF5b3V0OiBwaXhlbGl6YXRpb25QaXBlbGluZS5nZXRCaW5kR3JvdXBMYXlvdXQoMCksCiAgICAgICAgICAgICAgICBlbnRyaWVzOiBbCiAgICAgICAgICAgICAgICAgICAgeyBiaW5kaW5nOiAwLCByZXNvdXJjZTogdGhpcy5zdGF0ZS5tdWx0aXBhc3MuaW50ZXJtZWRpYXRlVGV4dHVyZVZpZXcgfSwKICAgICAgICAgICAgICAgICAgICB7IGJpbmRpbmc6IDEsIHJlc291cmNlOiB0aGlzLnN0YXRlLm11bHRpcGFzcy5zYW1wbGVyIH0KICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICBsYWJlbDogJ0NhY2hlZCBUZXh0dXJlIEJpbmQgR3JvdXAnCiAgICAgICAgICAgIH0pOwogICAgICAgICAgICB0aGlzLmxvZygnZGVidWcnLCAnVGV4dHVyZSBiaW5kIGdyb3VwIGNhY2hlZCcpOwogICAgICAgIH0KCiAgICAgICAgdGhpcy5sb2coJ2luZm8nLCBgSW50ZXJtZWRpYXRlIHRleHR1cmUgY3JlYXRlZDogJHt3aWR0aH14JHtoZWlnaHR9YCk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogR2V0IHBpcGVsaW5lIGZvciBlZmZlY3QKICAgICAqIEBwYXJhbSB7bnVtYmVyfSBlZmZlY3RJZCAtIEVmZmVjdCBJRAogICAgICogQHJldHVybnMge0dQVVJlbmRlclBpcGVsaW5lfG51bGx9IFBpcGVsaW5lIG9yIG51bGwKICAgICAqLwogICAgZ2V0UGlwZWxpbmUoZWZmZWN0SWQpIHsKICAgICAgICByZXR1cm4gdGhpcy5zdGF0ZS5waXBlbGluZXMuZ2V0KGVmZmVjdElkKSB8fCBudWxsOwogICAgfQogICAgCiAgICAvKioKICAgICAqIFNpbmdsZS1wYXNzIHJlbmRlcmluZzogRWZmZWN0IGRpcmVjdGx5IHRvIHNjcmVlbgogICAgICogQHBhcmFtIHtFZmZlY3R9IGVmZmVjdCAtIEVmZmVjdCB0byByZW5kZXIKICAgICAqIEBwYXJhbSB7bnVtYmVyfSB0aW1lc3RhbXAgLSBDdXJyZW50IHRpbWVzdGFtcAogICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gQ2FudmFzIHdpZHRoCiAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gQ2FudmFzIGhlaWdodAogICAgICovCiAgICByZW5kZXJTaW5nbGVQYXNzKGVmZmVjdCwgdGltZXN0YW1wLCB3aWR0aCwgaGVpZ2h0KSB7CiAgICAgICAgY29uc3QgcGlwZWxpbmUgPSB0aGlzLmdldFBpcGVsaW5lKGVmZmVjdC5pZCk7CiAgICAgICAgaWYgKCFwaXBlbGluZSkgewogICAgICAgICAgICB0aGlzLmxvZygnd2FybicsIGBObyBwaXBlbGluZSBmb3IgZWZmZWN0ICR7ZWZmZWN0LmlkfWApOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIAogICAgICAgIC8vIFVwZGF0ZSBlZmZlY3QgdW5pZm9ybXMKICAgICAgICBjb25zdCBtYXBwZWRQYXJhbXMgPSBlZmZlY3QuZ2V0TWFwcGVkUGFyYW1ldGVycygpOwogICAgICAgIG1hcHBlZFBhcmFtcy5yZXNvbHV0aW9uWCA9IHdpZHRoOwogICAgICAgIG1hcHBlZFBhcmFtcy5yZXNvbHV0aW9uWSA9IGhlaWdodDsKICAgICAgICBlZmZlY3Qud3JpdGVVbmlmb3Jtcyh0aGlzLnN0YXRlLmRldmljZSwgbWFwcGVkUGFyYW1zKTsKICAgICAgICAKICAgICAgICAvLyBDcmVhdGUgY29tbWFuZCBlbmNvZGVyCiAgICAgICAgY29uc3QgY29tbWFuZEVuY29kZXIgPSB0aGlzLnN0YXRlLmRldmljZS5jcmVhdGVDb21tYW5kRW5jb2Rlcih7CiAgICAgICAgICAgIGxhYmVsOiAnU2luZ2xlIFBhc3MgQ29tbWFuZCBFbmNvZGVyJwogICAgICAgIH0pOwogICAgICAgIAogICAgICAgIC8vIEdldCBzY3JlZW4gdGV4dHVyZQogICAgICAgIGNvbnN0IHNjcmVlblZpZXcgPSB0aGlzLnN0YXRlLmNvbnRleHQuZ2V0Q3VycmVudFRleHR1cmUoKS5jcmVhdGVWaWV3KCk7CiAgICAgICAgCiAgICAgICAgLy8gUmVuZGVyIGVmZmVjdCB0byBzY3JlZW4KICAgICAgICBjb25zdCByZW5kZXJQYXNzID0gY29tbWFuZEVuY29kZXIuYmVnaW5SZW5kZXJQYXNzKHsKICAgICAgICAgICAgY29sb3JBdHRhY2htZW50czogW3sKICAgICAgICAgICAgICAgIHZpZXc6IHNjcmVlblZpZXcsCiAgICAgICAgICAgICAgICBjbGVhclZhbHVlOiB7IHI6IDAuMCwgZzogMC4wLCBiOiAwLjAsIGE6IDEuMCB9LAogICAgICAgICAgICAgICAgbG9hZE9wOiAnY2xlYXInLAogICAgICAgICAgICAgICAgc3RvcmVPcDogJ3N0b3JlJwogICAgICAgICAgICB9XSwKICAgICAgICAgICAgbGFiZWw6ICdFZmZlY3QgdG8gU2NyZWVuJwogICAgICAgIH0pOwogICAgICAgIAogICAgICAgIHJlbmRlclBhc3Muc2V0UGlwZWxpbmUocGlwZWxpbmUpOwogICAgICAgIHJlbmRlclBhc3Muc2V0QmluZEdyb3VwKDAsIGVmZmVjdC5nZXRCaW5kR3JvdXAoKSk7CiAgICAgICAgcmVuZGVyUGFzcy5kcmF3KDMpOwogICAgICAgIHJlbmRlclBhc3MuZW5kKCk7CiAgICAgICAgCiAgICAgICAgLy8gU3VibWl0CiAgICAgICAgdGhpcy5zdGF0ZS5kZXZpY2UucXVldWUuc3VibWl0KFtjb21tYW5kRW5jb2Rlci5maW5pc2goKV0pOwogICAgfQogICAgCiAgICAvKioKICAgICAqIE11bHRpLXBhc3MgcmVuZGVyaW5nOiBGaXJzdCBlZmZlY3Qg4oaSIFRleHR1cmUg4oaSIFNlY29uZCBlZmZlY3Qg4oaSIFNjcmVlbgogICAgICogQHBhcmFtIHtFZmZlY3R9IGZpcnN0RWZmZWN0IC0gRmlyc3QgZWZmZWN0IChlLmcuLCBUViBzdGF0aWMpCiAgICAgKiBAcGFyYW0ge0VmZmVjdH0gc2Vjb25kRWZmZWN0IC0gU2Vjb25kIGVmZmVjdCAoZS5nLiwgcGl4ZWxpemF0aW9uKQogICAgICogQHBhcmFtIHtudW1iZXJ9IHRpbWVzdGFtcCAtIEN1cnJlbnQgdGltZXN0YW1wCiAgICAgKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBDYW52YXMgd2lkdGgKICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBDYW52YXMgaGVpZ2h0CiAgICAgKi8KICAgIHJlbmRlck11bHRpUGFzcyhmaXJzdEVmZmVjdCwgc2Vjb25kRWZmZWN0LCB0aW1lc3RhbXAsIHdpZHRoLCBoZWlnaHQpIHsKICAgICAgICBjb25zdCBmaXJzdFBpcGVsaW5lID0gdGhpcy5nZXRQaXBlbGluZShmaXJzdEVmZmVjdC5pZCk7CiAgICAgICAgY29uc3Qgc2Vjb25kUGlwZWxpbmUgPSB0aGlzLmdldFBpcGVsaW5lKHNlY29uZEVmZmVjdC5pZCk7CiAgICAgICAgCiAgICAgICAgaWYgKCFmaXJzdFBpcGVsaW5lIHx8ICFzZWNvbmRQaXBlbGluZSkgewogICAgICAgICAgICB0aGlzLmxvZygnd2FybicsICdNaXNzaW5nIHBpcGVsaW5lIGZvciBtdWx0aS1wYXNzIHJlbmRlcmluZycpOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIAogICAgICAgIC8vIFVwZGF0ZSBmaXJzdCBlZmZlY3QgdW5pZm9ybXMKICAgICAgICBjb25zdCBmaXJzdFBhcmFtcyA9IGZpcnN0RWZmZWN0LmdldE1hcHBlZFBhcmFtZXRlcnMoKTsKICAgICAgICBmaXJzdFBhcmFtcy5yZXNvbHV0aW9uWCA9IHdpZHRoOwogICAgICAgIGZpcnN0UGFyYW1zLnJlc29sdXRpb25ZID0gaGVpZ2h0OwogICAgICAgIGZpcnN0RWZmZWN0LndyaXRlVW5pZm9ybXModGhpcy5zdGF0ZS5kZXZpY2UsIGZpcnN0UGFyYW1zKTsKICAgICAgICAKICAgICAgICAvLyBVcGRhdGUgc2Vjb25kIGVmZmVjdCB1bmlmb3JtcwogICAgICAgIGNvbnN0IHNlY29uZFBhcmFtcyA9IHNlY29uZEVmZmVjdC5nZXRNYXBwZWRQYXJhbWV0ZXJzKCk7CiAgICAgICAgaWYgKHNlY29uZEVmZmVjdC51cGRhdGVDYW52YXNEaW1lbnNpb25zKSB7CiAgICAgICAgICAgIHNlY29uZEVmZmVjdC51cGRhdGVDYW52YXNEaW1lbnNpb25zKHdpZHRoLCBoZWlnaHQpOwogICAgICAgIH0KICAgICAgICBzZWNvbmRFZmZlY3Qud3JpdGVVbmlmb3Jtcyh0aGlzLnN0YXRlLmRldmljZSwgc2Vjb25kUGFyYW1zKTsKICAgICAgICAKICAgICAgICAvLyBDcmVhdGUgY29tbWFuZCBlbmNvZGVyCiAgICAgICAgY29uc3QgY29tbWFuZEVuY29kZXIgPSB0aGlzLnN0YXRlLmRldmljZS5jcmVhdGVDb21tYW5kRW5jb2Rlcih7CiAgICAgICAgICAgIGxhYmVsOiAnTXVsdGkgUGFzcyBDb21tYW5kIEVuY29kZXInCiAgICAgICAgfSk7CiAgICAgICAgCiAgICAgICAgLy8gUEFTUyAxOiBSZW5kZXIgZmlyc3QgZWZmZWN0IHRvIGludGVybWVkaWF0ZSB0ZXh0dXJlCiAgICAgICAgY29uc3QgcGFzczEgPSBjb21tYW5kRW5jb2Rlci5iZWdpblJlbmRlclBhc3MoewogICAgICAgICAgICBjb2xvckF0dGFjaG1lbnRzOiBbewogICAgICAgICAgICAgICAgdmlldzogdGhpcy5zdGF0ZS5tdWx0aXBhc3MuaW50ZXJtZWRpYXRlVGV4dHVyZVZpZXcsCiAgICAgICAgICAgICAgICBjbGVhclZhbHVlOiB7IHI6IDAuMCwgZzogMC4wLCBiOiAwLjAsIGE6IDEuMCB9LAogICAgICAgICAgICAgICAgbG9hZE9wOiAnY2xlYXInLAogICAgICAgICAgICAgICAgc3RvcmVPcDogJ3N0b3JlJwogICAgICAgICAgICB9XSwKICAgICAgICAgICAgbGFiZWw6ICdQYXNzIDE6IEZpcnN0IEVmZmVjdCB0byBUZXh0dXJlJwogICAgICAgIH0pOwogICAgICAgIAogICAgICAgIHBhc3MxLnNldFBpcGVsaW5lKGZpcnN0UGlwZWxpbmUpOwogICAgICAgIHBhc3MxLnNldEJpbmRHcm91cCgwLCBmaXJzdEVmZmVjdC5nZXRCaW5kR3JvdXAoKSk7CiAgICAgICAgcGFzczEuZHJhdygzKTsKICAgICAgICBwYXNzMS5lbmQoKTsKICAgICAgICAKICAgICAgICAvLyBQQVNTIDI6IFJlbmRlciBzZWNvbmQgZWZmZWN0ICh3aXRoIHRleHR1cmUgaW5wdXQpIHRvIHNjcmVlbgogICAgICAgIGNvbnN0IHNjcmVlblZpZXcgPSB0aGlzLnN0YXRlLmNvbnRleHQuZ2V0Q3VycmVudFRleHR1cmUoKS5jcmVhdGVWaWV3KCk7CiAgICAgICAgCiAgICAgICAgY29uc3QgcGFzczIgPSBjb21tYW5kRW5jb2Rlci5iZWdpblJlbmRlclBhc3MoewogICAgICAgICAgICBjb2xvckF0dGFjaG1lbnRzOiBbewogICAgICAgICAgICAgICAgdmlldzogc2NyZWVuVmlldywKICAgICAgICAgICAgICAgIGNsZWFyVmFsdWU6IHsgcjogMC4wLCBnOiAwLjAsIGI6IDAuMCwgYTogMS4wIH0sCiAgICAgICAgICAgICAgICBsb2FkT3A6ICdjbGVhcicsCiAgICAgICAgICAgICAgICBzdG9yZU9wOiAnc3RvcmUnCiAgICAgICAgICAgIH1dLAogICAgICAgICAgICBsYWJlbDogJ1Bhc3MgMjogU2Vjb25kIEVmZmVjdCB0byBTY3JlZW4nCiAgICAgICAgfSk7CiAgICAgICAgCiAgICAgICAgcGFzczIuc2V0UGlwZWxpbmUoc2Vjb25kUGlwZWxpbmUpOwoKICAgICAgICAvLyBVc2UgY2FjaGVkIGJpbmQgZ3JvdXAg4oCUIGNyZWF0ZWQgb25jZSBpbiBjcmVhdGVJbnRlcm1lZGlhdGVUZXh0dXJlKCksIHJlYnVpbHQgb24gcmVzaXplCiAgICAgICAgLy8gRmFsbCBiYWNrIHRvIGJ1aWxkaW5nIGl0IGhlcmUgb25seSBvbiB0aGUgdmVyeSBmaXJzdCBmcmFtZSAocGlwZWxpbmUgY3JlYXRlZCBhZnRlciB0ZXh0dXJlKQogICAgICAgIGlmICghdGhpcy5zdGF0ZS5tdWx0aXBhc3MudGV4dHVyZUJpbmRHcm91cCkgewogICAgICAgICAgICB0aGlzLnN0YXRlLm11bHRpcGFzcy50ZXh0dXJlQmluZEdyb3VwID0gdGhpcy5zdGF0ZS5kZXZpY2UuY3JlYXRlQmluZEdyb3VwKHsKICAgICAgICAgICAgICAgIGxheW91dDogc2Vjb25kUGlwZWxpbmUuZ2V0QmluZEdyb3VwTGF5b3V0KDApLAogICAgICAgICAgICAgICAgZW50cmllczogWwogICAgICAgICAgICAgICAgICAgIHsgYmluZGluZzogMCwgcmVzb3VyY2U6IHRoaXMuc3RhdGUubXVsdGlwYXNzLmludGVybWVkaWF0ZVRleHR1cmVWaWV3IH0sCiAgICAgICAgICAgICAgICAgICAgeyBiaW5kaW5nOiAxLCByZXNvdXJjZTogdGhpcy5zdGF0ZS5tdWx0aXBhc3Muc2FtcGxlciB9CiAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgbGFiZWw6ICdDYWNoZWQgVGV4dHVyZSBCaW5kIEdyb3VwJwogICAgICAgICAgICB9KTsKICAgICAgICAgICAgdGhpcy5sb2coJ2RlYnVnJywgJ1RleHR1cmUgYmluZCBncm91cCBidWlsdCBvbiBmaXJzdCByZW5kZXIgKHBpcGVsaW5lIHdhcyBub3QgcmVhZHkgYXQgdGV4dHVyZSBjcmVhdGlvbiknKTsKICAgICAgICB9CgogICAgICAgIHBhc3MyLnNldEJpbmRHcm91cCgwLCB0aGlzLnN0YXRlLm11bHRpcGFzcy50ZXh0dXJlQmluZEdyb3VwKTsKICAgICAgICBwYXNzMi5zZXRCaW5kR3JvdXAoMSwgc2Vjb25kRWZmZWN0LmdldEJpbmRHcm91cCgpKTsKICAgICAgICBwYXNzMi5kcmF3KDMpOwogICAgICAgIHBhc3MyLmVuZCgpOwogICAgICAgIAogICAgICAgIC8vIFN1Ym1pdCBib3RoIHBhc3NlcwogICAgICAgIHRoaXMuc3RhdGUuZGV2aWNlLnF1ZXVlLnN1Ym1pdChbY29tbWFuZEVuY29kZXIuZmluaXNoKCldKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBIYW5kbGUgY2FudmFzIHJlc2l6ZQogICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gTmV3IHdpZHRoCiAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gTmV3IGhlaWdodAogICAgICovCiAgICByZXNpemUod2lkdGgsIGhlaWdodCkgewogICAgICAgIGlmICghdGhpcy5zdGF0ZS5pc0luaXRpYWxpemVkKSByZXR1cm47CiAgICAgICAgCiAgICAgICAgLy8gUmVjcmVhdGUgaW50ZXJtZWRpYXRlIHRleHR1cmUgd2l0aCBuZXcgc2l6ZQogICAgICAgIHRoaXMuY3JlYXRlSW50ZXJtZWRpYXRlVGV4dHVyZSh3aWR0aCwgaGVpZ2h0KTsKICAgICAgICAKICAgICAgICB0aGlzLmxvZygnZGVidWcnLCBgUmVzaXplZCB0byAke3dpZHRofXgke2hlaWdodH1gKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBHZXQgcmVuZGVyZXIgc3RhdGUgZm9yIGRlYnVnZ2luZwogICAgICogQHJldHVybnMge09iamVjdH0gQ3VycmVudCBzdGF0ZQogICAgICovCiAgICBnZXRTdGF0ZSgpIHsKICAgICAgICByZXR1cm4gewogICAgICAgICAgICAuLi5zdXBlci5nZXRTdGF0ZSgpLAogICAgICAgICAgICBmb3JtYXQ6IHRoaXMuc3RhdGUuZm9ybWF0LAogICAgICAgICAgICBwaXBlbGluZXNDcmVhdGVkOiB0aGlzLnN0YXRlLnBpcGVsaW5lcy5zaXplLAogICAgICAgICAgICBlZmZlY3RzUmVnaXN0ZXJlZDogdGhpcy5zdGF0ZS5lZmZlY3RzLnNpemUsCiAgICAgICAgICAgIGhhc0ludGVybWVkaWF0ZVRleHR1cmU6IHRoaXMuc3RhdGUubXVsdGlwYXNzLmludGVybWVkaWF0ZVRleHR1cmUgIT09IG51bGwKICAgICAgICB9OwogICAgfQogICAgCiAgICAvKioKICAgICAqIENsZWFuIHVwIFdlYkdQVSByZXNvdXJjZXMKICAgICAqLwogICAgZGVzdHJveSgpIHsKICAgICAgICB0aGlzLmxvZygnaW5mbycsICdEZXN0cm95aW5nIFdlYkdQVSByZW5kZXJlci4uLicpOwogICAgICAgIAogICAgICAgIC8vIERlc3Ryb3kgaW50ZXJtZWRpYXRlIHRleHR1cmUKICAgICAgICBpZiAodGhpcy5zdGF0ZS5tdWx0aXBhc3MuaW50ZXJtZWRpYXRlVGV4dHVyZSkgewogICAgICAgICAgICB0aGlzLnN0YXRlLm11bHRpcGFzcy5pbnRlcm1lZGlhdGVUZXh0dXJlLmRlc3Ryb3koKTsKICAgICAgICAgICAgdGhpcy5zdGF0ZS5tdWx0aXBhc3MuaW50ZXJtZWRpYXRlVGV4dHVyZSA9IG51bGw7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIC8vIERlc3Ryb3kgZGV2aWNlCiAgICAgICAgaWYgKHRoaXMuc3RhdGUuZGV2aWNlKSB7CiAgICAgICAgICAgIHRoaXMuc3RhdGUuZGV2aWNlLmRlc3Ryb3koKTsKICAgICAgICAgICAgdGhpcy5zdGF0ZS5kZXZpY2UgPSBudWxsOwogICAgICAgIH0KICAgICAgICAKICAgICAgICAvLyBDbGVhciBzdGF0ZQogICAgICAgIHRoaXMuc3RhdGUucGlwZWxpbmVzLmNsZWFyKCk7CiAgICAgICAgdGhpcy5zdGF0ZS5lZmZlY3RzLmNsZWFyKCk7CiAgICAgICAgdGhpcy5zdGF0ZS5pc0luaXRpYWxpemVkID0gZmFsc2U7CiAgICAgICAgCiAgICAgICAgdGhpcy5sb2coJ2luZm8nLCAnV2ViR1BVIHJlbmRlcmVyIGRlc3Ryb3llZCcpOwogICAgfQp9CgpXZWJHUFVSZW5kZXJlcjsKCgovLyBXZWJHTFJlbmRlcmVyLmpzIC0gV2ViR0wgMi4wIHJlbmRlcmluZyBpbXBsZW1lbnRhdGlvbgovLyBGYWxsYmFjayByZW5kZXJlciBmb3IgYnJvd3NlcnMgd2l0aG91dCBXZWJHUFUgc3VwcG9ydAovLyBJbXBsZW1lbnRzIElSZW5kZXJlciBpbnRlcmZhY2UgZm9yIHJlbmRlcmVyIGFic3RyYWN0aW9uCgpjbGFzcyBXZWJHTFJlbmRlcmVyIGV4dGVuZHMgSVJlbmRlcmVyIHsKICAgIGNvbnN0cnVjdG9yKCkgewogICAgICAgIHN1cGVyKCd3ZWJnbCcpOwogICAgICAgIAogICAgICAgIHRoaXMuc3RhdGUgPSB7CiAgICAgICAgICAgIC4uLnRoaXMuc3RhdGUsICAvLyBJbmhlcml0IGZyb20gSVJlbmRlcmVyCiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBXZWJHTCByZXNvdXJjZXMKICAgICAgICAgICAgZ2w6IG51bGwsCiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBQcm9ncmFtcyAoZXF1aXZhbGVudCB0byBwaXBlbGluZXMpCiAgICAgICAgICAgIHByb2dyYW1zOiBuZXcgTWFwKCksICAvLyBlZmZlY3RJZCDihpIgV2ViR0xQcm9ncmFtCiAgICAgICAgICAgIHByb2dyYW1JbmZvOiBuZXcgTWFwKCksICAvLyBlZmZlY3RJZCDihpIge3Byb2dyYW0sIHVuaWZvcm1Mb2NhdGlvbnMsIGF0dHJpYkxvY2F0aW9uc30KICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIE11bHRpLXBhc3MgcmVuZGVyaW5nCiAgICAgICAgICAgIG11bHRpcGFzczogewogICAgICAgICAgICAgICAgZnJhbWVidWZmZXI6IG51bGwsCiAgICAgICAgICAgICAgICB0ZXh0dXJlOiBudWxsLAogICAgICAgICAgICAgICAgd2lkdGg6IDAsCiAgICAgICAgICAgICAgICBoZWlnaHQ6IDAKICAgICAgICAgICAgfSwKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIEZ1bGxzY3JlZW4gcXVhZCAoZm9yIHJlbmRlcmluZykKICAgICAgICAgICAgcXVhZDogewogICAgICAgICAgICAgICAgdmFvOiBudWxsLAogICAgICAgICAgICAgICAgdmVydGV4QnVmZmVyOiBudWxsCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBSZWdpc3RlcmVkIGVmZmVjdHMKICAgICAgICAgICAgZWZmZWN0czogbmV3IE1hcCgpICAvLyBlZmZlY3RJZCDihpIgRWZmZWN0IGluc3RhbmNlCiAgICAgICAgfTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBJbml0aWFsaXplIFdlYkdMIDIuMAogICAgICogQHBhcmFtIHtIVE1MQ2FudmFzRWxlbWVudH0gY2FudmFzIC0gVGFyZ2V0IGNhbnZhcwogICAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IFRydWUgaWYgc3VjY2Vzc2Z1bAogICAgICovCiAgICBhc3luYyBpbml0aWFsaXplKGNhbnZhcykgewogICAgICAgIHRyeSB7CiAgICAgICAgICAgIHRoaXMuc3RhdGUuY2FudmFzID0gY2FudmFzOwogICAgICAgICAgICB0aGlzLmxvZygnaW5mbycsICdJbml0aWFsaXppbmcgV2ViR0wgMi4wLi4uJyk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBDaGVjayBjYW52YXMgdmFsaWRpdHkKICAgICAgICAgICAgaWYgKCFjYW52YXMgfHwgIShjYW52YXMgaW5zdGFuY2VvZiBIVE1MQ2FudmFzRWxlbWVudCkpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBjYW52YXMgZWxlbWVudCBwcm92aWRlZCcpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBHZXQgV2ViR0wyIGNvbnRleHQKICAgICAgICAgICAgY29uc3QgZ2wgPSBjYW52YXMuZ2V0Q29udGV4dCgnd2ViZ2wyJywgewogICAgICAgICAgICAgICAgYWxwaGE6IGZhbHNlLAogICAgICAgICAgICAgICAgZGVwdGg6IGZhbHNlLAogICAgICAgICAgICAgICAgc3RlbmNpbDogZmFsc2UsCiAgICAgICAgICAgICAgICBhbnRpYWxpYXM6IGZhbHNlLAogICAgICAgICAgICAgICAgcHJlbXVsdGlwbGllZEFscGhhOiBmYWxzZQogICAgICAgICAgICB9KTsKICAgICAgICAgICAgCiAgICAgICAgICAgIGlmICghZ2wpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignRmFpbGVkIHRvIGdldCBXZWJHTCAyLjAgY29udGV4dCcpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICB0aGlzLnN0YXRlLmdsID0gZ2w7CiAgICAgICAgICAgIHRoaXMubG9nKCdpbmZvJywgJ1dlYkdMIDIuMCBjb250ZXh0IGFjcXVpcmVkJyk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBTZXR1cCBXZWJHTCBzdGF0ZQogICAgICAgICAgICBnbC52aWV3cG9ydCgwLCAwLCBjYW52YXMud2lkdGgsIGNhbnZhcy5oZWlnaHQpOwogICAgICAgICAgICBnbC5jbGVhckNvbG9yKDAuMCwgMC4wLCAwLjAsIDEuMCk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBEaXNhYmxlIGRlcHRoIHRlc3QgKHdlJ3JlIGRvaW5nIDJEIHJlbmRlcmluZykKICAgICAgICAgICAgZ2wuZGlzYWJsZShnbC5ERVBUSF9URVNUKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIEVuYWJsZSBibGVuZGluZyBmb3IgdHJhbnNwYXJlbnQgZWZmZWN0cwogICAgICAgICAgICBnbC5lbmFibGUoZ2wuQkxFTkQpOwogICAgICAgICAgICBnbC5ibGVuZEZ1bmMoZ2wuU1JDX0FMUEhBLCBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIENyZWF0ZSBmdWxsc2NyZWVuIHF1YWQgZm9yIHJlbmRlcmluZwogICAgICAgICAgICB0aGlzLmNyZWF0ZUZ1bGxzY3JlZW5RdWFkKCk7CiAgICAgICAgICAgIAogICAgICAgICAgICB0aGlzLnN0YXRlLmlzSW5pdGlhbGl6ZWQgPSB0cnVlOwogICAgICAgICAgICB0aGlzLmxvZygnaW5mbycsICdXZWJHTCAyLjAgaW5pdGlhbGl6ZWQgc3VjY2Vzc2Z1bGx5Jyk7CiAgICAgICAgICAgIAogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICAgICAgCiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgICAgICAgdGhpcy5sb2coJ2Vycm9yJywgJ0ZhaWxlZCB0byBpbml0aWFsaXplIFdlYkdMIDIuMDonLCBlcnJvcik7CiAgICAgICAgICAgIHRocm93IGVycm9yOwogICAgICAgIH0KICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBDcmVhdGUgZnVsbHNjcmVlbiBxdWFkIGdlb21ldHJ5CiAgICAgKi8KICAgIGNyZWF0ZUZ1bGxzY3JlZW5RdWFkKCkgewogICAgICAgIGNvbnN0IGdsID0gdGhpcy5zdGF0ZS5nbDsKICAgICAgICAKICAgICAgICAvLyBDcmVhdGUgVkFPCiAgICAgICAgdGhpcy5zdGF0ZS5xdWFkLnZhbyA9IGdsLmNyZWF0ZVZlcnRleEFycmF5KCk7CiAgICAgICAgZ2wuYmluZFZlcnRleEFycmF5KHRoaXMuc3RhdGUucXVhZC52YW8pOwogICAgICAgIAogICAgICAgIC8vIEZ1bGxzY3JlZW4gdHJpYW5nbGUgKG1vcmUgZWZmaWNpZW50IHRoYW4gcXVhZCkKICAgICAgICAvLyBVc2VzIHZlcnRleCBJRCBpbiBzaGFkZXIgdG8gZ2VuZXJhdGUgcG9zaXRpb25zCiAgICAgICAgLy8gTm8gdmVydGV4IGRhdGEgbmVlZGVkIQogICAgICAgIAogICAgICAgIGdsLmJpbmRWZXJ0ZXhBcnJheShudWxsKTsKICAgICAgICAKICAgICAgICB0aGlzLmxvZygnZGVidWcnLCAnRnVsbHNjcmVlbiBxdWFkIGNyZWF0ZWQnKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBSZWdpc3RlciBhbiBlZmZlY3QgKGNyZWF0ZSBHUFUgcmVzb3VyY2VzKQogICAgICogQHBhcmFtIHtFZmZlY3R9IGVmZmVjdCAtIEVmZmVjdCBpbnN0YW5jZQogICAgICovCiAgICBhc3luYyByZWdpc3RlckVmZmVjdChlZmZlY3QpIHsKICAgICAgICBpZiAoIXRoaXMuc3RhdGUuaXNJbml0aWFsaXplZCkgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JlbmRlcmVyIG5vdCBpbml0aWFsaXplZCcpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICB0cnkgewogICAgICAgICAgICAvLyBTdG9yZSBlZmZlY3QgcmVmZXJlbmNlCiAgICAgICAgICAgIHRoaXMuc3RhdGUuZWZmZWN0cy5zZXQoZWZmZWN0LmlkLCBlZmZlY3QpOwogICAgICAgICAgICAKICAgICAgICAgICAgdGhpcy5sb2coJ2RlYnVnJywgYEVmZmVjdCByZWdpc3RlcmVkOiAke2VmZmVjdC5uYW1lfSAoSUQ6ICR7ZWZmZWN0LmlkfSlgKTsKICAgICAgICAgICAgCiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgICAgICAgdGhpcy5sb2coJ2Vycm9yJywgYEZhaWxlZCB0byByZWdpc3RlciBlZmZlY3QgJHtlZmZlY3QubmFtZX06YCwgZXJyb3IpOwogICAgICAgICAgICB0aHJvdyBlcnJvcjsKICAgICAgICB9CiAgICB9CiAgICAKICAgIC8qKgogICAgICogQ3JlYXRlIFdlYkdMIHByb2dyYW0gKHBpcGVsaW5lKSBmb3IgYW4gZWZmZWN0CiAgICAgKiBAcGFyYW0ge0VmZmVjdH0gZWZmZWN0IC0gRWZmZWN0IHRvIGNyZWF0ZSBwcm9ncmFtIGZvcgogICAgICogQHBhcmFtIHtib29sZWFufSBuZWVkc1RleHR1cmVJbnB1dCAtIFdoZXRoZXIgZWZmZWN0IG5lZWRzIHRleHR1cmUgaW5wdXQKICAgICAqIEByZXR1cm5zIHtQcm9taXNlPFdlYkdMUHJvZ3JhbT59IENyZWF0ZWQgcHJvZ3JhbQogICAgICovCiAgICBhc3luYyBjcmVhdGVQaXBlbGluZShlZmZlY3QsIG5lZWRzVGV4dHVyZUlucHV0ID0gZmFsc2UpIHsKICAgICAgICB0cnkgewogICAgICAgICAgICBjb25zdCBnbCA9IHRoaXMuc3RhdGUuZ2w7CiAgICAgICAgICAgIHRoaXMubG9nKCdkZWJ1ZycsIGBDcmVhdGluZyBXZWJHTCBwcm9ncmFtIGZvciAke2VmZmVjdC5uYW1lfWApOwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gVXNlIGVtYmVkZGVkIHNoYWRlcnMKICAgICAgICAgICAgY29uc3QgdmVydGV4Q29kZSA9IFdFQkdMX1NIQURFUlMudmVydGV4X2Z1bGxzY3JlZW47CiAgICAgICAgICAgIGNvbnN0IGZyYWdtZW50Q29kZSA9IGVmZmVjdC5pZCA9PT0gMCA/IFdFQkdMX1NIQURFUlMudHZfc3RhdGljIDogV0VCR0xfU0hBREVSUy5waXhlbGl6YXRpb247CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBDb21waWxlIHNoYWRlcnMKICAgICAgICAgICAgY29uc3QgdmVydGV4U2hhZGVyID0gdGhpcy5jb21waWxlU2hhZGVyKGdsLCBnbC5WRVJURVhfU0hBREVSLCB2ZXJ0ZXhDb2RlLCBgJHtlZmZlY3QubmFtZX0gVmVydGV4YCk7CiAgICAgICAgICAgIGNvbnN0IGZyYWdtZW50U2hhZGVyID0gdGhpcy5jb21waWxlU2hhZGVyKGdsLCBnbC5GUkFHTUVOVF9TSEFERVIsIGZyYWdtZW50Q29kZSwgYCR7ZWZmZWN0Lm5hbWV9IEZyYWdtZW50YCk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBDcmVhdGUgcHJvZ3JhbQogICAgICAgICAgICBjb25zdCBwcm9ncmFtID0gZ2wuY3JlYXRlUHJvZ3JhbSgpOwogICAgICAgICAgICBnbC5hdHRhY2hTaGFkZXIocHJvZ3JhbSwgdmVydGV4U2hhZGVyKTsKICAgICAgICAgICAgZ2wuYXR0YWNoU2hhZGVyKHByb2dyYW0sIGZyYWdtZW50U2hhZGVyKTsKICAgICAgICAgICAgZ2wubGlua1Byb2dyYW0ocHJvZ3JhbSk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBDaGVjayBsaW5rIHN0YXR1cwogICAgICAgICAgICBpZiAoIWdsLmdldFByb2dyYW1QYXJhbWV0ZXIocHJvZ3JhbSwgZ2wuTElOS19TVEFUVVMpKSB7CiAgICAgICAgICAgICAgICBjb25zdCBpbmZvID0gZ2wuZ2V0UHJvZ3JhbUluZm9Mb2cocHJvZ3JhbSk7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFByb2dyYW0gbGluayBmYWlsZWQ6ICR7aW5mb31gKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgLy8gR2V0IHVuaWZvcm0gbG9jYXRpb25zCiAgICAgICAgICAgIGNvbnN0IHVuaWZvcm1Mb2NhdGlvbnMgPSB0aGlzLmdldFVuaWZvcm1Mb2NhdGlvbnMoZ2wsIHByb2dyYW0sIGVmZmVjdCwgbmVlZHNUZXh0dXJlSW5wdXQpOwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gU3RvcmUgcHJvZ3JhbSBpbmZvCiAgICAgICAgICAgIGNvbnN0IHByb2dyYW1JbmZvID0gewogICAgICAgICAgICAgICAgcHJvZ3JhbSwKICAgICAgICAgICAgICAgIHVuaWZvcm1Mb2NhdGlvbnMsCiAgICAgICAgICAgICAgICBuZWVkc1RleHR1cmVJbnB1dAogICAgICAgICAgICB9OwogICAgICAgICAgICAKICAgICAgICAgICAgdGhpcy5zdGF0ZS5wcm9ncmFtcy5zZXQoZWZmZWN0LmlkLCBwcm9ncmFtKTsKICAgICAgICAgICAgdGhpcy5zdGF0ZS5wcm9ncmFtSW5mby5zZXQoZWZmZWN0LmlkLCBwcm9ncmFtSW5mbyk7CiAgICAgICAgICAgIAogICAgICAgICAgICB0aGlzLmxvZygnaW5mbycsIGBXZWJHTCBwcm9ncmFtIGNyZWF0ZWQgZm9yICR7ZWZmZWN0Lm5hbWV9YCk7CiAgICAgICAgICAgIAogICAgICAgICAgICByZXR1cm4gcHJvZ3JhbTsKICAgICAgICAgICAgCiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgICAgICAgdGhpcy5sb2coJ2Vycm9yJywgYEZhaWxlZCB0byBjcmVhdGUgcHJvZ3JhbSBmb3IgJHtlZmZlY3QubmFtZX06YCwgZ
lZCkKICAgICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQogICAgICAgIAovLyBMb2dnZXIgLSBTdHJ1Y3R1cmVkIGxvZ2dpbmcgc3lzdGVtIGZvciBkZWJ1Z2dpbmcKLy8gQ3JpdGljYWwgZm9yIG1vYmlsZSBkZWJ1Z2dpbmcgYW5kIHJlbW90ZSB0ZXN0aW5nCgpjbGFzcyBMb2dnZXIgewogICAgc3RhdGljIGxldmVscyA9IHsKICAgICAgICBERUJVRzogMCwKICAgICAgICBJTkZPOiAxLAogICAgICAgIFdBUk46IDIsCiAgICAgICAgRVJST1I6IDMKICAgIH07CiAgICAKICAgIHN0YXRpYyBjdXJyZW50TGV2ZWwgPSBMb2dnZXIubGV2ZWxzLklORk87CiAgICBzdGF0aWMgbG9ncyA9IFtdOyAgLy8gU3RvcmUgbG9ncyBmb3IgcmVtb3RlIGRlYnVnZ2luZwogICAgc3RhdGljIG1heExvZ3MgPSAxMDAwOwogICAgCiAgICAvKioKICAgICAqIExvZyBhIG1lc3NhZ2Ugd2l0aCBsZXZlbCwgY29tcG9uZW50LCBhbmQgb3B0aW9uYWwgZGF0YQogICAgICovCiAgICBzdGF0aWMgbG9nKGxldmVsLCBjb21wb25lbnQsIG1lc3NhZ2UsIGRhdGEgPSBudWxsKSB7CiAgICAgICAgaWYgKGxldmVsIDwgTG9nZ2VyLmN1cnJlbnRMZXZlbCkgcmV0dXJuOwogICAgICAgIAogICAgICAgIGNvbnN0IHRpbWVzdGFtcCA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKTsKICAgICAgICBjb25zdCBsZXZlbE5hbWUgPSBPYmplY3Qua2V5cyhMb2dnZXIubGV2ZWxzKVtsZXZlbF07CiAgICAgICAgCiAgICAgICAgY29uc3QgbG9nRW50cnkgPSB7CiAgICAgICAgICAgIHRpbWVzdGFtcCwKICAgICAgICAgICAgbGV2ZWw6IGxldmVsTmFtZSwKICAgICAgICAgICAgY29tcG9uZW50LAogICAgICAgICAgICBtZXNzYWdlLAogICAgICAgICAgICBkYXRhCiAgICAgICAgfTsKICAgICAgICAKICAgICAgICAvLyBTdG9yZSBsb2cKICAgICAgICBMb2dnZXIubG9ncy5wdXNoKGxvZ0VudHJ5KTsKICAgICAgICAKICAgICAgICAvLyBLZWVwIG9ubHkgbGFzdCBOIGxvZ3MKICAgICAgICBpZiAoTG9nZ2VyLmxvZ3MubGVuZ3RoID4gTG9nZ2VyLm1heExvZ3MpIHsKICAgICAgICAgICAgTG9nZ2VyLmxvZ3Muc2hpZnQoKTsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgLy8gQ29uc29sZSBvdXRwdXQgd2l0aCBjb2xvciBjb2RpbmcKICAgICAgICBjb25zdCBjb25zb2xlTWV0aG9kID0gWydsb2cnLCAnaW5mbycsICd3YXJuJywgJ2Vycm9yJ11bbGV2ZWxdOwogICAgICAgIGNvbnN0IHByZWZpeCA9IGBbJHtsZXZlbE5hbWV9XSBbJHtjb21wb25lbnR9XWA7CiAgICAgICAgCiAgICAgICAgaWYgKGRhdGEgIT09IG51bGwpIHsKICAgICAgICAgICAgY29uc29sZVtjb25zb2xlTWV0aG9kXShwcmVmaXgsIG1lc3NhZ2UsIGRhdGEpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGNvbnNvbGVbY29uc29sZU1ldGhvZF0ocHJlZml4LCBtZXNzYWdlKTsKICAgICAgICB9CiAgICB9CiAgICAKICAgIHN0YXRpYyBkZWJ1Zyhjb21wb25lbnQsIG1lc3NhZ2UsIGRhdGEgPSBudWxsKSB7CiAgICAgICAgTG9nZ2VyLmxvZyhMb2dnZXIubGV2ZWxzLkRFQlVHLCBjb21wb25lbnQsIG1lc3NhZ2UsIGRhdGEpOwogICAgfQogICAgCiAgICBzdGF0aWMgaW5mbyhjb21wb25lbnQsIG1lc3NhZ2UsIGRhdGEgPSBudWxsKSB7CiAgICAgICAgTG9nZ2VyLmxvZyhMb2dnZXIubGV2ZWxzLklORk8sIGNvbXBvbmVudCwgbWVzc2FnZSwgZGF0YSk7CiAgICB9CiAgICAKICAgIHN0YXRpYyB3YXJuKGNvbXBvbmVudCwgbWVzc2FnZSwgZGF0YSA9IG51bGwpIHsKICAgICAgICBMb2dnZXIubG9nKExvZ2dlci5sZXZlbHMuV0FSTiwgY29tcG9uZW50LCBtZXNzYWdlLCBkYXRhKTsKICAgIH0KICAgIAogICAgc3RhdGljIGVycm9yKGNvbXBvbmVudCwgbWVzc2FnZSwgZGF0YSA9IG51bGwpIHsKICAgICAgICBMb2dnZXIubG9nKExvZ2dlci5sZXZlbHMuRVJST1IsIGNvbXBvbmVudCwgbWVzc2FnZSwgZGF0YSk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogRXhwb3J0IGxvZ3MgYXMgSlNPTiAoZm9yIHJlbW90ZSBkZWJ1Z2dpbmcpCiAgICAgKi8KICAgIHN0YXRpYyBleHBvcnRMb2dzKCkgewogICAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShMb2dnZXIubG9ncywgbnVsbCwgMik7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogRG93bmxvYWQgbG9ncyBhcyBmaWxlIChmb3IgbW9iaWxlIGRlYnVnZ2luZykKICAgICAqLwogICAgc3RhdGljIGRvd25sb2FkTG9ncygpIHsKICAgICAgICBjb25zdCBsb2dEYXRhID0gTG9nZ2VyLmV4cG9ydExvZ3MoKTsKICAgICAgICBjb25zdCBibG9iID0gbmV3IEJsb2IoW2xvZ0RhdGFdLCB7IHR5cGU6ICdhcHBsaWNhdGlvbi9qc29uJyB9KTsKICAgICAgICBjb25zdCB1cmwgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKGJsb2IpOwogICAgICAgIAogICAgICAgIGNvbnN0IGxpbmsgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7CiAgICAgICAgbGluay5ocmVmID0gdXJsOwogICAgICAgIGxpbmsuZG93bmxvYWQgPSBgdHYtc3RhdGljLWxvZ3MtJHtEYXRlLm5vdygpfS5qc29uYDsKICAgICAgICBsaW5rLmNsaWNrKCk7CiAgICAgICAgCiAgICAgICAgVVJMLnJldm9rZU9iamVjdFVSTCh1cmwpOwogICAgICAgIExvZ2dlci5pbmZvKCdMT0dHRVInLCAnTG9ncyBkb3dubG9hZGVkJyk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogU2hvdyBkZWJ1ZyBvdmVybGF5IChmb3IgbW9iaWxlIGRlYnVnZ2luZykKICAgICAqLwogICAgc3RhdGljIHNob3dEZWJ1Z092ZXJsYXkoKSB7CiAgICAgICAgLy8gUmVtb3ZlIGV4aXN0aW5nIG92ZXJsYXkgaWYgcHJlc2VudAogICAgICAgIGNvbnN0IGV4aXN0aW5nID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2RlYnVnLW92ZXJsYXknKTsKICAgICAgICBpZiAoZXhpc3RpbmcpIHsKICAgICAgICAgICAgZXhpc3RpbmcucmVtb3ZlKCk7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgY29uc3Qgb3ZlcmxheSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpOwogICAgICAgIG92ZXJsYXkuaWQgPSAnZGVidWctb3ZlcmxheSc7CiAgICAgICAgb3ZlcmxheS5zdHlsZS5jc3NUZXh0ID0gYAogICAgICAgICAgICBwb3NpdGlvbjogZml4ZWQ7CiAgICAgICAgICAgIHRvcDogMTBweDsKICAgICAgICAgICAgcmlnaHQ6IDEwcHg7CiAgICAgICAgICAgIHdpZHRoOiAzMDBweDsKICAgICAgICAgICAgbWF4LWhlaWdodDogNDAwcHg7CiAgICAgICAgICAgIGJhY2tncm91bmQ6IHJnYmEoMCwgMCwgMCwgMC45KTsKICAgICAgICAgICAgY29sb3I6ICMwZjA7CiAgICAgICAgICAgIGZvbnQtZmFtaWx5OiBtb25vc3BhY2U7CiAgICAgICAgICAgIGZvbnQtc2l6ZTogMTBweDsKICAgICAgICAgICAgcGFkZGluZzogMTBweDsKICAgICAgICAgICAgb3ZlcmZsb3cteTogYXV0bzsKICAgICAgICAgICAgei1pbmRleDogMTAwMDA7CiAgICAgICAgICAgIGJvcmRlcjogMXB4IHNvbGlkICMwZjA7CiAgICAgICAgICAgIHBvaW50ZXItZXZlbnRzOiBub25lOwogICAgICAgIGA7CiAgICAgICAgCiAgICAgICAgLy8gRm9ybWF0IHJlY2VudCBsb2dzCiAgICAgICAgY29uc3QgcmVjZW50TG9ncyA9IExvZ2dlci5sb2dzLnNsaWNlKC01MCk7CiAgICAgICAgb3ZlcmxheS5pbm5lckhUTUwgPSByZWNlbnRMb2dzLm1hcChsb2cgPT4gCiAgICAgICAgICAgIGA8ZGl2IHN0eWxlPSJtYXJnaW4tYm90dG9tOiA1cHg7IGNvbG9yOiAkewogICAgICAgICAgICAgICAgbG9nLmxldmVsID09PSAnRVJST1InID8gJyNmMDAnIDogCiAgICAgICAgICAgICAgICBsb2cubGV2ZWwgPT09ICdXQVJOJyA/ICcjZmYwJyA6IAogICAgICAgICAgICAgICAgbG9nLmxldmVsID09PSAnSU5GTycgPyAnIzBmMCcgOiAKICAgICAgICAgICAgICAgICcjODg4JwogICAgICAgICAgICB9Ij4KICAgICAgICAgICAgICAgIFske2xvZy5sZXZlbH1dICR7bG9nLmNvbXBvbmVudH06ICR7bG9nLm1lc3NhZ2V9CiAgICAgICAgICAgIDwvZGl2PmAKICAgICAgICApLmpvaW4oJycpOwogICAgICAgIAogICAgICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQob3ZlcmxheSk7CiAgICAgICAgTG9nZ2VyLmluZm8oJ0xPR0dFUicsICdEZWJ1ZyBvdmVybGF5IGRpc3BsYXllZCcpOwogICAgfQogICAgCiAgICAvKioKICAgICAqIENsZWFyIGFsbCBsb2dzCiAgICAgKi8KICAgIHN0YXRpYyBjbGVhckxvZ3MoKSB7CiAgICAgICAgTG9nZ2VyLmxvZ3MgPSBbXTsKICAgICAgICBMb2dnZXIuaW5mbygnTE9HR0VSJywgJ0xvZ3MgY2xlYXJlZCcpOwogICAgfQogICAgCiAgICAvKioKICAgICAqIFNldCBsb2dnaW5nIGxldmVsCiAgICAgKi8KICAgIHN0YXRpYyBzZXRMZXZlbChsZXZlbCkgewogICAgICAgIExvZ2dlci5jdXJyZW50TGV2ZWwgPSBsZXZlbDsKICAgICAgICBMb2dnZXIuaW5mbygnTE9HR0VSJywgYExvZyBsZXZlbCBzZXQgdG8gJHtPYmplY3Qua2V5cyhMb2dnZXIubGV2ZWxzKVtsZXZlbF19YCk7CiAgICB9Cn0KCi8vIEdsb2JhbCBrZXlib2FyZCBzaG9ydGN1dHMgZm9yIGRlYnVnZ2luZyAoZGV2IG1vZGUpCmlmICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJykgewogICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2tleWRvd24nLCAoZSkgPT4gewogICAgICAgIC8vIEN0cmwrU2hpZnQrRCA9IFRvZ2dsZSBkZWJ1ZyBvdmVybGF5CiAgICAgICAgaWYgKGUuY3RybEtleSAmJiBlLnNoaWZ0S2V5ICYmIGUua2V5ID09PSAnRCcpIHsKICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpOwogICAgICAgICAgICBMb2dnZXIuc2hvd0RlYnVnT3ZlcmxheSgpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICAvLyBDdHJsK1NoaWZ0K0wgPSBEb3dubG9hZCBsb2dzCiAgICAgICAgaWYgKGUuY3RybEtleSAmJiBlLnNoaWZ0S2V5ICYmIGUua2V5ID09PSAnTCcpIHsKICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpOwogICAgICAgICAgICBMb2dnZXIuZG93bmxvYWRMb2dzKCk7CiAgICAgICAgfQogICAgfSk7Cn0KCi8vIEV4cG9ydCBmb3IgRVMgbW9kdWxlcwpMb2dnZXI7CgoKLy8gSVJlbmRlcmVyLmpzIC0gQWJzdHJhY3QgcmVuZGVyZXIgaW50ZXJmYWNlCi8vIEJvdGggV2ViR1BVIGFuZCBXZWJHTCByZW5kZXJlcnMgbXVzdCBpbXBsZW1lbnQgdGhpcyBpbnRlcmZhY2UKLy8gRW5zdXJlcyB0aGV5IGNhbiBiZSB1c2VkIGludGVyY2hhbmdlYWJseSBieSB0aGUgYXBwbGljYXRpb24KCi8qKgogKiBBYnN0cmFjdCBiYXNlIGNsYXNzIGZvciByZW5kZXJlcnMKICogRGVmaW5lcyB0aGUgY29udHJhY3QgdGhhdCBib3RoIFdlYkdQVSBhbmQgV2ViR0wgcmVuZGVyZXJzIG11c3QgZm9sbG93CiAqLwpjbGFzcyBJUmVuZGVyZXIgewogICAgY29uc3RydWN0b3IodHlwZSkgewogICAgICAgIHRoaXMudHlwZSA9IHR5cGU7ICAvLyAnd2ViZ3B1JyBvciAnd2ViZ2wnCiAgICAgICAgCiAgICAgICAgdGhpcy5zdGF0ZSA9IHsKICAgICAgICAgICAgaXNJbml0aWFsaXplZDogZmFsc2UsCiAgICAgICAgICAgIGNhbnZhczogbnVsbAogICAgICAgIH07CiAgICB9CiAgICAKICAgIC8qKgogICAgICogSW5pdGlhbGl6ZSB0aGUgcmVuZGVyZXIgd2l0aCBhIGNhbnZhcwogICAgICogQHBhcmFtIHtIVE1MQ2FudmFzRWxlbWVudH0gY2FudmFzIC0gVGFyZ2V0IGNhbnZhcyBlbGVtZW50CiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gVHJ1ZSBpZiBpbml0aWFsaXphdGlvbiBzdWNjZXNzZnVsCiAgICAgKi8KICAgIGFzeW5jIGluaXRpYWxpemUoY2FudmFzKSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke3RoaXMuY29uc3RydWN0b3IubmFtZX0gbXVzdCBpbXBsZW1lbnQgaW5pdGlhbGl6ZSgpYCk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogUmVnaXN0ZXIgYW4gZWZmZWN0IHdpdGggdGhlIHJlbmRlcmVyCiAgICAgKiBAcGFyYW0ge0VmZmVjdH0gZWZmZWN0IC0gRWZmZWN0IGluc3RhbmNlIHRvIHJlZ2lzdGVyCiAgICAgKi8KICAgIGFzeW5jIHJlZ2lzdGVyRWZmZWN0KGVmZmVjdCkgewogICAgICAgIHRocm93IG5ldyBFcnJvcihgJHt0aGlzLmNvbnN0cnVjdG9yLm5hbWV9IG11c3QgaW1wbGVtZW50IHJlZ2lzdGVyRWZmZWN0KClgKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBDcmVhdGUgcmVuZGVyaW5nIHBpcGVsaW5lIGZvciBhbiBlZmZlY3QKICAgICAqIEBwYXJhbSB7RWZmZWN0fSBlZmZlY3QgLSBFZmZlY3QgdG8gY3JlYXRlIHBpcGVsaW5lIGZvcgogICAgICogQHBhcmFtIHtib29sZWFufSBuZWVkc1RleHR1cmVJbnB1dCAtIFdoZXRoZXIgZWZmZWN0IG5lZWRzIHRleHR1cmUgaW5wdXQgKGZvciBwb3N0LXByb2Nlc3NpbmcpCiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxhbnk+fSBDcmVhdGVkIHBpcGVsaW5lICh0eXBlIGRlcGVuZHMgb24gcmVuZGVyZXIpCiAgICAgKi8KICAgIGFzeW5jIGNyZWF0ZVBpcGVsaW5lKGVmZmVjdCwgbmVlZHNUZXh0dXJlSW5wdXQgPSBmYWxzZSkgewogICAgICAgIHRocm93IG5ldyBFcnJvcihgJHt0aGlzLmNvbnN0cnVjdG9yLm5hbWV9IG11c3QgaW1wbGVtZW50IGNyZWF0ZVBpcGVsaW5lKClgKTsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBDcmVhdGUgaW50ZXJtZWRpYXRlIHRleHR1cmUgZm9yIG11bHRpLXBhc3MgcmVuZGVyaW5nCiAgICAgKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBUZXh0dXJlIHdpZHRoCiAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gVGV4dHVyZSBoZWlnaHQKICAgICAqLwogICAgY3JlYXRlSW50ZXJtZWRpYXRlVGV4dHVyZSh3aWR0aCwgaGVpZ2h0KSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke3RoaXMuY29uc3RydWN0b3IubmFtZX0gbXVzdCBpbXBsZW1lbnQgY3JlYXRlSW50ZXJtZWRpYXRlVGV4dHVyZSgpYCk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogUmVuZGVyIGEgc2luZ2xlIGVmZmVjdCBkaXJlY3RseSB0byBzY3JlZW4KICAgICAqIEBwYXJhbSB7RWZmZWN0fSBlZmZlY3QgLSBFZmZlY3QgdG8gcmVuZGVyCiAgICAgKiBAcGFyYW0ge251bWJlcn0gdGltZXN0YW1wIC0gQ3VycmVudCB0aW1lc3RhbXAKICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIENhbnZhcyB3aWR0aAogICAgICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIENhbnZhcyBoZWlnaHQKICAgICAqLwogICAgcmVuZGVyU2luZ2xlUGFzcyhlZmZlY3QsIHRpbWVzdGFtcCwgd2lkdGgsIGhlaWdodCkgewogICAgICAgIHRocm93IG5ldyBFcnJvcihgJHt0aGlzLmNvbnN0cnVjdG9yLm5hbWV9IG11c3QgaW1wbGVtZW50IHJlbmRlclNpbmdsZVBhc3MoKWApOwogICAgfQogICAgCiAgICAvKioKICAgICAqIFJlbmRlciB0d28gZWZmZWN0cyBpbiBzZXF1ZW5jZSAobXVsdGktcGFzcyByZW5kZXJpbmcpCiAgICAgKiBAcGFyYW0ge0VmZmVjdH0gZmlyc3RFZmZlY3QgLSBGaXJzdCBlZmZlY3QgKHJlbmRlcnMgdG8gaW50ZXJtZWRpYXRlIHRleHR1cmUpCiAgICAgKiBAcGFyYW0ge0VmZmVjdH0gc2Vjb25kRWZmZWN0IC0gU2Vjb25kIGVmZmVjdCAocmVhZHMgdGV4dHVyZSwgcmVuZGVycyB0byBzY3JlZW4pCiAgICAgKiBAcGFyYW0ge251bWJlcn0gdGltZXN0YW1wIC0gQ3VycmVudCB0aW1lc3RhbXAKICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIENhbnZhcyB3aWR0aAogICAgICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIENhbnZhcyBoZWlnaHQKICAgICAqLwogICAgcmVuZGVyTXVsdGlQYXNzKGZpcnN0RWZmZWN0LCBzZWNvbmRFZmZlY3QsIHRpbWVzdGFtcCwgd2lkdGgsIGhlaWdodCkgewogICAgICAgIHRocm93IG5ldyBFcnJvcihgJHt0aGlzLmNvbnN0cnVjdG9yLm5hbWV9IG11c3QgaW1wbGVtZW50IHJlbmRlck11bHRpUGFzcygpYCk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogSGFuZGxlIGNhbnZhcyByZXNpemUKICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIE5ldyB3aWR0aAogICAgICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIE5ldyBoZWlnaHQKICAgICAqLwogICAgcmVzaXplKHdpZHRoLCBoZWlnaHQpIHsKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7dGhpcy5jb25zdHJ1Y3Rvci5uYW1lfSBtdXN0IGltcGxlbWVudCByZXNpemUoKWApOwogICAgfQogICAgCiAgICAvKioKICAgICAqIEdldCByZW5kZXJlciB0eXBlICgnd2ViZ3B1JyBvciAnd2ViZ2wnKQogICAgICogQHJldHVybnMge3N0cmluZ30gUmVuZGVyZXIgdHlwZQogICAgICovCiAgICBnZXRUeXBlKCkgewogICAgICAgIHJldHVybiB0aGlzLnR5cGU7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogR2V0IHJlbmRlcmVyIHN0YXRlIGZvciBkZWJ1Z2dpbmcKICAgICAqIEByZXR1cm5zIHtPYmplY3R9IEN1cnJlbnQgc3RhdGUKICAgICAqLwogICAgZ2V0U3RhdGUoKSB7CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgdHlwZTogdGhpcy50eXBlLAogICAgICAgICAgICBpc0luaXRpYWxpemVkOiB0aGlzLnN0YXRlLmlzSW5pdGlhbGl6ZWQKICAgICAgICB9OwogICAgfQogICAgCiAgICAvKioKICAgICAqIENsZWFuIHVwIGFsbCBHUFUgcmVzb3VyY2VzCiAgICAgKi8KICAgIGRlc3Ryb3koKSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke3RoaXMuY29uc3RydWN0b3IubmFtZX0gbXVzdCBpbXBsZW1lbnQgZGVzdHJveSgpYCk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogSGVscGVyIG1ldGhvZCBmb3IgbG9nZ2luZwogICAgICovCiAgICBsb2cobGV2ZWwsIG1lc3NhZ2UsIGRhdGEgPSBudWxsKSB7CiAgICAgICAgTG9nZ2VyW2xldmVsXSh0aGlzLnR5cGUudG9VcHBlckNhc2UoKSwgbWVzc2FnZSwgZGF0YSk7CiAgICB9Cn0KCklSZW5kZXJlcjsKCgovLyBXZWJHUFVSZW5kZXJlci5qcyAtIFdlYkdQVSByZW5kZXJpbmcgaW1wbGVtZW50YXRpb24KLy8gUmVmYWN0b3JlZCBmcm9tIHYxIG1haW4uanMgV2ViR1BVIGNvZGUKLy8gSW1wbGVtZW50cyBJUmVuZGVyZXIgaW50ZXJmYWNlIGZvciByZW5kZXJlciBhYnN0cmFjdGlvbgoKY2xhc3MgV2ViR1BVUmVuZGVyZXIgZXh0ZW5kcyBJUmVuZGVyZXIgewogICAgY29uc3RydWN0b3IoKSB7CiAgICAgICAgc3VwZXIoJ3dlYmdwdScpOwogICAgICAgIAogICAgICAgIHRoaXMuc3RhdGUgPSB7CiAgICAgICAgICAgIC4uLnRoaXMuc3RhdGUsICAvLyBJbmhlcml0IGZyb20gSVJlbmRlcmVyCiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBXZWJHUFUgcmVzb3VyY2VzCiAgICAgICAgICAgIGFkYXB0ZXI6IG51bGwsCiAgICAgICAgICAgIGRldmljZTogbnVsbCwKICAgICAgICAgICAgY29udGV4dDogbnVsbCwKICAgICAgICAgICAgZm9ybWF0OiBudWxsLAogICAgICAgICAgICAKICAgICAgICAgICAgLy8gTXVsdGktcGFzcyByZW5kZXJpbmcKICAgICAgICAgICAgbXVsdGlwYXNzOiB7CiAgICAgICAgICAgICAgICBpbnRlcm1lZGlhdGVUZXh0dXJlOiBudWxsLAogICAgICAgICAgICAgICAgaW50ZXJtZWRpYXRlVGV4dHVyZVZpZXc6IG51bGwsCiAgICAgICAgICAgICAgICBzYW1wbGVyOiBudWxsLAogICAgICAgICAgICAgICAgdGV4dHVyZUJpbmRHcm91cDogbnVsbCAgLy8gQ2FjaGVkIOKAlCByZWJ1aWx0IG9ubHkgb24gcmVzaXplLCBub3QgZXZlcnkgZnJhbWUKICAgICAgICAgICAgfSwKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIFBpcGVsaW5lcyAocmVnaXN0ZXJlZCBlZmZlY3RzKQogICAgICAgICAgICBwaXBlbGluZXM6IG5ldyBNYXAoKSwgIC8vIGVmZmVjdElkIOKGkiBHUFVSZW5kZXJQaXBlbGluZQogICAgICAgICAgICBlZmZlY3RzOiBuZXcgTWFwKCkgICAgIC8vIGVmZmVjdElkIOKGkiBFZmZlY3QgaW5zdGFuY2UKICAgICAgICB9OwogICAgfQogICAgCiAgICAvKioKICAgICAqIEluaXRpYWxpemUgV2ViR1BVCiAgICAgKiBAcGFyYW0ge0hUTUxDYW52YXNFbGVtZW50fSBjYW52YXMgLSBUYXJnZXQgY2FudmFzCiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gVHJ1ZSBpZiBzdWNjZXNzZnVsCiAgICAgKi8KICAgIGFzeW5jIGluaXRpYWxpemUoY2FudmFzLCBleGlzdGluZ0FkYXB0ZXIgPSBudWxsKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgICAgdGhpcy5zdGF0ZS5jYW52YXMgPSBjYW52YXM7CiAgICAgICAgICAgIHRoaXMubG9nKCdpbmZvJywgJ0luaXRpYWxpemluZyBXZWJHUFUuLi4nKTsKCiAgICAgICAgICAgIC8vIENoZWNrIFdlYkdQVSBzdXBwb3J0CiAgICAgICAgICAgIGlmICghbmF2aWdhdG9yLmdwdSkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdXZWJHUFUgbm90IHN1cHBvcnRlZCBpbiB0aGlzIGJyb3dzZXInKTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy8gVXNlIHRoZSBhZGFwdGVyIGZyb20gUmVuZGVyZXJGYWN0b3J5IGRldGVjdGlvbiBpZiBwcm92aWRlZCwKICAgICAgICAgICAgLy8gb3RoZXJ3aXNlIHJlcXVlc3QgYSBuZXcgb25lIChmYWxsYmFjayBmb3IgZGlyZWN0IGluc3RhbnRpYXRpb24pCiAgICAgICAgICAgIGlmIChleGlzdGluZ0FkYXB0ZXIpIHsKICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUuYWRhcHRlciA9IGV4aXN0aW5nQWRhcHRlcjsKICAgICAgICAgICAgICAgIHRoaXMubG9nKCdpbmZvJywgJ1dlYkdQVSBhZGFwdGVyIHJldXNlZCBmcm9tIGRldGVjdGlvbiAoc2tpcHBpbmcgc2Vjb25kIHJlcXVlc3RBZGFwdGVyKScpOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS5hZGFwdGVyID0gYXdhaXQgbmF2aWdhdG9yLmdwdS5yZXF1ZXN0QWRhcHRlcih7CiAgICAgICAgICAgICAgICAgICAgcG93ZXJQcmVmZXJlbmNlOiAnaGlnaC1wZXJmb3JtYW5jZScKICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9CgogICAgICAgICAgICBpZiAoIXRoaXMuc3RhdGUuYWRhcHRlcikgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBXZWJHUFUgYWRhcHRlciBmb3VuZCcpOwogICAgICAgICAgICB9CgogICAgICAgICAgICB0aGlzLmxvZygnaW5mbycsICdXZWJHUFUgYWRhcHRlciBhY3F1aXJlZCcpOwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gUmVxdWVzdCBkZXZpY2UKICAgICAgICAgICAgdGhpcy5zdGF0ZS5kZXZpY2UgPSBhd2FpdCB0aGlzLnN0YXRlLmFkYXB0ZXIucmVxdWVzdERldmljZSgpOwogICAgICAgICAgICAKICAgICAgICAgICAgaWYgKCF0aGlzLnN0YXRlLmRldmljZSkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdGYWlsZWQgdG8gZ2V0IFdlYkdQVSBkZXZpY2UnKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgdGhpcy5sb2coJ2luZm8nLCAnV2ViR1BVIGRldmljZSBhY3F1aXJlZCcpOwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gU2V0dXAgZGV2aWNlIGVycm9yIGhhbmRsaW5nIChjcml0aWNhbCBmb3IgaU9TIGRlYnVnZ2luZykKICAgICAgICAgICAgdGhpcy5zdGF0ZS5kZXZpY2UuYWRkRXZlbnRMaXN0ZW5lcigndW5jYXB0dXJlZGVycm9yJywgKGV2ZW50KSA9PiB7CiAgICAgICAgICAgICAgICB0aGlzLmxvZygnZXJyb3InLCAnV2ViR1BVIHVuY2FwdHVyZWQgZXJyb3I6JywgZXZlbnQuZXJyb3IpOwogICAgICAgICAgICAgICAgdGhpcy5sb2coJ2Vycm9yJywgJ0Vycm9yIHR5cGU6JywgZXZlbnQuZXJyb3IuY29uc3RydWN0b3IubmFtZSk7CiAgICAgICAgICAgICAgICB0aGlzLmxvZygnZXJyb3InLCAnRXJyb3IgbWVzc2FnZTonLCBldmVudC5lcnJvci5tZXNzYWdlKTsKICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBBbHNvIGxpc3RlbiBmb3IgZGV2aWNlIGxvc3QgZXZlbnRzIChpT1Mtc3BlY2lmaWMgaXNzdWVzKQogICAgICAgICAgICB0aGlzLnN0YXRlLmRldmljZS5sb3N0LnRoZW4oKGluZm8pID0+IHsKICAgICAgICAgICAgICAgIHRoaXMubG9nKCdlcnJvcicsIGBXZWJHUFUgZGV2aWNlIGxvc3Q6ICR7aW5mby5yZWFzb259YCk7CiAgICAgICAgICAgICAgICB0aGlzLmxvZygnZXJyb3InLCAnRGV2aWNlIGxvc3QgbWVzc2FnZTonLCBpbmZvLm1lc3NhZ2UpOwogICAgICAgICAgICB9KTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIFZhbGlkYXRlIGNhbnZhcyBiZWZvcmUgZ2V0dGluZyBjb250ZXh0CiAgICAgICAgICAgIGlmICghY2FudmFzIHx8ICEoY2FudmFzIGluc3RhbmNlb2YgSFRNTENhbnZhc0VsZW1lbnQpKSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY2FudmFzIGVsZW1lbnQgcHJvdmlkZWQnKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgaWYgKCFjYW52YXMuaXNDb25uZWN0ZWQpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQ2FudmFzIG11c3QgYmUgYXR0YWNoZWQgdG8gRE9NIGJlZm9yZSBnZXR0aW5nIFdlYkdQVSBjb250ZXh0Jyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgCiAgICAgICAgICAgIHRoaXMubG9nKCdkZWJ1ZycsIGBHZXR0aW5nIFdlYkdQVSBjb250ZXh0IGZyb20gY2FudmFzOiAke2NhbnZhcy5pZH0sICR7Y2FudmFzLndpZHRofXgke2NhbnZhcy5oZWlnaHR9YCk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBHZXQgY29udGV4dCAtIHRyeSB3aXRoIGVtcHR5IG9wdGlvbnMgZmlyc3QsIHRoZW4gd2l0aCBleHBsaWNpdCBvcHRpb25zCiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLmNvbnRleHQgPSBjYW52YXMuZ2V0Q29udGV4dCgnd2ViZ3B1Jyk7CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIC8vIElmIHRoYXQgZGlkbid0IHdvcmssIHRyeSB3aXRoIGV4cGxpY2l0IG51bGwKICAgICAgICAgICAgICAgIGlmICghdGhpcy5zdGF0ZS5jb250ZXh0KSB7CiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coJ3dhcm4nLCAnRmlyc3QgY29udGV4dCBhdHRlbXB0IGZhaWxlZCwgdHJ5aW5nIHdpdGggZXhwbGljaXQgb3B0aW9ucy4uLicpOwogICAgICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUuY29udGV4dCA9IGNhbnZhcy5nZXRDb250ZXh0KCd3ZWJncHUnLCB7fSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIGlmICghdGhpcy5zdGF0ZS5jb250ZXh0KSB7CiAgICAgICAgICAgICAgICAgICAgLy8gRGV0YWlsZWQgZGlhZ25vc3RpYyBpbmZvCiAgICAgICAgICAgICAgICAgICAgY29uc3QgY29udGV4dFR5cGVzID0gW107CiAgICAgICAgICAgICAgICAgICAgdHJ5IHsgaWYgKGNhbnZhcy5nZXRDb250ZXh0KCcyZCcpKSBjb250ZXh0VHlwZXMucHVzaCgnMmQnKTsgfSBjYXRjaChlKSB7fQogICAgICAgICAgICAgICAgICAgIHRyeSB7IGlmIChjYW52YXMuZ2V0Q29udGV4dCgnd2ViZ2wnKSkgY29udGV4dFR5cGVzLnB1c2goJ3dlYmdsJyk7IH0gY2F0Y2goZSkge30KICAgICAgICAgICAgICAgICAgICB0cnkgeyBpZiAoY2FudmFzLmdldENvbnRleHQoJ3dlYmdsMicpKSBjb250ZXh0VHlwZXMucHVzaCgnd2ViZ2wyJyk7IH0gY2F0Y2goZSkge30KICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoCiAgICAgICAgICAgICAgICAgICAgICAgIGBGYWlsZWQgdG8gZ2V0IFdlYkdQVSBjb250ZXh0LlxuYCArCiAgICAgICAgICAgICAgICAgICAgICAgIGBDYW52YXMgSUQ6ICR7Y2FudmFzLmlkIHx8ICd1bm5hbWVkJ31cbmAgKwogICAgICAgICAgICAgICAgICAgICAgICBgRGltZW5zaW9uczogJHtjYW52YXMud2lkdGh9eCR7Y2FudmFzLmhlaWdodH1cbmAgKwogICAgICAgICAgICAgICAgICAgICAgICBgSW4gRE9NOiAke2NhbnZhcy5pc0Nvbm5lY3RlZH1cbmAgKwogICAgICAgICAgICAgICAgICAgICAgICBgUGFyZW50OiAke2NhbnZhcy5wYXJlbnRFbGVtZW50ID8gY2FudmFzLnBhcmVudEVsZW1lbnQudGFnTmFtZSA6ICdub25lJ31cbmAgKwogICAgICAgICAgICAgICAgICAgICAgICBgT3RoZXIgY29udGV4dHMgd29yazogJHtjb250ZXh0VHlwZXMuam9pbignLCAnKSB8fCAnbm9uZSB0cmllZCd9XG5gICsKICAgICAgICAgICAgICAgICAgICAgICAgYFRoaXMgbWF5IGJlIGNhdXNlZCBieSBhIGJyb3dzZXIgZXh0ZW5zaW9uIG9yIHRoZSBjYW52YXMgYWxyZWFkeSBoYXZpbmcgYSBjb250ZXh0LmAKICAgICAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9IGNhdGNoIChlcnJvcikgewogICAgICAgICAgICAgICAgaWYgKGVycm9yLm1lc3NhZ2UgJiYgZXJyb3IubWVzc2FnZS5pbmNsdWRlcygnRmFpbGVkIHRvIGdldCBXZWJHUFUgY29udGV4dCcpKSB7CiAgICAgICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4Y2VwdGlvbiB3aGlsZSBnZXR0aW5nIFdlYkdQVSBjb250ZXh0OiAke2Vycm9yLm1lc3NhZ2V9YCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgCiAgICAgICAgICAgIHRoaXMubG9nKCdpbmZvJywgJ1dlYkdQVSBjb250ZXh0IG9idGFpbmVkIHN1Y2Nlc3NmdWxseScpOwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gR2V0IHByZWZlcnJlZCBmb3JtYXQKICAgICAgICAgICAgdGhpcy5zdGF0ZS5mb3JtYXQgPSBuYXZpZ2F0b3IuZ3B1LmdldFByZWZlcnJlZENhbnZhc0Zvcm1hdCgpOwogICAgICAgICAgICAKICAgICAgICAgICAgdGhpcy5sb2coJ2luZm8nLCBgUHJlZmVycmVkIGNhbnZhcyBmb3JtYXQ6ICR7dGhpcy5zdGF0ZS5mb3JtYXR9YCk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBDb25maWd1cmUgY29udGV4dCAobWF0Y2ggdjEgc2V0dGluZ3MgZXhhY3RseSkKICAgICAgICAgICAgdGhpcy5zdGF0ZS5jb250ZXh0LmNvbmZpZ3VyZSh7CiAgICAgICAgICAgICAgICBkZXZpY2U6IHRoaXMuc3RhdGUuZGV2aWNlLAogICAgICAgICAgICAgICAgZm9ybWF0OiB0aGlzLnN0YXRlLmZvcm1hdCwKICAgICAgICAgICAgICAgIGFscGhhTW9kZTogJ29wYXF1ZScKICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIAogICAgICAgICAgICB0aGlzLnN0YXRlLmlzSW5pdGlhbGl6ZWQgPSB0cnVlOwogICAgICAgICAgICB0aGlzLmxvZygnaW5mbycsIGBXZWJHUFUgaW5pdGlhbGl6ZWQgd2l0aCBmb3JtYXQ6ICR7dGhpcy5zdGF0ZS5mb3JtYXR9YCk7CiAgICAgICAgICAgIAogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICAgICAgCiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgICAgICAgdGhpcy5sb2coJ2Vycm9yJywgJ0ZhaWxlZCB0byBpbml0aWFsaXplIFdlYkdQVTonLCBlcnJvcik7CiAgICAgICAgICAgIHRocm93IGVycm9yOwogICAgICAgIH0KICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBSZWdpc3RlciBhbiBlZmZlY3QgKGNyZWF0ZSBHUFUgcmVzb3VyY2VzKQogICAgICogQHBhcmFtIHtFZmZlY3R9IGVmZmVjdCAtIEVmZmVjdCBpbnN0YW5jZQogICAgICovCiAgICBhc3luYyByZWdpc3RlckVmZmVjdChlZmZlY3QpIHsKICAgICAgICBpZiAoIXRoaXMuc3RhdGUuaXNJbml0aWFsaXplZCkgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JlbmRlcmVyIG5vdCBpbml0aWFsaXplZCcpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICB0cnkgewogICAgICAgICAgICAvLyBDcmVhdGUgZWZmZWN0J3MgR1BVIHJlc291cmNlcyAodW5pZm9ybXMsIGJpbmQgZ3JvdXBzKQogICAgICAgICAgICBhd2FpdCBlZmZlY3QuY3JlYXRlVW5pZm9ybXModGhpcy5zdGF0ZS5kZXZpY2UpOwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gU3RvcmUgZWZmZWN0IHJlZmVyZW5jZQogICAgICAgICAgICB0aGlzLnN0YXRlLmVmZmVjdHMuc2V0KGVmZmVjdC5pZCwgZWZmZWN0KTsKICAgICAgICAgICAgCiAgICAgICAgICAgIHRoaXMubG9nKCdkZWJ1ZycsIGBFZmZlY3QgcmVnaXN0ZXJlZDogJHtlZmZlY3QubmFtZX0gKElEOiAke2VmZmVjdC5pZH0pYCk7CiAgICAgICAgICAgIAogICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgICAgICAgIHRoaXMubG9nKCdlcnJvcicsIGBGYWlsZWQgdG8gcmVnaXN0ZXIgZWZmZWN0ICR7ZWZmZWN0Lm5hbWV9OmAsIGVycm9yKTsKICAgICAgICAgICAgdGhyb3cgZXJyb3I7CiAgICAgICAgfQogICAgfQogICAgCiAgICAvKioKICAgICAqIENyZWF0ZSByZW5kZXIgcGlwZWxpbmUgZm9yIGFuIGVmZmVjdAogICAgICogQHBhcmFtIHtFZmZlY3R9IGVmZmVjdCAtIEVmZmVjdCB0byBjcmVhdGUgcGlwZWxpbmUgZm9yCiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IG5lZWRzVGV4dHVyZUlucHV0IC0gV2hldGhlciBlZmZlY3QgbmVlZHMgdGV4dHVyZSBpbnB1dAogICAgICogQHJldHVybnMge1Byb21pc2U8R1BVUmVuZGVyUGlwZWxpbmU+fSBDcmVhdGVkIHBpcGVsaW5lCiAgICAgKi8KICAgIGFzeW5jIGNyZWF0ZVBpcGVsaW5lKGVmZmVjdCwgbmVlZHNUZXh0dXJlSW5wdXQgPSBmYWxzZSkgewogICAgICAgIHRyeSB7CiAgICAgICAgICAgIHRoaXMubG9nKCdkZWJ1ZycsIGBDcmVhdGluZyBwaXBlbGluZSBmb3IgJHtlZmZlY3QubmFtZX1gKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8vIFVzZSBlbWJlZGRlZCBzaGFkZXJzCiAgICAgICAgICAgIGNvbnN0IHZlcnRleENvZGUgPSBXRUJHUFVfU0hBREVSUy52ZXJ0ZXhfZnVsbHNjcmVlbjsKICAgICAgICAgICAgY29uc3QgZnJhZ21lbnRDb2RlID0gZWZmZWN0LmlkID09PSAwID8gV0VCR1BVX1NIQURFUlMudHZfc3RhdGljIDogV0VCR1BVX1NIQURFUlMucGl4ZWxpemF0aW9uOwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gQ3JlYXRlIHNoYWRlciBtb2R1bGVzIHdpdGggdmFsaWRhdGlvbgogICAgICAgICAgICBjb25zdCB2ZXJ0ZXhNb2R1bGUgPSB0aGlzLnN0YXRlLmRldmljZS5jcmVhdGVTaGFkZXJNb2R1bGUoewogICAgICAgICAgICAgICAgY29kZTogdmVydGV4Q29kZSwKICAgICAgICAgICAgICAgIGxhYmVsOiBgJHtlZmZlY3QubmFtZX0gVmVydGV4IFNoYWRlcmAKICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBDaGVjayBmb3Igc2hhZGVyIGNvbXBpbGF0aW9uIGVycm9ycyAoZXNwZWNpYWxseSBpbXBvcnRhbnQgZm9yIGlPUykKICAgICAgICAgICAgY29uc3QgdmVydGV4SW5mbyA9IGF3YWl0IHZlcnRleE1vZHVsZS5nZXRDb21waWxhdGlvbkluZm8oKTsKICAgICAgICAgICAgaWYgKHZlcnRleEluZm8ubWVzc2FnZXMubGVuZ3RoID4gMCkgewogICAgICAgICAgICAgICAgZm9yIChjb25zdCBtZXNzYWdlIG9mIHZlcnRleEluZm8ubWVzc2FnZXMpIHsKICAgICAgICAgICAgICAgICAgICBpZiAobWVzc2FnZS50eXBlID09PSAnZXJyb3InKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubG9nKCdlcnJvcicsIGBWZXJ0ZXggc2hhZGVyIGVycm9yOiAke21lc3NhZ2UubWVzc2FnZX1gKTsKICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBWZXJ0ZXggc2hhZGVyIGNvbXBpbGF0aW9uIGZhaWxlZDogJHttZXNzYWdlLm1lc3NhZ2V9YCk7CiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChtZXNzYWdlLnR5cGUgPT09ICd3YXJuaW5nJykgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZygnd2FybicsIGBWZXJ0ZXggc2hhZGVyIHdhcm5pbmc6ICR7bWVzc2FnZS5tZXNzYWdlfWApOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgY29uc3QgZnJhZ21lbnRNb2R1bGUgPSB0aGlzLnN0YXRlLmRldmljZS5jcmVhdGVTaGFkZXJNb2R1bGUoewogICAgICAgICAgICAgICAgY29kZTogZnJhZ21lbnRDb2RlLAogICAgICAgICAgICAgICAgbGFiZWw6IGAke2VmZmVjdC5uYW1lfSBGcmFnbWVudCBTaGFkZXJgCiAgICAgICAgICAgIH0pOwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gQ2hlY2sgZm9yIGZyYWdtZW50IHNoYWRlciBjb21waWxhdGlvbiBlcnJvcnMKICAgICAgICAgICAgY29uc3QgZnJhZ21lbnRJbmZvID0gYXdhaXQgZnJhZ21lbnRNb2R1bGUuZ2V0Q29tcGlsYXRpb25JbmZvKCk7CiAgICAgICAgICAgIGlmIChmcmFnbWVudEluZm8ubWVzc2FnZXMubGVuZ3RoID4gMCkgewogICAgICAgICAgICAgICAgZm9yIChjb25zdCBtZXNzYWdlIG9mIGZyYWdtZW50SW5mby5tZXNzYWdlcykgewogICAgICAgICAgICAgICAgICAgIGlmIChtZXNzYWdlLnR5cGUgPT09ICdlcnJvcicpIHsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coJ2Vycm9yJywgYEZyYWdtZW50IHNoYWRlciBlcnJvcjogJHttZXNzYWdlLm1lc3NhZ2V9YCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRnJhZ21lbnQgc2hhZGVyIGNvbXBpbGF0aW9uIGZhaWxlZDogJHttZXNzYWdlLm1lc3NhZ2V9YC
PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ImVuIj4KPGhlYWQ+CiAgICA8bWV0YSBjaGFyc2V0PSJVVEYtOCI+CiAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEuMCwgdXNlci1zY2FsYWJsZT1ubywgbWF4aW11bS1zY2FsZT0xLjAiPgogICAgPG1ldGEgbmFtZT0iYXBwbGUtbW9iaWxlLXdlYi1hcHAtY2FwYWJsZSIgY29udGVudD0ieWVzIj4KICAgIDxtZXRhIG5hbWU9ImFwcGxlLW1vYmlsZS13ZWItYXBwLXN0YXR1cy1iYXItc3R5bGUiIGNvbnRlbnQ9ImJsYWNrLWZ1bGxzY3JlZW4iPgogICAgPG1ldGEgbmFtZT0ibW9iaWxlLXdlYi1hcHAtY2FwYWJsZSIgY29udGVudD0ieWVzIj4KICAgIAogICAgPHRpdGxlPkJyb2tlbiBMaW5rIGJ5IE15RmkgU3R1ZGlvPC90aXRsZT4KICAgIAogICAgPHN0eWxlPgoKICAgICAgICAvKiBSZXNldCBhbmQgcHJldmVudCBzY3JvbGxpbmcgKi8KICAgICAgICAqIHsKICAgICAgICAgICAgbWFyZ2luOiAwOwogICAgICAgICAgICBwYWRkaW5nOiAwOwogICAgICAgICAgICBib3gtc2l6aW5nOiBib3JkZXItYm94OwogICAgICAgICAgICBvdmVyZmxvdzogaGlkZGVuOwogICAgICAgICAgICB0b3VjaC1hY3Rpb246IG5vbmU7IC8qIFByZXZlbnQgdG91Y2ggc2Nyb2xsaW5nIGFuZCBnZXN0dXJlcyAqLwogICAgICAgICAgICAtd2Via2l0LXRvdWNoLWNhbGxvdXQ6IG5vbmU7IC8qIFByZXZlbnQgaU9TIGNhbGxvdXQgKi8KICAgICAgICAgICAgLXdlYmtpdC11c2VyLXNlbGVjdDogbm9uZTsgLyogUHJldmVudCB0ZXh0IHNlbGVjdGlvbiAqLwogICAgICAgICAgICB1c2VyLXNlbGVjdDogbm9uZTsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgaHRtbCwgYm9keSB7CiAgICAgICAgICAgIHdpZHRoOiAxMDB2dzsKICAgICAgICAgICAgaGVpZ2h0OiAxMDB2aDsKICAgICAgICAgICAgb3ZlcmZsb3c6IGhpZGRlbjsKICAgICAgICAgICAgcG9zaXRpb246IGZpeGVkOyAvKiBQcmV2ZW50IHNjcm9sbCBvbiBtb2JpbGUgKi8KICAgICAgICAgICAgYmFja2dyb3VuZDogIzAwMDsKICAgICAgICAgICAgZm9udC1mYW1pbHk6IC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgJ1NlZ29lIFVJJywgUm9ib3RvLCBPeHlnZW4sIFVidW50dSwgQ2FudGFyZWxsLCBzYW5zLXNlcmlmOwogICAgICAgIH0KICAgICAgICAKICAgICAgICBib2R5IHsKICAgICAgICAgICAgZGlzcGxheTogZmxleDsKICAgICAgICAgICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7CiAgICAgICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIC8qIENhbnZhcyAtIGZ1bGxzY3JlZW4gd2l0aCBpT1MgU2FmYXJpIFdlYkdQVSBmaXhlcyAqLwogICAgICAgIGNhbnZhcyB7CiAgICAgICAgICAgIGRpc3BsYXk6IGJsb2NrOwogICAgICAgICAgICB3aWR0aDogMTAwdnc7CiAgICAgICAgICAgIGhlaWdodDogMTAwdmg7CiAgICAgICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTsgLyogQ2hhbmdlZCBmcm9tIGZpeGVkIGZvciBpT1MgY29tcG9zaXRpbmcgKi8KICAgICAgICAgICAgdG9wOiAwOwogICAgICAgICAgICBsZWZ0OiAwOwogICAgICAgICAgICB0b3VjaC1hY3Rpb246IG5vbmU7IC8qIENyaXRpY2FsIGZvciBwcmV2ZW50aW5nIHNjcm9sbGluZyAqLwogICAgICAgICAgICBjdXJzb3I6IGRlZmF1bHQ7CiAgICAgICAgICAgIHotaW5kZXg6IDE7CiAgICAgICAgICAgIG9wYWNpdHk6IDE7IC8qIEV4cGxpY2l0IGZvciBpT1MgKi8KICAgICAgICAgICAgdmlzaWJpbGl0eTogdmlzaWJsZTsgLyogRXhwbGljaXQgZm9yIGlPUyAqLwogICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybTogdHJhbnNsYXRlM2QoMCwgMCwgMCk7IC8qIEZvcmNlIEdQVSBsYXllciBvbiBpT1MgKi8KICAgICAgICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUzZCgwLCAwLCAwKTsKICAgICAgICAgICAgLXdlYmtpdC1iYWNrZmFjZS12aXNpYmlsaXR5OiBoaWRkZW47CiAgICAgICAgICAgIGJhY2tmYWNlLXZpc2liaWxpdHk6IGhpZGRlbjsKICAgICAgICB9CiAgICAgICAgCiAgICAKICAgIDwvc3R5bGU+CjwvaGVhZD4KPGJvZHk+CiAgICA8Y2FudmFzIGlkPSJzdGF0aWNDYW52YXMiCiAgICAgICAgICAgIHJvbGU9ImltZyIKICAgICAgICAgICAgYXJpYS1sYWJlbD0iQnJva2VuIExpbmsgYnkgTXlGaSBTdHVkaW8uIFRoaXMgd2luZG93IGlzIGZpbGxlZCB3aXRoIGJsYWNrLWFuZC13aGl0ZSBUViBzdGF0aWMuIFRoZXJlIGlzIG5vIHNvdW5kIGF0IGZpcnN0LiBPbmNlIHlvdSB0b3VjaCB0aGUgcGFnZSwgcGVyY3Vzc2l2ZSBzdGF0aWMgaXMgaGVhcmQgdGhhdCByZWFjdHMgdG8gd2hlcmUgeW91IHRvdWNoLiBZb3VyIHRvdWNoIGFsc28gYWZmZWN0cyB0aGUgYXBwZWFyYW5jZSBvZiB0aGUgc3RhdGljOiB0b3VjaGluZyB0aGUgbGVmdCBzaWRlIG9mIHRoZSBwYWdlIGNhdXNlcyBsYXJnZXIgcGl4ZWxzIHRvIGFwcGVhciBvbiB0aGUgc2NyZWVuLCB3aGlsZSB0b3VjaGluZyB0aGUgcmlnaHQgc2lkZSBjYXVzZXMgbWFueSBzbWFsbCBwaXhlbHMgdG8gYXBwZWFyLiBUb3VjaGluZyB0aGUgdG9wIG9mIHRoZSBzY3JlZW4gY2F1c2VzIHRoZSBwaXhlbHMgdG8gYmVjb21lIHNlZS10aHJvdWdoLCB3aGlsZSB0b3VjaGluZyB0aGUgYm90dG9tIG9mIHRoZSBzY3JlZW4gY2F1c2VzIHRoZSBwaXhlbHMgdG8gYmUgb3BhcXVlLiI+QnJva2VuIExpbmsgYnkgTXlGaSBTdHVkaW8uIFRoaXMgd2luZG93IGlzIGZpbGxlZCB3aXRoIGJsYWNrLWFuZC13aGl0ZSBUViBzdGF0aWMuIFRoZXJlIGlzIG5vIHNvdW5kIGF0IGZpcnN0LiBPbmNlIHlvdSB0b3VjaCB0aGUgcGFnZSwgcGVyY3Vzc2l2ZSBzdGF0aWMgaXMgaGVhcmQgdGhhdCByZWFjdHMgdG8gd2hlcmUgeW91IHRvdWNoLiBZb3VyIHRvdWNoIGFsc28gYWZmZWN0cyB0aGUgYXBwZWFyYW5jZSBvZiB0aGUgc3RhdGljOiB0b3VjaGluZyB0aGUgbGVmdCBzaWRlIG9mIHRoZSBwYWdlIGNhdXNlcyBsYXJnZXIgcGl4ZWxzIHRvIGFwcGVhciBvbiB0aGUgc2NyZWVuLCB3aGlsZSB0b3VjaGluZyB0aGUgcmlnaHQgc2lkZSBjYXVzZXMgbWFueSBzbWFsbCBwaXhlbHMgdG8gYXBwZWFyLiBUb3VjaGluZyB0aGUgdG9wIG9mIHRoZSBzY3JlZW4gY2F1c2VzIHRoZSBwaXhlbHMgdG8gYmVjb21lIHNlZS10aHJvdWdoLCB3aGlsZSB0b3VjaGluZyB0aGUgYm90dG9tIG9mIHRoZSBzY3JlZW4gY2F1c2VzIHRoZSBwaXhlbHMgdG8gYmUgb3BhcXVlLjwvY2FudmFzPgogICAgCiAgICA8c2NyaXB0IHR5cGU9Im1vZHVsZSI+CiAgICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KICAgICAgICAvLyBTSEFERVJTIChFbWJlZGRlZCBhcyB0ZW1wbGF0ZSBzdHJpbmdzKQogICAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiAgICAgICAgCiAgICAgICAgY29uc3QgV0VCR1BVX1NIQURFUlMgPSB7CiAgICAgICAgICAgIHZlcnRleF9mdWxsc2NyZWVuOiBgLy8gRnVsbHNjcmVlbiBWZXJ0ZXggU2hhZGVyCi8vIEdlbmVyYXRlcyBhIGZ1bGxzY3JlZW4gdHJpYW5nbGUgd2l0aG91dCB2ZXJ0ZXggYnVmZmVycwovLyBFZmZpY2llbnQgdGVjaG5pcXVlIGZvciBmdWxsc2NyZWVuIHBvc3QtcHJvY2Vzc2luZyBlZmZlY3RzCgpzdHJ1Y3QgVmVydGV4T3V0cHV0IHsKICAgIEBidWlsdGluKHBvc2l0aW9uKSBwb3NpdGlvbjogdmVjNDxmMzI+LAogICAgQGxvY2F0aW9uKDApIHRleENvb3JkOiB2ZWMyPGYzMj4sCn0KCkB2ZXJ0ZXgKZm4gdnNfbWFpbihAYnVpbHRpbih2ZXJ0ZXhfaW5kZXgpIHZlcnRleEluZGV4OiB1MzIpIC0+IFZlcnRleE91dHB1dCB7CiAgICB2YXIgb3V0cHV0OiBWZXJ0ZXhPdXRwdXQ7CiAgICAKICAgIC8vIEdlbmVyYXRlIGZ1bGxzY3JlZW4gdHJpYW5nbGUKICAgIC8vIFZlcnRleCAwOiAoLTEsIC0xKSBib3R0b20tbGVmdAogICAgLy8gVmVydGV4IDE6ICggMywgLTEpIGJvdHRvbS1yaWdodCAob2ZmLXNjcmVlbikKICAgIC8vIFZlcnRleCAyOiAoLTEsICAzKSB0b3AtbGVmdCAob2ZmLXNjcmVlbikKICAgIC8vIFRoaXMgdHJpYW5nbGUgY292ZXJzIHRoZSBlbnRpcmUgc2NyZWVuIGVmZmljaWVudGx5CiAgICAKICAgIC8vIENvcnJlY3QgZnVsbHNjcmVlbiB0cmlhbmdsZSBnZW5lcmF0aW9uCiAgICBsZXQgeCA9IGYzMihpMzIodmVydGV4SW5kZXggJiAxdSkpICogNC4wIC0gMS4wOwogICAgbGV0IHkgPSBmMzIoaTMyKHZlcnRleEluZGV4ID4+IDF1KSkgKiA0LjAgLSAxLjA7CiAgICAKICAgIG91dHB1dC5wb3NpdGlvbiA9IHZlYzQ8ZjMyPih4LCB5LCAwLjAsIDEuMCk7CiAgICAKICAgIC8vIENvbnZlcnQgZnJvbSBjbGlwIHNwYWNlICgtMSB0byAxKSB0byBVViBzcGFjZSAoMCB0byAxKQogICAgb3V0cHV0LnRleENvb3JkID0gdmVjMjxmMzI+KAogICAgICAgICh4ICsgMS4wKSAqIDAuNSwKICAgICAgICAoMS4wIC0geSkgKiAwLjUKICAgICk7CiAgICAKICAgIHJldHVybiBvdXRwdXQ7Cn0KCmAsCiAgICAgICAgICAgIHR2X3N0YXRpYzogYC8vIFRWIFN0YXRpYyBGcmFnbWVudCBTaGFkZXIKLy8gUHJvY2VkdXJhbGx5IGdlbmVyYXRlcyBhdXRoZW50aWMgYmxhY2sgJiB3aGl0ZSBUViBzdGF0aWMgc25vdwovLyBObyBDUlQgYXJ0aWZhY3RzIC0gcHVyZSBkaWdpdGFsIG5vaXNlIHJlcHJlc2VudGF0aW9uCi8vIE9wdGltaXplZCBmb3IgNjBmcHMrIG9uIGFsbCBkZXZpY2VzCgovLyBVbmlmb3JtcwpzdHJ1Y3QgU3RhdGljVW5pZm9ybXMgewogICAgdGltZTogZjMyLCAgICAgICAgICAgLy8gQ3VycmVudCB0aW1lIGZvciBhbmltYXRpb24KICAgIGludGVuc2l0eTogZjMyLCAgICAgIC8vIFN0YXRpYyBpbnRlbnNpdHkgKDAtMSkKICAgIF9wYWQyOiBmMzIsICAgICAgICAgIC8vIHJlc2VydmVkCiAgICBzcGVlZDogZjMyLCAgICAgICAgICAvLyBBbmltYXRpb24gc3BlZWQgbXVsdGlwbGllcgogICAgY29udHJhc3Q6IGYzMiwgICAgICAgLy8gQ29udHJhc3QgbXVsdGlwbGllcgogICAgX3BhZDU6IGYzMiwgICAgICAgICAgLy8gcmVzZXJ2ZWQKICAgIGJyaWdodG5lc3M6IGYzMiwgICAgIC8vIE92ZXJhbGwgYnJpZ2h0bmVzcyAoMC0xKQogICAgcGFkZGluZzE6IGYzMiwgICAgICAgLy8gQWxpZ25tZW50IHBhZGRpbmcKICAgIHJlc29sdXRpb246IHZlYzI8ZjMyPiwgLy8gU2NyZWVuIHJlc29sdXRpb24KICAgIHBhZGRpbmcyOiB2ZWMyPGYzMj4gICAgLy8gQWxpZ25tZW50IHBhZGRpbmcKfQoKQGdyb3VwKDApIEBiaW5kaW5nKDApIHZhcjx1bmlmb3JtPiBwYXJhbXM6IFN0YXRpY1VuaWZvcm1zOwoKc3RydWN0IFZlcnRleE91dHB1dCB7CiAgICBAYnVpbHRpbihwb3NpdGlvbikgcG9zaXRpb246IHZlYzQ8ZjMyPiwKICAgIEBsb2NhdGlvbigwKSB0ZXhDb29yZDogdmVjMjxmMzI+LAp9CgovLyBJbnRlZ2VyLWJhc2VkIGhhc2ggZnVuY3Rpb24gKG5vIGZsb2F0aW5nIHBvaW50IGJpYXMpCi8vIFVzZXMgb25seSBpbnRlZ2VyIHBpeGVsIGNvb3JkaW5hdGVzIGZvciBwZXJmZWN0IHVuaWZvcm1pdHkKZm4gaGFzaEludCh4OiB1MzIsIHk6IHUzMiwgZnJhbWU6IHUzMikgLT4gZjMyIHsKICAgIC8vIFBDRyBoYXNoIC0gaW5kdXN0cnkgc3RhbmRhcmQgZm9yIHJhbmRvbSBudW1iZXIgZ2VuZXJhdGlvbgogICAgdmFyIHNlZWQgPSB4ICsgeSAqIDM3NDc2MTM5M3UgKyBmcmFtZSAqIDY2ODI2NTI2M3U7CiAgICBzZWVkID0gKHNlZWQgXiAoc2VlZCA+PiAxNXUpKSAqIDE1OTczMzQ2Nzd1OwogICAgc2VlZCA9IChzZWVkIF4gKHNlZWQgPj4gMTV1KSkgKiAzODEyMDE1ODAxdTsKICAgIHNlZWQgPSBzZWVkIF4gKHNlZWQgPj4gMTV1KTsKICAgIAogICAgLy8gQ29udmVydCB0byAwLTEgcmFuZ2UKICAgIHJldHVybiBmMzIoc2VlZCkgLyA0Mjk0OTY3Mjk1LjA7Cn0KCi8vIFJlbW92ZWQgbm9pc2UoKSBhbmQgZmJtKCkgZnVuY3Rpb25zIC0gbm90IG5lZWRlZCBmb3IgcHVyZSByYW5kb20gc3RhdGljCgovLyBIaWdoLWZyZXF1ZW5jeSBub2lzZSBmb3IgZmluZSBkZXRhaWwgKHBlci1waXhlbCByYW5kb21uZXNzKQovLyBVc2VzIGludGVnZXIgcGl4ZWwgY29vcmRpbmF0ZXMgLSBlbGltaW5hdGVzIEFMTCBmbG9hdGluZyBwb2ludCBhcnRpZmFjdHMKZm4gZmFzdE5vaXNlKHBpeGVsUG9zOiB2ZWMyPGYzMj4sIHRpbWU6IGYzMiwgc2NhbGU6IGYzMikgLT4gZjMyIHsKICAgIC8vIFNjYWxlIGRvd24gY29vcmRpbmF0ZXMgdG8gbWFrZSBlYWNoIG5vaXNlICJwaXhlbCIgbGFyZ2VyCiAgICAvLyBzY2FsZSA9IDEwLjAgbWVhbnMgZWFjaCByYW5kb20gdmFsdWUgY292ZXJzIGEgMTB4MTAgYmxvY2sgb2Ygc2NyZWVuIHBpeGVscwogICAgbGV0IHNjYWxlZFBvcyA9IHBpeGVsUG9zIC8gc2NhbGU7CiAgICAKICAgIC8vIENvbnZlcnQgdG8gaW50ZWdlciBwaXhlbCBjb29yZGluYXRlcwogICAgbGV0IHggPSB1MzIoc2NhbGVkUG9zLngpOwogICAgbGV0IHkgPSB1MzIoc2NhbGVkUG9zLnkpOwogICAgCiAgICAvLyBGcmFtZSBjb3VudGVyIGZvciBhbmltYXRpb24KICAgIGxldCBmcmFtZSA9IHUzMih0aW1lICogNjAuMCk7CiAgICAKICAgIC8vIFB1cmUgaW50ZWdlci1iYXNlZCBoYXNoIC0gbm8gaW50ZXJwb2xhdGlvbiwgbm8gcGF0dGVybnMKICAgIHJldHVybiBoYXNoSW50KHgsIHksIGZyYW1lKTsKfQoKQGZyYWdtZW50CmZuIGZzX21haW4oaW5wdXQ6IFZlcnRleE91dHB1dCkgLT4gQGxvY2F0aW9uKDApIHZlYzQ8ZjMyPiB7CiAgICBsZXQgdXYgPSBpbnB1dC50ZXhDb29yZDsKICAgIAogICAgLy8gQW5pbWF0ZWQgdGltZSBmb3IgY2hhbmdpbmcgbm9pc2UgZWFjaCBmcmFtZQogICAgbGV0IHRpbWVBbmltYXRlZCA9IHBhcmFtcy50aW1lICogcGFyYW1zLnNwZWVkOwogICAgCiAgICAvLyBQdXJlIHBlci1waXhlbCByYW5kb20gbm9pc2UKICAgIC8vIENoYW5nZXMgY29tcGxldGVseSBldmVyeSBmcmFtZSAtIG5vIHBlcnNpc3RlbnQgcGF0dGVybnMKICAgIGxldCBwaXhlbFBvcyA9IHV2ICogcGFyYW1zLnJlc29sdXRpb247CiAgICAKICAgIC8vIEdyYWluIHNjYWxlOiAxMC4wID0gZWFjaCByYW5kb20gdmFsdWUgaXMgYSAxMHgxMCBwaXhlbCBibG9jawogICAgbGV0IGdyYWluU2NhbGUgPSAyLjA7CiAgICBsZXQgc3RhdGljVmFsdWUgPSBmYXN0Tm9pc2UocGl4ZWxQb3MsIHRpbWVBbmltYXRlZCwgZ3JhaW5TY2FsZSk7CiAgICAKICAgIC8vIEFwcGx5IGludGVuc2l0eQogICAgdmFyIHZhbHVlID0gc3RhdGljVmFsdWUgKiBwYXJhbXMuaW50ZW5zaXR5OwogICAgCiAgICAvLyBBcHBseSBjb250cmFzdCB0byBwdXNoIHRvd2FyZHMgYmxhY2sgYW5kIHdoaXRlIGV4dHJlbWVzCiAgICB2YWx1ZSA9ICh2YWx1ZSAtIDAuNSkgKiBwYXJhbXMuY29udHJhc3QgKyAwLjU7CiAgICAKICAgIC8vIEFwcGx5IGJyaWdodG5lc3MgYWRqdXN0bWVudAogICAgdmFsdWUgPSB2YWx1ZSAqIHBhcmFtcy5icmlnaHRuZXNzICsgKDEuMCAtIHBhcmFtcy5icmlnaHRuZXNzKSAqIDAuNTsKICAgIAogICAgLy8gQ2xhbXAgdG8gdmFsaWQgcmFuZ2UKICAgIHZhbHVlID0gY2xhbXAodmFsdWUsIDAuMCwgMS4wKTsKICAgIAogICAgLy8gUHVyZSBibGFjayAmIHdoaXRlIG91dHB1dCAobm8gY29sb3Igc2VwYXJhdGlvbikKICAgIGxldCBjb2xvciA9IHZlYzM8ZjMyPih2YWx1ZSk7CiAgICAKICAgIHJldHVybiB2ZWM0PGYzMj4oY29sb3IsIDEuMCk7Cn0KCmAsCiAgICAgICAgICAgIHBpeGVsaXphdGlvbjogYC8vIFBpeGVsaXphdGlvbiBFZmZlY3QgRnJhZ21lbnQgU2hhZGVyCi8vIENyZWF0ZXMgZHluYW1pYyBwaXhlbCBncmlkIG92ZXJsYXkgd2l0aCBjb25maWd1cmFibGUgZ3JhbnVsYXJpdHkKLy8gVGFrZXMgaW5wdXQgdGV4dHVyZSAoVFYgc3RhdGljKSBhbmQgcGl4ZWxpemVzIGl0CgovLyBJbnB1dCB0ZXh0dXJlIChmcm9tIHByZXZpb3VzIHJlbmRlciBwYXNzIC0gVFYgc3RhdGljKQpAZ3JvdXAoMCkgQGJpbmRpbmcoMCkgdmFyIGlucHV0VGV4dHVyZTogdGV4dHVyZV8yZDxmMzI+OwpAZ3JvdXAoMCkgQGJpbmRpbmcoMSkgdmFyIGlucHV0U2FtcGxlcjogc2FtcGxlcjsKCi8vIEVmZmVjdCBwYXJhbWV0ZXJzIHVuaWZvcm0gYnVmZmVyIChiaW5kIGdyb3VwIDEgLSBlZmZlY3Qtc3BlY2lmaWMpCnN0cnVjdCBFZmZlY3RVbmlmb3JtcyB7CiAgICBwaXhlbFJvd3M6IGYzMiwgICAgIC8vIE51bWJlciBvZiBwaXhlbCByb3dzICh2ZXJ0aWNhbCBncmFudWxhcml0eSkKICAgIHBpeGVsQ29sczogZjMyLCAgICAgLy8gTnVtYmVyIG9mIHBpeGVsIGNvbHVtbnMgKGhvcml6b250YWwgZ3JhbnVsYXJpdHkpIAogICAgY2FudmFzV2lkdGg6IGYzMiwgICAvLyBDYW52YXMgd2lkdGggaW4gcGl4ZWxzCiAgICBjYW52YXNIZWlnaHQ6IGYzMiwgIC8vIENhbnZhcyBoZWlnaHQgaW4gcGl4ZWxzCiAgICBibGVuZEZhY3RvcjogZjMyLCAgIC8vIEJsZW5kIGJldHdlZW4gc29saWQgKDAuMCkgYW5kIHRyYW5zcGFyZW50L2ZvZ2d5ICgxLjApCiAgICB0aW1lOiBmMzIsICAgICAgICAgIC8vIFRpbWUgZm9yIHN1YnRsZSBhbmltYXRpb24vdmFyaWF0aW9uCiAgICBfcGFkZGluZzE6IGYzMiwgICAgIC8vIFBhZGRpbmcgZm9yIGFsaWdubWVudAogICAgX3BhZGRpbmcyOiBmMzIsICAgICAvLyBQYWRkaW5nIGZvciBhbGlnbm1lbnQKfQpAZ3JvdXAoMSkgQGJpbmRpbmcoMCkgdmFyPHVuaWZvcm0+IGVmZmVjdFBhcmFtczogRWZmZWN0VW5pZm9ybXM7CgpzdHJ1Y3QgVmVydGV4T3V0cHV0IHsKICAgIEBidWlsdGluKHBvc2l0aW9uKSBwb3NpdGlvbjogdmVjNDxmMzI+LAogICAgQGxvY2F0aW9uKDApIHRleENvb3JkOiB2ZWMyPGYzMj4sCn0KCi8vIEhhc2ggZnVuY3Rpb24gZm9yIGdyaXR0aW5lc3Mvbm9pc2UKZm4gaGFzaChwOiB2ZWMyPGYzMj4pIC0+IGYzMiB7CiAgICBsZXQgcDMgPSBmcmFjdCh2ZWMzPGYzMj4ocC54LCBwLnksIHAueCkgKiAwLjEzKTsKICAgIGxldCBkcCA9IGRvdCh2ZWMzPGYzMj4ocC54LCBwLnksIHAueCkgKyB2ZWMzPGYzMj4ocDMueSwgcDMueiwgcDMueCksIHAzICsgdmVjMzxmMzI+KDMzLjMzKSk7CiAgICByZXR1cm4gZnJhY3QoKHAzLnggKyBwMy55KSAqIGRwKTsKfQoKLy8gU21vb3RoIG5vaXNlIGZvciBmb2dneSBlZmZlY3QKZm4gc21vb3RoTm9pc2UodXY6IHZlYzI8ZjMyPiwgc2NhbGU6IGYzMikgLT4gZjMyIHsKICAgIGxldCBzY2FsZWQgPSB1diAqIHNjYWxlOwogICAgbGV0IGkgPSBmbG9vcihzY2FsZWQpOwogICAgbGV0IGYgPSBmcmFjdChzY2FsZWQpOwogICAgCiAgICAvLyBTbW9vdGggaW50ZXJwb2xhdGlvbgogICAgbGV0IHUgPSBmICogZiAqICgzLjAgLSAyLjAgKiBmKTsKICAgIAogICAgLy8gU2FtcGxlIGNvcm5lcnMKICAgIGxldCBhID0gaGFzaChpKTsKICAgIGxldCBiID0gaGFzaChpICsgdmVjMjxmMzI+KDEuMCwgMC4wKSk7CiAgICBsZXQgYyA9IGhhc2goaSArIHZlYzI8ZjMyPigwLjAsIDEuMCkpOwogICAgbGV0IGQgPSBoYXNoKGkgKyB2ZWMyPGYzMj4oMS4wLCAxLjApKTsKICAgIAogICAgLy8gQmlsaW5lYXIgaW50ZXJwb2xhdGlvbgogICAgcmV0dXJuIG1peChtaXgoYSwgYiwgdS54KSwgbWl4KGMsIGQsIHUueCksIHUueSk7Cn0KCkBmcmFnbWVudApmbiBmc19tYWluKGlucHV0OiBWZXJ0ZXhPdXRwdXQpIC0+IEBsb2NhdGlvbigwKSB2ZWM0PGYzMj4gewogICAgbGV0IHRleENvb3JkID0gaW5wdXQudGV4Q29vcmQ7CiAgICAKICAgIC8vIENhbGN1bGF0ZSB3aGljaCBwaXhlbCBncmlkIGNlbGwgdGhpcyBmcmFnbWVudCBiZWxvbmdzIHRvCiAgICBsZXQgcGl4ZWxHcmlkUG9zID0gZmxvb3IodGV4Q29vcmQgKiB2ZWMyPGYzMj4oZWZmZWN0UGFyYW1zLnBpeGVsQ29scywgZWZmZWN0UGFyYW1zLnBpeGVsUm93cykpOwogICAgCiAgICAvLyBDYWxjdWxhdGUgdGhlIGNlbnRlciBvZiB0aGUgcGl4ZWwgY2VsbCBmb3Igc2FtcGxpbmcKICAgIC8vIEFkZGluZyAwLjUgY2VudGVycyB0aGUgc2FtcGxpbmcgcG9pbnQgd2l0aGluIGVhY2ggcGl4ZWwgY2VsbAogICAgbGV0IHBpeGVsQ2VudGVyID0gKHBpeGVsR3JpZFBvcyArIHZlYzI8ZjMyPigwLjUsIDAuNSkpIC8gdmVjMjxmMzI+KGVmZmVjdFBhcmFtcy5waXhlbENvbHMsIGVmZmVjdFBhcmFtcy5waXhlbFJvd3MpOwogICAgCiAgICAvLyBTYW1wbGUgdGhlIHBpeGVsYXRlZCBjb2xvciAoZnJvbSBwaXhlbCBjZW50ZXIgLSBzb2xpZCBibG9ja3MpCiAgICBsZXQgcGl4ZWxDb2xvciA9IHRleHR1cmVTYW1wbGUoaW5wdXRUZXh0dXJlLCBpbnB1dFNhbXBsZXIsIHBpeGVsQ2VudGVyKTsKICAgIAogICAgLy8gU2FtcGxlIHRoZSBvcmlnaW5hbCB0ZXh0dXJlIChmcm9tIGFjdHVhbCBwb3NpdGlvbiAtIHVuZGVybHlpbmcgc3RhdGljKQogICAgbGV0IG9yaWdpbmFsQ29sb3IgPSB0ZXh0dXJlU2FtcGxlKGlucHV0VGV4dHVyZSwgaW5wdXRTYW1wbGVyLCB0ZXhDb29yZCk7CiAgICAKICAgIC8vIEF0IGJsZW5kRmFjdG9yID0gMC4wOiBmdWxseSBvcGFxdWUgcGl4ZWxzIChsZWZ0IHNpZGUpCiAgICAvLyBBdCBibGVuZEZhY3RvciA9IDEuMDogZm9nZ3kvZ3JpdHR5IGJsZW5kIHNob3dpbmcgdW5kZXJseWluZyBzdGF0aWMgKHJpZ2h0IHNpZGUpCiAgICAKICAgIGlmIChlZmZlY3RQYXJhbXMuYmxlbmRGYWN0b3IgPD0gMC4wMSkgewogICAgICAgIC8vIEZ1bGx5IG9wYXF1ZSAtIGp1c3QgcmV0dXJuIHBpeGVsYXRlZCBjb2xvcgogICAgICAgIHJldHVybiBwaXhlbENvbG9yOwogICAgfQogICAgCiAgICAvLyBBZGQgZ3JpdHRpbmVzcyB1c2luZyBub2lzZSAtIHRoaXMgY3JlYXRlcyB0ZXh0dXJlIGluIHRoZSBibGVuZAogICAgbGV0IHBpeGVsUG9zID0gdGV4Q29vcmQgKiB2ZWMyPGYzMj4oZWZmZWN0UGFyYW1zLmNhbnZhc1dpZHRoLCBlZmZlY3RQYXJhbXMuY2FudmFzSGVpZ2h0KTsKICAgIGxldCBncml0dGluZXNzID0gc21vb3RoTm9pc2UocGl4ZWxQb3MsIDAuNSkgKiAwLjMgKyAwLjc7IC8vIFJhbmdlOiAwLjcgdG8gMS4wCiAgICAKICAgIC8vIENhbGN1bGF0ZSBibGVuZCBhbW91bnQgd2l0aCBncml0dGluZXNzCiAgICBsZXQgYmxlbmRBbW91bnQgPSBlZmZlY3RQYXJhbXMuYmxlbmRGYWN0b3IgKiBncml0dGluZXNzOwogICAgCiAgICAvLyBCbGVuZCBiZXR3ZWVuIHBpeGVsYXRlZCAoc29saWQpIGFuZCBvcmlnaW5hbCAoZm9nZ3kvdHJhbnNwYXJlbnQpCiAgICBsZXQgZmluYWxDb2xvciA9IG1peChwaXhlbENvbG9yLCBvcmlnaW5hbENvbG9yLCBibGVuZEFtb3VudCk7CiAgICAKICAgIHJldHVybiBmaW5hbENvbG9yOwp9CgpgCiAgICAgICAgfTsKICAgICAgICAKICAgICAgICBjb25zdCBXRUJHTF9TSEFERVJTID0gewogICAgICAgICAgICB2ZXJ0ZXhfZnVsbHNjcmVlbjogYCN2ZXJzaW9uIDMwMCBlcwovLyBGdWxsc2NyZWVuIHZlcnRleCBzaGFkZXIgLSBHTFNMIEVTIDMuMDAgKFdlYkdMIDIuMCkKLy8gQ29udmVydGVkIGZyb20gV0dTTCB2ZXJ0ZXhfZnVsbHNjcmVlbi53Z3NsCgpwcmVjaXNpb24gaGlnaHAgZmxvYXQ7CgovLyBPdXRwdXRzIHRvIGZyYWdtZW50IHNoYWRlcgpvdXQgdmVjMiB2VVY7Cgp2b2lkIG1haW4oKSB7CiAgICAvLyBHZW5lcmF0ZSBmdWxsc2NyZWVuIHRyaWFuZ2xlIHVzaW5nIHZlcnRleCBJRAogICAgLy8gVmVydGV4IDA6ICgtMSwgLTEpIGJvdHRvbS1sZWZ0CiAgICAvLyBWZXJ0ZXggMTogKDMsIC0xKSBib3R0b20tcmlnaHQgKG9mZnNjcmVlbikKICAgIC8vIFZlcnRleCAyOiAoLTEsIDMpIHRvcC1sZWZ0IChvZmZzY3JlZW4pCiAgICAKICAgIC8vIENhbGN1bGF0ZSBwb3NpdGlvbiBiYXNlZCBvbiB2ZXJ0ZXggSUQKICAgIC8vIGdsX1ZlcnRleElEIDAg4oaSIHg9LTEsIHk9LTEKICAgIC8vIGdsX1ZlcnRleElEIDEg4oaSIHg9MywgeT0tMQogICAgLy8gZ2xfVmVydGV4SUQgMiDihpIgeD0tMSwgeT0zCiAgICBmbG9hdCB4ID0gZmxvYXQoKGdsX1ZlcnRleElEICYgMSkgPDwgMikgLSAxLjA7CiAgICBmbG9hdCB5ID0gZmxvYXQoKGdsX1ZlcnRleElEICYgMikgPDwgMSkgLSAxLjA7CiAgICAKICAgIGdsX1Bvc2l0aW9uID0gdmVjNCh4LCB5LCAwLjAsIDEuMCk7CiAgICAKICAgIC8vIENhbGN1bGF0ZSBVViBjb29yZGluYXRlcyAoMCwwKSBhdCBib3R0b20tbGVmdCwgKDEsMSkgYXQgdG9wLXJpZ2h0CiAgICAvLyBGbGlwIFkgYmVjYXVzZSB0ZXh0dXJlIGNvb3JkaW5hdGVzIGFyZSB0b3AtZG93biBpbiBXZWJHTAogICAgdlVWID0gdmVjMigKICAgICAgICAoeCArIDEuMCkgKiAwLjUsCiAgICAgICAgMS4wIC0gKHkgKyAxLjApICogMC41CiAgICApOwp9CgpgLAogICAgICAgICAgICB0dl9zdGF0aWM6IGAjdmVyc2lvbiAzMDAgZXMKLy8gVFYgU3RhdGljIEZyYWdtZW50IFNoYWRlciAtIEdMU0wgRVMgMy4wMCAoV2ViR0wgMi4wKQovLyBDb252ZXJ0ZWQgZnJvbSBXR1NMIHR2X3N0YXRpYy53Z3NsCi8vIFByb2NlZHVyYWxseSBnZW5lcmF0ZXMgYXV0aGVudGljIGJsYWNrICYgd2hpdGUgVFYgc3RhdGljIHNub3cKCnByZWNpc2lvbiBoaWdocCBmbG9hdDsKCi8vIFVuaWZvcm1zIChtYXRjaGVzIFdHU0wgU3RhdGljVW5pZm9ybXMgc3RydWN0KQp1bmlmb3JtIGZsb2F0IHRpbWU7ICAgICAgICAgICAvLyBDdXJyZW50IHRpbWUgZm9yIGFuaW1hdGlvbgp1bmlmb3JtIGZsb2F0IGludGVuc2l0eTsgICAgICAvLyBTdGF0aWMgaW50ZW5zaXR5ICgwLTEpCnVuaWZvcm0gZmxvYXQgc3BlZWQ7ICAgICAgICAgIC8vIEFuaW1hdGlvbiBzcGVlZCBtdWx0aXBsaWVyCnVuaWZvcm0gZmxvYXQgY29udHJhc3Q7ICAgICAgIC8vIENvbnRyYXN0IG11bHRpcGxpZXIKdW5pZm9ybSBmbG9hdCBicmlnaHRuZXNzOyAgICAgLy8gT3ZlcmFsbCBicmlnaHRuZXNzICgwLTEpCi8vIHBhZGRpbmcxIG5vdCBuZWVkZWQgaW4gR0xTTAp1bmlmb3JtIHZlYzIgcmVzb2x1dGlvbjsgICAgICAvLyBTY3JlZW4gcmVzb2x1dGlvbgovLyBwYWRkaW5nMiBub3QgbmVlZGVkIGluIEdMU0wKCi8vIElucHV0IGZyb20gdmVydGV4IHNoYWRlcgppbiB2ZWMyIHZVVjsKCi8vIE91dHB1dCBjb2xvcgpvdXQgdmVjNCBmcmFnQ29sb3I7CgovLyBJbnRlZ2VyLWJhc2VkIGhhc2ggZnVuY3Rpb24gKG5vIGZsb2F0aW5nIHBvaW50IGJpYXMpCi8vIFVzZXMgb25seSBpbnRlZ2VyIHBpeGVsIGNvb3JkaW5hdGVzIGZvciBwZXJmZWN0IHVuaWZvcm1pdHkKZmxvYXQgaGFzaEludCh1aW50IHgsIHVpbnQgeSwgdWludCBmcmFtZSkgewogICAgLy8gUENHIGhhc2ggLSBpbmR1c3RyeSBzdGFuZGFyZCBmb3IgcmFuZG9tIG51bWJlciBnZW5lcmF0aW9uCiAgICB1aW50IHNlZWQgPSB4ICsgeSAqIDM3NDc2MTM5M3UgKyBmcmFtZSAqIDY2ODI2NTI2M3U7CiAgICBzZWVkID0gKHNlZWQgXiAoc2VlZCA+PiAxNXUpKSAqIDE1OTczMzQ2Nzd1OwogICAgc2VlZCA9IChzZWVkIF4gKHNlZWQgPj4gMTV1KSkgKiAzODEyMDE1ODAxdTsKICAgIHNlZWQgPSBzZWVkIF4gKHNlZWQgPj4gMTV1KTsKICAgIAogICAgLy8gQ29udmVydCB0byAwLTEgcmFuZ2UKICAgIHJldHVybiBmbG9hdChzZWVkKSAvIDQyOTQ5NjcyOTUuMDsKfQoKLy8gSGlnaC1mcmVxdWVuY3kgbm9pc2UgZm9yIGZpbmUgZGV0YWlsIChwZXItcGl4ZWwgcmFuZG9tbmVzcykKLy8gVXNlcyBpbnRlZ2VyIHBpeGVsIGNvb3JkaW5hdGVzIC0gZWxpbWluYXRlcyBBTEwgZmxvYXRpbmcgcG9pbnQgYXJ0aWZhY3RzCmZsb2F0IGZhc3ROb2lzZSh2ZWMyIHBpeGVsUG9zLCBmbG9hdCB0LCBmbG9hdCBzY2FsZSkgewogICAgLy8gU2NhbGUgZG93biBjb29yZGluYXRlcyB0byBtYWtlIGVhY2ggbm9pc2UgInBpeGVsIiBsYXJnZXIKICAgIC8vIHNjYWxlID0gMTAuMCBtZWFucyBlYWNoIHJhbmRvbSB2YWx1ZSBjb3ZlcnMgYSAxMHgxMCBibG9jayBvZiBzY3JlZW4gcGl4ZWxzCiAgICB2ZWMyIHNjYWxlZFBvcyA9IHBpeGVsUG9zIC8gc2NhbGU7CiAgICAKICAgIC8vIENvbnZlcnQgdG8gaW50ZWdlciBwaXhlbCBjb29yZGluYXRlcwogICAgdWludCB4ID0gdWludChzY2FsZWRQb3MueCk7CiAgICB1aW50IHkgPSB1aW50KHNjYWxlZFBvcy55KTsKICAgIAogICAgLy8gRnJhbWUgY291bnRlciBmb3IgYW5pbWF0aW9uCiAgICB1aW50IGZyYW1lID0gdWludCh0ICogNjAuMCk7CiAgICAKICAgIC8vIFB1cmUgaW50ZWdlci1iYXNlZCBoYXNoIC0gbm8gaW50ZXJwb2xhdGlvbiwgbm8gcGF0dGVybnMKICAgIHJldHVybiBoYXNoSW50KHgsIHksIGZyYW1lKTsKfQoKdm9pZCBtYWluKCkgewogICAgdmVjMiB1diA9IHZVVjsKICAgIAogICAgLy8gQW5pbWF0ZWQgdGltZSBmb3IgY2hhbmdpbmcgbm9pc2UgZWFjaCBmcmFtZQogICAgZmxvYXQgdGltZUFuaW1hdGVkID0gdGltZSAqIHNwZWVkOwogICAgCiAgICAvLyBQdXJlIHBlci1waXhlbCByYW5kb20gbm9pc2UKICAgIC8vIENoYW5nZXMgY29tcGxldGVseSBldmVyeSBmcmFtZSAtIG5vIHBlcnNpc3RlbnQgcGF0dGVybnMKICAgIHZlYzIgcGl4ZWxQb3MgPSB1diAqIHJlc29sdXRpb247CiAgICAKICAgIC8vIEdyYWluIHNjYWxlOiAxMC4wID0gZWFjaCByYW5kb20gdmFsdWUgaXMgYSAxMHgxMCBwaXhlbCBibG9jawogICAgZmxvYXQgZ3JhaW5TY2FsZSA9IDIuMDsKICAgIGZsb2F0IHN0YXRpY1ZhbHVlID0gZmFzdE5vaXNlKHBpeGVsUG9zLCB0aW1lQW5pbWF0ZWQsIGdyYWluU2NhbGUpOwogICAgCiAgICAvLyBBcHBseSBpbnRlbnNpdHkKICAgIGZsb2F0IHZhbHVlID0gc3RhdGljVmFsdWUgKiBpbnRlbnNpdHk7CiAgICAKICAgIC8vIEFwcGx5IGNvbnRyYXN0IHRvIHB1c2ggdG93YXJkcyBibGFjayBhbmQgd2hpdGUgZXh0cmVtZXMKICAgIHZhbHVlID0gKHZhbHVlIC0gMC41KSAqIGNvbnRyYXN0ICsgMC41OwogICAgCiAgICAvLyBBcHBseSBicmlnaHRuZXNzIGFkanVzdG1lbnQKICAgIHZhbHVlID0gdmFsdWUgKiBicmlnaHRuZXNzICsgKDEuMCAtIGJyaWdodG5lc3MpICogMC41OwogICAgCiAgICAvLyBDbGFtcCB0byB2YWxpZCByYW5nZQogICAgdmFsdWUgPSBjbGFtcCh2YWx1ZSwgMC4wLCAxLjApOwogICAgCiAgICAvLyBQdXJlIGJsYWNrICYgd2hpdGUgb3V0cHV0IChubyBjb2xvciBzZXBhcmF0aW9uKQogICAgdmVjMyBjb2xvciA9IHZlYzModmFsdWUpOwogICAgCiAgICBmcmFnQ29sb3IgPSB2ZWM0KGNvbG9yLCAxLjApOwp9CgpgLAogICAgICAgICAgICBwaXhlbGl6YXRpb246IGAjdmVyc2lvbiAzMDAgZXMKLy8gUGl4ZWxpemF0aW9uIEVmZmVjdCBGcmFnbWVudCBTaGFkZXIgLSBHTFNMIEVTIDMuMDAgKFdlYkdMIDIuMCkKLy8gQ29udmVydGVkIGZyb20gV0dTTCBwaXhlbGl6YXRpb24ud2dzbAovLyBDcmVhdGVzIGR5bmFtaWMgcGl4ZWwgZ3JpZCBvdmVybGF5IHdpdGggY29uZmlndXJhYmxlIGdyYW51bGFyaXR5CgpwcmVjaXNpb24gaGlnaHAgZmxvYXQ7CgovLyBJbnB1dCB0ZXh0dXJlIChmcm9tIHByZXZpb3VzIHJlbmRlciBwYXNzIC0gVFYgc3RhdGljKQp1bmlmb3JtIHNhbXBsZXIyRCBpbnB1dFRleHR1cmU7CgovLyBFZmZlY3QgcGFyYW1ldGVycyAobWF0Y2hlcyBXR1NMIEVmZmVjdFVuaWZvcm1zIHN0cnVjdCkKdW5pZm9ybSBmbG9hdCBwaXhlbFJvd3M7ICAgICAvLyBOdW1iZXIgb2YgcGl4ZWwgcm93cyAodmVydGljYWwgZ3JhbnVsYXJpdHkpCnVuaWZvcm0gZmxvYXQgcGl4ZWxDb2xzOyAgICAgLy8gTnVtYmVyIG9mIHBpeGVsIGNvbHVtbnMgKGhvcml6b250YWwgZ3JhbnVsYXJpdHkpCnVuaWZvcm0gZmxvYXQgY2FudmFzV2lkdGg7ICAgLy8gQ2FudmFzIHdpZHRoIGluIHBpeGVscwp1bmlmb3JtIGZsb2F0IGNhbnZhc0hlaWdodDsgIC8vIENhbnZhcyBoZWlnaHQgaW4gcGl4ZWxzCnVuaWZvcm0gZmxvYXQgYmxlbmRGYWN0b3I7ICAgLy8gQmxlbmQgYmV0d2VlbiBzb2xpZCAoMC4wKSBhbmQgdHJhbnNwYXJlbnQvZm9nZ3kgKDEuMCkKdW5pZm9ybSBmbG9hdCB0aW1lOyAgICAgICAgICAvLyBUaW1lIGZvciBzdWJ0bGUgYW5pbWF0aW9uL3ZhcmlhdGlvbgovLyBwYWRkaW5nIG5vdCBuZWVkZWQgaW4gR0xTTAoKLy8gSW5wdXQgZnJvbSB2ZXJ0ZXggc2hhZGVyCmluIHZlYzIgdlVWOwoKLy8gT3V0cHV0IGNvbG9yCm91dCB2ZWM0IGZyYWdDb2xvcjsKCi8vIEhhc2ggZnVuY3Rpb24gZm9yIGdyaXR0aW5lc3Mvbm9pc2UKZmxvYXQgaGFzaCh2ZWMyIHApIHsKICAgIHZlYzMgcDMgPSBmcmFjdCh2ZWMzKHAueCwgcC55LCBwLngpICogMC4xMyk7CiAgICBmbG9hdCBkcCA9IGRvdCh2ZWMzKHAueCwgcC55LCBwLngpICsgdmVjMyhwMy55LCBwMy56LCBwMy54KSwgcDMgKyB2ZWMzKDMzLjMzKSk7CiAgICByZXR1cm4gZnJhY3QoKHAzLnggKyBwMy55KSAqIGRwKTsKfQoKLy8gU21vb3RoIG5vaXNlIGZvciBmb2dneSBlZmZlY3QKZmxvYXQgc21vb3RoTm9pc2UodmVjMiB1diwgZmxvYXQgc2NhbGUpIHsKICAgIHZlYzIgc2NhbGVkID0gdXYgKiBzY2FsZTsKICAgIHZlYzIgaSA9IGZsb29yKHNjYWxlZCk7CiAgICB2ZWMyIGYgPSBmcmFjdChzY2FsZWQpOwogICAgCiAgICAvLyBTbW9vdGggaW50ZXJwb2xhdGlvbgogICAgdmVjMiB1ID0gZiAqIGYgKiAoMy4wIC0gMi4wICogZik7CiAgICAKICAgIC8vIFNhbXBsZSBjb3JuZXJzCiAgICBmbG9hdCBhID0gaGFzaChpKTsKICAgIGZsb2F0IGIgPSBoYXNoKGkgKyB2ZWMyKDEuMCwgMC4wKSk7CiAgICBmbG9hdCBjID0gaGFzaChpICsgdmVjMigwLjAsIDEuMCkpOwogICAgZmxvYXQgZCA9IGhhc2goaSArIHZlYzIoMS4wLCAxLjApKTsKICAgIAogICAgLy8gQmlsaW5lYXIgaW50ZXJwb2xhdGlvbgogICAgcmV0dXJuIG1peChtaXgoYSwgYiwgdS54KSwgbWl4KGMsIGQsIHUueCksIHUueSk7Cn0KCnZvaWQgbWFpbigpIHsKICAgIHZlYzIgdGV4Q29vcmQgPSB2VVY7CiAgICAKICAgIC8vIENhbGN1bGF0ZSB3aGljaCBwaXhlbCBncmlkIGNlbGwgdGhpcyBmcmFnbWVudCBiZWxvbmdzIHRvCiAgICB2ZWMyIHBpeGVsR3JpZFBvcyA9IGZsb29yKHRleENvb3JkICogdmVjMihwaXhlbENvbHMsIHBpeGVsUm93cykpOwogICAgCiAgICAvLyBDYWxjdWxhdGUgdGhlIGNlbnRlciBvZiB0aGUgcGl4ZWwgY2VsbCBmb3Igc2FtcGxpbmcKICAgIC8vIEFkZGluZyAwLjUgY2VudGVycyB0aGUgc2FtcGxpbmcgcG9pbnQgd2l0aGluIGVhY2ggcGl4ZWwgY2VsbAogICAgdmVjMiBwaXhlbENlbnRlciA9IChwaXhlbEdyaWRQb3MgKyB2ZWMyKDAuNSwgMC41KSkgLyB2ZWMyKHBpeGVsQ29scywgcGl4ZWxSb3dzKTsKICAgIAogICAgLy8gU2FtcGxlIHRoZSBwaXhlbGF0ZWQgY29sb3IgKGZyb20gcGl4ZWwgY2VudGVyIC0gc29saWQgYmxvY2tzKQogICAgdmVjNCBwaXhlbENvbG9yID0gdGV4dHVyZShpbnB1dFRleHR1cmUsIHBpeGVsQ2VudGVyKTsKICAgIAogICAgLy8gU2FtcGxlIHRoZSBvcmlnaW5hbCB0ZXh0dXJlIChmcm9tIGFjdHVhbCBwb3NpdGlvbiAtIHVuZGVybHlpbmcgc3RhdGljKQogICAgdmVjNCBvcmlnaW5hbENvbG9yID0gdGV4dHVyZShpbnB1dFRleHR1cmUsIHRleENvb3JkKTsKICAgIAogICAgLy8gQXQgYmxlbmRGYWN0b3IgPSAwLjA6IGZ1bGx5IG9wYXF1ZSBwaXhlbHMgKGxlZnQgc2lkZSkKICAgIC8vIEF0IGJsZW5kRmFjdG9yID0gMS4wOiBmb2dneS9ncml0dHkgYmxlbmQgc2hvd2luZyB1bmRlcmx5aW5nIHN0YXRpYyAocmlnaHQgc2lkZSkKICAgIAogICAgaWYgKGJsZW5kRmFjdG9yIDw9IDAuMDEpIHsKICAgICAgICAvLyBGdWxseSBvcGFxdWUgLSBqdXN0IHJldHVybiBwaXhlbGF0ZWQgY29sb3IKICAgICAgICBmcmFnQ29sb3IgPSBwaXhlbENvbG9yOwogICAgICAgIHJldHVybjsKICAgIH0KICAgIAogICAgLy8gQWRkIGdyaXR0aW5lc3MgdXNpbmcgbm9pc2UgLSB0aGlzIGNyZWF0ZXMgdGV4dHVyZSBpbiB0aGUgYmxlbmQKICAgIHZlYzIgcGl4ZWxQb3MgPSB0ZXhDb29yZCAqIHZlYzIoY2FudmFzV2lkdGgsIGNhbnZhc0hlaWdodCk7CiAgICBmbG9hdCBncml0dGluZXNzID0gc21vb3RoTm9pc2UocGl4ZWxQb3MsIDAuNSkgKiAwLjMgKyAwLjc7IC8vIFJhbmdlOiAwLjcgdG8gMS4wCiAgICAKICAgIC8vIENhbGN1bGF0ZSBibGVuZCBhbW91bnQgd2l0aCBncml0dGluZXNzCiAgICBmbG9hdCBibGVuZEFtb3VudCA9IGJsZW5kRmFjdG9yICogZ3JpdHRpbmVzczsKICAgIAogICAgLy8gQmxlbmQgYmV0d2VlbiBwaXhlbGF0ZWQgKHNvbGlkKSBhbmQgb3JpZ2luYWwgKGZvZ2d5L3RyYW5zcGFyZW50KQogICAgdmVjNCBmaW5hbENvbG9yID0gbWl4KHBpeGVsQ29sb3IsIG9yaWdpbmFsQ29sb3IsIGJsZW5kQW1vdW50KTsKICAgIAogICAgZnJhZ0NvbG9yID0gZmluYWxDb2xvcjsKfQoKYAogICAgICAgIH07CiAgICAgICAgCiAgICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KICAgICAgICAvLyBKQVZBU0NSSVBUIE1PRFVMRVMgKEZsYXR0ZW5
in real time plays audio and video in real time. \n\nClick and drag the mouse over the instrument to play. \n\nDrag and drop audio files onto the instrument to load samples. \n\nPress the ‘D’ key to begin recording. The instrument will record and save the next 10 seconds of sound + video. \n\nThis instrument is designed to be played exclusively on laptop + desktop computers. \n\nProduced by MyFi Studio \nhttps://www.myfi.studio \n\nThe Bass and MyFi Studio partner to create interactive art and music-making experiences by presenting a series of Electronic Music Labs. Made possible with generous support by Art Bridges. \n\nMyFi Studio’s collection of instruments will be available on The Bass Museum of Art’s website beginning July 31, 2024. \nhttps://thebass.org \n\nInspired by Nam June Paik, MyFi Studio created in real time (2024), a collection of custom electronic music instruments. Credited with originating the term “electronic superhighway” (1974), Nam June Paik went on to create artwork that positioned digital media as an artistic medium just as social networks expanded globally, making way for the current entanglements between humans and technology. Works like Paik’s Internet Dweller (1994) corresponded with the public launch of the World Wide Web. \n\nTo further perpetuate the potency of connectivity and collaboration that the internet provides, The Bass commissioned MyFi Studio to create 404 custom electronic music instruments, offering a new avenue for internet citizens to co-create new work as a collective. The Bass and MyFi Studio will retain an additional 25 instruments each for ongoing and future use by the public. \n\nin real time is shaped by MyFi Studio’s electronic instrument building and improvisational performance practice. This collection of instruments is generated by code, written in p5.js and stored on Ethereum. \n\nin real time exists on the networks and systems that Nam June Paik imagined.
in real time plays audio and video in real time. \n\nClick and drag the mouse over the instrument to play. \n\nDrag and drop audio files onto the instrument to load samples. \n\nPress the ‘D’ key to begin recording. The instrument will record and save the next 10 seconds of sound + video. \n\nThis instrument is designed to be played exclusively on laptop + desktop computers. \n\nProduced by MyFi Studio \nhttps://www.myfi.studio \n\nThe Bass and MyFi Studio partner to create interactive art and music-making experiences by presenting a series of Electronic Music Labs. Made possible with generous support by Art Bridges. \n\nMyFi Studio’s collection of instruments will be available on The Bass Museum of Art’s website beginning July 31, 2024. \nhttps://thebass.org \n\nInspired by Nam June Paik, MyFi Studio created in real time (2024), a collection of custom electronic music instruments. Credited with originating the term “electronic superhighway” (1974), Nam June Paik went on to create artwork that positioned digital media as an artistic medium just as social networks expanded globally, making way for the current entanglements between humans and technology. Works like Paik’s Internet Dweller (1994) corresponded with the public launch of the World Wide Web. \n\nTo further perpetuate the potency of connectivity and collaboration that the internet provides, The Bass commissioned MyFi Studio to create 404 custom electronic music instruments, offering a new avenue for internet citizens to co-create new work as a collective. The Bass and MyFi Studio will retain an additional 25 instruments each for ongoing and future use by the public. \n\nin real time is shaped by MyFi Studio’s electronic instrument building and improvisational performance practice. This collection of instruments is generated by code, written in p5.js and stored on Ethereum. \n\nin real time exists on the networks and systems that Nam June Paik imagined.
in real time plays audio and video in real time. Click and drag the mouse over the instrument to play. Drag and drop audio files onto the instrument to load samples. Press the ‘D’ key to begin recording. The instrument will record and save the next 10 seconds of sound + video. This instrument is designed to be played exclusively on laptop + desktop computers. Produced by MyFi Studio https://www.myfi.studio The Bass and MyFi Studio partner to create interactive art and music-making experiences by presenting a series of Electronic Music Labs. Made possible with generous support by Art Bridges. MyFi Studio’s collection of instruments will be available on The Bass Museum of Art’s website beginning July 31, 2024. https://thebass.org Inspired by Nam June Paik, MyFi Studio created in real time (2024), a collection of custom electronic music instruments. Credited with originating the term “electronic superhighway” (1974), Nam June Paik went on to create artwork that positioned digital media as an artistic medium just as social networks expanded globally, making way for the current entanglements between humans and technology. Works like Paik’s Internet Dweller (1994) corresponded with the public launch of the World Wide Web. To further perpetuate the potency of connectivity and collaboration that the internet provides, The Bass commissioned MyFi Studio to create 404 custom electronic music instruments, offering a new avenue for internet citizens to co-create new work as a collective. The Bass and MyFi Studio will retain an additional 25 instruments each for ongoing and future use by the public. in real time is shaped by MyFi Studio’s electronic instrument building and improvisational performance practice. This collection of instruments is generated by code, written in p5.js and stored on Ethereum. in real time exists on the networks and systems that Nam June Paik imagined.
in real time plays audio and video in real time. Click and drag the mouse over the instrument to play. Drag and drop audio files onto the instrument to load samples. Press the ‘D’ key to begin recording. The instrument will record and save the next 10 seconds of sound + video. This instrument is designed to be played exclusively on laptop + desktop computers. Produced by MyFi Studio https://www.myfi.studio The Bass and MyFi Studio partner to create interactive art and music-making experiences by presenting a series of Electronic Music Labs. Made possible with generous support by Art Bridges. MyFi Studio’s collection of instruments will be available on The Bass Museum of Art’s website beginning July 31, 2024. https://thebass.org Inspired by Nam June Paik, MyFi Studio created in real time (2024), a collection of custom electronic music instruments. Credited with originating the term “electronic superhighway” (1974), Nam June Paik went on to create artwork that positioned digital media as an artistic medium just as social networks expanded globally, making way for the current entanglements between humans and technology. Works like Paik’s Internet Dweller (1994) corresponded with the public launch of the World Wide Web. To further perpetuate the potency of connectivity and collaboration that the internet provides, The Bass commissioned MyFi Studio to create 404 custom electronic music instruments, offering a new avenue for internet citizens to co-create new work as a collective. The Bass and MyFi Studio will retain an additional 25 instruments each for ongoing and future use by the public. in real time is shaped by MyFi Studio’s electronic instrument building and improvisational performance practice. This collection of instruments is generated by code, written in p5.js and stored on Ethereum. in real time exists on the networks and systems that Nam June Paik imagined.
in real time plays audio and video in real time. Click and drag the mouse over the instrument to play. Drag and drop audio files onto the instrument to load samples. Press the ‘D’ key to begin recording. The instrument will record and save the next 10 seconds of sound + video. This instrument is designed to be played exclusively on laptop + desktop computers. Produced by MyFi Studio https://www.myfi.studio The Bass and MyFi Studio partner to create interactive art and music-making experiences by presenting a series of Electronic Music Labs. Made possible with generous support by Art Bridges. MyFi Studio’s collection of instruments will be available on The Bass Museum of Art’s website beginning July 31, 2024. https://thebass.org Inspired by Nam June Paik, MyFi Studio created in real time (2024), a collection of custom electronic music instruments. Credited with originating the term “electronic superhighway” (1974), Nam June Paik went on to create artwork that positioned digital media as an artistic medium just as social networks expanded globally, making way for the current entanglements between humans and technology. Works like Paik’s Internet Dweller (1994) corresponded with the public launch of the World Wide Web. To further perpetuate the potency of connectivity and collaboration that the internet provides, The Bass commissioned MyFi Studio to create 404 custom electronic music instruments, offering a new avenue for internet citizens to co-create new work as a collective. The Bass and MyFi Studio will retain an additional 25 instruments each for ongoing and future use by the public. in real time is shaped by MyFi Studio’s electronic instrument building and improvisational performance practice. This collection of instruments is generated by code, written in p5.js and stored on Ethereum. in real time exists on the networks and systems that Nam June Paik imagined.
let mic,sampler,soundFile,newSoundFile,initialMouse=!1,firstClickReleased=!1,firstLoop=!0,displayInstrument=!1,recButton,playButton,pitchButtons,sliceButtons,instrumentButtons,loadSample=!1,toyType,instrumentType,sequences=[[392,987.77,392,987.77,415.3,1046.5,415.3,1046.5,466.16,1174.66,466.16,1174.66,415.3,1046.5,415.3,1046.5],[987.76,784,739.98,784,987.76,784,739.98,739.98,784],[587.33,587.33,739.99,1046.5,1046.5,739.99,523.25,523.25,659.25,932.33,932.33,554.37,698.46,698.46],[349.23,440,493.885,587.33,698.46,880,987.77,1318.51,1396.92,1760,1975.54,3135.96,2793.82,2349.32,1975.54,2349.32],[349.23,698.46,349.23,349.23,698.46,349.23,698.46,349.23,698.46,698.46,622.25,523.25,698.46,622.25,698.46,622.25,523.25,698.46,622.25,523.25,698.46,622.25,523.25,698.46,622.25,622.25,622.25,622.25],[392,783.99,587.33,659.25,698.46,392,783.99,587.33,659.25,698.46,659.25,587.33,659.25],[587.33,523.25,440,587.33,523.25,440,369.99,369.99,369.99,587.33,523.25,440,659.25,830.61,1174.66,622.25,783.99,1108.73],[392,987.77,349.23,880,349.23,392,987.77,392,987.77,349.23,880,349.23,880,392,987.77,349.23,880,293.66,369.99,440,554.37,587.33,554.37],[329.63,493.88,830.61,493.88,369.99,554.37,880,415.3,622.25,987.77,622.25,440,659.25,1108.73]],sequence,pitchRatio,pitchRatios=[[1.49857,1.18918,1,.890816,.5],[1.49824,1.2599,1,.890816,.841],[1.3348,1.18918,1,.8908,.7071],[1.1225,1.0595,1,.9439,.8907],[1.2599,1.1225,1,.84086,.7492]],ratioIndex=-1,sequenceIndex=-1,charSize,game,timer=1,gameTimer=1,animationSpeed,backgroundColor,charColor,flashColor,buttonColor,colorPalette,diameter,printWidth,printHeight,strokeWidth,canvas;function setup(){tokenId=parseInt(tokenId),randomSeed(1e3*tokenId),rt=window.rt,loadInitalData(),canvas=createCanvas(windowWidth,windowHeight),printWidth=windowWidth,printHeight=windowHeight,strokeWidth=printWidth<printHeight?printWidth/50:printHeight/50,canvas.drop(gotFile),ellipseMode(CENTER),rectMode(CENTER),noStroke(),chooseColorPalette(),diameter=printWidth<printHeight?.15*printWidth:.15*printHeight,animationSpeed=15}function draw(){background(backgroundColor),instructionLoaded&&(loadedSoundFile=loadSound(loadedInstruction)),initialMouse||(fill(charColor),rect(3*printWidth/8,printHeight/2,printWidth/4,printHeight),fill(flashColor),rect(5*printWidth/8,printHeight/2,printWidth/4,printHeight),fill(buttonColor),rect(7*printWidth/8,printHeight/2,printWidth/4,printHeight)),firstClickReleased&&(mouseIsPressed?(recButton.collision(),instrumentButtons.collision()):instrumentButtons.sequencer&&instrumentButtons.turnSliderOff(),fill(charColor),circle(printWidth/2,printHeight/2-mic.getLevel()*printHeight/2,.33*diameter),recButton.draw(),displayInstrument||sampler.thresholdReached||sampler.amplitudeThreshold()),displayInstrument&&instrumentButtons.draw(),loadSample&&soundFile.isLoaded()&&(console.log("sample finished loading :::"),loadSample=!1,instrumentButtons.recordingLoaded(),soundFile.playMode("restart"),displayInstrument=!0,"looper"!=instrumentType&&"sequencer"!=instrumentType||(firstLoop?firstLoop=!1:instrumentButtons.buttons[0].togglePause(),instrumentButtons.buttons[0].play())),"looper"!=instrumentType&&"sequencer"!=instrumentType||!firstClickReleased||(animationSpeed=floor(map(instrumentButtons.buttons[0].sliderLERP,.5,4,40,7))),displayInstrument&&(timer%animationSpeed==0&&soundFile.isPlaying()?game.play():displayInstrument&&game.draw(),soundFile.isPlaying())&&timer++}class sampleRecorder{constructor(){this.recorder=new p5.SoundRecorder,this.recorder.setInput(mic.mic),soundFile=new p5.SoundFile,this.thresholdReached=!0}startRecord(){console.log("start record"),this.thresholdReached=!1}amplitudeThreshold(){.03<mic.getLevel()&&(this.thresholdReached=!0,"looper"==instrumentType||"sequencer"==instrumentType?(newSoundFile=new p5.SoundFile,this.recorder.record(newSoundFile)):(soundFile=new p5.SoundFile,this.recorder.record(soundFile)))}stopRecord(){console.log("stop record"),this.thresholdReached?(this.recorder.stop(),"looper"!=instrumentType&&"sequencer"!=instrumentType||(instrumentButtons.buttons[0].playing&&instrumentButtons.buttons[0].togglePause(),soundFile.disconnect(),soundFile=newSoundFile),loadSample=!0):console.log("amplitude threshold never exceeded"),console.log("stoped rec. begin loading sample")}loadInstruction(){console.log("load instruction sound file from link"),this.recorder.stop(),"looper"!=instrumentType&&"sequencer"!=instrumentType||instrumentButtons.buttons[0].playing&&instrumentButtons.buttons[0].togglePause(),soundFile=loadedSoundFile,loadSample=!0,instructionLoaded=!1,console.log("MEOWWW")}}class microphone{constructor(){this.mic=new p5.AudioIn,this.mic.start(),this.mic.amp(4)}getLevel(){return this.mic.getLevel()}}class recordButton{constructor(t,e,i){this.x=t,this.y=e,this.diameter=i,this.state=!1}draw(){instructionLoaded&&sampler.loadInstruction(),this.state?fill(charColor):fill(buttonColor),circle(this.x,this.y,this.diameter)}collision(){var t=this.x-mouseX,e=this.y-mouseY;pow(pow(t,2)+pow(e,2),.5)<=this.diameter/2&&(("looper"==instrumentType||"sequencer"==instrumentType)&&instrumentButtons.buttons[0].sliding||this.toggle())}toggle(){millis()-this.lastPush<50?this.lastPush=millis():(this.lastPush=millis(),this.state=!this.state,displayInstrument=(this.state?(instrumentButtons.recordingStarted(),sampler.startRecord()):sampler.stopRecord(),!1),this.state?fill(charColor):fill(buttonColor),circle(this.x,this.y,this.diameter))}}class instrumentInterface{constructor(t,e){if(this.intstrumentType=t,this.play=!1,this.pitch=!1,this.slice=!1,this.sequencer=!1,this.buttons=[],this.diameter=e,"pitch"==t){this.pitch=!0,this.x=.75*printWidth,this.y=printHeight/2,this.state=!1,fill(buttonColor);for(let t=0;t<5;t++)this.buttons[t]=new audioButton("pitch",t),this.buttons[t].pitchConstructor(this.x,printHeight*(.125+.1875*t),this.diameter,pitchRatio[t])}else"slice"==t?(this.slice=!0,this.x=printWidth/8,this.y=3*printHeight/4,this.state=!1,fill(buttonColor),this.buttons[0]=new audioButton("slice",0),this.buttons[0].sliceConstructor(this.x,this.y,this.diameter,0,.25),this.buttons[1]=new audioButton("slice",1),this.buttons[1].sliceConstructor(3*this.x,this.y,this.diameter,.25,.5),this.buttons[2]=new audioButton("slice",2),this.buttons[2].sliceConstructor(5*this.x,this.y,this.diameter,.5,.75),this.buttons[3]=new audioButton("slice",3),this.buttons[3].sliceConstructor(7*this.x,this.y,this.diameter,.75,1)):"looper"!=t&&"sequencer"!=t||(this.sequencer=!0,this.state=!1,fill(buttonColor),this.buttons[0]=new slider("looper"),"looper"==t?(this.x=.25*printWidth,this.y=.5*printHeight,this.buttons[0].sequencerConstructor(this.x,this.y,this.diameter)):"sequencer"==t&&(this.x=.5*printWidth,this.y=.25*printHeight,this.buttons[0].sequencerConstructor(this.x,this.y,this.diameter),this.buttons[0].toggleMelodicSequencer()))}recordingStarted(){this.state=!1;for(let t=0;t<this.buttons.length;t++)this.buttons[t].state=!1;displayInstrument&&this.draw()}recordingLoaded(){for(let t=0;t<this.buttons.length;t++)this.buttons[t].recordingLoaded();this.state=!0,this.draw()}draw(){for(let t=0;t<this.buttons.length;t++)this.buttons[t].draw()}collision(){if(this.state)for(let t=0;t<this.buttons.length;t++)this.buttons[t].collision()}turnSliderOff(){this.buttons[0].sliding=!1}resetPitchRatios(){if(this.pitch)for(let t=0;t<5;t++)this.buttons[t].setRatio(pitchRatio[t])}resetSequence(){this.sequencer&&this.buttons[0].toggleMelodicSequencer()}}class slider{constructor(t){this.sequencer=!1,this.sliding=!1,this.playing=!1,this.melodic=!1,this.minPitchRatio=.5,this.maxPitchRatio=4,"looper"==t&&(this.sequencer=!0)}sequencerConstructor(t,e,i){this.x=t,this.y=e,this.startX=t,this.startY=e,this.diameter=i,this.sliderValue=.5,this.sliderLERP=1}toggleMelodicSequencer(){this.melodic=!0,this.sequenceNoteIndex=0,this.sequence=[];for(let t=0;t<sequence.length;t++)this.sequence[t]=sequence[t]/sequence[0]}draw(){var t=this.state?charColor:buttonColor;this.sequencer&&!this.melodic?(stroke(buttonColor),strokeWeight(strokeWidth),line(this.startX,.25*this.startY,this.startX,1.75*this.startY),noStroke(),fill(t),this.sliding&&fill(flashColor),circle(this.x,this.y,this.diameter),this.state&&this.play()):this.sequencer&&this.melodic&&(stroke(buttonColor),strokeWeight(strokeWidth),line(.25*this.startX,this.startY,1.75*this.startX,this.startY),noStroke(),fill(t),this.sliding&&fill(flashColor),circle(this.x,this.y,this.diameter),this.state)&&this.play()}play(){var t,e;this.playing?(t=millis()/1e3,this.melodic?(e=this.sequence[this.sequenceNoteIndex],soundFile.rate(.5*e*this.sliderLERP),t-this.lastBeat>=.5*this.secondsPerBeat&&(this.lastBeat=t,this.secondsPerBeat=soundFile.duration()*map(this.sliderValue,0,1,this.maxPitchRatio,this.minPitchRatio),this.sequenceNoteIndex==this.sequence.length-1?this.sequenceNoteIndex=0:this.sequenceNoteIndex++)):soundFile.rate(this.sliderLERP)):(this.lastBeat=millis()/1e3,soundFile.rate(map(this.sliderLERP,0,1,this.minPitchRatio,this.maxPitchRatio)),soundFile.loop(),this.secondsPerBeat=soundFile.duration()*map(this.sliderValue,0,1,this.maxPitchRatio,this.minPitchRatio),this.playing=!0)}reset(){this.playing&&soundFile.jump()}togglePause(){this.playing&&(soundFile.isPlaying()?soundFile.pause():soundFile.loop())}recordingStarted(){this.state=!1,this.playing=!1,soundFile.stop(),this.draw()}recordingLoaded(){this.state=!0,this.draw(),console.log("length of recording loaded: "+soundFile.duration()),this.play()}saveSliderValue(t){this.sliderValue=t,this.melodic?(mouseX/printWidth<=.125?this.x=.125*printWidth:.875<=mouseX/printWidth?this.x=.875*printWidth:this.x=mouseX,this.sliderLERP=t<=.5?map(t,0,.5,.5,1):t<=.75?map(t,.5,.75,1,2):map(t,.75,1,2,4)):(mouseY/printHeight<=.125?this.y=.125*printHeight:.875<=mouseY/printHeight?this.y=.875*printHeight:this.y=mouseY,this.sliderLERP=t<=.25?map(t,0,.25,4,2):t<=.5?map(t,.25,.5,2,1):map(t,.5,1,1,.5))}getSliderValue(){let t;return this.melodic?(t=map(mouseX/printWidth,.125,.875,0,1))<0?t=0:1<t&&(t=1):(t=map(mouseY/printHeight,.125,.875,0,1))<0?t=0:1<t&&(t=1),t}collision(){var t,e,i;this.state&&(this.sliding?(i=this.getSliderValue(),this.saveSliderValue(i)):(i=this.getSliderValue(),this.sequencer,t=this.x-mouseX,e=this.y-mouseY,pow(pow(t,2)+pow(e,2),.5)<=diameter/2&&(this.sliding=!0,this.saveSliderValue(i))),this.draw())}}class audioButton{constructor(t,e){this.playback=!1,this.pitch=!1,this.slice=!1,this.buttonIndex=e,"pitch"==t?this.pitch=!0:"slice"==t?this.slice=!0:"play"==t&&(this.playback=!0)}playConstructor(t,e,i){this.x=t,this.y=e,this.diameter=i,this.state=!1,fill(buttonColor),circle(this.x,this.y,this.diameter)}pitchConstructor(t,e,i,s){this.x=t,this.y=e,this.diameter=i,this.shiftRatio=s,this.state=!1,this.lit=!1,fill(buttonColor),circle(this.x,this.y,this.diameter)}sliceConstructor(t,e,i,s,o){this.x=t,this.y=e,this.diameter=i,this.start=s,this.end=o,this.state=!1,fill(buttonColor),circle(this.x,this.y,this.diameter)}draw(){this.state?this.lit?fill(flashColor):fill(charColor):fill(buttonColor),circle(this.x,this.y,this.diameter),this.lit&&!soundFile.isPlaying()&&(this.lit=!1)}unlitOtherButtons(){for(let t=0;t<instrumentButtons.buttons.length;t++)t!=this.buttonIndex&&(instrumentButtons.buttons[t].lit=!1)}recordingStarted(){this.state=!1,this.draw()}recordingLoaded(){this.state=!0,this.draw(),this.slice&&(console.log("length of recording loaded: "+soundFile.duration()),this.playTime=.24999*soundFile.duration(),this.startTime=this.start*soundFile.duration())}setRatio(t){this.shiftRatio=t}collision(){var t,e;this.state&&(millis()-this.lastPush<50?this.lastPush=millis():(this.lastPush=millis(),t=this.x-mouseX,e=this.y-mouseY,pow(pow(t,2)+pow(e,2),.5)<=this.diameter/2&&(this.pitch?(soundFile.rate(this.shiftRatio),soundFile.play()):this.slice?(soundFile.play(),soundFile.jump(this.startTime,this.playTime)):this.playback&&(soundFile.rate(1),soundFile.play()),this.lit=!0,this.unlitOtherButtons())))}play(){this.slice?(soundFile.play(),soundFile.jump(this.startTime,this.playTime),this.lit=!0,this.unlitOtherButtons()):this.pitch&&("undefined"===this.shiftRatio?console.log("undefffff"):(soundFile.rate(this.shiftRatio),soundFile.play(),this.lit=!0,this.unlitOtherButtons()))}}function keyTyped(){"1"===key?instrumentButtons.slice?instrumentButtons.buttons[0].play():instrumentButtons.pitch&&instrumentButtons.buttons[4].play():"2"===key?instrumentButtons.slice?instrumentButtons.buttons[1].play():instrumentButtons.pitch&&instrumentButtons.buttons[3].play():"3"===key?(instrumentButtons.slice||instrumentButtons.pitch)&&instrumentButtons.buttons[2].play():"4"===key?instrumentButtons.slice?instrumentButtons.buttons[3].play():instrumentButtons.pitch&&instrumentButtons.buttons[1].play():"5"===key?instrumentButtons.pitch&&instrumentButtons.buttons[0].play():"r"===key||"R"===key?instrumentButtons.sequencer&&instrumentButtons.buttons[0].reset():32===keyCode?instrumentButtons.sequencer&&instrumentButtons.buttons[0].togglePause():68===keyCode?instrumentButtons.state&&soundFile.save():13==keyCode&&("sequencer"==instrumentButtons.intstrumentType?(console.log("hello"),chooseSequence(),instrumentButtons.resetSequence()):instrumentButtons.pitch&&(choosePitchRatios(),instrumentButtons.resetPitchRatios()))}function gotFile(t){background(0),"audio"===t.type&&(soundFile.isPlaying()&&instrumentButtons.sequencer&&instrumentButtons.buttons[0].togglePause(),soundFile=loadSound(t))}function touchStarted(){var t;initialMouse||(userStartAudio(),initialMouse=!0,mic=new microphone,sampler=new sampleRecorder,(t=mouseX)<printWidth/4?(instrumentType="pitch",choosePitchRatios(),chooseColors(0)):t<printWidth/2?(instrumentType="slice",chooseColors(1)):t<.75*printWidth?(instrumentType="looper",chooseColors(2)):(instrumentType="sequencer",chooseSequence(),chooseColors(3)),console.log("instrument chosen: "+instrumentType),instrumentButtons=new instrumentInterface(instrumentType,diameter),game=new diceGame)}function mouseReleased(){firstClickReleased||(firstClickReleased=!0,recButton=new recordButton(.5*printWidth,printHeight/2,diameter),console.log("record button created"))}class diceGame{constructor(){charSize=printWidth<printHeight?.41*printWidth:.41*printHeight,textSize(charSize),textAlign(CENTER),this.die=[],this.die[0]=new dice(0),this.die[1]=new dice(1),this.die[2]=new dice(2)}play(){fill(charColor);var t,e,i,s=gameTimer%100;49==s?(t=this.die[0].rollValue(),e=this.die[1].rollValue(),i=this.die[2].rollValue(),(e<t&&i<t?this.die[0]:t<e&&i<e?this.die[1]:t<i&&e<i?this.die[2]:t==e&&t!=i?(this.die[0].won(),this.die[1]):((t==i&&t!=e?this.die[0]:(e==i&&t!=e||this.die[0].won(),this.die[1])).won(),this.die[2])).won()):99==s&&(this.die[0].roll(),this.die[1].roll(),this.die[2].roll()),this.die[0].draw(),this.die[1].draw(),this.die[2].draw(),gameTimer++}draw(){fill(charColor),this.die[0].draw(),this.die[1].draw(),this.die[2].draw()}}class dice{constructor(t){this.playerIndex=t,this.state=!1,this.rolling=!0,this.value=-1,this.diceChars=[],this.diceChars[0]=-1,this.diceChars[1]=9856,this.diceChars[2]=9857,this.diceChars[3]=9858,this.diceChars[4]=9859,this.diceChars[5]=9860,this.diceChars[6]=9861,this.winner=!1,"pitch"==instrumentType?(this.x=.22*printWidth,this.y=(this.playerIndex+1)*(.61*printHeight/2)):"looper"==instrumentType?(this.x=.78*printWidth,this.y=(this.playerIndex+1)*(.61*printHeight/2)):"sequencer"==instrumentType?(this.x=(1+2*this.playerIndex)*(printWidth/6),this.y=.9*printHeight):"slice"==instrumentType&&(this.x=(1+2*this.playerIndex)*(printWidth/6),this.y=.33*printHeight)}roll(){this.rolling=!0,this.winner=!1}rollValue(){return this.rolling=!1,this.value=random([1,2,3,4,5,6]),this.value}won(){this.winner=!0}draw(){var t;this.rolling?(t=1+gameTimer%6,text(String.fromCodePoint(this.diceChars[t]),this.x,this.y)):(this.winner&&gameTimer%2==0?fill(flashColor):fill(charColor),text(String.fromCodePoint(this.diceChars[this.value]),this.x,this.y))}}let colorPalettes=[[[227,163,181],[235,228,86],[225,114,0],[0,77,142]],[[183,185,239],[213,111,49],[112,147,247],[78,63,158]],[[44,46,75],[173,161,128],[143,106,116],[152,87,87]],[[173,161,128],[185,71,30],[18,2,2],[147,30,18]],[[234,97,42],[26,37,39],[245,245,14],[134,223,252]],[[117,251,76],[232,57,183],[154,31,110],[61,126,34]],[[44,98,209],[193,94,48],[124,28,23],[35,84,117]],[[226,216,133],[142,208,224],[224,188,129],[180,111,50]],[[162,210,169],[191,179,129],[149,142,125],[159,161,94]],[[193,142,186],[156,196,125],[164,201,223],[225,227,144]],[[136,47,120],[95,114,214],[199,143,74],[13,44,74]],[[212,128,93],[99,31,116],[26,67,174],[59,133,39]],[[86,119,45],[157,75,32],[136,114,121],[219,186,136]],[[145,188,211],[251,244,179],[214,145,159],[243,194,61]],[[194,92,40],[177,90,43],[69,49,100],[194,230,89]],[[172,56,46],[112,24,12],[17,46,39],[48,90,94]],[[166,201,199],[241,159,236],[146,133,162],[182,180,72]],[[252,145,171],[254,253,169],[109,93,133],[250,98,71]],[[218,223,218],[9,100,82],[181,245,124],[101,192,213]],[[64,194,16],[5,25,100],[118,108,203],[213,67,231]],[[250,47,3],[244,123,3],[80,121,1],[166,197,7]],[[92,26,16],[70,81,118],[227,81,66],[157,193,135]],[[215,160,255],[255,195,165],[1,225,255],[255,170,202]],[[0,60,209],[148,247,239],[217,1,22],[255,41,179]]],indexShuffler=[[0,1,2,3],[3,1,2,0],[1,0,2,3],[3,2,0,1],[2,3,0,1],[1,2,0,3],[2,1,0,3],[0,1,3,2],[0,3,2,1],[0,2,3,1],[3,0,1,2],[1,2,3,0],[1,3,2,0],[2,3,1,0],[1,0,3,2],[0,3,1,2],[1,3,0,2],[0,2,1,3],[2,0,1,3],[2,0,3,1],[3,0,2,1],[3,2,1,0],[2,1,3,0],[3,1,0,2]];function chooseColorPalette(){var t=(tokenId+21)%colorPalettes.length,e=floor((tokenId+21)/colorPalettes.length)%(colorPalettes.length*indexShuffler.length),t=colorPalettes[t],e=indexShuffler[e];backgroundColor=t[e[0]],charColor=t[e[1]],flashColor=t[e[2]],buttonColor=t[e[3]],(colorPalette=[])[0]=t[e[0]],colorPalette[1]=t[e[1]],colorPalette[2]=t[e[2]],colorPalette[3]=t[e[3]]}function chooseColors(e){backgroundColor=colorPalette[e];var i=[];for(let t=0;t<4;t++)t!=e&&i.push(t);buttonColor=colorPalette[i[0]],charColor=colorPalette[i[1]],flashColor=colorPalette[i[2]]}function chooseSequence(){sequenceIndex=-1==sequenceIndex?floor(random(0,sequences.length)):(sequenceIndex+1)%sequences.length,sequence=sequences[sequenceIndex]}function choosePitchRatios(){ratioIndex=-1==ratioIndex?floor(random(0,pitchRatios.length)):(ratioIndex+1)%pitchRatios.length,pitchRatio=pitchRatios[ratioIndex]}let paste,instructionLoaded=!1,loadedInstruction,loadedSoundFile,rt=(document.addEventListener("paste",function(t){clipdata=t.clipboardData||window.clipboardData,paste=clipdata.getData("text/plain"),console.log(paste),console.log("SUBMIT INSTRUCTIONS TO ETHEREUM!"),t={instruction:paste},rt.mutateToken({tokenId:tokenId,data:t}),rt.commitToken({tokenId:tokenId})}),{});const loadInitalData=async()=>{await rt?.init();var t=await rt,t=(console.log("res.errors: "+t.errors),console.log("tokenIds: "+t.tokenIds),(rt?.getToken({tokenId:tokenId})).data);console.log("tokenId: "+tokenId),console.log("data: "+t),t&&loadInstruction(t)};function loadInstruction(t){console.log("loading instruction: "+t),loadedInstruction=t.instruction,instructionLoaded=!0,console.log("link: "+loadedInstruction)}
let mic,sampler,soundFile,newSoundFile,initialMouse=!1,firstClickReleased=!1,firstLoop=!0,displayInstrument=!1,recButton,playButton,pitchButtons,sliceButtons,instrumentButtons,loadSample=!1,toyType,instrumentType,sequences=[[392,987.77,392,987.77,415.3,1046.5,415.3,1046.5,466.16,1174.66,466.16,1174.66,415.3,1046.5,415.3,1046.5],[987.76,784,739.98,784,987.76,784,739.98,739.98,784],[587.33,587.33,739.99,1046.5,1046.5,739.99,523.25,523.25,659.25,932.33,932.33,554.37,698.46,698.46],[349.23,440,493.885,587.33,698.46,880,987.77,1318.51,1396.92,1760,1975.54,3135.96,2793.82,2349.32,1975.54,2349.32],[349.23,698.46,349.23,349.23,698.46,349.23,698.46,349.23,698.46,698.46,622.25,523.25,698.46,622.25,698.46,622.25,523.25,698.46,622.25,523.25,698.46,622.25,523.25,698.46,622.25,622.25,622.25,622.25],[392,783.99,587.33,659.25,698.46,392,783.99,587.33,659.25,698.46,659.25,587.33,659.25],[587.33,523.25,440,587.33,523.25,440,369.99,369.99,369.99,587.33,523.25,440,659.25,830.61,1174.66,622.25,783.99,1108.73],[392,987.77,349.23,880,349.23,392,987.77,392,987.77,349.23,880,349.23,880,392,987.77,349.23,880,293.66,369.99,440,554.37,587.33,554.37],[329.63,493.88,830.61,493.88,369.99,554.37,880,415.3,622.25,987.77,622.25,440,659.25,1108.73]],sequence,pitchRatio,pitchRatios=[[1.49857,1.18918,1,.890816,.5],[1.49824,1.2599,1,.890816,.841],[1.3348,1.18918,1,.8908,.7071],[1.1225,1.0595,1,.9439,.8907],[1.2599,1.1225,1,.84086,.7492]],ratioIndex=-1,sequenceIndex=-1,charSize,game,timer=1,gameTimer=1,animationSpeed,backgroundColor,charColor,flashColor,buttonColor,colorPalette,diameter,printWidth,printHeight,strokeWidth,canvas;function setup(){tokenId=parseInt(tokenId);randomSeed(1e3*tokenId),rt=window.rt,loadInitalData(),canvas=createCanvas(windowWidth,windowHeight),printWidth=windowWidth,printHeight=windowHeight,strokeWidth=printWidth<printHeight?printWidth/50:printHeight/50,canvas.drop(gotFile),ellipseMode(CENTER),rectMode(CENTER),noStroke(),chooseColorPalette(),diameter=printWidth<printHeight?.15*printWidth:.15*printHeight,animationSpeed=15}function draw(){background(backgroundColor),instructionLoaded&&(loadedSoundFile=loadSound(loadedInstruction)),initialMouse||(fill(charColor),rect(3*printWidth/8,printHeight/2,printWidth/4,printHeight),fill(flashColor),rect(5*printWidth/8,printHeight/2,printWidth/4,printHeight),fill(buttonColor),rect(7*printWidth/8,printHeight/2,printWidth/4,printHeight)),firstClickReleased&&(mouseIsPressed?(recButton.collision(),instrumentButtons.collision()):instrumentButtons.sequencer&&instrumentButtons.turnSliderOff(),fill(charColor),circle(printWidth/2,printHeight/2-mic.getLevel()*printHeight/2,.33*diameter),recButton.draw(),displayInstrument||sampler.thresholdReached||sampler.amplitudeThreshold()),displayInstrument&&instrumentButtons.draw(),loadSample&&soundFile.isLoaded()&&(console.log(sample finished loading :::),loadSample=!1,instrumentButtons.recordingLoaded(),soundFile.playMode("restart"),displayInstrument=!0,"looper"!=instrumentType&&"sequencer"!=instrumentType||(firstLoop?firstLoop=!1:instrumentButtons.buttons[0].togglePause(),instrumentButtons.buttons[0].play())),"looper"!=instrumentType&&"sequencer"!=instrumentType||!firstClickReleased||(animationSpeed=floor(map(instrumentButtons.buttons[0].sliderLERP,.5,4,40,7))),displayInstrument&&(timer%animationSpeed==0&&soundFile.isPlaying()?game.play():displayInstrument&&game.draw(),soundFile.isPlaying())&&timer++}class sampleRecorder{constructor(){this.recorder=new p5.SoundRecorder,this.recorder.setInput(mic.mic),soundFile=new p5.SoundFile,this.thresholdReached=!0}startRecord(){console.log("start record"),this.thresholdReached=!1}amplitudeThreshold(){.03<mic.getLevel()&&(this.thresholdReached=!0,"looper"==instrumentType||"sequencer"==instrumentType?(newSoundFile=new p5.SoundFile,this.recorder.record(newSoundFile)):(soundFile=new p5.SoundFile,this.recorder.record(soundFile)))}stopRecord(){console.log("stop record"),this.thresholdReached?(this.recorder.stop(),"looper"!=instrumentType&&"sequencer"!=instrumentType||(instrumentButtons.buttons[0].playing&&instrumentButtons.buttons[0].togglePause(),soundFile.disconnect(),soundFile=newSoundFile),loadSample=!0):console.log("amplitude threshold never exceeded"),console.log("stoped rec. begin loading sample")}loadInstruction(){console.log("load instruction sound file from link"),this.recorder.stop(),"looper"!=instrumentType&&"sequencer"!=instrumentType||instrumentButtons.buttons[0].playing&&instrumentButtons.buttons[0].togglePause(),soundFile=loadedSoundFile,loadSample=!0,instructionLoaded=!1,console.log("MEOWWW")}}class microphone{constructor(){this.mic=new p5.AudioIn,this.mic.start(),this.mic.amp(4)}getLevel(){return this.mic.getLevel()}}class recordButton{constructor(t,e,i){this.x=t,this.y=e,this.diameter=i,this.state=!1}draw(){instructionLoaded&&sampler.loadInstruction(),this.state?fill(charColor):fill(buttonColor),circle(this.x,this.y,this.diameter)}collision(){var t=this.x-mouseX,e=this.y-mouseY;pow(pow(t,2)+pow(e,2),.5)<=this.diameter/2&&(("looper"==instrumentType||"sequencer"==instrumentType)&&instrumentButtons.buttons[0].sliding||this.toggle())}toggle(){millis()-this.lastPush<50?this.lastPush=millis():(this.lastPush=millis(),this.state=!this.state,displayInstrument=(this.state?(instrumentButtons.recordingStarted(),sampler.startRecord()):sampler.stopRecord(),!1),this.state?fill(charColor):fill(buttonColor),circle(this.x,this.y,this.diameter))}}class instrumentInterface{constructor(t,e){if(this.intstrumentType=t,this.play=!1,this.pitch=!1,this.slice=!1,this.sequencer=!1,this.buttons=[],this.diameter=e,"pitch"==t){this.pitch=!0,this.x=.75*printWidth,this.y=printHeight/2,this.state=!1,fill(buttonColor);for(let t=0;t<5;t++)this.buttons[t]=new audioButton("pitch",t),this.buttons[t].pitchConstructor(this.x,printHeight*(.125+.1875*t),this.diameter,pitchRatio[t])}else"slice"==t?(this.slice=!0,this.x=printWidth/8,this.y=3*printHeight/4,this.state=!1,fill(buttonColor),this.buttons[0]=new audioButton("slice",0),this.buttons[0].sliceConstructor(this.x,this.y,this.diameter,0,.25),this.buttons[1]=new audioButton("slice",1),this.buttons[1].sliceConstructor(3*this.x,this.y,this.diameter,.25,.5),this.buttons[2]=new audioButton("slice",2),this.buttons[2].sliceConstructor(5*this.x,this.y,this.diameter,.5,.75),this.buttons[3]=new audioButton("slice",3),this.buttons[3].sliceConstructor(7*this.x,this.y,this.diameter,.75,1)):"looper"!=t&&"sequencer"!=t||(this.sequencer=!0,this.state=!1,fill(buttonColor),this.buttons[0]=new slider("looper"),"looper"==t?(this.x=.25*printWidth,this.y=.5*printHeight,this.buttons[0].sequencerConstructor(this.x,this.y,this.diameter)):"sequencer"==t&&(this.x=.5*printWidth,this.y=.25*printHeight,this.buttons[0].sequencerConstructor(this.x,this.y,this.diameter),this.buttons[0].toggleMelodicSequencer()))}recordingStarted(){this.state=!1;for(let t=0;t<this.buttons.length;t++)this.buttons[t].state=!1;displayInstrument&&this.draw()}recordingLoaded(){for(let t=0;t<this.buttons.length;t++)this.buttons[t].recordingLoaded();this.state=!0,this.draw()}draw(){for(let t=0;t<this.buttons.length;t++)this.buttons[t].draw()}collision(){if(this.state)for(let t=0;t<this.buttons.length;t++)this.buttons[t].collision()}turnSliderOff(){this.buttons[0].sliding=!1}resetPitchRatios(){if(this.pitch)for(let t=0;t<5;t++)this.buttons[t].setRatio(pitchRatio[t])}resetSequence(){this.sequencer&&this.buttons[0].toggleMelodicSequencer()}}class slider{constructor(t){this.sequencer=!1,this.sliding=!1,this.playing=!1,this.melodic=!1,this.minPitchRatio=.5,this.maxPitchRatio=4,"looper"==t&&(this.sequencer=!0)}sequencerConstructor(t,e,i){this.x=t,this.y=e,this.startX=t,this.startY=e,this.diameter=i,this.sliderValue=.5,this.sliderLERP=1}toggleMelodicSequencer(){this.melodic=!0,this.sequenceNoteIndex=0,this.sequence=[];for(let t=0;t<sequence.length;t++)this.sequence[t]=sequence[t]/sequence[0]}draw(){let t;t=this.state?charColor:buttonColor,this.sequencer&&!this.melodic?(stroke(buttonColor),strokeWeight(strokeWidth),line(this.startX,.25*this.startY,this.startX,1.75*this.startY),noStroke(),fill(t),this.sliding&&fill(flashColor),circle(this.x,this.y,this.diameter),this.state&&this.play()):this.sequencer&&this.melodic&&(stroke(buttonColor),strokeWeight(strokeWidth),line(.25*this.startX,this.startY,1.75*this.startX,this.startY),noStroke(),fill(t),this.sliding&&fill(flashColor),circle(this.x,this.y,this.diameter),this.state)&&this.play()}play(){var t,e;this.playing?(t=millis()/1e3,this.melodic?(e=this.sequence[this.sequenceNoteIndex],soundFile.rate(.5*e*this.sliderLERP),t-this.lastBeat>=.5*this.secondsPerBeat&&(this.lastBeat=t,this.secondsPerBeat=soundFile.duration()*map(this.sliderValue,0,1,this.maxPitchRatio,this.minPitchRatio),this.sequenceNoteIndex==this.sequence.length-1?this.sequenceNoteIndex=0:this.sequenceNoteIndex++)):soundFile.rate(this.sliderLERP)):(this.lastBeat=millis()/1e3,soundFile.rate(map(this.sliderLERP,0,1,this.minPitchRatio,this.maxPitchRatio)),soundFile.loop(),this.secondsPerBeat=soundFile.duration()*map(this.sliderValue,0,1,this.maxPitchRatio,this.minPitchRatio),this.playing=!0)}reset(){this.playing&&soundFile.jump()}togglePause(){this.playing&&(soundFile.isPlaying()?soundFile.pause():soundFile.loop())}recordingStarted(){this.state=!1,this.playing=!1,soundFile.stop(),this.draw()}recordingLoaded(){this.state=!0,this.draw(),console.log("length of recording loaded: "+soundFile.duration()),this.play()}saveSliderValue(t){this.sliderValue=t,this.melodic?(mouseX/printWidth<=.125?this.x=.125*printWidth:.875<=mouseX/printWidth?this.x=.875*printWidth:this.x=mouseX,this.sliderLERP=t<=.5?map(t,0,.5,.5,1):t<=.75?map(t,.5,.75,1,2):map(t,.75,1,2,4)):(mouseY/printHeight<=.125?this.y=.125*printHeight:.875<=mouseY/printHeight?this.y=.875*printHeight:this.y=mouseY,this.sliderLERP=t<=.25?map(t,0,.25,4,2):t<=.5?map(t,.25,.5,2,1):map(t,.5,1,1,.5))}getSliderValue(){let t;return this.melodic?(t=map(mouseX/printWidth,.125,.875,0,1))<0?t=0:1<t&&(t=1):(t=map(mouseY/printHeight,.125,.875,0,1))<0?t=0:1<t&&(t=1),t}collision(){if(this.state){if(this.sliding){var i=this.getSliderValue();this.saveSliderValue(i)}else{i=this.getSliderValue();let t,e;e=(this.sequencer,t=this.x-mouseX,this.y-mouseY),pow(pow(t,2)+pow(e,2),.5)<=diameter/2&&(this.sliding=!0,this.saveSliderValue(i))}this.draw()}}}class audioButton{constructor(t,e){this.playback=!1,this.pitch=!1,this.slice=!1,this.buttonIndex=e,"pitch"==t?this.pitch=!0:"slice"==t?this.slice=!0:"play"==t&&(this.playback=!0)}playConstructor(t,e,i){this.x=t,this.y=e,this.diameter=i,this.state=!1,fill(buttonColor),circle(this.x,this.y,this.diameter)}pitchConstructor(t,e,i,s){this.x=t,this.y=e,this.diameter=i,this.shiftRatio=s,this.state=!1,this.lit=!1,fill(buttonColor),circle(this.x,this.y,this.diameter)}sliceConstructor(t,e,i,s,o){this.x=t,this.y=e,this.diameter=i,this.start=s,this.end=o,this.state=!1,fill(buttonColor),circle(this.x,this.y,this.diameter)}draw(){this.state?this.lit?fill(flashColor):fill(charColor):fill(buttonColor),circle(this.x,this.y,this.diameter),this.lit&&!soundFile.isPlaying()&&(this.lit=!1)}unlitOtherButtons(){for(let t=0;t<instrumentButtons.buttons.length;t++)t!=this.buttonIndex&&(instrumentButtons.buttons[t].lit=!1)}recordingStarted(){this.state=!1,this.draw()}recordingLoaded(){this.state=!0,this.draw(),this.slice&&(console.log("length of recording loaded: "+soundFile.duration()),this.playTime=.24999*soundFile.duration(),this.startTime=this.start*soundFile.duration())}setRatio(t){this.shiftRatio=t}collision(){var t,e;this.state&&(millis()-this.lastPush<50?this.lastPush=millis():(this.lastPush=millis(),t=this.x-mouseX,e=this.y-mouseY,pow(pow(t,2)+pow(e,2),.5)<=this.diameter/2&&(this.pitch?(soundFile.rate(this.shiftRatio),soundFile.play()):this.slice?(soundFile.play(),soundFile.jump(this.startTime,this.playTime)):this.playback&&(soundFile.rate(1),soundFile.play()),this.lit=!0,this.unlitOtherButtons())))}play(){this.slice?(soundFile.play(),soundFile.jump(this.startTime,this.playTime),this.lit=!0,this.unlitOtherButtons()):this.pitch&&("undefined"===this.shiftRatio?console.log("undefffff"):(soundFile.rate(this.shiftRatio),soundFile.play(),this.lit=!0,this.unlitOtherButtons()))}}function keyTyped(){"1"===key?instrumentButtons.slice?instrumentButtons.buttons[0].play():instrumentButtons.pitch&&instrumentButtons.buttons[4].play():"2"===key?instrumentButtons.slice?instrumentButtons.buttons[1].play():instrumentButtons.pitch&&instrumentButtons.buttons[3].play():"3"===key?(instrumentButtons.slice||instrumentButtons.pitch)&&instrumentButtons.buttons[2].play():"4"===key?instrumentButtons.slice?instrumentButtons.buttons[3].play():instrumentButtons.pitch&&instrumentButtons.buttons[1].play():"5"===key?instrumentButtons.pitch&&instrumentButtons.buttons[0].play():"r"===key||"R"===key?instrumentButtons.sequencer&&instrumentButtons.buttons[0].reset():32===keyCode?instrumentButtons.sequencer&&instrumentButtons.buttons[0].togglePause():68===keyCode?instrumentButtons.state&&soundFile.save():13==keyCode&&("sequencer"==instrumentButtons.intstrumentType?(console.log("hello"),chooseSequence(),instrumentButtons.resetSequence()):instrumentButtons.pitch&&(choosePitchRatios(),instrumentButtons.resetPitchRatios()))}function gotFile(t){background(0),"audio"===t.type&&(soundFile.isPlaying()&&instrumentButtons.sequencer&&instrumentButtons.buttons[0].togglePause(),soundFile=loadSound(t))}function touchStarted(){var t;initialMouse||(userStartAudio(),initialMouse=!0,mic=new microphone,sampler=new sampleRecorder,(t=mouseX)<printWidth/4?(instrumentType="pitch",choosePitchRatios(),chooseColors(0)):t<printWidth/2?(instrumentType="slice",chooseColors(1)):t<.75*printWidth?(instrumentType="looper",chooseColors(2)):(instrumentType="sequencer",chooseSequence(),chooseColors(3)),console.log("instrument chosen: "+instrumentType),instrumentButtons=new instrumentInterface(instrumentType,diameter),game=new diceGame)}function mouseReleased(){firstClickReleased||(firstClickReleased=!0,recButton=new recordButton(.5*printWidth,printHeight/2,diameter),console.log("record button created"))}class diceGame{constructor(){charSize=printWidth<printHeight?.41*printWidth:.41*printHeight,textSize(charSize),textAlign(CENTER),this.die=[],this.die[0]=new dice(0),this.die[1]=new dice(1),this.die[2]=new dice(2)}play(){fill(charColor);var t,e,i,s=gameTimer%100;49==s?(t=this.die[0].rollValue(),e=this.die[1].rollValue(),i=this.die[2].rollValue(),(e<t&&i<t?this.die[0]:t<e&&i<e?this.die[1]:t<i&&e<i?this.die[2]:t==e&&t!=i?(this.die[0].won(),this.die[1]):((t==i&&t!=e?this.die[0]:(e==i&&t!=e||this.die[0].won(),this.die[1])).won(),this.die[2])).won()):99==s&&(this.die[0].roll(),this.die[1].roll(),this.die[2].roll()),this.die[0].draw(),this.die[1].draw(),this.die[2].draw(),gameTimer++}draw(){fill(charColor),this.die[0].draw(),this.die[1].draw(),this.die[2].draw()}}class dice{constructor(t){this.playerIndex=t,this.state=!1,this.rolling=!0,this.value=-1,this.diceChars=[],this.diceChars[0]=-1,this.diceChars[1]=9856,this.diceChars[2]=9857,this.diceChars[3]=9858,this.diceChars[4]=9859,this.diceChars[5]=9860,this.diceChars[6]=9861,this.winner=!1,"pitch"==instrumentType?(this.x=.22*printWidth,this.y=(this.playerIndex+1)*(.61*printHeight/2)):"looper"==instrumentType?(this.x=.78*printWidth,this.y=(this.playerIndex+1)*(.61*printHeight/2)):"sequencer"==instrumentType?(this.x=(1+2*this.playerIndex)*(printWidth/6),this.y=.9*printHeight):"slice"==instrumentType&&(this.x=(1+2*this.playerIndex)*(printWidth/6),this.y=.33*printHeight)}roll(){this.rolling=!0,this.winner=!1}rollValue(){return this.rolling=!1,this.value=random([1,2,3,4,5,6]),this.value}won(){this.winner=!0}draw(){var t;this.rolling?(t=1+gameTimer%6,text(String.fromCodePoint(this.diceChars[t]),this.x,this.y)):(this.winner&&gameTimer%2==0?fill(flashColor):fill(charColor),text(String.fromCodePoint(this.diceChars[this.value]),this.x,this.y))}}let colorPalettes=[[[227,163,181],[235,228,86],[225,114,0],[0,77,142]],[[183,185,239],[213,111,49],[112,147,247],[78,63,158]],[[44,46,75],[173,161,128],[143,106,116],[152,87,87]],[[173,161,128],[185,71,30],[18,2,2],[147,30,18]],[[234,97,42],[26,37,39],[245,245,14],[134,223,252]],[[117,251,76],[232,57,183],[154,31,110],[61,126,34]],[[44,98,209],[193,94,48],[124,28,23],[35,84,117]],[[226,216,133],[142,208,224],[224,188,129],[180,111,50]],[[162,210,169],[191,179,129],[149,142,125],[159,161,94]],[[193,142,186],[156,196,125],[164,201,223],[225,227,144]],[[136,47,120],[95,114,214],[199,143,74],[13,44,74]],[[212,128,93],[99,31,116],[26,67,174],[59,133,39]],[[86,119,45],[157,75,32],[136,114,121],[219,186,136]],[[145,188,211],[251,244,179],[214,145,159],[243,194,61]],[[194,92,40],[177,90,43],[69,49,100],[194,230,89]],[[172,56,46],[112,24,12],[17,46,39],[48,90,94]],[[166,201,199],[241,159,236],[146,133,162],[182,180,72]],[[252,145,171],[254,253,169],[109,93,133],[250,98,71]],[[218,223,218],[9,100,82],[181,245,124],[101,192,213]],[[64,194,16],[5,25,100],[118,108,203],[213,67,231]],[[250,47,3],[244,123,3],[80,121,1],[166,197,7]],[[92,26,16],[70,81,118],[227,81,66],[157,193,135]],[[215,160,255],[255,195,165],[1,225,255],[255,170,202]],[[0,60,209],[148,247,239],[217,1,22],[255,41,179]]],indexShuffler=[[0,1,2,3],[3,1,2,0],[1,0,2,3],[3,2,0,1],[2,3,0,1],[1,2,0,3],[2,1,0,3],[0,1,3,2],[0,3,2,1],[0,2,3,1],[3,0,1,2],[1,2,3,0],[1,3,2,0],[2,3,1,0],[1,0,3,2],[0,3,1,2],[1,3,0,2],[0,2,1,3],[2,0,1,3],[2,0,3,1],[3,0,2,1],[3,2,1,0],[2,1,3,0],[3,1,0,2]];function chooseColorPalette(){var t=(tokenId+21)%colorPalettes.length,e=floor((tokenId+21)/colorPalettes.length)%(colorPalettes.length*indexShuffler.length),t=colorPalettes[t],e=indexShuffler[e];backgroundColor=t[e[0]],charColor=t[e[1]],flashColor=t[e[2]],buttonColor=t[e[3]],(colorPalette=[])[0]=t[e[0]],colorPalette[1]=t[e[1]],colorPalette[2]=t[e[2]],colorPalette[3]=t[e[3]]}function chooseColors(e){backgroundColor=colorPalette[e];var i=[];for(let t=0;t<4;t++)t!=e&&i.push(t);buttonColor=colorPalette[i[0]],charColor=colorPalette[i[1]],flashColor=colorPalette[i[2]]}function chooseSequence(){sequenceIndex=-1==sequenceIndex?floor(random(0,sequences.length)):(sequenceIndex+1)%sequences.length,sequence=sequences[sequenceIndex]}function choosePitchRatios(){ratioIndex=-1==ratioIndex?floor(random(0,pitchRatios.length)):(ratioIndex+1)%pitchRatios.length,pitchRatio=pitchRatios[ratioIndex]}let paste,instructionLoaded=!1,loadedInstruction,loadedSoundFile,rt=(document.addEventListener("paste",function(t){clipdata=t.clipboardData||window.clipboardData,paste=clipdata.getData("text/plain"),console.log(paste),console.log("SUBMIT INSTRUCTIONS TO ETHEREUM!");t={instruction:paste};rt.mutateToken({tokenId:tokenId,data:t}),rt.commitToken({tokenId:tokenId})}),{});const loadInitalData=async()=>{await rt?.init();var t=await rt,t=(console.log("res.errors: "+t.errors),console.log("tokenIds: "+t.tokenIds),rt?.getToken({tokenId:tokenId}))["data"];console.log("tokenId: "+tokenId),console.log("data: "+t),t&&loadInstruction(t)};function loadInstruction(t){console.log("loading instruction: "+t),loadedInstruction=t.instruction,instructionLoaded=!0,console.log("link: "+loadedInstruction)}
On-chain drum machines and harmonic sequencers. Each NFT is a unique instrument. These musical instruments are interactive and best played on persistence.wtf on a desktop computer. Controls: [space] pause the beat [-] and [+] decrease or increase the tempo [r] reset back to the first beat (the first row) Save your pattern on chain: 1) Open your instrument on persistence.wtf 2) Create your pattern by playing the buttons and sliders 3) Press [space] to pause the instrument 4) Press [s] to save the pattern 5) Click [Save onchain] in the pop-up 6) In your wallet confirm the transaction circles are bad was produced by MyFi Studio https://www.myfi.studio/
DESCRIPTION_UPGRADE:On-chain drum machines and harmonic sequencers. Each NFT is a unique instrument. These musical instruments are interactive and best played on persistence.wtf on a desktop computer. Controls: [space] pause the beat [-] and [+] decrease or increase the tempo [r] reset back to the first beat (the first row) Save your pattern on chain: 1) Open your instrument on persistence.wtf 2) Create your pattern by playing the buttons and sliders 3) Press [space] to pause the instrument 4) Press [s] to save the pattern 5) Click [Save onchain] in the pop-up 6) In your wallet confirm the transaction circles are bad was produced by MyFi Studio https://www.myfi.studio/
let cyano=[44,46,75],creamSpore=[173,161,128],clay=[143,106,116],cOrall=[152,87,87],west=[173,161,128],rust=[185,71,30],blackRust=[18,2,2],darkRed=[147,30,18],kuramaOrange=[234,97,42],kuramaDark=[26,37,39],kuramaCloak=[245,245,14],rasengan=[134,223,252],nightGardenGreen=[117,251,76],nigthGardenPink=[232,57,183],maroooon=[154,31,110],poisonMoss=[61,126,34],glitchPalmBlue=[44,98,209],glitchPalmOrange=[193,94,48],brick=[124,28,23],wetMold=[35,84,117],pastelRollerCoasterYellow=[226,216,133],pastelRollerCoasterBlue=[142,208,224],pastelSand=[224,188,129],pastelDust=[180,111,50],ube=[183,185,239],car=[213,111,49],blu=[112,147,247],bluberi=[78,63,158],sgSkin=[162,210,169],sgNip=[191,179,129],sg3=[149,142,125],sg4=[159,161,94],colorPalettes=[[cyano,creamSpore,clay,cOrall],[kuramaOrange,kuramaDark,rasengan,kuramaCloak],[west,rust,blackRust,darkRed],[nightGardenGreen,nigthGardenPink,maroooon,poisonMoss],[glitchPalmBlue,glitchPalmOrange,brick,wetMold],[pastelRollerCoasterYellow,pastelRollerCoasterBlue,pastelSand,pastelDust],[ube,car,blu,bluberi],[sgSkin,sgNip,sg3,sg4],],colorPalette,backgroundColor,circleColor,currentBeatColor=[189,43,60],buttonOnColor,accentColor,initialMouse=!1,now,tempo,millisPerBeat,lastBeat=0,beat=0,subdivision=0,beatsPerMeasure,sounds=[],delay=new p5.Delay,bassDelay=new p5.Delay,harmonicRatios=[1,1.0593878,1.122449,1.189184,1.26,1.33489796,1.41428571,1.498367,1.58735,1.681837,1.78184,1.887755,2,],bassHarmonics=[.5,.5298,.56122,.5947,.63,.6673,.70714,.74918,.7937,.8408,.8622,.9439,1,],subdivisions,keyFreqRatio,beatButtons,sliders,playing=!1,currentSoundIndex=0,rt={};function setup(){document.body.style.TouchAction="none",getAudioContext().suspend(),"undefined"!=typeof tokenId?(console.log("token id: ",tokenId),randomSeed(tokenId+3098)):randomSeed(3098),createCanvas(windowWidth,windowHeight),chooseColors(),angleMode(DEGREES),millisPerBeat=60/(tempo=300)*1e3,subdivisions=floor(random(6,40)),console.log("subs: "+subdivisions),beatButtons=new beatButtonInterface(subdivisions,!0),keyFreqRatio=random(bassHarmonics),console.log("keyFreqRatio: "+keyFreqRatio),sounds[0]=new sound("bass_drum"),sounds[1]=new sound("hi_hat"),sounds[2]=new sound("synth01"),sounds[3]=new sound("synth02"),rt=window.rt,playing||(playing=!0)}function draw(){mouseIsPressed&&(beatButtons.display(),sliders.display()),initialMouse&&sliders.animate(),beatButtons.play&&playAudio()}function playAudio(){if((now=millis())-lastBeat>=millisPerBeat){beatButtons.next();for(let t=0;t<beatButtons.rows[beat].length;t++)beatButtons.rows[beat][t].on&&sounds[t].play();lastBeat=now}}const loadInitalData=async()=>{let t=await rt?.init();console.log("res",t);let{data:s}=rt?.getToken({tokenId});s&&loadPattern(s)};function chooseColors(){colorPalette=random(colorPalettes),.5>=random()?(backgroundColor=colorPalette[0],circleColor=colorPalette[1]):(backgroundColor=colorPalette[1],circleColor=colorPalette[0]),buttonOnColor=colorPalette[2],accentColor=colorPalette[3],background(backgroundColor[0],backgroundColor[1],backgroundColor[2])}class beatButtonInterface{constructor(t,s){noStroke(),this.subdivisions=t,this.yStart=.1*windowHeight,this.yGap=.25;let e=.84*windowHeight;this.diameter=e/(t*(1+this.yGap)-this.yGap),this.xGap=.3*this.diameter,this.xStart=this.diameter/2+windowWidth/2-2*this.diameter-1.5*this.xGap,s||(this.xStart=this.xStart-.25*windowWidth),this.xGap=.3*this.diameter,this.rows=[],fill(circleColor[0],circleColor[1],circleColor[2]),this.xStop=0;for(let i=0;i<subdivisions;i++){let o=[];for(let r=0;r<4;r++)o[r]=new beatButton(this.xStart+r*(this.diameter+this.xGap),this.yStart+i*(this.diameter+this.diameter*this.yGap),this.diameter),i==subdivisions-1&&3==r&&(this.xStop=this.diameter/2+this.xStart+r*(this.diameter+this.xGap));this.rows[i]=o}}next(){this.play&&(this.turnRowOff(beat),beat=(beat+1)%subdivisions,this.turnRowOn(beat))}start(){this.play=!0,lastBeat=millis(),beat=0,this.turnRowOn(0)}reset(){if(lastBeat=millis(),this.turnRowOff(beat),beat=0,this.turnRowOn(0),this.play)for(let t=0;t<beatButtons.rows[beat].length;t++)beatButtons.rows[beat][t].on&&sounds[t].play()}pause(){this.play=!this.play}turnRowOn(t){this.rows[t][0].turnOn(),this.rows[t][1].turnOn(),this.rows[t][2].turnOn(),this.rows[t][3].turnOn()}turnRowOff(t){this.rows[t][0].turnOff(),this.rows[t][1].turnOff(),this.rows[t][2].turnOff(),this.rows[t][3].turnOff()}display(){for(let t=0;t<this.rows.length;t++)for(let s=0;s<this.rows[t].length;s++)this.rows[t][s].collision()&&(this.rows[t][s].toggle(),currentSoundIndex=s)}}class beatButton{constructor(t,s,e){this.x=t,this.y=s,this.diameter=e,this.on=!1,this.play=!1,circle(this.x,this.y,e)}collision(){let t=this.x-mouseX,s=this.y-mouseY;return pow(pow(t,2)+pow(s,2),.5)<=this.diameter/2}toggle(){if(millis()-this.lastPush<20){this.lastPush=millis();return}this.lastPush=millis(),this.on=!this.on,this.on?(fill(buttonOnColor[0],buttonOnColor[1],buttonOnColor[2]),circle(this.x,this.y,this.diameter)):(fill(circleColor[0],circleColor[1],circleColor[2]),circle(this.x,this.y,this.diameter))}turnOn(){fill(currentBeatColor[0],currentBeatColor[1],currentBeatColor[2]),circle(this.x,this.y,this.diameter)}turnOff(){this.on?fill(buttonOnColor[0],buttonOnColor[1],buttonOnColor[2]):fill(circleColor[0],circleColor[1],circleColor[2]),circle(this.x,this.y,this.diameter)}}class sliderInterface{constructor(t,s,e){this.sliders=[],s+=.1*windowWidth;for(let i=0;i<t;i++)this.sliders[i]=new slider(s,50+e+i*(.15*windowHeight),.4*windowWidth,44,24)}display(){for(let t=0;t<this.sliders.length;t++)this.sliders[t].collision()}animate(){for(let t=0;t<this.sliders.length;t++)this.sliders[t].animate()}}class slider{constructor(t,s,e,i,o){this.x=t,this.y=s,this.length=e,this.height=i,this.curviness=o,this.valueSequence=[];for(let r=0;r<subdivisions;r++){this.valueSequence[r]=[];for(let l=0;l<sounds.length;l++)this.valueSequence[r][l]=.06}fill(accentColor[0],accentColor[1],accentColor[2]),this.topShape=rect(this.x,this.y,e+13,this.height,this.curviness),fill(circleColor[0],circleColor[1],circleColor[2]),this.baseShape=rect(t,s,e,i,o),fill(buttonOnColor[0],buttonOnColor[1],buttonOnColor[2]),this.topShape=rect(t,s,e/8,i,o)}collision(){this.y<=mouseY&&mouseY<=this.y+this.height&&this.x<=mouseX&&mouseX<=this.x+this.length&&(strokeWeight(0),fill(circleColor[0],circleColor[1],circleColor[2]),this.baseShape=rect(this.x,this.y,this.length,this.height,this.curviness),mouseX-this.x<=2*this.curviness?(fill(accentColor[0],accentColor[1],accentColor[2]),this.topShape=rect(this.x,this.y,2.5*this.curviness+13,this.height,this.curviness),fill(buttonOnColor[0],buttonOnColor[1],buttonOnColor[2]),this.topShape=rect(this.x,this.y,2.5*this.curviness,this.height,this.curviness)):(fill(accentColor[0],accentColor[1],accentColor[2]),this.topShape=rect(this.x,this.y,mouseX-this.x+13,this.height,this.curviness),fill(buttonOnColor[0],buttonOnColor[1],buttonOnColor[2]),this.topShape=rect(this.x,this.y,mouseX-this.x,this.height,this.curviness)),this.valueSequence[beat][currentSoundIndex]=(mouseX-this.x)/this.length)}currentValue(t){return t!=currentSoundIndex?this.valueSequence[beat][t]:mouseIsPressed&&this.y<=mouseY&&mouseY<=this.y+this.height&&this.x<=mouseX&&mouseX<=this.x+this.length?(mouseX-this.x)/this.length:this.valueSequence[beat][currentSoundIndex]}animate(){fill(circleColor[0],circleColor[1],circleColor[2]),this.baseShape=rect(this.x,this.y,this.length,this.height,this.curviness);let t=this.valueSequence[beat][currentSoundIndex]*this.length;t<=2*this.curviness?(fill(accentColor[0],accentColor[1],accentColor[2]),this.topShape=rect(this.x,this.y,2.5*this.curviness+13,this.height,this.curviness),fill(buttonOnColor[0],buttonOnColor[1],buttonOnColor[2]),this.topShape=rect(this.x,this.y,2.5*this.curviness,this.height,this.curviness)):(fill(accentColor[0],accentColor[1],accentColor[2]),this.topShape=rect(this.x,this.y,t+13,this.height,this.curviness),fill(buttonOnColor[0],buttonOnColor[1],buttonOnColor[2]),this.topShape=rect(this.x,this.y,t,this.height,this.curviness))}}function mousePressed(){initialMouse||(userStartAudio(),initialMouse=!0,background(backgroundColor[0],backgroundColor[1],backgroundColor[2]),beatButtons=new beatButtonInterface(subdivisions,!1),sliders=new sliderInterface(2,beatButtons.xStop,.63*windowHeight),loadInitalData(),beatButtons.start())}function loadPattern(t){console.log("loading pattern",sliders);for(let s=0;s<t.beatButtons.length;s++){let e=t.beatButtons[s];for(let i=0;i<e.length;i++)1==e[i]&&beatButtons.rows[s][i].toggle()}for(let o=0;o<subdivisions;o++)for(let r=0;r<4;r++)sliders.sliders[0].valueSequence[o][r]=t.sliders[r][0][o],sliders.sliders[1].valueSequence[o][r]=t.sliders[r][1][o];millisPerBeat=60/(tempo=t.tempo)*1e3}function savePattern(){let t={beatButtons:[],sliders:[],tempo:0};for(let s=0;s<beatButtons.rows.length;s++){let e=beatButtons.rows[s];for(let i=0;i<e.length;i++)t.beatButtons[s]||(t.beatButtons[s]=[]),t.beatButtons[s][i]=e[i].on?1:0}for(let o=0;o<subdivisions;o++)for(let r=0;r<4;r++)t.sliders[r]||(t.sliders[r]=[]),t.sliders[r][0]||(t.sliders[r][0]=[]),t.sliders[r][1]||(t.sliders[r][1]=[]),t.sliders[r][0][o]=sliders.sliders[0].valueSequence[o][r],t.sliders[r][1][o]=sliders.sliders[1].valueSequence[o][r];t.tempo=tempo,console.log("tokenId",tokenId),rt.mutateToken({tokenId,data:t}),rt.commitToken({tokenId})}function touchStarted(){mousePressed()}function keyTyped(){"r"===key||"R"===key?beatButtons.reset():"s"===key||"S"===key?!1==beatButtons.play&&savePattern():32==keyCode?beatButtons.pause():189==keyCode?millisPerBeat=60/--tempo*1e3:187==keyCode&&(millisPerBeat=60/++tempo*1e3)}class sound{constructor(t){if(this.envelope=new p5.Envelope,this.bassDrum=!1,this.hiHat=!1,this.synth01=!1,this.synth02=!1,this.instrument=t,this.oscillators=[],this.currentlyPlaying=!1,"bass_drum"==t)this.bassDrum=!0,this.startFrequency=98*keyFreqRatio,this.oscillators[0]=new p5.Oscillator("sine"),this.oscillators[0].amp(this.envelope),this.oscillators[0].freq(this.startFrequency),this.filter=new p5.HighPass,this.filter.freq(120),this.filter.res(16),this.oscillators[0].connect(this.filter),this.setADSR(5e-4,.2,0,.015);else if("hi_hat"==t)this.oscillators[0]=new p5.Noise,this.oscillators[0].amp(this.envelope),this.hiHat=!0,this.setADSR(1e-4,.07,.001,.02);else if("synth01"==t){this.envelope=[],this.envelope[0]=new p5.Envelope,this.envelope[1]=new p5.Envelope,this.synth01=!0,this.oscillators[0]=new p5.SawOsc,this.oscillators[1]=new p5.SqrOsc,this.startFrequency=[],this.filter=[],this.startFrequency[0]=391.995*keyFreqRatio,this.startFrequency[1]=198.2475*keyFreqRatio,this.currentFreq=this.startFrequency[0],this.oscillators[0].amp(this.envelope[0]),this.oscillators[0].freq(this.startFrequency[0]),this.oscillators[1].amp(this.envelope[1]),this.oscillators[1].freq(this.startFrequency[1]),this.filter[0]=new p5.LowPass,this.filter[1]=new p5.LowPass,this.oscillators[0].disconnect(),this.oscillators[1].disconnect(),this.oscillators[0].connect(this.filter[0]),this.oscillators[1].connect(this.filter[1]),this.filter[0].freq(this.startFrequency[0]),this.filter[1].freq(this.startFrequency[1]),this.filter[0].res(10),this.filter[1].res(18);let s=.01,e=.02,i=.2,o=.2;this.setADSR(s,e,i,o),this.oscillators[0].amp(this.envelope[0]),this.oscillators[1].amp(this.envelope[1])}else if("synth02"==t){this.envelope=[],this.envelope[0]=new p5.Envelope,this.envelope[1]=new p5.Envelope,this.synth02=!0,this.oscillators[0]=new p5.SawOsc,this.oscillators[1]=new p5.SqrOsc,this.startFrequency=[],this.filter=[],this.startFrequency[0]=sounds[2].currentFreq,this.startFrequency[1]=3+this.startFrequency[0],this.oscillators[0].amp(this.envelope[0]),this.oscillators[0].freq(this.startFrequency[0]),this.oscillators[1].amp(this.envelope[1]),this.oscillators[1].freq(this.startFrequency[1]),this.filter[0]=new p5.LowPass,this.filter[1]=new p5.LowPass,this.oscillators[0].disconnect(),this.oscillators[1].disconnect(),this.oscillators[0].connect(this.filter[0]),this.oscillators[1].connect(this.filter[1]),this.filter[0].freq(this.startFrequency[0]),this.filter[1].freq(this.startFrequency[1]),this.filter[0].res(10),this.filter[1].res(18);let r=.01,l=.001,n=.25,a=.35;this.setADSR(r,l,n,a),this.oscillators[0].amp(this.envelope[0]),this.oscillators[1].amp(this.envelope[1])}}setADSR(t,s,e,i){this.bassDrum?(this.oscillators[0].start(),this.envelope.setADSR(t,s,e,i),this.envelope.mult(3),bassDelay.process(this.oscillators[0],0,0,1e4)):this.hiHat?(this.oscillators[0].start(),this.envelope.setADSR(t,s,e,i),this.envelope.setRange(.32,0),delay.process(this.oscillators[0],.1,.2,1e4),this.envelope.setExp(),this.envelope.mult(1.4)):this.synth01?(this.oscillators[0].start(),this.oscillators[1].start(),this.envelope[0].setADSR(t,s,e,i),this.envelope[1].setADSR(t+.1,s,e,i+.05)):this.synth02&&(this.oscillators[0].start(),this.oscillators[1].start(),this.envelope[0].setADSR(t,s,e,i),this.envelope[1].setADSR(t+.1,s,e,i+.05))}play(){if(this.bassDrum){let t=map(sliders.sliders[0].currentValue(0)-.06,0,1,0,1.5),s=map(sliders.sliders[1].currentValue(0)-.06,0,1,0,5);if(s<1)bassDelay.process(this.oscillators[0],0,0,1e4);else{let e=millisPerBeat/(s+1)/1e3;bassDelay.process(this.oscillators[0],e,.4+s/30,5e3)}this.oscillators[0].freq(this.startFrequency+this.startFrequency*t-.06),this.envelope.play()}else if(this.hiHat){let i=.05+.8*sliders.sliders[0].currentValue(1),o=.01+.8*sliders.sliders[1].currentValue(1);delay.process(this.oscillators[0],i,o,1e4),this.envelope.play()}else if(this.synth01){let r=map(sliders.sliders[0].currentValue(2)-.06,0,1,0,1.5),l=[];l[0]=this.startFrequency[0]+this.startFrequency[0]*r-.06,l[1]=this.startFrequency[1]+this.startFrequency[1]*r-.06,this.oscillators[0].freq(l[0]),this.oscillators[1].freq(l[1]);let n=l[0]*map(sliders.sliders[1].currentValue(2),0,1,.7,1.5);this.filter[0].freq(n),n=l[1]*map(sliders.sliders[1].currentValue(2),0,1,.7,1.5),this.filter[1].freq(n),this.envelope[0].play(),this.envelope[1].play(),this.currentFreq=l[0]}else if(this.synth02){let a=harmonicRatios[floor(map(sliders.sliders[0].currentValue(3)-.06,0,1,0,13))],h=[];h[0]=sounds[2].currentFreq*a,h[1]=(sounds[2].currentFreq+3)*a,this.oscillators[0].freq(h[0]),this.oscillators[1].freq(h[1]);let $=h[0]*map(sliders.sliders[1].currentValue(3),0,1,.7,1.5);this.filter[0].freq($),$=h[1]*map(sliders.sliders[1].currentValue(3),0,1,.7,1.5),this.filter[1].freq($),this.envelope[0].play(),this.envelope[1].play()}this.currentlyPlaying=!0}}