openship 0.4.8 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +27 -1
  2. package/dist/bare-FSUAM5V5.js +23 -0
  3. package/dist/{bowser-O3AEA6AN.js → bowser-HNOTPGJO.js} +2 -2
  4. package/dist/{chunk-5MZ624VX.js → chunk-2GWYYHOR.js} +1 -1
  5. package/dist/chunk-3FYIXVX5.js +8051 -0
  6. package/dist/{chunk-ILFETZOM.js → chunk-3LDWWY7U.js} +21 -1
  7. package/dist/{chunk-W73X43R7.js → chunk-3NQQXMDR.js} +3 -3
  8. package/dist/{chunk-OWED2GRM.js → chunk-42WQABXM.js} +2 -2
  9. package/dist/{chunk-TYVME3XD.js → chunk-6FH4AXVY.js} +20 -3
  10. package/dist/{chunk-OXWDY22G.js → chunk-6ODUBKUB.js} +3 -3
  11. package/dist/{chunk-DYPH4HCI.js → chunk-AO252K7Z.js} +1 -1
  12. package/dist/{chunk-XPPZ7B2J.js → chunk-B3CE2OMR.js} +14 -12
  13. package/dist/{chunk-IXCHURVK.js → chunk-DOD2BXHQ.js} +4 -4
  14. package/dist/{chunk-VWPEKOH6.js → chunk-DRK3MEDS.js} +3 -3
  15. package/dist/{chunk-V6AN6XLZ.js → chunk-EMXI4UCU.js} +125 -47
  16. package/dist/{chunk-GKHUSZCD.js → chunk-EP2TNALB.js} +2 -2
  17. package/dist/{chunk-SLTYVHU7.js → chunk-GUQ3QCJ7.js} +942 -519
  18. package/dist/chunk-I3DPMTSF.js +29 -0
  19. package/dist/{chunk-L2VOGB2X.js → chunk-IW2UKBVF.js} +3 -3
  20. package/dist/{chunk-VDMQJHPI.js → chunk-IXM5245F.js} +228 -13
  21. package/dist/{chunk-MZ2WEHHY.js → chunk-JIMUYEKN.js} +4 -4
  22. package/dist/chunk-OGY63DGD.js +705 -0
  23. package/dist/{chunk-O6ZZF52V.js → chunk-ONKEYSMY.js} +2 -2
  24. package/dist/{chunk-6APULWSU.js → chunk-OTLSJYAC.js} +1744 -118
  25. package/dist/{chunk-EI575GHN.js → chunk-PDW4L3NV.js} +3 -3
  26. package/dist/{chunk-5NYUCONN.js → chunk-PSZSKEPA.js} +33 -51
  27. package/dist/{chunk-KI2EY3WB.js → chunk-PXKCZB2I.js} +1 -1
  28. package/dist/{chunk-FXTBHTWY.js → chunk-QEH4QUBX.js} +649 -85
  29. package/dist/{chunk-6APIPIJY.js → chunk-QWHBRY2K.js} +5 -5
  30. package/dist/{chunk-6B5YCFFV.js → chunk-RVER2EOO.js} +5 -5
  31. package/dist/{chunk-Q2CIRAOK.js → chunk-RXQBD4ZY.js} +1 -1
  32. package/dist/{chunk-TGIINPVM.js → chunk-TWJCLD4W.js} +60 -10
  33. package/dist/{chunk-4Z5QO7N6.js → chunk-VDDMADOF.js} +3 -3
  34. package/dist/{chunk-BBHX7T4R.js → chunk-VE2YOK4I.js} +991 -254
  35. package/dist/{chunk-2D3I5G6P.js → chunk-VZ2ZHPS2.js} +73 -43
  36. package/dist/{chunk-AVIB7CT7.js → chunk-WNWQBB7F.js} +2 -2
  37. package/dist/{chunk-FRNAR33O.js → chunk-XZYFZ6A5.js} +3 -3
  38. package/dist/{chunk-RPHRPFEH.js → chunk-ZCFVHA25.js} +1 -1
  39. package/dist/{chunk-FPRHYBY2.js → chunk-ZFJXPCQP.js} +1 -1
  40. package/dist/{chunk-JYGD5WSN.js → chunk-ZWLDLTJP.js} +1 -1
  41. package/dist/cloud-E5M6VMCG.js +31 -0
  42. package/dist/{cloud-7QYOGF7F.js → cloud-KRTZ2IL5.js} +3 -3
  43. package/dist/{detect-AZLOHUFX.js → detect-ALF4GXRX.js} +7 -8
  44. package/dist/{dist-IQJ6H6UZ.js → dist-BM6NPWIH.js} +3 -3
  45. package/dist/{dist-es-X3B5QYKB.js → dist-es-2YRDXMUU.js} +6 -6
  46. package/dist/{dist-es-OSNJBLXB.js → dist-es-CCVZEFRZ.js} +5 -5
  47. package/dist/{dist-es-VNKHQVIB.js → dist-es-IOH6G4GM.js} +4 -4
  48. package/dist/{dist-es-RYHIPOTN.js → dist-es-JGBPABJI.js} +14 -14
  49. package/dist/{dist-es-JSTDUS7Q.js → dist-es-KWSMDPIP.js} +6 -6
  50. package/dist/{dist-es-5DY7K32L.js → dist-es-UYDDOVZ3.js} +6 -6
  51. package/dist/{dist-es-WV4AMOII.js → dist-es-XUOR4NQN.js} +8 -8
  52. package/dist/docker-QECQJ5P4.js +32 -0
  53. package/dist/docker-edge-executor-62N64MGS.js +17 -0
  54. package/dist/edge-import-CQWHN2Q3.js +48 -0
  55. package/dist/ensure-container-edge-MJVXJQG5.js +32 -0
  56. package/dist/{event-streams-EHRAKL75.js → event-streams-TR4GAC53.js} +4 -4
  57. package/dist/{executor-XJ6RP4Q2.js → executor-JELARVKC.js} +8 -8
  58. package/dist/index.js +1209 -560
  59. package/dist/{loadSso-46FQRIZS.js → loadSso-UGF4JMRK.js} +10 -10
  60. package/dist/{local-executor-V7U5VOZW.js → local-executor-WOFZD72X.js} +4 -4
  61. package/dist/nginx-AXGNWRKZ.js +31 -0
  62. package/dist/node-entry.js +4 -0
  63. package/dist/{noop-FMMFG2EZ.js → noop-NJ72F46T.js} +3 -3
  64. package/dist/openresty-lua-IE4P5YQX.js +81 -0
  65. package/dist/server/index.js +116248 -94749
  66. package/dist/server/lua/geo_country.lua +31 -6
  67. package/dist/server/lua/maxminddb.lua +403 -0
  68. package/dist/server/lua/mgmt_api.lua +431 -68
  69. package/dist/server/lua/pipe_log.lua +10 -4
  70. package/dist/server/lua/site_logger.lua +220 -12
  71. package/dist/server/migrations/0073_project_volumes_object_storage.sql +3 -0
  72. package/dist/server/migrations/0074_project_compose_path.sql +1 -0
  73. package/dist/server/migrations/0075_service_command_argv.sql +1 -0
  74. package/dist/server/migrations/0076_rollback_retention.sql +17 -0
  75. package/dist/server/migrations/0077_domain_redirect.sql +13 -0
  76. package/dist/server/migrations/0078_grant_source_scope.sql +30 -0
  77. package/dist/server/migrations/0079_project_readiness.sql +18 -0
  78. package/dist/server/migrations/0080_deployment_error_classification.sql +26 -0
  79. package/dist/server/migrations/0081_project_readiness_repair.sql +34 -0
  80. package/dist/server/migrations/0082_edge_target_verification.sql +39 -0
  81. package/dist/server/migrations/0083_service_incident.sql +84 -0
  82. package/dist/server/migrations/0084_analytics_daily_rollup.sql +72 -0
  83. package/dist/server/migrations/0085_resource_usage.sql +68 -0
  84. package/dist/server/migrations/0086_remote_infra_updates.sql +41 -0
  85. package/dist/server/migrations/0087_server_container_version_columns.sql +17 -0
  86. package/dist/server/migrations/0088_audit_source_and_settings.sql +27 -0
  87. package/dist/server/migrations/0089_auto_scan_infra.sql +7 -0
  88. package/dist/server/migrations/0090_project_collect_paths.sql +18 -0
  89. package/dist/server/migrations/0091_project_server_id.sql +26 -0
  90. package/dist/server/migrations/0092_project_internal_alias.sql +13 -0
  91. package/dist/server/migrations/0093_service_incident_org_index.sql +13 -0
  92. package/dist/server/migrations/0094_backup_restore_meta.sql +15 -0
  93. package/dist/server/migrations/0095_backup_restore_cancel.sql +19 -0
  94. package/dist/server/migrations/0096_backup_policy_retention_defaults.sql +20 -0
  95. package/dist/server/migrations/0097_update_status_upstream_only.sql +35 -0
  96. package/dist/server/migrations/meta/_journal.json +175 -0
  97. package/dist/setup-FA4PW4NU.js +21 -0
  98. package/dist/{signin-ITOPKKUB.js → signin-3M3UPB6K.js} +10 -10
  99. package/dist/{sso-oidc-NON2PD7Y.js → sso-oidc-3VDIYOEJ.js} +10 -10
  100. package/dist/{sts-HHFFSAY2.js → sts-B3WIYLXR.js} +9 -9
  101. package/package.json +6 -3
  102. package/dist/bare-JY5Y5ELU.js +0 -23
  103. package/dist/chunk-SJIFLLX4.js +0 -2931
  104. package/dist/chunk-VFINNTUL.js +0 -362
  105. package/dist/cloud-KYWY3RP4.js +0 -30
  106. package/dist/docker-LODK5Y2S.js +0 -16
  107. package/dist/docker-edge-executor-VHW3JPJS.js +0 -13
  108. package/dist/edge-import-ABUDKKJI.js +0 -45
  109. package/dist/ensure-container-edge-SW6HENSG.js +0 -31
  110. package/dist/nginx-3L4SIBJA.js +0 -24
  111. package/dist/openresty-lua-4WLGDSER.js +0 -42
  112. package/dist/setup-NU6T2PDU.js +0 -20
