{
  "files": {
    "app/fight_r5/runtime.py": "IiIiQWRhcHQgbm9ybWFsaXplZCBzYW1lLWZyYW1lIFBvc2UgdG8gUjU7IHB1Ymxpc2ggb25seSBjdXJyZW50IHJlYWwgb2JqZWN0cy4iIiIKZnJvbSBjb2xsZWN0aW9ucyBpbXBvcnQgQ291bnRlcgpmcm9tIGFwcC5jb250cmFjdHMuZnJhbWVzIGltcG9ydCBGcmFtZUVudmVsb3BlLCBQb3NlT2JzZXJ2YXRpb24KZnJvbSBhcHAucG9zZV9jb25maWcgaW1wb3J0IFBPU0VfTU9ERUwKZnJvbSBhcHAuaW50cnVzaW9uIGltcG9ydCBpbnNpZGUKZnJvbSBhcHAuZXZlbnRfY29vbGRvd24gaW1wb3J0IGFsbG93X2V2ZW50CmZyb20gLmNvcmUgaW1wb3J0IFI1Q29yZQoKCmNsYXNzIFI1UnVudGltZToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBjb25maWcsIGV2ZW50X2lkX2ZhY3RvcnksIHdhbGxfbnMsIGNvbnRhaW5zPU5vbmUpOgogICAgICAgIHNlbGYuY29uZmlnPWNvbmZpZztzZWxmLmV2ZW50X2lkX2ZhY3Rvcnk9ZXZlbnRfaWRfZmFjdG9yeTtzZWxmLndhbGxfbnM9d2FsbF9ucwogICAgICAgIHNlbGYuY29udGFpbnM9Y29udGFpbnM7c2VsZi5tZXRyaWNzPUNvdW50ZXIoKQogICAgICAgIHNlbGYuY29yZT1SNUNvcmUoY29uZmlnLnI1LHBlcnNvbl9zY29yZT1jb25maWcucG9saWN5LnBlcnNvbl9zY29yZSxqb2ludF9zY29yZT1jb25maWcucG9saWN5LmpvaW50X3Njb3JlKQogICAgICAgIHNlbGYuY2xlYXIoKQoKICAgIGRlZiBjbGVhcihzZWxmKToKICAgICAgICBzZWxmLmNvcmUuY2xlYXIoKTtzZWxmLl9pZGVudGl0eT1Ob25lO3NlbGYuX2xhc3RfcHRzPU5vbmU7c2VsZi5fbGFzdF9zZXE9Tm9uZQogICAgICAgIHNlbGYuX2dhcF9wZW5kaW5nPUZhbHNlO3NlbGYuX2V2ZW50X2lkPU5vbmU7c2VsZi5sYXN0X3Jlc3VsdD1Ob25lCgogICAgZGVmIF9icmVha19tb3Rpb24oc2VsZik6CiAgICAgICAgZnJvbSAuZ2VvbWV0cnkgaW1wb3J0IFNwYXRpYWwKICAgICAgICBmcm9tIC5kZWNpc2lvbiBpbXBvcnQgUmVmaW5lZAogICAgICAgIHNlbGYuY29yZS5zcGF0aWFsPVNwYXRpYWwoc2VsZi5jb3JlLmdlb21ldHJ5KQogICAgICAgIHNlbGYuY29yZS5kZWNpc2lvbj1SZWZpbmVkKHNlbGYuY29uZmlnLnI1LmRlY2lzaW9uKCksZGljdChjb21wYWN0X2hhbmQ9LjEyLGNvbXBhY3RfbWF4X3NwZWVkPTEuKSkKICAgICAgICBzZWxmLmNvcmUuaG9sZHMuY2xlYXIoKTtzZWxmLmNvcmUuZXBpc29kZS5wcmV2aW91c19xdWlldD1GYWxzZTtzZWxmLmNvcmUuZXBpc29kZS5xdWlldD0wLgoKICAgIGRlZiBldmFsdWF0ZShzZWxmLCBmcmFtZSwgcG9zZXMsIGlkcywgKiwgZ2FwX2JlZm9yZT1GYWxzZSk6CiAgICAgICAgZnJvbSBhcHAuZmlnaHRfcnVudGltZSBpbXBvcnQgRmlnaHREaXNwbGF5LCBGaWdodEV2ZW50CiAgICAgICAgaWYgbm90IGlzaW5zdGFuY2UoZnJhbWUsRnJhbWVFbnZlbG9wZSkgb3IgdHlwZShnYXBfYmVmb3JlKSBpcyBub3QgYm9vbDoKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBGSUdIVCBSNSBGcmFtZS4nKQogICAgICAgIHBvc2VzLGlkcz10dXBsZShwb3NlcyksdHVwbGUoaWRzKQogICAgICAgIGlmIGxlbihwb3NlcykhPWxlbihpZHMpOnJhaXNlIFZhbHVlRXJyb3IoJ1Bvc2UvVHJhY2tpbmcgYXNzb2NpYXRpb24gZGlmZmVycy4nKQogICAgICAgIHNlZW49c2V0KCkKICAgICAgICBmb3IgcCx0aWQgaW4gemlwKHBvc2VzLGlkcyk6CiAgICAgICAgICAgIGlmIG5vdCBpc2luc3RhbmNlKHAsUG9zZU9ic2VydmF0aW9uKSBvciBwLmZyYW1lIT1mcmFtZSBvciBwLm1vZGVsX2tleSE9UE9TRV9NT0RFTDoKICAgICAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ0ZJR0hUIFI1IHJlcXVpcmVzIHNhbWUtRnJhbWUgY2Fub25pY2FsIFBvc2UuJykKICAgICAgICAgICAgaWYgdGlkIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgaWYgdHlwZSh0aWQpIGlzIG5vdCBpbnQgb3IgdGlkPDEgb3IgdGlkIGluIHNlZW46cmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBGSUdIVCB0cmFjayBJRC4nKQogICAgICAgICAgICAgICAgc2Vlbi5hZGQodGlkKQogICAgICAgIHBvaW50cz10dXBsZSgoKHAuYmJveF94eXh5WzBdK3AuYmJveF94eXh5WzJdKS8yLHAuYmJveF94eXh5WzNdKSBmb3IgcCBpbiBwb3NlcykKICAgICAgICBzZWxlY3RlZD1baSBmb3IgaSxwIGluIGVudW1lcmF0ZShwb2ludHMpIGlmIChzZWxmLmNvbnRhaW5zKHApIGlmIHNlbGYuY29udGFpbnMgZWxzZSBpbnNpZGUocCxzZWxmLmNvbmZpZy5yb2kpKV0KICAgICAgICByb3dzPVsoRmlnaHREaXNwbGF5KHAsaSBpbiBzZWxlY3RlZCwnTU9OSVRPUklORycgaWYgaSBpbiBzZWxlY3RlZCBlbHNlICdPVVRTSURFJyxzZWxmLmNvbmZpZy5jb25maWRlbmNlKSwpIGZvciBpLHAgaW4gZW51bWVyYXRlKHBvaW50cyldCiAgICAgICAgcHRzPWZyYW1lLnB0c19ucwogICAgICAgIGlmIHR5cGUocHRzKSBpcyBub3QgaW50IG9yIG5vdCAwPD1wdHM8MioqNjMgb3IgdHlwZShmcmFtZS5mcmFtZV9zZXEpIGlzIG5vdCBpbnQgb3IgZnJhbWUuZnJhbWVfc2VxPDA6CiAgICAgICAgICAgIHNlbGYuX2dhcF9wZW5kaW5nPVRydWU7c2VsZi5tZXRyaWNzWydpbnZhbGlkX3B0cyddKz0xO3JldHVybiB0dXBsZShyb3dzKSwoKQogICAgICAgIGlkZW50aXR5PShmcmFtZS5zZXJ2ZXJfaWQsZnJhbWUuc291cmNlX2lkLGZyYW1lLnN0cmVhbV9pZCxmcmFtZS5ydW5faWQsZnJhbWUucnVuX2dlbmVyYXRpb24sCiAgICAgICAgICAgICAgICAgIGZyYW1lLmZyYW1lX3dpZHRoLGZyYW1lLmZyYW1lX2hlaWdodCxmcmFtZS5jb25maWdfdmVyc2lvbikKICAgICAgICBpZiBzZWxmLl9pZGVudGl0eSBpcyBub3QgTm9uZSBhbmQgc2VsZi5faWRlbnRpdHkhPWlkZW50aXR5OgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdGSUdIVCBSNSBydW4vc291cmNlL2NvbmZpZy9nZW9tZXRyeSBjaGFuZ2VkOyBjbGVhciBvciBjcmVhdGUgYSBuZXcgZW5naW5lLicpCiAgICAgICAgaWYgc2VsZi5fbGFzdF9wdHMgaXMgbm90IE5vbmUgYW5kIChwdHM8PXNlbGYuX2xhc3RfcHRzIG9yIGZyYW1lLmZyYW1lX3NlcTw9c2VsZi5fbGFzdF9zZXEpOgogICAgICAgICAgICBzZWxmLm1ldHJpY3NbJ3N0YWxlX2ZyYW1lJ10rPTE7cmV0dXJuIHR1cGxlKHJvd3MpLCgpCiAgICAgICAgc2VsZi5faWRlbnRpdHk9aWRlbnRpdHk7c2VsZi5fbGFzdF9wdHM9cHRzO3NlbGYuX2xhc3Rfc2VxPWZyYW1lLmZyYW1lX3NlcQogICAgICAgIGlmIG5vdCBzZWxmLmNvbmZpZy5lbmFibGVkOnJldHVybiB0dXBsZShyb3dzKSwoKQogICAgICAgIGlmIGdhcF9iZWZvcmUgb3Igc2VsZi5fZ2FwX3BlbmRpbmc6c2VsZi5fYnJlYWtfbW90aW9uKCkKICAgICAgICBzZWxmLl9nYXBfcGVuZGluZz1GYWxzZQogICAgICAgIHcsaD1mcmFtZS5mcmFtZV93aWR0aCxmcmFtZS5mcmFtZV9oZWlnaHQKICAgICAgICBwZXJzb25zPVtdCiAgICAgICAgZm9yIGkgaW4gc2VsZWN0ZWQ6CiAgICAgICAgICAgIHA9cG9zZXNbaV0KICAgICAgICAgICAgcGVyc29ucy5hcHBlbmQoZGljdChzY29yZT1wLnNjb3JlLGJib3g9W3YqKHcgaWYgayUyPT0wIGVsc2UgaCkgZm9yIGssdiBpbiBlbnVtZXJhdGUocC5iYm94X3h5eHkpXSwKICAgICAgICAgICAgICAgIGtleXBvaW50cz1bW3gqdyx5Kmgsc10gZm9yIHgseSxzIGluIHAua2V5cG9pbnRzXSx0cmFja19pZD1pZHNbaV0scXVlcnk9aSkpCiAgICAgICAgcixfPXNlbGYuY29yZS5zdGVwKGRpY3Qoc2Vjb25kcz1wdHMvMWU5LHdpZHRoPXcsaGVpZ2h0PWgscGVyc29ucz1wZXJzb25zKSkKICAgICAgICBzZWxmLmxhc3RfcmVzdWx0PXI7ZXZlbnRzPVtdCiAgICAgICAgaWYgbm90IHJbJ2VwaXNvZGUnXVsnbGF0Y2hlZCddOnNlbGYuX2V2ZW50X2lkPU5vbmUKICAgICAgICBpZiByWydlcGlzb2RlJ11bJ2V2ZW50J106CiAgICAgICAgICAgIHNlbGYuX2V2ZW50X2lkPU5vbmUKICAgICAgICAgICAgaWYgYWxsb3dfZXZlbnQoc2VsZiwnRklHSFQnKToKICAgICAgICAgICAgICAgIGk9c2VsZWN0ZWRbclsnY3VycmVudF9vcmRlcnMnXVswXV07ZWlkPXNlbGYuZXZlbnRfaWRfZmFjdG9yeSgpO3NlbGYuX2V2ZW50X2lkPWVpZAogICAgICAgICAgICAgICAgZXZlbnRzLmFwcGVuZChGaWdodEV2ZW50KGVpZCxmcmFtZSxpZHNbaV0sc2VsZi5jb25maWcuZ2VvbWV0cnkucm9pX2lkLHN0cihpKSwKICAgICAgICAgICAgICAgICAgICBwb3Nlc1tpXS5zY29yZSxwb3Nlc1tpXS5iYm94X3h5eHkscG9zZXNbaV0ubW9kZWxfa2V5LHNlbGYud2FsbF9ucygpLy8xMDAwMDAwKSkKICAgICAgICAgICAgICAgIHNlbGYubWV0cmljc1snZXZlbnRzX2FkbWl0dGVkJ10rPTEKICAgICAgICAgICAgZWxzZTpzZWxmLm1ldHJpY3NbJ2V2ZW50c19zdXBwcmVzc2VkX2J5X3dlYl9jb29sZG93biddKz0xCiAgICAgICAgZm9yIG9yZGVyIGluIHJbJ2Rpc3BsYXlfb3JkZXJzJ106CiAgICAgICAgICAgIGk9c2VsZWN0ZWRbb3JkZXJdCiAgICAgICAgICAgIHJvd3NbaV09KEZpZ2h0RGlzcGxheShwb2ludHNbaV0sVHJ1ZSwnRklHSFQnLHNlbGYuY29uZmlnLmNvbmZpZGVuY2Usc2VsZi5fZXZlbnRfaWQpLCkKICAgICAgICByZXR1cm4gdHVwbGUocm93cyksdHVwbGUoZXZlbnRzKQo=",
    "app/fight_runtime.py": "IiIiVGVtcG9yYXJ5IEZJR0hUIGFkYXB0ZXI6IHNoYXJlZCBQb3NlL1RyYWNraW5nLCBpbmRlcGVuZGVudCBwYWlyIEV2ZW50cyBhbmQgUk9JLiIiIgpmcm9tIGRhdGFjbGFzc2VzIGltcG9ydCBkYXRhY2xhc3MsIGZpZWxkcywgcmVwbGFjZQppbXBvcnQgb3MKaW1wb3J0IHRpbWUKaW1wb3J0IHV1aWQKCmZyb20gYXBwLmZpZ2h0X2NvbmZpZyBpbXBvcnQgRmlnaHRDb25maWcKZnJvbSBhcHAuZmlnaHRfc2NlbmFyaW8gaW1wb3J0IEZpZ2h0RW5naW5lCmZyb20gYXBwLmludHJ1c2lvbiBpbXBvcnQgSW50cnVzaW9uQ29uZmlnLCBJbnRydXNpb25FdmVudCwgaW5zaWRlCgojIEV4aXN0aW5nIHNldHRpbmdzIGtleXMgb25seS4gRXhwbGljaXQgc2F2ZWQvV2ViIHZhbHVlcyBhcmUgbm90IG92ZXJ3cml0dGVuLgojIEZpZ2h0Q29uZmlnIHJlbWFpbnMgdGhlIHByZS1kZW1vIHRlbXBvcmFsIHBvbGljeSBmb3IgcmVncmVzc2lvbi9yb2xsYmFjay4KREVNT19GSUdIVF9ERUZBVUxUUyA9IGRpY3QocGVyc29uX3Njb3JlPS4xNSwgam9pbnRfc2NvcmU9LjEwLAogICAgcGFpcl9kaXN0YW5jZV9yYXRpbz0xLjgsIHBhaXJfY2xvc2VfaG9sZF9zZWNvbmRzPS4xLAogICAgYXJtX21vdGlvbl93aW5kb3dfc2Vjb25kcz0xLiwgYXJtX21vdGlvbl9yYXRpbz0uMTAsCiAgICB0b3dhcmRfb3Bwb25lbnRfcmF0aW89LjAxLCByZXF1aXJlZF9idXJzdHM9MSkKCgpAZGF0YWNsYXNzKGZyb3plbj1UcnVlKQpjbGFzcyBGaWdodFNldHRpbmdzOgogICAgcG9saWN5OiBGaWdodENvbmZpZwogICAgZ2VvbWV0cnk6IEludHJ1c2lvbkNvbmZpZwogICAgZW5naW5lOiBzdHIgPSAnbGVnYWN5JwogICAgcjU6IG9iamVjdCB8IE5vbmUgPSBOb25lCiAgICBzY2VuYXJpb19uYW1lID0gJ0ZJR0hUJwoKICAgIEBjbGFzc21ldGhvZAogICAgZGVmIHBhcnNlKGNscywgdmFsdWUpOgogICAgICAgIG5hbWVzID0ge2YubmFtZSBmb3IgZiBpbiBmaWVsZHMoRmlnaHRDb25maWcpfQogICAgICAgIHJvaV9uYW1lcyA9IHsncm9pJywgJ3JvaV9pZCcsICdyb2lfbmFtZScsICdkZWJ1Z19yb2knfQogICAgICAgIGlmIHR5cGUodmFsdWUpIGlzIG5vdCBkaWN0IG9yIHNldCh2YWx1ZSktbmFtZXMtcm9pX25hbWVzLXsnZW5naW5lJywncjUnfToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBGSUdIVCBzZXR0aW5ncy4nKQogICAgICAgIGVuZ2luZT12YWx1ZS5nZXQoJ2VuZ2luZScsJ2xlZ2FjeScpCiAgICAgICAgaWYgZW5naW5lIG5vdCBpbiAoJ2xlZ2FjeScsJ3I1Jyk6cmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBGSUdIVCBlbmdpbmUuJykKICAgICAgICBwb2xpY3lfdmFsdWVzPWRpY3QoREVNT19GSUdIVF9ERUZBVUxUUywgKip7azp2IGZvciBrLHYgaW4gdmFsdWUuaXRlbXMoKSBpZiBrIGluIG5hbWVzfSkKICAgICAgICByNT1Ob25lCiAgICAgICAgaWYgZW5naW5lPT0ncjUnOgogICAgICAgICAgICBmcm9tIGFwcC5maWdodF9yNS5jb25maWcgaW1wb3J0IFI1Q29uZmlnLCBzY29yZV9mbG9vcgogICAgICAgICAgICBwb2xpY3lfdmFsdWVzWydwZXJzb25fc2NvcmUnXT1zY29yZV9mbG9vcihwb2xpY3lfdmFsdWVzWydwZXJzb25fc2NvcmUnXSwuMjUpCiAgICAgICAgICAgIHBvbGljeV92YWx1ZXNbJ2pvaW50X3Njb3JlJ109c2NvcmVfZmxvb3IocG9saWN5X3ZhbHVlc1snam9pbnRfc2NvcmUnXSwuMTApCiAgICAgICAgICAgIHI1PVI1Q29uZmlnLnBhcnNlKHZhbHVlWydyNSddKSBpZiAncjUnIGluIHZhbHVlIGVsc2UgUjVDb25maWcoKQogICAgICAgIGVsaWYgJ3I1JyBpbiB2YWx1ZToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignUjUgc2V0dGluZ3MgcmVxdWlyZSB0aGUgQUktb3duZWQgcjUgZW5naW5lIHNlbGVjdGlvbi4nKQogICAgICAgIHBvbGljeSA9IEZpZ2h0Q29uZmlnLnBhcnNlKHBvbGljeV92YWx1ZXMpCiAgICAgICAgcm9pPXZhbHVlLmdldCgncm9pJykKICAgICAgICBnZW9tZXRyeSA9IEludHJ1c2lvbkNvbmZpZyhlbmFibGVkPXBvbGljeS5lbmFibGVkLGNvbmZpZGVuY2U9cG9saWN5LnBlcnNvbl9zY29yZSwKICAgICAgICAgICAgcm9pPSgoMC4sMC4pLCgxLiwwLiksKDEuLDEuKSwoMC4sMS4pKSBpZiByb2kgaXMgTm9uZSBvciByb2kgPT0gW10gZWxzZSByb2ksCiAgICAgICAgICAgIHJvaV9pZD12YWx1ZS5nZXQoJ3JvaV9pZCcsJ3ByaW1hcnknKSxyb2lfbmFtZT12YWx1ZS5nZXQoJ3JvaV9uYW1lJywnRmlnaHQgUk9JJyksCiAgICAgICAgICAgIGRlYnVnX3JvaT12YWx1ZS5nZXQoJ2RlYnVnX3JvaScsVHJ1ZSkpCiAgICAgICAgcmV0dXJuIGNscyhwb2xpY3ksZ2VvbWV0cnksZW5naW5lLHI1KQoKICAgIEBwcm9wZXJ0eQogICAgZGVmIGVuYWJsZWQoc2VsZik6IHJldHVybiBzZWxmLnBvbGljeS5lbmFibGVkCiAgICBAcHJvcGVydHkKICAgIGRlZiBjb25maWRlbmNlKHNlbGYpOiByZXR1cm4gc2VsZi5wb2xpY3kucGVyc29uX3Njb3JlCiAgICBAcHJvcGVydHkKICAgIGRlZiByb2koc2VsZik6IHJldHVybiBzZWxmLmdlb21ldHJ5LnJvaQogICAgQHByb3BlcnR5CiAgICBkZWYgcm9pX25hbWUoc2VsZik6IHJldHVybiBzZWxmLmdlb21ldHJ5LnJvaV9uYW1lCiAgICBAcHJvcGVydHkKICAgIGRlZiBkZWJ1Z19yb2koc2VsZik6IHJldHVybiBzZWxmLmdlb21ldHJ5LmRlYnVnX3JvaQogICAgZGVmIHBheWxvYWQoc2VsZik6CiAgICAgICAgcmV0dXJuIHtrOnYgZm9yIGssdiBpbiBzZWxmLmdlb21ldHJ5LnBheWxvYWQoKS5pdGVtcygpCiAgICAgICAgICAgICAgICBpZiBrIGluICgnZW5hYmxlZCcsJ2NvbmZpZGVuY2UnLCdyb2knLCdyb2lfaWQnLCdyb2lfbmFtZScsJ2RlYnVnX3JvaScsJ3BvaW50X3gnLCdwb2ludF95Jyl9CiAgICBkZWYgc2V0dGluZ3NfcGF5bG9hZChzZWxmKToKICAgICAgICB2YWx1ZT1kaWN0KHNlbGYucG9saWN5LnBheWxvYWQoKSwqKntrOnYgZm9yIGssdiBpbiBzZWxmLmdlb21ldHJ5LnBheWxvYWQoKS5pdGVtcygpCiAgICAgICAgICAgICAgICAgICAgaWYgayBpbiAoJ3JvaScsJ3JvaV9pZCcsJ3JvaV9uYW1lJywnZGVidWdfcm9pJyl9KQogICAgICAgIGlmIHNlbGYuZW5naW5lPT0ncjUnOnZhbHVlLnVwZGF0ZShlbmdpbmU9J3I1JyxyNT1zZWxmLnI1LnBheWxvYWQoKSkKICAgICAgICByZXR1cm4gdmFsdWUKCgpAZGF0YWNsYXNzKGZyb3plbj1UcnVlKQpjbGFzcyBGaWdodERpc3BsYXk6CiAgICBwb2ludDogdHVwbGUKICAgIGluc2lkZTogYm9vbAogICAgc3RhdGU6IHN0cgogICAgY29uZmlkZW5jZTogZmxvYXQKICAgIGV2ZW50X2lkOiBzdHIgfCBOb25lID0gTm9uZQogICAgZGVmIHBheWxvYWQoc2VsZik6CiAgICAgICAgcmV0dXJuIGRpY3Qoc2NlbmFyaW89J0ZJR0hUJyxwb2ludD1saXN0KHNlbGYucG9pbnQpLGluc2lkZT1zZWxmLmluc2lkZSxzdGF0ZT1zZWxmLnN0YXRlLAogICAgICAgICAgICAgICAgICAgIGNvbmZpZGVuY2U9c2VsZi5jb25maWRlbmNlLGV2ZW50SWQ9c2VsZi5ldmVudF9pZCkKCgpjbGFzcyBGaWdodEV2ZW50KEludHJ1c2lvbkV2ZW50KToKICAgIGRlZiBwYXlsb2FkKHNlbGYpOiByZXR1cm4gZGljdChzdXBlcigpLnBheWxvYWQoKSxzY2VuYXJpbz0nRklHSFQnKQoKCmNsYXNzIEZpZ2h0U2NlbmFyaW86CiAgICBkZWYgX19pbml0X18oc2VsZixjb25maWcsZXZlbnRfaWRfZmFjdG9yeT1sYW1iZGE6c3RyKHV1aWQudXVpZDQoKSksd2FsbF9ucz10aW1lLnRpbWVfbnMsCiAgICAgICAgICAgICAgICAgKiwgY3VycmVudF9mcmFtZV9mYWxsYmFjaz1Ob25lLCBldmVudF9jb29sZG93bl9zZWNvbmRzPU5vbmUsIGNvbnRhaW5zPU5vbmUpOgogICAgICAgIGlmIGNvbmZpZy5lbmdpbmU9PSdyNSc6CiAgICAgICAgICAgIGZyb20gYXBwLmZpZ2h0X3I1LnJ1bnRpbWUgaW1wb3J0IFI1UnVudGltZQogICAgICAgICAgICBzZWxmLmNvbmZpZz1jb25maWc7c2VsZi5jb250YWlucz1jb250YWlucztzZWxmLl9ldmVudHM9e30KICAgICAgICAgICAgc2VsZi5lbmdpbmU9UjVSdW50aW1lKGNvbmZpZyxldmVudF9pZF9mYWN0b3J5LHdhbGxfbnMsY29udGFpbnMpCiAgICAgICAgICAgIHJldHVybgogICAgICAgICMgUHJpdmF0ZSBjb25zdHJ1Y3Rvci9lbnZpcm9ubWVudCBwb2xpY3k7IG5vIG5ldyBwdWJsaWMgU2V0dGluZ3MgZmllbGRzLgogICAgICAgIGlmIGN1cnJlbnRfZnJhbWVfZmFsbGJhY2sgaXMgTm9uZToKICAgICAgICAgICAgdmFsdWUgPSBvcy5lbnZpcm9uLmdldCgnQ09OVEVYVFJBX0ZJR0hUX0NVUlJFTlRfRlJBTUVfRkFMTEJBQ0snLCAnZmFsc2UnKQogICAgICAgICAgICBpZiB2YWx1ZSBub3QgaW4gKCd0cnVlJywgJ2ZhbHNlJyk6CiAgICAgICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdJbnZhbGlkIEZJR0hUIGN1cnJlbnQtZnJhbWUgdG9nZ2xlLicpCiAgICAgICAgICAgIGN1cnJlbnRfZnJhbWVfZmFsbGJhY2sgPSB2YWx1ZSA9PSAndHJ1ZScKICAgICAgICBpZiBldmVudF9jb29sZG93bl9zZWNvbmRzIGlzIE5vbmU6CiAgICAgICAgICAgIGV2ZW50X2Nvb2xkb3duX3NlY29uZHMgPSBmbG9hdChvcy5lbnZpcm9uLmdldCgKICAgICAgICAgICAgICAgICdDT05URVhUUkFfRklHSFRfRVZFTlRfQ09PTERPV05fU0VDT05EUycsICcyLjAnKSkKICAgICAgICBzZWxmLmNvbmZpZz1jb25maWcKICAgICAgICBzZWxmLmNvbnRhaW5zPWNvbnRhaW5zCiAgICAgICAgc2VsZi5lbmdpbmU9RmlnaHRFbmdpbmUoY29uZmlnLnBvbGljeSwgY3VycmVudF9mcmFtZV9mYWxsYmFjaz1jdXJyZW50X2ZyYW1lX2ZhbGxiYWNrLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50X2Nvb2xkb3duX3NlY29uZHM9ZXZlbnRfY29vbGRvd25fc2Vjb25kcykKICAgICAgICBzZWxmLl9ldmVudHM9e307c2VsZi5ldmVudF9pZF9mYWN0b3J5PWV2ZW50X2lkX2ZhY3Rvcnk7c2VsZi53YWxsX25zPXdhbGxfbnMKCiAgICBkZWYgZXZhbHVhdGUoc2VsZixmcmFtZSxwb3NlcyxpZHMsKixnYXBfYmVmb3JlPUZhbHNlKToKICAgICAgICBpZiBzZWxmLmNvbmZpZy5lbmdpbmU9PSdyNSc6CiAgICAgICAgICAgIHJldHVybiBzZWxmLmVuZ2luZS5ldmFsdWF0ZShmcmFtZSxwb3NlcyxpZHMsZ2FwX2JlZm9yZT1nYXBfYmVmb3JlKQogICAgICAgIHBvaW50cz10dXBsZSgoKHAuYmJveF94eXh5WzBdK3AuYmJveF94eXh5WzJdKS8yLHAuYmJveF94eXh5WzNdKSBmb3IgcCBpbiBwb3NlcykKICAgICAgICBzZWxlY3RlZD1baSBmb3IgaSxwIGluIGVudW1lcmF0ZShwb2ludHMpIGlmIChzZWxmLmNvbnRhaW5zKHApIGlmIHNlbGYuY29udGFpbnMgZWxzZSBpbnNpZGUocCxzZWxmLmNvbmZpZy5yb2kpKV0KICAgICAgICByZXN1bHQ9c2VsZi5lbmdpbmUuZXZhbHVhdGUoZnJhbWUsdHVwbGUocG9zZXNbaV0gZm9yIGkgaW4gc2VsZWN0ZWQpLHR1cGxlKGlkc1tpXSBmb3IgaSBpbiBzZWxlY3RlZCksZ2FwX2JlZm9yZT1nYXBfYmVmb3JlKQogICAgICAgIHJvd3M9WyhGaWdodERpc3BsYXkocCxpIGluIHNlbGVjdGVkLCdNT05JVE9SSU5HJyBpZiBpIGluIHNlbGVjdGVkIGVsc2UgJ09VVFNJREUnLHNlbGYuY29uZmlnLmNvbmZpZGVuY2UpLCkgZm9yIGkscCBpbiBlbnVtZXJhdGUocG9pbnRzKV0KICAgICAgICBpZiBub3QgcmVzdWx0LmFjY2VwdGVkOnJldHVybiB0dXBsZShyb3dzKSwoKQogICAgICAgIGFjdGl2ZT17cC50cmFja19pZHMgZm9yIHAgaW4gcmVzdWx0LnBhaXJzIGlmIHAuYWxlcnR9CiAgICAgICAgIyBQYWlyIHN0YXRlIHJlbWFpbnMgZW5naW5lLW93bmVkOyBrZWVwIGJvdW5kZWQgVVVJRHMgdGhyb3VnaCBicmllZiBtaXNzaW5nL1JPSSBnYXBzLgogICAgICAgIHNlbGYuX2V2ZW50cz17azp2IGZvciBrLHYgaW4gc2VsZi5fZXZlbnRzLml0ZW1zKCkgaWYgayBpbiBzZWxmLmVuZ2luZS5sYXRjaGVkX3BhaXJzKCl9CiAgICAgICAgZXZlbnRzPVtdCiAgICAgICAgZm9yIGV2ZW50IGluIHJlc3VsdC5ldmVudF9jYW5kaWRhdGVzOgogICAgICAgICAgICBpPXNlbGVjdGVkW2ludChldmVudC5vYmplY3RfcmVmc1swXSldCiAgICAgICAgICAgIGVpZD1zZWxmLmV2ZW50X2lkX2ZhY3RvcnkoKTtzZWxmLl9ldmVudHNbZXZlbnQudHJhY2tfaWRzXT1laWQKICAgICAgICAgICAgZXZlbnRzLmFwcGVuZChGaWdodEV2ZW50KGVpZCxmcmFtZSxldmVudC50cmFja19pZHNbMF0sc2VsZi5jb25maWcuZ2VvbWV0cnkucm9pX2lkLHN0cihpKSwKICAgICAgICAgICAgICAgIHBvc2VzW2ldLnNjb3JlLHBvc2VzW2ldLmJib3hfeHl4eSxwb3Nlc1tpXS5tb2RlbF9rZXksc2VsZi53YWxsX25zKCkvLzEwMDAwMDApKQogICAgICAgIGZvciBwYWlyIGluIGFjdGl2ZToKICAgICAgICAgICAgZm9yIGkgaW4gc2VsZWN0ZWQ6CiAgICAgICAgICAgICAgICBpZiBpZHNbaV0gaW4gcGFpcjoKICAgICAgICAgICAgICAgICAgICBpZiByb3dzW2ldWzBdLnN0YXRlID09ICdNT05JVE9SSU5HJzoKICAgICAgICAgICAgICAgICAgICAgICAgcm93c1tpXSA9ICgpCiAgICAgICAgICAgICAgICAgICAgcm93c1tpXSs9IChGaWdodERpc3BsYXkocG9pbnRzW2ldLFRydWUsJ0ZJR0hUJyxzZWxmLmNvbmZpZy5jb25maWRlbmNlLHNlbGYuX2V2ZW50cy5nZXQocGFpcikpLCkKICAgICAgICByZXR1cm4gdHVwbGUocm93cyksdHVwbGUoZXZlbnRzKQoKICAgIGRlZiBjbGVhcihzZWxmKTogc2VsZi5lbmdpbmUuY2xlYXIoKTtzZWxmLl9ldmVudHMuY2xlYXIoKQoKCmRlZiBwcm9qZWN0X2ZpZ2h0KHNwZWMsc2NlbmFyaW9zKToKICAgIHJlcT1uZXh0KHMgZm9yIHMgaW4gc2NlbmFyaW9zIGlmIHNbJ3NjZW5hcmlvQ29kZSddPT0nRklHSFQnKQogICAgaWYgbm90IHJlcVsnZW5hYmxlZCddIGFuZCAnZmlnaHQnIG5vdCBpbiBzcGVjOnJldHVybgogICAgcm9pPXJlcVsncm9pcyddWzBdIGlmIHJlcVsncm9pcyddIGVsc2UgTm9uZQogICAgY2ZnPWRpY3Qoc3BlYy5nZXQoJ2ZpZ2h0Jykgb3Ige30sZW5hYmxlZD1yZXFbJ2VuYWJsZWQnXSxwZXJzb25fc2NvcmU9REVNT19GSUdIVF9ERUZBVUxUU1sncGVyc29uX3Njb3JlJ10gaWYgcmVxWydjb25maWRlbmNlJ10gaXMgTm9uZSBlbHNlIHJlcVsnY29uZmlkZW5jZSddLAogICAgICAgICAgICAgcm9pPXJvaVsncG9pbnRzJ10gaWYgcm9pIGVsc2UgW10scm9pX25hbWU9cm9pWydsYWJlbCddIGlmIHJvaSBlbHNlICdGaWdodCBST0knKQogICAgc3BlY1snZmlnaHQnXT1GaWdodFNldHRpbmdzLnBhcnNlKGNmZykuc2V0dGluZ3NfcGF5bG9hZCgpCgoKZGVmIHZhbGlkYXRlKHNwZWMpOgogICAgY2ZnPUZpZ2h0U2V0dGluZ3MucGFyc2Uoc3BlYy5nZXQoJ2ZpZ2h0Jykgb3Ige30pCiAgICBpZiBjZmcuZW5hYmxlZCBhbmQgKG5vdCBzcGVjLmdldCgnc2VydmVyX2lkJykgb3Igbm90IHNwZWMuZ2V0KCdzb3VyY2VfaWQnKSBvciAoc3BlYy5nZXQoJ3RyYWNraW5nJykgb3Ige30pLmdldCgnZW5hYmxlZCcsVHJ1ZSkgaXMgbm90IFRydWUpOgogICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ0ZJR0hUIHJlcXVpcmVzIGNhbm9uaWNhbCBpZGVudGl0eSBhbmQgc2hhcmVkIFRyYWNraW5nLicpCiAgICByZXR1cm4gY2ZnCg==",
    "app/multi_provider_results.py": "IiIiUFIxMyBib3VuZGVkIG11bHRpLXByb3ZpZGVyIEZyYW1lIGNvb3JkaW5hdG9yLgoKVGhlIGNvb3JkaW5hdG9yIG93bnMgRnJhbWUgYWNjZXB0YW5jZS9maW5hbGl6YXRpb24gYW5kIHNjZW5hcmlvIHN0YXRlLiBJdCBzdG9yZXMKb25seSBpbW11dGFibGUgY29waWVkIG1ldGFkYXRhLCBuZXZlciBTREsgRnJhbWUgd3JhcHBlcnMgb3IgcGl4ZWxzLiBQcm92aWRlcgpyZXN1bHRzIGFycml2aW5nIGFmdGVyIGEgRnJhbWUgZGVhZGxpbmUvZmluYWxpemF0aW9uL2V2aWN0aW9uIGFyZSBoZWFsdGgKcmVzcG9uc2VzIGJ1dCBjYW5ub3QgbXV0YXRlIFRyYWNraW5nLCBTY2VuYXJpbywgRXZlbnQgb3IgTWV0YWRhdGEgc3RhdGUuCiIiIgpmcm9tIF9fZnV0dXJlX18gaW1wb3J0IGFubm90YXRpb25zCgpmcm9tIGNvbGxlY3Rpb25zIGltcG9ydCBDb3VudGVyLCBPcmRlcmVkRGljdApmcm9tIGRhdGFjbGFzc2VzIGltcG9ydCBkYXRhY2xhc3MsIGZpZWxkLCByZXBsYWNlCmltcG9ydCBvcwppbXBvcnQgdGhyZWFkaW5nCmltcG9ydCB0aW1lCgpmcm9tIGFwcC5jb250cmFjdHMuZnJhbWVzIGltcG9ydCBEZXRlY3Rpb25PYnNlcnZhdGlvbiwgUG9zZU9ic2VydmF0aW9uCmZyb20gYXBwLmNvbnRyYWN0cy52aXN1YWxpemF0aW9uIGltcG9ydCBGcmFtZVJlc3VsdCwgVmlzdWFsaXphdGlvbkNvbW1hbmQKZnJvbSBhcHAucmVnaW9uX3NjZW5hcmlvIGltcG9ydCBhbGVydGVkLCBldmVudF9pZHMsIG1lbWJlcnMsIHZpc2libGUgYXMgc2NlbmFyaW9fdmlzaWJsZQoKCkBkYXRhY2xhc3MKY2xhc3MgX09wZW5GcmFtZToKICAgIGZyYW1lOiBvYmplY3QKICAgIGFkbWl0dGVkX2F0OiBmbG9hdAogICAgZGVhZGxpbmU6IGZsb2F0CiAgICByZXF1aXJlZDogc2V0W3N0cl0KICAgIHJlc3VsdHM6IGRpY3QKICAgIHN0YXRlOiBzdHIgPSAnT1BFTicKICAgIGdhcHM6IHNldCA9IGZpZWxkKGRlZmF1bHRfZmFjdG9yeT1zZXQpCiAgICBjbGFpbWVkOiBib29sID0gRmFsc2UKICAgIHNlbGVjdGVkX2F0OiBmbG9hdCB8IE5vbmUgPSBOb25lCgoKZGVmIHB1YmxpY19wb3NpdGlvbnMoY29tbWFuZHMsIGV2ZW50cywgY2FwYWNpdHk9MzAwKToKICAgICIiIktlZXAgRXZlbnQgcmVmcyBhbmQgZWFjaCB2aXNpYmxlIHByb3ZpZGVyJ3MgcmVwcmVzZW50YXRpdmUgYmVmb3JlIGZpbGwuIiIiCiAgICBmcm9tIGFwcC5jcm93ZF9ldmVudCBpbXBvcnQgQ3Jvd2RFdmVudAogICAgcmVxdWlyZWQgPSB7aW50KGUub2JqZWN0X3JlZikgZm9yIGUgaW4gZXZlbnRzIGlmIG5vdCBpc2luc3RhbmNlKGUsIENyb3dkRXZlbnQpfQogICAgaWYgYW55KGkgPCAwIG9yIGkgPj0gbGVuKGNvbW1hbmRzKSBmb3IgaSBpbiByZXF1aXJlZCk6CiAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignRXZlbnQgb2JqZWN0IHJlZmVyZW5jZSBpcyBvdXRzaWRlIHByb3ZpZGVyIGNvbW1hbmRzLicpCiAgICBpZiBsZW4oY29tbWFuZHMpIDw9IGNhcGFjaXR5OgogICAgICAgIHJldHVybiBsaXN0KHJhbmdlKGxlbihjb21tYW5kcykpKQogICAgcmVwcmVzZW50YXRpdmVzID0ge30KICAgIGZvciBpLCBjb21tYW5kIGluIGVudW1lcmF0ZShjb21tYW5kcyk6CiAgICAgICAgaWYgbm90IGNvbW1hbmQudmlzaWJsZToKICAgICAgICAgICAgY29udGludWUKICAgICAgICBkID0gY29tbWFuZC5kZXRlY3Rpb24KICAgICAgICBzZXBhcmF0ZV9jbGFzc2VzID0gZC5tb2RlbF9rZXkgaW4gKCdSRkRFVFJGaXJlU21va2UnLCAnQXdpcm9zX3BlcnNvbl9hbmRfaGVhZF9kZXRlY3Rpb24nKQogICAgICAgIGdyb3VwID0gKGQubW9kZWxfa2V5LCBkLmNsYXNzX2lkIGlmIHNlcGFyYXRlX2NsYXNzZXMgZWxzZSBOb25lKQogICAgICAgICMgQ1JPV0QncyBjb3VudCBsYWJlbCBtdXN0IHN1cnZpdmUgYWhlYWQgb2YgaXRzIHBsYWluIGJveGVzLgogICAgICAgIHJhbmsgPSAoaW50KCcgfCBQJyBpbiBjb21tYW5kLmxhYmVsX3RleHQgb3IgJyB8IEgnIGluIGNvbW1hbmQubGFiZWxfdGV4dCksCiAgICAgICAgICAgICAgICBpbnQoYWxlcnRlZChjb21tYW5kLnNjZW5hcmlvKSksIGQuc2NvcmUsIC1pKQogICAgICAgIGlmIGdyb3VwIG5vdCBpbiByZXByZXNlbnRhdGl2ZXMgb3IgcmFuayA+IHJlcHJlc2VudGF0aXZlc1tncm91cF1bMF06CiAgICAgICAgICAgIHJlcHJlc2VudGF0aXZlc1tncm91cF0gPSAocmFuaywgaSkKICAgIHJlcXVpcmVkLnVwZGF0ZShpIGZvciBfLCBpIGluIHJlcHJlc2VudGF0aXZlcy52YWx1ZXMoKSkKICAgIGlmIGxlbihyZXF1aXJlZCkgPiBjYXBhY2l0eToKICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoJ01hbmRhdG9yeSBtZXRhZGF0YSBvYmplY3QgY2FwYWNpdHkgZXhjZWVkZWQuJykKICAgIHJhbmtlZCA9IHNvcnRlZCgoaSBmb3IgaSBpbiByYW5nZShsZW4oY29tbWFuZHMpKSBpZiBpIG5vdCBpbiByZXF1aXJlZCksCiAgICAgICAgICAgICAgICAgICAga2V5PWxhbWJkYSBpOiAobm90IGNvbW1hbmRzW2ldLnZpc2libGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm90IChhbGVydGVkKGNvbW1hbmRzW2ldLnNjZW5hcmlvKSBvciBjb21tYW5kc1tpXS5ldmVudF9pZHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1jb21tYW5kc1tpXS5kZXRlY3Rpb24uc2NvcmUsIGkpKQogICAgcmV0dXJuIHNvcnRlZChyZXF1aXJlZCB8IHNldChyYW5rZWRbOmNhcGFjaXR5LWxlbihyZXF1aXJlZCldKSkKCgpjbGFzcyBNdWx0aVByb3ZpZGVyQ29vcmRpbmF0b3I6CiAgICBkZWYgX19pbml0X18oc2VsZiwgc3BlYywgaW5ncmVzcywgcHJvdmlkZXJfcGxhbiwgY29sbGVjdG9yLCBpc19jdXJyZW50LCBvbl9mYXRhbCwKICAgICAgICAgICAgICAgICAqLCBwdWJsaXNoZXI9Tm9uZSwgb25fcHJvdmlkZXJfZnJhbWU9Tm9uZSwgY2xvY2s9dGltZS5tb25vdG9uaWMpOgogICAgICAgIHNlbGYuc3BlYyA9IHNwZWMKICAgICAgICBzZWxmLmluZ3Jlc3MgPSBpbmdyZXNzCiAgICAgICAgc2VsZi5wbGFuID0gcHJvdmlkZXJfcGxhbgogICAgICAgIHNlbGYuY29sbGVjdG9yID0gY29sbGVjdG9yCiAgICAgICAgc2VsZi5pc19jdXJyZW50ID0gaXNfY3VycmVudAogICAgICAgIHNlbGYub25fZmF0YWwgPSBvbl9mYXRhbAogICAgICAgIHNlbGYucHVibGlzaGVyID0gcHVibGlzaGVyCiAgICAgICAgc2VsZi5vbl9wcm92aWRlcl9mcmFtZSA9IG9uX3Byb3ZpZGVyX2ZyYW1lCiAgICAgICAgc2VsZi5jbG9jayA9IGNsb2NrCgogICAgICAgIHNlbGYuZnJlc2huZXNzX3MgPSBmbG9hdChvcy5lbnZpcm9uLmdldCgKICAgICAgICAgICAgJ0NPTlRFWFRSQV9QUk9WSURFUl9SRVNVTFRfRlJFU0hORVNTX01TJywgJzEwMCcpKSAvIDEwMDAuMAogICAgICAgIHNlbGYuc3RhbGxfcyA9IGZsb2F0KG9zLmVudmlyb24uZ2V0KCdDT05URVhUUkFfUFJPVklERVJfU1RBTExfU0VDT05EUycsICcyLjAnKSkKICAgICAgICBzZWxmLnN0YXJ0dXBfcyA9IGZsb2F0KG9zLmVudmlyb24uZ2V0KCdDT05URVhUUkFfUFJPVklERVJfU1RBUlRVUF9TRUNPTkRTJywgJzEwLjAnKSkKICAgICAgICBmbGFnID0gb3MuZW52aXJvbi5nZXQoJ0NPTlRFWFRSQV9QUk9WSURFUl9GUkVTSE5FU1NfRU5BQkxFRCcsICd0cnVlJykubG93ZXIoKQogICAgICAgIGlmIGZsYWcgbm90IGluICgndHJ1ZScsICdmYWxzZScpOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdJbnZhbGlkIGZyZXNobmVzcyBmbGFnLicpCiAgICAgICAgc2VsZi5mcmVzaG5lc3NfZW5hYmxlZCA9IGZsYWcgPT0gJ3RydWUnCiAgICAgICAgaWYgbm90IHNlbGYuZnJlc2huZXNzX2VuYWJsZWQgYW5kIGxlbihwcm92aWRlcl9wbGFuLnByb3ZpZGVycykgIT0gMToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignRnJlc2huZXNzIE9GRiByZXF1aXJlcyBvbmUgcHJvdmlkZXIgcGVyIGNvb3JkaW5hdG9yLicpCiAgICAgICAgaWYgKG5vdCAwIDwgc2VsZi5mcmVzaG5lc3NfcyA8PSAxMCBvciBub3QgMCA8IHNlbGYuc3RhbGxfcyA8PSAzMDAKICAgICAgICAgICAgICAgIG9yIG5vdCBzZWxmLnN0YWxsX3MgPD0gc2VsZi5zdGFydHVwX3MgPD0gMzAwKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBtdWx0aS1wcm92aWRlciB0aW1pbmcgc2V0dGluZ3MuJykKICAgICAgICBzZWxmLmNhcGFjaXR5ID0gMiBpZiBzZWxmLmZyZXNobmVzc19lbmFibGVkIGVsc2UgMwoKICAgICAgICBmcm9tIGFwcC5zdHJlYW1fc2V0dGluZ3MgaW1wb3J0IHJldmlzaW9uLCBkaXNwbGF5X3Njb3JlLCB2aXN1YWxfb3B0aW9ucwogICAgICAgIHNlbGYuc2NlbmFyaW9fcmV2aXNpb24gPSAoc3BlYy5nZXQoJ19wcm92aWRlcl9ydW50aW1lJykgb3Ige30pLmdldCgncmV2aXNpb24nKSBvciByZXZpc2lvbihzcGVjKQogICAgICAgIHNlbGYuZGlzcGxheV90aHJlc2hvbGQgPSBkaXNwbGF5X3Njb3JlKAogICAgICAgICAgICBzcGVjLCAoKHNwZWMuZ2V0KCdpbmZlcmVuY2VfcHJvZmlsZScpIG9yIHt9KS5nZXQoJ3RocmVzaG9sZHMnKSBvciB7fSkuZ2V0KCdzY29yZScsIC41KSkKICAgICAgICBzZWxmLmRpc3BsYXlfY2F0ZWdvcmllcywgc2VsZi5kZWJ1Z19hbGxfY2FuZGlkYXRlcyA9IHZpc3VhbF9vcHRpb25zKHNwZWMpCiAgICAgICAgc2VsZi5kaXNwbGF5X2NhdGVnb3JpZXMgPSAoZnJvemVuc2V0KHNlbGYuZGlzcGxheV9jYXRlZ29yaWVzKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIHNlbGYuZGlzcGxheV9jYXRlZ29yaWVzIGlzIG5vdCBOb25lIGVsc2UgTm9uZSkKICAgICAgICBzZWxmLmNhbWVyYV9pZCA9IHNwZWMuZ2V0KCdjYW1lcmFfaWQnKQoKICAgICAgICBmcm9tIGFwcC5yZWdpb25fc2NlbmFyaW8gaW1wb3J0IGNvbXBvc2UKICAgICAgICBmcm9tIGFwcC5mYWxsX3J1bnRpbWUgaW1wb3J0IEZhbGxTZXR0aW5ncywgRmFsbFNjZW5hcmlvCiAgICAgICAgZnJvbSBhcHAuZmlnaHRfcnVudGltZSBpbXBvcnQgRmlnaHRTZXR0aW5ncywgRmlnaHRTY2VuYXJpbwogICAgICAgIGZyb20gYXBwLmZpcmVfY29uZmlnIGltcG9ydCBidWlsZF9lbmdpbmUKICAgICAgICBmcm9tIGFwcC5jcm93ZF9jb25maWcgaW1wb3J0IENyb3dkQ29uZmlnCiAgICAgICAgZnJvbSBhcHAuY3Jvd2Rfc2NlbmFyaW8gaW1wb3J0IENyb3dkCiAgICAgICAgZnJvbSBhcHAuY3Jvd2RfcmVzdWx0IGltcG9ydCBDcm93ZFJlc3VsdFByb2Nlc3NvcgogICAgICAgIGZyb20gYXBwLnBvc2VfY29uZmlnIGltcG9ydCBQb3NlQ29uZmlnCiAgICAgICAgc2VsZi5yZWdpb24gPSBjb21wb3NlKHNwZWMpCiAgICAgICAgZmFsbF9jZmcgPSBGYWxsU2V0dGluZ3MucGFyc2Uoc3BlYy5nZXQoJ2ZhbGwnKSBvciB7fSkKICAgICAgICBmaWdodF9jZmcgPSBGaWdodFNldHRpbmdzLnBhcnNlKHNwZWMuZ2V0KCdmaWdodCcpIG9yIHt9KQogICAgICAgIHNlbGYuZmFsbCA9IEZhbGxTY2VuYXJpbyhmYWxsX2NmZykgaWYgZmFsbF9jZmcuZW5hYmxlZCBlbHNlIE5vbmUKICAgICAgICBzZWxmLmZpZ2h0ID0gRmlnaHRTY2VuYXJpbyhmaWdodF9jZmcpIGlmIGZpZ2h0X2NmZy5lbmFibGVkIGVsc2UgTm9uZQogICAgICAgIHNlbGYuZmlyZSA9IGJ1aWxkX2VuZ2luZShzcGVjKQogICAgICAgIGZyb20gYXBwLmV2ZW50X2Nvb2xkb3duIGltcG9ydCBFdmVudENvb2xkb3duCiAgICAgICAgc2VsZi5ldmVudF9jb29sZG93biA9IEV2ZW50Q29vbGRvd24oY2xvY2s9c2VsZi5jbG9jaywgb3ZlcnJpZGVzPXNwZWMuZ2V0KCdldmVudF9jb29sZG93bnMnKSkKICAgICAgICBlbmdpbmVzID0gZ2V0YXR0cihzZWxmLnJlZ2lvbiwgJ2VuZ2luZXMnLCAoc2VsZi5yZWdpb24sKSkKICAgICAgICBmb3IgZW5naW5lIGluICgqZW5naW5lcywgc2VsZi5mYWxsLmVuZ2luZSBpZiBzZWxmLmZhbGwgZWxzZSBOb25lLAogICAgICAgICAgICAgICAgICAgICAgIHNlbGYuZmlnaHQuZW5naW5lIGlmIHNlbGYuZmlnaHQgZWxzZSBOb25lLCBzZWxmLmZpcmUpOgogICAgICAgICAgICBpZiBlbmdpbmUgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICBlbmdpbmUuZXZlbnRfYWRtaXNzaW9uID0gc2VsZi5ldmVudF9jb29sZG93bi5hbGxvdwogICAgICAgIGNyb3dkX2NmZyA9IENyb3dkQ29uZmlnLnBhcnNlKHNwZWMuZ2V0KCdjcm93ZCcpIG9yIHt9KQogICAgICAgIHNlbGYuY3Jvd2QgPSAoQ3Jvd2RSZXN1bHRQcm9jZXNzb3IoCiAgICAgICAgICAgIENyb3dkKGNyb3dkX2NmZyksIGNhbWVyYV9pZD1zZWxmLmNhbWVyYV9pZCwKICAgICAgICAgICAgc2NlbmFyaW9fcmV2aXNpb249c2VsZi5zY2VuYXJpb19yZXZpc2lvbikgaWYgY3Jvd2RfY2ZnLmVuYWJsZWQgZWxzZSBOb25lKQogICAgICAgIGlmIHNlbGYuY3Jvd2QgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIHNlbGYuY3Jvd2QuZW5naW5lLmV2ZW50X2FkbWlzc2lvbiA9IHNlbGYuZXZlbnRfY29vbGRvd24uYWxsb3cKICAgICAgICBzZWxmLnBvc2VfY29uZmlnID0gKFBvc2VDb25maWcucGFyc2Uoc3BlYy5nZXQoJ3Bvc2UnKSBvciB7fSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIGFueShwLmtleSA9PSAncG9zZScgZm9yIHAgaW4gcHJvdmlkZXJfcGxhbi5wcm92aWRlcnMpIGVsc2UgTm9uZSkKCiAgICAgICAgZnJvbSBhcHAuYnl0ZV90cmFja2luZyBpbXBvcnQgQnl0ZVRyYWNrZXIsIFRyYWNraW5nU2V0dGluZ3MKICAgICAgICB0cmFja2luZyA9IGRpY3Qoc3BlYy5nZXQoJ3RyYWNraW5nJykgb3Ige30pCiAgICAgICAgdHJhY2tpbmdbJ2ZyYW1lX3JhdGUnXSA9IGluZ3Jlc3Muc2FtcGxlci5mcHMKICAgICAgICB0cmFja2luZ19jZmcgPSBUcmFja2luZ1NldHRpbmdzLnBhcnNlKHRyYWNraW5nKQogICAgICAgIHNlbGYudHJhY2tlciA9IChCeXRlVHJhY2tlcih0cmFja2luZ19jZmcsIG1ldHJpY3M9aW5ncmVzcy5tZXRyaWNzKQogICAgICAgICAgICAgICAgICAgICAgICBpZiBwcm92aWRlcl9wbGFuLnBlcnNvbl9vd25lciBhbmQgdHJhY2tpbmdfY2ZnLmVuYWJsZWQgZWxzZSBOb25lKQoKICAgICAgICBzZWxmLnZpc3VhbCA9IE5vbmUKICAgICAgICBzZWxmLmFydGlmYWN0cyA9IE5vbmUKICAgICAgICBzZWxmLl9zYW1wbGVzID0gTm9uZQogICAgICAgIHNlbGYuX2N2ID0gdGhyZWFkaW5nLkNvbmRpdGlvbigpCiAgICAgICAgc2VsZi5fZnJhbWVzID0gT3JkZXJlZERpY3QoKQogICAgICAgIHNlbGYuX2Nsb3NlZCA9IEZhbHNlCiAgICAgICAgc2VsZi5fdGhyZWFkID0gTm9uZQogICAgICAgIHNlbGYuX2xhc3RfYWRtaXR0ZWQgPSAtMQogICAgICAgIHNlbGYuX2xhc3RfcHVibGlzaGVkID0gLTEKICAgICAgICBzZWxmLl9sYXRlc3QgPSBOb25lCiAgICAgICAgc2VsZi5fZXJyb3IgPSBOb25lCiAgICAgICAgc2VsZi5fbWV0cmljcyA9IENvdW50ZXIoKQogICAgICAgIG5vdyA9IHNlbGYuY2xvY2soKQogICAgICAgIHNlbGYuX3Byb3ZpZGVycyA9IHsKICAgICAgICAgICAgcC5rZXk6IGRpY3Qoc3RhdGU9J0FDVElWRScsIHJlYXNvbj1Ob25lLCBmaXJzdF9pbnB1dF9hdD1Ob25lLAogICAgICAgICAgICAgICAgICAgICAgICBsYXN0X2lucHV0X2F0PU5vbmUsIGxhc3RfcmVzcG9uc2VfYXQ9Tm9uZSwKICAgICAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2VzPTAsIGxhdGU9MCwgYnVzeV9kcm9wPTApCiAgICAgICAgICAgIGZvciBwIGluIHByb3ZpZGVyX3BsYW4ucHJvdmlkZXJzCiAgICAgICAgfQogICAgICAgIHNlbGYuX2RlcGVuZGVuY2llcyA9IHsKICAgICAgICAgICAgc2NlbmFyaW86IHByb3ZpZGVyLmtleQogICAgICAgICAgICBmb3IgcHJvdmlkZXIgaW4gcHJvdmlkZXJfcGxhbi5wcm92aWRlcnMKICAgICAgICAgICAgZm9yIHNjZW5hcmlvIGluIHByb3ZpZGVyLnNjZW5hcmlvcwogICAgICAgIH0KICAgICAgICBzZWxmLl9yZXF1ZXN0ZWQgPSBzZXQocHJvdmlkZXJfcGxhbi5yZXF1ZXN0ZWRfc2NlbmFyaW9zKQogICAgICAgIHNlbGYuX3N0YXJ0ZWRfYXQgPSBub3cKICAgICAgICBzZWxmLl9wZXJzb25fZ2FwX3BlbmRpbmcgPSBGYWxzZQogICAgICAgIHNlbGYuX2dhcF9wZW5kaW5nID0ge3Aua2V5OiBGYWxzZSBmb3IgcCBpbiBwcm92aWRlcl9wbGFuLnByb3ZpZGVyc30KICAgICAgICBzZWxmLl9maW5hbGl6aW5nID0gTm9uZQogICAgICAgIHNlbGYuX2JyYW5jaF9yZWxlYXNlID0ge30KICAgICAgICBzZWxmLl90aW1pbmdzID0ge30KICAgICAgICBzZWxmLl9yZXRpcmVkID0gT3JkZXJlZERpY3QoKQoKICAgIGRlZiBfbm90aWZ5X2ZhdGFsKHNlbGYsIHJlYXNvbiwgZXJyb3I9Tm9uZSk6CiAgICAgICAgIyBQcmVzZXJ2ZSB0aGUgZmlyc3QgZmFpbHVyZSBib3VuZGFyeSBiZWZvcmUgU3RyZWFtR3JvdXAgY2xlYXJzIHRoZSBwYXRoLgogICAgICAgIGltcG9ydCBqc29uCiAgICAgICAgaW1wb3J0IHN5cwogICAgICAgIGltcG9ydCB0cmFjZWJhY2sKICAgICAgICBmcm9tIHBhdGhsaWIgaW1wb3J0IFBhdGgKICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICBkaWFnbm9zdGljID0gZGljdChjb2RlPSdNVUxUSV9QUk9WSURFUl9GQVRBTCcsIHJlYXNvbj1yZWFzb24sCiAgICAgICAgICAgICAgICBtb25vdG9uaWNfbnM9dGltZS5tb25vdG9uaWNfbnMoKSwgZXJyb3I9c2VsZi5fZXJyb3IsCiAgICAgICAgICAgICAgICBwcm92aWRlcnM9e2s6IHtuOiB2W25dIGZvciBuIGluICgnc3RhdGUnLCAncmVhc29uJywgJ3Jlc3BvbnNlcycsICdsYXRlJyl9CiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBrLCB2IGluIHNlbGYuX3Byb3ZpZGVycy5pdGVtcygpfSkKICAgICAgICBpZiBlcnJvciBpcyBub3QgTm9uZToKICAgICAgICAgICAgZGlhZ25vc3RpY1snZXhjZXB0aW9uX3R5cGUnXSA9IHR5cGUoZXJyb3IpLl9fbmFtZV9fCiAgICAgICAgICAgIGRpYWdub3N0aWNbJ2xvY2F0aW9ucyddID0gW2RpY3QoZmlsZT1QYXRoKGYuZmlsZW5hbWUpLm5hbWUsIGxpbmU9Zi5saW5lbm8sIGZ1bmN0aW9uPWYubmFtZSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgZiBpbiB0cmFjZWJhY2suZXh0cmFjdF90YihlcnJvci5fX3RyYWNlYmFja19fKVstNDpdXQogICAgICAgIHRyeToKICAgICAgICAgICAgcHJpbnQoanNvbi5kdW1wcyhkaWFnbm9zdGljKSwgZmlsZT1zeXMuc3RkZXJyLCBmbHVzaD1UcnVlKQogICAgICAgIGV4Y2VwdCBPU0Vycm9yOgogICAgICAgICAgICBwYXNzCiAgICAgICAgc2VsZi5vbl9mYXRhbCgpCgogICAgZGVmIF90aW1pbmdfbG9ja2VkKHNlbGYsIHByb3ZpZGVyLCBzdGFnZSwgc2Vjb25kcyk6CiAgICAgICAgaWYgc2Vjb25kcyBpcyBOb25lIG9yIHNlY29uZHMgPCAwOgogICAgICAgICAgICByZXR1cm4KICAgICAgICBtcyA9IHNlY29uZHMgKiAxMDAwCiAgICAgICAgcm93ID0gc2VsZi5fdGltaW5ncy5zZXRkZWZhdWx0KHByb3ZpZGVyLCB7fSkuc2V0ZGVmYXVsdCgKICAgICAgICAgICAgc3RhZ2UsIGRpY3QoY291bnQ9MCwgc3VtX21zPTAuLCBtYXhfbXM9MC4sIG92ZXJfMTAwbXM9MCkpCiAgICAgICAgcm93Wydjb3VudCddICs9IDEKICAgICAgICByb3dbJ3N1bV9tcyddICs9IG1zCiAgICAgICAgcm93WydtYXhfbXMnXSA9IG1heChyb3dbJ21heF9tcyddLCBtcykKICAgICAgICByb3dbJ292ZXJfMTAwbXMnXSArPSBpbnQobXMgPiAxMDApCgogICAgZGVmIHByb3ZpZGVyX2dhdGVfdGltZShzZWxmLCBwcm92aWRlciwgc2VxLCBlbnRlcmVkX2F0KToKICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICBzdGF0ZSA9IHNlbGYuX2ZyYW1lcy5nZXQoc2VxKQogICAgICAgICAgICBpZiAoc3RhdGUgaXMgTm9uZSBvciBzdGF0ZS5zdGF0ZSAhPSAnT1BFTicgb3Igc2VsZi5fY2xvc2VkCiAgICAgICAgICAgICAgICAgICAgb3Igbm90IHNlbGYuaXNfY3VycmVudCgpIG9yIHNlbGYuX3Byb3ZpZGVyc1twcm92aWRlcl1bJ3N0YXRlJ10gIT0gJ0FDVElWRScKICAgICAgICAgICAgICAgICAgICBvciAoc2VsZi5mcmVzaG5lc3NfZW5hYmxlZCBhbmQgZW50ZXJlZF9hdCA+IHN0YXRlLmRlYWRsaW5lKSk6CiAgICAgICAgICAgICAgICByZXR1cm4gTm9uZQogICAgICAgICAgICBzdGF0ZS5jbGFpbWVkID0gVHJ1ZQogICAgICAgICAgICBzZWxmLl9wcm92aWRlcnNbcHJvdmlkZXJdLnNldGRlZmF1bHQoJ2ZpcnN0X3JlcXVlc3RfYXQnLCBlbnRlcmVkX2F0KQogICAgICAgICAgICBzZWxmLl90aW1pbmdfbG9ja2VkKHByb3ZpZGVyLCAnc2VsZWN0ZWRfdG9fZ2F0ZScsIGVudGVyZWRfYXQtc3RhdGUuYWRtaXR0ZWRfYXQpCiAgICAgICAgICAgIHJldHVybiBzdGF0ZS5hZG1pdHRlZF9hdAoKICAgIGRlZiBfcmV0aXJlX2xvY2tlZChzZWxmLCBzZXEsIHJlYXNvbik6CiAgICAgICAgc2VsZi5fcmV0aXJlZFtzZXFdID0gcmVhc29uCiAgICAgICAgd2hpbGUgbGVuKHNlbGYuX3JldGlyZWQpID4gNjQ6CiAgICAgICAgICAgIHNlbGYuX3JldGlyZWQucG9waXRlbShsYXN0PUZhbHNlKQoKICAgIGRlZiByZWdpc3Rlcl9icmFuY2hfcmVsZWFzZShzZWxmLCBrZXksIHJlbGVhc2UpOgogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHNlbGYuX2JyYW5jaF9yZWxlYXNlW2tleV0gPSByZWxlYXNlCiAgICAgICAgICAgIGRpc2FibGVkID0gc2VsZi5fY2xvc2VkIG9yIHNlbGYuX3Byb3ZpZGVyc1trZXldWydzdGF0ZSddICE9ICdBQ1RJVkUnCiAgICAgICAgaWYgZGlzYWJsZWQ6CiAgICAgICAgICAgIHJlbGVhc2UoKQoKICAgIGRlZiBzdG9wX2FkbWlzc2lvbihzZWxmKToKICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICBzZWxmLl9jbG9zZWQgPSBUcnVlCiAgICAgICAgICAgIHNlbGYuX2ZyYW1lcy5jbGVhcigpCiAgICAgICAgICAgIHJlbGVhc2VzID0gbGlzdChzZWxmLl9icmFuY2hfcmVsZWFzZS52YWx1ZXMoKSkKICAgICAgICAgICAgc2VsZi5fY3Yubm90aWZ5X2FsbCgpCiAgICAgICAgZm9yIHJlbGVhc2UgaW4gcmVsZWFzZXM6CiAgICAgICAgICAgIHJlbGVhc2UoKQoKICAgIGRlZiBfZXZpY3RfbG9ja2VkKHNlbGYsIHN0YXRlKToKICAgICAgICBzZWxmLl9yZXRpcmVfbG9ja2VkKHN0YXRlLmZyYW1lLmZyYW1lX3NlcSwgJ2V2aWN0ZWQnKQogICAgICAgIHN0YXRlLnN0YXRlID0gJ0VWSUNURUQnCiAgICAgICAgZm9yIGtleSBpbiBzZWxmLl9nYXBfcGVuZGluZzoKICAgICAgICAgICAgc2VsZi5fZ2FwX3BlbmRpbmdba2V5XSA9IFRydWUKICAgICAgICBzZWxmLl9tZXRyaWNzWydmcmFtZV9ldmljdGVkJ10gKz0gMQoKICAgIGRlZiBzdGFydChzZWxmKToKICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICBpZiBzZWxmLl9jbG9zZWQgb3Igc2VsZi5fdGhyZWFkIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgcmFpc2UgUnVudGltZUVycm9yKCdNdWx0aS1wcm92aWRlciBjb29yZGluYXRvciBjYW5ub3Qgc3RhcnQgdHdpY2UuJykKICAgICAgICAgICAgaWYgc2VsZi5wdWJsaXNoZXIgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICBpZiBub3Qgc2VsZi5wdWJsaXNoZXIuY2hhbm5lbChzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbMV0sIHNlbGYuaW5ncmVzcy5pZGVudGl0eVszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuaW5ncmVzcy5pZGVudGl0eVs0XSwgJ1NUQVJUSU5HJyk6CiAgICAgICAgICAgICAgICAgICAgcmFpc2UgUnVudGltZUVycm9yKCdNZXRhZGF0YSBjaGFubmVsIHdvcmtlciBhZG1pc3Npb24gcmVqZWN0ZWQuJykKICAgICAgICAgICAgZnJvbSBhcHAubWV0YWRhdGFfc2FtcGxlcyBpbXBvcnQgTWV0YWRhdGFTYW1wbGVzCiAgICAgICAgICAgIGZyb20gYXBwLm1ldGFkYXRhX3Zpc3VhbCBpbXBvcnQgTWV0YWRhdGFWaXN1YWwKICAgICAgICAgICAgZnJvbSBhcHAuZXZlbnRfY2FwdHVyZSBpbXBvcnQgRXZlbnRDYXB0dXJlCiAgICAgICAgICAgIHNlbGYuX3NhbXBsZXMgPSBNZXRhZGF0YVNhbXBsZXMuZnJvbV9lbnZpcm9ubWVudCgpCiAgICAgICAgICAgIGlmIG9zLmVudmlyb24uZ2V0KCdDT05URVhUUkFfTUVUQURBVEFfVklTVUFMX0VOQUJMRUQnLCAndHJ1ZScpLmxvd2VyKCkgPT0gJ3RydWUnOgogICAgICAgICAgICAgICAgc2VsZi52aXN1YWwgPSBNZXRhZGF0YVZpc3VhbC5mcm9tX2Vudmlyb25tZW50KGRpc3BsYXlfdGhyZXNob2xkPXNlbGYuZGlzcGxheV90aHJlc2hvbGQpCiAgICAgICAgICAgIHNlbGYuYXJ0aWZhY3RzID0gRXZlbnRDYXB0dXJlLmZyb21fZW52aXJvbm1lbnQoc2VsZi5zcGVjKQogICAgICAgICAgICBzZWxmLl90aHJlYWQgPSB0aHJlYWRpbmcuVGhyZWFkKAogICAgICAgICAgICAgICAgdGFyZ2V0PXNlbGYuX3J1biwgbmFtZT0nbXVsdGktcHJvdmlkZXItcmVzdWx0cycsIGRhZW1vbj1UcnVlKQogICAgICAgICAgICBzZWxmLl90aHJlYWQuc3RhcnQoKQoKICAgIGRlZiBhZG1pdChzZWxmLCBmcmFtZSwgYWRtaXR0ZWRfYXQ9Tm9uZSk6CiAgICAgICAgYWRtaXR0ZWRfYXQgPSBzZWxmLmNsb2NrKCkgaWYgYWRtaXR0ZWRfYXQgaXMgTm9uZSBlbHNlIGZsb2F0KGFkbWl0dGVkX2F0KQogICAgICAgIGZhdGFsID0gRmFsc2UKICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICBpZiBzZWxmLl9jbG9zZWQgb3Igbm90IHNlbGYuaXNfY3VycmVudCgpIG9yIGZyYW1lLmZyYW1lX3NlcSA8PSBzZWxmLl9sYXN0X2FkbWl0dGVkOgogICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljc1snYWRtaXNzaW9uX3N0YWxlJ10gKz0gMQogICAgICAgICAgICAgICAgcmV0dXJuIEZhbHNlCiAgICAgICAgICAgIHNlbGYuX2xhc3RfYWRtaXR0ZWQgPSBmcmFtZS5mcmFtZV9zZXEKICAgICAgICAgICAgYWN0aXZlID0ge2sgZm9yIGssIHYgaW4gc2VsZi5fcHJvdmlkZXJzLml0ZW1zKCkgaWYgdlsnc3RhdGUnXSA9PSAnQUNUSVZFJ30KICAgICAgICAgICAgZm9yIGtleSBpbiBhY3RpdmU6CiAgICAgICAgICAgICAgICBzdGF0dXMgPSBzZWxmLl9wcm92aWRlcnNba2V5XQogICAgICAgICAgICAgICAgaWYgc3RhdHVzWydmaXJzdF9pbnB1dF9hdCddIGlzIE5vbmU6CiAgICAgICAgICAgICAgICAgICAgc3RhdHVzWydmaXJzdF9pbnB1dF9hdCddID0gYWRtaXR0ZWRfYXQKICAgICAgICAgICAgICAgIHN0YXR1c1snbGFzdF9pbnB1dF9hdCddID0gYWRtaXR0ZWRfYXQKICAgICAgICAgICAgd2hpbGUgbGVuKHNlbGYuX2ZyYW1lcykgPj0gc2VsZi5jYXBhY2l0eToKICAgICAgICAgICAgICAgIGV2aWN0YWJsZSA9IG5leHQoKHNlcSBmb3Igc2VxLCBzIGluIHNlbGYuX2ZyYW1lcy5pdGVtcygpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBzZWxmLmZyZXNobmVzc19lbmFibGVkIG9yIG5vdCAocy5jbGFpbWVkIG9yIHMucmVzdWx0cykpLCBOb25lKQogICAgICAgICAgICAgICAgaWYgZXZpY3RhYmxlIGlzIE5vbmU6CiAgICAgICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljc1snYWRtaXNzaW9uX2NhcGFjaXR5X2Ryb3AnXSArPSAxCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIEZhbHNlCiAgICAgICAgICAgICAgICBvbGRlc3QgPSBzZWxmLl9mcmFtZXMucG9wKGV2aWN0YWJsZSkKICAgICAgICAgICAgICAgIHNlbGYuX2V2aWN0X2xvY2tlZChvbGRlc3QpCiAgICAgICAgICAgIHNlbGYuX2ZyYW1lc1tmcmFtZS5mcmFtZV9zZXFdID0gX09wZW5GcmFtZSgKICAgICAgICAgICAgICAgIGZyYW1lLCBhZG1pdHRlZF9hdCwgYWRtaXR0ZWRfYXQrc2VsZi5mcmVzaG5lc3NfcywgYWN0aXZlLCB7fSkKICAgICAgICAgICAgc2VsZi5fbWV0cmljc1snYWRtaXR0ZWQnXSArPSAxCiAgICAgICAgICAgIGZhdGFsID0gc2VsZi5fY2hlY2tfYWxsX3VuYXZhaWxhYmxlX2xvY2tlZCgpCiAgICAgICAgICAgIHNlbGYuX2N2Lm5vdGlmeV9hbGwoKQogICAgICAgIGlmIGZhdGFsOgogICAgICAgICAgICBzZWxmLl9ub3RpZnlfZmF0YWwoJ2FkbWlzc2lvbl91bmF2YWlsYWJsZScpCiAgICAgICAgcmV0dXJuIG5vdCBmYXRhbAoKICAgIGRlZiBpc19vcGVuKHNlbGYsIGZyYW1lX3NlcSk6CiAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgc3RhdGUgPSBzZWxmLl9mcmFtZXMuZ2V0KGZyYW1lX3NlcSkKICAgICAgICAgICAgcmV0dXJuIGJvb2wobm90IHNlbGYuX2Nsb3NlZCBhbmQgc2VsZi5pc19jdXJyZW50KCkgYW5kIHN0YXRlCiAgICAgICAgICAgICAgICAgICAgICAgIGFuZCBzdGF0ZS5zdGF0ZSA9PSAnT1BFTicKICAgICAgICAgICAgICAgICAgICAgICAgYW5kIChub3Qgc2VsZi5mcmVzaG5lc3NfZW5hYmxlZCBvciBzZWxmLmNsb2NrKCkgPD0gc3RhdGUuZGVhZGxpbmUpKQoKICAgIGRlZiBwcm92aWRlcl9hdmFpbGFibGUoc2VsZiwga2V5KToKICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICByZXR1cm4gc2VsZi5fcHJvdmlkZXJzLmdldChrZXksIHt9KS5nZXQoJ3N0YXRlJykgPT0gJ0FDVElWRScKCiAgICBkZWYgbm90ZV9wcm92aWRlcl9wcm9ncmVzcyhzZWxmLCBrZXksIHN0YWdlKToKICAgICAgICBpZiBzdGFnZSBub3QgaW4gKCdpbmZlcl9vdXRwdXQnLCAnY2FsbGJhY2snKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBwcm92aWRlciBwcm9ncmVzcyBzdGFnZS4nKQogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHN0YXR1cyA9IHNlbGYuX3Byb3ZpZGVyc1trZXldCiAgICAgICAgICAgIGlmIG5vdCBzZWxmLl9jbG9zZWQgYW5kIHN0YXR1c1snc3RhdGUnXSA9PSAnQUNUSVZFJzoKICAgICAgICAgICAgICAgIHN0YXR1c1snbGFzdF9wcm9ncmVzc19hdCddID0gc2VsZi5jbG9jaygpCiAgICAgICAgICAgICAgICBzdGF0dXNbJ2xhc3RfcHJvZ3Jlc3Nfc3RhZ2UnXSA9IHN0YWdlCgogICAgZGVmIG5vdGVfYnVzeV9kcm9wKHNlbGYsIGtleSk6CiAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgaWYga2V5IGluIHNlbGYuX3Byb3ZpZGVyczoKICAgICAgICAgICAgICAgIHNlbGYuX3Byb3ZpZGVyc1trZXldWydidXN5X2Ryb3AnXSArPSAxCiAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ2xhdGVzdF9idXN5X2Ryb3AnXSArPSAxCgogICAgZGVmIHN1Ym1pdChzZWxmLCBwcm92aWRlciwgZnJhbWUsIGNvcGllZCwgcmVzcG9uc2VfYXQ9Tm9uZSwgKiwgdGltaW5nPU5vbmUpOgogICAgICAgIHJlc3BvbnNlX2F0ID0gc2VsZi5jbG9jaygpIGlmIHJlc3BvbnNlX2F0IGlzIE5vbmUgZWxzZSBmbG9hdChyZXNwb25zZV9hdCkKICAgICAgICBsb2NrX3N0YXJ0ZWQgPSBzZWxmLmNsb2NrKCkKICAgICAgICBhY2NlcHRlZCA9IEZhbHNlCiAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgc3RhdHVzID0gc2VsZi5fcHJvdmlkZXJzLmdldChwcm92aWRlcikKICAgICAgICAgICAgaWYgc3RhdHVzIGlzIE5vbmU6CiAgICAgICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdVbmtub3duIHByb3ZpZGVyLicpCiAgICAgICAgICAgICMgRXZlbiBhIGxhdGUgb3IgZW1wdHkgcmVzdWx0IHByb3ZlcyBwcm92aWRlciBsaXZlbmVzcy4KICAgICAgICAgICAgc3RhdHVzWydsYXN0X3Jlc3BvbnNlX2F0J10gPSByZXNwb25zZV9hdAogICAgICAgICAgICBzdGF0dXMuc2V0ZGVmYXVsdCgnZmlyc3RfcmVzcG9uc2VfYXQnLCByZXNwb25zZV9hdCkKICAgICAgICAgICAgc3RhdHVzWydyZXNwb25zZXMnXSArPSAxCiAgICAgICAgICAgIHN0YXRlID0gc2VsZi5fZnJhbWVzLmdldChmcmFtZS5mcmFtZV9zZXEpCiAgICAgICAgICAgIGFjY2VwdGFuY2VfYXQgPSBzZWxmLmNsb2NrKCkKICAgICAgICAgICAgaWYgc3RhdGUgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICBzZWxmLl90aW1pbmdfbG9ja2VkKHByb3ZpZGVyLCAnc2VsZWN0ZWRfdG9fcmVzcG9uc2UnLCByZXNwb25zZV9hdC1zdGF0ZS5hZG1pdHRlZF9hdCkKICAgICAgICAgICAgICAgIGlmIGFjY2VwdGFuY2VfYXQgPiBzdGF0ZS5kZWFkbGluZToKICAgICAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydvdmVyX2ZyZXNobmVzc18nICsgcHJvdmlkZXJdICs9IDEKICAgICAgICAgICAgc2VsZi5fdGltaW5nX2xvY2tlZChwcm92aWRlciwgJ3N1Ym1pdF9sb2NrX3dhaXQnLCBhY2NlcHRhbmNlX2F0LWxvY2tfc3RhcnRlZCkKICAgICAgICAgICAgaWYgdGltaW5nIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgc2VsZWN0ZWQsIGdhdGUsIGluZmVyLCBjYWxsYmFjaywgY29weV9kb25lID0gdGltaW5nCiAgICAgICAgICAgICAgICBmb3Igc3RhZ2UsIHN0YXJ0LCBlbmQgaW4gKAogICAgICAgICAgICAgICAgICAgICAgICAoJ2dhdGVfdG9faW5mZXInLCBnYXRlLCBpbmZlciksCiAgICAgICAgICAgICAgICAgICAgICAgICgnaW5mZXJfdG9fY2FsbGJhY2snLCBpbmZlciwgY2FsbGJhY2spLAogICAgICAgICAgICAgICAgICAgICAgICAoJ2NhbGxiYWNrX2NvcHknLCBjYWxsYmFjaywgY29weV9kb25lKSwKICAgICAgICAgICAgICAgICAgICAgICAgKCdzZWxlY3RlZF90b19jYWxsYmFjaycsIHNlbGVjdGVkLCBjYWxsYmFjayksCiAgICAgICAgICAgICAgICAgICAgICAgICgnc2VsZWN0ZWRfdG9fYWNjZXB0X2NoZWNrJywgc2VsZWN0ZWQsIGFjY2VwdGFuY2VfYXQpKToKICAgICAgICAgICAgICAgICAgICBpZiBzdGFydCBpcyBub3QgTm9uZSBhbmQgZW5kIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLl90aW1pbmdfbG9ja2VkKHByb3ZpZGVyLCBzdGFnZSwgZW5kLXN0YXJ0KQogICAgICAgICAgICBpZiAoc3RhdHVzWydzdGF0ZSddICE9ICdBQ1RJVkUnIG9yIHN0YXRlIGlzIE5vbmUgb3Igc3RhdGUuc3RhdGUgIT0gJ09QRU4nCiAgICAgICAgICAgICAgICAgICAgb3IgKHNlbGYuZnJlc2huZXNzX2VuYWJsZWQgYW5kIGFjY2VwdGFuY2VfYXQgPiBzdGF0ZS5kZWFkbGluZSkKICAgICAgICAgICAgICAgICAgICBvciBmcmFtZS5mcmFtZV9zZXEgPD0gc2VsZi5fbGFzdF9wdWJsaXNoZWQpOgogICAgICAgICAgICAgICAgc3RhdHVzWydsYXRlJ10gKz0gMQogICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljc1snbGF0ZV9yZXN1bHQnXSArPSAxCiAgICAgICAgICAgICAgICByZWFzb24gPSAoJ3Byb3ZpZGVyX2Rpc2FibGVkJyBpZiBzdGF0dXNbJ3N0YXRlJ10gIT0gJ0FDVElWRScgZWxzZQogICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX3JldGlyZWQuZ2V0KGZyYW1lLmZyYW1lX3NlcSwgJ21pc3Npbmdfc2xvdCcpIGlmIHN0YXRlIGlzIE5vbmUgZWxzZQogICAgICAgICAgICAgICAgICAgICAgICAgICdjbG9zZWRfZnJhbWUnIGlmIHN0YXRlLnN0YXRlICE9ICdPUEVOJyBlbHNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgJ2RlYWRsaW5lJyBpZiBhY2NlcHRhbmNlX2F0ID4gc3RhdGUuZGVhZGxpbmUgZWxzZSAnYmFja3dhcmQnKQogICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljc1sncmVqZWN0ZWRfJyArIHByb3ZpZGVyICsgJ18nICsgcmVhc29uXSArPSAxCiAgICAgICAgICAgICAgICByZXR1cm4gRmFsc2UKICAgICAgICAgICAgaWYgcHJvdmlkZXIgbm90IGluIHN0YXRlLnJlcXVpcmVkIG9yIHByb3ZpZGVyIGluIHN0YXRlLnJlc3VsdHM6CiAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydkdXBsaWNhdGVfb3JfdW5yZXF1aXJlZF9yZXN1bHQnXSArPSAxCiAgICAgICAgICAgICAgICByZXR1cm4gRmFsc2UKICAgICAgICAgICAgaWYgKChmcmFtZS5mcmFtZV93aWR0aCwgZnJhbWUuZnJhbWVfaGVpZ2h0KSAhPSAoY29waWVkLndpZHRoLCBjb3BpZWQuaGVpZ2h0KQogICAgICAgICAgICAgICAgICAgIG9yIGxlbihjb3BpZWQuZGV0ZWN0aW9ucykgPiAzMDApOgogICAgICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignUHJvdmlkZXIgcmVzdWx0IGFzc29jaWF0aW9uIGRpZmZlcnMuJykKICAgICAgICAgICAgc3RhdGUucmVzdWx0c1twcm92aWRlcl0gPSBjb3BpZWQKICAgICAgICAgICAgYWNjZXB0ZWQgPSBUcnVlCiAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ2FjY2VwdGVkX3Jlc3VsdCddICs9IDEKICAgICAgICAgICAgZnJvbSBhcHAucGlwZWxpbmVfZGlhZ25vc3RpY3MgaW1wb3J0IGRpYWdub3N0aWNzCiAgICAgICAgICAgIGlmIGRpYWdub3N0aWNzLmVuYWJsZWQ6CiAgICAgICAgICAgICAgICBkaWFnbm9zdGljcy5mb3JfcHJvdmlkZXIocHJvdmlkZXIpLm1hcmsoJ2FjY2VwdGVkJykKICAgICAgICAgICAgc2VsZi5fY3Yubm90aWZ5X2FsbCgpCiAgICAgICAgaWYgc2VsZi5vbl9wcm92aWRlcl9mcmFtZSBpcyBub3QgTm9uZToKICAgICAgICAgICAgc2VsZi5vbl9wcm92aWRlcl9mcmFtZShwcm92aWRlciwgdGltZS50aW1lKCkpCiAgICAgICAgcmV0dXJuIGFjY2VwdGVkCgogICAgZGVmIG1hcmtfcHJvdmlkZXJfdW5hdmFpbGFibGUoc2VsZiwga2V5LCByZWFzb249J3Byb3ZpZGVyX3VuYXZhaWxhYmxlJyk6CiAgICAgICAgZmF0YWwgPSBGYWxzZQogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHN0YXR1cyA9IHNlbGYuX3Byb3ZpZGVycy5nZXQoa2V5KQogICAgICAgICAgICBpZiBzdGF0dXMgaXMgTm9uZSBvciBzdGF0dXNbJ3N0YXRlJ10gIT0gJ0FDVElWRSc6CiAgICAgICAgICAgICAgICByZXR1cm4gRmFsc2UKICAgICAgICAgICAgc3RhdHVzWydzdGF0ZSddID0gJ1VOQVZBSUxBQkxFJwogICAgICAgICAgICBzdGF0dXNbJ3JlYXNvbiddID0gc3RyKHJlYXNvbikKICAgICAgICAgICAgc2VsZi5fbWV0cmljc1sncHJvdmlkZXJfdW5hdmFpbGFibGUnXSArPSAxCiAgICAgICAgICAgIGZvciBzdGF0ZSBpbiBzZWxmLl9mcmFtZXMudmFsdWVzKCk6CiAgICAgICAgICAgICAgICBzdGF0ZS5yZXF1aXJlZC5kaXNjYXJkKGtleSkKICAgICAgICAgICAgICAgIHN0YXRlLnJlc3VsdHMucG9wKGtleSwgTm9uZSkKICAgICAgICAgICAgc2VsZi5fZ2FwX3BlbmRpbmdba2V5XSA9IFRydWUKICAgICAgICAgICAgZmF0YWwgPSBzZWxmLl9jaGVja19hbGxfdW5hdmFpbGFibGVfbG9ja2VkKCkKICAgICAgICAgICAgc2VsZi5fY3Yubm90aWZ5X2FsbCgpCiAgICAgICAgICAgIHJlbGVhc2UgPSBzZWxmLl9icmFuY2hfcmVsZWFzZS5nZXQoa2V5KQogICAgICAgIGlmIHJlbGVhc2UgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIHJlbGVhc2UoKQogICAgICAgIGlmIGZhdGFsOgogICAgICAgICAgICBzZWxmLl9ub3RpZnlfZmF0YWwoJ3Byb3ZpZGVyX3VuYXZhaWxhYmxlJykKICAgICAgICByZXR1cm4gVHJ1ZQoKICAgIGRlZiBfY2hlY2tfYWxsX3VuYXZhaWxhYmxlX2xvY2tlZChzZWxmKToKICAgICAgICBpZiBub3Qgc2VsZi5fcmVxdWVzdGVkOgogICAgICAgICAgICByZXR1cm4gbm90IGFueSh2WydzdGF0ZSddID09ICdBQ1RJVkUnIGZvciB2IGluIHNlbGYuX3Byb3ZpZGVycy52YWx1ZXMoKSkKICAgICAgICBhY3RpdmUgPSB7cyBmb3IgcyBpbiBzZWxmLl9yZXF1ZXN0ZWQKICAgICAgICAgICAgICAgICAgaWYgc2VsZi5fcHJvdmlkZXJzW3NlbGYuX2RlcGVuZGVuY2llc1tzXV1bJ3N0YXRlJ10gPT0gJ0FDVElWRSd9CiAgICAgICAgcmV0dXJuIG5vdCBhY3RpdmUKCiAgICBkZWYgX3JlYWR5X2xvY2tlZChzZWxmLCBub3cpOgogICAgICAgIGZvciBzZXEsIHN0YXRlIGluIHNlbGYuX2ZyYW1lcy5pdGVtcygpOgogICAgICAgICAgICBpZiBzdGF0ZS5zdGF0ZSAhPSAnT1BFTic6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICBpZiBzdGF0ZS5yZXF1aXJlZCA8PSBzZXQoc3RhdGUucmVzdWx0cykgb3IgKHNlbGYuZnJlc2huZXNzX2VuYWJsZWQgYW5kIG5vdyA+PSBzdGF0ZS5kZWFkbGluZSk6CiAgICAgICAgICAgICAgICByZXR1cm4gc2VxCiAgICAgICAgICAgIGlmIG5vdCBzZWxmLmZyZXNobmVzc19lbmFibGVkIGFuZCBzdGF0ZS5jbGFpbWVkOgogICAgICAgICAgICAgICAgcmV0dXJuIE5vbmUKICAgICAgICByZXR1cm4gTm9uZQoKICAgIGRlZiBfbmV4dF93YWl0X2xvY2tlZChzZWxmLCBub3cpOgogICAgICAgIGlmIG5vdCBzZWxmLmZyZXNobmVzc19lbmFibGVkOgogICAgICAgICAgICByZXR1cm4gLjEKICAgICAgICBkZWFkbGluZXMgPSBbcy5kZWFkbGluZSBmb3IgcyBpbiBzZWxmLl9mcmFtZXMudmFsdWVzKCkgaWYgcy5zdGF0ZSA9PSAnT1BFTiddCiAgICAgICAgd2FpdCA9IG1heCgwLiwgbWluKGRlYWRsaW5lcyktbm93KSBpZiBkZWFkbGluZXMgZWxzZSAuMQogICAgICAgIHJldHVybiBtaW4od2FpdCwgLjEpCgogICAgZGVmIF9jaGVja19zdGFsbHNfbG9ja2VkKHNlbGYsIG5vdyk6CiAgICAgICAgdW5hdmFpbGFibGUgPSBbXQogICAgICAgIGlucHV0X3JlY2VudCA9IGFueSh2WydsYXN0X2lucHV0X2F0J10gaXMgbm90IE5vbmUgYW5kIG5vdy12WydsYXN0X2lucHV0X2F0J10gPD0gc2VsZi5zdGFsbF9zCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciB2IGluIHNlbGYuX3Byb3ZpZGVycy52YWx1ZXMoKSkKICAgICAgICBpZiBub3QgaW5wdXRfcmVjZW50OgogICAgICAgICAgICByZXR1cm4gdW5hdmFpbGFibGUKICAgICAgICBmb3Iga2V5LCBzdGF0dXMgaW4gc2VsZi5fcHJvdmlkZXJzLml0ZW1zKCk6CiAgICAgICAgICAgIGlmIHN0YXR1c1snc3RhdGUnXSAhPSAnQUNUSVZFJyBvciBzdGF0dXNbJ2ZpcnN0X2lucHV0X2F0J10gaXMgTm9uZToKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIHJlc3BvbmRlZCA9IHN0YXR1c1snbGFzdF9yZXNwb25zZV9hdCddIGlzIG5vdCBOb25lCiAgICAgICAgICAgIHJlZmVyZW5jZSA9IHN0YXR1c1snbGFzdF9yZXNwb25zZV9hdCddIGlmIHJlc3BvbmRlZCBlbHNlIHN0YXR1c1snZmlyc3RfaW5wdXRfYXQnXQogICAgICAgICAgICBpZiByZXNwb25kZWQ6CiAgICAgICAgICAgICAgICByZWZlcmVuY2UgPSBtYXgocmVmZXJlbmNlLCBzdGF0dXMuZ2V0KCdsYXN0X3Byb2dyZXNzX2F0JywgcmVmZXJlbmNlKSkKICAgICAgICAgICAgaWYgbm93LXJlZmVyZW5jZSA+PSAoc2VsZi5zdGFsbF9zIGlmIHJlc3BvbmRlZCBlbHNlIHNlbGYuc3RhcnR1cF9zKToKICAgICAgICAgICAgICAgIHVuYXZhaWxhYmxlLmFwcGVuZChrZXkpCiAgICAgICAgcmV0dXJuIHVuYXZhaWxhYmxlCgogICAgZGVmIF9ydW4oc2VsZik6CiAgICAgICAgdHJ5OgogICAgICAgICAgICB3aGlsZSBUcnVlOgogICAgICAgICAgICAgICAgc3RhdGUgPSBOb25lCiAgICAgICAgICAgICAgICBzdGFsbHMgPSBbXQogICAgICAgICAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgICAgICAgICBpZiBzZWxmLl9jbG9zZWQgb3Igbm90IHNlbGYuaXNfY3VycmVudCgpOgogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4KICAgICAgICAgICAgICAgICAgICBub3cgPSBzZWxmLmNsb2NrKCkKICAgICAgICAgICAgICAgICAgICBzdGFsbHMgPSBzZWxmLl9jaGVja19zdGFsbHNfbG9ja2VkKG5vdykKICAgICAgICAgICAgICAgICAgICBmb3Iga2V5IGluIHN0YWxsczoKICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzID0gc2VsZi5fcHJvdmlkZXJzW2tleV0KICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzWydzdGF0ZSddID0gJ1VOQVZBSUxBQkxFJwogICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXNbJ3JlYXNvbiddID0gJ3Byb3ZpZGVyX3N0YWxsZWQnCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ3Byb3ZpZGVyX3N0YWxsZWQnXSArPSAxCiAgICAgICAgICAgICAgICAgICAgICAgIGZvciBvcGVuX3N0YXRlIGluIHNlbGYuX2ZyYW1lcy52YWx1ZXMoKToKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wZW5fc3RhdGUucmVxdWlyZWQuZGlzY2FyZChrZXkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcGVuX3N0YXRlLnJlc3VsdHMucG9wKGtleSwgTm9uZSkKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fZ2FwX3BlbmRpbmdba2V5XSA9IFRydWUKICAgICAgICAgICAgICAgICAgICBmYXRhbCA9IHNlbGYuX2NoZWNrX2FsbF91bmF2YWlsYWJsZV9sb2NrZWQoKQogICAgICAgICAgICAgICAgICAgIHNlcSA9IHNlbGYuX3JlYWR5X2xvY2tlZChub3cpCiAgICAgICAgICAgICAgICAgICAgaWYgc2VxIGlzIG5vdCBOb25lIGFuZCBub3QgZmF0YWw6CiAgICAgICAgICAgICAgICAgICAgICAgIGZvciBvbGRlciBpbiBbayBmb3IgayBpbiBzZWxmLl9mcmFtZXMgaWYgayA8IHNlcV06CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLl9ldmljdF9sb2NrZWQoc2VsZi5fZnJhbWVzLnBvcChvbGRlcikpCiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlID0gc2VsZi5fZnJhbWVzLnBvcChzZXEpCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIHNlcSA8PSBzZWxmLl9sYXN0X3B1Ymxpc2hlZDoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX2V2aWN0X2xvY2tlZChzdGF0ZSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ2JhY2t3YXJkX2Ryb3AnXSArPSAxCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZSA9IE5vbmUKICAgICAgICAgICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgQ2xhaW0gYmVmb3JlIGFueSB0ZW1wb3JhbCBtdXRhdGlvbjsgYWNjZXB0ZWQgcmVzdWx0cwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBhcmUgZnJvemVuIGV2ZW4gaWYgU3RvcC9kaXNhYmxlIGFycml2ZXMgZHVyaW5nIGhhbmRvZmYuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZS5zdGF0ZSA9ICdGSU5BTElaSU5HJwogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fcmV0aXJlX2xvY2tlZChzZXEsICdmaW5hbGl6aW5nJykKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBrZXkgaW4gc2VsZi5fZ2FwX3BlbmRpbmc6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYga2V5IGluIHN0YXRlLnJlc3VsdHM6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIHNlbGYuX2dhcF9wZW5kaW5nW2tleV06CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZS5nYXBzLmFkZChrZXkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX2dhcF9wZW5kaW5nW2tleV0gPSBGYWxzZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX2dhcF9wZW5kaW5nW2tleV0gPSBUcnVlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLl9maW5hbGl6aW5nID0gc3RhdGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ2ZpbmFsaXppbmdfY2xhaW1zJ10gKz0gMQogICAgICAgICAgICAgICAgICAgIGlmIHN0YXRlIGlzIE5vbmUgYW5kIG5vdCBmYXRhbDoKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fY3Yud2FpdChzZWxmLl9uZXh0X3dhaXRfbG9ja2VkKG5vdykpCiAgICAgICAgICAgICAgICBmb3Iga2V5IGluIHN0YWxsczoKICAgICAgICAgICAgICAgICAgICByZWxlYXNlID0gc2VsZi5fYnJhbmNoX3JlbGVhc2UuZ2V0KGtleSkKICAgICAgICAgICAgICAgICAgICBpZiByZWxlYXNlIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgICAgICAgICByZWxlYXNlKCkKICAgICAgICAgICAgICAgIGlmIGZhdGFsOgogICAgICAgICAgICAgICAgICAgIHNlbGYuX25vdGlmeV9mYXRhbCgncHJvdmlkZXJfc3RhbGxlZCcpCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgICAgICAgICBpZiBzdGF0ZSBpcyBub3QgTm9uZToKICAgICAgICAgICAgICAgICAgICBzZWxmLl9maW5hbGl6ZShzdGF0ZSkKICAgICAgICAgICAgICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZS5zdGF0ZSA9ICdGSU5BTElaRUQnCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX3JldGlyZV9sb2NrZWQoc2VxLCAnZmluYWxpemVkJykKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fZmluYWxpemluZyA9IE5vbmUKICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGVycm9yOgogICAgICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICAgICAgc2VsZi5fZXJyb3IgPSAnTVVMVElfUFJPVklERVJfUkVTVUxUX0ZBSUxFRCcKICAgICAgICAgICAgICAgIHNlbGYuX2Nsb3NlZCA9IFRydWUKICAgICAgICAgICAgICAgIHNlbGYuX2ZyYW1lcy5jbGVhcigpCiAgICAgICAgICAgIHNlbGYuX25vdGlmeV9mYXRhbCgncmVzdWx0X2V4Y2VwdGlvbicsIGVycm9yKQoKICAgIGRlZiBfb2JzZXJ2YXRpb25zKHNlbGYsIHByb3ZpZGVyLCBmcmFtZSwgY29waWVkKToKICAgICAgICBvYnNlcnZhdGlvbnMgPSB0dXBsZSgKICAgICAgICAgICAgRGV0ZWN0aW9uT2JzZXJ2YXRpb24oZnJhbWUsIHByb3ZpZGVyLm1vZGVsLCBkLmNsYXNzX2lkLCBkLnNjb3JlLCBkLmJib3hfeHl4eSkKICAgICAgICAgICAgZm9yIGQgaW4gY29waWVkLmRldGVjdGlvbnMpCiAgICAgICAgcG9zZXMgPSB0dXBsZSgKICAgICAgICAgICAgUG9zZU9ic2VydmF0aW9uKGZyYW1lLCBwcm92aWRlci5tb2RlbCwgZC5zY29yZSwgZC5iYm94X3h5eHksIGQua2V5cG9pbnRzKQogICAgICAgICAgICBpZiBkLmtleXBvaW50cyBpcyBub3QgTm9uZSBlbHNlIE5vbmUgZm9yIGQgaW4gY29waWVkLmRldGVjdGlvbnMpCiAgICAgICAgZnJvbSBhcHAucG9zZV9jb25maWcgaW1wb3J0IFBPU0VfTU9ERUwKICAgICAgICBpZiBwcm92aWRlci5tb2RlbCA9PSBQT1NFX01PREVMIGFuZCBhbnkocCBpcyBOb25lIGZvciBwIGluIHBvc2VzKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignUG9zZSBwcm92aWRlciByZXR1cm5lZCBhIHBlcnNvbiB3aXRob3V0IGtleXBvaW50cy4nKQogICAgICAgIGlmIHByb3ZpZGVyLm1vZGVsICE9IFBPU0VfTU9ERUwgYW5kIGFueShwIGlzIG5vdCBOb25lIGZvciBwIGluIHBvc2VzKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignTm9uLVBvc2UgcHJvdmlkZXIgcmV0dXJuZWQgdW5leHBlY3RlZCBrZXlwb2ludHMuJykKICAgICAgICByZXR1cm4gb2JzZXJ2YXRpb25zLCBwb3NlcwoKICAgIGRlZiBfcGVyc29uX3Jlc3VsdChzZWxmLCBwcm92aWRlciwgZnJhbWUsIGNvcGllZCwgZ2FwX2JlZm9yZSk6CiAgICAgICAgZnJvbSBhcHAucG9zZV9jb25maWcgaW1wb3J0IFBPU0VfTU9ERUwKICAgICAgICBmcm9tIGFwcC5jbGFzc19jYXRhbG9nIGltcG9ydCBjb2NvX25hbWUKICAgICAgICBmcm9tIGFwcC5waXBlbGluZV9kaWFnbm9zdGljcyBpbXBvcnQgZGlhZ25vc3RpY3MKICAgICAgICBtZXRyaWMgPSBkaWFnbm9zdGljcy5mb3JfcHJvdmlkZXIocHJvdmlkZXIua2V5KQogICAgICAgIHdpdGggbWV0cmljLnBoYXNlKCdyZXN1bHRfb2JzZXJ2YXRpb25zJyk6CiAgICAgICAgICAgIG9ic2VydmF0aW9ucywgcG9zZXMgPSBzZWxmLl9vYnNlcnZhdGlvbnMocHJvdmlkZXIsIGZyYW1lLCBjb3BpZWQpCiAgICAgICAgc2VsZWN0ZWQgPSB0dXBsZShpIGZvciBpLCBvIGluIGVudW1lcmF0ZShvYnNlcnZhdGlvbnMpIGlmIG8uY2xhc3NfaWQgPT0gMCkKICAgICAgICBpZiBwcm92aWRlci5tb2RlbCA9PSBQT1NFX01PREVMIGFuZCBzZWxmLnBvc2VfY29uZmlnIGFuZCBzZWxmLnBvc2VfY29uZmlnLm5tc19lbmFibGVkOgogICAgICAgICAgICBmcm9tIGFwcC5wb3NlX25tcyBpbXBvcnQgcG9zZV9ubXNfaW5kaWNlcwogICAgICAgICAgICB3aXRoIG1ldHJpYy5waGFzZSgncmVzdWx0X25tcycpOgogICAgICAgICAgICAgICAgc2VsZWN0ZWQgPSB0dXBsZShpIGZvciBpIGluIHNlbGYucG9zZV9ubXMob2JzZXJ2YXRpb25zKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBvYnNlcnZhdGlvbnNbaV0uY2xhc3NfaWQgPT0gMCkKICAgICAgICBzZWxlY3RlZF9vYnMgPSB0dXBsZShvYnNlcnZhdGlvbnNbaV0gZm9yIGkgaW4gc2VsZWN0ZWQpCiAgICAgICAgd2l0aCBtZXRyaWMucGhhc2UoJ3Jlc3VsdF90cmFja2luZycpOgogICAgICAgICAgICBzZWxlY3RlZF9pZHMgPSAoc2VsZi50cmFja2VyLnVwZGF0ZShzZWxlY3RlZF9vYnMpIGlmIHNlbGYudHJhY2tlciBpcyBub3QgTm9uZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBbTm9uZV0gKiBsZW4oc2VsZWN0ZWRfb2JzKSkKICAgICAgICBpZHMgPSBbTm9uZV0gKiBsZW4ob2JzZXJ2YXRpb25zKQogICAgICAgIGZvciBpLCB0aWQgaW4gemlwKHNlbGVjdGVkLCBzZWxlY3RlZF9pZHMpOgogICAgICAgICAgICBpZHNbaV0gPSB0aWQKCiAgICAgICAgZGVjaXNpb25zID0gW05vbmVdICogbGVuKG9ic2VydmF0aW9ucykKICAgICAgICBldmVudHMgPSAoKQogICAgICAgIGlmIHNlbGYucmVnaW9uIGlzIG5vdCBOb25lOgogICAgICAgICAgICB3aXRoIG1ldHJpYy5waGFzZSgncmVzdWx0X3JlZ2lvbicpOgogICAgICAgICAgICAgICAgZ2FwX29wdGlvbnMgPSAoeydnYXBfYmVmb3JlJzogZ2FwX2JlZm9yZX0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIGdldGF0dHIoc2VsZi5pbmdyZXNzLCAnc291cmNlX2xhdGVzdCcsIEZhbHNlKSBlbHNlIHt9KQogICAgICAgICAgICAgICAgcm93cywgZW1pdHRlZCA9IHNlbGYucmVnaW9uLmV2YWx1YXRlKGZyYW1lLCBzZWxlY3RlZF9vYnMsIHNlbGVjdGVkX2lkcywgKipnYXBfb3B0aW9ucykKICAgICAgICAgICAgZm9yIGksIHJvdyBpbiB6aXAoc2VsZWN0ZWQsIHJvd3MpOgogICAgICAgICAgICAgICAgZGVjaXNpb25zW2ldID0gcm93CiAgICAgICAgICAgIGV2ZW50cyArPSB0dXBsZShyZXBsYWNlKGUsIG9iamVjdF9yZWY9c3RyKHNlbGVjdGVkW2ludChlLm9iamVjdF9yZWYpXSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgZSBpbiBlbWl0dGVkKQogICAgICAgIGlmIHByb3ZpZGVyLm1vZGVsID09IFBPU0VfTU9ERUw6CiAgICAgICAgICAgIHNlbGVjdGVkX3Bvc2VzID0gdHVwbGUocG9zZXNbaV0gZm9yIGkgaW4gc2VsZWN0ZWQpCiAgICAgICAgICAgIGZvciBzY2VuYXJpbyBpbiAoc2VsZi5mYWxsLCBzZWxmLmZpZ2h0KToKICAgICAgICAgICAgICAgIGlmIHNjZW5hcmlvIGlzIE5vbmU6CiAgICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgIHdpdGggbWV0cmljLnBoYXNlKCdyZXN1bHRfJysoJ2ZhbGwnIGlmIHNjZW5hcmlvIGlzIHNlbGYuZmFsbCBlbHNlICdmaWdodCcpKToKICAgICAgICAgICAgICAgICAgICByb3dzLCBlbWl0dGVkID0gc2NlbmFyaW8uZXZhbHVhdGUoCiAgICAgICAgICAgICAgICAgICAgICAgIGZyYW1lLCBzZWxlY3RlZF9wb3Nlcywgc2VsZWN0ZWRfaWRzLCBnYXBfYmVmb3JlPWdhcF9iZWZvcmUpCiAgICAgICAgICAgICAgICBmb3IgaSwgcm93IGluIHppcChzZWxlY3RlZCwgcm93cyk6CiAgICAgICAgICAgICAgICAgICAgZGVjaXNpb25zW2ldID0gKCptZW1iZXJzKGRlY2lzaW9uc1tpXSksICptZW1iZXJzKHJvdykpCiAgICAgICAgICAgICAgICBldmVudHMgKz0gdHVwbGUocmVwbGFjZShlLCBvYmplY3RfcmVmPXN0cihzZWxlY3RlZFtpbnQoZS5vYmplY3RfcmVmKV0pKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBlIGluIGVtaXR0ZWQpCgogICAgICAgIHNlbGVjdGVkX3NldCA9IHNldChzZWxlY3RlZCkKICAgICAgICBjb21tYW5kcyA9IFtdCiAgICAgICAgZm9yIGksIChvYnNlcnZhdGlvbiwgcG9zZSkgaW4gZW51bWVyYXRlKHppcChvYnNlcnZhdGlvbnMsIHBvc2VzKSk6CiAgICAgICAgICAgIGRlY2lzaW9uID0gZGVjaXNpb25zW2ldCiAgICAgICAgICAgIGxhYmVsID0gY29jb19uYW1lKG9ic2VydmF0aW9uLmNsYXNzX2lkKQogICAgICAgICAgICBjYXRlZ29yeV92aXNpYmxlID0gKAogICAgICAgICAgICAgICAgc2VsZi5kaXNwbGF5X2NhdGVnb3JpZXMgaXMgTm9uZSBvciBsYWJlbCBpbiBzZWxmLmRpc3BsYXlfY2F0ZWdvcmllcykKICAgICAgICAgICAgaWYgb2JzZXJ2YXRpb24uY2xhc3NfaWQgPT0gMDoKICAgICAgICAgICAgICAgIHZpc2libGUgPSAoCiAgICAgICAgICAgICAgICAgICAgaSBpbiBzZWxlY3RlZF9zZXQKICAgICAgICAgICAgICAgICAgICBhbmQgKHNjZW5hcmlvX3Zpc2libGUob2JzZXJ2YXRpb24uc2NvcmUsIGRlY2lzaW9uKSBpZiBkZWNpc2lvbiBlbHNlCiAgICAgICAgICAgICAgICAgICAgICAgICAob2JzZXJ2YXRpb24uc2NvcmUgPj0gc2VsZi5wb3NlX2NvbmZpZy5wZXJzb25fc2NvcmUKICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBwcm92aWRlci5tb2RlbCA9PSBQT1NFX01PREVMIGFuZCBzZWxmLnBvc2VfY29uZmlnCiAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBvYnNlcnZhdGlvbi5zY29yZSA+IHNlbGYuZGlzcGxheV90aHJlc2hvbGQpKQogICAgICAgICAgICAgICAgICAgIGFuZCBjYXRlZ29yeV92aXNpYmxlKQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgIyBNZWRpdW0gbWF5IG93biBwZXJzb24gVHJhY2tpbmcgYW5kIHN0aWxsIHByb3ZpZGUgZnV0dXJlIG5vbi1wZXJzb24KICAgICAgICAgICAgICAgICMgQ09DTyBjbGFzc2VzLiBUaG9zZSBvYmplY3RzIHN0YXkgZGlzcGxheS1vbmx5IGhlcmUuCiAgICAgICAgICAgICAgICB2aXNpYmxlID0gb2JzZXJ2YXRpb24uc2NvcmUgPiBzZWxmLmRpc3BsYXlfdGhyZXNob2xkIGFuZCBjYXRlZ29yeV92aXNpYmxlCiAgICAgICAgICAgIGNvbW1hbmRzLmFwcGVuZChWaXN1YWxpemF0aW9uQ29tbWFuZCgKICAgICAgICAgICAgICAgIG9ic2VydmF0aW9uLCBsYWJlbCwKICAgICAgICAgICAgICAgIGNvbG9yPScjRkYzMDMwJyBpZiBhbGVydGVkKGRlY2lzaW9uKSBlbHNlICcjMDBDQzY2JywKICAgICAgICAgICAgICAgIHZpc2libGU9dmlzaWJsZSwgdHJhY2tfaWQ9aWRzW2ldLCBldmVudF9pZHM9ZXZlbnRfaWRzKGRlY2lzaW9uKSwKICAgICAgICAgICAgICAgIHNjZW5hcmlvPWRlY2lzaW9uLCBwb3NlPXBvc2UpKQoKICAgICAgICBjb25maWdzID0gbWVtYmVycyhzZWxmLnJlZ2lvbi5jb25maWcgaWYgc2VsZi5yZWdpb24gZWxzZSBOb25lKQogICAgICAgIGlmIHNlbGYuZmFsbCBpcyBub3QgTm9uZToKICAgICAgICAgICAgY29uZmlncyArPSAoc2VsZi5mYWxsLmNvbmZpZywpCiAgICAgICAgaWYgc2VsZi5maWdodCBpcyBub3QgTm9uZToKICAgICAgICAgICAgY29uZmlncyArPSAoc2VsZi5maWdodC5jb25maWcsKQogICAgICAgIHJlc3VsdCA9IEZyYW1lUmVzdWx0KAogICAgICAgICAgICBmcmFtZSwgdHVwbGUoY29tbWFuZHMpLCBldmVudHMsCiAgICAgICAgICAgIGNvbmZpZ3MgaWYgbGVuKGNvbmZpZ3MpID4gMSBlbHNlIGNvbmZpZ3NbMF0gaWYgY29uZmlncyBlbHNlIE5vbmUsCiAgICAgICAgICAgIHNlbGYuc2NlbmFyaW9fcmV2aXNpb24sIHNlbGYuZGVidWdfYWxsX2NhbmRpZGF0ZXMsCiAgICAgICAgICAgIHNlbGYucG9zZV9jb25maWcgaWYgcHJvdmlkZXIubW9kZWwgPT0gUE9TRV9NT0RFTCBlbHNlIE5vbmUsCiAgICAgICAgICAgIHR1cGxlKGkgaW4gc2VsZWN0ZWRfc2V0IGZvciBpIGluIHJhbmdlKGxlbihvYnNlcnZhdGlvbnMpKSkKICAgICAgICAgICAgICAgIGlmIHByb3ZpZGVyLm1vZGVsID09IFBPU0VfTU9ERUwgZWxzZSBOb25lLAogICAgICAgICAgICBwcm92aWRlcl9tb2RlbD1wcm92aWRlci5tb2RlbCwgY2FtZXJhX2lkPXNlbGYuY2FtZXJhX2lkKQogICAgICAgIHJldHVybiByZXN1bHQsIGlkcwoKICAgIGRlZiBwb3NlX25tcyhzZWxmLCBvYnNlcnZhdGlvbnMpOgogICAgICAgIGZyb20gYXBwLnBvc2Vfbm1zIGltcG9ydCBwb3NlX25tc19pbmRpY2VzCiAgICAgICAgcmV0dXJuIHBvc2Vfbm1zX2luZGljZXMob2JzZXJ2YXRpb25zLCBzZWxmLnBvc2VfY29uZmlnLm5tc19pb3VfdGhyZXNob2xkKQoKICAgIGRlZiBfcGxhaW5fbWVkaXVtX3Jlc3VsdChzZWxmLCBwcm92aWRlciwgZnJhbWUsIGNvcGllZCk6CiAgICAgICAgZnJvbSBhcHAuY2xhc3NfY2F0YWxvZyBpbXBvcnQgY29jb19uYW1lCiAgICAgICAgb2JzZXJ2YXRpb25zLCBfID0gc2VsZi5fb2JzZXJ2YXRpb25zKHByb3ZpZGVyLCBmcmFtZSwgY29waWVkKQogICAgICAgIGNvbW1hbmRzID0gW10KICAgICAgICBmb3Igb2JzZXJ2YXRpb24gaW4gb2JzZXJ2YXRpb25zOgogICAgICAgICAgICBpZiBzZWxmLnBsYW4ucGVyc29uX293bmVyID09ICdwb3NlJyBhbmQgb2JzZXJ2YXRpb24uY2xhc3NfaWQgPT0gMDoKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIGxhYmVsID0gY29jb19uYW1lKG9ic2VydmF0aW9uLmNsYXNzX2lkKQogICAgICAgICAgICBjb21tYW5kcy5hcHBlbmQoVmlzdWFsaXphdGlvbkNvbW1hbmQoCiAgICAgICAgICAgICAgICBvYnNlcnZhdGlvbiwgbGFiZWwsIGNvbG9yPScjMDBDQzY2JywKICAgICAgICAgICAgICAgIHZpc2libGU9KG9ic2VydmF0aW9uLnNjb3JlID4gc2VsZi5kaXNwbGF5X3RocmVzaG9sZAogICAgICAgICAgICAgICAgICAgICAgICAgYW5kIChzZWxmLmRpc3BsYXlfY2F0ZWdvcmllcyBpcyBOb25lIG9yIGxhYmVsIGluIHNlbGYuZGlzcGxheV9jYXRlZ29yaWVzKSkpKQogICAgICAgIHJldHVybiBGcmFtZVJlc3VsdChmcmFtZSwgdHVwbGUoY29tbWFuZHMpLCBwcm92aWRlcl9tb2RlbD1wcm92aWRlci5tb2RlbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FtZXJhX2lkPXNlbGYuY2FtZXJhX2lkKQoKICAgIGRlZiBfZmluYWxpemUoc2VsZiwgc3RhdGUpOgogICAgICAgIGZyb20gYXBwLnBpcGVsaW5lX2RpYWdub3N0aWNzIGltcG9ydCBkaWFnbm9zdGljcwogICAgICAgIG1ldHJpYyA9IGRpYWdub3N0aWNzLmZvcl9wcm92aWRlcihzZWxmLnBsYW4ucHJvdmlkZXJzWzBdLmtleSkKICAgICAgICB3aXRoIG1ldHJpYy5waGFzZSgncmVzdWx0X3RvdGFsJyk6CiAgICAgICAgICAgIHNlbGYuX2ZpbmFsaXplX3Jlc3VsdChzdGF0ZSwgbWV0cmljKQoKICAgIGRlZiBfZmluYWxpemVfcmVzdWx0KHNlbGYsIHN0YXRlLCBtZXRyaWMpOgogICAgICAgIGZyYW1lID0gc3RhdGUuZnJhbWUKICAgICAgICBwbGFuX2J5X2tleSA9IHtwLmtleTogcCBmb3IgcCBpbiBzZWxmLnBsYW4ucHJvdmlkZXJzfQogICAgICAgIHBhcnRzID0gW10KICAgICAgICBwZXJzb25faWRzID0gTm9uZQogICAgICAgIHBlcnNvbl9rZXkgPSBzZWxmLnBsYW4ucGVyc29uX293bmVyCiAgICAgICAgaWYgcGVyc29uX2tleSBhbmQgcGVyc29uX2tleSBpbiBzdGF0ZS5yZXN1bHRzOgogICAgICAgICAgICBnYXBfYmVmb3JlID0gcGVyc29uX2tleSBpbiBzdGF0ZS5nYXBzCiAgICAgICAgICAgIGlmIGhhc2F0dHIoc2VsZi5pbmdyZXNzLCAncmVzdWx0X2dhcCcpOgogICAgICAgICAgICAgICAgZ2FwX2JlZm9yZSA9IHNlbGYuaW5ncmVzcy5yZXN1bHRfZ2FwKGZyYW1lKSBvciBnYXBfYmVmb3JlCiAgICAgICAgICAgIHJlc3VsdCwgcGVyc29uX2lkcyA9IHNlbGYuX3BlcnNvbl9yZXN1bHQoCiAgICAgICAgICAgICAgICBwbGFuX2J5X2tleVtwZXJzb25fa2V5XSwgZnJhbWUsIHN0YXRlLnJlc3VsdHNbcGVyc29uX2tleV0sIGdhcF9iZWZvcmUpCiAgICAgICAgICAgIHBhcnRzLmFwcGVuZChyZXN1bHQpCiAgICAgICAgICAgIHdpdGggbWV0cmljLnBoYXNlKCdyZXN1bHRfY29sbGVjdG9yJyk6CiAgICAgICAgICAgICAgICBzZWxmLl9jb2xsZWN0X3BlcnNvbihmcmFtZSwgcGxhbl9ieV9rZXlbcGVyc29uX2tleV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZS5yZXN1bHRzW3BlcnNvbl9rZXldLCBwZXJzb25faWRzKQogICAgICAgIGlmICdtZWRpdW0nIGluIHN0YXRlLnJlc3VsdHMgYW5kIHBlcnNvbl9rZXkgIT0gJ21lZGl1bSc6CiAgICAgICAgICAgIHBhcnRzLmFwcGVuZChzZWxmLl9wbGFpbl9tZWRpdW1fcmVzdWx0KAogICAgICAgICAgICAgICAgcGxhbl9ieV9rZXlbJ21lZGl1bSddLCBmcmFtZSwgc3RhdGUucmVzdWx0c1snbWVkaXVtJ10pKQoKICAgICAgICBpZiAnZmlyZScgaW4gc3RhdGUucmVzdWx0cyBhbmQgc2VsZi5maXJlIGlzIG5vdCBOb25lOgogICAgICAgICAgICBmcm9tIGFwcC5maXJlX3Jlc3VsdCBpbXBvcnQgZXZhbHVhdGVfcmVzdWx0CiAgICAgICAgICAgIG9ic2VydmF0aW9ucywgXyA9IHNlbGYuX29ic2VydmF0aW9ucygKICAgICAgICAgICAgICAgIHBsYW5fYnlfa2V5WydmaXJlJ10sIGZyYW1lLCBzdGF0ZS5yZXN1bHRzWydmaXJlJ10pCiAgICAgICAgICAgIHJlc3VsdCA9IGV2YWx1YXRlX3Jlc3VsdCgKICAgICAgICAgICAgICAgIHNlbGYuZmlyZSwgZnJhbWUsIG9ic2VydmF0aW9ucywgY2FtZXJhX2lkPXNlbGYuY2FtZXJhX2lkLAogICAgICAgICAgICAgICAgc2NlbmFyaW9fcmV2aXNpb249c2VsZi5zY2VuYXJpb19yZXZpc2lvbiwgZ2FwX2JlZm9yZT0nZmlyZScgaW4gc3RhdGUuZ2FwcykKICAgICAgICAgICAgaWYgcmVzdWx0IGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgcGFydHMuYXBwZW5kKHJlc3VsdCkKCiAgICAgICAgaWYgJ2Nyb3dkJyBpbiBzdGF0ZS5yZXN1bHRzIGFuZCBzZWxmLmNyb3dkIGlzIG5vdCBOb25lOgogICAgICAgICAgICBvYnNlcnZhdGlvbnMsIF8gPSBzZWxmLl9vYnNlcnZhdGlvbnMoCiAgICAgICAgICAgICAgICBwbGFuX2J5X2tleVsnY3Jvd2QnXSwgZnJhbWUsIHN0YXRlLnJlc3VsdHNbJ2Nyb3dkJ10pCiAgICAgICAgICAgIGdhcCA9ICdjcm93ZCcgaW4gc3RhdGUuZ2FwcwogICAgICAgICAgICBpZiBoYXNhdHRyKHNlbGYuaW5ncmVzcywgJ3Jlc3VsdF9nYXAnKToKICAgICAgICAgICAgICAgIGdhcCA9IHNlbGYuaW5ncmVzcy5yZXN1bHRfZ2FwKGZyYW1lKSBvciBnYXAKICAgICAgICAgICAgcmVzdWx0ID0gc2VsZi5jcm93ZC5wcm9jZXNzKGZyYW1lLCBvYnNlcnZhdGlvbnMsIGdhcF9iZWZvcmU9Z2FwKQogICAgICAgICAgICBpZiByZXN1bHQgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICBwYXJ0cy5hcHBlbmQocmVzdWx0KQoKICAgICAgICB3aXRoIG1ldHJpYy5waGFzZSgncmVzdWx0X2NvbXBvc2l0aW9uJyk6CiAgICAgICAgICAgIHJlc3VsdCA9IHNlbGYuX2NvbXBvc2VfcmVzdWx0KGZyYW1lLCBwYXJ0cywgcGVyc29uX2tleSwgc3RhdGUpCgogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIGlmIHN0YXRlLnN0YXRlICE9ICdGSU5BTElaSU5HJyBvciBmcmFtZS5mcmFtZV9zZXEgPD0gc2VsZi5fbGFzdF9wdWJsaXNoZWQ6CiAgICAgICAgICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoJ0ludmFsaWQgZmluYWxpemF0aW9uIG93bmVyc2hpcC4nKQogICAgICAgICAgICBzZWxmLl9sYXN0X3B1Ymxpc2hlZCA9IGZyYW1lLmZyYW1lX3NlcQogICAgICAgICAgICBzZWxmLl9sYXRlc3QgPSByZXN1bHQKICAgICAgICAgICAgc2VsZi5fbWV0cmljc1snZmluYWxpemVkJ10gKz0gMQogICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydldmVudHNfY3JlYXRlZCddICs9IGxlbihyZXN1bHQuZXZlbnRzKQoKICAgICAgICBpZiBzZWxmLl9zYW1wbGVzIGlzIG5vdCBOb25lIGFuZCBzZWxmLl9zYW1wbGVzLmVuYWJsZWQoKToKICAgICAgICAgICAgc2VsZi5fc2FtcGxlcy5jYXB0dXJlKHJlc3VsdC5zbmFwc2hvdCh2aXNpYmxlX29ubHk9RmFsc2UpKQogICAgICAgIGlmIHNlbGYudmlzdWFsIGlzIG5vdCBOb25lOgogICAgICAgICAgICBzZWxmLnZpc3VhbC5zdWJtaXRfcmVzdWx0KHJlc3VsdCkKICAgICAgICBpZiBzZWxmLmFydGlmYWN0cyBpcyBub3QgTm9uZToKICAgICAgICAgICAgd2l0aCBtZXRyaWMucGhhc2UoJ3Jlc3VsdF9hcnRpZmFjdF9oYW5kb2ZmJyk6CiAgICAgICAgICAgICAgICBhY2NlcHRlZCA9IHNlbGYuYXJ0aWZhY3RzLnN1Ym1pdChyZXN1bHQpCiAgICAgICAgICAgIGlmIGFjY2VwdGVkIGlzIEZhbHNlIGFuZCByZXN1bHQuZXZlbnRzOgogICAgICAgICAgICAgICAgcmFpc2UgUnVudGltZUVycm9yKCdTY2VuYXJpbyBFdmVudCBoYW5kb2ZmIHJlamVjdGVkLicpCiAgICAgICAgaWYgc2VsZi5wdWJsaXNoZXIgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIHdpdGggbWV0cmljLnBoYXNlKCdyZXN1bHRfcHVibGlzaCcpOgogICAgICAgICAgICAgICAgc2VsZi5wdWJsaXNoZXIuY2hhbm5lbChmcmFtZS5zb3VyY2VfaWQsIGZyYW1lLnJ1bl9pZCwgZnJhbWUucnVuX2dlbmVyYXRpb24sICdSVU5OSU5HJykKICAgICAgICAgICAgICAgIG5vdGUgPSBnZXRhdHRyKHNlbGYucHVibGlzaGVyLCAnbm90ZV9mcmFtZV90aW1pbmcnLCBOb25lKQogICAgICAgICAgICAgICAgaWYgbm90ZSBpcyBub3QgTm9uZSBhbmQgc3RhdGUuc2VsZWN0ZWRfYXQgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICAgICAgbm90ZShmcmFtZSwgcm91bmQoc3RhdGUuc2VsZWN0ZWRfYXQqMWU5KSwgcm91bmQoc3RhdGUuYWRtaXR0ZWRfYXQqMWU5KSkKICAgICAgICAgICAgICAgIGlmIG5vdCBzZWxmLnB1Ymxpc2hlci5zdWJtaXQocmVzdWx0LnNuYXBzaG90KCkpOgogICAgICAgICAgICAgICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ3B1Ymxpc2hlcl9yZWplY3RlZCddICs9IDEKCiAgICBkZWYgX2NvbXBvc2VfcmVzdWx0KHNlbGYsIGZyYW1lLCBwYXJ0cywgcGVyc29uX2tleSwgc3RhdGUpOgogICAgICAgIGlmIGxlbihzZWxmLnBsYW4ucHJvdmlkZXJzKSA9PSAxIGFuZCBsZW4ocGFydHMpID09IDE6CiAgICAgICAgICAgIHJlc3VsdCA9IHBhcnRzWzBdCiAgICAgICAgICAgIGlmIHJlc3VsdC5mcmFtZSAhPSBmcmFtZToKICAgICAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ0ZvcmVpZ24gcHJvdmlkZXIgcmVzdWx0IGZyYW1lLicpCiAgICAgICAgICAgIHB1YmxpY19wb3NpdGlvbnMocmVzdWx0LmNvbW1hbmRzLCByZXN1bHQuZXZlbnRzKQogICAgICAgICAgICBmaWVsZHMgPSBkaWN0KHNjZW5hcmlvX3JldmlzaW9uPXNlbGYuc2NlbmFyaW9fcmV2aXNpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGVidWdfYWxsX2NhbmRpZGF0ZXM9c2VsZi5kZWJ1Z19hbGxfY2FuZGlkYXRlcywKICAgICAgICAgICAgICAgICAgICAgICAgICBwb3NlX2NvbmZpZz1zZWxmLnBvc2VfY29uZmlnIGlmIHBlcnNvbl9rZXkgPT0gJ3Bvc2UnIGVsc2UgTm9uZSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjYW1lcmFfaWQ9c2VsZi5jYW1lcmFfaWQpCiAgICAgICAgICAgIGNoYW5nZXMgPSB7a2V5OiB2YWx1ZSBmb3Iga2V5LCB2YWx1ZSBpbiBmaWVsZHMuaXRlbXMoKSBpZiBnZXRhdHRyKHJlc3VsdCwga2V5KSAhPSB2YWx1ZX0KICAgICAgICAgICAgcmV0dXJuIHJlcGxhY2UocmVzdWx0LCAqKmNoYW5nZXMpIGlmIGNoYW5nZXMgZWxzZSByZXN1bHQKCiAgICAgICAgIyBPbmx5IHRoZSBzaGFyZWQtcHJvdmlkZXIgcGF0aCBuZWVkcyBjb21wb3NpdGlvbiBhbmQgcmVmZXJlbmNlIHJlbWFwcGluZy4KICAgICAgICByYXdfY29tbWFuZHMsIHJhd19ldmVudHMsIGNvbmZpZ3MgPSBbXSwgW10sIFtdCiAgICAgICAgZnJvbSBhcHAuY3Jvd2RfZXZlbnQgaW1wb3J0IENyb3dkRXZlbnQKICAgICAgICBjcm93ZF9yZWdpb25zID0gTm9uZQogICAgICAgIGZvciBwYXJ0IGluIHBhcnRzOgogICAgICAgICAgICBpZiBwYXJ0LmNyb3dkX3JlZ2lvbnMgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICBjcm93ZF9yZWdpb25zID0gcGFydC5jcm93ZF9yZWdpb25zCiAgICAgICAgICAgIG9mZnNldCA9IGxlbihyYXdfY29tbWFuZHMpCiAgICAgICAgICAgIHJhd19jb21tYW5kcy5leHRlbmQocGFydC5jb21tYW5kcykKICAgICAgICAgICAgcmF3X2V2ZW50cy5leHRlbmQoCiAgICAgICAgICAgICAgICBldmVudCBpZiBpc2luc3RhbmNlKGV2ZW50LCBDcm93ZEV2ZW50KSBlbHNlIHJlcGxhY2UoZXZlbnQsIG9iamVjdF9yZWY9c3RyKGludChldmVudC5vYmplY3RfcmVmKStvZmZzZXQpKQogICAgICAgICAgICAgICAgZm9yIGV2ZW50IGluIHBhcnQuZXZlbnRzKQogICAgICAgICAgICBjb25maWdzLmV4dGVuZChtZW1iZXJzKHBhcnQuc2NlbmFyaW9fY29uZmlnKSkKCiAgICAgICAgc2VsZWN0ZWRfcG9zaXRpb25zID0gcHVibGljX3Bvc2l0aW9ucyhyYXdfY29tbWFuZHMsIHJhd19ldmVudHMpCiAgICAgICAgaWYgbGVuKHJhd19jb21tYW5kcykgPiBsZW4oc2VsZWN0ZWRfcG9zaXRpb25zKToKICAgICAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ2NvbW1hbmRfY2FwX2Ryb3AnXSArPSBsZW4ocmF3X2NvbW1hbmRzKS1sZW4oc2VsZWN0ZWRfcG9zaXRpb25zKQogICAgICAgIHJlbWFwID0ge29sZF9pbmRleDogbmV3X2luZGV4IGZvciBuZXdfaW5kZXgsIG9sZF9pbmRleCBpbiBlbnVtZXJhdGUoc2VsZWN0ZWRfcG9zaXRpb25zKX0KICAgICAgICBjb21tYW5kcyA9IFtyYXdfY29tbWFuZHNbaV0gZm9yIGkgaW4gc2VsZWN0ZWRfcG9zaXRpb25zXQogICAgICAgIGV2ZW50cyA9IFtldmVudCBpZiBpc2luc3RhbmNlKGV2ZW50LCBDcm93ZEV2ZW50KSBlbHNlIHJlcGxhY2UoZXZlbnQsIG9iamVjdF9yZWY9c3RyKHJlbWFwW2ludChldmVudC5vYmplY3RfcmVmKV0pKQogICAgICAgICAgICAgICAgICBmb3IgZXZlbnQgaW4gcmF3X2V2ZW50c10KCiAgICAgICAgcmV0dXJuIEZyYW1lUmVzdWx0KAogICAgICAgICAgICBmcmFtZSwgdHVwbGUoY29tbWFuZHMpLCB0dXBsZShldmVudHMpLAogICAgICAgICAgICB0dXBsZShjb25maWdzKSBpZiBsZW4oY29uZmlncykgPiAxIGVsc2UgY29uZmlnc1swXSBpZiBjb25maWdzIGVsc2UgTm9uZSwKICAgICAgICAgICAgc2VsZi5zY2VuYXJpb19yZXZpc2lvbiwgc2VsZi5kZWJ1Z19hbGxfY2FuZGlkYXRlcywKICAgICAgICAgICAgc2VsZi5wb3NlX2NvbmZpZyBpZiBwZXJzb25fa2V5ID09ICdwb3NlJyBhbmQgcGVyc29uX2tleSBpbiBzdGF0ZS5yZXN1bHRzIGVsc2UgTm9uZSwKICAgICAgICAgICAgY2FtZXJhX2lkPXNlbGYuY2FtZXJhX2lkLCBjcm93ZF9yZWdpb25zPWNyb3dkX3JlZ2lvbnMpCgogICAgZGVmIF9jb2xsZWN0X3BlcnNvbihzZWxmLCBmcmFtZSwgcHJvdmlkZXIsIGNvcGllZCwgaWRzKToKICAgICAgICBpZiBzZWxmLmNvbGxlY3RvciBpcyBOb25lOgogICAgICAgICAgICByZXR1cm4KICAgICAgICBpdGVtcyA9IFtdCiAgICAgICAgZm9yIGRldGVjdGlvbiwgdGlkIGluIHppcChjb3BpZWQuZGV0ZWN0aW9ucywgaWRzKToKICAgICAgICAgICAgaWYgZGV0ZWN0aW9uLmNsYXNzX2lkICE9IDA6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICBpdGVtID0gZGljdChkZXRlY3Rpb24uZG93bnN0cmVhbSgpLCB0cmFja19pZD10aWQpCiAgICAgICAgICAgIGlmIGRldGVjdGlvbi5rZXlwb2ludHMgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICBpdGVtWydrZXlwb2ludHMnXSA9IFtsaXN0KGspIGZvciBrIGluIGRldGVjdGlvbi5rZXlwb2ludHNdCiAgICAgICAgICAgIGl0ZW1zLmFwcGVuZChpdGVtKQogICAgICAgIHRhc2sgPSAncG9zZScgaWYgcHJvdmlkZXIua2V5ID09ICdwb3NlJyBlbHNlICdkZXQnCiAgICAgICAgc2VsZi5jb2xsZWN0b3IuYWRkKAogICAgICAgICAgICB0YXNrLCBmcmFtZS5mcmFtZV9zZXEsIGZyYW1lLnB0c19ucyBvciAwLAogICAgICAgICAgICB7J3cnOiBmcmFtZS5mcmFtZV93aWR0aCwgJ2gnOiBmcmFtZS5mcmFtZV9oZWlnaHQsCiAgICAgICAgICAgICAnY291bnQnOiBsZW4oaXRlbXMpLCAnaXRlbXMnOiBpdGVtcywgJ2ZyYW1lJzogZnJhbWV9LAogICAgICAgICAgICBtYXhfZnJhbWVzPTMyLCBtZXRyaWNzPXNlbGYuaW5ncmVzcy5tZXRyaWNzKQoKICAgIGRlZiBzY2VuYXJpb19zdGF0dXMoc2VsZik6CiAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgYWN0aXZlLCBkaXNhYmxlZCA9IFtdLCBbXQogICAgICAgICAgICBmb3Igc2NlbmFyaW8gaW4gc29ydGVkKHNlbGYuX3JlcXVlc3RlZCk6CiAgICAgICAgICAgICAgICBrZXkgPSBzZWxmLl9kZXBlbmRlbmNpZXNbc2NlbmFyaW9dCiAgICAgICAgICAgICAgICBzdGF0dXMgPSBzZWxmLl9wcm92aWRlcnNba2V5XQogICAgICAgICAgICAgICAgaWYgc3RhdHVzWydzdGF0ZSddID09ICdBQ1RJVkUnOgogICAgICAgICAgICAgICAgICAgIGFjdGl2ZS5hcHBlbmQoc2NlbmFyaW8pCiAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgIGRpc2FibGVkLmFwcGVuZCh7J25hbWUnOiBzY2VuYXJpbywgJ3JlYXNvbic6IHN0YXR1c1sncmVhc29uJ119KQogICAgICAgICAgICByZXR1cm4geydhY3RpdmUnOiBhY3RpdmUsICdkaXNhYmxlZCc6IGRpc2FibGVkfQoKICAgIGRlZiBzdGF0dXMoc2VsZik6CiAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgcHJvdmlkZXJzID0gewogICAgICAgICAgICAgICAga2V5OiB7CiAgICAgICAgICAgICAgICAgICAgKip7azogdiBmb3IgaywgdiBpbiB2YWx1ZS5pdGVtcygpCiAgICAgICAgICAgICAgICAgICAgICAgaWYgayBub3QgaW4gKCdmaXJzdF9pbnB1dF9hdCcsICdsYXN0X2lucHV0X2F0JywgJ2xhc3RfcmVzcG9uc2VfYXQnKX0sCiAgICAgICAgICAgICAgICAgICAgJ2xhc3RfcmVzcG9uc2VfYWdlX3MnOiAoCiAgICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKHNlbGYuY2xvY2soKS12YWx1ZVsnbGFzdF9yZXNwb25zZV9hdCddLCAzKQogICAgICAgICAgICAgICAgICAgICAgICBpZiB2YWx1ZVsnbGFzdF9yZXNwb25zZV9hdCddIGlzIG5vdCBOb25lIGVsc2UgTm9uZSksCiAgICAgICAgICAgICAgICAgICAgJ2ZpcnN0X2lucHV0X2F0JzogdmFsdWVbJ2ZpcnN0X2lucHV0X2F0J10sCiAgICAgICAgICAgICAgICAgICAgJ2ZpcnN0X3Jlc3BvbnNlX2F0JzogdmFsdWUuZ2V0KCdmaXJzdF9yZXNwb25zZV9hdCcpLAogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZm9yIGtleSwgdmFsdWUgaW4gc2VsZi5fcHJvdmlkZXJzLml0ZW1zKCkKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZGljdCgKICAgICAgICAgICAgICAgIHNvdXJjZV9sYXRlc3RfdHJpYWw9Z2V0YXR0cihzZWxmLmluZ3Jlc3MsICdzb3VyY2VfbGF0ZXN0JywgRmFsc2UpLAogICAgICAgICAgICAgICAgZXZlbnRfY29vbGRvd249c2VsZi5ldmVudF9jb29sZG93bi5zdGF0dXMoKSwKICAgICAgICAgICAgICAgIHN0YXRlPSdFUlJPUicgaWYgc2VsZi5fZXJyb3IgZWxzZSAoJ1NUT1BQRUQnIGlmIHNlbGYuX2Nsb3NlZCBlbHNlCiAgICAgICAgICAgICAgICAgICAgICAoJ0NPTk5FQ1RFRCcgaWYgc2VsZi5fbWV0cmljc1snZmluYWxpemVkJ10gZWxzZSAnUFJFUEFSRUQnKSksCiAgICAgICAgICAgICAgICBlcnJvcj1zZWxmLl9lcnJvciwgZnJlc2huZXNzX21zPXJvdW5kKHNlbGYuZnJlc2huZXNzX3MqMTAwMCksCiAgICAgICAgICAgICAgICBmcmVzaG5lc3NfZW5hYmxlZD1zZWxmLmZyZXNobmVzc19lbmFibGVkLCBzdGFydHVwX3NlY29uZHM9c2VsZi5zdGFydHVwX3MsCiAgICAgICAgICAgICAgICBzdGFsbF9zZWNvbmRzPXNlbGYuc3RhbGxfcywgcXVldWVkPWxlbihzZWxmLl9mcmFtZXMpLCBjYXBhY2l0eT1zZWxmLmNhcGFjaXR5LAogICAgICAgICAgICAgICAgaW5mbGlnaHRfYWdlX3M9bWF4KChzZWxmLmNsb2NrKCktcy5hZG1pdHRlZF9hdCBmb3IgcyBpbiBzZWxmLl9mcmFtZXMudmFsdWVzKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBzLmNsYWltZWQgYW5kIG5vdCBzLnJlc3VsdHMpLCBkZWZhdWx0PTApLAogICAgICAgICAgICAgICAgcGVuZGluZ19hZ2Vfcz1tYXgoKHNlbGYuY2xvY2soKS1zLmFkbWl0dGVkX2F0IGZvciBzIGluIHNlbGYuX2ZyYW1lcy52YWx1ZXMoKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgbm90IHMuY2xhaW1lZCksIGRlZmF1bHQ9MCksCiAgICAgICAgICAgICAgICBwcm92aWRlcnM9cHJvdmlkZXJzLCBzY2VuYXJpb3M9c2VsZi5zY2VuYXJpb19zdGF0dXMoKSwKICAgICAgICAgICAgICAgIHByb3ZpZGVyX3RpbWluZz17a2V5OiB7c3RhZ2U6IGRpY3Qocm93KSBmb3Igc3RhZ2UsIHJvdyBpbiBzdGFnZXMuaXRlbXMoKX0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIGtleSwgc3RhZ2VzIGluIHNlbGYuX3RpbWluZ3MuaXRlbXMoKX0sCiAgICAgICAgICAgICAgICBhcnRpZmFjdHM9c2VsZi5hcnRpZmFjdHMuc3RhdHVzKCkgaWYgc2VsZi5hcnRpZmFjdHMgZWxzZSBOb25lLAogICAgICAgICAgICAgICAgdmlzdWFsPXNlbGYudmlzdWFsLnN0YXR1cygpIGlmIHNlbGYudmlzdWFsIGVsc2UgTm9uZSwKICAgICAgICAgICAgICAgIHBlcmZvcm1hbmNlPXNlbGYuaW5ncmVzcy5tZXRyaWNzLnNuYXBzaG90KCksCiAgICAgICAgICAgICAgICBjb2xsZWN0b3JfZnJhbWVzPXNlbGYuX2NvbGxlY3Rvcl9mcmFtZV9jb3VudCgpLAogICAgICAgICAgICAgICAgZmluYWxpemluZz1pbnQoc2VsZi5fZmluYWxpemluZyBpcyBub3QgTm9uZSksCiAgICAgICAgICAgICAgICAqKnNlbGYuX21ldHJpY3MpCgogICAgZGVmIF9jb2xsZWN0b3JfZnJhbWVfY291bnQoc2VsZik6CiAgICAgICAgaWYgc2VsZi5jb2xsZWN0b3IgaXMgTm9uZToKICAgICAgICAgICAgcmV0dXJuIDAKICAgICAgICB3aXRoIHNlbGYuY29sbGVjdG9yLmxvY2s6CiAgICAgICAgICAgIHJldHVybiBsZW4oc2VsZi5jb2xsZWN0b3IuZnJhbWVzKQoKICAgIGRlZiBsYXRlc3RfcmVzdWx0KHNlbGYpOgogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHJldHVybiBzZWxmLl9sYXRlc3QKCiAgICBkZWYgc25hcHNob3Qoc2VsZik6CiAgICAgICAgcmVzdWx0ID0gc2VsZi5sYXRlc3RfcmVzdWx0KCkKICAgICAgICByZXR1cm4gcmVzdWx0LnNuYXBzaG90KHZpc2libGVfb25seT1GYWxzZSkgaWYgcmVzdWx0IGVsc2UgTm9uZQoKICAgIGRlZiBjbG9zZShzZWxmLCB0aW1lb3V0KToKICAgICAgICBkZWFkbGluZSA9IHNlbGYuY2xvY2soKSArIG1heCgwLCB0aW1lb3V0KQogICAgICAgIHNlbGYuc3RvcF9hZG1pc3Npb24oKQogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHNlbGYuX2Nsb3NlZCA9IFRydWUKICAgICAgICAgICAgc2VsZi5fZnJhbWVzLmNsZWFyKCkKICAgICAgICAgICAgc2VsZi5fY3Yubm90aWZ5X2FsbCgpCiAgICAgICAgaWYgc2VsZi5fdGhyZWFkIGlzIG5vdCBOb25lIGFuZCBzZWxmLl90aHJlYWQgaXMgbm90IHRocmVhZGluZy5jdXJyZW50X3RocmVhZCgpOgogICAgICAgICAgICBzZWxmLl90aHJlYWQuam9pbihtYXgoMCwgZGVhZGxpbmUtc2VsZi5jbG9jaygpKSkKICAgICAgICAgICAgaWYgc2VsZi5fdGhyZWFkLmlzX2FsaXZlKCk6CiAgICAgICAgICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoJ011bHRpLXByb3ZpZGVyIGNvb3JkaW5hdG9yIGNsZWFudXAgdGltZWQgb3V0LicpCiAgICAgICAgaWYgc2VsZi50cmFja2VyIGlzIG5vdCBOb25lOgogICAgICAgICAgICBzZWxmLnRyYWNrZXIucmVzZXQoKQogICAgICAgIGlmIHNlbGYucmVnaW9uOgogICAgICAgICAgICBzZWxmLnJlZ2lvbi5jbGVhcigpCiAgICAgICAgaWYgc2VsZi5mYWxsOgogICAgICAgICAgICBzZWxmLmZhbGwuY2xlYXIoKQogICAgICAgIGlmIHNlbGYuZmlnaHQ6CiAgICAgICAgICAgIHNlbGYuZmlnaHQuY2xlYXIoKQogICAgICAgIGlmIHNlbGYuZmlyZToKICAgICAgICAgICAgc2VsZi5maXJlLmNsZWFyKCkKICAgICAgICBpZiBzZWxmLmNyb3dkOgogICAgICAgICAgICBzZWxmLmNyb3dkLmNsb3NlKCkKICAgICAgICBpZiBoYXNhdHRyKHNlbGYuaW5ncmVzcywgJ21ldHJpY3MnKToKICAgICAgICAgICAgc2VsZi5pbmdyZXNzLm1ldHJpY3MuY2xvc2UoKQogICAgICAgIGlmIHNlbGYudmlzdWFsIGlzIG5vdCBOb25lIGFuZCBub3Qgc2VsZi52aXN1YWwuY2xvc2UobWF4KDAsIGRlYWRsaW5lLXNlbGYuY2xvY2soKSkpOgogICAgICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoJ1Zpc3VhbCB3b3JrZXIgY2xlYW51cCB0aW1lZCBvdXQuJykKICAgICAgICBpZiBzZWxmLmFydGlmYWN0cyBpcyBub3QgTm9uZSBhbmQgbm90IHNlbGYuYXJ0aWZhY3RzLmNsb3NlKG1heCgwLCBkZWFkbGluZS1zZWxmLmNsb2NrKCkpKToKICAgICAgICAgICAgcmFpc2UgUnVudGltZUVycm9yKCdBcnRpZmFjdCBjYXB0dXJlIGNsZWFudXAgdGltZWQgb3V0LicpCiAgICAgICAgaWYgc2VsZi5wdWJsaXNoZXIgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIHNlbGYucHVibGlzaGVyLmNoYW5uZWwoCiAgICAgICAgICAgICAgICBzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbMV0sIHNlbGYuaW5ncmVzcy5pZGVudGl0eVszXSwKICAgICAgICAgICAgICAgIHNlbGYuaW5ncmVzcy5pZGVudGl0eVs0XSwgJ0VSUk9SJyBpZiBzZWxmLl9lcnJvciBlbHNlICdTVE9QUEVEJykKICAgICAgICAgICAgaWYgbm90IHNlbGYucHVibGlzaGVyLndhaXRfY2hhbm5lbCgKICAgICAgICAgICAgICAgICAgICBzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbMV0sIHNlbGYuaW5ncmVzcy5pZGVudGl0eVszXSwKICAgICAgICAgICAgICAgICAgICBzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbNF0sIG1heCgwLCBkZWFkbGluZS1zZWxmLmNsb2NrKCkpKToKICAgICAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcignTWV0YWRhdGEgY2hhbm5lbCB3b3JrZXIgY2xlYW51cCBmYWlsZWQgb3IgdGltZWQgb3V0LicpCg==",
    "app/det_result_path.py": "IiIiUElQRUNPUkUtMDEvRlJBTUVSRVNVTFQtMDE6IFNESyBjYWxsYmFja+ydgCDrj4Xrpr0g6rCS66eMIGJvdW5kZWQgcXVldWXsl5Ag64SY6ri064ukLiIiIgoKZnJvbSBjb2xsZWN0aW9ucyBpbXBvcnQgQ291bnRlciwgZGVxdWUKZnJvbSBkYXRhY2xhc3NlcyBpbXBvcnQgcmVwbGFjZQpmcm9tIGFwcC5yZWdpb25fc2NlbmFyaW8gaW1wb3J0IGFsZXJ0ZWQsIGV2ZW50X2lkcywgbWVtYmVycywgdmlzaWJsZSBhcyBzY2VuYXJpb192aXNpYmxlCmltcG9ydCB0aHJlYWRpbmcKaW1wb3J0IHRpbWUKCmZyb20gYXBwLmNvbnRyYWN0cy5mcmFtZXMgaW1wb3J0IERldGVjdGlvbk9ic2VydmF0aW9uLCBQb3NlT2JzZXJ2YXRpb24KZnJvbSBhcHAucG9zZV9jb25maWcgaW1wb3J0IFBFUlNPTl9NT0RFTFMsIFBPU0VfTU9ERUwKZnJvbSBhcHAuZmlyZV9jb25maWcgaW1wb3J0IEZJUkVfTU9ERUwsIEZJUkVfTkFNRVMKZnJvbSBhcHAuY3Jvd2RfY29uZmlnIGltcG9ydCBDUk9XRF9NT0RFTApmcm9tIGFwcC5jb250cmFjdHMudmlzdWFsaXphdGlvbiBpbXBvcnQgVmlzdWFsaXphdGlvbkNvbW1hbmQsIEZyYW1lUmVzdWx0CmZyb20gYXBwLm1ldGFkYXRhX3NhbXBsZXMgaW1wb3J0IE1ldGFkYXRhU2FtcGxlcwoKCmNsYXNzIERldFJlc3VsdFBhdGg6CiAgICBkZWYgX19pbml0X18oc2VsZiwgaW5ncmVzcywgdHJhY2tlciwgbW9kZWxfa2V5LCB0aHJlc2hvbGQsIGNvbGxlY3RvciwKICAgICAgICAgICAgICAgICBpc19jdXJyZW50LCBvbl9lcnJvciwgKiwgcHVibGlzaGVyPU5vbmUsIGNhcGFjaXR5PTMyLCBtYXhfYWdlPTEuMCwKICAgICAgICAgICAgICAgICBjbG9jaz10aW1lLm1vbm90b25pYywgZGlzcGxheV90aHJlc2hvbGQ9Tm9uZSwgdmlzdWFsPU5vbmUsIGludHJ1c2lvbj1Ob25lLAogICAgICAgICAgICAgICAgIHNjZW5hcmlvX3JldmlzaW9uPU5vbmUsIGRpc3BsYXlfY2F0ZWdvcmllcz1Ob25lLCBkZWJ1Z19hbGxfY2FuZGlkYXRlcz1GYWxzZSwgcG9zZV9jb25maWc9Tm9uZSwKICAgICAgICAgICAgICAgICBjYW1lcmFfaWQ9Tm9uZSwgZmlyZT1Ob25lLCBmYWxsPU5vbmUsIGZpZ2h0PU5vbmUsIGNyb3dkPU5vbmUpOgogICAgICAgIGlmIG1vZGVsX2tleSBub3QgaW4gUEVSU09OX01PREVMUyB8IHtGSVJFX01PREVMLCBDUk9XRF9NT0RFTH06CiAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ0Nhbm9uaWNhbCBEZXQgcGF0aCByZXF1aXJlcyBDT0NPIFJGREVUUk1lZGl1bS4nKQogICAgICAgIGlmIG1vZGVsX2tleSA9PSBGSVJFX01PREVMIGFuZCAoaW50cnVzaW9uIGlzIG5vdCBOb25lIG9yIHBvc2VfY29uZmlnIGlzIG5vdCBOb25lKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignRmlyZSBjYW5ub3QgY29uc3VtZSBwZXJzb24gU2NlbmFyaW8vUG9zZSBzZXR0aW5ncy4nKQogICAgICAgIGlmIGZpcmUgaXMgbm90IE5vbmUgYW5kIG1vZGVsX2tleSAhPSBGSVJFX01PREVMOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdGSVJFIHNjZW5hcmlvIHJlcXVpcmVzIHRoZSBGaXJlIHByb3ZpZGVyLicpCiAgICAgICAgaWYgZmlyZSBpcyBub3QgTm9uZSBhbmQgKGludHJ1c2lvbiBpcyBub3QgTm9uZSBvciB0cmFja2VyIGlzIG5vdCBOb25lKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignRklSRSBzY2VuYXJpbyBjYW5ub3QgY29uc3VtZSBwZXJzb24gU2NlbmFyaW8vVHJhY2tpbmcgc3RhdGUuJykKICAgICAgICBpZiBmYWxsIGlzIG5vdCBOb25lIGFuZCAobW9kZWxfa2V5ICE9IFBPU0VfTU9ERUwgb3IgdHJhY2tlciBpcyBOb25lIG9yIGZpcmUgaXMgbm90IE5vbmUpOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdGQUxMIHJlcXVpcmVzIG9uZSBQb3NlIHByb3ZpZGVyIGFuZCBzaGFyZWQgVHJhY2tpbmcuJykKICAgICAgICBpZiBmaWdodCBpcyBub3QgTm9uZSBhbmQgKG1vZGVsX2tleSAhPSBQT1NFX01PREVMIG9yIHRyYWNrZXIgaXMgTm9uZSBvciBmaXJlIGlzIG5vdCBOb25lKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignRklHSFQgcmVxdWlyZXMgb25lIFBvc2UgcHJvdmlkZXIgYW5kIHNoYXJlZCBUcmFja2luZy4nKQogICAgICAgIGlmIChjcm93ZCBpcyBub3QgTm9uZSkgIT0gKG1vZGVsX2tleSA9PSBDUk9XRF9NT0RFTCkgb3IgKGNyb3dkIGlzIG5vdCBOb25lIGFuZCBhbnkoeCBpcyBub3QgTm9uZSBmb3IgeCBpbiAodHJhY2tlcixpbnRydXNpb24sZmFsbCxmaWdodCxmaXJlLHBvc2VfY29uZmlnKSkpOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdDUk9XRCByZXF1aXJlcyBzdGFuZGFsb25lIHByb3ZpZGVyIHdpdGhvdXQgVHJhY2tpbmcuJykKICAgICAgICBpZiBub3QgMCA8PSB0aHJlc2hvbGQgPD0gMSBvciB0eXBlKGNhcGFjaXR5KSBpcyBub3QgaW50IG9yIG5vdCAxIDw9IGNhcGFjaXR5IDw9IDI1NjoKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBEZXQgcXVldWUgc2V0dGluZ3MuJykKICAgICAgICBpZiBub3QgMCA8IG1heF9hZ2UgPCBmbG9hdCgnaW5mJyk6CiAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ0ludmFsaWQgRGV0IHF1ZXVlIGFnZS4nKQogICAgICAgIGlmIHRyYWNrZXIgaXMgTm9uZSBhbmQgaW50cnVzaW9uIGlzIG5vdCBOb25lOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdJTlRSVVNJT04gcmVxdWlyZXMgVHJhY2tpbmcgT24uJykKICAgICAgICBzZWxmLmluZ3Jlc3MsIHNlbGYudHJhY2tlciwgc2VsZi5tb2RlbF9rZXkgPSBpbmdyZXNzLCB0cmFja2VyLCBtb2RlbF9rZXkKICAgICAgICBzZWxmLnRocmVzaG9sZCwgc2VsZi5jb2xsZWN0b3IgPSB0aHJlc2hvbGQsIGNvbGxlY3RvcgogICAgICAgIHNlbGYuZGlzcGxheV90aHJlc2hvbGQgPSB0aHJlc2hvbGQgaWYgZGlzcGxheV90aHJlc2hvbGQgaXMgTm9uZSBlbHNlIGRpc3BsYXlfdGhyZXNob2xkCiAgICAgICAgaWYgdHlwZShzZWxmLmRpc3BsYXlfdGhyZXNob2xkKSBub3QgaW4gKGludCwgZmxvYXQpIG9yIG5vdCAwIDw9IHNlbGYuZGlzcGxheV90aHJlc2hvbGQgPD0gMToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBkaXNwbGF5IHRocmVzaG9sZC4nKQogICAgICAgIHNlbGYudmlzdWFsID0gdmlzdWFsCiAgICAgICAgc2VsZi5wb3NlX2NvbmZpZyA9IHBvc2VfY29uZmlnCiAgICAgICAgc2VsZi5pbnRydXNpb24gPSBpbnRydXNpb24KICAgICAgICBzZWxmLmZpcmUgPSBmaXJlCiAgICAgICAgc2VsZi5mYWxsID0gZmFsbAogICAgICAgIHNlbGYuZmlnaHQsIHNlbGYuY3Jvd2QgPSBmaWdodCwgY3Jvd2QKICAgICAgICBzZWxmLmNhbWVyYV9pZCA9IGNhbWVyYV9pZAogICAgICAgIHNlbGYuYXJ0aWZhY3RzID0gTm9uZQogICAgICAgIHNlbGYuc2NlbmFyaW9fcmV2aXNpb24gPSBzY2VuYXJpb19yZXZpc2lvbgogICAgICAgIGZyb20gYXBwLnN0cmVhbV9zZXR0aW5ncyBpbXBvcnQgZGlzcGxheV9jYXRlZ29yaWVzIGFzIHZhbGlkYXRlX2NhdGVnb3JpZXMKICAgICAgICBzZWxlY3RlZCA9IHZhbGlkYXRlX2NhdGVnb3JpZXMoZGlzcGxheV9jYXRlZ29yaWVzKQogICAgICAgIHNlbGYuZGlzcGxheV9jYXRlZ29yaWVzID0gZnJvemVuc2V0KHNlbGVjdGVkKSBpZiBzZWxlY3RlZCBpcyBub3QgTm9uZSBlbHNlIE5vbmUKICAgICAgICBzZWxmLmRlYnVnX2FsbF9jYW5kaWRhdGVzID0gZGVidWdfYWxsX2NhbmRpZGF0ZXMKICAgICAgICBzZWxmLmlzX2N1cnJlbnQsIHNlbGYub25fZXJyb3IsIHNlbGYucHVibGlzaGVyID0gaXNfY3VycmVudCwgb25fZXJyb3IsIHB1Ymxpc2hlcgogICAgICAgIHNlbGYuY2FwYWNpdHksIHNlbGYubWF4X2FnZSwgc2VsZi5jbG9jayA9IGNhcGFjaXR5LCBtYXhfYWdlLCBjbG9jawogICAgICAgIHNlbGYuX2N2ID0gdGhyZWFkaW5nLkNvbmRpdGlvbigpCiAgICAgICAgc2VsZi5fcXVldWUgPSBkZXF1ZSgpCiAgICAgICAgc2VsZi5fY2xvc2VkID0gRmFsc2UKICAgICAgICBzZWxmLl9sYXN0X3NlcSA9IC0xCiAgICAgICAgc2VsZi5fbWV0cmljcyA9IENvdW50ZXIoKQogICAgICAgIHNlbGYuX2xhdGVzdCA9IE5vbmUKICAgICAgICBzZWxmLl9lcnJvciA9IE5vbmUKICAgICAgICBzZWxmLl90aHJlYWQgPSBOb25lCiAgICAgICAgc2VsZi5fc2FtcGxlcyA9IE1ldGFkYXRhU2FtcGxlcy5mcm9tX2Vudmlyb25tZW50KCkKCiAgICBkZWYgc3RhcnQoc2VsZik6CiAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgaWYgc2VsZi5fY2xvc2VkIG9yIHNlbGYuX3RocmVhZCBpcyBub3QgTm9uZToKICAgICAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcignRGV0IHJlc3VsdCB3b3JrZXIgY2Fubm90IHN0YXJ0IHR3aWNlLicpCiAgICAgICAgICAgIGlmIHNlbGYucHVibGlzaGVyIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgaWYgbm90IHNlbGYucHVibGlzaGVyLmNoYW5uZWwoc2VsZi5pbmdyZXNzLmlkZW50aXR5WzFdLCBzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbM10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbNF0sICdTVEFSVElORycpOgogICAgICAgICAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcignTWV0YWRhdGEgY2hhbm5lbCB3b3JrZXIgYWRtaXNzaW9uIHJlamVjdGVkLicpCiAgICAgICAgICAgIHNlbGYuX3RocmVhZCA9IHRocmVhZGluZy5UaHJlYWQodGFyZ2V0PXNlbGYuX3J1biwgbmFtZT0nZGV0LXJlc3VsdHMnLCBkYWVtb249VHJ1ZSkKICAgICAgICAgICAgc2VsZi5fdGhyZWFkLnN0YXJ0KCkKCiAgICBkZWYgc3VibWl0KHNlbGYsIGZyYW1lLCBjb3BpZWQsIGhhbmRsZT1Ob25lLCAqLCBnYXBfYmVmb3JlPUZhbHNlKToKICAgICAgICBpZiAoZnJhbWUuc2VydmVyX2lkLCBmcmFtZS5zb3VyY2VfaWQsIGZyYW1lLnN0cmVhbV9pZCwgZnJhbWUucnVuX2lkLCBmcmFtZS5ydW5fZ2VuZXJhdGlvbikgIT0gc2VsZi5pbmdyZXNzLmlkZW50aXR5OgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdTdGFsZSBvciBmb3JlaWduIEZyYW1lLicpCiAgICAgICAgaWYgKGZyYW1lLmZyYW1lX3dpZHRoLCBmcmFtZS5mcmFtZV9oZWlnaHQpICE9IChjb3BpZWQud2lkdGgsIGNvcGllZC5oZWlnaHQpOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdOYXRpdmUvaW5ncmVzcyBzb3VyY2UgZGltZW5zaW9ucyBkaWZmZXIuJykKICAgICAgICBpZiBsZW4oY29waWVkLmRldGVjdGlvbnMpID4gMzAwOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdOYXRpdmUgY2FuZGlkYXRlIGxpbWl0IGV4Y2VlZGVkLicpCiAgICAgICAgaWYgc2VsZi5tb2RlbF9rZXkgPT0gRklSRV9NT0RFTCBhbmQgYW55KGQuY2xhc3NfaWQgbm90IGluICgwLDEpIGZvciBkIGluIGNvcGllZC5kZXRlY3Rpb25zKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBGaXJlIGNsYXNzIGlkLicpCiAgICAgICAgb2JzZXJ2YXRpb25zID0gdHVwbGUoRGV0ZWN0aW9uT2JzZXJ2YXRpb24oZnJhbWUsIHNlbGYubW9kZWxfa2V5LCBkLmNsYXNzX2lkLCBkLnNjb3JlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkLmJib3hfeHl4eSkgZm9yIGQgaW4gY29waWVkLmRldGVjdGlvbnMpCiAgICAgICAgcG9zZXMgPSB0dXBsZShQb3NlT2JzZXJ2YXRpb24oZnJhbWUsc2VsZi5tb2RlbF9rZXksZC5zY29yZSxkLmJib3hfeHl4eSxkLmtleXBvaW50cykKICAgICAgICAgICAgICAgICAgICAgIGlmIGQua2V5cG9pbnRzIGlzIG5vdCBOb25lIGVsc2UgTm9uZSBmb3IgZCBpbiBjb3BpZWQuZGV0ZWN0aW9ucykKICAgICAgICBpZiBhbnkoKHAgaXMgbm90IE5vbmUpICE9IChzZWxmLm1vZGVsX2tleSA9PSBQT1NFX01PREVMKSBmb3IgcCBpbiBwb3Nlcyk6CiAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ1Byb3ZpZGVyIG91dHB1dCBjb250cmFjdCBtaXNtYXRjaC4nKQogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIGlmIHNlbGYuX2Nsb3NlZCBvciBub3Qgc2VsZi5pc19jdXJyZW50KCk6CiAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydzdGFsZSddICs9IDEKICAgICAgICAgICAgICAgIHJldHVybiBGYWxzZQogICAgICAgICAgICBpZiBmcmFtZS5mcmFtZV9zZXEgPD0gc2VsZi5fbGFzdF9zZXE6CiAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydvdXRfb2Zfb3JkZXInXSArPSAxCiAgICAgICAgICAgICAgICByZXR1cm4gRmFsc2UKICAgICAgICAgICAgc2VsZi5fbGFzdF9zZXEgPSBmcmFtZS5mcmFtZV9zZXEKICAgICAgICAgICAgaWYgKHNlbGYuZmFsbCBpcyBub3QgTm9uZSBvciBzZWxmLmZpZ2h0IGlzIG5vdCBOb25lIG9yIHNlbGYuY3Jvd2QgaXMgbm90IE5vbmUpIGFuZCBoYXNhdHRyKHNlbGYuaW5ncmVzcywgJ3Jlc3VsdF9nYXAnKToKICAgICAgICAgICAgICAgIGdhcF9iZWZvcmUgPSBzZWxmLmluZ3Jlc3MucmVzdWx0X2dhcChmcmFtZSkgb3IgZ2FwX2JlZm9yZQogICAgICAgICAgICAgICAgaWYgZ2FwX2JlZm9yZToKICAgICAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydmYWxsX3Vwc3RyZWFtX2dhcCddICs9IDEKICAgICAgICAgICAgaWYgbGVuKHNlbGYuX3F1ZXVlKSA9PSBzZWxmLmNhcGFjaXR5OgogICAgICAgICAgICAgICAgc2VsZi5fcXVldWUucG9wbGVmdCgpCiAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydxdWV1ZV9kcm9wJ10gKz0gMQogICAgICAgICAgICAgICAgaWYgc2VsZi5fcXVldWU6CiAgICAgICAgICAgICAgICAgICAgc2VsZi5fcXVldWVbMF0gPSAoKnNlbGYuX3F1ZXVlWzBdWzotMV0sIFRydWUpCiAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgIGdhcF9iZWZvcmUgPSBUcnVlCiAgICAgICAgICAgIHNlbGYuX3F1ZXVlLmFwcGVuZCgoc2VsZi5jbG9jaygpLCBmcmFtZSwgY29waWVkLCBvYnNlcnZhdGlvbnMsIHBvc2VzLCBoYW5kbGUsIGdhcF9iZWZvcmUpKQogICAgICAgICAgICBzZWxmLl9jdi5ub3RpZnkoKQogICAgICAgICAgICByZXR1cm4gVHJ1ZQoKICAgIGRlZiBfcnVuKHNlbGYpOgogICAgICAgIHNraXBwZWRfYmVmb3JlID0gRmFsc2UKICAgICAgICB0cnk6CiAgICAgICAgICAgIHdoaWxlIFRydWU6CiAgICAgICAgICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICAgICAgICAgIHNlbGYuX2N2LndhaXRfZm9yKGxhbWJkYTogc2VsZi5fY2xvc2VkIG9yIHNlbGYuX3F1ZXVlLCAuMjUgaWYgc2VsZi5pbnRydXNpb24gb3Igc2VsZi5jcm93ZCBlbHNlIE5vbmUpCiAgICAgICAgICAgICAgICAgICAgaWYgc2VsZi5fY2xvc2VkOgogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4KICAgICAgICAgICAgICAgICAgICBpdGVtID0gc2VsZi5fcXVldWUucG9wbGVmdCgpIGlmIHNlbGYuX3F1ZXVlIGVsc2UgTm9uZQogICAgICAgICAgICAgICAgIyBTY2VuYXJpbyBzdGF0ZSBpcyB3b3JrZXItb3duZWQ7IGNsb3NlKCkgY2xlYXJzIGl0IG9ubHkgYWZ0ZXIgam9pbi4KICAgICAgICAgICAgICAgIGlmIGl0ZW0gaXMgTm9uZToKICAgICAgICAgICAgICAgICAgICBpZiBzZWxmLmNyb3dkOgogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmNyb3dkLmV4cGlyZV9pZGxlKCkKICAgICAgICAgICAgICAgICAgICBpZiBzZWxmLmludHJ1c2lvbjoKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5pbnRydXNpb24uZXhwaXJlKCkKICAgICAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICAgICAgc3VibWl0dGVkLCBmcmFtZSwgY29waWVkLCBvYnNlcnZhdGlvbnMsIHBvc2VzLCBoYW5kbGUsIGdhcF9iZWZvcmUgPSBpdGVtCiAgICAgICAgICAgICAgICBpZiBub3Qgc2VsZi5pc19jdXJyZW50KCkgb3Igc2VsZi5jbG9jaygpIC0gc3VibWl0dGVkID4gc2VsZi5tYXhfYWdlOgogICAgICAgICAgICAgICAgICAgIGlmIHNlbGYuaW50cnVzaW9uOgogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmludHJ1c2lvbi5leHBpcmUoKQogICAgICAgICAgICAgICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ3N0YWxlJ10gKz0gMQogICAgICAgICAgICAgICAgICAgIHNraXBwZWRfYmVmb3JlID0gVHJ1ZQogICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgICAgICAjIFRoaXMgYWNjZXB0ZWQgRnJhbWUgZmluaXNoZXMgZXZlbnQgaGFuZG9mZiBldmVuIGlmIFN0b3AgYXJyaXZlcyBkdXJpbmcgZXZhbHVhdGlvbi4KICAgICAgICAgICAgICAgICMgY2xvc2UoKSBqb2lucyB0aGlzIHdvcmtlciBiZWZvcmUgY2xvc2luZyBjYXB0dXJlIG9yIHN3aXRjaGluZyB0byBhIG5ldyBydW4uCiAgICAgICAgICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICAgICAgICAgIGlmIHNlbGYuX2Nsb3NlZCBvciBub3Qgc2VsZi5pc19jdXJyZW50KCk6CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgICAgICBnYXBfYmVmb3JlID0gZ2FwX2JlZm9yZSBvciBza2lwcGVkX2JlZm9yZQogICAgICAgICAgICAgICAgc2tpcHBlZF9iZWZvcmUgPSBGYWxzZQogICAgICAgICAgICAgICAgbWV0cmljcyA9IGdldGF0dHIoc2VsZi5pbmdyZXNzLCAnbWV0cmljcycsIE5vbmUpCiAgICAgICAgICAgICAgICBzdGFydGVkX25zID0gdGltZS5tb25vdG9uaWNfbnMoKQogICAgICAgICAgICAgICAgZGV0YWlsID0gbWV0cmljcyBpcyBub3QgTm9uZSBhbmQgbWV0cmljcy5kZXRhaWxfZW5hYmxlZCgpCiAgICAgICAgICAgICAgICBzdGFydGVkX2NwdSA9IHRpbWUudGhyZWFkX3RpbWVfbnMoKSBpZiBkZXRhaWwgZWxzZSAwCiAgICAgICAgICAgICAgICBpZiBtZXRyaWNzOgogICAgICAgICAgICAgICAgICAgIG1ldHJpY3MuZHVyYXRpb24oJ3F1ZXVlJywgaW50KChzZWxmLmNsb2NrKCkgLSBzdWJtaXR0ZWQpICogMWU5KSkKICAgICAgICAgICAgICAgIGlmIHNlbGYuY3Jvd2QgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gc2VsZi5jcm93ZC5wcm9jZXNzKGZyYW1lLCBvYnNlcnZhdGlvbnMsIGdhcF9iZWZvcmU9Z2FwX2JlZm9yZSkKICAgICAgICAgICAgICAgICAgICBpZiByZXN1bHQgaXMgTm9uZToKICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgICAgICB2aXNpYmxlID0ge2lkKGMuZGV0ZWN0aW9uKSBmb3IgYyBpbiByZXN1bHQuY29tbWFuZHN9CiAgICAgICAgICAgICAgICAgICAga2VwdCA9IHR1cGxlKGlkKG8pIGluIHZpc2libGUgZm9yIG8gaW4gb2JzZXJ2YXRpb25zKQogICAgICAgICAgICAgICAgICAgIGlkcywgZXZlbnRzID0gW05vbmVdKmxlbihvYnNlcnZhdGlvbnMpLCByZXN1bHQuZXZlbnRzCiAgICAgICAgICAgICAgICBlbGlmIHNlbGYuZmlyZSBpcyBub3QgTm9uZToKICAgICAgICAgICAgICAgICAgICBzY2VuYXJpb19zdGFydCwgc2NlbmFyaW9fY3B1ID0gdGltZS5tb25vdG9uaWNfbnMoKSwgdGltZS50aHJlYWRfdGltZV9ucygpCiAgICAgICAgICAgICAgICAgICAgZnJvbSBhcHAuZmlyZV9yZXN1bHQgaW1wb3J0IGV2YWx1YXRlX3Jlc3VsdCBhcyBldmFsdWF0ZV9maXJlX3Jlc3VsdAogICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IGV2YWx1YXRlX2ZpcmVfcmVzdWx0KHNlbGYuZmlyZSwgZnJhbWUsIG9ic2VydmF0aW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgY2FtZXJhX2lkPXNlbGYuY2FtZXJhX2lkLCBzY2VuYXJpb19yZXZpc2lvbj1zZWxmLnNjZW5hcmlvX3JldmlzaW9uKQogICAgICAgICAgICAgICAgICAgIGlmIHJlc3VsdCBpcyBOb25lOgogICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICAgICAgICAgIHZpc2libGUgPSB7aWQoY29tbWFuZC5kZXRlY3Rpb24pIGZvciBjb21tYW5kIGluIHJlc3VsdC5jb21tYW5kc30KICAgICAgICAgICAgICAgICAgICBrZXB0ID0gdHVwbGUoaWQob2JzZXJ2YXRpb24pIGluIHZpc2libGUgZm9yIG9ic2VydmF0aW9uIGluIG9ic2VydmF0aW9ucykKICAgICAgICAgICAgICAgICAgICBpZHMgPSBbTm9uZV0gKiBsZW4ob2JzZXJ2YXRpb25zKQogICAgICAgICAgICAgICAgICAgIGV2ZW50cyA9IHJlc3VsdC5ldmVudHMKICAgICAgICAgICAgICAgICAgICBpZiBtZXRyaWNzOgogICAgICAgICAgICAgICAgICAgICAgICBtZXRyaWNzLmR1cmF0aW9uKCdzY2VuYXJpb19jcHUnLCB0aW1lLnRocmVhZF90aW1lX25zKCkgLSBzY2VuYXJpb19jcHUpCiAgICAgICAgICAgICAgICAgICAgICAgIG1ldHJpY3MuZHVyYXRpb24oJ3NjZW5hcmlvJywgdGltZS5tb25vdG9uaWNfbnMoKSAtIHNjZW5hcmlvX3N0YXJ0KQogICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZD10dXBsZShyYW5nZShsZW4ob2JzZXJ2YXRpb25zKSkpCiAgICAgICAgICAgICAgICAgICAgaWYgc2VsZi5wb3NlX2NvbmZpZyBhbmQgc2VsZi5wb3NlX2NvbmZpZy5ubXNfZW5hYmxlZDoKICAgICAgICAgICAgICAgICAgICAgICAgZnJvbSBhcHAucG9zZV9ubXMgaW1wb3J0IHBvc2Vfbm1zX2luZGljZXMKICAgICAgICAgICAgICAgICAgICAgICAgbm1zX3N0YXJ0PXRpbWUubW9ub3RvbmljX25zKCkKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWQ9cG9zZV9ubXNfaW5kaWNlcyhvYnNlcnZhdGlvbnMsc2VsZi5wb3NlX2NvbmZpZy5ubXNfaW91X3RocmVzaG9sZCkKICAgICAgICAgICAgICAgICAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ25tc19jYWxscyddKz0xCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydubXNfZWxhcHNlZF9ucyddKz10aW1lLm1vbm90b25pY19ucygpLW5tc19zdGFydAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljc1snbm1zX3N1cHByZXNzZWQnXSs9bGVuKG9ic2VydmF0aW9ucyktbGVuKHNlbGVjdGVkKQogICAgICAgICAgICAgICAgICAgIHNlbGVjdGVkX3NldD1zZXQoc2VsZWN0ZWQpCiAgICAgICAgICAgICAgICAgICAga2VwdD10dXBsZShpIGluIHNlbGVjdGVkX3NldCBmb3IgaSBpbiByYW5nZShsZW4ob2JzZXJ2YXRpb25zKSkpCiAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRfb2JzZXJ2YXRpb25zPXR1cGxlKG9ic2VydmF0aW9uc1tpXSBmb3IgaSBpbiBzZWxlY3RlZCkKICAgICAgICAgICAgICAgICAgICB0cmFja2luZ19zdGFydD10aW1lLm1vbm90b25pY19ucygpCiAgICAgICAgICAgICAgICAgICAgdHJhY2tpbmdfY3B1ID0gdGltZS50aHJlYWRfdGltZV9ucygpCiAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRfaWRzID0gKHNlbGYudHJhY2tlci51cGRhdGUoc2VsZWN0ZWRfb2JzZXJ2YXRpb25zKSBpZiBzZWxmLnRyYWNrZXIgaXMgbm90IE5vbmUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBbTm9uZV0gKiBsZW4oc2VsZWN0ZWRfb2JzZXJ2YXRpb25zKSkKICAgICAgICAgICAgICAgICAgICBpZHM9W05vbmVdKmxlbihvYnNlcnZhdGlvbnMpCiAgICAgICAgICAgICAgICAgICAgaWYgbGVuKHNlbGVjdGVkX2lkcykhPWxlbihzZWxlY3RlZCk6CiAgICAgICAgICAgICAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ1RyYWNrZXIgY2FuZGlkYXRlIGFzc29jaWF0aW9uIGlzIGluY29tcGxldGUuJykKICAgICAgICAgICAgICAgICAgICBmb3IgaSx0aWQgaW4gemlwKHNlbGVjdGVkLHNlbGVjdGVkX2lkcyk6aWRzW2ldPXRpZAogICAgICAgICAgICAgICAgICAgIHRyYWNraW5nX2NwdSA9IHRpbWUudGhyZWFkX3RpbWVfbnMoKSAtIHRyYWNraW5nX2NwdQogICAgICAgICAgICAgICAgICAgIGlmIG1ldHJpY3M6CiAgICAgICAgICAgICAgICAgICAgICAgIG1ldHJpY3MuZHVyYXRpb24oJ3RyYWNraW5nJywgdGltZS5tb25vdG9uaWNfbnMoKSAtIHRyYWNraW5nX3N0YXJ0KQogICAgICAgICAgICAgICAgICAgICAgICBtZXRyaWNzLmR1cmF0aW9uKCd0cmFja2luZ19jcHUnLCB0cmFja2luZ19jcHUpCiAgICAgICAgICAgICAgICAgICAgaWYgbGVuKGlkcykgIT0gbGVuKG9ic2VydmF0aW9ucyk6CiAgICAgICAgICAgICAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ1RyYWNrZXIgY2FuZGlkYXRlIGFzc29jaWF0aW9uIGlzIGluY29tcGxldGUuJykKICAgICAgICAgICAgICAgICAgICBkZWNpc2lvbnMsIGV2ZW50cyA9ICgoTm9uZSwpKmxlbihvYnNlcnZhdGlvbnMpLCAoKSkKICAgICAgICAgICAgICAgICAgICBpZiBzZWxmLmludHJ1c2lvbjoKICAgICAgICAgICAgICAgICAgICAgICAgc2NlbmFyaW9fc3RhcnQsIHNjZW5hcmlvX2NwdSA9IHRpbWUubW9ub3RvbmljX25zKCksIHRpbWUudGhyZWFkX3RpbWVfbnMoKQogICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZF9kZWNpc2lvbnMsIGV2ZW50cyA9IHNlbGYuaW50cnVzaW9uLmV2YWx1YXRlKGZyYW1lLCBzZWxlY3RlZF9vYnNlcnZhdGlvbnMsIHNlbGVjdGVkX2lkcykKICAgICAgICAgICAgICAgICAgICAgICAgZGVjaXNpb25zPVtOb25lXSpsZW4ob2JzZXJ2YXRpb25zKQogICAgICAgICAgICAgICAgICAgICAgICBmb3IgaSxkIGluIHppcChzZWxlY3RlZCxzZWxlY3RlZF9kZWNpc2lvbnMpOmRlY2lzaW9uc1tpXT1kCiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50cz10dXBsZShyZXBsYWNlKGUsb2JqZWN0X3JlZj1zdHIoc2VsZWN0ZWRbaW50KGUub2JqZWN0X3JlZildKSkgZm9yIGUgaW4gZXZlbnRzKQogICAgICAgICAgICAgICAgICAgICAgICBpZiBtZXRyaWNzOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0cmljcy5kdXJhdGlvbignc2NlbmFyaW9fY3B1JywgdGltZS50aHJlYWRfdGltZV9ucygpIC0gc2NlbmFyaW9fY3B1KQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0cmljcy5kdXJhdGlvbignc2NlbmFyaW8nLCB0aW1lLm1vbm90b25pY19ucygpIC0gc2NlbmFyaW9fc3RhcnQpCiAgICAgICAgICAgICAgICAgICAgZm9yIHNjZW5hcmlvIGluIChzZWxmLmZhbGwsIHNlbGYuZmlnaHQpOgogICAgICAgICAgICAgICAgICAgICAgICBpZiBzY2VuYXJpbyBpcyBOb25lOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgICAgICAgICAgc2NlbmFyaW9fc3RhcnQsIHNjZW5hcmlvX2NwdSA9IHRpbWUubW9ub3RvbmljX25zKCksIHRpbWUudGhyZWFkX3RpbWVfbnMoKQogICAgICAgICAgICAgICAgICAgICAgICBmYWxsX2RlY2lzaW9ucywgZmFsbF9ldmVudHMgPSBzY2VuYXJpby5ldmFsdWF0ZShmcmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR1cGxlKHBvc2VzW2ldIGZvciBpIGluIHNlbGVjdGVkKSwgc2VsZWN0ZWRfaWRzLCBnYXBfYmVmb3JlPWdhcF9iZWZvcmUpCiAgICAgICAgICAgICAgICAgICAgICAgIGRlY2lzaW9ucyA9IGxpc3QoZGVjaXNpb25zKQogICAgICAgICAgICAgICAgICAgICAgICBmb3IgaW5kZXgsIGRlY2lzaW9uIGluIHppcChzZWxlY3RlZCwgZmFsbF9kZWNpc2lvbnMpOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjaXNpb25zW2luZGV4XSA9ICgqbWVtYmVycyhkZWNpc2lvbnNbaW5kZXhdKSwgKm1lbWJlcnMoZGVjaXNpb24pKQogICAgICAgICAgICAgICAgICAgICAgICBldmVudHMgKz0gdHVwbGUocmVwbGFjZShlLCBvYmplY3RfcmVmPXN0cihzZWxlY3RlZFtpbnQoZS5vYmplY3RfcmVmKV0pKSBmb3IgZSBpbiBmYWxsX2V2ZW50cykKICAgICAgICAgICAgICAgICAgICAgICAgaWYgbWV0cmljczoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldHJpY3MuZHVyYXRpb24oJ3NjZW5hcmlvX2NwdScsIHRpbWUudGhyZWFkX3RpbWVfbnMoKSAtIHNjZW5hcmlvX2NwdSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldHJpY3MuZHVyYXRpb24oJ3NjZW5hcmlvJywgdGltZS5tb25vdG9uaWNfbnMoKSAtIHNjZW5hcmlvX3N0YXJ0KQogICAgICAgICAgICAgICAgICAgIGNvbW1hbmRzID0gdHVwbGUoVmlzdWFsaXphdGlvbkNvbW1hbmQobywgc2VsZi5fbGFiZWwoby5jbGFzc19pZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj0nI0ZGMzAzMCcgaWYgYWxlcnRlZChkKSBlbHNlICcjMDBDQzY2JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpc2libGU9a2VlcCBhbmQgKHNjZW5hcmlvX3Zpc2libGUoby5zY29yZSwgZCkgaWYgZCBlbHNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoby5zY29yZSA+PSBzZWxmLnBvc2VfY29uZmlnLnBlcnNvbl9zY29yZSBpZiBzZWxmLnBvc2VfY29uZmlnIGVsc2Ugby5zY29yZSA+IHNlbGYuZGlzcGxheV90aHJlc2hvbGQpIGFuZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHNlbGYuZGlzcGxheV9jYXRlZ29yaWVzIGlzIE5vbmUgb3Igc2VsZi5fbGFiZWwoby5jbGFzc19pZCkgaW4gc2VsZi5kaXNwbGF5X2NhdGVnb3JpZXMpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNrX2lkPXRpZCwgZXZlbnRfaWRzPWV2ZW50X2lkcyhkKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjZW5hcmlvPWQsIHBvc2U9cCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBvLCB0aWQsIGQsIHAsIGtlZXAgaW4gemlwKG9ic2VydmF0aW9ucywgaWRzLCBkZWNpc2lvbnMsIHBvc2VzLCBrZXB0KSkKICAgICAgICAgICAgICAgICAgICBjb25maWdzID0gbWVtYmVycyhzZWxmLmludHJ1c2lvbi5jb25maWcgaWYgc2VsZi5pbnRydXNpb24gZWxzZSBOb25lKQogICAgICAgICAgICAgICAgICAgIGlmIHNlbGYuZmFsbCBpcyBub3QgTm9uZToKICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlncyArPSAoc2VsZi5mYWxsLmNvbmZpZywpCiAgICAgICAgICAgICAgICAgICAgaWYgc2VsZi5maWdodCBpcyBub3QgTm9uZToKICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlncyArPSAoc2VsZi5maWdodC5jb25maWcsKQogICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IEZyYW1lUmVzdWx0KGZyYW1lLCBjb21tYW5kcywgZXZlbnRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZ3MgaWYgbGVuKGNvbmZpZ3MpID4gMSBlbHNlIGNvbmZpZ3NbMF0gaWYgY29uZmlncyBlbHNlIE5vbmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5zY2VuYXJpb19yZXZpc2lvbiwgc2VsZi5kZWJ1Z19hbGxfY2FuZGlkYXRlcywgc2VsZi5wb3NlX2NvbmZpZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXB0IGlmIHNlbGYucG9zZV9jb25maWcgZWxzZSBOb25lLCBwcm92aWRlcl9tb2RlbD1zZWxmLm1vZGVsX2tleSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYW1lcmFfaWQ9c2VsZi5jYW1lcmFfaWQpCiAgICAgICAgICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICAgICAgICAgIGlmIHNlbGYuX2Nsb3NlZCBvciBub3Qgc2VsZi5pc19jdXJyZW50KCk6CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIHNlbGYuZmFsbCBpcyBOb25lIGFuZCBzZWxmLmZpZ2h0IGlzIE5vbmUgYW5kIG5vdCAoc2VsZi5jcm93ZCBhbmQgcmVzdWx0LmV2ZW50cyk6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX2xhdGVzdCA9IHJlc3VsdAogICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ2V2ZW50c19jcmVhdGVkJ10gKz0gbGVuKGV2ZW50cykKICAgICAgICAgICAgICAgIGlmIHNlbGYuX3NhbXBsZXMgaXMgbm90IE5vbmUgYW5kIHNlbGYuX3NhbXBsZXMuZW5hYmxlZCgpOgogICAgICAgICAgICAgICAgICAgIHNlbGYuX3NhbXBsZXMuY2FwdHVyZShyZXN1bHQuc25hcHNob3QodmlzaWJsZV9vbmx5PUZhbHNlKSkKICAgICAgICAgICAgICAgIGlmIHNlbGYudmlzdWFsIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgICAgIHNlbGYudmlzdWFsLnN1Ym1pdF9yZXN1bHQocmVzdWx0KQogICAgICAgICAgICAgICAgaWYgc2VsZi5hcnRpZmFjdHMgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICAgICAgYWNjZXB0ZWQgPSBzZWxmLmFydGlmYWN0cy5zdWJtaXQocmVzdWx0KQogICAgICAgICAgICAgICAgICAgIGlmIGFjY2VwdGVkIGlzIEZhbHNlIGFuZCBhbnkoZS5wYXlsb2FkKClbJ3NjZW5hcmlvJ10gaW4gKCdGQUxMJywnRklHSFQnLCdDUk9XRCcpIGZvciBlIGluIGV2ZW50cyk6CiAgICAgICAgICAgICAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcignRkFMTCBFdmVudCBoYW5kb2ZmIHJlamVjdGVkLicpCiAgICAgICAgICAgICAgICBpdGVtcyA9IFtkaWN0KGQuZG93bnN0cmVhbSgpLCB0cmFja19pZD10aWQpCiAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgZCwgdGlkLCBrZWVwIGluIHppcChjb3BpZWQuZGV0ZWN0aW9ucywgaWRzLCBrZXB0KSBpZiBrZWVwIGFuZCBkLnNjb3JlID4gc2VsZi50aHJlc2hvbGRdCiAgICAgICAgICAgICAgICAjIERldC1vbmx5IGNvbXBhdGliaWxpdHkgY29sbGVjdG9yLiBQb3NlIGpvaW7snYAg7J20IGtleeulvCDsgqzsmqntlZjsp4Ag7JWK64qU64ukLgogICAgICAgICAgICAgICAgY29sbGVjdG9yX2ZyYW1lcyA9IHNlbGYuY29sbGVjdG9yLmFkZCgncG9zZScgaWYgc2VsZi5tb2RlbF9rZXk9PVBPU0VfTU9ERUwgZWxzZSAnZGV0JywgZnJhbWUuZnJhbWVfc2VxLCBmcmFtZS5wdHNfbnMgb3IgMCwKICAgICAgICAgICAgICAgICAgICB7J3cnOiBmcmFtZS5mcmFtZV93aWR0aCwgJ2gnOiBmcmFtZS5mcmFtZV9oZWlnaHQsICdjb3VudCc6IGxlbihpdGVtcyksCiAgICAgICAgICAgICAgICAgICAgICdpdGVtcyc6IGl0ZW1zLCAnZnJhbWUnOiBmcmFtZX0sIG1heF9mcmFtZXM9MTAwMCwgbWV0cmljcz1tZXRyaWNzKQogICAgICAgICAgICAgICAgaWYgZGV0YWlsOgogICAgICAgICAgICAgICAgICAgIHB1Ymxpc2hfc3RhcnQsIHB1Ymxpc2hfY3B1ID0gdGltZS5tb25vdG9uaWNfbnMoKSwgdGltZS50aHJlYWRfdGltZV9ucygpCiAgICAgICAgICAgICAgICBpZiBzZWxmLnB1Ymxpc2hlciBpcyBub3QgTm9uZToKICAgICAgICAgICAgICAgICAgICBpZiBtZXRyaWNzOgogICAgICAgICAgICAgICAgICAgICAgICBtZXRyaWNzLm1hcmsoJ3Jlc3VsdCcsIChjb3BpZWQuZnJhbWVfbnVtYmVyLCBjb3BpZWQucHRzKSkKICAgICAgICAgICAgICAgICAgICBhY2NlcHRlZCA9IHNlbGYucHVibGlzaGVyLmNoYW5uZWwoZnJhbWUuc291cmNlX2lkLCBmcmFtZS5ydW5faWQsIGZyYW1lLnJ1bl9nZW5lcmF0aW9uLCAnUlVOTklORycpCiAgICAgICAgICAgICAgICAgICAgaWYgbm90IGFjY2VwdGVkIG9yIG5vdCBzZWxmLnB1Ymxpc2hlci5zdWJtaXQocmVzdWx0LnNuYXBzaG90KCkpOgogICAgICAgICAgICAgICAgICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljc1sncHVibGlzaGVyX3JlamVjdGVkJ10gKz0gMQogICAgICAgICAgICAgICAgICAgIGVsaWYgbWV0cmljczoKICAgICAgICAgICAgICAgICAgICAgICAgbWV0cmljcy5tYXJrKCdwdWJsaXNoZXJfc3VibWl0JywgKGNvcGllZC5mcmFtZV9udW1iZXIsIGNvcGllZC5wdHMpKQogICAgICAgICAgICAgICAgZWxpZiBtZXRyaWNzOgogICAgICAgICAgICAgICAgICAgIG1ldHJpY3MubWFyaygncmVzdWx0JywgKGNvcGllZC5mcmFtZV9udW1iZXIsIGNvcGllZC5wdHMpKQogICAgICAgICAgICAgICAgaWYgZGV0YWlsOgogICAgICAgICAgICAgICAgICAgIG1ldHJpY3MuZHVyYXRpb24oJ3Jlc3VsdF9wdWJsaXNoJywgdGltZS5tb25vdG9uaWNfbnMoKSAtIHB1Ymxpc2hfc3RhcnQpCiAgICAgICAgICAgICAgICAgICAgbWV0cmljcy5kdXJhdGlvbigncmVzdWx0X3B1Ymxpc2hfY3B1JywgdGltZS50aHJlYWRfdGltZV9ucygpIC0gcHVibGlzaF9jcHUpCiAgICAgICAgICAgICAgICAgICAgbWV0cmljcy5kdXJhdGlvbigncmVzdWx0X3dvcmtfY3B1JywgdGltZS50aHJlYWRfdGltZV9ucygpIC0gc3RhcnRlZF9jcHUpCiAgICAgICAgICAgICAgICBpZiBtZXRyaWNzOgogICAgICAgICAgICAgICAgICAgIG1ldHJpY3MuZHVyYXRpb24oJ3Jlc3VsdF93b3JrJywgdGltZS5tb25vdG9uaWNfbnMoKSAtIHN0YXJ0ZWRfbnMpCiAgICAgICAgICAgICAgICBpZiBkZXRhaWw6CiAgICAgICAgICAgICAgICAgICAgbGlmZWN5Y2xlX3N0YXJ0LCBsaWZlY3ljbGVfY3B1ID0gdGltZS5tb25vdG9uaWNfbnMoKSwgdGltZS50aHJlYWRfdGltZV9ucygpCiAgICAgICAgICAgICAgICBpZiBoYW5kbGUgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICAgICAgaGFuZGxlLm1hcmtfc291cmNlX3N0YWdlKCdpbmZlcmVuY2VfZnJhbWVfY29tcGxldGVkJykKICAgICAgICAgICAgICAgICAgICBoYW5kbGUubWFya19mcmFtZShkZXRlY3Rpb25fY291bnQ9bGVuKGl0ZW1zKSkKICAgICAgICAgICAgICAgIGlmIGRldGFpbDoKICAgICAgICAgICAgICAgICAgICBtZXRyaWNzLmR1cmF0aW9uKCdyZXN1bHRfbGlmZWN5Y2xlJywgdGltZS5tb25vdG9uaWNfbnMoKSAtIGxpZmVjeWNsZV9zdGFydCkKICAgICAgICAgICAgICAgICAgICBtZXRyaWNzLmR1cmF0aW9uKCdyZXN1bHRfbGlmZWN5Y2xlX2NwdScsIHRpbWUudGhyZWFkX3RpbWVfbnMoKSAtIGxpZmVjeWNsZV9jcHUpCiAgICAgICAgICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICAgICAgICAgIGlmIHR5cGUoY29sbGVjdG9yX2ZyYW1lcykgaXMgaW50OgogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydjb2xsZWN0b3JfZnJhbWVzJ10gPSBjb2xsZWN0b3JfZnJhbWVzCiAgICAgICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljc1sncHJvY2Vzc2VkJ10gKz0gMQogICAgICAgIGV4Y2VwdCBFeGNlcHRpb246CiAgICAgICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgICAgICBzZWxmLl9lcnJvciA9ICdERVRfUkVTVUxUX0ZBSUxFRCcKICAgICAgICAgICAgICAgIHNlbGYuX3F1ZXVlLmNsZWFyKCkKICAgICAgICAgICAgICAgIHNlbGYuX2Nsb3NlZCA9IFRydWUKICAgICAgICAgICAgc2VsZi5vbl9lcnJvcigpCgogICAgZGVmIF9sYWJlbChzZWxmLCBjbGFzc19pZCk6CiAgICAgICAgaWYgc2VsZi5tb2RlbF9rZXkgPT0gRklSRV9NT0RFTDoKICAgICAgICAgICAgcmV0dXJuIEZJUkVfTkFNRVNbY2xhc3NfaWRdCiAgICAgICAgZnJvbSBhcHAuY2xhc3NfY2F0YWxvZyBpbXBvcnQgY29jb19uYW1lCiAgICAgICAgcmV0dXJuIGNvY29fbmFtZShjbGFzc19pZCkKCiAgICBkZWYgc25hcHNob3Qoc2VsZik6CiAgICAgICAgcmVzdWx0ID0gc2VsZi5sYXRlc3RfcmVzdWx0KCkKICAgICAgICByZXR1cm4gcmVzdWx0LnNuYXBzaG90KHZpc2libGVfb25seT1GYWxzZSkgaWYgcmVzdWx0IGVsc2UgTm9uZQoKICAgIGRlZiBsYXRlc3RfcmVzdWx0KHNlbGYpOgogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHJldHVybiBzZWxmLl9sYXRlc3QKCiAgICBkZWYgc3RhdHVzKHNlbGYpOgogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHJldHVybiBkaWN0KHN0YXRlPSdFUlJPUicgaWYgc2VsZi5fZXJyb3IgZWxzZSAoJ1NUT1BQRUQnIGlmIHNlbGYuX2Nsb3NlZCBlbHNlCiAgICAgICAgICAgICAgICAgICAgICAgICgnQ09OTkVDVEVEJyBpZiBzZWxmLl9tZXRyaWNzWydwcm9jZXNzZWQnXSBlbHNlICdQUkVQQVJFRCcpKSwKICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3I9c2VsZi5fZXJyb3IsIGRpc3BsYXlfdGhyZXNob2xkPXNlbGYuZGlzcGxheV90aHJlc2hvbGQsCiAgICAgICAgICAgICAgICAgICAgICAgIHZpc3VhbD1zZWxmLnZpc3VhbC5zdGF0dXMoKSBpZiBzZWxmLnZpc3VhbCBlbHNlIE5vbmUsCiAgICAgICAgICAgICAgICAgICAgICAgIGFydGlmYWN0cz1zZWxmLmFydGlmYWN0cy5zdGF0dXMoKSBpZiBzZWxmLmFydGlmYWN0cyBlbHNlIE5vbmUsCiAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZV9lcnJvcj1zZWxmLl9zYW1wbGVzLmVycm9yIGlmIHNlbGYuX3NhbXBsZXMgZWxzZSBOb25lLAogICAgICAgICAgICAgICAgICAgICAgICBwZXJmb3JtYW5jZT1zZWxmLmluZ3Jlc3MubWV0cmljcy5zbmFwc2hvdCgpIGlmIGhhc2F0dHIoc2VsZi5pbmdyZXNzLCAnbWV0cmljcycpIGVsc2UgTm9uZSwKICAgICAgICAgICAgICAgICAgICAgICAgZmlyZV9tZXRyaWNzPWRpY3Qoc2VsZi5maXJlLm1ldHJpY3MpIGlmIHNlbGYuZmlyZSBpcyBub3QgTm9uZSBlbHNlIE5vbmUsCiAgICAgICAgICAgICAgICAgICAgICAgIHF1ZXVlZD1sZW4oc2VsZi5fcXVldWUpLCAqKnNlbGYuX21ldHJpY3MpCgogICAgZGVmIGNsb3NlKHNlbGYsIHRpbWVvdXQpOgogICAgICAgIGRlYWRsaW5lID0gdGltZS5tb25vdG9uaWMoKSArIG1heCgwLCB0aW1lb3V0KQogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHNlbGYuX2Nsb3NlZCA9IFRydWUKICAgICAgICAgICAgc2VsZi5fcXVldWUuY2xlYXIoKQogICAgICAgICAgICBzZWxmLl9sYXRlc3QgPSBOb25lCiAgICAgICAgICAgIHNlbGYuX2N2Lm5vdGlmeV9hbGwoKQogICAgICAgIGlmIHNlbGYuX3RocmVhZCBpcyBub3QgTm9uZToKICAgICAgICAgICAgc2VsZi5fdGhyZWFkLmpvaW4obWF4KDAsIHRpbWVvdXQpKQogICAgICAgICAgICBpZiBzZWxmLl90aHJlYWQuaXNfYWxpdmUoKToKICAgICAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcignRGV0IHJlc3VsdCB3b3JrZXIgY2xlYW51cCB0aW1lZCBvdXQuJykKICAgICAgICBpZiBzZWxmLnRyYWNrZXIgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIHNlbGYudHJhY2tlci5yZXNldCgpCiAgICAgICAgaWYgc2VsZi5pbnRydXNpb246CiAgICAgICAgICAgIHNlbGYuaW50cnVzaW9uLmNsZWFyKCkKICAgICAgICBpZiBzZWxmLmZpcmU6CiAgICAgICAgICAgIHNlbGYuZmlyZS5jbGVhcigpCiAgICAgICAgaWYgc2VsZi5mYWxsOgogICAgICAgICAgICBzZWxmLmZhbGwuY2xlYXIoKQogICAgICAgIGlmIHNlbGYuZmlnaHQ6CiAgICAgICAgICAgIHNlbGYuZmlnaHQuY2xlYXIoKQogICAgICAgIGlmIHNlbGYuY3Jvd2Q6CiAgICAgICAgICAgIHNlbGYuY3Jvd2QuY2xvc2UoKQogICAgICAgIGlmIGhhc2F0dHIoc2VsZi5pbmdyZXNzLCAnbWV0cmljcycpOgogICAgICAgICAgICBzZWxmLmluZ3Jlc3MubWV0cmljcy5jbG9zZSgpCiAgICAgICAgaWYgc2VsZi52aXN1YWwgaXMgbm90IE5vbmUgYW5kIG5vdCBzZWxmLnZpc3VhbC5jbG9zZShtYXgoMCwgZGVhZGxpbmUgLSB0aW1lLm1vbm90b25pYygpKSk6CiAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcignVmlzdWFsIHdvcmtlciBjbGVhbnVwIHRpbWVkIG91dC4nKQogICAgICAgIGlmIHNlbGYuYXJ0aWZhY3RzIGlzIG5vdCBOb25lIGFuZCBub3Qgc2VsZi5hcnRpZmFjdHMuY2xvc2UobWF4KDAsIGRlYWRsaW5lIC0gdGltZS5tb25vdG9uaWMoKSkpOgogICAgICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoJ0FydGlmYWN0IGNhcHR1cmUgY2xlYW51cCB0aW1lZCBvdXQuJykKICAgICAgICBpZiBzZWxmLnB1Ymxpc2hlciBpcyBub3QgTm9uZToKICAgICAgICAgICAgc2VsZi5wdWJsaXNoZXIuY2hhbm5lbChzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbMV0sIHNlbGYuaW5ncmVzcy5pZGVudGl0eVszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbNF0sICdFUlJPUicgaWYgc2VsZi5fZXJyb3IgZWxzZSAnU1RPUFBFRCcpCiAgICAgICAgICAgIGlmIG5vdCBzZWxmLnB1Ymxpc2hlci53YWl0X2NoYW5uZWwoc2VsZi5pbmdyZXNzLmlkZW50aXR5WzFdLCBzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbM10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5pbmdyZXNzLmlkZW50aXR5WzRdLCBtYXgoMCwgZGVhZGxpbmUgLSB0aW1lLm1vbm90b25pYygpKSk6CiAgICAgICAgICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoJ01ldGFkYXRhIGNoYW5uZWwgd29ya2VyIGNsZWFudXAgZmFpbGVkIG9yIHRpbWVkIG91dC4nKQo="
  },
  "settings": {
    "configured": {
      "enabled": true,
      "person_score": 0.25,
      "joint_score": 0.1,
      "pair_distance_ratio": 1.8,
      "pair_close_hold_seconds": 0.1,
      "arm_motion_window_seconds": 1.0,
      "arm_motion_ratio": 0.1,
      "toward_opponent_ratio": 0.01,
      "fight_window_seconds": 1.5,
      "required_bursts": 1,
      "burst_min_interval_seconds": 0.25,
      "rearm_quiet_seconds": 2.0,
      "pair_retention_seconds": 5.0,
      "max_people": 32,
      "max_pairs": 128,
      "history_capacity": 64,
      "roi_id": "primary",
      "roi_name": "Fight ROI",
      "debug_roi": true,
      "roi": [
        [
          0.0,
          0.0
        ],
        [
          1.0,
          0.0
        ],
        [
          1.0,
          1.0
        ],
        [
          0.0,
          1.0
        ]
      ],
      "engine": "r5",
      "r5": {
        "schema_version": 1,
        "window_seconds": 1.0,
        "min_samples": 2,
        "contact_min_samples": 3
      }
    },
    "effective": {
      "enabled": true,
      "person_score": 0.25,
      "joint_score": 0.1,
      "pair_distance_ratio": 1.8,
      "pair_close_hold_seconds": 0.1,
      "arm_motion_window_seconds": 1.0,
      "arm_motion_ratio": 0.1,
      "toward_opponent_ratio": 0.01,
      "fight_window_seconds": 1.5,
      "required_bursts": 1,
      "burst_min_interval_seconds": 0.25,
      "rearm_quiet_seconds": 2.0,
      "pair_retention_seconds": 5.0,
      "max_people": 32,
      "max_pairs": 128,
      "history_capacity": 64,
      "roi_id": "primary",
      "roi_name": "Fight ROI",
      "debug_roi": true,
      "roi": [
        [
          0.0,
          0.0
        ],
        [
          1.0,
          0.0
        ],
        [
          1.0,
          1.0
        ],
        [
          0.0,
          1.0
        ]
      ],
      "engine": "r5",
      "r5": {
        "schema_version": 1,
        "window_seconds": 1.0,
        "min_samples": 2,
        "contact_min_samples": 3
      }
    },
    "restart_pending": false
  },
  "configs": {
    "CONTEXTRA_CONTROL_TEMPLATE_FILE": {
      "sha256": "f35ab1a3153590dd12b201e15c3de35e6e0398151d9262c89710aedc600269f7",
      "channels": [
        {
          "camera": null,
          "fight": {
            "enabled": false,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": null
        }
      ]
    },
    "STREAMS_CONFIG_PATH": {
      "sha256": "bc7c4b827c24110ca7a0eed2655486d1ca0e3ad48a93dcf7580657ed935eacc8",
      "channels": []
    },
    "STREAMS_RUNTIME_PATH": {
      "sha256": "f7941f6e03190591dcb1c3c39ee23df3d625efb168fd7f2efcdbeb10b57f831d",
      "channels": [
        {
          "camera": 1,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.3,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 2,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.3,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 4,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.3,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 5,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.3,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 12,
          "fight": {
            "enabled": false,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 3,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.3,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 17,
          "fight": {
            "enabled": false,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 13,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.3,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 14,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.3,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 28,
          "fight": {
            "enabled": false,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 26,
          "fight": {
            "enabled": false,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 27,
          "fight": {
            "enabled": false,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 22,
          "fight": {
            "enabled": false,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 23,
          "fight": {
            "enabled": false,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 29,
          "fight": {
            "enabled": false,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 24,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 6,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 8,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 9,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 10,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 11,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 7,
          "fight": {
            "enabled": false,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 15,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 16,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 18,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 19,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 21,
          "fight": {
            "enabled": true,
            "person_score": 0.25,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 20,
          "fight": {
            "enabled": true,
            "person_score": 0.35,
            "joint_score": 0.1,
            "pair_distance_ratio": 1.8,
            "pair_close_hold_seconds": 0.1,
            "arm_motion_window_seconds": 1.0,
            "arm_motion_ratio": 0.1,
            "toward_opponent_ratio": 0.01,
            "fight_window_seconds": 1.5,
            "required_bursts": 1,
            "burst_min_interval_seconds": 0.25,
            "rearm_quiet_seconds": 2.0,
            "pair_retention_seconds": 5.0,
            "max_people": 32,
            "max_pairs": 128,
            "history_capacity": 64,
            "roi_id": "primary",
            "roi_name": "Fight ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ],
            "engine": "r5",
            "r5": {
              "schema_version": 1,
              "window_seconds": 1.0,
              "min_samples": 2,
              "contact_min_samples": 3
            }
          },
          "cooldown": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        }
      ]
    }
  },
  "camera24": {
    "cameraId": "24",
    "streamId": "camera-1fdaa47a21ac5365934a42c53f6d327f",
    "runId": "f750a06a-51d7-4401-a106-be1ff413e499",
    "runGeneration": 4,
    "desiredState": "RUNNING",
    "observedState": "RUNNING",
    "lastError": null
  },
  "images": {
    "analytics": "sha256:54ce2980ed2b0296c1a873daa3794c6aec2572304d42e49749505c0e12ea44bc",
    "ai-control-sidecar": "sha256:9afaf2830398090fa8a7f10fb1349106fda8ae41750f83588589a40db9094820",
    "ai-gateway": "sha256:f9b672d8b5beffd4b705339fdeb4494f73604899eafef23e99f90590761f8239",
    "redis": "sha256:8231d3786e10c470840c27963f3d19672dc7ef3e5d5adc512c01d44faada5672",
    "postgresql": "sha256:26ff894de07212639974012ba2be1fc8b1a6dc6a7b18035c35c48fd26092c0a9"
  },
  "free_root": 211703128064
}