{
  "files": {
    "app/fall_runtime.py": "IiIiRkFMTC1XSVJFLTAxOiBsb2NhbCBST0kvZGVjaXNpb24gYWRhcHRlcjsgb25lIG93bmVyLCBubyB0cmFja2VyIG9yIGRlbGl2ZXJ5IEkvTy4iIiIKZnJvbSBkYXRhY2xhc3NlcyBpbXBvcnQgZGF0YWNsYXNzLCBmaWVsZHMKaW1wb3J0IG9zCmltcG9ydCB0aW1lCmltcG9ydCB1dWlkCgpmcm9tIGFwcC5mYWxsX2NvbmZpZyBpbXBvcnQgRmFsbENvbmZpZwpmcm9tIGFwcC5mYWxsX3NjZW5hcmlvIGltcG9ydCBGYWxsRW5naW5lCmZyb20gYXBwLmludHJ1c2lvbiBpbXBvcnQgSW50cnVzaW9uQ29uZmlnLCBJbnRydXNpb25FdmVudCwgaW5zaWRlCgojIFNlcHRlbWJlciBkZW1vIGRlZmF1bHRzIGZvciBleGlzdGluZyBzZXR0aW5ncyBrZXlzIG9ubHk7IGV4cGxpY2l0IHZhbHVlcyB3aW4uCiMgS2VlcCBGYWxsQ29uZmlnIGRlZmF1bHRzIGFzIHRoZSByZXByb2R1Y2libGUgcHJlLWRlbW8gdGVtcG9yYWwgcG9saWN5LgpERU1PX0ZBTExfREVGQVVMVFMgPSBkaWN0KHBlcnNvbl9zY29yZT0uMTUsIGpvaW50X3Njb3JlPS4xMCwgZG93bl9hbmdsZV9kZWc9NTAuKQoKCkBkYXRhY2xhc3MoZnJvemVuPVRydWUpCmNsYXNzIEZhbGxTZXR0aW5nczoKICAgIHBvbGljeTogRmFsbENvbmZpZwogICAgZ2VvbWV0cnk6IEludHJ1c2lvbkNvbmZpZwogICAgc2NlbmFyaW9fbmFtZSA9ICdGQUxMJwoKICAgIEBjbGFzc21ldGhvZAogICAgZGVmIHBhcnNlKGNscywgdmFsdWUpOgogICAgICAgIGlmIHR5cGUodmFsdWUpIGlzIG5vdCBkaWN0OgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdJbnZhbGlkIEZBTEwgc2V0dGluZ3MuJykKICAgICAgICBuYW1lcyA9IHtmLm5hbWUgZm9yIGYgaW4gZmllbGRzKEZhbGxDb25maWcpfQogICAgICAgIHJvaV9uYW1lcyA9IHsncm9pJywgJ3JvaV9pZCcsICdyb2lfbmFtZScsICdkZWJ1Z19yb2knfQogICAgICAgIGlmIHNldCh2YWx1ZSkgLSBuYW1lcyAtIHJvaV9uYW1lczoKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBGQUxMIHNldHRpbmdzIGZpZWxkcy4nKQogICAgICAgIHZhbHVlcyA9IGRpY3QoREVNT19GQUxMX0RFRkFVTFRTLCAqKntrOiB2IGZvciBrLCB2IGluIHZhbHVlLml0ZW1zKCkgaWYgayBpbiBuYW1lc30pCiAgICAgICAgIyBTaXRlIGRlZmF1bHQgYXBwbGllcyBvbmx5IHRvIGFic2VudCB2YWx1ZXM7IGFuIGV4cGxpY2l0IHBlci1jYW1lcmEgT2ZmIHdpbnMuCiAgICAgICAgZGVmYXVsdCA9IG9zLmVudmlyb24uZ2V0KCdDT05URVhUUkFfRkFMTF9TS0lQX0RPV05fSE9MRF9ERUZBVUxUJywgJ3RydWUnKQogICAgICAgIGlmIGRlZmF1bHQgbm90IGluICgndHJ1ZScsICdmYWxzZScpOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdJbnZhbGlkIEZBTEwgc2l0ZSBkZWZhdWx0LicpCiAgICAgICAgdmFsdWVzLnNldGRlZmF1bHQoJ3Rlc3Rfc2tpcF9kb3duX2hvbGQnLCBkZWZhdWx0ID09ICd0cnVlJykKICAgICAgICBwb2xpY3kgPSBGYWxsQ29uZmlnLnBhcnNlKHZhbHVlcykKICAgICAgICByb2kgPSB2YWx1ZS5nZXQoJ3JvaScpCiAgICAgICAgZ2VvbWV0cnkgPSBJbnRydXNpb25Db25maWcoZW5hYmxlZD1wb2xpY3kuZW5hYmxlZCwgY29uZmlkZW5jZT1wb2xpY3kucGVyc29uX3Njb3JlLAogICAgICAgICAgICByb2k9KCgwLiwgMC4pLCAoMS4sIDAuKSwgKDEuLCAxLiksICgwLiwgMS4pKSBpZiByb2kgaXMgTm9uZSBvciByb2kgPT0gW10gZWxzZSByb2ksCiAgICAgICAgICAgIHJvaV9pZD12YWx1ZS5nZXQoJ3JvaV9pZCcsICdwcmltYXJ5JyksIHJvaV9uYW1lPXZhbHVlLmdldCgncm9pX25hbWUnLCAnRmFsbCBST0knKSwKICAgICAgICAgICAgZGVidWdfcm9pPXZhbHVlLmdldCgnZGVidWdfcm9pJywgVHJ1ZSksIHBvaW50X3g9LjUsIHBvaW50X3k9MS4pCiAgICAgICAgcmV0dXJuIGNscyhwb2xpY3ksIGdlb21ldHJ5KQoKICAgIEBwcm9wZXJ0eQogICAgZGVmIGVuYWJsZWQoc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYucG9saWN5LmVuYWJsZWQKCiAgICBAcHJvcGVydHkKICAgIGRlZiBjb25maWRlbmNlKHNlbGYpOgogICAgICAgIHJldHVybiBzZWxmLnBvbGljeS5wZXJzb25fc2NvcmUKCiAgICBAcHJvcGVydHkKICAgIGRlZiByb2koc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuZ2VvbWV0cnkucm9pCgogICAgQHByb3BlcnR5CiAgICBkZWYgcm9pX25hbWUoc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuZ2VvbWV0cnkucm9pX25hbWUKCiAgICBAcHJvcGVydHkKICAgIGRlZiBkZWJ1Z19yb2koc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuZ2VvbWV0cnkuZGVidWdfcm9pCgogICAgZGVmIHBheWxvYWQoc2VsZik6CiAgICAgICAgcmV0dXJuIHtrOiB2IGZvciBrLCB2IGluIHNlbGYuZ2VvbWV0cnkucGF5bG9hZCgpLml0ZW1zKCkKICAgICAgICAgICAgICAgIGlmIGsgaW4gKCdlbmFibGVkJywgJ2NvbmZpZGVuY2UnLCAncm9pJywgJ3JvaV9pZCcsICdyb2lfbmFtZScsICdkZWJ1Z19yb2knLCAncG9pbnRfeCcsICdwb2ludF95Jyl9CgogICAgZGVmIHNldHRpbmdzX3BheWxvYWQoc2VsZik6CiAgICAgICAgcmV0dXJuIGRpY3Qoc2VsZi5wb2xpY3kucGF5bG9hZCgpLCAqKntrOiB2IGZvciBrLCB2IGluIHNlbGYuZ2VvbWV0cnkucGF5bG9hZCgpLml0ZW1zKCkKICAgICAgICAgICAgICAgICAgICBpZiBrIGluICgncm9pJywgJ3JvaV9pZCcsICdyb2lfbmFtZScsICdkZWJ1Z19yb2knKX0pCgoKQGRhdGFjbGFzcyhmcm96ZW49VHJ1ZSkKY2xhc3MgRmFsbERpc3BsYXk6CiAgICBwb2ludDogdHVwbGUKICAgIGluc2lkZTogYm9vbAogICAgc3RhdGU6IHN0cgogICAgY29uZmlkZW5jZTogZmxvYXQKICAgIGV2ZW50X2lkOiBzdHIgfCBOb25lID0gTm9uZQoKICAgIGRlZiBwYXlsb2FkKHNlbGYpOgogICAgICAgIHJldHVybiBkaWN0KHNjZW5hcmlvPSdGQUxMJywgcG9pbnQ9bGlzdChzZWxmLnBvaW50KSwgaW5zaWRlPXNlbGYuaW5zaWRlLAogICAgICAgICAgICAgICAgICAgIHN0YXRlPXNlbGYuc3RhdGUsIGNvbmZpZGVuY2U9c2VsZi5jb25maWRlbmNlLCBldmVudElkPXNlbGYuZXZlbnRfaWQpCgoKQGRhdGFjbGFzcyhmcm96ZW49VHJ1ZSkKY2xhc3MgRmFsbEV2ZW50KEludHJ1c2lvbkV2ZW50KToKICAgIGRlZiBwYXlsb2FkKHNlbGYpOgogICAgICAgIHJldHVybiBkaWN0KHN1cGVyKCkucGF5bG9hZCgpLCBzY2VuYXJpbz0nRkFMTCcpCgoKY2xhc3MgRmFsbFNjZW5hcmlvOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGNvbmZpZywgKiwgd2FsbF9ucz10aW1lLnRpbWVfbnMsIGV2ZW50X2lkX2ZhY3Rvcnk9bGFtYmRhOiBzdHIodXVpZC51dWlkNCgpKSwKICAgICAgICAgICAgICAgICBkaXJlY3RfZG93bj1Ob25lLCBkaXJlY3RfZG93bl9jb29sZG93bl9zZWNvbmRzPU5vbmUpOgogICAgICAgICMgQUktcHJpdmF0ZTogbmV2ZXIgYWRkIHRoZXNlIG9wdGlvbnMgdG8gU2V0dGluZ3MvTWV0YWRhdGEvRXZlbnQgcGF5bG9hZHMuCiAgICAgICAgaWYgZGlyZWN0X2Rvd24gaXMgTm9uZToKICAgICAgICAgICAgdmFsdWUgPSBvcy5lbnZpcm9uLmdldCgnQ09OVEVYVFJBX0ZBTExfREVNT19ESVJFQ1RfRE9XTicsICd0cnVlJykKICAgICAgICAgICAgaWYgdmFsdWUgbm90IGluICgndHJ1ZScsICdmYWxzZScpOgogICAgICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBGQUxMIGRpcmVjdC1kb3duIHRvZ2dsZS4nKQogICAgICAgICAgICBkaXJlY3RfZG93biA9IHZhbHVlID09ICd0cnVlJwogICAgICAgIGlmIGRpcmVjdF9kb3duX2Nvb2xkb3duX3NlY29uZHMgaXMgTm9uZToKICAgICAgICAgICAgZGlyZWN0X2Rvd25fY29vbGRvd25fc2Vjb25kcyA9IGZsb2F0KG9zLmVudmlyb24uZ2V0KAogICAgICAgICAgICAgICAgJ0NPTlRFWFRSQV9GQUxMX0RJUkVDVF9ET1dOX0NPT0xET1dOX1NFQ09ORFMnLCAnMi4wJykpCiAgICAgICAgc2VsZi5jb25maWcgPSBjb25maWcKICAgICAgICBzZWxmLmVuZ2luZSA9IEZhbGxFbmdpbmUoY29uZmlnLnBvbGljeSwgZGlyZWN0X2Rvd249ZGlyZWN0X2Rvd24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdF9kb3duX2Nvb2xkb3duX3NlY29uZHM9ZGlyZWN0X2Rvd25fY29vbGRvd25fc2Vjb25kcykKICAgICAgICBzZWxmLndhbGxfbnMgPSB3YWxsX25zCiAgICAgICAgc2VsZi5ldmVudF9pZF9mYWN0b3J5ID0gZXZlbnRfaWRfZmFjdG9yeQogICAgICAgIHNlbGYuX2V2ZW50cyA9IHt9CgogICAgZGVmIGV2YWx1YXRlKHNlbGYsIGZyYW1lLCBwb3NlcywgdHJhY2tfaWRzLCAqLCBnYXBfYmVmb3JlPUZhbHNlKToKICAgICAgICBwb2ludHMgPSB0dXBsZSgoKHAuYmJveF94eXh5WzBdK3AuYmJveF94eXh5WzJdKS8yLCBwLmJib3hfeHl4eVszXSkgZm9yIHAgaW4gcG9zZXMpCiAgICAgICAgc2VsZWN0ZWQgPSB0dXBsZShpIGZvciBpLCBwb2ludCBpbiBlbnVtZXJhdGUocG9pbnRzKSBpZiBpbnNpZGUocG9pbnQsIHNlbGYuY29uZmlnLnJvaSkpCiAgICAgICAgcmVzdWx0ID0gc2VsZi5lbmdpbmUuZXZhbHVhdGUoZnJhbWUsIHR1cGxlKHBvc2VzW2ldIGZvciBpIGluIHNlbGVjdGVkKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0dXBsZSh0cmFja19pZHNbaV0gZm9yIGkgaW4gc2VsZWN0ZWQpLCBnYXBfYmVmb3JlPWdhcF9iZWZvcmUpCiAgICAgICAgaWYgbm90IHJlc3VsdC5hY2NlcHRlZDoKICAgICAgICAgICAgcmV0dXJuIHR1cGxlKEZhbGxEaXNwbGF5KHAsIGkgaW4gc2VsZWN0ZWQsICdUSU1FX1VOQVZBSUxBQkxFJywgc2VsZi5jb25maWcuY29uZmlkZW5jZSkKICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBpLCBwIGluIGVudW1lcmF0ZShwb2ludHMpKSwgKCkKICAgICAgICBzZWxmLl9ldmVudHMgPSB7dGlkOiBlaWQgZm9yIHRpZCwgZWlkIGluIHNlbGYuX2V2ZW50cy5pdGVtcygpCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzZWxmLmVuZ2luZS5pbnNwZWN0KHRpZCkgb3Ige30pLmdldCgnbGF0Y2hlZCcpfQogICAgICAgIGV2ZW50cyA9IFtdCiAgICAgICAgZm9yIGNhbmRpZGF0ZSBpbiByZXN1bHQuZXZlbnRfY2FuZGlkYXRlczoKICAgICAgICAgICAgb3JpZ2luYWwgPSBzZWxlY3RlZFtpbnQoY2FuZGlkYXRlLm9iamVjdF9yZWYpXQogICAgICAgICAgICBldmVudF9pZCA9IHNlbGYuZXZlbnRfaWRfZmFjdG9yeSgpCiAgICAgICAgICAgIGlmIHR5cGUoZXZlbnRfaWQpIGlzIG5vdCBzdHIgb3Igbm90IGV2ZW50X2lkIG9yIGxlbihldmVudF9pZCkgPiAxMDA6CiAgICAgICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdJbnZhbGlkIEZBTEwgRXZlbnQgSUQuJykKICAgICAgICAgICAgc2VsZi5fZXZlbnRzW2NhbmRpZGF0ZS50cmFja19pZF0gPSBldmVudF9pZAogICAgICAgICAgICBldmVudHMuYXBwZW5kKEZhbGxFdmVudChldmVudF9pZCwgZnJhbWUsIGNhbmRpZGF0ZS50cmFja19pZCwgc2VsZi5jb25maWcuZ2VvbWV0cnkucm9pX2lkLAogICAgICAgICAgICAgICAgc3RyKG9yaWdpbmFsKSwgY2FuZGlkYXRlLnBlcnNvbl9zY29yZSwgY2FuZGlkYXRlLmJib3hfeHl4eSwKICAgICAgICAgICAgICAgIHBvc2VzW29yaWdpbmFsXS5tb2RlbF9rZXksIHNlbGYud2FsbF9ucygpLy8xXzAwMF8wMDApKQogICAgICAgIGRlY2lzaW9ucyA9IFtGYWxsRGlzcGxheShwLCBGYWxzZSwgJ09VVFNJREUnLCBzZWxmLmNvbmZpZy5jb25maWRlbmNlKSBmb3IgcCBpbiBwb2ludHNdCiAgICAgICAgZm9yIGluZGV4LCBkZWNpc2lvbiBpbiB6aXAoc2VsZWN0ZWQsIHJlc3VsdC5kZWNpc2lvbnMpOgogICAgICAgICAgICBkZWNpc2lvbnNbaW5kZXhdID0gRmFsbERpc3BsYXkocG9pbnRzW2luZGV4XSwgVHJ1ZSwgZGVjaXNpb24uc3RhdGUsIHNlbGYuY29uZmlnLmNvbmZpZGVuY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLl9ldmVudHMuZ2V0KGRlY2lzaW9uLnRyYWNrX2lkKSBpZiBkZWNpc2lvbi5hbGVydCBlbHNlIE5vbmUpCiAgICAgICAgcmV0dXJuIHR1cGxlKGRlY2lzaW9ucyksIHR1cGxlKGV2ZW50cykKCiAgICBkZWYgY2xlYXIoc2VsZik6CiAgICAgICAgc2VsZi5lbmdpbmUuY2xlYXIoKQogICAgICAgIHNlbGYuX2V2ZW50cy5jbGVhcigpCgoKZGVmIHByb2plY3RfZmFsbChzcGVjLCBzY2VuYXJpb3MpOgogICAgcmVxdWVzdCA9IG5leHQocyBmb3IgcyBpbiBzY2VuYXJpb3MgaWYgc1snc2NlbmFyaW9Db2RlJ10gPT0gJ0ZBTEwnKQogICAgaWYgbm90IHJlcXVlc3RbJ2VuYWJsZWQnXSBhbmQgJ2ZhbGwnIG5vdCBpbiBzcGVjOgogICAgICAgIHJldHVybgogICAgY2ZnID0gZGljdChzcGVjLmdldCgnZmFsbCcpIG9yIHt9KQogICAgcm9pID0gcmVxdWVzdFsncm9pcyddWzBdIGlmIHJlcXVlc3RbJ3JvaXMnXSBlbHNlIE5vbmUKICAgIGNmZy51cGRhdGUoZW5hYmxlZD1yZXF1ZXN0WydlbmFibGVkJ10sIHBlcnNvbl9zY29yZT1ERU1PX0ZBTExfREVGQVVMVFNbJ3BlcnNvbl9zY29yZSddIGlmIHJlcXVlc3RbJ2NvbmZpZGVuY2UnXSBpcyBOb25lIGVsc2UgcmVxdWVzdFsnY29uZmlkZW5jZSddLAogICAgICAgICAgICAgICByb2k9cm9pWydwb2ludHMnXSBpZiByb2kgZWxzZSBbXSwgcm9pX25hbWU9cm9pWydsYWJlbCddIGlmIHJvaSBlbHNlICdGYWxsIFJPSScpCiAgICBzcGVjWydmYWxsJ10gPSBGYWxsU2V0dGluZ3MucGFyc2UoY2ZnKS5zZXR0aW5nc19wYXlsb2FkKCkKCgpkZWYgdmFsaWRhdGUoc3BlYyk6CiAgICBjb25maWcgPSBGYWxsU2V0dGluZ3MucGFyc2Uoc3BlYy5nZXQoJ2ZhbGwnKSBvciB7fSkKICAgIGlmIGNvbmZpZy5lbmFibGVkOgogICAgICAgIGlmIG5vdCBzcGVjLmdldCgnc2VydmVyX2lkJykgb3Igbm90IHNwZWMuZ2V0KCdzb3VyY2VfaWQnKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignRkFMTCByZXF1aXJlcyBjYW5vbmljYWwgaWRlbnRpdHkuJykKICAgICAgICBpZiBub3QgKHNwZWMuZ2V0KCd0cmFja2luZycpIG9yIHt9KS5nZXQoJ2VuYWJsZWQnLCBUcnVlKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignRkFMTCByZXF1aXJlcyBUcmFja2luZyBPbi4nKQogICAgcmV0dXJuIGNvbmZpZwo=",
    "app/scenario_parameters.py": "IiIiU2NlbmFyaW8tbG9jYWwgV2ViIHR1bmluZyBwcm9qZWN0aW9uIGZvciBQUjEzLgoKUHVibGljIFN0YXJ0IHBhcmFtZXRlcnMgYXJlIHBlcm1pc3NpdmUgYnkgZGVzaWduOiB1bmtub3duL251bGwvaW52YWxpZCB0dW5pbmcKdmFsdWVzIGFyZSBpZ25vcmVkLCB3aGlsZSB0aGUgc3Vycm91bmRpbmcgU3RhcnQvUk9JL2lkZW50aXR5IGNvbnRyYWN0IHJlbWFpbnMKc3RyaWN0IGluIHNlY3VyZV9jb250cm9sLiAgQSBjYW5kaWRhdGUgc2NlbmFyaW8gY29uZmlnIGlzIHBhcnNlZCBiZWZvcmUgaXQgaXMKc3RvcmVkIHNvIGludmFsaWQgaW50ZXItZmllbGQgY29tYmluYXRpb25zIGZhbGwgYmFjayBhdG9taWNhbGx5LgoiIiIKZnJvbSBfX2Z1dHVyZV9fIGltcG9ydCBhbm5vdGF0aW9ucwoKZnJvbSBjb3B5IGltcG9ydCBkZWVwY29weQppbXBvcnQgbG9nZ2luZwppbXBvcnQgbWF0aAppbXBvcnQgcmUKZnJvbSBhcHAuY3Jvd2RfY29uZmlnIGltcG9ydCBFVkVOVF9QQVJBTUVURVJTCgpMT0cgPSBsb2dnaW5nLmdldExvZ2dlcihfX25hbWVfXykKCgpkZWYgX251bWJlcih2YWx1ZSwgKiwgbG93PU5vbmUsIGhpZ2g9Tm9uZSwgbG93X29wZW49RmFsc2UpOgogICAgaWYgdHlwZSh2YWx1ZSkgbm90IGluIChpbnQsIGZsb2F0KToKICAgICAgICByZXR1cm4gTm9uZQogICAgdHJ5OgogICAgICAgIGlmIG5vdCBtYXRoLmlzZmluaXRlKHZhbHVlKToKICAgICAgICAgICAgcmV0dXJuIE5vbmUKICAgIGV4Y2VwdCBPdmVyZmxvd0Vycm9yOgogICAgICAgIHJldHVybiBOb25lCiAgICB2YWx1ZSA9IGZsb2F0KHZhbHVlKQogICAgaWYgbG93IGlzIG5vdCBOb25lIGFuZCAodmFsdWUgPD0gbG93IGlmIGxvd19vcGVuIGVsc2UgdmFsdWUgPCBsb3cpOgogICAgICAgIHJldHVybiBOb25lCiAgICBpZiBoaWdoIGlzIG5vdCBOb25lIGFuZCB2YWx1ZSA+IGhpZ2g6CiAgICAgICAgcmV0dXJuIE5vbmUKICAgIHJldHVybiB2YWx1ZQoKCmRlZiBfaW50ZWdlcih2YWx1ZSwgKiwgbG93LCBoaWdoKToKICAgIHJldHVybiB2YWx1ZSBpZiB0eXBlKHZhbHVlKSBpcyBpbnQgYW5kIGxvdyA8PSB2YWx1ZSA8PSBoaWdoIGVsc2UgTm9uZQoKCl9SVUxFUyA9IHsKICAgICdJTlRSVVNJT04nOiB7CiAgICAgICAgJ3BlcnNvbl9jb25maWRlbmNlJzogbGFtYmRhIHY6IF9udW1iZXIodiwgbG93PTAsIGhpZ2g9MSksCiAgICAgICAgJ2R3ZWxsX3NlY29uZHMnOiBsYW1iZGEgdjogX251bWJlcih2LCBsb3c9MCwgaGlnaD0zNjAwLCBsb3dfb3Blbj1UcnVlKSwKICAgICAgICAncmVhcm1fc2Vjb25kcyc6IGxhbWJkYSB2OiBfbnVtYmVyKHYsIGxvdz0wLCBoaWdoPTM2MDAsIGxvd19vcGVuPVRydWUpLAogICAgICAgICdncmFjZV9zZWNvbmRzJzogbGFtYmRhIHY6IF9udW1iZXIodiwgbG93PTAsIGhpZ2g9MzYwMCwgbG93X29wZW49VHJ1ZSksCiAgICB9LAogICAgJ0xPSVRFUklORyc6IHsKICAgICAgICAncGVyc29uX2NvbmZpZGVuY2UnOiBsYW1iZGEgdjogX251bWJlcih2LCBsb3c9MCwgaGlnaD0xKSwKICAgICAgICAnZHdlbGxfc2Vjb25kcyc6IGxhbWJkYSB2OiBfbnVtYmVyKHYsIGxvdz0wLCBoaWdoPTM2MDAsIGxvd19vcGVuPVRydWUpLAogICAgICAgICdyZWFybV9zZWNvbmRzJzogbGFtYmRhIHY6IF9udW1iZXIodiwgbG93PTAsIGhpZ2g9MzYwMCwgbG93X29wZW49VHJ1ZSksCiAgICAgICAgJ2dyYWNlX3NlY29uZHMnOiBsYW1iZGEgdjogX251bWJlcih2LCBsb3c9MCwgaGlnaD0zNjAwLCBsb3dfb3Blbj1UcnVlKSwKICAgIH0sCiAgICAnRkFMTCc6IHsKICAgICAgICAncGVyc29uX2NvbmZpZGVuY2UnOiBsYW1iZGEgdjogX251bWJlcih2LCBsb3c9MCwgaGlnaD0xKSwKICAgICAgICAncG9zZV9jb25maWRlbmNlJzogbGFtYmRhIHY6IF9udW1iZXIodiwgbG93PTAsIGhpZ2g9MSksCiAgICAgICAgJ2Rvd25fYW5nbGVfZGVnJzogbGFtYmRhIHY6IF9udW1iZXIodiwgbG93PTAsIGhpZ2g9OTApLAogICAgICAgICdyZWNvdmVyeV9ob2xkX3NlY29uZHMnOiBsYW1iZGEgdjogX251bWJlcih2LCBsb3c9LjAwMSwgaGlnaD0zNjAwKSwKICAgIH0sCiAgICAnRklHSFQnOiB7CiAgICAgICAgJ3BlcnNvbl9jb25maWRlbmNlJzogbGFtYmRhIHY6IF9udW1iZXIodiwgbG93PTAsIGhpZ2g9MSksCiAgICAgICAgJ3Bvc2VfY29uZmlkZW5jZSc6IGxhbWJkYSB2OiBfbnVtYmVyKHYsIGxvdz0wLCBoaWdoPTEpLAogICAgICAgICdwYWlyX2Rpc3RhbmNlX3JhdGlvJzogbGFtYmRhIHY6IF9udW1iZXIodiwgbG93PTAsIGhpZ2g9MzAsIGxvd19vcGVuPVRydWUpLAogICAgICAgICdwYWlyX2Nsb3NlX2hvbGRfc2Vjb25kcyc6IGxhbWJkYSB2OiBfbnVtYmVyKHYsIGxvdz0wLCBoaWdoPTMwLCBsb3dfb3Blbj1UcnVlKSwKICAgICAgICAnYXJtX21vdGlvbl9yYXRpbyc6IGxhbWJkYSB2OiBfbnVtYmVyKHYsIGxvdz0wLCBoaWdoPTMwLCBsb3dfb3Blbj1UcnVlKSwKICAgICAgICAncmVxdWlyZWRfYnVyc3RzJzogbGFtYmRhIHY6IF9pbnRlZ2VyKHYsIGxvdz0xLCBoaWdoPTE2KSwKICAgIH0sCiAgICAnQ1JPV0QnOiB7CiAgICAgICAgJ3BlcnNvbl9jb25maWRlbmNlJzogbGFtYmRhIHY6IF9udW1iZXIodiwgbG93PTAsIGhpZ2g9MSksCiAgICAgICAgJ2hlYWRfY29uZmlkZW5jZSc6IGxhbWJkYSB2OiBfbnVtYmVyKHYsIGxvdz0wLCBoaWdoPTEpLAogICAgICAgICd3aW5kb3dfc2Vjb25kcyc6IGxhbWJkYSB2OiBfbnVtYmVyKHYsIGxvdz0wLCBoaWdoPTM2MDAsIGxvd19vcGVuPVRydWUpLAogICAgICAgICdyZXBvcnRfc2Vjb25kcyc6IGxhbWJkYSB2OiBfbnVtYmVyKHYsIGxvdz0wLCBoaWdoPTM2MDAsIGxvd19vcGVuPVRydWUpLAogICAgfSwKICAgICdGSVJFJzogewogICAgICAgICdmbGFtZV9jb25maWRlbmNlJzogbGFtYmRhIHY6IF9udW1iZXIodiwgbG93PTAsIGhpZ2g9MSksCiAgICAgICAgJ2ZsYW1lX3dpbmRvd19zZWNvbmRzJzogbGFtYmRhIHY6IF9udW1iZXIodiwgbG93PTAsIGhpZ2g9MzYwMCwgbG93X29wZW49VHJ1ZSksCiAgICAgICAgJ2ZsYW1lX3Bvc2l0aXZlX3JhdGlvJzogbGFtYmRhIHY6IF9udW1iZXIodiwgbG93PTAsIGhpZ2g9MSwgbG93X29wZW49VHJ1ZSksCiAgICAgICAgJ3Ntb2tlX2NvbmZpZGVuY2UnOiBsYW1iZGEgdjogX251bWJlcih2LCBsb3c9MCwgaGlnaD0xKSwKICAgICAgICAnc21va2Vfd2luZG93X3NlY29uZHMnOiBsYW1iZGEgdjogX251bWJlcih2LCBsb3c9MCwgaGlnaD0zNjAwLCBsb3dfb3Blbj1UcnVlKSwKICAgICAgICAnc21va2VfcG9zaXRpdmVfcmF0aW8nOiBsYW1iZGEgdjogX251bWJlcih2LCBsb3c9MCwgaGlnaD0xLCBsb3dfb3Blbj1UcnVlKSwKICAgICAgICAnY2xlYXJfc2Vjb25kcyc6IGxhbWJkYSB2OiBfbnVtYmVyKHYsIGxvdz0wLCBoaWdoPTM2MDAsIGxvd19vcGVuPVRydWUpLAogICAgfSwKfQoKCmRlZiBzYW5pdGl6ZShjb2RlLCByYXcpOgogICAgIiIiUmV0dXJuIHZhbGlkIHB1YmxpYyB0dW5pbmcgdmFsdWVzOyBpbnZhbGlkL3Vua25vd24gdmFsdWVzIGFyZSBpZ25vcmVkLiIiIgogICAgaWYgcmF3IGlzIE5vbmU6CiAgICAgICAgcmV0dXJuIHt9LCAoKQogICAgaWYgdHlwZShyYXcpIGlzIG5vdCBkaWN0OgogICAgICAgIHJldHVybiB7fSwgKCgnKicsICdJTlZBTElEX0NPTlRBSU5FUicpLCkKICAgIHJ1bGVzID0gX1JVTEVTW2NvZGVdCiAgICBhY2NlcHRlZCwgaWdub3JlZCA9IHt9LCBbXQogICAgZm9yIGtleSwgdmFsdWUgaW4gcmF3Lml0ZW1zKCk6CiAgICAgICAgaWYga2V5ID09ICdjb29sZG93bl9zZWNvbmRzJyBvciAoY29kZSA9PSAnQ1JPV0QnIGFuZCBrZXkgaW4gRVZFTlRfUEFSQU1FVEVSUyk6CiAgICAgICAgICAgIGNvbnRpbnVlICAjIEFkbWlzc2lvbiBzZXR0aW5ncyBhcmUgdmFsaWRhdGVkIHNlcGFyYXRlbHkgZnJvbSBvcHRpb25hbCB0dW5pbmcuCiAgICAgICAgcnVsZSA9IHJ1bGVzLmdldChrZXkpCiAgICAgICAgaWYgcnVsZSBpcyBOb25lOgogICAgICAgICAgICBpZ25vcmVkLmFwcGVuZCgoc3RyKGtleSksICdVTktOT1dOX1BBUkFNRVRFUicpKQogICAgICAgICAgICBjb250aW51ZQogICAgICAgIGlmIHZhbHVlIGlzIE5vbmU6CiAgICAgICAgICAgIGlnbm9yZWQuYXBwZW5kKChrZXksICdOVUxMX1BBUkFNRVRFUicpKQogICAgICAgICAgICBjb250aW51ZQogICAgICAgIHBhcnNlZCA9IHJ1bGUodmFsdWUpCiAgICAgICAgaWYgcGFyc2VkIGlzIE5vbmU6CiAgICAgICAgICAgIGlnbm9yZWQuYXBwZW5kKChrZXksICdJTlZBTElEX1ZBTFVFJykpCiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgYWNjZXB0ZWRba2V5XSA9IHBhcnNlZAogICAgcmV0dXJuIGFjY2VwdGVkLCB0dXBsZShpZ25vcmVkKQoKCmRlZiBfbG9nX2lnbm9yZWQoY29kZSwgaWdub3JlZCk6CiAgICBmb3Iga2V5LCByZWFzb24gaW4gaWdub3JlZFs6MzJdOgogICAgICAgIGtleSA9IGtleSBpZiByZS5mdWxsbWF0Y2gocidbQS1aYS16MC05X117MSw2NH0nLCBrZXkpIGVsc2UgJ0lOVkFMSURfS0VZJwogICAgICAgIExPRy5pbmZvKCdzY2VuYXJpb19wYXJhbWV0ZXJfaWdub3JlZCBzY2VuYXJpbz0lcyBwYXJhbWV0ZXI9JXMgcmVhc29uPSVzJywKICAgICAgICAgICAgICAgICBjb2RlLCBrZXksIHJlYXNvbikKCgpkZWYgYXBwbHkoc3BlYywgcmVxdWVzdCk6CiAgICAiIiJBdG9taWNhbGx5IGFwcGx5IHZhbGlkIHR1bmluZyB2YWx1ZXMgdG8gb25lIHByaXZhdGUgY2FuZGlkYXRlIHNwZWMuCgogICAgUmV0dXJucyBUcnVlIHdoZW4gdGhlIG92ZXJyaWRlIHNldCB3YXMgYWNjZXB0ZWQuICBGYWxzZSBtZWFucyBlaXRoZXIgbm8KICAgIHVzYWJsZSB2YWx1ZXMgd2VyZSBzdXBwbGllZCBvciB0aGUgY29tcGxldGUgY2FuZGlkYXRlIGZhaWxlZCBzY2VuYXJpbwogICAgdmFsaWRhdGlvbjsgaW4gYm90aCBjYXNlcyB0aGUgb3JpZ2luYWwgc2F2ZWQvZGVmYXVsdCBjb25maWcgaXMgcHJlc2VydmVkLgogICAgIiIiCiAgICBjb2RlID0gcmVxdWVzdFsnc2NlbmFyaW9Db2RlJ10KICAgIGlmIGNvZGUgPT0gJ0ZJR0hUJzoKICAgICAgICBmcm9tIGFwcC5maWdodF9yNS53ZWIgaW1wb3J0IGFwcGx5X3BhcmFtZXRlcnMKICAgICAgICBoYW5kbGVkID0gYXBwbHlfcGFyYW1ldGVycyhzcGVjLCByZXF1ZXN0KQogICAgICAgIGlmIGhhbmRsZWQgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIHJldHVybiBoYW5kbGVkCiAgICBmcm9tIGFwcC5ldmVudF9jb29sZG93biBpbXBvcnQgZGVmYXVsdF9zZWNvbmRzCiAgICByYXcgPSByZXF1ZXN0LmdldCgncGFyYW1ldGVycycpCiAgICBjb29sZG93biA9IF9udW1iZXIocmF3LmdldCgnY29vbGRvd25fc2Vjb25kcycpLCBsb3c9MCwgaGlnaD0zMDApIGlmIHR5cGUocmF3KSBpcyBkaWN0IGVsc2UgTm9uZQogICAgc3BlYy5zZXRkZWZhdWx0KCdldmVudF9jb29sZG93bnMnLCB7fSlbY29kZV0gPSBkZWZhdWx0X3NlY29uZHMoKSBpZiBjb29sZG93biBpcyBOb25lIGVsc2UgY29vbGRvd24KICAgIGlmIGNvZGUgPT0gJ0NST1dEJzoKICAgICAgICBmcm9tIGFwcC5jcm93ZF9jb25maWcgaW1wb3J0IENyb3dkQ29uZmlnLCB2YWxpZGF0ZV9ldmVudF9wYXJhbWV0ZXJzCiAgICAgICAgc3BlYy5wb3AoJ2Nyb3dkX3N0YXJ0X3JlamVjdGlvbicsIE5vbmUpCiAgICAgICAgY3VycmVudCA9IENyb3dkQ29uZmlnLnBhcnNlKHNwZWMuZ2V0KCdjcm93ZCcpIG9yIHt9KQogICAgICAgIGlmIHJlcXVlc3RbJ2VuYWJsZWQnXToKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgcmVxdWlyZWQgPSB2YWxpZGF0ZV9ldmVudF9wYXJhbWV0ZXJzKHJhdykKICAgICAgICAgICAgZXhjZXB0IFZhbHVlRXJyb3IgYXMgZXJyb3I6CiAgICAgICAgICAgICAgICByZWFzb24gPSBzdHIoZXJyb3IpCiAgICAgICAgICAgICAgICBzcGVjWydjcm93ZCddID0gY3VycmVudC5wYXRjaGVkKGRpY3QoZW5hYmxlZD1GYWxzZSwgZXZlbnRfZW5hYmxlZD1GYWxzZSkpLnNldHRpbmdzX3BheWxvYWQoKQogICAgICAgICAgICAgICAgc3BlY1snY3Jvd2Rfc3RhcnRfcmVqZWN0aW9uJ10gPSByZWFzb24KICAgICAgICAgICAgICAgIExPRy5pbmZvKCdzY2VuYXJpb19za2lwcGVkIHNjZW5hcmlvPUNST1dEIHJlYXNvbj0lcycsIHJlYXNvbikKICAgICAgICAgICAgICAgIHJldHVybiBGYWxzZQogICAgICAgICAgICBzcGVjWydjcm93ZCddID0gY3VycmVudC5wYXRjaGVkKGRpY3QocmVxdWlyZWQsIGV2ZW50X2VuYWJsZWQ9VHJ1ZSkpLnNldHRpbmdzX3BheWxvYWQoKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIHNwZWNbJ2Nyb3dkJ10gPSBjdXJyZW50LnBhdGNoZWQoZGljdChldmVudF9lbmFibGVkPUZhbHNlKSkuc2V0dGluZ3NfcGF5bG9hZCgpCiAgICB2YWx1ZXMsIGlnbm9yZWQgPSBzYW5pdGl6ZShjb2RlLCByZXF1ZXN0LmdldCgncGFyYW1ldGVycycpKQogICAgX2xvZ19pZ25vcmVkKGNvZGUsIGlnbm9yZWQpCiAgICBpZiBub3QgdmFsdWVzOgogICAgICAgIHJldHVybiBjb29sZG93biBpcyBub3QgTm9uZSBvciAoY29kZSA9PSAnQ1JPV0QnIGFuZCByZXF1ZXN0WydlbmFibGVkJ10pCgogICAgYmVmb3JlID0gZGVlcGNvcHkoc3BlYykKICAgIHRyeToKICAgICAgICBpZiBjb2RlID09ICdJTlRSVVNJT04nOgogICAgICAgICAgICBmcm9tIGFwcC5pbnRydXNpb24gaW1wb3J0IEludHJ1c2lvbkNvbmZpZwogICAgICAgICAgICBjZmcgPSBkaWN0KHNwZWMuZ2V0KCdpbnRydXNpb24nKSBvciB7fSkKICAgICAgICAgICAgbWFwcGluZyA9IHsncGVyc29uX2NvbmZpZGVuY2UnOiAnY29uZmlkZW5jZSd9CiAgICAgICAgICAgIGNmZy51cGRhdGUoe21hcHBpbmcuZ2V0KGssIGspOiB2IGZvciBrLCB2IGluIHZhbHVlcy5pdGVtcygpfSkKICAgICAgICAgICAgc3BlY1snaW50cnVzaW9uJ10gPSBJbnRydXNpb25Db25maWcucGFyc2UoY2ZnKS5wYXlsb2FkKCkKCiAgICAgICAgZWxpZiBjb2RlID09ICdMT0lURVJJTkcnOgogICAgICAgICAgICBmcm9tIGFwcC5sb2l0ZXJpbmcgaW1wb3J0IExvaXRlcmluZ0NvbmZpZwogICAgICAgICAgICBjZmcgPSBkaWN0KHNwZWMuZ2V0KCdsb2l0ZXJpbmcnKSBvciB7fSkKICAgICAgICAgICAgbWFwcGluZyA9IHsncGVyc29uX2NvbmZpZGVuY2UnOiAnY29uZmlkZW5jZSd9CiAgICAgICAgICAgIGNmZy51cGRhdGUoe21hcHBpbmcuZ2V0KGssIGspOiB2IGZvciBrLCB2IGluIHZhbHVlcy5pdGVtcygpfSkKICAgICAgICAgICAgc3BlY1snbG9pdGVyaW5nJ10gPSBMb2l0ZXJpbmdDb25maWcucGFyc2UoY2ZnKS5wYXlsb2FkKCkKCiAgICAgICAgZWxpZiBjb2RlID09ICdGQUxMJzoKICAgICAgICAgICAgZnJvbSBhcHAuZmFsbF9ydW50aW1lIGltcG9ydCBGYWxsU2V0dGluZ3MKICAgICAgICAgICAgY2ZnID0gZGljdChzcGVjLmdldCgnZmFsbCcpIG9yIHt9KQogICAgICAgICAgICBtYXBwaW5nID0geydwZXJzb25fY29uZmlkZW5jZSc6ICdwZXJzb25fc2NvcmUnLCAncG9zZV9jb25maWRlbmNlJzogJ2pvaW50X3Njb3JlJ30KICAgICAgICAgICAgY2ZnLnVwZGF0ZSh7bWFwcGluZy5nZXQoaywgayk6IHYgZm9yIGssIHYgaW4gdmFsdWVzLml0ZW1zKCl9KQogICAgICAgICAgICBzcGVjWydmYWxsJ10gPSBGYWxsU2V0dGluZ3MucGFyc2UoY2ZnKS5zZXR0aW5nc19wYXlsb2FkKCkKCiAgICAgICAgZWxpZiBjb2RlID09ICdGSUdIVCc6CiAgICAgICAgICAgIGZyb20gYXBwLmZpZ2h0X3J1bnRpbWUgaW1wb3J0IEZpZ2h0U2V0dGluZ3MKICAgICAgICAgICAgY2ZnID0gZGljdChzcGVjLmdldCgnZmlnaHQnKSBvciB7fSkKICAgICAgICAgICAgbWFwcGluZyA9IHsncGVyc29uX2NvbmZpZGVuY2UnOiAncGVyc29uX3Njb3JlJywgJ3Bvc2VfY29uZmlkZW5jZSc6ICdqb2ludF9zY29yZSd9CiAgICAgICAgICAgIGNmZy51cGRhdGUoe21hcHBpbmcuZ2V0KGssIGspOiB2IGZvciBrLCB2IGluIHZhbHVlcy5pdGVtcygpfSkKICAgICAgICAgICAgc3BlY1snZmlnaHQnXSA9IEZpZ2h0U2V0dGluZ3MucGFyc2UoY2ZnKS5zZXR0aW5nc19wYXlsb2FkKCkKCiAgICAgICAgZWxpZiBjb2RlID09ICdDUk9XRCc6CiAgICAgICAgICAgIGZyb20gYXBwLmNyb3dkX2NvbmZpZyBpbXBvcnQgQ3Jvd2RDb25maWcKICAgICAgICAgICAgY2ZnID0gQ3Jvd2RDb25maWcucGFyc2Uoc3BlYy5nZXQoJ2Nyb3dkJykgb3Ige30pLnBhdGNoZWQodmFsdWVzKQogICAgICAgICAgICBzcGVjWydjcm93ZCddID0gY2ZnLnNldHRpbmdzX3BheWxvYWQoKQoKICAgICAgICBlbGlmIGNvZGUgPT0gJ0ZJUkUnOgogICAgICAgICAgICBmcm9tIGFwcC5maXJlX2NvbmZpZyBpbXBvcnQgRmlyZUNvbmZpZwogICAgICAgICAgICBmcm9tIGFwcC5maXJlX3NjZW5hcmlvIGltcG9ydCBGaXJlU2NlbmFyaW9Db25maWcKICAgICAgICAgICAgY3VycmVudCA9IEZpcmVDb25maWcucGFyc2Uoc3BlYy5nZXQoJ2ZpcmUnKSBvciB7fSkKICAgICAgICAgICAgY2ZnID0gKGN1cnJlbnQuc2NlbmFyaW8uc2V0dGluZ3NfcGF5bG9hZCgpIGlmIGN1cnJlbnQuc2NlbmFyaW8KICAgICAgICAgICAgICAgICAgIGVsc2UgRmlyZVNjZW5hcmlvQ29uZmlnKCkuc2V0dGluZ3NfcGF5bG9hZCgpKQogICAgICAgICAgICBjZmcudXBkYXRlKHZhbHVlcykKICAgICAgICAgICAgc2NlbmFyaW8gPSBGaXJlU2NlbmFyaW9Db25maWcucGFyc2UoY2ZnKQogICAgICAgICAgICBzcGVjWydmaXJlJ10gPSBGaXJlQ29uZmlnKGVuYWJsZWQ9Y3VycmVudC5lbmFibGVkLCBzY2VuYXJpbz1zY2VuYXJpbykucGF5bG9hZCgpCiAgICAgICAgZWxzZToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignVW5rbm93biBzY2VuYXJpbyBjb2RlLicpCiAgICAgICAgcmV0dXJuIFRydWUKICAgIGV4Y2VwdCAoVHlwZUVycm9yLCBWYWx1ZUVycm9yKToKICAgICAgICBzcGVjLmNsZWFyKCkKICAgICAgICBzcGVjLnVwZGF0ZShiZWZvcmUpCiAgICAgICAgTE9HLmluZm8oJ3NjZW5hcmlvX3BhcmFtZXRlcl9vdmVycmlkZV9yZXZlcnRlZCBzY2VuYXJpbz0lcyByZWFzb249SU5URVJfRklFTERfSU5WQUxJRCcsIGNvZGUpCiAgICAgICAgcmV0dXJuIEZhbHNlCgoKZGVmIGxlZ2FjeV9wcm9qZWN0aW9uX3ZpZXcoc3BlYywgc2NlbmFyaW9zKToKICAgICIiIkludGVybmFsIGNvbXBhdGliaWxpdHkgdmlldyBmb3Igb2xkIHByb2plY3RvcnM7IG5ldmVyIGEgcHVibGljIHNjaGVtYS4iIiIKICAgIG91dCA9IGRlZXBjb3B5KHNjZW5hcmlvcykKICAgIGZvciByZXF1ZXN0IGluIG91dDoKICAgICAgICBjb2RlID0gcmVxdWVzdFsnc2NlbmFyaW9Db2RlJ10KICAgICAgICBpZiBjb2RlID09ICdDUk9XRCcgYW5kIHNwZWMuZ2V0KCdjcm93ZF9zdGFydF9yZWplY3Rpb24nKToKICAgICAgICAgICAgcmVxdWVzdFsnZW5hYmxlZCddID0gRmFsc2UKICAgICAgICBpZiBjb2RlID09ICdJTlRSVVNJT04nOgogICAgICAgICAgICBmcm9tIGFwcC5pbnRydXNpb24gaW1wb3J0IEludHJ1c2lvbkNvbmZpZwogICAgICAgICAgICByZXF1ZXN0Wydjb25maWRlbmNlJ10gPSBJbnRydXNpb25Db25maWcucGFyc2Uoc3BlYy5nZXQoJ2ludHJ1c2lvbicpIG9yIHt9KS5jb25maWRlbmNlCiAgICAgICAgZWxpZiBjb2RlID09ICdMT0lURVJJTkcnOgogICAgICAgICAgICBmcm9tIGFwcC5sb2l0ZXJpbmcgaW1wb3J0IExvaXRlcmluZ0NvbmZpZwogICAgICAgICAgICByZXF1ZXN0Wydjb25maWRlbmNlJ10gPSBMb2l0ZXJpbmdDb25maWcucGFyc2Uoc3BlYy5nZXQoJ2xvaXRlcmluZycpIG9yIHt9KS5jb25maWRlbmNlCiAgICAgICAgZWxpZiBjb2RlID09ICdGQUxMJzoKICAgICAgICAgICAgZnJvbSBhcHAuZmFsbF9ydW50aW1lIGltcG9ydCBGYWxsU2V0dGluZ3MKICAgICAgICAgICAgcmVxdWVzdFsnY29uZmlkZW5jZSddID0gRmFsbFNldHRpbmdzLnBhcnNlKHNwZWMuZ2V0KCdmYWxsJykgb3Ige30pLnBvbGljeS5wZXJzb25fc2NvcmUKICAgICAgICBlbGlmIGNvZGUgPT0gJ0ZJR0hUJzoKICAgICAgICAgICAgZnJvbSBhcHAuZmlnaHRfcnVudGltZSBpbXBvcnQgRmlnaHRTZXR0aW5ncwogICAgICAgICAgICByZXF1ZXN0Wydjb25maWRlbmNlJ10gPSBGaWdodFNldHRpbmdzLnBhcnNlKHNwZWMuZ2V0KCdmaWdodCcpIG9yIHt9KS5wb2xpY3kucGVyc29uX3Njb3JlCiAgICAgICAgZWxzZToKICAgICAgICAgICAgcmVxdWVzdFsnY29uZmlkZW5jZSddID0gTm9uZQogICAgcmV0dXJuIG91dAo=",
    "app/secure_control.py": "IiIiT3B0LWluIFJ1bnRpbWUgYnJpZGdlOiBvbmUgZXhpc3RpbmcgQ2FtZXJhQ29tbWFuZHMgb3duZXIgYW5kIGV4aXN0aW5nIE1hbmFnZXIgbGlmZWN5Y2xlLgoKVGhpcyBtb2R1bGUgaW50ZW50aW9uYWxseSBkb2VzIG5vdCBpbXBvcnQgdGhlIFNpZGVjYXIsIEdQVSBvciBhIGRhdGFiYXNlLiBUaGUKTWFuYWdlcidzIGNvbW1hbmQgbG9jayBhbHNvIGZlbmNlcyBsZWdhY3kgQ0xJL0FQSSB3cml0ZXJzIGR1cmluZyBwcm9qZWN0aW9uLgoiIiIKaW1wb3J0IGFzeW5jaW8KZnJvbSBjb250ZXh0bGliIGltcG9ydCBhc3luY2NvbnRleHRtYW5hZ2VyCmZyb20gY29weSBpbXBvcnQgZGVlcGNvcHkKZnJvbSBkYXRhY2xhc3NlcyBpbXBvcnQgZGF0YWNsYXNzLCBmaWVsZAppbXBvcnQgaG1hYwppbXBvcnQganNvbgppbXBvcnQgbG9nZ2luZwpmcm9tIHV1aWQgaW1wb3J0IHV1aWQ0CmZyb20gY29udGV4dHJhX3RyYWNlIGltcG9ydCBlbWl0IGFzIHRyYWNlX2VtaXQKZnJvbSBjb250ZXh0cmFfdHJhY2UuaHR0cCBpbXBvcnQgUkVRVUVTVF9JRAppbXBvcnQgbWF0aApmcm9tIHVybGxpYi5wYXJzZSBpbXBvcnQgdXJsc3BsaXQKZnJvbSB1dWlkIGltcG9ydCB1dWlkNSwgTkFNRVNQQUNFX1VSTAoKZnJvbSBmYXN0YXBpIGltcG9ydCBBUElSb3V0ZXIsIFJlcXVlc3QKZnJvbSBmYXN0YXBpLnJlc3BvbnNlcyBpbXBvcnQgSlNPTlJlc3BvbnNlCgpDT0RFUyA9IGZyb3plbnNldCh7J0ZJUkUnLCdGQUxMJywnSU5UUlVTSU9OJywnTE9JVEVSSU5HJywnRklHSFQnLCdDUk9XRCd9KQpNQVhfQk9EWSA9IDY1NTM2CkxPRyA9IGxvZ2dpbmcuZ2V0TG9nZ2VyKF9fbmFtZV9fKQoKCmRlZiBjb21tYW5kX2Vycm9yKGVycm9yKToKICAgIGltcG9ydCByZQogICAgZnJvbSBhcHAuZmlnaHRfcjUuY29uZmlnIGltcG9ydCBSNUNvbmZpZ0Vycm9yCiAgICB2YWx1ZSA9IHN0cihlcnJvcikKICAgIGlmIGlzaW5zdGFuY2UoZXJyb3IsIChDb250cm9sRXJyb3IsIFI1Q29uZmlnRXJyb3IpKSBhbmQgcmUuZnVsbG1hdGNoKCdbQS1aXVtBLVowLTlfXXswLDYzfScsIHZhbHVlKToKICAgICAgICByZXR1cm4gdmFsdWUKICAgIHJldHVybiAnUlVOVElNRV9DT01NQU5EX1JFSkVDVEVEJwoKCmNsYXNzIENvbnRyb2xFcnJvcihWYWx1ZUVycm9yKToKICAgIHBhc3MKCgpkZWYgZGVjb2RlKHJhdyk6CiAgICBkZWYgcGFpcnMoaXRlbXMpOgogICAgICAgIGQgPSB7fQogICAgICAgIGZvciBrLCB2IGluIGl0ZW1zOgogICAgICAgICAgICBpZiBrIGluIGQ6CiAgICAgICAgICAgICAgICByYWlzZSBDb250cm9sRXJyb3IoJ0RVUExJQ0FURV9LRVknKQogICAgICAgICAgICBkW2tdID0gdgogICAgICAgIHJldHVybiBkCiAgICBkZWYgYmFkKF8pOgogICAgICAgIHJhaXNlIENvbnRyb2xFcnJvcignSU5WQUxJRF9OVU1CRVInKQogICAgaWYgbGVuKHJhdykgPiBNQVhfQk9EWToKICAgICAgICByYWlzZSBDb250cm9sRXJyb3IoJ0JPRFlfVE9PX0xBUkdFJykKICAgIHRyeToKICAgICAgICBkID0ganNvbi5sb2FkcyhyYXcsIG9iamVjdF9wYWlyc19ob29rPXBhaXJzLCBwYXJzZV9jb25zdGFudD1iYWQpCiAgICAgICAgaWYgbm90IGlzaW5zdGFuY2UoZCwgZGljdCk6CiAgICAgICAgICAgIHJhaXNlIENvbnRyb2xFcnJvcignQk9EWV9OT1RfT0JKRUNUJykKICAgICAgICByZXR1cm4gZAogICAgZXhjZXB0IChWYWx1ZUVycm9yLCBVbmljb2RlRXJyb3IsIFJlY3Vyc2lvbkVycm9yKToKICAgICAgICByYWlzZSBDb250cm9sRXJyb3IoJ0lOVkFMSURfQk9EWScpIGZyb20gTm9uZQoKCmRlZiBjYW1lcmFfaWQoZCk6CiAgICB2ID0gZC5nZXQoJ2NhbWVyYUlkJykKICAgIGlmIHR5cGUodikgaXMgbm90IGludCBvciBub3QgMSA8PSB2IDw9IDIqKjUzLTE6CiAgICAgICAgcmFpc2UgQ29udHJvbEVycm9yKCdDQU1FUkFfSURfSU5WQUxJRCcpCiAgICByZXR1cm4gdgoKCmRlZiB2YWxpZGF0ZV9zdGFydChkKToKICAgIGNhbWVyYV9pZChkKQogICAgcmVxdWlyZWQgPSB7J2NhbWVyYUlkJywncnRzcFVybCcsJ3N0YXJ0V2FsbFRpbWVNcycsJ3J0cENsb2NrUmF0ZScsJ3NjZW5hcmlvcyd9CiAgICBpZiBub3QgcmVxdWlyZWQgPD0gc2V0KGQpIG9yIHNldChkKS1yZXF1aXJlZC17J3JlY1NlcnZlcklkJywncmVjQ2FtZXJhSWQnfToKICAgICAgICByYWlzZSBDb250cm9sRXJyb3IoJ1NUQVJUX0ZJRUxEU19JTlZBTElEJykKICAgIHUgPSBkWydydHNwVXJsJ10KICAgIHRyeToKICAgICAgICBwID0gdXJsc3BsaXQodSkKICAgICAgICBpZiAobm90IGlzaW5zdGFuY2UodSwgc3RyKSBvciBsZW4odSk+NDA5NiBvciBwLnNjaGVtZSE9J3J0c3AnIG9yIG5vdCBwLmhvc3RuYW1lCiAgICAgICAgICAgICAgICBvciBwLnBvcnQgPT0gMCBvciBwLmZyYWdtZW50IG9yIGFueShjLmlzc3BhY2UoKSBvciBvcmQoYyk8MzIgZm9yIGMgaW4gdSkpOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCkKICAgIGV4Y2VwdCAoVHlwZUVycm9yLCBWYWx1ZUVycm9yKToKICAgICAgICByYWlzZSBDb250cm9sRXJyb3IoJ1JUU1BfSU5WQUxJRCcpIGZyb20gTm9uZQogICAgaWYgdHlwZShkWydzdGFydFdhbGxUaW1lTXMnXSkgaXMgbm90IGludCBvciBub3QgMCA8IGRbJ3N0YXJ0V2FsbFRpbWVNcyddIDw9IDIqKjUzLTE6CiAgICAgICAgcmFpc2UgQ29udHJvbEVycm9yKCdBTkNIT1JfSU5WQUxJRCcpCiAgICBpZiB0eXBlKGRbJ3J0cENsb2NrUmF0ZSddKSBpcyBub3QgaW50IG9yIGRbJ3J0cENsb2NrUmF0ZSddICE9IDkwMDAwOgogICAgICAgIHJhaXNlIENvbnRyb2xFcnJvcignQ0xPQ0tfUkFURV9VTlNVUFBPUlRFRCcpCiAgICBzY2VuYXJpb3MgPSBkWydzY2VuYXJpb3MnXQogICAgaWYgbm90IGlzaW5zdGFuY2Uoc2NlbmFyaW9zLCBsaXN0KSBvciBsZW4oc2NlbmFyaW9zKSAhPSA2OgogICAgICAgIHJhaXNlIENvbnRyb2xFcnJvcignU0NFTkFSSU9fU05BUFNIT1RfUkVRVUlSRUQnKQogICAgc2VlbiA9IHNldCgpCiAgICBmb3IgcyBpbiBzY2VuYXJpb3M6CiAgICAgICAgaWYgKG5vdCBpc2luc3RhbmNlKHMsIGRpY3QpIG9yIG5vdCB7J3NjZW5hcmlvQ29kZScsJ2VuYWJsZWQnfSA8PSBzZXQocykKICAgICAgICAgICAgICAgIG9yIHNldChzKS17J3NjZW5hcmlvQ29kZScsJ2VuYWJsZWQnLCdyb2lzJywncGFyYW1ldGVycyd9KToKICAgICAgICAgICAgcmFpc2UgQ29udHJvbEVycm9yKCdTQ0VOQVJJT19GSUVMRFNfSU5WQUxJRCcpCiAgICAgICAgbmFtZSA9IHNbJ3NjZW5hcmlvQ29kZSddCiAgICAgICAgaWYgbm90IGlzaW5zdGFuY2UobmFtZSwgc3RyKSBvciBuYW1lIG5vdCBpbiBDT0RFUyBvciBuYW1lIGluIHNlZW4gb3IgdHlwZShzWydlbmFibGVkJ10pIGlzIG5vdCBib29sOgogICAgICAgICAgICByYWlzZSBDb250cm9sRXJyb3IoJ1NDRU5BUklPX0NPREVfSU5WQUxJRCcpCiAgICAgICAgc2Vlbi5hZGQobmFtZSkKICAgICAgICAjIHBhcmFtZXRlcnMgaXMgaW50ZW50aW9uYWxseSBmYWlsLXNvZnQ7IHN0cmljdCBTdGFydC9ST0kvaWRlbnRpdHkgdmFsaWRhdGlvbgogICAgICAgICMgc3RheXMgaGVyZSB3aGlsZSBzY2VuYXJpb19wYXJhbWV0ZXJzIHNhbml0aXplcyBpbmRpdmlkdWFsIHR1bmluZyB2YWx1ZXMuCiAgICAgICAgcm9pcyA9IHMuZ2V0KCdyb2lzJykKICAgICAgICAjIE5vcm1hbGl6ZSBiZWZvcmUgY29tbWFuZCBjYW5vbmljYWxpemF0aW9uIHNvIGVxdWl2YWxlbnQgZW1wdHkgUk9JIHJlcXVlc3RzIGRlZHVwbGljYXRlLgogICAgICAgIGlmIHJvaXMgaXMgTm9uZToKICAgICAgICAgICAgc1sncm9pcyddID0gcm9pcyA9IFtdCiAgICAgICAgaWYgbm90IGlzaW5zdGFuY2Uocm9pcywgbGlzdCkgb3IgbGVuKHJvaXMpID4gMzI6CiAgICAgICAgICAgIHJhaXNlIENvbnRyb2xFcnJvcignUk9JX0xJU1RfSU5WQUxJRCcpCiAgICAgICAgZm9yIHJvaSBpbiByb2lzOgogICAgICAgICAgICBpZiBub3QgaXNpbnN0YW5jZShyb2ksIGRpY3QpIG9yIHNldChyb2kpICE9IHsnbGFiZWwnLCdwb2ludHMnfToKICAgICAgICAgICAgICAgIHJhaXNlIENvbnRyb2xFcnJvcignUk9JX0ZJRUxEU19JTlZBTElEJykKICAgICAgICAgICAgbGFiZWwsIHBvaW50cyA9IHJvaVsnbGFiZWwnXSwgcm9pWydwb2ludHMnXQogICAgICAgICAgICBpZiAobm90IGlzaW5zdGFuY2UobGFiZWwsc3RyKSBvciBub3QgbGFiZWwuc3RyaXAoKSBvciBsZW4obGFiZWwpPjY0CiAgICAgICAgICAgICAgICAgICAgb3IgYW55KG9yZChjKTwzMiBmb3IgYyBpbiBsYWJlbCkgb3Igbm90IGlzaW5zdGFuY2UocG9pbnRzLGxpc3QpIG9yIG5vdCAzPD1sZW4ocG9pbnRzKTw9MzIpOgogICAgICAgICAgICAgICAgcmFpc2UgQ29udHJvbEVycm9yKCdST0lfSU5WQUxJRCcpCiAgICAgICAgICAgIGZvciBwYWlyIGluIHBvaW50czoKICAgICAgICAgICAgICAgIGlmIG5vdCBpc2luc3RhbmNlKHBhaXIsIGxpc3QpIG9yIGxlbihwYWlyKSE9MiBvciBhbnkodHlwZSh2KSBub3QgaW4gKGZsb2F0LGludCkgb3Igbm90IG1hdGguaXNmaW5pdGUodikgb3Igbm90IDA8PXY8PTEgZm9yIHYgaW4gcGFpcik6CiAgICAgICAgICAgICAgICAgICAgcmFpc2UgQ29udHJvbEVycm9yKCdST0lfQ09PUkRJTkFURVNfSU5WQUxJRCcpCiAgICBmb3IgayBpbiAoJ3JlY1NlcnZlcklkJywncmVjQ2FtZXJhSWQnKToKICAgICAgICBpZiBkLmdldChrKSBpcyBub3QgTm9uZSBhbmQgKG5vdCBpc2luc3RhbmNlKGRba10sIHN0cikgb3Igbm90IGRba10gb3IgbGVuKGRba10pPjI1Nik6CiAgICAgICAgICAgIHJhaXNlIENvbnRyb2xFcnJvcignUkVDX0lEX0lOVkFMSUQnKQogICAgIyBNdWx0aS1wcm92aWRlciBydW50aW1lIG93bnMgY29leGlzdGVuY2UuIFNjZW5hcmlvIHR1bmluZyB2YWx1ZXMgYXJlCiAgICAjIHNhbml0aXplZCBsYXRlciBhZ2FpbnN0IHRoZSBzYXZlZC9kZWZhdWx0IGNhbmRpZGF0ZSBzcGVjLgoKCkBkYXRhY2xhc3MoZnJvemVuPVRydWUpCmNsYXNzIFN0YXJ0OgogICAgIyBDYW5vbmljYWwgdGV4dCBtYWtlcyBkdXBsaWNhdGUgaW4tZmxpZ2h0IHJlcXVlc3RzIGNvbXBhcmUgYnkgdmFsdWUsIG5vdCBvYmplY3QgaWRlbnRpdHkuCiAgICB0ZXh0OiBzdHIgPSBmaWVsZChyZXByPUZhbHNlKQoKCmNsYXNzIENvbnRyb2xTZXJ2aWNlOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIG1hbmFnZXIsIHNlcnZlcl9pZCwgdGVtcGxhdGU9Tm9uZSk6CiAgICAgICAgc2VsZi5tYW5hZ2VyLCBzZWxmLnNlcnZlcl9pZCwgc2VsZi50ZW1wbGF0ZSA9IG1hbmFnZXIsIHNlcnZlcl9pZCwgZGVlcGNvcHkodGVtcGxhdGUpCgogICAgZGVmIHN0YXJ0X2NhbWVyYShzZWxmLCByZXF1ZXN0KToKICAgICAgICBkID0gZGVjb2RlKHJlcXVlc3QudGV4dCkKICAgICAgICB2YWxpZGF0ZV9zdGFydChkKQogICAgICAgIG0gPSBzZWxmLm1hbmFnZXIKICAgICAgICB3aXRoIG0uX2NvbW1hbmRzOgogICAgICAgICAgICB0cnk6CiAgICAgICAgICAgICAgICBzaWQgPSBtLmNhbWVyYV9zdHJlYW1faWQoc3RyKGRbJ2NhbWVyYUlkJ10pKQogICAgICAgICAgICAgICAgZyA9IG0uZ2V0KHNpZCkKICAgICAgICAgICAgZXhjZXB0IEtleUVycm9yOgogICAgICAgICAgICAgICAgZyA9IE5vbmUKICAgICAgICAgICAgICAgIHNpZCA9ICdjYW1lcmEtJyArIHV1aWQ1KE5BTUVTUEFDRV9VUkwsIHN0cihkWydjYW1lcmFJZCddKSkuaGV4CiAgICAgICAgICAgIGlmIGcgaXMgTm9uZToKICAgICAgICAgICAgICAgIGlmIHNlbGYudGVtcGxhdGUgaXMgTm9uZToKICAgICAgICAgICAgICAgICAgICByYWlzZSBDb250cm9sRXJyb3IoJ0NBTUVSQV9OT1RfUFJPVklTSU9ORUQnKQogICAgICAgICAgICAgICAgc3BlYyA9IGRlZXBjb3B5KHNlbGYudGVtcGxhdGUpCiAgICAgICAgICAgICAgICBzcGVjLnVwZGF0ZShzdHJlYW1faWQ9c2lkLCBzb3VyY2VfaWQ9c3RyKGRbJ2NhbWVyYUlkJ10pLCBzZXJ2ZXJfaWQ9c2VsZi5zZXJ2ZXJfaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYW1lcmFfaWQ9ZFsnY2FtZXJhSWQnXSwgc291cmNlX3R5cGU9J3J0c3AnLCBhdXRvc3RhcnQ9RmFsc2UpCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBpZiBnLnNwZWMuZ2V0KCdzZXJ2ZXJfaWQnKSAhPSBzZWxmLnNlcnZlcl9pZDoKICAgICAgICAgICAgICAgICAgICByYWlzZSBDb250cm9sRXJyb3IoJ1NFUlZFUl9JRF9DT05GTElDVCcpCiAgICAgICAgICAgICAgICAjIE5ldmVyIHJldml2ZSBhIFN0b3Agc3RpbGwgY2xlYW5pbmcgdXAuIFJlc3RhcnQgYWxyZWFkeSBvd25lZCBieSBNYW5hZ2VyIGlzIGRpZmZlcmVudC4KICAgICAgICAgICAgICAgIGlmIGcub2JzZXJ2ZWRfc3RhdGUgPT0gJ3N0b3BwaW5nJyBhbmQgZy5fcGVuZGluZ19yZXN0YXJ0IGlzIE5vbmU6CiAgICAgICAgICAgICAgICAgICAgcmFpc2UgQ29udHJvbEVycm9yKCdTVE9QX0NMRUFOVVBfUEVORElORycpCiAgICAgICAgICAgICAgICBzcGVjID0gZGVlcGNvcHkobS5fc2F2ZWRfc3BlYyhnKSkKICAgICAgICAgICAgICAgIGlmIHNwZWMuZ2V0KCdzb3VyY2VfdHlwZScsICdydHNwJykgIT0gJ3J0c3AnOgogICAgICAgICAgICAgICAgICAgIHJhaXNlIENvbnRyb2xFcnJvcignU09VUkNFX1RZUEVfQ09ORkxJQ1QnKQogICAgICAgICAgICAgICAgaWYgc3BlYy5nZXQoJ2NhbWVyYV9pZCcsIGRbJ2NhbWVyYUlkJ10pICE9IGRbJ2NhbWVyYUlkJ106CiAgICAgICAgICAgICAgICAgICAgcmFpc2UgQ29udHJvbEVycm9yKCdDQU1FUkFfSURfVFlQRV9DT05GTElDVCcpCiAgICAgICAgICAgIHNwZWNbJ3VyaSddID0gZFsncnRzcFVybCddCiAgICAgICAgICAgIHNwZWNbJ2NhbWVyYV9pZCddID0gZFsnY2FtZXJhSWQnXQogICAgICAgICAgICBvbGRfYW5jaG9yID0gc3BlYy5nZXQoJ2ZyYW1lX3RpbWVfYW5jaG9yJykgb3Ige30KICAgICAgICAgICAgIyBSZXBsYXlpbmcgdGhlIHNhbWUgdGVzdCBBbmNob3IgbXVzdCBub3QgcHJvbW90ZSBpdCB0byBhIHJlYWwgY2xvY2sgc291cmNlLgogICAgICAgICAgICBzcGVjWydmcmFtZV90aW1lX2FuY2hvciddID0geydzdGFydFdhbGxUaW1lTXMnOiBkWydzdGFydFdhbGxUaW1lTXMnXSwKICAgICAgICAgICAgICAgICdzeW50aGV0aWMnOiBib29sKG9sZF9hbmNob3IuZ2V0KCdzeW50aGV0aWMnLCBGYWxzZSkpCiAgICAgICAgICAgICAgICBpZiBvbGRfYW5jaG9yLmdldCgnc3RhcnRXYWxsVGltZU1zJykgPT0gZFsnc3RhcnRXYWxsVGltZU1zJ10gZWxzZSBGYWxzZX0KICAgICAgICAgICAgc3BlY1sndHJhY2tpbmcnXSA9IGRpY3Qoc3BlYy5nZXQoJ3RyYWNraW5nJykgb3Ige30sIGVuYWJsZWQ9VHJ1ZSkKICAgICAgICAgICAgZnJvbSBhcHAuc2NlbmFyaW9fcGFyYW1ldGVycyBpbXBvcnQgYXBwbHkgYXMgYXBwbHlfc2NlbmFyaW9fcGFyYW1ldGVycywgbGVnYWN5X3Byb2plY3Rpb25fdmlldwogICAgICAgICAgICBmb3IgcHVibGljX3JlcXVlc3QgaW4gZFsnc2NlbmFyaW9zJ106CiAgICAgICAgICAgICAgICBhcHBseV9zY2VuYXJpb19wYXJhbWV0ZXJzKHNwZWMsIHB1YmxpY19yZXF1ZXN0KQogICAgICAgICAgICBwcm9qZWN0ZWRfc2NlbmFyaW9zID0gbGVnYWN5X3Byb2plY3Rpb25fdmlldyhzcGVjLCBkWydzY2VuYXJpb3MnXSkKICAgICAgICAgICAgaW50cnVzaW9uID0gbmV4dChzIGZvciBzIGluIHByb2plY3RlZF9zY2VuYXJpb3MgaWYgc1snc2NlbmFyaW9Db2RlJ109PSdJTlRSVVNJT04nKQogICAgICAgICAgICBjZmcgPSBkaWN0KHNwZWMuZ2V0KCdpbnRydXNpb24nKSBvciB7fSkKICAgICAgICAgICAgY2ZnLnVwZGF0ZShlbmFibGVkPWludHJ1c2lvblsnZW5hYmxlZCddLCBjb25maWRlbmNlPWludHJ1c2lvblsnY29uZmlkZW5jZSddKQogICAgICAgICAgICByb2kgPSBpbnRydXNpb25bJ3JvaXMnXVswXSBpZiBpbnRydXNpb25bJ3JvaXMnXSBlbHNlIE5vbmUKICAgICAgICAgICAgY2ZnWydyb2knXSA9IHJvaVsncG9pbnRzJ10gaWYgcm9pIGVsc2UgW1swLiwwLl0sWzEuLDAuXSxbMS4sMS5dLFswLiwxLl1dCiAgICAgICAgICAgIGlmIHJvaToKICAgICAgICAgICAgICAgIGNmZ1sncm9pX25hbWUnXSA9IHJvaVsnbGFiZWwnXQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgY2ZnLnBvcCgncm9pX25hbWUnLCBOb25lKQogICAgICAgICAgICBzcGVjWydpbnRydXNpb24nXSA9IGNmZwogICAgICAgICAgICBmcm9tIGFwcC5yZWdpb25fc2NlbmFyaW8gaW1wb3J0IHByb2plY3RfbG9pdGVyaW5nLCB2YWxpZGF0ZSBhcyB2YWxpZGF0ZV9yZWdpb24KICAgICAgICAgICAgZnJvbSBhcHAuZmlyZV9jb25maWcgaW1wb3J0IHByb2plY3RfZmlyZQogICAgICAgICAgICBmcm9tIGFwcC5mYWxsX3J1bnRpbWUgaW1wb3J0IHByb2plY3RfZmFsbAogICAgICAgICAgICBmcm9tIGFwcC5maWdodF9ydW50aW1lIGltcG9ydCBwcm9qZWN0X2ZpZ2h0CiAgICAgICAgICAgIGZyb20gYXBwLmNyb3dkX3J1bnRpbWUgaW1wb3J0IHByb2plY3RfY3Jvd2RfY2FuZGlkYXRlCiAgICAgICAgICAgIHNwZWNbJ3NjZW5hcmlvcyddID0gJ29mZicKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgcHJvamVjdF9sb2l0ZXJpbmcoc3BlYywgcHJvamVjdGVkX3NjZW5hcmlvcykKICAgICAgICAgICAgICAgIHByb2plY3RfZmFsbChzcGVjLCBwcm9qZWN0ZWRfc2NlbmFyaW9zKQogICAgICAgICAgICAgICAgcHJvamVjdF9maWdodChzcGVjLCBwcm9qZWN0ZWRfc2NlbmFyaW9zKQogICAgICAgICAgICAgICAgcHJvamVjdF9maXJlKHNwZWMsIHByb2plY3RlZF9zY2VuYXJpb3MpCiAgICAgICAgICAgICAgICBzcGVjID0gcHJvamVjdF9jcm93ZF9jYW5kaWRhdGUoc3BlYywgcHJvamVjdGVkX3NjZW5hcmlvcykKICAgICAgICAgICAgICAgIHZhbGlkYXRlX3JlZ2lvbihzcGVjKQogICAgICAgICAgICBleGNlcHQgVmFsdWVFcnJvciBhcyBleGM6CiAgICAgICAgICAgICAgICBpZiBzdHIoZXhjKSA9PSAnTkVFRFNfTVVMVElfUFJPVklERVJfUlVOVElNRV9DT05GSVJNQVRJT04nIG9yIHN0cihleGMpLnN0YXJ0c3dpdGgoJ0NST1dEXycpOgogICAgICAgICAgICAgICAgICAgIHJhaXNlIENvbnRyb2xFcnJvcihzdHIoZXhjKSkgZnJvbSBOb25lCiAgICAgICAgICAgICAgICByYWlzZSBDb250cm9sRXJyb3IoJ0xPSVRFUklOR19DT05GSUdVUkFUSU9OX1VOU1VQUE9SVEVEJykgZnJvbSBleGMKICAgICAgICAgICAgIyBOb24tc2VjcmV0IHByb3ZlbmFuY2U6IHVuc3VwcG9ydGVkIHJlcXVlc3RzIGFyZSBleHBsaWNpdCBza2lwcywgbm90IHNpbGVudCBzdWNjZXNzLgogICAgICAgICAgICBzcGVjWydzZWN1cmVfY29udHJvbF9wcm9qZWN0aW9uJ10gPSB7CiAgICAgICAgICAgICAgICAncHJvZmlsZSc6ICdSRVNUX1NUQVRFTEVTUycsCiAgICAgICAgICAgICAgICAnc2tpcHBlZFNjZW5hcmlvcyc6IFtzWydzY2VuYXJpb0NvZGUnXSBmb3IgcyBpbiBkWydzY2VuYXJpb3MnXQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgc1snZW5hYmxlZCddIGFuZCBzWydzY2VuYXJpb0NvZGUnXSBub3QgaW4gKCdJTlRSVVNJT04nLCAnTE9JVEVSSU5HJywgJ0ZJUkUnLCAnRkFMTCcsICdGSUdIVCcsICdDUk9XRCcpXSwKICAgICAgICAgICAgICAgICdpZ25vcmVkSW50cnVzaW9uUm9pcyc6IG1heCgwLCBsZW4oaW50cnVzaW9uWydyb2lzJ10pLTEpLAogICAgICAgICAgICAgICAgJ3JlcXVlc3RlZFJ0cENsb2NrUmF0ZSc6IGRbJ3J0cENsb2NrUmF0ZSddLAogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIHNwZWMuZ2V0KCdjcm93ZF9zdGFydF9yZWplY3Rpb24nKToKICAgICAgICAgICAgICAgIHNwZWNbJ3NlY3VyZV9jb250cm9sX3Byb2plY3Rpb24nXVsnc2tpcHBlZFNjZW5hcmlvcyddLmFwcGVuZCgnQ1JPV0QnKQogICAgICAgICAgICAgICAgc3BlY1snc2VjdXJlX2NvbnRyb2xfcHJvamVjdGlvbiddWydjcm93ZFNraXBSZWFzb24nXSA9IHNwZWNbJ2Nyb3dkX3N0YXJ0X3JlamVjdGlvbiddCiAgICAgICAgICAgICMgSW5mZXJlbmNlL21vZGVsL3NvdXJjZSBvcHRpb25zIGFuZCBsb2NhbCBzdG9yYWdlIGtub2JzIHJlbWFpbiB0aGUgc2F2ZWQgdmFsdWVzLgogICAgICAgICAgICBzcGVjWydzY2VuYXJpb3MnXSA9ICdvZmYnCiAgICAgICAgICAgIGZvciBrZXkgaW4gKCdyZWNTZXJ2ZXJJZCcsJ3JlY0NhbWVyYUlkJyk6CiAgICAgICAgICAgICAgICBpZiBrZXkgaW4gZDoKICAgICAgICAgICAgICAgICAgICBzcGVjWydyZWNfc2VydmVyX2lkJyBpZiBrZXk9PSdyZWNTZXJ2ZXJJZCcgZWxzZSAncmVjX2NhbWVyYV9pZCddID0gZFtrZXldCiAgICAgICAgICAgIHJldHVybiBtLmFwcGx5X2FuZF9zdGFydChzcGVjKQoKICAgIGRlZiBzdG9wX2NhbWVyYShzZWxmLCBjYW1lcmEpOgogICAgICAgIHdpdGggc2VsZi5tYW5hZ2VyLl9jb21tYW5kczoKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgc2lkID0gc2VsZi5tYW5hZ2VyLmNhbWVyYV9zdHJlYW1faWQoc3RyKGNhbWVyYSkpCiAgICAgICAgICAgIGV4Y2VwdCBLZXlFcnJvcjoKICAgICAgICAgICAgICAgIHJldHVybiBOb25lCiAgICAgICAgICAgIGdyb3VwID0gc2VsZi5tYW5hZ2VyLmdldChzaWQpCiAgICAgICAgICAgIGlmIGdyb3VwLnNwZWMuZ2V0KCdzZXJ2ZXJfaWQnKSAhPSBzZWxmLnNlcnZlcl9pZDoKICAgICAgICAgICAgICAgIHJhaXNlIENvbnRyb2xFcnJvcignU0VSVkVSX0lEX0NPTkZMSUNUJykKICAgICAgICAgICAgcmV0dXJuIHNlbGYubWFuYWdlci5zdG9wKHNpZCkKCgoKZGVmIGF1dGhvcml6ZWQocmVxdWVzdCwgdG9rZW4pOgogICAgdmFsdWVzID0gcmVxdWVzdC5oZWFkZXJzLmdldGxpc3QoJ2F1dGhvcml6YXRpb24nKQogICAgcmV0dXJuIChsZW4odmFsdWVzKSA9PSAxIGFuZAogICAgICAgICAgICBobWFjLmNvbXBhcmVfZGlnZXN0KHZhbHVlc1swXS5lbmNvZGUoJ3V0Zi04JyksICgnQmVhcmVyICcrdG9rZW4pLmVuY29kZSgndXRmLTgnKSkpCgoKZGVmIGJ1aWxkX3JvdXRlcihtYW5hZ2VyLCB0b2tlbiwgc2VydmVyX2lkLCB0ZW1wbGF0ZT1Ob25lKToKICAgIGZyb20gYXBwLmFwcGxpY2F0aW9uLmNhbWVyYV9jb21tYW5kcyBpbXBvcnQgQ2FtZXJhQ29tbWFuZHMsIENvbW1hbmRVbmF2YWlsYWJsZQogICAgc2VydmljZSA9IENvbnRyb2xTZXJ2aWNlKG1hbmFnZXIsIHNlcnZlcl9pZCwgdGVtcGxhdGUpCiAgICBvd25lciA9IENhbWVyYUNvbW1hbmRzKHNlcnZpY2UsIGNhcGFjaXR5PTE2LCBoaXN0b3J5PTY0KQoKICAgIGRlZiBjb21wbGV0ZWQoam9iLCBmdXR1cmUpOgogICAgICAgIGZyb20gYXBwLnRyYWNlX2NvbW1hbmRzIGltcG9ydCBjb21wbGV0aW9uCiAgICAgICAgY29tcGxldGlvbihqb2IsIGZ1dHVyZSwgZW1pdD10cmFjZV9lbWl0LCBlcnJvcl9jb2RlPWNvbW1hbmRfZXJyb3IsIGxvZ2dlcj1MT0cpCgogICAgQGFzeW5jY29udGV4dG1hbmFnZXIKICAgIGFzeW5jIGRlZiBsaWZlc3BhbihhcHApOgogICAgICAgIHRyeToKICAgICAgICAgICAgeWllbGQKICAgICAgICBmaW5hbGx5OgogICAgICAgICAgICBpZiBub3QgYXdhaXQgYXN5bmNpby50b190aHJlYWQob3duZXIuY2xvc2UsIDIpOgogICAgICAgICAgICAgICAgcmFpc2UgUnVudGltZUVycm9yKCdTRUNVUkVfQ09NTUFORF9DTEVBTlVQX1BFTkRJTkcnKQoKICAgIHJvdXRlciA9IEFQSVJvdXRlcihsaWZlc3Bhbj1saWZlc3BhbikKCiAgICBAcm91dGVyLmdldCgnL2ludGVybmFsL3NlY3VyZS1jb250cm9sL3RyYWluaW5nL3NldHRpbmdzJykKICAgIGRlZiB0cmFpbmluZ19zZXR0aW5ncyhyZXF1ZXN0OiBSZXF1ZXN0KToKICAgICAgICBpZiBub3QgYXV0aG9yaXplZChyZXF1ZXN0LCB0b2tlbik6CiAgICAgICAgICAgIHJldHVybiBKU09OUmVzcG9uc2UoeydlcnJvcic6J0NPTlRST0xfVU5BVVRIT1JJWkVEJ30sc3RhdHVzX2NvZGU9NDAxKQogICAgICAgIHRyYWluaW5nID0gZ2V0YXR0cihyZXF1ZXN0LmFwcC5zdGF0ZSwgJ3RyYWluaW5nJywgTm9uZSkKICAgICAgICBpZiB0cmFpbmluZyBpcyBOb25lOgogICAgICAgICAgICByZXR1cm4gSlNPTlJlc3BvbnNlKHsnZXJyb3InOidUUkFJTklOR19OT1RfQ09ORklHVVJFRCd9LHN0YXR1c19jb2RlPTUwMykKICAgICAgICByZXR1cm4gZGljdCgqKnRyYWluaW5nLnN0b3JlLnNldHRpbmdzKCksIHN0YXR1cz10cmFpbmluZy5zdGF0dXMoKSkKCiAgICBAcm91dGVyLnBhdGNoKCcvaW50ZXJuYWwvc2VjdXJlLWNvbnRyb2wvdHJhaW5pbmcvc2V0dGluZ3MnKQogICAgYXN5bmMgZGVmIHBhdGNoX3RyYWluaW5nX3NldHRpbmdzKHJlcXVlc3Q6IFJlcXVlc3QpOgogICAgICAgIGlmIG5vdCBhdXRob3JpemVkKHJlcXVlc3QsIHRva2VuKToKICAgICAgICAgICAgcmV0dXJuIEpTT05SZXNwb25zZSh7J2Vycm9yJzonQ09OVFJPTF9VTkFVVEhPUklaRUQnfSxzdGF0dXNfY29kZT00MDEpCiAgICAgICAgdHJhaW5pbmcgPSBnZXRhdHRyKHJlcXVlc3QuYXBwLnN0YXRlLCAndHJhaW5pbmcnLCBOb25lKQogICAgICAgIGlmIHRyYWluaW5nIGlzIE5vbmU6CiAgICAgICAgICAgIHJldHVybiBKU09OUmVzcG9uc2UoeydlcnJvcic6J1RSQUlOSU5HX05PVF9DT05GSUdVUkVEJ30sc3RhdHVzX2NvZGU9NTAzKQogICAgICAgIHRyeToKICAgICAgICAgICAgcmF3ID0gYnl0ZWFycmF5KCkKICAgICAgICAgICAgYXN5bmMgd2l0aCBhc3luY2lvLnRpbWVvdXQoMSk6CiAgICAgICAgICAgICAgICBhc3luYyBmb3IgY2h1bmsgaW4gcmVxdWVzdC5zdHJlYW0oKToKICAgICAgICAgICAgICAgICAgICByYXcuZXh0ZW5kKGNodW5rKQogICAgICAgICAgICAgICAgICAgIGlmIGxlbihyYXcpPjQwOTY6CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBKU09OUmVzcG9uc2UoeydlcnJvcic6J0JPRFlfVE9PX0xBUkdFJ30sc3RhdHVzX2NvZGU9NDEzKQogICAgICAgICAgICB2YWx1ZSA9IGRlY29kZShieXRlcyhyYXcpKQogICAgICAgICAgICBpZiBzZXQodmFsdWUpICE9IHsnZXhwZWN0ZWRfcmV2aXNpb24nLCdjaGFuZ2VzJ306CiAgICAgICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdJbnZhbGlkIHRyYWluaW5nIHBhdGNoLicpCiAgICAgICAgICAgIHJldHVybiBhd2FpdCBhc3luY2lvLnRvX3RocmVhZCh0cmFpbmluZy5zdG9yZS5wYXRjaCx2YWx1ZVsnZXhwZWN0ZWRfcmV2aXNpb24nXSx2YWx1ZVsnY2hhbmdlcyddKQogICAgICAgIGV4Y2VwdCBSdW50aW1lRXJyb3I6CiAgICAgICAgICAgIHJldHVybiBKU09OUmVzcG9uc2UoeydlcnJvcic6J1JFVklTSU9OX0NPTkZMSUNUJ30sc3RhdHVzX2NvZGU9NDA5KQogICAgICAgIGV4Y2VwdCAoVmFsdWVFcnJvciwgVHlwZUVycm9yLCBUaW1lb3V0RXJyb3IpOgogICAgICAgICAgICByZXR1cm4gSlNPTlJlc3BvbnNlKHsnZXJyb3InOidJTlZBTElEX1RSQUlOSU5HX1NFVFRJTkdTJ30sc3RhdHVzX2NvZGU9NDIyKQogICAgICAgIGV4Y2VwdCBPU0Vycm9yOgogICAgICAgICAgICByZXR1cm4gSlNPTlJlc3BvbnNlKHsnZXJyb3InOidUUkFJTklOR19QRVJTSVNURU5DRV9GQUlMRUQnfSxzdGF0dXNfY29kZT01MDMpCgogICAgQHJvdXRlci5nZXQoJy9pbnRlcm5hbC9zZWN1cmUtY29udHJvbC9ydW50aW1lLXN0YXR1cycpCiAgICBhc3luYyBkZWYgcnVudGltZV9zdGF0dXMocmVxdWVzdDogUmVxdWVzdCk6CiAgICAgICAgaWYgbm90IGF1dGhvcml6ZWQocmVxdWVzdCwgdG9rZW4pOgogICAgICAgICAgICByZXR1cm4gSlNPTlJlc3BvbnNlKHsnZXJyb3InOiAnQ09OVFJPTF9VTkFVVEhPUklaRUQnfSwgc3RhdHVzX2NvZGU9NDAxKQogICAgICAgICMgUGFyZW50LW9ubHkgbGlmZWN5Y2xlIHNuYXBzaG90czsgbmV2ZXIgcXVlcnkgYSBjaGlsZCBjb2xsZWN0b3Igb3ZlciBJUEMuCiAgICAgICAgd2l0aCBtYW5hZ2VyLl9sb2NrOgogICAgICAgICAgICBncm91cHMgPSBsaXN0KG1hbmFnZXIuX2dyb3Vwcy52YWx1ZXMoKSkKICAgICAgICBzdHJlYW1zID0gW10KICAgICAgICBjb3VudHMgPSBkaWN0KHJ1bm5pbmc9MCwgc3RhcnRpbmc9MCwgc3RvcHBlZD0wLCBlcnJvcj0wLCB0b3RhbD1sZW4oZ3JvdXBzKSkKICAgICAgICBmb3IgZ3JvdXAgaW4gZ3JvdXBzOgogICAgICAgICAgICBzID0gZ3JvdXAubGlmZWN5Y2xlLnNuYXBzaG90KCkKICAgICAgICAgICAgb2JzZXJ2ZWQgPSBzWydvYnNlcnZlZF9zdGF0ZSddLnVwcGVyKCkKICAgICAgICAgICAgZXJyb3IgPSBOb25lCiAgICAgICAgICAgIGlmIG9ic2VydmVkIG5vdCBpbiAoJ1JVTk5JTkcnLCAnU1RBUlRJTkcnLCAnU1RPUFBFRCcsICdFUlJPUicpOgogICAgICAgICAgICAgICAgZXJyb3IsIG9ic2VydmVkID0gJ1RSQU5TSVRJT05fJyArIG9ic2VydmVkLCAnRVJST1InCiAgICAgICAgICAgIGVsaWYgcy5nZXQoJ2xhc3RfZXJyb3InKToKICAgICAgICAgICAgICAgIGVycm9yID0gJ1JVTlRJTUVfUkVQT1JURURfRVJST1InCiAgICAgICAgICAgIGNvdW50c1tvYnNlcnZlZC5sb3dlcigpXSArPSAxCiAgICAgICAgICAgIHN0cmVhbXMuYXBwZW5kKHsnY2FtZXJhSWQnOiBzdHIoZ3JvdXAuc3BlYy5nZXQoJ3NvdXJjZV9pZCcpIG9yIGdyb3VwLnN0cmVhbV9pZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnc3RyZWFtSWQnOiBncm91cC5zdHJlYW1faWQsICdydW5JZCc6IHNbJ3J1bl9pZCddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3J1bkdlbmVyYXRpb24nOiBzWydydW5fZ2VuZXJhdGlvbiddLCAnZGVzaXJlZFN0YXRlJzogc1snZGVzaXJlZF9zdGF0ZSddLnVwcGVyKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnb2JzZXJ2ZWRTdGF0ZSc6IG9ic2VydmVkLCAnbGFzdEVycm9yJzogZXJyb3J9KQogICAgICAgIHJldHVybiB7J3NlcnZlcklkJzogc2VydmVyX2lkLCAnc3RhdHVzJzogJ1JFQURZJywgJ21vZGVsTmFtZSc6IE5vbmUsCiAgICAgICAgICAgICAgICAnZGVwZW5kZW5jaWVzJzogeydydW50aW1lJzogeydvayc6IFRydWUsICdlcnJvcic6IE5vbmV9fSwKICAgICAgICAgICAgICAgICdzdHJlYW1Db3VudHMnOiBjb3VudHMsICdzdHJlYW1zJzogc3RyZWFtc30KCiAgICBhc3luYyBkZWYgY29tbWFuZChyZXF1ZXN0LCBhY3Rpb24pOgogICAgICAgIHJlcXVlc3RfaWQgPSBSRVFVRVNUX0lELmdldCgpIG9yIHV1aWQ0KCkuaGV4CiAgICAgICAgaWYgbm90IGF1dGhvcml6ZWQocmVxdWVzdCwgdG9rZW4pOgogICAgICAgICAgICByZXR1cm4gSlNPTlJlc3BvbnNlKHsnZXJyb3InOidDT05UUk9MX1VOQVVUSE9SSVpFRCd9LHN0YXR1c19jb2RlPTQwMSkKICAgICAgICByYXc9Ynl0ZWFycmF5KCkKICAgICAgICB0cnk6CiAgICAgICAgICAgIGFzeW5jIHdpdGggYXN5bmNpby50aW1lb3V0KC4yNSk6CiAgICAgICAgICAgICAgICBhc3luYyBmb3IgY2h1bmsgaW4gcmVxdWVzdC5zdHJlYW0oKToKICAgICAgICAgICAgICAgICAgICBpZiBsZW4ocmF3KStsZW4oY2h1bmspPk1BWF9CT0RZOgogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gSlNPTlJlc3BvbnNlKHsnZXJyb3InOidCT0RZX1RPT19MQVJHRSd9LHN0YXR1c19jb2RlPTQxMykKICAgICAgICAgICAgICAgICAgICByYXcuZXh0ZW5kKGNodW5rKQogICAgICAgIGV4Y2VwdCBUaW1lb3V0RXJyb3I6CiAgICAgICAgICAgIHJldHVybiBKU09OUmVzcG9uc2UoeydlcnJvcic6J0JPRFlfVElNRU9VVCd9LHN0YXR1c19jb2RlPTQwOCkKICAgICAgICB0cnk6CiAgICAgICAgICAgIGQgPSBkZWNvZGUocmF3KQogICAgICAgICAgICBjYW0gPSBjYW1lcmFfaWQoZCkKICAgICAgICAgICAgaWYgYWN0aW9uID09ICdzdGFydCc6CiAgICAgICAgICAgICAgICB2YWxpZGF0ZV9zdGFydChkKQogICAgICAgICAgICAgICAgdmFsdWUgPSBTdGFydChqc29uLmR1bXBzKGQsc29ydF9rZXlzPVRydWUsc2VwYXJhdG9ycz0oJywnLCc6JyksYWxsb3dfbmFuPUZhbHNlKSkKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIGlmIHNldChkKSAhPSB7J2NhbWVyYUlkJ306CiAgICAgICAgICAgICAgICAgICAgcmFpc2UgQ29udHJvbEVycm9yKCdTVE9QX0ZJRUxEU19JTlZBTElEJykKICAgICAgICAgICAgICAgIHZhbHVlID0gTm9uZQogICAgICAgICAgICBqb2IgPSBvd25lci5zdWJtaXQoY2FtLCB2YWx1ZSwgYWN0aW9uKQogICAgICAgICAgICAjIFJlZ2lzdGVyIG9uY2UgZXZlbiB3aGVuIGFuIGluLWZsaWdodCBkdXBsaWNhdGUgcmV1c2VzIHRoZSBzYW1lIG9wZXJhdGlvbi4KICAgICAgICAgICAgaWYgbm90IGdldGF0dHIoam9iLCAnX3NlY3VyZV9vYnNlcnZlZCcsIEZhbHNlKToKICAgICAgICAgICAgICAgIGpvYi5fc2VjdXJlX29ic2VydmVkID0gVHJ1ZQogICAgICAgICAgICAgICAgam9iLl90cmFjZV9yZXF1ZXN0ID0gcmVxdWVzdF9pZAogICAgICAgICAgICAgICAgTE9HLmluZm8oJ3NlY3VyZV9jb21tYW5kIG9wZXJhdGlvbj0lcyBjYW1lcmE9JXMgYWN0aW9uPSVzIG91dGNvbWU9QUNDRVBURUQnLAogICAgICAgICAgICAgICAgICAgICAgICAgam9iLm9wZXJhdGlvbl9pZCwgY2FtLCBhY3Rpb24pCiAgICAgICAgICAgICAgICBqb2IuZnV0dXJlLmFkZF9kb25lX2NhbGxiYWNrKGxhbWJkYSBkb25lOiBjb21wbGV0ZWQoam9iLCBkb25lKSkKICAgICAgICAgICAgdHJhY2VfZW1pdChkaXJlY3Rpb249J1dFQl9UT19BSScsIGNvbXBvbmVudD0ncnVudGltZScsIHBoYXNlPSdDT01NQU5EX0FDQ0VQVEVEJywKICAgICAgICAgICAgICAgICAgICAgICByZXF1ZXN0SWQ9cmVxdWVzdF9pZCwgb3BlcmF0aW9uSWQ9am9iLm9wZXJhdGlvbl9pZCwgY2FtZXJhSWQ9c3RyKGNhbSksIGFjdGlvbj1hY3Rpb24pCiAgICAgICAgICAgICMgV2FpdCBvbmx5IGZvciBhZG1pc3Npb24gd29yaywgbmV2ZXIgZm9yIEdQVS9maXJzdCBGcmFtZS4gVGltZW91dCBkb2VzIE5PVCBjYW5jZWwgdGhlIGpvYi4KICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgZnV0dXJlID0gYXN5bmNpby53cmFwX2Z1dHVyZShqb2IuZnV0dXJlKQogICAgICAgICAgICAgICAgIyBUaGUgSFRUUCBidWRnZXQgbWF5IGVuZCBiZWZvcmUgcXVldWVkIHdvcmsuIENvbnN1bWUgbGF0ZXIgZXJyb3JzIHdpdGhvdXQKICAgICAgICAgICAgICAgICMgY2FuY2VsbGluZyB3b3JrIG9yIGxvc2luZyBpdHMgc3RhdHVzIGluIENhbWVyYUNvbW1hbmRzJyBib3VuZGVkIGhpc3RvcnkuCiAgICAgICAgICAgICAgICBmdXR1cmUuYWRkX2RvbmVfY2FsbGJhY2sobGFtYmRhIGRvbmU6IE5vbmUgaWYgZG9uZS5jYW5jZWxsZWQoKSBlbHNlIGRvbmUuZXhjZXB0aW9uKCkpCiAgICAgICAgICAgICAgICBncm91cCA9IGF3YWl0IGFzeW5jaW8ud2FpdF9mb3IoYXN5bmNpby5zaGllbGQoZnV0dXJlKSwgLjM1KQogICAgICAgICAgICAgICAgaWYgZ3JvdXAgaXMgTm9uZToKICAgICAgICAgICAgICAgICAgICBzdGF0ZSA9ICdTVE9QUEVEJwogICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICBzdGF0ZSA9IGdyb3VwLm9ic2VydmVkX3N0YXRlLnVwcGVyKCkKICAgICAgICAgICAgZXhjZXB0IGFzeW5jaW8uVGltZW91dEVycm9yOgogICAgICAgICAgICAgICAgc3RhdGUgPSAnQ09NTUFORF9QRU5ESU5HJwogICAgICAgICAgICBleGNlcHQgQ29udHJvbEVycm9yIGFzIGV4YzoKICAgICAgICAgICAgICAgIHJldHVybiBKU09OUmVzcG9uc2UoeydlcnJvcic6Y29tbWFuZF9lcnJvcihleGMpfSxzdGF0dXNfY29kZT00MDkpCiAgICAgICAgICAgIGV4Y2VwdCBFeGNlcHRpb246CiAgICAgICAgICAgICAgICByZXR1cm4gSlNPTlJlc3BvbnNlKHsnZXJyb3InOidSVU5USU1FX0NPTU1BTkRfUkVKRUNURUQnfSxzdGF0dXNfY29kZT00MDkpCiAgICAgICAgICAgIHNraXBwZWQgPSBbXQogICAgICAgICAgICByZXR1cm4gSlNPTlJlc3BvbnNlKHsncmVzdWx0JzonQ09NTUFORF9BQ0NFUFRFRCcsJ2NhbWVyYUlkJzpjYW0sJ29wZXJhdGlvbklkJzpqb2Iub3BlcmF0aW9uX2lkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnb2JzZXJ2ZWRTdGF0ZSc6c3RhdGUsJ3NraXBwZWRTY2VuYXJpb3MnOnNraXBwZWR9LHN0YXR1c19jb2RlPTIwMikKICAgICAgICBleGNlcHQgQ29udHJvbEVycm9yIGFzIGV4YzoKICAgICAgICAgICAgcmV0dXJuIEpTT05SZXNwb25zZSh7J2Vycm9yJzpzdHIoZXhjKX0sc3RhdHVzX2NvZGU9NDIyKQogICAgICAgIGV4Y2VwdCBDb21tYW5kVW5hdmFpbGFibGU6CiAgICAgICAgICAgIHJldHVybiBKU09OUmVzcG9uc2UoeydlcnJvcic6J0NBTUVSQV9DT01NQU5EX0JVU1knfSxzdGF0dXNfY29kZT01MDMpCgogICAgQHJvdXRlci5wb3N0KCcvaW50ZXJuYWwvc2VjdXJlLWNvbnRyb2wvc3RhcnQnKQogICAgYXN5bmMgZGVmIHN0YXJ0KHJlcXVlc3Q6UmVxdWVzdCk6CiAgICAgICAgcmV0dXJuIGF3YWl0IGNvbW1hbmQocmVxdWVzdCwnc3RhcnQnKQoKICAgIEByb3V0ZXIucG9zdCgnL2ludGVybmFsL3NlY3VyZS1jb250cm9sL3N0b3AnKQogICAgYXN5bmMgZGVmIHN0b3AocmVxdWVzdDpSZXF1ZXN0KToKICAgICAgICByZXR1cm4gYXdhaXQgY29tbWFuZChyZXF1ZXN0LCdzdG9wJykKCiAgICBAcm91dGVyLmdldCgnL2ludGVybmFsL3NlY3VyZS1jb250cm9sL29wZXJhdGlvbnMve2lkZW50aWZpZXJ9JykKICAgIGFzeW5jIGRlZiBzdGF0dXMoaWRlbnRpZmllcjpzdHIscmVxdWVzdDpSZXF1ZXN0KToKICAgICAgICBpZiBub3QgYXV0aG9yaXplZChyZXF1ZXN0LCB0b2tlbik6CiAgICAgICAgICAgIHJldHVybiBKU09OUmVzcG9uc2UoeydlcnJvcic6J0NPTlRST0xfVU5BVVRIT1JJWkVEJ30sc3RhdHVzX2NvZGU9NDAxKQogICAgICAgIGpvYj1vd25lci5nZXQoaWRlbnRpZmllcikKICAgICAgICBpZiBqb2IgaXMgTm9uZToKICAgICAgICAgICAgcmV0dXJuIEpTT05SZXNwb25zZSh7J2Vycm9yJzonTk9UX0ZPVU5EJ30sc3RhdHVzX2NvZGU9NDA0KQogICAgICAgIHN0YXRlPSdQRU5ESU5HJwogICAgICAgIGVycm9yPU5vbmUKICAgICAgICBpZiBqb2IuZnV0dXJlLmRvbmUoKToKICAgICAgICAgICAgc3RhdGU9J0ZBSUxFRCcgaWYgam9iLmZ1dHVyZS5leGNlcHRpb24oKSBlbHNlICdDT01NQU5EX0FQUExJRUQnCiAgICAgICAgICAgIGlmIGpvYi5mdXR1cmUuZXhjZXB0aW9uKCk6CiAgICAgICAgICAgICAgICBlcnJvcj1jb21tYW5kX2Vycm9yKGpvYi5mdXR1cmUuZXhjZXB0aW9uKCkpCiAgICAgICAgcmV0dXJuIHsnb3BlcmF0aW9uSWQnOmlkZW50aWZpZXIsJ2NhbWVyYUlkJzpqb2IuY2FtZXJhX2lkLCdzdGF0dXMnOnN0YXRlLCdlcnJvcic6ZXJyb3J9CgogICAgcmV0dXJuIHJvdXRlcgo=",
    "app/stream_settings.py": "IiIiVEhSRVNILTAxOiDtkZzsi5wg7ZWE7YSw7JmAIOq4sOyhtCBkb3duc3RyZWFtIO2VhO2EsOulvCDrtoTrpqztlZwg7LWc7IaMIOyEpOyglSBwcm9qZWN0aW9uLiIiIgpmcm9tIGNvcHkgaW1wb3J0IGRlZXBjb3B5CmltcG9ydCBoYXNobGliCmltcG9ydCBqc29uCmltcG9ydCBtYXRoCmZyb20gYXBwLmludHJ1c2lvbiBpbXBvcnQgSW50cnVzaW9uQ29uZmlnCmZyb20gYXBwLmxvaXRlcmluZyBpbXBvcnQgTG9pdGVyaW5nQ29uZmlnCmZyb20gYXBwLnJlZ2lvbl9zY2VuYXJpbyBpbXBvcnQgdmFsaWRhdGUgYXMgdmFsaWRhdGVfcmVnaW9uX3NjZW5hcmlvCmZyb20gYXBwLmNsYXNzX2NhdGFsb2cgaW1wb3J0IENPQ09fTkFNRVMKZnJvbSBhcHAucG9zZV9jb25maWcgaW1wb3J0IFBvc2VDb25maWcsIGV4ZWN1dGlvbl9wbGFuCmZyb20gYXBwLmZpcmVfY29uZmlnIGltcG9ydCBGaXJlQ29uZmlnLCBGSVJFX01PREVMLCBGSVJFX05BTUVTCmZyb20gYXBwLmJ5dGVfdHJhY2tpbmcgaW1wb3J0IFRyYWNraW5nU2V0dGluZ3MKZnJvbSBhcHAuZmFsbF9ydW50aW1lIGltcG9ydCBGYWxsU2V0dGluZ3MsIHZhbGlkYXRlIGFzIHZhbGlkYXRlX2ZhbGwKZnJvbSBhcHAuZmlnaHRfcnVudGltZSBpbXBvcnQgRmlnaHRTZXR0aW5ncywgdmFsaWRhdGUgYXMgdmFsaWRhdGVfZmlnaHQKZnJvbSBhcHAuY3Jvd2RfY29uZmlnIGltcG9ydCBDcm93ZENvbmZpZywgQ1JPV0RfTU9ERUwsIENST1dEX05BTUVTCgoKZGVmIHRyYWNraW5nX3NldHRpbmdzKHNwZWMpOgogICAgdmFsaWRhdGVfcmVnaW9uX3NjZW5hcmlvKHNwZWMpCiAgICB2YWxpZGF0ZV9mYWxsKHNwZWMpCiAgICB2YWxpZGF0ZV9maWdodChzcGVjKQogICAgdHJhY2tpbmcgPSBUcmFja2luZ1NldHRpbmdzLnBhcnNlKHNwZWMuZ2V0KCd0cmFja2luZycsIHt9KSkKICAgIGlmIG5vdCB0cmFja2luZy5lbmFibGVkOgogICAgICAgIGlmIG5vdCBzcGVjLmdldCgnc2VydmVyX2lkJykgb3Igbm90IHNwZWMuZ2V0KCdzb3VyY2VfaWQnKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignQ2Fub25pY2FsIGlkZW50aXR5IGlzIHJlcXVpcmVkIGZvciBUcmFja2luZyBPZmYuJykKICAgICAgICBpZiBJbnRydXNpb25Db25maWcucGFyc2Uoc3BlYy5nZXQoJ2ludHJ1c2lvbicsIHt9KSkuZW5hYmxlZDoKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSU5UUlVTSU9OIHJlcXVpcmVzIFRyYWNraW5nIE9uLicpCiAgICByZXR1cm4gdHJhY2tpbmcKCgpkZWYgZGlzcGxheV9jYXRlZ29yaWVzKHZhbHVlKToKICAgIGlmIHZhbHVlIGlzIE5vbmU6CiAgICAgICAgcmV0dXJuIE5vbmUKICAgIGlmICh0eXBlKHZhbHVlKSBpcyBub3QgbGlzdCBvciBsZW4odmFsdWUpID4gODAKICAgICAgICAgICAgb3IgYW55KHR5cGUoaykgaXMgbm90IHN0ciBvciBrIG5vdCBpbiAoKkNPQ09fTkFNRVMsICpGSVJFX05BTUVTLCAqQ1JPV0RfTkFNRVMpIGZvciBrIGluIHZhbHVlKQogICAgICAgICAgICBvciBsZW4oc2V0KHZhbHVlKSkgIT0gbGVuKHZhbHVlKSk6CiAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBkaXNwbGF5IGNhdGVnb3JpZXMuJykKICAgIHJldHVybiBzb3J0ZWQodmFsdWUpCgoKZGVmIHZpc3VhbF9vcHRpb25zKHNwZWMpOgogICAgdmFsdWUgPSBzcGVjLmdldCgndmlzdWFsaXphdGlvbicpIG9yIHt9CiAgICBpZiBub3QgaXNpbnN0YW5jZSh2YWx1ZSwgZGljdCkgb3Igc2V0KHZhbHVlKSAtIHsnc2NvcmVfdGhyZXNob2xkJywgJ2NhdGVnb3JpZXMnLCAnZGVidWdfYWxsX2NhbmRpZGF0ZXMnfToKICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdJbnZhbGlkIHZpc3VhbGl6YXRpb24gc2V0dGluZ3MuJykKICAgIGNhdGVnb3JpZXMgPSBkaXNwbGF5X2NhdGVnb3JpZXModmFsdWUuZ2V0KCdjYXRlZ29yaWVzJykpCiAgICBkZWJ1ZyA9IHZhbHVlLmdldCgnZGVidWdfYWxsX2NhbmRpZGF0ZXMnLCBGYWxzZSkKICAgIGlmIHR5cGUoZGVidWcpIGlzIG5vdCBib29sOgogICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ0ludmFsaWQgZGVidWcgY2FuZGlkYXRlIHNldHRpbmcuJykKICAgIHJldHVybiBjYXRlZ29yaWVzLCBkZWJ1ZwoKCmRlZiBzY29yZSh2YWx1ZSk6CiAgICBpZiB0eXBlKHZhbHVlKSBub3QgaW4gKGludCwgZmxvYXQpIG9yIG5vdCBtYXRoLmlzZmluaXRlKHZhbHVlKSBvciBub3QgMCA8PSB2YWx1ZSA8PSAxOgogICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ1Njb3JlIG11c3QgYmUgZmluaXRlIGFuZCBiZXR3ZWVuIHplcm8gYW5kIG9uZS4nKQogICAgcmV0dXJuIHZhbHVlCgoKZGVmIGRpc3BsYXlfc2NvcmUoc3BlYywgZmFsbGJhY2spOgogICAgdmFsdWUgPSBzcGVjLmdldCgndmlzdWFsaXphdGlvbicpIG9yIHt9CiAgICB2aXN1YWxfb3B0aW9ucyhzcGVjKQogICAgcmV0dXJuIHNjb3JlKHZhbHVlLmdldCgnc2NvcmVfdGhyZXNob2xkJywgZmFsbGJhY2spKQoKCmRlZiByZXZpc2lvbihzcGVjKToKICAgIHJldHVybiBoYXNobGliLnNoYTI1Nihqc29uLmR1bXBzKHNwZWMsIHNvcnRfa2V5cz1UcnVlLCBzZXBhcmF0b3JzPSgnLCcsICc6JyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbG93X25hbj1GYWxzZSkuZW5jb2RlKCkpLmhleGRpZ2VzdCgpCgoKZGVmIHNldHRpbmdzX3ZpZXcoc3BlYyk6CiAgICBkb3duc3RyZWFtID0gKChzcGVjLmdldCgnaW5mZXJlbmNlX3Byb2ZpbGUnKSBvciB7fSkuZ2V0KCd0aHJlc2hvbGRzJykgb3Ige30pLmdldCgnc2NvcmUnLCAuNSkKICAgIHBsYW4gPSBleGVjdXRpb25fcGxhbihzcGVjKQogICAgZnJvbSBhcHAucHJvdmlkZXJfcGxhbiBpbXBvcnQgcGxhbiBhcyBtYWtlX3Byb3ZpZGVyX3BsYW4KICAgIHByb3ZpZGVycyA9IG1ha2VfcHJvdmlkZXJfcGxhbihzcGVjKQogICAgY2F0ZWdvcmllcyA9IFtdCiAgICBmb3IgcHJvdmlkZXIgaW4gcHJvdmlkZXJzLnByb3ZpZGVyczoKICAgICAgICBpZiBwcm92aWRlci5rZXkgPT0gJ2ZpcmUnOgogICAgICAgICAgICBuYW1lcyA9IEZJUkVfTkFNRVMKICAgICAgICAgICAgZm9yIGksIGtleSBpbiBlbnVtZXJhdGUobmFtZXMpOgogICAgICAgICAgICAgICAgY2F0ZWdvcmllcy5hcHBlbmQoZGljdChrZXk9a2V5LCBkaXNwbGF5TmFtZT1rZXksIG1vZGVsS2V5PXByb3ZpZGVyLm1vZGVsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzc0lkPWksIHNjZW5hcmlvcz1bJ0ZJUkUnXSkpCiAgICAgICAgZWxpZiBwcm92aWRlci5rZXkgPT0gJ2Nyb3dkJzoKICAgICAgICAgICAgZm9yIGksIGtleSBpbiBlbnVtZXJhdGUoQ1JPV0RfTkFNRVMpOgogICAgICAgICAgICAgICAgY2F0ZWdvcmllcy5hcHBlbmQoZGljdChrZXk9a2V5LCBkaXNwbGF5TmFtZT1rZXksIG1vZGVsS2V5PXByb3ZpZGVyLm1vZGVsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzc0lkPWksIHNjZW5hcmlvcz1bJ0NST1dEJ10pKQogICAgICAgIGVsaWYgcHJvdmlkZXIua2V5ID09ICdwb3NlJzoKICAgICAgICAgICAgY2F0ZWdvcmllcy5hcHBlbmQoZGljdChrZXk9J3BlcnNvbicsIGRpc3BsYXlOYW1lPSdwZXJzb24nLCBtb2RlbEtleT1wcm92aWRlci5tb2RlbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzc0lkPTAsIHNjZW5hcmlvcz1saXN0KHByb3ZpZGVyLnNjZW5hcmlvcykpKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIGZvciBpLCBrZXkgaW4gZW51bWVyYXRlKENPQ09fTkFNRVMpOgogICAgICAgICAgICAgICAgY2F0ZWdvcmllcy5hcHBlbmQoZGljdCgKICAgICAgICAgICAgICAgICAgICBrZXk9a2V5LCBkaXNwbGF5TmFtZT1rZXksIG1vZGVsS2V5PXByb3ZpZGVyLm1vZGVsLCBjbGFzc0lkPWksCiAgICAgICAgICAgICAgICAgICAgc2NlbmFyaW9zPShsaXN0KHByb3ZpZGVyLnNjZW5hcmlvcykgaWYgaSA9PSAwIGVsc2UgW10pKSkKICAgIHJldHVybiBkaWN0KAogICAgICAgIHJldmlzaW9uPXJldmlzaW9uKHNwZWMpLCBkaXNwbGF5X3Njb3JlPWRpc3BsYXlfc2NvcmUoc3BlYywgZG93bnN0cmVhbSksCiAgICAgICAgcG9zZT1Qb3NlQ29uZmlnLnBhcnNlKHNwZWMuZ2V0KCdwb3NlJywge30pKS5wYXlsb2FkKCksCiAgICAgICAgZmlyZT1GaXJlQ29uZmlnLnBhcnNlKHNwZWMuZ2V0KCdmaXJlJywge30pKS5wYXlsb2FkKCksCiAgICAgICAgZXhlY3V0aW9uX3BsYW49cGxhbiwgZG93bnN0cmVhbV9zY29yZT1kb3duc3RyZWFtLAogICAgICAgIGZyYW1lX3RpbWVfYW5jaG9yPXNwZWMuZ2V0KCdmcmFtZV90aW1lX2FuY2hvcicpLAogICAgICAgIGFuYWx5c2lzRnBzVGFyZ2V0PXNwZWMuZ2V0KCdhbmFseXNpc19mcHNfdGFyZ2V0JywgMTApLAogICAgICAgIHRyYWNraW5nPXRyYWNraW5nX3NldHRpbmdzKHNwZWMpLnBheWxvYWQoKSwKICAgICAgICBpbnRydXNpb249SW50cnVzaW9uQ29uZmlnLnBhcnNlKHNwZWMuZ2V0KCdpbnRydXNpb24nLCB7fSkpLnBheWxvYWQoKSwKICAgICAgICBsb2l0ZXJpbmc9TG9pdGVyaW5nQ29uZmlnLnBhcnNlKHNwZWMuZ2V0KCdsb2l0ZXJpbmcnLCB7fSkpLnBheWxvYWQoKSwKICAgICAgICBmYWxsPUZhbGxTZXR0aW5ncy5wYXJzZShzcGVjLmdldCgnZmFsbCcpIG9yIHt9KS5zZXR0aW5nc19wYXlsb2FkKCksCiAgICAgICAgZmlnaHQ9RmlnaHRTZXR0aW5ncy5wYXJzZShzcGVjLmdldCgnZmlnaHQnKSBvciB7fSkuc2V0dGluZ3NfcGF5bG9hZCgpLAogICAgICAgIGNyb3dkPUNyb3dkQ29uZmlnLnBhcnNlKHNwZWMuZ2V0KCdjcm93ZCcpIG9yIHt9KS5zZXR0aW5nc19wYXlsb2FkKCksCiAgICAgICAgZGlzcGxheV9jYXRlZ29yaWVzPXZpc3VhbF9vcHRpb25zKHNwZWMpWzBdLAogICAgICAgIGRlYnVnX2FsbF9jYW5kaWRhdGVzPXZpc3VhbF9vcHRpb25zKHNwZWMpWzFdLAogICAgICAgIGNhdGVnb3JpZXM9Y2F0ZWdvcmllcykKCgpkZWYgcGF0Y2hfc2V0dGluZ3Moc3BlYywgY2hhbmdlcyk6CiAgICBpZiBub3QgY2hhbmdlcyBvciBzZXQoY2hhbmdlcykgLSB7J3RyYWNraW5nJywgJ2ZpcmUnLCAnZmFsbCcsICdmaWdodCcsICdjcm93ZCcsICdwb3NlJywgJ2Rpc3BsYXlfc2NvcmUnLCAnZG93bnN0cmVhbV9zY29yZScsICdmcmFtZV90aW1lX2FuY2hvcicsICdhbmFseXNpc0Zwc1RhcmdldCcsICdpbnRydXNpb24nLCAnbG9pdGVyaW5nJywgJ2Rpc3BsYXlfY2F0ZWdvcmllcycsICdkZWJ1Z19hbGxfY2FuZGlkYXRlcyd9OgogICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ1Vuc3VwcG9ydGVkIHN0cmVhbSBzZXR0aW5ncy4nKQogICAgY2FuZGlkYXRlID0gZGVlcGNvcHkoc3BlYykKICAgIGZvciBmaWVsZCwgdmFsdWUgaW4gY2hhbmdlcy5pdGVtcygpOgogICAgICAgIGlmIGZpZWxkIGluICgnZmlnaHQnLCAnY3Jvd2QnKToKICAgICAgICAgICAgaWYgdHlwZSh2YWx1ZSkgaXMgbm90IGRpY3Q6CiAgICAgICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdJbnZhbGlkIHNjZW5hcmlvIHBhdGNoLicpCiAgICAgICAgICAgIHBhcnNlciA9IEZpZ2h0U2V0dGluZ3MgaWYgZmllbGQgPT0gJ2ZpZ2h0JyBlbHNlIENyb3dkQ29uZmlnCiAgICAgICAgICAgIGN1cnJlbnQgPSBwYXJzZXIucGFyc2Uoc3BlYy5nZXQoZmllbGQpIG9yIHt9KS5zZXR0aW5nc19wYXlsb2FkKCkKICAgICAgICAgICAgbWVyZ2VkPWRpY3QoY3VycmVudCwgKip2YWx1ZSkKICAgICAgICAgICAgaWYgZmllbGQ9PSdmaWdodCcgYW5kIHZhbHVlLmdldCgnZW5naW5lJyk9PSdsZWdhY3knOm1lcmdlZC5wb3AoJ3I1JyxOb25lKQogICAgICAgICAgICBjb25maWd1cmVkID0gcGFyc2VyLnBhcnNlKG1lcmdlZCkuc2V0dGluZ3NfcGF5bG9hZCgpCiAgICAgICAgICAgIGlmIGNvbmZpZ3VyZWQgIT0gY3VycmVudDoKICAgICAgICAgICAgICAgIGNhbmRpZGF0ZVtmaWVsZF0gPSBjb25maWd1cmVkCiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgaWYgZmllbGQgPT0gJ2ZhbGwnOgogICAgICAgICAgICBpZiB0eXBlKHZhbHVlKSBpcyBub3QgZGljdDoKICAgICAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ0ludmFsaWQgRkFMTCBzZXR0aW5ncyBwYXRjaC4nKQogICAgICAgICAgICBjdXJyZW50ID0gRmFsbFNldHRpbmdzLnBhcnNlKHNwZWMuZ2V0KCdmYWxsJykgb3Ige30pLnNldHRpbmdzX3BheWxvYWQoKQogICAgICAgICAgICBjb25maWd1cmVkID0gRmFsbFNldHRpbmdzLnBhcnNlKGRpY3QoY3VycmVudCwgKip2YWx1ZSkpLnNldHRpbmdzX3BheWxvYWQoKQogICAgICAgICAgICBpZiBjb25maWd1cmVkICE9IGN1cnJlbnQ6CiAgICAgICAgICAgICAgICBjYW5kaWRhdGVbZmllbGRdID0gY29uZmlndXJlZAogICAgICAgICAgICBjb250aW51ZQogICAgICAgIGlmIGZpZWxkID09ICd0cmFja2luZyc6CiAgICAgICAgICAgIGlmIHR5cGUodmFsdWUpIGlzIG5vdCBkaWN0OgogICAgICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCB0cmFja2luZyBzZXR0aW5ncy4nKQogICAgICAgICAgICBjdXJyZW50ID0gVHJhY2tpbmdTZXR0aW5ncy5wYXJzZShzcGVjLmdldCgndHJhY2tpbmcnLCB7fSkpLnBheWxvYWQoKQogICAgICAgICAgICBjb25maWd1cmVkID0gVHJhY2tpbmdTZXR0aW5ncy5wYXJzZShkaWN0KGN1cnJlbnQsICoqdmFsdWUpKQogICAgICAgICAgICBpZiBjb25maWd1cmVkLnBheWxvYWQoKSAhPSBjdXJyZW50OgogICAgICAgICAgICAgICAgY2FuZGlkYXRlWyd0cmFja2luZyddID0gZGljdChzcGVjLmdldCgndHJhY2tpbmcnLCB7fSksICoqdmFsdWUpCiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgaWYgZmllbGQgPT0gJ2ZpcmUnOgogICAgICAgICAgICBpZiB0eXBlKHZhbHVlKSBpcyBub3QgZGljdDoKICAgICAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ0ludmFsaWQgRmlyZSBzZXR0aW5ncy4nKQogICAgICAgICAgICBjdXJyZW50ID0gRmlyZUNvbmZpZy5wYXJzZShzcGVjLmdldCgnZmlyZScsIHt9KSkucGF5bG9hZCgpCiAgICAgICAgICAgIGNvbmZpZ3VyZWQgPSBGaXJlQ29uZmlnLnBhcnNlKGN1cnJlbnQpLnBhdGNoZWQodmFsdWUpCiAgICAgICAgICAgIGlmIGNvbmZpZ3VyZWQucGF5bG9hZCgpICE9IGN1cnJlbnQ6CiAgICAgICAgICAgICAgICBjYW5kaWRhdGVbJ2ZpcmUnXSA9IGNvbmZpZ3VyZWQucGF5bG9hZCgpCiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgaWYgZmllbGQgPT0gJ3Bvc2UnOgogICAgICAgICAgICBpZiBub3QgaXNpbnN0YW5jZSh2YWx1ZSwgZGljdCk6CiAgICAgICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdJbnZhbGlkIFBvc2Ugc2V0dGluZ3MuJykKICAgICAgICAgICAgY3VycmVudCA9IFBvc2VDb25maWcucGFyc2Uoc3BlYy5nZXQoJ3Bvc2UnLCB7fSkpLnBheWxvYWQoKQogICAgICAgICAgICBjb25maWd1cmVkID0gUG9zZUNvbmZpZy5wYXJzZShkaWN0KGN1cnJlbnQsICoqdmFsdWUpKQogICAgICAgICAgICBpZiBjb25maWd1cmVkLnBheWxvYWQoKSAhPSBjdXJyZW50OgogICAgICAgICAgICAgICAgY2FuZGlkYXRlWydwb3NlJ10gPSBjb25maWd1cmVkLnBheWxvYWQoKQogICAgICAgICAgICBjb250aW51ZQogICAgICAgIGlmIGZpZWxkIGluICgnZGlzcGxheV9jYXRlZ29yaWVzJywgJ2RlYnVnX2FsbF9jYW5kaWRhdGVzJyk6CiAgICAgICAgICAgIGlmIG5vdCBzcGVjLmdldCgnc2VydmVyX2lkJykgb3Igbm90IHNwZWMuZ2V0KCdzb3VyY2VfaWQnKToKICAgICAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ0Nhbm9uaWNhbCBpZGVudGl0eSBpcyByZXF1aXJlZCBmb3IgZGlzcGxheSBzZXR0aW5ncy4nKQogICAgICAgICAgICBpZiBmaWVsZCA9PSAnZGlzcGxheV9jYXRlZ29yaWVzJzoKICAgICAgICAgICAgICAgIHZhbHVlID0gZGlzcGxheV9jYXRlZ29yaWVzKHZhbHVlKQogICAgICAgICAgICAgICAgaW5kZXgsIGtleSA9IDAsICdjYXRlZ29yaWVzJwogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgaWYgdHlwZSh2YWx1ZSkgaXMgbm90IGJvb2w6CiAgICAgICAgICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBkZWJ1ZyBjYW5kaWRhdGUgc2V0dGluZy4nKQogICAgICAgICAgICAgICAgaW5kZXgsIGtleSA9IDEsIGZpZWxkCiAgICAgICAgICAgIGlmIHZhbHVlICE9IHZpc3VhbF9vcHRpb25zKHNwZWMpW2luZGV4XToKICAgICAgICAgICAgICAgIGNhbmRpZGF0ZVsndmlzdWFsaXphdGlvbiddID0gZGljdChjYW5kaWRhdGUuZ2V0KCd2aXN1YWxpemF0aW9uJykgb3Ige30pCiAgICAgICAgICAgICAgICBjYW5kaWRhdGVbJ3Zpc3VhbGl6YXRpb24nXVtrZXldID0gdmFsdWUKICAgICAgICAgICAgY29udGludWUKICAgICAgICBpZiBmaWVsZCA9PSAnbG9pdGVyaW5nJzoKICAgICAgICAgICAgaWYgdHlwZSh2YWx1ZSkgaXMgbm90IGRpY3Q6CiAgICAgICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdJbnZhbGlkIExPSVRFUklORyBzZXR0aW5ncy4nKQogICAgICAgICAgICBjdXJyZW50ID0gTG9pdGVyaW5nQ29uZmlnLnBhcnNlKHNwZWMuZ2V0KCdsb2l0ZXJpbmcnLCB7fSkpLnBheWxvYWQoKQogICAgICAgICAgICBjb25maWd1cmVkID0gTG9pdGVyaW5nQ29uZmlnLnBhcnNlKGRpY3QoY3VycmVudCwgKip2YWx1ZSkpCiAgICAgICAgICAgIGlmIGNvbmZpZ3VyZWQucGF5bG9hZCgpICE9IGN1cnJlbnQ6CiAgICAgICAgICAgICAgICBjYW5kaWRhdGVbZmllbGRdID0gY29uZmlndXJlZC5wYXlsb2FkKCkKICAgICAgICAgICAgY29udGludWUKICAgICAgICBpZiBmaWVsZCA9PSAnaW50cnVzaW9uJzoKICAgICAgICAgICAgaWYgbm90IGlzaW5zdGFuY2UodmFsdWUsIGRpY3QpOgogICAgICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBJTlRSVVNJT04gc2V0dGluZ3MuJykKICAgICAgICAgICAgY3VycmVudCA9IEludHJ1c2lvbkNvbmZpZy5wYXJzZShzcGVjLmdldCgnaW50cnVzaW9uJywge30pKS5wYXlsb2FkKCkKICAgICAgICAgICAgY29uZmlndXJlZCA9IEludHJ1c2lvbkNvbmZpZy5wYXJzZShkaWN0KGN1cnJlbnQsICoqdmFsdWUpKQogICAgICAgICAgICBpZiBjb25maWd1cmVkLmVuYWJsZWQgYW5kIChub3Qgc3BlYy5nZXQoJ3NlcnZlcl9pZCcpIG9yIG5vdCBzcGVjLmdldCgnc291cmNlX2lkJykpOgogICAgICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignQ2Fub25pY2FsIGlkZW50aXR5IGlzIHJlcXVpcmVkIGZvciBJTlRSVVNJT04uJykKICAgICAgICAgICAgaWYgY29uZmlndXJlZC5wYXlsb2FkKCkgIT0gY3VycmVudDoKICAgICAgICAgICAgICAgIGNhbmRpZGF0ZVtmaWVsZF0gPSBjb25maWd1cmVkLnBheWxvYWQoKQogICAgICAgICAgICBjb250aW51ZQogICAgICAgIGlmIGZpZWxkID09ICdhbmFseXNpc0Zwc1RhcmdldCc6CiAgICAgICAgICAgIGZyb20gYXBwLmFuYWx5c2lzX21ldHJpY3MgaW1wb3J0IGFuYWx5c2lzX2ZwcwogICAgICAgICAgICBpZiBub3Qgc3BlYy5nZXQoJ3NlcnZlcl9pZCcpIG9yIG5vdCBzcGVjLmdldCgnc291cmNlX2lkJyk6CiAgICAgICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdDYW5vbmljYWwgRnJhbWUgaWRlbnRpdHkgaXMgcmVxdWlyZWQgZm9yIEZQUyBzZWxlY3Rpb24uJykKICAgICAgICAgICAgdmFsdWUgPSBhbmFseXNpc19mcHModmFsdWUpCiAgICAgICAgICAgIGlmIHZhbHVlICE9IHNwZWMuZ2V0KCdhbmFseXNpc19mcHNfdGFyZ2V0JywgMTApOgogICAgICAgICAgICAgICAgY2FuZGlkYXRlWydhbmFseXNpc19mcHNfdGFyZ2V0J10gPSB2YWx1ZQogICAgICAgICAgICBjb250aW51ZQogICAgICAgIGlmIGZpZWxkID09ICdmcmFtZV90aW1lX2FuY2hvcic6CiAgICAgICAgICAgIGZyb20gYXBwLmZyYW1lX3RpbWUgaW1wb3J0IEZyYW1lQW5jaG9yCiAgICAgICAgICAgIGlmIHZhbHVlIGlzIG5vdCBOb25lIGFuZCAobm90IHNwZWMuZ2V0KCdzZXJ2ZXJfaWQnKSBvciBub3Qgc3BlYy5nZXQoJ3NvdXJjZV9pZCcpKToKICAgICAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ0Nhbm9uaWNhbCBGcmFtZSBpZGVudGl0eSBpcyByZXF1aXJlZCBmb3IgdGltZSBzZXR0aW5ncy4nKQogICAgICAgICAgICBjYW5kaWRhdGVbZmllbGRdID0gRnJhbWVBbmNob3IubW9kZWxfdmFsaWRhdGUodmFsdWUpLm1vZGVsX2R1bXAoKSBpZiB2YWx1ZSBpcyBub3QgTm9uZSBlbHNlIE5vbmUKICAgICAgICAgICAgY29udGludWUKICAgICAgICBzY29yZSh2YWx1ZSkKICAgICAgICBpZiBmaWVsZCA9PSAnZGlzcGxheV9zY29yZSc6CiAgICAgICAgICAgIGlmIG5vdCBzcGVjLmdldCgnc2VydmVyX2lkJykgb3Igbm90IHNwZWMuZ2V0KCdzb3VyY2VfaWQnKToKICAgICAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ0Nhbm9uaWNhbCBGcmFtZSBpZGVudGl0eSBpcyByZXF1aXJlZCBmb3IgZGlzcGxheSBzZXR0aW5ncy4nKQogICAgICAgICAgICBjYW5kaWRhdGVbJ3Zpc3VhbGl6YXRpb24nXSA9IGRpY3QoY2FuZGlkYXRlLmdldCgndmlzdWFsaXphdGlvbicpIG9yIHt9KQogICAgICAgICAgICBjYW5kaWRhdGVbJ3Zpc3VhbGl6YXRpb24nXVsnc2NvcmVfdGhyZXNob2xkJ10gPSB2YWx1ZQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIGlmIHZhbHVlID09IDA6CiAgICAgICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdEb3duc3RyZWFtIHNjb3JlIG11c3QgYmUgZ3JlYXRlciB0aGFuIHplcm8uJykKICAgICAgICAgICAgcHJvZmlsZSA9IGNhbmRpZGF0ZVsnaW5mZXJlbmNlX3Byb2ZpbGUnXSA9IGRpY3QoY2FuZGlkYXRlLmdldCgnaW5mZXJlbmNlX3Byb2ZpbGUnKSBvciB7fSkKICAgICAgICAgICAgcHJvZmlsZVsndGhyZXNob2xkcyddID0gZGljdChwcm9maWxlLmdldCgndGhyZXNob2xkcycpIG9yIHt9KQogICAgICAgICAgICBwcm9maWxlWyd0aHJlc2hvbGRzJ11bJ3Njb3JlJ10gPSB2YWx1ZQogICAgZXhlY3V0aW9uX3BsYW4oY2FuZGlkYXRlKQogICAgdHJhY2tpbmdfc2V0dGluZ3MoY2FuZGlkYXRlKQogICAgcmV0dXJuIGNhbmRpZGF0ZQo=",
    "app/det_result_path.py": "IiIiUElQRUNPUkUtMDEvRlJBTUVSRVNVTFQtMDE6IFNESyBjYWxsYmFja+ydgCDrj4Xrpr0g6rCS66eMIGJvdW5kZWQgcXVldWXsl5Ag64SY6ri064ukLiIiIgoKZnJvbSBjb2xsZWN0aW9ucyBpbXBvcnQgQ291bnRlciwgZGVxdWUKZnJvbSBkYXRhY2xhc3NlcyBpbXBvcnQgcmVwbGFjZQpmcm9tIGFwcC5yZWdpb25fc2NlbmFyaW8gaW1wb3J0IGFsZXJ0ZWQsIGV2ZW50X2lkcywgbWVtYmVycywgdmlzaWJsZSBhcyBzY2VuYXJpb192aXNpYmxlCmltcG9ydCB0aHJlYWRpbmcKaW1wb3J0IHRpbWUKCmZyb20gYXBwLmNvbnRyYWN0cy5mcmFtZXMgaW1wb3J0IERldGVjdGlvbk9ic2VydmF0aW9uLCBQb3NlT2JzZXJ2YXRpb24KZnJvbSBhcHAucG9zZV9jb25maWcgaW1wb3J0IFBFUlNPTl9NT0RFTFMsIFBPU0VfTU9ERUwKZnJvbSBhcHAuZmlyZV9jb25maWcgaW1wb3J0IEZJUkVfTU9ERUwsIEZJUkVfTkFNRVMKZnJvbSBhcHAuY3Jvd2RfY29uZmlnIGltcG9ydCBDUk9XRF9NT0RFTApmcm9tIGFwcC5jb250cmFjdHMudmlzdWFsaXphdGlvbiBpbXBvcnQgVmlzdWFsaXphdGlvbkNvbW1hbmQsIEZyYW1lUmVzdWx0CmZyb20gYXBwLm1ldGFkYXRhX3NhbXBsZXMgaW1wb3J0IE1ldGFkYXRhU2FtcGxlcwoKCmNsYXNzIERldFJlc3VsdFBhdGg6CiAgICBkZWYgX19pbml0X18oc2VsZiwgaW5ncmVzcywgdHJhY2tlciwgbW9kZWxfa2V5LCB0aHJlc2hvbGQsIGNvbGxlY3RvciwKICAgICAgICAgICAgICAgICBpc19jdXJyZW50LCBvbl9lcnJvciwgKiwgcHVibGlzaGVyPU5vbmUsIGNhcGFjaXR5PTMyLCBtYXhfYWdlPTEuMCwKICAgICAgICAgICAgICAgICBjbG9jaz10aW1lLm1vbm90b25pYywgZGlzcGxheV90aHJlc2hvbGQ9Tm9uZSwgdmlzdWFsPU5vbmUsIGludHJ1c2lvbj1Ob25lLAogICAgICAgICAgICAgICAgIHNjZW5hcmlvX3JldmlzaW9uPU5vbmUsIGRpc3BsYXlfY2F0ZWdvcmllcz1Ob25lLCBkZWJ1Z19hbGxfY2FuZGlkYXRlcz1GYWxzZSwgcG9zZV9jb25maWc9Tm9uZSwKICAgICAgICAgICAgICAgICBjYW1lcmFfaWQ9Tm9uZSwgZmlyZT1Ob25lLCBmYWxsPU5vbmUsIGZpZ2h0PU5vbmUsIGNyb3dkPU5vbmUpOgogICAgICAgIGlmIG1vZGVsX2tleSBub3QgaW4gUEVSU09OX01PREVMUyB8IHtGSVJFX01PREVMLCBDUk9XRF9NT0RFTH06CiAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ0Nhbm9uaWNhbCBEZXQgcGF0aCByZXF1aXJlcyBDT0NPIFJGREVUUk1lZGl1bS4nKQogICAgICAgIGlmIG1vZGVsX2tleSA9PSBGSVJFX01PREVMIGFuZCAoaW50cnVzaW9uIGlzIG5vdCBOb25lIG9yIHBvc2VfY29uZmlnIGlzIG5vdCBOb25lKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignRmlyZSBjYW5ub3QgY29uc3VtZSBwZXJzb24gU2NlbmFyaW8vUG9zZSBzZXR0aW5ncy4nKQogICAgICAgIGlmIGZpcmUgaXMgbm90IE5vbmUgYW5kIG1vZGVsX2tleSAhPSBGSVJFX01PREVMOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdGSVJFIHNjZW5hcmlvIHJlcXVpcmVzIHRoZSBGaXJlIHByb3ZpZGVyLicpCiAgICAgICAgaWYgZmlyZSBpcyBub3QgTm9uZSBhbmQgKGludHJ1c2lvbiBpcyBub3QgTm9uZSBvciB0cmFja2VyIGlzIG5vdCBOb25lKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignRklSRSBzY2VuYXJpbyBjYW5ub3QgY29uc3VtZSBwZXJzb24gU2NlbmFyaW8vVHJhY2tpbmcgc3RhdGUuJykKICAgICAgICBpZiBmYWxsIGlzIG5vdCBOb25lIGFuZCAobW9kZWxfa2V5ICE9IFBPU0VfTU9ERUwgb3IgdHJhY2tlciBpcyBOb25lIG9yIGZpcmUgaXMgbm90IE5vbmUpOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdGQUxMIHJlcXVpcmVzIG9uZSBQb3NlIHByb3ZpZGVyIGFuZCBzaGFyZWQgVHJhY2tpbmcuJykKICAgICAgICBpZiBmaWdodCBpcyBub3QgTm9uZSBhbmQgKG1vZGVsX2tleSAhPSBQT1NFX01PREVMIG9yIHRyYWNrZXIgaXMgTm9uZSBvciBmaXJlIGlzIG5vdCBOb25lKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignRklHSFQgcmVxdWlyZXMgb25lIFBvc2UgcHJvdmlkZXIgYW5kIHNoYXJlZCBUcmFja2luZy4nKQogICAgICAgIGlmIChjcm93ZCBpcyBub3QgTm9uZSkgIT0gKG1vZGVsX2tleSA9PSBDUk9XRF9NT0RFTCkgb3IgKGNyb3dkIGlzIG5vdCBOb25lIGFuZCBhbnkoeCBpcyBub3QgTm9uZSBmb3IgeCBpbiAodHJhY2tlcixpbnRydXNpb24sZmFsbCxmaWdodCxmaXJlLHBvc2VfY29uZmlnKSkpOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdDUk9XRCByZXF1aXJlcyBzdGFuZGFsb25lIHByb3ZpZGVyIHdpdGhvdXQgVHJhY2tpbmcuJykKICAgICAgICBpZiBub3QgMCA8PSB0aHJlc2hvbGQgPD0gMSBvciB0eXBlKGNhcGFjaXR5KSBpcyBub3QgaW50IG9yIG5vdCAxIDw9IGNhcGFjaXR5IDw9IDI1NjoKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBEZXQgcXVldWUgc2V0dGluZ3MuJykKICAgICAgICBpZiBub3QgMCA8IG1heF9hZ2UgPCBmbG9hdCgnaW5mJyk6CiAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ0ludmFsaWQgRGV0IHF1ZXVlIGFnZS4nKQogICAgICAgIGlmIHRyYWNrZXIgaXMgTm9uZSBhbmQgaW50cnVzaW9uIGlzIG5vdCBOb25lOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdJTlRSVVNJT04gcmVxdWlyZXMgVHJhY2tpbmcgT24uJykKICAgICAgICBzZWxmLmluZ3Jlc3MsIHNlbGYudHJhY2tlciwgc2VsZi5tb2RlbF9rZXkgPSBpbmdyZXNzLCB0cmFja2VyLCBtb2RlbF9rZXkKICAgICAgICBzZWxmLnRocmVzaG9sZCwgc2VsZi5jb2xsZWN0b3IgPSB0aHJlc2hvbGQsIGNvbGxlY3RvcgogICAgICAgIHNlbGYuZGlzcGxheV90aHJlc2hvbGQgPSB0aHJlc2hvbGQgaWYgZGlzcGxheV90aHJlc2hvbGQgaXMgTm9uZSBlbHNlIGRpc3BsYXlfdGhyZXNob2xkCiAgICAgICAgaWYgdHlwZShzZWxmLmRpc3BsYXlfdGhyZXNob2xkKSBub3QgaW4gKGludCwgZmxvYXQpIG9yIG5vdCAwIDw9IHNlbGYuZGlzcGxheV90aHJlc2hvbGQgPD0gMToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBkaXNwbGF5IHRocmVzaG9sZC4nKQogICAgICAgIHNlbGYudmlzdWFsID0gdmlzdWFsCiAgICAgICAgc2VsZi5wb3NlX2NvbmZpZyA9IHBvc2VfY29uZmlnCiAgICAgICAgc2VsZi5pbnRydXNpb24gPSBpbnRydXNpb24KICAgICAgICBzZWxmLmZpcmUgPSBmaXJlCiAgICAgICAgc2VsZi5mYWxsID0gZmFsbAogICAgICAgIHNlbGYuZmlnaHQsIHNlbGYuY3Jvd2QgPSBmaWdodCwgY3Jvd2QKICAgICAgICBzZWxmLmNhbWVyYV9pZCA9IGNhbWVyYV9pZAogICAgICAgIHNlbGYuYXJ0aWZhY3RzID0gTm9uZQogICAgICAgIHNlbGYuc2NlbmFyaW9fcmV2aXNpb24gPSBzY2VuYXJpb19yZXZpc2lvbgogICAgICAgIGZyb20gYXBwLnN0cmVhbV9zZXR0aW5ncyBpbXBvcnQgZGlzcGxheV9jYXRlZ29yaWVzIGFzIHZhbGlkYXRlX2NhdGVnb3JpZXMKICAgICAgICBzZWxlY3RlZCA9IHZhbGlkYXRlX2NhdGVnb3JpZXMoZGlzcGxheV9jYXRlZ29yaWVzKQogICAgICAgIHNlbGYuZGlzcGxheV9jYXRlZ29yaWVzID0gZnJvemVuc2V0KHNlbGVjdGVkKSBpZiBzZWxlY3RlZCBpcyBub3QgTm9uZSBlbHNlIE5vbmUKICAgICAgICBzZWxmLmRlYnVnX2FsbF9jYW5kaWRhdGVzID0gZGVidWdfYWxsX2NhbmRpZGF0ZXMKICAgICAgICBzZWxmLmlzX2N1cnJlbnQsIHNlbGYub25fZXJyb3IsIHNlbGYucHVibGlzaGVyID0gaXNfY3VycmVudCwgb25fZXJyb3IsIHB1Ymxpc2hlcgogICAgICAgIHNlbGYuY2FwYWNpdHksIHNlbGYubWF4X2FnZSwgc2VsZi5jbG9jayA9IGNhcGFjaXR5LCBtYXhfYWdlLCBjbG9jawogICAgICAgIHNlbGYuX2N2ID0gdGhyZWFkaW5nLkNvbmRpdGlvbigpCiAgICAgICAgc2VsZi5fcXVldWUgPSBkZXF1ZSgpCiAgICAgICAgc2VsZi5fY2xvc2VkID0gRmFsc2UKICAgICAgICBzZWxmLl9sYXN0X3NlcSA9IC0xCiAgICAgICAgc2VsZi5fbWV0cmljcyA9IENvdW50ZXIoKQogICAgICAgIHNlbGYuX2xhdGVzdCA9IE5vbmUKICAgICAgICBzZWxmLl9lcnJvciA9IE5vbmUKICAgICAgICBzZWxmLl90aHJlYWQgPSBOb25lCiAgICAgICAgc2VsZi5fc2FtcGxlcyA9IE1ldGFkYXRhU2FtcGxlcy5mcm9tX2Vudmlyb25tZW50KCkKCiAgICBkZWYgc3RhcnQoc2VsZik6CiAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgaWYgc2VsZi5fY2xvc2VkIG9yIHNlbGYuX3RocmVhZCBpcyBub3QgTm9uZToKICAgICAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcignRGV0IHJlc3VsdCB3b3JrZXIgY2Fubm90IHN0YXJ0IHR3aWNlLicpCiAgICAgICAgICAgIGlmIHNlbGYucHVibGlzaGVyIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgaWYgbm90IHNlbGYucHVibGlzaGVyLmNoYW5uZWwoc2VsZi5pbmdyZXNzLmlkZW50aXR5WzFdLCBzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbM10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbNF0sICdTVEFSVElORycpOgogICAgICAgICAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcignTWV0YWRhdGEgY2hhbm5lbCB3b3JrZXIgYWRtaXNzaW9uIHJlamVjdGVkLicpCiAgICAgICAgICAgIHNlbGYuX3RocmVhZCA9IHRocmVhZGluZy5UaHJlYWQodGFyZ2V0PXNlbGYuX3J1biwgbmFtZT0nZGV0LXJlc3VsdHMnLCBkYWVtb249VHJ1ZSkKICAgICAgICAgICAgc2VsZi5fdGhyZWFkLnN0YXJ0KCkKCiAgICBkZWYgc3VibWl0KHNlbGYsIGZyYW1lLCBjb3BpZWQsIGhhbmRsZT1Ob25lLCAqLCBnYXBfYmVmb3JlPUZhbHNlKToKICAgICAgICBpZiAoZnJhbWUuc2VydmVyX2lkLCBmcmFtZS5zb3VyY2VfaWQsIGZyYW1lLnN0cmVhbV9pZCwgZnJhbWUucnVuX2lkLCBmcmFtZS5ydW5fZ2VuZXJhdGlvbikgIT0gc2VsZi5pbmdyZXNzLmlkZW50aXR5OgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdTdGFsZSBvciBmb3JlaWduIEZyYW1lLicpCiAgICAgICAgaWYgKGZyYW1lLmZyYW1lX3dpZHRoLCBmcmFtZS5mcmFtZV9oZWlnaHQpICE9IChjb3BpZWQud2lkdGgsIGNvcGllZC5oZWlnaHQpOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdOYXRpdmUvaW5ncmVzcyBzb3VyY2UgZGltZW5zaW9ucyBkaWZmZXIuJykKICAgICAgICBpZiBsZW4oY29waWVkLmRldGVjdGlvbnMpID4gMzAwOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdOYXRpdmUgY2FuZGlkYXRlIGxpbWl0IGV4Y2VlZGVkLicpCiAgICAgICAgaWYgc2VsZi5tb2RlbF9rZXkgPT0gRklSRV9NT0RFTCBhbmQgYW55KGQuY2xhc3NfaWQgbm90IGluICgwLDEpIGZvciBkIGluIGNvcGllZC5kZXRlY3Rpb25zKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBGaXJlIGNsYXNzIGlkLicpCiAgICAgICAgb2JzZXJ2YXRpb25zID0gdHVwbGUoRGV0ZWN0aW9uT2JzZXJ2YXRpb24oZnJhbWUsIHNlbGYubW9kZWxfa2V5LCBkLmNsYXNzX2lkLCBkLnNjb3JlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkLmJib3hfeHl4eSkgZm9yIGQgaW4gY29waWVkLmRldGVjdGlvbnMpCiAgICAgICAgcG9zZXMgPSB0dXBsZShQb3NlT2JzZXJ2YXRpb24oZnJhbWUsc2VsZi5tb2RlbF9rZXksZC5zY29yZSxkLmJib3hfeHl4eSxkLmtleXBvaW50cykKICAgICAgICAgICAgICAgICAgICAgIGlmIGQua2V5cG9pbnRzIGlzIG5vdCBOb25lIGVsc2UgTm9uZSBmb3IgZCBpbiBjb3BpZWQuZGV0ZWN0aW9ucykKICAgICAgICBpZiBhbnkoKHAgaXMgbm90IE5vbmUpICE9IChzZWxmLm1vZGVsX2tleSA9PSBQT1NFX01PREVMKSBmb3IgcCBpbiBwb3Nlcyk6CiAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ1Byb3ZpZGVyIG91dHB1dCBjb250cmFjdCBtaXNtYXRjaC4nKQogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIGlmIHNlbGYuX2Nsb3NlZCBvciBub3Qgc2VsZi5pc19jdXJyZW50KCk6CiAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydzdGFsZSddICs9IDEKICAgICAgICAgICAgICAgIHJldHVybiBGYWxzZQogICAgICAgICAgICBpZiBmcmFtZS5mcmFtZV9zZXEgPD0gc2VsZi5fbGFzdF9zZXE6CiAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydvdXRfb2Zfb3JkZXInXSArPSAxCiAgICAgICAgICAgICAgICByZXR1cm4gRmFsc2UKICAgICAgICAgICAgc2VsZi5fbGFzdF9zZXEgPSBmcmFtZS5mcmFtZV9zZXEKICAgICAgICAgICAgaWYgKHNlbGYuZmFsbCBpcyBub3QgTm9uZSBvciBzZWxmLmZpZ2h0IGlzIG5vdCBOb25lIG9yIHNlbGYuY3Jvd2QgaXMgbm90IE5vbmUpIGFuZCBoYXNhdHRyKHNlbGYuaW5ncmVzcywgJ3Jlc3VsdF9nYXAnKToKICAgICAgICAgICAgICAgIGdhcF9iZWZvcmUgPSBzZWxmLmluZ3Jlc3MucmVzdWx0X2dhcChmcmFtZSkgb3IgZ2FwX2JlZm9yZQogICAgICAgICAgICAgICAgaWYgZ2FwX2JlZm9yZToKICAgICAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydmYWxsX3Vwc3RyZWFtX2dhcCddICs9IDEKICAgICAgICAgICAgaWYgbGVuKHNlbGYuX3F1ZXVlKSA9PSBzZWxmLmNhcGFjaXR5OgogICAgICAgICAgICAgICAgc2VsZi5fcXVldWUucG9wbGVmdCgpCiAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydxdWV1ZV9kcm9wJ10gKz0gMQogICAgICAgICAgICAgICAgaWYgc2VsZi5fcXVldWU6CiAgICAgICAgICAgICAgICAgICAgc2VsZi5fcXVldWVbMF0gPSAoKnNlbGYuX3F1ZXVlWzBdWzotMV0sIFRydWUpCiAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgIGdhcF9iZWZvcmUgPSBUcnVlCiAgICAgICAgICAgIHNlbGYuX3F1ZXVlLmFwcGVuZCgoc2VsZi5jbG9jaygpLCBmcmFtZSwgY29waWVkLCBvYnNlcnZhdGlvbnMsIHBvc2VzLCBoYW5kbGUsIGdhcF9iZWZvcmUpKQogICAgICAgICAgICBzZWxmLl9jdi5ub3RpZnkoKQogICAgICAgICAgICByZXR1cm4gVHJ1ZQoKICAgIGRlZiBfcnVuKHNlbGYpOgogICAgICAgIHNraXBwZWRfYmVmb3JlID0gRmFsc2UKICAgICAgICB0cnk6CiAgICAgICAgICAgIHdoaWxlIFRydWU6CiAgICAgICAgICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICAgICAgICAgIHNlbGYuX2N2LndhaXRfZm9yKGxhbWJkYTogc2VsZi5fY2xvc2VkIG9yIHNlbGYuX3F1ZXVlLCAuMjUgaWYgc2VsZi5pbnRydXNpb24gb3Igc2VsZi5jcm93ZCBlbHNlIE5vbmUpCiAgICAgICAgICAgICAgICAgICAgaWYgc2VsZi5fY2xvc2VkOgogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4KICAgICAgICAgICAgICAgICAgICBpdGVtID0gc2VsZi5fcXVldWUucG9wbGVmdCgpIGlmIHNlbGYuX3F1ZXVlIGVsc2UgTm9uZQogICAgICAgICAgICAgICAgIyBTY2VuYXJpbyBzdGF0ZSBpcyB3b3JrZXItb3duZWQ7IGNsb3NlKCkgY2xlYXJzIGl0IG9ubHkgYWZ0ZXIgam9pbi4KICAgICAgICAgICAgICAgIGlmIGl0ZW0gaXMgTm9uZToKICAgICAgICAgICAgICAgICAgICBpZiBzZWxmLmNyb3dkOgogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmNyb3dkLmV4cGlyZV9pZGxlKCkKICAgICAgICAgICAgICAgICAgICBpZiBzZWxmLmludHJ1c2lvbjoKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5pbnRydXNpb24uZXhwaXJlKCkKICAgICAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICAgICAgc3VibWl0dGVkLCBmcmFtZSwgY29waWVkLCBvYnNlcnZhdGlvbnMsIHBvc2VzLCBoYW5kbGUsIGdhcF9iZWZvcmUgPSBpdGVtCiAgICAgICAgICAgICAgICBpZiBub3Qgc2VsZi5pc19jdXJyZW50KCkgb3Igc2VsZi5jbG9jaygpIC0gc3VibWl0dGVkID4gc2VsZi5tYXhfYWdlOgogICAgICAgICAgICAgICAgICAgIGlmIHNlbGYuaW50cnVzaW9uOgogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmludHJ1c2lvbi5leHBpcmUoKQogICAgICAgICAgICAgICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ3N0YWxlJ10gKz0gMQogICAgICAgICAgICAgICAgICAgIHNraXBwZWRfYmVmb3JlID0gVHJ1ZQogICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgICAgICAjIFRoaXMgYWNjZXB0ZWQgRnJhbWUgZmluaXNoZXMgZXZlbnQgaGFuZG9mZiBldmVuIGlmIFN0b3AgYXJyaXZlcyBkdXJpbmcgZXZhbHVhdGlvbi4KICAgICAgICAgICAgICAgICMgY2xvc2UoKSBqb2lucyB0aGlzIHdvcmtlciBiZWZvcmUgY2xvc2luZyBjYXB0dXJlIG9yIHN3aXRjaGluZyB0byBhIG5ldyBydW4uCiAgICAgICAgICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICAgICAgICAgIGlmIHNlbGYuX2Nsb3NlZCBvciBub3Qgc2VsZi5pc19jdXJyZW50KCk6CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgICAgICBnYXBfYmVmb3JlID0gZ2FwX2JlZm9yZSBvciBza2lwcGVkX2JlZm9yZQogICAgICAgICAgICAgICAgc2tpcHBlZF9iZWZvcmUgPSBGYWxzZQogICAgICAgICAgICAgICAgbWV0cmljcyA9IGdldGF0dHIoc2VsZi5pbmdyZXNzLCAnbWV0cmljcycsIE5vbmUpCiAgICAgICAgICAgICAgICBzdGFydGVkX25zID0gdGltZS5tb25vdG9uaWNfbnMoKQogICAgICAgICAgICAgICAgZGV0YWlsID0gbWV0cmljcyBpcyBub3QgTm9uZSBhbmQgbWV0cmljcy5kZXRhaWxfZW5hYmxlZCgpCiAgICAgICAgICAgICAgICBzdGFydGVkX2NwdSA9IHRpbWUudGhyZWFkX3RpbWVfbnMoKSBpZiBkZXRhaWwgZWxzZSAwCiAgICAgICAgICAgICAgICBpZiBtZXRyaWNzOgogICAgICAgICAgICAgICAgICAgIG1ldHJpY3MuZHVyYXRpb24oJ3F1ZXVlJywgaW50KChzZWxmLmNsb2NrKCkgLSBzdWJtaXR0ZWQpICogMWU5KSkKICAgICAgICAgICAgICAgIGlmIHNlbGYuY3Jvd2QgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gc2VsZi5jcm93ZC5wcm9jZXNzKGZyYW1lLCBvYnNlcnZhdGlvbnMsIGdhcF9iZWZvcmU9Z2FwX2JlZm9yZSkKICAgICAgICAgICAgICAgICAgICBpZiByZXN1bHQgaXMgTm9uZToKICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgICAgICB2aXNpYmxlID0ge2lkKGMuZGV0ZWN0aW9uKSBmb3IgYyBpbiByZXN1bHQuY29tbWFuZHN9CiAgICAgICAgICAgICAgICAgICAga2VwdCA9IHR1cGxlKGlkKG8pIGluIHZpc2libGUgZm9yIG8gaW4gb2JzZXJ2YXRpb25zKQogICAgICAgICAgICAgICAgICAgIGlkcywgZXZlbnRzID0gW05vbmVdKmxlbihvYnNlcnZhdGlvbnMpLCByZXN1bHQuZXZlbnRzCiAgICAgICAgICAgICAgICBlbGlmIHNlbGYuZmlyZSBpcyBub3QgTm9uZToKICAgICAgICAgICAgICAgICAgICBzY2VuYXJpb19zdGFydCwgc2NlbmFyaW9fY3B1ID0gdGltZS5tb25vdG9uaWNfbnMoKSwgdGltZS50aHJlYWRfdGltZV9ucygpCiAgICAgICAgICAgICAgICAgICAgZnJvbSBhcHAuZmlyZV9yZXN1bHQgaW1wb3J0IGV2YWx1YXRlX3Jlc3VsdCBhcyBldmFsdWF0ZV9maXJlX3Jlc3VsdAogICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IGV2YWx1YXRlX2ZpcmVfcmVzdWx0KHNlbGYuZmlyZSwgZnJhbWUsIG9ic2VydmF0aW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgY2FtZXJhX2lkPXNlbGYuY2FtZXJhX2lkLCBzY2VuYXJpb19yZXZpc2lvbj1zZWxmLnNjZW5hcmlvX3JldmlzaW9uKQogICAgICAgICAgICAgICAgICAgIGlmIHJlc3VsdCBpcyBOb25lOgogICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICAgICAgICAgIHZpc2libGUgPSB7aWQoY29tbWFuZC5kZXRlY3Rpb24pIGZvciBjb21tYW5kIGluIHJlc3VsdC5jb21tYW5kc30KICAgICAgICAgICAgICAgICAgICBrZXB0ID0gdHVwbGUoaWQob2JzZXJ2YXRpb24pIGluIHZpc2libGUgZm9yIG9ic2VydmF0aW9uIGluIG9ic2VydmF0aW9ucykKICAgICAgICAgICAgICAgICAgICBpZHMgPSBbTm9uZV0gKiBsZW4ob2JzZXJ2YXRpb25zKQogICAgICAgICAgICAgICAgICAgIGV2ZW50cyA9IHJlc3VsdC5ldmVudHMKICAgICAgICAgICAgICAgICAgICBpZiBtZXRyaWNzOgogICAgICAgICAgICAgICAgICAgICAgICBtZXRyaWNzLmR1cmF0aW9uKCdzY2VuYXJpb19jcHUnLCB0aW1lLnRocmVhZF90aW1lX25zKCkgLSBzY2VuYXJpb19jcHUpCiAgICAgICAgICAgICAgICAgICAgICAgIG1ldHJpY3MuZHVyYXRpb24oJ3NjZW5hcmlvJywgdGltZS5tb25vdG9uaWNfbnMoKSAtIHNjZW5hcmlvX3N0YXJ0KQogICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZD10dXBsZShyYW5nZShsZW4ob2JzZXJ2YXRpb25zKSkpCiAgICAgICAgICAgICAgICAgICAgaWYgc2VsZi5wb3NlX2NvbmZpZyBhbmQgc2VsZi5wb3NlX2NvbmZpZy5ubXNfZW5hYmxlZDoKICAgICAgICAgICAgICAgICAgICAgICAgZnJvbSBhcHAucG9zZV9ubXMgaW1wb3J0IHBvc2Vfbm1zX2luZGljZXMKICAgICAgICAgICAgICAgICAgICAgICAgbm1zX3N0YXJ0PXRpbWUubW9ub3RvbmljX25zKCkKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWQ9cG9zZV9ubXNfaW5kaWNlcyhvYnNlcnZhdGlvbnMsc2VsZi5wb3NlX2NvbmZpZy5ubXNfaW91X3RocmVzaG9sZCkKICAgICAgICAgICAgICAgICAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ25tc19jYWxscyddKz0xCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydubXNfZWxhcHNlZF9ucyddKz10aW1lLm1vbm90b25pY19ucygpLW5tc19zdGFydAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljc1snbm1zX3N1cHByZXNzZWQnXSs9bGVuKG9ic2VydmF0aW9ucyktbGVuKHNlbGVjdGVkKQogICAgICAgICAgICAgICAgICAgIHNlbGVjdGVkX3NldD1zZXQoc2VsZWN0ZWQpCiAgICAgICAgICAgICAgICAgICAga2VwdD10dXBsZShpIGluIHNlbGVjdGVkX3NldCBmb3IgaSBpbiByYW5nZShsZW4ob2JzZXJ2YXRpb25zKSkpCiAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRfb2JzZXJ2YXRpb25zPXR1cGxlKG9ic2VydmF0aW9uc1tpXSBmb3IgaSBpbiBzZWxlY3RlZCkKICAgICAgICAgICAgICAgICAgICB0cmFja2luZ19zdGFydD10aW1lLm1vbm90b25pY19ucygpCiAgICAgICAgICAgICAgICAgICAgdHJhY2tpbmdfY3B1ID0gdGltZS50aHJlYWRfdGltZV9ucygpCiAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRfaWRzID0gKHNlbGYudHJhY2tlci51cGRhdGUoc2VsZWN0ZWRfb2JzZXJ2YXRpb25zKSBpZiBzZWxmLnRyYWNrZXIgaXMgbm90IE5vbmUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBbTm9uZV0gKiBsZW4oc2VsZWN0ZWRfb2JzZXJ2YXRpb25zKSkKICAgICAgICAgICAgICAgICAgICBpZHM9W05vbmVdKmxlbihvYnNlcnZhdGlvbnMpCiAgICAgICAgICAgICAgICAgICAgaWYgbGVuKHNlbGVjdGVkX2lkcykhPWxlbihzZWxlY3RlZCk6CiAgICAgICAgICAgICAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ1RyYWNrZXIgY2FuZGlkYXRlIGFzc29jaWF0aW9uIGlzIGluY29tcGxldGUuJykKICAgICAgICAgICAgICAgICAgICBmb3IgaSx0aWQgaW4gemlwKHNlbGVjdGVkLHNlbGVjdGVkX2lkcyk6aWRzW2ldPXRpZAogICAgICAgICAgICAgICAgICAgIHRyYWNraW5nX2NwdSA9IHRpbWUudGhyZWFkX3RpbWVfbnMoKSAtIHRyYWNraW5nX2NwdQogICAgICAgICAgICAgICAgICAgIGlmIG1ldHJpY3M6CiAgICAgICAgICAgICAgICAgICAgICAgIG1ldHJpY3MuZHVyYXRpb24oJ3RyYWNraW5nJywgdGltZS5tb25vdG9uaWNfbnMoKSAtIHRyYWNraW5nX3N0YXJ0KQogICAgICAgICAgICAgICAgICAgICAgICBtZXRyaWNzLmR1cmF0aW9uKCd0cmFja2luZ19jcHUnLCB0cmFja2luZ19jcHUpCiAgICAgICAgICAgICAgICAgICAgaWYgbGVuKGlkcykgIT0gbGVuKG9ic2VydmF0aW9ucyk6CiAgICAgICAgICAgICAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ1RyYWNrZXIgY2FuZGlkYXRlIGFzc29jaWF0aW9uIGlzIGluY29tcGxldGUuJykKICAgICAgICAgICAgICAgICAgICBkZWNpc2lvbnMsIGV2ZW50cyA9ICgoTm9uZSwpKmxlbihvYnNlcnZhdGlvbnMpLCAoKSkKICAgICAgICAgICAgICAgICAgICBpZiBzZWxmLmludHJ1c2lvbjoKICAgICAgICAgICAgICAgICAgICAgICAgc2NlbmFyaW9fc3RhcnQsIHNjZW5hcmlvX2NwdSA9IHRpbWUubW9ub3RvbmljX25zKCksIHRpbWUudGhyZWFkX3RpbWVfbnMoKQogICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZF9kZWNpc2lvbnMsIGV2ZW50cyA9IHNlbGYuaW50cnVzaW9uLmV2YWx1YXRlKGZyYW1lLCBzZWxlY3RlZF9vYnNlcnZhdGlvbnMsIHNlbGVjdGVkX2lkcykKICAgICAgICAgICAgICAgICAgICAgICAgZGVjaXNpb25zPVtOb25lXSpsZW4ob2JzZXJ2YXRpb25zKQogICAgICAgICAgICAgICAgICAgICAgICBmb3IgaSxkIGluIHppcChzZWxlY3RlZCxzZWxlY3RlZF9kZWNpc2lvbnMpOmRlY2lzaW9uc1tpXT1kCiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50cz10dXBsZShyZXBsYWNlKGUsb2JqZWN0X3JlZj1zdHIoc2VsZWN0ZWRbaW50KGUub2JqZWN0X3JlZildKSkgZm9yIGUgaW4gZXZlbnRzKQogICAgICAgICAgICAgICAgICAgICAgICBpZiBtZXRyaWNzOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0cmljcy5kdXJhdGlvbignc2NlbmFyaW9fY3B1JywgdGltZS50aHJlYWRfdGltZV9ucygpIC0gc2NlbmFyaW9fY3B1KQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0cmljcy5kdXJhdGlvbignc2NlbmFyaW8nLCB0aW1lLm1vbm90b25pY19ucygpIC0gc2NlbmFyaW9fc3RhcnQpCiAgICAgICAgICAgICAgICAgICAgZm9yIHNjZW5hcmlvIGluIChzZWxmLmZhbGwsIHNlbGYuZmlnaHQpOgogICAgICAgICAgICAgICAgICAgICAgICBpZiBzY2VuYXJpbyBpcyBOb25lOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgICAgICAgICAgc2NlbmFyaW9fc3RhcnQsIHNjZW5hcmlvX2NwdSA9IHRpbWUubW9ub3RvbmljX25zKCksIHRpbWUudGhyZWFkX3RpbWVfbnMoKQogICAgICAgICAgICAgICAgICAgICAgICBmYWxsX2RlY2lzaW9ucywgZmFsbF9ldmVudHMgPSBzY2VuYXJpby5ldmFsdWF0ZShmcmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR1cGxlKHBvc2VzW2ldIGZvciBpIGluIHNlbGVjdGVkKSwgc2VsZWN0ZWRfaWRzLCBnYXBfYmVmb3JlPWdhcF9iZWZvcmUpCiAgICAgICAgICAgICAgICAgICAgICAgIGRlY2lzaW9ucyA9IGxpc3QoZGVjaXNpb25zKQogICAgICAgICAgICAgICAgICAgICAgICBmb3IgaW5kZXgsIGRlY2lzaW9uIGluIHppcChzZWxlY3RlZCwgZmFsbF9kZWNpc2lvbnMpOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjaXNpb25zW2luZGV4XSA9ICgqbWVtYmVycyhkZWNpc2lvbnNbaW5kZXhdKSwgKm1lbWJlcnMoZGVjaXNpb24pKQogICAgICAgICAgICAgICAgICAgICAgICBldmVudHMgKz0gdHVwbGUocmVwbGFjZShlLCBvYmplY3RfcmVmPXN0cihzZWxlY3RlZFtpbnQoZS5vYmplY3RfcmVmKV0pKSBmb3IgZSBpbiBmYWxsX2V2ZW50cykKICAgICAgICAgICAgICAgICAgICAgICAgaWYgbWV0cmljczoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldHJpY3MuZHVyYXRpb24oJ3NjZW5hcmlvX2NwdScsIHRpbWUudGhyZWFkX3RpbWVfbnMoKSAtIHNjZW5hcmlvX2NwdSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldHJpY3MuZHVyYXRpb24oJ3NjZW5hcmlvJywgdGltZS5tb25vdG9uaWNfbnMoKSAtIHNjZW5hcmlvX3N0YXJ0KQogICAgICAgICAgICAgICAgICAgIGNvbW1hbmRzID0gdHVwbGUoVmlzdWFsaXphdGlvbkNvbW1hbmQobywgc2VsZi5fbGFiZWwoby5jbGFzc19pZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj0nI0ZGMzAzMCcgaWYgYWxlcnRlZChkKSBlbHNlICcjMDBDQzY2JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpc2libGU9a2VlcCBhbmQgKHNjZW5hcmlvX3Zpc2libGUoby5zY29yZSwgZCkgaWYgZCBlbHNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoby5zY29yZSA+PSBzZWxmLnBvc2VfY29uZmlnLnBlcnNvbl9zY29yZSBpZiBzZWxmLnBvc2VfY29uZmlnIGVsc2Ugby5zY29yZSA+IHNlbGYuZGlzcGxheV90aHJlc2hvbGQpIGFuZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHNlbGYuZGlzcGxheV9jYXRlZ29yaWVzIGlzIE5vbmUgb3Igc2VsZi5fbGFiZWwoby5jbGFzc19pZCkgaW4gc2VsZi5kaXNwbGF5X2NhdGVnb3JpZXMpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNrX2lkPXRpZCwgZXZlbnRfaWRzPWV2ZW50X2lkcyhkKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjZW5hcmlvPWQsIHBvc2U9cCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBvLCB0aWQsIGQsIHAsIGtlZXAgaW4gemlwKG9ic2VydmF0aW9ucywgaWRzLCBkZWNpc2lvbnMsIHBvc2VzLCBrZXB0KSkKICAgICAgICAgICAgICAgICAgICBjb25maWdzID0gbWVtYmVycyhzZWxmLmludHJ1c2lvbi5jb25maWcgaWYgc2VsZi5pbnRydXNpb24gZWxzZSBOb25lKQogICAgICAgICAgICAgICAgICAgIGlmIHNlbGYuZmFsbCBpcyBub3QgTm9uZToKICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlncyArPSAoc2VsZi5mYWxsLmNvbmZpZywpCiAgICAgICAgICAgICAgICAgICAgaWYgc2VsZi5maWdodCBpcyBub3QgTm9uZToKICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlncyArPSAoc2VsZi5maWdodC5jb25maWcsKQogICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IEZyYW1lUmVzdWx0KGZyYW1lLCBjb21tYW5kcywgZXZlbnRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZ3MgaWYgbGVuKGNvbmZpZ3MpID4gMSBlbHNlIGNvbmZpZ3NbMF0gaWYgY29uZmlncyBlbHNlIE5vbmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5zY2VuYXJpb19yZXZpc2lvbiwgc2VsZi5kZWJ1Z19hbGxfY2FuZGlkYXRlcywgc2VsZi5wb3NlX2NvbmZpZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXB0IGlmIHNlbGYucG9zZV9jb25maWcgZWxzZSBOb25lLCBwcm92aWRlcl9tb2RlbD1zZWxmLm1vZGVsX2tleSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYW1lcmFfaWQ9c2VsZi5jYW1lcmFfaWQpCiAgICAgICAgICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICAgICAgICAgIGlmIHNlbGYuX2Nsb3NlZCBvciBub3Qgc2VsZi5pc19jdXJyZW50KCk6CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIHNlbGYuZmFsbCBpcyBOb25lIGFuZCBzZWxmLmZpZ2h0IGlzIE5vbmUgYW5kIG5vdCAoc2VsZi5jcm93ZCBhbmQgcmVzdWx0LmV2ZW50cyk6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX2xhdGVzdCA9IHJlc3VsdAogICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ2V2ZW50c19jcmVhdGVkJ10gKz0gbGVuKGV2ZW50cykKICAgICAgICAgICAgICAgIGlmIHNlbGYuX3NhbXBsZXMgaXMgbm90IE5vbmUgYW5kIHNlbGYuX3NhbXBsZXMuZW5hYmxlZCgpOgogICAgICAgICAgICAgICAgICAgIHNlbGYuX3NhbXBsZXMuY2FwdHVyZShyZXN1bHQuc25hcHNob3QodmlzaWJsZV9vbmx5PUZhbHNlKSkKICAgICAgICAgICAgICAgIGlmIHNlbGYudmlzdWFsIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgICAgIHNlbGYudmlzdWFsLnN1Ym1pdF9yZXN1bHQocmVzdWx0KQogICAgICAgICAgICAgICAgaWYgc2VsZi5hcnRpZmFjdHMgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICAgICAgYWNjZXB0ZWQgPSBzZWxmLmFydGlmYWN0cy5zdWJtaXQocmVzdWx0KQogICAgICAgICAgICAgICAgICAgIGlmIGFjY2VwdGVkIGlzIEZhbHNlIGFuZCBhbnkoZS5wYXlsb2FkKClbJ3NjZW5hcmlvJ10gaW4gKCdGQUxMJywnRklHSFQnLCdDUk9XRCcpIGZvciBlIGluIGV2ZW50cyk6CiAgICAgICAgICAgICAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcignRkFMTCBFdmVudCBoYW5kb2ZmIHJlamVjdGVkLicpCiAgICAgICAgICAgICAgICBpdGVtcyA9IFtkaWN0KGQuZG93bnN0cmVhbSgpLCB0cmFja19pZD10aWQpCiAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgZCwgdGlkLCBrZWVwIGluIHppcChjb3BpZWQuZGV0ZWN0aW9ucywgaWRzLCBrZXB0KSBpZiBrZWVwIGFuZCBkLnNjb3JlID4gc2VsZi50aHJlc2hvbGRdCiAgICAgICAgICAgICAgICAjIERldC1vbmx5IGNvbXBhdGliaWxpdHkgY29sbGVjdG9yLiBQb3NlIGpvaW7snYAg7J20IGtleeulvCDsgqzsmqntlZjsp4Ag7JWK64qU64ukLgogICAgICAgICAgICAgICAgY29sbGVjdG9yX2ZyYW1lcyA9IHNlbGYuY29sbGVjdG9yLmFkZCgncG9zZScgaWYgc2VsZi5tb2RlbF9rZXk9PVBPU0VfTU9ERUwgZWxzZSAnZGV0JywgZnJhbWUuZnJhbWVfc2VxLCBmcmFtZS5wdHNfbnMgb3IgMCwKICAgICAgICAgICAgICAgICAgICB7J3cnOiBmcmFtZS5mcmFtZV93aWR0aCwgJ2gnOiBmcmFtZS5mcmFtZV9oZWlnaHQsICdjb3VudCc6IGxlbihpdGVtcyksCiAgICAgICAgICAgICAgICAgICAgICdpdGVtcyc6IGl0ZW1zLCAnZnJhbWUnOiBmcmFtZX0sIG1heF9mcmFtZXM9MTAwMCwgbWV0cmljcz1tZXRyaWNzKQogICAgICAgICAgICAgICAgaWYgZGV0YWlsOgogICAgICAgICAgICAgICAgICAgIHB1Ymxpc2hfc3RhcnQsIHB1Ymxpc2hfY3B1ID0gdGltZS5tb25vdG9uaWNfbnMoKSwgdGltZS50aHJlYWRfdGltZV9ucygpCiAgICAgICAgICAgICAgICBpZiBzZWxmLnB1Ymxpc2hlciBpcyBub3QgTm9uZToKICAgICAgICAgICAgICAgICAgICBpZiBtZXRyaWNzOgogICAgICAgICAgICAgICAgICAgICAgICBtZXRyaWNzLm1hcmsoJ3Jlc3VsdCcsIChjb3BpZWQuZnJhbWVfbnVtYmVyLCBjb3BpZWQucHRzKSkKICAgICAgICAgICAgICAgICAgICBhY2NlcHRlZCA9IHNlbGYucHVibGlzaGVyLmNoYW5uZWwoZnJhbWUuc291cmNlX2lkLCBmcmFtZS5ydW5faWQsIGZyYW1lLnJ1bl9nZW5lcmF0aW9uLCAnUlVOTklORycpCiAgICAgICAgICAgICAgICAgICAgaWYgbm90IGFjY2VwdGVkIG9yIG5vdCBzZWxmLnB1Ymxpc2hlci5zdWJtaXQocmVzdWx0LnNuYXBzaG90KCkpOgogICAgICAgICAgICAgICAgICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljc1sncHVibGlzaGVyX3JlamVjdGVkJ10gKz0gMQogICAgICAgICAgICAgICAgICAgIGVsaWYgbWV0cmljczoKICAgICAgICAgICAgICAgICAgICAgICAgbWV0cmljcy5tYXJrKCdwdWJsaXNoZXJfc3VibWl0JywgKGNvcGllZC5mcmFtZV9udW1iZXIsIGNvcGllZC5wdHMpKQogICAgICAgICAgICAgICAgZWxpZiBtZXRyaWNzOgogICAgICAgICAgICAgICAgICAgIG1ldHJpY3MubWFyaygncmVzdWx0JywgKGNvcGllZC5mcmFtZV9udW1iZXIsIGNvcGllZC5wdHMpKQogICAgICAgICAgICAgICAgaWYgZGV0YWlsOgogICAgICAgICAgICAgICAgICAgIG1ldHJpY3MuZHVyYXRpb24oJ3Jlc3VsdF9wdWJsaXNoJywgdGltZS5tb25vdG9uaWNfbnMoKSAtIHB1Ymxpc2hfc3RhcnQpCiAgICAgICAgICAgICAgICAgICAgbWV0cmljcy5kdXJhdGlvbigncmVzdWx0X3B1Ymxpc2hfY3B1JywgdGltZS50aHJlYWRfdGltZV9ucygpIC0gcHVibGlzaF9jcHUpCiAgICAgICAgICAgICAgICAgICAgbWV0cmljcy5kdXJhdGlvbigncmVzdWx0X3dvcmtfY3B1JywgdGltZS50aHJlYWRfdGltZV9ucygpIC0gc3RhcnRlZF9jcHUpCiAgICAgICAgICAgICAgICBpZiBtZXRyaWNzOgogICAgICAgICAgICAgICAgICAgIG1ldHJpY3MuZHVyYXRpb24oJ3Jlc3VsdF93b3JrJywgdGltZS5tb25vdG9uaWNfbnMoKSAtIHN0YXJ0ZWRfbnMpCiAgICAgICAgICAgICAgICBpZiBkZXRhaWw6CiAgICAgICAgICAgICAgICAgICAgbGlmZWN5Y2xlX3N0YXJ0LCBsaWZlY3ljbGVfY3B1ID0gdGltZS5tb25vdG9uaWNfbnMoKSwgdGltZS50aHJlYWRfdGltZV9ucygpCiAgICAgICAgICAgICAgICBpZiBoYW5kbGUgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICAgICAgaGFuZGxlLm1hcmtfc291cmNlX3N0YWdlKCdpbmZlcmVuY2VfZnJhbWVfY29tcGxldGVkJykKICAgICAgICAgICAgICAgICAgICBoYW5kbGUubWFya19mcmFtZShkZXRlY3Rpb25fY291bnQ9bGVuKGl0ZW1zKSkKICAgICAgICAgICAgICAgIGlmIGRldGFpbDoKICAgICAgICAgICAgICAgICAgICBtZXRyaWNzLmR1cmF0aW9uKCdyZXN1bHRfbGlmZWN5Y2xlJywgdGltZS5tb25vdG9uaWNfbnMoKSAtIGxpZmVjeWNsZV9zdGFydCkKICAgICAgICAgICAgICAgICAgICBtZXRyaWNzLmR1cmF0aW9uKCdyZXN1bHRfbGlmZWN5Y2xlX2NwdScsIHRpbWUudGhyZWFkX3RpbWVfbnMoKSAtIGxpZmVjeWNsZV9jcHUpCiAgICAgICAgICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICAgICAgICAgIGlmIHR5cGUoY29sbGVjdG9yX2ZyYW1lcykgaXMgaW50OgogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydjb2xsZWN0b3JfZnJhbWVzJ10gPSBjb2xsZWN0b3JfZnJhbWVzCiAgICAgICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljc1sncHJvY2Vzc2VkJ10gKz0gMQogICAgICAgIGV4Y2VwdCBFeGNlcHRpb246CiAgICAgICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgICAgICBzZWxmLl9lcnJvciA9ICdERVRfUkVTVUxUX0ZBSUxFRCcKICAgICAgICAgICAgICAgIHNlbGYuX3F1ZXVlLmNsZWFyKCkKICAgICAgICAgICAgICAgIHNlbGYuX2Nsb3NlZCA9IFRydWUKICAgICAgICAgICAgc2VsZi5vbl9lcnJvcigpCgogICAgZGVmIF9sYWJlbChzZWxmLCBjbGFzc19pZCk6CiAgICAgICAgaWYgc2VsZi5tb2RlbF9rZXkgPT0gRklSRV9NT0RFTDoKICAgICAgICAgICAgcmV0dXJuIEZJUkVfTkFNRVNbY2xhc3NfaWRdCiAgICAgICAgZnJvbSBhcHAuY2xhc3NfY2F0YWxvZyBpbXBvcnQgY29jb19uYW1lCiAgICAgICAgcmV0dXJuIGNvY29fbmFtZShjbGFzc19pZCkKCiAgICBkZWYgc25hcHNob3Qoc2VsZik6CiAgICAgICAgcmVzdWx0ID0gc2VsZi5sYXRlc3RfcmVzdWx0KCkKICAgICAgICByZXR1cm4gcmVzdWx0LnNuYXBzaG90KHZpc2libGVfb25seT1GYWxzZSkgaWYgcmVzdWx0IGVsc2UgTm9uZQoKICAgIGRlZiBsYXRlc3RfcmVzdWx0KHNlbGYpOgogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHJldHVybiBzZWxmLl9sYXRlc3QKCiAgICBkZWYgc3RhdHVzKHNlbGYpOgogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHJldHVybiBkaWN0KHN0YXRlPSdFUlJPUicgaWYgc2VsZi5fZXJyb3IgZWxzZSAoJ1NUT1BQRUQnIGlmIHNlbGYuX2Nsb3NlZCBlbHNlCiAgICAgICAgICAgICAgICAgICAgICAgICgnQ09OTkVDVEVEJyBpZiBzZWxmLl9tZXRyaWNzWydwcm9jZXNzZWQnXSBlbHNlICdQUkVQQVJFRCcpKSwKICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3I9c2VsZi5fZXJyb3IsIGRpc3BsYXlfdGhyZXNob2xkPXNlbGYuZGlzcGxheV90aHJlc2hvbGQsCiAgICAgICAgICAgICAgICAgICAgICAgIHZpc3VhbD1zZWxmLnZpc3VhbC5zdGF0dXMoKSBpZiBzZWxmLnZpc3VhbCBlbHNlIE5vbmUsCiAgICAgICAgICAgICAgICAgICAgICAgIGFydGlmYWN0cz1zZWxmLmFydGlmYWN0cy5zdGF0dXMoKSBpZiBzZWxmLmFydGlmYWN0cyBlbHNlIE5vbmUsCiAgICAgICAgICAgICAgICBmaWdodF9ub3RpZmljYXRpb249c2VsZi5maWdodC5ub3RpZmljYXRpb25fc3RhdHVzKCkgaWYgc2VsZi5maWdodCBlbHNlIE5vbmUsCiAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZV9lcnJvcj1zZWxmLl9zYW1wbGVzLmVycm9yIGlmIHNlbGYuX3NhbXBsZXMgZWxzZSBOb25lLAogICAgICAgICAgICAgICAgICAgICAgICBwZXJmb3JtYW5jZT1zZWxmLmluZ3Jlc3MubWV0cmljcy5zbmFwc2hvdCgpIGlmIGhhc2F0dHIoc2VsZi5pbmdyZXNzLCAnbWV0cmljcycpIGVsc2UgTm9uZSwKICAgICAgICAgICAgICAgICAgICAgICAgZmlyZV9tZXRyaWNzPWRpY3Qoc2VsZi5maXJlLm1ldHJpY3MpIGlmIHNlbGYuZmlyZSBpcyBub3QgTm9uZSBlbHNlIE5vbmUsCiAgICAgICAgICAgICAgICAgICAgICAgIHF1ZXVlZD1sZW4oc2VsZi5fcXVldWUpLCAqKnNlbGYuX21ldHJpY3MpCgogICAgZGVmIGNsb3NlKHNlbGYsIHRpbWVvdXQpOgogICAgICAgIGRlYWRsaW5lID0gdGltZS5tb25vdG9uaWMoKSArIG1heCgwLCB0aW1lb3V0KQogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHNlbGYuX2Nsb3NlZCA9IFRydWUKICAgICAgICAgICAgc2VsZi5fcXVldWUuY2xlYXIoKQogICAgICAgICAgICBzZWxmLl9sYXRlc3QgPSBOb25lCiAgICAgICAgICAgIHNlbGYuX2N2Lm5vdGlmeV9hbGwoKQogICAgICAgIGlmIHNlbGYuX3RocmVhZCBpcyBub3QgTm9uZToKICAgICAgICAgICAgc2VsZi5fdGhyZWFkLmpvaW4obWF4KDAsIHRpbWVvdXQpKQogICAgICAgICAgICBpZiBzZWxmLl90aHJlYWQuaXNfYWxpdmUoKToKICAgICAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcignRGV0IHJlc3VsdCB3b3JrZXIgY2xlYW51cCB0aW1lZCBvdXQuJykKICAgICAgICBpZiBzZWxmLnRyYWNrZXIgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIHNlbGYudHJhY2tlci5yZXNldCgpCiAgICAgICAgaWYgc2VsZi5pbnRydXNpb246CiAgICAgICAgICAgIHNlbGYuaW50cnVzaW9uLmNsZWFyKCkKICAgICAgICBpZiBzZWxmLmZpcmU6CiAgICAgICAgICAgIHNlbGYuZmlyZS5jbGVhcigpCiAgICAgICAgaWYgc2VsZi5mYWxsOgogICAgICAgICAgICBzZWxmLmZhbGwuY2xlYXIoKQogICAgICAgIGlmIHNlbGYuZmlnaHQ6CiAgICAgICAgICAgIHNlbGYuZmlnaHQuY2xlYXIoKQogICAgICAgIGlmIHNlbGYuY3Jvd2Q6CiAgICAgICAgICAgIHNlbGYuY3Jvd2QuY2xvc2UoKQogICAgICAgIGlmIGhhc2F0dHIoc2VsZi5pbmdyZXNzLCAnbWV0cmljcycpOgogICAgICAgICAgICBzZWxmLmluZ3Jlc3MubWV0cmljcy5jbG9zZSgpCiAgICAgICAgaWYgc2VsZi52aXN1YWwgaXMgbm90IE5vbmUgYW5kIG5vdCBzZWxmLnZpc3VhbC5jbG9zZShtYXgoMCwgZGVhZGxpbmUgLSB0aW1lLm1vbm90b25pYygpKSk6CiAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcignVmlzdWFsIHdvcmtlciBjbGVhbnVwIHRpbWVkIG91dC4nKQogICAgICAgIGlmIHNlbGYuYXJ0aWZhY3RzIGlzIG5vdCBOb25lIGFuZCBub3Qgc2VsZi5hcnRpZmFjdHMuY2xvc2UobWF4KDAsIGRlYWRsaW5lIC0gdGltZS5tb25vdG9uaWMoKSkpOgogICAgICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoJ0FydGlmYWN0IGNhcHR1cmUgY2xlYW51cCB0aW1lZCBvdXQuJykKICAgICAgICBpZiBzZWxmLnB1Ymxpc2hlciBpcyBub3QgTm9uZToKICAgICAgICAgICAgc2VsZi5wdWJsaXNoZXIuY2hhbm5lbChzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbMV0sIHNlbGYuaW5ncmVzcy5pZGVudGl0eVszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbNF0sICdFUlJPUicgaWYgc2VsZi5fZXJyb3IgZWxzZSAnU1RPUFBFRCcpCiAgICAgICAgICAgIGlmIG5vdCBzZWxmLnB1Ymxpc2hlci53YWl0X2NoYW5uZWwoc2VsZi5pbmdyZXNzLmlkZW50aXR5WzFdLCBzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbM10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5pbmdyZXNzLmlkZW50aXR5WzRdLCBtYXgoMCwgZGVhZGxpbmUgLSB0aW1lLm1vbm90b25pYygpKSk6CiAgICAgICAgICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoJ01ldGFkYXRhIGNoYW5uZWwgd29ya2VyIGNsZWFudXAgZmFpbGVkIG9yIHRpbWVkIG91dC4nKQo=",
    "app/multi_provider_results.py": "IiIiUFIxMyBib3VuZGVkIG11bHRpLXByb3ZpZGVyIEZyYW1lIGNvb3JkaW5hdG9yLgoKVGhlIGNvb3JkaW5hdG9yIG93bnMgRnJhbWUgYWNjZXB0YW5jZS9maW5hbGl6YXRpb24gYW5kIHNjZW5hcmlvIHN0YXRlLiBJdCBzdG9yZXMKb25seSBpbW11dGFibGUgY29waWVkIG1ldGFkYXRhLCBuZXZlciBTREsgRnJhbWUgd3JhcHBlcnMgb3IgcGl4ZWxzLiBQcm92aWRlcgpyZXN1bHRzIGFycml2aW5nIGFmdGVyIGEgRnJhbWUgZGVhZGxpbmUvZmluYWxpemF0aW9uL2V2aWN0aW9uIGFyZSBoZWFsdGgKcmVzcG9uc2VzIGJ1dCBjYW5ub3QgbXV0YXRlIFRyYWNraW5nLCBTY2VuYXJpbywgRXZlbnQgb3IgTWV0YWRhdGEgc3RhdGUuCiIiIgpmcm9tIF9fZnV0dXJlX18gaW1wb3J0IGFubm90YXRpb25zCgpmcm9tIGNvbGxlY3Rpb25zIGltcG9ydCBDb3VudGVyLCBPcmRlcmVkRGljdApmcm9tIGRhdGFjbGFzc2VzIGltcG9ydCBkYXRhY2xhc3MsIGZpZWxkLCByZXBsYWNlCmltcG9ydCBvcwppbXBvcnQgdGhyZWFkaW5nCmltcG9ydCB0aW1lCgpmcm9tIGFwcC5jb250cmFjdHMuZnJhbWVzIGltcG9ydCBEZXRlY3Rpb25PYnNlcnZhdGlvbiwgUG9zZU9ic2VydmF0aW9uCmZyb20gYXBwLmNvbnRyYWN0cy52aXN1YWxpemF0aW9uIGltcG9ydCBGcmFtZVJlc3VsdCwgVmlzdWFsaXphdGlvbkNvbW1hbmQKZnJvbSBhcHAucmVnaW9uX3NjZW5hcmlvIGltcG9ydCBhbGVydGVkLCBldmVudF9pZHMsIG1lbWJlcnMsIHZpc2libGUgYXMgc2NlbmFyaW9fdmlzaWJsZQoKCkBkYXRhY2xhc3MKY2xhc3MgX09wZW5GcmFtZToKICAgIGZyYW1lOiBvYmplY3QKICAgIGFkbWl0dGVkX2F0OiBmbG9hdAogICAgZGVhZGxpbmU6IGZsb2F0CiAgICByZXF1aXJlZDogc2V0W3N0cl0KICAgIHJlc3VsdHM6IGRpY3QKICAgIHN0YXRlOiBzdHIgPSAnT1BFTicKICAgIGdhcHM6IHNldCA9IGZpZWxkKGRlZmF1bHRfZmFjdG9yeT1zZXQpCiAgICBjbGFpbWVkOiBib29sID0gRmFsc2UKICAgIHNlbGVjdGVkX2F0OiBmbG9hdCB8IE5vbmUgPSBOb25lCgoKZGVmIHB1YmxpY19wb3NpdGlvbnMoY29tbWFuZHMsIGV2ZW50cywgY2FwYWNpdHk9MzAwKToKICAgICIiIktlZXAgRXZlbnQgcmVmcyBhbmQgZWFjaCB2aXNpYmxlIHByb3ZpZGVyJ3MgcmVwcmVzZW50YXRpdmUgYmVmb3JlIGZpbGwuIiIiCiAgICBmcm9tIGFwcC5jcm93ZF9ldmVudCBpbXBvcnQgQ3Jvd2RFdmVudAogICAgcmVxdWlyZWQgPSB7aW50KGUub2JqZWN0X3JlZikgZm9yIGUgaW4gZXZlbnRzIGlmIG5vdCBpc2luc3RhbmNlKGUsIENyb3dkRXZlbnQpfQogICAgaWYgYW55KGkgPCAwIG9yIGkgPj0gbGVuKGNvbW1hbmRzKSBmb3IgaSBpbiByZXF1aXJlZCk6CiAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignRXZlbnQgb2JqZWN0IHJlZmVyZW5jZSBpcyBvdXRzaWRlIHByb3ZpZGVyIGNvbW1hbmRzLicpCiAgICBpZiBsZW4oY29tbWFuZHMpIDw9IGNhcGFjaXR5OgogICAgICAgIHJldHVybiBsaXN0KHJhbmdlKGxlbihjb21tYW5kcykpKQogICAgcmVwcmVzZW50YXRpdmVzID0ge30KICAgIGZvciBpLCBjb21tYW5kIGluIGVudW1lcmF0ZShjb21tYW5kcyk6CiAgICAgICAgaWYgbm90IGNvbW1hbmQudmlzaWJsZToKICAgICAgICAgICAgY29udGludWUKICAgICAgICBkID0gY29tbWFuZC5kZXRlY3Rpb24KICAgICAgICBzZXBhcmF0ZV9jbGFzc2VzID0gZC5tb2RlbF9rZXkgaW4gKCdSRkRFVFJGaXJlU21va2UnLCAnQXdpcm9zX3BlcnNvbl9hbmRfaGVhZF9kZXRlY3Rpb24nKQogICAgICAgIGdyb3VwID0gKGQubW9kZWxfa2V5LCBkLmNsYXNzX2lkIGlmIHNlcGFyYXRlX2NsYXNzZXMgZWxzZSBOb25lKQogICAgICAgICMgQ1JPV0QncyBjb3VudCBsYWJlbCBtdXN0IHN1cnZpdmUgYWhlYWQgb2YgaXRzIHBsYWluIGJveGVzLgogICAgICAgIHJhbmsgPSAoaW50KCcgfCBQJyBpbiBjb21tYW5kLmxhYmVsX3RleHQgb3IgJyB8IEgnIGluIGNvbW1hbmQubGFiZWxfdGV4dCksCiAgICAgICAgICAgICAgICBpbnQoYWxlcnRlZChjb21tYW5kLnNjZW5hcmlvKSksIGQuc2NvcmUsIC1pKQogICAgICAgIGlmIGdyb3VwIG5vdCBpbiByZXByZXNlbnRhdGl2ZXMgb3IgcmFuayA+IHJlcHJlc2VudGF0aXZlc1tncm91cF1bMF06CiAgICAgICAgICAgIHJlcHJlc2VudGF0aXZlc1tncm91cF0gPSAocmFuaywgaSkKICAgIHJlcXVpcmVkLnVwZGF0ZShpIGZvciBfLCBpIGluIHJlcHJlc2VudGF0aXZlcy52YWx1ZXMoKSkKICAgIGlmIGxlbihyZXF1aXJlZCkgPiBjYXBhY2l0eToKICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoJ01hbmRhdG9yeSBtZXRhZGF0YSBvYmplY3QgY2FwYWNpdHkgZXhjZWVkZWQuJykKICAgIHJhbmtlZCA9IHNvcnRlZCgoaSBmb3IgaSBpbiByYW5nZShsZW4oY29tbWFuZHMpKSBpZiBpIG5vdCBpbiByZXF1aXJlZCksCiAgICAgICAgICAgICAgICAgICAga2V5PWxhbWJkYSBpOiAobm90IGNvbW1hbmRzW2ldLnZpc2libGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm90IChhbGVydGVkKGNvbW1hbmRzW2ldLnNjZW5hcmlvKSBvciBjb21tYW5kc1tpXS5ldmVudF9pZHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1jb21tYW5kc1tpXS5kZXRlY3Rpb24uc2NvcmUsIGkpKQogICAgcmV0dXJuIHNvcnRlZChyZXF1aXJlZCB8IHNldChyYW5rZWRbOmNhcGFjaXR5LWxlbihyZXF1aXJlZCldKSkKCgpjbGFzcyBNdWx0aVByb3ZpZGVyQ29vcmRpbmF0b3I6CiAgICBkZWYgX19pbml0X18oc2VsZiwgc3BlYywgaW5ncmVzcywgcHJvdmlkZXJfcGxhbiwgY29sbGVjdG9yLCBpc19jdXJyZW50LCBvbl9mYXRhbCwKICAgICAgICAgICAgICAgICAqLCBwdWJsaXNoZXI9Tm9uZSwgb25fcHJvdmlkZXJfZnJhbWU9Tm9uZSwgY2xvY2s9dGltZS5tb25vdG9uaWMpOgogICAgICAgIHNlbGYuc3BlYyA9IHNwZWMKICAgICAgICBzZWxmLmluZ3Jlc3MgPSBpbmdyZXNzCiAgICAgICAgc2VsZi5wbGFuID0gcHJvdmlkZXJfcGxhbgogICAgICAgIHNlbGYuY29sbGVjdG9yID0gY29sbGVjdG9yCiAgICAgICAgc2VsZi5pc19jdXJyZW50ID0gaXNfY3VycmVudAogICAgICAgIHNlbGYub25fZmF0YWwgPSBvbl9mYXRhbAogICAgICAgIHNlbGYucHVibGlzaGVyID0gcHVibGlzaGVyCiAgICAgICAgc2VsZi5vbl9wcm92aWRlcl9mcmFtZSA9IG9uX3Byb3ZpZGVyX2ZyYW1lCiAgICAgICAgc2VsZi5jbG9jayA9IGNsb2NrCgogICAgICAgIHNlbGYuZnJlc2huZXNzX3MgPSBmbG9hdChvcy5lbnZpcm9uLmdldCgKICAgICAgICAgICAgJ0NPTlRFWFRSQV9QUk9WSURFUl9SRVNVTFRfRlJFU0hORVNTX01TJywgJzEwMCcpKSAvIDEwMDAuMAogICAgICAgIHNlbGYuc3RhbGxfcyA9IGZsb2F0KG9zLmVudmlyb24uZ2V0KCdDT05URVhUUkFfUFJPVklERVJfU1RBTExfU0VDT05EUycsICcyLjAnKSkKICAgICAgICBzZWxmLnN0YXJ0dXBfcyA9IGZsb2F0KG9zLmVudmlyb24uZ2V0KCdDT05URVhUUkFfUFJPVklERVJfU1RBUlRVUF9TRUNPTkRTJywgJzEwLjAnKSkKICAgICAgICBmbGFnID0gb3MuZW52aXJvbi5nZXQoJ0NPTlRFWFRSQV9QUk9WSURFUl9GUkVTSE5FU1NfRU5BQkxFRCcsICd0cnVlJykubG93ZXIoKQogICAgICAgIGlmIGZsYWcgbm90IGluICgndHJ1ZScsICdmYWxzZScpOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdJbnZhbGlkIGZyZXNobmVzcyBmbGFnLicpCiAgICAgICAgc2VsZi5mcmVzaG5lc3NfZW5hYmxlZCA9IGZsYWcgPT0gJ3RydWUnCiAgICAgICAgaWYgbm90IHNlbGYuZnJlc2huZXNzX2VuYWJsZWQgYW5kIGxlbihwcm92aWRlcl9wbGFuLnByb3ZpZGVycykgIT0gMToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignRnJlc2huZXNzIE9GRiByZXF1aXJlcyBvbmUgcHJvdmlkZXIgcGVyIGNvb3JkaW5hdG9yLicpCiAgICAgICAgaWYgKG5vdCAwIDwgc2VsZi5mcmVzaG5lc3NfcyA8PSAxMCBvciBub3QgMCA8IHNlbGYuc3RhbGxfcyA8PSAzMDAKICAgICAgICAgICAgICAgIG9yIG5vdCBzZWxmLnN0YWxsX3MgPD0gc2VsZi5zdGFydHVwX3MgPD0gMzAwKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBtdWx0aS1wcm92aWRlciB0aW1pbmcgc2V0dGluZ3MuJykKICAgICAgICBzZWxmLmNhcGFjaXR5ID0gMiBpZiBzZWxmLmZyZXNobmVzc19lbmFibGVkIGVsc2UgMwoKICAgICAgICBmcm9tIGFwcC5zdHJlYW1fc2V0dGluZ3MgaW1wb3J0IHJldmlzaW9uLCBkaXNwbGF5X3Njb3JlLCB2aXN1YWxfb3B0aW9ucwogICAgICAgIHNlbGYuc2NlbmFyaW9fcmV2aXNpb24gPSAoc3BlYy5nZXQoJ19wcm92aWRlcl9ydW50aW1lJykgb3Ige30pLmdldCgncmV2aXNpb24nKSBvciByZXZpc2lvbihzcGVjKQogICAgICAgIHNlbGYuZGlzcGxheV90aHJlc2hvbGQgPSBkaXNwbGF5X3Njb3JlKAogICAgICAgICAgICBzcGVjLCAoKHNwZWMuZ2V0KCdpbmZlcmVuY2VfcHJvZmlsZScpIG9yIHt9KS5nZXQoJ3RocmVzaG9sZHMnKSBvciB7fSkuZ2V0KCdzY29yZScsIC41KSkKICAgICAgICBzZWxmLmRpc3BsYXlfY2F0ZWdvcmllcywgc2VsZi5kZWJ1Z19hbGxfY2FuZGlkYXRlcyA9IHZpc3VhbF9vcHRpb25zKHNwZWMpCiAgICAgICAgc2VsZi5kaXNwbGF5X2NhdGVnb3JpZXMgPSAoZnJvemVuc2V0KHNlbGYuZGlzcGxheV9jYXRlZ29yaWVzKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIHNlbGYuZGlzcGxheV9jYXRlZ29yaWVzIGlzIG5vdCBOb25lIGVsc2UgTm9uZSkKICAgICAgICBzZWxmLmNhbWVyYV9pZCA9IHNwZWMuZ2V0KCdjYW1lcmFfaWQnKQoKICAgICAgICBmcm9tIGFwcC5yZWdpb25fc2NlbmFyaW8gaW1wb3J0IGNvbXBvc2UKICAgICAgICBmcm9tIGFwcC5mYWxsX3J1bnRpbWUgaW1wb3J0IEZhbGxTZXR0aW5ncywgRmFsbFNjZW5hcmlvCiAgICAgICAgZnJvbSBhcHAuZmlnaHRfcnVudGltZSBpbXBvcnQgRmlnaHRTZXR0aW5ncywgRmlnaHRTY2VuYXJpbwogICAgICAgIGZyb20gYXBwLmZpcmVfY29uZmlnIGltcG9ydCBidWlsZF9lbmdpbmUKICAgICAgICBmcm9tIGFwcC5jcm93ZF9jb25maWcgaW1wb3J0IENyb3dkQ29uZmlnCiAgICAgICAgZnJvbSBhcHAuY3Jvd2Rfc2NlbmFyaW8gaW1wb3J0IENyb3dkCiAgICAgICAgZnJvbSBhcHAuY3Jvd2RfcmVzdWx0IGltcG9ydCBDcm93ZFJlc3VsdFByb2Nlc3NvcgogICAgICAgIGZyb20gYXBwLnBvc2VfY29uZmlnIGltcG9ydCBQb3NlQ29uZmlnCiAgICAgICAgc2VsZi5yZWdpb24gPSBjb21wb3NlKHNwZWMpCiAgICAgICAgZmFsbF9jZmcgPSBGYWxsU2V0dGluZ3MucGFyc2Uoc3BlYy5nZXQoJ2ZhbGwnKSBvciB7fSkKICAgICAgICBmaWdodF9jZmcgPSBGaWdodFNldHRpbmdzLnBhcnNlKHNwZWMuZ2V0KCdmaWdodCcpIG9yIHt9KQogICAgICAgIHNlbGYuZmFsbCA9IEZhbGxTY2VuYXJpbyhmYWxsX2NmZykgaWYgZmFsbF9jZmcuZW5hYmxlZCBlbHNlIE5vbmUKICAgICAgICBzZWxmLmZpZ2h0ID0gRmlnaHRTY2VuYXJpbyhmaWdodF9jZmcpIGlmIGZpZ2h0X2NmZy5lbmFibGVkIGVsc2UgTm9uZQogICAgICAgIHNlbGYuZmlyZSA9IGJ1aWxkX2VuZ2luZShzcGVjKQogICAgICAgIGZyb20gYXBwLmV2ZW50X2Nvb2xkb3duIGltcG9ydCBFdmVudENvb2xkb3duCiAgICAgICAgc2VsZi5ldmVudF9jb29sZG93biA9IEV2ZW50Q29vbGRvd24oY2xvY2s9c2VsZi5jbG9jaywgb3ZlcnJpZGVzPXNwZWMuZ2V0KCdldmVudF9jb29sZG93bnMnKSkKICAgICAgICBlbmdpbmVzID0gZ2V0YXR0cihzZWxmLnJlZ2lvbiwgJ2VuZ2luZXMnLCAoc2VsZi5yZWdpb24sKSkKICAgICAgICBmb3IgZW5naW5lIGluICgqZW5naW5lcywgc2VsZi5mYWxsLmVuZ2luZSBpZiBzZWxmLmZhbGwgZWxzZSBOb25lLAogICAgICAgICAgICAgICAgICAgICAgIHNlbGYuZmlnaHQuZW5naW5lIGlmIHNlbGYuZmlnaHQgZWxzZSBOb25lLCBzZWxmLmZpcmUpOgogICAgICAgICAgICBpZiBlbmdpbmUgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICBlbmdpbmUuZXZlbnRfYWRtaXNzaW9uID0gc2VsZi5ldmVudF9jb29sZG93bi5hbGxvdwogICAgICAgIGNyb3dkX2NmZyA9IENyb3dkQ29uZmlnLnBhcnNlKHNwZWMuZ2V0KCdjcm93ZCcpIG9yIHt9KQogICAgICAgIHNlbGYuY3Jvd2QgPSAoQ3Jvd2RSZXN1bHRQcm9jZXNzb3IoCiAgICAgICAgICAgIENyb3dkKGNyb3dkX2NmZyksIGNhbWVyYV9pZD1zZWxmLmNhbWVyYV9pZCwKICAgICAgICAgICAgc2NlbmFyaW9fcmV2aXNpb249c2VsZi5zY2VuYXJpb19yZXZpc2lvbikgaWYgY3Jvd2RfY2ZnLmVuYWJsZWQgZWxzZSBOb25lKQogICAgICAgIGlmIHNlbGYuY3Jvd2QgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIHNlbGYuY3Jvd2QuZW5naW5lLmV2ZW50X2FkbWlzc2lvbiA9IHNlbGYuZXZlbnRfY29vbGRvd24uYWxsb3cKICAgICAgICBzZWxmLnBvc2VfY29uZmlnID0gKFBvc2VDb25maWcucGFyc2Uoc3BlYy5nZXQoJ3Bvc2UnKSBvciB7fSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIGFueShwLmtleSA9PSAncG9zZScgZm9yIHAgaW4gcHJvdmlkZXJfcGxhbi5wcm92aWRlcnMpIGVsc2UgTm9uZSkKCiAgICAgICAgZnJvbSBhcHAuYnl0ZV90cmFja2luZyBpbXBvcnQgQnl0ZVRyYWNrZXIsIFRyYWNraW5nU2V0dGluZ3MKICAgICAgICB0cmFja2luZyA9IGRpY3Qoc3BlYy5nZXQoJ3RyYWNraW5nJykgb3Ige30pCiAgICAgICAgdHJhY2tpbmdbJ2ZyYW1lX3JhdGUnXSA9IGluZ3Jlc3Muc2FtcGxlci5mcHMKICAgICAgICB0cmFja2luZ19jZmcgPSBUcmFja2luZ1NldHRpbmdzLnBhcnNlKHRyYWNraW5nKQogICAgICAgIHNlbGYudHJhY2tlciA9IChCeXRlVHJhY2tlcih0cmFja2luZ19jZmcsIG1ldHJpY3M9aW5ncmVzcy5tZXRyaWNzKQogICAgICAgICAgICAgICAgICAgICAgICBpZiBwcm92aWRlcl9wbGFuLnBlcnNvbl9vd25lciBhbmQgdHJhY2tpbmdfY2ZnLmVuYWJsZWQgZWxzZSBOb25lKQoKICAgICAgICBzZWxmLnZpc3VhbCA9IE5vbmUKICAgICAgICBzZWxmLmFydGlmYWN0cyA9IE5vbmUKICAgICAgICBzZWxmLl9zYW1wbGVzID0gTm9uZQogICAgICAgIHNlbGYuX2N2ID0gdGhyZWFkaW5nLkNvbmRpdGlvbigpCiAgICAgICAgc2VsZi5fZnJhbWVzID0gT3JkZXJlZERpY3QoKQogICAgICAgIHNlbGYuX2Nsb3NlZCA9IEZhbHNlCiAgICAgICAgc2VsZi5fdGhyZWFkID0gTm9uZQogICAgICAgIHNlbGYuX2xhc3RfYWRtaXR0ZWQgPSAtMQogICAgICAgIHNlbGYuX2xhc3RfcHVibGlzaGVkID0gLTEKICAgICAgICBzZWxmLl9sYXRlc3QgPSBOb25lCiAgICAgICAgc2VsZi5fZXJyb3IgPSBOb25lCiAgICAgICAgc2VsZi5fbWV0cmljcyA9IENvdW50ZXIoKQogICAgICAgIG5vdyA9IHNlbGYuY2xvY2soKQogICAgICAgIHNlbGYuX3Byb3ZpZGVycyA9IHsKICAgICAgICAgICAgcC5rZXk6IGRpY3Qoc3RhdGU9J0FDVElWRScsIHJlYXNvbj1Ob25lLCBmaXJzdF9pbnB1dF9hdD1Ob25lLAogICAgICAgICAgICAgICAgICAgICAgICBsYXN0X2lucHV0X2F0PU5vbmUsIGxhc3RfcmVzcG9uc2VfYXQ9Tm9uZSwKICAgICAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2VzPTAsIGxhdGU9MCwgYnVzeV9kcm9wPTApCiAgICAgICAgICAgIGZvciBwIGluIHByb3ZpZGVyX3BsYW4ucHJvdmlkZXJzCiAgICAgICAgfQogICAgICAgIHNlbGYuX2RlcGVuZGVuY2llcyA9IHsKICAgICAgICAgICAgc2NlbmFyaW86IHByb3ZpZGVyLmtleQogICAgICAgICAgICBmb3IgcHJvdmlkZXIgaW4gcHJvdmlkZXJfcGxhbi5wcm92aWRlcnMKICAgICAgICAgICAgZm9yIHNjZW5hcmlvIGluIHByb3ZpZGVyLnNjZW5hcmlvcwogICAgICAgIH0KICAgICAgICBzZWxmLl9yZXF1ZXN0ZWQgPSBzZXQocHJvdmlkZXJfcGxhbi5yZXF1ZXN0ZWRfc2NlbmFyaW9zKQogICAgICAgIHNlbGYuX3N0YXJ0ZWRfYXQgPSBub3cKICAgICAgICBzZWxmLl9wZXJzb25fZ2FwX3BlbmRpbmcgPSBGYWxzZQogICAgICAgIHNlbGYuX2dhcF9wZW5kaW5nID0ge3Aua2V5OiBGYWxzZSBmb3IgcCBpbiBwcm92aWRlcl9wbGFuLnByb3ZpZGVyc30KICAgICAgICBzZWxmLl9maW5hbGl6aW5nID0gTm9uZQogICAgICAgIHNlbGYuX2JyYW5jaF9yZWxlYXNlID0ge30KICAgICAgICBzZWxmLl90aW1pbmdzID0ge30KICAgICAgICBzZWxmLl9yZXRpcmVkID0gT3JkZXJlZERpY3QoKQoKICAgIGRlZiBfbm90aWZ5X2ZhdGFsKHNlbGYsIHJlYXNvbiwgZXJyb3I9Tm9uZSk6CiAgICAgICAgIyBQcmVzZXJ2ZSB0aGUgZmlyc3QgZmFpbHVyZSBib3VuZGFyeSBiZWZvcmUgU3RyZWFtR3JvdXAgY2xlYXJzIHRoZSBwYXRoLgogICAgICAgIGltcG9ydCBqc29uCiAgICAgICAgaW1wb3J0IHN5cwogICAgICAgIGltcG9ydCB0cmFjZWJhY2sKICAgICAgICBmcm9tIHBhdGhsaWIgaW1wb3J0IFBhdGgKICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICBkaWFnbm9zdGljID0gZGljdChjb2RlPSdNVUxUSV9QUk9WSURFUl9GQVRBTCcsIHJlYXNvbj1yZWFzb24sCiAgICAgICAgICAgICAgICBtb25vdG9uaWNfbnM9dGltZS5tb25vdG9uaWNfbnMoKSwgZXJyb3I9c2VsZi5fZXJyb3IsCiAgICAgICAgICAgICAgICBwcm92aWRlcnM9e2s6IHtuOiB2W25dIGZvciBuIGluICgnc3RhdGUnLCAncmVhc29uJywgJ3Jlc3BvbnNlcycsICdsYXRlJyl9CiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBrLCB2IGluIHNlbGYuX3Byb3ZpZGVycy5pdGVtcygpfSkKICAgICAgICBpZiBlcnJvciBpcyBub3QgTm9uZToKICAgICAgICAgICAgZGlhZ25vc3RpY1snZXhjZXB0aW9uX3R5cGUnXSA9IHR5cGUoZXJyb3IpLl9fbmFtZV9fCiAgICAgICAgICAgIGRpYWdub3N0aWNbJ2xvY2F0aW9ucyddID0gW2RpY3QoZmlsZT1QYXRoKGYuZmlsZW5hbWUpLm5hbWUsIGxpbmU9Zi5saW5lbm8sIGZ1bmN0aW9uPWYubmFtZSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgZiBpbiB0cmFjZWJhY2suZXh0cmFjdF90YihlcnJvci5fX3RyYWNlYmFja19fKVstNDpdXQogICAgICAgIHRyeToKICAgICAgICAgICAgcHJpbnQoanNvbi5kdW1wcyhkaWFnbm9zdGljKSwgZmlsZT1zeXMuc3RkZXJyLCBmbHVzaD1UcnVlKQogICAgICAgIGV4Y2VwdCBPU0Vycm9yOgogICAgICAgICAgICBwYXNzCiAgICAgICAgc2VsZi5vbl9mYXRhbCgpCgogICAgZGVmIF90aW1pbmdfbG9ja2VkKHNlbGYsIHByb3ZpZGVyLCBzdGFnZSwgc2Vjb25kcyk6CiAgICAgICAgaWYgc2Vjb25kcyBpcyBOb25lIG9yIHNlY29uZHMgPCAwOgogICAgICAgICAgICByZXR1cm4KICAgICAgICBtcyA9IHNlY29uZHMgKiAxMDAwCiAgICAgICAgcm93ID0gc2VsZi5fdGltaW5ncy5zZXRkZWZhdWx0KHByb3ZpZGVyLCB7fSkuc2V0ZGVmYXVsdCgKICAgICAgICAgICAgc3RhZ2UsIGRpY3QoY291bnQ9MCwgc3VtX21zPTAuLCBtYXhfbXM9MC4sIG92ZXJfMTAwbXM9MCkpCiAgICAgICAgcm93Wydjb3VudCddICs9IDEKICAgICAgICByb3dbJ3N1bV9tcyddICs9IG1zCiAgICAgICAgcm93WydtYXhfbXMnXSA9IG1heChyb3dbJ21heF9tcyddLCBtcykKICAgICAgICByb3dbJ292ZXJfMTAwbXMnXSArPSBpbnQobXMgPiAxMDApCgogICAgZGVmIHByb3ZpZGVyX2dhdGVfdGltZShzZWxmLCBwcm92aWRlciwgc2VxLCBlbnRlcmVkX2F0KToKICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICBzdGF0ZSA9IHNlbGYuX2ZyYW1lcy5nZXQoc2VxKQogICAgICAgICAgICBpZiAoc3RhdGUgaXMgTm9uZSBvciBzdGF0ZS5zdGF0ZSAhPSAnT1BFTicgb3Igc2VsZi5fY2xvc2VkCiAgICAgICAgICAgICAgICAgICAgb3Igbm90IHNlbGYuaXNfY3VycmVudCgpIG9yIHNlbGYuX3Byb3ZpZGVyc1twcm92aWRlcl1bJ3N0YXRlJ10gIT0gJ0FDVElWRScKICAgICAgICAgICAgICAgICAgICBvciAoc2VsZi5mcmVzaG5lc3NfZW5hYmxlZCBhbmQgZW50ZXJlZF9hdCA+IHN0YXRlLmRlYWRsaW5lKSk6CiAgICAgICAgICAgICAgICByZXR1cm4gTm9uZQogICAgICAgICAgICBzdGF0ZS5jbGFpbWVkID0gVHJ1ZQogICAgICAgICAgICBzZWxmLl9wcm92aWRlcnNbcHJvdmlkZXJdLnNldGRlZmF1bHQoJ2ZpcnN0X3JlcXVlc3RfYXQnLCBlbnRlcmVkX2F0KQogICAgICAgICAgICBzZWxmLl90aW1pbmdfbG9ja2VkKHByb3ZpZGVyLCAnc2VsZWN0ZWRfdG9fZ2F0ZScsIGVudGVyZWRfYXQtc3RhdGUuYWRtaXR0ZWRfYXQpCiAgICAgICAgICAgIHJldHVybiBzdGF0ZS5hZG1pdHRlZF9hdAoKICAgIGRlZiBfcmV0aXJlX2xvY2tlZChzZWxmLCBzZXEsIHJlYXNvbik6CiAgICAgICAgc2VsZi5fcmV0aXJlZFtzZXFdID0gcmVhc29uCiAgICAgICAgd2hpbGUgbGVuKHNlbGYuX3JldGlyZWQpID4gNjQ6CiAgICAgICAgICAgIHNlbGYuX3JldGlyZWQucG9waXRlbShsYXN0PUZhbHNlKQoKICAgIGRlZiByZWdpc3Rlcl9icmFuY2hfcmVsZWFzZShzZWxmLCBrZXksIHJlbGVhc2UpOgogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHNlbGYuX2JyYW5jaF9yZWxlYXNlW2tleV0gPSByZWxlYXNlCiAgICAgICAgICAgIGRpc2FibGVkID0gc2VsZi5fY2xvc2VkIG9yIHNlbGYuX3Byb3ZpZGVyc1trZXldWydzdGF0ZSddICE9ICdBQ1RJVkUnCiAgICAgICAgaWYgZGlzYWJsZWQ6CiAgICAgICAgICAgIHJlbGVhc2UoKQoKICAgIGRlZiBzdG9wX2FkbWlzc2lvbihzZWxmKToKICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICBzZWxmLl9jbG9zZWQgPSBUcnVlCiAgICAgICAgICAgIHNlbGYuX2ZyYW1lcy5jbGVhcigpCiAgICAgICAgICAgIHJlbGVhc2VzID0gbGlzdChzZWxmLl9icmFuY2hfcmVsZWFzZS52YWx1ZXMoKSkKICAgICAgICAgICAgc2VsZi5fY3Yubm90aWZ5X2FsbCgpCiAgICAgICAgZm9yIHJlbGVhc2UgaW4gcmVsZWFzZXM6CiAgICAgICAgICAgIHJlbGVhc2UoKQoKICAgIGRlZiBfZXZpY3RfbG9ja2VkKHNlbGYsIHN0YXRlKToKICAgICAgICBzZWxmLl9yZXRpcmVfbG9ja2VkKHN0YXRlLmZyYW1lLmZyYW1lX3NlcSwgJ2V2aWN0ZWQnKQogICAgICAgIHN0YXRlLnN0YXRlID0gJ0VWSUNURUQnCiAgICAgICAgZm9yIGtleSBpbiBzZWxmLl9nYXBfcGVuZGluZzoKICAgICAgICAgICAgc2VsZi5fZ2FwX3BlbmRpbmdba2V5XSA9IFRydWUKICAgICAgICBzZWxmLl9tZXRyaWNzWydmcmFtZV9ldmljdGVkJ10gKz0gMQoKICAgIGRlZiBzdGFydChzZWxmKToKICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICBpZiBzZWxmLl9jbG9zZWQgb3Igc2VsZi5fdGhyZWFkIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgcmFpc2UgUnVudGltZUVycm9yKCdNdWx0aS1wcm92aWRlciBjb29yZGluYXRvciBjYW5ub3Qgc3RhcnQgdHdpY2UuJykKICAgICAgICAgICAgaWYgc2VsZi5wdWJsaXNoZXIgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICBpZiBub3Qgc2VsZi5wdWJsaXNoZXIuY2hhbm5lbChzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbMV0sIHNlbGYuaW5ncmVzcy5pZGVudGl0eVszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuaW5ncmVzcy5pZGVudGl0eVs0XSwgJ1NUQVJUSU5HJyk6CiAgICAgICAgICAgICAgICAgICAgcmFpc2UgUnVudGltZUVycm9yKCdNZXRhZGF0YSBjaGFubmVsIHdvcmtlciBhZG1pc3Npb24gcmVqZWN0ZWQuJykKICAgICAgICAgICAgZnJvbSBhcHAubWV0YWRhdGFfc2FtcGxlcyBpbXBvcnQgTWV0YWRhdGFTYW1wbGVzCiAgICAgICAgICAgIGZyb20gYXBwLm1ldGFkYXRhX3Zpc3VhbCBpbXBvcnQgTWV0YWRhdGFWaXN1YWwKICAgICAgICAgICAgZnJvbSBhcHAuZXZlbnRfY2FwdHVyZSBpbXBvcnQgRXZlbnRDYXB0dXJlCiAgICAgICAgICAgIHNlbGYuX3NhbXBsZXMgPSBNZXRhZGF0YVNhbXBsZXMuZnJvbV9lbnZpcm9ubWVudCgpCiAgICAgICAgICAgIGlmIG9zLmVudmlyb24uZ2V0KCdDT05URVhUUkFfTUVUQURBVEFfVklTVUFMX0VOQUJMRUQnLCAndHJ1ZScpLmxvd2VyKCkgPT0gJ3RydWUnOgogICAgICAgICAgICAgICAgc2VsZi52aXN1YWwgPSBNZXRhZGF0YVZpc3VhbC5mcm9tX2Vudmlyb25tZW50KGRpc3BsYXlfdGhyZXNob2xkPXNlbGYuZGlzcGxheV90aHJlc2hvbGQpCiAgICAgICAgICAgIHNlbGYuYXJ0aWZhY3RzID0gRXZlbnRDYXB0dXJlLmZyb21fZW52aXJvbm1lbnQoc2VsZi5zcGVjKQogICAgICAgICAgICBzZWxmLl90aHJlYWQgPSB0aHJlYWRpbmcuVGhyZWFkKAogICAgICAgICAgICAgICAgdGFyZ2V0PXNlbGYuX3J1biwgbmFtZT0nbXVsdGktcHJvdmlkZXItcmVzdWx0cycsIGRhZW1vbj1UcnVlKQogICAgICAgICAgICBzZWxmLl90aHJlYWQuc3RhcnQoKQoKICAgIGRlZiBhZG1pdChzZWxmLCBmcmFtZSwgYWRtaXR0ZWRfYXQ9Tm9uZSk6CiAgICAgICAgYWRtaXR0ZWRfYXQgPSBzZWxmLmNsb2NrKCkgaWYgYWRtaXR0ZWRfYXQgaXMgTm9uZSBlbHNlIGZsb2F0KGFkbWl0dGVkX2F0KQogICAgICAgIGZhdGFsID0gRmFsc2UKICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICBpZiBzZWxmLl9jbG9zZWQgb3Igbm90IHNlbGYuaXNfY3VycmVudCgpIG9yIGZyYW1lLmZyYW1lX3NlcSA8PSBzZWxmLl9sYXN0X2FkbWl0dGVkOgogICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljc1snYWRtaXNzaW9uX3N0YWxlJ10gKz0gMQogICAgICAgICAgICAgICAgcmV0dXJuIEZhbHNlCiAgICAgICAgICAgIHNlbGYuX2xhc3RfYWRtaXR0ZWQgPSBmcmFtZS5mcmFtZV9zZXEKICAgICAgICAgICAgYWN0aXZlID0ge2sgZm9yIGssIHYgaW4gc2VsZi5fcHJvdmlkZXJzLml0ZW1zKCkgaWYgdlsnc3RhdGUnXSA9PSAnQUNUSVZFJ30KICAgICAgICAgICAgZm9yIGtleSBpbiBhY3RpdmU6CiAgICAgICAgICAgICAgICBzdGF0dXMgPSBzZWxmLl9wcm92aWRlcnNba2V5XQogICAgICAgICAgICAgICAgaWYgc3RhdHVzWydmaXJzdF9pbnB1dF9hdCddIGlzIE5vbmU6CiAgICAgICAgICAgICAgICAgICAgc3RhdHVzWydmaXJzdF9pbnB1dF9hdCddID0gYWRtaXR0ZWRfYXQKICAgICAgICAgICAgICAgIHN0YXR1c1snbGFzdF9pbnB1dF9hdCddID0gYWRtaXR0ZWRfYXQKICAgICAgICAgICAgd2hpbGUgbGVuKHNlbGYuX2ZyYW1lcykgPj0gc2VsZi5jYXBhY2l0eToKICAgICAgICAgICAgICAgIGV2aWN0YWJsZSA9IG5leHQoKHNlcSBmb3Igc2VxLCBzIGluIHNlbGYuX2ZyYW1lcy5pdGVtcygpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBzZWxmLmZyZXNobmVzc19lbmFibGVkIG9yIG5vdCAocy5jbGFpbWVkIG9yIHMucmVzdWx0cykpLCBOb25lKQogICAgICAgICAgICAgICAgaWYgZXZpY3RhYmxlIGlzIE5vbmU6CiAgICAgICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljc1snYWRtaXNzaW9uX2NhcGFjaXR5X2Ryb3AnXSArPSAxCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIEZhbHNlCiAgICAgICAgICAgICAgICBvbGRlc3QgPSBzZWxmLl9mcmFtZXMucG9wKGV2aWN0YWJsZSkKICAgICAgICAgICAgICAgIHNlbGYuX2V2aWN0X2xvY2tlZChvbGRlc3QpCiAgICAgICAgICAgIHNlbGYuX2ZyYW1lc1tmcmFtZS5mcmFtZV9zZXFdID0gX09wZW5GcmFtZSgKICAgICAgICAgICAgICAgIGZyYW1lLCBhZG1pdHRlZF9hdCwgYWRtaXR0ZWRfYXQrc2VsZi5mcmVzaG5lc3NfcywgYWN0aXZlLCB7fSkKICAgICAgICAgICAgc2VsZi5fbWV0cmljc1snYWRtaXR0ZWQnXSArPSAxCiAgICAgICAgICAgIGZhdGFsID0gc2VsZi5fY2hlY2tfYWxsX3VuYXZhaWxhYmxlX2xvY2tlZCgpCiAgICAgICAgICAgIHNlbGYuX2N2Lm5vdGlmeV9hbGwoKQogICAgICAgIGlmIGZhdGFsOgogICAgICAgICAgICBzZWxmLl9ub3RpZnlfZmF0YWwoJ2FkbWlzc2lvbl91bmF2YWlsYWJsZScpCiAgICAgICAgcmV0dXJuIG5vdCBmYXRhbAoKICAgIGRlZiBpc19vcGVuKHNlbGYsIGZyYW1lX3NlcSk6CiAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgc3RhdGUgPSBzZWxmLl9mcmFtZXMuZ2V0KGZyYW1lX3NlcSkKICAgICAgICAgICAgcmV0dXJuIGJvb2wobm90IHNlbGYuX2Nsb3NlZCBhbmQgc2VsZi5pc19jdXJyZW50KCkgYW5kIHN0YXRlCiAgICAgICAgICAgICAgICAgICAgICAgIGFuZCBzdGF0ZS5zdGF0ZSA9PSAnT1BFTicKICAgICAgICAgICAgICAgICAgICAgICAgYW5kIChub3Qgc2VsZi5mcmVzaG5lc3NfZW5hYmxlZCBvciBzZWxmLmNsb2NrKCkgPD0gc3RhdGUuZGVhZGxpbmUpKQoKICAgIGRlZiBwcm92aWRlcl9hdmFpbGFibGUoc2VsZiwga2V5KToKICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICByZXR1cm4gc2VsZi5fcHJvdmlkZXJzLmdldChrZXksIHt9KS5nZXQoJ3N0YXRlJykgPT0gJ0FDVElWRScKCiAgICBkZWYgbm90ZV9wcm92aWRlcl9wcm9ncmVzcyhzZWxmLCBrZXksIHN0YWdlKToKICAgICAgICBpZiBzdGFnZSBub3QgaW4gKCdpbmZlcl9vdXRwdXQnLCAnY2FsbGJhY2snKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignSW52YWxpZCBwcm92aWRlciBwcm9ncmVzcyBzdGFnZS4nKQogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHN0YXR1cyA9IHNlbGYuX3Byb3ZpZGVyc1trZXldCiAgICAgICAgICAgIGlmIG5vdCBzZWxmLl9jbG9zZWQgYW5kIHN0YXR1c1snc3RhdGUnXSA9PSAnQUNUSVZFJzoKICAgICAgICAgICAgICAgIHN0YXR1c1snbGFzdF9wcm9ncmVzc19hdCddID0gc2VsZi5jbG9jaygpCiAgICAgICAgICAgICAgICBzdGF0dXNbJ2xhc3RfcHJvZ3Jlc3Nfc3RhZ2UnXSA9IHN0YWdlCgogICAgZGVmIG5vdGVfYnVzeV9kcm9wKHNlbGYsIGtleSk6CiAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgaWYga2V5IGluIHNlbGYuX3Byb3ZpZGVyczoKICAgICAgICAgICAgICAgIHNlbGYuX3Byb3ZpZGVyc1trZXldWydidXN5X2Ryb3AnXSArPSAxCiAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ2xhdGVzdF9idXN5X2Ryb3AnXSArPSAxCgogICAgZGVmIHN1Ym1pdChzZWxmLCBwcm92aWRlciwgZnJhbWUsIGNvcGllZCwgcmVzcG9uc2VfYXQ9Tm9uZSwgKiwgdGltaW5nPU5vbmUpOgogICAgICAgIHJlc3BvbnNlX2F0ID0gc2VsZi5jbG9jaygpIGlmIHJlc3BvbnNlX2F0IGlzIE5vbmUgZWxzZSBmbG9hdChyZXNwb25zZV9hdCkKICAgICAgICBsb2NrX3N0YXJ0ZWQgPSBzZWxmLmNsb2NrKCkKICAgICAgICBhY2NlcHRlZCA9IEZhbHNlCiAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgc3RhdHVzID0gc2VsZi5fcHJvdmlkZXJzLmdldChwcm92aWRlcikKICAgICAgICAgICAgaWYgc3RhdHVzIGlzIE5vbmU6CiAgICAgICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCdVbmtub3duIHByb3ZpZGVyLicpCiAgICAgICAgICAgICMgRXZlbiBhIGxhdGUgb3IgZW1wdHkgcmVzdWx0IHByb3ZlcyBwcm92aWRlciBsaXZlbmVzcy4KICAgICAgICAgICAgc3RhdHVzWydsYXN0X3Jlc3BvbnNlX2F0J10gPSByZXNwb25zZV9hdAogICAgICAgICAgICBzdGF0dXMuc2V0ZGVmYXVsdCgnZmlyc3RfcmVzcG9uc2VfYXQnLCByZXNwb25zZV9hdCkKICAgICAgICAgICAgc3RhdHVzWydyZXNwb25zZXMnXSArPSAxCiAgICAgICAgICAgIHN0YXRlID0gc2VsZi5fZnJhbWVzLmdldChmcmFtZS5mcmFtZV9zZXEpCiAgICAgICAgICAgIGFjY2VwdGFuY2VfYXQgPSBzZWxmLmNsb2NrKCkKICAgICAgICAgICAgaWYgc3RhdGUgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICBzZWxmLl90aW1pbmdfbG9ja2VkKHByb3ZpZGVyLCAnc2VsZWN0ZWRfdG9fcmVzcG9uc2UnLCByZXNwb25zZV9hdC1zdGF0ZS5hZG1pdHRlZF9hdCkKICAgICAgICAgICAgICAgIGlmIGFjY2VwdGFuY2VfYXQgPiBzdGF0ZS5kZWFkbGluZToKICAgICAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydvdmVyX2ZyZXNobmVzc18nICsgcHJvdmlkZXJdICs9IDEKICAgICAgICAgICAgc2VsZi5fdGltaW5nX2xvY2tlZChwcm92aWRlciwgJ3N1Ym1pdF9sb2NrX3dhaXQnLCBhY2NlcHRhbmNlX2F0LWxvY2tfc3RhcnRlZCkKICAgICAgICAgICAgaWYgdGltaW5nIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgc2VsZWN0ZWQsIGdhdGUsIGluZmVyLCBjYWxsYmFjaywgY29weV9kb25lID0gdGltaW5nCiAgICAgICAgICAgICAgICBmb3Igc3RhZ2UsIHN0YXJ0LCBlbmQgaW4gKAogICAgICAgICAgICAgICAgICAgICAgICAoJ2dhdGVfdG9faW5mZXInLCBnYXRlLCBpbmZlciksCiAgICAgICAgICAgICAgICAgICAgICAgICgnaW5mZXJfdG9fY2FsbGJhY2snLCBpbmZlciwgY2FsbGJhY2spLAogICAgICAgICAgICAgICAgICAgICAgICAoJ2NhbGxiYWNrX2NvcHknLCBjYWxsYmFjaywgY29weV9kb25lKSwKICAgICAgICAgICAgICAgICAgICAgICAgKCdzZWxlY3RlZF90b19jYWxsYmFjaycsIHNlbGVjdGVkLCBjYWxsYmFjayksCiAgICAgICAgICAgICAgICAgICAgICAgICgnc2VsZWN0ZWRfdG9fYWNjZXB0X2NoZWNrJywgc2VsZWN0ZWQsIGFjY2VwdGFuY2VfYXQpKToKICAgICAgICAgICAgICAgICAgICBpZiBzdGFydCBpcyBub3QgTm9uZSBhbmQgZW5kIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLl90aW1pbmdfbG9ja2VkKHByb3ZpZGVyLCBzdGFnZSwgZW5kLXN0YXJ0KQogICAgICAgICAgICBpZiAoc3RhdHVzWydzdGF0ZSddICE9ICdBQ1RJVkUnIG9yIHN0YXRlIGlzIE5vbmUgb3Igc3RhdGUuc3RhdGUgIT0gJ09QRU4nCiAgICAgICAgICAgICAgICAgICAgb3IgKHNlbGYuZnJlc2huZXNzX2VuYWJsZWQgYW5kIGFjY2VwdGFuY2VfYXQgPiBzdGF0ZS5kZWFkbGluZSkKICAgICAgICAgICAgICAgICAgICBvciBmcmFtZS5mcmFtZV9zZXEgPD0gc2VsZi5fbGFzdF9wdWJsaXNoZWQpOgogICAgICAgICAgICAgICAgc3RhdHVzWydsYXRlJ10gKz0gMQogICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljc1snbGF0ZV9yZXN1bHQnXSArPSAxCiAgICAgICAgICAgICAgICByZWFzb24gPSAoJ3Byb3ZpZGVyX2Rpc2FibGVkJyBpZiBzdGF0dXNbJ3N0YXRlJ10gIT0gJ0FDVElWRScgZWxzZQogICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX3JldGlyZWQuZ2V0KGZyYW1lLmZyYW1lX3NlcSwgJ21pc3Npbmdfc2xvdCcpIGlmIHN0YXRlIGlzIE5vbmUgZWxzZQogICAgICAgICAgICAgICAgICAgICAgICAgICdjbG9zZWRfZnJhbWUnIGlmIHN0YXRlLnN0YXRlICE9ICdPUEVOJyBlbHNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgJ2RlYWRsaW5lJyBpZiBhY2NlcHRhbmNlX2F0ID4gc3RhdGUuZGVhZGxpbmUgZWxzZSAnYmFja3dhcmQnKQogICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljc1sncmVqZWN0ZWRfJyArIHByb3ZpZGVyICsgJ18nICsgcmVhc29uXSArPSAxCiAgICAgICAgICAgICAgICByZXR1cm4gRmFsc2UKICAgICAgICAgICAgaWYgcHJvdmlkZXIgbm90IGluIHN0YXRlLnJlcXVpcmVkIG9yIHByb3ZpZGVyIGluIHN0YXRlLnJlc3VsdHM6CiAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydkdXBsaWNhdGVfb3JfdW5yZXF1aXJlZF9yZXN1bHQnXSArPSAxCiAgICAgICAgICAgICAgICByZXR1cm4gRmFsc2UKICAgICAgICAgICAgaWYgKChmcmFtZS5mcmFtZV93aWR0aCwgZnJhbWUuZnJhbWVfaGVpZ2h0KSAhPSAoY29waWVkLndpZHRoLCBjb3BpZWQuaGVpZ2h0KQogICAgICAgICAgICAgICAgICAgIG9yIGxlbihjb3BpZWQuZGV0ZWN0aW9ucykgPiAzMDApOgogICAgICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignUHJvdmlkZXIgcmVzdWx0IGFzc29jaWF0aW9uIGRpZmZlcnMuJykKICAgICAgICAgICAgc3RhdGUucmVzdWx0c1twcm92aWRlcl0gPSBjb3BpZWQKICAgICAgICAgICAgYWNjZXB0ZWQgPSBUcnVlCiAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ2FjY2VwdGVkX3Jlc3VsdCddICs9IDEKICAgICAgICAgICAgZnJvbSBhcHAucGlwZWxpbmVfZGlhZ25vc3RpY3MgaW1wb3J0IGRpYWdub3N0aWNzCiAgICAgICAgICAgIGlmIGRpYWdub3N0aWNzLmVuYWJsZWQ6CiAgICAgICAgICAgICAgICBkaWFnbm9zdGljcy5mb3JfcHJvdmlkZXIocHJvdmlkZXIpLm1hcmsoJ2FjY2VwdGVkJykKICAgICAgICAgICAgc2VsZi5fY3Yubm90aWZ5X2FsbCgpCiAgICAgICAgaWYgc2VsZi5vbl9wcm92aWRlcl9mcmFtZSBpcyBub3QgTm9uZToKICAgICAgICAgICAgc2VsZi5vbl9wcm92aWRlcl9mcmFtZShwcm92aWRlciwgdGltZS50aW1lKCkpCiAgICAgICAgcmV0dXJuIGFjY2VwdGVkCgogICAgZGVmIG1hcmtfcHJvdmlkZXJfdW5hdmFpbGFibGUoc2VsZiwga2V5LCByZWFzb249J3Byb3ZpZGVyX3VuYXZhaWxhYmxlJyk6CiAgICAgICAgZmF0YWwgPSBGYWxzZQogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHN0YXR1cyA9IHNlbGYuX3Byb3ZpZGVycy5nZXQoa2V5KQogICAgICAgICAgICBpZiBzdGF0dXMgaXMgTm9uZSBvciBzdGF0dXNbJ3N0YXRlJ10gIT0gJ0FDVElWRSc6CiAgICAgICAgICAgICAgICByZXR1cm4gRmFsc2UKICAgICAgICAgICAgc3RhdHVzWydzdGF0ZSddID0gJ1VOQVZBSUxBQkxFJwogICAgICAgICAgICBzdGF0dXNbJ3JlYXNvbiddID0gc3RyKHJlYXNvbikKICAgICAgICAgICAgc2VsZi5fbWV0cmljc1sncHJvdmlkZXJfdW5hdmFpbGFibGUnXSArPSAxCiAgICAgICAgICAgIGZvciBzdGF0ZSBpbiBzZWxmLl9mcmFtZXMudmFsdWVzKCk6CiAgICAgICAgICAgICAgICBzdGF0ZS5yZXF1aXJlZC5kaXNjYXJkKGtleSkKICAgICAgICAgICAgICAgIHN0YXRlLnJlc3VsdHMucG9wKGtleSwgTm9uZSkKICAgICAgICAgICAgc2VsZi5fZ2FwX3BlbmRpbmdba2V5XSA9IFRydWUKICAgICAgICAgICAgZmF0YWwgPSBzZWxmLl9jaGVja19hbGxfdW5hdmFpbGFibGVfbG9ja2VkKCkKICAgICAgICAgICAgc2VsZi5fY3Yubm90aWZ5X2FsbCgpCiAgICAgICAgICAgIHJlbGVhc2UgPSBzZWxmLl9icmFuY2hfcmVsZWFzZS5nZXQoa2V5KQogICAgICAgIGlmIHJlbGVhc2UgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIHJlbGVhc2UoKQogICAgICAgIGlmIGZhdGFsOgogICAgICAgICAgICBzZWxmLl9ub3RpZnlfZmF0YWwoJ3Byb3ZpZGVyX3VuYXZhaWxhYmxlJykKICAgICAgICByZXR1cm4gVHJ1ZQoKICAgIGRlZiBfY2hlY2tfYWxsX3VuYXZhaWxhYmxlX2xvY2tlZChzZWxmKToKICAgICAgICBpZiBub3Qgc2VsZi5fcmVxdWVzdGVkOgogICAgICAgICAgICByZXR1cm4gbm90IGFueSh2WydzdGF0ZSddID09ICdBQ1RJVkUnIGZvciB2IGluIHNlbGYuX3Byb3ZpZGVycy52YWx1ZXMoKSkKICAgICAgICBhY3RpdmUgPSB7cyBmb3IgcyBpbiBzZWxmLl9yZXF1ZXN0ZWQKICAgICAgICAgICAgICAgICAgaWYgc2VsZi5fcHJvdmlkZXJzW3NlbGYuX2RlcGVuZGVuY2llc1tzXV1bJ3N0YXRlJ10gPT0gJ0FDVElWRSd9CiAgICAgICAgcmV0dXJuIG5vdCBhY3RpdmUKCiAgICBkZWYgX3JlYWR5X2xvY2tlZChzZWxmLCBub3cpOgogICAgICAgIGZvciBzZXEsIHN0YXRlIGluIHNlbGYuX2ZyYW1lcy5pdGVtcygpOgogICAgICAgICAgICBpZiBzdGF0ZS5zdGF0ZSAhPSAnT1BFTic6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICBpZiBzdGF0ZS5yZXF1aXJlZCA8PSBzZXQoc3RhdGUucmVzdWx0cykgb3IgKHNlbGYuZnJlc2huZXNzX2VuYWJsZWQgYW5kIG5vdyA+PSBzdGF0ZS5kZWFkbGluZSk6CiAgICAgICAgICAgICAgICByZXR1cm4gc2VxCiAgICAgICAgICAgIGlmIG5vdCBzZWxmLmZyZXNobmVzc19lbmFibGVkIGFuZCBzdGF0ZS5jbGFpbWVkOgogICAgICAgICAgICAgICAgcmV0dXJuIE5vbmUKICAgICAgICByZXR1cm4gTm9uZQoKICAgIGRlZiBfbmV4dF93YWl0X2xvY2tlZChzZWxmLCBub3cpOgogICAgICAgIGlmIG5vdCBzZWxmLmZyZXNobmVzc19lbmFibGVkOgogICAgICAgICAgICByZXR1cm4gLjEKICAgICAgICBkZWFkbGluZXMgPSBbcy5kZWFkbGluZSBmb3IgcyBpbiBzZWxmLl9mcmFtZXMudmFsdWVzKCkgaWYgcy5zdGF0ZSA9PSAnT1BFTiddCiAgICAgICAgd2FpdCA9IG1heCgwLiwgbWluKGRlYWRsaW5lcyktbm93KSBpZiBkZWFkbGluZXMgZWxzZSAuMQogICAgICAgIHJldHVybiBtaW4od2FpdCwgLjEpCgogICAgZGVmIF9jaGVja19zdGFsbHNfbG9ja2VkKHNlbGYsIG5vdyk6CiAgICAgICAgdW5hdmFpbGFibGUgPSBbXQogICAgICAgIGlucHV0X3JlY2VudCA9IGFueSh2WydsYXN0X2lucHV0X2F0J10gaXMgbm90IE5vbmUgYW5kIG5vdy12WydsYXN0X2lucHV0X2F0J10gPD0gc2VsZi5zdGFsbF9zCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciB2IGluIHNlbGYuX3Byb3ZpZGVycy52YWx1ZXMoKSkKICAgICAgICBpZiBub3QgaW5wdXRfcmVjZW50OgogICAgICAgICAgICByZXR1cm4gdW5hdmFpbGFibGUKICAgICAgICBmb3Iga2V5LCBzdGF0dXMgaW4gc2VsZi5fcHJvdmlkZXJzLml0ZW1zKCk6CiAgICAgICAgICAgIGlmIHN0YXR1c1snc3RhdGUnXSAhPSAnQUNUSVZFJyBvciBzdGF0dXNbJ2ZpcnN0X2lucHV0X2F0J10gaXMgTm9uZToKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIHJlc3BvbmRlZCA9IHN0YXR1c1snbGFzdF9yZXNwb25zZV9hdCddIGlzIG5vdCBOb25lCiAgICAgICAgICAgIHJlZmVyZW5jZSA9IHN0YXR1c1snbGFzdF9yZXNwb25zZV9hdCddIGlmIHJlc3BvbmRlZCBlbHNlIHN0YXR1c1snZmlyc3RfaW5wdXRfYXQnXQogICAgICAgICAgICBpZiByZXNwb25kZWQ6CiAgICAgICAgICAgICAgICByZWZlcmVuY2UgPSBtYXgocmVmZXJlbmNlLCBzdGF0dXMuZ2V0KCdsYXN0X3Byb2dyZXNzX2F0JywgcmVmZXJlbmNlKSkKICAgICAgICAgICAgaWYgbm93LXJlZmVyZW5jZSA+PSAoc2VsZi5zdGFsbF9zIGlmIHJlc3BvbmRlZCBlbHNlIHNlbGYuc3RhcnR1cF9zKToKICAgICAgICAgICAgICAgIHVuYXZhaWxhYmxlLmFwcGVuZChrZXkpCiAgICAgICAgcmV0dXJuIHVuYXZhaWxhYmxlCgogICAgZGVmIF9ydW4oc2VsZik6CiAgICAgICAgdHJ5OgogICAgICAgICAgICB3aGlsZSBUcnVlOgogICAgICAgICAgICAgICAgc3RhdGUgPSBOb25lCiAgICAgICAgICAgICAgICBzdGFsbHMgPSBbXQogICAgICAgICAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgICAgICAgICBpZiBzZWxmLl9jbG9zZWQgb3Igbm90IHNlbGYuaXNfY3VycmVudCgpOgogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4KICAgICAgICAgICAgICAgICAgICBub3cgPSBzZWxmLmNsb2NrKCkKICAgICAgICAgICAgICAgICAgICBzdGFsbHMgPSBzZWxmLl9jaGVja19zdGFsbHNfbG9ja2VkKG5vdykKICAgICAgICAgICAgICAgICAgICBmb3Iga2V5IGluIHN0YWxsczoKICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzID0gc2VsZi5fcHJvdmlkZXJzW2tleV0KICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzWydzdGF0ZSddID0gJ1VOQVZBSUxBQkxFJwogICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXNbJ3JlYXNvbiddID0gJ3Byb3ZpZGVyX3N0YWxsZWQnCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ3Byb3ZpZGVyX3N0YWxsZWQnXSArPSAxCiAgICAgICAgICAgICAgICAgICAgICAgIGZvciBvcGVuX3N0YXRlIGluIHNlbGYuX2ZyYW1lcy52YWx1ZXMoKToKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wZW5fc3RhdGUucmVxdWlyZWQuZGlzY2FyZChrZXkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcGVuX3N0YXRlLnJlc3VsdHMucG9wKGtleSwgTm9uZSkKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fZ2FwX3BlbmRpbmdba2V5XSA9IFRydWUKICAgICAgICAgICAgICAgICAgICBmYXRhbCA9IHNlbGYuX2NoZWNrX2FsbF91bmF2YWlsYWJsZV9sb2NrZWQoKQogICAgICAgICAgICAgICAgICAgIHNlcSA9IHNlbGYuX3JlYWR5X2xvY2tlZChub3cpCiAgICAgICAgICAgICAgICAgICAgaWYgc2VxIGlzIG5vdCBOb25lIGFuZCBub3QgZmF0YWw6CiAgICAgICAgICAgICAgICAgICAgICAgIGZvciBvbGRlciBpbiBbayBmb3IgayBpbiBzZWxmLl9mcmFtZXMgaWYgayA8IHNlcV06CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLl9ldmljdF9sb2NrZWQoc2VsZi5fZnJhbWVzLnBvcChvbGRlcikpCiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlID0gc2VsZi5fZnJhbWVzLnBvcChzZXEpCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIHNlcSA8PSBzZWxmLl9sYXN0X3B1Ymxpc2hlZDoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX2V2aWN0X2xvY2tlZChzdGF0ZSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ2JhY2t3YXJkX2Ryb3AnXSArPSAxCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZSA9IE5vbmUKICAgICAgICAgICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgQ2xhaW0gYmVmb3JlIGFueSB0ZW1wb3JhbCBtdXRhdGlvbjsgYWNjZXB0ZWQgcmVzdWx0cwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBhcmUgZnJvemVuIGV2ZW4gaWYgU3RvcC9kaXNhYmxlIGFycml2ZXMgZHVyaW5nIGhhbmRvZmYuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZS5zdGF0ZSA9ICdGSU5BTElaSU5HJwogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fcmV0aXJlX2xvY2tlZChzZXEsICdmaW5hbGl6aW5nJykKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBrZXkgaW4gc2VsZi5fZ2FwX3BlbmRpbmc6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYga2V5IGluIHN0YXRlLnJlc3VsdHM6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIHNlbGYuX2dhcF9wZW5kaW5nW2tleV06CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZS5nYXBzLmFkZChrZXkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX2dhcF9wZW5kaW5nW2tleV0gPSBGYWxzZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX2dhcF9wZW5kaW5nW2tleV0gPSBUcnVlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLl9maW5hbGl6aW5nID0gc3RhdGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ2ZpbmFsaXppbmdfY2xhaW1zJ10gKz0gMQogICAgICAgICAgICAgICAgICAgIGlmIHN0YXRlIGlzIE5vbmUgYW5kIG5vdCBmYXRhbDoKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fY3Yud2FpdChzZWxmLl9uZXh0X3dhaXRfbG9ja2VkKG5vdykpCiAgICAgICAgICAgICAgICBmb3Iga2V5IGluIHN0YWxsczoKICAgICAgICAgICAgICAgICAgICByZWxlYXNlID0gc2VsZi5fYnJhbmNoX3JlbGVhc2UuZ2V0KGtleSkKICAgICAgICAgICAgICAgICAgICBpZiByZWxlYXNlIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgICAgICAgICByZWxlYXNlKCkKICAgICAgICAgICAgICAgIGlmIGZhdGFsOgogICAgICAgICAgICAgICAgICAgIHNlbGYuX25vdGlmeV9mYXRhbCgncHJvdmlkZXJfc3RhbGxlZCcpCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgICAgICAgICBpZiBzdGF0ZSBpcyBub3QgTm9uZToKICAgICAgICAgICAgICAgICAgICBzZWxmLl9maW5hbGl6ZShzdGF0ZSkKICAgICAgICAgICAgICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZS5zdGF0ZSA9ICdGSU5BTElaRUQnCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX3JldGlyZV9sb2NrZWQoc2VxLCAnZmluYWxpemVkJykKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fZmluYWxpemluZyA9IE5vbmUKICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGVycm9yOgogICAgICAgICAgICB3aXRoIHNlbGYuX2N2OgogICAgICAgICAgICAgICAgc2VsZi5fZXJyb3IgPSAnTVVMVElfUFJPVklERVJfUkVTVUxUX0ZBSUxFRCcKICAgICAgICAgICAgICAgIHNlbGYuX2Nsb3NlZCA9IFRydWUKICAgICAgICAgICAgICAgIHNlbGYuX2ZyYW1lcy5jbGVhcigpCiAgICAgICAgICAgIHNlbGYuX25vdGlmeV9mYXRhbCgncmVzdWx0X2V4Y2VwdGlvbicsIGVycm9yKQoKICAgIGRlZiBfb2JzZXJ2YXRpb25zKHNlbGYsIHByb3ZpZGVyLCBmcmFtZSwgY29waWVkKToKICAgICAgICBvYnNlcnZhdGlvbnMgPSB0dXBsZSgKICAgICAgICAgICAgRGV0ZWN0aW9uT2JzZXJ2YXRpb24oZnJhbWUsIHByb3ZpZGVyLm1vZGVsLCBkLmNsYXNzX2lkLCBkLnNjb3JlLCBkLmJib3hfeHl4eSkKICAgICAgICAgICAgZm9yIGQgaW4gY29waWVkLmRldGVjdGlvbnMpCiAgICAgICAgcG9zZXMgPSB0dXBsZSgKICAgICAgICAgICAgUG9zZU9ic2VydmF0aW9uKGZyYW1lLCBwcm92aWRlci5tb2RlbCwgZC5zY29yZSwgZC5iYm94X3h5eHksIGQua2V5cG9pbnRzKQogICAgICAgICAgICBpZiBkLmtleXBvaW50cyBpcyBub3QgTm9uZSBlbHNlIE5vbmUgZm9yIGQgaW4gY29waWVkLmRldGVjdGlvbnMpCiAgICAgICAgZnJvbSBhcHAucG9zZV9jb25maWcgaW1wb3J0IFBPU0VfTU9ERUwKICAgICAgICBpZiBwcm92aWRlci5tb2RlbCA9PSBQT1NFX01PREVMIGFuZCBhbnkocCBpcyBOb25lIGZvciBwIGluIHBvc2VzKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignUG9zZSBwcm92aWRlciByZXR1cm5lZCBhIHBlcnNvbiB3aXRob3V0IGtleXBvaW50cy4nKQogICAgICAgIGlmIHByb3ZpZGVyLm1vZGVsICE9IFBPU0VfTU9ERUwgYW5kIGFueShwIGlzIG5vdCBOb25lIGZvciBwIGluIHBvc2VzKToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcignTm9uLVBvc2UgcHJvdmlkZXIgcmV0dXJuZWQgdW5leHBlY3RlZCBrZXlwb2ludHMuJykKICAgICAgICByZXR1cm4gb2JzZXJ2YXRpb25zLCBwb3NlcwoKICAgIGRlZiBfcGVyc29uX3Jlc3VsdChzZWxmLCBwcm92aWRlciwgZnJhbWUsIGNvcGllZCwgZ2FwX2JlZm9yZSk6CiAgICAgICAgZnJvbSBhcHAucG9zZV9jb25maWcgaW1wb3J0IFBPU0VfTU9ERUwKICAgICAgICBmcm9tIGFwcC5jbGFzc19jYXRhbG9nIGltcG9ydCBjb2NvX25hbWUKICAgICAgICBmcm9tIGFwcC5waXBlbGluZV9kaWFnbm9zdGljcyBpbXBvcnQgZGlhZ25vc3RpY3MKICAgICAgICBtZXRyaWMgPSBkaWFnbm9zdGljcy5mb3JfcHJvdmlkZXIocHJvdmlkZXIua2V5KQogICAgICAgIHdpdGggbWV0cmljLnBoYXNlKCdyZXN1bHRfb2JzZXJ2YXRpb25zJyk6CiAgICAgICAgICAgIG9ic2VydmF0aW9ucywgcG9zZXMgPSBzZWxmLl9vYnNlcnZhdGlvbnMocHJvdmlkZXIsIGZyYW1lLCBjb3BpZWQpCiAgICAgICAgc2VsZWN0ZWQgPSB0dXBsZShpIGZvciBpLCBvIGluIGVudW1lcmF0ZShvYnNlcnZhdGlvbnMpIGlmIG8uY2xhc3NfaWQgPT0gMCkKICAgICAgICBpZiBwcm92aWRlci5tb2RlbCA9PSBQT1NFX01PREVMIGFuZCBzZWxmLnBvc2VfY29uZmlnIGFuZCBzZWxmLnBvc2VfY29uZmlnLm5tc19lbmFibGVkOgogICAgICAgICAgICBmcm9tIGFwcC5wb3NlX25tcyBpbXBvcnQgcG9zZV9ubXNfaW5kaWNlcwogICAgICAgICAgICB3aXRoIG1ldHJpYy5waGFzZSgncmVzdWx0X25tcycpOgogICAgICAgICAgICAgICAgc2VsZWN0ZWQgPSB0dXBsZShpIGZvciBpIGluIHNlbGYucG9zZV9ubXMob2JzZXJ2YXRpb25zKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBvYnNlcnZhdGlvbnNbaV0uY2xhc3NfaWQgPT0gMCkKICAgICAgICBzZWxlY3RlZF9vYnMgPSB0dXBsZShvYnNlcnZhdGlvbnNbaV0gZm9yIGkgaW4gc2VsZWN0ZWQpCiAgICAgICAgd2l0aCBtZXRyaWMucGhhc2UoJ3Jlc3VsdF90cmFja2luZycpOgogICAgICAgICAgICBzZWxlY3RlZF9pZHMgPSAoc2VsZi50cmFja2VyLnVwZGF0ZShzZWxlY3RlZF9vYnMpIGlmIHNlbGYudHJhY2tlciBpcyBub3QgTm9uZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBbTm9uZV0gKiBsZW4oc2VsZWN0ZWRfb2JzKSkKICAgICAgICBpZHMgPSBbTm9uZV0gKiBsZW4ob2JzZXJ2YXRpb25zKQogICAgICAgIGZvciBpLCB0aWQgaW4gemlwKHNlbGVjdGVkLCBzZWxlY3RlZF9pZHMpOgogICAgICAgICAgICBpZHNbaV0gPSB0aWQKCiAgICAgICAgZGVjaXNpb25zID0gW05vbmVdICogbGVuKG9ic2VydmF0aW9ucykKICAgICAgICBldmVudHMgPSAoKQogICAgICAgIGlmIHNlbGYucmVnaW9uIGlzIG5vdCBOb25lOgogICAgICAgICAgICB3aXRoIG1ldHJpYy5waGFzZSgncmVzdWx0X3JlZ2lvbicpOgogICAgICAgICAgICAgICAgZ2FwX29wdGlvbnMgPSAoeydnYXBfYmVmb3JlJzogZ2FwX2JlZm9yZX0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIGdldGF0dHIoc2VsZi5pbmdyZXNzLCAnc291cmNlX2xhdGVzdCcsIEZhbHNlKSBlbHNlIHt9KQogICAgICAgICAgICAgICAgcm93cywgZW1pdHRlZCA9IHNlbGYucmVnaW9uLmV2YWx1YXRlKGZyYW1lLCBzZWxlY3RlZF9vYnMsIHNlbGVjdGVkX2lkcywgKipnYXBfb3B0aW9ucykKICAgICAgICAgICAgZm9yIGksIHJvdyBpbiB6aXAoc2VsZWN0ZWQsIHJvd3MpOgogICAgICAgICAgICAgICAgZGVjaXNpb25zW2ldID0gcm93CiAgICAgICAgICAgIGV2ZW50cyArPSB0dXBsZShyZXBsYWNlKGUsIG9iamVjdF9yZWY9c3RyKHNlbGVjdGVkW2ludChlLm9iamVjdF9yZWYpXSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgZSBpbiBlbWl0dGVkKQogICAgICAgIGlmIHByb3ZpZGVyLm1vZGVsID09IFBPU0VfTU9ERUw6CiAgICAgICAgICAgIHNlbGVjdGVkX3Bvc2VzID0gdHVwbGUocG9zZXNbaV0gZm9yIGkgaW4gc2VsZWN0ZWQpCiAgICAgICAgICAgIGZvciBzY2VuYXJpbyBpbiAoc2VsZi5mYWxsLCBzZWxmLmZpZ2h0KToKICAgICAgICAgICAgICAgIGlmIHNjZW5hcmlvIGlzIE5vbmU6CiAgICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgIHdpdGggbWV0cmljLnBoYXNlKCdyZXN1bHRfJysoJ2ZhbGwnIGlmIHNjZW5hcmlvIGlzIHNlbGYuZmFsbCBlbHNlICdmaWdodCcpKToKICAgICAgICAgICAgICAgICAgICByb3dzLCBlbWl0dGVkID0gc2NlbmFyaW8uZXZhbHVhdGUoCiAgICAgICAgICAgICAgICAgICAgICAgIGZyYW1lLCBzZWxlY3RlZF9wb3Nlcywgc2VsZWN0ZWRfaWRzLCBnYXBfYmVmb3JlPWdhcF9iZWZvcmUpCiAgICAgICAgICAgICAgICBmb3IgaSwgcm93IGluIHppcChzZWxlY3RlZCwgcm93cyk6CiAgICAgICAgICAgICAgICAgICAgZGVjaXNpb25zW2ldID0gKCptZW1iZXJzKGRlY2lzaW9uc1tpXSksICptZW1iZXJzKHJvdykpCiAgICAgICAgICAgICAgICBldmVudHMgKz0gdHVwbGUocmVwbGFjZShlLCBvYmplY3RfcmVmPXN0cihzZWxlY3RlZFtpbnQoZS5vYmplY3RfcmVmKV0pKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBlIGluIGVtaXR0ZWQpCgogICAgICAgIHNlbGVjdGVkX3NldCA9IHNldChzZWxlY3RlZCkKICAgICAgICBjb21tYW5kcyA9IFtdCiAgICAgICAgZm9yIGksIChvYnNlcnZhdGlvbiwgcG9zZSkgaW4gZW51bWVyYXRlKHppcChvYnNlcnZhdGlvbnMsIHBvc2VzKSk6CiAgICAgICAgICAgIGRlY2lzaW9uID0gZGVjaXNpb25zW2ldCiAgICAgICAgICAgIGxhYmVsID0gY29jb19uYW1lKG9ic2VydmF0aW9uLmNsYXNzX2lkKQogICAgICAgICAgICBjYXRlZ29yeV92aXNpYmxlID0gKAogICAgICAgICAgICAgICAgc2VsZi5kaXNwbGF5X2NhdGVnb3JpZXMgaXMgTm9uZSBvciBsYWJlbCBpbiBzZWxmLmRpc3BsYXlfY2F0ZWdvcmllcykKICAgICAgICAgICAgaWYgb2JzZXJ2YXRpb24uY2xhc3NfaWQgPT0gMDoKICAgICAgICAgICAgICAgIHZpc2libGUgPSAoCiAgICAgICAgICAgICAgICAgICAgaSBpbiBzZWxlY3RlZF9zZXQKICAgICAgICAgICAgICAgICAgICBhbmQgKHNjZW5hcmlvX3Zpc2libGUob2JzZXJ2YXRpb24uc2NvcmUsIGRlY2lzaW9uKSBpZiBkZWNpc2lvbiBlbHNlCiAgICAgICAgICAgICAgICAgICAgICAgICAob2JzZXJ2YXRpb24uc2NvcmUgPj0gc2VsZi5wb3NlX2NvbmZpZy5wZXJzb25fc2NvcmUKICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBwcm92aWRlci5tb2RlbCA9PSBQT1NFX01PREVMIGFuZCBzZWxmLnBvc2VfY29uZmlnCiAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBvYnNlcnZhdGlvbi5zY29yZSA+IHNlbGYuZGlzcGxheV90aHJlc2hvbGQpKQogICAgICAgICAgICAgICAgICAgIGFuZCBjYXRlZ29yeV92aXNpYmxlKQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgIyBNZWRpdW0gbWF5IG93biBwZXJzb24gVHJhY2tpbmcgYW5kIHN0aWxsIHByb3ZpZGUgZnV0dXJlIG5vbi1wZXJzb24KICAgICAgICAgICAgICAgICMgQ09DTyBjbGFzc2VzLiBUaG9zZSBvYmplY3RzIHN0YXkgZGlzcGxheS1vbmx5IGhlcmUuCiAgICAgICAgICAgICAgICB2aXNpYmxlID0gb2JzZXJ2YXRpb24uc2NvcmUgPiBzZWxmLmRpc3BsYXlfdGhyZXNob2xkIGFuZCBjYXRlZ29yeV92aXNpYmxlCiAgICAgICAgICAgIGNvbW1hbmRzLmFwcGVuZChWaXN1YWxpemF0aW9uQ29tbWFuZCgKICAgICAgICAgICAgICAgIG9ic2VydmF0aW9uLCBsYWJlbCwKICAgICAgICAgICAgICAgIGNvbG9yPScjRkYzMDMwJyBpZiBhbGVydGVkKGRlY2lzaW9uKSBlbHNlICcjMDBDQzY2JywKICAgICAgICAgICAgICAgIHZpc2libGU9dmlzaWJsZSwgdHJhY2tfaWQ9aWRzW2ldLCBldmVudF9pZHM9ZXZlbnRfaWRzKGRlY2lzaW9uKSwKICAgICAgICAgICAgICAgIHNjZW5hcmlvPWRlY2lzaW9uLCBwb3NlPXBvc2UpKQoKICAgICAgICBjb25maWdzID0gbWVtYmVycyhzZWxmLnJlZ2lvbi5jb25maWcgaWYgc2VsZi5yZWdpb24gZWxzZSBOb25lKQogICAgICAgIGlmIHNlbGYuZmFsbCBpcyBub3QgTm9uZToKICAgICAgICAgICAgY29uZmlncyArPSAoc2VsZi5mYWxsLmNvbmZpZywpCiAgICAgICAgaWYgc2VsZi5maWdodCBpcyBub3QgTm9uZToKICAgICAgICAgICAgY29uZmlncyArPSAoc2VsZi5maWdodC5jb25maWcsKQogICAgICAgIHJlc3VsdCA9IEZyYW1lUmVzdWx0KAogICAgICAgICAgICBmcmFtZSwgdHVwbGUoY29tbWFuZHMpLCBldmVudHMsCiAgICAgICAgICAgIGNvbmZpZ3MgaWYgbGVuKGNvbmZpZ3MpID4gMSBlbHNlIGNvbmZpZ3NbMF0gaWYgY29uZmlncyBlbHNlIE5vbmUsCiAgICAgICAgICAgIHNlbGYuc2NlbmFyaW9fcmV2aXNpb24sIHNlbGYuZGVidWdfYWxsX2NhbmRpZGF0ZXMsCiAgICAgICAgICAgIHNlbGYucG9zZV9jb25maWcgaWYgcHJvdmlkZXIubW9kZWwgPT0gUE9TRV9NT0RFTCBlbHNlIE5vbmUsCiAgICAgICAgICAgIHR1cGxlKGkgaW4gc2VsZWN0ZWRfc2V0IGZvciBpIGluIHJhbmdlKGxlbihvYnNlcnZhdGlvbnMpKSkKICAgICAgICAgICAgICAgIGlmIHByb3ZpZGVyLm1vZGVsID09IFBPU0VfTU9ERUwgZWxzZSBOb25lLAogICAgICAgICAgICBwcm92aWRlcl9tb2RlbD1wcm92aWRlci5tb2RlbCwgY2FtZXJhX2lkPXNlbGYuY2FtZXJhX2lkKQogICAgICAgIHJldHVybiByZXN1bHQsIGlkcwoKICAgIGRlZiBwb3NlX25tcyhzZWxmLCBvYnNlcnZhdGlvbnMpOgogICAgICAgIGZyb20gYXBwLnBvc2Vfbm1zIGltcG9ydCBwb3NlX25tc19pbmRpY2VzCiAgICAgICAgcmV0dXJuIHBvc2Vfbm1zX2luZGljZXMob2JzZXJ2YXRpb25zLCBzZWxmLnBvc2VfY29uZmlnLm5tc19pb3VfdGhyZXNob2xkKQoKICAgIGRlZiBfcGxhaW5fbWVkaXVtX3Jlc3VsdChzZWxmLCBwcm92aWRlciwgZnJhbWUsIGNvcGllZCk6CiAgICAgICAgZnJvbSBhcHAuY2xhc3NfY2F0YWxvZyBpbXBvcnQgY29jb19uYW1lCiAgICAgICAgb2JzZXJ2YXRpb25zLCBfID0gc2VsZi5fb2JzZXJ2YXRpb25zKHByb3ZpZGVyLCBmcmFtZSwgY29waWVkKQogICAgICAgIGNvbW1hbmRzID0gW10KICAgICAgICBmb3Igb2JzZXJ2YXRpb24gaW4gb2JzZXJ2YXRpb25zOgogICAgICAgICAgICBpZiBzZWxmLnBsYW4ucGVyc29uX293bmVyID09ICdwb3NlJyBhbmQgb2JzZXJ2YXRpb24uY2xhc3NfaWQgPT0gMDoKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIGxhYmVsID0gY29jb19uYW1lKG9ic2VydmF0aW9uLmNsYXNzX2lkKQogICAgICAgICAgICBjb21tYW5kcy5hcHBlbmQoVmlzdWFsaXphdGlvbkNvbW1hbmQoCiAgICAgICAgICAgICAgICBvYnNlcnZhdGlvbiwgbGFiZWwsIGNvbG9yPScjMDBDQzY2JywKICAgICAgICAgICAgICAgIHZpc2libGU9KG9ic2VydmF0aW9uLnNjb3JlID4gc2VsZi5kaXNwbGF5X3RocmVzaG9sZAogICAgICAgICAgICAgICAgICAgICAgICAgYW5kIChzZWxmLmRpc3BsYXlfY2F0ZWdvcmllcyBpcyBOb25lIG9yIGxhYmVsIGluIHNlbGYuZGlzcGxheV9jYXRlZ29yaWVzKSkpKQogICAgICAgIHJldHVybiBGcmFtZVJlc3VsdChmcmFtZSwgdHVwbGUoY29tbWFuZHMpLCBwcm92aWRlcl9tb2RlbD1wcm92aWRlci5tb2RlbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FtZXJhX2lkPXNlbGYuY2FtZXJhX2lkKQoKICAgIGRlZiBfZmluYWxpemUoc2VsZiwgc3RhdGUpOgogICAgICAgIGZyb20gYXBwLnBpcGVsaW5lX2RpYWdub3N0aWNzIGltcG9ydCBkaWFnbm9zdGljcwogICAgICAgIG1ldHJpYyA9IGRpYWdub3N0aWNzLmZvcl9wcm92aWRlcihzZWxmLnBsYW4ucHJvdmlkZXJzWzBdLmtleSkKICAgICAgICB3aXRoIG1ldHJpYy5waGFzZSgncmVzdWx0X3RvdGFsJyk6CiAgICAgICAgICAgIHNlbGYuX2ZpbmFsaXplX3Jlc3VsdChzdGF0ZSwgbWV0cmljKQoKICAgIGRlZiBfZmluYWxpemVfcmVzdWx0KHNlbGYsIHN0YXRlLCBtZXRyaWMpOgogICAgICAgIGZyYW1lID0gc3RhdGUuZnJhbWUKICAgICAgICBwbGFuX2J5X2tleSA9IHtwLmtleTogcCBmb3IgcCBpbiBzZWxmLnBsYW4ucHJvdmlkZXJzfQogICAgICAgIHBhcnRzID0gW10KICAgICAgICBwZXJzb25faWRzID0gTm9uZQogICAgICAgIHBlcnNvbl9rZXkgPSBzZWxmLnBsYW4ucGVyc29uX293bmVyCiAgICAgICAgaWYgcGVyc29uX2tleSBhbmQgcGVyc29uX2tleSBpbiBzdGF0ZS5yZXN1bHRzOgogICAgICAgICAgICBnYXBfYmVmb3JlID0gcGVyc29uX2tleSBpbiBzdGF0ZS5nYXBzCiAgICAgICAgICAgIGlmIGhhc2F0dHIoc2VsZi5pbmdyZXNzLCAncmVzdWx0X2dhcCcpOgogICAgICAgICAgICAgICAgZ2FwX2JlZm9yZSA9IHNlbGYuaW5ncmVzcy5yZXN1bHRfZ2FwKGZyYW1lKSBvciBnYXBfYmVmb3JlCiAgICAgICAgICAgIHJlc3VsdCwgcGVyc29uX2lkcyA9IHNlbGYuX3BlcnNvbl9yZXN1bHQoCiAgICAgICAgICAgICAgICBwbGFuX2J5X2tleVtwZXJzb25fa2V5XSwgZnJhbWUsIHN0YXRlLnJlc3VsdHNbcGVyc29uX2tleV0sIGdhcF9iZWZvcmUpCiAgICAgICAgICAgIHBhcnRzLmFwcGVuZChyZXN1bHQpCiAgICAgICAgICAgIHdpdGggbWV0cmljLnBoYXNlKCdyZXN1bHRfY29sbGVjdG9yJyk6CiAgICAgICAgICAgICAgICBzZWxmLl9jb2xsZWN0X3BlcnNvbihmcmFtZSwgcGxhbl9ieV9rZXlbcGVyc29uX2tleV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZS5yZXN1bHRzW3BlcnNvbl9rZXldLCBwZXJzb25faWRzKQogICAgICAgIGlmICdtZWRpdW0nIGluIHN0YXRlLnJlc3VsdHMgYW5kIHBlcnNvbl9rZXkgIT0gJ21lZGl1bSc6CiAgICAgICAgICAgIHBhcnRzLmFwcGVuZChzZWxmLl9wbGFpbl9tZWRpdW1fcmVzdWx0KAogICAgICAgICAgICAgICAgcGxhbl9ieV9rZXlbJ21lZGl1bSddLCBmcmFtZSwgc3RhdGUucmVzdWx0c1snbWVkaXVtJ10pKQoKICAgICAgICBpZiAnZmlyZScgaW4gc3RhdGUucmVzdWx0cyBhbmQgc2VsZi5maXJlIGlzIG5vdCBOb25lOgogICAgICAgICAgICBmcm9tIGFwcC5maXJlX3Jlc3VsdCBpbXBvcnQgZXZhbHVhdGVfcmVzdWx0CiAgICAgICAgICAgIG9ic2VydmF0aW9ucywgXyA9IHNlbGYuX29ic2VydmF0aW9ucygKICAgICAgICAgICAgICAgIHBsYW5fYnlfa2V5WydmaXJlJ10sIGZyYW1lLCBzdGF0ZS5yZXN1bHRzWydmaXJlJ10pCiAgICAgICAgICAgIHJlc3VsdCA9IGV2YWx1YXRlX3Jlc3VsdCgKICAgICAgICAgICAgICAgIHNlbGYuZmlyZSwgZnJhbWUsIG9ic2VydmF0aW9ucywgY2FtZXJhX2lkPXNlbGYuY2FtZXJhX2lkLAogICAgICAgICAgICAgICAgc2NlbmFyaW9fcmV2aXNpb249c2VsZi5zY2VuYXJpb19yZXZpc2lvbiwgZ2FwX2JlZm9yZT0nZmlyZScgaW4gc3RhdGUuZ2FwcykKICAgICAgICAgICAgaWYgcmVzdWx0IGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgcGFydHMuYXBwZW5kKHJlc3VsdCkKCiAgICAgICAgaWYgJ2Nyb3dkJyBpbiBzdGF0ZS5yZXN1bHRzIGFuZCBzZWxmLmNyb3dkIGlzIG5vdCBOb25lOgogICAgICAgICAgICBvYnNlcnZhdGlvbnMsIF8gPSBzZWxmLl9vYnNlcnZhdGlvbnMoCiAgICAgICAgICAgICAgICBwbGFuX2J5X2tleVsnY3Jvd2QnXSwgZnJhbWUsIHN0YXRlLnJlc3VsdHNbJ2Nyb3dkJ10pCiAgICAgICAgICAgIGdhcCA9ICdjcm93ZCcgaW4gc3RhdGUuZ2FwcwogICAgICAgICAgICBpZiBoYXNhdHRyKHNlbGYuaW5ncmVzcywgJ3Jlc3VsdF9nYXAnKToKICAgICAgICAgICAgICAgIGdhcCA9IHNlbGYuaW5ncmVzcy5yZXN1bHRfZ2FwKGZyYW1lKSBvciBnYXAKICAgICAgICAgICAgcmVzdWx0ID0gc2VsZi5jcm93ZC5wcm9jZXNzKGZyYW1lLCBvYnNlcnZhdGlvbnMsIGdhcF9iZWZvcmU9Z2FwKQogICAgICAgICAgICBpZiByZXN1bHQgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICBwYXJ0cy5hcHBlbmQocmVzdWx0KQoKICAgICAgICB3aXRoIG1ldHJpYy5waGFzZSgncmVzdWx0X2NvbXBvc2l0aW9uJyk6CiAgICAgICAgICAgIHJlc3VsdCA9IHNlbGYuX2NvbXBvc2VfcmVzdWx0KGZyYW1lLCBwYXJ0cywgcGVyc29uX2tleSwgc3RhdGUpCgogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIGlmIHN0YXRlLnN0YXRlICE9ICdGSU5BTElaSU5HJyBvciBmcmFtZS5mcmFtZV9zZXEgPD0gc2VsZi5fbGFzdF9wdWJsaXNoZWQ6CiAgICAgICAgICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoJ0ludmFsaWQgZmluYWxpemF0aW9uIG93bmVyc2hpcC4nKQogICAgICAgICAgICBzZWxmLl9sYXN0X3B1Ymxpc2hlZCA9IGZyYW1lLmZyYW1lX3NlcQogICAgICAgICAgICBzZWxmLl9sYXRlc3QgPSByZXN1bHQKICAgICAgICAgICAgc2VsZi5fbWV0cmljc1snZmluYWxpemVkJ10gKz0gMQogICAgICAgICAgICBzZWxmLl9tZXRyaWNzWydldmVudHNfY3JlYXRlZCddICs9IGxlbihyZXN1bHQuZXZlbnRzKQoKICAgICAgICBpZiBzZWxmLl9zYW1wbGVzIGlzIG5vdCBOb25lIGFuZCBzZWxmLl9zYW1wbGVzLmVuYWJsZWQoKToKICAgICAgICAgICAgc2VsZi5fc2FtcGxlcy5jYXB0dXJlKHJlc3VsdC5zbmFwc2hvdCh2aXNpYmxlX29ubHk9RmFsc2UpKQogICAgICAgIGlmIHNlbGYudmlzdWFsIGlzIG5vdCBOb25lOgogICAgICAgICAgICBzZWxmLnZpc3VhbC5zdWJtaXRfcmVzdWx0KHJlc3VsdCkKICAgICAgICBpZiBzZWxmLmFydGlmYWN0cyBpcyBub3QgTm9uZToKICAgICAgICAgICAgd2l0aCBtZXRyaWMucGhhc2UoJ3Jlc3VsdF9hcnRpZmFjdF9oYW5kb2ZmJyk6CiAgICAgICAgICAgICAgICBhY2NlcHRlZCA9IHNlbGYuYXJ0aWZhY3RzLnN1Ym1pdChyZXN1bHQpCiAgICAgICAgICAgIGlmIGFjY2VwdGVkIGlzIEZhbHNlIGFuZCByZXN1bHQuZXZlbnRzOgogICAgICAgICAgICAgICAgcmFpc2UgUnVudGltZUVycm9yKCdTY2VuYXJpbyBFdmVudCBoYW5kb2ZmIHJlamVjdGVkLicpCiAgICAgICAgaWYgc2VsZi5wdWJsaXNoZXIgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIHdpdGggbWV0cmljLnBoYXNlKCdyZXN1bHRfcHVibGlzaCcpOgogICAgICAgICAgICAgICAgc2VsZi5wdWJsaXNoZXIuY2hhbm5lbChmcmFtZS5zb3VyY2VfaWQsIGZyYW1lLnJ1bl9pZCwgZnJhbWUucnVuX2dlbmVyYXRpb24sICdSVU5OSU5HJykKICAgICAgICAgICAgICAgIG5vdGUgPSBnZXRhdHRyKHNlbGYucHVibGlzaGVyLCAnbm90ZV9mcmFtZV90aW1pbmcnLCBOb25lKQogICAgICAgICAgICAgICAgaWYgbm90ZSBpcyBub3QgTm9uZSBhbmQgc3RhdGUuc2VsZWN0ZWRfYXQgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICAgICAgbm90ZShmcmFtZSwgcm91bmQoc3RhdGUuc2VsZWN0ZWRfYXQqMWU5KSwgcm91bmQoc3RhdGUuYWRtaXR0ZWRfYXQqMWU5KSkKICAgICAgICAgICAgICAgIGlmIG5vdCBzZWxmLnB1Ymxpc2hlci5zdWJtaXQocmVzdWx0LnNuYXBzaG90KCkpOgogICAgICAgICAgICAgICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ3B1Ymxpc2hlcl9yZWplY3RlZCddICs9IDEKCiAgICBkZWYgX2NvbXBvc2VfcmVzdWx0KHNlbGYsIGZyYW1lLCBwYXJ0cywgcGVyc29uX2tleSwgc3RhdGUpOgogICAgICAgIGlmIGxlbihzZWxmLnBsYW4ucHJvdmlkZXJzKSA9PSAxIGFuZCBsZW4ocGFydHMpID09IDE6CiAgICAgICAgICAgIHJlc3VsdCA9IHBhcnRzWzBdCiAgICAgICAgICAgIGlmIHJlc3VsdC5mcmFtZSAhPSBmcmFtZToKICAgICAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoJ0ZvcmVpZ24gcHJvdmlkZXIgcmVzdWx0IGZyYW1lLicpCiAgICAgICAgICAgIHB1YmxpY19wb3NpdGlvbnMocmVzdWx0LmNvbW1hbmRzLCByZXN1bHQuZXZlbnRzKQogICAgICAgICAgICBmaWVsZHMgPSBkaWN0KHNjZW5hcmlvX3JldmlzaW9uPXNlbGYuc2NlbmFyaW9fcmV2aXNpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGVidWdfYWxsX2NhbmRpZGF0ZXM9c2VsZi5kZWJ1Z19hbGxfY2FuZGlkYXRlcywKICAgICAgICAgICAgICAgICAgICAgICAgICBwb3NlX2NvbmZpZz1zZWxmLnBvc2VfY29uZmlnIGlmIHBlcnNvbl9rZXkgPT0gJ3Bvc2UnIGVsc2UgTm9uZSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjYW1lcmFfaWQ9c2VsZi5jYW1lcmFfaWQpCiAgICAgICAgICAgIGNoYW5nZXMgPSB7a2V5OiB2YWx1ZSBmb3Iga2V5LCB2YWx1ZSBpbiBmaWVsZHMuaXRlbXMoKSBpZiBnZXRhdHRyKHJlc3VsdCwga2V5KSAhPSB2YWx1ZX0KICAgICAgICAgICAgcmV0dXJuIHJlcGxhY2UocmVzdWx0LCAqKmNoYW5nZXMpIGlmIGNoYW5nZXMgZWxzZSByZXN1bHQKCiAgICAgICAgIyBPbmx5IHRoZSBzaGFyZWQtcHJvdmlkZXIgcGF0aCBuZWVkcyBjb21wb3NpdGlvbiBhbmQgcmVmZXJlbmNlIHJlbWFwcGluZy4KICAgICAgICByYXdfY29tbWFuZHMsIHJhd19ldmVudHMsIGNvbmZpZ3MgPSBbXSwgW10sIFtdCiAgICAgICAgZnJvbSBhcHAuY3Jvd2RfZXZlbnQgaW1wb3J0IENyb3dkRXZlbnQKICAgICAgICBjcm93ZF9yZWdpb25zID0gTm9uZQogICAgICAgIGZvciBwYXJ0IGluIHBhcnRzOgogICAgICAgICAgICBpZiBwYXJ0LmNyb3dkX3JlZ2lvbnMgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICBjcm93ZF9yZWdpb25zID0gcGFydC5jcm93ZF9yZWdpb25zCiAgICAgICAgICAgIG9mZnNldCA9IGxlbihyYXdfY29tbWFuZHMpCiAgICAgICAgICAgIHJhd19jb21tYW5kcy5leHRlbmQocGFydC5jb21tYW5kcykKICAgICAgICAgICAgcmF3X2V2ZW50cy5leHRlbmQoCiAgICAgICAgICAgICAgICBldmVudCBpZiBpc2luc3RhbmNlKGV2ZW50LCBDcm93ZEV2ZW50KSBlbHNlIHJlcGxhY2UoZXZlbnQsIG9iamVjdF9yZWY9c3RyKGludChldmVudC5vYmplY3RfcmVmKStvZmZzZXQpKQogICAgICAgICAgICAgICAgZm9yIGV2ZW50IGluIHBhcnQuZXZlbnRzKQogICAgICAgICAgICBjb25maWdzLmV4dGVuZChtZW1iZXJzKHBhcnQuc2NlbmFyaW9fY29uZmlnKSkKCiAgICAgICAgc2VsZWN0ZWRfcG9zaXRpb25zID0gcHVibGljX3Bvc2l0aW9ucyhyYXdfY29tbWFuZHMsIHJhd19ldmVudHMpCiAgICAgICAgaWYgbGVuKHJhd19jb21tYW5kcykgPiBsZW4oc2VsZWN0ZWRfcG9zaXRpb25zKToKICAgICAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY3NbJ2NvbW1hbmRfY2FwX2Ryb3AnXSArPSBsZW4ocmF3X2NvbW1hbmRzKS1sZW4oc2VsZWN0ZWRfcG9zaXRpb25zKQogICAgICAgIHJlbWFwID0ge29sZF9pbmRleDogbmV3X2luZGV4IGZvciBuZXdfaW5kZXgsIG9sZF9pbmRleCBpbiBlbnVtZXJhdGUoc2VsZWN0ZWRfcG9zaXRpb25zKX0KICAgICAgICBjb21tYW5kcyA9IFtyYXdfY29tbWFuZHNbaV0gZm9yIGkgaW4gc2VsZWN0ZWRfcG9zaXRpb25zXQogICAgICAgIGV2ZW50cyA9IFtldmVudCBpZiBpc2luc3RhbmNlKGV2ZW50LCBDcm93ZEV2ZW50KSBlbHNlIHJlcGxhY2UoZXZlbnQsIG9iamVjdF9yZWY9c3RyKHJlbWFwW2ludChldmVudC5vYmplY3RfcmVmKV0pKQogICAgICAgICAgICAgICAgICBmb3IgZXZlbnQgaW4gcmF3X2V2ZW50c10KCiAgICAgICAgcmV0dXJuIEZyYW1lUmVzdWx0KAogICAgICAgICAgICBmcmFtZSwgdHVwbGUoY29tbWFuZHMpLCB0dXBsZShldmVudHMpLAogICAgICAgICAgICB0dXBsZShjb25maWdzKSBpZiBsZW4oY29uZmlncykgPiAxIGVsc2UgY29uZmlnc1swXSBpZiBjb25maWdzIGVsc2UgTm9uZSwKICAgICAgICAgICAgc2VsZi5zY2VuYXJpb19yZXZpc2lvbiwgc2VsZi5kZWJ1Z19hbGxfY2FuZGlkYXRlcywKICAgICAgICAgICAgc2VsZi5wb3NlX2NvbmZpZyBpZiBwZXJzb25fa2V5ID09ICdwb3NlJyBhbmQgcGVyc29uX2tleSBpbiBzdGF0ZS5yZXN1bHRzIGVsc2UgTm9uZSwKICAgICAgICAgICAgY2FtZXJhX2lkPXNlbGYuY2FtZXJhX2lkLCBjcm93ZF9yZWdpb25zPWNyb3dkX3JlZ2lvbnMpCgogICAgZGVmIF9jb2xsZWN0X3BlcnNvbihzZWxmLCBmcmFtZSwgcHJvdmlkZXIsIGNvcGllZCwgaWRzKToKICAgICAgICBpZiBzZWxmLmNvbGxlY3RvciBpcyBOb25lOgogICAgICAgICAgICByZXR1cm4KICAgICAgICBpdGVtcyA9IFtdCiAgICAgICAgZm9yIGRldGVjdGlvbiwgdGlkIGluIHppcChjb3BpZWQuZGV0ZWN0aW9ucywgaWRzKToKICAgICAgICAgICAgaWYgZGV0ZWN0aW9uLmNsYXNzX2lkICE9IDA6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICBpdGVtID0gZGljdChkZXRlY3Rpb24uZG93bnN0cmVhbSgpLCB0cmFja19pZD10aWQpCiAgICAgICAgICAgIGlmIGRldGVjdGlvbi5rZXlwb2ludHMgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICBpdGVtWydrZXlwb2ludHMnXSA9IFtsaXN0KGspIGZvciBrIGluIGRldGVjdGlvbi5rZXlwb2ludHNdCiAgICAgICAgICAgIGl0ZW1zLmFwcGVuZChpdGVtKQogICAgICAgIHRhc2sgPSAncG9zZScgaWYgcHJvdmlkZXIua2V5ID09ICdwb3NlJyBlbHNlICdkZXQnCiAgICAgICAgc2VsZi5jb2xsZWN0b3IuYWRkKAogICAgICAgICAgICB0YXNrLCBmcmFtZS5mcmFtZV9zZXEsIGZyYW1lLnB0c19ucyBvciAwLAogICAgICAgICAgICB7J3cnOiBmcmFtZS5mcmFtZV93aWR0aCwgJ2gnOiBmcmFtZS5mcmFtZV9oZWlnaHQsCiAgICAgICAgICAgICAnY291bnQnOiBsZW4oaXRlbXMpLCAnaXRlbXMnOiBpdGVtcywgJ2ZyYW1lJzogZnJhbWV9LAogICAgICAgICAgICBtYXhfZnJhbWVzPTMyLCBtZXRyaWNzPXNlbGYuaW5ncmVzcy5tZXRyaWNzKQoKICAgIGRlZiBzY2VuYXJpb19zdGF0dXMoc2VsZik6CiAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgYWN0aXZlLCBkaXNhYmxlZCA9IFtdLCBbXQogICAgICAgICAgICBmb3Igc2NlbmFyaW8gaW4gc29ydGVkKHNlbGYuX3JlcXVlc3RlZCk6CiAgICAgICAgICAgICAgICBrZXkgPSBzZWxmLl9kZXBlbmRlbmNpZXNbc2NlbmFyaW9dCiAgICAgICAgICAgICAgICBzdGF0dXMgPSBzZWxmLl9wcm92aWRlcnNba2V5XQogICAgICAgICAgICAgICAgaWYgc3RhdHVzWydzdGF0ZSddID09ICdBQ1RJVkUnOgogICAgICAgICAgICAgICAgICAgIGFjdGl2ZS5hcHBlbmQoc2NlbmFyaW8pCiAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgIGRpc2FibGVkLmFwcGVuZCh7J25hbWUnOiBzY2VuYXJpbywgJ3JlYXNvbic6IHN0YXR1c1sncmVhc29uJ119KQogICAgICAgICAgICByZXR1cm4geydhY3RpdmUnOiBhY3RpdmUsICdkaXNhYmxlZCc6IGRpc2FibGVkfQoKICAgIGRlZiBzdGF0dXMoc2VsZik6CiAgICAgICAgd2l0aCBzZWxmLl9jdjoKICAgICAgICAgICAgcHJvdmlkZXJzID0gewogICAgICAgICAgICAgICAga2V5OiB7CiAgICAgICAgICAgICAgICAgICAgKip7azogdiBmb3IgaywgdiBpbiB2YWx1ZS5pdGVtcygpCiAgICAgICAgICAgICAgICAgICAgICAgaWYgayBub3QgaW4gKCdmaXJzdF9pbnB1dF9hdCcsICdsYXN0X2lucHV0X2F0JywgJ2xhc3RfcmVzcG9uc2VfYXQnKX0sCiAgICAgICAgICAgICAgICAgICAgJ2xhc3RfcmVzcG9uc2VfYWdlX3MnOiAoCiAgICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKHNlbGYuY2xvY2soKS12YWx1ZVsnbGFzdF9yZXNwb25zZV9hdCddLCAzKQogICAgICAgICAgICAgICAgICAgICAgICBpZiB2YWx1ZVsnbGFzdF9yZXNwb25zZV9hdCddIGlzIG5vdCBOb25lIGVsc2UgTm9uZSksCiAgICAgICAgICAgICAgICAgICAgJ2ZpcnN0X2lucHV0X2F0JzogdmFsdWVbJ2ZpcnN0X2lucHV0X2F0J10sCiAgICAgICAgICAgICAgICAgICAgJ2ZpcnN0X3Jlc3BvbnNlX2F0JzogdmFsdWUuZ2V0KCdmaXJzdF9yZXNwb25zZV9hdCcpLAogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZm9yIGtleSwgdmFsdWUgaW4gc2VsZi5fcHJvdmlkZXJzLml0ZW1zKCkKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZGljdCgKICAgICAgICAgICAgICAgIHNvdXJjZV9sYXRlc3RfdHJpYWw9Z2V0YXR0cihzZWxmLmluZ3Jlc3MsICdzb3VyY2VfbGF0ZXN0JywgRmFsc2UpLAogICAgICAgICAgICAgICAgZXZlbnRfY29vbGRvd249c2VsZi5ldmVudF9jb29sZG93bi5zdGF0dXMoKSwKICAgICAgICAgICAgICAgIHN0YXRlPSdFUlJPUicgaWYgc2VsZi5fZXJyb3IgZWxzZSAoJ1NUT1BQRUQnIGlmIHNlbGYuX2Nsb3NlZCBlbHNlCiAgICAgICAgICAgICAgICAgICAgICAoJ0NPTk5FQ1RFRCcgaWYgc2VsZi5fbWV0cmljc1snZmluYWxpemVkJ10gZWxzZSAnUFJFUEFSRUQnKSksCiAgICAgICAgICAgICAgICBlcnJvcj1zZWxmLl9lcnJvciwgZnJlc2huZXNzX21zPXJvdW5kKHNlbGYuZnJlc2huZXNzX3MqMTAwMCksCiAgICAgICAgICAgICAgICBmcmVzaG5lc3NfZW5hYmxlZD1zZWxmLmZyZXNobmVzc19lbmFibGVkLCBzdGFydHVwX3NlY29uZHM9c2VsZi5zdGFydHVwX3MsCiAgICAgICAgICAgICAgICBzdGFsbF9zZWNvbmRzPXNlbGYuc3RhbGxfcywgcXVldWVkPWxlbihzZWxmLl9mcmFtZXMpLCBjYXBhY2l0eT1zZWxmLmNhcGFjaXR5LAogICAgICAgICAgICAgICAgaW5mbGlnaHRfYWdlX3M9bWF4KChzZWxmLmNsb2NrKCktcy5hZG1pdHRlZF9hdCBmb3IgcyBpbiBzZWxmLl9mcmFtZXMudmFsdWVzKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBzLmNsYWltZWQgYW5kIG5vdCBzLnJlc3VsdHMpLCBkZWZhdWx0PTApLAogICAgICAgICAgICAgICAgcGVuZGluZ19hZ2Vfcz1tYXgoKHNlbGYuY2xvY2soKS1zLmFkbWl0dGVkX2F0IGZvciBzIGluIHNlbGYuX2ZyYW1lcy52YWx1ZXMoKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgbm90IHMuY2xhaW1lZCksIGRlZmF1bHQ9MCksCiAgICAgICAgICAgICAgICBwcm92aWRlcnM9cHJvdmlkZXJzLCBzY2VuYXJpb3M9c2VsZi5zY2VuYXJpb19zdGF0dXMoKSwKICAgICAgICAgICAgICAgIHByb3ZpZGVyX3RpbWluZz17a2V5OiB7c3RhZ2U6IGRpY3Qocm93KSBmb3Igc3RhZ2UsIHJvdyBpbiBzdGFnZXMuaXRlbXMoKX0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIGtleSwgc3RhZ2VzIGluIHNlbGYuX3RpbWluZ3MuaXRlbXMoKX0sCiAgICAgICAgICAgICAgICBhcnRpZmFjdHM9c2VsZi5hcnRpZmFjdHMuc3RhdHVzKCkgaWYgc2VsZi5hcnRpZmFjdHMgZWxzZSBOb25lLAogICAgICAgICAgICAgICAgZmlnaHRfbm90aWZpY2F0aW9uPXNlbGYuZmlnaHQubm90aWZpY2F0aW9uX3N0YXR1cygpIGlmIHNlbGYuZmlnaHQgZWxzZSBOb25lLAogICAgICAgICAgICAgICAgdmlzdWFsPXNlbGYudmlzdWFsLnN0YXR1cygpIGlmIHNlbGYudmlzdWFsIGVsc2UgTm9uZSwKICAgICAgICAgICAgICAgIHBlcmZvcm1hbmNlPXNlbGYuaW5ncmVzcy5tZXRyaWNzLnNuYXBzaG90KCksCiAgICAgICAgICAgICAgICBjb2xsZWN0b3JfZnJhbWVzPXNlbGYuX2NvbGxlY3Rvcl9mcmFtZV9jb3VudCgpLAogICAgICAgICAgICAgICAgZmluYWxpemluZz1pbnQoc2VsZi5fZmluYWxpemluZyBpcyBub3QgTm9uZSksCiAgICAgICAgICAgICAgICAqKnNlbGYuX21ldHJpY3MpCgogICAgZGVmIF9jb2xsZWN0b3JfZnJhbWVfY291bnQoc2VsZik6CiAgICAgICAgaWYgc2VsZi5jb2xsZWN0b3IgaXMgTm9uZToKICAgICAgICAgICAgcmV0dXJuIDAKICAgICAgICB3aXRoIHNlbGYuY29sbGVjdG9yLmxvY2s6CiAgICAgICAgICAgIHJldHVybiBsZW4oc2VsZi5jb2xsZWN0b3IuZnJhbWVzKQoKICAgIGRlZiBsYXRlc3RfcmVzdWx0KHNlbGYpOgogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHJldHVybiBzZWxmLl9sYXRlc3QKCiAgICBkZWYgc25hcHNob3Qoc2VsZik6CiAgICAgICAgcmVzdWx0ID0gc2VsZi5sYXRlc3RfcmVzdWx0KCkKICAgICAgICByZXR1cm4gcmVzdWx0LnNuYXBzaG90KHZpc2libGVfb25seT1GYWxzZSkgaWYgcmVzdWx0IGVsc2UgTm9uZQoKICAgIGRlZiBjbG9zZShzZWxmLCB0aW1lb3V0KToKICAgICAgICBkZWFkbGluZSA9IHNlbGYuY2xvY2soKSArIG1heCgwLCB0aW1lb3V0KQogICAgICAgIHNlbGYuc3RvcF9hZG1pc3Npb24oKQogICAgICAgIHdpdGggc2VsZi5fY3Y6CiAgICAgICAgICAgIHNlbGYuX2Nsb3NlZCA9IFRydWUKICAgICAgICAgICAgc2VsZi5fZnJhbWVzLmNsZWFyKCkKICAgICAgICAgICAgc2VsZi5fY3Yubm90aWZ5X2FsbCgpCiAgICAgICAgaWYgc2VsZi5fdGhyZWFkIGlzIG5vdCBOb25lIGFuZCBzZWxmLl90aHJlYWQgaXMgbm90IHRocmVhZGluZy5jdXJyZW50X3RocmVhZCgpOgogICAgICAgICAgICBzZWxmLl90aHJlYWQuam9pbihtYXgoMCwgZGVhZGxpbmUtc2VsZi5jbG9jaygpKSkKICAgICAgICAgICAgaWYgc2VsZi5fdGhyZWFkLmlzX2FsaXZlKCk6CiAgICAgICAgICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoJ011bHRpLXByb3ZpZGVyIGNvb3JkaW5hdG9yIGNsZWFudXAgdGltZWQgb3V0LicpCiAgICAgICAgaWYgc2VsZi50cmFja2VyIGlzIG5vdCBOb25lOgogICAgICAgICAgICBzZWxmLnRyYWNrZXIucmVzZXQoKQogICAgICAgIGlmIHNlbGYucmVnaW9uOgogICAgICAgICAgICBzZWxmLnJlZ2lvbi5jbGVhcigpCiAgICAgICAgaWYgc2VsZi5mYWxsOgogICAgICAgICAgICBzZWxmLmZhbGwuY2xlYXIoKQogICAgICAgIGlmIHNlbGYuZmlnaHQ6CiAgICAgICAgICAgIHNlbGYuZmlnaHQuY2xlYXIoKQogICAgICAgIGlmIHNlbGYuZmlyZToKICAgICAgICAgICAgc2VsZi5maXJlLmNsZWFyKCkKICAgICAgICBpZiBzZWxmLmNyb3dkOgogICAgICAgICAgICBzZWxmLmNyb3dkLmNsb3NlKCkKICAgICAgICBpZiBoYXNhdHRyKHNlbGYuaW5ncmVzcywgJ21ldHJpY3MnKToKICAgICAgICAgICAgc2VsZi5pbmdyZXNzLm1ldHJpY3MuY2xvc2UoKQogICAgICAgIGlmIHNlbGYudmlzdWFsIGlzIG5vdCBOb25lIGFuZCBub3Qgc2VsZi52aXN1YWwuY2xvc2UobWF4KDAsIGRlYWRsaW5lLXNlbGYuY2xvY2soKSkpOgogICAgICAgICAgICByYWlzZSBSdW50aW1lRXJyb3IoJ1Zpc3VhbCB3b3JrZXIgY2xlYW51cCB0aW1lZCBvdXQuJykKICAgICAgICBpZiBzZWxmLmFydGlmYWN0cyBpcyBub3QgTm9uZSBhbmQgbm90IHNlbGYuYXJ0aWZhY3RzLmNsb3NlKG1heCgwLCBkZWFkbGluZS1zZWxmLmNsb2NrKCkpKToKICAgICAgICAgICAgcmFpc2UgUnVudGltZUVycm9yKCdBcnRpZmFjdCBjYXB0dXJlIGNsZWFudXAgdGltZWQgb3V0LicpCiAgICAgICAgaWYgc2VsZi5wdWJsaXNoZXIgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIHNlbGYucHVibGlzaGVyLmNoYW5uZWwoCiAgICAgICAgICAgICAgICBzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbMV0sIHNlbGYuaW5ncmVzcy5pZGVudGl0eVszXSwKICAgICAgICAgICAgICAgIHNlbGYuaW5ncmVzcy5pZGVudGl0eVs0XSwgJ0VSUk9SJyBpZiBzZWxmLl9lcnJvciBlbHNlICdTVE9QUEVEJykKICAgICAgICAgICAgaWYgbm90IHNlbGYucHVibGlzaGVyLndhaXRfY2hhbm5lbCgKICAgICAgICAgICAgICAgICAgICBzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbMV0sIHNlbGYuaW5ncmVzcy5pZGVudGl0eVszXSwKICAgICAgICAgICAgICAgICAgICBzZWxmLmluZ3Jlc3MuaWRlbnRpdHlbNF0sIG1heCgwLCBkZWFkbGluZS1zZWxmLmNsb2NrKCkpKToKICAgICAgICAgICAgICAgIHJhaXNlIFJ1bnRpbWVFcnJvcignTWV0YWRhdGEgY2hhbm5lbCB3b3JrZXIgY2xlYW51cCBmYWlsZWQgb3IgdGltZWQgb3V0LicpCg=="
  },
  "configs": {
    "CONTEXTRA_CONTROL_TEMPLATE_FILE": {
      "sha256": "f35ab1a3153590dd12b201e15c3de35e6e0398151d9262c89710aedc600269f7",
      "channels": [
        {
          "camera": null,
          "fall": 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": "ecd32c5fd2d8f1ed13fd71963a647cc4f042117f52bf78fc3a9acbd82838a41a",
      "channels": [
        {
          "camera": 1,
          "fall": {
            "enabled": true,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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,
          "fall": {
            "enabled": true,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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,
          "fall": {
            "enabled": true,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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,
          "fall": {
            "enabled": true,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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,
          "fall": 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": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 3,
          "fall": {
            "enabled": true,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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,
          "fall": 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": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 13,
          "fall": null,
          "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,
          "fall": null,
          "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,
          "fall": 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": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 26,
          "fall": 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": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 27,
          "fall": {
            "enabled": true,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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,
          "fall": 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": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 23,
          "fall": 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": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 29,
          "fall": 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": {
            "FIRE": 10.0,
            "FALL": 10.0,
            "INTRUSION": 10.0,
            "LOITERING": 10.0,
            "FIGHT": 10.0,
            "CROWD": 10.0
          }
        },
        {
          "camera": 24,
          "fall": null,
          "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,
          "fall": {
            "enabled": true,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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,
          "fall": {
            "enabled": false,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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,
          "fall": {
            "enabled": false,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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,
          "fall": {
            "enabled": false,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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
          }
        },
        {
          "camera": 6,
          "fall": {
            "enabled": false,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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
          }
        },
        {
          "camera": 16,
          "fall": {
            "enabled": false,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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
          }
        },
        {
          "camera": 18,
          "fall": {
            "enabled": false,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "fight": {
            "enabled": true,
            "person_score": 0.45,
            "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,
          "fall": {
            "enabled": false,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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
          }
        },
        {
          "camera": 8,
          "fall": {
            "enabled": false,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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
          }
        },
        {
          "camera": 9,
          "fall": {
            "enabled": false,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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
          }
        },
        {
          "camera": 10,
          "fall": {
            "enabled": false,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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
          }
        },
        {
          "camera": 11,
          "fall": {
            "enabled": false,
            "person_score": 0.15,
            "joint_score": 0.3,
            "upright_angle_deg": 35.0,
            "down_angle_deg": 50.0,
            "torso_delta_deg": 25.0,
            "hip_drop_ratio": 0.25,
            "span_collapse_ratio": 0.7,
            "knee_guard_angle_deg": 100.0,
            "knee_guard_torso_max_deg": 45.0,
            "upright_hold_seconds": 0.5,
            "transition_window_seconds": 0.8,
            "transition_to_down_seconds": 0.8,
            "down_hold_seconds": 0.7,
            "test_skip_down_hold": true,
            "missing_grace_seconds": 0.5,
            "recovery_hold_seconds": 1.0,
            "confirmed_retention_seconds": 5.0,
            "reference_window_seconds": 1.0,
            "unconfirmed_retention_seconds": 5.0,
            "max_states": 1024,
            "history_capacity": 256,
            "roi_id": "primary",
            "roi_name": "Fall ROI",
            "debug_roi": true,
            "roi": [
              [
                0.0,
                0.0
              ],
              [
                1.0,
                0.0
              ],
              [
                1.0,
                1.0
              ],
              [
                0.0,
                1.0
              ]
            ]
          },
          "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
          }
        }
      ]
    }
  },
  "runtime_counts": {
    "running": 0,
    "starting": 0,
    "stopped": 28,
    "error": 0,
    "total": 28
  },
  "streams": [
    {
      "streamId": "camera-b80c8fefa677534085fb2c162d75df03",
      "cameraId": "1",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-334b6b3112a25bfcbf4f870c0954b343",
      "cameraId": "2",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-ff6c5a08b2fa56b6ac006830f4074b6a",
      "cameraId": "4",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-afca48e959ea5a28b8a488e0cc6eda1c",
      "cameraId": "5",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-3a8b9d4cb2925153b16070f43a18999e",
      "cameraId": "12",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-c093c7f66edf595e953970de788efbaa",
      "cameraId": "3",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-071beeb1b1ed5e7c87e330a0877942b4",
      "cameraId": "17",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-12f1810436a25810a811e616e5314449",
      "cameraId": "13",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-fc340caed62953cabfc2f46c1a22d325",
      "cameraId": "14",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-ab827ed286c25c7f8eee0326d169f0da",
      "cameraId": "28",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-0c49e57f9f0c56d48fdb7d3ae6246ec9",
      "cameraId": "26",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-fb5ee05b8ff05a2d8e7aa74358a96b3b",
      "cameraId": "27",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-51e4ac9a92ed5ca595abf9260e15f813",
      "cameraId": "22",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-b515d77a162958569697c82f3c839a7d",
      "cameraId": "23",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-31c1fa4986355943b57ec7e667e181db",
      "cameraId": "29",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-1fdaa47a21ac5365934a42c53f6d327f",
      "cameraId": "24",
      "state": null,
      "runId": "144e377f-1359-462b-9a11-14d78f845592",
      "runGeneration": 1
    },
    {
      "streamId": "camera-c06243dceaed5ddfbc34c28ae6c89ede",
      "cameraId": "8",
      "state": null,
      "runId": "2bc2c84a-7168-4b51-8ec0-9129fe9a391d",
      "runGeneration": 1
    },
    {
      "streamId": "camera-b756dcb03600525dbacb285c0f1a07e2",
      "cameraId": "9",
      "state": null,
      "runId": "b8e50ccd-1db1-4762-b596-be068d0d77bb",
      "runGeneration": 1
    },
    {
      "streamId": "camera-e1e5b788f4295a329f7e63865921a5e5",
      "cameraId": "10",
      "state": null,
      "runId": "22255235-1178-474c-ad86-01c2f78f5da8",
      "runGeneration": 2
    },
    {
      "streamId": "camera-2342aa206cb653c8976461bcac17bdcc",
      "cameraId": "11",
      "state": null,
      "runId": "77ea2833-f110-45a0-a197-60b584da7f51",
      "runGeneration": 3
    },
    {
      "streamId": "camera-5bd20866347853f7bc79d2aae304b443",
      "cameraId": "7",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-6d5f64e6d53b5df680057d9a26547399",
      "cameraId": "15",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-7fb92d7386ec5509ba7b7be21db93784",
      "cameraId": "16",
      "state": null,
      "runId": "50d56af3-33f3-4bb8-a3bc-d23ff8253bf6",
      "runGeneration": 1
    },
    {
      "streamId": "camera-70ede393d2265e569f1631b79e2b724b",
      "cameraId": "18",
      "state": null,
      "runId": "5aec71d0-9192-43ad-87b4-46bc9ee6b3d9",
      "runGeneration": 2
    },
    {
      "streamId": "camera-38a01d76c5185afc9b9414cb038b4370",
      "cameraId": "19",
      "state": null,
      "runId": "4c41ad8a-ecc7-462b-a68e-75c9d1c759e9",
      "runGeneration": 1
    },
    {
      "streamId": "camera-2c6e5af15b9d589190d2786607a2882e",
      "cameraId": "21",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-289dd7fb89ab53ff803d2fd731906127",
      "cameraId": "20",
      "state": null,
      "runId": null,
      "runGeneration": 0
    },
    {
      "streamId": "camera-c6577abe8c0f5a02ac84aa94c2247b1e",
      "cameraId": "6",
      "state": null,
      "runId": null,
      "runGeneration": 0
    }
  ],
  "images": {
    "analytics": "sha256:68823dd031b21abbee0ad5a0086ee21f127ae5ed7eb806724c984169be5d6c4b",
    "ai-control-sidecar": "sha256:9afaf2830398090fa8a7f10fb1349106fda8ae41750f83588589a40db9094820",
    "ai-gateway": "sha256:f9b672d8b5beffd4b705339fdeb4494f73604899eafef23e99f90590761f8239",
    "redis": "sha256:8231d3786e10c470840c27963f3d19672dc7ef3e5d5adc512c01d44faada5672",
    "postgresql": "sha256:26ff894de07212639974012ba2be1fc8b1a6dc6a7b18035c35c48fd26092c0a9"
  },
  "free_root": 211755069440,
  "active": {
    "transaction": "artifact-r5-notification-20261101-r01",
    "compose": "/workspace/contextra/runtime/state/transactions/artifact-r5-notification-20261101-r01/compose.json",
    "physical": "/workspace/contextra/runtime/state/transactions/artifact-r5-notification-20261101-r01/compose.physical.json",
    "compose_semantic_sha256": "82b262233df01a291dd5871e702dbb33b6b21323842ace3323aebdbc55b78204",
    "profile": "internal",
    "enrolled": true
  }
}