@@ -0,0 +1,705 @@
1
+ #!/usr/bin/env sh
2
+ ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
+ import { createRequire as __ospCreateRequire } from "node:module";
4
+ const require = __ospCreateRequire(import.meta.url);
5
+ import {
6
+ sq
7
+ } from "./chunk-ZFJXPCQP.js";
8
+ import {
9
+ safeErrorMessage
10
+ } from "./chunk-OTLSJYAC.js";
11
+
12
+ // ../../packages/adapters/src/infra/openresty-lua.ts
13
+ import { createHash, randomBytes } from "crypto";
14
+ import { existsSync, readFileSync } from "fs";
15
+ import { dirname, join } from "path";
16
+ import { fileURLToPath } from "url";
17
+
18
+ // ../../packages/adapters/src/infra/lua-embedded.ts
19
+ var EMBEDDED_LUA = {
20
+ "geo_country.lua": "LS0gZ2VvX2NvdW50cnkubHVhCi0tIE1heE1pbmQgR2VvTGl0ZTItQ291bnRyeSBsb29rdXAgd2l0aCBwZXItd29ya2VyIExSVSBjYWNoZS4KLS0KLS0gREIgYW5kIGNhY2hlIGFyZSBwZXItd29ya2VyIG9ubHk6IG9uZSBsb2FkIHBlciB3b3JrZXIsIHNoYXJlZCBieSBhbGwKLS0gcmVxdWVzdHMuIE5vIHJlbG9hZCBwZXIgc3RyZWFtIG9yIHBlciByZXF1ZXN0LgotLQotLSBEZXBlbmRlbmNpZXM6Ci0tICAgTHVhIGJpbmRpbmcg4oCUIGBvcGVuc2hpcC5tYXhtaW5kZGJgLCB2ZW5kb3JlZCBiZXNpZGUgdGhpcyBmaWxlLiBGYWxscyBiYWNrIHRvCi0tICAgICAgICAgICAgICAgICBgcmVzdHkubWF4bWluZGRiYCBmb3IgYSBiYXJlIGJveCB0aGF0IGhhcyB0aGUgb3BtIHBhY2thZ2UKLS0gICAgICAgICAgICAgICAgIGluc3RhbGxlZCBmcm9tIGJlZm9yZSB3ZSB2ZW5kb3JlZCBpdC4KLS0gICBDIGxpYnJhcnkgICDigJQgbGlibWF4bWluZGRiLnNvIChgYXBrIGFkZCBsaWJtYXhtaW5kZGJgIGluIGFwcHMvZWRnZS9Eb2NrZXJmaWxlOwotLSAgICAgICAgICAgICAgICAgaW5zdGFsbEdlb0RlcHMoKSBmb3IgYmFyZSBib3hlcykKLS0gICBEYXRhYmFzZSAgICDigJQgL3Vzci9zaGFyZS9HZW9JUC9HZW9MaXRlMi1Db3VudHJ5Lm1tZGIgKGJha2VkIGludG8gdGhlIGVkZ2UKLS0gICAgICAgICAgICAgICAgIGltYWdlIGZyb20gYXBwcy9hcGkvYXNzZXRzL2dlb2lwLCBzbyBubyBydW50aW1lIGRvd25sb2FkKQotLQotLSBGYWxscyBiYWNrIGdyYWNlZnVsbHkgLSBpZiB0aGUgbGlicmFyeSBvciBkYXRhYmFzZSBpcyBtaXNzaW5nLAotLSBnZXRfY291bnRyeV9jb2RlKCkgcmV0dXJucyBuaWwuICBCb3RoIHNpdGVfbG9nZ2VyLmx1YSBhbmQgcGlwZV9sb2cubHVhCi0tIHdyYXAgdGhpcyBtb2R1bGUgaW4gcGNhbGwocmVxdWlyZSwgLi4uKSBzbyBhIG1pc3NpbmcgREIgbmV2ZXIgY3Jhc2hlcwotLSB0aGUgcmVxdWVzdCBwaXBlbGluZS4gbWdtdF9hcGkgYEdFVCAvc3RhdHVzYCByZXBvcnRzIHdoZXRoZXIgZ2VvIGFjdHVhbGx5Ci0tIHJlc29sdmVkLCBzbyBhIHNpbGVudGx5LWRhcmsgZWRnZSBpcyB2aXNpYmxlIGluc3RlYWQgb2YganVzdCB5aWVsZGluZyBhbgotLSBlbXB0eSBjb3VudHJ5IG1hcC4KCmxvY2FsIF9NID0ge30KCmxvY2FsIERCX1BBVEggPSAiL3Vzci9zaGFyZS9HZW9JUC9HZW9MaXRlMi1Db3VudHJ5Lm1tZGIiCgotLSBWZW5kb3JlZCBjb3B5IGZpcnN0LCBvcG0taW5zdGFsbGVkIGNvcHkgc2Vjb25kLiBgZmZpLmxvYWQoJ2xpYm1heG1pbmRkYicpYAotLSBydW5zIGF0IHJlcXVpcmUgdGltZSBpbiBib3RoLCBzbyBhIG1pc3NpbmcgLnNvIHN1cmZhY2VzIGhlcmUgYXMgbW1kYl9vaz1mYWxzZS4KbG9jYWwgbW1kYl9vaywgbWF4bWluZCA9IHBjYWxsKHJlcXVpcmUsICJvcGVuc2hpcC5tYXhtaW5kZGIiKQppZiBub3QgbW1kYl9vayB0aGVuCiAgICBtbWRiX29rLCBtYXhtaW5kID0gcGNhbGwocmVxdWlyZSwgInJlc3R5Lm1heG1pbmRkYiIpCmVuZApsb2NhbCBscnVjYWNoZV9vaywgbHJ1Y2FjaGUgPSBwY2FsbChyZXF1aXJlLCAicmVzdHkubHJ1Y2FjaGUiKQoKbG9jYWwgY2FjaGUgICAgICAgICAgICAtLSBvbmUgTFJVIHBlciB3b3JrZXIKbG9jYWwgZ2VvX2luaXR0ZWQgPSBmYWxzZSAgLS0gREIgb3BlbmVkIG9uY2UgcGVyIHdvcmtlciBvbiBmaXJzdCBsb29rdXAKLS0gV2h5IGdlbyBpcyBvZmYsIGZvciBgR0VUIC9zdGF0dXNgLiBEaXN0aW5ndWlzaGluZyAibm8gRkZJIGJpbmRpbmcgLyBubyAuc28iCi0tIGZyb20gIm5vIGRhdGFiYXNlIiBtYXR0ZXJzOiB0aGV5IG5lZWQgZGlmZmVyZW50IGZpeGVzLCBhbmQgYm90aCB1c2VkIHRvCi0tIHByZXNlbnQgaWRlbnRpY2FsbHkgYXMgYW4gZW1wdHkgY291bnRyeSBtYXAuCmxvY2FsIGdlb19yZWFzb24gPSAibm90IGluaXRpYWxpc2VkIgoKLS0gSW5pdCBNYXhNaW5kIG9uY2UgcGVyIHdvcmtlcjsgc3Vic2VxdWVudCBsb29rdXBzIChhbnkgc3RyZWFtKSByZXVzZS4KbG9jYWwgZnVuY3Rpb24gZW5zdXJlX2dlb19pbml0KCkKICAgIGlmIGdlb19pbml0dGVkIHRoZW4KICAgICAgICByZXR1cm4gdHJ1ZQogICAgZW5kCiAgICBpZiBub3QgbW1kYl9vayBvciBub3QgbWF4bWluZCB0aGVuCiAgICAgICAgZ2VvX3JlYXNvbiA9ICJtYXhtaW5kZGIgRkZJIGJpbmRpbmcgdW5hdmFpbGFibGUgKGxpYm1heG1pbmRkYi5zbyBtaXNzaW5nPykiCiAgICAgICAgcmV0dXJuIGZhbHNlCiAgICBlbmQKICAgIGxvY2FsIG9rLCBlcnIgPSBtYXhtaW5kLmluaXQoREJfUEFUSCkKICAgIGlmIG5vdCBvayB0aGVuCiAgICAgICAgZ2VvX3JlYXNvbiA9ICJkYXRhYmFzZSB1bnJlYWRhYmxlIGF0ICIgLi4gREJfUEFUSCAuLiAiOiAiIC4uIChlcnIgb3IgInVua25vd24iKQogICAgICAgIG5neC5sb2cobmd4LldBUk4sCiAgICAgICAgICAgICJbZ2VvX2NvdW50cnldIEdlb0xpdGUyIGRhdGFiYXNlIG5vdCBmb3VuZCBhdCAiIC4uIERCX1BBVEggLi4KICAgICAgICAgICAgIiAtIGdlbyBsb29rdXBzIGRpc2FibGVkOiAiIC4uIChlcnIgb3IgInVua25vd24iKSkKICAgICAgICByZXR1cm4gZmFsc2UKICAgIGVuZAogICAgZ2VvX2luaXR0ZWQgPSB0cnVlCiAgICBnZW9fcmVhc29uID0gIm9rIgogICAgbmd4LmxvZyhuZ3guSU5GTywgIltnZW9fY291bnRyeV0gR2VvTGl0ZTItQ291bnRyeSBsb2FkZWQgZnJvbSAiIC4uIERCX1BBVEgpCiAgICByZXR1cm4gdHJ1ZQplbmQKCi0tIENyZWF0ZSBMUlUgY2FjaGUgb25jZSBwZXIgd29ya2VyIChtYXggNTAwMDAgSVBzKS4KbG9jYWwgZnVuY3Rpb24gZ2V0X2NhY2hlKCkKICAgIGlmIGNhY2hlIHRoZW4KICAgICAgICByZXR1cm4gY2FjaGUKICAgIGVuZAogICAgaWYgbm90IGxydWNhY2hlX29rIG9yIG5vdCBscnVjYWNoZSB0aGVuCiAgICAgICAgcmV0dXJuIG5pbAogICAgZW5kCiAgICBsb2NhbCBjLCBlcnIgPSBscnVjYWNoZS5uZXcoNTAwMDApCiAgICBpZiBub3QgYyB0aGVuCiAgICAgICAgcmV0dXJuIG5pbAogICAgZW5kCiAgICBjYWNoZSA9IGMKICAgIHJldHVybiBjYWNoZQplbmQKCi0tLSBHZXQgY291bnRyeSBJU08gY29kZSBmb3IgSVAuIFVzZXMgaW4tbWVtb3J5IExSVSBjYWNoZSB0aGVuIE1heE1pbmQgREIuCi0tIEBwYXJhbSBpcCBzdHJpbmcgKGUuZy4gIjguOC44LjgiKQotLSBAcmV0dXJuIHN0cmluZ3xuaWwgY291bnRyeSBjb2RlIChlLmcuICJVUyIpIG9yIG5pbApmdW5jdGlvbiBfTS5nZXRfY291bnRyeV9jb2RlKGlwKQogICAgaWYgbm90IGlwIG9yIGlwID09ICIiIHRoZW4KICAgICAgICByZXR1cm4gbmlsCiAgICBlbmQKCiAgICBsb2NhbCBjID0gZ2V0X2NhY2hlKCkKICAgIGlmIGMgdGhlbgogICAgICAgIGxvY2FsIGNhY2hlZCA9IGM6Z2V0KGlwKQogICAgICAgIGlmIGNhY2hlZCB+PSBuaWwgdGhlbgogICAgICAgICAgICAtLSBmYWxzZSBtZWFucyAibG9va2VkIHVwLCBubyByZXN1bHQiIC0gYXZvaWRzIHJlcGVhdGVkIERCIG1pc3NlcwogICAgICAgICAgICByZXR1cm4gKGNhY2hlZCA9PSBmYWxzZSkgYW5kIG5pbCBvciBjYWNoZWQKICAgICAgICBlbmQKICAgIGVuZAoKICAgIGlmIG5vdCBlbnN1cmVfZ2VvX2luaXQoKSB0aGVuCiAgICAgICAgaWYgYyB0aGVuIGM6c2V0KGlwLCBmYWxzZSkgZW5kCiAgICAgICAgcmV0dXJuIG5pbAogICAgZW5kCgogICAgbG9jYWwgb2ssIHJlcywgZXJyID0gcGNhbGwobWF4bWluZC5sb29rdXAsIGlwKQogICAgbG9jYWwgY29kZSA9IG5pbAogICAgaWYgb2sgYW5kIHJlcyBhbmQgcmVzLmNvdW50cnkgYW5kIHJlcy5jb3VudHJ5Lmlzb19jb2RlIHRoZW4KICAgICAgICBjb2RlID0gcmVzLmNvdW50cnkuaXNvX2NvZGUKICAgIGVuZAoKICAgIGlmIGMgdGhlbgogICAgICAgIGM6c2V0KGlwLCBjb2RlIG9yIGZhbHNlKQogICAgZW5kCiAgICByZXR1cm4gY29kZQplbmQKCmZ1bmN0aW9uIF9NLmVuc3VyZV9nZW9faW5pdCgpCiAgICByZXR1cm4gZW5zdXJlX2dlb19pbml0KCkKZW5kCgotLS0gSGVhbHRoIGZvciBgR0VUIC9zdGF0dXNgOiBkb2VzIGdlbyBhY3R1YWxseSByZXNvbHZlLCBhbmQgaWYgbm90LCB3aHkuCi0tIEByZXR1cm4gYm9vbGVhbiBhdmFpbGFibGUsIHN0cmluZyByZWFzb24sIHN0cmluZyBkYl9wYXRoCmZ1bmN0aW9uIF9NLnN0YXR1cygpCiAgICBsb2NhbCBvayA9IGVuc3VyZV9nZW9faW5pdCgpCiAgICByZXR1cm4gb2ssIGdlb19yZWFzb24sIERCX1BBVEgKZW5kCgpyZXR1cm4gX00K",
21
+ "maxminddb.lua": "LS0gbWF4bWluZGRiLmx1YSDigJQgVkVORE9SRUQgVEhJUkQtUEFSVFkuIERvIG5vdCBlZGl0OyByZS12ZW5kb3IgaW5zdGVhZC4KLS0KLS0gVXBzdHJlYW06IGFuamlhMDUzMi9sdWEtcmVzdHktbWF4bWluZGRiIHYxLjMuMiAob3BtKS4gTG9hZGVkIGFzCi0tIGBvcGVuc2hpcC5tYXhtaW5kZGJgIChzZWUgZ2VvX2NvdW50cnkubHVhKS4gVmVyYmF0aW0gZXhjZXB0IHRoaXMgaGVhZGVyIGFuZCBPTkUKLS0gbWFya2VkIGNoYW5nZSB0byB0aGUgYGZmaS5sb2FkYCBjYWxsIOKAlCBzZWFyY2ggIk9QRU5TSElQIExPQ0FMIE1PRElGSUNBVElPTiIuCi0tCi0tIFdoeSB2ZW5kb3JlZCByYXRoZXIgdGhhbiBgb3BtIGdldGAgYXQgaW1hZ2UgYnVpbGQ6IGBvcG1gIG5lZWRzIHBlcmwsIHdoaWNoIHRoZQotLSBvcGVucmVzdHkgYWxwaW5lIGJhc2UgZG9lcyBub3Qgc2hpcCwgYW5kIGEgYnVpbGQtdGltZSBmZXRjaCB3b3VsZCBtYWtlIHRoZQotLSBpbWFnZSBub24tcmVwcm9kdWNpYmxlLiBFdmVyeXRoaW5nIGVsc2UgaW4gdGhpcyBkaXJlY3RvcnkgaXMgYWxyZWFkeSBzaGlwcGVkCi0tIGJ5IHVzIChhbmQgYmFzZTY0LWVtYmVkZGVkIGludG8gdGhlIEpTIGJ1bmRsZSksIHNvIGEgcGlubmVkIGNvcHkgaXMgdGhlIGhvdXNlCi0tIHBhdHRlcm4g4oCUIHNhbWUgcmVhc29uaW5nIGFzIHRoZSB2ZW5kb3JlZCBHZW9MaXRlMiBEQiBpbiBhcHBzL2FwaS9hc3NldHMvZ2VvaXAuCi0tCi0tIE5lZWRzIGxpYm1heG1pbmRkYi5zbyBhdCBydW50aW1lIChgYXBrIGFkZCBsaWJtYXhtaW5kZGJgLCBpbiBhcHBzL2VkZ2UvRG9ja2VyZmlsZSkuCi0tIGBmZmkubG9hZGAgYmVsb3cgcnVucyBhdCBSRVFVSVJFIHRpbWUsIHNvIGEgbWlzc2luZyAuc28gdGhyb3dzIG9uIHJlcXVpcmUg4oCUCi0tIGdlb19jb3VudHJ5Lmx1YSBwY2FsbHMgaXQgZm9yIGV4YWN0bHkgdGhhdCByZWFzb24uCi0tCi0tIFJlLXZlbmRvciB3aXRoOgotLSAgIGN1cmwgLWZzU0wgaHR0cHM6Ly9vcG0ub3BlbnJlc3R5Lm9yZy9hcGkvcGtnL3RhcmJhbGwvYW5qaWEwNTMyL2x1YS1yZXN0eS1tYXhtaW5kZGItPHY+Lm9wbS50YXIuZ3ogXAotLSAgICAgfCB0YXIgeHogLU8gJyovbGliL3Jlc3R5L21heG1pbmRkYi5sdWEnID4gcGFja2FnZXMvYWRhcHRlcnMvc3JjL2luZnJhL2x1YS9tYXhtaW5kZGIubHVhCi0tICAgIyB0aGVuIHJlLWFwcGx5IHRoaXMgaGVhZGVyIGFuZCBydW4gYGJ1biBydW4gZW1iZWQ6bHVhYAotLVtbCglDb3B5cmlnaHQgMjAxNy1ub3cgYW5qaWEgKGFuamlhMDUzMkBnbWFpbC5jb20pCgoJTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7Cgl5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCglZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKCQlodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKCVVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmUKCWRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCglXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KCVNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKCWxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgpdXQoKLS0gY29weSBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9saWxpZW4xMDEwL2x1YS1yZXN0eS1tYXhtaW5kZGIvYmxvYi9mOTY2MzNlMjQyOGY4ZjdiY2MxZTJhN2EyOGI3NDdiMzMyMzNhOGRiL3Jlc3R5L21heG1pbmRkYi5sdWEjTDUtTDEyCgpsb2NhbCBmZmkgICAgICAgICAgICAgICAgID0gcmVxdWlyZSAoJ2ZmaScpCmxvY2FsIGZmaV9uZXcgICAgICAgICAgICAgPSBmZmkubmV3CmxvY2FsIGZmaV9zdHIgICAgICAgICAgICAgPSBmZmkuc3RyaW5nCmxvY2FsIGZmaV9jYXN0ICAgICAgICAgICAgPSBmZmkuY2FzdApsb2NhbCBmZmlfZ2MgICAgICAgICAgICAgID0gZmZpLmdjCmxvY2FsIEMgICAgICAgICAgICAgICAgICAgPSBmZmkuQwoKbG9jYWwgX00gICAgPXt9Cl9NLl9WRVJTSU9OID0gJzEuMy4yJwpsb2NhbCBtdCA9IHsgX19pbmRleCA9IF9NIH0KCi0tIGNvcHkgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vbGlsaWVuMTAxMC9sdWEtcmVzdHktbWF4bWluZGRiL2Jsb2IvZjk2NjMzZTI0MjhmOGY3YmNjMWUyYTdhMjhiNzQ3YjMzMjMzYThkYi9yZXN0eS9tYXhtaW5kZGIubHVhI0wzNi1MMTI2CmZmaS5jZGVmW1sKCnR5cGVkZWYgbG9uZyBpbnQgc3NpemVfdDsKCnR5cGVkZWYgdW5zaWduZWQgaW50IG1tZGJfdWludDEyOF90IF9fYXR0cmlidXRlX18gKChfX21vZGVfXyhUSSkpKTsKCnR5cGVkZWYgc3RydWN0IE1NREJfZW50cnlfcyB7CiAgc3RydWN0IE1NREJfcyAqbW1kYjsKICB1aW50MzJfdCBvZmZzZXQ7Cn0gTU1EQl9lbnRyeV9zOwoKdHlwZWRlZiBzdHJ1Y3QgTU1EQl9sb29rdXBfcmVzdWx0X3MgewogIGJvb2wgZm91bmRfZW50cnk7CiAgTU1EQl9lbnRyeV9zIGVudHJ5OwogIHVpbnQxNl90IG5ldG1hc2s7Cn0gTU1EQl9sb29rdXBfcmVzdWx0X3M7Cgp0eXBlZGVmIHN0cnVjdCBNTURCX2VudHJ5X2RhdGFfcyB7CiAgYm9vbCBoYXNfZGF0YTsKICB1bmlvbiB7CiAgICB1aW50MzJfdCBwb2ludGVyOwogICAgY29uc3QgY2hhciAqdXRmOF9zdHJpbmc7CiAgICBkb3VibGUgZG91YmxlX3ZhbHVlOwogICAgY29uc3QgdWludDhfdCAqYnl0ZXM7CiAgICB1aW50MTZfdCB1aW50MTY7CiAgICB1aW50MzJfdCB1aW50MzI7CiAgICBpbnQzMl90IGludDMyOwogICAgdWludDY0X3QgdWludDY0OwogICAgbW1kYl91aW50MTI4X3QgdWludDEyODsKICAgIGJvb2wgYm9vbGVhbjsKICAgIGZsb2F0IGZsb2F0X3ZhbHVlOwogIH07CgogIHVpbnQzMl90IG9mZnNldDsKICB1aW50MzJfdCBvZmZzZXRfdG9fbmV4dDsKICB1aW50MzJfdCBkYXRhX3NpemU7CiAgdWludDMyX3QgdHlwZTsKfSBNTURCX2VudHJ5X2RhdGFfczsKCnR5cGVkZWYgc3RydWN0IE1NREJfZW50cnlfZGF0YV9saXN0X3MgewogIE1NREJfZW50cnlfZGF0YV9zIGVudHJ5X2RhdGE7CiAgc3RydWN0IE1NREJfZW50cnlfZGF0YV9saXN0X3MgKm5leHQ7Cn0gTU1EQl9lbnRyeV9kYXRhX2xpc3RfczsKCnR5cGVkZWYgc3RydWN0IE1NREJfZGVzY3JpcHRpb25fcyB7CiAgY29uc3QgY2hhciAqbGFuZ3VhZ2U7CiAgY29uc3QgY2hhciAqZGVzY3JpcHRpb247Cn0gTU1EQl9kZXNjcmlwdGlvbl9zOwoKdHlwZWRlZiBzdHJ1Y3QgTU1EQl9tZXRhZGF0YV9zIHsKICB1aW50MzJfdCBub2RlX2NvdW50OwogIHVpbnQxNl90IHJlY29yZF9zaXplOwogIHVpbnQxNl90IGlwX3ZlcnNpb247CiAgY29uc3QgY2hhciAqZGF0YWJhc2VfdHlwZTsKICBzdHJ1Y3QgewogICAgc2l6ZV90IGNvdW50OwogICAgY29uc3QgY2hhciAqKm5hbWVzOwogIH0gbGFuZ3VhZ2VzOwogIHVpbnQxNl90IGJpbmFyeV9mb3JtYXRfbWFqb3JfdmVyc2lvbjsKICB1aW50MTZfdCBiaW5hcnlfZm9ybWF0X21pbm9yX3ZlcnNpb247CiAgdWludDY0X3QgYnVpbGRfZXBvY2g7CiAgc3RydWN0IHsKICAgIHNpemVfdCBjb3VudDsKICAgIE1NREJfZGVzY3JpcHRpb25fcyAqKmRlc2NyaXB0aW9uczsKICB9IGRlc2NyaXB0aW9uOwp9IE1NREJfbWV0YWRhdGFfczsKCnR5cGVkZWYgc3RydWN0IE1NREJfaXB2NF9zdGFydF9ub2RlX3MgewogIHVpbnQxNl90IG5ldG1hc2s7CiAgdWludDMyX3Qgbm9kZV92YWx1ZTsKfSBNTURCX2lwdjRfc3RhcnRfbm9kZV9zOwoKdHlwZWRlZiBzdHJ1Y3QgTU1EQl9zIHsKICB1aW50MzJfdCBmbGFnczsKICBjb25zdCBjaGFyICpmaWxlbmFtZTsKICBzc2l6ZV90IGZpbGVfc2l6ZTsKICBjb25zdCB1aW50OF90ICpmaWxlX2NvbnRlbnQ7CiAgY29uc3QgdWludDhfdCAqZGF0YV9zZWN0aW9uOwogIHVpbnQzMl90IGRhdGFfc2VjdGlvbl9zaXplOwogIGNvbnN0IHVpbnQ4X3QgKm1ldGFkYXRhX3NlY3Rpb247CiAgdWludDMyX3QgbWV0YWRhdGFfc2VjdGlvbl9zaXplOwogIHVpbnQxNl90IGZ1bGxfcmVjb3JkX2J5dGVfc2l6ZTsKICB1aW50MTZfdCBkZXB0aDsKICBNTURCX2lwdjRfc3RhcnRfbm9kZV9zIGlwdjRfc3RhcnRfbm9kZTsKICBNTURCX21ldGFkYXRhX3MgbWV0YWRhdGE7Cn0gTU1EQl9zOwoKdHlwZWRlZiAgY2hhciAqIHBjaGFyOwoKTU1EQl9sb29rdXBfcmVzdWx0X3MgTU1EQl9sb29rdXBfc3RyaW5nKE1NREJfcyAqY29uc3QgbW1kYiwgICBjb25zdCBjaGFyICpjb25zdCBpcHN0ciwgaW50ICpjb25zdCBnYWlfZXJyb3IsaW50ICpjb25zdCBtbWRiX2Vycm9yKTsKaW50IE1NREJfb3Blbihjb25zdCBjaGFyICpjb25zdCBmaWxlbmFtZSwgdWludDMyX3QgZmxhZ3MsIE1NREJfcyAqY29uc3QgbW1kYik7CmludCBNTURCX2FnZXRfdmFsdWUoTU1EQl9lbnRyeV9zICpjb25zdCBzdGFydCwgIE1NREJfZW50cnlfZGF0YV9zICpjb25zdCBlbnRyeV9kYXRhLCAgY29uc3QgY2hhciAqY29uc3QgKmNvbnN0IHBhdGgpOwpjaGFyICpNTURCX3N0cmVycm9yKGludCBlcnJvcl9jb2RlKTsKCmludCBNTURCX2dldF9lbnRyeV9kYXRhX2xpc3QoTU1EQl9lbnRyeV9zICpzdGFydCwgTU1EQl9lbnRyeV9kYXRhX2xpc3RfcyAqKmNvbnN0IGVudHJ5X2RhdGFfbGlzdCk7CnZvaWQgTU1EQl9mcmVlX2VudHJ5X2RhdGFfbGlzdChNTURCX2VudHJ5X2RhdGFfbGlzdF9zICpjb25zdCBlbnRyeV9kYXRhX2xpc3QpOwp2b2lkIE1NREJfY2xvc2UoTU1EQl9zICpjb25zdCBtbWRiKTsKY29uc3QgY2hhciAqZ2FpX3N0cmVycm9yKGludCBlcnJjb2RlKTsKXV0KCi0tIGVycm9yIGNvZGVzIAotLSBodHRwczovL2dpdGh1Yi5jb20vbWF4bWluZC9saWJtYXhtaW5kZGIvYmxvYi9tYXN0ZXIvaW5jbHVkZS9tYXhtaW5kZGIuaCNMNjYKbG9jYWwgTU1EQl9TVUNDRVNTICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID0gICAwCmxvY2FsIE1NREJfRklMRV9PUEVOX0VSUk9SICAgICAgICAgICAgICAgICAgICAgICAgICA9ICAgMQpsb2NhbCBNTURCX0NPUlJVUFRfU0VBUkNIX1RSRUVfRVJST1IgICAgICAgICAgICAgICAgPSAgIDIKbG9jYWwgTU1EQl9JTlZBTElEX01FVEFEQVRBX0VSUk9SICAgICAgICAgICAgICAgICAgID0gICAzCmxvY2FsIE1NREJfSU9fRVJST1IgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9ICAgNApsb2NhbCBNTURCX09VVF9PRl9NRU1PUllfRVJST1IgICAgICAgICAgICAgICAgICAgICAgPSAgIDUKbG9jYWwgTU1EQl9VTktOT1dOX0RBVEFCQVNFX0ZPUk1BVF9FUlJPUiAgICAgICAgICAgID0gICA2CmxvY2FsIE1NREJfSU5WQUxJRF9EQVRBX0VSUk9SICAgICAgICAgICAgICAgICAgICAgICA9ICAgNwpsb2NhbCBNTURCX0lOVkFMSURfTE9PS1VQX1BBVEhfRVJST1IgICAgICAgICAgICAgICAgPSAgIDgKbG9jYWwgTU1EQl9MT09LVVBfUEFUSF9ET0VTX05PVF9NQVRDSF9EQVRBX0VSUk9SICAgID0gICA5CmxvY2FsIE1NREJfSU5WQUxJRF9OT0RFX05VTUJFUl9FUlJPUiAgICAgICAgICAgICAgICA9ICAgMTAKbG9jYWwgTU1EQl9JUFY2X0xPT0tVUF9JTl9JUFY0X0RBVEFCQVNFX0VSUk9SICAgICAgID0gICAxMQoKLS0gZGF0YSB0eXBlCi0tIGh0dHBzOi8vZ2l0aHViLmNvbS9tYXhtaW5kL2xpYm1heG1pbmRkYi9ibG9iL21hc3Rlci9pbmNsdWRlL21heG1pbmRkYi5oI0w0MApsb2NhbCBNTURCX0RBVEFfVFlQRV9FWFRFTkRFRCAgICAgICAgICAgICAgICAgICAgICAgPSAgIDAKbG9jYWwgTU1EQl9EQVRBX1RZUEVfUE9JTlRFUiAgICAgICAgICAgICAgICAgICAgICAgID0gICAxCmxvY2FsIE1NREJfREFUQV9UWVBFX1VURjhfU1RSSU5HICAgICAgICAgICAgICAgICAgICA9ICAgMgpsb2NhbCBNTURCX0RBVEFfVFlQRV9ET1VCTEUgICAgICAgICAgICAgICAgICAgICAgICAgPSAgIDMKbG9jYWwgTU1EQl9EQVRBX1RZUEVfQllURVMgICAgICAgICAgICAgICAgICAgICAgICAgID0gICA0CmxvY2FsIE1NREJfREFUQV9UWVBFX1VJTlQxNiAgICAgICAgICAgICAgICAgICAgICAgICA9ICAgNQpsb2NhbCBNTURCX0RBVEFfVFlQRV9VSU5UMzIgICAgICAgICAgICAgICAgICAgICAgICAgPSAgIDYKbG9jYWwgTU1EQl9EQVRBX1RZUEVfTUFQICAgICAgICAgICAgICAgICAgICAgICAgICAgID0gICA3CmxvY2FsIE1NREJfREFUQV9UWVBFX0lOVDMyICAgICAgICAgICAgICAgICAgICAgICAgICA9ICAgOApsb2NhbCBNTURCX0RBVEFfVFlQRV9VSU5UNjQgICAgICAgICAgICAgICAgICAgICAgICAgPSAgIDkKbG9jYWwgTU1EQl9EQVRBX1RZUEVfVUlOVDEyOCAgICAgICAgICAgICAgICAgICAgICAgID0gICAxMApsb2NhbCBNTURCX0RBVEFfVFlQRV9BUlJBWSAgICAgICAgICAgICAgICAgICAgICAgICAgPSAgIDExCmxvY2FsIE1NREJfREFUQV9UWVBFX0NPTlRBSU5FUiAgICAgICAgICAgICAgICAgICAgICA9ICAgMTIKbG9jYWwgTU1EQl9EQVRBX1RZUEVfRU5EX01BUktFUiAgICAgICAgICAgICAgICAgICAgID0gICAxMwpsb2NhbCBNTURCX0RBVEFfVFlQRV9CT09MRUFOICAgICAgICAgICAgICAgICAgICAgICAgPSAgIDE0CmxvY2FsIE1NREJfREFUQV9UWVBFX0ZMT0FUICAgICAgICAgICAgICAgICAgICAgICAgICA9ICAgMTUKCi0tIGNvcHkgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vbGlsaWVuMTAxMC9sdWEtcmVzdHktbWF4bWluZGRiL2Jsb2IvZjk2NjMzZTI0MjhmOGY3YmNjMWUyYTdhMjhiNzQ3YjMzMjMzYThkYi9yZXN0eS9tYXhtaW5kZGIubHVhI0wxMzYtTDEzOAotLSB5b3Ugc2hvdWxkIGluc3RhbGwgdGhlIGxpYm1heG1pbmRkYiB0byB5b3VyIHN5c3RlbQotLQotLSDilIDilIAgT1BFTlNISVAgTE9DQUwgTU9ESUZJQ0FUSU9OICh0aGUgb25seSBkZXZpYXRpb24gZnJvbSB1cHN0cmVhbSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACi0tIFVwc3RyZWFtIGlzIGBmZmkubG9hZCgnbGlibWF4bWluZGRiJylgLCB3aGljaCByZXNvbHZlcyB0aGUgTElOS0VSIG5hbWUKLS0gYGxpYm1heG1pbmRkYi5zb2Ag4oCUIGFuZCB0aGF0IHVudmVyc2lvbmVkIHN5bWxpbmsgc2hpcHMgaW4gdGhlIC1kZXYgcGFja2FnZSwgbm90Ci0tIHRoZSBydW50aW1lIG9uZS4gQWxwaW5lJ3MgYGxpYm1heG1pbmRkYmAgYW5kIERlYmlhbidzIGBsaWJtYXhtaW5kZGIwYCBib3RoIGdpdmUKLS0gb25seSBgbGlibWF4bWluZGRiLnNvLjBgLCBzbyB0aGUgYmFyZSBuYW1lIGZhaWxzIG9uIGEgbm9ybWFsIHJ1bnRpbWUgaW5zdGFsbCBhbmQKLS0gZ2VvIGdvZXMgc2lsZW50bHkgZGFyayAoZ2VvX2NvdW50cnkgcGNhbGxzIHRoaXMgcmVxdWlyZSkuIFRyeSB0aGUgc29uYW1lIHRvbyBzbwotLSB0aGUgcnVudGltZSBwYWNrYWdlIGFsb25lIGlzIGVub3VnaCBvbiBldmVyeSBkaXN0cm8uCmxvY2FsIG1heG0KZG8KICAgIGxvY2FsIGNhbmRpZGF0ZXMgPSB7ICdsaWJtYXhtaW5kZGInLCAnbGlibWF4bWluZGRiLnNvLjAnLCAnbGlibWF4bWluZGRiLnNvJyB9CiAgICBsb2NhbCBsYXN0X2VycgogICAgZm9yIGkgPSAxLCAjY2FuZGlkYXRlcyBkbwogICAgICAgIGxvY2FsIG9rLCBsaWIgPSBwY2FsbChmZmkubG9hZCwgY2FuZGlkYXRlc1tpXSkKICAgICAgICBpZiBvayB0aGVuIG1heG0gPSBsaWI7IGJyZWFrIGVuZAogICAgICAgIGxhc3RfZXJyID0gbGliCiAgICBlbmQKICAgIGlmIG5vdCBtYXhtIHRoZW4KICAgICAgICBlcnJvcignbGlibWF4bWluZGRiIG5vdCBsb2FkYWJsZSAodHJpZWQgJyAuLiB0YWJsZS5jb25jYXQoY2FuZGlkYXRlcywgJywgJykgLi4KICAgICAgICAgICAgICAnKTogJyAuLiB0b3N0cmluZyhsYXN0X2VyciksIDIpCiAgICBlbmQKZW5kCi0taHR0cHM6Ly9naXRodWIuY29tL21heG1pbmQvbGlibWF4bWluZGRiCmxvY2FsIG1tZGIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9IGZmaV9uZXcoJ01NREJfcycpCmxvY2FsIGluaXR0ZWQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9IGZhbHNlCgpsb2NhbCBmdW5jdGlvbiBtbWRiX3N0cmVycm9yKHJjKQogICAgcmV0dXJuIGZmaV9zdHIobWF4bS5NTURCX3N0cmVycm9yKHJjKSkKZW5kCgpsb2NhbCBmdW5jdGlvbiBnYWlfc3RyZXJyb3IocmMpCiAgICByZXR1cm4gZmZpX3N0cihDLmdhaV9zdHJlcnJvcihyYykpCmVuZAoKZnVuY3Rpb24gX00uaW5pdChkYmZpbGUpCiAgaWYgbm90IGluaXR0ZWQgdGhlbgogICAgbG9jYWwgbWF4bWluZF9yZWFkeSAgID0gbWF4bS5NTURCX29wZW4oZGJmaWxlLDAsbW1kYikKCiAgICBpZiBtYXhtaW5kX3JlYWR5IH49IE1NREJfU1VDQ0VTUyB0aGVuCiAgICAgICAgcmV0dXJuIG5pbCwgbW1kYl9zdHJlcnJvcihtYXhtaW5kX3JlYWR5KQogICAgZW5kCiAgICAKICAgIGluaXR0ZWQgPSB0cnVlCiAgICAKICAgIGZmaV9nYyhtbWRiLCBtYXhtLk1NREJfY2xvc2UpCiAgZW5kCiAgcmV0dXJuIGluaXR0ZWQKZW5kCgpmdW5jdGlvbiBfTS5pbml0dGVkKCkKICAgIHJldHVybiBpbml0dGVkCmVuZAoKLS0gaHR0cHM6Ly9naXRodWIuY29tL21heG1pbmQvbGlibWF4bWluZGRiL2Jsb2IvbWFzdGVyL3NyYy9tYXhtaW5kZGIuYyNMMTkzOCAKLS0gTE9DQUwgTU1EQl9lbnRyeV9kYXRhX2xpc3RfcyAqZHVtcF9lbnRyeV9kYXRhX2xpc3QoIEZJTEUgKnN0cmVhbSwgTU1EQl9lbnRyeV9kYXRhX2xpc3RfcyAqZW50cnlfZGF0YV9saXN0LCBpbnQgaW5kZW50LCBpbnQgKnN0YXR1cykKbG9jYWwgZnVuY3Rpb24gX2R1bXBfZW50cnlfZGF0YV9saXN0KGVudHJ5X2RhdGFfbGlzdCxzdGF0dXMpCgogIGlmIG5vdCBlbnRyeV9kYXRhX2xpc3QgdGhlbgogICAgcmV0dXJuIG5pbCxNTURCX0lOVkFMSURfREFUQV9FUlJPUgogIGVuZAogIAogIGxvY2FsIGVudHJ5X2RhdGFfaXRlbSA9IGVudHJ5X2RhdGFfbGlzdFswXS5lbnRyeV9kYXRhCiAgbG9jYWwgZGF0YV90eXBlID0gZW50cnlfZGF0YV9pdGVtLnR5cGUKICBsb2NhbCBkYXRhX3NpemUgPSBlbnRyeV9kYXRhX2l0ZW0uZGF0YV9zaXplCiAgbG9jYWwgcmVzdWx0CiAgCiAgaWYgZGF0YV90eXBlID09IE1NREJfREFUQV9UWVBFX01BUCB0aGVuCiAgICByZXN1bHQgPSB7fQogICAgCiAgICBsb2NhbCBzaXplID0gZW50cnlfZGF0YV9pdGVtLmRhdGFfc2l6ZQogICAgCiAgICBlbnRyeV9kYXRhX2xpc3QgPSBlbnRyeV9kYXRhX2xpc3RbMF0ubmV4dAogICAgCiAgICB3aGlsZShzaXplID4gMCBhbmQgZW50cnlfZGF0YV9saXN0KQogICAgZG8gCiAgICAgIGVudHJ5X2RhdGFfaXRlbSA9IGVudHJ5X2RhdGFfbGlzdFswXS5lbnRyeV9kYXRhCiAgICAgIGRhdGFfdHlwZSA9IGVudHJ5X2RhdGFfaXRlbS50eXBlCiAgICAgIGRhdGFfc2l6ZSA9IGVudHJ5X2RhdGFfaXRlbS5kYXRhX3NpemUKICAgICAgCiAgICAgIGlmIE1NREJfREFUQV9UWVBFX1VURjhfU1RSSU5HICB+PSBkYXRhX3R5cGUgdGhlbgogICAgICAgIHJldHVybiBuaWwsTU1EQl9JTlZBTElEX0RBVEFfRVJST1IKICAgICAgZW5kCiAgICAgIAogICAgICBsb2NhbCBrZXkgPSBmZmlfc3RyKGVudHJ5X2RhdGFfaXRlbS51dGY4X3N0cmluZyxkYXRhX3NpemUpCgogICAgICBpZiBub3Qga2V5IHRoZW4KICAgICAgICByZXR1cm4gbmlsLE1NREJfT1VUX09GX01FTU9SWV9FUlJPUgogICAgICBlbmQKICAgICAgCiAgICAgIGxvY2FsIHZhbAogICAgICBlbnRyeV9kYXRhX2xpc3QgPSBlbnRyeV9kYXRhX2xpc3RbMF0ubmV4dAogICAgICBlbnRyeV9kYXRhX2xpc3Qsc3RhdHVzLHZhbCA9IF9kdW1wX2VudHJ5X2RhdGFfbGlzdChlbnRyeV9kYXRhX2xpc3QpCiAgICAgIAogICAgICBpZiBzdGF0dXMgfj0gTU1EQl9TVUNDRVNTIHRoZW4KICAgICAgICByZXR1cm4gbmlsLHN0YXR1cwogICAgICBlbmQKCiAgICAgIHJlc3VsdFtrZXldID0gdmFsCiAgICAgIAogICAgICBzaXplID0gc2l6ZSAtMSAKICAgIGVuZAogICAgCgogIGVsc2VpZiBlbnRyeV9kYXRhX2xpc3RbMF0uZW50cnlfZGF0YS50eXBlID09IE1NREJfREFUQV9UWVBFX0FSUkFZIHRoZW4KICAgIGxvY2FsIHNpemUgPSBlbnRyeV9kYXRhX2xpc3RbMF0uZW50cnlfZGF0YS5kYXRhX3NpemUKICAgIHJlc3VsdCA9IHt9CgogICAgZW50cnlfZGF0YV9saXN0ID0gZW50cnlfZGF0YV9saXN0WzBdLm5leHQKICAgIAogICAgbG9jYWwgaSA9IDEKICAgIHdoaWxlKGkgPD0gc2l6ZSBhbmQgZW50cnlfZGF0YV9saXN0KQogICAgZG8KICAgICAgbG9jYWwgdmFsCiAgICAgIGVudHJ5X2RhdGFfbGlzdCxzdGF0dXMsdmFsID0gX2R1bXBfZW50cnlfZGF0YV9saXN0KGVudHJ5X2RhdGFfbGlzdCkKICAgICAgCiAgICAgIGlmIHN0YXR1cyB+PSBNTURCX1NVQ0NFU1MgdGhlbgogICAgICAgIHJldHVybiBuaWwsbmlsLHZhbAogICAgICBlbmQKICAgICAgCiAgICAgIHJlc3VsdFtpXSA9IHZhbAogICAgICBpID0gaSArIDEKICAgIGVuZAoKICAgIAogIGVsc2UKICAgIGVudHJ5X2RhdGFfaXRlbSA9IGVudHJ5X2RhdGFfbGlzdFswXS5lbnRyeV9kYXRhCiAgICBkYXRhX3R5cGUgPSBlbnRyeV9kYXRhX2l0ZW0udHlwZQogICAgZGF0YV9zaXplID0gZW50cnlfZGF0YV9pdGVtLmRhdGFfc2l6ZQogICAgCiAgICBsb2NhbCB2YWwKICAgIC0tIHN0cmluZyB0eXBlICJrZXkiOiJ2YWwiCiAgICAtLSBvdGhlciB0eXBlICJrZXkiOnZhbAogICAgLS0gZGVmYXVsdCBvdGhlciB0eXBlCiAgICBpZiBkYXRhX3R5cGUgPT0gTU1EQl9EQVRBX1RZUEVfVVRGOF9TVFJJTkcgdGhlbgogICAgICB2YWwgPSBmZmlfc3RyKGVudHJ5X2RhdGFfaXRlbS51dGY4X3N0cmluZyxkYXRhX3NpemUpCiAgICAgIGlmIG5vdCB2YWwgdGhlbgogICAgICAgIHN0YXR1cyA9IE1NREJfT1VUX09GX01FTU9SWV9FUlJPUgogICAgICAgIHJldHVybiBuaWwsc3RhdHVzCiAgICAgIGVuZAogICAgZWxzZWlmIGRhdGFfdHlwZSA9PSBNTURCX0RBVEFfVFlQRV9CWVRFUyB0aGVuCiAgICAgIHZhbCA9IGZmaV9zdHIoZmZpX2Nhc3QoJ2NoYXIgKiAnLGVudHJ5X2RhdGFfaXRlbS5ieXRlcyksZGF0YV9zaXplKQogICAgICBpZiBub3QgdmFsIHRoZW4KICAgICAgICBzdGF0dXMgPSBNTURCX09VVF9PRl9NRU1PUllfRVJST1IKICAgICAgICByZXR1cm4gbmlsLHN0YXR1cwogICAgICBlbmQKICAgIGVsc2VpZiBkYXRhX3R5cGUgPT0gTU1EQl9EQVRBX1RZUEVfRE9VQkxFIHRoZW4KICAgICAgdmFsID0gZW50cnlfZGF0YV9pdGVtLmRvdWJsZV92YWx1ZQogICAgZWxzZWlmIGRhdGFfdHlwZSA9PSBNTURCX0RBVEFfVFlQRV9GTE9BVCB0aGVuCiAgICAgIHZhbCA9IGVudHJ5X2RhdGFfaXRlbS5mbG9hdF92YWx1ZQogICAgZWxzZWlmIGRhdGFfdHlwZSA9PSBNTURCX0RBVEFfVFlQRV9VSU5UMTYgdGhlbgogICAgICB2YWwgPSBlbnRyeV9kYXRhX2l0ZW0udWludDE2CiAgICBlbHNlaWYgZGF0YV90eXBlID09IE1NREJfREFUQV9UWVBFX1VJTlQzMiB0aGVuCiAgICAgIHZhbCA9IGVudHJ5X2RhdGFfaXRlbS51aW50MzIKICAgIGVsc2VpZiBkYXRhX3R5cGUgPT0gTU1EQl9EQVRBX1RZUEVfQk9PTEVBTiB0aGVuCiAgICAgIHZhbCA9IGVudHJ5X2RhdGFfaXRlbS5ib29sZWFuCiAgICBlbHNlaWYgZGF0YV90eXBlID09IE1NREJfREFUQV9UWVBFX1VJTlQ2NCB0aGVuCiAgICAgIHZhbCA9IGVudHJ5X2RhdGFfaXRlbS51aW50NjQKICAgIGVsc2VpZiBkYXRhX3R5cGUgPT0gTU1EQl9EQVRBX1RZUEVfSU5UMzIgdGhlbgogICAgICB2YWwgPSBlbnRyeV9kYXRhX2l0ZW0uaW50MzIKICAgIGVsc2UKICAgICAgcmV0dXJuIG5pbCxNTURCX0lOVkFMSURfREFUQV9FUlJPUgogICAgZW5kCiAgICAKICAgIHJlc3VsdCA9IHZhbAogICAgZW50cnlfZGF0YV9saXN0ID0gZW50cnlfZGF0YV9saXN0WzBdLm5leHQKICBlbmQKCiAgc3RhdHVzID0gTU1EQl9TVUNDRVNTCiAgcmV0dXJuIGVudHJ5X2RhdGFfbGlzdCxzdGF0dXMscmVzdWx0CmVuZAoKZnVuY3Rpb24gX00ubG9va3VwKGlwKQoKICBpZiBub3QgaW5pdHRlZCB0aGVuCiAgICAgIHJldHVybiBuaWwsICJub3QgaW5pdGlhbGl6ZWQiCiAgZW5kCiAgCiAgLS0gY29weSBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9saWxpZW4xMDEwL2x1YS1yZXN0eS1tYXhtaW5kZGIvYmxvYi9mOTY2MzNlMjQyOGY4ZjdiY2MxZTJhN2EyOGI3NDdiMzMyMzNhOGRiL3Jlc3R5L21heG1pbmRkYi5sdWEjTDE1OS1MMTc2CiAgbG9jYWwgZ2FpX2Vycm9yID0gZmZpX25ldygnaW50WzFdJykKICBsb2NhbCBtbWRiX2Vycm9yID0gZmZpX25ldygnaW50WzFdJykKCiAgbG9jYWwgcmVzdWx0ID0gbWF4bS5NTURCX2xvb2t1cF9zdHJpbmcobW1kYixpcCxnYWlfZXJyb3IsbW1kYl9lcnJvcikKCiAgaWYgbW1kYl9lcnJvclswXSB+PSBNTURCX1NVQ0NFU1MgdGhlbgogICAgcmV0dXJuIG5pbCwnbG9va3VwIGZhaWxlZDogJyAuLiBtbWRiX3N0cmVycm9yKG1tZGJfZXJyb3JbMF0pCiAgZW5kCgogIGlmIGdhaV9lcnJvclswXSB+PSBNTURCX1NVQ0NFU1MgdGhlbgogICAgcmV0dXJuIG5pbCwnbG9va3VwIGZhaWxlZDogJyAuLiBnYWlfc3RyZXJyb3IoZ2FpX2Vycm9yWzBdKQogIGVuZAoKICBpZiB0cnVlIH49IHJlc3VsdC5mb3VuZF9lbnRyeSB0aGVuCiAgICByZXR1cm4gbmlsLCdub3QgZm91bmQnCiAgZW5kCgogIGxvY2FsIGVudHJ5X2RhdGFfbGlzdCA9IGZmaV9jYXN0KCdNTURCX2VudHJ5X2RhdGFfbGlzdF9zICoqY29uc3QnLGZmaV9uZXcoIk1NREJfZW50cnlfZGF0YV9saXN0X3MiKSkKCiAgbG9jYWwgc3RhdHVzID0gbWF4bS5NTURCX2dldF9lbnRyeV9kYXRhX2xpc3QocmVzdWx0LmVudHJ5LGVudHJ5X2RhdGFfbGlzdCkKCiAgaWYgc3RhdHVzIH49IE1NREJfU1VDQ0VTUyB0aGVuCiAgICByZXR1cm4gbmlsLCdnZXQgZW50cnkgZGF0YSBmYWlsZWQ6ICcgLi4gbW1kYl9zdHJlcnJvcihzdGF0dXMpCiAgZW5kICAKICAKICBsb2NhbCBoZWFkID0gZW50cnlfZGF0YV9saXN0WzBdIC0tIFNhdmUgc28gdGhpcyBjYW4gYmUgcGFzc2VkIHRvIGZyZWUgZm4uCiAgbG9jYWwgXyxzdGF0dXMscmVzdWx0ID0gX2R1bXBfZW50cnlfZGF0YV9saXN0KGVudHJ5X2RhdGFfbGlzdCkKICBtYXhtLk1NREJfZnJlZV9lbnRyeV9kYXRhX2xpc3QoaGVhZCkKICAKICBpZiBzdGF0dXMgfj0gTU1EQl9TVUNDRVNTIHRoZW4KICAgIHJldHVybiBuaWwsJ2R1bXAgZW50cnkgZGF0YSBmYWlsZWQ6ICcgLi4gbW1kYl9zdHJlcnJvcihzdGF0dXMpCiAgZW5kCiAgCiAgCiAgcmV0dXJuIHJlc3VsdAplbmQKCi0tIGNvcHkgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vbGlsaWVuMTAxMC9sdWEtcmVzdHktbWF4bWluZGRiL2Jsb2IvbWFzdGVyL3Jlc3R5L21heG1pbmRkYi5sdWEjTDIwOAotLSBodHRwczovL3d3dy5tYXhtaW5kLmNvbS9lbi9nZW9pcDItZGF0YWJhc2VzICB5b3Ugc2hvdWxkIGRvd25sb2FkICB0aGUgbW1kYiBmaWxlIGZyb20gbWF4bWluZAogCnJldHVybiBfTTsK",
22
+ "mgmt_api.lua": "LS0gbWdtdF9hcGkubHVhCi0tIFJFU1QgYW5hbHl0aWNzIGVuZHBvaW50cyBiYWNrZWQgYnkgbmd4LnNoYXJlZC5kaWN0LgotLSBJbnRlcm5hbCBtYW5hZ2VtZW50IHBvcnQgb25seSAoMTI3LjAuMC4xOjkxNDUpLgoKbG9jYWwgY2pzb24gPSByZXF1aXJlICJjanNvbi5zYWZlIgoKbG9jYWwgYW5hbHl0aWNzICAgID0gbmd4LnNoYXJlZC5hbmFseXRpY3MKbG9jYWwgcmVxdWVzdF9kYXRhID0gbmd4LnNoYXJlZC5yZXF1ZXN0X2RhdGEKbG9jYWwgdXJpICAgICAgICAgID0gbmd4LnZhci51cmkKCmxvY2FsIGZ1bmN0aW9uIGpzb24oZGF0YSwgY29kZSkKICAgIG5neC5zdGF0dXMgPSBjb2RlIG9yIDIwMAogICAgbmd4LmhlYWRlclsiQ29udGVudC1UeXBlIl0gPSAiYXBwbGljYXRpb24vanNvbiIKICAgIG5neC5zYXkoY2pzb24uZW5jb2RlKGRhdGEpKQogICAgcmV0dXJuIG5neC5leGl0KG5neC5zdGF0dXMpCmVuZAoKbG9jYWwgZnVuY3Rpb24gYmFkKG1zZykKICAgIHJldHVybiBqc29uKHsgZXJyb3IgPSBtc2cgfSwgNDAwKQplbmQKCi0tIOKUgOKUgCBHRVQgL2hlYWx0aCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKLS0gQmFyZSAib2siLCBOT1QgSlNPTi4gcHJvYmVNZ210KCkgaW4gYXBwcy9hcGkvc3JjL2xpYi9wcm9qZWN0LWFuYWx5dGljcy50cwotLSBhc3NlcnRzIGBib2R5LnRyaW0oKSA9PT0gIm9rImAsIHNvIGFueXRoaW5nIHJpY2hlciBoZXJlIHNpbGVudGx5IHJlcG9ydHMgZXZlcnkKLS0gZWRnZSBhcyB1bnJlYWNoYWJsZSBhbmQgc3RvcHMgdGhlIGFuYWx5dGljcyBzY3JhcGUuIFJpY2hlciBkaWFnbm9zdGljcyBnbyBvbgotLSAvc3RhdHVzIGJlbG93LgoKaWYgdXJpID09ICIvaGVhbHRoIiB0aGVuCiAgICBuZ3guc2F5KCJvayIpCiAgICByZXR1cm4gbmd4LmV4aXQoMjAwKQplbmQKCi0tIOKUgOKUgCBHRVQgL3N0YXR1cyAtIGRpYWdub3NhYmxlIGVkZ2UgaGVhbHRoIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAotLSBXaHkgdGhpcyBleGlzdHM6IGdlbyBmYWlsaW5nIGlzIElOVklTSUJMRSBvdGhlcndpc2UuIGdlb19jb3VudHJ5Lmx1YSBwY2FsbHMgaXRzCi0tIEZGSSBiaW5kaW5nIGFuZCByZXR1cm5zIG5pbCBvbiBmYWlsdXJlLCBzbyBhIG1pc3NpbmcgbGlibWF4bWluZGRiLnNvIG9yIGEKLS0gbWlzc2luZyBkYXRhYmFzZSBwcmVzZW50cyBleGFjdGx5IGxpa2UgIm5vYm9keSB2aXNpdGVkIGZyb20gYSBrbm93biBjb3VudHJ5IiDigJQKLS0gYW4gZW1wdHkgbWFwIHdpdGggbm8gZXJyb3IgYW55d2hlcmUuIFRoaXMgcmVwb3J0cyB3aGljaCBpdCBpcy4KLS0KLS0gQWxzbyByZXBvcnRzIHNoYXJlZC1kaWN0IGhlYWRyb29tOiB0aGVzZSB6b25lcyBMUlUtRVZJQ1Qgd2hlbiBmdWxsIHJhdGhlciB0aGFuCi0tIGVycm9yaW5nLCBzbyBhIGZ1bGwgYHZpc2l0b3JzYCB6b25lIHNpbGVudGx5IFVOREVSQ09VTlRTLiBDYWxsZXJzIHN1cmZhY2UgdGhhdAotLSBhcyAiYXBwcm94aW1hdGUiIGluc3RlYWQgb2YgcHJlc2VudGluZyBhbiBldmljdGlvbiBhcnRpZmFjdCBhcyBhIG1lYXN1cmVtZW50LgoKaWYgdXJpID09ICIvc3RhdHVzIiB0aGVuCiAgICBsb2NhbCBnZW9fYXZhaWxhYmxlLCBnZW9fcmVhc29uLCBnZW9fZGIgPSBmYWxzZSwgImdlb19jb3VudHJ5IG1vZHVsZSBub3QgbG9hZGFibGUiLCBuaWwKICAgIGxvY2FsIGdlb19vaywgZ2VvID0gcGNhbGwocmVxdWlyZSwgIm9wZW5zaGlwLmdlb19jb3VudHJ5IikKICAgIGlmIGdlb19vayBhbmQgZ2VvIGFuZCBnZW8uc3RhdHVzIHRoZW4KICAgICAgICBnZW9fYXZhaWxhYmxlLCBnZW9fcmVhc29uLCBnZW9fZGIgPSBnZW8uc3RhdHVzKCkKICAgIGVuZAoKICAgIGxvY2FsIGRpY3RzID0ge30KICAgIGZvciBfLCBuYW1lIGluIGlwYWlycyh7ICJhbmFseXRpY3MiLCAicmVxdWVzdF9kYXRhIiwgInJ1bGVzIiwgInJsX2NvdW50ZXJzIiwgInZpc2l0b3JzIiB9KSBkbwogICAgICAgIGxvY2FsIGQgPSBuZ3guc2hhcmVkW25hbWVdCiAgICAgICAgaWYgZCB0aGVuCiAgICAgICAgICAgIGRpY3RzW25hbWVdID0gewogICAgICAgICAgICAgICAgY2FwYWNpdHkgICA9IGQuY2FwYWNpdHkgYW5kIGQ6Y2FwYWNpdHkoKSBvciBuaWwsCiAgICAgICAgICAgICAgICBmcmVlX3NwYWNlID0gZC5mcmVlX3NwYWNlIGFuZCBkOmZyZWVfc3BhY2UoKSBvciBuaWwsCiAgICAgICAgICAgIH0KICAgICAgICBlbmQKICAgIGVuZAoKICAgIHJldHVybiBqc29uKHsKICAgICAgICBvayAgPSB0cnVlLAogICAgICAgIGdlbyA9IHsgYXZhaWxhYmxlID0gZ2VvX2F2YWlsYWJsZSwgcmVhc29uID0gZ2VvX3JlYXNvbiwgZGIgPSBnZW9fZGIgfSwKICAgICAgICBkaWN0cyA9IGRpY3RzLAogICAgfSkKZW5kCgotLSDilIDilIAgL3J1bGVzIC0gcGVyLXJvdXRlIHJ1bGVzIGNhY2hlICh3cml0dGVuIGJ5IHRoZSBBUEksIHJlYWQgYnkgcnVsZXNfZ3VhcmQpIOKUgOKUgAotLSBQT1NUIC9ydWxlcyAgYm9keTogeyAiaG9zdCI6ICIuLi4iLCAicnVsZXMiOiBbIHsgInBhdGhQcmVmaXgiOiAiLyIsICJzcGVjIjogey4uLn0gfSBdIH0KLS0gICDihpIgcmVwbGFjZXMgdGhlIHJ1bGVzZXQgZm9yIHRoYXQgaG9zdCBpbiB0aGUgYHJ1bGVzYCBzaGFyZWQgZGljdCAocmVsb2FkLWZyZWUpLgotLSAgIEFuIGVtcHR5L2Fic2VudCBgcnVsZXNgIGFycmF5IGNsZWFycyB0aGUgaG9zdC4KLS0gR0VUICAvcnVsZXM/aG9zdD0uLi4gICDihpIgdGhlIHN0b3JlZCBydWxlc2V0IChkZWJ1ZykuCi0tIERFTEVURSAvcnVsZXM/aG9zdD0uLi4g4oaSIGNsZWFyIHRoZSBob3N0J3MgcnVsZXNldC4KLS0gSGFuZGxlZCBCRUZPUkUgdGhlIGFuYWx5dGljcyBndWFyZDogcnVsZXMgdXNlIHRoZWlyIG93biBkaWN0LgotLSDilIDilIAgL2FuYWx5dGljcy9jb25maWcgLSBwZXItaG9zdCBjb2xsZWN0aW9uIHN3aXRjaGVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAotLQotLSBQT1NUIGJvZHk6IHsgImhvc3RzIjogWyB7ICJob3N0IjogIi4uLiIsICJwYXRocyI6IHRydWV8ZmFsc2UgfSwgLi4uIF0gfQotLSBHRVQgID9ob3N0PS4uLiAg4oaSIHsgaG9zdCwgcGF0aHMgfQotLQotLSBBIExJU1QsIG5vdCBhIHNpbmdsZSBob3N0OiBhIHNoYXJlZCBkaWN0IGlzIFJBTSwgc28gYSBmdWxsIG5naW54IHJlc3RhcnQgKGEgcmVib290LCBhCi0tIGBkb2NrZXIgcmVzdGFydGAsIGEgcGFja2FnZSB1cGdyYWRlKSBlbXB0aWVzIGl0IGFuZCBldmVyeSBob3N0IG9uIHRoZSBib3ggaGFzIHRvIGJlCi0tIHJlLXNldCBhdCBvbmNlLiBgb3BlbnJlc3R5IC1zIHJlbG9hZGAgcHJlc2VydmVzIHRoZSB6b25lIOKAlCB2ZXJpZmllZCDigJQgc28gb25seSBhIHJlYWwKLS0gcmVzdGFydCBsb3NlcyBpdCwgd2hpY2ggaXMgd2h5IHRoZSByZWNvbmNpbGUgYmVsb3cgZXhpc3RzIGFuZCB3aHkgaXQgbmVlZHMgdG8gY29zdCBvbmUKLS0gcm91bmQgdHJpcCBwZXIgc2VydmVyIHJhdGhlciB0aGFuIG9uZSBwZXIgZG9tYWluLgotLQotLSBMaXZlcyBpbiB0aGUgYHJ1bGVzYCB6b25lIHJhdGhlciB0aGFuIGBhbmFseXRpY3NgIGZvciB0aGUgcmVhc29uIHNpdGVfbG9nZ2VyIHN0YXRlczoKLS0gdGhlIGFuYWx5dGljcyB6b25lIGlzIGEgMjU2IE1CIGNodXJuIG9mIGNvdW50ZXJzIHVuZGVyIExSVSBwcmVzc3VyZSwgYW5kIGFuIGV2aWN0ZWQKLS0gY29uZmlnIGZsYWcgd291bGQgc2lsZW50bHkgY2hhbmdlIHdoYXQgaXMgY29sbGVjdGVkLiBUaGlzIHpvbmUgaG9sZHMgYSBmZXcgc21hbGwgdmFsdWVzLgotLQotLSBEZWxpYmVyYXRlbHkgaXRzIG93biBlbmRwb2ludCByYXRoZXIgdGhhbiBhIGZpZWxkIG9uIC9ydWxlczogdGhlIEFQSSBvbmx5IHB1c2hlcyAvcnVsZXMKLS0gZm9yIGhvc3RzIHRoYXQgSEFWRSBydWxlcywgc28gYSBwcm9qZWN0IHdpdGggbm9uZSB3b3VsZCBuZXZlciByZWNlaXZlIHRoaXMgZmxhZy4KLS0KLS0gTm8gVFRMIOKAlCBhIHNoYXJlZCBkaWN0IGlzIFJBTSBhbmQgaXMgbG9zdCBvbiByZXN0YXJ0IGVpdGhlciB3YXksIHNvIHRoZSBBUEkgcmUtcHVzaGVzIG9uCi0tIGV2ZXJ5IHJvdXRlIGFwcGx5IGFuZCB0aGUgZGF0YWJhc2Ugc3RheXMgdGhlIHNvdXJjZSBvZiB0cnV0aC4KaWYgdXJpID09ICIvYW5hbHl0aWNzL2NvbmZpZyIgdGhlbgogICAgbG9jYWwgcnVsZXMgPSBuZ3guc2hhcmVkLnJ1bGVzCiAgICBpZiBub3QgcnVsZXMgdGhlbiByZXR1cm4ganNvbih7IGVycm9yID0gInJ1bGVzIGRpY3QgdW5hdmFpbGFibGUiIH0sIDUwMykgZW5kCiAgICBsb2NhbCBtZXRob2QgPSBuZ3gucmVxLmdldF9tZXRob2QoKQoKICAgIGlmIG1ldGhvZCA9PSAiR0VUIiB0aGVuCiAgICAgICAgbG9jYWwgaG9zdCA9IG5neC52YXIuYXJnX2hvc3QKICAgICAgICBpZiBub3QgaG9zdCBvciBob3N0ID09ICIiIHRoZW4gcmV0dXJuIGJhZCgibWlzc2luZyA/aG9zdD0iKSBlbmQKICAgICAgICBob3N0ID0gaG9zdDpsb3dlcigpCiAgICAgICAgcmV0dXJuIGpzb24oeyBob3N0ID0gaG9zdCwgcGF0aHMgPSBydWxlczpnZXQoImNmZzoiIC4uIGhvc3QgLi4gIjpwYXRocyIpID09IDEgfSkKICAgIGVuZAoKICAgIGlmIG1ldGhvZCA9PSAiUE9TVCIgdGhlbgogICAgICAgIG5neC5yZXEucmVhZF9ib2R5KCkKICAgICAgICBsb2NhbCBib2R5ID0gbmd4LnJlcS5nZXRfYm9keV9kYXRhKCkKICAgICAgICBpZiBub3QgYm9keSB0aGVuIHJldHVybiBiYWQoImVtcHR5IGJvZHkiKSBlbmQKICAgICAgICBsb2NhbCBwYXlsb2FkID0gY2pzb24uZGVjb2RlKGJvZHkpCiAgICAgICAgaWYgdHlwZShwYXlsb2FkKSB+PSAidGFibGUiIG9yIHR5cGUocGF5bG9hZC5ob3N0cykgfj0gInRhYmxlIiB0aGVuCiAgICAgICAgICAgIHJldHVybiBiYWQoImV4cGVjdGVkIHsgaG9zdHM6IFsgeyBob3N0LCBwYXRocyB9IF0gfSIpCiAgICAgICAgZW5kCiAgICAgICAgbG9jYWwgYXBwbGllZCA9IDAKICAgICAgICBmb3IgXywgZW50cnkgaW4gaXBhaXJzKHBheWxvYWQuaG9zdHMpIGRvCiAgICAgICAgICAgIGlmIHR5cGUoZW50cnkpID09ICJ0YWJsZSIgYW5kIGVudHJ5Lmhvc3QgdGhlbgogICAgICAgICAgICAgICAgbG9jYWwga2V5ID0gImNmZzoiIC4uIHRvc3RyaW5nKGVudHJ5Lmhvc3QpOmxvd2VyKCkgLi4gIjpwYXRocyIKICAgICAgICAgICAgICAgIGlmIGVudHJ5LnBhdGhzID09IHRydWUgdGhlbgogICAgICAgICAgICAgICAgICAgIHJ1bGVzOnNldChrZXksIDEpCiAgICAgICAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgICAgICAgLS0gRGVsZXRlZCByYXRoZXIgdGhhbiBzZXQgdG8gMCwgc28gImFic2VudCIgaXMgdGhlIG9ubHkgb2ZmIHN0YXRlIHRoZXJlCiAgICAgICAgICAgICAgICAgICAgLS0gaXMuIFR3byByZXByZXNlbnRhdGlvbnMgb2Ygb2ZmIGlzIGhvdyBhIHJlYWRlciBlbmRzIHVwIHRyZWF0aW5nIG9uZSBvZgogICAgICAgICAgICAgICAgICAgIC0tIHRoZW0gYXMgb24g4oCUIGFuZCBhYnNlbnQgaXMgYWxzbyB3aGF0IGEgcmVzdGFydGVkIGJveCBzdGFydHMgZnJvbSwgc28KICAgICAgICAgICAgICAgICAgICAtLSBvZmYgaGFzIHRvIG1lYW4gZXhhY3RseSB0aGUgc2FtZSB0aGluZyBpbiBib3RoIGNhc2VzLgogICAgICAgICAgICAgICAgICAgIHJ1bGVzOmRlbGV0ZShrZXkpCiAgICAgICAgICAgICAgICBlbmQKICAgICAgICAgICAgICAgIGFwcGxpZWQgPSBhcHBsaWVkICsgMQogICAgICAgICAgICBlbmQKICAgICAgICBlbmQKICAgICAgICByZXR1cm4ganNvbih7IG9rID0gdHJ1ZSwgYXBwbGllZCA9IGFwcGxpZWQgfSkKICAgIGVuZAoKICAgIHJldHVybiBqc29uKHsgZXJyb3IgPSAibWV0aG9kIG5vdCBhbGxvd2VkIiB9LCA0MDUpCmVuZAoKaWYgdXJpID09ICIvcnVsZXMiIHRoZW4KICAgIGxvY2FsIHJ1bGVzID0gbmd4LnNoYXJlZC5ydWxlcwogICAgaWYgbm90IHJ1bGVzIHRoZW4gcmV0dXJuIGpzb24oeyBlcnJvciA9ICJydWxlcyBkaWN0IHVuYXZhaWxhYmxlIiB9LCA1MDMpIGVuZAogICAgbG9jYWwgbWV0aG9kID0gbmd4LnJlcS5nZXRfbWV0aG9kKCkKCiAgICBpZiBtZXRob2QgPT0gIkdFVCIgdGhlbgogICAgICAgIGxvY2FsIGhvc3QgPSBuZ3gudmFyLmFyZ19ob3N0CiAgICAgICAgaWYgbm90IGhvc3Qgb3IgaG9zdCA9PSAiIiB0aGVuIHJldHVybiBiYWQoIm1pc3NpbmcgP2hvc3Q9IikgZW5kCiAgICAgICAgaG9zdCA9IGhvc3Q6bG93ZXIoKQogICAgICAgIGxvY2FsIHJhdyA9IHJ1bGVzOmdldChob3N0KQogICAgICAgIHJldHVybiBqc29uKHsgaG9zdCA9IGhvc3QsIHJ1bGVzID0gcmF3IGFuZCBjanNvbi5kZWNvZGUocmF3KSBvciB7fSB9KQogICAgZW5kCgogICAgaWYgbWV0aG9kID09ICJERUxFVEUiIHRoZW4KICAgICAgICBsb2NhbCBob3N0ID0gbmd4LnZhci5hcmdfaG9zdAogICAgICAgIGlmIG5vdCBob3N0IG9yIGhvc3QgPT0gIiIgdGhlbiByZXR1cm4gYmFkKCJtaXNzaW5nID9ob3N0PSIpIGVuZAogICAgICAgIHJ1bGVzOmRlbGV0ZShob3N0Omxvd2VyKCkpCiAgICAgICAgcmV0dXJuIGpzb24oeyBvayA9IHRydWUgfSkKICAgIGVuZAoKICAgIGlmIG1ldGhvZCA9PSAiUE9TVCIgdGhlbgogICAgICAgIG5neC5yZXEucmVhZF9ib2R5KCkKICAgICAgICBsb2NhbCBib2R5ID0gbmd4LnJlcS5nZXRfYm9keV9kYXRhKCkKICAgICAgICBpZiBub3QgYm9keSB0aGVuIHJldHVybiBiYWQoImVtcHR5IGJvZHkiKSBlbmQKICAgICAgICBsb2NhbCBwYXlsb2FkID0gY2pzb24uZGVjb2RlKGJvZHkpCiAgICAgICAgaWYgdHlwZShwYXlsb2FkKSB+PSAidGFibGUiIG9yIG5vdCBwYXlsb2FkLmhvc3QgdGhlbgogICAgICAgICAgICByZXR1cm4gYmFkKCJleHBlY3RlZCB7IGhvc3QsIHJ1bGVzOiBbLi4uXSB9IikKICAgICAgICBlbmQKICAgICAgICBsb2NhbCBob3N0ID0gdG9zdHJpbmcocGF5bG9hZC5ob3N0KTpsb3dlcigpCiAgICAgICAgbG9jYWwgbGlzdCA9IHBheWxvYWQucnVsZXMKICAgICAgICBpZiB0eXBlKGxpc3QpIH49ICJ0YWJsZSIgb3IgI2xpc3QgPT0gMCB0aGVuCiAgICAgICAgICAgIHJ1bGVzOmRlbGV0ZShob3N0KSAgICAgICAgICAgICAgICAgLS0gZW1wdHkgc2V0ID0gY2xlYXIgdGhlIGhvc3QKICAgICAgICAgICAgcmV0dXJuIGpzb24oeyBvayA9IHRydWUsIGhvc3QgPSBob3N0LCBjb3VudCA9IDAgfSkKICAgICAgICBlbmQKICAgICAgICBsb2NhbCBvaywgZXJyID0gcnVsZXM6c2V0KGhvc3QsIGNqc29uLmVuY29kZShsaXN0KSkKICAgICAgICBpZiBub3Qgb2sgdGhlbiByZXR1cm4ganNvbih7IGVycm9yID0gInNldCBmYWlsZWQ6ICIgLi4gKGVyciBvciAiPyIpIH0sIDUwMCkgZW5kCiAgICAgICAgcmV0dXJuIGpzb24oeyBvayA9IHRydWUsIGhvc3QgPSBob3N0LCBjb3VudCA9ICNsaXN0IH0pCiAgICBlbmQKCiAgICByZXR1cm4ganNvbih7IGVycm9yID0gIm1ldGhvZCBub3QgYWxsb3dlZCIgfSwgNDA1KQplbmQKCmlmIG5vdCBhbmFseXRpY3MgdGhlbgogICAgcmV0dXJuIGpzb24oeyBlcnJvciA9ICJhbmFseXRpY3MgZGljdCB1bmF2YWlsYWJsZSIgfSwgNTAzKQplbmQKCi0tIOKUgOKUgCBQZXItbWludXRlIGNvdW50cnkgaW5kZXgg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACi0tCi0tIHNpdGVfbG9nZ2VyIHdyaXRlcyBvbmUga2V5IHBlciAoZG9tYWluLCBtaW51dGUsIGNvdW50cnkpOiBgYzp7ZG9tYWlufTp7bWlufTp7Q0N9YC4KLS0gUmVhZGluZyB0aGVtIGJhY2sgbmVlZHMga2V5IERJU0NPVkVSWSwgYW5kIGBnZXRfa2V5c2AgaXMgdGhlIG9ubHkgbWVjaGFuaXNtLgotLQotLSBUaGlzIHVzZWQgdG8gc2l0IElOU0lERSB0aGUgcGVyLW1pbnV0ZSBsb29wLCBzbyBhIDI0aCB3aW5kb3cgcmFuIHVwIHRvIDE0NDAKLS0gYGdldF9rZXlzKDEwMDAwKWAgY2FsbHMg4oCUIGVhY2ggYSBmdWxsIHNjYW4gb2YgYSAyNTYgTUIgem9uZSwgZWFjaCBob2xkaW5nIHRoZQotLSBkaWN0IGxvY2sgYWdhaW5zdCBldmVyeSB3b3JrZXIuIE9uZSBzY2FuIHBlciByZXF1ZXN0IGluc3RlYWQsIGJ1Y2tldGVkIGJ5Ci0tIG1pbnV0ZSBpbiBhIHNpbmdsZSBwYXNzOyB0aGUgbG9vcCB0aGVuIGRvZXMgcGxhaW4gdGFibGUgbG9va3Vwcy4KLS0KLS0gYGdldF9rZXlzKDApYCAoYWxsIGtleXMpIHJhdGhlciB0aGFuIDEwMDAwOiB0aGUgY2FwIHNpbGVudGx5IFRSVU5DQVRFRCwgc28gYQotLSBidXN5IGJveCBqdXN0IGxvc3QgY291bnRyaWVzIHdpdGggbm8gZXJyb3IuIFVuYm91bmRlZCBpcyBzYWZlIHByZWNpc2VseSBiZWNhdXNlCi0tIHRoaXMgaXMgbm93IGNhbGxlZCBvbmNlIOKAlCBzZWUgdGhlIGNvbW1lbnQgb24gdGhlIGNhbGwuCi0tLSBSZWFkIGFuIGVudW1lcmFibGUgc2V0IHdyaXR0ZW4gYnkgc2l0ZV9sb2dnZXIncyBpbmRleF9hZGQuCi0tCi0tIFJlcGxhY2VzIGBnZXRfa2V5c2AsIHdoaWNoIHdhbGtlZCBFVkVSWSBrZXkgaW4gdGhlIDI1NiBNQiB6b25lIGhvbGRpbmcgaXRzIGxvY2sg4oCUIGNvc3QKLS0gcHJvcG9ydGlvbmFsIHRvIHpvbmUgcG9wdWxhdGlvbiByYXRoZXIgdGhhbiB0byB0aGUgYW5zd2VyLCBvbiBhIHBhdGggY2FsbGVkIGZvdXIKLS0gZGlmZmVyZW50IHdheXMuIEhlcmUgdGhlIGNvdW50ZXIgc2F5cyBob3cgbWFueSBtZW1iZXJzIGV4aXN0IGFuZCB0aGUgc2xvdHMgbmFtZSB0aGVtLCBzbwotLSBhIHJlYWQgY29zdHMgZXhhY3RseSBhcyBtdWNoIGFzIHRoZSBkYXRhIGl0IHJldHVybnMuCi0tCi0tIE92ZXItcmVhZHMgc2xpZ2h0bHkgYnkgZGVzaWduOiBhIHNsb3QgY2FuIGJlIHdyaXR0ZW4gdHdpY2UgaWYgdHdvIHdvcmtlcnMgcmFjZSBvbiBhCi0tIG1lbWJlcidzIGZpcnN0IHNpZ2h0aW5nLCBhbmQgc2xvdHMgb3V0bGl2ZSBub3RoaW5nIChzYW1lIFRUTCBhcyB0aGVpciBjb3VudGVycykuIEJvdGgKLS0gY29sbGFwc2UgaGFybWxlc3NseSBiZWNhdXNlIHRoZSBjYWxsZXIga2V5cyByZXN1bHRzIGJ5IG1lbWJlci4KbG9jYWwgZnVuY3Rpb24gcmVhZF9pbmRleChjb3VudGVyX2tleSwgc2xvdF9wcmVmaXgpCiAgICBsb2NhbCBuID0gdG9udW1iZXIoYW5hbHl0aWNzOmdldChjb3VudGVyX2tleSkpIG9yIDAKICAgIGlmIG4gPD0gMCB0aGVuIHJldHVybiB7fSBlbmQKICAgIGxvY2FsIG91dCwgc2VlbiA9IHt9LCB7fQogICAgZm9yIGkgPSAxLCBuIGRvCiAgICAgICAgbG9jYWwgbSA9IGFuYWx5dGljczpnZXQoc2xvdF9wcmVmaXggLi4gaSkKICAgICAgICBpZiBtIGFuZCBub3Qgc2VlblttXSB0aGVuCiAgICAgICAgICAgIHNlZW5bbV0gPSB0cnVlCiAgICAgICAgICAgIG91dFsjb3V0ICsgMV0gPSBtCiAgICAgICAgZW5kCiAgICBlbmQKICAgIHJldHVybiBvdXQKZW5kCgotLS0gRHJhaW4gYSBjb3VudGVyIFdJVEhPVVQgbG9zaW5nIGEgY29uY3VycmVudCBpbmNyZW1lbnQuCi0tCi0tIFdhcyBgZ2V0YCB0aGVuIGBkZWxldGVgOiBhIHJlcXVlc3QgbGFuZGluZyBiZXR3ZWVuIHRoZSB0d28gaGFkIGl0cyBjb3VudCBkZWxldGVkIGFsb25nCi0tIHdpdGggdGhlIHZhbHVlIHRoYXQgaGFkIGp1c3QgYmVlbiByZWFkLiBTdWJ0cmFjdGluZyBleGFjdGx5IHdoYXQgd2FzIHJlYWQgbGVhdmVzIGFueQotLSBjb25jdXJyZW50IGluY3JlbWVudCBiZWhpbmQgYXMgYSByZXNpZHVhbCB0aGUgbmV4dCBzY3JhcGUgY29sbGVjdHMuCmxvY2FsIGZ1bmN0aW9uIGRyYWluKGtleSkKICAgIGxvY2FsIHYgPSB0b251bWJlcihhbmFseXRpY3M6Z2V0KGtleSkpIG9yIDAKICAgIGlmIHYgfj0gMCB0aGVuIGFuYWx5dGljczppbmNyKGtleSwgLXYpIGVuZAogICAgcmV0dXJuIHYKZW5kCgotLS0gT25lIGRheSdzIHJvbGx1cCBmb3Igb25lIGRvbWFpbiwgcmVhZCB0aHJvdWdoIGl0cyBpbmRleGVzLgotLQotLSBSZXR1cm5zIHRoZSBzYW1lIGBzdWZmaXgg4oaSIHZhbHVlYCBzaGFwZSB0aGUgb2xkIHdob2xlLXpvbmUgY2xhc3NpZmllciBwcm9kdWNlZCwgc28gYm90aAotLSBjYWxsZXJzIHN0YXllZCB1bmNoYW5nZWQ6IGJhcmUgY291bnRyeSBjb2RlcywgYHM6e2NvZGV9YCwgYHA6e3BhdGh9YCwgYHZgLCBgcG5gLgpsb2NhbCBmdW5jdGlvbiByZWFkX3JvbGx1cChkb21haW4sIGRheSkKICAgIGxvY2FsIGdwZnggPSAiZzoiIC4uIGRvbWFpbiAuLiAiOiIgLi4gZGF5IC4uICI6IgogICAgbG9jYWwgb3V0ID0ge30KCiAgICBmb3IgXywgY2MgaW4gaXBhaXJzKHJlYWRfaW5kZXgoZ3BmeCAuLiAiY24iLCBncGZ4IC4uICJjaToiKSkgZG8KICAgICAgICBvdXRbY2NdID0gdG9udW1iZXIoYW5hbHl0aWNzOmdldChncGZ4IC4uIGNjKSkgb3IgMAogICAgZW5kCiAgICBmb3IgXywgY29kZSBpbiBpcGFpcnMocmVhZF9pbmRleChncGZ4IC4uICJzbiIsIGdwZnggLi4gInNpOiIpKSBkbwogICAgICAgIG91dFsiczoiIC4uIGNvZGVdID0gdG9udW1iZXIoYW5hbHl0aWNzOmdldChncGZ4IC4uICJzOiIgLi4gY29kZSkpIG9yIDAKICAgIGVuZAogICAgLS0gYHBuYCBkb3VibGVzIGFzIHRoZSBwYXRoIGluZGV4J3MgY291bnRlciwgc28gcGF0aHMgbmVlZCBubyBzZXBhcmF0ZSBvbmUuIFdoZW4gcGF0aAogICAgLS0gY29sbGVjdGlvbiBpcyBzd2l0Y2hlZCBvZmYgZm9yIHRoaXMgaG9zdCB0aGVyZSBpcyBubyBjb3VudGVyIGFuZCB0aGlzIHJlYWRzIG5vdGhpbmcuCiAgICBmb3IgXywgcGF0aCBpbiBpcGFpcnMocmVhZF9pbmRleChncGZ4IC4uICJwbiIsIGdwZnggLi4gInBpOiIpKSBkbwogICAgICAgIG91dFsicDoiIC4uIHBhdGhdID0gdG9udW1iZXIoYW5hbHl0aWNzOmdldChncGZ4IC4uICJwOiIgLi4gcGF0aCkpIG9yIDAKICAgIGVuZAogICAgLS0gVGhlIG92ZXItY2FwIGJ1Y2tldCBoYXMgYSBmaXhlZCBuYW1lLCBzbyBpdCBpcyBub3QgaW4gdGhlIGluZGV4LgogICAgbG9jYWwgb3RoZXIgPSB0b251bWJlcihhbmFseXRpY3M6Z2V0KGdwZnggLi4gInA6b3RoZXIiKSkKICAgIGlmIG90aGVyIHRoZW4gb3V0WyJwOm90aGVyIl0gPSBvdGhlciBlbmQKCiAgICBsb2NhbCB2ID0gdG9udW1iZXIoYW5hbHl0aWNzOmdldChncGZ4IC4uICJ2IikpCiAgICBpZiB2IHRoZW4gb3V0WyJ2Il0gPSB2IGVuZAogICAgcmV0dXJuIG91dAplbmQKCmxvY2FsIGZ1bmN0aW9uIHNjYW5fY291bnRyeV9pbmRleChkb21haW4sIGZyb21fbSwgdG9fbSkKICAgIC0tIFdhbGtzIHRoZSByZXF1ZXN0ZWQgTUlOVVRFUyBhbmQgcmVhZHMgZWFjaCBvbmUncyBvd24gaW5kZXguIEJvdW5kZWQgYnkgdGhlIHdpbmRvdwogICAgLS0gKGNhcHBlZCBhdCAxNDQwIGJ5IHRoZSBjYWxsZXIpLCBub3QgYnkgaG93IG11Y2ggaXMgaW4gdGhlIHpvbmUuCiAgICBsb2NhbCBieV9taW51dGUgPSB7fQogICAgZm9yIG0gPSBmcm9tX20sIHRvX20gZG8KICAgICAgICBsb2NhbCBtcGZ4ID0gImM6IiAuLiBkb21haW4gLi4gIjoiIC4uIG0gLi4gIjoiCiAgICAgICAgbG9jYWwgY2NzID0gcmVhZF9pbmRleChtcGZ4IC4uICJuIiwgbXBmeCAuLiAiaToiKQogICAgICAgIGlmICNjY3MgPiAwIHRoZW4KICAgICAgICAgICAgbG9jYWwgc2xvdCA9IHt9CiAgICAgICAgICAgIGZvciBpID0gMSwgI2NjcyBkbwogICAgICAgICAgICAgICAgLS0gRnVsbCBrZXksIGJlY2F1c2UgdGhlIGZsdXNoIGRyYWlucyBieSBrZXkuCiAgICAgICAgICAgICAgICBzbG90W2Njc1tpXV0gPSBtcGZ4IC4uIGNjc1tpXQogICAgICAgICAgICBlbmQKICAgICAgICAgICAgYnlfbWludXRlW21dID0gc2xvdAogICAgICAgIGVuZAogICAgZW5kCiAgICByZXR1cm4gYnlfbWludXRlCmVuZAoKLS0tIFNwbGl0IGEgbmFtZXNwYWNlZCBhbmFseXRpY3Mga2V5IGludG8ga2luZCAvIGRvbWFpbiAvIG1pZCAvIHJlc3QuCi0tCi0tIExheW91dHM6IGBjOntkb21haW59OnttaW51dGV9OntDQ31gIGFuZCBgZzp7ZG9tYWlufTp7ZGF5fTp7c3VmZml4fWAuCi0tIFBvc2l0aW9uYWwsIE5PVCBhIGZ1bGwgc3BsaXQgb24gIjoiLCBiZWNhdXNlIGBzdWZmaXhgIGxlZ2l0aW1hdGVseSBjb250YWlucwotLSBjb2xvbnMg4oCUIGEgbm9ybWFsaXplZCBwYXRoIGtleSBsb29rcyBsaWtlIGBnOnguY29tOjIwMjYwODAzOnA6L3VzZXJzLzppZGAuCi0tIEhvc3RuYW1lcyBjYW5ub3QgY29udGFpbiAiOiIsIHNvIHRoZSBmaXJzdCB0aHJlZSBzZXBhcmF0b3JzIGFyZSB1bmFtYmlndW91cy4KbG9jYWwgZnVuY3Rpb24gc3BsaXRfa2V5KGspCiAgICBsb2NhbCBwMSA9IGs6ZmluZCgiOiIsIDEsIHRydWUpCiAgICBpZiBub3QgcDEgdGhlbiByZXR1cm4gbmlsIGVuZAogICAgbG9jYWwgcDIgPSBrOmZpbmQoIjoiLCBwMSArIDEsIHRydWUpCiAgICBpZiBub3QgcDIgdGhlbiByZXR1cm4gbmlsIGVuZAogICAgbG9jYWwgcDMgPSBrOmZpbmQoIjoiLCBwMiArIDEsIHRydWUpCiAgICBpZiBub3QgcDMgdGhlbgogICAgICAgIHJldHVybiBrOnN1YigxLCBwMSAtIDEpLCBrOnN1YihwMSArIDEsIHAyIC0gMSksIGs6c3ViKHAyICsgMSksIG5pbAogICAgZW5kCiAgICByZXR1cm4gazpzdWIoMSwgcDEgLSAxKSwgazpzdWIocDEgKyAxLCBwMiAtIDEpLCBrOnN1YihwMiArIDEsIHAzIC0gMSksIGs6c3ViKHAzICsgMSkKZW5kCgotLS0gUmVhZCBvbmUgbWludXRlJ3MgY291bnRyeSBjb3VudHMgb3V0IG9mIGEgc2Nhbm5lZCBpbmRleC4KLS0gQHBhcmFtIHNsb3QgdGFibGV8bmlsICBDQyDihpIgZnVsbCBkaWN0IGtleSwgZnJvbSBzY2FuX2NvdW50cnlfaW5kZXgKLS0gQHBhcmFtIGRlbCBib29sZWFuICAgICBkcmFpbiBlYWNoIGtleSBhZnRlciByZWFkaW5nIChmbHVzaCBzZW1hbnRpY3MpCi0tIEByZXR1cm4gdGFibGV8bmlsIGNvdW50cywgb3IgbmlsIHdoZW4gdGhlIG1pbnV0ZSBoYWQgbm8gY291bnRyeSBkYXRhCmxvY2FsIGZ1bmN0aW9uIHJlYWRfbWludXRlX2NvdW50cmllcyhzbG90LCBkZWwpCiAgICBpZiBub3Qgc2xvdCB0aGVuIHJldHVybiBuaWwgZW5kCiAgICBsb2NhbCBjb3VudHMsIGFueSA9IHt9LCBmYWxzZQogICAgZm9yIGNjLCBrZXkgaW4gcGFpcnMoc2xvdCkgZG8KICAgICAgICAtLSBgZHJhaW5gIHN1YnRyYWN0cyB3aGF0IGl0IHJlYWQgaW5zdGVhZCBvZiBkZWxldGluZywgc28gYSByZXF1ZXN0IGFycml2aW5nCiAgICAgICAgLS0gbWlkLWZsdXNoIGlzIG5vdCB0aHJvd24gYXdheSB3aXRoIHRoZSB2YWx1ZSB0aGF0IHdhcyBqdXN0IHJlYWQuCiAgICAgICAgY291bnRzW2NjXSA9IGRlbCBhbmQgZHJhaW4oa2V5KSBvciAodG9udW1iZXIoYW5hbHl0aWNzOmdldChrZXkpKSBvciAwKQogICAgICAgIGFueSA9IHRydWUKICAgIGVuZAogICAgcmV0dXJuIGFueSBhbmQgY291bnRzIG9yIG5pbAplbmQKCi0tIOKUgOKUgCBQT1NUIC9hbmFseXRpY3MvY29sbGVjdCAtIHRoZSBTQ1JBUEVSJ3MgZW5kcG9pbnQ6IGV2ZXJ5IGRvbWFpbiwgT05FIHNjYW4g4pSA4pSACi0tCi0tIEJvZHk6IHsgImRheSI6ICJZWVlZTU1ERCIsICJkb21haW5zIjogWyB7ICJkb21haW4iOiAieC5jb20iLCAiZnJvbSI6IE0sICJ0byI6IE0gfSBdIH0KLS0gUmV0dXJuczogeyAiZG9tYWlucyI6IHsgInguY29tIjogeyBidWNrZXRzOiBbLi4uXSwgZmx1c2hlZDogTiwgcm9sbHVwOiB7Li4ufSB9IH0gfQotLQotLSBXaHkgdGhpcyBleGlzdHMgcmF0aGVyIHRoYW4gbG9vcGluZyB0aGUgc2luZ2xlLWRvbWFpbiBlbmRwb2ludHM6Ci0tCi0tIGBnZXRfa2V5c2AgaXMgdGhlIG9ubHkga2V5LWRpc2NvdmVyeSBtZWNoYW5pc20gYSBzaGFyZWQgZGljdCBvZmZlcnMsIGl0IHdhbGtzIHRoZQotLSBXSE9MRSB6b25lLCBhbmQgaXQgaG9sZHMgdGhlIGRpY3QgbG9jayBhZ2FpbnN0IGV2ZXJ5IG5naW54IHdvcmtlciB3aGlsZSBpdCBkb2VzLgotLSBUaGUgc2NyYXBlciBuZWVkcyBib3RoIHRoZSBwZXItbWludXRlIGNvdW50cmllcyAoZmx1c2gpIGFuZCB0aGUgZGFpbHkgcm9sbHVwIGZvcgotLSBlYWNoIGRvbWFpbiwgc28gY2FsbGluZyB0aGUgcGVyLWRvbWFpbiBlbmRwb2ludHMgY29zdCAyTisxIHVuYm91bmRlZCBzY2FucyBvZiBhCi0tIDI1NiBNQiB6b25lIOKAlCBwbHVzIDJOKzEgU1NIL2V4ZWMgcm91bmQgdHJpcHMg4oCUIGV2ZXJ5IHN3ZWVwLiBPbiBhIDUwLWRvbWFpbiBib3gKLS0gdGhhdCBpcyAxMDEgZnVsbCBzY2FucyBhbmQgMTAxIHJvdW5kIHRyaXBzLCBvbiBhIHNjaGVkdWxlLCB0byBjb2xsZWN0IGRhdGEgdGhhdAotLSBvbmUgcGFzcyBhbHJlYWR5IGhhcyBpbiBoYW5kLgotLQotLSBTbzogb25lIGBnZXRfa2V5cygwKWAsIGNsYXNzaWZ5IGV2ZXJ5IGtleSBieSAoa2luZCwgZG9tYWluKSBpbiBhIHNpbmdsZSBwYXNzLCB0aGVuCi0tIHNlcnZlIGFsbCBkb21haW5zIGZyb20gdGhlIGluLW1lbW9yeSBpbmRleC4gMk4rMSBzY2FucyDihpIgMSwgYW5kIDJOKzEgcm91bmQgdHJpcHMKLS0g4oaSIDEuIFRoZSBwZXItZG9tYWluIEdFVCBlbmRwb2ludHMgc3RheSBmb3IgdGhlIFJFQUQgcGF0aCwgd2hlcmUgYSBwYWdlIHZpZXcgd2FudHMKLS0gb25lIGRvbWFpbidzIGxpdmUgdGFpbCBhbmQgYSBzaW5nbGUgc2NhbiBpcyB0aGUgaG9uZXN0IGNvc3QuCi0tCi0tIEZsdXNoIHNlbWFudGljcyBhcmUgdW5jaGFuZ2VkIGFuZCBzdGlsbCBhdG9taWMgcGVyIGtleTogbWludXRlIGNvdW50ZXJzIGFuZCB0aGVpcgotLSBjb3VudHJ5IGtleXMgYXJlIGRlbGV0ZWQgYXMgdGhleSBhcmUgcmVhZCwgc28gYSBidWNrZXQgaXMgaGFuZGVkIHRvIGV4YWN0bHkgb25lCi0tIGNhbGxlciBubyBtYXR0ZXIgaG93IG1hbnkgY29sbGVjdG9ycyByYWNlLiBUaGUgZGFpbHkgcm9sbHVwIGlzIHJlYWQtb25seSDigJQgdGhlCi0tIGVkZ2Uga2VlcHMgcnVubmluZyB0b3RhbHMgZm9yIHRoZSBkYXksIGFuZCBkZWxldGluZyB0aGVtIHdvdWxkIGxvc2UgdGhlIHRvdGFscyBmb3IKLS0gZXZlcnkgbGF0ZXIgc2NyYXBlIG9mIHRoZSBzYW1lIGRheS4KCmlmIHVyaSA9PSAiL2FuYWx5dGljcy9jb2xsZWN0IiBhbmQgbmd4LnJlcS5nZXRfbWV0aG9kKCkgPT0gIlBPU1QiIHRoZW4KICAgIG5neC5yZXEucmVhZF9ib2R5KCkKICAgIGxvY2FsIGJvZHkgPSBuZ3gucmVxLmdldF9ib2R5X2RhdGEoKQogICAgaWYgbm90IGJvZHkgdGhlbiByZXR1cm4gYmFkKCJlbXB0eSBib2R5IikgZW5kCiAgICBsb2NhbCBwYXlsb2FkID0gY2pzb24uZGVjb2RlKGJvZHkpCiAgICBpZiB0eXBlKHBheWxvYWQpIH49ICJ0YWJsZSIgb3IgdHlwZShwYXlsb2FkLmRvbWFpbnMpIH49ICJ0YWJsZSIgdGhlbgogICAgICAgIHJldHVybiBiYWQoJ2V4cGVjdGVkIHsgZGF5LCBkb21haW5zOiBbe2RvbWFpbiwgZnJvbSwgdG99XSB9JykKICAgIGVuZAoKICAgIGxvY2FsIGRheSA9IHBheWxvYWQuZGF5CiAgICBpZiB0eXBlKGRheSkgfj0gInN0cmluZyIgb3IgI2RheSB+PSA4IHRoZW4gZGF5ID0gb3MuZGF0ZSgiISVZJW0lZCIpIGVuZAoKICAgIC0tIFJlcXVlc3RlZCBkb21haW5zIOKGkiB0aGVpciBtaW51dGUgd2luZG93LiBBbHNvIHRoZSBtZW1iZXJzaGlwIHRlc3QgdGhlIHNjYW4KICAgIC0tIHVzZXMsIHNvIGFuIHVucmVxdWVzdGVkIGRvbWFpbidzIGtleXMgYXJlIHNraXBwZWQgd2l0aG91dCBhIHN0cmluZyBjb21wYXJlCiAgICAtLSBwZXIgZG9tYWluLgogICAgbG9jYWwgd2FudCwgb3JkZXIgPSB7fSwge30KICAgIGZvciBpID0gMSwgI3BheWxvYWQuZG9tYWlucyBkbwogICAgICAgIGxvY2FsIGQgPSBwYXlsb2FkLmRvbWFpbnNbaV0KICAgICAgICBpZiB0eXBlKGQpID09ICJ0YWJsZSIgYW5kIHR5cGUoZC5kb21haW4pID09ICJzdHJpbmciIGFuZCBkLmRvbWFpbiB+PSAiIiB0aGVuCiAgICAgICAgICAgIGxvY2FsIG5hbWUgPSBkLmRvbWFpbjpsb3dlcigpCiAgICAgICAgICAgIGxvY2FsIGZyb21fbSwgdG9fbSA9IHRvbnVtYmVyKGQuZnJvbSksIHRvbnVtYmVyKGQudG8pCiAgICAgICAgICAgIGlmIGZyb21fbSBhbmQgdG9fbSB0aGVuCiAgICAgICAgICAgICAgICBpZiB0b19tIC0gZnJvbV9tID4gMTQ0MCB0aGVuIHRvX20gPSBmcm9tX20gKyAxNDQwIGVuZCAtLSBjYXAgYXQgMjRoCiAgICAgICAgICAgICAgICBpZiBub3Qgd2FudFtuYW1lXSB0aGVuIG9yZGVyWyNvcmRlciArIDFdID0gbmFtZSBlbmQKICAgICAgICAgICAgICAgIHdhbnRbbmFtZV0gPSB7IGZyb20gPSBmcm9tX20sIHRvID0gdG9fbSB9CiAgICAgICAgICAgIGVuZAogICAgICAgIGVuZAogICAgZW5kCiAgICBpZiAjb3JkZXIgPT0gMCB0aGVuIHJldHVybiBqc29uKHsgZG9tYWlucyA9IHt9IH0pIGVuZAoKICAgIC0tIOKUgOKUgCBQZXItZG9tYWluIGluZGV4IHJlYWRzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAogICAgLS0KICAgIC0tIFdhcyBhIHNpbmdsZSBgZ2V0X2tleXMoMClgIHBhc3MgY2xhc3NpZnlpbmcgZXZlcnkga2V5IGluIHRoZSB6b25lLiBPbmUgc2NhbiBpcyBiZXR0ZXIKICAgIC0tIHRoYW4gMk4rMSwgYnV0IGl0IHN0aWxsIHdhbGtlZCBrZXlzIGJlbG9uZ2luZyB0byBkb21haW5zIG5vYm9keSBhc2tlZCBhYm91dCwgYW5kIGhlbGQKICAgIC0tIHRoZSB6b25lIGxvY2sgd2hpbGUgZG9pbmcgaXQuIE5vdyBlYWNoIHJlcXVlc3RlZCBkb21haW4gcmVhZHMgb25seSBpdHMgb3duIGluZGV4ZXMuCiAgICBsb2NhbCBjb3VudHJpZXMgPSB7fSAgIC0tIGRvbWFpbiDihpIgbWludXRlIOKGkiBDQyDihpIgZGljdCBrZXkKICAgIGxvY2FsIHJvbGx1cHMgPSB7fSAgICAgLS0gZG9tYWluIOKGkiBzdWZmaXgg4oaSIHZhbHVlCiAgICBmb3IgaSA9IDEsICNvcmRlciBkbwogICAgICAgIGxvY2FsIGRvbWFpbiA9IG9yZGVyW2ldCiAgICAgICAgbG9jYWwgdyA9IHdhbnRbZG9tYWluXQogICAgICAgIGNvdW50cmllc1tkb21haW5dID0gc2Nhbl9jb3VudHJ5X2luZGV4KGRvbWFpbiwgdy5mcm9tLCB3LnRvKQogICAgICAgIHJvbGx1cHNbZG9tYWluXSA9IHJlYWRfcm9sbHVwKGRvbWFpbiwgZGF5KQogICAgZW5kCgogICAgLS0g4pSA4pSAIFNlcnZlIGVhY2ggZG9tYWluIGZyb20gdGhlIGluZGV4IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAogICAgbG9jYWwgb3V0ID0ge30KICAgIGZvciBpID0gMSwgI29yZGVyIGRvCiAgICAgICAgbG9jYWwgZG9tYWluID0gb3JkZXJbaV0KICAgICAgICBsb2NhbCB3ID0gd2FudFtkb21haW5dCiAgICAgICAgbG9jYWwgY2lkeCA9IGNvdW50cmllc1tkb21haW5dIG9yIHt9CgogICAgICAgIGxvY2FsIGJ1Y2tldHMsIGZsdXNoZWQgPSB7fSwgMAogICAgICAgIGZvciBtID0gdy5mcm9tLCB3LnRvIGRvCiAgICAgICAgICAgIGxvY2FsIHAgPSAiczoiIC4uIGRvbWFpbiAuLiAiOiIgLi4gbQogICAgICAgICAgICAtLSBEcmFpbiBGSVJTVCwgdGhlbiBkZWNpZGU6IGBkcmFpbmAgcmV0dXJucyB3aGF0IGl0IHRvb2ssIGFuZCBhIGNvdW50ZXIgbGVmdAogICAgICAgICAgICAtLSBhdCAwIGJ5IGFuIGVhcmxpZXIgZmx1c2ggbXVzdCBub3QgZW1pdCBhIGJ1Y2tldCBvZiB6ZXJvcy4gKFplcm8gaXMgdHJ1dGh5IGluCiAgICAgICAgICAgIC0tIEx1YSwgc28gdGhlIG9sZCBgaWYgciB0aGVuYCB3b3VsZCBoYXZlIHN0YXJ0ZWQgZG9pbmcgZXhhY3RseSB0aGF0IHRoZSBtb21lbnQKICAgICAgICAgICAgLS0ga2V5cyBzdG9wcGVkIGJlaW5nIGRlbGV0ZWQuKQogICAgICAgICAgICBsb2NhbCByID0gZHJhaW4ocCAuLiAiOnIiKQogICAgICAgICAgICBpZiByID4gMCB0aGVuCiAgICAgICAgICAgICAgICBsb2NhbCBydF91cyA9IGRyYWluKHAgLi4gIjp0IikKICAgICAgICAgICAgICAgIGJ1Y2tldHNbI2J1Y2tldHMgKyAxXSA9IHsKICAgICAgICAgICAgICAgICAgICBtaW51dGUgICAgICAgICAgPSBtLAogICAgICAgICAgICAgICAgICAgIHJlcXVlc3RzICAgICAgICA9IHIsCiAgICAgICAgICAgICAgICAgICAgdW5pcXVlX3JlcXVlc3RzID0gZHJhaW4ocCAuLiAiOnUiKSwKICAgICAgICAgICAgICAgICAgICBiYW5kd2lkdGhfaW4gICAgPSBkcmFpbihwIC4uICI6aSIpLAogICAgICAgICAgICAgICAgICAgIGJhbmR3aWR0aF9vdXQgICA9IGRyYWluKHAgLi4gIjpvIiksCiAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2VfdGltZSAgID0gcnRfdXMgLyAxMDAwMDAwLAogICAgICAgICAgICAgICAgICAgIGNvdW50cmllcyAgICAgICA9IHJlYWRfbWludXRlX2NvdW50cmllcyhjaWR4W21dLCB0cnVlKSwKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGZsdXNoZWQgPSBmbHVzaGVkICsgMQogICAgICAgICAgICBlbmQKICAgICAgICBlbmQKCiAgICAgICAgLS0gRGFpbHkgcm9sbHVwLCBzYW1lIGtleSBjbGFzc2lmaWNhdGlvbiB0aGUgc2luZ2xlLWRvbWFpbiBlbmRwb2ludCB1c2VzLgogICAgICAgIGxvY2FsIGdlbywgcGF0aHMsIHN0YXR1c2VzLCB2aXNpdG9ycyA9IHt9LCB7fSwge30sIDAKICAgICAgICBmb3Igc3VmZml4LCB2IGluIHBhaXJzKHJvbGx1cHNbZG9tYWluXSBvciB7fSkgZG8KICAgICAgICAgICAgaWYgc3VmZml4ID09ICJ2IiB0aGVuCiAgICAgICAgICAgICAgICB2aXNpdG9ycyA9IHYKICAgICAgICAgICAgZWxzZWlmIHN1ZmZpeDpzdWIoMSwgMikgPT0gInA6IiB0aGVuCiAgICAgICAgICAgICAgICBwYXRoc1tzdWZmaXg6c3ViKDMpXSA9IHYKICAgICAgICAgICAgZWxzZWlmIHN1ZmZpeDpzdWIoMSwgMikgPT0gInM6IiB0aGVuCiAgICAgICAgICAgICAgICBzdGF0dXNlc1tzdWZmaXg6c3ViKDMpXSA9IHYKICAgICAgICAgICAgZWxzZWlmIHN1ZmZpeDptYXRjaCgiXiV1JXUkIikgdGhlbgogICAgICAgICAgICAgICAgZ2VvW3N1ZmZpeF0gPSB2CiAgICAgICAgICAgIGVuZAogICAgICAgICAgICAtLSBBbnl0aGluZyBlbHNlIChgcG5gKSBpcyBib29ra2VlcGluZzogbmV2ZXIgcmVwb3J0ZWQgYXMgYSBjb3VudHJ5LgogICAgICAgIGVuZAoKICAgICAgICBvdXRbZG9tYWluXSA9IHsKICAgICAgICAgICAgYnVja2V0cyA9IGJ1Y2tldHMsCiAgICAgICAgICAgIGZsdXNoZWQgPSBmbHVzaGVkLAogICAgICAgICAgICByb2xsdXAgID0gewogICAgICAgICAgICAgICAgZGF5ID0gZGF5LCBjb3VudHJpZXMgPSBnZW8sIHZpc2l0b3JzID0gdmlzaXRvcnMsCiAgICAgICAgICAgICAgICBwYXRocyA9IHBhdGhzLCBzdGF0dXNlcyA9IHN0YXR1c2VzLAogICAgICAgICAgICB9LAogICAgICAgIH0KICAgIGVuZAoKICAgIHJldHVybiBqc29uKHsgZGF5ID0gZGF5LCBkb21haW5zID0gb3V0IH0pCmVuZAoKLS0g4pSA4pSAIEdFVCAvYW5hbHl0aWNzIC0gbWludXRlLWJ1Y2tldCB0aW1lIHNlcmllcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKLS0gP2RvbWFpbj1leGFtcGxlLmNvbSZmcm9tPUVQT0NIX01JTiZ0bz1FUE9DSF9NSU4KCmlmIHVyaSA9PSAiL2FuYWx5dGljcyIgdGhlbgogICAgbG9jYWwgZG9tYWluID0gbmd4LnZhci5hcmdfZG9tYWluCiAgICBpZiBub3QgZG9tYWluIG9yIGRvbWFpbiA9PSAiIiB0aGVuIHJldHVybiBiYWQoIm1pc3NpbmcgP2RvbWFpbj0iKSBlbmQKICAgIGRvbWFpbiA9IGRvbWFpbjpsb3dlcigpCgogICAgbG9jYWwgZnJvbV9tID0gdG9udW1iZXIobmd4LnZhci5hcmdfZnJvbSkKICAgIGxvY2FsIHRvX20gICA9IHRvbnVtYmVyKG5neC52YXIuYXJnX3RvKQogICAgaWYgbm90IGZyb21fbSBvciBub3QgdG9fbSB0aGVuCiAgICAgICAgcmV0dXJuIGJhZCgibWlzc2luZyA/ZnJvbT0gYW5kID90bz0gKGVwb2NoIG1pbnV0ZXMpIikKICAgIGVuZAogICAgLS0gQ2FwIGF0IDI0aAogICAgaWYgdG9fbSAtIGZyb21fbSA+IDE0NDAgdGhlbiB0b19tID0gZnJvbV9tICsgMTQ0MCBlbmQKCiAgICAtLSBPTkUgc2NhbiBmb3IgdGhlIHdob2xlIHdpbmRvdyAoc2VlIHNjYW5fY291bnRyeV9pbmRleCkuCiAgICBsb2NhbCBjb3VudHJ5X2luZGV4ID0gc2Nhbl9jb3VudHJ5X2luZGV4KGRvbWFpbiwgZnJvbV9tLCB0b19tKQoKICAgIGxvY2FsIGJ1Y2tldHMgPSB7fQogICAgZm9yIG0gPSBmcm9tX20sIHRvX20gZG8KICAgICAgICBsb2NhbCBwID0gInM6IiAuLiBkb21haW4gLi4gIjoiIC4uIG0KICAgICAgICBsb2NhbCByID0gYW5hbHl0aWNzOmdldChwIC4uICI6ciIpCiAgICAgICAgaWYgciB0aGVuCiAgICAgICAgICAgIC0tIFJlc3BvbnNlIHRpbWUgc3RvcmVkIGFzIG1pY3Jvc2Vjb25kcywgY29udmVydCB0byBzZWNvbmRzIChmbG9hdCkKICAgICAgICAgICAgbG9jYWwgcnRfdXMgPSBhbmFseXRpY3M6Z2V0KHAgLi4gIjp0Iikgb3IgMAogICAgICAgICAgICBidWNrZXRzWyNidWNrZXRzICsgMV0gPSB7CiAgICAgICAgICAgICAgICBtaW51dGUgICAgICAgICAgID0gbSwKICAgICAgICAgICAgICAgIHJlcXVlc3RzICAgICAgICAgPSByLAogICAgICAgICAgICAgICAgdW5pcXVlX3JlcXVlc3RzICA9IGFuYWx5dGljczpnZXQocCAuLiAiOnUiKSBvciAwLAogICAgICAgICAgICAgICAgYmFuZHdpZHRoX2luICAgICA9IGFuYWx5dGljczpnZXQocCAuLiAiOmkiKSBvciAwLAogICAgICAgICAgICAgICAgYmFuZHdpZHRoX291dCAgICA9IGFuYWx5dGljczpnZXQocCAuLiAiOm8iKSBvciAwLAogICAgICAgICAgICAgICAgcmVzcG9uc2VfdGltZSAgICA9IHJ0X3VzIC8gMTAwMDAwMCwKICAgICAgICAgICAgICAgIGNvdW50cmllcyAgICAgICAgPSByZWFkX21pbnV0ZV9jb3VudHJpZXMoY291bnRyeV9pbmRleFttXSwgZmFsc2UpLAogICAgICAgICAgICB9CiAgICAgICAgZW5kCiAgICBlbmQKCiAgICByZXR1cm4ganNvbih7IGRvbWFpbiA9IGRvbWFpbiwgYnVja2V0cyA9IGJ1Y2tldHMgfSkKZW5kCgotLSDilIDilIAgUE9TVCAvYW5hbHl0aWNzL2ZsdXNoIC0gcmVhZCArIGRlbGV0ZSBtaW51dGUgYnVja2V0cyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKLS0gU2FtZSBhcyBHRVQgL2FuYWx5dGljcyBidXQgZGVsZXRlcyB0aGUgcmV0dXJuZWQgYnVja2V0cyBmcm9tIHNoYXJlZCBtZW1vcnkuCi0tIFVzZWQgYnkgdGhlIHNjcmFwZXIgdG8gYXRvbWljYWxseSBtb3ZlIGRhdGEgZnJvbSBPcGVuUmVzdHkg4oaSIERCLgotLSA/ZG9tYWluPWV4YW1wbGUuY29tJmZyb209RVBPQ0hfTUlOJnRvPUVQT0NIX01JTgoKaWYgdXJpID09ICIvYW5hbHl0aWNzL2ZsdXNoIiBhbmQgbmd4LnJlcS5nZXRfbWV0aG9kKCkgPT0gIlBPU1QiIHRoZW4KICAgIGxvY2FsIGRvbWFpbiA9IG5neC52YXIuYXJnX2RvbWFpbgogICAgaWYgbm90IGRvbWFpbiBvciBkb21haW4gPT0gIiIgdGhlbiByZXR1cm4gYmFkKCJtaXNzaW5nID9kb21haW49IikgZW5kCiAgICBkb21haW4gPSBkb21haW46bG93ZXIoKQoKICAgIGxvY2FsIGZyb21fbSA9IHRvbnVtYmVyKG5neC52YXIuYXJnX2Zyb20pCiAgICBsb2NhbCB0b19tICAgPSB0b251bWJlcihuZ3gudmFyLmFyZ190bykKICAgIGlmIG5vdCBmcm9tX20gb3Igbm90IHRvX20gdGhlbgogICAgICAgIHJldHVybiBiYWQoIm1pc3NpbmcgP2Zyb209IGFuZCA/dG89IChlcG9jaCBtaW51dGVzKSIpCiAgICBlbmQKICAgIGlmIHRvX20gLSBmcm9tX20gPiAxNDQwIHRoZW4gdG9fbSA9IGZyb21fbSArIDE0NDAgZW5kCgogICAgLS0gT05FIHNjYW4gZm9yIHRoZSB3aG9sZSB3aW5kb3cgKHNlZSBzY2FuX2NvdW50cnlfaW5kZXgpLgogICAgbG9jYWwgY291bnRyeV9pbmRleCA9IHNjYW5fY291bnRyeV9pbmRleChkb21haW4sIGZyb21fbSwgdG9fbSkKCiAgICBsb2NhbCBidWNrZXRzID0ge30KICAgIGxvY2FsIGZsdXNoZWQgPSAwCiAgICBmb3IgbSA9IGZyb21fbSwgdG9fbSBkbwogICAgICAgIGxvY2FsIHAgPSAiczoiIC4uIGRvbWFpbiAuLiAiOiIgLi4gbQogICAgICAgIC0tIERyYWluLCBkb24ndCBkZWxldGUg4oCUIHNlZSBgZHJhaW5gLiBBIGNvdW50ZXIgYWxyZWFkeSBhdCAwIGlzIG5vdCBhIGJ1Y2tldC4KICAgICAgICBsb2NhbCByID0gZHJhaW4ocCAuLiAiOnIiKQogICAgICAgIGlmIHIgPiAwIHRoZW4KICAgICAgICAgICAgbG9jYWwgcnRfdXMgPSBkcmFpbihwIC4uICI6dCIpCiAgICAgICAgICAgIGJ1Y2tldHNbI2J1Y2tldHMgKyAxXSA9IHsKICAgICAgICAgICAgICAgIG1pbnV0ZSAgICAgICAgICAgPSBtLAogICAgICAgICAgICAgICAgcmVxdWVzdHMgICAgICAgICA9IHIsCiAgICAgICAgICAgICAgICB1bmlxdWVfcmVxdWVzdHMgID0gZHJhaW4ocCAuLiAiOnUiKSwKICAgICAgICAgICAgICAgIGJhbmR3aWR0aF9pbiAgICAgPSBkcmFpbihwIC4uICI6aSIpLAogICAgICAgICAgICAgICAgYmFuZHdpZHRoX291dCAgICA9IGRyYWluKHAgLi4gIjpvIiksCiAgICAgICAgICAgICAgICByZXNwb25zZV90aW1lICAgID0gcnRfdXMgLyAxMDAwMDAwLAogICAgICAgICAgICAgICAgLS0gRHJhaW5lZCB0b286IHRoaXMgZW5kcG9pbnQgaGFuZHMgdGhlIG1pbnV0ZSB0byB0aGUgREIsIHNvIHRoZSBjb3VudHJ5CiAgICAgICAgICAgICAgICAtLSBrZXlzIG11c3QgZ28gd2l0aCBpdCBvciB0aGV5IHdvdWxkIGJlIGNvdW50ZWQgdHdpY2UuCiAgICAgICAgICAgICAgICBjb3VudHJpZXMgICAgICAgID0gcmVhZF9taW51dGVfY291bnRyaWVzKGNvdW50cnlfaW5kZXhbbV0sIHRydWUpLAogICAgICAgICAgICB9CiAgICAgICAgICAgIGZsdXNoZWQgPSBmbHVzaGVkICsgMQogICAgICAgIGVuZAogICAgZW5kCgogICAgcmV0dXJuIGpzb24oeyBkb21haW4gPSBkb21haW4sIGJ1Y2tldHMgPSBidWNrZXRzLCBmbHVzaGVkID0gZmx1c2hlZCB9KQplbmQKCi0tIOKUgOKUgCBHRVQgL2FuYWx5dGljcy90b3RhbHMgLSBsaWZldGltZSBjb3VudGVycyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKLS0gP2RvbWFpbj1leGFtcGxlLmNvbSAgICAgIOKGkiBzaW5nbGUgZG9tYWluCi0tIChubyBkb21haW4pICAgICAgICAgICAgICDihpIgYWxsIGtub3duIGRvbWFpbnMKCmlmIHVyaSA9PSAiL2FuYWx5dGljcy90b3RhbHMiIHRoZW4KICAgIGxvY2FsIGRvbWFpbiA9IG5neC52YXIuYXJnX2RvbWFpbgoKICAgIGlmIG5vdCBkb21haW4gb3IgZG9tYWluID09ICIiIHRoZW4KICAgICAgICAtLSBUaGUgc2NyYXBlcidzIGRvbWFpbi1kaXNjb3ZlcnkgY2FsbC4gUmVhZCBmcm9tIHRoZSBgZG5gL2BkaTpgIGluZGV4IHRoYXQKICAgICAgICAtLSBzaXRlX2xvZ2dlciBhcHBlbmRzIHRvIHRoZSBmaXJzdCB0aW1lIGl0IGV2ZXIgc2VlcyBhIGhvc3QsIHNvIHRoaXMgbm8gbG9uZ2VyCiAgICAgICAgLS0gd2Fsa3MgdGhlIHpvbmUuIEl0IHdhcyB0aGUgd29yc3QgcGxhY2UgZm9yIGEgc2NhbjogYSBjYXAgaGVyZSBzaWxlbnRseSBkcm9wcGVkCiAgICAgICAgLS0gd2hvbGUgZG9tYWlucyBmcm9tIGV2ZXJ5IHN1YnNlcXVlbnQgZmx1c2guCiAgICAgICAgbG9jYWwgZG9tYWlucyA9IHt9CiAgICAgICAgZm9yIF8sIGQgaW4gaXBhaXJzKHJlYWRfaW5kZXgoImRuIiwgImRpOiIpKSBkbwogICAgICAgICAgICAtLSBBIGhvc3QgY2FuIGJlIGluZGV4ZWQgYnV0IGhhdmUgaGFkIGl0cyBsaWZldGltZSB0b3RhbHMgZXZpY3RlZDsgcmVwb3J0IGl0CiAgICAgICAgICAgIC0tIHdpdGggemVyb3MgcmF0aGVyIHRoYW4gb21pdHRpbmcgaXQsIHNvIHRoZSBzY3JhcGVyIHN0aWxsIGFza3MgZm9yIGl0cyBidWNrZXRzLgogICAgICAgICAgICBkb21haW5zWyNkb21haW5zICsgMV0gPSB7CiAgICAgICAgICAgICAgICBkb21haW4gICAgICAgID0gZCwKICAgICAgICAgICAgICAgIHJlcXVlc3RzICAgICAgPSBhbmFseXRpY3M6Z2V0KCJ0OiIgLi4gZCAuLiAiOnIiKSBvciAwLAogICAgICAgICAgICAgICAgYmFuZHdpZHRoX2luICA9IGFuYWx5dGljczpnZXQoInQ6IiAuLiBkIC4uICI6aSIpIG9yIDAsCiAgICAgICAgICAgICAgICBiYW5kd2lkdGhfb3V0ID0gYW5hbHl0aWNzOmdldCgidDoiIC4uIGQgLi4gIjpvIikgb3IgMCwKICAgICAgICAgICAgfQogICAgICAgIGVuZAogICAgICAgIHJldHVybiBqc29uKHsgZG9tYWlucyA9IGRvbWFpbnMgfSkKICAgIGVuZAoKICAgIGRvbWFpbiA9IGRvbWFpbjpsb3dlcigpCiAgICByZXR1cm4ganNvbih7CiAgICAgICAgZG9tYWluICAgICAgICA9IGRvbWFpbiwKICAgICAgICByZXF1ZXN0cyAgICAgID0gYW5hbHl0aWNzOmdldCgidDoiIC4uIGRvbWFpbiAuLiAiOnIiKSBvciAwLAogICAgICAgIGJhbmR3aWR0aF9pbiAgPSBhbmFseXRpY3M6Z2V0KCJ0OiIgLi4gZG9tYWluIC4uICI6aSIpIG9yIDAsCiAgICAgICAgYmFuZHdpZHRoX291dCA9IGFuYWx5dGljczpnZXQoInQ6IiAuLiBkb21haW4gLi4gIjpvIikgb3IgMCwKICAgIH0pCmVuZAoKLS0g4pSA4pSAIEdFVCAvYW5hbHl0aWNzL2dlbyAtIGRhaWx5IHJvbGx1cCBmb3IgYSBkYXkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACi0tID9kb21haW49ZXhhbXBsZS5jb20mZGF5PVlZWVlNTURECi0tCi0tIE5hbWVkIC9nZW8gZm9yIGNvbXBhdGliaWxpdHk7IGl0IG5vdyByZXR1cm5zIHRoZSB3aG9sZSBkYWlseSByb2xsdXAg4oCUIGNvdW50cmllcywKLS0gZGlzdGluY3QgdmlzaXRvcnMsIHRvcCBwYXRocywgc3RhdHVzLWNvZGUgbWl4LiBPbmUgc2NhbiBzZXJ2ZXMgYWxsIGZvdXI6IHRoZXkKLS0gc2hhcmUgdGhlIGBnOntkb21haW59OntkYXl9OmAgcHJlZml4IHByZWNpc2VseSBzbyBhIHJlYWRlciBuZXZlciBuZWVkcyBhIHNlY29uZAotLSBwYXNzIG92ZXIgdGhlIHpvbmUuCi0tCi0tIEtleSBsYXlvdXQgdW5kZXIgdGhhdCBwcmVmaXggKHdyaXR0ZW4gYnkgc2l0ZV9sb2dnZXIubHVhKToKLS0gICA8Q0M+ICAgICAgICAgICAgRVhBQ1RMWSB0d28gdXBwZXJjYXNlIGxldHRlcnMg4oaSIGNvdW50cnkgaGl0IGNvdW50Ci0tICAgdiAgICAgICAgICAgICAgIGRpc3RpbmN0IHZpc2l0b3JzIHRvZGF5Ci0tICAgcDo8cGF0aD4gICAgICAgIHBhdGggY291bnRlcgotLSAgIHBuICAgICAgICAgICAgICBkaXN0aW5jdC1wYXRoIGNvdW50ZXIgKGNhcmRpbmFsaXR5IGNhcCBib29ra2VlcGluZykKLS0gICBzOjxzdGF0dXM+ICAgICAgc3RhdHVzLWNvZGUgY291bnRlcgotLQotLSBDb3VudHJ5IG1hdGNoaW5nIGlzIHN0cmljdCAoXiV1JXUkKSByYXRoZXIgdGhhbiAid2hhdGV2ZXIncyBsZWZ0IjogYSBib29ra2VlcGluZwotLSBrZXkgbGlrZSBgcG5gIHdvdWxkIG90aGVyd2lzZSBzdXJmYWNlIGFzIGEgY291bnRyeSBuYW1lZCAicG4iIGFuZCBnZXQgcGxvdHRlZC4KCmlmIHVyaSA9PSAiL2FuYWx5dGljcy9nZW8iIHRoZW4KICAgIGxvY2FsIGRvbWFpbiA9IG5neC52YXIuYXJnX2RvbWFpbgogICAgaWYgbm90IGRvbWFpbiBvciBkb21haW4gPT0gIiIgdGhlbiByZXR1cm4gYmFkKCJtaXNzaW5nID9kb21haW49IikgZW5kCiAgICBkb21haW4gPSBkb21haW46bG93ZXIoKQoKICAgIGxvY2FsIGRheSA9IG5neC52YXIuYXJnX2RheQogICAgaWYgbm90IGRheSBvciAjZGF5IH49IDggdGhlbgogICAgICAgIGRheSA9IG9zLmRhdGUoIiElWSVtJWQiKQogICAgZW5kCgogICAgLS0gUmVhZCB0aHJvdWdoIHRoZSB3cml0ZS10aW1lIGluZGV4ZXMg4oCUIHNhbWUgaGVscGVyIC9hbmFseXRpY3MvY29sbGVjdCB1c2VzLCBzbyB0aGUgdHdvCiAgICAtLSBlbmRwb2ludHMgY2Fubm90IGRpc2FncmVlIGFib3V0IHdoYXQgYSBkYXkgY29udGFpbnMuIFJlcGxhY2VzIGEgYGdldF9rZXlzKDApYCB0aGF0CiAgICAtLSB3YWxrZWQgdGhlIHdob2xlIHpvbmUgdG8gZmluZCBrZXlzIHVuZGVyIG9uZSBwcmVmaXguCiAgICBsb2NhbCByb2xsdXAgPSByZWFkX3JvbGx1cChkb21haW4sIGRheSkKICAgIGxvY2FsIGNvdW50cmllcywgcGF0aHMsIHN0YXR1c2VzID0ge30sIHt9LCB7fQogICAgbG9jYWwgdmlzaXRvcnMgPSB0b251bWJlcihyb2xsdXBbInYiXSkgb3IgMAogICAgZm9yIHN1ZmZpeCwgdiBpbiBwYWlycyhyb2xsdXApIGRvCiAgICAgICAgaWYgc3VmZml4ID09ICJ2IiBvciBzdWZmaXggPT0gInBuIiB0aGVuCiAgICAgICAgICAgIC0tIGJvb2trZWVwaW5nLCBub3QgZGF0YQogICAgICAgIGVsc2VpZiBzdWZmaXg6c3ViKDEsIDIpID09ICJwOiIgdGhlbgogICAgICAgICAgICBwYXRoc1tzdWZmaXg6c3ViKDMpXSA9IHYKICAgICAgICBlbHNlaWYgc3VmZml4OnN1YigxLCAyKSA9PSAiczoiIHRoZW4KICAgICAgICAgICAgc3RhdHVzZXNbc3VmZml4OnN1YigzKV0gPSB2CiAgICAgICAgZWxzZWlmIHN1ZmZpeDptYXRjaCgiXiV1JXUkIikgdGhlbgogICAgICAgICAgICAtLSBDb3VudHJ5IGNvZGVzIG9ubHkuIEFueXRoaW5nIGVsc2UgdW5kZXIgdGhpcyBwcmVmaXggaXMgYm9va2tlZXBpbmcsIGFuZAogICAgICAgICAgICAtLSBsZXR0aW5nIG9uZSB0aHJvdWdoIG1hZGUgYHBuYCBwbG90IGFzIGEgY291bnRyeSBhbmQgc2tldyBldmVyeSBwZXJjZW50YWdlLgogICAgICAgICAgICBjb3VudHJpZXNbc3VmZml4XSA9IHYKICAgICAgICBlbmQKICAgIGVuZAogICAgcmV0dXJuIGpzb24oewogICAgICAgIGRvbWFpbiAgICA9IGRvbWFpbiwKICAgICAgICBkYXkgICAgICAgPSBkYXksCiAgICAgICAgY291bnRyaWVzID0gY291bnRyaWVzLAogICAgICAgIHZpc2l0b3JzICA9IHZpc2l0b3JzLAogICAgICAgIHBhdGhzICAgICA9IHBhdGhzLAogICAgICAgIHN0YXR1c2VzICA9IHN0YXR1c2VzLAogICAgfSkKZW5kCgotLSDilIDilIAgR0VUIC9sb2dzL3JlY2VudCAtIHJhdyByZXF1ZXN0IHJpbmcgYnVmZmVyIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAotLSA/ZG9tYWluPWV4YW1wbGUuY29tJmxpbWl0PTUwCgppZiB1cmkgPT0gIi9sb2dzL3JlY2VudCIgdGhlbgogICAgaWYgbm90IHJlcXVlc3RfZGF0YSB0aGVuCiAgICAgICAgcmV0dXJuIGpzb24oeyBlcnJvciA9ICJyZXF1ZXN0X2RhdGEgZGljdCB1bmF2YWlsYWJsZSIgfSwgNTAzKQogICAgZW5kCgogICAgbG9jYWwgZG9tYWluID0gbmd4LnZhci5hcmdfZG9tYWluCiAgICBpZiBub3QgZG9tYWluIG9yIGRvbWFpbiA9PSAiIiB0aGVuIHJldHVybiBiYWQoIm1pc3NpbmcgP2RvbWFpbj0iKSBlbmQKICAgIGRvbWFpbiA9IGRvbWFpbjpsb3dlcigpCgogICAgbG9jYWwgbGltaXQgPSBtYXRoLm1pbih0b251bWJlcihuZ3gudmFyLmFyZ19saW1pdCkgb3IgNTAsIDEwMDApCiAgICBsb2NhbCBzZXEgICA9IHJlcXVlc3RfZGF0YTpnZXQoInJsb2c6IiAuLiBkb21haW4gLi4gIjpzZXEiKSBvciAwCiAgICBsb2NhbCBvdXQgICA9IHt9CgogICAgZm9yIGkgPSAwLCBsaW1pdCAtIDEgZG8KICAgICAgICBsb2NhbCBzbG90ID0gKHNlcSAtIGkpICUgMTAwMAogICAgICAgIGlmIHNsb3QgPCAwIHRoZW4gc2xvdCA9IHNsb3QgKyAxMDAwIGVuZAogICAgICAgIGxvY2FsIHJhdyA9IHJlcXVlc3RfZGF0YTpnZXQoInJsb2c6IiAuLiBkb21haW4gLi4gIjoiIC4uIHNsb3QpCiAgICAgICAgaWYgcmF3IHRoZW4gb3V0WyNvdXQgKyAxXSA9IHJhdyBlbmQKICAgIGVuZAoKICAgIC0tIFJldHVybiBwcmUtZW5jb2RlZCBKU09OIGVudHJpZXMgYXMgYSBKU09OIGFycmF5CiAgICBuZ3guaGVhZGVyWyJDb250ZW50LVR5cGUiXSA9ICJhcHBsaWNhdGlvbi9qc29uIgogICAgbmd4LnByaW50KCJbIikKICAgIGZvciBpZHgsIGVudHJ5IGluIGlwYWlycyhvdXQpIGRvCiAgICAgICAgaWYgaWR4ID4gMSB0aGVuIG5neC5wcmludCgiLCIpIGVuZAogICAgICAgIG5neC5wcmludChlbnRyeSkKICAgIGVuZAogICAgbmd4LnNheSgiXSIpCiAgICByZXR1cm4gbmd4LmV4aXQoMjAwKQplbmQKCi0tIOKUgOKUgCA0MDQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACnJldHVybiBqc29uKHsgZXJyb3IgPSAibm90IGZvdW5kIiB9LCA0MDQpCg==",
23
+ "pipe_log.lua": "LS0gcGlwZV9sb2cubHVhCi0tIFB1c2ggcmVxdWVzdCBsb2cgaW50byBzaGFyZWQgZGljdCBxdWV1ZSBsb2dfcGlwZTpxOntob3N0fSBmb3IgL3N0cmVhbSBTU0UuCi0tIFBheWxvYWQgc2hhcGUgbWF0Y2hlcyByZXF1ZXN0TG9nZ2VyLmpzIChpZCwgaXAsIGNvdW50cnkgd2hlbiBrbm93biwKLS0gdGltZXN0YW1wLCBkYXRlLCB1cmksIG1ldGhvZCwgc3RhdHVzLCB1c2VyQWdlbnQsIHJlcXVlc3RTaXplLCByZXNwb25zZVNpemUsCi0tIHJlc3BvbnNlVGltZSkuCi0tCi0tIENhbGxlZCB2aWEgbmd4LnRpbWVyLmF0IGZyb20gc2l0ZV9sb2dnZXIgKHByZW1hdHVyZSBpcyBmaXJzdCBhcmcpLgoKbG9jYWwgY2pzb24gPSByZXF1aXJlICJjanNvbi5zYWZlIgoKbG9jYWwgU1VCX1BSRUZJWCAgID0gImxvZ19waXBlOnN1YjoiCmxvY2FsIFFVRVVFX1BSRUZJWCA9ICJsb2dfcGlwZTpxOiIKbG9jYWwgUVVFVUVfTUFYX0xFTiA9IDIwMDAKCi0tIFNBRkUgTE9BRDogR2VvSVAgKHBlci13b3JrZXIsIGNhY2hlZCBieSByZXF1aXJlKQpsb2NhbCBnZW9fb2ssIGdlbyA9IHBjYWxsKHJlcXVpcmUsICJvcGVuc2hpcC5nZW9fY291bnRyeSIpCmlmIG5vdCBnZW9fb2sgdGhlbiBnZW8gPSBuaWwgZW5kCgotLSBSZXVzZWQgcGF5bG9hZCB0YWJsZSBwZXIgd29ya2VyIChjbGVhcmVkIGFmdGVyIGVuY29kZSB0byBhdm9pZCBHQyBwcmVzc3VyZSkKbG9jYWwgcGF5bG9hZCA9IHt9CgotLSBgY2NgIGlzIHRoZSBjb3VudHJ5IHNpdGVfbG9nZ2VyIGFscmVhZHkgcmVzb2x2ZWQgZm9yIHRoaXMgcmVxdWVzdC4gUGFzc2VkIGluIHJhdGhlcgotLSB0aGFuIGxvb2tlZCB1cCBhZ2Fpbjogb25lIG1tZGIgaGl0IHBlciByZXF1ZXN0LCBhbmQgdGhlIGxpdmUgZnJhbWUgY2FuIG5ldmVyIGRpc2FncmVlCi0tIHdpdGggdGhlIHJvbGx1cCBvciB0aGUgcmluZyBidWZmZXIgYWJvdXQgd2hlcmUgYSBoaXQgY2FtZSBmcm9tLgpsb2NhbCBmdW5jdGlvbiBwaXBlX3JlcXVlc3RfbG9nKHByZW1hdHVyZSwgaG9zdCwgaXAsIHRzLCB1YSwgdXJpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcV9sZW4sIGJ5dGVzLCBydCwgbWV0aG9kLCBzdGF0dXMsIGNjKQogICAgaWYgcHJlbWF0dXJlIHRoZW4gcmV0dXJuIGVuZAoKICAgIGxvY2FsIHNoID0gbmd4LnNoYXJlZC5yZXF1ZXN0X2RhdGEKICAgIGlmIG5vdCBzaCB0aGVuIHJldHVybiBlbmQKCiAgICAtLSBEb3VibGUtY2hlY2sgc3Vic2NyaWJlciBpcyBzdGlsbCBhY3RpdmUgKGd1YXJkIGFnYWluc3QgcmFjZSkKICAgIGlmIG5vdCBzaDpnZXQoU1VCX1BSRUZJWCAuLiBob3N0KSB0aGVuIHJldHVybiBlbmQKCiAgICBwY2FsbChmdW5jdGlvbigpCiAgICAgICAgLS0gRmFsbHMgYmFjayB0byBpdHMgb3duIGxvb2t1cCBvbmx5IGlmIHRoZSBjYWxsZXIgcGFzc2VkIG5vdGhpbmcsIHdoaWNoIGhhcHBlbnMKICAgICAgICAtLSB3aGVuIGEgYm94IGlzIG1pZC1kZXBsb3kgYW5kIHN0aWxsIGhhcyB0aGUgcHJldmlvdXMgc2l0ZV9sb2dnZXIuCiAgICAgICAgbG9jYWwgY291bnRyeSA9IGNjCiAgICAgICAgaWYgKG5vdCBjb3VudHJ5IG9yIGNvdW50cnkgPT0gIiIpIGFuZCBnZW8gYW5kIGdlby5nZXRfY291bnRyeV9jb2RlIHRoZW4KICAgICAgICAgICAgbG9jYWwgb2tfY2MsIHJlcyA9IHBjYWxsKGdlby5nZXRfY291bnRyeV9jb2RlLCBpcCkKICAgICAgICAgICAgaWYgb2tfY2MgdGhlbiBjb3VudHJ5ID0gcmVzIGVuZAogICAgICAgIGVuZAoKICAgICAgICBwYXlsb2FkLmlkICAgICAgICAgICA9IHN0cmluZy5mb3JtYXQoIiUuM2YtJWQiLCB0cywgbWF0aC5yYW5kb20oMTAwMDAsIDk5OTk5KSkKICAgICAgICBwYXlsb2FkLmhvc3QgICAgICAgICA9IGhvc3QKICAgICAgICBwYXlsb2FkLmlwICAgICAgICAgICA9IGlwCiAgICAgICAgaWYgY291bnRyeSBhbmQgdHlwZShjb3VudHJ5KSA9PSAic3RyaW5nIiBhbmQgY291bnRyeSB+PSAiIiB0aGVuCiAgICAgICAgICAgIHBheWxvYWQuY291bnRyeSA9IGNvdW50cnkKICAgICAgICBlbmQKICAgICAgICBwYXlsb2FkLnRpbWVzdGFtcCAgICA9IHRzCiAgICAgICAgcGF5bG9hZC5kYXRlICAgICAgICAgPSBvcy5kYXRlKCIhJVktJW0tJWQgJUg6JU06JVMiLCB0cykKICAgICAgICBwYXlsb2FkLnVyaSAgICAgICAgICA9IHVyaQogICAgICAgIHBheWxvYWQubWV0aG9kICAgICAgID0gbWV0aG9kIG9yICJHRVQiCiAgICAgICAgcGF5bG9hZC5zdGF0dXMgICAgICAgPSB0b251bWJlcihzdGF0dXMpIG9yIDAKICAgICAgICBwYXlsb2FkLnVzZXJBZ2VudCAgICA9IHVhIG9yICIiCiAgICAgICAgcGF5bG9hZC5yZXF1ZXN0U2l6ZSAgPSB0b251bWJlcihyZXFfbGVuKSBvciAwCiAgICAgICAgcGF5bG9hZC5yZXNwb25zZVNpemUgPSB0b251bWJlcihieXRlcykgb3IgMAogICAgICAgIHBheWxvYWQucmVzcG9uc2VUaW1lID0gdG9udW1iZXIocnQpIG9yIDAKCiAgICAgICAgbG9jYWwgYm9keSA9IGNqc29uLmVuY29kZShwYXlsb2FkKQoKICAgICAgICAtLSBDbGVhciBwYXlsb2FkIHRhYmxlIGZvciBuZXh0IHJldXNlCiAgICAgICAgZm9yIGsgaW4gcGFpcnMocGF5bG9hZCkgZG8gcGF5bG9hZFtrXSA9IG5pbCBlbmQKCiAgICAgICAgaWYgbm90IGJvZHkgdGhlbiByZXR1cm4gZW5kCgogICAgICAgIGxvY2FsIHFrZXkgPSBRVUVVRV9QUkVGSVggLi4gaG9zdAogICAgICAgIHNoOmxwdXNoKHFrZXksIGJvZHkpCiAgICAgICAgaWYgc2g6bGxlbihxa2V5KSA+IFFVRVVFX01BWF9MRU4gdGhlbgogICAgICAgICAgICBzaDpycG9wKHFrZXkpCiAgICAgICAgZW5kCiAgICBlbmQpCmVuZAoKcmV0dXJuIHsKICAgIHBpcGVfcmVxdWVzdF9sb2cgPSBwaXBlX3JlcXVlc3RfbG9nLAp9Cg==",
24
+ "pipe_stream.lua": "LS0gcGlwZV9zdHJlYW0ubHVhCi0tIGNvbnRlbnRfYnlfbHVhOiBTU0UgZW5kcG9pbnQgZm9yIHJlYWwtdGltZSByZXF1ZXN0IGxvZyBzdHJlYW1pbmcuCi0tIEdFVCAvbG9ncy9zdHJlYW0/ZG9tYWluPWV4YW1wbGUuY29tCi0tIEludGVybmFsIG9ubHkgLSAxMjcuMC4wLjE6OTE0NQoKbG9jYWwgc2ggPSBuZ3guc2hhcmVkLnJlcXVlc3RfZGF0YQppZiBub3Qgc2ggdGhlbgogICAgbmd4LnN0YXR1cyA9IDUwMwogICAgbmd4LnNheSgic2hhcmVkIGRpY3QgdW5hdmFpbGFibGUiKQogICAgcmV0dXJuIG5neC5leGl0KDUwMykKZW5kCgpsb2NhbCBkb21haW4gPSBuZ3gudmFyLmFyZ19kb21haW4KaWYgbm90IGRvbWFpbiBvciBkb21haW4gPT0gIiIgdGhlbgogICAgbmd4LnN0YXR1cyA9IDQwMAogICAgbmd4LnNheSgibWlzc2luZyA/ZG9tYWluPSBwYXJhbWV0ZXIiKQogICAgcmV0dXJuIG5neC5leGl0KDQwMCkKZW5kCgpkb21haW4gPSBkb21haW46bG93ZXIoKQppZiBkb21haW46c3ViKDEsIDQpID09ICJ3d3cuIiB0aGVuIGRvbWFpbiA9IGRvbWFpbjpzdWIoNSkgZW5kCgpsb2NhbCBTVUJfS0VZICAgPSAibG9nX3BpcGU6c3ViOiIgLi4gZG9tYWluCmxvY2FsIFFVRVVFX0tFWSA9ICJsb2dfcGlwZTpxOiIgICAuLiBkb21haW4KCi0tIENsZWFyIHN0YWxlIHF1ZXVlIGVudHJpZXMsIG1hcmsgc3Vic2NyaWJlciBhY3RpdmUKc2g6ZGVsZXRlKFFVRVVFX0tFWSkKc2g6c2V0KFNVQl9LRVksIHRydWUsIDMwKQoKbmd4LmhlYWRlclsiQ29udGVudC1UeXBlIl0gICAgICA9ICJ0ZXh0L2V2ZW50LXN0cmVhbSIKbmd4LmhlYWRlclsiQ2FjaGUtQ29udHJvbCJdICAgICA9ICJuby1jYWNoZSwgbm8tc3RvcmUiCm5neC5oZWFkZXJbIkNvbm5lY3Rpb24iXSAgICAgICAgPSAia2VlcC1hbGl2ZSIKbmd4LmhlYWRlclsiWC1BY2NlbC1CdWZmZXJpbmciXSA9ICJubyIKCi0tIFNlbmQgaW5pdGlhbCBTU0UgY29tbWVudCBzbyB0aGUgZmlyc3QgZmx1c2ggaGFzIGRhdGEuCi0tIFdpdGhvdXQgdGhpcywgbmd4LmZsdXNoIG9uIGFuIGVtcHR5IGJ1ZmZlciBzZW5kcyBjaHVua2VkLUVPRiAoMFxyXG5cclxuKQotLSBhbmQgdGVybWluYXRlcyB0aGUgcmVzcG9uc2UgaW1tZWRpYXRlbHkuCm5neC5wcmludCgiOiBjb25uZWN0ZWRcblxuIikKaWYgbm90IG5neC5mbHVzaCh0cnVlKSB0aGVuCiAgICBzaDpkZWxldGUoU1VCX0tFWSkKICAgIHJldHVybgplbmQKCmxvY2FsIHN0YXJ0ZWQgID0gbmd4Lm5vdygpCmxvY2FsIGxhc3RfaGIgID0gc3RhcnRlZApsb2NhbCBsYXN0X3JlZiA9IHN0YXJ0ZWQKCndoaWxlIHRydWUgZG8KICAgIC0tIE1heCAxIGhvdXIgcGVyIGNvbm5lY3Rpb24KICAgIGlmIG5neC5ub3coKSAtIHN0YXJ0ZWQgPiAzNjAwIHRoZW4KICAgICAgICBzaDpkZWxldGUoU1VCX0tFWSkKICAgICAgICByZXR1cm4KICAgIGVuZAoKICAgIC0tIERyYWluIHVwIHRvIDEwMCBxdWV1ZWQgZW50cmllcyBwZXIgY3ljbGUKICAgIGxvY2FsIHNlbnQgPSAwCiAgICB3aGlsZSBzZW50IDwgMTAwIGRvCiAgICAgICAgbG9jYWwgZW50cnkgPSBzaDpycG9wKFFVRVVFX0tFWSkKICAgICAgICBpZiBub3QgZW50cnkgdGhlbiBicmVhayBlbmQKICAgICAgICBuZ3gucHJpbnQoImV2ZW50OiByZXF1ZXN0XG5kYXRhOiAiLCBlbnRyeSwgIlxuXG4iKQogICAgICAgIHNlbnQgPSBzZW50ICsgMQogICAgZW5kCgogICAgaWYgc2VudCA+IDAgdGhlbgogICAgICAgIGlmIG5vdCBuZ3guZmx1c2godHJ1ZSkgdGhlbgogICAgICAgICAgICBzaDpkZWxldGUoU1VCX0tFWSkKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgZW5kCiAgICBlbmQKCiAgICBsb2NhbCBub3cgPSBuZ3gubm93KCkKCiAgICAtLSBIZWFydGJlYXQgZXZlcnkgMTVzCiAgICBpZiBub3cgLSBsYXN0X2hiID4gMTUgdGhlbgogICAgICAgIG5neC5wcmludCgiOiBwaW5nXG5cbiIpCiAgICAgICAgaWYgbm90IG5neC5mbHVzaCh0cnVlKSB0aGVuCiAgICAgICAgICAgIHNoOmRlbGV0ZShTVUJfS0VZKQogICAgICAgICAgICByZXR1cm4KICAgICAgICBlbmQKICAgICAgICBsYXN0X2hiID0gbm93CiAgICBlbmQKCiAgICAtLSBSZWZyZXNoIHN1YnNjcmliZXIgVFRMIGV2ZXJ5IDEwcwogICAgaWYgbm93IC0gbGFzdF9yZWYgPiAxMCB0aGVuCiAgICAgICAgc2g6c2V0KFNVQl9LRVksIHRydWUsIDMwKQogICAgICAgIGxhc3RfcmVmID0gbm93CiAgICBlbmQKCiAgICBuZ3guc2xlZXAoMC4wNSkKZW5kCg==",
25
+ "rules_guard.lua": "LS0gcnVsZXNfZ3VhcmQubHVhCi0tIGFjY2Vzc19ieV9sdWEgZHJpdmVyOiBlbmZvcmNlIHBlci1yb3V0ZSBydWxlcyAobWV0aG9kIMK3IElQL0NJRFIgYWxsb3ctZGVueSDCtwotLSBjb3VudHJ5IGFsbG93L2JhbiDCtyBiYWQgdXNlci1hZ2VudCDCtyBob3RsaW5rIMK3IHJhdGUtbGltaXQpIGZvciB0aGUgcmVxdWVzdCdzCi0tIGhvc3QuIFJ1bGVzIGFyZSBwdXNoZWQgcmVsb2FkLWZyZWUgYnkgbWdtdF9hcGkgYFBPU1QgL3J1bGVzYDsgdGhlIERCCi0tIGByb3V0ZV9ydWxlYCB0YWJsZSBpcyB0aGUgc291cmNlIG9mIHRydXRoLiBBbGwgcGFyc2luZy9jb21waWxpbmcvbWF0Y2hpbmcKLS0gbGl2ZXMgaW4gb3BlbnNoaXAucnVsZXNfbGliIChsb2FkZWQgT05DRSBwZXIgd29ya2VyKSDigJQgdGhpcyBmaWxlIGlzIHJlLXJ1bgotLSBldmVyeSByZXF1ZXN0IHNvIGl0IHN0YXlzIG1pbmltYWwuIFNlZSBydWxlc19saWIubHVhIGZvciB0aGUgY29tcGlsZWQgc2hhcGUuCi0tCi0tIEVuZm9yY2VtZW50IHVzZXMgdGhlIGNvbm5lY3RpbmcgcGVlciAobmd4LnZhci5yZW1vdGVfYWRkcik7IGZyb250IGEgcmVhbF9pcAotLSBjb25maWcgaWYgYmVoaW5kIGEgdHJ1c3RlZCBwcm94eS4gTm8gdXNlci1zdXBwbGllZCB2YWx1ZSBpcyBldmVyIHVzZWQgYXMgYQotLSBMdWEgcGF0dGVybiBvciB3cml0dGVuIGludG8gYSByZXNwb25zZSBoZWFkZXIuCgpsb2NhbCBydWxlcyA9IG5neC5zaGFyZWQucnVsZXMKaWYgbm90IHJ1bGVzIHRoZW4gcmV0dXJuIGVuZAoKLS0gUmF0ZS1saW1pdCBjb3VudGVycyBsaXZlIGluIHRoZWlyIE9XTiBkaWN0IHNvIGEgaGlnaC1jYXJkaW5hbGl0eSBmbG9vZCAoYSBuZXcKLS0gcmw6IGtleSBwZXIgc291cmNlIElQIHBlciBzZWNvbmQpIGNhbid0IExSVS1ldmljdCB0aGUgcnVsZXNldHMgYW5kIHNpbGVudGx5Ci0tIGRpc2FibGUgZW5mb3JjZW1lbnQuIEZhbGwgYmFjayB0byBgcnVsZXNgIG9uIGEgYm94IHdob3NlIGNvbmZpZyBwcmVkYXRlcyB0aGUKLS0gc2VwYXJhdGUgZGljdCAoc3RpbGwgd29ya3MsIGp1c3Qgc2hhcmVzIHRoZSB6b25lIHVudGlsIHRoZSBuZXh0IHJlbG9hZCkuCmxvY2FsIGNvdW50ZXJzID0gbmd4LnNoYXJlZC5ybF9jb3VudGVycyBvciBydWxlcwoKbG9jYWwgaG9zdCA9IG5neC52YXIuaG9zdAppZiBub3QgaG9zdCB0aGVuIHJldHVybiBlbmQKCmxvY2FsIHJhdyA9IHJ1bGVzOmdldChob3N0KQppZiBub3QgcmF3IHRoZW4gcmV0dXJuIGVuZCAgICAgICAgICAtLSBmYXN0IHBhdGg6IG5vdGhpbmcgY29uZmlndXJlZCBmb3IgdGhpcyBob3N0Cgpsb2NhbCBsaWIgPSByZXF1aXJlICJvcGVuc2hpcC5ydWxlc19saWIiCmxvY2FsIGVudHJpZXMgPSBsaWIuZ2V0KGhvc3QsIHJhdykKbG9jYWwgbiA9ICNlbnRyaWVzCmlmIG4gPT0gMCB0aGVuIHJldHVybiBlbmQKCi0tIOKUgOKUgCBMb25nZXN0IG1hdGNoaW5nIHBhdGhQcmVmaXggd2lucyDilIDilIAKbG9jYWwgdXJpID0gbmd4LnZhci51cmkgb3IgIi8iCmxvY2FsIGNob3NlbiwgY2hvc2VuX2xlbiA9IG5pbCwgLTEKZm9yIGkgPSAxLCBuIGRvCiAgICBsb2NhbCBlID0gZW50cmllc1tpXQogICAgbG9jYWwgcCA9IGUucGF0aFByZWZpeAogICAgaWYgcCA9PSBuaWwgb3IgcCA9PSAiIiBvciBwID09ICIvIiB0aGVuCiAgICAgICAgaWYgY2hvc2VuX2xlbiA8IDAgdGhlbiBjaG9zZW4sIGNob3Nlbl9sZW4gPSBlLCAwIGVuZAogICAgZWxzZWlmIHVyaSA9PSBwIG9yIHN0cmluZy5zdWIodXJpLCAxLCAjcCkgPT0gcCB0aGVuCiAgICAgICAgaWYgI3AgPiBjaG9zZW5fbGVuIHRoZW4gY2hvc2VuLCBjaG9zZW5fbGVuID0gZSwgI3AgZW5kCiAgICBlbmQKZW5kCmlmIG5vdCBjaG9zZW4gdGhlbiByZXR1cm4gZW5kCgpsb2NhbCBzcGVjID0gY2hvc2VuLnNwZWMKbG9jYWwgZGVueV9zdGF0dXMgPSBzcGVjLmJsb2NrU3RhdHVzIG9yIDQwMwoKbG9jYWwgaXBzID0gbmd4LnZhci5yZW1vdGVfYWRkciBvciAiMC4wLjAuMCIKbG9jYWwgaXBpID0gbGliLmlwdjRfdG9faW50KGlwcykKCi0tIENvdW50cnkgcmVzb2x2ZWQgYXQgbW9zdCBvbmNlIHBlciByZXF1ZXN0IChvbmx5IHdoZW4gYSBjb3VudHJ5IHJ1bGUgZXhpc3RzKS4KbG9jYWwgY291bnRyeV9jYWNoZQpsb2NhbCBmdW5jdGlvbiBjb3VudHJ5X29mKCkKICAgIGlmIGNvdW50cnlfY2FjaGUgPT0gbmlsIHRoZW4KICAgICAgICBsb2NhbCBvaywgZ2VvID0gcGNhbGwocmVxdWlyZSwgIm9wZW5zaGlwLmdlb19jb3VudHJ5IikKICAgICAgICBjb3VudHJ5X2NhY2hlID0gKG9rIGFuZCBnZW8gYW5kIGdlby5nZXRfY291bnRyeV9jb2RlKGlwcykpIG9yIGZhbHNlCiAgICBlbmQKICAgIHJldHVybiBjb3VudHJ5X2NhY2hlIG9yIG5pbAplbmQKCi0tIOKUgOKUgCAxLiBBY2Nlc3M6IG1ldGhvZCBhbGxvdy1saXN0LCBJUCBhbGxvdy9kZW55LCBjb3VudHJ5IGFsbG93LWxpc3Qg4pSA4pSACmxvY2FsIGFjY2VzcyA9IHNwZWMuYWNjZXNzCmlmIGFjY2VzcyB0aGVuCiAgICBpZiBhY2Nlc3MubWV0aG9kcyBhbmQgbm90IGFjY2Vzcy5tZXRob2RzW25neC5yZXEuZ2V0X21ldGhvZCgpXSB0aGVuCiAgICAgICAgcmV0dXJuIG5neC5leGl0KGRlbnlfc3RhdHVzKQogICAgZW5kCiAgICBpZiBsaWIubWF0Y2hfY29tcGlsZWQoYWNjZXNzLmRlbnksIGlwaSwgaXBzKSB0aGVuIHJldHVybiBuZ3guZXhpdChkZW55X3N0YXR1cykgZW5kCiAgICBpZiBhY2Nlc3MuYWxsb3cgYW5kIG5vdCBsaWIubWF0Y2hfY29tcGlsZWQoYWNjZXNzLmFsbG93LCBpcGksIGlwcykgdGhlbgogICAgICAgIHJldHVybiBuZ3guZXhpdChkZW55X3N0YXR1cykKICAgIGVuZAogICAgLS0gQWxsb3ctbGlzdDogYW4gdW5yZXNvbHZlZCBjb3VudHJ5IGlzIG5vdCBvbiB0aGUgbGlzdCDihpIgYmxvY2tlZCAoZGVmYXVsdC1kZW55KS4KICAgIGlmIGFjY2Vzcy5hbGxvd0NvdW50cmllcyBhbmQgbm90IGFjY2Vzcy5hbGxvd0NvdW50cmllc1tjb3VudHJ5X29mKCkgb3IgIiJdIHRoZW4KICAgICAgICByZXR1cm4gbmd4LmV4aXQoZGVueV9zdGF0dXMpCiAgICBlbmQKZW5kCgotLSDilIDilIAgMi4gQmFuOiBJUC9DSURSLCBjb3VudHJ5LCB1c2VyLWFnZW50IOKUgOKUgApsb2NhbCBiYW4gPSBzcGVjLmJhbgppZiBiYW4gdGhlbgogICAgaWYgbGliLm1hdGNoX2NvbXBpbGVkKGJhbi5pcHMsIGlwaSwgaXBzKSBvciBsaWIubWF0Y2hfY29tcGlsZWQoYmFuLmNpZHJzLCBpcGksIGlwcykgdGhlbgogICAgICAgIHJldHVybiBuZ3guZXhpdChkZW55X3N0YXR1cykKICAgIGVuZAogICAgaWYgYmFuLmNvdW50cmllcyB0aGVuCiAgICAgICAgbG9jYWwgY2MgPSBjb3VudHJ5X29mKCkKICAgICAgICAtLSBGYWlsIENMT1NFRCAobWF0Y2hlcyB0aGUgYWxsb3ctbGlzdCBhYm92ZSk6IGlmIGdlbyBpcyB1bmF2YWlsYWJsZSB3ZQogICAgICAgIC0tIGNhbm5vdCBwcm92ZSB0aGUgY2xpZW50IGlzIE5PVCBmcm9tIGEgYmFubmVkIGNvdW50cnksIHNvIGJsb2NrIHJhdGhlcgogICAgICAgIC0tIHRoYW4gc2lsZW50bHkgbGV0dGluZyBiYW5uZWQgdHJhZmZpYyB0aHJvdWdoLiBBIGJsb2NrZWQgaG9zdCBpcyBhIGxvdWQKICAgICAgICAtLSBzaWduYWwgdG8gZml4IGdlbzsgZmFpbC1vcGVuIHdvdWxkIGJlIGEgc2lsZW50IHNlY3VyaXR5IGhvbGUuCiAgICAgICAgaWYgbm90IGNjIHRoZW4KICAgICAgICAgICAgbmd4LmxvZyhuZ3guV0FSTiwgInJ1bGVzX2d1YXJkOiBjb3VudHJ5IGJhbiBhY3RpdmUgYnV0IGdlbyB1bmF2YWlsYWJsZSDigJQgYmxvY2tpbmcgKGZhaWwtY2xvc2VkKSIpCiAgICAgICAgICAgIHJldHVybiBuZ3guZXhpdChkZW55X3N0YXR1cykKICAgICAgICBlbmQKICAgICAgICBpZiBiYW4uY291bnRyaWVzW2NjXSB0aGVuIHJldHVybiBuZ3guZXhpdChkZW55X3N0YXR1cykgZW5kCiAgICBlbmQKICAgIGlmIGJhbi5lbXB0eVVBIG9yIGJhbi51YXMgdGhlbgogICAgICAgIGxvY2FsIHVhID0gbmd4LnZhci5odHRwX3VzZXJfYWdlbnQKICAgICAgICBpZiBiYW4uZW1wdHlVQSBhbmQgKHVhID09IG5pbCBvciB1YSA9PSAiIikgdGhlbiByZXR1cm4gbmd4LmV4aXQoZGVueV9zdGF0dXMpIGVuZAogICAgICAgIGlmIGJhbi51YXMgYW5kIHVhIGFuZCB1YSB+PSAiIiB0aGVuCiAgICAgICAgICAgIGxvY2FsIHVhbCA9IHN0cmluZy5sb3dlcih1YSkKICAgICAgICAgICAgZm9yIGkgPSAxLCAjYmFuLnVhcyBkbwogICAgICAgICAgICAgICAgaWYgc3RyaW5nLmZpbmQodWFsLCBiYW4udWFzW2ldLCAxLCB0cnVlKSB0aGVuIHJldHVybiBuZ3guZXhpdChkZW55X3N0YXR1cykgZW5kCiAgICAgICAgICAgIGVuZAogICAgICAgIGVuZAogICAgZW5kCmVuZAoKLS0g4pSA4pSAIDMuIEhvdGxpbms6IG9ubHkgbGlzdGVkIHJlZmVyZXIgaG9zdHMgKGVtcHR5IHJlZmVyZXIgcGVyIGFsbG93RW1wdHkpIOKUgOKUgApsb2NhbCBob3QgPSBzcGVjLmhvdGxpbmsKaWYgaG90IHRoZW4KICAgIGxvY2FsIHJlZiA9IG5neC52YXIuaHR0cF9yZWZlcmVyCiAgICBpZiByZWYgPT0gbmlsIG9yIHJlZiA9PSAiIiB0aGVuCiAgICAgICAgaWYgbm90IGhvdC5hbGxvd0VtcHR5IHRoZW4gcmV0dXJuIG5neC5leGl0KGRlbnlfc3RhdHVzKSBlbmQKICAgIGVsc2UKICAgICAgICBsb2NhbCByaG9zdCA9IHN0cmluZy5tYXRjaChyZWYsICJeJXcrOi8vKFteL10rKSIpICAgICAgICAgIC0tIGF1dGhvcml0eQogICAgICAgIGlmIHJob3N0IHRoZW4gcmhvc3QgPSBzdHJpbmcubG93ZXIoc3RyaW5nLm1hdGNoKHJob3N0LCAiXihbXjpdKykiKSBvciByaG9zdCkgZW5kIC0tIHN0cmlwIDpwb3J0CiAgICAgICAgaWYgbm90IChyaG9zdCBhbmQgaG90LnJlZmVyZXJzW3Job3N0XSkgdGhlbiByZXR1cm4gbmd4LmV4aXQoZGVueV9zdGF0dXMpIGVuZAogICAgZW5kCmVuZAoKLS0g4pSA4pSAIDQuIFJhdGUgbGltaXQg4oCUIGZpeGVkIDFzIHdpbmRvdyBwZXIgKGhvc3QsIHBhdGgsIGlwKSDilIDilIAKbG9jYWwgcmwgPSBzcGVjLnJsCmlmIHJsIHRoZW4KICAgIGxvY2FsIGtleSA9ICJybDoiIC4uIGhvc3QgLi4gIjoiIC4uIChjaG9zZW4ucGF0aFByZWZpeCBvciAiLyIpIC4uICI6IiAuLiBpcHMKICAgICAgICAuLiAiOiIgLi4gbWF0aC5mbG9vcihuZ3gubm93KCkpCiAgICBsb2NhbCBjID0gY291bnRlcnM6aW5jcihrZXksIDEsIDAsIDIpICAtLSBpbml0IDAsIDJzIFRUTCDihpIgc2VsZi1leHBpcmluZyBidWNrZXRzCiAgICBpZiBjIGFuZCBjID4gcmwubGltaXQgdGhlbgogICAgICAgIG5neC5oZWFkZXJbIlJldHJ5LUFmdGVyIl0gPSAiMSIKICAgICAgICByZXR1cm4gbmd4LmV4aXQocmwuc3RhdHVzKQogICAgZW5kCmVuZAo=",
26
+ "rules_lib.lua": "LS0gcnVsZXNfbGliLmx1YQotLSBQZXItd29ya2VyIGhlbHBlcnMgKyBwYXJzZWQtcnVsZSBjYWNoZSBmb3IgcnVsZXNfZ3VhcmQubHVhIChhY2Nlc3MgcGhhc2UpLgotLSBMb2FkZWQgT05DRSBwZXIgd29ya2VyIHZpYSByZXF1aXJlKCJvcGVuc2hpcC5ydWxlc19saWIiKS4gVGhlIGFjY2VzcyBmaWxlIGlzCi0tIHJlLWV4ZWN1dGVkIG9uIGV2ZXJ5IHJlcXVlc3QsIHNvIGFsbCBwYXJzaW5nL2NvbXBpbGluZy9tYXRjaGluZyBsaXZlcyBoZXJlIHRvCi0tIGF2b2lkIHJlLWNyZWF0aW5nIGNsb3N1cmVzIGFuZCByZS1kZWNvZGluZyBKU09OIG9uIHRoZSBob3QgcGF0aC4KLS0KLS0gU2hhcmVkLWRpY3QgdmFsdWUgYHJ1bGVzW2hvc3RdYCA9IEpTT04gYXJyYXkgb2YgeyBwYXRoUHJlZml4LCBzcGVjIH0gd2hlcmUKLS0gc3BlYyBtYXRjaGVzIEByZXBvL2NvcmUgUm91dGVSdWxlU3BlYy4gcGFyc2UoKSBkZWNvZGVzICsgcHJlY29tcGlsZXMgQ0lEUnMgdG8KLS0gaW50ZWdlcnMsIGxvd2VyY2FzZXMgVUEvcmVmZXJlciBuZWVkbGVzLCBhbmQgYnVpbGRzIE8oMSkgc2V0cyBmb3IKLS0gY291bnRyaWVzL21ldGhvZHMgT05DRTsgdGhlIGNvbXBpbGVkIHJlc3VsdCBpcyBMUlUtY2FjaGVkIHBlciBob3N0IGFuZCByZXVzZWQKLS0gdW50aWwgdGhlIHJhdyBzdHJpbmcgY2hhbmdlcyAocnVsZSBlZGl0cyBhcmUgcmFyZSwgcmVxdWVzdHMgYXJlIGhvdCkuCi0tCi0tIFNFQ1VSSVRZOiBub3RoaW5nIGhlcmUgdHVybnMgYSBydWxlIHZhbHVlIGludG8gTHVhIGNvZGUgb3IgYSBMdWEgcGF0dGVybi4KLS0gU3RyaW5ncyBhcmUgY29tcGFyZWQgd2l0aCBgPT1gL3NldC1sb29rdXBzOyB1c2VyLWFnZW50IG1hdGNoaW5nIGlzCi0tIHN0cmluZy5maW5kKGhheSwgbmVlZGxlLCAxLCB0cnVlKSDigJQgUExBSU4sIG5ldmVyIGEgcmVnZXguCgpsb2NhbCBjanNvbiA9IHJlcXVpcmUgImNqc29uLnNhZmUiCmxvY2FsIGxydWNhY2hlID0gcmVxdWlyZSAicmVzdHkubHJ1Y2FjaGUiCgpsb2NhbCBNID0ge30KCmxvY2FsIGNhY2hlID0gbHJ1Y2FjaGUubmV3KDEwMjQpIC0tIGNvbXBpbGVkIHJ1bGVzLCBwZXIgd29ya2VyLCB+MTAyNCBob3N0cwoKLS0g4pSA4pSAIElQdjQgaGVscGVycyDilIDilIAKbG9jYWwgZnVuY3Rpb24gaXB2NF90b19pbnQocykKICAgIGxvY2FsIGEsIGIsIGMsIGQgPSBzdHJpbmcubWF0Y2gocywgIl4oJWQrKSUuKCVkKyklLiglZCspJS4oJWQrKSQiKQogICAgaWYgbm90IGEgdGhlbiByZXR1cm4gbmlsIGVuZAogICAgYSwgYiwgYywgZCA9IHRvbnVtYmVyKGEpLCB0b251bWJlcihiKSwgdG9udW1iZXIoYyksIHRvbnVtYmVyKGQpCiAgICBpZiBhID4gMjU1IG9yIGIgPiAyNTUgb3IgYyA+IDI1NSBvciBkID4gMjU1IHRoZW4gcmV0dXJuIG5pbCBlbmQKICAgIHJldHVybiBhICogMTY3NzcyMTYgKyBiICogNjU1MzYgKyBjICogMjU2ICsgZAplbmQKTS5pcHY0X3RvX2ludCA9IGlwdjRfdG9faW50CgotLSBQcmVjb21waWxlIGEgQ0lEUiAvIGJhcmUtSVAgc3RyaW5nIGludG8gYSBjaGVhcCBtYXRjaCBkZXNjcmlwdG9yLgpsb2NhbCBmdW5jdGlvbiBjb21waWxlX2NpZHIocykKICAgIGxvY2FsIGJhc2UsIGJpdHMgPSBzdHJpbmcubWF0Y2gocywgIl4oW14vXSspLyglZCspJCIpCiAgICBpZiBiYXNlIHRoZW4KICAgICAgICBiaXRzID0gdG9udW1iZXIoYml0cykKICAgICAgICBsb2NhbCBiYXNlaSA9IGlwdjRfdG9faW50KGJhc2UpCiAgICAgICAgaWYgbm90IGJhc2VpIG9yIGJpdHMgPCAwIG9yIGJpdHMgPiAzMiB0aGVuIHJldHVybiB7IGV4YWN0ID0gcyB9IGVuZAogICAgICAgIGlmIGJpdHMgPT0gMCB0aGVuIHJldHVybiB7IGFsbCA9IHRydWUgfSBlbmQKICAgICAgICBsb2NhbCBkaXYgPSAyIF4gKDMyIC0gYml0cykgLS0gY29tcGFyZSB0aGUgdG9wIGBiaXRzYCBiaXRzCiAgICAgICAgcmV0dXJuIHsgbmV0ID0gbWF0aC5mbG9vcihiYXNlaSAvIGRpdiksIGRpdiA9IGRpdiB9CiAgICBlbmQKICAgIGxvY2FsIGkgPSBpcHY0X3RvX2ludChzKQogICAgaWYgaSB0aGVuIHJldHVybiB7IGlwID0gaSB9IGVuZAogICAgcmV0dXJuIHsgZXhhY3QgPSBzIH0gLS0gSVB2NiAvIHVucGFyc2VhYmxlIOKGkiBsaXRlcmFsIHN0cmluZyBjb21wYXJlCmVuZAoKbG9jYWwgZnVuY3Rpb24gY29tcGlsZV9saXN0KGxpc3QpCiAgICBpZiB0eXBlKGxpc3QpIH49ICJ0YWJsZSIgdGhlbiByZXR1cm4gbmlsIGVuZAogICAgbG9jYWwgb3V0LCBuID0ge30sIDAKICAgIGZvciBfLCBzIGluIGlwYWlycyhsaXN0KSBkbwogICAgICAgIGlmIHR5cGUocykgPT0gInN0cmluZyIgYW5kIHMgfj0gIiIgdGhlbgogICAgICAgICAgICBuID0gbiArIDEKICAgICAgICAgICAgb3V0W25dID0gY29tcGlsZV9jaWRyKHMpCiAgICAgICAgZW5kCiAgICBlbmQKICAgIHJldHVybiBuID4gMCBhbmQgb3V0IG9yIG5pbAplbmQKCi0tIE1hdGNoIGEgY2xpZW50IChpbnQgZm9ybSBgaXBpYCwgbWF5IGJlIG5pbCBmb3Igbm9uLUlQdjQ7IHJhdyBgaXBzYCkgYWdhaW5zdCBhCi0tIGNvbXBpbGVkIENJRFIvSVAgbGlzdC4KbG9jYWwgZnVuY3Rpb24gbWF0Y2hfY29tcGlsZWQoY29tcGlsZWQsIGlwaSwgaXBzKQogICAgaWYgbm90IGNvbXBpbGVkIHRoZW4gcmV0dXJuIGZhbHNlIGVuZAogICAgZm9yIGkgPSAxLCAjY29tcGlsZWQgZG8KICAgICAgICBsb2NhbCBjID0gY29tcGlsZWRbaV0KICAgICAgICBpZiBjLmFsbCB0aGVuCiAgICAgICAgICAgIHJldHVybiB0cnVlCiAgICAgICAgZWxzZWlmIGMuaXAgdGhlbgogICAgICAgICAgICBpZiBpcGkgYW5kIGlwaSA9PSBjLmlwIHRoZW4gcmV0dXJuIHRydWUgZW5kCiAgICAgICAgZWxzZWlmIGMubmV0IHRoZW4KICAgICAgICAgICAgaWYgaXBpIGFuZCBtYXRoLmZsb29yKGlwaSAvIGMuZGl2KSA9PSBjLm5ldCB0aGVuIHJldHVybiB0cnVlIGVuZAogICAgICAgIGVsc2VpZiBjLmV4YWN0ID09IGlwcyB0aGVuCiAgICAgICAgICAgIHJldHVybiB0cnVlCiAgICAgICAgZW5kCiAgICBlbmQKICAgIHJldHVybiBmYWxzZQplbmQKTS5tYXRjaF9jb21waWxlZCA9IG1hdGNoX2NvbXBpbGVkCgpsb2NhbCBmdW5jdGlvbiBsb3dlcl9saXN0KGxpc3QpCiAgICBpZiB0eXBlKGxpc3QpIH49ICJ0YWJsZSIgdGhlbiByZXR1cm4gbmlsIGVuZAogICAgbG9jYWwgb3V0LCBuID0ge30sIDAKICAgIGZvciBfLCBzIGluIGlwYWlycyhsaXN0KSBkbwogICAgICAgIGlmIHR5cGUocykgPT0gInN0cmluZyIgYW5kIHMgfj0gIiIgdGhlbgogICAgICAgICAgICBuID0gbiArIDEKICAgICAgICAgICAgb3V0W25dID0gc3RyaW5nLmxvd2VyKHMpCiAgICAgICAgZW5kCiAgICBlbmQKICAgIHJldHVybiBuID4gMCBhbmQgb3V0IG9yIG5pbAplbmQKCi0tIEJ1aWxkIGFuIE8oMSkgbG9va3VwIHNldCBmcm9tIGEgc3RyaW5nIGxpc3QgKG9wdGlvbmFsbHkgbG93ZXJjYXNlZCkuCmxvY2FsIGZ1bmN0aW9uIHRvX3NldChsaXN0LCBsb3dlcikKICAgIGlmIHR5cGUobGlzdCkgfj0gInRhYmxlIiB0aGVuIHJldHVybiBuaWwgZW5kCiAgICBsb2NhbCBzZXQsIGFueSA9IHt9LCBmYWxzZQogICAgZm9yIF8sIHMgaW4gaXBhaXJzKGxpc3QpIGRvCiAgICAgICAgaWYgdHlwZShzKSA9PSAic3RyaW5nIiBhbmQgcyB+PSAiIiB0aGVuCiAgICAgICAgICAgIHNldFtsb3dlciBhbmQgc3RyaW5nLmxvd2VyKHMpIG9yIHNdID0gdHJ1ZQogICAgICAgICAgICBhbnkgPSB0cnVlCiAgICAgICAgZW5kCiAgICBlbmQKICAgIHJldHVybiBhbnkgYW5kIHNldCBvciBuaWwKZW5kCgotLSBDb21waWxlIG9uZSBSb3V0ZVJ1bGVTcGVjIGludG8gYSBmYXN0LW1hdGNoIHNoYXBlLgpsb2NhbCBmdW5jdGlvbiBjb21waWxlX3NwZWMoc3BlYykKICAgIGlmIHR5cGUoc3BlYykgfj0gInRhYmxlIiB0aGVuIHJldHVybiB7IGJsb2NrU3RhdHVzID0gNDAzIH0gZW5kCiAgICBsb2NhbCBvdXQgPSB7fQoKICAgIGxvY2FsIHJsID0gc3BlYy5yYXRlTGltaXQKICAgIGxvY2FsIHJwcyA9IHJsIGFuZCB0b251bWJlcihybC5ycHMpCiAgICBpZiBycHMgYW5kIHJwcyA+IDAgdGhlbgogICAgICAgIG91dC5ybCA9IHsKICAgICAgICAgICAgbGltaXQgPSBtYXRoLmZsb29yKHJwcykgKyBtYXRoLmZsb29yKHRvbnVtYmVyKHJsLmJ1cnN0KSBvciAwKSwKICAgICAgICAgICAgc3RhdHVzID0gdG9udW1iZXIocmwuc3RhdHVzKSBvciA0MjksCiAgICAgICAgfQogICAgZW5kCgogICAgbG9jYWwgYmFuID0gc3BlYy5iYW4KICAgIGlmIHR5cGUoYmFuKSA9PSAidGFibGUiIHRoZW4KICAgICAgICBvdXQuYmFuID0gewogICAgICAgICAgICBpcHMgPSBjb21waWxlX2xpc3QoYmFuLmlwcyksCiAgICAgICAgICAgIGNpZHJzID0gY29tcGlsZV9saXN0KGJhbi5jaWRycyksCiAgICAgICAgICAgIGNvdW50cmllcyA9IHRvX3NldChiYW4uY291bnRyaWVzKSwKICAgICAgICAgICAgdWFzID0gbG93ZXJfbGlzdChiYW4udXNlckFnZW50cyksCiAgICAgICAgICAgIGVtcHR5VUEgPSBiYW4uZW1wdHlVc2VyQWdlbnQgPT0gdHJ1ZSwKICAgICAgICB9CiAgICBlbmQKCiAgICBsb2NhbCBhY2MgPSBzcGVjLmFjY2VzcwogICAgaWYgdHlwZShhY2MpID09ICJ0YWJsZSIgdGhlbgogICAgICAgIG91dC5hY2Nlc3MgPSB7CiAgICAgICAgICAgIGFsbG93ID0gY29tcGlsZV9saXN0KGFjYy5hbGxvd0NpZHJzKSwKICAgICAgICAgICAgZGVueSA9IGNvbXBpbGVfbGlzdChhY2MuZGVueUNpZHJzKSwKICAgICAgICAgICAgYWxsb3dDb3VudHJpZXMgPSB0b19zZXQoYWNjLmFsbG93Q291bnRyaWVzKSwKICAgICAgICAgICAgbWV0aG9kcyA9IHRvX3NldChhY2MubWV0aG9kcyksCiAgICAgICAgfQogICAgZW5kCgogICAgbG9jYWwgaG90ID0gc3BlYy5ob3RsaW5rCiAgICBpZiB0eXBlKGhvdCkgPT0gInRhYmxlIiB0aGVuCiAgICAgICAgbG9jYWwgcmVmcyA9IHRvX3NldChob3QuYWxsb3dSZWZlcmVycywgdHJ1ZSkKICAgICAgICBpZiByZWZzIHRoZW4KICAgICAgICAgICAgb3V0LmhvdGxpbmsgPSB7IHJlZmVyZXJzID0gcmVmcywgYWxsb3dFbXB0eSA9IGhvdC5hbGxvd0VtcHR5IH49IGZhbHNlIH0KICAgICAgICBlbmQKICAgIGVuZAoKICAgIG91dC5ibG9ja1N0YXR1cyA9ICh0eXBlKHNwZWMuYmxvY2spID09ICJ0YWJsZSIgYW5kIHRvbnVtYmVyKHNwZWMuYmxvY2suc3RhdHVzKSkgb3IgNDAzCiAgICByZXR1cm4gb3V0CmVuZAoKbG9jYWwgZnVuY3Rpb24gcGFyc2UocmF3KQogICAgbG9jYWwgZW50cmllcyA9IGNqc29uLmRlY29kZShyYXcpCiAgICBpZiB0eXBlKGVudHJpZXMpIH49ICJ0YWJsZSIgdGhlbiByZXR1cm4ge30gZW5kCiAgICBsb2NhbCBvdXQsIG4gPSB7fSwgMAogICAgZm9yIF8sIGUgaW4gaXBhaXJzKGVudHJpZXMpIGRvCiAgICAgICAgaWYgdHlwZShlKSA9PSAidGFibGUiIHRoZW4KICAgICAgICAgICAgbiA9IG4gKyAxCiAgICAgICAgICAgIG91dFtuXSA9IHsgcGF0aFByZWZpeCA9IGUucGF0aFByZWZpeCwgc3BlYyA9IGNvbXBpbGVfc3BlYyhlLnNwZWMpIH0KICAgICAgICBlbmQKICAgIGVuZAogICAgcmV0dXJuIG91dAplbmQKCi0tIExSVS1jYWNoZWQgcGFyc2U6IHJldXNlIHRoZSBjb21waWxlZCBmb3JtIHVudGlsIHRoZSByYXcgZGljdCBzdHJpbmcgY2hhbmdlcy4KZnVuY3Rpb24gTS5nZXQoaG9zdCwgcmF3KQogICAgbG9jYWwgaGl0ID0gY2FjaGU6Z2V0KGhvc3QpCiAgICBpZiBoaXQgYW5kIGhpdC5yYXcgPT0gcmF3IHRoZW4gcmV0dXJuIGhpdC5wYXJzZWQgZW5kCiAgICBsb2NhbCBwYXJzZWQgPSBwYXJzZShyYXcpCiAgICBjYWNoZTpzZXQoaG9zdCwgeyByYXcgPSByYXcsIHBhcnNlZCA9IHBhcnNlZCB9KQogICAgcmV0dXJuIHBhcnNlZAplbmQKCnJldHVybiBNCg==",
27
+ "site_logger.lua": "LS0gc2l0ZV9sb2dnZXIubHVhCi0tIE9wZW5SZXN0eSBsb2dfYnlfbHVhIC0gcnVucyBBRlRFUiB0aGUgcmVzcG9uc2UgaXMgc2VudC4KLS0gUHVyZSBzaGFyZWQtZGljdCBhbmFseXRpY3MuICBObyBSZWRpcywgbm8gdGltZXJzIGZvciBjb3VudGVycywgbm8gYmF0Y2hpbmcuCi0tIEV2ZXJ5IGluY3IoKSBpcyBhdG9taWMgYWNyb3NzIHdvcmtlcnMuCi0tCi0tIFNoYXJlZCBkaWN0IGtleSBzY2hlbWEgKGFuYWx5dGljcyB6b25lKToKLS0gICBzOntkb21haW59OntlcG9jaF9taW59OnIgICAgICAgIHJlcXVlc3QgY291bnQgICAgICAgICAgICAgICAoVFRMIDI0aCkKLS0gICBzOntkb21haW59OntlcG9jaF9taW59OmkgICAgICAgIGJhbmR3aWR0aCBpbiAgYnl0ZXMgICAgICAgICAoVFRMIDI0aCkKLS0gICBzOntkb21haW59OntlcG9jaF9taW59Om8gICAgICAgIGJhbmR3aWR0aCBvdXQgYnl0ZXMgICAgICAgICAoVFRMIDI0aCkKLS0gICBzOntkb21haW59OntlcG9jaF9taW59OnQgICAgICAgIHJlc3BvbnNlIHRpbWUgc3VtIChzZWNvbmRzKSAoVFRMIDI0aCkKLS0gICBzOntkb21haW59OntlcG9jaF9taW59OnUgICAgICAgIHBhZ2UgKG5vbi1zdGF0aWMpIHJlcXVlc3RzICAoVFRMIDI0aCkKLS0gICBjOntkb21haW59OntlcG9jaF9taW59OntDQ30gICAgIGNvdW50cnkgcGVyIG1pbnV0ZSAgICAgICAgICAoVFRMIDI0aCkKLS0gICB0Ontkb21haW59OnIgLyA6aSAvIDpvICAgICAgICAgIGxpZmV0aW1lIHRvdGFscyAgICAgICAgICAgICAobm8gVFRMKQotLSAgIGQ6e2RvbWFpbn0gICAgICAgICAgICAgICAgICAgICAgZG9tYWluIGluZGV4IG1hcmtlciAgICAgICAgIChubyBUVEwpCi0tCi0tICAgRGFpbHkgcm9sbHVwLCBhbGwgdW5kZXIgb25lIGBnOntkb21haW59OntZWVlZTU1ERH06YCBwcmVmaXggc28gbWdtdF9hcGkncwotLSAgIC9hbmFseXRpY3MvZ2VvIHNlcnZlcyB0aGUgd2hvbGUgZGF5IGluIGEgU0lOR0xFIGRpY3Qgc2NhbjoKLS0gICBnOntkb21haW59OntZWVlZTU1ERH06e0NDfSAgICAgIGNvdW50cnkgaGl0IGNvdW50ICAgICAgICAgICAoVFRMIDQ4aCkKLS0gICBnOntkb21haW59OntZWVlZTU1ERH06diAgICAgICAgIGRpc3RpbmN0IHZpc2l0b3JzICAgICAgICAgICAoVFRMIDQ4aCkKLS0gICBnOntkb21haW59OntZWVlZTU1ERH06cDp7cGF0aH0gIHBhdGggaGl0IGNvdW50ICAgICAgICAgICAgICAoVFRMIDQ4aCkKLS0gICBnOntkb21haW59OntZWVlZTU1ERH06czp7Y29kZX0gIHN0YXR1cy1jb2RlIGNvdW50ICAgICAgICAgICAoVFRMIDQ4aCkKLS0KLS0gU2hhcmVkIGRpY3Qga2V5IHNjaGVtYSAodmlzaXRvcnMgem9uZSk6Ci0tICAgdnNhbHQ6e1lZWVlNTUREfSAgICAgICAgICAgICAgICBwZXItZGF5IGhhc2ggc2FsdCAgICAgICAgICAgKFRUTCA0OGgpCi0tICAgdmQ6e2RvbWFpbn06e1lZWVlNTUREfTp7aGFzaH0gICBkaXN0aW5jdC12aXNpdG9yIG1hcmtlciAgICAgKFRUTCA0OGgpCi0tCi0tIFNoYXJlZCBkaWN0IGtleSBzY2hlbWEgKHJlcXVlc3RfZGF0YSB6b25lKToKLS0gICBybG9nOntkb21haW59OnNlcSAgICAgICAgICAgICAgIG1vbm90b25pYyB3cml0ZSBwb2ludGVyCi0tICAgcmxvZzp7ZG9tYWlufTp7c2xvdH0gICAgICAgICAgICBKU09OIGVudHJ5IChyaW5nIGJ1ZikgICAgICAgKFRUTCAxaCkKLS0gICBsb2dfcGlwZTpzdWI6e2RvbWFpbn0gICAgICAgICAgIGxpdmUgc3Vic2NyaWJlciBmbGFnICAgICAgICAoVFRMIDMwcykKLS0gICBsb2dfcGlwZTpxOntkb21haW59ICAgICAgICAgICAgIGxpdmUgbG9nIHF1ZXVlIGVudHJpZXMKLS0KLS0gTk9URSBvbiBgOnVgIOKAlCBpdCBjb3VudHMgbm9uLXN0YXRpYyBSRVFVRVNUUywgbm90IHBlb3BsZS4gSXQgd2FzIHN1cmZhY2VkIGFzCi0tICJ1bmlxdWUgSVBzIiBhbGwgdGhlIHdheSB0byB0aGUgZGFzaGJvYXJkLCB3aGljaCBpdCBuZXZlciB3YXMuIFJlYWwgZGlzdGluY3QKLS0gdmlzaXRvcnMgYXJlIHRoZSBgdmQ6YC9gOnZgIHBhaXIgYmVsb3cuCgpsb2NhbCBjanNvbiA9IHJlcXVpcmUgImNqc29uLnNhZmUiCgotLSBTQUZFIExPQUQ6IEdlb0lQIE1vZHVsZSAocGVyLXdvcmtlciwgY2FjaGVkIGJ5IHJlcXVpcmUpCmxvY2FsIGdlb19vaywgZ2VvID0gcGNhbGwocmVxdWlyZSwgIm9wZW5zaGlwLmdlb19jb3VudHJ5IikKaWYgbm90IGdlb19vayB0aGVuCiAgICBnZW8gPSBuaWwKICAgIG5neC5sb2cobmd4LldBUk4sICJbc2l0ZV9sb2dnZXJdIGdlb19jb3VudHJ5IG1vZHVsZSBub3QgYXZhaWxhYmxlLiBHZW9JUCBkaXNhYmxlZC4iKQplbmQKCi0tIFNBRkUgTE9BRDogUGlwZSBtb2R1bGUgKHBlci13b3JrZXIsIGNhY2hlZCBieSByZXF1aXJlKQpsb2NhbCBwaXBlX29rLCBwaXBlX2xvZyA9IHBjYWxsKHJlcXVpcmUsICJvcGVuc2hpcC5waXBlX2xvZyIpCmlmIG5vdCBwaXBlX29rIHRoZW4gcGlwZV9sb2cgPSBuaWwgZW5kCgpsb2NhbCBhbmFseXRpY3MgICAgPSBuZ3guc2hhcmVkLmFuYWx5dGljcwpsb2NhbCByZXF1ZXN0X2RhdGEgPSBuZ3guc2hhcmVkLnJlcXVlc3RfZGF0YQotLSBQZXItaG9zdCBlZGdlIGNvbmZpZywgcHVzaGVkIGJ5IHRoZSBBUEkgKHNlZSBtZ210X2FwaSdzIC9hbmFseXRpY3MvY29uZmlnKS4KLS0KLS0gVGhlIGBydWxlc2Agem9uZSwgTk9UIGBhbmFseXRpY3NgOiB0aGlzIGhvbGRzIGEgaGFuZGZ1bCBvZiBzbWFsbCBjb25maWcgdmFsdWVzIGFuZCBpcwotLSBuZXZlciB1bmRlciBldmljdGlvbiBwcmVzc3VyZSwgd2hlcmVhcyB0aGUgYW5hbHl0aWNzIHpvbmUgaXMgYSAyNTYgTUIgY2h1cm4gb2YgY291bnRlcnMuCi0tIEFuIGV2aWN0ZWQgZmxhZyB0aGVyZSB3b3VsZCBzaWxlbnRseSBzdG9wIHBhdGggY29sbGVjdGlvbiB3aXRoIG5vdGhpbmcgdG8gZXhwbGFpbiB3aHkuCmxvY2FsIHJ1bGVzX2RpY3QgICA9IG5neC5zaGFyZWQucnVsZXMKLS0gT3B0aW9uYWw6IGEgYm94IHdob3NlIG5naW54LmNvbmYgcHJlZGF0ZXMgdGhpcyB6b25lIGtlZXBzIHdvcmtpbmcsIGp1c3Qgd2l0aG91dAotLSBkaXN0aW5jdC12aXNpdG9yIGNvdW50cy4gTmV2ZXIgYXNzdW1lIGEgZGljdCBleGlzdHMuCmxvY2FsIHZpc2l0b3JzICAgICA9IG5neC5zaGFyZWQudmlzaXRvcnMKaWYgbm90IGFuYWx5dGljcyBvciBub3QgcmVxdWVzdF9kYXRhIHRoZW4gcmV0dXJuIGVuZAoKLS0g4pSA4pSAIEhlbHBlcnMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgpsb2NhbCBmdW5jdGlvbiBub3JtYWxpemUoaG9zdCkKICAgIGlmIG5vdCBob3N0IHRoZW4gcmV0dXJuIG5pbCBlbmQKICAgIGxvY2FsIGggPSBob3N0Omxvd2VyKCkKICAgIGlmIGg6c3ViKDEsIDQpID09ICJ3d3cuIiB0aGVuIGggPSBoOnN1Yig1KSBlbmQKICAgIHJldHVybiBoCmVuZAoKbG9jYWwgX2RheSA9IHsgc3RyID0gIiIsIHRzID0gMCB9CmxvY2FsIGZ1bmN0aW9uIHRvZGF5KCkKICAgIGxvY2FsIG5vdyA9IG5neC5ub3coKQogICAgaWYgbm93IC0gX2RheS50cyA+IDYwIHRoZW4KICAgICAgICBfZGF5LnN0ciA9IG9zLmRhdGUoIiElWSVtJWQiLCBub3cpCiAgICAgICAgX2RheS50cyA9IG5vdwogICAgZW5kCiAgICByZXR1cm4gX2RheS5zdHIKZW5kCgotLSBGYXN0IGNoZWNrIGlmIFVSSSBpcyBhIHN0YXRpYyBhc3NldCAoZm9yIHVuaXF1ZV9yZXF1ZXN0cyBjb3VudGVyKQpsb2NhbCBmdW5jdGlvbiBpc19zdGF0aWNfYXNzZXQodSkKICAgIGxvY2FsIGxvd2VyID0gdTpsb3dlcigpCgogICAgLS0gU3RhdGljIGZpbGUgZXh0ZW5zaW9ucwogICAgaWYgbG93ZXI6bWF0Y2goIiUuanMkIikgb3IgbG93ZXI6bWF0Y2goIiUuY3NzJCIpIG9yCiAgICAgICBsb3dlcjptYXRjaCgiJS5qcGckIikgb3IgbG93ZXI6bWF0Y2goIiUuanBlZyQiKSBvcgogICAgICAgbG93ZXI6bWF0Y2goIiUucG5nJCIpIG9yIGxvd2VyOm1hdGNoKCIlLmdpZiQiKSBvcgogICAgICAgbG93ZXI6bWF0Y2goIiUuc3ZnJCIpIG9yIGxvd2VyOm1hdGNoKCIlLndlYnAkIikgb3IKICAgICAgIGxvd2VyOm1hdGNoKCIlLmljbyQiKSBvciBsb3dlcjptYXRjaCgiJS5ibXAkIikgb3IKICAgICAgIGxvd2VyOm1hdGNoKCIlLndvZmYyPyQiKSBvciBsb3dlcjptYXRjaCgiJS50dGYkIikgb3IKICAgICAgIGxvd2VyOm1hdGNoKCIlLmVvdCQiKSBvciBsb3dlcjptYXRjaCgiJS5vdGYkIikgb3IKICAgICAgIGxvd2VyOm1hdGNoKCIlLm1wNCQiKSBvciBsb3dlcjptYXRjaCgiJS53ZWJtJCIpIG9yCiAgICAgICBsb3dlcjptYXRjaCgiJS5tcDMkIikgb3IgbG93ZXI6bWF0Y2goIiUud2F2JCIpIG9yCiAgICAgICBsb3dlcjptYXRjaCgiJS5wZGYkIikgb3IgbG93ZXI6bWF0Y2goIiUuemlwJCIpIG9yCiAgICAgICBsb3dlcjptYXRjaCgiJS50YXIkIikgb3IgbG93ZXI6bWF0Y2goIiUuZ3okIikgb3IKICAgICAgIGxvd2VyOm1hdGNoKCIlLnhtbCQiKSBvciBsb3dlcjptYXRjaCgiJS5qc29uJCIpIG9yCiAgICAgICBsb3dlcjptYXRjaCgiJS50eHQkIikgb3IgbG93ZXI6bWF0Y2goIiUubWFwJCIpIHRoZW4KICAgICAgICByZXR1cm4gdHJ1ZQogICAgZW5kCgogICAgLS0gQ29tbW9uIHN0YXRpYyBwYXRocwogICAgaWYgbG93ZXI6bWF0Y2goIl4vX25leHQvc3RhdGljLyIpIG9yCiAgICAgICBsb3dlcjptYXRjaCgiXi9zdGF0aWMvIikgb3IKICAgICAgIGxvd2VyOm1hdGNoKCJeL2Fzc2V0cy8iKSBvcgogICAgICAgbG93ZXI6bWF0Y2goIl4vcHVibGljLyIpIG9yCiAgICAgICBsb3dlcjptYXRjaCgiL2Zhdmljb24lLmljbyIpIHRoZW4KICAgICAgICByZXR1cm4gdHJ1ZQogICAgZW5kCgogICAgcmV0dXJuIGZhbHNlCmVuZAoKLS0gQ29sbGFwc2UgYSByZXF1ZXN0IFVSSSBpbnRvIGEgbG93LWNhcmRpbmFsaXR5IGJ1Y2tldCBzdWl0YWJsZSBhcyBhIGRpY3Qga2V5LgotLSBXaXRob3V0IHRoaXMsICJ0b3AgcGF0aHMiIGlzIHVuYm91bmRlZDogZXZlcnkgP3Rva2VuPSwgZXZlcnkgL29yZGVycy80ODIxOSwgYW5kCi0tIGV2ZXJ5IDQwNCBhIHNjYW5uZXIgcHJvYmVzIG1pbnRzIGEgcGVybWFuZW50IGtleSwgYW5kIHRoZSBhbmFseXRpY3Mgem9uZQotLSBMUlUtZXZpY3RzIHJlYWwgY291bnRlcnMgdG8gc3RvcmUganVuay4KbG9jYWwgZnVuY3Rpb24gbm9ybWFsaXplX3BhdGgodSkKICAgIC0tIFF1ZXJ5IHN0cmluZyBjYXJyaWVzIGlkcy90b2tlbnMgYW5kIG5ldmVyIGlkZW50aWZpZXMgdGhlIHJvdXRlLgogICAgbG9jYWwgcGF0aCA9IHU6bWF0Y2goIl4oW14/I10qKSIpIG9yIHUKICAgIGlmIHBhdGggPT0gIiIgdGhlbiByZXR1cm4gIi8iIGVuZAogICAgLS0gTnVtZXJpYyBhbmQgVVVJRC9oZXggc2VnbWVudHMgYXJlIGlkcywgbm90IHJvdXRlczogL29yZGVycy80ODIxOSBhbmQKICAgIC0tIC9vcmRlcnMvNDgyMjAgYXJlIG9uZSBwYXRoLgogICAgcGF0aCA9IHBhdGg6Z3N1YigiLyVkKyIsICIvOmlkIikKICAgIHBhdGggPSBwYXRoOmdzdWIoIi8leCV4JXgleCV4JXgleCV4JS0/JXgqJS0/JXgqJS0/JXgqJS0/JXgqIiwgIi86aWQiKQogICAgLS0gQm91bmQgdGhlIGtleSBpdHNlbGYg4oCUIGEgbG9uZyBVUkkgbXVzdCBub3QgYmVjb21lIGEgbG9uZyBrZXkuCiAgICBpZiAjcGF0aCA+IDEyMCB0aGVuIHBhdGggPSBwYXRoOnN1YigxLCAxMjApIC4uICLigKYiIGVuZAogICAgcmV0dXJuIHBhdGgKZW5kCgotLSDilIDilIAgRW51bWVyYWJsZSBzZXRzLCB3aXRob3V0IGEgem9uZSBzY2FuIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAotLQotLSBSZWFkaW5nIHRoZXNlIGNvdW50ZXJzIGJhY2sgdXNlZCB0byBuZWVkIGtleSBESVNDT1ZFUlksIGFuZCBhIHNoYXJlZCBkaWN0IG9mZmVycyBleGFjdGx5Ci0tIG9uZSBtZWNoYW5pc20gZm9yIHRoYXQ6IGBnZXRfa2V5c2AsIHdoaWNoIHdhbGtzIEVWRVJZIGtleSBpbiB0aGUgem9uZSBob2xkaW5nIGl0cyBsb2NrLgotLSBDb3N0IHNjYWxlZCB3aXRoIGhvdyBtdWNoIHdhcyBpbiB0aGUgMjU2IE1CIHpvbmUsIG5vdCB3aXRoIHdoYXQgd2FzIGJlaW5nIGFza2VkIGZvciwgYW5kCi0tIGl0IHJhbiBvbiB0aGUgbWdtdCBwYXRoIGZvdXIgZGlmZmVyZW50IHdheXMuCi0tCi0tIFNvIGV2ZXJ5IHVuYm91bmRlZCBzZXQgbm93IGNhcnJpZXMgaXRzIG93biBpbmRleDogYSBjb3VudGVyIHBsdXMgbnVtYmVyZWQgc2xvdHMuCi0tCi0tICAgICA8Y291bnRlcj4gICAgICAgIGhvdyBtYW55IGRpc3RpbmN0IG1lbWJlcnMKLS0gICAgIDxwcmVmaXg+PG4+ICAgICAgdGhlIG4tdGggbWVtYmVyCi0tCi0tIEEgcmVhZGVyIHJlYWRzIHRoZSBjb3VudGVyIGFuZCB0aGVuIHJlYWRzIHNsb3RzIDEuLm4uIEJvdW5kZWQgYnkgdGhlIGFuc3dlci4KLS0KLS0gVGhlIHdyaXRlIG9ubHkgaGFwcGVucyBvbiBhIG1lbWJlcidzIEZJUlNUIHNpZ2h0aW5nLCBzbyBzdGVhZHkgc3RhdGUgY29zdHMgbm90aGluZzogdGhlCi0tIG1pbGxpb250aCByZXF1ZXN0IGZyb20gR2VybWFueSB0b2RheSB0YWtlcyB0aGUgcGxhaW4gYGluY3JgIHBhdGggYW5kIHRvdWNoZXMgbm8gaW5kZXguCmxvY2FsIGZ1bmN0aW9uIGluZGV4X2FkZChjb3VudGVyX2tleSwgc2xvdF9wcmVmaXgsIG1lbWJlciwgdHRsKQogICAgbG9jYWwgbiA9IGFuYWx5dGljczppbmNyKGNvdW50ZXJfa2V5LCAxLCAwLCB0dGwpCiAgICBpZiBuIHRoZW4gYW5hbHl0aWNzOnNldChzbG90X3ByZWZpeCAuLiBuLCBtZW1iZXIsIHR0bCkgZW5kCmVuZAoKLS0tIEFkZCAxIHRvIGEgY291bnRlciwgY3JlYXRpbmcgaXQgKHdpdGggVFRMKSBhbmQgaW5kZXhpbmcgaXQgb24gZmlyc3Qgc2lnaHRpbmcuCi0tCi0tIGBpbmNyYCB3aXRoIG5vIGBpbml0YCByZXR1cm5zIG5pbCBmb3IgYW4gYWJzZW50IGtleSwgd2hpY2ggZG91YmxlcyBhcyB0aGUgZXhpc3RlbmNlCi0tIHByb2JlIOKAlCBzbyB0aGUgY29tbW9uIGNhc2UgaXMgT05FIGhhc2ggb3BlcmF0aW9uLiBUVEwgaXMgc2V0IGJ5IHRoZSBjcmVhdGluZyBgc2FmZV9hZGRgCi0tIHJhdGhlciB0aGFuIHBhc3NlZCB0byBgaW5jcmA6IHNoZGljdCByZWplY3RzIGBpbml0X3R0bGAgd2l0aG91dCBgaW5pdGAsIGFuZCB0aGF0IHJhaXNlcyBhCi0tIEx1YSBlcnJvciB3aGljaCBhYm9ydHMgdGhlIHdob2xlIGxvZyBoYW5kbGVyIChpdCBoYXMgc2lsZW50bHkgemVyb2VkIGV2ZXJ5IGNvdW50ZXIgYmVsb3cKLS0gaXQgYmVmb3JlKS4KbG9jYWwgZnVuY3Rpb24gYnVtcF9pbmRleGVkKGtleSwgdHRsLCBjb3VudGVyX2tleSwgc2xvdF9wcmVmaXgsIG1lbWJlcikKICAgIGlmIGFuYWx5dGljczppbmNyKGtleSwgMSkgdGhlbiByZXR1cm4gZW5kCiAgICBpZiBhbmFseXRpY3M6c2FmZV9hZGQoa2V5LCAxLCB0dGwpIHRoZW4KICAgICAgICBpbmRleF9hZGQoY291bnRlcl9rZXksIHNsb3RfcHJlZml4LCBtZW1iZXIsIHR0bCkKICAgIGVsc2UKICAgICAgICAtLSBBbm90aGVyIHdvcmtlciBjcmVhdGVkIGl0IGJldHdlZW4gb3VyIHByb2JlIGFuZCBvdXIgYWRkOyBvdXIgKzEgc3RpbGwgY291bnRzLgogICAgICAgIGFuYWx5dGljczppbmNyKGtleSwgMSkKICAgIGVuZAplbmQKCmxvY2FsIFJJTkcgICA9IDEwMDAKbG9jYWwgRDI0SCAgID0gODY0MDAKbG9jYWwgRDQ4SCAgID0gMTcyODAwCmxvY2FsIEQxSCAgICA9IDM2MDAKCi0tIERpc3RpbmN0IHBhdGhzIHRyYWNrZWQgcGVyIGRvbWFpbiBwZXIgZGF5LiBQYXN0IHRoaXMgdGhlIHRhaWwgZm9sZHMgaW50bwotLSAib3RoZXIiIHJhdGhlciB0aGFuIGdyb3dpbmcgdGhlIHpvbmUg4oCUIGEgVVJMLWZ1enppbmcgYm90IGlzIGNhcHBlZCBhdCBvbmUKLS0gZXh0cmEga2V5LCBub3QgdGhvdXNhbmRzLgpsb2NhbCBQQVRIX0NBUkRJTkFMSVRZX0NBUCA9IDIwMDAKCi0tIOKUgOKUgCBDYXB0dXJlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKbG9jYWwgaG9zdCA9IG5vcm1hbGl6ZShuZ3gudmFyLmhvc3QpCmlmIG5vdCBob3N0IHRoZW4gcmV0dXJuIGVuZAoKbG9jYWwgaXAgICAgICA9IG5neC52YXIucmVtb3RlX2FkZHIgICAgb3IgIjAuMC4wLjAiCmxvY2FsIHRzICAgICAgPSBuZ3gubm93KCkKbG9jYWwgdWEgICAgICA9IG5neC52YXIuaHR0cF91c2VyX2FnZW50IG9yICIiCmxvY2FsIHVyaSAgICAgPSBuZ3gudmFyLnJlcXVlc3RfdXJpICAgIG9yICIvIgpsb2NhbCByZXFfbGVuID0gdG9udW1iZXIobmd4LnZhci5yZXF1ZXN0X2xlbmd0aCkgb3IgMApsb2NhbCBieXRlcyAgID0gdG9udW1iZXIobmd4LnZhci5ieXRlc19zZW50KSAgICAgb3IgMApsb2NhbCBydCAgICAgID0gdG9udW1iZXIobmd4LnZhci5yZXF1ZXN0X3RpbWUpICAgb3IgMCAgLS0gc2Vjb25kcyAoZmxvYXQpCmxvY2FsIG1ldGhvZCAgPSBuZ3gudmFyLnJlcXVlc3RfbWV0aG9kIG9yICJHRVQiCmxvY2FsIHN0YXR1cyAgPSBuZ3gudmFyLnN0YXR1cyAgICAgICAgIG9yICIwIgoKLS0gQ2xpZW50IGNvdW50cnksIHJlc29sdmVkIE9OQ0UgcGVyIHJlcXVlc3QuCi0tCi0tIEhvaXN0ZWQgb3V0IG9mIHRoZSBnZW8gYmxvY2sgYmVjYXVzZSBUSFJFRSBjb25zdW1lcnMgbmVlZCBpdCDigJQgdGhlIGRhaWx5L3Blci1taW51dGUKLS0gcm9sbHVwcywgdGhlIHJhdyByaW5nIGJ1ZmZlciBiZWhpbmQgL2xvZ3MvcmVjZW50LCBhbmQgdGhlIGxpdmUgU1NFIHBpcGUuIEl0IHVzZWQgdG8gYmUKLS0gbG9va2VkIHVwIGluc2lkZSB0aGUgcm9sbHVwIGFuZCBhZ2FpbiBpbnNpZGUgcGlwZV9sb2csIHNvIHRoZSByaW5nIGJ1ZmZlciBoYWQgbm8KLS0gY291bnRyeSBhdCBhbGw6IGEgcmVxdWVzdC1sb2cgbGlzdCBzaG93ZWQgZmxhZ3Mgb24gcm93cyB0aGF0IGFycml2ZWQgbGl2ZSBhbmQgbm9uZSBvbgotLSByb3dzIGJhY2tmaWxsZWQgZnJvbSAvbG9ncy9yZWNlbnQsIGZvciB0aGUgc2FtZSB0cmFmZmljLgotLQotLSBwY2FsbCdkIGJlY2F1c2UgYSBjb3JydXB0IG9yIHBhcnRpYWxseS13cml0dGVuIG1tZGIgbWFrZXMgdGhlIGxvb2t1cCByYWlzZSwgYW5kIGFuCi0tIGVycm9yIGhlcmUgd291bGQgYWJvcnQgZXZlcnkgY291bnRlciBiZWxvdyBpdCAoc2VlIHRoZSBzZWN0aW9uIGhlYWRlcikuCmxvY2FsIGNjID0gbmlsCmlmIGdlbyBhbmQgZ2VvLmdldF9jb3VudHJ5X2NvZGUgdGhlbgogICAgbG9jYWwgb2tfY2MsIHJlcyA9IHBjYWxsKGdlby5nZXRfY291bnRyeV9jb2RlLCBpcCkKICAgIGlmIG9rX2NjIGFuZCB0eXBlKHJlcykgPT0gInN0cmluZyIgYW5kIHJlcyB+PSAiIiB0aGVuIGNjID0gcmVzIGVuZAplbmQKCi0tIOKUgOKUgCAxLiBNaW51dGUtYnVja2V0IGNvdW50ZXJzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKbG9jYWwgbWludXRlID0gbWF0aC5mbG9vcih0cyAvIDYwKQpsb2NhbCBwID0gInM6IiAuLiBob3N0IC4uICI6IiAuLiBtaW51dGUKCmFuYWx5dGljczppbmNyKHAgLi4gIjpyIiwgMSwgICAgICAwLCBEMjRIKQphbmFseXRpY3M6aW5jcihwIC4uICI6aSIsIHJlcV9sZW4sIDAsIEQyNEgpCmFuYWx5dGljczppbmNyKHAgLi4gIjpvIiwgYnl0ZXMsICAgMCwgRDI0SCkKCi0tIFJlc3BvbnNlIHRpbWUgYXMgZmxvYXQgc2Vjb25kcyAobWF0Y2hlcyBvcmlnaW5hbCBwcmVjaXNpb24pCmlmIHJ0ID4gMCB0aGVuCiAgICAtLSBzYWZlX2FkZCBpbml0aWFsaXplcywgaW5jciBhZGRzIC0gZW11bGF0ZSBISU5DUkJZRkxPQVQgd2l0aCBpbnRlZ2VyIG1pY3JvcwogICAgbG9jYWwgcnRfdXMgPSBtYXRoLmZsb29yKHJ0ICogMTAwMDAwMCkKICAgIGFuYWx5dGljczppbmNyKHAgLi4gIjp0IiwgcnRfdXMsIDAsIEQyNEgpCmVuZAoKLS0gVW5pcXVlIChub24tc3RhdGljKSByZXF1ZXN0IGNvdW50ZXIKaWYgbm90IGlzX3N0YXRpY19hc3NldCh1cmkpIHRoZW4KICAgIGFuYWx5dGljczppbmNyKHAgLi4gIjp1IiwgMSwgMCwgRDI0SCkKZW5kCgotLSDilIDilIAgMi4gTGlmZXRpbWUgdG90YWxzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKYW5hbHl0aWNzOmluY3IoInQ6IiAuLiBob3N0IC4uICI6ciIsIDEsICAgICAgIDApCmFuYWx5dGljczppbmNyKCJ0OiIgLi4gaG9zdCAuLiAiOmkiLCByZXFfbGVuLCAwKQphbmFseXRpY3M6aW5jcigidDoiIC4uIGhvc3QgLi4gIjpvIiwgYnl0ZXMsICAgMCkKCi0tIERvbWFpbiBpbmRleC4gYHNhZmVfYWRkYCByZXR1cm5pbmcgdHJ1ZSBtZWFucyB0aGlzIGlzIHRoZSBmaXJzdCByZXF1ZXN0IHRoaXMgYm94IGhhcwotLSBldmVyIHNlZW4gZm9yIHRoZSBob3N0LCB3aGljaCBpcyBleGFjdGx5IHdoZW4gdGhlIGVudW1lcmFibGUgaW5kZXggbmVlZHMgYXBwZW5kaW5nIOKAlAotLSBzbyBkb21haW4gZGlzY292ZXJ5IG5vIGxvbmdlciBjb3N0cyBhIHpvbmUgc2NhbiBlaXRoZXIuCmlmIGFuYWx5dGljczpzYWZlX2FkZCgiZDoiIC4uIGhvc3QsIDEpIHRoZW4KICAgIGluZGV4X2FkZCgiZG4iLCAiZGk6IiwgaG9zdCkKZW5kCgotLSDilIDilIAgMy4gRGFpbHkgcm9sbHVwOiBnZW8sIHZpc2l0b3JzLCBwYXRocywgc3RhdHVzZXMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACi0tCi0tIEVhY2ggc3ViLWJsb2NrIGlzIHBjYWxsJ2QgU0VQQVJBVEVMWSwgYW5kIHRoYXQgaXMgbG9hZC1iZWFyaW5nIHJhdGhlciB0aGFuCi0tIGRlZmVuc2l2ZSBoYWJpdC4gQSByYWlzZWQgZXJyb3IgaW4gbG9nX2J5X2x1YSBhYm9ydHMgdGhlIHJlbWFpbmRlciBvZiB0aGUKLS0gaGFuZGxlciwgc28gb25lIGJhZCBzaGRpY3QgY2FsbCBzaWxlbnRseSB6ZXJvZXMgZXZlcnkgY291bnRlciB3cml0dGVuIGFmdGVyIGl0IOKAlAotLSB3aGljaCBpcyBleGFjdGx5IHdoYXQgYW4gYGluY3IoLi4uLCBuaWwsIHR0bClgIGhlcmUgZGlkOiBwYXRocyBBTkQgc3RhdHVzZXMgcmVhZAotLSBhcyAibm8gdHJhZmZpYyIgd2hpbGUgcmVxdWVzdHMgYW5kIGJhbmR3aWR0aCBsb29rZWQgcGVyZmVjdC4gSXNvbGF0aW5nIHRoZW0KLS0gbWVhbnMgYSBmdXR1cmUgZWRpdCBjYW4gbG9zZSBhdCBtb3N0IGl0cyBvd24gbWV0cmljLgoKbG9jYWwgZGF5ICA9IHRvZGF5KCkKbG9jYWwgZ3BmeCA9ICJnOiIgLi4gaG9zdCAuLiAiOiIgLi4gZGF5IC4uICI6IgoKLS0gM2EuIEdlb0lQLiBgY2NgIHdhcyByZXNvbHZlZCBvbmNlIGFib3ZlIGFuZCBpcyByZXVzZWQgYnkgdGhlIHJpbmcgYnVmZmVyIGFuZCB0aGUKLS0gbGl2ZSBwaXBlLCBzbyBhIHJlcXVlc3QgY29zdHMgZXhhY3RseSBvbmUgbW1kYiBsb29rdXAgbm8gbWF0dGVyIGhvdyBtYW55IGNvbnN1bWVycwotLSByZXBvcnQgaXRzIGNvdW50cnkuCmlmIGNjIHRoZW4KICAgIHBjYWxsKGZ1bmN0aW9uKCkKICAgICAgICAtLSBEYWlseSBnZW8gKGZvciAvYW5hbHl0aWNzL2dlbyBlbmRwb2ludCkKICAgICAgICBidW1wX2luZGV4ZWQoZ3BmeCAuLiBjYywgRDQ4SCwgZ3BmeCAuLiAiY24iLCBncGZ4IC4uICJjaToiLCBjYykKICAgICAgICAtLSBQZXItbWludXRlIGdlbyAoZm9yIHRoZSB0aW1lLXNlcmllcyBjb3VudHJ5IGJyZWFrZG93bikuIEluZGV4ZWQgcGVyIE1JTlVURSwgc28KICAgICAgICAtLSB0aGUgc2NyYXBlciByZWFkcyBvbmx5IHRoZSBtaW51dGVzIGluIGl0cyB3aW5kb3cuCiAgICAgICAgbG9jYWwgbXBmeCA9ICJjOiIgLi4gaG9zdCAuLiAiOiIgLi4gbWludXRlIC4uICI6IgogICAgICAgIGJ1bXBfaW5kZXhlZChtcGZ4IC4uIGNjLCBEMjRILCBtcGZ4IC4uICJuIiwgbXBmeCAuLiAiaToiLCBjYykKICAgIGVuZCkKZW5kCgotLSAzYi4gRGlzdGluY3QgdmlzaXRvcnMg4oCUIGEgQ09VTlQsIG5ldmVyIGFuIGlkZW50aXR5LgotLQotLSBUaGUgYWRkcmVzcyBpcyBoYXNoZWQgd2l0aCBhIHNhbHQgdGhhdCBpcyBnZW5lcmF0ZWQgb24gdGhpcyBib3gsIHJvdGF0ZXMgZGFpbHksCi0tIGFuZCBpcyBuZXZlciB3cml0dGVuIGFueXdoZXJlIGJ1dCB0aGlzIHNoYXJlZCBkaWN0LCBzbyB0aGUgbWFya2VyIGtleXMgYXJlIG5vdAotLSByZXZlcnNpYmxlIHRvIGFuIElQIGFuZCBhcmUgd29ydGhsZXNzIHRoZSBuZXh0IGRheS4gT25seSB0aGUgcmVzdWx0aW5nIGNvdW50ZXIKLS0gaXMgZXZlciBmbHVzaGVkIHRvIFBvc3RncmVzOyBubyBwZXItdmlzaXRvciByb3cgZXhpc3RzIGF0IGFueSBsYXllci4gVGhhdCBpcwotLSB3aGF0IGxldHMgdXMgcmVwb3J0IHJlYWwgdmlzaXRvciBudW1iZXJzIHdoaWxlIHN0aWxsIG5vdCBjb2xsZWN0aW5nIGJlaGF2aW91cmFsCi0tIGFuYWx5dGljcyBvbiBhbnlvbmUncyBlbmQgdXNlcnMuCi0tCi0tIFBlciBEQVksIG5vdCBwZXIgbWludXRlOiBhIHBlci1taW51dGUgc2V0IGlzIH4xNDQweCB0aGUga2V5cyBmb3IgYSBudW1iZXIKLS0gbm9ib2R5IHJlYWRzLCBhbmQgd291bGQgZXZpY3QgdGhlIGNvdW50ZXJzIGl0IGV4aXN0cyB0byBhbm5vdGF0ZS4KcGNhbGwoZnVuY3Rpb24oKQppZiB2aXNpdG9ycyB0aGVuCiAgICBsb2NhbCBzYWx0X2tleSA9ICJ2c2FsdDoiIC4uIGRheQogICAgbG9jYWwgc2FsdCA9IHZpc2l0b3JzOmdldChzYWx0X2tleSkKICAgIGlmIG5vdCBzYWx0IHRoZW4KICAgICAgICAtLSBGaXJzdCB3cml0ZXIgd2luczsgYSByYWNpbmcgd29ya2VyJ3Mgc2FmZV9hZGQgZmFpbHMgYW5kIGl0IHJlLXJlYWRzLiBUaGUKICAgICAgICAtLSBzYWx0IG9ubHkgaGFzIHRvIGJlIHVucHJlZGljdGFibGUgYW5kIHN0YWJsZSBmb3IgdGhlIGRheS4KICAgICAgICBzYWx0ID0gdG9zdHJpbmcobmd4Lm5vdygpKSAuLiB0b3N0cmluZyhtYXRoLnJhbmRvbSgxLCAyMTQ3NDgzNjQ3KSkKICAgICAgICBsb2NhbCBvayA9IHZpc2l0b3JzOnNhZmVfYWRkKHNhbHRfa2V5LCBzYWx0LCBENDhIKQogICAgICAgIGlmIG5vdCBvayB0aGVuIHNhbHQgPSB2aXNpdG9yczpnZXQoc2FsdF9rZXkpIG9yIHNhbHQgZW5kCiAgICBlbmQKICAgIC0tIHNhZmVfYWRkIGlzIHRoZSBkZWR1cDogaXQgc3VjY2VlZHMgT05MWSBvbiB0aGlzIHZpc2l0b3IncyBmaXJzdCByZXF1ZXN0CiAgICAtLSB0b2RheSwgc28gdGhlIGNvdW50ZXIgYmVsb3cgaW5jcmVtZW50cyBleGFjdGx5IG9uY2UgcGVyIGRpc3RpbmN0IHZpc2l0b3IuCiAgICBsb2NhbCBtYXJrZXIgPSAidmQ6IiAuLiBob3N0IC4uICI6IiAuLiBkYXkgLi4gIjoiIC4uIG5neC5jcmMzMl9sb25nKHNhbHQgLi4gaXApCiAgICBpZiB2aXNpdG9yczpzYWZlX2FkZChtYXJrZXIsIDEsIEQ0OEgpIHRoZW4KICAgICAgICBhbmFseXRpY3M6aW5jcihncGZ4IC4uICJ2IiwgMSwgMCwgRDQ4SCkKICAgIGVuZAplbmQKZW5kKQoKLS0gM2MuIFRvcCBwYXRocyDigJQgT1BULUlOLCBub24tc3RhdGljIG9ubHksIG5vcm1hbGl6ZWQgYW5kIGNhcmRpbmFsaXR5LWNhcHBlZC4KLS0KLS0gT2ZmIHVubGVzcyB0aGUgcHJvamVjdCB0dXJuZWQgaXQgb24sIGJlY2F1c2UgdGhpcyBvbmUgYmxvY2sgaXMgdGhlIG1vc3QgZXhwZW5zaXZlIHRoaW5nCi0tIHRoZSBsb2cgaGFuZGxlciBkb2VzLiBNZWFzdXJlZCBvbiB0aGUgc2hpcHBlZCBlZGdlIGltYWdlLCBwZXIgcmVxdWVzdDoKLS0KLS0gICAgIHBhdGhzICh3aG9sZSBibG9jaykgICAgICAgIDEuNzIgdXMgICAgICA8LSA1NyUgb2YgdGhlIGNvdW50ZXIgcGF0aAotLSAgICAgICBvZiB3aGljaCBzdHJpbmcgd29yayAgICAgMS4zOCB1cyAgICAgIG5vcm1hbGl6ZV9wYXRoICsgaXNfc3RhdGljX2Fzc2V0Ci0tICAgICBtaW51dGUgYnVja2V0cyAoNSBpbmNyKSAgICAwLjYxIHVzCi0tICAgICBjb3VudHJ5ICgyIGluY3IpICAgICAgICAgICAwLjI0IHVzCi0tICAgICBzdGF0dXMgKDEgaW5jcikgICAgICAgICAgICAwLjE0IHVzCi0tICAgICB0aGlzIGZsYWcgcmVhZCAoMSBnZXQpICAgICAwLjA3IHVzCi0tCi0tIFNvIHRoZSBnYXRlIGNvc3RzIDAuMDcgdXMgYW5kIHNhdmVzIDEuNzIgdXMg4oCUIHRoZSBjb3VudGVyIHBhdGggZHJvcHMgZnJvbSB+My4wIHVzIHRvCi0tIH4xLjM1IHVzIHdpdGggcGF0aHMgb2ZmLiBJdCBpcyBhbHNvIHRoZSBoaWdoZXN0LWNhcmRpbmFsaXR5IGRpbWVuc2lvbiAodXAgdG8KLS0gUEFUSF9DQVJESU5BTElUWV9DQVAga2V5cyBwZXIgZG9tYWluIHBlciBkYXksIGFnYWluc3QgfjIwMCBjb3VudHJpZXMgYW5kIGEgZmV3IGRvemVuCi0tIHN0YXR1c2VzKSBhbmQgdGhlIGxhcmdlc3QgY29sdW1uIGluIHRoZSBkYWlseSByb2xsdXAuCi0tCi0tIEFic2VudCBmbGFnID0gb2ZmLiBBIGJveCB3aG9zZSBkaWN0IHdhcyBqdXN0IHJlc3RhcnRlZCB0aGVyZWZvcmUgY29sbGVjdHMgbm90aGluZyB1bnRpbAotLSB0aGUgQVBJIHJlLXB1c2hlcywgd2hpY2ggaXMgdGhlIHNhZmUgZGlyZWN0aW9uOiBubyBkYXRhIGJlYXRzIGRhdGEgbm9ib2R5IGFza2VkIHRvIHBheQotLSBmb3IuIFRoZSBEQiBpcyB0aGUgc291cmNlIG9mIHRydXRoIGFuZCByZS1wdXNoZXMgb24gZXZlcnkgcm91dGUgYXBwbHkuCmxvY2FsIGNvbGxlY3RfcGF0aHMgPSBydWxlc19kaWN0IGFuZCBydWxlc19kaWN0OmdldCgiY2ZnOiIgLi4gaG9zdCAuLiAiOnBhdGhzIikKCnBjYWxsKGZ1bmN0aW9uKCkKaWYgY29sbGVjdF9wYXRocyBhbmQgbm90IGlzX3N0YXRpY19hc3NldCh1cmkpIHRoZW4KICAgIC0tIEhvaXN0ZWQ6IG5vcm1hbGl6ZV9wYXRoIGlzIHRoZSBzaW5nbGUgbW9zdCBleHBlbnNpdmUgY2FsbCBpbiB0aGlzIGhhbmRsZXIgKH4xLjQgdXMKICAgIC0tIG9mIHN0cmluZyB3b3JrKSwgc28gaXQgcnVucyBleGFjdGx5IG9uY2UgZXZlbiB0aG91Z2ggYm90aCB0aGUgY291bnRlciBrZXkgYW5kIHRoZQogICAgLS0gaW5kZXggc2xvdCBuZWVkIGl0cyByZXN1bHQuCiAgICBsb2NhbCBub3JtID0gbm9ybWFsaXplX3BhdGgodXJpKQogICAgbG9jYWwgcGF0aF9rZXkgPSBncGZ4IC4uICJwOiIgLi4gbm9ybQogICAgLS0gaW5jci10aGVuLWFkZDogdGhlIGhvdCBwYXRoIGlzIE9ORSBoYXNoIGhpdCBvbiBhbiBleGlzdGluZyBrZXkuIGBpbmNyYCB3aXRoCiAgICAtLSBubyBpbml0IHJldHVybnMgbmlsIGZvciBhbiBhYnNlbnQga2V5LCB3aGljaCBkb3VibGVzIGFzIHRoZSBleGlzdGVuY2UgcHJvYmUsCiAgICAtLSBzbyBvbmx5IGEgcGF0aCB1bnNlZW4gdG9kYXkgcmVhY2hlcyB0aGUgY2FwIGNoZWNrIGJlbG93LgogICAgLS0KICAgIC0tIERlbGliZXJhdGVseSBubyBpbml0X3R0bCBoZXJlOiBzaGRpY3QgcmVqZWN0cyBpbml0X3R0bCB1bmxlc3MgaW5pdCBpcyBhbHNvCiAgICAtLSBnaXZlbiAoIidpbml0X3R0bCcgbXVzdCBiZSB1c2VkIHdpdGggJ2luaXQnIiksIGFuZCB0aGF0IHJhaXNlcyBhIEx1YSBlcnJvcgogICAgLS0gd2hpY2ggYWJvcnRzIHRoZSB3aG9sZSBsb2cgaGFuZGxlciDigJQgdGFraW5nIHRoZSBzdGF0dXMgY291bnRlcnMgYmVsb3cgZG93bgogICAgLS0gd2l0aCBpdC4gVGhlIFRUTCBpcyBzZXQgYnkgdGhlIHNhZmVfYWRkIG9uIHRoZSBjcmVhdGluZyByZXF1ZXN0IGluc3RlYWQuCiAgICBpZiBub3QgYW5hbHl0aWNzOmluY3IocGF0aF9rZXksIDEpIHRoZW4KICAgICAgICBsb2NhbCBkaXN0aW5jdCA9IGFuYWx5dGljczppbmNyKGdwZnggLi4gInBuIiwgMSwgMCwgRDQ4SCkgb3IgMAogICAgICAgIGlmIGRpc3RpbmN0ID4gUEFUSF9DQVJESU5BTElUWV9DQVAgdGhlbgogICAgICAgICAgICBhbmFseXRpY3M6aW5jcihncGZ4IC4uICJwOm90aGVyIiwgMSwgMCwgRDQ4SCkKICAgICAgICBlbHNlCiAgICAgICAgICAgIC0tIGBwbmAgd2FzIGFscmVhZHkgdGhlIGRpc3RpbmN0LXBhdGggY291bnRlciwgc28gdGhlIHNsb3RzIGp1c3QgZ2l2ZSBpdCBhbgogICAgICAgICAgICAtLSBlbnVtZXJhYmxlIHNpZGUuIFN0b3JlZCBXSVRIT1VUIHRoZSAicDoiIHByZWZpeDsgdGhlIHJlYWRlciBhZGRzIGl0IGJhY2suCiAgICAgICAgICAgIGlmIGFuYWx5dGljczpzYWZlX2FkZChwYXRoX2tleSwgMSwgRDQ4SCkgdGhlbgogICAgICAgICAgICAgICAgYW5hbHl0aWNzOnNldChncGZ4IC4uICJwaToiIC4uIGRpc3RpbmN0LCBub3JtLCBENDhIKQogICAgICAgICAgICBlbmQKICAgICAgICBlbmQKICAgIGVuZAplbmQKZW5kKQoKLS0gM2QuIFN0YXR1cy1jb2RlIG1peC4gQm91bmRlZCBieSBjb25zdHJ1Y3Rpb24gKGEgZmV3IGRvemVuIGNvZGVzKS4KcGNhbGwoZnVuY3Rpb24oKQogICAgYnVtcF9pbmRleGVkKGdwZnggLi4gInM6IiAuLiBzdGF0dXMsIEQ0OEgsIGdwZnggLi4gInNuIiwgZ3BmeCAuLiAic2k6Iiwgc3RhdHVzKQplbmQpCgotLSDilIDilIAgNC4gUmF3IHJlcXVlc3QgcmluZyBidWZmZXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgpwY2FsbChmdW5jdGlvbigpCiAgICBsb2NhbCBva19qLCBqID0gcGNhbGwoY2pzb24uZW5jb2RlLCB7CiAgICAgICAgaXAgICAgID0gaXAsCiAgICAgICAgLS0gbmlsIGlzIHNpbXBseSBvbWl0dGVkIGJ5IGNqc29uLCBzbyBhIGJveCB3aXRoIG5vIEdlb0lQIHdyaXRlcyB0aGUgc2FtZSBzaGFwZQogICAgICAgIC0tIG1pbnVzIHRoaXMga2V5IHJhdGhlciB0aGFuIGEgbnVsbCB0aGUgcmVhZGVyIGhhcyB0byBzcGVjaWFsLWNhc2UuCiAgICAgICAgY291bnRyeSA9IGNjLAogICAgICAgIHRzICAgICA9IHRzLAogICAgICAgIG1ldGhvZCA9IG1ldGhvZCwKICAgICAgICBzdGF0dXMgPSBzdGF0dXMsCiAgICAgICAgdXJpICAgID0gdXJpLAogICAgICAgIHVhICAgICA9IHVhLAogICAgICAgIGJ3X2luICA9IHJlcV9sZW4sCiAgICAgICAgYndfb3V0ID0gYnl0ZXMsCiAgICAgICAgcnQgICAgID0gcnQsCiAgICB9KQogICAgaWYgb2tfaiBhbmQgaiB0aGVuCiAgICAgICAgbG9jYWwgc2VxICA9IHJlcXVlc3RfZGF0YTppbmNyKCJybG9nOiIgLi4gaG9zdCAuLiAiOnNlcSIsIDEsIDApCiAgICAgICAgbG9jYWwgc2xvdCA9IHNlcSAlIFJJTkcKICAgICAgICByZXF1ZXN0X2RhdGE6c2V0KCJybG9nOiIgLi4gaG9zdCAuLiAiOiIgLi4gc2xvdCwgaiwgRDFIKQogICAgZW5kCmVuZCkKCi0tIOKUgOKUgCA1LiBMaXZlLWxvZyBwaXBlIChvbmx5IHdoZW4gYSBzdWJzY3JpYmVyIGlzIHdhdGNoaW5nKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKLS0gRmlyZSB2aWEgdGltZXIgdG8gYXZvaWQgYmxvY2tpbmcgdGhlIGxvZyBwaGFzZQoKaWYgcGlwZV9sb2cgYW5kIHBpcGVfbG9nLnBpcGVfcmVxdWVzdF9sb2cKICAgYW5kIHJlcXVlc3RfZGF0YTpnZXQoImxvZ19waXBlOnN1YjoiIC4uIGhvc3QpIHRoZW4KICAgIG5neC50aW1lci5hdCgwLCBwaXBlX2xvZy5waXBlX3JlcXVlc3RfbG9nLAogICAgICAgICAgICAgICAgIGhvc3QsIGlwLCB0cywgdWEsIHVyaSwgcmVxX2xlbiwgYnl0ZXMsIHJ0LCBtZXRob2QsIHN0YXR1cywgY2MpCmVuZAo=",
28
+ "webhook_handler.lua": "LS0gd2ViaG9va19oYW5kbGVyLmx1YQotLSBIYW5kbGVzIGluY29taW5nIHdlYmhvb2sgZXZlbnRzIGZvcndhcmRlZCBmcm9tIHRoZSBTYWFTIGVkZ2UuCi0tIEludGVybmFsIG1hbmFnZW1lbnQgcG9ydCBvbmx5ICgxMjcuMC4wLjE6OTE0NSkuCi0tCi0tIFJvdXRlczoKLS0gICBQT1NUIC9faG9va3MvcHVzaCAgICAgICAgICAtIHJlY2VpdmUgYSBmb3J3YXJkZWQgR2l0SHViIHB1c2ggZXZlbnQKLS0gICBHRVQgIC9faG9va3MvcGVuZGluZyAgICAgICAtIGZldGNoIHN0b3JlZCBldmVudHMgKGZvciBsb2NhbCBhcHAgcG9sbGluZykKLS0gICBQT1NUIC9faG9va3MvYWNrICAgICAgICAgICAtIGFja25vd2xlZGdlIGNvbnN1bWVkIGV2ZW50cwotLQotLSBCZWhhdmlvciBvbiBQT1NUIC9faG9va3MvcHVzaDoKLS0gICAxLiBUcnkgdG8gcHJveHkgdG8gYSBsb2NhbCBPcGVuc2hpcCBBUEkgKGNvbmZpZ3VyYWJsZSB2aWEgWC1PcGVuc2hpcC1VcmwgaGVhZGVyKQotLSAgIDIuIElmIE9wZW5zaGlwIGlzIG5vdCByZWFjaGFibGUsIHN0b3JlIHRoZSBldmVudCBpbiBzaGFyZWQgZGljdCBmb3IgbGF0ZXIgcG9sbGluZwoKbG9jYWwgY2pzb24gPSByZXF1aXJlICJjanNvbi5zYWZlIgoKbG9jYWwgd2ViaG9va19ldmVudHMgPSBuZ3guc2hhcmVkLndlYmhvb2tfZXZlbnRzCmxvY2FsIHVyaSAgICAgICAgICAgID0gbmd4LnZhci51cmkKbG9jYWwgbWV0aG9kICAgICAgICAgPSBuZ3gucmVxLmdldF9tZXRob2QoKQoKbG9jYWwgZnVuY3Rpb24ganNvbl9yZXNwb25zZShkYXRhLCBjb2RlKQogICAgbmd4LnN0YXR1cyA9IGNvZGUgb3IgMjAwCiAgICBuZ3guaGVhZGVyWyJDb250ZW50LVR5cGUiXSA9ICJhcHBsaWNhdGlvbi9qc29uIgogICAgbmd4LnNheShjanNvbi5lbmNvZGUoZGF0YSkpCiAgICByZXR1cm4gbmd4LmV4aXQobmd4LnN0YXR1cykKZW5kCgotLSDilIDilIAgUE9TVCAvX2hvb2tzL3B1c2gg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACi0tIFJlY2VpdmVzIGZvcndhcmRlZCB3ZWJob29rIHBheWxvYWQgZnJvbSBTYWFTLgotLSBIZWFkZXJzOgotLSAgIFgtT3BlbnNoaXAtVXJsOiBodHRwOi8vMTI3LjAuMC4xOjM0NTYgKGlmIE9wZW5zaGlwIHJ1bnMgb24gdGhpcyBzZXJ2ZXIpCi0tICAgWC1Ib29rLUlkOiB0aGUgc3Vic2NyaXB0aW9uIGhvb2tJZCAoZm9yIGNvcnJlbGF0aW9uKQoKaWYgdXJpID09ICIvX2hvb2tzL3B1c2giIGFuZCBtZXRob2QgPT0gIlBPU1QiIHRoZW4KICAgIG5neC5yZXEucmVhZF9ib2R5KCkKICAgIGxvY2FsIGJvZHkgPSBuZ3gucmVxLmdldF9ib2R5X2RhdGEoKQogICAgaWYgbm90IGJvZHkgdGhlbgogICAgICAgIHJldHVybiBqc29uX3Jlc3BvbnNlKHsgZXJyb3IgPSAiZW1wdHkgYm9keSIgfSwgNDAwKQogICAgZW5kCgogICAgbG9jYWwgb3BlbnNoaXBfdXJsID0gbmd4LnJlcS5nZXRfaGVhZGVycygpWyJ4LW9wZW5zaGlwLXVybCJdCgogICAgLS0gSWYgT3BlbnNoaXAgcnVucyBvbiB0aGlzIHNlcnZlciwgcHJveHkgZGlyZWN0bHkKICAgIGlmIG9wZW5zaGlwX3VybCBhbmQgb3BlbnNoaXBfdXJsIH49ICIiIHRoZW4KICAgICAgICBsb2NhbCBodHRwID0gcmVxdWlyZSAicmVzdHkuaHR0cCIKICAgICAgICBsb2NhbCBodHRwYyA9IGh0dHAubmV3KCkKICAgICAgICBodHRwYzpzZXRfdGltZW91dCg1MDAwKQoKICAgICAgICBsb2NhbCB0YXJnZXQgPSBvcGVuc2hpcF91cmwgLi4gIi9hcGkvd2ViaG9va3MvcHVzaCIKICAgICAgICBsb2NhbCByZXMsIGVyciA9IGh0dHBjOnJlcXVlc3RfdXJpKHRhcmdldCwgewogICAgICAgICAgICBtZXRob2QgID0gIlBPU1QiLAogICAgICAgICAgICBib2R5ICAgID0gYm9keSwKICAgICAgICAgICAgaGVhZGVycyA9IHsKICAgICAgICAgICAgICAgIFsiQ29udGVudC1UeXBlIl0gPSAiYXBwbGljYXRpb24vanNvbiIsCiAgICAgICAgICAgICAgICBbIlgtSG9vay1JZCJdICAgID0gbmd4LnJlcS5nZXRfaGVhZGVycygpWyJ4LWhvb2staWQiXSBvciAiIiwKICAgICAgICAgICAgfSwKICAgICAgICB9KQoKICAgICAgICBpZiByZXMgYW5kIHJlcy5zdGF0dXMgPCA1MDAgdGhlbgogICAgICAgICAgICAtLSBPcGVuc2hpcCBoYW5kbGVkIGl0ICgyeHggb3IgNHh4KQogICAgICAgICAgICByZXR1cm4ganNvbl9yZXNwb25zZSh7IG9rID0gdHJ1ZSwgcHJveGllZCA9IHRydWUsIHN0YXR1cyA9IHJlcy5zdGF0dXMgfSkKICAgICAgICBlbmQKCiAgICAgICAgLS0gT3BlbnNoaXAgdW5yZWFjaGFibGUgb3IgZXJyb3JlZCAtIGZhbGwgdGhyb3VnaCB0byBzdG9yZQogICAgZW5kCgogICAgLS0gU3RvcmUgZm9yIGxhdGVyIHBvbGxpbmcgYnkgbG9jYWwvZGVza3RvcCBhcHAKICAgIGxvY2FsIGV2ZW50X2lkID0gbmd4Lm5vdygpIC4uICI6IiAuLiBtYXRoLnJhbmRvbSgxMDAwMDAsIDk5OTk5OSkKICAgIGxvY2FsIGV2ZW50ID0gY2pzb24uZW5jb2RlKHsKICAgICAgICBpZCAgICAgICA9IGV2ZW50X2lkLAogICAgICAgIGhvb2tfaWQgID0gbmd4LnJlcS5nZXRfaGVhZGVycygpWyJ4LWhvb2staWQiXSBvciAiIiwKICAgICAgICBwYXlsb2FkICA9IGJvZHksCiAgICAgICAgcmVjZWl2ZWQgPSBuZ3gubm93KCksCiAgICB9KQoKICAgIC0tIFVzZSBhIHNsb3QtYmFzZWQgcmluZyBidWZmZXIgKG1heCAyMDAgZXZlbnRzKQogICAgbG9jYWwgbWF4X2V2ZW50cyA9IDIwMAogICAgbG9jYWwgaWR4ID0gd2ViaG9va19ldmVudHM6aW5jcigiX2lkeCIsIDEsIDApIG9yIDAKICAgIGxvY2FsIHNsb3QgPSAoaWR4ICUgbWF4X2V2ZW50cykKICAgIHdlYmhvb2tfZXZlbnRzOnNldCgiZXZ0OiIgLi4gc2xvdCwgZXZlbnQsIDM2MDApIC0tIDFoIFRUTAogICAgd2ViaG9va19ldmVudHM6c2V0KCJfY291bnQiLCBtYXRoLm1pbihpZHgsIG1heF9ldmVudHMpKQoKICAgIHJldHVybiBqc29uX3Jlc3BvbnNlKHsgb2sgPSB0cnVlLCBzdG9yZWQgPSB0cnVlLCBldmVudF9pZCA9IGV2ZW50X2lkIH0pCmVuZAoKLS0g4pSA4pSAIEdFVCAvX2hvb2tzL3BlbmRpbmcg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACi0tIFJldHVybnMgc3RvcmVkIHdlYmhvb2sgZXZlbnRzIGZvciBsb2NhbCBhcHAgdG8gY29uc3VtZS4KCmlmIHVyaSA9PSAiL19ob29rcy9wZW5kaW5nIiBhbmQgbWV0aG9kID09ICJHRVQiIHRoZW4KICAgIGlmIG5vdCB3ZWJob29rX2V2ZW50cyB0aGVuCiAgICAgICAgcmV0dXJuIGpzb25fcmVzcG9uc2UoeyBldmVudHMgPSB7fSB9KQogICAgZW5kCgogICAgbG9jYWwgY291bnQgPSB3ZWJob29rX2V2ZW50czpnZXQoIl9jb3VudCIpIG9yIDAKICAgIGxvY2FsIGlkeCAgID0gd2ViaG9va19ldmVudHM6Z2V0KCJfaWR4Iikgb3IgMAogICAgbG9jYWwgZXZlbnRzID0ge30KCiAgICAtLSBSZWFkIGFsbCBzdG9yZWQgZXZlbnRzIChuZXdlc3QgZmlyc3QpCiAgICBsb2NhbCBtYXhfZXZlbnRzID0gMjAwCiAgICBsb2NhbCBzdGFydCA9IG1hdGgubWF4KDAsIGlkeCAtIGNvdW50KQogICAgZm9yIGkgPSBzdGFydCwgaWR4IC0gMSBkbwogICAgICAgIGxvY2FsIHNsb3QgPSBpICUgbWF4X2V2ZW50cwogICAgICAgIGxvY2FsIHJhdyA9IHdlYmhvb2tfZXZlbnRzOmdldCgiZXZ0OiIgLi4gc2xvdCkKICAgICAgICBpZiByYXcgdGhlbgogICAgICAgICAgICBsb2NhbCBwYXJzZWQgPSBjanNvbi5kZWNvZGUocmF3KQogICAgICAgICAgICBpZiBwYXJzZWQgdGhlbgogICAgICAgICAgICAgICAgZXZlbnRzWyNldmVudHMgKyAxXSA9IHBhcnNlZAogICAgICAgICAgICBlbmQKICAgICAgICBlbmQKICAgIGVuZAoKICAgIHJldHVybiBqc29uX3Jlc3BvbnNlKHsgZXZlbnRzID0gZXZlbnRzIH0pCmVuZAoKLS0g4pSA4pSAIFBPU1QgL19ob29rcy9hY2sg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACi0tIEFja25vd2xlZGdlIGV2ZW50cyBoYXZlIGJlZW4gY29uc3VtZWQgLSBjbGVhcnMgdGhlIHN0b3JlLgoKaWYgdXJpID09ICIvX2hvb2tzL2FjayIgYW5kIG1ldGhvZCA9PSAiUE9TVCIgdGhlbgogICAgaWYgd2ViaG9va19ldmVudHMgdGhlbgogICAgICAgIHdlYmhvb2tfZXZlbnRzOmZsdXNoX2FsbCgpCiAgICAgICAgd2ViaG9va19ldmVudHM6Zmx1c2hfZXhwaXJlZCgpCiAgICBlbmQKICAgIHJldHVybiBqc29uX3Jlc3BvbnNlKHsgb2sgPSB0cnVlIH0pCmVuZAoKLS0g4pSA4pSAIEZhbGxiYWNrIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApyZXR1cm4ganNvbl9yZXNwb25zZSh7IGVycm9yID0gIm5vdCBmb3VuZCIgfSwgNDA0KQo="
29
+ };
30
+
31
+ // ../../packages/adapters/src/infra/cloudflare-ips.generated.ts
32
+ var CLOUDFLARE_IPV4 = [
33
+ "173.245.48.0/20",
34
+ "103.21.244.0/22",
35
+ "103.22.200.0/22",
36
+ "103.31.4.0/22",
37
+ "141.101.64.0/18",
38
+ "108.162.192.0/18",
39
+ "190.93.240.0/20",
40
+ "188.114.96.0/20",
41
+ "197.234.240.0/22",
42
+ "198.41.128.0/17",
43
+ "162.158.0.0/15",
44
+ "104.16.0.0/13",
45
+ "104.24.0.0/14",
46
+ "172.64.0.0/13",
47
+ "131.0.72.0/22"
48
+ ];
49
+ var CLOUDFLARE_IPV6 = [
50
+ "2400:cb00::/32",
51
+ "2606:4700::/32",
52
+ "2803:f800::/32",
53
+ "2405:b500::/32",
54
+ "2405:8100::/32",
55
+ "2a06:98c0::/29",
56
+ "2c0f:f248::/32"
57
+ ];
58
+
59
+ // ../../packages/adapters/src/infra/edge-real-ip.ts
60
+ var EDGE_REAL_IP_CONF_NAME = "openship-real-ip.conf";
61
+ function edgeRealIpHeader() {
62
+ const raw = process.env.OPENSHIP_EDGE_REAL_IP_HEADER?.trim();
63
+ if (raw && /^[A-Za-z0-9-]{1,64}$/.test(raw)) return raw;
64
+ return "CF-Connecting-IP";
65
+ }
66
+ function edgeTrustedProxies() {
67
+ const raw = process.env.OPENSHIP_EDGE_TRUSTED_PROXIES?.trim();
68
+ if (!raw) return [];
69
+ const CIDR = /^(?:(?:\d{1,3}\.){3}\d{1,3}|[0-9a-fA-F:]+)(?:\/\d{1,3})?$/;
70
+ return raw.split(/[,\s]+/).map((s) => s.trim()).filter((s) => s.length > 0 && s.length <= 64 && CIDR.test(s));
71
+ }
72
+ function edgeRealIpConf() {
73
+ const header = edgeRealIpHeader();
74
+ const extra = edgeTrustedProxies();
75
+ const lines = [
76
+ "# Openship \u2014 recover the real client address from a trusted front proxy.",
77
+ "#",
78
+ "# GENERATED. Source: packages/adapters/src/infra/edge-real-ip.ts",
79
+ "#",
80
+ "# Without this, remote_addr is the PROXY on any box behind Cloudflare or a load",
81
+ "# balancer, which silently breaks four things at once: visitor country resolves to",
82
+ "# the PoP, distinct-visitor counts collapse toward the number of PoPs, per-IP rate",
83
+ "# limits put the whole planet behind one PoP in a single bucket, and IP bans ban a",
84
+ "# PoP instead of a visitor.",
85
+ "#",
86
+ "# set_real_ip_from does NOT mean 'trust this header'. It means 'trust this header",
87
+ "# only when the TCP peer is one of these addresses'. Someone hitting the origin",
88
+ "# directly with a forged header is not connecting FROM Cloudflare, so the header is",
89
+ "# ignored and their real address stands. The trust is anchored to who opened the",
90
+ `# socket, which a client cannot forge.`,
91
+ "#",
92
+ `# The header is ${header}.`,
93
+ ...header.toLowerCase() === "cf-connecting-ip" ? [
94
+ "# Cloudflare OVERWRITES CF-Connecting-IP, so its value holds nothing the client",
95
+ "# supplied. It deliberately is NOT X-Forwarded-For: Cloudflare APPENDS to that",
96
+ "# one, so XFF arrives as '<client-controlled>, <real client>' and reading it",
97
+ "# left-to-right would let a visitor choose their own apparent address \u2014 and",
98
+ "# with it their rate-limit bucket and which ban rules miss them."
99
+ ] : [
100
+ "# NOT the default (CF-Connecting-IP) \u2014 set via OPENSHIP_EDGE_REAL_IP_HEADER.",
101
+ "# If this is X-Forwarded-For, note that proxies APPEND to it, so the header is",
102
+ "# partly client-controlled; real_ip_recursive below is what makes nginx walk it",
103
+ "# from the right and stop at the last untrusted hop, which is the real client."
104
+ ],
105
+ "",
106
+ `real_ip_header ${header};`,
107
+ "",
108
+ "# Walk a multi-hop header from the RIGHT, skipping trusted addresses. Inert for a",
109
+ "# single-value header like CF-Connecting-IP; load-bearing for X-Forwarded-For, where",
110
+ "# the left-hand entries are whatever the client sent.",
111
+ "real_ip_recursive on;",
112
+ "",
113
+ `# Cloudflare's published edge ranges (${CLOUDFLARE_IPV4.length} v4 + ${CLOUDFLARE_IPV6.length} v6).`,
114
+ "# Trusted unconditionally, which is safe by construction: on a box that is not behind",
115
+ "# Cloudflare no peer ever matches, so every line here is inert. Refresh with",
116
+ "# `bun run update:cloudflare-ips`.",
117
+ ...CLOUDFLARE_IPV4.map((c) => `set_real_ip_from ${c};`),
118
+ ...CLOUDFLARE_IPV6.map((c) => `set_real_ip_from ${c};`)
119
+ ];
120
+ if (extra.length > 0) {
121
+ lines.push(
122
+ "",
123
+ "# Operator-declared proxies (OPENSHIP_EDGE_TRUSTED_PROXIES). Each of these can set",
124
+ "# the header above and be believed, so keep the list to hosts you control.",
125
+ ...extra.map((c) => `set_real_ip_from ${c};`)
126
+ );
127
+ }
128
+ return lines.join("\n") + "\n";
129
+ }
130
+
131
+ // ../../packages/adapters/src/infra/edge-not-found.ts
132
+ var EDGE_UNROUTED_SENTINEL = "openship-edge-unrouted";
133
+ var HTML_FRAGMENTS = [
134
+ `<!doctype html>`,
135
+ `<!--${EDGE_UNROUTED_SENTINEL}-->`,
136
+ `<html lang="en">`,
137
+ `<head>`,
138
+ `<meta charset="utf-8">`,
139
+ `<meta name="viewport" content="width=device-width,initial-scale=1">`,
140
+ // An unrouted host must never enter a search index under our page.
141
+ `<meta name="robots" content="noindex,nofollow">`,
142
+ `<title>Service not found</title>`,
143
+ `<style>`,
144
+ // Matches the dashboard's theme: a neutral black-on-white scale, mirrored for
145
+ // dark. No webfont, no image, no external request — the page must render on a
146
+ // box whose only working listener is the one serving it. Colours are `rgb()`,
147
+ // never `#rrggbb`: see the no-`#` invariant in the header.
148
+ `:root{color-scheme:light dark}`,
149
+ `*{box-sizing:border-box}`,
150
+ `body{margin:0;min-height:100vh;display:flex;align-items:center;justify-content:center;background:rgb(255,255,255);color:rgba(0,0,0,.66);font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased}`,
151
+ `main{width:100%;max-width:32rem;padding:2.5rem 1.5rem;text-align:center}`,
152
+ // The muted scale is .56, not the .4–.52 it started at: black at .52 on white is
153
+ // 4.3:1 and at .4 is 2.9:1, both under WCAG AA's 4.5:1 for text this small, and
154
+ // this is the most-seen page the edge serves. .56 ≈ 4.75:1.
155
+ `.tag{display:inline-flex;align-items:center;gap:.5rem;margin-bottom:1.25rem;padding:.25rem .625rem;border:1px solid rgba(0,0,0,.1);border-radius:999px;font-size:12px;color:rgba(0,0,0,.56)}`,
156
+ `.dot{width:6px;height:6px;border-radius:50%;background:rgb(224,169,10)}`,
157
+ `h1{margin:0 0 .5rem;font-size:1.375rem;font-weight:600;letter-spacing:-.01em;color:rgba(0,0,0,.92)}`,
158
+ `p{margin:0 auto 1.5rem;max-width:26rem}`,
159
+ `ul{display:inline-block;margin:0;padding:0;list-style:none;text-align:left;font-size:13.5px;color:rgba(0,0,0,.56)}`,
160
+ `li{position:relative;padding:.2rem 0 .2rem 1rem}`,
161
+ `li::before{content:"";position:absolute;left:0;top:.75em;width:4px;height:4px;border-radius:50%;background:rgba(0,0,0,.25)}`,
162
+ `footer{margin-top:2.25rem;font-size:12px;color:rgba(0,0,0,.56)}`,
163
+ `@media(prefers-color-scheme:dark){`,
164
+ `body{background:rgb(10,10,10);color:rgba(255,255,255,.66)}`,
165
+ `.tag{border-color:rgba(255,255,255,.12);color:rgba(255,255,255,.56)}`,
166
+ `h1{color:rgba(255,255,255,.95)}`,
167
+ `ul{color:rgba(255,255,255,.56)}`,
168
+ `li::before{background:rgba(255,255,255,.28)}`,
169
+ `footer{color:rgba(255,255,255,.56)}`,
170
+ `}`,
171
+ `</style>`,
172
+ `</head>`,
173
+ `<body>`,
174
+ `<main>`,
175
+ `<span class="tag"><span class="dot"></span>404 &middot; no route</span>`,
176
+ `<h1>Service not found</h1>`,
177
+ // "reachable, but nothing is configured" is the whole message: it separates a
178
+ // down app from an address that was never wired up, which is the distinction a
179
+ // raw TLS error or a stock 404 destroys.
180
+ `<p>This server is reachable, but no application is configured for the address you requested.</p>`,
181
+ `<ul>`,
182
+ `<li>Check the address for a typo</li>`,
183
+ `<li>The deployment may have been removed or renamed</li>`,
184
+ `<li>A newly added domain can take a few minutes to start serving</li>`,
185
+ `</ul>`,
186
+ `<footer>Served by Openship</footer>`,
187
+ `</main>`,
188
+ `</body>`,
189
+ `</html>`
190
+ ];
191
+ var EDGE_NOT_FOUND_HTML = HTML_FRAGMENTS.join("");
192
+ var EDGE_NOT_FOUND_LOCATION = ` server_tokens off;
193
+
194
+ location / {
195
+ types { }
196
+ default_type text/html;
197
+ return 404 '${EDGE_NOT_FOUND_HTML}';
198
+ }`;
199
+
200
+ // ../../packages/adapters/src/infra/openresty-lua.ts
201
+ var OPENRESTY_LUA_DIR = "/usr/local/openresty/site/lualib/openship";
202
+ var LUA_LOGGER_PATH = `${OPENRESTY_LUA_DIR}/site_logger.lua`;
203
+ var RULES_GUARD_PATH = `${OPENRESTY_LUA_DIR}/rules_guard.lua`;
204
+ var OPENRESTY_MGMT_PORT = 9145;
205
+ var OPENRESTY_SITE_LUALIB = OPENRESTY_LUA_DIR.replace(/\/[^/]+$/, "");
206
+ var EDGE_LUA_PACKAGE_PATH = `${OPENRESTY_SITE_LUALIB}/?.lua;;`;
207
+ var EDGE_SERVER_NAMES_HASH_BUCKET_SIZE = 128;
208
+ var EDGE_SHARED_DICTS = [
209
+ /** Analytics counters. */
210
+ { name: "analytics", size: "256m" },
211
+ /** Raw-log ring buffers + the live-log pipe. */
212
+ { name: "request_data", size: "128m" },
213
+ /** Per-route rules cache: written reload-free by mgmt_api `POST /rules`, read
214
+ * by rules_guard.lua in the access phase. The DB (route_rule) is the source
215
+ * of truth, so losing this dict costs a re-push, not a ruleset. */
216
+ { name: "rules", size: "32m" },
217
+ /** Rate-limit COUNTERS, kept apart from `rules` so a high-cardinality flood (a
218
+ * fresh key per source IP per second) can't LRU-evict the rulesets and
219
+ * silently disable enforcement mid-attack.
220
+ *
221
+ * 32m, matching openresty module migration 1.1.0, which raises it from the
222
+ * original 16m on boxes already installed. Both must state the same target: a
223
+ * fresh install writes THIS value, so leaving it at 16m meant a new box got the
224
+ * size the migration exists to correct — and only bare boxes that consented to
225
+ * the migration would ever reach 32m. The migration stays because the
226
+ * `grep || sed` convergence below is append-only and cannot resize an existing
227
+ * directive; `edge-shared-dicts.test.ts` pins the two together. */
228
+ { name: "rl_counters", size: "32m" },
229
+ /**
230
+ * Distinct-visitor sets. One key per (domain, day, salted-IP hash) — high
231
+ * cardinality and short-lived, so it gets its own zone for the same reason
232
+ * `rl_counters` does: a busy day's visitor set must not LRU-evict the analytics
233
+ * counters or the rulesets.
234
+ *
235
+ * Privacy: keys hold a per-day-salted hash, never an address, and only the
236
+ * resulting COUNT is ever flushed to Postgres. Nothing that identifies a visitor
237
+ * leaves the box — see the visitor block in site_logger.lua.
238
+ *
239
+ * 64m ≈ 1M distinct visitors/day. Past that the zone LRU-evicts and the count
240
+ * UNDERSTATES; `GET /status` reports free_space so a reader can mark it
241
+ * approximate rather than present an eviction artifact as a measurement.
242
+ */
243
+ { name: "visitors", size: "64m" }
244
+ ];
245
+ function parseNginxVersion(raw) {
246
+ const m = raw.match(/nginx version:\s*\S*?\/(\d+)\.(\d+)\.(\d+)/i);
247
+ if (!m) return void 0;
248
+ return [Number(m[1]), Number(m[2]), Number(m[3])];
249
+ }
250
+ var OPENRESTY_DEFAULT_PATHS = {
251
+ bin: "/usr/local/openresty/bin/openresty",
252
+ confPath: "/usr/local/openresty/nginx/conf/nginx.conf",
253
+ confDir: "/usr/local/openresty/nginx/conf",
254
+ sitesDir: "/usr/local/openresty/nginx/conf/sites-enabled",
255
+ pidPath: "/usr/local/openresty/nginx/logs/nginx.pid"
256
+ };
257
+ var EDGE_DEFAULT_CERT_DIRNAME = "openship-default-cert";
258
+ function edgeDefaultCertPaths(confDir) {
259
+ const dir = `${confDir}/${EDGE_DEFAULT_CERT_DIRNAME}`;
260
+ return { dir, certPath: `${dir}/fullchain.pem`, keyPath: `${dir}/privkey.pem` };
261
+ }
262
+ var EDGE_DEFAULT_CERT_CN = "openship-edge-default";
263
+ var EDGE_HOST_STATE_DIR = "/var/lib/openship/edge";
264
+ var EDGE_CONTAINER_MOUNTS = [
265
+ { host: `${EDGE_HOST_STATE_DIR}/sites-enabled`, container: OPENRESTY_DEFAULT_PATHS.sitesDir },
266
+ { host: "/etc/letsencrypt", container: "/etc/letsencrypt" },
267
+ { host: `${EDGE_HOST_STATE_DIR}/acme`, container: "/var/www/acme" },
268
+ { host: "/opt/openship/static", container: "/opt/openship/static" }
269
+ ];
270
+ var EDGE_HOST_PATHS = {
271
+ bin: OPENRESTY_DEFAULT_PATHS.bin,
272
+ confPath: OPENRESTY_DEFAULT_PATHS.confPath,
273
+ confDir: OPENRESTY_DEFAULT_PATHS.confDir,
274
+ sitesDir: `${EDGE_HOST_STATE_DIR}/sites-enabled`,
275
+ pidPath: OPENRESTY_DEFAULT_PATHS.pidPath
276
+ };
277
+ var KNOWN_CONF_PATHS = [
278
+ "/usr/local/openresty/nginx/conf/nginx.conf",
279
+ "/etc/openresty/nginx.conf",
280
+ "/etc/nginx/nginx.conf"
281
+ ];
282
+ async function detectOpenRestyPaths(executor) {
283
+ const raw = await executor.exec("openresty -V 2>&1 || true");
284
+ const parseFlag = (flag) => {
285
+ const m = raw.match(new RegExp(`--${flag}=([^\\s]+)`));
286
+ return m ? m[1] : null;
287
+ };
288
+ const bin = parseFlag("sbin-path") ?? OPENRESTY_DEFAULT_PATHS.bin;
289
+ let confPath = parseFlag("conf-path") ?? OPENRESTY_DEFAULT_PATHS.confPath;
290
+ const pidPath = parseFlag("pid-path") ?? OPENRESTY_DEFAULT_PATHS.pidPath;
291
+ if (!await executor.exists(confPath)) {
292
+ let found = false;
293
+ for (const candidate of KNOWN_CONF_PATHS) {
294
+ if (candidate !== confPath && await executor.exists(candidate)) {
295
+ confPath = candidate;
296
+ found = true;
297
+ break;
298
+ }
299
+ }
300
+ if (!found) {
301
+ }
302
+ }
303
+ const confDir = confPath.replace(/\/[^/]+$/, "");
304
+ const nginxVersion = parseNginxVersion(raw);
305
+ return {
306
+ bin,
307
+ confPath,
308
+ confDir,
309
+ sitesDir: `${confDir}/sites-enabled`,
310
+ pidPath,
311
+ ...nginxVersion ? { nginxVersion } : {}
312
+ };
313
+ }
314
+ function buildReloadCommand(paths, opts = {}) {
315
+ if (opts.containerEdge) {
316
+ return `${paths.bin} -t 2>&1 || exit 1
317
+ ${paths.bin} -s reload 2>&1 || exit 1`;
318
+ }
319
+ return `${paths.bin} -t 2>&1 || exit 1
320
+
321
+ reload_err=$(${paths.bin} -s reload 2>&1) && exit 0
322
+
323
+ if [ "$(cat /proc/1/comm 2>/dev/null)" = "openresty" ] || [ "$(cat /proc/1/comm 2>/dev/null)" = "nginx" ]; then
324
+ echo "openresty reload failed and openresty is PID 1 (containerized edge) \u2014 not killing it; the container supervisor owns restarts." >&2
325
+ echo "$reload_err" >&2
326
+ exit 1
327
+ fi
328
+
329
+ if [ -f ${paths.pidPath} ] && kill -0 "$(cat ${paths.pidPath} 2>/dev/null)" 2>/dev/null; then
330
+ echo "openresty (pid $(cat ${paths.pidPath})) is running but refused -s reload" >&2
331
+ exit 1
332
+ fi
333
+
334
+ rm -f ${paths.pidPath}
335
+ ${paths.bin}`;
336
+ }
337
+ async function ensureEdgeDefaultCert(executor, confDir) {
338
+ const { dir, certPath, keyPath } = edgeDefaultCertPaths(confDir);
339
+ try {
340
+ if (await executor.exists(certPath) && await executor.exists(keyPath)) {
341
+ return { certPath, keyPath };
342
+ }
343
+ } catch {
344
+ return null;
345
+ }
346
+ const staging = `${dir}.staging-${process.pid}-${randomBytes(4).toString("hex")}`;
347
+ try {
348
+ await executor.mkdir(staging);
349
+ await executor.exec(
350
+ `openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -days 3650 -subj ${sq(`/CN=${EDGE_DEFAULT_CERT_CN}`)} -keyout ${sq(`${staging}/privkey.pem`)} -out ${sq(`${staging}/fullchain.pem`)} 2>/dev/null`
351
+ );
352
+ await executor.exec(`chmod 600 ${sq(`${staging}/privkey.pem`)}`);
353
+ await executor.mkdir(dir);
354
+ await executor.exec(
355
+ `mv -f ${sq(`${staging}/fullchain.pem`)} ${sq(`${staging}/privkey.pem`)} ${sq(dir)}/`
356
+ );
357
+ if (!await executor.exists(certPath) || !await executor.exists(keyPath)) return null;
358
+ return { certPath, keyPath };
359
+ } catch (err) {
360
+ console.warn(
361
+ `[openresty] could not create the edge's default certificate \u2014 an unrouted HTTPS host will get a TLS error instead of the "service not found" page (is openssl installed?): ${safeErrorMessage(err)}`
362
+ );
363
+ return null;
364
+ } finally {
365
+ await executor.rm(staging).catch(() => void 0);
366
+ }
367
+ }
368
+ async function ensureOpenRestyConfig(executor, paths) {
369
+ await executor.mkdir(paths.sitesDir);
370
+ await executor.mkdir("/var/www/acme");
371
+ const pidDir = paths.pidPath.replace(/\/[^/]+$/, "");
372
+ await executor.mkdir(pidDir);
373
+ const defaultCert = await ensureEdgeDefaultCert(executor, paths.confDir);
374
+ await executor.writeFile(`${paths.sitesDir}/_management.conf`, MANAGEMENT_BLOCK);
375
+ await executor.writeFile(`${paths.sitesDir}/_default.conf`, edgeDefaultCatchAllConf(defaultCert));
376
+ if (!await executor.exists(paths.confPath)) {
377
+ await executor.mkdir(paths.confDir);
378
+ await executor.writeFile(
379
+ paths.confPath,
380
+ MINIMAL_NGINX_CONF(paths.confDir, paths.sitesDir)
381
+ );
382
+ return;
383
+ }
384
+ const hasCorrectInclude = await executor.exec(`grep -qF 'include ${paths.sitesDir}/' ${paths.confPath}`).then(() => true).catch(() => false);
385
+ if (!hasCorrectInclude) {
386
+ const hasWrongInclude = await executor.exec(`grep -q 'include.*sites-enabled' ${paths.confPath}`).then(() => true).catch(() => false);
387
+ if (hasWrongInclude) {
388
+ await executor.exec(
389
+ `sed -i 's|include.*/sites-enabled/\\*\\.conf;|include ${paths.sitesDir}/*.conf;|' ${paths.confPath}`
390
+ );
391
+ } else {
392
+ await executor.exec(
393
+ `sed -i '/http *{/a \\ include ${paths.sitesDir}/*.conf;' ${paths.confPath}`
394
+ );
395
+ }
396
+ }
397
+ }
398
+ function MINIMAL_NGINX_CONF(confDir, sitesDir) {
399
+ return `# Auto-generated by Openship - safe to extend
400
+ worker_processes auto;
401
+ events {
402
+ worker_connections 1024;
403
+ }
404
+ http {
405
+ include ${confDir}/mime.types;
406
+ default_type application/octet-stream;
407
+ sendfile on;
408
+ keepalive_timeout 65;
409
+ # See EDGE_SERVER_NAMES_HASH_BUCKET_SIZE \u2014 the 64-byte default fails
410
+ # \`nginx -t\` outright for any server_name past ~63 chars, refusing the reload
411
+ # and wedging every route on the box, not just the long one.
412
+ server_names_hash_bucket_size ${EDGE_SERVER_NAMES_HASH_BUCKET_SIZE};
413
+ include ${sitesDir}/*.conf;
414
+ }
415
+ `;
416
+ }
417
+ var GEOIP_DIR = "/usr/share/GeoIP";
418
+ var GEOIP_DB_PATH = `${GEOIP_DIR}/GeoLite2-Country.mmdb`;
419
+ var GEOIP_DB_URL = process.env.OPENSHIP_GEOIP_URL?.trim() || "https://raw.githubusercontent.com/oblien/openship/main/apps/api/assets/geoip/GeoLite2-Country.mmdb";
420
+ var LUA_SRC_DIR = process.env.OPENSHIP_LUA_DIR?.trim() || join(dirname(fileURLToPath(import.meta.url)), "lua");
421
+ var VHOST_REFERENCED_LUA = ["rules_guard.lua", "rules_lib.lua", "site_logger.lua"];
422
+ function luaSourceAvailable() {
423
+ return VHOST_REFERENCED_LUA.every(
424
+ (f) => EMBEDDED_LUA[f] !== void 0 || existsSync(join(LUA_SRC_DIR, f))
425
+ );
426
+ }
427
+ function readLua(filename) {
428
+ const onDisk = join(LUA_SRC_DIR, filename);
429
+ if (existsSync(onDisk)) return readFileSync(onDisk, "utf-8");
430
+ const embedded = EMBEDDED_LUA[filename];
431
+ if (embedded !== void 0) return Buffer.from(embedded, "base64").toString("utf-8");
432
+ throw new Error(
433
+ `Lua script "${filename}" not found on disk (${LUA_SRC_DIR}) or in EMBEDDED_LUA \u2014 add it to packages/adapters/src/infra/lua/ and run \`bun run embed:lua\`.`
434
+ );
435
+ }
436
+ var EDGE_MGMT_SERVER_BLOCK = `server {
437
+ listen 127.0.0.1:${OPENRESTY_MGMT_PORT};
438
+
439
+ # Long-running Lua content handlers need generous timeouts
440
+ send_timeout 3600s;
441
+ keepalive_timeout 3600s;
442
+ lua_check_client_abort on;
443
+
444
+ # SSE live-log stream (long-lived connection)
445
+ location = /logs/stream {
446
+ content_by_lua_file ${OPENRESTY_LUA_DIR}/pipe_stream.lua;
447
+ }
448
+
449
+ # REST analytics + health (short-lived)
450
+ location / {
451
+ content_by_lua_file ${OPENRESTY_LUA_DIR}/mgmt_api.lua;
452
+ }
453
+ }`;
454
+ var MANAGEMENT_BLOCK = `# Openship internal management - analytics & live-log streaming
455
+ # Auto-generated - do not edit manually
456
+ ${EDGE_MGMT_SERVER_BLOCK}
457
+ `;
458
+ var ACME_HTTP01_PORT = 49180;
459
+ var ACME_CHALLENGE_LOCATION = ` location /.well-known/acme-challenge/ {
460
+ proxy_pass http://127.0.0.1:${ACME_HTTP01_PORT};
461
+ proxy_set_header Host $host;
462
+ }`;
463
+ var EDGE_CHALLENGE_URL_PREFIX = "/.well-known/oblien-proxy-challenge/";
464
+ var EDGE_CHALLENGE_ROOT = "/var/www/acme/oblien";
465
+ var EDGE_CHALLENGE_DIR = `${EDGE_CHALLENGE_ROOT}${EDGE_CHALLENGE_URL_PREFIX}`.replace(/\/$/, "");
466
+ var EDGE_CHALLENGE_HOST_DIR = `${EDGE_HOST_STATE_DIR}/acme/oblien${EDGE_CHALLENGE_URL_PREFIX}`.replace(
467
+ /\/$/,
468
+ ""
469
+ );
470
+ var EDGE_CHALLENGE_LOCATION = ` location ${EDGE_CHALLENGE_URL_PREFIX} {
471
+ root ${EDGE_CHALLENGE_ROOT};
472
+ default_type text/plain;
473
+ try_files $uri =404;
474
+ }`;
475
+ function edgeChallengeVhostConf(host) {
476
+ return `# Auto-generated by Openship - do not edit manually
477
+ # openship-oblien-challenge: answers ${EDGE_CHALLENGE_URL_PREFIX}<token> for
478
+ # Host: ${host}, so Openship Cloud's shared edge can prove this box controls that
479
+ # routing target. Everything else gets the shared not-found page - this is
480
+ # scaffolding, not a site.
481
+ server {
482
+ listen 80;
483
+ server_name ${host};
484
+
485
+ ${EDGE_CHALLENGE_LOCATION}
486
+
487
+ ${EDGE_NOT_FOUND_LOCATION}
488
+ }
489
+ `;
490
+ }
491
+ var EDGE_HTTPS_REJECT_BLOCK = `# HTTPS catch-all. WITHOUT a 443 default_server, nginx serves the first-loaded
492
+ # 443 vhost to any request whose SNI matches no server_name - so a domain we do
493
+ # NOT route (removed / never-added / just pointed at this IP) silently gets some
494
+ # other app's cert + backend. That is cross-serving, a security hole. Owning the
495
+ # 443 default closes it: an unrouted host is answered HERE, never by a fallthrough.
496
+ #
497
+ # This is the no-certificate variant, used only when the placeholder cert could not
498
+ # be created. It refuses the handshake, so the visitor gets a raw TLS error and a
499
+ # Cloudflare-proxied host gets error 525 - correct, but unfriendly. See
500
+ # edgeHttpsDefaultBlock. ssl_reject_handshake (OpenResty/nginx >= 1.19.4; our
501
+ # installer pulls the newest LTS) needs no certificate.
502
+ server {
503
+ listen 443 ssl default_server;
504
+ ssl_reject_handshake on;
505
+ }`;
506
+ function edgeHttpsDefaultBlock(cert) {
507
+ if (!cert) return EDGE_HTTPS_REJECT_BLOCK;
508
+ return `# HTTPS catch-all. WITHOUT a 443 default_server, nginx serves the first-loaded
509
+ # 443 vhost to any request whose SNI matches no server_name - so a domain we do
510
+ # NOT route (removed / never-added / just pointed at this IP) silently gets some
511
+ # other app's cert + backend. That is cross-serving, a security hole. Owning the
512
+ # 443 default closes it: an unrouted host is answered HERE, never by a fallthrough.
513
+ #
514
+ # The cert below belongs to no domain and is trusted by nothing - it exists so the
515
+ # handshake COMPLETES and the request can be answered with a page instead of
516
+ # ERR_SSL_UNRECOGNIZED_NAME_ALERT (Cloudflare "Full" reports the refusal as error
517
+ # 525; "Full (Strict)" validates the cert and will still show 526). Keep this block a
518
+ # dead end: no proxy_pass, no root, no HSTS, no reuse of a real certificate - that is
519
+ # what stops it from becoming the cross-serving it prevents. And never set
520
+ # ssl_certificate at http scope: this block would inherit a real domain's cert.
521
+ server {
522
+ listen 443 ssl default_server;
523
+ server_name _;
524
+
525
+ ssl_certificate ${cert.certPath};
526
+ ssl_certificate_key ${cert.keyPath};
527
+
528
+ ${EDGE_NOT_FOUND_LOCATION}
529
+ }`;
530
+ }
531
+ function edgeDefaultCatchAllConf(cert) {
532
+ return `# Openship default catch-all - prevents the stock OpenResty welcome page AND
533
+ # stops an unmatched Host/SNI from being served the first real vhost by default.
534
+ # Auto-generated - do not edit manually
535
+ server {
536
+ listen 80 default_server;
537
+ server_name _;
538
+
539
+ ${ACME_CHALLENGE_LOCATION}
540
+
541
+ ${EDGE_NOT_FOUND_LOCATION}
542
+ }
543
+
544
+ ${edgeHttpsDefaultBlock(cert)}
545
+ `;
546
+ }
547
+ var LUA_SCRIPTS = [
548
+ "site_logger.lua",
549
+ "pipe_log.lua",
550
+ "pipe_stream.lua",
551
+ "mgmt_api.lua",
552
+ "geo_country.lua",
553
+ // Vendored FFI binding geo_country requires as `openship.maxminddb`. Ships with
554
+ // the rest so a bare box needs no `opm get` (which needs perl) — see the file
555
+ // header. Flat, like every other script: ensureLuaScripts writes this list into
556
+ // one directory and its presence scan is a plain `ls -1`.
557
+ "maxminddb.lua",
558
+ "rules_lib.lua",
559
+ "rules_guard.lua"
560
+ ];
561
+ var LUA_VERSION_MARKER = `${OPENRESTY_LUA_DIR}/.openship-lua-version`;
562
+ function luaBundleHash() {
563
+ const h = createHash("sha256");
564
+ for (const name of LUA_SCRIPTS) {
565
+ h.update(name);
566
+ h.update("\0");
567
+ h.update(readLua(name));
568
+ h.update("\0");
569
+ }
570
+ return h.digest("hex");
571
+ }
572
+ async function ensureLuaScripts(executor, paths) {
573
+ try {
574
+ if (!luaSourceAvailable()) {
575
+ console.error(
576
+ "[openresty] Lua unavailable in this build (not on disk or embedded) \u2014 edge rules/logging disabled. Run `bun run embed:lua` in packages/adapters."
577
+ );
578
+ return { repaired: [], available: false };
579
+ }
580
+ const expected = luaBundleHash();
581
+ await executor.mkdir(OPENRESTY_LUA_DIR);
582
+ const listing = await executor.exec(`ls -1 '${OPENRESTY_LUA_DIR}' 2>/dev/null || true`).catch(() => "");
583
+ const present = new Set(listing.split("\n").map((s) => s.trim()).filter(Boolean));
584
+ const missing = LUA_SCRIPTS.filter((name) => !present.has(name));
585
+ const onBoxVersion = (await executor.readFile(LUA_VERSION_MARKER).catch(() => "")).trim();
586
+ if (missing.length === 0 && onBoxVersion === expected) {
587
+ return { repaired: [], available: true };
588
+ }
589
+ for (const name of LUA_SCRIPTS) {
590
+ await executor.writeFile(`${OPENRESTY_LUA_DIR}/${name}`, readLua(name));
591
+ }
592
+ await executor.writeFile(LUA_VERSION_MARKER, expected);
593
+ const reason = missing.length ? `missing: ${missing.join(", ")}` : "version changed";
594
+ console.warn(`[openresty] (re)installed Lua (${reason}) \u2014 reloading edge.`);
595
+ await executor.exec(buildReloadCommand(paths)).catch((err) => {
596
+ console.error(`[openresty] reload after Lua (re)install failed: ${safeErrorMessage(err)}`);
597
+ });
598
+ return { repaired: missing.length ? missing : [...LUA_SCRIPTS], available: true };
599
+ } catch (err) {
600
+ console.error(`[openresty] ensureLuaScripts failed (deploy continues): ${safeErrorMessage(err)}`);
601
+ return { repaired: [], available: false };
602
+ }
603
+ }
604
+ async function installGeoDeps(executor) {
605
+ try {
606
+ const hasPkg = async (cmd) => {
607
+ try {
608
+ await executor.exec(`command -v ${cmd}`);
609
+ return true;
610
+ } catch {
611
+ return false;
612
+ }
613
+ };
614
+ if (await hasPkg("apt-get")) {
615
+ await executor.exec(
616
+ "apt-get update -qq && apt-get install -y -qq libmaxminddb0 libmaxminddb-dev"
617
+ );
618
+ } else if (await hasPkg("dnf")) {
619
+ await executor.exec("dnf install -y libmaxminddb libmaxminddb-devel");
620
+ } else if (await hasPkg("yum")) {
621
+ await executor.exec("yum install -y libmaxminddb libmaxminddb-devel");
622
+ } else if (await hasPkg("apk")) {
623
+ await executor.exec("apk add --no-cache libmaxminddb");
624
+ }
625
+ } catch {
626
+ }
627
+ try {
628
+ const exists = await executor.exists(GEOIP_DB_PATH);
629
+ if (!exists) {
630
+ await executor.mkdir(GEOIP_DIR);
631
+ await executor.exec(
632
+ `curl -fsSL -o ${GEOIP_DB_PATH} "${GEOIP_DB_URL}"`
633
+ );
634
+ }
635
+ } catch {
636
+ }
637
+ }
638
+ async function deployLuaScripts(executor, paths) {
639
+ await installGeoDeps(executor);
640
+ if (!luaSourceAvailable()) {
641
+ throw new Error(
642
+ `OpenResty Lua is unavailable in this build \u2014 not on disk (LUA_SRC_DIR=${LUA_SRC_DIR}) and not in EMBEDDED_LUA. The edge scripts (rules_guard.lua/site_logger.lua) can't be installed. Run \`bun run embed:lua\` in packages/adapters to regenerate lua-embedded.ts.`
643
+ );
644
+ }
645
+ await executor.mkdir(OPENRESTY_LUA_DIR);
646
+ for (const name of LUA_SCRIPTS) {
647
+ await executor.writeFile(
648
+ `${OPENRESTY_LUA_DIR}/${name}`,
649
+ readLua(name)
650
+ );
651
+ }
652
+ await ensureOpenRestyConfig(executor, paths);
653
+ for (const dict of EDGE_SHARED_DICTS) {
654
+ await executor.exec(
655
+ `grep -q 'lua_shared_dict ${dict.name} ' ${paths.confPath} || sed -i '/http *{/a \\ lua_shared_dict ${dict.name} ${dict.size};' ${paths.confPath}`
656
+ );
657
+ }
658
+ await executor.exec(
659
+ `grep -q 'lua_package_path' ${paths.confPath} || sed -i '/http *{/a \\ lua_package_path "${EDGE_LUA_PACKAGE_PATH}";' ${paths.confPath}`
660
+ );
661
+ const realIpPath = `${paths.confDir}/${EDGE_REAL_IP_CONF_NAME}`;
662
+ await executor.writeFile(realIpPath, edgeRealIpConf());
663
+ await executor.exec(
664
+ `grep -q '${EDGE_REAL_IP_CONF_NAME}' '${paths.confPath}' || sed -i '/http *{/a \\ include ${realIpPath};' '${paths.confPath}'`
665
+ );
666
+ await executor.exec(buildReloadCommand(paths));
667
+ }
668
+
669
+ export {
670
+ OPENRESTY_LUA_DIR,
671
+ LUA_LOGGER_PATH,
672
+ RULES_GUARD_PATH,
673
+ OPENRESTY_MGMT_PORT,
674
+ EDGE_LUA_PACKAGE_PATH,
675
+ EDGE_SERVER_NAMES_HASH_BUCKET_SIZE,
676
+ EDGE_SHARED_DICTS,
677
+ parseNginxVersion,
678
+ OPENRESTY_DEFAULT_PATHS,
679
+ EDGE_DEFAULT_CERT_DIRNAME,
680
+ edgeDefaultCertPaths,
681
+ EDGE_DEFAULT_CERT_CN,
682
+ EDGE_HOST_STATE_DIR,
683
+ EDGE_CONTAINER_MOUNTS,
684
+ EDGE_HOST_PATHS,
685
+ detectOpenRestyPaths,
686
+ buildReloadCommand,
687
+ ensureOpenRestyConfig,
688
+ GEOIP_DIR,
689
+ GEOIP_DB_PATH,
690
+ luaSourceAvailable,
691
+ EDGE_MGMT_SERVER_BLOCK,
692
+ ACME_HTTP01_PORT,
693
+ ACME_CHALLENGE_LOCATION,
694
+ EDGE_CHALLENGE_URL_PREFIX,
695
+ EDGE_CHALLENGE_ROOT,
696
+ EDGE_CHALLENGE_DIR,
697
+ EDGE_CHALLENGE_HOST_DIR,
698
+ EDGE_CHALLENGE_LOCATION,
699
+ edgeChallengeVhostConf,
700
+ EDGE_HTTPS_REJECT_BLOCK,
701
+ edgeHttpsDefaultBlock,
702
+ edgeDefaultCatchAllConf,
703
+ ensureLuaScripts,
704
+ deployLuaScripts
705
+ };