Iy0qLSBjb2Rpbmc6IElTTy04ODU5LTEgLSotCiMgcHlzcWxpdGUyL3Rlc3QvcmVncmVzc2lvbi5weTogcHlzcWxpdGUgcmVncmVzc2lvbiB0ZXN0cwojCiMgQ29weXJpZ2h0IChDKSAyMDA2IEdlcmhhcmQgSORyaW5nIDxnaEBnaGFlcmluZy5kZT4KIwojIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHB5c3FsaXRlLgojCiMgVGhpcyBzb2Z0d2FyZSBpcyBwcm92aWRlZCAnYXMtaXMnLCB3aXRob3V0IGFueSBleHByZXNzIG9yIGltcGxpZWQKIyB3YXJyYW50eS4gIEluIG5vIGV2ZW50IHdpbGwgdGhlIGF1dGhvcnMgYmUgaGVsZCBsaWFibGUgZm9yIGFueSBkYW1hZ2VzCiMgYXJpc2luZyBmcm9tIHRoZSB1c2Ugb2YgdGhpcyBzb2Z0d2FyZS4KIwojIFBlcm1pc3Npb24gaXMgZ3JhbnRlZCB0byBhbnlvbmUgdG8gdXNlIHRoaXMgc29mdHdhcmUgZm9yIGFueSBwdXJwb3NlLAojIGluY2x1ZGluZyBjb21tZXJjaWFsIGFwcGxpY2F0aW9ucywgYW5kIHRvIGFsdGVyIGl0IGFuZCByZWRpc3RyaWJ1dGUgaXQKIyBmcmVlbHksIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyByZXN0cmljdGlvbnM6CiMKIyAxLiBUaGUgb3JpZ2luIG9mIHRoaXMgc29mdHdhcmUgbXVzdCBub3QgYmUgbWlzcmVwcmVzZW50ZWQ7IHlvdSBtdXN0IG5vdAojICAgIGNsYWltIHRoYXQgeW91IHdyb3RlIHRoZSBvcmlnaW5hbCBzb2Z0d2FyZS4gSWYgeW91IHVzZSB0aGlzIHNvZnR3YXJlCiMgICAgaW4gYSBwcm9kdWN0LCBhbiBhY2tub3dsZWRnbWVudCBpbiB0aGUgcHJvZHVjdCBkb2N1bWVudGF0aW9uIHdvdWxkIGJlCiMgICAgYXBwcmVjaWF0ZWQgYnV0IGlzIG5vdCByZXF1aXJlZC4KIyAyLiBBbHRlcmVkIHNvdXJjZSB2ZXJzaW9ucyBtdXN0IGJlIHBsYWlubHkgbWFya2VkIGFzIHN1Y2gsIGFuZCBtdXN0IG5vdCBiZQojICAgIG1pc3JlcHJlc2VudGVkIGFzIGJlaW5nIHRoZSBvcmlnaW5hbCBzb2Z0d2FyZS4KIyAzLiBUaGlzIG5vdGljZSBtYXkgbm90IGJlIHJlbW92ZWQgb3IgYWx0ZXJlZCBmcm9tIGFueSBzb3VyY2UgZGlzdHJpYnV0aW9uLgoKaW1wb3J0IGRhdGV0aW1lCmltcG9ydCB1bml0dGVzdAppbXBvcnQgc3FsaXRlMyBhcyBzcWxpdGUKCmNsYXNzIFJlZ3Jlc3Npb25UZXN0cyh1bml0dGVzdC5UZXN0Q2FzZSk6CiAgICBkZWYgc2V0VXAoc2VsZik6CiAgICAgICAgc2VsZi5jb24gPSBzcWxpdGUuY29ubmVjdCgiOm1lbW9yeToiKQoKICAgIGRlZiB0ZWFyRG93bihzZWxmKToKICAgICAgICBzZWxmLmNvbi5jbG9zZSgpCgogICAgZGVmIENoZWNrUHJhZ21hVXNlclZlcnNpb24oc2VsZik6CiAgICAgICAgIyBUaGlzIHVzZWQgdG8gY3Jhc2ggcHlzcWxpdGUgYmVjYXVzZSB0aGlzIHByYWdtYSBjb21tYW5kIHJldHVybnMgTlVMTCBmb3IgdGhlIGNvbHVtbiBuYW1lCiAgICAgICAgY3VyID0gc2VsZi5jb24uY3Vyc29yKCkKICAgICAgICBjdXIuZXhlY3V0ZSgicHJhZ21hIHVzZXJfdmVyc2lvbiIpCgogICAgZGVmIENoZWNrUHJhZ21hU2NoZW1hVmVyc2lvbihzZWxmKToKICAgICAgICAjIFRoaXMgc3RpbGwgY3Jhc2hlZCBweXNxbGl0ZSA8PSAyLjIuMQogICAgICAgIGNvbiA9IHNxbGl0ZS5jb25uZWN0KCI6bWVtb3J5OiIsIGRldGVjdF90eXBlcz1zcWxpdGUuUEFSU0VfQ09MTkFNRVMpCiAgICAgICAgdHJ5OgogICAgICAgICAgICBjdXIgPSBzZWxmLmNvbi5jdXJzb3IoKQogICAgICAgICAgICBjdXIuZXhlY3V0ZSgicHJhZ21hIHNjaGVtYV92ZXJzaW9uIikKICAgICAgICBmaW5hbGx5OgogICAgICAgICAgICBjdXIuY2xvc2UoKQogICAgICAgICAgICBjb24uY2xvc2UoKQoKICAgIGRlZiBDaGVja1N0YXRlbWVudFJlc2V0KHNlbGYpOgogICAgICAgICMgcHlzcWxpdGUgMi4xLjAgdG8gMi4yLjAgaGF2ZSB0aGUgcHJvYmxlbSB0aGF0IG5vdCBhbGwgc3RhdGVtZW50cyBhcmUKICAgICAgICAjIHJlc2V0IGJlZm9yZSBhIHJvbGxiYWNrLCBidXQgb25seSB0aG9zZSB0aGF0IGFyZSBzdGlsbCBpbiB0aGUKICAgICAgICAjIHN0YXRlbWVudCBjYWNoZS4gVGhlIG90aGVycyBhcmUgbm90IGFjY2Vzc2libGUgZnJvbSB0aGUgY29ubmVjdGlvbiBvYmplY3QuCiAgICAgICAgY29uID0gc3FsaXRlLmNvbm5lY3QoIjptZW1vcnk6IiwgY2FjaGVkX3N0YXRlbWVudHM9NSkKICAgICAgICBjdXJzb3JzID0gW2Nvbi5jdXJzb3IoKSBmb3IgeCBpbiByYW5nZSg1KV0KICAgICAgICBjdXJzb3JzWzBdLmV4ZWN1dGUoImNyZWF0ZSB0YWJsZSB0ZXN0KHgpIikKICAgICAgICBmb3IgaSBpbiByYW5nZSgxMCk6CiAgICAgICAgICAgIGN1cnNvcnNbMF0uZXhlY3V0ZW1hbnkoImluc2VydCBpbnRvIHRlc3QoeCkgdmFsdWVzICg/KSIsIFsoeCwpIGZvciB4IGluIHJhbmdlKDEwKV0pCgogICAgICAgIGZvciBpIGluIHJhbmdlKDUpOgogICAgICAgICAgICBjdXJzb3JzW2ldLmV4ZWN1dGUoIiAiICogaSArICJzZWxlY3QgeCBmcm9tIHRlc3QiKQoKICAgICAgICBjb24ucm9sbGJhY2soKQoKICAgIGRlZiBDaGVja0NvbHVtbk5hbWVXaXRoU3BhY2VzKHNlbGYpOgogICAgICAgIGN1ciA9IHNlbGYuY29uLmN1cnNvcigpCiAgICAgICAgY3VyLmV4ZWN1dGUoJ3NlbGVjdCAxIGFzICJmb28gYmFyIFtkYXRldGltZV0iJykKICAgICAgICBzZWxmLmFzc2VydEVxdWFsKGN1ci5kZXNjcmlwdGlvblswXVswXSwgImZvbyBiYXIiKQoKICAgICAgICBjdXIuZXhlY3V0ZSgnc2VsZWN0IDEgYXMgImZvbyBiYXoiJykKICAgICAgICBzZWxmLmFzc2VydEVxdWFsKGN1ci5kZXNjcmlwdGlvblswXVswXSwgImZvbyBiYXoiKQoKICAgIGRlZiBDaGVja1N0YXRlbWVudEF2YWlsYWJsZShzZWxmKToKICAgICAgICAjIHB5c3FsaXRlIHVwIHRvIDIuMy4yIGNyYXNoZWQgb24gdGhpcywgYmVjYXVzZSB0aGUgYWN0aXZlIHN0YXRlbWVudCBoYW5kbGUgd2FzIG5vdCBjaGVja2VkCiAgICAgICAgIyBiZWZvcmUgdHJ5aW5nIHRvIGZldGNoIGRhdGEgZnJvbSBpdC4gY2xvc2UoKSBkZXN0cm95cyB0aGUgYWN0aXZlIHN0YXRlbWVudCAuLi4KICAgICAgICBjb24gPSBzcWxpdGUuY29ubmVjdCgiOm1lbW9yeToiLCBkZXRlY3RfdHlwZXM9c3FsaXRlLlBBUlNFX0RFQ0xUWVBFUykKICAgICAgICBjdXIgPSBjb24uY3Vyc29yKCkKICAgICAgICBjdXIuZXhlY3V0ZSgic2VsZWN0IDQgdW5pb24gc2VsZWN0IDUiKQogICAgICAgIGN1ci5jbG9zZSgpCiAgICAgICAgY3VyLmZldGNob25lKCkKICAgICAgICBjdXIuZmV0Y2hvbmUoKQoKICAgIGRlZiBDaGVja1N0YXRlbWVudEZpbmFsaXphdGlvbk9uQ2xvc2VEYihzZWxmKToKICAgICAgICAjIHB5c3FsaXRlIHZlcnNpb25zIDw9IDIuMy4zIG9ubHkgZmluYWxpemVkIHN0YXRlbWVudHMgaW4gdGhlIHN0YXRlbWVudAogICAgICAgICMgY2FjaGUgd2hlbiBjbG9zaW5nIHRoZSBkYXRhYmFzZS4gc3RhdGVtZW50cyB0aGF0IHdlcmUgc3RpbGwKICAgICAgICAjIHJlZmVyZW5jZWQgaW4gY3Vyc29ycyB3ZXJlbid0IGNsb3NlZCBhbiBjb3VsZCBwcm92b2tlICIKICAgICAgICAjICJPcGVyYXRpb25hbEVycm9yOiBVbmFibGUgdG8gY2xvc2UgZHVlIHRvIHVuZmluYWxpc2VkIHN0YXRlbWVudHMiLgogICAgICAgIGNvbiA9IHNxbGl0ZS5jb25uZWN0KCI6bWVtb3J5OiIpCiAgICAgICAgY3Vyc29ycyA9IFtdCiAgICAgICAgIyBkZWZhdWx0IHN0YXRlbWVudCBjYWNoZSBzaXplIGlzIDEwMAogICAgICAgIGZvciBpIGluIHJhbmdlKDEwNSk6CiAgICAgICAgICAgIGN1ciA9IGNvbi5jdXJzb3IoKQogICAgICAgICAgICBjdXJzb3JzLmFwcGVuZChjdXIpCiAgICAgICAgICAgIGN1ci5leGVjdXRlKCJzZWxlY3QgMSB4IHVuaW9uIHNlbGVjdCAiICsgc3RyKGkpKQogICAgICAgIGNvbi5jbG9zZSgpCgogICAgZGVmIENoZWNrT25Db25mbGljdFJvbGxiYWNrKHNlbGYpOgogICAgICAgIGlmIHNxbGl0ZS5zcWxpdGVfdmVyc2lvbl9pbmZvIDwgKDMsIDIsIDIpOgogICAgICAgICAgICByZXR1cm4KICAgICAgICBjb24gPSBzcWxpdGUuY29ubmVjdCgiOm1lbW9yeToiKQogICAgICAgIGNvbi5leGVjdXRlKCJjcmVhdGUgdGFibGUgZm9vKHgsIHVuaXF1ZSh4KSBvbiBjb25mbGljdCByb2xsYmFjaykiKQogICAgICAgIGNvbi5leGVjdXRlKCJpbnNlcnQgaW50byBmb28oeCkgdmFsdWVzICgxKSIpCiAgICAgICAgdHJ5OgogICAgICAgICAgICBjb24uZXhlY3V0ZSgiaW5zZXJ0IGludG8gZm9vKHgpIHZhbHVlcyAoMSkiKQogICAgICAgIGV4Y2VwdCBzcWxpdGUuRGF0YWJhc2VFcnJvcjoKICAgICAgICAgICAgcGFzcwogICAgICAgIGNvbi5leGVjdXRlKCJpbnNlcnQgaW50byBmb28oeCkgdmFsdWVzICgyKSIpCiAgICAgICAgdHJ5OgogICAgICAgICAgICBjb24uY29tbWl0KCkKICAgICAgICBleGNlcHQgc3FsaXRlLk9wZXJhdGlvbmFsRXJyb3I6CiAgICAgICAgICAgIHNlbGYuZmFpbCgicHlzcWxpdGUga25ldyBub3RoaW5nIGFib3V0IHRoZSBpbXBsaWNpdCBST0xMQkFDSyIpCgogICAgZGVmIENoZWNrV29ya2Fyb3VuZEZvckJ1Z2d5U3FsaXRlVHJhbnNmZXJCaW5kaW5ncyhzZWxmKToKICAgICAgICAiIiIKICAgICAgICBweXNxbGl0ZSB3b3VsZCBjcmFzaCB3aXRoIG9sZGVyIFNRTGl0ZSB2ZXJzaW9ucyB1bmxlc3MKICAgICAgICBhIHdvcmthcm91bmQgaXMgaW1wbGVtZW50ZWQuCiAgICAgICAgIiIiCiAgICAgICAgc2VsZi5jb24uZXhlY3V0ZSgiY3JlYXRlIHRhYmxlIGZvbyhiYXIpIikKICAgICAgICBzZWxmLmNvbi5leGVjdXRlKCJkcm9wIHRhYmxlIGZvbyIpCiAgICAgICAgc2VsZi5jb24uZXhlY3V0ZSgiY3JlYXRlIHRhYmxlIGZvbyhiYXIpIikKCiAgICBkZWYgQ2hlY2tFbXB0eVN0YXRlbWVudChzZWxmKToKICAgICAgICAiIiIKICAgICAgICBweXNxbGl0ZSB1c2VkIHRvIHNlZ2ZhdWx0IHdpdGggU1FMaXRlIHZlcnNpb25zIDMuNS54LiBUaGVzZSByZXR1cm4gTlVMTAogICAgICAgIGZvciAibm8tb3BlcmF0aW9uIiBzdGF0ZW1lbnRzCiAgICAgICAgIiIiCiAgICAgICAgc2VsZi5jb24uZXhlY3V0ZSgiIikKCiAgICBkZWYgQ2hlY2tUeXBlTWFwVXNhZ2Uoc2VsZik6CiAgICAgICAgIiIiCiAgICAgICAgcHlzcWxpdGUgdW50aWwgMi40LjEgZGlkIG5vdCByZWJ1aWxkIHRoZSByb3dfY2FzdF9tYXAgd2hlbiByZWNvbXBpbGluZwogICAgICAgIGEgc3RhdGVtZW50LiBUaGlzIHRlc3QgZXhoaWJpdHMgdGhlIHByb2JsZW0uCiAgICAgICAgIiIiCiAgICAgICAgU0VMRUNUID0gInNlbGVjdCAqIGZyb20gZm9vIgogICAgICAgIGNvbiA9IHNxbGl0ZS5jb25uZWN0KCI6bWVtb3J5OiIsZGV0ZWN0X3R5cGVzPXNxbGl0ZS5QQVJTRV9ERUNMVFlQRVMpCiAgICAgICAgY29uLmV4ZWN1dGUoImNyZWF0ZSB0YWJsZSBmb28oYmFyIHRpbWVzdGFtcCkiKQogICAgICAgIGNvbi5leGVjdXRlKCJpbnNlcnQgaW50byBmb28oYmFyKSB2YWx1ZXMgKD8pIiwgKGRhdGV0aW1lLmRhdGV0aW1lLm5vdygpLCkpCiAgICAgICAgY29uLmV4ZWN1dGUoU0VMRUNUKQogICAgICAgIGNvbi5leGVjdXRlKCJkcm9wIHRhYmxlIGZvbyIpCiAgICAgICAgY29uLmV4ZWN1dGUoImNyZWF0ZSB0YWJsZSBmb28oYmFyIGludGVnZXIpIikKICAgICAgICBjb24uZXhlY3V0ZSgiaW5zZXJ0IGludG8gZm9vKGJhcikgdmFsdWVzICg1KSIpCiAgICAgICAgY29uLmV4ZWN1dGUoU0VMRUNUKQoKICAgIGRlZiBDaGVja0Vycm9yTXNnRGVjb2RlRXJyb3Ioc2VsZik6CiAgICAgICAgIyBXaGVuIHBvcnRpbmcgdGhlIG1vZHVsZSB0byBQeXRob24gMy4wLCB0aGUgZXJyb3IgbWVzc2FnZSBhYm91dAogICAgICAgICMgZGVjb2RpbmcgZXJyb3JzIGRpc2FwcGVhcmVkLiBUaGlzIHZlcmlmaWVzIHRoZXkncmUgYmFjayBhZ2Fpbi4KICAgICAgICBmYWlsdXJlID0gTm9uZQogICAgICAgIHRyeToKICAgICAgICAgICAgc2VsZi5jb24uZXhlY3V0ZSgic2VsZWN0ICd4eHgnIHx8ID8gfHwgJ3l5eScgY29sbmFtZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGJ5dGVzKGJ5dGVhcnJheShbMjUwXSkpLCkpLmZldGNob25lKCkKICAgICAgICAgICAgZmFpbHVyZSA9ICJzaG91bGQgaGF2ZSByYWlzZWQgYW4gT3BlcmF0aW9uYWxFcnJvciB3aXRoIGRldGFpbGVkIGRlc2NyaXB0aW9uIgogICAgICAgIGV4Y2VwdCBzcWxpdGUuT3BlcmF0aW9uYWxFcnJvciBhcyBlOgogICAgICAgICAgICBtc2cgPSBlLmFyZ3NbMF0KICAgICAgICAgICAgaWYgbm90IG1zZy5zdGFydHN3aXRoKCJDb3VsZCBub3QgZGVjb2RlIHRvIFVURi04IGNvbHVtbiAnY29sbmFtZScgd2l0aCB0ZXh0ICd4eHgiKToKICAgICAgICAgICAgICAgIGZhaWx1cmUgPSAiT3BlcmF0aW9uYWxFcnJvciBkaWQgbm90IGhhdmUgZXhwZWN0ZWQgZGVzY3JpcHRpb24gdGV4dCIKICAgICAgICBpZiBmYWlsdXJlOgogICAgICAgICAgICBzZWxmLmZhaWwoZmFpbHVyZSkKCiAgICBkZWYgQ2hlY2tSZWdpc3RlckFkYXB0ZXIoc2VsZik6CiAgICAgICAgIiIiCiAgICAgICAgU2VlIGlzc3VlIDMzMTIuCiAgICAgICAgIiIiCiAgICAgICAgc2VsZi5hc3NlcnRSYWlzZXMoVHlwZUVycm9yLCBzcWxpdGUucmVnaXN0ZXJfYWRhcHRlciwge30sIE5vbmUpCgogICAgZGVmIENoZWNrU2V0SXNvbGF0aW9uTGV2ZWwoc2VsZik6CiAgICAgICAgIiIiCiAgICAgICAgU2VlIGlzc3VlIDMzMTIuCiAgICAgICAgIiIiCiAgICAgICAgY29uID0gc3FsaXRlLmNvbm5lY3QoIjptZW1vcnk6IikKICAgICAgICBzZXRhdHRyKGNvbiwgImlzb2xhdGlvbl9sZXZlbCIsICJceGU5IikKCiAgICBkZWYgQ2hlY2tTdHJTdWJjbGFzcyhzZWxmKToKICAgICAgICAiIiIKICAgICAgICBUaGUgUHl0aG9uIDMuMCBwb3J0IG9mIHRoZSBtb2R1bGUgZGlkbid0IGNvcGUgd2l0aCB2YWx1ZXMgb2Ygc3ViY2xhc3NlcyBvZiBzdHIuCiAgICAgICAgIiIiCiAgICAgICAgY2xhc3MgTXlTdHIoc3RyKTogcGFzcwogICAgICAgIHNlbGYuY29uLmV4ZWN1dGUoInNlbGVjdCA/IiwgKE15U3RyKCJhYmMiKSwpKQoKICAgIGRlZiBDaGVja0Nvbm5lY3Rpb25DYWxsKHNlbGYpOgogICAgICAgICIiIgogICAgICAgIENhbGwgYSBjb25uZWN0aW9uIHdpdGggYSBub24tc3RyaW5nIFNRTCByZXF1ZXN0OiBjaGVjayBlcnJvciBoYW5kbGluZwogICAgICAgIG9mIHRoZSBzdGF0ZW1lbnQgY29uc3RydWN0b3IuCiAgICAgICAgIiIiCiAgICAgICAgc2VsZi5hc3NlcnRSYWlzZXMoc3FsaXRlLldhcm5pbmcsIHNlbGYuY29uLCAxKQoKICAgIGRlZiBDaGVja0NvbGxhdGlvbihzZWxmKToKICAgICAgICBkZWYgY29sbGF0aW9uX2NiKGEsIGIpOgogICAgICAgICAgICByZXR1cm4gMQogICAgICAgIHNlbGYuYXNzZXJ0UmFpc2VzKHNxbGl0ZS5Qcm9ncmFtbWluZ0Vycm9yLCBzZWxmLmNvbi5jcmVhdGVfY29sbGF0aW9uLAogICAgICAgICAgICAjIExvbmUgc3Vycm9nYXRlIGNhbm5vdCBiZSBlbmNvZGVkIHRvIHRoZSBkZWZhdWx0IGVuY29kaW5nICh1dGY4KQogICAgICAgICAgICAiXHVEQzgwIiwgY29sbGF0aW9uX2NiKQoKZGVmIHN1aXRlKCk6CiAgICByZWdyZXNzaW9uX3N1aXRlID0gdW5pdHRlc3QubWFrZVN1aXRlKFJlZ3Jlc3Npb25UZXN0cywgIkNoZWNrIikKICAgIHJldHVybiB1bml0dGVzdC5UZXN0U3VpdGUoKHJlZ3Jlc3Npb25fc3VpdGUsKSkKCmRlZiB0ZXN0KCk6CiAgICBydW5uZXIgPSB1bml0dGVzdC5UZXh0VGVzdFJ1bm5lcigpCiAgICBydW5uZXIucnVuKHN1aXRlKCkpCgppZiBfX25hbWVfXyA9PSAiX19tYWluX18iOgogICAgdGVzdCgpCg==