@rakay-technology/kraft 0.7.4

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 (504) hide show
  1. package/README.md +263 -0
  2. package/dist/bare-HL2GUYE2.js +27 -0
  3. package/dist/bowser-HNOTPGJO.js +2825 -0
  4. package/dist/chunk-3CJLKL6E.js +124 -0
  5. package/dist/chunk-3NQQXMDR.js +2098 -0
  6. package/dist/chunk-42WQABXM.js +439 -0
  7. package/dist/chunk-5GPXMTE4.js +25 -0
  8. package/dist/chunk-AJ4QZLZ2.js +1069 -0
  9. package/dist/chunk-AO252K7Z.js +137 -0
  10. package/dist/chunk-BQMFIXHI.js +975 -0
  11. package/dist/chunk-DM3PKWDC.js +2453 -0
  12. package/dist/chunk-DOD2BXHQ.js +1364 -0
  13. package/dist/chunk-DRK3MEDS.js +2870 -0
  14. package/dist/chunk-EW4PHKB2.js +13914 -0
  15. package/dist/chunk-HMJUFZK7.js +340 -0
  16. package/dist/chunk-I2TOOF2A.js +517 -0
  17. package/dist/chunk-I3DPMTSF.js +29 -0
  18. package/dist/chunk-JSCZT76F.js +2588 -0
  19. package/dist/chunk-MNV2QFHW.js +138 -0
  20. package/dist/chunk-MOLPYPVH.js +2529 -0
  21. package/dist/chunk-N4OALTFK.js +295 -0
  22. package/dist/chunk-OFXBNFNL.js +458 -0
  23. package/dist/chunk-ONKEYSMY.js +1388 -0
  24. package/dist/chunk-PDW4L3NV.js +17 -0
  25. package/dist/chunk-PNNXWA2A.js +1947 -0
  26. package/dist/chunk-PNRPKRJU.js +11105 -0
  27. package/dist/chunk-PVOWHIND.js +26781 -0
  28. package/dist/chunk-PXKCZB2I.js +46 -0
  29. package/dist/chunk-PZVKPCKE.js +475 -0
  30. package/dist/chunk-QWHBRY2K.js +4945 -0
  31. package/dist/chunk-RFOBMHQ7.js +338 -0
  32. package/dist/chunk-RHLNVZMS.js +28 -0
  33. package/dist/chunk-RVER2EOO.js +577 -0
  34. package/dist/chunk-S3QBGGVP.js +81 -0
  35. package/dist/chunk-TAML5WMA.js +198 -0
  36. package/dist/chunk-THTEUDBC.js +3188 -0
  37. package/dist/chunk-WYNM7L22.js +329 -0
  38. package/dist/chunk-XGCG4MD5.js +102 -0
  39. package/dist/chunk-XVKUFMIB.js +148 -0
  40. package/dist/chunk-XZYFZ6A5.js +50 -0
  41. package/dist/chunk-Y7PVJUXJ.js +2275 -0
  42. package/dist/chunk-YRSZPVMB.js +306 -0
  43. package/dist/chunk-YZUKHG3S.js +362 -0
  44. package/dist/chunk-ZVFS4LUA.js +116 -0
  45. package/dist/chunk-ZWLDLTJP.js +1417 -0
  46. package/dist/detect-676SNZK4.js +48 -0
  47. package/dist/dist-es-2YRDXMUU.js +73 -0
  48. package/dist/dist-es-CCVZEFRZ.js +91 -0
  49. package/dist/dist-es-EDUSMF6Q.js +488 -0
  50. package/dist/dist-es-IOH6G4GM.js +380 -0
  51. package/dist/dist-es-KWSMDPIP.js +26 -0
  52. package/dist/dist-es-UYDDOVZ3.js +173 -0
  53. package/dist/dist-es-XUOR4NQN.js +321 -0
  54. package/dist/docker-GOT3Q7DJ.js +41 -0
  55. package/dist/docker-edge-executor-VO6JHHW2.js +19 -0
  56. package/dist/edge-import-NFCHIW7G.js +50 -0
  57. package/dist/edge-preflight-QUJ757C6.js +45 -0
  58. package/dist/ensure-container-edge-Q7IZXHGM.js +38 -0
  59. package/dist/event-streams-TR4GAC53.js +46 -0
  60. package/dist/executor-GKXKN52K.js +42 -0
  61. package/dist/host-channel-preflight-Z6HYSPKO.js +48 -0
  62. package/dist/index.d.ts +2 -0
  63. package/dist/index.js +9469 -0
  64. package/dist/loadSso-UGF4JMRK.js +581 -0
  65. package/dist/local-executor-OMMDKXCM.js +13 -0
  66. package/dist/nginx-VITTWZZU.js +42 -0
  67. package/dist/node-bootstrap.js +277 -0
  68. package/dist/node-entry.js +55 -0
  69. package/dist/noop-CLLJHCPL.js +11 -0
  70. package/dist/openresty-lua-6I3Z6PEQ.js +90 -0
  71. package/dist/privilege-UQAI2HV4.js +20 -0
  72. package/dist/server/engine/ChangeLog +2289 -0
  73. package/dist/server/engine/Documentations +5 -0
  74. package/dist/server/engine/LICENSE +674 -0
  75. package/dist/server/engine/README.md +34 -0
  76. package/dist/server/engine/conf/amavisd +150 -0
  77. package/dist/server/engine/conf/clamav +71 -0
  78. package/dist/server/engine/conf/core +632 -0
  79. package/dist/server/engine/conf/dovecot +151 -0
  80. package/dist/server/engine/conf/fail2ban +72 -0
  81. package/dist/server/engine/conf/global +698 -0
  82. package/dist/server/engine/conf/iredapd +52 -0
  83. package/dist/server/engine/conf/logwatch +28 -0
  84. package/dist/server/engine/conf/postfix +97 -0
  85. package/dist/server/engine/conf/postgresql +93 -0
  86. package/dist/server/engine/conf/spamassassin +39 -0
  87. package/dist/server/engine/dialog/config_via_dialog.sh +258 -0
  88. package/dist/server/engine/dialog/optional_components.sh +122 -0
  89. package/dist/server/engine/dialog/pgsql_config.sh +52 -0
  90. package/dist/server/engine/dialog/virtual_domain_config.sh +94 -0
  91. package/dist/server/engine/functions/amavisd.sh +267 -0
  92. package/dist/server/engine/functions/backend.sh +85 -0
  93. package/dist/server/engine/functions/clamav.sh +100 -0
  94. package/dist/server/engine/functions/cleanup.sh +393 -0
  95. package/dist/server/engine/functions/dovecot.sh +583 -0
  96. package/dist/server/engine/functions/fail2ban.sh +209 -0
  97. package/dist/server/engine/functions/iredapd.sh +356 -0
  98. package/dist/server/engine/functions/optional_components.sh +24 -0
  99. package/dist/server/engine/functions/packages.sh +522 -0
  100. package/dist/server/engine/functions/packages_freebsd.sh +179 -0
  101. package/dist/server/engine/functions/postfix.sh +457 -0
  102. package/dist/server/engine/functions/postgresql.sh +239 -0
  103. package/dist/server/engine/functions/spamassassin.sh +49 -0
  104. package/dist/server/engine/functions/system_accounts.sh +128 -0
  105. package/dist/server/engine/iRedMail.sh +144 -0
  106. package/dist/server/engine/pkgs/get_all.sh +338 -0
  107. package/dist/server/engine/pkgs/pkgs.freebsd.sha256 +3 -0
  108. package/dist/server/engine/pkgs/pkgs.openbsd.sha256 +6 -0
  109. package/dist/server/engine/pkgs/pkgs.sha256 +1 -0
  110. package/dist/server/engine/samples/amavisd/amavisd.conf +702 -0
  111. package/dist/server/engine/samples/amavisd/amavisd.mysql +278 -0
  112. package/dist/server/engine/samples/amavisd/amavisd.pgsql +253 -0
  113. package/dist/server/engine/samples/amavisd/amavisd.schema +942 -0
  114. package/dist/server/engine/samples/amavisd/default_spam_policy.sql +46 -0
  115. package/dist/server/engine/samples/dovecot/dovecot-2.4-mariadb.conf +758 -0
  116. package/dist/server/engine/samples/dovecot/dovecot-2.4-openldap.conf +767 -0
  117. package/dist/server/engine/samples/dovecot/dovecot-2.4-pgsql.conf +762 -0
  118. package/dist/server/engine/samples/dovecot/dovecot-last-login.conf +50 -0
  119. package/dist/server/engine/samples/dovecot/dovecot-ldap.conf +21 -0
  120. package/dist/server/engine/samples/dovecot/dovecot-share-folder.conf +22 -0
  121. package/dist/server/engine/samples/dovecot/dovecot-sql.conf +28 -0
  122. package/dist/server/engine/samples/dovecot/dovecot-used-quota.conf +13 -0
  123. package/dist/server/engine/samples/dovecot/dovecot.conf +484 -0
  124. package/dist/server/engine/samples/dovecot/dovecot.sieve +7 -0
  125. package/dist/server/engine/samples/dovecot/dovecot2-quota-warning.sh +38 -0
  126. package/dist/server/engine/samples/dovecot/sql/imap_share_folder.mysql +16 -0
  127. package/dist/server/engine/samples/dovecot/sql/last_login.mysql +12 -0
  128. package/dist/server/engine/samples/dovecot/sql/used_quota.mysql +26 -0
  129. package/dist/server/engine/samples/dovecot/systemd/override.conf +3 -0
  130. package/dist/server/engine/samples/fail2ban/action.d/banned_db.conf +9 -0
  131. package/dist/server/engine/samples/fail2ban/bin/fail2ban_banned_db +268 -0
  132. package/dist/server/engine/samples/fail2ban/fail2ban.local +17 -0
  133. package/dist/server/engine/samples/fail2ban/filter.d/dovecot.iredmail.conf +5 -0
  134. package/dist/server/engine/samples/fail2ban/filter.d/postfix-pregreet.iredmail.conf +16 -0
  135. package/dist/server/engine/samples/fail2ban/filter.d/postfix.iredmail.conf +18 -0
  136. package/dist/server/engine/samples/fail2ban/filter.d/roundcube.iredmail.conf +9 -0
  137. package/dist/server/engine/samples/fail2ban/jail.d/dovecot.local +8 -0
  138. package/dist/server/engine/samples/fail2ban/jail.d/nginx-http-auth.local +8 -0
  139. package/dist/server/engine/samples/fail2ban/jail.d/postfix-pregreet.local +9 -0
  140. package/dist/server/engine/samples/fail2ban/jail.d/postfix.local +8 -0
  141. package/dist/server/engine/samples/fail2ban/jail.d/roundcube.local +9 -0
  142. package/dist/server/engine/samples/fail2ban/jail.d/sogo.local +8 -0
  143. package/dist/server/engine/samples/fail2ban/jail.d/sshd.local +11 -0
  144. package/dist/server/engine/samples/fail2ban/jail.local +6 -0
  145. package/dist/server/engine/samples/fail2ban/openbsd/rc +27 -0
  146. package/dist/server/engine/samples/fail2ban/sql/fail2ban.mysql +49 -0
  147. package/dist/server/engine/samples/fail2ban/sql/fail2ban.pgsql +48 -0
  148. package/dist/server/engine/samples/firewall/firewalld/services/ssh.xml +6 -0
  149. package/dist/server/engine/samples/firewall/firewalld/zones/iredmail.xml +15 -0
  150. package/dist/server/engine/samples/firewall/iptables/ip6tables.init.debian +362 -0
  151. package/dist/server/engine/samples/firewall/iptables/ip6tables.rules +53 -0
  152. package/dist/server/engine/samples/firewall/iptables/iptables.init.debian +363 -0
  153. package/dist/server/engine/samples/firewall/iptables/iptables.rules +54 -0
  154. package/dist/server/engine/samples/firewall/nftables.conf +58 -0
  155. package/dist/server/engine/samples/freebsd/newsyslog.conf.d/dovecot.conf +3 -0
  156. package/dist/server/engine/samples/freebsd/newsyslog.conf.d/iredapd.conf +1 -0
  157. package/dist/server/engine/samples/freebsd/newsyslog.conf.d/mlmmjadmin.conf +1 -0
  158. package/dist/server/engine/samples/freebsd/newsyslog.conf.d/php-fpm.conf +2 -0
  159. package/dist/server/engine/samples/freebsd/newsyslog.conf.d/slapd.conf +1 -0
  160. package/dist/server/engine/samples/freebsd/syslog.d/dovecot.conf +2 -0
  161. package/dist/server/engine/samples/freebsd/syslog.d/fail2ban.conf +2 -0
  162. package/dist/server/engine/samples/freebsd/syslog.d/iredapd.conf +2 -0
  163. package/dist/server/engine/samples/freebsd/syslog.d/mlmmjadmin.conf +2 -0
  164. package/dist/server/engine/samples/freebsd/syslog.d/php-fpm.conf +2 -0
  165. package/dist/server/engine/samples/freebsd/syslog.d/slapd.conf +2 -0
  166. package/dist/server/engine/samples/iredmail/iredmail.mysql +491 -0
  167. package/dist/server/engine/samples/iredmail/iredmail.pgsql +465 -0
  168. package/dist/server/engine/samples/iredmail/iredmail.schema +456 -0
  169. package/dist/server/engine/samples/iredmail/used_quota_triggers_dovecot_2.3.pgsql +40 -0
  170. package/dist/server/engine/samples/iredmail/used_quota_triggers_dovecot_2.4.pgsql +18 -0
  171. package/dist/server/engine/samples/logrotate/dovecot +13 -0
  172. package/dist/server/engine/samples/logrotate/iredapd +13 -0
  173. package/dist/server/engine/samples/logrotate/mlmmjadmin +13 -0
  174. package/dist/server/engine/samples/logrotate/openldap +19 -0
  175. package/dist/server/engine/samples/logrotate/php-fpm +13 -0
  176. package/dist/server/engine/samples/openbsd/ldapd.conf +58 -0
  177. package/dist/server/engine/samples/openbsd/pf.conf +28 -0
  178. package/dist/server/engine/samples/postfix/command_filter.pcre +3 -0
  179. package/dist/server/engine/samples/postfix/freebsd/mailer.conf +9 -0
  180. package/dist/server/engine/samples/postfix/helo_access.pcre +180 -0
  181. package/dist/server/engine/samples/postfix/ldap/catchall_maps.cf +11 -0
  182. package/dist/server/engine/samples/postfix/ldap/recipient_bcc_maps_domain.cf +11 -0
  183. package/dist/server/engine/samples/postfix/ldap/recipient_bcc_maps_user.cf +11 -0
  184. package/dist/server/engine/samples/postfix/ldap/relay_domains.cf +11 -0
  185. package/dist/server/engine/samples/postfix/ldap/sender_bcc_maps_domain.cf +11 -0
  186. package/dist/server/engine/samples/postfix/ldap/sender_bcc_maps_user.cf +11 -0
  187. package/dist/server/engine/samples/postfix/ldap/sender_dependent_relayhost_maps_domain.cf +11 -0
  188. package/dist/server/engine/samples/postfix/ldap/sender_dependent_relayhost_maps_user.cf +11 -0
  189. package/dist/server/engine/samples/postfix/ldap/sender_login_maps.cf +11 -0
  190. package/dist/server/engine/samples/postfix/ldap/transport_maps_domain.cf +11 -0
  191. package/dist/server/engine/samples/postfix/ldap/transport_maps_user.cf +11 -0
  192. package/dist/server/engine/samples/postfix/ldap/virtual_alias_maps.cf +11 -0
  193. package/dist/server/engine/samples/postfix/ldap/virtual_group_maps.cf +11 -0
  194. package/dist/server/engine/samples/postfix/ldap/virtual_group_members_maps.cf +11 -0
  195. package/dist/server/engine/samples/postfix/ldap/virtual_mailbox_domains.cf +11 -0
  196. package/dist/server/engine/samples/postfix/ldap/virtual_mailbox_maps.cf +12 -0
  197. package/dist/server/engine/samples/postfix/main.cf +282 -0
  198. package/dist/server/engine/samples/postfix/main.cf.amavisd +7 -0
  199. package/dist/server/engine/samples/postfix/main.cf.dovecot +8 -0
  200. package/dist/server/engine/samples/postfix/main.cf.ldap +39 -0
  201. package/dist/server/engine/samples/postfix/main.cf.mlmmj +5 -0
  202. package/dist/server/engine/samples/postfix/main.cf.mysql +39 -0
  203. package/dist/server/engine/samples/postfix/main.cf.pgsql +39 -0
  204. package/dist/server/engine/samples/postfix/main.cf.postscreen +30 -0
  205. package/dist/server/engine/samples/postfix/master.cf +101 -0
  206. package/dist/server/engine/samples/postfix/mysql/catchall_maps.cf +5 -0
  207. package/dist/server/engine/samples/postfix/mysql/domain_alias_catchall_maps.cf +5 -0
  208. package/dist/server/engine/samples/postfix/mysql/domain_alias_maps.cf +5 -0
  209. package/dist/server/engine/samples/postfix/mysql/recipient_bcc_maps_domain.cf +5 -0
  210. package/dist/server/engine/samples/postfix/mysql/recipient_bcc_maps_user.cf +5 -0
  211. package/dist/server/engine/samples/postfix/mysql/relay_domains.cf +5 -0
  212. package/dist/server/engine/samples/postfix/mysql/sender_bcc_maps_domain.cf +5 -0
  213. package/dist/server/engine/samples/postfix/mysql/sender_bcc_maps_user.cf +5 -0
  214. package/dist/server/engine/samples/postfix/mysql/sender_dependent_relayhost_maps.cf +6 -0
  215. package/dist/server/engine/samples/postfix/mysql/sender_login_maps.cf +5 -0
  216. package/dist/server/engine/samples/postfix/mysql/transport_maps_domain.cf +5 -0
  217. package/dist/server/engine/samples/postfix/mysql/transport_maps_maillist.cf +5 -0
  218. package/dist/server/engine/samples/postfix/mysql/transport_maps_user.cf +5 -0
  219. package/dist/server/engine/samples/postfix/mysql/virtual_alias_maps.cf +5 -0
  220. package/dist/server/engine/samples/postfix/mysql/virtual_mailbox_domains.cf +5 -0
  221. package/dist/server/engine/samples/postfix/mysql/virtual_mailbox_maps.cf +5 -0
  222. package/dist/server/engine/samples/postfix/pgsql/catchall_maps.cf +5 -0
  223. package/dist/server/engine/samples/postfix/pgsql/domain_alias_catchall_maps.cf +5 -0
  224. package/dist/server/engine/samples/postfix/pgsql/domain_alias_maps.cf +5 -0
  225. package/dist/server/engine/samples/postfix/pgsql/recipient_bcc_maps_domain.cf +5 -0
  226. package/dist/server/engine/samples/postfix/pgsql/recipient_bcc_maps_user.cf +5 -0
  227. package/dist/server/engine/samples/postfix/pgsql/relay_domains.cf +5 -0
  228. package/dist/server/engine/samples/postfix/pgsql/sender_bcc_maps_domain.cf +5 -0
  229. package/dist/server/engine/samples/postfix/pgsql/sender_bcc_maps_user.cf +5 -0
  230. package/dist/server/engine/samples/postfix/pgsql/sender_dependent_relayhost_maps.cf +6 -0
  231. package/dist/server/engine/samples/postfix/pgsql/sender_login_maps.cf +5 -0
  232. package/dist/server/engine/samples/postfix/pgsql/transport_maps_domain.cf +5 -0
  233. package/dist/server/engine/samples/postfix/pgsql/transport_maps_maillist.cf +5 -0
  234. package/dist/server/engine/samples/postfix/pgsql/transport_maps_user.cf +5 -0
  235. package/dist/server/engine/samples/postfix/pgsql/virtual_alias_maps.cf +5 -0
  236. package/dist/server/engine/samples/postfix/pgsql/virtual_mailbox_domains.cf +5 -0
  237. package/dist/server/engine/samples/postfix/pgsql/virtual_mailbox_maps.cf +5 -0
  238. package/dist/server/engine/samples/postfix/postscreen_access.cidr +6 -0
  239. package/dist/server/engine/samples/postgresql/sql/add_first_domain_and_user.sql +34 -0
  240. package/dist/server/engine/samples/postgresql/sql/grant_permissions.sql +14 -0
  241. package/dist/server/engine/samples/postgresql/sql/init_vmail_db.sql +15 -0
  242. package/dist/server/engine/samples/rsyslog.d/1-iredmail-dovecot.conf +23 -0
  243. package/dist/server/engine/samples/rsyslog.d/1-iredmail-fail2ban.conf +2 -0
  244. package/dist/server/engine/samples/rsyslog.d/1-iredmail-iredapd.conf +12 -0
  245. package/dist/server/engine/samples/rsyslog.d/1-iredmail-mlmmjadmin.conf +12 -0
  246. package/dist/server/engine/samples/rsyslog.d/1-iredmail-openldap.conf +2 -0
  247. package/dist/server/engine/samples/rsyslog.d/1-iredmail-phpfpm.conf +3 -0
  248. package/dist/server/engine/samples/spamassassin/local.cf +186 -0
  249. package/dist/server/engine/samples/spamassassin/razor.conf +1 -0
  250. package/dist/server/engine/samples/systemd/clamd.service.d/override.conf +2 -0
  251. package/dist/server/engine/samples/systemd/mariadb.service.d/override.conf +3 -0
  252. package/dist/server/engine/samples/systemd/slapd.service.d/override.conf +6 -0
  253. package/dist/server/engine/samples/yum/CentOS-Linux-AppStream.repo +6 -0
  254. package/dist/server/engine/samples/yum/CentOS-Linux-PowerTools.repo +6 -0
  255. package/dist/server/engine/samples/yum/CentOS-Stream-AppStream.repo +7 -0
  256. package/dist/server/engine/samples/yum/CentOS-Stream-PowerTools.repo +7 -0
  257. package/dist/server/engine/samples/yum/symas-openldap.repo +6 -0
  258. package/dist/server/engine/tools/add_enabled_service.py +60 -0
  259. package/dist/server/engine/tools/backup_mysql.sh +238 -0
  260. package/dist/server/engine/tools/backup_openldap.sh +230 -0
  261. package/dist/server/engine/tools/backup_pgsql.sh +217 -0
  262. package/dist/server/engine/tools/backup_sogo.sh +156 -0
  263. package/dist/server/engine/tools/create_mail_user_OpenLDAP.py +335 -0
  264. package/dist/server/engine/tools/create_mail_user_OpenLDAP.sh +287 -0
  265. package/dist/server/engine/tools/create_mail_user_SQL.sh +127 -0
  266. package/dist/server/engine/tools/enable_postscreen.sh +144 -0
  267. package/dist/server/engine/tools/fail2ban_unban_ip.sh +39 -0
  268. package/dist/server/engine/tools/find_sasl_login_ip.sh +20 -0
  269. package/dist/server/engine/tools/find_top_sasl_usernames.sh +28 -0
  270. package/dist/server/engine/tools/generate_ssl_keys.sh +85 -0
  271. package/dist/server/engine/tools/kill_high_cpu_sogo_process.sh +32 -0
  272. package/dist/server/engine/tools/ldap_assign_user_to_groups.py +151 -0
  273. package/dist/server/engine/tools/ldap_move_members_to_another_group.py +129 -0
  274. package/dist/server/engine/tools/migrate_sql_alias_table.py +177 -0
  275. package/dist/server/engine/update/0.9.8/amavisd.mysql +29 -0
  276. package/dist/server/engine/update/0.9.8/amavisd.pgsql +39 -0
  277. package/dist/server/engine/update/0.9.8/iredmail.mysql +53 -0
  278. package/dist/server/engine/update/0.9.8/iredmail.pgsql +61 -0
  279. package/dist/server/engine/update/0.9.9/iredmail.mysql +2 -0
  280. package/dist/server/engine/update/0.9.9/iredmail.pgsql +2 -0
  281. package/dist/server/engine/update/1.0/iredmail.mysql +2 -0
  282. package/dist/server/engine/update/1.0/iredmail.pgsql +2 -0
  283. package/dist/server/engine/update/1.2/last_login.mysql +16 -0
  284. package/dist/server/engine/update/1.4.0/iredmail.mysql +22 -0
  285. package/dist/server/engine/update/1.4.0/iredmail.pgsql +20 -0
  286. package/dist/server/engine/update/1.4.1/iredmail.mysql +3 -0
  287. package/dist/server/engine/update/1.4.1/iredmail.pgsql +3 -0
  288. package/dist/server/engine/update/1.4.1/sogo.mysql +11 -0
  289. package/dist/server/engine/update/1.4.1/sogo.pgsql +30 -0
  290. package/dist/server/engine/update/1.4.1/update-ldap.py +66 -0
  291. package/dist/server/engine/update/1.4.2/iredmail.mysql +9 -0
  292. package/dist/server/engine/update/1.4.2/iredmail.pgsql +9 -0
  293. package/dist/server/engine/update/1.4.2/sogo.pgsql +30 -0
  294. package/dist/server/engine/update/1.6.0/sogo_view.pgsql +27 -0
  295. package/dist/server/engine/update/1.6.3/iredmail.mysql +1 -0
  296. package/dist/server/engine/update/1.7.0/fail2ban.mysql +11 -0
  297. package/dist/server/engine/update/1.7.0/fail2ban.pgsql +12 -0
  298. package/dist/server/engine/update/1.7.1/amavisd.mysql +1 -0
  299. package/dist/server/engine/update/1.7.2/vmail.mysql +30 -0
  300. package/dist/server/engine/update/1.7.3/deleted_mailboxes.mysql +43 -0
  301. package/dist/server/engine/update/1.7.3/iredadmin.mysql +26 -0
  302. package/dist/server/engine/update/1.7.3/vmail.mysql +79 -0
  303. package/dist/server/engine/update/1.7.3/vmail.pgsql +9 -0
  304. package/dist/server/engine/update/README.md +1 -0
  305. package/dist/server/engine/update/ldap/README.md +39 -0
  306. package/dist/server/engine/update/ldap/update-ldap-dovecot-2.3.py +69 -0
  307. package/dist/server/index.js +349016 -0
  308. package/dist/server/lua/geo_country.lua +127 -0
  309. package/dist/server/lua/maxminddb.lua +403 -0
  310. package/dist/server/lua/mgmt_api.lua +654 -0
  311. package/dist/server/lua/pipe_stream.lua +103 -0
  312. package/dist/server/lua/rules_guard.lua +132 -0
  313. package/dist/server/lua/rules_lib.lua +176 -0
  314. package/dist/server/lua/site_logger.lua +405 -0
  315. package/dist/server/lua/webhook_handler.lua +126 -0
  316. package/dist/server/migrations/0000_init.sql +666 -0
  317. package/dist/server/migrations/0001_brief_tomorrow_man.sql +47 -0
  318. package/dist/server/migrations/0002_funny_dazzler.sql +2 -0
  319. package/dist/server/migrations/0003_third_killer_shrike.sql +1 -0
  320. package/dist/server/migrations/0004_session_active_org_not_null.sql +10 -0
  321. package/dist/server/migrations/0005_warm_amazoness.sql +3 -0
  322. package/dist/server/migrations/0006_lumpy_joystick.sql +1 -0
  323. package/dist/server/migrations/0007_outgoing_maginty.sql +2 -0
  324. package/dist/server/migrations/0008_frozen_cutover.sql +3 -0
  325. package/dist/server/migrations/0009_credits_billing.sql +142 -0
  326. package/dist/server/migrations/0010_credit_grant_dedupe.sql +14 -0
  327. package/dist/server/migrations/0011_remove_credit_ledger.sql +23 -0
  328. package/dist/server/migrations/0012_smart_deploys_and_git_rollback.sql +81 -0
  329. package/dist/server/migrations/0013_fix_check_run_rollup_unique.sql +38 -0
  330. package/dist/server/migrations/0014_default_rollback_git.sql +9 -0
  331. package/dist/server/migrations/0015_billing_idempotency_grants.sql +41 -0
  332. package/dist/server/migrations/0016_github_auth_high_findings.sql +30 -0
  333. package/dist/server/migrations/0017_spooky_rumiko_fujikawa.sql +6 -0
  334. package/dist/server/migrations/0018_calm_shatterstar.sql +1 -0
  335. package/dist/server/migrations/0019_rename_workspace_install_to_prepare.sql +1 -0
  336. package/dist/server/migrations/0020_uneven_the_renegades.sql +13 -0
  337. package/dist/server/migrations/0021_shiny_firestar.sql +2 -0
  338. package/dist/server/migrations/0022_version_on_success_backfill.sql +6 -0
  339. package/dist/server/migrations/0023_productive_gorilla_man.sql +17 -0
  340. package/dist/server/migrations/0024_sleepy_peter_quill.sql +2 -0
  341. package/dist/server/migrations/0025_smooth_blue_shield.sql +1 -0
  342. package/dist/server/migrations/0026_mail_backup_source.sql +11 -0
  343. package/dist/server/migrations/0027_opposite_anthem.sql +6 -0
  344. package/dist/server/migrations/0028_stale_rogue.sql +18 -0
  345. package/dist/server/migrations/0029_bouncy_loners.sql +16 -0
  346. package/dist/server/migrations/0030_bright_darkstar.sql +6 -0
  347. package/dist/server/migrations/0031_conscious_catseye.sql +13 -0
  348. package/dist/server/migrations/0032_wet_mimic.sql +51 -0
  349. package/dist/server/migrations/0033_eminent_molly_hayes.sql +2 -0
  350. package/dist/server/migrations/0034_nervous_surge.sql +1 -0
  351. package/dist/server/migrations/0035_thankful_morgan_stark.sql +1 -0
  352. package/dist/server/migrations/0036_gorgeous_scalphunter.sql +17 -0
  353. package/dist/server/migrations/0037_clever_makkari.sql +28 -0
  354. package/dist/server/migrations/0038_young_magneto.sql +1 -0
  355. package/dist/server/migrations/0039_secret_lady_ursula.sql +15 -0
  356. package/dist/server/migrations/0040_sharp_red_wolf.sql +16 -0
  357. package/dist/server/migrations/0041_round_spyke.sql +4 -0
  358. package/dist/server/migrations/0042_dapper_havok.sql +1 -0
  359. package/dist/server/migrations/0043_fast_sharon_ventura.sql +15 -0
  360. package/dist/server/migrations/0044_amused_shape.sql +8 -0
  361. package/dist/server/migrations/0045_amusing_korath.sql +1 -0
  362. package/dist/server/migrations/0046_white_harrier.sql +35 -0
  363. package/dist/server/migrations/0047_sloppy_strong_guy.sql +2 -0
  364. package/dist/server/migrations/0048_funny_emma_frost.sql +2 -0
  365. package/dist/server/migrations/0049_nappy_piledriver.sql +3 -0
  366. package/dist/server/migrations/0050_add_service_deployment_image_digest.sql +1 -0
  367. package/dist/server/migrations/0051_add_update_status.sql +19 -0
  368. package/dist/server/migrations/0052_add_notice_target.sql +2 -0
  369. package/dist/server/migrations/0053_colossal_sandman.sql +14 -0
  370. package/dist/server/migrations/0054_add_instance_smtp.sql +5 -0
  371. package/dist/server/migrations/0055_rainy_klaw.sql +22 -0
  372. package/dist/server/migrations/0056_moaning_daredevil.sql +2 -0
  373. package/dist/server/migrations/0057_complete_prism.sql +18 -0
  374. package/dist/server/migrations/0058_add_server_is_local.sql +1 -0
  375. package/dist/server/migrations/0059_legal_fixer.sql +18 -0
  376. package/dist/server/migrations/0060_add_route_strategy_host_port.sql +3 -0
  377. package/dist/server/migrations/0061_notification_default_multi_kind.sql +3 -0
  378. package/dist/server/migrations/0062_add_incoming_webhook.sql +21 -0
  379. package/dist/server/migrations/0063_add_migration_logs.sql +1 -0
  380. package/dist/server/migrations/0064_add_migration_partial.sql +2 -0
  381. package/dist/server/migrations/0065_custom_app_template.sql +14 -0
  382. package/dist/server/migrations/0066_ensure_migration_partial_columns.sql +2 -0
  383. package/dist/server/migrations/0067_webhook_delivery.sql +28 -0
  384. package/dist/server/migrations/0068_add_migration_target_volumes.sql +1 -0
  385. package/dist/server/migrations/0069_add_project_composite_routes.sql +1 -0
  386. package/dist/server/migrations/0070_forward_git_to_server.sql +1 -0
  387. package/dist/server/migrations/0071_gh_device_token.sql +3 -0
  388. package/dist/server/migrations/0072_gh_device_token_method.sql +1 -0
  389. package/dist/server/migrations/0073_project_volumes_object_storage.sql +3 -0
  390. package/dist/server/migrations/0074_project_compose_path.sql +1 -0
  391. package/dist/server/migrations/0075_service_command_argv.sql +1 -0
  392. package/dist/server/migrations/0076_rollback_retention.sql +17 -0
  393. package/dist/server/migrations/0077_domain_redirect.sql +13 -0
  394. package/dist/server/migrations/0078_grant_source_scope.sql +30 -0
  395. package/dist/server/migrations/0079_project_readiness.sql +18 -0
  396. package/dist/server/migrations/0080_deployment_error_classification.sql +26 -0
  397. package/dist/server/migrations/0081_project_readiness_repair.sql +34 -0
  398. package/dist/server/migrations/0082_edge_target_verification.sql +39 -0
  399. package/dist/server/migrations/0083_service_incident.sql +84 -0
  400. package/dist/server/migrations/0084_analytics_daily_rollup.sql +72 -0
  401. package/dist/server/migrations/0085_resource_usage.sql +68 -0
  402. package/dist/server/migrations/0086_remote_infra_updates.sql +41 -0
  403. package/dist/server/migrations/0087_server_container_version_columns.sql +17 -0
  404. package/dist/server/migrations/0088_audit_source_and_settings.sql +27 -0
  405. package/dist/server/migrations/0089_auto_scan_infra.sql +7 -0
  406. package/dist/server/migrations/0090_project_collect_paths.sql +18 -0
  407. package/dist/server/migrations/0091_project_server_id.sql +26 -0
  408. package/dist/server/migrations/0092_project_internal_alias.sql +13 -0
  409. package/dist/server/migrations/0093_service_incident_org_index.sql +13 -0
  410. package/dist/server/migrations/0094_backup_restore_meta.sql +15 -0
  411. package/dist/server/migrations/0095_backup_restore_cancel.sql +19 -0
  412. package/dist/server/migrations/0096_backup_policy_retention_defaults.sql +20 -0
  413. package/dist/server/migrations/0097_update_status_upstream_only.sql +35 -0
  414. package/dist/server/migrations/0098_instance_product_mode.sql +12 -0
  415. package/dist/server/migrations/0099_mail_webmail_project.sql +24 -0
  416. package/dist/server/migrations/0100_server_ssh_private_key.sql +11 -0
  417. package/dist/server/migrations/0101_mail_resume_step.sql +12 -0
  418. package/dist/server/migrations/0102_project_workload_axes.sql +19 -0
  419. package/dist/server/migrations/0103_dns_credential.sql +41 -0
  420. package/dist/server/migrations/0104_instance_host_control.sql +15 -0
  421. package/dist/server/migrations/0105_mail_inbound_rules.sql +80 -0
  422. package/dist/server/migrations/0106_mcp_call_tracking.sql +23 -0
  423. package/dist/server/migrations/0107_build_minute_metering_indexes.sql +20 -0
  424. package/dist/server/migrations/0108_credential.sql +68 -0
  425. package/dist/server/migrations/0109_service_build_args.sql +9 -0
  426. package/dist/server/migrations/0110_service_deployment_host_ports.sql +18 -0
  427. package/dist/server/migrations/0111_host_port_claim.sql +381 -0
  428. package/dist/server/migrations/0112_backup_run_execution_lease.sql +12 -0
  429. package/dist/server/migrations/0113_docker_migration_execution_lease.sql +11 -0
  430. package/dist/server/migrations/0114_build_session_execution_lease_index.sql +6 -0
  431. package/dist/server/migrations/0115_orphan_target_key.sql +3 -0
  432. package/dist/server/migrations/0116_domain_ssl_challenge.sql +2 -0
  433. package/dist/server/migrations/0117_github_installation_workspace_scope.sql +24 -0
  434. package/dist/server/migrations/0118_git_sources.sql +66 -0
  435. package/dist/server/migrations/0119_backup_run_batch.sql +8 -0
  436. package/dist/server/migrations/0120_domain_primary_unique.sql +24 -0
  437. package/dist/server/migrations/0121_host_port_claim_overlap.sql +14 -0
  438. package/dist/server/migrations/0122_data_transfer_staging.sql +45 -0
  439. package/dist/server/migrations/0123_drop_cloud_infra.sql +7 -0
  440. package/dist/server/migrations/0124_mail_dmarc_report.sql +23 -0
  441. package/dist/server/migrations/0125_server_security_snapshot.sql +22 -0
  442. package/dist/server/migrations/meta/0000_snapshot.json +4848 -0
  443. package/dist/server/migrations/meta/0001_snapshot.json +4991 -0
  444. package/dist/server/migrations/meta/0002_snapshot.json +5013 -0
  445. package/dist/server/migrations/meta/0003_snapshot.json +5020 -0
  446. package/dist/server/migrations/meta/0004_snapshot.json +5020 -0
  447. package/dist/server/migrations/meta/0005_snapshot.json +5039 -0
  448. package/dist/server/migrations/meta/0006_snapshot.json +5045 -0
  449. package/dist/server/migrations/meta/0007_snapshot.json +5057 -0
  450. package/dist/server/migrations/meta/0016_snapshot.json +6053 -0
  451. package/dist/server/migrations/meta/0017_snapshot.json +6091 -0
  452. package/dist/server/migrations/meta/0018_snapshot.json +6098 -0
  453. package/dist/server/migrations/meta/0019_snapshot.json +6098 -0
  454. package/dist/server/migrations/meta/0020_snapshot.json +6201 -0
  455. package/dist/server/migrations/meta/0021_snapshot.json +6213 -0
  456. package/dist/server/migrations/meta/0022_snapshot.json +6213 -0
  457. package/dist/server/migrations/meta/0023_snapshot.json +6331 -0
  458. package/dist/server/migrations/meta/0024_snapshot.json +6343 -0
  459. package/dist/server/migrations/meta/0025_snapshot.json +6350 -0
  460. package/dist/server/migrations/meta/0026_snapshot.json +6440 -0
  461. package/dist/server/migrations/meta/0027_snapshot.json +6447 -0
  462. package/dist/server/migrations/meta/0028_snapshot.json +6581 -0
  463. package/dist/server/migrations/meta/0029_snapshot.json +6710 -0
  464. package/dist/server/migrations/meta/0030_snapshot.json +6748 -0
  465. package/dist/server/migrations/meta/0031_snapshot.json +6859 -0
  466. package/dist/server/migrations/meta/0032_snapshot.json +7222 -0
  467. package/dist/server/migrations/meta/0033_snapshot.json +7249 -0
  468. package/dist/server/migrations/meta/0034_snapshot.json +7255 -0
  469. package/dist/server/migrations/meta/0035_snapshot.json +7262 -0
  470. package/dist/server/migrations/meta/0036_snapshot.json +7392 -0
  471. package/dist/server/migrations/meta/0037_snapshot.json +7602 -0
  472. package/dist/server/migrations/meta/0038_snapshot.json +7609 -0
  473. package/dist/server/migrations/meta/0039_snapshot.json +7714 -0
  474. package/dist/server/migrations/meta/0040_snapshot.json +7820 -0
  475. package/dist/server/migrations/meta/0041_snapshot.json +7833 -0
  476. package/dist/server/migrations/meta/0042_snapshot.json +7839 -0
  477. package/dist/server/migrations/meta/0043_snapshot.json +7938 -0
  478. package/dist/server/migrations/meta/0044_snapshot.json +7982 -0
  479. package/dist/server/migrations/meta/0045_snapshot.json +7989 -0
  480. package/dist/server/migrations/meta/0046_snapshot.json +8263 -0
  481. package/dist/server/migrations/meta/0047_snapshot.json +8275 -0
  482. package/dist/server/migrations/meta/0048_snapshot.json +8289 -0
  483. package/dist/server/migrations/meta/0049_snapshot.json +8308 -0
  484. package/dist/server/migrations/meta/0050_snapshot.json +8314 -0
  485. package/dist/server/migrations/meta/0051_snapshot.json +8460 -0
  486. package/dist/server/migrations/meta/0052_snapshot.json +8472 -0
  487. package/dist/server/migrations/meta/0053_snapshot.json +8556 -0
  488. package/dist/server/migrations/meta/0054_snapshot.json +8586 -0
  489. package/dist/server/migrations/meta/0055_snapshot.json +8756 -0
  490. package/dist/server/migrations/meta/0056_snapshot.json +8777 -0
  491. package/dist/server/migrations/meta/0057_snapshot.json +8904 -0
  492. package/dist/server/migrations/meta/0058_snapshot.json +8911 -0
  493. package/dist/server/migrations/meta/0059_snapshot.json +9061 -0
  494. package/dist/server/migrations/meta/0060_snapshot.json +9081 -0
  495. package/dist/server/migrations/meta/_journal.json +888 -0
  496. package/dist/server/pglite/pglite.data +0 -0
  497. package/dist/server/pglite/pglite.wasm +0 -0
  498. package/dist/setup-JWKZIECM.js +25 -0
  499. package/dist/signin-3M3UPB6K.js +667 -0
  500. package/dist/ssh-client-NWQVRCV7.js +29 -0
  501. package/dist/sso-oidc-3VDIYOEJ.js +834 -0
  502. package/dist/sts-B3WIYLXR.js +1426 -0
  503. package/dist/up-P5DMQ5YO.js +55 -0
  504. package/package.json +58 -0
@@ -0,0 +1,975 @@
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
+ describeProcess,
7
+ probeListeningPortOwners
8
+ } from "./chunk-WYNM7L22.js";
9
+ import {
10
+ envOps,
11
+ opScript
12
+ } from "./chunk-YRSZPVMB.js";
13
+ import {
14
+ resolveEnvironment
15
+ } from "./chunk-OFXBNFNL.js";
16
+ import {
17
+ sq
18
+ } from "./chunk-MNV2QFHW.js";
19
+ import {
20
+ SYSTEM,
21
+ answered,
22
+ refused,
23
+ safeErrorMessage
24
+ } from "./chunk-PVOWHIND.js";
25
+
26
+ // ../../packages/adapters/src/infra/openresty-lua.ts
27
+ import { createHash, randomBytes } from "crypto";
28
+ import { existsSync, readFileSync } from "fs";
29
+ import { dirname, join } from "path";
30
+ import { fileURLToPath } from "url";
31
+
32
+ // ../../packages/adapters/src/infra/lua-embedded.ts
33
+ var EMBEDDED_LUA = {
34
+ "geo_country.lua": "LS0gZ2VvX2NvdW50cnkubHVhCi0tIE1heE1pbmQgR2VvTGl0ZTItQ291bnRyeSBsb29rdXAgd2l0aCBwZXItd29ya2VyIExSVSBjYWNoZS4KLS0KLS0gREIgYW5kIGNhY2hlIGFyZSBwZXItd29ya2VyIG9ubHk6IG9uZSBsb2FkIHBlciB3b3JrZXIsIHNoYXJlZCBieSBhbGwKLS0gcmVxdWVzdHMuIE5vIHJlbG9hZCBwZXIgc3RyZWFtIG9yIHBlciByZXF1ZXN0LgotLQotLSBEZXBlbmRlbmNpZXM6Ci0tICAgTHVhIGJpbmRpbmcg4oCUIGBrcmFmdC5tYXhtaW5kZGJgLCB2ZW5kb3JlZCBiZXNpZGUgdGhpcyBmaWxlLiBGYWxscyBiYWNrIHRvCi0tICAgICAgICAgICAgICAgICBgcmVzdHkubWF4bWluZGRiYCBmb3IgYSBiYXJlIGJveCB0aGF0IGhhcyB0aGUgb3BtIHBhY2thZ2UKLS0gICAgICAgICAgICAgICAgIGluc3RhbGxlZCBmcm9tIGJlZm9yZSB3ZSB2ZW5kb3JlZCBpdC4KLS0gICBDIGxpYnJhcnkgICDigJQgbGlibWF4bWluZGRiLnNvIChgYXBrIGFkZCBsaWJtYXhtaW5kZGJgIGluIGFwcHMvZWRnZS9Eb2NrZXJmaWxlOwotLSAgICAgICAgICAgICAgICAgaW5zdGFsbEdlb0RlcHMoKSBmb3IgYmFyZSBib3hlcykKLS0gICBEYXRhYmFzZSAgICDigJQgL3Vzci9zaGFyZS9HZW9JUC9HZW9MaXRlMi1Db3VudHJ5Lm1tZGIgKGJha2VkIGludG8gdGhlIGVkZ2UKLS0gICAgICAgICAgICAgICAgIGltYWdlIGZyb20gYXBwcy9hcGkvYXNzZXRzL2dlb2lwLCBzbyBubyBydW50aW1lIGRvd25sb2FkKQotLQotLSBGYWxscyBiYWNrIGdyYWNlZnVsbHkgLSBpZiB0aGUgbGlicmFyeSBvciBkYXRhYmFzZSBpcyBtaXNzaW5nLAotLSBnZXRfY291bnRyeV9jb2RlKCkgcmV0dXJucyBuaWwuICBzaXRlX2xvZ2dlci5sdWEgd3JhcHMgdGhpcyBtb2R1bGUgaW4KLS0gcGNhbGwocmVxdWlyZSwgLi4uKSBzbyBhIG1pc3NpbmcgREIgbmV2ZXIgY3Jhc2hlcyB0aGUgcmVxdWVzdCBwaXBlbGluZQotLSAodGhlIGNvdW50cnkgaXQgcmVzb2x2ZXMgZmxvd3MgaW50byB0aGUgcmluZyBidWZmZXIsIGFuZCBmcm9tIHRoZXJlIHRvCi0tIGJvdGggL2xvZ3MvcmVjZW50IGFuZCB0aGUgbGl2ZSBTU0Ugc3RyZWFtKS4gbWdtdF9hcGkgYEdFVCAvc3RhdHVzYCByZXBvcnRzIHdoZXRoZXIgZ2VvIGFjdHVhbGx5Ci0tIHJlc29sdmVkLCBzbyBhIHNpbGVudGx5LWRhcmsgZWRnZSBpcyB2aXNpYmxlIGluc3RlYWQgb2YganVzdCB5aWVsZGluZyBhbgotLSBlbXB0eSBjb3VudHJ5IG1hcC4KCmxvY2FsIF9NID0ge30KCmxvY2FsIERCX1BBVEggPSAiL3Vzci9zaGFyZS9HZW9JUC9HZW9MaXRlMi1Db3VudHJ5Lm1tZGIiCgotLSBWZW5kb3JlZCBjb3B5IGZpcnN0LCBvcG0taW5zdGFsbGVkIGNvcHkgc2Vjb25kLiBgZmZpLmxvYWQoJ2xpYm1heG1pbmRkYicpYAotLSBydW5zIGF0IHJlcXVpcmUgdGltZSBpbiBib3RoLCBzbyBhIG1pc3NpbmcgLnNvIHN1cmZhY2VzIGhlcmUgYXMgbW1kYl9vaz1mYWxzZS4KbG9jYWwgbW1kYl9vaywgbWF4bWluZCA9IHBjYWxsKHJlcXVpcmUsICJrcmFmdC5tYXhtaW5kZGIiKQppZiBub3QgbW1kYl9vayB0aGVuCiAgICBtbWRiX29rLCBtYXhtaW5kID0gcGNhbGwocmVxdWlyZSwgInJlc3R5Lm1heG1pbmRkYiIpCmVuZApsb2NhbCBscnVjYWNoZV9vaywgbHJ1Y2FjaGUgPSBwY2FsbChyZXF1aXJlLCAicmVzdHkubHJ1Y2FjaGUiKQoKbG9jYWwgY2FjaGUgICAgICAgICAgICAtLSBvbmUgTFJVIHBlciB3b3JrZXIKbG9jYWwgZ2VvX2luaXR0ZWQgPSBmYWxzZSAgLS0gREIgb3BlbmVkIG9uY2UgcGVyIHdvcmtlciBvbiBmaXJzdCBsb29rdXAKLS0gV2h5IGdlbyBpcyBvZmYsIGZvciBgR0VUIC9zdGF0dXNgLiBEaXN0aW5ndWlzaGluZyAibm8gRkZJIGJpbmRpbmcgLyBubyAuc28iCi0tIGZyb20gIm5vIGRhdGFiYXNlIiBtYXR0ZXJzOiB0aGV5IG5lZWQgZGlmZmVyZW50IGZpeGVzLCBhbmQgYm90aCB1c2VkIHRvCi0tIHByZXNlbnQgaWRlbnRpY2FsbHkgYXMgYW4gZW1wdHkgY291bnRyeSBtYXAuCmxvY2FsIGdlb19yZWFzb24gPSAibm90IGluaXRpYWxpc2VkIgoKLS0gSW5pdCBNYXhNaW5kIG9uY2UgcGVyIHdvcmtlcjsgc3Vic2VxdWVudCBsb29rdXBzIChhbnkgc3RyZWFtKSByZXVzZS4KbG9jYWwgZnVuY3Rpb24gZW5zdXJlX2dlb19pbml0KCkKICAgIGlmIGdlb19pbml0dGVkIHRoZW4KICAgICAgICByZXR1cm4gdHJ1ZQogICAgZW5kCiAgICBpZiBub3QgbW1kYl9vayBvciBub3QgbWF4bWluZCB0aGVuCiAgICAgICAgZ2VvX3JlYXNvbiA9ICJtYXhtaW5kZGIgRkZJIGJpbmRpbmcgdW5hdmFpbGFibGUgKGxpYm1heG1pbmRkYi5zbyBtaXNzaW5nPykiCiAgICAgICAgcmV0dXJuIGZhbHNlCiAgICBlbmQKICAgIGxvY2FsIG9rLCBlcnIgPSBtYXhtaW5kLmluaXQoREJfUEFUSCkKICAgIGlmIG5vdCBvayB0aGVuCiAgICAgICAgZ2VvX3JlYXNvbiA9ICJkYXRhYmFzZSB1bnJlYWRhYmxlIGF0ICIgLi4gREJfUEFUSCAuLiAiOiAiIC4uIChlcnIgb3IgInVua25vd24iKQogICAgICAgIG5neC5sb2cobmd4LldBUk4sCiAgICAgICAgICAgICJbZ2VvX2NvdW50cnldIEdlb0xpdGUyIGRhdGFiYXNlIG5vdCBmb3VuZCBhdCAiIC4uIERCX1BBVEggLi4KICAgICAgICAgICAgIiAtIGdlbyBsb29rdXBzIGRpc2FibGVkOiAiIC4uIChlcnIgb3IgInVua25vd24iKSkKICAgICAgICByZXR1cm4gZmFsc2UKICAgIGVuZAogICAgZ2VvX2luaXR0ZWQgPSB0cnVlCiAgICBnZW9fcmVhc29uID0gIm9rIgogICAgbmd4LmxvZyhuZ3guSU5GTywgIltnZW9fY291bnRyeV0gR2VvTGl0ZTItQ291bnRyeSBsb2FkZWQgZnJvbSAiIC4uIERCX1BBVEgpCiAgICByZXR1cm4gdHJ1ZQplbmQKCi0tIENyZWF0ZSBMUlUgY2FjaGUgb25jZSBwZXIgd29ya2VyIChtYXggNTAwMDAgSVBzKS4KbG9jYWwgZnVuY3Rpb24gZ2V0X2NhY2hlKCkKICAgIGlmIGNhY2hlIHRoZW4KICAgICAgICByZXR1cm4gY2FjaGUKICAgIGVuZAogICAgaWYgbm90IGxydWNhY2hlX29rIG9yIG5vdCBscnVjYWNoZSB0aGVuCiAgICAgICAgcmV0dXJuIG5pbAogICAgZW5kCiAgICBsb2NhbCBjLCBlcnIgPSBscnVjYWNoZS5uZXcoNTAwMDApCiAgICBpZiBub3QgYyB0aGVuCiAgICAgICAgcmV0dXJuIG5pbAogICAgZW5kCiAgICBjYWNoZSA9IGMKICAgIHJldHVybiBjYWNoZQplbmQKCi0tLSBHZXQgY291bnRyeSBJU08gY29kZSBmb3IgSVAuIFVzZXMgaW4tbWVtb3J5IExSVSBjYWNoZSB0aGVuIE1heE1pbmQgREIuCi0tIEBwYXJhbSBpcCBzdHJpbmcgKGUuZy4gIjguOC44LjgiKQotLSBAcmV0dXJuIHN0cmluZ3xuaWwgY291bnRyeSBjb2RlIChlLmcuICJVUyIpIG9yIG5pbApmdW5jdGlvbiBfTS5nZXRfY291bnRyeV9jb2RlKGlwKQogICAgaWYgbm90IGlwIG9yIGlwID09ICIiIHRoZW4KICAgICAgICByZXR1cm4gbmlsCiAgICBlbmQKCiAgICBsb2NhbCBjID0gZ2V0X2NhY2hlKCkKICAgIGlmIGMgdGhlbgogICAgICAgIGxvY2FsIGNhY2hlZCA9IGM6Z2V0KGlwKQogICAgICAgIGlmIGNhY2hlZCB+PSBuaWwgdGhlbgogICAgICAgICAgICAtLSBmYWxzZSBtZWFucyAibG9va2VkIHVwLCBubyByZXN1bHQiIC0gYXZvaWRzIHJlcGVhdGVkIERCIG1pc3NlcwogICAgICAgICAgICByZXR1cm4gKGNhY2hlZCA9PSBmYWxzZSkgYW5kIG5pbCBvciBjYWNoZWQKICAgICAgICBlbmQKICAgIGVuZAoKICAgIGlmIG5vdCBlbnN1cmVfZ2VvX2luaXQoKSB0aGVuCiAgICAgICAgaWYgYyB0aGVuIGM6c2V0KGlwLCBmYWxzZSkgZW5kCiAgICAgICAgcmV0dXJuIG5pbAogICAgZW5kCgogICAgbG9jYWwgb2ssIHJlcywgZXJyID0gcGNhbGwobWF4bWluZC5sb29rdXAsIGlwKQogICAgbG9jYWwgY29kZSA9IG5pbAogICAgaWYgb2sgYW5kIHJlcyBhbmQgcmVzLmNvdW50cnkgYW5kIHJlcy5jb3VudHJ5Lmlzb19jb2RlIHRoZW4KICAgICAgICBjb2RlID0gcmVzLmNvdW50cnkuaXNvX2NvZGUKICAgIGVuZAoKICAgIGlmIGMgdGhlbgogICAgICAgIGM6c2V0KGlwLCBjb2RlIG9yIGZhbHNlKQogICAgZW5kCiAgICByZXR1cm4gY29kZQplbmQKCmZ1bmN0aW9uIF9NLmVuc3VyZV9nZW9faW5pdCgpCiAgICByZXR1cm4gZW5zdXJlX2dlb19pbml0KCkKZW5kCgotLS0gSGVhbHRoIGZvciBgR0VUIC9zdGF0dXNgOiBkb2VzIGdlbyBhY3R1YWxseSByZXNvbHZlLCBhbmQgaWYgbm90LCB3aHkuCi0tIEByZXR1cm4gYm9vbGVhbiBhdmFpbGFibGUsIHN0cmluZyByZWFzb24sIHN0cmluZyBkYl9wYXRoCmZ1bmN0aW9uIF9NLnN0YXR1cygpCiAgICBsb2NhbCBvayA9IGVuc3VyZV9nZW9faW5pdCgpCiAgICByZXR1cm4gb2ssIGdlb19yZWFzb24sIERCX1BBVEgKZW5kCgpyZXR1cm4gX00K",
35
+ "maxminddb.lua": "LS0gbWF4bWluZGRiLmx1YSDigJQgVkVORE9SRUQgVEhJUkQtUEFSVFkuIERvIG5vdCBlZGl0OyByZS12ZW5kb3IgaW5zdGVhZC4KLS0KLS0gVXBzdHJlYW06IGFuamlhMDUzMi9sdWEtcmVzdHktbWF4bWluZGRiIHYxLjMuMiAob3BtKS4gTG9hZGVkIGFzCi0tIGBrcmFmdC5tYXhtaW5kZGJgIChzZWUgZ2VvX2NvdW50cnkubHVhKS4gVmVyYmF0aW0gZXhjZXB0IHRoaXMgaGVhZGVyIGFuZCBPTkUKLS0gbWFya2VkIGNoYW5nZSB0byB0aGUgYGZmaS5sb2FkYCBjYWxsIOKAlCBzZWFyY2ggIktSQUZUIExPQ0FMIE1PRElGSUNBVElPTiIuCi0tCi0tIFdoeSB2ZW5kb3JlZCByYXRoZXIgdGhhbiBgb3BtIGdldGAgYXQgaW1hZ2UgYnVpbGQ6IGBvcG1gIG5lZWRzIHBlcmwsIHdoaWNoIHRoZQotLSBvcGVucmVzdHkgYWxwaW5lIGJhc2UgZG9lcyBub3Qgc2hpcCwgYW5kIGEgYnVpbGQtdGltZSBmZXRjaCB3b3VsZCBtYWtlIHRoZQotLSBpbWFnZSBub24tcmVwcm9kdWNpYmxlLiBFdmVyeXRoaW5nIGVsc2UgaW4gdGhpcyBkaXJlY3RvcnkgaXMgYWxyZWFkeSBzaGlwcGVkCi0tIGJ5IHVzIChhbmQgYmFzZTY0LWVtYmVkZGVkIGludG8gdGhlIEpTIGJ1bmRsZSksIHNvIGEgcGlubmVkIGNvcHkgaXMgdGhlIGhvdXNlCi0tIHBhdHRlcm4g4oCUIHNhbWUgcmVhc29uaW5nIGFzIHRoZSB2ZW5kb3JlZCBHZW9MaXRlMiBEQiBpbiBhcHBzL2FwaS9hc3NldHMvZ2VvaXAuCi0tCi0tIE5lZWRzIGxpYm1heG1pbmRkYi5zbyBhdCBydW50aW1lIChgYXBrIGFkZCBsaWJtYXhtaW5kZGJgLCBpbiBhcHBzL2VkZ2UvRG9ja2VyZmlsZSkuCi0tIGBmZmkubG9hZGAgYmVsb3cgcnVucyBhdCBSRVFVSVJFIHRpbWUsIHNvIGEgbWlzc2luZyAuc28gdGhyb3dzIG9uIHJlcXVpcmUg4oCUCi0tIGdlb19jb3VudHJ5Lmx1YSBwY2FsbHMgaXQgZm9yIGV4YWN0bHkgdGhhdCByZWFzb24uCi0tCi0tIFJlLXZlbmRvciB3aXRoOgotLSAgIGN1cmwgLWZzU0wgaHR0cHM6Ly9vcG0ub3BlbnJlc3R5Lm9yZy9hcGkvcGtnL3RhcmJhbGwvYW5qaWEwNTMyL2x1YS1yZXN0eS1tYXhtaW5kZGItPHY+Lm9wbS50YXIuZ3ogXAotLSAgICAgfCB0YXIgeHogLU8gJyovbGliL3Jlc3R5L21heG1pbmRkYi5sdWEnID4gcGFja2FnZXMvYWRhcHRlcnMvc3JjL2luZnJhL2x1YS9tYXhtaW5kZGIubHVhCi0tICAgIyB0aGVuIHJlLWFwcGx5IHRoaXMgaGVhZGVyIGFuZCBydW4gYGJ1biBydW4gZW1iZWQ6bHVhYAotLVtbCglDb3B5cmlnaHQgMjAxNy1ub3cgYW5qaWEgKGFuamlhMDUzMkBnbWFpbC5jb20pCgoJTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7Cgl5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCglZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKCQlodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKCVVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmUKCWRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCglXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KCVNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKCWxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgpdXQoKLS0gY29weSBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9saWxpZW4xMDEwL2x1YS1yZXN0eS1tYXhtaW5kZGIvYmxvYi9mOTY2MzNlMjQyOGY4ZjdiY2MxZTJhN2EyOGI3NDdiMzMyMzNhOGRiL3Jlc3R5L21heG1pbmRkYi5sdWEjTDUtTDEyCgpsb2NhbCBmZmkgICAgICAgICAgICAgICAgID0gcmVxdWlyZSAoJ2ZmaScpCmxvY2FsIGZmaV9uZXcgICAgICAgICAgICAgPSBmZmkubmV3CmxvY2FsIGZmaV9zdHIgICAgICAgICAgICAgPSBmZmkuc3RyaW5nCmxvY2FsIGZmaV9jYXN0ICAgICAgICAgICAgPSBmZmkuY2FzdApsb2NhbCBmZmlfZ2MgICAgICAgICAgICAgID0gZmZpLmdjCmxvY2FsIEMgICAgICAgICAgICAgICAgICAgPSBmZmkuQwoKbG9jYWwgX00gICAgPXt9Cl9NLl9WRVJTSU9OID0gJzEuMy4yJwpsb2NhbCBtdCA9IHsgX19pbmRleCA9IF9NIH0KCi0tIGNvcHkgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vbGlsaWVuMTAxMC9sdWEtcmVzdHktbWF4bWluZGRiL2Jsb2IvZjk2NjMzZTI0MjhmOGY3YmNjMWUyYTdhMjhiNzQ3YjMzMjMzYThkYi9yZXN0eS9tYXhtaW5kZGIubHVhI0wzNi1MMTI2CmZmaS5jZGVmW1sKCnR5cGVkZWYgbG9uZyBpbnQgc3NpemVfdDsKCnR5cGVkZWYgdW5zaWduZWQgaW50IG1tZGJfdWludDEyOF90IF9fYXR0cmlidXRlX18gKChfX21vZGVfXyhUSSkpKTsKCnR5cGVkZWYgc3RydWN0IE1NREJfZW50cnlfcyB7CiAgc3RydWN0IE1NREJfcyAqbW1kYjsKICB1aW50MzJfdCBvZmZzZXQ7Cn0gTU1EQl9lbnRyeV9zOwoKdHlwZWRlZiBzdHJ1Y3QgTU1EQl9sb29rdXBfcmVzdWx0X3MgewogIGJvb2wgZm91bmRfZW50cnk7CiAgTU1EQl9lbnRyeV9zIGVudHJ5OwogIHVpbnQxNl90IG5ldG1hc2s7Cn0gTU1EQl9sb29rdXBfcmVzdWx0X3M7Cgp0eXBlZGVmIHN0cnVjdCBNTURCX2VudHJ5X2RhdGFfcyB7CiAgYm9vbCBoYXNfZGF0YTsKICB1bmlvbiB7CiAgICB1aW50MzJfdCBwb2ludGVyOwogICAgY29uc3QgY2hhciAqdXRmOF9zdHJpbmc7CiAgICBkb3VibGUgZG91YmxlX3ZhbHVlOwogICAgY29uc3QgdWludDhfdCAqYnl0ZXM7CiAgICB1aW50MTZfdCB1aW50MTY7CiAgICB1aW50MzJfdCB1aW50MzI7CiAgICBpbnQzMl90IGludDMyOwogICAgdWludDY0X3QgdWludDY0OwogICAgbW1kYl91aW50MTI4X3QgdWludDEyODsKICAgIGJvb2wgYm9vbGVhbjsKICAgIGZsb2F0IGZsb2F0X3ZhbHVlOwogIH07CgogIHVpbnQzMl90IG9mZnNldDsKICB1aW50MzJfdCBvZmZzZXRfdG9fbmV4dDsKICB1aW50MzJfdCBkYXRhX3NpemU7CiAgdWludDMyX3QgdHlwZTsKfSBNTURCX2VudHJ5X2RhdGFfczsKCnR5cGVkZWYgc3RydWN0IE1NREJfZW50cnlfZGF0YV9saXN0X3MgewogIE1NREJfZW50cnlfZGF0YV9zIGVudHJ5X2RhdGE7CiAgc3RydWN0IE1NREJfZW50cnlfZGF0YV9saXN0X3MgKm5leHQ7Cn0gTU1EQl9lbnRyeV9kYXRhX2xpc3RfczsKCnR5cGVkZWYgc3RydWN0IE1NREJfZGVzY3JpcHRpb25fcyB7CiAgY29uc3QgY2hhciAqbGFuZ3VhZ2U7CiAgY29uc3QgY2hhciAqZGVzY3JpcHRpb247Cn0gTU1EQl9kZXNjcmlwdGlvbl9zOwoKdHlwZWRlZiBzdHJ1Y3QgTU1EQl9tZXRhZGF0YV9zIHsKICB1aW50MzJfdCBub2RlX2NvdW50OwogIHVpbnQxNl90IHJlY29yZF9zaXplOwogIHVpbnQxNl90IGlwX3ZlcnNpb247CiAgY29uc3QgY2hhciAqZGF0YWJhc2VfdHlwZTsKICBzdHJ1Y3QgewogICAgc2l6ZV90IGNvdW50OwogICAgY29uc3QgY2hhciAqKm5hbWVzOwogIH0gbGFuZ3VhZ2VzOwogIHVpbnQxNl90IGJpbmFyeV9mb3JtYXRfbWFqb3JfdmVyc2lvbjsKICB1aW50MTZfdCBiaW5hcnlfZm9ybWF0X21pbm9yX3ZlcnNpb247CiAgdWludDY0X3QgYnVpbGRfZXBvY2g7CiAgc3RydWN0IHsKICAgIHNpemVfdCBjb3VudDsKICAgIE1NREJfZGVzY3JpcHRpb25fcyAqKmRlc2NyaXB0aW9uczsKICB9IGRlc2NyaXB0aW9uOwp9IE1NREJfbWV0YWRhdGFfczsKCnR5cGVkZWYgc3RydWN0IE1NREJfaXB2NF9zdGFydF9ub2RlX3MgewogIHVpbnQxNl90IG5ldG1hc2s7CiAgdWludDMyX3Qgbm9kZV92YWx1ZTsKfSBNTURCX2lwdjRfc3RhcnRfbm9kZV9zOwoKdHlwZWRlZiBzdHJ1Y3QgTU1EQl9zIHsKICB1aW50MzJfdCBmbGFnczsKICBjb25zdCBjaGFyICpmaWxlbmFtZTsKICBzc2l6ZV90IGZpbGVfc2l6ZTsKICBjb25zdCB1aW50OF90ICpmaWxlX2NvbnRlbnQ7CiAgY29uc3QgdWludDhfdCAqZGF0YV9zZWN0aW9uOwogIHVpbnQzMl90IGRhdGFfc2VjdGlvbl9zaXplOwogIGNvbnN0IHVpbnQ4X3QgKm1ldGFkYXRhX3NlY3Rpb247CiAgdWludDMyX3QgbWV0YWRhdGFfc2VjdGlvbl9zaXplOwogIHVpbnQxNl90IGZ1bGxfcmVjb3JkX2J5dGVfc2l6ZTsKICB1aW50MTZfdCBkZXB0aDsKICBNTURCX2lwdjRfc3RhcnRfbm9kZV9zIGlwdjRfc3RhcnRfbm9kZTsKICBNTURCX21ldGFkYXRhX3MgbWV0YWRhdGE7Cn0gTU1EQl9zOwoKdHlwZWRlZiAgY2hhciAqIHBjaGFyOwoKTU1EQl9sb29rdXBfcmVzdWx0X3MgTU1EQl9sb29rdXBfc3RyaW5nKE1NREJfcyAqY29uc3QgbW1kYiwgICBjb25zdCBjaGFyICpjb25zdCBpcHN0ciwgaW50ICpjb25zdCBnYWlfZXJyb3IsaW50ICpjb25zdCBtbWRiX2Vycm9yKTsKaW50IE1NREJfb3Blbihjb25zdCBjaGFyICpjb25zdCBmaWxlbmFtZSwgdWludDMyX3QgZmxhZ3MsIE1NREJfcyAqY29uc3QgbW1kYik7CmludCBNTURCX2FnZXRfdmFsdWUoTU1EQl9lbnRyeV9zICpjb25zdCBzdGFydCwgIE1NREJfZW50cnlfZGF0YV9zICpjb25zdCBlbnRyeV9kYXRhLCAgY29uc3QgY2hhciAqY29uc3QgKmNvbnN0IHBhdGgpOwpjaGFyICpNTURCX3N0cmVycm9yKGludCBlcnJvcl9jb2RlKTsKCmludCBNTURCX2dldF9lbnRyeV9kYXRhX2xpc3QoTU1EQl9lbnRyeV9zICpzdGFydCwgTU1EQl9lbnRyeV9kYXRhX2xpc3RfcyAqKmNvbnN0IGVudHJ5X2RhdGFfbGlzdCk7CnZvaWQgTU1EQl9mcmVlX2VudHJ5X2RhdGFfbGlzdChNTURCX2VudHJ5X2RhdGFfbGlzdF9zICpjb25zdCBlbnRyeV9kYXRhX2xpc3QpOwp2b2lkIE1NREJfY2xvc2UoTU1EQl9zICpjb25zdCBtbWRiKTsKY29uc3QgY2hhciAqZ2FpX3N0cmVycm9yKGludCBlcnJjb2RlKTsKXV0KCi0tIGVycm9yIGNvZGVzIAotLSBodHRwczovL2dpdGh1Yi5jb20vbWF4bWluZC9saWJtYXhtaW5kZGIvYmxvYi9tYXN0ZXIvaW5jbHVkZS9tYXhtaW5kZGIuaCNMNjYKbG9jYWwgTU1EQl9TVUNDRVNTICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID0gICAwCmxvY2FsIE1NREJfRklMRV9PUEVOX0VSUk9SICAgICAgICAgICAgICAgICAgICAgICAgICA9ICAgMQpsb2NhbCBNTURCX0NPUlJVUFRfU0VBUkNIX1RSRUVfRVJST1IgICAgICAgICAgICAgICAgPSAgIDIKbG9jYWwgTU1EQl9JTlZBTElEX01FVEFEQVRBX0VSUk9SICAgICAgICAgICAgICAgICAgID0gICAzCmxvY2FsIE1NREJfSU9fRVJST1IgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9ICAgNApsb2NhbCBNTURCX09VVF9PRl9NRU1PUllfRVJST1IgICAgICAgICAgICAgICAgICAgICAgPSAgIDUKbG9jYWwgTU1EQl9VTktOT1dOX0RBVEFCQVNFX0ZPUk1BVF9FUlJPUiAgICAgICAgICAgID0gICA2CmxvY2FsIE1NREJfSU5WQUxJRF9EQVRBX0VSUk9SICAgICAgICAgICAgICAgICAgICAgICA9ICAgNwpsb2NhbCBNTURCX0lOVkFMSURfTE9PS1VQX1BBVEhfRVJST1IgICAgICAgICAgICAgICAgPSAgIDgKbG9jYWwgTU1EQl9MT09LVVBfUEFUSF9ET0VTX05PVF9NQVRDSF9EQVRBX0VSUk9SICAgID0gICA5CmxvY2FsIE1NREJfSU5WQUxJRF9OT0RFX05VTUJFUl9FUlJPUiAgICAgICAgICAgICAgICA9ICAgMTAKbG9jYWwgTU1EQl9JUFY2X0xPT0tVUF9JTl9JUFY0X0RBVEFCQVNFX0VSUk9SICAgICAgID0gICAxMQoKLS0gZGF0YSB0eXBlCi0tIGh0dHBzOi8vZ2l0aHViLmNvbS9tYXhtaW5kL2xpYm1heG1pbmRkYi9ibG9iL21hc3Rlci9pbmNsdWRlL21heG1pbmRkYi5oI0w0MApsb2NhbCBNTURCX0RBVEFfVFlQRV9FWFRFTkRFRCAgICAgICAgICAgICAgICAgICAgICAgPSAgIDAKbG9jYWwgTU1EQl9EQVRBX1RZUEVfUE9JTlRFUiAgICAgICAgICAgICAgICAgICAgICAgID0gICAxCmxvY2FsIE1NREJfREFUQV9UWVBFX1VURjhfU1RSSU5HICAgICAgICAgICAgICAgICAgICA9ICAgMgpsb2NhbCBNTURCX0RBVEFfVFlQRV9ET1VCTEUgICAgICAgICAgICAgICAgICAgICAgICAgPSAgIDMKbG9jYWwgTU1EQl9EQVRBX1RZUEVfQllURVMgICAgICAgICAgICAgICAgICAgICAgICAgID0gICA0CmxvY2FsIE1NREJfREFUQV9UWVBFX1VJTlQxNiAgICAgICAgICAgICAgICAgICAgICAgICA9ICAgNQpsb2NhbCBNTURCX0RBVEFfVFlQRV9VSU5UMzIgICAgICAgICAgICAgICAgICAgICAgICAgPSAgIDYKbG9jYWwgTU1EQl9EQVRBX1RZUEVfTUFQICAgICAgICAgICAgICAgICAgICAgICAgICAgID0gICA3CmxvY2FsIE1NREJfREFUQV9UWVBFX0lOVDMyICAgICAgICAgICAgICAgICAgICAgICAgICA9ICAgOApsb2NhbCBNTURCX0RBVEFfVFlQRV9VSU5UNjQgICAgICAgICAgICAgICAgICAgICAgICAgPSAgIDkKbG9jYWwgTU1EQl9EQVRBX1RZUEVfVUlOVDEyOCAgICAgICAgICAgICAgICAgICAgICAgID0gICAxMApsb2NhbCBNTURCX0RBVEFfVFlQRV9BUlJBWSAgICAgICAgICAgICAgICAgICAgICAgICAgPSAgIDExCmxvY2FsIE1NREJfREFUQV9UWVBFX0NPTlRBSU5FUiAgICAgICAgICAgICAgICAgICAgICA9ICAgMTIKbG9jYWwgTU1EQl9EQVRBX1RZUEVfRU5EX01BUktFUiAgICAgICAgICAgICAgICAgICAgID0gICAxMwpsb2NhbCBNTURCX0RBVEFfVFlQRV9CT09MRUFOICAgICAgICAgICAgICAgICAgICAgICAgPSAgIDE0CmxvY2FsIE1NREJfREFUQV9UWVBFX0ZMT0FUICAgICAgICAgICAgICAgICAgICAgICAgICA9ICAgMTUKCi0tIGNvcHkgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vbGlsaWVuMTAxMC9sdWEtcmVzdHktbWF4bWluZGRiL2Jsb2IvZjk2NjMzZTI0MjhmOGY3YmNjMWUyYTdhMjhiNzQ3YjMzMjMzYThkYi9yZXN0eS9tYXhtaW5kZGIubHVhI0wxMzYtTDEzOAotLSB5b3Ugc2hvdWxkIGluc3RhbGwgdGhlIGxpYm1heG1pbmRkYiB0byB5b3VyIHN5c3RlbQotLQotLSDilIDilIAgS1JBRlQgTE9DQUwgTU9ESUZJQ0FUSU9OICh0aGUgb25seSBkZXZpYXRpb24gZnJvbSB1cHN0cmVhbSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACi0tIFVwc3RyZWFtIGlzIGBmZmkubG9hZCgnbGlibWF4bWluZGRiJylgLCB3aGljaCByZXNvbHZlcyB0aGUgTElOS0VSIG5hbWUKLS0gYGxpYm1heG1pbmRkYi5zb2Ag4oCUIGFuZCB0aGF0IHVudmVyc2lvbmVkIHN5bWxpbmsgc2hpcHMgaW4gdGhlIC1kZXYgcGFja2FnZSwgbm90Ci0tIHRoZSBydW50aW1lIG9uZS4gQWxwaW5lJ3MgYGxpYm1heG1pbmRkYmAgYW5kIERlYmlhbidzIGBsaWJtYXhtaW5kZGIwYCBib3RoIGdpdmUKLS0gb25seSBgbGlibWF4bWluZGRiLnNvLjBgLCBzbyB0aGUgYmFyZSBuYW1lIGZhaWxzIG9uIGEgbm9ybWFsIHJ1bnRpbWUgaW5zdGFsbCBhbmQKLS0gZ2VvIGdvZXMgc2lsZW50bHkgZGFyayAoZ2VvX2NvdW50cnkgcGNhbGxzIHRoaXMgcmVxdWlyZSkuIFRyeSB0aGUgc29uYW1lIHRvbyBzbwotLSB0aGUgcnVudGltZSBwYWNrYWdlIGFsb25lIGlzIGVub3VnaCBvbiBldmVyeSBkaXN0cm8uCmxvY2FsIG1heG0KZG8KICAgIGxvY2FsIGNhbmRpZGF0ZXMgPSB7ICdsaWJtYXhtaW5kZGInLCAnbGlibWF4bWluZGRiLnNvLjAnLCAnbGlibWF4bWluZGRiLnNvJyB9CiAgICBsb2NhbCBsYXN0X2VycgogICAgZm9yIGkgPSAxLCAjY2FuZGlkYXRlcyBkbwogICAgICAgIGxvY2FsIG9rLCBsaWIgPSBwY2FsbChmZmkubG9hZCwgY2FuZGlkYXRlc1tpXSkKICAgICAgICBpZiBvayB0aGVuIG1heG0gPSBsaWI7IGJyZWFrIGVuZAogICAgICAgIGxhc3RfZXJyID0gbGliCiAgICBlbmQKICAgIGlmIG5vdCBtYXhtIHRoZW4KICAgICAgICBlcnJvcignbGlibWF4bWluZGRiIG5vdCBsb2FkYWJsZSAodHJpZWQgJyAuLiB0YWJsZS5jb25jYXQoY2FuZGlkYXRlcywgJywgJykgLi4KICAgICAgICAgICAgICAnKTogJyAuLiB0b3N0cmluZyhsYXN0X2VyciksIDIpCiAgICBlbmQKZW5kCi0taHR0cHM6Ly9naXRodWIuY29tL21heG1pbmQvbGlibWF4bWluZGRiCmxvY2FsIG1tZGIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9IGZmaV9uZXcoJ01NREJfcycpCmxvY2FsIGluaXR0ZWQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9IGZhbHNlCgpsb2NhbCBmdW5jdGlvbiBtbWRiX3N0cmVycm9yKHJjKQogICAgcmV0dXJuIGZmaV9zdHIobWF4bS5NTURCX3N0cmVycm9yKHJjKSkKZW5kCgpsb2NhbCBmdW5jdGlvbiBnYWlfc3RyZXJyb3IocmMpCiAgICByZXR1cm4gZmZpX3N0cihDLmdhaV9zdHJlcnJvcihyYykpCmVuZAoKZnVuY3Rpb24gX00uaW5pdChkYmZpbGUpCiAgaWYgbm90IGluaXR0ZWQgdGhlbgogICAgbG9jYWwgbWF4bWluZF9yZWFkeSAgID0gbWF4bS5NTURCX29wZW4oZGJmaWxlLDAsbW1kYikKCiAgICBpZiBtYXhtaW5kX3JlYWR5IH49IE1NREJfU1VDQ0VTUyB0aGVuCiAgICAgICAgcmV0dXJuIG5pbCwgbW1kYl9zdHJlcnJvcihtYXhtaW5kX3JlYWR5KQogICAgZW5kCiAgICAKICAgIGluaXR0ZWQgPSB0cnVlCiAgICAKICAgIGZmaV9nYyhtbWRiLCBtYXhtLk1NREJfY2xvc2UpCiAgZW5kCiAgcmV0dXJuIGluaXR0ZWQKZW5kCgpmdW5jdGlvbiBfTS5pbml0dGVkKCkKICAgIHJldHVybiBpbml0dGVkCmVuZAoKLS0gaHR0cHM6Ly9naXRodWIuY29tL21heG1pbmQvbGlibWF4bWluZGRiL2Jsb2IvbWFzdGVyL3NyYy9tYXhtaW5kZGIuYyNMMTkzOCAKLS0gTE9DQUwgTU1EQl9lbnRyeV9kYXRhX2xpc3RfcyAqZHVtcF9lbnRyeV9kYXRhX2xpc3QoIEZJTEUgKnN0cmVhbSwgTU1EQl9lbnRyeV9kYXRhX2xpc3RfcyAqZW50cnlfZGF0YV9saXN0LCBpbnQgaW5kZW50LCBpbnQgKnN0YXR1cykKbG9jYWwgZnVuY3Rpb24gX2R1bXBfZW50cnlfZGF0YV9saXN0KGVudHJ5X2RhdGFfbGlzdCxzdGF0dXMpCgogIGlmIG5vdCBlbnRyeV9kYXRhX2xpc3QgdGhlbgogICAgcmV0dXJuIG5pbCxNTURCX0lOVkFMSURfREFUQV9FUlJPUgogIGVuZAogIAogIGxvY2FsIGVudHJ5X2RhdGFfaXRlbSA9IGVudHJ5X2RhdGFfbGlzdFswXS5lbnRyeV9kYXRhCiAgbG9jYWwgZGF0YV90eXBlID0gZW50cnlfZGF0YV9pdGVtLnR5cGUKICBsb2NhbCBkYXRhX3NpemUgPSBlbnRyeV9kYXRhX2l0ZW0uZGF0YV9zaXplCiAgbG9jYWwgcmVzdWx0CiAgCiAgaWYgZGF0YV90eXBlID09IE1NREJfREFUQV9UWVBFX01BUCB0aGVuCiAgICByZXN1bHQgPSB7fQogICAgCiAgICBsb2NhbCBzaXplID0gZW50cnlfZGF0YV9pdGVtLmRhdGFfc2l6ZQogICAgCiAgICBlbnRyeV9kYXRhX2xpc3QgPSBlbnRyeV9kYXRhX2xpc3RbMF0ubmV4dAogICAgCiAgICB3aGlsZShzaXplID4gMCBhbmQgZW50cnlfZGF0YV9saXN0KQogICAgZG8gCiAgICAgIGVudHJ5X2RhdGFfaXRlbSA9IGVudHJ5X2RhdGFfbGlzdFswXS5lbnRyeV9kYXRhCiAgICAgIGRhdGFfdHlwZSA9IGVudHJ5X2RhdGFfaXRlbS50eXBlCiAgICAgIGRhdGFfc2l6ZSA9IGVudHJ5X2RhdGFfaXRlbS5kYXRhX3NpemUKICAgICAgCiAgICAgIGlmIE1NREJfREFUQV9UWVBFX1VURjhfU1RSSU5HICB+PSBkYXRhX3R5cGUgdGhlbgogICAgICAgIHJldHVybiBuaWwsTU1EQl9JTlZBTElEX0RBVEFfRVJST1IKICAgICAgZW5kCiAgICAgIAogICAgICBsb2NhbCBrZXkgPSBmZmlfc3RyKGVudHJ5X2RhdGFfaXRlbS51dGY4X3N0cmluZyxkYXRhX3NpemUpCgogICAgICBpZiBub3Qga2V5IHRoZW4KICAgICAgICByZXR1cm4gbmlsLE1NREJfT1VUX09GX01FTU9SWV9FUlJPUgogICAgICBlbmQKICAgICAgCiAgICAgIGxvY2FsIHZhbAogICAgICBlbnRyeV9kYXRhX2xpc3QgPSBlbnRyeV9kYXRhX2xpc3RbMF0ubmV4dAogICAgICBlbnRyeV9kYXRhX2xpc3Qsc3RhdHVzLHZhbCA9IF9kdW1wX2VudHJ5X2RhdGFfbGlzdChlbnRyeV9kYXRhX2xpc3QpCiAgICAgIAogICAgICBpZiBzdGF0dXMgfj0gTU1EQl9TVUNDRVNTIHRoZW4KICAgICAgICByZXR1cm4gbmlsLHN0YXR1cwogICAgICBlbmQKCiAgICAgIHJlc3VsdFtrZXldID0gdmFsCiAgICAgIAogICAgICBzaXplID0gc2l6ZSAtMSAKICAgIGVuZAogICAgCgogIGVsc2VpZiBlbnRyeV9kYXRhX2xpc3RbMF0uZW50cnlfZGF0YS50eXBlID09IE1NREJfREFUQV9UWVBFX0FSUkFZIHRoZW4KICAgIGxvY2FsIHNpemUgPSBlbnRyeV9kYXRhX2xpc3RbMF0uZW50cnlfZGF0YS5kYXRhX3NpemUKICAgIHJlc3VsdCA9IHt9CgogICAgZW50cnlfZGF0YV9saXN0ID0gZW50cnlfZGF0YV9saXN0WzBdLm5leHQKICAgIAogICAgbG9jYWwgaSA9IDEKICAgIHdoaWxlKGkgPD0gc2l6ZSBhbmQgZW50cnlfZGF0YV9saXN0KQogICAgZG8KICAgICAgbG9jYWwgdmFsCiAgICAgIGVudHJ5X2RhdGFfbGlzdCxzdGF0dXMsdmFsID0gX2R1bXBfZW50cnlfZGF0YV9saXN0KGVudHJ5X2RhdGFfbGlzdCkKICAgICAgCiAgICAgIGlmIHN0YXR1cyB+PSBNTURCX1NVQ0NFU1MgdGhlbgogICAgICAgIHJldHVybiBuaWwsbmlsLHZhbAogICAgICBlbmQKICAgICAgCiAgICAgIHJlc3VsdFtpXSA9IHZhbAogICAgICBpID0gaSArIDEKICAgIGVuZAoKICAgIAogIGVsc2UKICAgIGVudHJ5X2RhdGFfaXRlbSA9IGVudHJ5X2RhdGFfbGlzdFswXS5lbnRyeV9kYXRhCiAgICBkYXRhX3R5cGUgPSBlbnRyeV9kYXRhX2l0ZW0udHlwZQogICAgZGF0YV9zaXplID0gZW50cnlfZGF0YV9pdGVtLmRhdGFfc2l6ZQogICAgCiAgICBsb2NhbCB2YWwKICAgIC0tIHN0cmluZyB0eXBlICJrZXkiOiJ2YWwiCiAgICAtLSBvdGhlciB0eXBlICJrZXkiOnZhbAogICAgLS0gZGVmYXVsdCBvdGhlciB0eXBlCiAgICBpZiBkYXRhX3R5cGUgPT0gTU1EQl9EQVRBX1RZUEVfVVRGOF9TVFJJTkcgdGhlbgogICAgICB2YWwgPSBmZmlfc3RyKGVudHJ5X2RhdGFfaXRlbS51dGY4X3N0cmluZyxkYXRhX3NpemUpCiAgICAgIGlmIG5vdCB2YWwgdGhlbgogICAgICAgIHN0YXR1cyA9IE1NREJfT1VUX09GX01FTU9SWV9FUlJPUgogICAgICAgIHJldHVybiBuaWwsc3RhdHVzCiAgICAgIGVuZAogICAgZWxzZWlmIGRhdGFfdHlwZSA9PSBNTURCX0RBVEFfVFlQRV9CWVRFUyB0aGVuCiAgICAgIHZhbCA9IGZmaV9zdHIoZmZpX2Nhc3QoJ2NoYXIgKiAnLGVudHJ5X2RhdGFfaXRlbS5ieXRlcyksZGF0YV9zaXplKQogICAgICBpZiBub3QgdmFsIHRoZW4KICAgICAgICBzdGF0dXMgPSBNTURCX09VVF9PRl9NRU1PUllfRVJST1IKICAgICAgICByZXR1cm4gbmlsLHN0YXR1cwogICAgICBlbmQKICAgIGVsc2VpZiBkYXRhX3R5cGUgPT0gTU1EQl9EQVRBX1RZUEVfRE9VQkxFIHRoZW4KICAgICAgdmFsID0gZW50cnlfZGF0YV9pdGVtLmRvdWJsZV92YWx1ZQogICAgZWxzZWlmIGRhdGFfdHlwZSA9PSBNTURCX0RBVEFfVFlQRV9GTE9BVCB0aGVuCiAgICAgIHZhbCA9IGVudHJ5X2RhdGFfaXRlbS5mbG9hdF92YWx1ZQogICAgZWxzZWlmIGRhdGFfdHlwZSA9PSBNTURCX0RBVEFfVFlQRV9VSU5UMTYgdGhlbgogICAgICB2YWwgPSBlbnRyeV9kYXRhX2l0ZW0udWludDE2CiAgICBlbHNlaWYgZGF0YV90eXBlID09IE1NREJfREFUQV9UWVBFX1VJTlQzMiB0aGVuCiAgICAgIHZhbCA9IGVudHJ5X2RhdGFfaXRlbS51aW50MzIKICAgIGVsc2VpZiBkYXRhX3R5cGUgPT0gTU1EQl9EQVRBX1RZUEVfQk9PTEVBTiB0aGVuCiAgICAgIHZhbCA9IGVudHJ5X2RhdGFfaXRlbS5ib29sZWFuCiAgICBlbHNlaWYgZGF0YV90eXBlID09IE1NREJfREFUQV9UWVBFX1VJTlQ2NCB0aGVuCiAgICAgIHZhbCA9IGVudHJ5X2RhdGFfaXRlbS51aW50NjQKICAgIGVsc2VpZiBkYXRhX3R5cGUgPT0gTU1EQl9EQVRBX1RZUEVfSU5UMzIgdGhlbgogICAgICB2YWwgPSBlbnRyeV9kYXRhX2l0ZW0uaW50MzIKICAgIGVsc2UKICAgICAgcmV0dXJuIG5pbCxNTURCX0lOVkFMSURfREFUQV9FUlJPUgogICAgZW5kCiAgICAKICAgIHJlc3VsdCA9IHZhbAogICAgZW50cnlfZGF0YV9saXN0ID0gZW50cnlfZGF0YV9saXN0WzBdLm5leHQKICBlbmQKCiAgc3RhdHVzID0gTU1EQl9TVUNDRVNTCiAgcmV0dXJuIGVudHJ5X2RhdGFfbGlzdCxzdGF0dXMscmVzdWx0CmVuZAoKZnVuY3Rpb24gX00ubG9va3VwKGlwKQoKICBpZiBub3QgaW5pdHRlZCB0aGVuCiAgICAgIHJldHVybiBuaWwsICJub3QgaW5pdGlhbGl6ZWQiCiAgZW5kCiAgCiAgLS0gY29weSBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9saWxpZW4xMDEwL2x1YS1yZXN0eS1tYXhtaW5kZGIvYmxvYi9mOTY2MzNlMjQyOGY4ZjdiY2MxZTJhN2EyOGI3NDdiMzMyMzNhOGRiL3Jlc3R5L21heG1pbmRkYi5sdWEjTDE1OS1MMTc2CiAgbG9jYWwgZ2FpX2Vycm9yID0gZmZpX25ldygnaW50WzFdJykKICBsb2NhbCBtbWRiX2Vycm9yID0gZmZpX25ldygnaW50WzFdJykKCiAgbG9jYWwgcmVzdWx0ID0gbWF4bS5NTURCX2xvb2t1cF9zdHJpbmcobW1kYixpcCxnYWlfZXJyb3IsbW1kYl9lcnJvcikKCiAgaWYgbW1kYl9lcnJvclswXSB+PSBNTURCX1NVQ0NFU1MgdGhlbgogICAgcmV0dXJuIG5pbCwnbG9va3VwIGZhaWxlZDogJyAuLiBtbWRiX3N0cmVycm9yKG1tZGJfZXJyb3JbMF0pCiAgZW5kCgogIGlmIGdhaV9lcnJvclswXSB+PSBNTURCX1NVQ0NFU1MgdGhlbgogICAgcmV0dXJuIG5pbCwnbG9va3VwIGZhaWxlZDogJyAuLiBnYWlfc3RyZXJyb3IoZ2FpX2Vycm9yWzBdKQogIGVuZAoKICBpZiB0cnVlIH49IHJlc3VsdC5mb3VuZF9lbnRyeSB0aGVuCiAgICByZXR1cm4gbmlsLCdub3QgZm91bmQnCiAgZW5kCgogIGxvY2FsIGVudHJ5X2RhdGFfbGlzdCA9IGZmaV9jYXN0KCdNTURCX2VudHJ5X2RhdGFfbGlzdF9zICoqY29uc3QnLGZmaV9uZXcoIk1NREJfZW50cnlfZGF0YV9saXN0X3MiKSkKCiAgbG9jYWwgc3RhdHVzID0gbWF4bS5NTURCX2dldF9lbnRyeV9kYXRhX2xpc3QocmVzdWx0LmVudHJ5LGVudHJ5X2RhdGFfbGlzdCkKCiAgaWYgc3RhdHVzIH49IE1NREJfU1VDQ0VTUyB0aGVuCiAgICByZXR1cm4gbmlsLCdnZXQgZW50cnkgZGF0YSBmYWlsZWQ6ICcgLi4gbW1kYl9zdHJlcnJvcihzdGF0dXMpCiAgZW5kICAKICAKICBsb2NhbCBoZWFkID0gZW50cnlfZGF0YV9saXN0WzBdIC0tIFNhdmUgc28gdGhpcyBjYW4gYmUgcGFzc2VkIHRvIGZyZWUgZm4uCiAgbG9jYWwgXyxzdGF0dXMscmVzdWx0ID0gX2R1bXBfZW50cnlfZGF0YV9saXN0KGVudHJ5X2RhdGFfbGlzdCkKICBtYXhtLk1NREJfZnJlZV9lbnRyeV9kYXRhX2xpc3QoaGVhZCkKICAKICBpZiBzdGF0dXMgfj0gTU1EQl9TVUNDRVNTIHRoZW4KICAgIHJldHVybiBuaWwsJ2R1bXAgZW50cnkgZGF0YSBmYWlsZWQ6ICcgLi4gbW1kYl9zdHJlcnJvcihzdGF0dXMpCiAgZW5kCiAgCiAgCiAgcmV0dXJuIHJlc3VsdAplbmQKCi0tIGNvcHkgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vbGlsaWVuMTAxMC9sdWEtcmVzdHktbWF4bWluZGRiL2Jsb2IvbWFzdGVyL3Jlc3R5L21heG1pbmRkYi5sdWEjTDIwOAotLSBodHRwczovL3d3dy5tYXhtaW5kLmNvbS9lbi9nZW9pcDItZGF0YWJhc2VzICB5b3Ugc2hvdWxkIGRvd25sb2FkICB0aGUgbW1kYiBmaWxlIGZyb20gbWF4bWluZAogCnJldHVybiBfTTsK",
36
+ "mgmt_api.lua": "LS0gbWdtdF9hcGkubHVhCi0tIFJFU1QgYW5hbHl0aWNzIGVuZHBvaW50cyBiYWNrZWQgYnkgbmd4LnNoYXJlZC5kaWN0LgotLSBJbnRlcm5hbCBtYW5hZ2VtZW50IHBvcnQgb25seSAoMTI3LjAuMC4xOjkxNDUpLgoKbG9jYWwgY2pzb24gPSByZXF1aXJlICJjanNvbi5zYWZlIgoKbG9jYWwgYW5hbHl0aWNzICAgID0gbmd4LnNoYXJlZC5hbmFseXRpY3MKbG9jYWwgcmVxdWVzdF9kYXRhID0gbmd4LnNoYXJlZC5yZXF1ZXN0X2RhdGEKbG9jYWwgdXJpICAgICAgICAgID0gbmd4LnZhci51cmkKCmxvY2FsIGZ1bmN0aW9uIGpzb24oZGF0YSwgY29kZSkKICAgIG5neC5zdGF0dXMgPSBjb2RlIG9yIDIwMAogICAgbmd4LmhlYWRlclsiQ29udGVudC1UeXBlIl0gPSAiYXBwbGljYXRpb24vanNvbiIKICAgIG5neC5zYXkoY2pzb24uZW5jb2RlKGRhdGEpKQogICAgcmV0dXJuIG5neC5leGl0KG5neC5zdGF0dXMpCmVuZAoKbG9jYWwgZnVuY3Rpb24gYmFkKG1zZykKICAgIHJldHVybiBqc29uKHsgZXJyb3IgPSBtc2cgfSwgNDAwKQplbmQKCi0tIOKUgOKUgCBHRVQgL2hlYWx0aCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKLS0gQmFyZSAib2siLCBOT1QgSlNPTi4gcHJvYmVNZ210KCkgaW4gYXBwcy9hcGkvc3JjL2xpYi9wcm9qZWN0LWFuYWx5dGljcy50cwotLSBhc3NlcnRzIGBib2R5LnRyaW0oKSA9PT0gIm9rImAsIHNvIGFueXRoaW5nIHJpY2hlciBoZXJlIHNpbGVudGx5IHJlcG9ydHMgZXZlcnkKLS0gZWRnZSBhcyB1bnJlYWNoYWJsZSBhbmQgc3RvcHMgdGhlIGFuYWx5dGljcyBzY3JhcGUuIFJpY2hlciBkaWFnbm9zdGljcyBnbyBvbgotLSAvc3RhdHVzIGJlbG93LgoKaWYgdXJpID09ICIvaGVhbHRoIiB0aGVuCiAgICBuZ3guc2F5KCJvayIpCiAgICByZXR1cm4gbmd4LmV4aXQoMjAwKQplbmQKCi0tIOKUgOKUgCBHRVQgL3N0YXR1cyAtIGRpYWdub3NhYmxlIGVkZ2UgaGVhbHRoIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAotLSBXaHkgdGhpcyBleGlzdHM6IGdlbyBmYWlsaW5nIGlzIElOVklTSUJMRSBvdGhlcndpc2UuIGdlb19jb3VudHJ5Lmx1YSBwY2FsbHMgaXRzCi0tIEZGSSBiaW5kaW5nIGFuZCByZXR1cm5zIG5pbCBvbiBmYWlsdXJlLCBzbyBhIG1pc3NpbmcgbGlibWF4bWluZGRiLnNvIG9yIGEKLS0gbWlzc2luZyBkYXRhYmFzZSBwcmVzZW50cyBleGFjdGx5IGxpa2UgIm5vYm9keSB2aXNpdGVkIGZyb20gYSBrbm93biBjb3VudHJ5IiDigJQKLS0gYW4gZW1wdHkgbWFwIHdpdGggbm8gZXJyb3IgYW55d2hlcmUuIFRoaXMgcmVwb3J0cyB3aGljaCBpdCBpcy4KLS0KLS0gQWxzbyByZXBvcnRzIHNoYXJlZC1kaWN0IGhlYWRyb29tOiB0aGVzZSB6b25lcyBMUlUtRVZJQ1Qgd2hlbiBmdWxsIHJhdGhlciB0aGFuCi0tIGVycm9yaW5nLCBzbyBhIGZ1bGwgYHZpc2l0b3JzYCB6b25lIHNpbGVudGx5IFVOREVSQ09VTlRTLiBDYWxsZXJzIHN1cmZhY2UgdGhhdAotLSBhcyAiYXBwcm94aW1hdGUiIGluc3RlYWQgb2YgcHJlc2VudGluZyBhbiBldmljdGlvbiBhcnRpZmFjdCBhcyBhIG1lYXN1cmVtZW50LgoKaWYgdXJpID09ICIvc3RhdHVzIiB0aGVuCiAgICBsb2NhbCBnZW9fYXZhaWxhYmxlLCBnZW9fcmVhc29uLCBnZW9fZGIgPSBmYWxzZSwgImdlb19jb3VudHJ5IG1vZHVsZSBub3QgbG9hZGFibGUiLCBuaWwKICAgIGxvY2FsIGdlb19vaywgZ2VvID0gcGNhbGwocmVxdWlyZSwgImtyYWZ0Lmdlb19jb3VudHJ5IikKICAgIGlmIGdlb19vayBhbmQgZ2VvIGFuZCBnZW8uc3RhdHVzIHRoZW4KICAgICAgICBnZW9fYXZhaWxhYmxlLCBnZW9fcmVhc29uLCBnZW9fZGIgPSBnZW8uc3RhdHVzKCkKICAgIGVuZAoKICAgIGxvY2FsIGRpY3RzID0ge30KICAgIGZvciBfLCBuYW1lIGluIGlwYWlycyh7ICJhbmFseXRpY3MiLCAicmVxdWVzdF9kYXRhIiwgInJ1bGVzIiwgInJsX2NvdW50ZXJzIiwgInZpc2l0b3JzIiB9KSBkbwogICAgICAgIGxvY2FsIGQgPSBuZ3guc2hhcmVkW25hbWVdCiAgICAgICAgaWYgZCB0aGVuCiAgICAgICAgICAgIGRpY3RzW25hbWVdID0gewogICAgICAgICAgICAgICAgY2FwYWNpdHkgICA9IGQuY2FwYWNpdHkgYW5kIGQ6Y2FwYWNpdHkoKSBvciBuaWwsCiAgICAgICAgICAgICAgICBmcmVlX3NwYWNlID0gZC5mcmVlX3NwYWNlIGFuZCBkOmZyZWVfc3BhY2UoKSBvciBuaWwsCiAgICAgICAgICAgIH0KICAgICAgICBlbmQKICAgIGVuZAoKICAgIHJldHVybiBqc29uKHsKICAgICAgICBvayAgPSB0cnVlLAogICAgICAgIGdlbyA9IHsgYXZhaWxhYmxlID0gZ2VvX2F2YWlsYWJsZSwgcmVhc29uID0gZ2VvX3JlYXNvbiwgZGIgPSBnZW9fZGIgfSwKICAgICAgICBkaWN0cyA9IGRpY3RzLAogICAgfSkKZW5kCgotLSDilIDilIAgL3J1bGVzIC0gcGVyLXJvdXRlIHJ1bGVzIGNhY2hlICh3cml0dGVuIGJ5IHRoZSBBUEksIHJlYWQgYnkgcnVsZXNfZ3VhcmQpIOKUgOKUgAotLSBQT1NUIC9ydWxlcyAgYm9keTogeyAiaG9zdCI6ICIuLi4iLCAicnVsZXMiOiBbIHsgInBhdGhQcmVmaXgiOiAiLyIsICJzcGVjIjogey4uLn0gfSBdIH0KLS0gICDihpIgcmVwbGFjZXMgdGhlIHJ1bGVzZXQgZm9yIHRoYXQgaG9zdCBpbiB0aGUgYHJ1bGVzYCBzaGFyZWQgZGljdCAocmVsb2FkLWZyZWUpLgotLSAgIEFuIGVtcHR5L2Fic2VudCBgcnVsZXNgIGFycmF5IGNsZWFycyB0aGUgaG9zdC4KLS0gR0VUICAvcnVsZXM/aG9zdD0uLi4gICDihpIgdGhlIHN0b3JlZCBydWxlc2V0IChkZWJ1ZykuCi0tIERFTEVURSAvcnVsZXM/aG9zdD0uLi4g4oaSIGNsZWFyIHRoZSBob3N0J3MgcnVsZXNldC4KLS0gSGFuZGxlZCBCRUZPUkUgdGhlIGFuYWx5dGljcyBndWFyZDogcnVsZXMgdXNlIHRoZWlyIG93biBkaWN0LgotLSDilIDilIAgL2FuYWx5dGljcy9jb25maWcgLSBwZXItaG9zdCBjb2xsZWN0aW9uIHN3aXRjaGVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAotLQotLSBQT1NUIGJvZHk6IHsgImhvc3RzIjogWyB7ICJob3N0IjogIi4uLiIsICJwYXRocyI6IHRydWV8ZmFsc2UgfSwgLi4uIF0gfQotLSBHRVQgID9ob3N0PS4uLiAg4oaSIHsgaG9zdCwgcGF0aHMgfQotLQotLSBBIExJU1QsIG5vdCBhIHNpbmdsZSBob3N0OiBhIHNoYXJlZCBkaWN0IGlzIFJBTSwgc28gYSBmdWxsIG5naW54IHJlc3RhcnQgKGEgcmVib290LCBhCi0tIGBkb2NrZXIgcmVzdGFydGAsIGEgcGFja2FnZSB1cGdyYWRlKSBlbXB0aWVzIGl0IGFuZCBldmVyeSBob3N0IG9uIHRoZSBib3ggaGFzIHRvIGJlCi0tIHJlLXNldCBhdCBvbmNlLiBgb3BlbnJlc3R5IC1zIHJlbG9hZGAgcHJlc2VydmVzIHRoZSB6b25lIOKAlCB2ZXJpZmllZCDigJQgc28gb25seSBhIHJlYWwKLS0gcmVzdGFydCBsb3NlcyBpdCwgd2hpY2ggaXMgd2h5IHRoZSByZWNvbmNpbGUgYmVsb3cgZXhpc3RzIGFuZCB3aHkgaXQgbmVlZHMgdG8gY29zdCBvbmUKLS0gcm91bmQgdHJpcCBwZXIgc2VydmVyIHJhdGhlciB0aGFuIG9uZSBwZXIgZG9tYWluLgotLQotLSBMaXZlcyBpbiB0aGUgYHJ1bGVzYCB6b25lIHJhdGhlciB0aGFuIGBhbmFseXRpY3NgIGZvciB0aGUgcmVhc29uIHNpdGVfbG9nZ2VyIHN0YXRlczoKLS0gdGhlIGFuYWx5dGljcyB6b25lIGlzIGEgMjU2IE1CIGNodXJuIG9mIGNvdW50ZXJzIHVuZGVyIExSVSBwcmVzc3VyZSwgYW5kIGFuIGV2aWN0ZWQKLS0gY29uZmlnIGZsYWcgd291bGQgc2lsZW50bHkgY2hhbmdlIHdoYXQgaXMgY29sbGVjdGVkLiBUaGlzIHpvbmUgaG9sZHMgYSBmZXcgc21hbGwgdmFsdWVzLgotLQotLSBEZWxpYmVyYXRlbHkgaXRzIG93biBlbmRwb2ludCByYXRoZXIgdGhhbiBhIGZpZWxkIG9uIC9ydWxlczogdGhlIEFQSSBvbmx5IHB1c2hlcyAvcnVsZXMKLS0gZm9yIGhvc3RzIHRoYXQgSEFWRSBydWxlcywgc28gYSBwcm9qZWN0IHdpdGggbm9uZSB3b3VsZCBuZXZlciByZWNlaXZlIHRoaXMgZmxhZy4KLS0KLS0gTm8gVFRMIOKAlCBhIHNoYXJlZCBkaWN0IGlzIFJBTSBhbmQgaXMgbG9zdCBvbiByZXN0YXJ0IGVpdGhlciB3YXksIHNvIHRoZSBBUEkgcmUtcHVzaGVzIG9uCi0tIGV2ZXJ5IHJvdXRlIGFwcGx5IGFuZCB0aGUgZGF0YWJhc2Ugc3RheXMgdGhlIHNvdXJjZSBvZiB0cnV0aC4KaWYgdXJpID09ICIvYW5hbHl0aWNzL2NvbmZpZyIgdGhlbgogICAgbG9jYWwgcnVsZXMgPSBuZ3guc2hhcmVkLnJ1bGVzCiAgICBpZiBub3QgcnVsZXMgdGhlbiByZXR1cm4ganNvbih7IGVycm9yID0gInJ1bGVzIGRpY3QgdW5hdmFpbGFibGUiIH0sIDUwMykgZW5kCiAgICBsb2NhbCBtZXRob2QgPSBuZ3gucmVxLmdldF9tZXRob2QoKQoKICAgIGlmIG1ldGhvZCA9PSAiR0VUIiB0aGVuCiAgICAgICAgbG9jYWwgaG9zdCA9IG5neC52YXIuYXJnX2hvc3QKICAgICAgICBpZiBub3QgaG9zdCBvciBob3N0ID09ICIiIHRoZW4gcmV0dXJuIGJhZCgibWlzc2luZyA/aG9zdD0iKSBlbmQKICAgICAgICBob3N0ID0gaG9zdDpsb3dlcigpCiAgICAgICAgcmV0dXJuIGpzb24oeyBob3N0ID0gaG9zdCwgcGF0aHMgPSBydWxlczpnZXQoImNmZzoiIC4uIGhvc3QgLi4gIjpwYXRocyIpID09IDEgfSkKICAgIGVuZAoKICAgIGlmIG1ldGhvZCA9PSAiUE9TVCIgdGhlbgogICAgICAgIG5neC5yZXEucmVhZF9ib2R5KCkKICAgICAgICBsb2NhbCBib2R5ID0gbmd4LnJlcS5nZXRfYm9keV9kYXRhKCkKICAgICAgICBpZiBub3QgYm9keSB0aGVuIHJldHVybiBiYWQoImVtcHR5IGJvZHkiKSBlbmQKICAgICAgICBsb2NhbCBwYXlsb2FkID0gY2pzb24uZGVjb2RlKGJvZHkpCiAgICAgICAgaWYgdHlwZShwYXlsb2FkKSB+PSAidGFibGUiIG9yIHR5cGUocGF5bG9hZC5ob3N0cykgfj0gInRhYmxlIiB0aGVuCiAgICAgICAgICAgIHJldHVybiBiYWQoImV4cGVjdGVkIHsgaG9zdHM6IFsgeyBob3N0LCBwYXRocyB9IF0gfSIpCiAgICAgICAgZW5kCiAgICAgICAgbG9jYWwgYXBwbGllZCA9IDAKICAgICAgICBmb3IgXywgZW50cnkgaW4gaXBhaXJzKHBheWxvYWQuaG9zdHMpIGRvCiAgICAgICAgICAgIGlmIHR5cGUoZW50cnkpID09ICJ0YWJsZSIgYW5kIGVudHJ5Lmhvc3QgdGhlbgogICAgICAgICAgICAgICAgbG9jYWwga2V5ID0gImNmZzoiIC4uIHRvc3RyaW5nKGVudHJ5Lmhvc3QpOmxvd2VyKCkgLi4gIjpwYXRocyIKICAgICAgICAgICAgICAgIGlmIGVudHJ5LnBhdGhzID09IHRydWUgdGhlbgogICAgICAgICAgICAgICAgICAgIHJ1bGVzOnNldChrZXksIDEpCiAgICAgICAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgICAgICAgLS0gRGVsZXRlZCByYXRoZXIgdGhhbiBzZXQgdG8gMCwgc28gImFic2VudCIgaXMgdGhlIG9ubHkgb2ZmIHN0YXRlIHRoZXJlCiAgICAgICAgICAgICAgICAgICAgLS0gaXMuIFR3byByZXByZXNlbnRhdGlvbnMgb2Ygb2ZmIGlzIGhvdyBhIHJlYWRlciBlbmRzIHVwIHRyZWF0aW5nIG9uZSBvZgogICAgICAgICAgICAgICAgICAgIC0tIHRoZW0gYXMgb24g4oCUIGFuZCBhYnNlbnQgaXMgYWxzbyB3aGF0IGEgcmVzdGFydGVkIGJveCBzdGFydHMgZnJvbSwgc28KICAgICAgICAgICAgICAgICAgICAtLSBvZmYgaGFzIHRvIG1lYW4gZXhhY3RseSB0aGUgc2FtZSB0aGluZyBpbiBib3RoIGNhc2VzLgogICAgICAgICAgICAgICAgICAgIHJ1bGVzOmRlbGV0ZShrZXkpCiAgICAgICAgICAgICAgICBlbmQKICAgICAgICAgICAgICAgIGFwcGxpZWQgPSBhcHBsaWVkICsgMQogICAgICAgICAgICBlbmQKICAgICAgICBlbmQKICAgICAgICByZXR1cm4ganNvbih7IG9rID0gdHJ1ZSwgYXBwbGllZCA9IGFwcGxpZWQgfSkKICAgIGVuZAoKICAgIHJldHVybiBqc29uKHsgZXJyb3IgPSAibWV0aG9kIG5vdCBhbGxvd2VkIiB9LCA0MDUpCmVuZAoKaWYgdXJpID09ICIvcnVsZXMiIHRoZW4KICAgIGxvY2FsIHJ1bGVzID0gbmd4LnNoYXJlZC5ydWxlcwogICAgaWYgbm90IHJ1bGVzIHRoZW4gcmV0dXJuIGpzb24oeyBlcnJvciA9ICJydWxlcyBkaWN0IHVuYXZhaWxhYmxlIiB9LCA1MDMpIGVuZAogICAgbG9jYWwgbWV0aG9kID0gbmd4LnJlcS5nZXRfbWV0aG9kKCkKCiAgICBpZiBtZXRob2QgPT0gIkdFVCIgdGhlbgogICAgICAgIGxvY2FsIGhvc3QgPSBuZ3gudmFyLmFyZ19ob3N0CiAgICAgICAgaWYgbm90IGhvc3Qgb3IgaG9zdCA9PSAiIiB0aGVuIHJldHVybiBiYWQoIm1pc3NpbmcgP2hvc3Q9IikgZW5kCiAgICAgICAgaG9zdCA9IGhvc3Q6bG93ZXIoKQogICAgICAgIGxvY2FsIHJhdyA9IHJ1bGVzOmdldChob3N0KQogICAgICAgIHJldHVybiBqc29uKHsgaG9zdCA9IGhvc3QsIHJ1bGVzID0gcmF3IGFuZCBjanNvbi5kZWNvZGUocmF3KSBvciB7fSB9KQogICAgZW5kCgogICAgaWYgbWV0aG9kID09ICJERUxFVEUiIHRoZW4KICAgICAgICBsb2NhbCBob3N0ID0gbmd4LnZhci5hcmdfaG9zdAogICAgICAgIGlmIG5vdCBob3N0IG9yIGhvc3QgPT0gIiIgdGhlbiByZXR1cm4gYmFkKCJtaXNzaW5nID9ob3N0PSIpIGVuZAogICAgICAgIHJ1bGVzOmRlbGV0ZShob3N0Omxvd2VyKCkpCiAgICAgICAgcmV0dXJuIGpzb24oeyBvayA9IHRydWUgfSkKICAgIGVuZAoKICAgIGlmIG1ldGhvZCA9PSAiUE9TVCIgdGhlbgogICAgICAgIG5neC5yZXEucmVhZF9ib2R5KCkKICAgICAgICBsb2NhbCBib2R5ID0gbmd4LnJlcS5nZXRfYm9keV9kYXRhKCkKICAgICAgICBpZiBub3QgYm9keSB0aGVuIHJldHVybiBiYWQoImVtcHR5IGJvZHkiKSBlbmQKICAgICAgICBsb2NhbCBwYXlsb2FkID0gY2pzb24uZGVjb2RlKGJvZHkpCiAgICAgICAgaWYgdHlwZShwYXlsb2FkKSB+PSAidGFibGUiIG9yIG5vdCBwYXlsb2FkLmhvc3QgdGhlbgogICAgICAgICAgICByZXR1cm4gYmFkKCJleHBlY3RlZCB7IGhvc3QsIHJ1bGVzOiBbLi4uXSB9IikKICAgICAgICBlbmQKICAgICAgICBsb2NhbCBob3N0ID0gdG9zdHJpbmcocGF5bG9hZC5ob3N0KTpsb3dlcigpCiAgICAgICAgbG9jYWwgbGlzdCA9IHBheWxvYWQucnVsZXMKICAgICAgICBpZiB0eXBlKGxpc3QpIH49ICJ0YWJsZSIgb3IgI2xpc3QgPT0gMCB0aGVuCiAgICAgICAgICAgIHJ1bGVzOmRlbGV0ZShob3N0KSAgICAgICAgICAgICAgICAgLS0gZW1wdHkgc2V0ID0gY2xlYXIgdGhlIGhvc3QKICAgICAgICAgICAgcmV0dXJuIGpzb24oeyBvayA9IHRydWUsIGhvc3QgPSBob3N0LCBjb3VudCA9IDAgfSkKICAgICAgICBlbmQKICAgICAgICBsb2NhbCBvaywgZXJyID0gcnVsZXM6c2V0KGhvc3QsIGNqc29uLmVuY29kZShsaXN0KSkKICAgICAgICBpZiBub3Qgb2sgdGhlbiByZXR1cm4ganNvbih7IGVycm9yID0gInNldCBmYWlsZWQ6ICIgLi4gKGVyciBvciAiPyIpIH0sIDUwMCkgZW5kCiAgICAgICAgcmV0dXJuIGpzb24oeyBvayA9IHRydWUsIGhvc3QgPSBob3N0LCBjb3VudCA9ICNsaXN0IH0pCiAgICBlbmQKCiAgICByZXR1cm4ganNvbih7IGVycm9yID0gIm1ldGhvZCBub3QgYWxsb3dlZCIgfSwgNDA1KQplbmQKCmlmIG5vdCBhbmFseXRpY3MgdGhlbgogICAgcmV0dXJuIGpzb24oeyBlcnJvciA9ICJhbmFseXRpY3MgZGljdCB1bmF2YWlsYWJsZSIgfSwgNTAzKQplbmQKCi0tIOKUgOKUgCBQZXItbWludXRlIGNvdW50cnkgaW5kZXgg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACi0tCi0tIHNpdGVfbG9nZ2VyIHdyaXRlcyBvbmUga2V5IHBlciAoZG9tYWluLCBtaW51dGUsIGNvdW50cnkpOiBgYzp7ZG9tYWlufTp7bWlufTp7Q0N9YC4KLS0gUmVhZGluZyB0aGVtIGJhY2sgbmVlZHMga2V5IERJU0NPVkVSWSwgYW5kIGBnZXRfa2V5c2AgaXMgdGhlIG9ubHkgbWVjaGFuaXNtLgotLQotLSBUaGlzIHVzZWQgdG8gc2l0IElOU0lERSB0aGUgcGVyLW1pbnV0ZSBsb29wLCBzbyBhIDI0aCB3aW5kb3cgcmFuIHVwIHRvIDE0NDAKLS0gYGdldF9rZXlzKDEwMDAwKWAgY2FsbHMg4oCUIGVhY2ggYSBmdWxsIHNjYW4gb2YgYSAyNTYgTUIgem9uZSwgZWFjaCBob2xkaW5nIHRoZQotLSBkaWN0IGxvY2sgYWdhaW5zdCBldmVyeSB3b3JrZXIuIE9uZSBzY2FuIHBlciByZXF1ZXN0IGluc3RlYWQsIGJ1Y2tldGVkIGJ5Ci0tIG1pbnV0ZSBpbiBhIHNpbmdsZSBwYXNzOyB0aGUgbG9vcCB0aGVuIGRvZXMgcGxhaW4gdGFibGUgbG9va3Vwcy4KLS0KLS0gYGdldF9rZXlzKDApYCAoYWxsIGtleXMpIHJhdGhlciB0aGFuIDEwMDAwOiB0aGUgY2FwIHNpbGVudGx5IFRSVU5DQVRFRCwgc28gYQotLSBidXN5IGJveCBqdXN0IGxvc3QgY291bnRyaWVzIHdpdGggbm8gZXJyb3IuIFVuYm91bmRlZCBpcyBzYWZlIHByZWNpc2VseSBiZWNhdXNlCi0tIHRoaXMgaXMgbm93IGNhbGxlZCBvbmNlIOKAlCBzZWUgdGhlIGNvbW1lbnQgb24gdGhlIGNhbGwuCi0tLSBSZWFkIGFuIGVudW1lcmFibGUgc2V0IHdyaXR0ZW4gYnkgc2l0ZV9sb2dnZXIncyBpbmRleF9hZGQuCi0tCi0tIFJlcGxhY2VzIGBnZXRfa2V5c2AsIHdoaWNoIHdhbGtlZCBFVkVSWSBrZXkgaW4gdGhlIDI1NiBNQiB6b25lIGhvbGRpbmcgaXRzIGxvY2sg4oCUIGNvc3QKLS0gcHJvcG9ydGlvbmFsIHRvIHpvbmUgcG9wdWxhdGlvbiByYXRoZXIgdGhhbiB0byB0aGUgYW5zd2VyLCBvbiBhIHBhdGggY2FsbGVkIGZvdXIKLS0gZGlmZmVyZW50IHdheXMuIEhlcmUgdGhlIGNvdW50ZXIgc2F5cyBob3cgbWFueSBtZW1iZXJzIGV4aXN0IGFuZCB0aGUgc2xvdHMgbmFtZSB0aGVtLCBzbwotLSBhIHJlYWQgY29zdHMgZXhhY3RseSBhcyBtdWNoIGFzIHRoZSBkYXRhIGl0IHJldHVybnMuCi0tCi0tIE92ZXItcmVhZHMgc2xpZ2h0bHkgYnkgZGVzaWduOiBhIHNsb3QgY2FuIGJlIHdyaXR0ZW4gdHdpY2UgaWYgdHdvIHdvcmtlcnMgcmFjZSBvbiBhCi0tIG1lbWJlcidzIGZpcnN0IHNpZ2h0aW5nLCBhbmQgc2xvdHMgb3V0bGl2ZSBub3RoaW5nIChzYW1lIFRUTCBhcyB0aGVpciBjb3VudGVycykuIEJvdGgKLS0gY29sbGFwc2UgaGFybWxlc3NseSBiZWNhdXNlIHRoZSBjYWxsZXIga2V5cyByZXN1bHRzIGJ5IG1lbWJlci4KbG9jYWwgZnVuY3Rpb24gcmVhZF9pbmRleChjb3VudGVyX2tleSwgc2xvdF9wcmVmaXgpCiAgICBsb2NhbCBuID0gdG9udW1iZXIoYW5hbHl0aWNzOmdldChjb3VudGVyX2tleSkpIG9yIDAKICAgIGlmIG4gPD0gMCB0aGVuIHJldHVybiB7fSBlbmQKICAgIGxvY2FsIG91dCwgc2VlbiA9IHt9LCB7fQogICAgZm9yIGkgPSAxLCBuIGRvCiAgICAgICAgbG9jYWwgbSA9IGFuYWx5dGljczpnZXQoc2xvdF9wcmVmaXggLi4gaSkKICAgICAgICBpZiBtIGFuZCBub3Qgc2VlblttXSB0aGVuCiAgICAgICAgICAgIHNlZW5bbV0gPSB0cnVlCiAgICAgICAgICAgIG91dFsjb3V0ICsgMV0gPSBtCiAgICAgICAgZW5kCiAgICBlbmQKICAgIHJldHVybiBvdXQKZW5kCgotLS0gRHJhaW4gYSBjb3VudGVyIFdJVEhPVVQgbG9zaW5nIGEgY29uY3VycmVudCBpbmNyZW1lbnQuCi0tCi0tIFdhcyBgZ2V0YCB0aGVuIGBkZWxldGVgOiBhIHJlcXVlc3QgbGFuZGluZyBiZXR3ZWVuIHRoZSB0d28gaGFkIGl0cyBjb3VudCBkZWxldGVkIGFsb25nCi0tIHdpdGggdGhlIHZhbHVlIHRoYXQgaGFkIGp1c3QgYmVlbiByZWFkLiBTdWJ0cmFjdGluZyBleGFjdGx5IHdoYXQgd2FzIHJlYWQgbGVhdmVzIGFueQotLSBjb25jdXJyZW50IGluY3JlbWVudCBiZWhpbmQgYXMgYSByZXNpZHVhbCB0aGUgbmV4dCBzY3JhcGUgY29sbGVjdHMuCmxvY2FsIGZ1bmN0aW9uIGRyYWluKGtleSkKICAgIGxvY2FsIHYgPSB0b251bWJlcihhbmFseXRpY3M6Z2V0KGtleSkpIG9yIDAKICAgIGlmIHYgfj0gMCB0aGVuIGFuYWx5dGljczppbmNyKGtleSwgLXYpIGVuZAogICAgcmV0dXJuIHYKZW5kCgotLS0gT25lIGRheSdzIHJvbGx1cCBmb3Igb25lIGRvbWFpbiwgcmVhZCB0aHJvdWdoIGl0cyBpbmRleGVzLgotLQotLSBSZXR1cm5zIHRoZSBzYW1lIGBzdWZmaXgg4oaSIHZhbHVlYCBzaGFwZSB0aGUgb2xkIHdob2xlLXpvbmUgY2xhc3NpZmllciBwcm9kdWNlZCwgc28gYm90aAotLSBjYWxsZXJzIHN0YXllZCB1bmNoYW5nZWQ6IGJhcmUgY291bnRyeSBjb2RlcywgYHM6e2NvZGV9YCwgYHA6e3BhdGh9YCwgYHZgLCBgcG5gLgpsb2NhbCBmdW5jdGlvbiByZWFkX3JvbGx1cChkb21haW4sIGRheSkKICAgIGxvY2FsIGdwZnggPSAiZzoiIC4uIGRvbWFpbiAuLiAiOiIgLi4gZGF5IC4uICI6IgogICAgbG9jYWwgb3V0ID0ge30KCiAgICBmb3IgXywgY2MgaW4gaXBhaXJzKHJlYWRfaW5kZXgoZ3BmeCAuLiAiY24iLCBncGZ4IC4uICJjaToiKSkgZG8KICAgICAgICBvdXRbY2NdID0gdG9udW1iZXIoYW5hbHl0aWNzOmdldChncGZ4IC4uIGNjKSkgb3IgMAogICAgZW5kCiAgICBmb3IgXywgY29kZSBpbiBpcGFpcnMocmVhZF9pbmRleChncGZ4IC4uICJzbiIsIGdwZnggLi4gInNpOiIpKSBkbwogICAgICAgIG91dFsiczoiIC4uIGNvZGVdID0gdG9udW1iZXIoYW5hbHl0aWNzOmdldChncGZ4IC4uICJzOiIgLi4gY29kZSkpIG9yIDAKICAgIGVuZAogICAgLS0gYHBuYCBkb3VibGVzIGFzIHRoZSBwYXRoIGluZGV4J3MgY291bnRlciwgc28gcGF0aHMgbmVlZCBubyBzZXBhcmF0ZSBvbmUuIFdoZW4gcGF0aAogICAgLS0gY29sbGVjdGlvbiBpcyBzd2l0Y2hlZCBvZmYgZm9yIHRoaXMgaG9zdCB0aGVyZSBpcyBubyBjb3VudGVyIGFuZCB0aGlzIHJlYWRzIG5vdGhpbmcuCiAgICBmb3IgXywgcGF0aCBpbiBpcGFpcnMocmVhZF9pbmRleChncGZ4IC4uICJwbiIsIGdwZnggLi4gInBpOiIpKSBkbwogICAgICAgIG91dFsicDoiIC4uIHBhdGhdID0gdG9udW1iZXIoYW5hbHl0aWNzOmdldChncGZ4IC4uICJwOiIgLi4gcGF0aCkpIG9yIDAKICAgIGVuZAogICAgLS0gVGhlIG92ZXItY2FwIGJ1Y2tldCBoYXMgYSBmaXhlZCBuYW1lLCBzbyBpdCBpcyBub3QgaW4gdGhlIGluZGV4LgogICAgbG9jYWwgb3RoZXIgPSB0b251bWJlcihhbmFseXRpY3M6Z2V0KGdwZnggLi4gInA6b3RoZXIiKSkKICAgIGlmIG90aGVyIHRoZW4gb3V0WyJwOm90aGVyIl0gPSBvdGhlciBlbmQKCiAgICBsb2NhbCB2ID0gdG9udW1iZXIoYW5hbHl0aWNzOmdldChncGZ4IC4uICJ2IikpCiAgICBpZiB2IHRoZW4gb3V0WyJ2Il0gPSB2IGVuZAogICAgcmV0dXJuIG91dAplbmQKCmxvY2FsIGZ1bmN0aW9uIHNjYW5fY291bnRyeV9pbmRleChkb21haW4sIGZyb21fbSwgdG9fbSkKICAgIC0tIFdhbGtzIHRoZSByZXF1ZXN0ZWQgTUlOVVRFUyBhbmQgcmVhZHMgZWFjaCBvbmUncyBvd24gaW5kZXguIEJvdW5kZWQgYnkgdGhlIHdpbmRvdwogICAgLS0gKGNhcHBlZCBhdCAxNDQwIGJ5IHRoZSBjYWxsZXIpLCBub3QgYnkgaG93IG11Y2ggaXMgaW4gdGhlIHpvbmUuCiAgICBsb2NhbCBieV9taW51dGUgPSB7fQogICAgZm9yIG0gPSBmcm9tX20sIHRvX20gZG8KICAgICAgICBsb2NhbCBtcGZ4ID0gImM6IiAuLiBkb21haW4gLi4gIjoiIC4uIG0gLi4gIjoiCiAgICAgICAgbG9jYWwgY2NzID0gcmVhZF9pbmRleChtcGZ4IC4uICJuIiwgbXBmeCAuLiAiaToiKQogICAgICAgIGlmICNjY3MgPiAwIHRoZW4KICAgICAgICAgICAgbG9jYWwgc2xvdCA9IHt9CiAgICAgICAgICAgIGZvciBpID0gMSwgI2NjcyBkbwogICAgICAgICAgICAgICAgLS0gRnVsbCBrZXksIGJlY2F1c2UgdGhlIGZsdXNoIGRyYWlucyBieSBrZXkuCiAgICAgICAgICAgICAgICBzbG90W2Njc1tpXV0gPSBtcGZ4IC4uIGNjc1tpXQogICAgICAgICAgICBlbmQKICAgICAgICAgICAgYnlfbWludXRlW21dID0gc2xvdAogICAgICAgIGVuZAogICAgZW5kCiAgICByZXR1cm4gYnlfbWludXRlCmVuZAoKLS0tIFNwbGl0IGEgbmFtZXNwYWNlZCBhbmFseXRpY3Mga2V5IGludG8ga2luZCAvIGRvbWFpbiAvIG1pZCAvIHJlc3QuCi0tCi0tIExheW91dHM6IGBjOntkb21haW59OnttaW51dGV9OntDQ31gIGFuZCBgZzp7ZG9tYWlufTp7ZGF5fTp7c3VmZml4fWAuCi0tIFBvc2l0aW9uYWwsIE5PVCBhIGZ1bGwgc3BsaXQgb24gIjoiLCBiZWNhdXNlIGBzdWZmaXhgIGxlZ2l0aW1hdGVseSBjb250YWlucwotLSBjb2xvbnMg4oCUIGEgbm9ybWFsaXplZCBwYXRoIGtleSBsb29rcyBsaWtlIGBnOnguY29tOjIwMjYwODAzOnA6L3VzZXJzLzppZGAuCi0tIEhvc3RuYW1lcyBjYW5ub3QgY29udGFpbiAiOiIsIHNvIHRoZSBmaXJzdCB0aHJlZSBzZXBhcmF0b3JzIGFyZSB1bmFtYmlndW91cy4KbG9jYWwgZnVuY3Rpb24gc3BsaXRfa2V5KGspCiAgICBsb2NhbCBwMSA9IGs6ZmluZCgiOiIsIDEsIHRydWUpCiAgICBpZiBub3QgcDEgdGhlbiByZXR1cm4gbmlsIGVuZAogICAgbG9jYWwgcDIgPSBrOmZpbmQoIjoiLCBwMSArIDEsIHRydWUpCiAgICBpZiBub3QgcDIgdGhlbiByZXR1cm4gbmlsIGVuZAogICAgbG9jYWwgcDMgPSBrOmZpbmQoIjoiLCBwMiArIDEsIHRydWUpCiAgICBpZiBub3QgcDMgdGhlbgogICAgICAgIHJldHVybiBrOnN1YigxLCBwMSAtIDEpLCBrOnN1YihwMSArIDEsIHAyIC0gMSksIGs6c3ViKHAyICsgMSksIG5pbAogICAgZW5kCiAgICByZXR1cm4gazpzdWIoMSwgcDEgLSAxKSwgazpzdWIocDEgKyAxLCBwMiAtIDEpLCBrOnN1YihwMiArIDEsIHAzIC0gMSksIGs6c3ViKHAzICsgMSkKZW5kCgotLS0gUmVhZCBvbmUgbWludXRlJ3MgY291bnRyeSBjb3VudHMgb3V0IG9mIGEgc2Nhbm5lZCBpbmRleC4KLS0gQHBhcmFtIHNsb3QgdGFibGV8bmlsICBDQyDihpIgZnVsbCBkaWN0IGtleSwgZnJvbSBzY2FuX2NvdW50cnlfaW5kZXgKLS0gQHBhcmFtIGRlbCBib29sZWFuICAgICBkcmFpbiBlYWNoIGtleSBhZnRlciByZWFkaW5nIChmbHVzaCBzZW1hbnRpY3MpCi0tIEByZXR1cm4gdGFibGV8bmlsIGNvdW50cywgb3IgbmlsIHdoZW4gdGhlIG1pbnV0ZSBoYWQgbm8gY291bnRyeSBkYXRhCmxvY2FsIGZ1bmN0aW9uIHJlYWRfbWludXRlX2NvdW50cmllcyhzbG90LCBkZWwpCiAgICBpZiBub3Qgc2xvdCB0aGVuIHJldHVybiBuaWwgZW5kCiAgICBsb2NhbCBjb3VudHMsIGFueSA9IHt9LCBmYWxzZQogICAgZm9yIGNjLCBrZXkgaW4gcGFpcnMoc2xvdCkgZG8KICAgICAgICAtLSBgZHJhaW5gIHN1YnRyYWN0cyB3aGF0IGl0IHJlYWQgaW5zdGVhZCBvZiBkZWxldGluZywgc28gYSByZXF1ZXN0IGFycml2aW5nCiAgICAgICAgLS0gbWlkLWZsdXNoIGlzIG5vdCB0aHJvd24gYXdheSB3aXRoIHRoZSB2YWx1ZSB0aGF0IHdhcyBqdXN0IHJlYWQuCiAgICAgICAgY291bnRzW2NjXSA9IGRlbCBhbmQgZHJhaW4oa2V5KSBvciAodG9udW1iZXIoYW5hbHl0aWNzOmdldChrZXkpKSBvciAwKQogICAgICAgIGFueSA9IHRydWUKICAgIGVuZAogICAgcmV0dXJuIGFueSBhbmQgY291bnRzIG9yIG5pbAplbmQKCi0tIOKUgOKUgCBQT1NUIC9hbmFseXRpY3MvY29sbGVjdCAtIHRoZSBTQ1JBUEVSJ3MgZW5kcG9pbnQ6IGV2ZXJ5IGRvbWFpbiwgT05FIHNjYW4g4pSA4pSACi0tCi0tIEJvZHk6IHsgImRheSI6ICJZWVlZTU1ERCIsICJkb21haW5zIjogWyB7ICJkb21haW4iOiAieC5jb20iLCAiZnJvbSI6IE0sICJ0byI6IE0gfSBdIH0KLS0gUmV0dXJuczogeyAiZG9tYWlucyI6IHsgInguY29tIjogeyBidWNrZXRzOiBbLi4uXSwgZmx1c2hlZDogTiwgcm9sbHVwOiB7Li4ufSB9IH0gfQotLQotLSBXaHkgdGhpcyBleGlzdHMgcmF0aGVyIHRoYW4gbG9vcGluZyB0aGUgc2luZ2xlLWRvbWFpbiBlbmRwb2ludHM6Ci0tCi0tIGBnZXRfa2V5c2AgaXMgdGhlIG9ubHkga2V5LWRpc2NvdmVyeSBtZWNoYW5pc20gYSBzaGFyZWQgZGljdCBvZmZlcnMsIGl0IHdhbGtzIHRoZQotLSBXSE9MRSB6b25lLCBhbmQgaXQgaG9sZHMgdGhlIGRpY3QgbG9jayBhZ2FpbnN0IGV2ZXJ5IG5naW54IHdvcmtlciB3aGlsZSBpdCBkb2VzLgotLSBUaGUgc2NyYXBlciBuZWVkcyBib3RoIHRoZSBwZXItbWludXRlIGNvdW50cmllcyAoZmx1c2gpIGFuZCB0aGUgZGFpbHkgcm9sbHVwIGZvcgotLSBlYWNoIGRvbWFpbiwgc28gY2FsbGluZyB0aGUgcGVyLWRvbWFpbiBlbmRwb2ludHMgY29zdCAyTisxIHVuYm91bmRlZCBzY2FucyBvZiBhCi0tIDI1NiBNQiB6b25lIOKAlCBwbHVzIDJOKzEgU1NIL2V4ZWMgcm91bmQgdHJpcHMg4oCUIGV2ZXJ5IHN3ZWVwLiBPbiBhIDUwLWRvbWFpbiBib3gKLS0gdGhhdCBpcyAxMDEgZnVsbCBzY2FucyBhbmQgMTAxIHJvdW5kIHRyaXBzLCBvbiBhIHNjaGVkdWxlLCB0byBjb2xsZWN0IGRhdGEgdGhhdAotLSBvbmUgcGFzcyBhbHJlYWR5IGhhcyBpbiBoYW5kLgotLQotLSBTbzogb25lIGBnZXRfa2V5cygwKWAsIGNsYXNzaWZ5IGV2ZXJ5IGtleSBieSAoa2luZCwgZG9tYWluKSBpbiBhIHNpbmdsZSBwYXNzLCB0aGVuCi0tIHNlcnZlIGFsbCBkb21haW5zIGZyb20gdGhlIGluLW1lbW9yeSBpbmRleC4gMk4rMSBzY2FucyDihpIgMSwgYW5kIDJOKzEgcm91bmQgdHJpcHMKLS0g4oaSIDEuIFRoZSBwZXItZG9tYWluIEdFVCBlbmRwb2ludHMgc3RheSBmb3IgdGhlIFJFQUQgcGF0aCwgd2hlcmUgYSBwYWdlIHZpZXcgd2FudHMKLS0gb25lIGRvbWFpbidzIGxpdmUgdGFpbCBhbmQgYSBzaW5nbGUgc2NhbiBpcyB0aGUgaG9uZXN0IGNvc3QuCi0tCi0tIEZsdXNoIHNlbWFudGljcyBhcmUgdW5jaGFuZ2VkIGFuZCBzdGlsbCBhdG9taWMgcGVyIGtleTogbWludXRlIGNvdW50ZXJzIGFuZCB0aGVpcgotLSBjb3VudHJ5IGtleXMgYXJlIGRlbGV0ZWQgYXMgdGhleSBhcmUgcmVhZCwgc28gYSBidWNrZXQgaXMgaGFuZGVkIHRvIGV4YWN0bHkgb25lCi0tIGNhbGxlciBubyBtYXR0ZXIgaG93IG1hbnkgY29sbGVjdG9ycyByYWNlLiBUaGUgZGFpbHkgcm9sbHVwIGlzIHJlYWQtb25seSDigJQgdGhlCi0tIGVkZ2Uga2VlcHMgcnVubmluZyB0b3RhbHMgZm9yIHRoZSBkYXksIGFuZCBkZWxldGluZyB0aGVtIHdvdWxkIGxvc2UgdGhlIHRvdGFscyBmb3IKLS0gZXZlcnkgbGF0ZXIgc2NyYXBlIG9mIHRoZSBzYW1lIGRheS4KCmlmIHVyaSA9PSAiL2FuYWx5dGljcy9jb2xsZWN0IiBhbmQgbmd4LnJlcS5nZXRfbWV0aG9kKCkgPT0gIlBPU1QiIHRoZW4KICAgIG5neC5yZXEucmVhZF9ib2R5KCkKICAgIGxvY2FsIGJvZHkgPSBuZ3gucmVxLmdldF9ib2R5X2RhdGEoKQogICAgaWYgbm90IGJvZHkgdGhlbiByZXR1cm4gYmFkKCJlbXB0eSBib2R5IikgZW5kCiAgICBsb2NhbCBwYXlsb2FkID0gY2pzb24uZGVjb2RlKGJvZHkpCiAgICBpZiB0eXBlKHBheWxvYWQpIH49ICJ0YWJsZSIgb3IgdHlwZShwYXlsb2FkLmRvbWFpbnMpIH49ICJ0YWJsZSIgdGhlbgogICAgICAgIHJldHVybiBiYWQoJ2V4cGVjdGVkIHsgZGF5LCBkb21haW5zOiBbe2RvbWFpbiwgZnJvbSwgdG99XSB9JykKICAgIGVuZAoKICAgIGxvY2FsIGRheSA9IHBheWxvYWQuZGF5CiAgICBpZiB0eXBlKGRheSkgfj0gInN0cmluZyIgb3IgI2RheSB+PSA4IHRoZW4gZGF5ID0gb3MuZGF0ZSgiISVZJW0lZCIpIGVuZAoKICAgIC0tIFJlcXVlc3RlZCBkb21haW5zIOKGkiB0aGVpciBtaW51dGUgd2luZG93LiBBbHNvIHRoZSBtZW1iZXJzaGlwIHRlc3QgdGhlIHNjYW4KICAgIC0tIHVzZXMsIHNvIGFuIHVucmVxdWVzdGVkIGRvbWFpbidzIGtleXMgYXJlIHNraXBwZWQgd2l0aG91dCBhIHN0cmluZyBjb21wYXJlCiAgICAtLSBwZXIgZG9tYWluLgogICAgbG9jYWwgd2FudCwgb3JkZXIgPSB7fSwge30KICAgIGZvciBpID0gMSwgI3BheWxvYWQuZG9tYWlucyBkbwogICAgICAgIGxvY2FsIGQgPSBwYXlsb2FkLmRvbWFpbnNbaV0KICAgICAgICBpZiB0eXBlKGQpID09ICJ0YWJsZSIgYW5kIHR5cGUoZC5kb21haW4pID09ICJzdHJpbmciIGFuZCBkLmRvbWFpbiB+PSAiIiB0aGVuCiAgICAgICAgICAgIGxvY2FsIG5hbWUgPSBkLmRvbWFpbjpsb3dlcigpCiAgICAgICAgICAgIGxvY2FsIGZyb21fbSwgdG9fbSA9IHRvbnVtYmVyKGQuZnJvbSksIHRvbnVtYmVyKGQudG8pCiAgICAgICAgICAgIGlmIGZyb21fbSBhbmQgdG9fbSB0aGVuCiAgICAgICAgICAgICAgICBpZiB0b19tIC0gZnJvbV9tID4gMTQ0MCB0aGVuIHRvX20gPSBmcm9tX20gKyAxNDQwIGVuZCAtLSBjYXAgYXQgMjRoCiAgICAgICAgICAgICAgICBpZiBub3Qgd2FudFtuYW1lXSB0aGVuIG9yZGVyWyNvcmRlciArIDFdID0gbmFtZSBlbmQKICAgICAgICAgICAgICAgIHdhbnRbbmFtZV0gPSB7IGZyb20gPSBmcm9tX20sIHRvID0gdG9fbSB9CiAgICAgICAgICAgIGVuZAogICAgICAgIGVuZAogICAgZW5kCiAgICBpZiAjb3JkZXIgPT0gMCB0aGVuIHJldHVybiBqc29uKHsgZG9tYWlucyA9IHt9IH0pIGVuZAoKICAgIC0tIOKUgOKUgCBQZXItZG9tYWluIGluZGV4IHJlYWRzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAogICAgLS0KICAgIC0tIFdhcyBhIHNpbmdsZSBgZ2V0X2tleXMoMClgIHBhc3MgY2xhc3NpZnlpbmcgZXZlcnkga2V5IGluIHRoZSB6b25lLiBPbmUgc2NhbiBpcyBiZXR0ZXIKICAgIC0tIHRoYW4gMk4rMSwgYnV0IGl0IHN0aWxsIHdhbGtlZCBrZXlzIGJlbG9uZ2luZyB0byBkb21haW5zIG5vYm9keSBhc2tlZCBhYm91dCwgYW5kIGhlbGQKICAgIC0tIHRoZSB6b25lIGxvY2sgd2hpbGUgZG9pbmcgaXQuIE5vdyBlYWNoIHJlcXVlc3RlZCBkb21haW4gcmVhZHMgb25seSBpdHMgb3duIGluZGV4ZXMuCiAgICBsb2NhbCBjb3VudHJpZXMgPSB7fSAgIC0tIGRvbWFpbiDihpIgbWludXRlIOKGkiBDQyDihpIgZGljdCBrZXkKICAgIGxvY2FsIHJvbGx1cHMgPSB7fSAgICAgLS0gZG9tYWluIOKGkiBzdWZmaXgg4oaSIHZhbHVlCiAgICBmb3IgaSA9IDEsICNvcmRlciBkbwogICAgICAgIGxvY2FsIGRvbWFpbiA9IG9yZGVyW2ldCiAgICAgICAgbG9jYWwgdyA9IHdhbnRbZG9tYWluXQogICAgICAgIGNvdW50cmllc1tkb21haW5dID0gc2Nhbl9jb3VudHJ5X2luZGV4KGRvbWFpbiwgdy5mcm9tLCB3LnRvKQogICAgICAgIHJvbGx1cHNbZG9tYWluXSA9IHJlYWRfcm9sbHVwKGRvbWFpbiwgZGF5KQogICAgZW5kCgogICAgLS0g4pSA4pSAIFNlcnZlIGVhY2ggZG9tYWluIGZyb20gdGhlIGluZGV4IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAogICAgbG9jYWwgb3V0ID0ge30KICAgIGZvciBpID0gMSwgI29yZGVyIGRvCiAgICAgICAgbG9jYWwgZG9tYWluID0gb3JkZXJbaV0KICAgICAgICBsb2NhbCB3ID0gd2FudFtkb21haW5dCiAgICAgICAgbG9jYWwgY2lkeCA9IGNvdW50cmllc1tkb21haW5dIG9yIHt9CgogICAgICAgIGxvY2FsIGJ1Y2tldHMsIGZsdXNoZWQgPSB7fSwgMAogICAgICAgIGZvciBtID0gdy5mcm9tLCB3LnRvIGRvCiAgICAgICAgICAgIGxvY2FsIHAgPSAiczoiIC4uIGRvbWFpbiAuLiAiOiIgLi4gbQogICAgICAgICAgICAtLSBEcmFpbiBGSVJTVCwgdGhlbiBkZWNpZGU6IGBkcmFpbmAgcmV0dXJucyB3aGF0IGl0IHRvb2ssIGFuZCBhIGNvdW50ZXIgbGVmdAogICAgICAgICAgICAtLSBhdCAwIGJ5IGFuIGVhcmxpZXIgZmx1c2ggbXVzdCBub3QgZW1pdCBhIGJ1Y2tldCBvZiB6ZXJvcy4gKFplcm8gaXMgdHJ1dGh5IGluCiAgICAgICAgICAgIC0tIEx1YSwgc28gdGhlIG9sZCBgaWYgciB0aGVuYCB3b3VsZCBoYXZlIHN0YXJ0ZWQgZG9pbmcgZXhhY3RseSB0aGF0IHRoZSBtb21lbnQKICAgICAgICAgICAgLS0ga2V5cyBzdG9wcGVkIGJlaW5nIGRlbGV0ZWQuKQogICAgICAgICAgICBsb2NhbCByID0gZHJhaW4ocCAuLiAiOnIiKQogICAgICAgICAgICBpZiByID4gMCB0aGVuCiAgICAgICAgICAgICAgICBsb2NhbCBydF91cyA9IGRyYWluKHAgLi4gIjp0IikKICAgICAgICAgICAgICAgIGJ1Y2tldHNbI2J1Y2tldHMgKyAxXSA9IHsKICAgICAgICAgICAgICAgICAgICBtaW51dGUgICAgICAgICAgPSBtLAogICAgICAgICAgICAgICAgICAgIHJlcXVlc3RzICAgICAgICA9IHIsCiAgICAgICAgICAgICAgICAgICAgdW5pcXVlX3JlcXVlc3RzID0gZHJhaW4ocCAuLiAiOnUiKSwKICAgICAgICAgICAgICAgICAgICBiYW5kd2lkdGhfaW4gICAgPSBkcmFpbihwIC4uICI6aSIpLAogICAgICAgICAgICAgICAgICAgIGJhbmR3aWR0aF9vdXQgICA9IGRyYWluKHAgLi4gIjpvIiksCiAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2VfdGltZSAgID0gcnRfdXMgLyAxMDAwMDAwLAogICAgICAgICAgICAgICAgICAgIGNvdW50cmllcyAgICAgICA9IHJlYWRfbWludXRlX2NvdW50cmllcyhjaWR4W21dLCB0cnVlKSwKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGZsdXNoZWQgPSBmbHVzaGVkICsgMQogICAgICAgICAgICBlbmQKICAgICAgICBlbmQKCiAgICAgICAgLS0gRGFpbHkgcm9sbHVwLCBzYW1lIGtleSBjbGFzc2lmaWNhdGlvbiB0aGUgc2luZ2xlLWRvbWFpbiBlbmRwb2ludCB1c2VzLgogICAgICAgIGxvY2FsIGdlbywgcGF0aHMsIHN0YXR1c2VzLCB2aXNpdG9ycyA9IHt9LCB7fSwge30sIDAKICAgICAgICBmb3Igc3VmZml4LCB2IGluIHBhaXJzKHJvbGx1cHNbZG9tYWluXSBvciB7fSkgZG8KICAgICAgICAgICAgaWYgc3VmZml4ID09ICJ2IiB0aGVuCiAgICAgICAgICAgICAgICB2aXNpdG9ycyA9IHYKICAgICAgICAgICAgZWxzZWlmIHN1ZmZpeDpzdWIoMSwgMikgPT0gInA6IiB0aGVuCiAgICAgICAgICAgICAgICBwYXRoc1tzdWZmaXg6c3ViKDMpXSA9IHYKICAgICAgICAgICAgZWxzZWlmIHN1ZmZpeDpzdWIoMSwgMikgPT0gInM6IiB0aGVuCiAgICAgICAgICAgICAgICBzdGF0dXNlc1tzdWZmaXg6c3ViKDMpXSA9IHYKICAgICAgICAgICAgZWxzZWlmIHN1ZmZpeDptYXRjaCgiXiV1JXUkIikgdGhlbgogICAgICAgICAgICAgICAgZ2VvW3N1ZmZpeF0gPSB2CiAgICAgICAgICAgIGVuZAogICAgICAgICAgICAtLSBBbnl0aGluZyBlbHNlIChgcG5gKSBpcyBib29ra2VlcGluZzogbmV2ZXIgcmVwb3J0ZWQgYXMgYSBjb3VudHJ5LgogICAgICAgIGVuZAoKICAgICAgICBvdXRbZG9tYWluXSA9IHsKICAgICAgICAgICAgYnVja2V0cyA9IGJ1Y2tldHMsCiAgICAgICAgICAgIGZsdXNoZWQgPSBmbHVzaGVkLAogICAgICAgICAgICByb2xsdXAgID0gewogICAgICAgICAgICAgICAgZGF5ID0gZGF5LCBjb3VudHJpZXMgPSBnZW8sIHZpc2l0b3JzID0gdmlzaXRvcnMsCiAgICAgICAgICAgICAgICBwYXRocyA9IHBhdGhzLCBzdGF0dXNlcyA9IHN0YXR1c2VzLAogICAgICAgICAgICB9LAogICAgICAgIH0KICAgIGVuZAoKICAgIHJldHVybiBqc29uKHsgZGF5ID0gZGF5LCBkb21haW5zID0gb3V0IH0pCmVuZAoKLS0g4pSA4pSAIEdFVCAvYW5hbHl0aWNzIC0gbWludXRlLWJ1Y2tldCB0aW1lIHNlcmllcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKLS0gP2RvbWFpbj1leGFtcGxlLmNvbSZmcm9tPUVQT0NIX01JTiZ0bz1FUE9DSF9NSU4KCmlmIHVyaSA9PSAiL2FuYWx5dGljcyIgdGhlbgogICAgbG9jYWwgZG9tYWluID0gbmd4LnZhci5hcmdfZG9tYWluCiAgICBpZiBub3QgZG9tYWluIG9yIGRvbWFpbiA9PSAiIiB0aGVuIHJldHVybiBiYWQoIm1pc3NpbmcgP2RvbWFpbj0iKSBlbmQKICAgIGRvbWFpbiA9IGRvbWFpbjpsb3dlcigpCgogICAgbG9jYWwgZnJvbV9tID0gdG9udW1iZXIobmd4LnZhci5hcmdfZnJvbSkKICAgIGxvY2FsIHRvX20gICA9IHRvbnVtYmVyKG5neC52YXIuYXJnX3RvKQogICAgaWYgbm90IGZyb21fbSBvciBub3QgdG9fbSB0aGVuCiAgICAgICAgcmV0dXJuIGJhZCgibWlzc2luZyA/ZnJvbT0gYW5kID90bz0gKGVwb2NoIG1pbnV0ZXMpIikKICAgIGVuZAogICAgLS0gQ2FwIGF0IDI0aAogICAgaWYgdG9fbSAtIGZyb21fbSA+IDE0NDAgdGhlbiB0b19tID0gZnJvbV9tICsgMTQ0MCBlbmQKCiAgICAtLSBPTkUgc2NhbiBmb3IgdGhlIHdob2xlIHdpbmRvdyAoc2VlIHNjYW5fY291bnRyeV9pbmRleCkuCiAgICBsb2NhbCBjb3VudHJ5X2luZGV4ID0gc2Nhbl9jb3VudHJ5X2luZGV4KGRvbWFpbiwgZnJvbV9tLCB0b19tKQoKICAgIGxvY2FsIGJ1Y2tldHMgPSB7fQogICAgZm9yIG0gPSBmcm9tX20sIHRvX20gZG8KICAgICAgICBsb2NhbCBwID0gInM6IiAuLiBkb21haW4gLi4gIjoiIC4uIG0KICAgICAgICBsb2NhbCByID0gYW5hbHl0aWNzOmdldChwIC4uICI6ciIpCiAgICAgICAgaWYgciB0aGVuCiAgICAgICAgICAgIC0tIFJlc3BvbnNlIHRpbWUgc3RvcmVkIGFzIG1pY3Jvc2Vjb25kcywgY29udmVydCB0byBzZWNvbmRzIChmbG9hdCkKICAgICAgICAgICAgbG9jYWwgcnRfdXMgPSBhbmFseXRpY3M6Z2V0KHAgLi4gIjp0Iikgb3IgMAogICAgICAgICAgICBidWNrZXRzWyNidWNrZXRzICsgMV0gPSB7CiAgICAgICAgICAgICAgICBtaW51dGUgICAgICAgICAgID0gbSwKICAgICAgICAgICAgICAgIHJlcXVlc3RzICAgICAgICAgPSByLAogICAgICAgICAgICAgICAgdW5pcXVlX3JlcXVlc3RzICA9IGFuYWx5dGljczpnZXQocCAuLiAiOnUiKSBvciAwLAogICAgICAgICAgICAgICAgYmFuZHdpZHRoX2luICAgICA9IGFuYWx5dGljczpnZXQocCAuLiAiOmkiKSBvciAwLAogICAgICAgICAgICAgICAgYmFuZHdpZHRoX291dCAgICA9IGFuYWx5dGljczpnZXQocCAuLiAiOm8iKSBvciAwLAogICAgICAgICAgICAgICAgcmVzcG9uc2VfdGltZSAgICA9IHJ0X3VzIC8gMTAwMDAwMCwKICAgICAgICAgICAgICAgIGNvdW50cmllcyAgICAgICAgPSByZWFkX21pbnV0ZV9jb3VudHJpZXMoY291bnRyeV9pbmRleFttXSwgZmFsc2UpLAogICAgICAgICAgICB9CiAgICAgICAgZW5kCiAgICBlbmQKCiAgICByZXR1cm4ganNvbih7IGRvbWFpbiA9IGRvbWFpbiwgYnVja2V0cyA9IGJ1Y2tldHMgfSkKZW5kCgotLSDilIDilIAgUE9TVCAvYW5hbHl0aWNzL2ZsdXNoIC0gcmVhZCArIGRlbGV0ZSBtaW51dGUgYnVja2V0cyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKLS0gU2FtZSBhcyBHRVQgL2FuYWx5dGljcyBidXQgZGVsZXRlcyB0aGUgcmV0dXJuZWQgYnVja2V0cyBmcm9tIHNoYXJlZCBtZW1vcnkuCi0tIFVzZWQgYnkgdGhlIHNjcmFwZXIgdG8gYXRvbWljYWxseSBtb3ZlIGRhdGEgZnJvbSBPcGVuUmVzdHkg4oaSIERCLgotLSA/ZG9tYWluPWV4YW1wbGUuY29tJmZyb209RVBPQ0hfTUlOJnRvPUVQT0NIX01JTgoKaWYgdXJpID09ICIvYW5hbHl0aWNzL2ZsdXNoIiBhbmQgbmd4LnJlcS5nZXRfbWV0aG9kKCkgPT0gIlBPU1QiIHRoZW4KICAgIGxvY2FsIGRvbWFpbiA9IG5neC52YXIuYXJnX2RvbWFpbgogICAgaWYgbm90IGRvbWFpbiBvciBkb21haW4gPT0gIiIgdGhlbiByZXR1cm4gYmFkKCJtaXNzaW5nID9kb21haW49IikgZW5kCiAgICBkb21haW4gPSBkb21haW46bG93ZXIoKQoKICAgIGxvY2FsIGZyb21fbSA9IHRvbnVtYmVyKG5neC52YXIuYXJnX2Zyb20pCiAgICBsb2NhbCB0b19tICAgPSB0b251bWJlcihuZ3gudmFyLmFyZ190bykKICAgIGlmIG5vdCBmcm9tX20gb3Igbm90IHRvX20gdGhlbgogICAgICAgIHJldHVybiBiYWQoIm1pc3NpbmcgP2Zyb209IGFuZCA/dG89IChlcG9jaCBtaW51dGVzKSIpCiAgICBlbmQKICAgIGlmIHRvX20gLSBmcm9tX20gPiAxNDQwIHRoZW4gdG9fbSA9IGZyb21fbSArIDE0NDAgZW5kCgogICAgLS0gT05FIHNjYW4gZm9yIHRoZSB3aG9sZSB3aW5kb3cgKHNlZSBzY2FuX2NvdW50cnlfaW5kZXgpLgogICAgbG9jYWwgY291bnRyeV9pbmRleCA9IHNjYW5fY291bnRyeV9pbmRleChkb21haW4sIGZyb21fbSwgdG9fbSkKCiAgICBsb2NhbCBidWNrZXRzID0ge30KICAgIGxvY2FsIGZsdXNoZWQgPSAwCiAgICBmb3IgbSA9IGZyb21fbSwgdG9fbSBkbwogICAgICAgIGxvY2FsIHAgPSAiczoiIC4uIGRvbWFpbiAuLiAiOiIgLi4gbQogICAgICAgIC0tIERyYWluLCBkb24ndCBkZWxldGUg4oCUIHNlZSBgZHJhaW5gLiBBIGNvdW50ZXIgYWxyZWFkeSBhdCAwIGlzIG5vdCBhIGJ1Y2tldC4KICAgICAgICBsb2NhbCByID0gZHJhaW4ocCAuLiAiOnIiKQogICAgICAgIGlmIHIgPiAwIHRoZW4KICAgICAgICAgICAgbG9jYWwgcnRfdXMgPSBkcmFpbihwIC4uICI6dCIpCiAgICAgICAgICAgIGJ1Y2tldHNbI2J1Y2tldHMgKyAxXSA9IHsKICAgICAgICAgICAgICAgIG1pbnV0ZSAgICAgICAgICAgPSBtLAogICAgICAgICAgICAgICAgcmVxdWVzdHMgICAgICAgICA9IHIsCiAgICAgICAgICAgICAgICB1bmlxdWVfcmVxdWVzdHMgID0gZHJhaW4ocCAuLiAiOnUiKSwKICAgICAgICAgICAgICAgIGJhbmR3aWR0aF9pbiAgICAgPSBkcmFpbihwIC4uICI6aSIpLAogICAgICAgICAgICAgICAgYmFuZHdpZHRoX291dCAgICA9IGRyYWluKHAgLi4gIjpvIiksCiAgICAgICAgICAgICAgICByZXNwb25zZV90aW1lICAgID0gcnRfdXMgLyAxMDAwMDAwLAogICAgICAgICAgICAgICAgLS0gRHJhaW5lZCB0b286IHRoaXMgZW5kcG9pbnQgaGFuZHMgdGhlIG1pbnV0ZSB0byB0aGUgREIsIHNvIHRoZSBjb3VudHJ5CiAgICAgICAgICAgICAgICAtLSBrZXlzIG11c3QgZ28gd2l0aCBpdCBvciB0aGV5IHdvdWxkIGJlIGNvdW50ZWQgdHdpY2UuCiAgICAgICAgICAgICAgICBjb3VudHJpZXMgICAgICAgID0gcmVhZF9taW51dGVfY291bnRyaWVzKGNvdW50cnlfaW5kZXhbbV0sIHRydWUpLAogICAgICAgICAgICB9CiAgICAgICAgICAgIGZsdXNoZWQgPSBmbHVzaGVkICsgMQogICAgICAgIGVuZAogICAgZW5kCgogICAgcmV0dXJuIGpzb24oeyBkb21haW4gPSBkb21haW4sIGJ1Y2tldHMgPSBidWNrZXRzLCBmbHVzaGVkID0gZmx1c2hlZCB9KQplbmQKCi0tIOKUgOKUgCBHRVQgL2FuYWx5dGljcy90b3RhbHMgLSBsaWZldGltZSBjb3VudGVycyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKLS0gP2RvbWFpbj1leGFtcGxlLmNvbSAgICAgIOKGkiBzaW5nbGUgZG9tYWluCi0tIChubyBkb21haW4pICAgICAgICAgICAgICDihpIgYWxsIGtub3duIGRvbWFpbnMKCmlmIHVyaSA9PSAiL2FuYWx5dGljcy90b3RhbHMiIHRoZW4KICAgIGxvY2FsIGRvbWFpbiA9IG5neC52YXIuYXJnX2RvbWFpbgoKICAgIGlmIG5vdCBkb21haW4gb3IgZG9tYWluID09ICIiIHRoZW4KICAgICAgICAtLSBUaGUgc2NyYXBlcidzIGRvbWFpbi1kaXNjb3ZlcnkgY2FsbC4gUmVhZCBmcm9tIHRoZSBgZG5gL2BkaTpgIGluZGV4IHRoYXQKICAgICAgICAtLSBzaXRlX2xvZ2dlciBhcHBlbmRzIHRvIHRoZSBmaXJzdCB0aW1lIGl0IGV2ZXIgc2VlcyBhIGhvc3QsIHNvIHRoaXMgbm8gbG9uZ2VyCiAgICAgICAgLS0gd2Fsa3MgdGhlIHpvbmUuIEl0IHdhcyB0aGUgd29yc3QgcGxhY2UgZm9yIGEgc2NhbjogYSBjYXAgaGVyZSBzaWxlbnRseSBkcm9wcGVkCiAgICAgICAgLS0gd2hvbGUgZG9tYWlucyBmcm9tIGV2ZXJ5IHN1YnNlcXVlbnQgZmx1c2guCiAgICAgICAgbG9jYWwgZG9tYWlucyA9IHt9CiAgICAgICAgZm9yIF8sIGQgaW4gaXBhaXJzKHJlYWRfaW5kZXgoImRuIiwgImRpOiIpKSBkbwogICAgICAgICAgICAtLSBBIGhvc3QgY2FuIGJlIGluZGV4ZWQgYnV0IGhhdmUgaGFkIGl0cyBsaWZldGltZSB0b3RhbHMgZXZpY3RlZDsgcmVwb3J0IGl0CiAgICAgICAgICAgIC0tIHdpdGggemVyb3MgcmF0aGVyIHRoYW4gb21pdHRpbmcgaXQsIHNvIHRoZSBzY3JhcGVyIHN0aWxsIGFza3MgZm9yIGl0cyBidWNrZXRzLgogICAgICAgICAgICBkb21haW5zWyNkb21haW5zICsgMV0gPSB7CiAgICAgICAgICAgICAgICBkb21haW4gICAgICAgID0gZCwKICAgICAgICAgICAgICAgIHJlcXVlc3RzICAgICAgPSBhbmFseXRpY3M6Z2V0KCJ0OiIgLi4gZCAuLiAiOnIiKSBvciAwLAogICAgICAgICAgICAgICAgYmFuZHdpZHRoX2luICA9IGFuYWx5dGljczpnZXQoInQ6IiAuLiBkIC4uICI6aSIpIG9yIDAsCiAgICAgICAgICAgICAgICBiYW5kd2lkdGhfb3V0ID0gYW5hbHl0aWNzOmdldCgidDoiIC4uIGQgLi4gIjpvIikgb3IgMCwKICAgICAgICAgICAgfQogICAgICAgIGVuZAogICAgICAgIHJldHVybiBqc29uKHsgZG9tYWlucyA9IGRvbWFpbnMgfSkKICAgIGVuZAoKICAgIGRvbWFpbiA9IGRvbWFpbjpsb3dlcigpCiAgICByZXR1cm4ganNvbih7CiAgICAgICAgZG9tYWluICAgICAgICA9IGRvbWFpbiwKICAgICAgICByZXF1ZXN0cyAgICAgID0gYW5hbHl0aWNzOmdldCgidDoiIC4uIGRvbWFpbiAuLiAiOnIiKSBvciAwLAogICAgICAgIGJhbmR3aWR0aF9pbiAgPSBhbmFseXRpY3M6Z2V0KCJ0OiIgLi4gZG9tYWluIC4uICI6aSIpIG9yIDAsCiAgICAgICAgYmFuZHdpZHRoX291dCA9IGFuYWx5dGljczpnZXQoInQ6IiAuLiBkb21haW4gLi4gIjpvIikgb3IgMCwKICAgIH0pCmVuZAoKLS0g4pSA4pSAIEdFVCAvYW5hbHl0aWNzL2dlbyAtIGRhaWx5IHJvbGx1cCBmb3IgYSBkYXkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACi0tID9kb21haW49ZXhhbXBsZS5jb20mZGF5PVlZWVlNTURECi0tCi0tIE5hbWVkIC9nZW8gZm9yIGNvbXBhdGliaWxpdHk7IGl0IG5vdyByZXR1cm5zIHRoZSB3aG9sZSBkYWlseSByb2xsdXAg4oCUIGNvdW50cmllcywKLS0gZGlzdGluY3QgdmlzaXRvcnMsIHRvcCBwYXRocywgc3RhdHVzLWNvZGUgbWl4LiBPbmUgc2NhbiBzZXJ2ZXMgYWxsIGZvdXI6IHRoZXkKLS0gc2hhcmUgdGhlIGBnOntkb21haW59OntkYXl9OmAgcHJlZml4IHByZWNpc2VseSBzbyBhIHJlYWRlciBuZXZlciBuZWVkcyBhIHNlY29uZAotLSBwYXNzIG92ZXIgdGhlIHpvbmUuCi0tCi0tIEtleSBsYXlvdXQgdW5kZXIgdGhhdCBwcmVmaXggKHdyaXR0ZW4gYnkgc2l0ZV9sb2dnZXIubHVhKToKLS0gICA8Q0M+ICAgICAgICAgICAgRVhBQ1RMWSB0d28gdXBwZXJjYXNlIGxldHRlcnMg4oaSIGNvdW50cnkgaGl0IGNvdW50Ci0tICAgdiAgICAgICAgICAgICAgIGRpc3RpbmN0IHZpc2l0b3JzIHRvZGF5Ci0tICAgcDo8cGF0aD4gICAgICAgIHBhdGggY291bnRlcgotLSAgIHBuICAgICAgICAgICAgICBkaXN0aW5jdC1wYXRoIGNvdW50ZXIgKGNhcmRpbmFsaXR5IGNhcCBib29ra2VlcGluZykKLS0gICBzOjxzdGF0dXM+ICAgICAgc3RhdHVzLWNvZGUgY291bnRlcgotLQotLSBDb3VudHJ5IG1hdGNoaW5nIGlzIHN0cmljdCAoXiV1JXUkKSByYXRoZXIgdGhhbiAid2hhdGV2ZXIncyBsZWZ0IjogYSBib29ra2VlcGluZwotLSBrZXkgbGlrZSBgcG5gIHdvdWxkIG90aGVyd2lzZSBzdXJmYWNlIGFzIGEgY291bnRyeSBuYW1lZCAicG4iIGFuZCBnZXQgcGxvdHRlZC4KCmlmIHVyaSA9PSAiL2FuYWx5dGljcy9nZW8iIHRoZW4KICAgIGxvY2FsIGRvbWFpbiA9IG5neC52YXIuYXJnX2RvbWFpbgogICAgaWYgbm90IGRvbWFpbiBvciBkb21haW4gPT0gIiIgdGhlbiByZXR1cm4gYmFkKCJtaXNzaW5nID9kb21haW49IikgZW5kCiAgICBkb21haW4gPSBkb21haW46bG93ZXIoKQoKICAgIGxvY2FsIGRheSA9IG5neC52YXIuYXJnX2RheQogICAgaWYgbm90IGRheSBvciAjZGF5IH49IDggdGhlbgogICAgICAgIGRheSA9IG9zLmRhdGUoIiElWSVtJWQiKQogICAgZW5kCgogICAgLS0gUmVhZCB0aHJvdWdoIHRoZSB3cml0ZS10aW1lIGluZGV4ZXMg4oCUIHNhbWUgaGVscGVyIC9hbmFseXRpY3MvY29sbGVjdCB1c2VzLCBzbyB0aGUgdHdvCiAgICAtLSBlbmRwb2ludHMgY2Fubm90IGRpc2FncmVlIGFib3V0IHdoYXQgYSBkYXkgY29udGFpbnMuIFJlcGxhY2VzIGEgYGdldF9rZXlzKDApYCB0aGF0CiAgICAtLSB3YWxrZWQgdGhlIHdob2xlIHpvbmUgdG8gZmluZCBrZXlzIHVuZGVyIG9uZSBwcmVmaXguCiAgICBsb2NhbCByb2xsdXAgPSByZWFkX3JvbGx1cChkb21haW4sIGRheSkKICAgIGxvY2FsIGNvdW50cmllcywgcGF0aHMsIHN0YXR1c2VzID0ge30sIHt9LCB7fQogICAgbG9jYWwgdmlzaXRvcnMgPSB0b251bWJlcihyb2xsdXBbInYiXSkgb3IgMAogICAgZm9yIHN1ZmZpeCwgdiBpbiBwYWlycyhyb2xsdXApIGRvCiAgICAgICAgaWYgc3VmZml4ID09ICJ2IiBvciBzdWZmaXggPT0gInBuIiB0aGVuCiAgICAgICAgICAgIC0tIGJvb2trZWVwaW5nLCBub3QgZGF0YQogICAgICAgIGVsc2VpZiBzdWZmaXg6c3ViKDEsIDIpID09ICJwOiIgdGhlbgogICAgICAgICAgICBwYXRoc1tzdWZmaXg6c3ViKDMpXSA9IHYKICAgICAgICBlbHNlaWYgc3VmZml4OnN1YigxLCAyKSA9PSAiczoiIHRoZW4KICAgICAgICAgICAgc3RhdHVzZXNbc3VmZml4OnN1YigzKV0gPSB2CiAgICAgICAgZWxzZWlmIHN1ZmZpeDptYXRjaCgiXiV1JXUkIikgdGhlbgogICAgICAgICAgICAtLSBDb3VudHJ5IGNvZGVzIG9ubHkuIEFueXRoaW5nIGVsc2UgdW5kZXIgdGhpcyBwcmVmaXggaXMgYm9va2tlZXBpbmcsIGFuZAogICAgICAgICAgICAtLSBsZXR0aW5nIG9uZSB0aHJvdWdoIG1hZGUgYHBuYCBwbG90IGFzIGEgY291bnRyeSBhbmQgc2tldyBldmVyeSBwZXJjZW50YWdlLgogICAgICAgICAgICBjb3VudHJpZXNbc3VmZml4XSA9IHYKICAgICAgICBlbmQKICAgIGVuZAogICAgcmV0dXJuIGpzb24oewogICAgICAgIGRvbWFpbiAgICA9IGRvbWFpbiwKICAgICAgICBkYXkgICAgICAgPSBkYXksCiAgICAgICAgY291bnRyaWVzID0gY291bnRyaWVzLAogICAgICAgIHZpc2l0b3JzICA9IHZpc2l0b3JzLAogICAgICAgIHBhdGhzICAgICA9IHBhdGhzLAogICAgICAgIHN0YXR1c2VzICA9IHN0YXR1c2VzLAogICAgfSkKZW5kCgotLSDilIDilIAgR0VUIC9sb2dzL3JlY2VudCAtIHJhdyByZXF1ZXN0IHJpbmcgYnVmZmVyIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAotLSA/ZG9tYWluPWV4YW1wbGUuY29tJmxpbWl0PTUwCgppZiB1cmkgPT0gIi9sb2dzL3JlY2VudCIgdGhlbgogICAgaWYgbm90IHJlcXVlc3RfZGF0YSB0aGVuCiAgICAgICAgcmV0dXJuIGpzb24oeyBlcnJvciA9ICJyZXF1ZXN0X2RhdGEgZGljdCB1bmF2YWlsYWJsZSIgfSwgNTAzKQogICAgZW5kCgogICAgbG9jYWwgZG9tYWluID0gbmd4LnZhci5hcmdfZG9tYWluCiAgICBpZiBub3QgZG9tYWluIG9yIGRvbWFpbiA9PSAiIiB0aGVuIHJldHVybiBiYWQoIm1pc3NpbmcgP2RvbWFpbj0iKSBlbmQKICAgIGRvbWFpbiA9IGRvbWFpbjpsb3dlcigpCgogICAgbG9jYWwgbGltaXQgPSBtYXRoLm1pbih0b251bWJlcihuZ3gudmFyLmFyZ19saW1pdCkgb3IgNTAsIDEwMDApCiAgICBsb2NhbCBzZXEgICA9IHJlcXVlc3RfZGF0YTpnZXQoInJsb2c6IiAuLiBkb21haW4gLi4gIjpzZXEiKSBvciAwCiAgICBsb2NhbCBvdXQgICA9IHt9CgogICAgZm9yIGkgPSAwLCBsaW1pdCAtIDEgZG8KICAgICAgICBsb2NhbCBzbG90ID0gKHNlcSAtIGkpICUgMTAwMAogICAgICAgIGlmIHNsb3QgPCAwIHRoZW4gc2xvdCA9IHNsb3QgKyAxMDAwIGVuZAogICAgICAgIGxvY2FsIHJhdyA9IHJlcXVlc3RfZGF0YTpnZXQoInJsb2c6IiAuLiBkb21haW4gLi4gIjoiIC4uIHNsb3QpCiAgICAgICAgaWYgcmF3IHRoZW4gb3V0WyNvdXQgKyAxXSA9IHJhdyBlbmQKICAgIGVuZAoKICAgIC0tIFJldHVybiBwcmUtZW5jb2RlZCBKU09OIGVudHJpZXMgYXMgYSBKU09OIGFycmF5CiAgICBuZ3guaGVhZGVyWyJDb250ZW50LVR5cGUiXSA9ICJhcHBsaWNhdGlvbi9qc29uIgogICAgbmd4LnByaW50KCJbIikKICAgIGZvciBpZHgsIGVudHJ5IGluIGlwYWlycyhvdXQpIGRvCiAgICAgICAgaWYgaWR4ID4gMSB0aGVuIG5neC5wcmludCgiLCIpIGVuZAogICAgICAgIG5neC5wcmludChlbnRyeSkKICAgIGVuZAogICAgbmd4LnNheSgiXSIpCiAgICByZXR1cm4gbmd4LmV4aXQoMjAwKQplbmQKCi0tIOKUgOKUgCA0MDQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACnJldHVybiBqc29uKHsgZXJyb3IgPSAibm90IGZvdW5kIiB9LCA0MDQpCg==",
37
+ "pipe_stream.lua": "LS0gcGlwZV9zdHJlYW0ubHVhCi0tIGNvbnRlbnRfYnlfbHVhOiBTU0UgZW5kcG9pbnQgZm9yIHJlYWwtdGltZSByZXF1ZXN0IGxvZyBzdHJlYW1pbmcuCi0tIEdFVCAvbG9ncy9zdHJlYW0/ZG9tYWluPWV4YW1wbGUuY29tCi0tIEludGVybmFsIG9ubHkgLSAxMjcuMC4wLjE6OTE0NQotLQotLSBSZWFkcyB0aGUgU0FNRSByaW5nIGJ1ZmZlciBzaXRlX2xvZ2dlci5sdWEgd3JpdGVzIChybG9nOntkb21haW59OnNlcSArCi0tIHJsb2c6e2RvbWFpbn06e3Nsb3R9KSwgYnkgYSBQRVItQ09OTkVDVElPTiBjdXJzb3IuIE5vdGhpbmcgaXMgY29uc3VtZWQ6IE4KLS0gY29uY3VycmVudCB3YXRjaGVycyBlYWNoIHdhbGsgdGhlIHJpbmcgaW5kZXBlbmRlbnRseSBhbmQgbm9uZSBzdGVhbHMgYW5vdGhlcidzCi0tIGZyYW1lcy4gVGhpcyBpcyB3aGF0IHJlcGxhY2VkIHRoZSBvbGQgc2luZ2xlLXN1YnNjcmliZXIgbG9nX3BpcGU6cSBxdWV1ZSDigJQKLS0gYSBjb250YWluZXJpemVkIGVkZ2UgdGFpbHMgdGhpcyBvdmVyIGBkb2NrZXIgZXhlYyBjdXJsYCwgYW5kIGEgY3VybCB0aGF0Ci0tIG91dGxpdmVzIGl0cyBjbGllbnQgKHRoZSBkYWVtb24gYnVmZmVycyBpdHMgc3Rkb3V0LCBzbyBubyBFUElQRSkgY2FuIG5vIGxvbmdlcgotLSBkcmFpbiB0aGUgcXVldWUgb3V0IGZyb20gdW5kZXIgdGhlIG5leHQgcmVhZGVyLgoKbG9jYWwgc2ggPSBuZ3guc2hhcmVkLnJlcXVlc3RfZGF0YQppZiBub3Qgc2ggdGhlbgogICAgbmd4LnN0YXR1cyA9IDUwMwogICAgbmd4LnNheSgic2hhcmVkIGRpY3QgdW5hdmFpbGFibGUiKQogICAgcmV0dXJuIG5neC5leGl0KDUwMykKZW5kCgpsb2NhbCBkb21haW4gPSBuZ3gudmFyLmFyZ19kb21haW4KaWYgbm90IGRvbWFpbiBvciBkb21haW4gPT0gIiIgdGhlbgogICAgbmd4LnN0YXR1cyA9IDQwMAogICAgbmd4LnNheSgibWlzc2luZyA/ZG9tYWluPSBwYXJhbWV0ZXIiKQogICAgcmV0dXJuIG5neC5leGl0KDQwMCkKZW5kCgpkb21haW4gPSBkb21haW46bG93ZXIoKQppZiBkb21haW46c3ViKDEsIDQpID09ICJ3d3cuIiB0aGVuIGRvbWFpbiA9IGRvbWFpbjpzdWIoNSkgZW5kCgotLSBNVVNUIG1hdGNoIHNpdGVfbG9nZ2VyLmx1YSdzIFJJTkcg4oCUIHNhbWUgc2xvdCBhcml0aG1ldGljIG9uIGJvdGggZW5kcy4KbG9jYWwgUklORyAgICA9IDEwMDAKbG9jYWwgU0VRX0tFWSA9ICJybG9nOiIgLi4gZG9tYWluIC4uICI6c2VxIgpsb2NhbCBzbG90X2tleSA9IGZ1bmN0aW9uKHNlcSkgcmV0dXJuICJybG9nOiIgLi4gZG9tYWluIC4uICI6IiAuLiAoc2VxICUgUklORykgZW5kCgpuZ3guaGVhZGVyWyJDb250ZW50LVR5cGUiXSAgICAgID0gInRleHQvZXZlbnQtc3RyZWFtIgpuZ3guaGVhZGVyWyJDYWNoZS1Db250cm9sIl0gICAgID0gIm5vLWNhY2hlLCBuby1zdG9yZSIKbmd4LmhlYWRlclsiQ29ubmVjdGlvbiJdICAgICAgICA9ICJrZWVwLWFsaXZlIgpuZ3guaGVhZGVyWyJYLUFjY2VsLUJ1ZmZlcmluZyJdID0gIm5vIgoKLS0gU2VuZCBpbml0aWFsIFNTRSBjb21tZW50IHNvIHRoZSBmaXJzdCBmbHVzaCBoYXMgZGF0YS4KLS0gV2l0aG91dCB0aGlzLCBuZ3guZmx1c2ggb24gYW4gZW1wdHkgYnVmZmVyIHNlbmRzIGNodW5rZWQtRU9GICgwXHJcblxyXG4pCi0tIGFuZCB0ZXJtaW5hdGVzIHRoZSByZXNwb25zZSBpbW1lZGlhdGVseS4Kbmd4LnByaW50KCI6IGNvbm5lY3RlZFxuXG4iKQppZiBub3Qgbmd4LmZsdXNoKHRydWUpIHRoZW4gcmV0dXJuIGVuZAoKLS0gU3RhcnQgYXQgdGhlIGN1cnJlbnQgaGVhZDogc3RyZWFtIG9ubHkgcmVxdWVzdHMgdGhhdCBhcnJpdmUgQUZURVIgY29ubmVjdC4KLS0gSGlzdG9yeSB1cCB0byB0aGlzIHBvaW50IGlzIHNlcnZlZCBzZXBhcmF0ZWx5IGJ5IC9sb2dzL3JlY2VudCwgYW5kIHRoZSBjbGllbnQKLS0gZGVkdXBzIHRoZSB0d28gYnkgdGhlIGRldGVybWluaXN0aWMgYHtob3N0fTp7c2VxfWAgaWQsIHNvIGEgcm93IHNlZW4gYnkgYm90aAotLSBjb2xsYXBzZXMgdG8gb25lLgpsb2NhbCBjdXJzb3IgID0gdG9udW1iZXIoc2g6Z2V0KFNFUV9LRVkpKSBvciAwCmxvY2FsIHN0YXJ0ZWQgPSBuZ3gubm93KCkKbG9jYWwgbGFzdF9oYiA9IHN0YXJ0ZWQKCndoaWxlIHRydWUgZG8KICAgIC0tIE1heCAxIGhvdXIgcGVyIGNvbm5lY3Rpb24uCiAgICBpZiBuZ3gubm93KCkgLSBzdGFydGVkID4gMzYwMCB0aGVuIHJldHVybiBlbmQKCiAgICBsb2NhbCBoZWFkID0gdG9udW1iZXIoc2g6Z2V0KFNFUV9LRVkpKSBvciAwCgogICAgLS0gSWYgd2UndmUgZmFsbGVuIG1vcmUgdGhhbiBhIGZ1bGwgcmluZyBiZWhpbmQsIHRoZSBvbGRlc3QgdW5yZWFkIHNsb3RzIGhhdmUKICAgIC0tIGFscmVhZHkgYmVlbiBvdmVyd3JpdHRlbi4gSnVtcCB0byB0aGUgb2xkZXN0IHNsb3Qgc3RpbGwgaG9sZGluZyBpdHMgb3duCiAgICAtLSBlbnRyeSAoaGVhZC1SSU5HIG1hcHMgdG8gaGVhZCdzIHNsb3QsIHNvIGhlYWQtUklORysxIGlzIHRoZSBvbGRlc3QgbGl2ZSBvbmUpCiAgICAtLSBhbmQgc2tpcCB0aGUgbG9zdCByYW5nZSDigJQgc2FtZSBib3VuZCB0aGUgb2xkIDIwMDAtZW50cnkgcXVldWUgaGFkLgogICAgaWYgY3Vyc29yIDwgaGVhZCAtIFJJTkcgdGhlbiBjdXJzb3IgPSBoZWFkIC0gUklORyBlbmQKCiAgICBsb2NhbCBzZW50ID0gMAogICAgd2hpbGUgY3Vyc29yIDwgaGVhZCBhbmQgc2VudCA8IDEwMCBkbwogICAgICAgIGxvY2FsIG5leHRfc2VxID0gY3Vyc29yICsgMQogICAgICAgIGxvY2FsIGVudHJ5ID0gc2g6Z2V0KHNsb3Rfa2V5KG5leHRfc2VxKSkKICAgICAgICBpZiBlbnRyeSB0aGVuCiAgICAgICAgICAgIG5neC5wcmludCgiZXZlbnQ6IHJlcXVlc3RcbmRhdGE6ICIsIGVudHJ5LCAiXG5cbiIpCiAgICAgICAgICAgIHNlbnQgPSBzZW50ICsgMQogICAgICAgICAgICBjdXJzb3IgPSBuZXh0X3NlcQogICAgICAgIGVsc2VpZiBuZXh0X3NlcSA8IGhlYWQgdGhlbgogICAgICAgICAgICAtLSBBIGxhdGVyIHNlcSBhbHJlYWR5IGV4aXN0cywgc28gdGhpcyBjYW4ndCBiZSB0aGUgaW5jcihzZXEp4oaSc2V0KHNsb3QpCiAgICAgICAgICAgIC0tIHdyaXRlIHdpbmRvdzogdGhlIHNsb3QgaXMgZ2VudWluZWx5IGxvc3QgKGV4cGlyZWQgb3Igd3JhcHBlZCkuIFNraXAgaXQuCiAgICAgICAgICAgIGN1cnNvciA9IG5leHRfc2VxCiAgICAgICAgZWxzZQogICAgICAgICAgICAtLSBuZXh0X3NlcSA9PSBoZWFkOiB0aGUgbmV3ZXN0IGVudHJ5J3Mgc2xvdCBtYXkgbm90IGJlIHdyaXR0ZW4geWV0CiAgICAgICAgICAgIC0tICh0aGUgbWljcm9zZWNvbmQgd2luZG93IGJldHdlZW4gaW5jcihzZXEpIGFuZCBzZXQoc2xvdCkpLiBSZXRyeSBpdAogICAgICAgICAgICAtLSBuZXh0IGN5Y2xlIHdpdGhvdXQgYWR2YW5jaW5nLgogICAgICAgICAgICBicmVhawogICAgICAgIGVuZAogICAgZW5kCgogICAgaWYgc2VudCA+IDAgdGhlbgogICAgICAgIGlmIG5vdCBuZ3guZmx1c2godHJ1ZSkgdGhlbiByZXR1cm4gZW5kCiAgICBlbmQKCiAgICBsb2NhbCBub3cgPSBuZ3gubm93KCkKCiAgICAtLSBIZWFydGJlYXQgZXZlcnkgMTVzLiBJdHMgZmx1c2ggaXMgYWxzbyBob3cgYSBkZWFkIGNsaWVudCBpcyBkZXRlY3RlZDogb25jZQogICAgLS0gdGhlIHJlYWRlciAoYSBgZG9ja2VyIGV4ZWMgY3VybGApIGdvZXMgYXdheSBhbmQgaXRzIHNvY2tldCBjbG9zZXMsIHRoaXMKICAgIC0tIGZsdXNoIGZhaWxzIGFuZCB0aGUgY29ubmVjdGlvbiB0ZWFycyBkb3duIGhlcmUuCiAgICBpZiBub3cgLSBsYXN0X2hiID4gMTUgdGhlbgogICAgICAgIG5neC5wcmludCgiOiBwaW5nXG5cbiIpCiAgICAgICAgaWYgbm90IG5neC5mbHVzaCh0cnVlKSB0aGVuIHJldHVybiBlbmQKICAgICAgICBsYXN0X2hiID0gbm93CiAgICBlbmQKCiAgICBuZ3guc2xlZXAoMC4wNSkKZW5kCg==",
38
+ "rules_guard.lua": "LS0gcnVsZXNfZ3VhcmQubHVhCi0tIGFjY2Vzc19ieV9sdWEgZHJpdmVyOiBlbmZvcmNlIHBlci1yb3V0ZSBydWxlcyAobWV0aG9kIMK3IElQL0NJRFIgYWxsb3ctZGVueSDCtwotLSBjb3VudHJ5IGFsbG93L2JhbiDCtyBiYWQgdXNlci1hZ2VudCDCtyBob3RsaW5rIMK3IHJhdGUtbGltaXQpIGZvciB0aGUgcmVxdWVzdCdzCi0tIGhvc3QuIFJ1bGVzIGFyZSBwdXNoZWQgcmVsb2FkLWZyZWUgYnkgbWdtdF9hcGkgYFBPU1QgL3J1bGVzYDsgdGhlIERCCi0tIGByb3V0ZV9ydWxlYCB0YWJsZSBpcyB0aGUgc291cmNlIG9mIHRydXRoLiBBbGwgcGFyc2luZy9jb21waWxpbmcvbWF0Y2hpbmcKLS0gbGl2ZXMgaW4ga3JhZnQucnVsZXNfbGliIChsb2FkZWQgT05DRSBwZXIgd29ya2VyKSDigJQgdGhpcyBmaWxlIGlzIHJlLXJ1bgotLSBldmVyeSByZXF1ZXN0IHNvIGl0IHN0YXlzIG1pbmltYWwuIFNlZSBydWxlc19saWIubHVhIGZvciB0aGUgY29tcGlsZWQgc2hhcGUuCi0tCi0tIEVuZm9yY2VtZW50IHVzZXMgdGhlIGNvbm5lY3RpbmcgcGVlciAobmd4LnZhci5yZW1vdGVfYWRkcik7IGZyb250IGEgcmVhbF9pcAotLSBjb25maWcgaWYgYmVoaW5kIGEgdHJ1c3RlZCBwcm94eS4gTm8gdXNlci1zdXBwbGllZCB2YWx1ZSBpcyBldmVyIHVzZWQgYXMgYQotLSBMdWEgcGF0dGVybiBvciB3cml0dGVuIGludG8gYSByZXNwb25zZSBoZWFkZXIuCgpsb2NhbCBydWxlcyA9IG5neC5zaGFyZWQucnVsZXMKaWYgbm90IHJ1bGVzIHRoZW4gcmV0dXJuIGVuZAoKLS0gUmF0ZS1saW1pdCBjb3VudGVycyBsaXZlIGluIHRoZWlyIE9XTiBkaWN0IHNvIGEgaGlnaC1jYXJkaW5hbGl0eSBmbG9vZCAoYSBuZXcKLS0gcmw6IGtleSBwZXIgc291cmNlIElQIHBlciBzZWNvbmQpIGNhbid0IExSVS1ldmljdCB0aGUgcnVsZXNldHMgYW5kIHNpbGVudGx5Ci0tIGRpc2FibGUgZW5mb3JjZW1lbnQuIEZhbGwgYmFjayB0byBgcnVsZXNgIG9uIGEgYm94IHdob3NlIGNvbmZpZyBwcmVkYXRlcyB0aGUKLS0gc2VwYXJhdGUgZGljdCAoc3RpbGwgd29ya3MsIGp1c3Qgc2hhcmVzIHRoZSB6b25lIHVudGlsIHRoZSBuZXh0IHJlbG9hZCkuCmxvY2FsIGNvdW50ZXJzID0gbmd4LnNoYXJlZC5ybF9jb3VudGVycyBvciBydWxlcwoKbG9jYWwgaG9zdCA9IG5neC52YXIuaG9zdAppZiBub3QgaG9zdCB0aGVuIHJldHVybiBlbmQKCmxvY2FsIHJhdyA9IHJ1bGVzOmdldChob3N0KQppZiBub3QgcmF3IHRoZW4gcmV0dXJuIGVuZCAgICAgICAgICAtLSBmYXN0IHBhdGg6IG5vdGhpbmcgY29uZmlndXJlZCBmb3IgdGhpcyBob3N0Cgpsb2NhbCBsaWIgPSByZXF1aXJlICJrcmFmdC5ydWxlc19saWIiCmxvY2FsIGVudHJpZXMgPSBsaWIuZ2V0KGhvc3QsIHJhdykKbG9jYWwgbiA9ICNlbnRyaWVzCmlmIG4gPT0gMCB0aGVuIHJldHVybiBlbmQKCi0tIOKUgOKUgCBMb25nZXN0IG1hdGNoaW5nIHBhdGhQcmVmaXggd2lucyDilIDilIAKbG9jYWwgdXJpID0gbmd4LnZhci51cmkgb3IgIi8iCmxvY2FsIGNob3NlbiwgY2hvc2VuX2xlbiA9IG5pbCwgLTEKZm9yIGkgPSAxLCBuIGRvCiAgICBsb2NhbCBlID0gZW50cmllc1tpXQogICAgbG9jYWwgcCA9IGUucGF0aFByZWZpeAogICAgaWYgcCA9PSBuaWwgb3IgcCA9PSAiIiBvciBwID09ICIvIiB0aGVuCiAgICAgICAgaWYgY2hvc2VuX2xlbiA8IDAgdGhlbiBjaG9zZW4sIGNob3Nlbl9sZW4gPSBlLCAwIGVuZAogICAgZWxzZWlmIHVyaSA9PSBwIG9yIHN0cmluZy5zdWIodXJpLCAxLCAjcCkgPT0gcCB0aGVuCiAgICAgICAgaWYgI3AgPiBjaG9zZW5fbGVuIHRoZW4gY2hvc2VuLCBjaG9zZW5fbGVuID0gZSwgI3AgZW5kCiAgICBlbmQKZW5kCmlmIG5vdCBjaG9zZW4gdGhlbiByZXR1cm4gZW5kCgpsb2NhbCBzcGVjID0gY2hvc2VuLnNwZWMKbG9jYWwgZGVueV9zdGF0dXMgPSBzcGVjLmJsb2NrU3RhdHVzIG9yIDQwMwoKbG9jYWwgaXBzID0gbmd4LnZhci5yZW1vdGVfYWRkciBvciAiMC4wLjAuMCIKbG9jYWwgaXBpID0gbGliLmlwdjRfdG9faW50KGlwcykKCi0tIENvdW50cnkgcmVzb2x2ZWQgYXQgbW9zdCBvbmNlIHBlciByZXF1ZXN0IChvbmx5IHdoZW4gYSBjb3VudHJ5IHJ1bGUgZXhpc3RzKS4KbG9jYWwgY291bnRyeV9jYWNoZQpsb2NhbCBmdW5jdGlvbiBjb3VudHJ5X29mKCkKICAgIGlmIGNvdW50cnlfY2FjaGUgPT0gbmlsIHRoZW4KICAgICAgICBsb2NhbCBvaywgZ2VvID0gcGNhbGwocmVxdWlyZSwgImtyYWZ0Lmdlb19jb3VudHJ5IikKICAgICAgICBjb3VudHJ5X2NhY2hlID0gKG9rIGFuZCBnZW8gYW5kIGdlby5nZXRfY291bnRyeV9jb2RlKGlwcykpIG9yIGZhbHNlCiAgICBlbmQKICAgIHJldHVybiBjb3VudHJ5X2NhY2hlIG9yIG5pbAplbmQKCi0tIOKUgOKUgCAxLiBBY2Nlc3M6IG1ldGhvZCBhbGxvdy1saXN0LCBJUCBhbGxvdy9kZW55LCBjb3VudHJ5IGFsbG93LWxpc3Qg4pSA4pSACmxvY2FsIGFjY2VzcyA9IHNwZWMuYWNjZXNzCmlmIGFjY2VzcyB0aGVuCiAgICBpZiBhY2Nlc3MubWV0aG9kcyBhbmQgbm90IGFjY2Vzcy5tZXRob2RzW25neC5yZXEuZ2V0X21ldGhvZCgpXSB0aGVuCiAgICAgICAgcmV0dXJuIG5neC5leGl0KGRlbnlfc3RhdHVzKQogICAgZW5kCiAgICBpZiBsaWIubWF0Y2hfY29tcGlsZWQoYWNjZXNzLmRlbnksIGlwaSwgaXBzKSB0aGVuIHJldHVybiBuZ3guZXhpdChkZW55X3N0YXR1cykgZW5kCiAgICBpZiBhY2Nlc3MuYWxsb3cgYW5kIG5vdCBsaWIubWF0Y2hfY29tcGlsZWQoYWNjZXNzLmFsbG93LCBpcGksIGlwcykgdGhlbgogICAgICAgIHJldHVybiBuZ3guZXhpdChkZW55X3N0YXR1cykKICAgIGVuZAogICAgLS0gQWxsb3ctbGlzdDogYW4gdW5yZXNvbHZlZCBjb3VudHJ5IGlzIG5vdCBvbiB0aGUgbGlzdCDihpIgYmxvY2tlZCAoZGVmYXVsdC1kZW55KS4KICAgIGlmIGFjY2Vzcy5hbGxvd0NvdW50cmllcyBhbmQgbm90IGFjY2Vzcy5hbGxvd0NvdW50cmllc1tjb3VudHJ5X29mKCkgb3IgIiJdIHRoZW4KICAgICAgICByZXR1cm4gbmd4LmV4aXQoZGVueV9zdGF0dXMpCiAgICBlbmQKZW5kCgotLSDilIDilIAgMi4gQmFuOiBJUC9DSURSLCBjb3VudHJ5LCB1c2VyLWFnZW50IOKUgOKUgApsb2NhbCBiYW4gPSBzcGVjLmJhbgppZiBiYW4gdGhlbgogICAgaWYgbGliLm1hdGNoX2NvbXBpbGVkKGJhbi5pcHMsIGlwaSwgaXBzKSBvciBsaWIubWF0Y2hfY29tcGlsZWQoYmFuLmNpZHJzLCBpcGksIGlwcykgdGhlbgogICAgICAgIHJldHVybiBuZ3guZXhpdChkZW55X3N0YXR1cykKICAgIGVuZAogICAgaWYgYmFuLmNvdW50cmllcyB0aGVuCiAgICAgICAgbG9jYWwgY2MgPSBjb3VudHJ5X29mKCkKICAgICAgICAtLSBGYWlsIENMT1NFRCAobWF0Y2hlcyB0aGUgYWxsb3ctbGlzdCBhYm92ZSk6IGlmIGdlbyBpcyB1bmF2YWlsYWJsZSB3ZQogICAgICAgIC0tIGNhbm5vdCBwcm92ZSB0aGUgY2xpZW50IGlzIE5PVCBmcm9tIGEgYmFubmVkIGNvdW50cnksIHNvIGJsb2NrIHJhdGhlcgogICAgICAgIC0tIHRoYW4gc2lsZW50bHkgbGV0dGluZyBiYW5uZWQgdHJhZmZpYyB0aHJvdWdoLiBBIGJsb2NrZWQgaG9zdCBpcyBhIGxvdWQKICAgICAgICAtLSBzaWduYWwgdG8gZml4IGdlbzsgZmFpbC1vcGVuIHdvdWxkIGJlIGEgc2lsZW50IHNlY3VyaXR5IGhvbGUuCiAgICAgICAgaWYgbm90IGNjIHRoZW4KICAgICAgICAgICAgbmd4LmxvZyhuZ3guV0FSTiwgInJ1bGVzX2d1YXJkOiBjb3VudHJ5IGJhbiBhY3RpdmUgYnV0IGdlbyB1bmF2YWlsYWJsZSDigJQgYmxvY2tpbmcgKGZhaWwtY2xvc2VkKSIpCiAgICAgICAgICAgIHJldHVybiBuZ3guZXhpdChkZW55X3N0YXR1cykKICAgICAgICBlbmQKICAgICAgICBpZiBiYW4uY291bnRyaWVzW2NjXSB0aGVuIHJldHVybiBuZ3guZXhpdChkZW55X3N0YXR1cykgZW5kCiAgICBlbmQKICAgIGlmIGJhbi5lbXB0eVVBIG9yIGJhbi51YXMgdGhlbgogICAgICAgIGxvY2FsIHVhID0gbmd4LnZhci5odHRwX3VzZXJfYWdlbnQKICAgICAgICBpZiBiYW4uZW1wdHlVQSBhbmQgKHVhID09IG5pbCBvciB1YSA9PSAiIikgdGhlbiByZXR1cm4gbmd4LmV4aXQoZGVueV9zdGF0dXMpIGVuZAogICAgICAgIGlmIGJhbi51YXMgYW5kIHVhIGFuZCB1YSB+PSAiIiB0aGVuCiAgICAgICAgICAgIGxvY2FsIHVhbCA9IHN0cmluZy5sb3dlcih1YSkKICAgICAgICAgICAgZm9yIGkgPSAxLCAjYmFuLnVhcyBkbwogICAgICAgICAgICAgICAgaWYgc3RyaW5nLmZpbmQodWFsLCBiYW4udWFzW2ldLCAxLCB0cnVlKSB0aGVuIHJldHVybiBuZ3guZXhpdChkZW55X3N0YXR1cykgZW5kCiAgICAgICAgICAgIGVuZAogICAgICAgIGVuZAogICAgZW5kCmVuZAoKLS0g4pSA4pSAIDMuIEhvdGxpbms6IG9ubHkgbGlzdGVkIHJlZmVyZXIgaG9zdHMgKGVtcHR5IHJlZmVyZXIgcGVyIGFsbG93RW1wdHkpIOKUgOKUgApsb2NhbCBob3QgPSBzcGVjLmhvdGxpbmsKaWYgaG90IHRoZW4KICAgIGxvY2FsIHJlZiA9IG5neC52YXIuaHR0cF9yZWZlcmVyCiAgICBpZiByZWYgPT0gbmlsIG9yIHJlZiA9PSAiIiB0aGVuCiAgICAgICAgaWYgbm90IGhvdC5hbGxvd0VtcHR5IHRoZW4gcmV0dXJuIG5neC5leGl0KGRlbnlfc3RhdHVzKSBlbmQKICAgIGVsc2UKICAgICAgICBsb2NhbCByaG9zdCA9IHN0cmluZy5tYXRjaChyZWYsICJeJXcrOi8vKFteL10rKSIpICAgICAgICAgIC0tIGF1dGhvcml0eQogICAgICAgIGlmIHJob3N0IHRoZW4gcmhvc3QgPSBzdHJpbmcubG93ZXIoc3RyaW5nLm1hdGNoKHJob3N0LCAiXihbXjpdKykiKSBvciByaG9zdCkgZW5kIC0tIHN0cmlwIDpwb3J0CiAgICAgICAgaWYgbm90IChyaG9zdCBhbmQgaG90LnJlZmVyZXJzW3Job3N0XSkgdGhlbiByZXR1cm4gbmd4LmV4aXQoZGVueV9zdGF0dXMpIGVuZAogICAgZW5kCmVuZAoKLS0g4pSA4pSAIDQuIFJhdGUgbGltaXQg4oCUIGZpeGVkIDFzIHdpbmRvdyBwZXIgKGhvc3QsIHBhdGgsIGlwKSDilIDilIAKbG9jYWwgcmwgPSBzcGVjLnJsCmlmIHJsIHRoZW4KICAgIGxvY2FsIGtleSA9ICJybDoiIC4uIGhvc3QgLi4gIjoiIC4uIChjaG9zZW4ucGF0aFByZWZpeCBvciAiLyIpIC4uICI6IiAuLiBpcHMKICAgICAgICAuLiAiOiIgLi4gbWF0aC5mbG9vcihuZ3gubm93KCkpCiAgICBsb2NhbCBjID0gY291bnRlcnM6aW5jcihrZXksIDEsIDAsIDIpICAtLSBpbml0IDAsIDJzIFRUTCDihpIgc2VsZi1leHBpcmluZyBidWNrZXRzCiAgICBpZiBjIGFuZCBjID4gcmwubGltaXQgdGhlbgogICAgICAgIG5neC5oZWFkZXJbIlJldHJ5LUFmdGVyIl0gPSAiMSIKICAgICAgICByZXR1cm4gbmd4LmV4aXQocmwuc3RhdHVzKQogICAgZW5kCmVuZAo=",
39
+ "rules_lib.lua": "LS0gcnVsZXNfbGliLmx1YQotLSBQZXItd29ya2VyIGhlbHBlcnMgKyBwYXJzZWQtcnVsZSBjYWNoZSBmb3IgcnVsZXNfZ3VhcmQubHVhIChhY2Nlc3MgcGhhc2UpLgotLSBMb2FkZWQgT05DRSBwZXIgd29ya2VyIHZpYSByZXF1aXJlKCJrcmFmdC5ydWxlc19saWIiKS4gVGhlIGFjY2VzcyBmaWxlIGlzCi0tIHJlLWV4ZWN1dGVkIG9uIGV2ZXJ5IHJlcXVlc3QsIHNvIGFsbCBwYXJzaW5nL2NvbXBpbGluZy9tYXRjaGluZyBsaXZlcyBoZXJlIHRvCi0tIGF2b2lkIHJlLWNyZWF0aW5nIGNsb3N1cmVzIGFuZCByZS1kZWNvZGluZyBKU09OIG9uIHRoZSBob3QgcGF0aC4KLS0KLS0gU2hhcmVkLWRpY3QgdmFsdWUgYHJ1bGVzW2hvc3RdYCA9IEpTT04gYXJyYXkgb2YgeyBwYXRoUHJlZml4LCBzcGVjIH0gd2hlcmUKLS0gc3BlYyBtYXRjaGVzIEByZXBvL2NvcmUgUm91dGVSdWxlU3BlYy4gcGFyc2UoKSBkZWNvZGVzICsgcHJlY29tcGlsZXMgQ0lEUnMgdG8KLS0gaW50ZWdlcnMsIGxvd2VyY2FzZXMgVUEvcmVmZXJlciBuZWVkbGVzLCBhbmQgYnVpbGRzIE8oMSkgc2V0cyBmb3IKLS0gY291bnRyaWVzL21ldGhvZHMgT05DRTsgdGhlIGNvbXBpbGVkIHJlc3VsdCBpcyBMUlUtY2FjaGVkIHBlciBob3N0IGFuZCByZXVzZWQKLS0gdW50aWwgdGhlIHJhdyBzdHJpbmcgY2hhbmdlcyAocnVsZSBlZGl0cyBhcmUgcmFyZSwgcmVxdWVzdHMgYXJlIGhvdCkuCi0tCi0tIFNFQ1VSSVRZOiBub3RoaW5nIGhlcmUgdHVybnMgYSBydWxlIHZhbHVlIGludG8gTHVhIGNvZGUgb3IgYSBMdWEgcGF0dGVybi4KLS0gU3RyaW5ncyBhcmUgY29tcGFyZWQgd2l0aCBgPT1gL3NldC1sb29rdXBzOyB1c2VyLWFnZW50IG1hdGNoaW5nIGlzCi0tIHN0cmluZy5maW5kKGhheSwgbmVlZGxlLCAxLCB0cnVlKSDigJQgUExBSU4sIG5ldmVyIGEgcmVnZXguCgpsb2NhbCBjanNvbiA9IHJlcXVpcmUgImNqc29uLnNhZmUiCmxvY2FsIGxydWNhY2hlID0gcmVxdWlyZSAicmVzdHkubHJ1Y2FjaGUiCgpsb2NhbCBNID0ge30KCmxvY2FsIGNhY2hlID0gbHJ1Y2FjaGUubmV3KDEwMjQpIC0tIGNvbXBpbGVkIHJ1bGVzLCBwZXIgd29ya2VyLCB+MTAyNCBob3N0cwoKLS0g4pSA4pSAIElQdjQgaGVscGVycyDilIDilIAKbG9jYWwgZnVuY3Rpb24gaXB2NF90b19pbnQocykKICAgIGxvY2FsIGEsIGIsIGMsIGQgPSBzdHJpbmcubWF0Y2gocywgIl4oJWQrKSUuKCVkKyklLiglZCspJS4oJWQrKSQiKQogICAgaWYgbm90IGEgdGhlbiByZXR1cm4gbmlsIGVuZAogICAgYSwgYiwgYywgZCA9IHRvbnVtYmVyKGEpLCB0b251bWJlcihiKSwgdG9udW1iZXIoYyksIHRvbnVtYmVyKGQpCiAgICBpZiBhID4gMjU1IG9yIGIgPiAyNTUgb3IgYyA+IDI1NSBvciBkID4gMjU1IHRoZW4gcmV0dXJuIG5pbCBlbmQKICAgIHJldHVybiBhICogMTY3NzcyMTYgKyBiICogNjU1MzYgKyBjICogMjU2ICsgZAplbmQKTS5pcHY0X3RvX2ludCA9IGlwdjRfdG9faW50CgotLSBQcmVjb21waWxlIGEgQ0lEUiAvIGJhcmUtSVAgc3RyaW5nIGludG8gYSBjaGVhcCBtYXRjaCBkZXNjcmlwdG9yLgpsb2NhbCBmdW5jdGlvbiBjb21waWxlX2NpZHIocykKICAgIGxvY2FsIGJhc2UsIGJpdHMgPSBzdHJpbmcubWF0Y2gocywgIl4oW14vXSspLyglZCspJCIpCiAgICBpZiBiYXNlIHRoZW4KICAgICAgICBiaXRzID0gdG9udW1iZXIoYml0cykKICAgICAgICBsb2NhbCBiYXNlaSA9IGlwdjRfdG9faW50KGJhc2UpCiAgICAgICAgaWYgbm90IGJhc2VpIG9yIGJpdHMgPCAwIG9yIGJpdHMgPiAzMiB0aGVuIHJldHVybiB7IGV4YWN0ID0gcyB9IGVuZAogICAgICAgIGlmIGJpdHMgPT0gMCB0aGVuIHJldHVybiB7IGFsbCA9IHRydWUgfSBlbmQKICAgICAgICBsb2NhbCBkaXYgPSAyIF4gKDMyIC0gYml0cykgLS0gY29tcGFyZSB0aGUgdG9wIGBiaXRzYCBiaXRzCiAgICAgICAgcmV0dXJuIHsgbmV0ID0gbWF0aC5mbG9vcihiYXNlaSAvIGRpdiksIGRpdiA9IGRpdiB9CiAgICBlbmQKICAgIGxvY2FsIGkgPSBpcHY0X3RvX2ludChzKQogICAgaWYgaSB0aGVuIHJldHVybiB7IGlwID0gaSB9IGVuZAogICAgcmV0dXJuIHsgZXhhY3QgPSBzIH0gLS0gSVB2NiAvIHVucGFyc2VhYmxlIOKGkiBsaXRlcmFsIHN0cmluZyBjb21wYXJlCmVuZAoKbG9jYWwgZnVuY3Rpb24gY29tcGlsZV9saXN0KGxpc3QpCiAgICBpZiB0eXBlKGxpc3QpIH49ICJ0YWJsZSIgdGhlbiByZXR1cm4gbmlsIGVuZAogICAgbG9jYWwgb3V0LCBuID0ge30sIDAKICAgIGZvciBfLCBzIGluIGlwYWlycyhsaXN0KSBkbwogICAgICAgIGlmIHR5cGUocykgPT0gInN0cmluZyIgYW5kIHMgfj0gIiIgdGhlbgogICAgICAgICAgICBuID0gbiArIDEKICAgICAgICAgICAgb3V0W25dID0gY29tcGlsZV9jaWRyKHMpCiAgICAgICAgZW5kCiAgICBlbmQKICAgIHJldHVybiBuID4gMCBhbmQgb3V0IG9yIG5pbAplbmQKCi0tIE1hdGNoIGEgY2xpZW50IChpbnQgZm9ybSBgaXBpYCwgbWF5IGJlIG5pbCBmb3Igbm9uLUlQdjQ7IHJhdyBgaXBzYCkgYWdhaW5zdCBhCi0tIGNvbXBpbGVkIENJRFIvSVAgbGlzdC4KbG9jYWwgZnVuY3Rpb24gbWF0Y2hfY29tcGlsZWQoY29tcGlsZWQsIGlwaSwgaXBzKQogICAgaWYgbm90IGNvbXBpbGVkIHRoZW4gcmV0dXJuIGZhbHNlIGVuZAogICAgZm9yIGkgPSAxLCAjY29tcGlsZWQgZG8KICAgICAgICBsb2NhbCBjID0gY29tcGlsZWRbaV0KICAgICAgICBpZiBjLmFsbCB0aGVuCiAgICAgICAgICAgIHJldHVybiB0cnVlCiAgICAgICAgZWxzZWlmIGMuaXAgdGhlbgogICAgICAgICAgICBpZiBpcGkgYW5kIGlwaSA9PSBjLmlwIHRoZW4gcmV0dXJuIHRydWUgZW5kCiAgICAgICAgZWxzZWlmIGMubmV0IHRoZW4KICAgICAgICAgICAgaWYgaXBpIGFuZCBtYXRoLmZsb29yKGlwaSAvIGMuZGl2KSA9PSBjLm5ldCB0aGVuIHJldHVybiB0cnVlIGVuZAogICAgICAgIGVsc2VpZiBjLmV4YWN0ID09IGlwcyB0aGVuCiAgICAgICAgICAgIHJldHVybiB0cnVlCiAgICAgICAgZW5kCiAgICBlbmQKICAgIHJldHVybiBmYWxzZQplbmQKTS5tYXRjaF9jb21waWxlZCA9IG1hdGNoX2NvbXBpbGVkCgpsb2NhbCBmdW5jdGlvbiBsb3dlcl9saXN0KGxpc3QpCiAgICBpZiB0eXBlKGxpc3QpIH49ICJ0YWJsZSIgdGhlbiByZXR1cm4gbmlsIGVuZAogICAgbG9jYWwgb3V0LCBuID0ge30sIDAKICAgIGZvciBfLCBzIGluIGlwYWlycyhsaXN0KSBkbwogICAgICAgIGlmIHR5cGUocykgPT0gInN0cmluZyIgYW5kIHMgfj0gIiIgdGhlbgogICAgICAgICAgICBuID0gbiArIDEKICAgICAgICAgICAgb3V0W25dID0gc3RyaW5nLmxvd2VyKHMpCiAgICAgICAgZW5kCiAgICBlbmQKICAgIHJldHVybiBuID4gMCBhbmQgb3V0IG9yIG5pbAplbmQKCi0tIEJ1aWxkIGFuIE8oMSkgbG9va3VwIHNldCBmcm9tIGEgc3RyaW5nIGxpc3QgKG9wdGlvbmFsbHkgbG93ZXJjYXNlZCkuCmxvY2FsIGZ1bmN0aW9uIHRvX3NldChsaXN0LCBsb3dlcikKICAgIGlmIHR5cGUobGlzdCkgfj0gInRhYmxlIiB0aGVuIHJldHVybiBuaWwgZW5kCiAgICBsb2NhbCBzZXQsIGFueSA9IHt9LCBmYWxzZQogICAgZm9yIF8sIHMgaW4gaXBhaXJzKGxpc3QpIGRvCiAgICAgICAgaWYgdHlwZShzKSA9PSAic3RyaW5nIiBhbmQgcyB+PSAiIiB0aGVuCiAgICAgICAgICAgIHNldFtsb3dlciBhbmQgc3RyaW5nLmxvd2VyKHMpIG9yIHNdID0gdHJ1ZQogICAgICAgICAgICBhbnkgPSB0cnVlCiAgICAgICAgZW5kCiAgICBlbmQKICAgIHJldHVybiBhbnkgYW5kIHNldCBvciBuaWwKZW5kCgotLSBDb21waWxlIG9uZSBSb3V0ZVJ1bGVTcGVjIGludG8gYSBmYXN0LW1hdGNoIHNoYXBlLgpsb2NhbCBmdW5jdGlvbiBjb21waWxlX3NwZWMoc3BlYykKICAgIGlmIHR5cGUoc3BlYykgfj0gInRhYmxlIiB0aGVuIHJldHVybiB7IGJsb2NrU3RhdHVzID0gNDAzIH0gZW5kCiAgICBsb2NhbCBvdXQgPSB7fQoKICAgIGxvY2FsIHJsID0gc3BlYy5yYXRlTGltaXQKICAgIGxvY2FsIHJwcyA9IHJsIGFuZCB0b251bWJlcihybC5ycHMpCiAgICBpZiBycHMgYW5kIHJwcyA+IDAgdGhlbgogICAgICAgIG91dC5ybCA9IHsKICAgICAgICAgICAgbGltaXQgPSBtYXRoLmZsb29yKHJwcykgKyBtYXRoLmZsb29yKHRvbnVtYmVyKHJsLmJ1cnN0KSBvciAwKSwKICAgICAgICAgICAgc3RhdHVzID0gdG9udW1iZXIocmwuc3RhdHVzKSBvciA0MjksCiAgICAgICAgfQogICAgZW5kCgogICAgbG9jYWwgYmFuID0gc3BlYy5iYW4KICAgIGlmIHR5cGUoYmFuKSA9PSAidGFibGUiIHRoZW4KICAgICAgICBvdXQuYmFuID0gewogICAgICAgICAgICBpcHMgPSBjb21waWxlX2xpc3QoYmFuLmlwcyksCiAgICAgICAgICAgIGNpZHJzID0gY29tcGlsZV9saXN0KGJhbi5jaWRycyksCiAgICAgICAgICAgIGNvdW50cmllcyA9IHRvX3NldChiYW4uY291bnRyaWVzKSwKICAgICAgICAgICAgdWFzID0gbG93ZXJfbGlzdChiYW4udXNlckFnZW50cyksCiAgICAgICAgICAgIGVtcHR5VUEgPSBiYW4uZW1wdHlVc2VyQWdlbnQgPT0gdHJ1ZSwKICAgICAgICB9CiAgICBlbmQKCiAgICBsb2NhbCBhY2MgPSBzcGVjLmFjY2VzcwogICAgaWYgdHlwZShhY2MpID09ICJ0YWJsZSIgdGhlbgogICAgICAgIG91dC5hY2Nlc3MgPSB7CiAgICAgICAgICAgIGFsbG93ID0gY29tcGlsZV9saXN0KGFjYy5hbGxvd0NpZHJzKSwKICAgICAgICAgICAgZGVueSA9IGNvbXBpbGVfbGlzdChhY2MuZGVueUNpZHJzKSwKICAgICAgICAgICAgYWxsb3dDb3VudHJpZXMgPSB0b19zZXQoYWNjLmFsbG93Q291bnRyaWVzKSwKICAgICAgICAgICAgbWV0aG9kcyA9IHRvX3NldChhY2MubWV0aG9kcyksCiAgICAgICAgfQogICAgZW5kCgogICAgbG9jYWwgaG90ID0gc3BlYy5ob3RsaW5rCiAgICBpZiB0eXBlKGhvdCkgPT0gInRhYmxlIiB0aGVuCiAgICAgICAgbG9jYWwgcmVmcyA9IHRvX3NldChob3QuYWxsb3dSZWZlcmVycywgdHJ1ZSkKICAgICAgICBpZiByZWZzIHRoZW4KICAgICAgICAgICAgb3V0LmhvdGxpbmsgPSB7IHJlZmVyZXJzID0gcmVmcywgYWxsb3dFbXB0eSA9IGhvdC5hbGxvd0VtcHR5IH49IGZhbHNlIH0KICAgICAgICBlbmQKICAgIGVuZAoKICAgIG91dC5ibG9ja1N0YXR1cyA9ICh0eXBlKHNwZWMuYmxvY2spID09ICJ0YWJsZSIgYW5kIHRvbnVtYmVyKHNwZWMuYmxvY2suc3RhdHVzKSkgb3IgNDAzCiAgICByZXR1cm4gb3V0CmVuZAoKbG9jYWwgZnVuY3Rpb24gcGFyc2UocmF3KQogICAgbG9jYWwgZW50cmllcyA9IGNqc29uLmRlY29kZShyYXcpCiAgICBpZiB0eXBlKGVudHJpZXMpIH49ICJ0YWJsZSIgdGhlbiByZXR1cm4ge30gZW5kCiAgICBsb2NhbCBvdXQsIG4gPSB7fSwgMAogICAgZm9yIF8sIGUgaW4gaXBhaXJzKGVudHJpZXMpIGRvCiAgICAgICAgaWYgdHlwZShlKSA9PSAidGFibGUiIHRoZW4KICAgICAgICAgICAgbiA9IG4gKyAxCiAgICAgICAgICAgIG91dFtuXSA9IHsgcGF0aFByZWZpeCA9IGUucGF0aFByZWZpeCwgc3BlYyA9IGNvbXBpbGVfc3BlYyhlLnNwZWMpIH0KICAgICAgICBlbmQKICAgIGVuZAogICAgcmV0dXJuIG91dAplbmQKCi0tIExSVS1jYWNoZWQgcGFyc2U6IHJldXNlIHRoZSBjb21waWxlZCBmb3JtIHVudGlsIHRoZSByYXcgZGljdCBzdHJpbmcgY2hhbmdlcy4KZnVuY3Rpb24gTS5nZXQoaG9zdCwgcmF3KQogICAgbG9jYWwgaGl0ID0gY2FjaGU6Z2V0KGhvc3QpCiAgICBpZiBoaXQgYW5kIGhpdC5yYXcgPT0gcmF3IHRoZW4gcmV0dXJuIGhpdC5wYXJzZWQgZW5kCiAgICBsb2NhbCBwYXJzZWQgPSBwYXJzZShyYXcpCiAgICBjYWNoZTpzZXQoaG9zdCwgeyByYXcgPSByYXcsIHBhcnNlZCA9IHBhcnNlZCB9KQogICAgcmV0dXJuIHBhcnNlZAplbmQKCnJldHVybiBNCg==",
40
+ "site_logger.lua": "LS0gc2l0ZV9sb2dnZXIubHVhCi0tIE9wZW5SZXN0eSBsb2dfYnlfbHVhIC0gcnVucyBBRlRFUiB0aGUgcmVzcG9uc2UgaXMgc2VudC4KLS0gUHVyZSBzaGFyZWQtZGljdCBhbmFseXRpY3MuICBObyBSZWRpcywgbm8gdGltZXJzIGZvciBjb3VudGVycywgbm8gYmF0Y2hpbmcuCi0tIEV2ZXJ5IGluY3IoKSBpcyBhdG9taWMgYWNyb3NzIHdvcmtlcnMuCi0tCi0tIFNoYXJlZCBkaWN0IGtleSBzY2hlbWEgKGFuYWx5dGljcyB6b25lKToKLS0gICBzOntkb21haW59OntlcG9jaF9taW59OnIgICAgICAgIHJlcXVlc3QgY291bnQgICAgICAgICAgICAgICAoVFRMIDI0aCkKLS0gICBzOntkb21haW59OntlcG9jaF9taW59OmkgICAgICAgIGJhbmR3aWR0aCBpbiAgYnl0ZXMgICAgICAgICAoVFRMIDI0aCkKLS0gICBzOntkb21haW59OntlcG9jaF9taW59Om8gICAgICAgIGJhbmR3aWR0aCBvdXQgYnl0ZXMgICAgICAgICAoVFRMIDI0aCkKLS0gICBzOntkb21haW59OntlcG9jaF9taW59OnQgICAgICAgIHJlc3BvbnNlIHRpbWUgc3VtIChzZWNvbmRzKSAoVFRMIDI0aCkKLS0gICBzOntkb21haW59OntlcG9jaF9taW59OnUgICAgICAgIHBhZ2UgKG5vbi1zdGF0aWMpIHJlcXVlc3RzICAoVFRMIDI0aCkKLS0gICBjOntkb21haW59OntlcG9jaF9taW59OntDQ30gICAgIGNvdW50cnkgcGVyIG1pbnV0ZSAgICAgICAgICAoVFRMIDI0aCkKLS0gICB0Ontkb21haW59OnIgLyA6aSAvIDpvICAgICAgICAgIGxpZmV0aW1lIHRvdGFscyAgICAgICAgICAgICAobm8gVFRMKQotLSAgIGQ6e2RvbWFpbn0gICAgICAgICAgICAgICAgICAgICAgZG9tYWluIGluZGV4IG1hcmtlciAgICAgICAgIChubyBUVEwpCi0tCi0tICAgRGFpbHkgcm9sbHVwLCBhbGwgdW5kZXIgb25lIGBnOntkb21haW59OntZWVlZTU1ERH06YCBwcmVmaXggc28gbWdtdF9hcGkncwotLSAgIC9hbmFseXRpY3MvZ2VvIHNlcnZlcyB0aGUgd2hvbGUgZGF5IGluIGEgU0lOR0xFIGRpY3Qgc2NhbjoKLS0gICBnOntkb21haW59OntZWVlZTU1ERH06e0NDfSAgICAgIGNvdW50cnkgaGl0IGNvdW50ICAgICAgICAgICAoVFRMIDQ4aCkKLS0gICBnOntkb21haW59OntZWVlZTU1ERH06diAgICAgICAgIGRpc3RpbmN0IHZpc2l0b3JzICAgICAgICAgICAoVFRMIDQ4aCkKLS0gICBnOntkb21haW59OntZWVlZTU1ERH06cDp7cGF0aH0gIHBhdGggaGl0IGNvdW50ICAgICAgICAgICAgICAoVFRMIDQ4aCkKLS0gICBnOntkb21haW59OntZWVlZTU1ERH06czp7Y29kZX0gIHN0YXR1cy1jb2RlIGNvdW50ICAgICAgICAgICAoVFRMIDQ4aCkKLS0KLS0gU2hhcmVkIGRpY3Qga2V5IHNjaGVtYSAodmlzaXRvcnMgem9uZSk6Ci0tICAgdnNhbHQ6e1lZWVlNTUREfSAgICAgICAgICAgICAgICBwZXItZGF5IGhhc2ggc2FsdCAgICAgICAgICAgKFRUTCA0OGgpCi0tICAgdmQ6e2RvbWFpbn06e1lZWVlNTUREfTp7aGFzaH0gICBkaXN0aW5jdC12aXNpdG9yIG1hcmtlciAgICAgKFRUTCA0OGgpCi0tCi0tIFNoYXJlZCBkaWN0IGtleSBzY2hlbWEgKHJlcXVlc3RfZGF0YSB6b25lKToKLS0gICBybG9nOntkb21haW59OnNlcSAgICAgICAgICAgICAgIG1vbm90b25pYyB3cml0ZSBwb2ludGVyCi0tICAgcmxvZzp7ZG9tYWlufTp7c2xvdH0gICAgICAgICAgICBKU09OIGVudHJ5IChyaW5nIGJ1ZikgICAgICAgKFRUTCAxaCkKLS0KLS0gVGhlIHJpbmcgaXMgQUxTTyB0aGUgbGl2ZSBzb3VyY2U6IHBpcGVfc3RyZWFtLmx1YSdzIFNTRSBlbmRwb2ludCByZWFkcyB0aGVzZQotLSBzbG90cyBieSBhIHBlci1jb25uZWN0aW9uIGN1cnNvciwgc28gdGhlcmUgaXMgbm8gc2VwYXJhdGUgbGl2ZSBxdWV1ZSBvcgotLSBzdWJzY3JpYmVyIGZsYWcg4oCUIGV2ZXJ5IHdhdGNoZXIgc2VlcyB0aGUgZnVsbCBzdHJlYW0gYW5kIHN0ZWFscyBmcm9tIG5vbmUuCi0tCi0tIE5PVEUgb24gYDp1YCDigJQgaXQgY291bnRzIG5vbi1zdGF0aWMgUkVRVUVTVFMsIG5vdCBwZW9wbGUuIEl0IHdhcyBzdXJmYWNlZCBhcwotLSAidW5pcXVlIElQcyIgYWxsIHRoZSB3YXkgdG8gdGhlIGRhc2hib2FyZCwgd2hpY2ggaXQgbmV2ZXIgd2FzLiBSZWFsIGRpc3RpbmN0Ci0tIHZpc2l0b3JzIGFyZSB0aGUgYHZkOmAvYDp2YCBwYWlyIGJlbG93LgoKbG9jYWwgY2pzb24gPSByZXF1aXJlICJjanNvbi5zYWZlIgoKLS0gU0FGRSBMT0FEOiBHZW9JUCBNb2R1bGUgKHBlci13b3JrZXIsIGNhY2hlZCBieSByZXF1aXJlKQpsb2NhbCBnZW9fb2ssIGdlbyA9IHBjYWxsKHJlcXVpcmUsICJrcmFmdC5nZW9fY291bnRyeSIpCmlmIG5vdCBnZW9fb2sgdGhlbgogICAgZ2VvID0gbmlsCiAgICBuZ3gubG9nKG5neC5XQVJOLCAiW3NpdGVfbG9nZ2VyXSBnZW9fY291bnRyeSBtb2R1bGUgbm90IGF2YWlsYWJsZS4gR2VvSVAgZGlzYWJsZWQuIikKZW5kCgpsb2NhbCBhbmFseXRpY3MgICAgPSBuZ3guc2hhcmVkLmFuYWx5dGljcwpsb2NhbCByZXF1ZXN0X2RhdGEgPSBuZ3guc2hhcmVkLnJlcXVlc3RfZGF0YQotLSBQZXItaG9zdCBlZGdlIGNvbmZpZywgcHVzaGVkIGJ5IHRoZSBBUEkgKHNlZSBtZ210X2FwaSdzIC9hbmFseXRpY3MvY29uZmlnKS4KLS0KLS0gVGhlIGBydWxlc2Agem9uZSwgTk9UIGBhbmFseXRpY3NgOiB0aGlzIGhvbGRzIGEgaGFuZGZ1bCBvZiBzbWFsbCBjb25maWcgdmFsdWVzIGFuZCBpcwotLSBuZXZlciB1bmRlciBldmljdGlvbiBwcmVzc3VyZSwgd2hlcmVhcyB0aGUgYW5hbHl0aWNzIHpvbmUgaXMgYSAyNTYgTUIgY2h1cm4gb2YgY291bnRlcnMuCi0tIEFuIGV2aWN0ZWQgZmxhZyB0aGVyZSB3b3VsZCBzaWxlbnRseSBzdG9wIHBhdGggY29sbGVjdGlvbiB3aXRoIG5vdGhpbmcgdG8gZXhwbGFpbiB3aHkuCmxvY2FsIHJ1bGVzX2RpY3QgICA9IG5neC5zaGFyZWQucnVsZXMKLS0gT3B0aW9uYWw6IGEgYm94IHdob3NlIG5naW54LmNvbmYgcHJlZGF0ZXMgdGhpcyB6b25lIGtlZXBzIHdvcmtpbmcsIGp1c3Qgd2l0aG91dAotLSBkaXN0aW5jdC12aXNpdG9yIGNvdW50cy4gTmV2ZXIgYXNzdW1lIGEgZGljdCBleGlzdHMuCmxvY2FsIHZpc2l0b3JzICAgICA9IG5neC5zaGFyZWQudmlzaXRvcnMKaWYgbm90IGFuYWx5dGljcyBvciBub3QgcmVxdWVzdF9kYXRhIHRoZW4gcmV0dXJuIGVuZAoKLS0g4pSA4pSAIEhlbHBlcnMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACgpsb2NhbCBmdW5jdGlvbiBub3JtYWxpemUoaG9zdCkKICAgIGlmIG5vdCBob3N0IHRoZW4gcmV0dXJuIG5pbCBlbmQKICAgIGxvY2FsIGggPSBob3N0Omxvd2VyKCkKICAgIGlmIGg6c3ViKDEsIDQpID09ICJ3d3cuIiB0aGVuIGggPSBoOnN1Yig1KSBlbmQKICAgIHJldHVybiBoCmVuZAoKbG9jYWwgX2RheSA9IHsgc3RyID0gIiIsIHRzID0gMCB9CmxvY2FsIGZ1bmN0aW9uIHRvZGF5KCkKICAgIGxvY2FsIG5vdyA9IG5neC5ub3coKQogICAgaWYgbm93IC0gX2RheS50cyA+IDYwIHRoZW4KICAgICAgICBfZGF5LnN0ciA9IG9zLmRhdGUoIiElWSVtJWQiLCBub3cpCiAgICAgICAgX2RheS50cyA9IG5vdwogICAgZW5kCiAgICByZXR1cm4gX2RheS5zdHIKZW5kCgotLSBGYXN0IGNoZWNrIGlmIFVSSSBpcyBhIHN0YXRpYyBhc3NldCAoZm9yIHVuaXF1ZV9yZXF1ZXN0cyBjb3VudGVyKQpsb2NhbCBmdW5jdGlvbiBpc19zdGF0aWNfYXNzZXQodSkKICAgIGxvY2FsIGxvd2VyID0gdTpsb3dlcigpCgogICAgLS0gU3RhdGljIGZpbGUgZXh0ZW5zaW9ucwogICAgaWYgbG93ZXI6bWF0Y2goIiUuanMkIikgb3IgbG93ZXI6bWF0Y2goIiUuY3NzJCIpIG9yCiAgICAgICBsb3dlcjptYXRjaCgiJS5qcGckIikgb3IgbG93ZXI6bWF0Y2goIiUuanBlZyQiKSBvcgogICAgICAgbG93ZXI6bWF0Y2goIiUucG5nJCIpIG9yIGxvd2VyOm1hdGNoKCIlLmdpZiQiKSBvcgogICAgICAgbG93ZXI6bWF0Y2goIiUuc3ZnJCIpIG9yIGxvd2VyOm1hdGNoKCIlLndlYnAkIikgb3IKICAgICAgIGxvd2VyOm1hdGNoKCIlLmljbyQiKSBvciBsb3dlcjptYXRjaCgiJS5ibXAkIikgb3IKICAgICAgIGxvd2VyOm1hdGNoKCIlLndvZmYyPyQiKSBvciBsb3dlcjptYXRjaCgiJS50dGYkIikgb3IKICAgICAgIGxvd2VyOm1hdGNoKCIlLmVvdCQiKSBvciBsb3dlcjptYXRjaCgiJS5vdGYkIikgb3IKICAgICAgIGxvd2VyOm1hdGNoKCIlLm1wNCQiKSBvciBsb3dlcjptYXRjaCgiJS53ZWJtJCIpIG9yCiAgICAgICBsb3dlcjptYXRjaCgiJS5tcDMkIikgb3IgbG93ZXI6bWF0Y2goIiUud2F2JCIpIG9yCiAgICAgICBsb3dlcjptYXRjaCgiJS5wZGYkIikgb3IgbG93ZXI6bWF0Y2goIiUuemlwJCIpIG9yCiAgICAgICBsb3dlcjptYXRjaCgiJS50YXIkIikgb3IgbG93ZXI6bWF0Y2goIiUuZ3okIikgb3IKICAgICAgIGxvd2VyOm1hdGNoKCIlLnhtbCQiKSBvciBsb3dlcjptYXRjaCgiJS5qc29uJCIpIG9yCiAgICAgICBsb3dlcjptYXRjaCgiJS50eHQkIikgb3IgbG93ZXI6bWF0Y2goIiUubWFwJCIpIHRoZW4KICAgICAgICByZXR1cm4gdHJ1ZQogICAgZW5kCgogICAgLS0gQ29tbW9uIHN0YXRpYyBwYXRocwogICAgaWYgbG93ZXI6bWF0Y2goIl4vX25leHQvc3RhdGljLyIpIG9yCiAgICAgICBsb3dlcjptYXRjaCgiXi9zdGF0aWMvIikgb3IKICAgICAgIGxvd2VyOm1hdGNoKCJeL2Fzc2V0cy8iKSBvcgogICAgICAgbG93ZXI6bWF0Y2goIl4vcHVibGljLyIpIG9yCiAgICAgICBsb3dlcjptYXRjaCgiL2Zhdmljb24lLmljbyIpIHRoZW4KICAgICAgICByZXR1cm4gdHJ1ZQogICAgZW5kCgogICAgcmV0dXJuIGZhbHNlCmVuZAoKLS0gQ29sbGFwc2UgYSByZXF1ZXN0IFVSSSBpbnRvIGEgbG93LWNhcmRpbmFsaXR5IGJ1Y2tldCBzdWl0YWJsZSBhcyBhIGRpY3Qga2V5LgotLSBXaXRob3V0IHRoaXMsICJ0b3AgcGF0aHMiIGlzIHVuYm91bmRlZDogZXZlcnkgP3Rva2VuPSwgZXZlcnkgL29yZGVycy80ODIxOSwgYW5kCi0tIGV2ZXJ5IDQwNCBhIHNjYW5uZXIgcHJvYmVzIG1pbnRzIGEgcGVybWFuZW50IGtleSwgYW5kIHRoZSBhbmFseXRpY3Mgem9uZQotLSBMUlUtZXZpY3RzIHJlYWwgY291bnRlcnMgdG8gc3RvcmUganVuay4KbG9jYWwgZnVuY3Rpb24gbm9ybWFsaXplX3BhdGgodSkKICAgIC0tIFF1ZXJ5IHN0cmluZyBjYXJyaWVzIGlkcy90b2tlbnMgYW5kIG5ldmVyIGlkZW50aWZpZXMgdGhlIHJvdXRlLgogICAgbG9jYWwgcGF0aCA9IHU6bWF0Y2goIl4oW14/I10qKSIpIG9yIHUKICAgIGlmIHBhdGggPT0gIiIgdGhlbiByZXR1cm4gIi8iIGVuZAogICAgLS0gTnVtZXJpYyBhbmQgVVVJRC9oZXggc2VnbWVudHMgYXJlIGlkcywgbm90IHJvdXRlczogL29yZGVycy80ODIxOSBhbmQKICAgIC0tIC9vcmRlcnMvNDgyMjAgYXJlIG9uZSBwYXRoLgogICAgcGF0aCA9IHBhdGg6Z3N1YigiLyVkKyIsICIvOmlkIikKICAgIHBhdGggPSBwYXRoOmdzdWIoIi8leCV4JXgleCV4JXgleCV4JS0/JXgqJS0/JXgqJS0/JXgqJS0/JXgqIiwgIi86aWQiKQogICAgLS0gQm91bmQgdGhlIGtleSBpdHNlbGYg4oCUIGEgbG9uZyBVUkkgbXVzdCBub3QgYmVjb21lIGEgbG9uZyBrZXkuCiAgICBpZiAjcGF0aCA+IDEyMCB0aGVuIHBhdGggPSBwYXRoOnN1YigxLCAxMjApIC4uICLigKYiIGVuZAogICAgcmV0dXJuIHBhdGgKZW5kCgotLSBSYXcgcmVxdWVzdCB0ZWxlbWV0cnkgbXVzdCBuZXZlciByZXRhaW4gY3JlZGVudGlhbHMgZnJvbSBhIFVSTC4gUXVlcnkKLS0gc3RyaW5ncyByb3V0aW5lbHkgY2FycnkgT0F1dGggY29kZXMsIHNpZ25lZCBVUkxzIGFuZCB0b2tlbnMsIHNvIGV4Y2x1ZGUgdGhlbQotLSBjb21wbGV0ZWx5LiBJbnZpdGF0aW9uIGNsYWltIGlkcyBhcmUgYmVhcmVyIGNyZWRlbnRpYWxzIGluIHRoZSBwYXRoIGl0c2VsZjsKLS0gY29sbGFwc2UgdGhvc2UgdHdvIGtub3duIHJvdXRlcyBiZWZvcmUgZWl0aGVyIHRvcC1wYXRoIGFnZ3JlZ2F0aW9uIG9yIHRoZQotLSBvbmUtaG91ciByZXF1ZXN0IHJpbmcgY2FuIG9ic2VydmUgdGhlbS4KbG9jYWwgZnVuY3Rpb24gdGVsZW1ldHJ5X3VyaSh1KQogICAgbG9jYWwgcGF0aCA9IHU6bWF0Y2goIl4oW14/I10qKSIpIG9yICIvIgogICAgaWYgcGF0aCA9PSAiIiB0aGVuIHJldHVybiAiLyIgZW5kCiAgICBpZiBwYXRoOm1hdGNoKCJeL2FjY2VwdCUtaW52aXRlL1teL10rIikgdGhlbgogICAgICAgIHJldHVybiAiL2FjY2VwdC1pbnZpdGUvOnRva2VuIgogICAgZW5kCiAgICBpZiBwYXRoOm1hdGNoKCJeL2FwaS9hdXRoL2ludml0YXRpb24lLXByZXZpZXcvW14vXSsiKSB0aGVuCiAgICAgICAgcmV0dXJuICIvYXBpL2F1dGgvaW52aXRhdGlvbi1wcmV2aWV3Lzp0b2tlbiIKICAgIGVuZAogICAgcmV0dXJuIHBhdGgKZW5kCgotLSDilIDilIAgRW51bWVyYWJsZSBzZXRzLCB3aXRob3V0IGEgem9uZSBzY2FuIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAotLQotLSBSZWFkaW5nIHRoZXNlIGNvdW50ZXJzIGJhY2sgdXNlZCB0byBuZWVkIGtleSBESVNDT1ZFUlksIGFuZCBhIHNoYXJlZCBkaWN0IG9mZmVycyBleGFjdGx5Ci0tIG9uZSBtZWNoYW5pc20gZm9yIHRoYXQ6IGBnZXRfa2V5c2AsIHdoaWNoIHdhbGtzIEVWRVJZIGtleSBpbiB0aGUgem9uZSBob2xkaW5nIGl0cyBsb2NrLgotLSBDb3N0IHNjYWxlZCB3aXRoIGhvdyBtdWNoIHdhcyBpbiB0aGUgMjU2IE1CIHpvbmUsIG5vdCB3aXRoIHdoYXQgd2FzIGJlaW5nIGFza2VkIGZvciwgYW5kCi0tIGl0IHJhbiBvbiB0aGUgbWdtdCBwYXRoIGZvdXIgZGlmZmVyZW50IHdheXMuCi0tCi0tIFNvIGV2ZXJ5IHVuYm91bmRlZCBzZXQgbm93IGNhcnJpZXMgaXRzIG93biBpbmRleDogYSBjb3VudGVyIHBsdXMgbnVtYmVyZWQgc2xvdHMuCi0tCi0tICAgICA8Y291bnRlcj4gICAgICAgIGhvdyBtYW55IGRpc3RpbmN0IG1lbWJlcnMKLS0gICAgIDxwcmVmaXg+PG4+ICAgICAgdGhlIG4tdGggbWVtYmVyCi0tCi0tIEEgcmVhZGVyIHJlYWRzIHRoZSBjb3VudGVyIGFuZCB0aGVuIHJlYWRzIHNsb3RzIDEuLm4uIEJvdW5kZWQgYnkgdGhlIGFuc3dlci4KLS0KLS0gVGhlIHdyaXRlIG9ubHkgaGFwcGVucyBvbiBhIG1lbWJlcidzIEZJUlNUIHNpZ2h0aW5nLCBzbyBzdGVhZHkgc3RhdGUgY29zdHMgbm90aGluZzogdGhlCi0tIG1pbGxpb250aCByZXF1ZXN0IGZyb20gR2VybWFueSB0b2RheSB0YWtlcyB0aGUgcGxhaW4gYGluY3JgIHBhdGggYW5kIHRvdWNoZXMgbm8gaW5kZXguCmxvY2FsIGZ1bmN0aW9uIGluZGV4X2FkZChjb3VudGVyX2tleSwgc2xvdF9wcmVmaXgsIG1lbWJlciwgdHRsKQogICAgbG9jYWwgbiA9IGFuYWx5dGljczppbmNyKGNvdW50ZXJfa2V5LCAxLCAwLCB0dGwpCiAgICBpZiBuIHRoZW4gYW5hbHl0aWNzOnNldChzbG90X3ByZWZpeCAuLiBuLCBtZW1iZXIsIHR0bCkgZW5kCmVuZAoKLS0tIEFkZCAxIHRvIGEgY291bnRlciwgY3JlYXRpbmcgaXQgKHdpdGggVFRMKSBhbmQgaW5kZXhpbmcgaXQgb24gZmlyc3Qgc2lnaHRpbmcuCi0tCi0tIGBpbmNyYCB3aXRoIG5vIGBpbml0YCByZXR1cm5zIG5pbCBmb3IgYW4gYWJzZW50IGtleSwgd2hpY2ggZG91YmxlcyBhcyB0aGUgZXhpc3RlbmNlCi0tIHByb2JlIOKAlCBzbyB0aGUgY29tbW9uIGNhc2UgaXMgT05FIGhhc2ggb3BlcmF0aW9uLiBUVEwgaXMgc2V0IGJ5IHRoZSBjcmVhdGluZyBgc2FmZV9hZGRgCi0tIHJhdGhlciB0aGFuIHBhc3NlZCB0byBgaW5jcmA6IHNoZGljdCByZWplY3RzIGBpbml0X3R0bGAgd2l0aG91dCBgaW5pdGAsIGFuZCB0aGF0IHJhaXNlcyBhCi0tIEx1YSBlcnJvciB3aGljaCBhYm9ydHMgdGhlIHdob2xlIGxvZyBoYW5kbGVyIChpdCBoYXMgc2lsZW50bHkgemVyb2VkIGV2ZXJ5IGNvdW50ZXIgYmVsb3cKLS0gaXQgYmVmb3JlKS4KbG9jYWwgZnVuY3Rpb24gYnVtcF9pbmRleGVkKGtleSwgdHRsLCBjb3VudGVyX2tleSwgc2xvdF9wcmVmaXgsIG1lbWJlcikKICAgIGlmIGFuYWx5dGljczppbmNyKGtleSwgMSkgdGhlbiByZXR1cm4gZW5kCiAgICBpZiBhbmFseXRpY3M6c2FmZV9hZGQoa2V5LCAxLCB0dGwpIHRoZW4KICAgICAgICBpbmRleF9hZGQoY291bnRlcl9rZXksIHNsb3RfcHJlZml4LCBtZW1iZXIsIHR0bCkKICAgIGVsc2UKICAgICAgICAtLSBBbm90aGVyIHdvcmtlciBjcmVhdGVkIGl0IGJldHdlZW4gb3VyIHByb2JlIGFuZCBvdXIgYWRkOyBvdXIgKzEgc3RpbGwgY291bnRzLgogICAgICAgIGFuYWx5dGljczppbmNyKGtleSwgMSkKICAgIGVuZAplbmQKCmxvY2FsIFJJTkcgICA9IDEwMDAKbG9jYWwgRDI0SCAgID0gODY0MDAKbG9jYWwgRDQ4SCAgID0gMTcyODAwCmxvY2FsIEQxSCAgICA9IDM2MDAKCi0tIERpc3RpbmN0IHBhdGhzIHRyYWNrZWQgcGVyIGRvbWFpbiBwZXIgZGF5LiBQYXN0IHRoaXMgdGhlIHRhaWwgZm9sZHMgaW50bwotLSAib3RoZXIiIHJhdGhlciB0aGFuIGdyb3dpbmcgdGhlIHpvbmUg4oCUIGEgVVJMLWZ1enppbmcgYm90IGlzIGNhcHBlZCBhdCBvbmUKLS0gZXh0cmEga2V5LCBub3QgdGhvdXNhbmRzLgpsb2NhbCBQQVRIX0NBUkRJTkFMSVRZX0NBUCA9IDIwMDAKCi0tIOKUgOKUgCBDYXB0dXJlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAoKbG9jYWwgaG9zdCA9IG5vcm1hbGl6ZShuZ3gudmFyLmhvc3QpCmlmIG5vdCBob3N0IHRoZW4gcmV0dXJuIGVuZAoKbG9jYWwgaXAgICAgICA9IG5neC52YXIucmVtb3RlX2FkZHIgICAgb3IgIjAuMC4wLjAiCmxvY2FsIHRzICAgICAgPSBuZ3gubm93KCkKbG9jYWwgdWEgICAgICA9IG5neC52YXIuaHR0cF91c2VyX2FnZW50IG9yICIiCmxvY2FsIHVyaSAgICAgPSB0ZWxlbWV0cnlfdXJpKG5neC52YXIucmVxdWVzdF91cmkgb3IgIi8iKQpsb2NhbCByZXFfbGVuID0gdG9udW1iZXIobmd4LnZhci5yZXF1ZXN0X2xlbmd0aCkgb3IgMApsb2NhbCBieXRlcyAgID0gdG9udW1iZXIobmd4LnZhci5ieXRlc19zZW50KSAgICAgb3IgMApsb2NhbCBydCAgICAgID0gdG9udW1iZXIobmd4LnZhci5yZXF1ZXN0X3RpbWUpICAgb3IgMCAgLS0gc2Vjb25kcyAoZmxvYXQpCmxvY2FsIG1ldGhvZCAgPSBuZ3gudmFyLnJlcXVlc3RfbWV0aG9kIG9yICJHRVQiCmxvY2FsIHN0YXR1cyAgPSBuZ3gudmFyLnN0YXR1cyAgICAgICAgIG9yICIwIgoKLS0gQ2xpZW50IGNvdW50cnksIHJlc29sdmVkIE9OQ0UgcGVyIHJlcXVlc3QuCi0tCi0tIEhvaXN0ZWQgb3V0IG9mIHRoZSBnZW8gYmxvY2sgYmVjYXVzZSBib3RoIHRoZSBkYWlseS9wZXItbWludXRlIHJvbGx1cHMgYW5kIHRoZSByYXcKLS0gcmluZyBidWZmZXIgbmVlZCBpdC4gVGhlIHJpbmcgaXMgdGhlIHNpbmdsZSBzb3VyY2UgZm9yIHRoZSByZXF1ZXN0IGxvZyDigJQgL2xvZ3MvcmVjZW50Ci0tIHJlYWRzIGl0IGRpcmVjdGx5IGFuZCB0aGUgbGl2ZSBTU0Ugc3RyZWFtIChwaXBlX3N0cmVhbS5sdWEpIHJlYWRzIHRoZSBzYW1lIHNsb3RzIGJ5Ci0tIGN1cnNvciDigJQgc28gcmVzb2x2aW5nIHRoZSBjb3VudHJ5IGhlcmUgbWVhbnMgZXZlcnkgcm93IGNhcnJpZXMgaXRzIGZsYWcgbm8gbWF0dGVyCi0tIHdoaWNoIHBhdGggZGVsaXZlcmVkIGl0LiBBbiBlYXJsaWVyIHNwbGl0IChsb29rZWQgdXAgaW4gdGhlIHJvbGx1cCwgYWdhaW4gaW4gYQotLSBzZXBhcmF0ZSBsaXZlIHBpcGUpIGxlZnQgdGhlIHJpbmcgd2l0aCBubyBjb3VudHJ5IGF0IGFsbC4KLS0KLS0gcGNhbGwnZCBiZWNhdXNlIGEgY29ycnVwdCBvciBwYXJ0aWFsbHktd3JpdHRlbiBtbWRiIG1ha2VzIHRoZSBsb29rdXAgcmFpc2UsIGFuZCBhbgotLSBlcnJvciBoZXJlIHdvdWxkIGFib3J0IGV2ZXJ5IGNvdW50ZXIgYmVsb3cgaXQgKHNlZSB0aGUgc2VjdGlvbiBoZWFkZXIpLgpsb2NhbCBjYyA9IG5pbAppZiBnZW8gYW5kIGdlby5nZXRfY291bnRyeV9jb2RlIHRoZW4KICAgIGxvY2FsIG9rX2NjLCByZXMgPSBwY2FsbChnZW8uZ2V0X2NvdW50cnlfY29kZSwgaXApCiAgICBpZiBva19jYyBhbmQgdHlwZShyZXMpID09ICJzdHJpbmciIGFuZCByZXMgfj0gIiIgdGhlbiBjYyA9IHJlcyBlbmQKZW5kCgotLSDilIDilIAgMS4gTWludXRlLWJ1Y2tldCBjb3VudGVycyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCmxvY2FsIG1pbnV0ZSA9IG1hdGguZmxvb3IodHMgLyA2MCkKbG9jYWwgcCA9ICJzOiIgLi4gaG9zdCAuLiAiOiIgLi4gbWludXRlCgphbmFseXRpY3M6aW5jcihwIC4uICI6ciIsIDEsICAgICAgMCwgRDI0SCkKYW5hbHl0aWNzOmluY3IocCAuLiAiOmkiLCByZXFfbGVuLCAwLCBEMjRIKQphbmFseXRpY3M6aW5jcihwIC4uICI6byIsIGJ5dGVzLCAgIDAsIEQyNEgpCgotLSBSZXNwb25zZSB0aW1lIGFzIGZsb2F0IHNlY29uZHMgKG1hdGNoZXMgb3JpZ2luYWwgcHJlY2lzaW9uKQppZiBydCA+IDAgdGhlbgogICAgLS0gc2FmZV9hZGQgaW5pdGlhbGl6ZXMsIGluY3IgYWRkcyAtIGVtdWxhdGUgSElOQ1JCWUZMT0FUIHdpdGggaW50ZWdlciBtaWNyb3MKICAgIGxvY2FsIHJ0X3VzID0gbWF0aC5mbG9vcihydCAqIDEwMDAwMDApCiAgICBhbmFseXRpY3M6aW5jcihwIC4uICI6dCIsIHJ0X3VzLCAwLCBEMjRIKQplbmQKCi0tIFVuaXF1ZSAobm9uLXN0YXRpYykgcmVxdWVzdCBjb3VudGVyCmlmIG5vdCBpc19zdGF0aWNfYXNzZXQodXJpKSB0aGVuCiAgICBhbmFseXRpY3M6aW5jcihwIC4uICI6dSIsIDEsIDAsIEQyNEgpCmVuZAoKLS0g4pSA4pSAIDIuIExpZmV0aW1lIHRvdGFscyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAKCmFuYWx5dGljczppbmNyKCJ0OiIgLi4gaG9zdCAuLiAiOnIiLCAxLCAgICAgICAwKQphbmFseXRpY3M6aW5jcigidDoiIC4uIGhvc3QgLi4gIjppIiwgcmVxX2xlbiwgMCkKYW5hbHl0aWNzOmluY3IoInQ6IiAuLiBob3N0IC4uICI6byIsIGJ5dGVzLCAgIDApCgotLSBEb21haW4gaW5kZXguIGBzYWZlX2FkZGAgcmV0dXJuaW5nIHRydWUgbWVhbnMgdGhpcyBpcyB0aGUgZmlyc3QgcmVxdWVzdCB0aGlzIGJveCBoYXMKLS0gZXZlciBzZWVuIGZvciB0aGUgaG9zdCwgd2hpY2ggaXMgZXhhY3RseSB3aGVuIHRoZSBlbnVtZXJhYmxlIGluZGV4IG5lZWRzIGFwcGVuZGluZyDigJQKLS0gc28gZG9tYWluIGRpc2NvdmVyeSBubyBsb25nZXIgY29zdHMgYSB6b25lIHNjYW4gZWl0aGVyLgppZiBhbmFseXRpY3M6c2FmZV9hZGQoImQ6IiAuLiBob3N0LCAxKSB0aGVuCiAgICBpbmRleF9hZGQoImRuIiwgImRpOiIsIGhvc3QpCmVuZAoKLS0g4pSA4pSAIDMuIERhaWx5IHJvbGx1cDogZ2VvLCB2aXNpdG9ycywgcGF0aHMsIHN0YXR1c2VzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAotLQotLSBFYWNoIHN1Yi1ibG9jayBpcyBwY2FsbCdkIFNFUEFSQVRFTFksIGFuZCB0aGF0IGlzIGxvYWQtYmVhcmluZyByYXRoZXIgdGhhbgotLSBkZWZlbnNpdmUgaGFiaXQuIEEgcmFpc2VkIGVycm9yIGluIGxvZ19ieV9sdWEgYWJvcnRzIHRoZSByZW1haW5kZXIgb2YgdGhlCi0tIGhhbmRsZXIsIHNvIG9uZSBiYWQgc2hkaWN0IGNhbGwgc2lsZW50bHkgemVyb2VzIGV2ZXJ5IGNvdW50ZXIgd3JpdHRlbiBhZnRlciBpdCDigJQKLS0gd2hpY2ggaXMgZXhhY3RseSB3aGF0IGFuIGBpbmNyKC4uLiwgbmlsLCB0dGwpYCBoZXJlIGRpZDogcGF0aHMgQU5EIHN0YXR1c2VzIHJlYWQKLS0gYXMgIm5vIHRyYWZmaWMiIHdoaWxlIHJlcXVlc3RzIGFuZCBiYW5kd2lkdGggbG9va2VkIHBlcmZlY3QuIElzb2xhdGluZyB0aGVtCi0tIG1lYW5zIGEgZnV0dXJlIGVkaXQgY2FuIGxvc2UgYXQgbW9zdCBpdHMgb3duIG1ldHJpYy4KCmxvY2FsIGRheSAgPSB0b2RheSgpCmxvY2FsIGdwZnggPSAiZzoiIC4uIGhvc3QgLi4gIjoiIC4uIGRheSAuLiAiOiIKCi0tIDNhLiBHZW9JUC4gYGNjYCB3YXMgcmVzb2x2ZWQgb25jZSBhYm92ZSBhbmQgaXMgcmV1c2VkIGJ5IHRoZSByaW5nIGJ1ZmZlciBhbmQgdGhlCi0tIGxpdmUgcGlwZSwgc28gYSByZXF1ZXN0IGNvc3RzIGV4YWN0bHkgb25lIG1tZGIgbG9va3VwIG5vIG1hdHRlciBob3cgbWFueSBjb25zdW1lcnMKLS0gcmVwb3J0IGl0cyBjb3VudHJ5LgppZiBjYyB0aGVuCiAgICBwY2FsbChmdW5jdGlvbigpCiAgICAgICAgLS0gRGFpbHkgZ2VvIChmb3IgL2FuYWx5dGljcy9nZW8gZW5kcG9pbnQpCiAgICAgICAgYnVtcF9pbmRleGVkKGdwZnggLi4gY2MsIEQ0OEgsIGdwZnggLi4gImNuIiwgZ3BmeCAuLiAiY2k6IiwgY2MpCiAgICAgICAgLS0gUGVyLW1pbnV0ZSBnZW8gKGZvciB0aGUgdGltZS1zZXJpZXMgY291bnRyeSBicmVha2Rvd24pLiBJbmRleGVkIHBlciBNSU5VVEUsIHNvCiAgICAgICAgLS0gdGhlIHNjcmFwZXIgcmVhZHMgb25seSB0aGUgbWludXRlcyBpbiBpdHMgd2luZG93LgogICAgICAgIGxvY2FsIG1wZnggPSAiYzoiIC4uIGhvc3QgLi4gIjoiIC4uIG1pbnV0ZSAuLiAiOiIKICAgICAgICBidW1wX2luZGV4ZWQobXBmeCAuLiBjYywgRDI0SCwgbXBmeCAuLiAibiIsIG1wZnggLi4gImk6IiwgY2MpCiAgICBlbmQpCmVuZAoKLS0gM2IuIERpc3RpbmN0IHZpc2l0b3JzIOKAlCBhIENPVU5ULCBuZXZlciBhbiBpZGVudGl0eS4KLS0KLS0gVGhlIGFkZHJlc3MgaXMgaGFzaGVkIHdpdGggYSBzYWx0IHRoYXQgaXMgZ2VuZXJhdGVkIG9uIHRoaXMgYm94LCByb3RhdGVzIGRhaWx5LAotLSBhbmQgaXMgbmV2ZXIgd3JpdHRlbiBhbnl3aGVyZSBidXQgdGhpcyBzaGFyZWQgZGljdCwgc28gdGhlIG1hcmtlciBrZXlzIGFyZSBub3QKLS0gcmV2ZXJzaWJsZSB0byBhbiBJUCBhbmQgYXJlIHdvcnRobGVzcyB0aGUgbmV4dCBkYXkuIE9ubHkgdGhlIHJlc3VsdGluZyBjb3VudGVyCi0tIGlzIGV2ZXIgZmx1c2hlZCB0byBQb3N0Z3Jlczsgbm8gcGVyLXZpc2l0b3Igcm93IGV4aXN0cyBhdCBhbnkgbGF5ZXIuIFRoYXQgaXMKLS0gd2hhdCBsZXRzIHVzIHJlcG9ydCByZWFsIHZpc2l0b3IgbnVtYmVycyB3aGlsZSBzdGlsbCBub3QgY29sbGVjdGluZyBiZWhhdmlvdXJhbAotLSBhbmFseXRpY3Mgb24gYW55b25lJ3MgZW5kIHVzZXJzLgotLQotLSBQZXIgREFZLCBub3QgcGVyIG1pbnV0ZTogYSBwZXItbWludXRlIHNldCBpcyB+MTQ0MHggdGhlIGtleXMgZm9yIGEgbnVtYmVyCi0tIG5vYm9keSByZWFkcywgYW5kIHdvdWxkIGV2aWN0IHRoZSBjb3VudGVycyBpdCBleGlzdHMgdG8gYW5ub3RhdGUuCnBjYWxsKGZ1bmN0aW9uKCkKaWYgdmlzaXRvcnMgdGhlbgogICAgbG9jYWwgc2FsdF9rZXkgPSAidnNhbHQ6IiAuLiBkYXkKICAgIGxvY2FsIHNhbHQgPSB2aXNpdG9yczpnZXQoc2FsdF9rZXkpCiAgICBpZiBub3Qgc2FsdCB0aGVuCiAgICAgICAgLS0gRmlyc3Qgd3JpdGVyIHdpbnM7IGEgcmFjaW5nIHdvcmtlcidzIHNhZmVfYWRkIGZhaWxzIGFuZCBpdCByZS1yZWFkcy4gVGhlCiAgICAgICAgLS0gc2FsdCBvbmx5IGhhcyB0byBiZSB1bnByZWRpY3RhYmxlIGFuZCBzdGFibGUgZm9yIHRoZSBkYXkuCiAgICAgICAgc2FsdCA9IHRvc3RyaW5nKG5neC5ub3coKSkgLi4gdG9zdHJpbmcobWF0aC5yYW5kb20oMSwgMjE0NzQ4MzY0NykpCiAgICAgICAgbG9jYWwgb2sgPSB2aXNpdG9yczpzYWZlX2FkZChzYWx0X2tleSwgc2FsdCwgRDQ4SCkKICAgICAgICBpZiBub3Qgb2sgdGhlbiBzYWx0ID0gdmlzaXRvcnM6Z2V0KHNhbHRfa2V5KSBvciBzYWx0IGVuZAogICAgZW5kCiAgICAtLSBzYWZlX2FkZCBpcyB0aGUgZGVkdXA6IGl0IHN1Y2NlZWRzIE9OTFkgb24gdGhpcyB2aXNpdG9yJ3MgZmlyc3QgcmVxdWVzdAogICAgLS0gdG9kYXksIHNvIHRoZSBjb3VudGVyIGJlbG93IGluY3JlbWVudHMgZXhhY3RseSBvbmNlIHBlciBkaXN0aW5jdCB2aXNpdG9yLgogICAgbG9jYWwgbWFya2VyID0gInZkOiIgLi4gaG9zdCAuLiAiOiIgLi4gZGF5IC4uICI6IiAuLiBuZ3guY3JjMzJfbG9uZyhzYWx0IC4uIGlwKQogICAgaWYgdmlzaXRvcnM6c2FmZV9hZGQobWFya2VyLCAxLCBENDhIKSB0aGVuCiAgICAgICAgYW5hbHl0aWNzOmluY3IoZ3BmeCAuLiAidiIsIDEsIDAsIEQ0OEgpCiAgICBlbmQKZW5kCmVuZCkKCi0tIDNjLiBUb3AgcGF0aHMg4oCUIE9QVC1JTiwgbm9uLXN0YXRpYyBvbmx5LCBub3JtYWxpemVkIGFuZCBjYXJkaW5hbGl0eS1jYXBwZWQuCi0tCi0tIE9mZiB1bmxlc3MgdGhlIHByb2plY3QgdHVybmVkIGl0IG9uLCBiZWNhdXNlIHRoaXMgb25lIGJsb2NrIGlzIHRoZSBtb3N0IGV4cGVuc2l2ZSB0aGluZwotLSB0aGUgbG9nIGhhbmRsZXIgZG9lcy4gTWVhc3VyZWQgb24gdGhlIHNoaXBwZWQgZWRnZSBpbWFnZSwgcGVyIHJlcXVlc3Q6Ci0tCi0tICAgICBwYXRocyAod2hvbGUgYmxvY2spICAgICAgICAxLjcyIHVzICAgICAgPC0gNTclIG9mIHRoZSBjb3VudGVyIHBhdGgKLS0gICAgICAgb2Ygd2hpY2ggc3RyaW5nIHdvcmsgICAgIDEuMzggdXMgICAgICBub3JtYWxpemVfcGF0aCArIGlzX3N0YXRpY19hc3NldAotLSAgICAgbWludXRlIGJ1Y2tldHMgKDUgaW5jcikgICAgMC42MSB1cwotLSAgICAgY291bnRyeSAoMiBpbmNyKSAgICAgICAgICAgMC4yNCB1cwotLSAgICAgc3RhdHVzICgxIGluY3IpICAgICAgICAgICAgMC4xNCB1cwotLSAgICAgdGhpcyBmbGFnIHJlYWQgKDEgZ2V0KSAgICAgMC4wNyB1cwotLQotLSBTbyB0aGUgZ2F0ZSBjb3N0cyAwLjA3IHVzIGFuZCBzYXZlcyAxLjcyIHVzIOKAlCB0aGUgY291bnRlciBwYXRoIGRyb3BzIGZyb20gfjMuMCB1cyB0bwotLSB+MS4zNSB1cyB3aXRoIHBhdGhzIG9mZi4gSXQgaXMgYWxzbyB0aGUgaGlnaGVzdC1jYXJkaW5hbGl0eSBkaW1lbnNpb24gKHVwIHRvCi0tIFBBVEhfQ0FSRElOQUxJVFlfQ0FQIGtleXMgcGVyIGRvbWFpbiBwZXIgZGF5LCBhZ2FpbnN0IH4yMDAgY291bnRyaWVzIGFuZCBhIGZldyBkb3plbgotLSBzdGF0dXNlcykgYW5kIHRoZSBsYXJnZXN0IGNvbHVtbiBpbiB0aGUgZGFpbHkgcm9sbHVwLgotLQotLSBBYnNlbnQgZmxhZyA9IG9mZi4gQSBib3ggd2hvc2UgZGljdCB3YXMganVzdCByZXN0YXJ0ZWQgdGhlcmVmb3JlIGNvbGxlY3RzIG5vdGhpbmcgdW50aWwKLS0gdGhlIEFQSSByZS1wdXNoZXMsIHdoaWNoIGlzIHRoZSBzYWZlIGRpcmVjdGlvbjogbm8gZGF0YSBiZWF0cyBkYXRhIG5vYm9keSBhc2tlZCB0byBwYXkKLS0gZm9yLiBUaGUgREIgaXMgdGhlIHNvdXJjZSBvZiB0cnV0aCBhbmQgcmUtcHVzaGVzIG9uIGV2ZXJ5IHJvdXRlIGFwcGx5Lgpsb2NhbCBjb2xsZWN0X3BhdGhzID0gcnVsZXNfZGljdCBhbmQgcnVsZXNfZGljdDpnZXQoImNmZzoiIC4uIGhvc3QgLi4gIjpwYXRocyIpCgpwY2FsbChmdW5jdGlvbigpCmlmIGNvbGxlY3RfcGF0aHMgYW5kIG5vdCBpc19zdGF0aWNfYXNzZXQodXJpKSB0aGVuCiAgICAtLSBIb2lzdGVkOiBub3JtYWxpemVfcGF0aCBpcyB0aGUgc2luZ2xlIG1vc3QgZXhwZW5zaXZlIGNhbGwgaW4gdGhpcyBoYW5kbGVyICh+MS40IHVzCiAgICAtLSBvZiBzdHJpbmcgd29yayksIHNvIGl0IHJ1bnMgZXhhY3RseSBvbmNlIGV2ZW4gdGhvdWdoIGJvdGggdGhlIGNvdW50ZXIga2V5IGFuZCB0aGUKICAgIC0tIGluZGV4IHNsb3QgbmVlZCBpdHMgcmVzdWx0LgogICAgbG9jYWwgbm9ybSA9IG5vcm1hbGl6ZV9wYXRoKHVyaSkKICAgIGxvY2FsIHBhdGhfa2V5ID0gZ3BmeCAuLiAicDoiIC4uIG5vcm0KICAgIC0tIGluY3ItdGhlbi1hZGQ6IHRoZSBob3QgcGF0aCBpcyBPTkUgaGFzaCBoaXQgb24gYW4gZXhpc3Rpbmcga2V5LiBgaW5jcmAgd2l0aAogICAgLS0gbm8gaW5pdCByZXR1cm5zIG5pbCBmb3IgYW4gYWJzZW50IGtleSwgd2hpY2ggZG91YmxlcyBhcyB0aGUgZXhpc3RlbmNlIHByb2JlLAogICAgLS0gc28gb25seSBhIHBhdGggdW5zZWVuIHRvZGF5IHJlYWNoZXMgdGhlIGNhcCBjaGVjayBiZWxvdy4KICAgIC0tCiAgICAtLSBEZWxpYmVyYXRlbHkgbm8gaW5pdF90dGwgaGVyZTogc2hkaWN0IHJlamVjdHMgaW5pdF90dGwgdW5sZXNzIGluaXQgaXMgYWxzbwogICAgLS0gZ2l2ZW4gKCInaW5pdF90dGwnIG11c3QgYmUgdXNlZCB3aXRoICdpbml0JyIpLCBhbmQgdGhhdCByYWlzZXMgYSBMdWEgZXJyb3IKICAgIC0tIHdoaWNoIGFib3J0cyB0aGUgd2hvbGUgbG9nIGhhbmRsZXIg4oCUIHRha2luZyB0aGUgc3RhdHVzIGNvdW50ZXJzIGJlbG93IGRvd24KICAgIC0tIHdpdGggaXQuIFRoZSBUVEwgaXMgc2V0IGJ5IHRoZSBzYWZlX2FkZCBvbiB0aGUgY3JlYXRpbmcgcmVxdWVzdCBpbnN0ZWFkLgogICAgaWYgbm90IGFuYWx5dGljczppbmNyKHBhdGhfa2V5LCAxKSB0aGVuCiAgICAgICAgbG9jYWwgZGlzdGluY3QgPSBhbmFseXRpY3M6aW5jcihncGZ4IC4uICJwbiIsIDEsIDAsIEQ0OEgpIG9yIDAKICAgICAgICBpZiBkaXN0aW5jdCA+IFBBVEhfQ0FSRElOQUxJVFlfQ0FQIHRoZW4KICAgICAgICAgICAgYW5hbHl0aWNzOmluY3IoZ3BmeCAuLiAicDpvdGhlciIsIDEsIDAsIEQ0OEgpCiAgICAgICAgZWxzZQogICAgICAgICAgICAtLSBgcG5gIHdhcyBhbHJlYWR5IHRoZSBkaXN0aW5jdC1wYXRoIGNvdW50ZXIsIHNvIHRoZSBzbG90cyBqdXN0IGdpdmUgaXQgYW4KICAgICAgICAgICAgLS0gZW51bWVyYWJsZSBzaWRlLiBTdG9yZWQgV0lUSE9VVCB0aGUgInA6IiBwcmVmaXg7IHRoZSByZWFkZXIgYWRkcyBpdCBiYWNrLgogICAgICAgICAgICBpZiBhbmFseXRpY3M6c2FmZV9hZGQocGF0aF9rZXksIDEsIEQ0OEgpIHRoZW4KICAgICAgICAgICAgICAgIGFuYWx5dGljczpzZXQoZ3BmeCAuLiAicGk6IiAuLiBkaXN0aW5jdCwgbm9ybSwgRDQ4SCkKICAgICAgICAgICAgZW5kCiAgICAgICAgZW5kCiAgICBlbmQKZW5kCmVuZCkKCi0tIDNkLiBTdGF0dXMtY29kZSBtaXguIEJvdW5kZWQgYnkgY29uc3RydWN0aW9uIChhIGZldyBkb3plbiBjb2RlcykuCnBjYWxsKGZ1bmN0aW9uKCkKICAgIGJ1bXBfaW5kZXhlZChncGZ4IC4uICJzOiIgLi4gc3RhdHVzLCBENDhILCBncGZ4IC4uICJzbiIsIGdwZnggLi4gInNpOiIsIHN0YXR1cykKZW5kKQoKLS0g4pSA4pSAIDQuIFJhdyByZXF1ZXN0IHJpbmcgYnVmZmVyIChhbHNvIHRoZSBsaXZlIFNTRSBzb3VyY2UpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAotLQotLSBgc2VxYCBpcyBjbGFpbWVkIEJFRk9SRSBlbmNvZGluZyBzbyB0aGUgc3RvcmVkIEpTT04gY2FuIGNhcnJ5IGEgZGV0ZXJtaW5pc3RpYwotLSBpZCAoYHtob3N0fTp7c2VxfWApLiBUaGF0IGlkIGlzIHRoZSBkZWR1cCBrZXkgZXZlcnl3aGVyZSBkb3duc3RyZWFtOiAvbG9ncy9yZWNlbnQKLS0gcmV0dXJucyB0aGVzZSBlbnRyaWVzIHZlcmJhdGltLCBhbmQgcGlwZV9zdHJlYW0ubHVhIHN0cmVhbXMgdGhlIHNhbWUgc2xvdHMgbGl2ZSwKLS0gc28gdGhlIHNhbWUgcmVxdWVzdCByZWFjaGVzIHRoZSBjbGllbnQgd2l0aCBvbmUgc3RhYmxlIGlkIGluc3RlYWQgb2YgYSBmcmVzaAotLSByYW5kb20gb25lIHBlciBzb3VyY2UuIGBpbmNyYCB3aXRoIGluaXQgMCBuZXZlciByZXR1cm5zIG5pbCBoZXJlOyBndWFyZCBhbnl3YXkKLS0gc28gYSBzaGRpY3QgaGljY3VwIGNhbid0IGluZGV4IGEgbmlsIGludG8gdGhlIHNsb3Qga2V5LgoKcGNhbGwoZnVuY3Rpb24oKQogICAgbG9jYWwgc2VxID0gcmVxdWVzdF9kYXRhOmluY3IoInJsb2c6IiAuLiBob3N0IC4uICI6c2VxIiwgMSwgMCkKICAgIGlmIG5vdCBzZXEgdGhlbiByZXR1cm4gZW5kCiAgICBsb2NhbCBva19qLCBqID0gcGNhbGwoY2pzb24uZW5jb2RlLCB7CiAgICAgICAgaWQgICAgID0gaG9zdCAuLiAiOiIgLi4gc2VxLAogICAgICAgIGlwICAgICA9IGlwLAogICAgICAgIC0tIG5pbCBpcyBzaW1wbHkgb21pdHRlZCBieSBjanNvbiwgc28gYSBib3ggd2l0aCBubyBHZW9JUCB3cml0ZXMgdGhlIHNhbWUgc2hhcGUKICAgICAgICAtLSBtaW51cyB0aGlzIGtleSByYXRoZXIgdGhhbiBhIG51bGwgdGhlIHJlYWRlciBoYXMgdG8gc3BlY2lhbC1jYXNlLgogICAgICAgIGNvdW50cnkgPSBjYywKICAgICAgICB0cyAgICAgPSB0cywKICAgICAgICBtZXRob2QgPSBtZXRob2QsCiAgICAgICAgc3RhdHVzID0gc3RhdHVzLAogICAgICAgIHVyaSAgICA9IHVyaSwKICAgICAgICB1YSAgICAgPSB1YSwKICAgICAgICBid19pbiAgPSByZXFfbGVuLAogICAgICAgIGJ3X291dCA9IGJ5dGVzLAogICAgICAgIHJ0ICAgICA9IHJ0LAogICAgfSkKICAgIGlmIG9rX2ogYW5kIGogdGhlbgogICAgICAgIHJlcXVlc3RfZGF0YTpzZXQoInJsb2c6IiAuLiBob3N0IC4uICI6IiAuLiAoc2VxICUgUklORyksIGosIEQxSCkKICAgIGVuZAplbmQpCg==",
41
+ "webhook_handler.lua": "LS0gd2ViaG9va19oYW5kbGVyLmx1YQotLSBIYW5kbGVzIGluY29taW5nIHdlYmhvb2sgZXZlbnRzIGZvcndhcmRlZCBmcm9tIHRoZSBTYWFTIGVkZ2UuCi0tIEludGVybmFsIG1hbmFnZW1lbnQgcG9ydCBvbmx5ICgxMjcuMC4wLjE6OTE0NSkuCi0tCi0tIFJvdXRlczoKLS0gICBQT1NUIC9faG9va3MvcHVzaCAgICAgICAgICAtIHJlY2VpdmUgYSBmb3J3YXJkZWQgR2l0SHViIHB1c2ggZXZlbnQKLS0gICBHRVQgIC9faG9va3MvcGVuZGluZyAgICAgICAtIGZldGNoIHN0b3JlZCBldmVudHMgKGZvciBsb2NhbCBhcHAgcG9sbGluZykKLS0gICBQT1NUIC9faG9va3MvYWNrICAgICAgICAgICAtIGFja25vd2xlZGdlIGNvbnN1bWVkIGV2ZW50cwotLQotLSBCZWhhdmlvciBvbiBQT1NUIC9faG9va3MvcHVzaDoKLS0gICAxLiBUcnkgdG8gcHJveHkgdG8gYSBsb2NhbCBLcmFmdCBBUEkgKGNvbmZpZ3VyYWJsZSB2aWEgWC1LcmFmdC1VcmwgaGVhZGVyKQotLSAgIDIuIElmIEtyYWZ0IGlzIG5vdCByZWFjaGFibGUsIHN0b3JlIHRoZSBldmVudCBpbiBzaGFyZWQgZGljdCBmb3IgbGF0ZXIgcG9sbGluZwoKbG9jYWwgY2pzb24gPSByZXF1aXJlICJjanNvbi5zYWZlIgoKbG9jYWwgd2ViaG9va19ldmVudHMgPSBuZ3guc2hhcmVkLndlYmhvb2tfZXZlbnRzCmxvY2FsIHVyaSAgICAgICAgICAgID0gbmd4LnZhci51cmkKbG9jYWwgbWV0aG9kICAgICAgICAgPSBuZ3gucmVxLmdldF9tZXRob2QoKQoKbG9jYWwgZnVuY3Rpb24ganNvbl9yZXNwb25zZShkYXRhLCBjb2RlKQogICAgbmd4LnN0YXR1cyA9IGNvZGUgb3IgMjAwCiAgICBuZ3guaGVhZGVyWyJDb250ZW50LVR5cGUiXSA9ICJhcHBsaWNhdGlvbi9qc29uIgogICAgbmd4LnNheShjanNvbi5lbmNvZGUoZGF0YSkpCiAgICByZXR1cm4gbmd4LmV4aXQobmd4LnN0YXR1cykKZW5kCgotLSDilIDilIAgUE9TVCAvX2hvb2tzL3B1c2gg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACi0tIFJlY2VpdmVzIGZvcndhcmRlZCB3ZWJob29rIHBheWxvYWQgZnJvbSBTYWFTLgotLSBIZWFkZXJzOgotLSAgIFgtS3JhZnQtVXJsOiBodHRwOi8vMTI3LjAuMC4xOjM0NTYgKGlmIEtyYWZ0IHJ1bnMgb24gdGhpcyBzZXJ2ZXIpCi0tICAgWC1Ib29rLUlkOiB0aGUgc3Vic2NyaXB0aW9uIGhvb2tJZCAoZm9yIGNvcnJlbGF0aW9uKQoKaWYgdXJpID09ICIvX2hvb2tzL3B1c2giIGFuZCBtZXRob2QgPT0gIlBPU1QiIHRoZW4KICAgIG5neC5yZXEucmVhZF9ib2R5KCkKICAgIGxvY2FsIGJvZHkgPSBuZ3gucmVxLmdldF9ib2R5X2RhdGEoKQogICAgaWYgbm90IGJvZHkgdGhlbgogICAgICAgIHJldHVybiBqc29uX3Jlc3BvbnNlKHsgZXJyb3IgPSAiZW1wdHkgYm9keSIgfSwgNDAwKQogICAgZW5kCgogICAgbG9jYWwga3JhZnRfdXJsID0gbmd4LnJlcS5nZXRfaGVhZGVycygpWyJ4LWtyYWZ0LXVybCJdCgogICAgLS0gSWYgS3JhZnQgcnVucyBvbiB0aGlzIHNlcnZlciwgcHJveHkgZGlyZWN0bHkKICAgIGlmIGtyYWZ0X3VybCBhbmQga3JhZnRfdXJsIH49ICIiIHRoZW4KICAgICAgICBsb2NhbCBodHRwID0gcmVxdWlyZSAicmVzdHkuaHR0cCIKICAgICAgICBsb2NhbCBodHRwYyA9IGh0dHAubmV3KCkKICAgICAgICBodHRwYzpzZXRfdGltZW91dCg1MDAwKQoKICAgICAgICBsb2NhbCB0YXJnZXQgPSBrcmFmdF91cmwgLi4gIi9hcGkvd2ViaG9va3MvcHVzaCIKICAgICAgICBsb2NhbCByZXMsIGVyciA9IGh0dHBjOnJlcXVlc3RfdXJpKHRhcmdldCwgewogICAgICAgICAgICBtZXRob2QgID0gIlBPU1QiLAogICAgICAgICAgICBib2R5ICAgID0gYm9keSwKICAgICAgICAgICAgaGVhZGVycyA9IHsKICAgICAgICAgICAgICAgIFsiQ29udGVudC1UeXBlIl0gPSAiYXBwbGljYXRpb24vanNvbiIsCiAgICAgICAgICAgICAgICBbIlgtSG9vay1JZCJdICAgID0gbmd4LnJlcS5nZXRfaGVhZGVycygpWyJ4LWhvb2staWQiXSBvciAiIiwKICAgICAgICAgICAgfSwKICAgICAgICB9KQoKICAgICAgICBpZiByZXMgYW5kIHJlcy5zdGF0dXMgPCA1MDAgdGhlbgogICAgICAgICAgICAtLSBLcmFmdCBoYW5kbGVkIGl0ICgyeHggb3IgNHh4KQogICAgICAgICAgICByZXR1cm4ganNvbl9yZXNwb25zZSh7IG9rID0gdHJ1ZSwgcHJveGllZCA9IHRydWUsIHN0YXR1cyA9IHJlcy5zdGF0dXMgfSkKICAgICAgICBlbmQKCiAgICAgICAgLS0gS3JhZnQgdW5yZWFjaGFibGUgb3IgZXJyb3JlZCAtIGZhbGwgdGhyb3VnaCB0byBzdG9yZQogICAgZW5kCgogICAgLS0gU3RvcmUgZm9yIGxhdGVyIHBvbGxpbmcgYnkgbG9jYWwvZGVza3RvcCBhcHAKICAgIGxvY2FsIGV2ZW50X2lkID0gbmd4Lm5vdygpIC4uICI6IiAuLiBtYXRoLnJhbmRvbSgxMDAwMDAsIDk5OTk5OSkKICAgIGxvY2FsIGV2ZW50ID0gY2pzb24uZW5jb2RlKHsKICAgICAgICBpZCAgICAgICA9IGV2ZW50X2lkLAogICAgICAgIGhvb2tfaWQgID0gbmd4LnJlcS5nZXRfaGVhZGVycygpWyJ4LWhvb2staWQiXSBvciAiIiwKICAgICAgICBwYXlsb2FkICA9IGJvZHksCiAgICAgICAgcmVjZWl2ZWQgPSBuZ3gubm93KCksCiAgICB9KQoKICAgIC0tIFVzZSBhIHNsb3QtYmFzZWQgcmluZyBidWZmZXIgKG1heCAyMDAgZXZlbnRzKQogICAgbG9jYWwgbWF4X2V2ZW50cyA9IDIwMAogICAgbG9jYWwgaWR4ID0gd2ViaG9va19ldmVudHM6aW5jcigiX2lkeCIsIDEsIDApIG9yIDAKICAgIGxvY2FsIHNsb3QgPSAoaWR4ICUgbWF4X2V2ZW50cykKICAgIHdlYmhvb2tfZXZlbnRzOnNldCgiZXZ0OiIgLi4gc2xvdCwgZXZlbnQsIDM2MDApIC0tIDFoIFRUTAogICAgd2ViaG9va19ldmVudHM6c2V0KCJfY291bnQiLCBtYXRoLm1pbihpZHgsIG1heF9ldmVudHMpKQoKICAgIHJldHVybiBqc29uX3Jlc3BvbnNlKHsgb2sgPSB0cnVlLCBzdG9yZWQgPSB0cnVlLCBldmVudF9pZCA9IGV2ZW50X2lkIH0pCmVuZAoKLS0g4pSA4pSAIEdFVCAvX2hvb2tzL3BlbmRpbmcg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACi0tIFJldHVybnMgc3RvcmVkIHdlYmhvb2sgZXZlbnRzIGZvciBsb2NhbCBhcHAgdG8gY29uc3VtZS4KCmlmIHVyaSA9PSAiL19ob29rcy9wZW5kaW5nIiBhbmQgbWV0aG9kID09ICJHRVQiIHRoZW4KICAgIGlmIG5vdCB3ZWJob29rX2V2ZW50cyB0aGVuCiAgICAgICAgcmV0dXJuIGpzb25fcmVzcG9uc2UoeyBldmVudHMgPSB7fSB9KQogICAgZW5kCgogICAgbG9jYWwgY291bnQgPSB3ZWJob29rX2V2ZW50czpnZXQoIl9jb3VudCIpIG9yIDAKICAgIGxvY2FsIGlkeCAgID0gd2ViaG9va19ldmVudHM6Z2V0KCJfaWR4Iikgb3IgMAogICAgbG9jYWwgZXZlbnRzID0ge30KCiAgICAtLSBSZWFkIGFsbCBzdG9yZWQgZXZlbnRzIChuZXdlc3QgZmlyc3QpCiAgICBsb2NhbCBtYXhfZXZlbnRzID0gMjAwCiAgICBsb2NhbCBzdGFydCA9IG1hdGgubWF4KDAsIGlkeCAtIGNvdW50KQogICAgZm9yIGkgPSBzdGFydCwgaWR4IC0gMSBkbwogICAgICAgIGxvY2FsIHNsb3QgPSBpICUgbWF4X2V2ZW50cwogICAgICAgIGxvY2FsIHJhdyA9IHdlYmhvb2tfZXZlbnRzOmdldCgiZXZ0OiIgLi4gc2xvdCkKICAgICAgICBpZiByYXcgdGhlbgogICAgICAgICAgICBsb2NhbCBwYXJzZWQgPSBjanNvbi5kZWNvZGUocmF3KQogICAgICAgICAgICBpZiBwYXJzZWQgdGhlbgogICAgICAgICAgICAgICAgZXZlbnRzWyNldmVudHMgKyAxXSA9IHBhcnNlZAogICAgICAgICAgICBlbmQKICAgICAgICBlbmQKICAgIGVuZAoKICAgIHJldHVybiBqc29uX3Jlc3BvbnNlKHsgZXZlbnRzID0gZXZlbnRzIH0pCmVuZAoKLS0g4pSA4pSAIFBPU1QgL19ob29rcy9hY2sg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACi0tIEFja25vd2xlZGdlIGV2ZW50cyBoYXZlIGJlZW4gY29uc3VtZWQgLSBjbGVhcnMgdGhlIHN0b3JlLgoKaWYgdXJpID09ICIvX2hvb2tzL2FjayIgYW5kIG1ldGhvZCA9PSAiUE9TVCIgdGhlbgogICAgaWYgd2ViaG9va19ldmVudHMgdGhlbgogICAgICAgIHdlYmhvb2tfZXZlbnRzOmZsdXNoX2FsbCgpCiAgICAgICAgd2ViaG9va19ldmVudHM6Zmx1c2hfZXhwaXJlZCgpCiAgICBlbmQKICAgIHJldHVybiBqc29uX3Jlc3BvbnNlKHsgb2sgPSB0cnVlIH0pCmVuZAoKLS0g4pSA4pSAIEZhbGxiYWNrIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgApyZXR1cm4ganNvbl9yZXNwb25zZSh7IGVycm9yID0gIm5vdCBmb3VuZCIgfSwgNDA0KQo="
42
+ };
43
+
44
+ // ../../packages/adapters/src/infra/cloudflare-ips.generated.ts
45
+ var CLOUDFLARE_IPV4 = [
46
+ "173.245.48.0/20",
47
+ "103.21.244.0/22",
48
+ "103.22.200.0/22",
49
+ "103.31.4.0/22",
50
+ "141.101.64.0/18",
51
+ "108.162.192.0/18",
52
+ "190.93.240.0/20",
53
+ "188.114.96.0/20",
54
+ "197.234.240.0/22",
55
+ "198.41.128.0/17",
56
+ "162.158.0.0/15",
57
+ "104.16.0.0/13",
58
+ "104.24.0.0/14",
59
+ "172.64.0.0/13",
60
+ "131.0.72.0/22"
61
+ ];
62
+ var CLOUDFLARE_IPV6 = [
63
+ "2400:cb00::/32",
64
+ "2606:4700::/32",
65
+ "2803:f800::/32",
66
+ "2405:b500::/32",
67
+ "2405:8100::/32",
68
+ "2a06:98c0::/29",
69
+ "2c0f:f248::/32"
70
+ ];
71
+
72
+ // ../../packages/adapters/src/infra/edge-real-ip.ts
73
+ var EDGE_REAL_IP_CONF_NAME = "kraft-real-ip.conf";
74
+ function edgeRealIpHeader() {
75
+ const raw = process.env.KRAFT_EDGE_REAL_IP_HEADER?.trim();
76
+ if (raw && /^[A-Za-z0-9-]{1,64}$/.test(raw)) return raw;
77
+ return "CF-Connecting-IP";
78
+ }
79
+ function edgeTrustedProxies() {
80
+ const raw = process.env.KRAFT_EDGE_TRUSTED_PROXIES?.trim();
81
+ if (!raw) return [];
82
+ const CIDR = /^(?:(?:\d{1,3}\.){3}\d{1,3}|[0-9a-fA-F:]+)(?:\/\d{1,3})?$/;
83
+ return raw.split(/[,\s]+/).map((s) => s.trim()).filter((s) => s.length > 0 && s.length <= 64 && CIDR.test(s));
84
+ }
85
+ function edgeRealIpConf() {
86
+ const header = edgeRealIpHeader();
87
+ const extra = edgeTrustedProxies();
88
+ const lines = [
89
+ "# Kraft \u2014 recover the real client address from a trusted front proxy.",
90
+ "#",
91
+ "# GENERATED. Source: packages/adapters/src/infra/edge-real-ip.ts",
92
+ "#",
93
+ "# Without this, remote_addr is the PROXY on any box behind Cloudflare or a load",
94
+ "# balancer, which silently breaks four things at once: visitor country resolves to",
95
+ "# the PoP, distinct-visitor counts collapse toward the number of PoPs, per-IP rate",
96
+ "# limits put the whole planet behind one PoP in a single bucket, and IP bans ban a",
97
+ "# PoP instead of a visitor.",
98
+ "#",
99
+ "# set_real_ip_from does NOT mean 'trust this header'. It means 'trust this header",
100
+ "# only when the TCP peer is one of these addresses'. Someone hitting the origin",
101
+ "# directly with a forged header is not connecting FROM Cloudflare, so the header is",
102
+ "# ignored and their real address stands. The trust is anchored to who opened the",
103
+ `# socket, which a client cannot forge.`,
104
+ "#",
105
+ `# The header is ${header}.`,
106
+ ...header.toLowerCase() === "cf-connecting-ip" ? [
107
+ "# Cloudflare OVERWRITES CF-Connecting-IP, so its value holds nothing the client",
108
+ "# supplied. It deliberately is NOT X-Forwarded-For: Cloudflare APPENDS to that",
109
+ "# one, so XFF arrives as '<client-controlled>, <real client>' and reading it",
110
+ "# left-to-right would let a visitor choose their own apparent address \u2014 and",
111
+ "# with it their rate-limit bucket and which ban rules miss them."
112
+ ] : [
113
+ "# NOT the default (CF-Connecting-IP) \u2014 set via KRAFT_EDGE_REAL_IP_HEADER.",
114
+ "# If this is X-Forwarded-For, note that proxies APPEND to it, so the header is",
115
+ "# partly client-controlled; real_ip_recursive below is what makes nginx walk it",
116
+ "# from the right and stop at the last untrusted hop, which is the real client."
117
+ ],
118
+ "",
119
+ `real_ip_header ${header};`,
120
+ "",
121
+ "# Walk a multi-hop header from the RIGHT, skipping trusted addresses. Inert for a",
122
+ "# single-value header like CF-Connecting-IP; load-bearing for X-Forwarded-For, where",
123
+ "# the left-hand entries are whatever the client sent.",
124
+ "real_ip_recursive on;",
125
+ "",
126
+ `# Cloudflare's published edge ranges (${CLOUDFLARE_IPV4.length} v4 + ${CLOUDFLARE_IPV6.length} v6).`,
127
+ "# Trusted unconditionally, which is safe by construction: on a box that is not behind",
128
+ "# Cloudflare no peer ever matches, so every line here is inert. Refresh with",
129
+ "# `bun run update:cloudflare-ips`.",
130
+ ...CLOUDFLARE_IPV4.map((c) => `set_real_ip_from ${c};`),
131
+ ...CLOUDFLARE_IPV6.map((c) => `set_real_ip_from ${c};`)
132
+ ];
133
+ if (extra.length > 0) {
134
+ lines.push(
135
+ "",
136
+ "# Operator-declared proxies (KRAFT_EDGE_TRUSTED_PROXIES). Each of these can set",
137
+ "# the header above and be believed, so keep the list to hosts you control.",
138
+ ...extra.map((c) => `set_real_ip_from ${c};`)
139
+ );
140
+ }
141
+ return lines.join("\n") + "\n";
142
+ }
143
+ var CLOUD_EDGE_REAL_IP_HEADER = "X-Real-IP";
144
+ function isCloudFrontedHost(hostname) {
145
+ const host = hostname.trim().toLowerCase().replace(/\.+$/, "");
146
+ const suffix = `.${SYSTEM.DOMAINS.CLOUD_DOMAIN.toLowerCase()}`;
147
+ return host.length > suffix.length && host.endsWith(suffix);
148
+ }
149
+ function cloudEdgeRealIpConf(indent = " ") {
150
+ const lines = [
151
+ "# Kraft Cloud's edge fronts this free host, so the peer is the edge and the",
152
+ "# visitor is named in X-Real-IP (which that front OVERWRITES). The http-scope block",
153
+ "# reads CF-Connecting-IP for Cloudflare-fronted custom domains, and there is one",
154
+ "# real_ip_header per scope \u2014 hence this override.",
155
+ "#",
156
+ "# Trust is scoped to this VHOST instead of to a peer list, deliberately. The Cloud",
157
+ "# edge reaches origins from its own address, which this box has no way to know and",
158
+ "# which Cloudflare's ranges (the visitor\u2192edge leg) do not contain \u2014 so a peer list",
159
+ "# here silently ignores the header and every free-domain visitor stays the edge.",
160
+ "#",
161
+ "# What bounds it is the server_name: this block exists only inside a <slug>.kraft.io",
162
+ "# vhost, a hostname whose only legitimate path is that edge. Someone who reaches this",
163
+ "# box directly on :80 with a forged Host AND a forged X-Real-IP can choose their own",
164
+ "# apparent address for THIS vhost \u2014 accepted, because the alternative is the address",
165
+ "# being wrong for every visitor all the time. Custom domains keep the peer-anchored",
166
+ "# http-scope block; do not widen this to them.",
167
+ `real_ip_header ${CLOUD_EDGE_REAL_IP_HEADER};`,
168
+ // OFF, unlike the http-scope block: the Cloud edge OVERWRITES X-Real-IP with a single
169
+ // address, so there is no list to walk, and "skip trusted addresses from the right"
170
+ // has no meaning once every address is trusted.
171
+ "real_ip_recursive off;",
172
+ "set_real_ip_from 0.0.0.0/0;",
173
+ "set_real_ip_from ::/0;"
174
+ ];
175
+ return lines.map((l) => `${indent}${l}`).join("\n") + "\n";
176
+ }
177
+
178
+ // ../../packages/adapters/src/infra/edge-not-found.ts
179
+ var EDGE_UNROUTED_SENTINEL = "kraft-edge-unrouted";
180
+ var HTML_FRAGMENTS = [
181
+ `<!doctype html>`,
182
+ `<!--${EDGE_UNROUTED_SENTINEL}-->`,
183
+ `<html lang="en">`,
184
+ `<head>`,
185
+ `<meta charset="utf-8">`,
186
+ `<meta name="viewport" content="width=device-width,initial-scale=1">`,
187
+ // An unrouted host must never enter a search index under our page.
188
+ `<meta name="robots" content="noindex,nofollow">`,
189
+ `<title>Service not found</title>`,
190
+ `<style>`,
191
+ // Matches the dashboard's theme: a neutral black-on-white scale, mirrored for
192
+ // dark. No webfont, no image, no external request — the page must render on a
193
+ // box whose only working listener is the one serving it. Colours are `rgb()`,
194
+ // never `#rrggbb`: see the no-`#` invariant in the header.
195
+ `:root{color-scheme:light dark}`,
196
+ `*{box-sizing:border-box}`,
197
+ `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}`,
198
+ `main{width:100%;max-width:32rem;padding:2.5rem 1.5rem;text-align:center}`,
199
+ // The muted scale is .56, not the .4–.52 it started at: black at .52 on white is
200
+ // 4.3:1 and at .4 is 2.9:1, both under WCAG AA's 4.5:1 for text this small, and
201
+ // this is the most-seen page the edge serves. .56 ≈ 4.75:1.
202
+ `.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)}`,
203
+ `.dot{width:6px;height:6px;border-radius:50%;background:rgb(224,169,10)}`,
204
+ `h1{margin:0 0 .5rem;font-size:1.375rem;font-weight:600;letter-spacing:-.01em;color:rgba(0,0,0,.92)}`,
205
+ `p{margin:0 auto 1.5rem;max-width:26rem}`,
206
+ `ul{display:inline-block;margin:0;padding:0;list-style:none;text-align:left;font-size:13.5px;color:rgba(0,0,0,.56)}`,
207
+ `li{position:relative;padding:.2rem 0 .2rem 1rem}`,
208
+ `li::before{content:"";position:absolute;left:0;top:.75em;width:4px;height:4px;border-radius:50%;background:rgba(0,0,0,.25)}`,
209
+ `footer{margin-top:2.25rem;font-size:12px;color:rgba(0,0,0,.56)}`,
210
+ `@media(prefers-color-scheme:dark){`,
211
+ `body{background:rgb(10,10,10);color:rgba(255,255,255,.66)}`,
212
+ `.tag{border-color:rgba(255,255,255,.12);color:rgba(255,255,255,.56)}`,
213
+ `h1{color:rgba(255,255,255,.95)}`,
214
+ `ul{color:rgba(255,255,255,.56)}`,
215
+ `li::before{background:rgba(255,255,255,.28)}`,
216
+ `footer{color:rgba(255,255,255,.56)}`,
217
+ `}`,
218
+ `</style>`,
219
+ `</head>`,
220
+ `<body>`,
221
+ `<main>`,
222
+ `<span class="tag"><span class="dot"></span>404 &middot; no route</span>`,
223
+ `<h1>Service not found</h1>`,
224
+ // "reachable, but nothing is configured" is the whole message: it separates a
225
+ // down app from an address that was never wired up, which is the distinction a
226
+ // raw TLS error or a stock 404 destroys.
227
+ `<p>This server is reachable, but no application is configured for the address you requested.</p>`,
228
+ `<ul>`,
229
+ `<li>Check the address for a typo</li>`,
230
+ `<li>The deployment may have been removed or renamed</li>`,
231
+ `<li>A newly added domain can take a few minutes to start serving</li>`,
232
+ `</ul>`,
233
+ `<footer>Served by Kraft</footer>`,
234
+ `</main>`,
235
+ `</body>`,
236
+ `</html>`
237
+ ];
238
+ var EDGE_NOT_FOUND_HTML = HTML_FRAGMENTS.join("");
239
+ var EDGE_NOT_FOUND_LOCATION = ` server_tokens off;
240
+
241
+ location / {
242
+ types { }
243
+ default_type text/html;
244
+ return 404 '${EDGE_NOT_FOUND_HTML}';
245
+ }`;
246
+
247
+ // ../../packages/adapters/src/infra/openresty-reload.ts
248
+ var NGINX_MASTER_RE = /\b(?:nginx|openresty)\s*:\s*master process/i;
249
+ var NGINX_WORKER_RE = /\b(?:nginx|openresty)\s*:\s*worker process/i;
250
+ var NGINX_PROCESS_RE = /\b(?:nginx|openresty)\b/i;
251
+ async function canonicalRemotePath(executor, path) {
252
+ const resolved = await executor.exec(`readlink -f ${sq(path)} 2>/dev/null || true`, { timeout: 5e3 }).catch(() => "");
253
+ return resolved.trim() || null;
254
+ }
255
+ function explicitNginxConfig(rawCommand) {
256
+ const match = rawCommand.match(
257
+ /(?:^|\s)-c(?:(?:\s+|=)(?:"([^"]+)"|'([^']+)'|(\S+))|(\S+))/
258
+ );
259
+ if (!match) return void 0;
260
+ const value = match[1] ?? match[2] ?? match[3] ?? match[4] ?? "";
261
+ return value.startsWith("/") ? value : null;
262
+ }
263
+ function hasExplicitNginxPrefix(rawCommand) {
264
+ return /(?:^|\s)-p(?:\s+|=|\S)/.test(rawCommand);
265
+ }
266
+ async function processStartTime(executor, pid) {
267
+ const value = await executor.exec(
268
+ `awk '{ line=$0; sub(/^.*\\) /, "", line); split(line, fields, " "); print fields[20] }' /proc/${pid}/stat 2>/dev/null || true`,
269
+ { timeout: 5e3 }
270
+ ).catch(() => "");
271
+ return /^\d+$/.test(value.trim()) ? value.trim() : null;
272
+ }
273
+ async function verifyNginxProcessIdentity(executor, occupant, paths) {
274
+ if (!occupant.pid) return "unknown";
275
+ const rawCommand = occupant.rawCommand?.trim();
276
+ if (!rawCommand || !NGINX_MASTER_RE.test(rawCommand)) return "unknown";
277
+ const [actualExe, expectedExe] = await Promise.all([
278
+ canonicalRemotePath(executor, `/proc/${occupant.pid}/exe`),
279
+ canonicalRemotePath(executor, paths.bin)
280
+ ]);
281
+ if (!actualExe || !expectedExe) return "unknown";
282
+ if (actualExe !== expectedExe) return "foreign";
283
+ if (hasExplicitNginxPrefix(rawCommand)) return "unknown";
284
+ const explicitConfig = explicitNginxConfig(rawCommand);
285
+ if (explicitConfig === null) return "unknown";
286
+ const effectiveConfig = explicitConfig ?? paths.compiledConfPath;
287
+ const [actualConfig, expectedConfig] = await Promise.all([
288
+ canonicalRemotePath(executor, effectiveConfig),
289
+ canonicalRemotePath(executor, paths.confPath)
290
+ ]);
291
+ if (!actualConfig || !expectedConfig || actualConfig !== expectedConfig)
292
+ return "unknown";
293
+ return "match";
294
+ }
295
+ async function resolveListeningNginxMaster(executor, occupant) {
296
+ const description = `${occupant.rawCommand ?? ""} ${occupant.command}`;
297
+ if (!occupant.pid || !NGINX_WORKER_RE.test(description)) return occupant;
298
+ const rawParent = await executor.exec(
299
+ `awk '/^PPid:/{print $2}' /proc/${occupant.pid}/status 2>/dev/null || true`
300
+ ).catch(() => "");
301
+ const parentPid = Number.parseInt(rawParent.trim(), 10);
302
+ if (!Number.isInteger(parentPid) || parentPid <= 1) return occupant;
303
+ const parent = await describeProcess(executor, parentPid).catch(() => null);
304
+ if (!parent) return occupant;
305
+ const parentDescription = `${parent.rawCommand ?? ""} ${parent.command}`;
306
+ return NGINX_MASTER_RE.test(parentDescription) ? parent : occupant;
307
+ }
308
+ async function reloadBareOpenResty(executor, paths, opts = {}) {
309
+ await executor.exec(`${sq(paths.bin)} -t -c ${sq(paths.confPath)} 2>&1`, {
310
+ timeout: 15e3
311
+ });
312
+ const listenerStates = await Promise.all([
313
+ probeListeningPortOwners(executor, 80),
314
+ probeListeningPortOwners(executor, 443)
315
+ ]);
316
+ if (listenerStates.some((state) => !state.checked)) {
317
+ throw new Error(
318
+ "OpenResty config is valid, but the port 80/443 listener probe was inconclusive; refusing to assume the managed daemon is stopped."
319
+ );
320
+ }
321
+ if (listenerStates.some((state) => !state.ownershipComplete)) {
322
+ throw new Error(
323
+ "OpenResty config is valid, but every listener on port 80/443 could not be identified; refusing to signal an unknown or mixed owner."
324
+ );
325
+ }
326
+ const occupants = listenerStates.flatMap((state) => state.occupants);
327
+ const verifiedMasters = /* @__PURE__ */ new Map();
328
+ let foreignListenerOwner = false;
329
+ let ambiguousNginxOwner = false;
330
+ let containerBackedNginxOwner = false;
331
+ for (const occupant of occupants) {
332
+ if (!occupant.rawCommand?.trim()) {
333
+ ambiguousNginxOwner = true;
334
+ continue;
335
+ }
336
+ const description = [
337
+ occupant.rawCommand,
338
+ occupant.command,
339
+ occupant.systemdUnit,
340
+ occupant.systemdDescription
341
+ ].filter(Boolean).join(" ");
342
+ if (!NGINX_PROCESS_RE.test(description)) {
343
+ foreignListenerOwner = true;
344
+ continue;
345
+ }
346
+ if (occupant.containerId) {
347
+ containerBackedNginxOwner = true;
348
+ continue;
349
+ }
350
+ const master = await resolveListeningNginxMaster(executor, occupant);
351
+ if (master.containerId) {
352
+ containerBackedNginxOwner = true;
353
+ continue;
354
+ }
355
+ const initialIdentity = await verifyNginxProcessIdentity(
356
+ executor,
357
+ master,
358
+ paths
359
+ );
360
+ if (initialIdentity === "foreign") {
361
+ foreignListenerOwner = true;
362
+ continue;
363
+ }
364
+ if (initialIdentity === "unknown" || !master.pid) {
365
+ ambiguousNginxOwner = true;
366
+ continue;
367
+ }
368
+ if (master.cgroupVerified !== true || !master.processCgroup) {
369
+ ambiguousNginxOwner = true;
370
+ continue;
371
+ }
372
+ const startTime = await processStartTime(executor, master.pid);
373
+ if (!startTime) {
374
+ ambiguousNginxOwner = true;
375
+ continue;
376
+ }
377
+ const refreshedMaster = await describeProcess(executor, master.pid).catch(
378
+ () => null
379
+ );
380
+ const confirmedStartTime = await processStartTime(executor, master.pid);
381
+ if (!refreshedMaster || confirmedStartTime !== startTime || refreshedMaster.cgroupVerified !== true || !refreshedMaster.processCgroup) {
382
+ ambiguousNginxOwner = true;
383
+ continue;
384
+ }
385
+ if (refreshedMaster.containerId) {
386
+ containerBackedNginxOwner = true;
387
+ continue;
388
+ }
389
+ const identity = await verifyNginxProcessIdentity(
390
+ executor,
391
+ refreshedMaster,
392
+ paths
393
+ );
394
+ if (identity !== "match") {
395
+ ambiguousNginxOwner = true;
396
+ continue;
397
+ }
398
+ verifiedMasters.set(master.pid, {
399
+ pid: master.pid,
400
+ startTime,
401
+ processCgroup: refreshedMaster.processCgroup
402
+ });
403
+ }
404
+ if (containerBackedNginxOwner) {
405
+ throw new Error(
406
+ "A container-backed nginx/OpenResty listener owns port 80/443; refusing to signal it from bare-host reload."
407
+ );
408
+ }
409
+ if (ambiguousNginxOwner) {
410
+ throw new Error(
411
+ "A live nginx/OpenResty listener was found, but its executable and configuration could not be verified, or its host ownership could not be proven; refusing to signal an ambiguous process."
412
+ );
413
+ }
414
+ if (foreignListenerOwner) {
415
+ throw new Error(
416
+ verifiedMasters.size > 0 ? "The managed OpenResty master shares ports 80/443 with a foreign listener; refusing a reload that cannot apply the validated configuration safely." : "A foreign listener owns port 80/443; refusing to treat a live daemon as stopped or report the managed route reload as complete."
417
+ );
418
+ }
419
+ if (verifiedMasters.size === 0) {
420
+ if (opts.allowStopped && occupants.length === 0) return;
421
+ const owners = occupants.map((occupant) => occupant.command).filter(Boolean);
422
+ throw new Error(
423
+ "OpenResty config is valid, but no verified bare-host master is listening on port 80/443" + (owners.length > 0 ? ` (found: ${owners.join(", ")})` : "") + "; refusing to start a second daemon."
424
+ );
425
+ }
426
+ if (verifiedMasters.size !== 1) {
427
+ throw new Error(
428
+ `Found ${verifiedMasters.size} verified nginx/OpenResty masters on ports 80/443; refusing an ambiguous reload.`
429
+ );
430
+ }
431
+ const target = [...verifiedMasters.values()][0];
432
+ await executor.exec(
433
+ `current_exe=$(readlink -f /proc/${target.pid}/exe 2>/dev/null || true); expected_exe=$(readlink -f ${sq(paths.bin)} 2>/dev/null || true); current_start=$(awk '{ line=$0; sub(/^.*\\) /, "", line); split(line, fields, " "); print fields[20] }' /proc/${target.pid}/stat 2>/dev/null || true); current_cgroup=$(cat /proc/${target.pid}/cgroup 2>/dev/null) || { echo "nginx master cgroup became unreadable; refusing reload" >&2; exit 1; }; [ -n "$current_exe" ] && [ "$current_exe" = "$expected_exe" ] && [ "$current_start" = ${sq(target.startTime)} ] && [ -n "$current_cgroup" ] && [ "$current_cgroup" = ${sq(target.processCgroup)} ] || { echo "nginx master identity changed; refusing reload" >&2; exit 1; }; kill -HUP ${target.pid}`,
434
+ { timeout: 5e3 }
435
+ ).catch((err) => {
436
+ throw new Error(
437
+ `Safe bare-host OpenResty reload failed: ${safeErrorMessage(err)}`
438
+ );
439
+ });
440
+ }
441
+
442
+ // ../../packages/adapters/src/infra/openresty-lua.ts
443
+ var OPENRESTY_LUA_DIR = "/usr/local/openresty/site/lualib/kraft";
444
+ var LUA_LOGGER_PATH = `${OPENRESTY_LUA_DIR}/site_logger.lua`;
445
+ var RULES_GUARD_PATH = `${OPENRESTY_LUA_DIR}/rules_guard.lua`;
446
+ var OPENRESTY_MGMT_PORT = 9145;
447
+ var OPENRESTY_SITE_LUALIB = OPENRESTY_LUA_DIR.replace(/\/[^/]+$/, "");
448
+ var EDGE_LUA_PACKAGE_PATH = `${OPENRESTY_SITE_LUALIB}/?.lua;;`;
449
+ var EDGE_SERVER_NAMES_HASH_BUCKET_SIZE = 128;
450
+ var EDGE_CLIENT_MAX_BODY_SIZE = "50m";
451
+ var EDGE_SHARED_DICTS = [
452
+ /** Analytics counters. */
453
+ { name: "analytics", size: "256m" },
454
+ /** Raw-log ring buffers + the live-log pipe. */
455
+ { name: "request_data", size: "128m" },
456
+ /** Per-route rules cache: written reload-free by mgmt_api `POST /rules`, read
457
+ * by rules_guard.lua in the access phase. The DB (route_rule) is the source
458
+ * of truth, so losing this dict costs a re-push, not a ruleset. */
459
+ { name: "rules", size: "32m" },
460
+ /** Rate-limit COUNTERS, kept apart from `rules` so a high-cardinality flood (a
461
+ * fresh key per source IP per second) can't LRU-evict the rulesets and
462
+ * silently disable enforcement mid-attack.
463
+ *
464
+ * 32m, matching openresty module migration 1.1.0, which raises it from the
465
+ * original 16m on boxes already installed. Both must state the same target: a
466
+ * fresh install writes THIS value, so leaving it at 16m meant a new box got the
467
+ * size the migration exists to correct — and only bare boxes that consented to
468
+ * the migration would ever reach 32m. The migration stays because the
469
+ * `grep || sed` convergence below is append-only and cannot resize an existing
470
+ * directive; `edge-shared-dicts.test.ts` pins the two together. */
471
+ { name: "rl_counters", size: "32m" },
472
+ /**
473
+ * Distinct-visitor sets. One key per (domain, day, salted-IP hash) — high
474
+ * cardinality and short-lived, so it gets its own zone for the same reason
475
+ * `rl_counters` does: a busy day's visitor set must not LRU-evict the analytics
476
+ * counters or the rulesets.
477
+ *
478
+ * Privacy: keys hold a per-day-salted hash, never an address, and only the
479
+ * resulting COUNT is ever flushed to Postgres. Nothing that identifies a visitor
480
+ * leaves the box — see the visitor block in site_logger.lua.
481
+ *
482
+ * 64m ≈ 1M distinct visitors/day. Past that the zone LRU-evicts and the count
483
+ * UNDERSTATES; `GET /status` reports free_space so a reader can mark it
484
+ * approximate rather than present an eviction artifact as a measurement.
485
+ */
486
+ { name: "visitors", size: "64m" }
487
+ ];
488
+ function parseNginxVersion(raw) {
489
+ const m = raw.match(/nginx version:\s*\S*?\/(\d+)\.(\d+)\.(\d+)/i);
490
+ if (!m) return void 0;
491
+ return [Number(m[1]), Number(m[2]), Number(m[3])];
492
+ }
493
+ var OPENRESTY_DEFAULT_PATHS = {
494
+ bin: "/usr/local/openresty/bin/openresty",
495
+ compiledConfPath: "/usr/local/openresty/nginx/conf/nginx.conf",
496
+ confPath: "/usr/local/openresty/nginx/conf/nginx.conf",
497
+ confDir: "/usr/local/openresty/nginx/conf",
498
+ sitesDir: "/usr/local/openresty/nginx/conf/sites-enabled",
499
+ pidPath: "/usr/local/openresty/nginx/logs/nginx.pid"
500
+ };
501
+ var EDGE_DEFAULT_CERT_DIRNAME = "kraft-default-cert";
502
+ function edgeDefaultCertPaths(confDir) {
503
+ const dir = `${confDir}/${EDGE_DEFAULT_CERT_DIRNAME}`;
504
+ return {
505
+ dir,
506
+ certPath: `${dir}/fullchain.pem`,
507
+ keyPath: `${dir}/privkey.pem`
508
+ };
509
+ }
510
+ var EDGE_DEFAULT_CERT_CN = "kraft-edge-default";
511
+ var EDGE_HOST_STATE_DIR = "/var/lib/kraft/edge";
512
+ var EDGE_CONTAINER_MOUNTS = [
513
+ {
514
+ host: `${EDGE_HOST_STATE_DIR}/sites-enabled`,
515
+ container: OPENRESTY_DEFAULT_PATHS.sitesDir
516
+ },
517
+ { host: "/etc/letsencrypt", container: "/etc/letsencrypt" },
518
+ { host: `${EDGE_HOST_STATE_DIR}/acme`, container: "/var/www/acme" },
519
+ { host: "/opt/kraft/static", container: "/opt/kraft/static" }
520
+ ];
521
+ var EDGE_SAME_PATH_MOUNTS = EDGE_CONTAINER_MOUNTS.filter((m) => m.host === m.container).map(
522
+ (m) => m.host.replace(/\/+$/, "")
523
+ );
524
+ var EDGE_HOST_PATHS = {
525
+ bin: OPENRESTY_DEFAULT_PATHS.bin,
526
+ compiledConfPath: OPENRESTY_DEFAULT_PATHS.compiledConfPath,
527
+ confPath: OPENRESTY_DEFAULT_PATHS.confPath,
528
+ confDir: OPENRESTY_DEFAULT_PATHS.confDir,
529
+ sitesDir: `${EDGE_HOST_STATE_DIR}/sites-enabled`,
530
+ pidPath: OPENRESTY_DEFAULT_PATHS.pidPath
531
+ };
532
+ var KNOWN_CONF_PATHS = [
533
+ "/usr/local/openresty/nginx/conf/nginx.conf",
534
+ "/etc/openresty/nginx.conf",
535
+ "/etc/nginx/nginx.conf"
536
+ ];
537
+ async function detectOpenRestyPaths(executor) {
538
+ const raw = await executor.exec("openresty -V 2>&1 || true");
539
+ const parseFlag = (flag) => {
540
+ const m = raw.match(new RegExp(`--${flag}=([^\\s]+)`));
541
+ return m ? m[1] : null;
542
+ };
543
+ const bin = parseFlag("sbin-path") ?? OPENRESTY_DEFAULT_PATHS.bin;
544
+ const compiledConfPath = parseFlag("conf-path") ?? OPENRESTY_DEFAULT_PATHS.compiledConfPath;
545
+ let confPath = compiledConfPath;
546
+ const pidPath = parseFlag("pid-path") ?? OPENRESTY_DEFAULT_PATHS.pidPath;
547
+ if (!await executor.exists(confPath)) {
548
+ let found = false;
549
+ for (const candidate of KNOWN_CONF_PATHS) {
550
+ if (candidate !== confPath && await executor.exists(candidate)) {
551
+ confPath = candidate;
552
+ found = true;
553
+ break;
554
+ }
555
+ }
556
+ if (!found) {
557
+ }
558
+ }
559
+ const confDir = confPath.replace(/\/[^/]+$/, "");
560
+ const nginxVersion = parseNginxVersion(raw);
561
+ return {
562
+ bin,
563
+ compiledConfPath,
564
+ confPath,
565
+ confDir,
566
+ sitesDir: `${confDir}/sites-enabled`,
567
+ pidPath,
568
+ ...nginxVersion ? { nginxVersion } : {}
569
+ };
570
+ }
571
+ function buildReloadCommand(paths) {
572
+ const bin = sq(paths?.bin || "openresty");
573
+ const config = sq(paths?.confPath || "/etc/openresty/nginx.conf");
574
+ return `${bin} -t -c ${config} 2>&1 || exit 1
575
+ ${bin} -s reload -c ${config} 2>&1 || exit 1`;
576
+ }
577
+ async function ensureEdgeDefaultCert(executor, confDir) {
578
+ const { dir, certPath, keyPath } = edgeDefaultCertPaths(confDir);
579
+ try {
580
+ if (await executor.exists(certPath) && await executor.exists(keyPath)) {
581
+ return { certPath, keyPath };
582
+ }
583
+ } catch {
584
+ return null;
585
+ }
586
+ const staging = `${dir}.staging-${process.pid}-${randomBytes(4).toString("hex")}`;
587
+ try {
588
+ await executor.mkdir(staging);
589
+ await executor.exec(
590
+ `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`
591
+ );
592
+ await executor.exec(`chmod 600 ${sq(`${staging}/privkey.pem`)}`);
593
+ await executor.mkdir(dir);
594
+ await executor.exec(
595
+ `mv -f ${sq(`${staging}/fullchain.pem`)} ${sq(`${staging}/privkey.pem`)} ${sq(dir)}/`
596
+ );
597
+ if (!await executor.exists(certPath) || !await executor.exists(keyPath))
598
+ return null;
599
+ return { certPath, keyPath };
600
+ } catch (err) {
601
+ console.warn(
602
+ `[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)}`
603
+ );
604
+ return null;
605
+ } finally {
606
+ await executor.rm(staging).catch(() => void 0);
607
+ }
608
+ }
609
+ async function ensureOpenRestyConfig(executor, paths) {
610
+ await executor.mkdir(paths.sitesDir);
611
+ await executor.mkdir("/var/www/acme");
612
+ const pidDir = paths.pidPath.replace(/\/[^/]+$/, "");
613
+ await executor.mkdir(pidDir);
614
+ const defaultCert = await ensureEdgeDefaultCert(executor, paths.confDir);
615
+ await executor.writeFile(
616
+ `${paths.sitesDir}/_management.conf`,
617
+ MANAGEMENT_BLOCK
618
+ );
619
+ await executor.writeFile(
620
+ `${paths.sitesDir}/_default.conf`,
621
+ edgeDefaultCatchAllConf(defaultCert)
622
+ );
623
+ if (!await executor.exists(paths.confPath)) {
624
+ await executor.mkdir(paths.confDir);
625
+ await executor.writeFile(
626
+ paths.confPath,
627
+ MINIMAL_NGINX_CONF(paths.confDir, paths.sitesDir)
628
+ );
629
+ return;
630
+ }
631
+ const hasCorrectInclude = await executor.exec(`grep -qF 'include ${paths.sitesDir}/' ${paths.confPath}`).then(() => true).catch(() => false);
632
+ if (!hasCorrectInclude) {
633
+ const hasWrongInclude = await executor.exec(`grep -q 'include.*sites-enabled' ${paths.confPath}`).then(() => true).catch(() => false);
634
+ if (hasWrongInclude) {
635
+ await executor.exec(
636
+ `sed -i 's|include.*/sites-enabled/\\*\\.conf;|include ${paths.sitesDir}/*.conf;|' ${paths.confPath}`
637
+ );
638
+ } else {
639
+ await executor.exec(
640
+ `sed -i '/http *{/a \\ include ${paths.sitesDir}/*.conf;' ${paths.confPath}`
641
+ );
642
+ }
643
+ }
644
+ const hasBodySize = await executor.exec(`grep -qE '^[[:space:]]*client_max_body_size' ${paths.confPath}`).then(() => true).catch(() => false);
645
+ if (!hasBodySize) {
646
+ await executor.exec(
647
+ `sed -i '/http *{/a \\ client_max_body_size ${EDGE_CLIENT_MAX_BODY_SIZE};' ${paths.confPath}`
648
+ );
649
+ }
650
+ }
651
+ function MINIMAL_NGINX_CONF(confDir, sitesDir) {
652
+ return `# Auto-generated by Kraft - safe to extend
653
+ worker_processes auto;
654
+ events {
655
+ worker_connections 1024;
656
+ }
657
+ http {
658
+ include ${confDir}/mime.types;
659
+ default_type application/octet-stream;
660
+ sendfile on;
661
+ keepalive_timeout 65;
662
+ # See EDGE_SERVER_NAMES_HASH_BUCKET_SIZE \u2014 the 64-byte default fails
663
+ # \`nginx -t\` outright for any server_name past ~63 chars, refusing the reload
664
+ # and wedging every route on the box, not just the long one.
665
+ server_names_hash_bucket_size ${EDGE_SERVER_NAMES_HASH_BUCKET_SIZE};
666
+ # See EDGE_CLIENT_MAX_BODY_SIZE \u2014 nginx's 1 MB default 413s an upload before the app
667
+ # ever sees it. A project's own value overrides this (server beats http).
668
+ client_max_body_size ${EDGE_CLIENT_MAX_BODY_SIZE};
669
+ include ${sitesDir}/*.conf;
670
+ }
671
+ `;
672
+ }
673
+ var GEOIP_DIR = "/usr/share/GeoIP";
674
+ var GEOIP_DB_PATH = `${GEOIP_DIR}/GeoLite2-Country.mmdb`;
675
+ var GEOIP_DB_URL = process.env.KRAFT_GEOIP_URL?.trim() || "https://raw.githubusercontent.com/rakay-technology/kraft/main/apps/api/assets/geoip/GeoLite2-Country.mmdb";
676
+ var LUA_SRC_DIR = process.env.KRAFT_LUA_DIR?.trim() || join(dirname(fileURLToPath(import.meta.url)), "lua");
677
+ var VHOST_REFERENCED_LUA = [
678
+ "rules_guard.lua",
679
+ "rules_lib.lua",
680
+ "site_logger.lua"
681
+ ];
682
+ function luaSourceAvailable() {
683
+ return VHOST_REFERENCED_LUA.every(
684
+ (f) => EMBEDDED_LUA[f] !== void 0 || existsSync(join(LUA_SRC_DIR, f))
685
+ );
686
+ }
687
+ function readLua(filename) {
688
+ const onDisk = join(LUA_SRC_DIR, filename);
689
+ if (existsSync(onDisk)) return readFileSync(onDisk, "utf-8");
690
+ const embedded = EMBEDDED_LUA[filename];
691
+ if (embedded !== void 0)
692
+ return Buffer.from(embedded, "base64").toString("utf-8");
693
+ throw new Error(
694
+ `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\`.`
695
+ );
696
+ }
697
+ var EDGE_MGMT_SERVER_BLOCK = `server {
698
+ listen 127.0.0.1:${OPENRESTY_MGMT_PORT};
699
+
700
+ # Long-running Lua content handlers need generous timeouts
701
+ send_timeout 3600s;
702
+ keepalive_timeout 3600s;
703
+ lua_check_client_abort on;
704
+
705
+ # SSE live-log stream (long-lived connection)
706
+ location = /logs/stream {
707
+ content_by_lua_file ${OPENRESTY_LUA_DIR}/pipe_stream.lua;
708
+ }
709
+
710
+ # REST analytics + health (short-lived)
711
+ location / {
712
+ content_by_lua_file ${OPENRESTY_LUA_DIR}/mgmt_api.lua;
713
+ }
714
+ }`;
715
+ var MANAGEMENT_BLOCK = `# Kraft internal management - analytics & live-log streaming
716
+ # Auto-generated - do not edit manually
717
+ ${EDGE_MGMT_SERVER_BLOCK}
718
+ `;
719
+ var ACME_HTTP01_PORT = 49180;
720
+ var ACME_CHALLENGE_LOCATION = ` location ^~ /.well-known/acme-challenge/ {
721
+ proxy_pass http://127.0.0.1:${ACME_HTTP01_PORT};
722
+ proxy_set_header Host $host;
723
+ }`;
724
+ var EDGE_CHALLENGE_URL_PREFIX = "/.well-known/oblien-proxy-challenge/";
725
+ var EDGE_CHALLENGE_ROOT = "/var/www/acme/oblien";
726
+ var EDGE_CHALLENGE_DIR = `${EDGE_CHALLENGE_ROOT}${EDGE_CHALLENGE_URL_PREFIX}`.replace(/\/$/, "");
727
+ var EDGE_CHALLENGE_HOST_DIR = `${EDGE_HOST_STATE_DIR}/acme/oblien${EDGE_CHALLENGE_URL_PREFIX}`.replace(
728
+ /\/$/,
729
+ ""
730
+ );
731
+ var EDGE_CHALLENGE_LOCATION = ` location ^~ ${EDGE_CHALLENGE_URL_PREFIX} {
732
+ root ${EDGE_CHALLENGE_ROOT};
733
+ default_type text/plain;
734
+ try_files $uri =404;
735
+ }`;
736
+ function edgeChallengeVhostConf(host) {
737
+ return `# Auto-generated by Kraft - do not edit manually
738
+ # kraft-oblien-challenge: answers ${EDGE_CHALLENGE_URL_PREFIX}<token> for
739
+ # Host: ${host}, so Kraft Cloud's shared edge can prove this box controls that
740
+ # routing target. Everything else gets the shared not-found page - this is
741
+ # scaffolding, not a site.
742
+ server {
743
+ listen 80;
744
+ server_name ${host};
745
+
746
+ ${EDGE_CHALLENGE_LOCATION}
747
+
748
+ ${EDGE_NOT_FOUND_LOCATION}
749
+ }
750
+ `;
751
+ }
752
+ var EDGE_HTTPS_REJECT_BLOCK = `# HTTPS catch-all. WITHOUT a 443 default_server, nginx serves the first-loaded
753
+ # 443 vhost to any request whose SNI matches no server_name - so a domain we do
754
+ # NOT route (removed / never-added / just pointed at this IP) silently gets some
755
+ # other app's cert + backend. That is cross-serving, a security hole. Owning the
756
+ # 443 default closes it: an unrouted host is answered HERE, never by a fallthrough.
757
+ #
758
+ # This is the no-certificate variant, used only when the placeholder cert could not
759
+ # be created. It refuses the handshake, so the visitor gets a raw TLS error and a
760
+ # Cloudflare-proxied host gets error 525 - correct, but unfriendly. See
761
+ # edgeHttpsDefaultBlock. ssl_reject_handshake (OpenResty/nginx >= 1.19.4; our
762
+ # installer pulls the newest LTS) needs no certificate.
763
+ server {
764
+ listen 443 ssl default_server;
765
+ ssl_reject_handshake on;
766
+ }`;
767
+ function edgeHttpsDefaultBlock(cert) {
768
+ if (!cert) return EDGE_HTTPS_REJECT_BLOCK;
769
+ return `# HTTPS catch-all. WITHOUT a 443 default_server, nginx serves the first-loaded
770
+ # 443 vhost to any request whose SNI matches no server_name - so a domain we do
771
+ # NOT route (removed / never-added / just pointed at this IP) silently gets some
772
+ # other app's cert + backend. That is cross-serving, a security hole. Owning the
773
+ # 443 default closes it: an unrouted host is answered HERE, never by a fallthrough.
774
+ #
775
+ # The cert below belongs to no domain and is trusted by nothing - it exists so the
776
+ # handshake COMPLETES and the request can be answered with a page instead of
777
+ # ERR_SSL_UNRECOGNIZED_NAME_ALERT (Cloudflare "Full" reports the refusal as error
778
+ # 525; "Full (Strict)" validates the cert and will still show 526). Keep this block a
779
+ # dead end: no proxy_pass, no root, no HSTS, no reuse of a real certificate - that is
780
+ # what stops it from becoming the cross-serving it prevents. And never set
781
+ # ssl_certificate at http scope: this block would inherit a real domain's cert.
782
+ server {
783
+ listen 443 ssl default_server;
784
+ server_name _;
785
+
786
+ ssl_certificate ${cert.certPath};
787
+ ssl_certificate_key ${cert.keyPath};
788
+
789
+ ${EDGE_NOT_FOUND_LOCATION}
790
+ }`;
791
+ }
792
+ function edgeDefaultCatchAllConf(cert) {
793
+ return `# Kraft default catch-all - prevents the stock OpenResty welcome page AND
794
+ # stops an unmatched Host/SNI from being served the first real vhost by default.
795
+ # Auto-generated - do not edit manually
796
+ server {
797
+ listen 80 default_server;
798
+ server_name _;
799
+
800
+ ${ACME_CHALLENGE_LOCATION}
801
+
802
+ ${EDGE_NOT_FOUND_LOCATION}
803
+ }
804
+
805
+ ${edgeHttpsDefaultBlock(cert)}
806
+ `;
807
+ }
808
+ var LUA_SCRIPTS = [
809
+ "site_logger.lua",
810
+ "pipe_stream.lua",
811
+ "mgmt_api.lua",
812
+ "geo_country.lua",
813
+ // Vendored FFI binding geo_country requires as `kraft.maxminddb`. Ships with
814
+ // the rest so a bare box needs no `opm get` (which needs perl) — see the file
815
+ // header. Flat, like every other script: ensureLuaScripts writes this list into
816
+ // one directory and its presence scan is a plain `ls -1`.
817
+ "maxminddb.lua",
818
+ "rules_lib.lua",
819
+ "rules_guard.lua"
820
+ ];
821
+ var LUA_VERSION_MARKER = `${OPENRESTY_LUA_DIR}/.kraft-lua-version`;
822
+ function luaBundleHash() {
823
+ const h = createHash("sha256");
824
+ for (const name of LUA_SCRIPTS) {
825
+ h.update(name);
826
+ h.update("\0");
827
+ h.update(readLua(name));
828
+ h.update("\0");
829
+ }
830
+ return h.digest("hex");
831
+ }
832
+ async function ensureLuaScripts(executor, paths) {
833
+ try {
834
+ if (!luaSourceAvailable()) {
835
+ console.error(
836
+ "[openresty] Lua unavailable in this build (not on disk or embedded) \u2014 edge rules/logging disabled. Run `bun run embed:lua` in packages/adapters."
837
+ );
838
+ return { repaired: [], available: false };
839
+ }
840
+ const expected = luaBundleHash();
841
+ await executor.mkdir(OPENRESTY_LUA_DIR);
842
+ const listing = await executor.exec(`ls -1 '${OPENRESTY_LUA_DIR}' 2>/dev/null || true`).catch(() => "");
843
+ const present = new Set(
844
+ listing.split("\n").map((s) => s.trim()).filter(Boolean)
845
+ );
846
+ const missing = LUA_SCRIPTS.filter((name) => !present.has(name));
847
+ const onBoxVersion = (await executor.readFile(LUA_VERSION_MARKER).catch(() => "")).trim();
848
+ if (missing.length === 0 && onBoxVersion === expected) {
849
+ return { repaired: [], available: true };
850
+ }
851
+ for (const name of LUA_SCRIPTS) {
852
+ await executor.writeFile(`${OPENRESTY_LUA_DIR}/${name}`, readLua(name));
853
+ }
854
+ await executor.writeFile(LUA_VERSION_MARKER, expected);
855
+ const reason = missing.length ? `missing: ${missing.join(", ")}` : "version changed";
856
+ console.warn(`[openresty] (re)installed Lua (${reason}) \u2014 reloading edge.`);
857
+ await reloadBareOpenResty(executor, paths).catch((err) => {
858
+ console.error(
859
+ `[openresty] reload after Lua (re)install failed: ${safeErrorMessage(err)}`
860
+ );
861
+ });
862
+ return {
863
+ repaired: missing.length ? missing : [...LUA_SCRIPTS],
864
+ available: true
865
+ };
866
+ } catch (err) {
867
+ console.error(
868
+ `[openresty] ensureLuaScripts failed (deploy continues): ${safeErrorMessage(err)}`
869
+ );
870
+ return { repaired: [], available: false };
871
+ }
872
+ }
873
+ async function installGeoDeps(executor) {
874
+ const profile = await resolveEnvironment(executor).catch(
875
+ (err) => safeErrorMessage(err)
876
+ );
877
+ const install = typeof profile === "string" ? refused(`the host profile could not be read: ${profile}`) : envOps(profile).pkgInstallVariants({
878
+ apt: answered(["libmaxminddb0", "libmaxminddb-dev"]),
879
+ dnf: answered(["libmaxminddb", "libmaxminddb-devel"]),
880
+ yum: answered(["libmaxminddb", "libmaxminddb-devel"]),
881
+ apk: answered(["libmaxminddb"]),
882
+ brew: refused(
883
+ "the bare edge is Linux-only, so Kraft has no macOS package for it."
884
+ )
885
+ });
886
+ if (install.supported) {
887
+ await executor.exec(opScript(install.value)).catch((err) => {
888
+ console.warn(
889
+ `[openresty] libmaxminddb install failed \u2014 geo lookups return nil: ${safeErrorMessage(err)}`
890
+ );
891
+ });
892
+ } else {
893
+ console.warn(
894
+ `[openresty] libmaxminddb not installed \u2014 geo lookups return nil: ${install.reason}`
895
+ );
896
+ }
897
+ try {
898
+ const exists = await executor.exists(GEOIP_DB_PATH);
899
+ if (!exists) {
900
+ await executor.mkdir(GEOIP_DIR);
901
+ await executor.exec(`curl -fsSL -o ${GEOIP_DB_PATH} "${GEOIP_DB_URL}"`);
902
+ }
903
+ } catch {
904
+ }
905
+ }
906
+ async function deployLuaScripts(executor, paths) {
907
+ await installGeoDeps(executor);
908
+ if (!luaSourceAvailable()) {
909
+ throw new Error(
910
+ `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.`
911
+ );
912
+ }
913
+ await executor.mkdir(OPENRESTY_LUA_DIR);
914
+ for (const name of LUA_SCRIPTS) {
915
+ await executor.writeFile(`${OPENRESTY_LUA_DIR}/${name}`, readLua(name));
916
+ }
917
+ await ensureOpenRestyConfig(executor, paths);
918
+ for (const dict of EDGE_SHARED_DICTS) {
919
+ await executor.exec(
920
+ `grep -q 'lua_shared_dict ${dict.name} ' ${paths.confPath} || sed -i '/http *{/a \\ lua_shared_dict ${dict.name} ${dict.size};' ${paths.confPath}`
921
+ );
922
+ }
923
+ await executor.exec(
924
+ `grep -q 'lua_package_path' ${paths.confPath} || sed -i '/http *{/a \\ lua_package_path "${EDGE_LUA_PACKAGE_PATH}";' ${paths.confPath}`
925
+ );
926
+ const realIpPath = `${paths.confDir}/${EDGE_REAL_IP_CONF_NAME}`;
927
+ await executor.writeFile(realIpPath, edgeRealIpConf());
928
+ await executor.exec(
929
+ `grep -q '${EDGE_REAL_IP_CONF_NAME}' '${paths.confPath}' || sed -i '/http *{/a \\ include ${realIpPath};' '${paths.confPath}'`
930
+ );
931
+ await reloadBareOpenResty(executor, paths);
932
+ }
933
+
934
+ export {
935
+ isCloudFrontedHost,
936
+ cloudEdgeRealIpConf,
937
+ reloadBareOpenResty,
938
+ OPENRESTY_LUA_DIR,
939
+ LUA_LOGGER_PATH,
940
+ RULES_GUARD_PATH,
941
+ OPENRESTY_MGMT_PORT,
942
+ EDGE_LUA_PACKAGE_PATH,
943
+ EDGE_SERVER_NAMES_HASH_BUCKET_SIZE,
944
+ EDGE_CLIENT_MAX_BODY_SIZE,
945
+ EDGE_SHARED_DICTS,
946
+ parseNginxVersion,
947
+ OPENRESTY_DEFAULT_PATHS,
948
+ EDGE_DEFAULT_CERT_DIRNAME,
949
+ edgeDefaultCertPaths,
950
+ EDGE_DEFAULT_CERT_CN,
951
+ EDGE_HOST_STATE_DIR,
952
+ EDGE_CONTAINER_MOUNTS,
953
+ EDGE_SAME_PATH_MOUNTS,
954
+ EDGE_HOST_PATHS,
955
+ detectOpenRestyPaths,
956
+ buildReloadCommand,
957
+ ensureOpenRestyConfig,
958
+ GEOIP_DIR,
959
+ GEOIP_DB_PATH,
960
+ luaSourceAvailable,
961
+ EDGE_MGMT_SERVER_BLOCK,
962
+ ACME_HTTP01_PORT,
963
+ ACME_CHALLENGE_LOCATION,
964
+ EDGE_CHALLENGE_URL_PREFIX,
965
+ EDGE_CHALLENGE_ROOT,
966
+ EDGE_CHALLENGE_DIR,
967
+ EDGE_CHALLENGE_HOST_DIR,
968
+ EDGE_CHALLENGE_LOCATION,
969
+ edgeChallengeVhostConf,
970
+ EDGE_HTTPS_REJECT_BLOCK,
971
+ edgeHttpsDefaultBlock,
972
+ edgeDefaultCatchAllConf,
973
+ ensureLuaScripts,
974
+ deployLuaScripts
975
+ };