sonamu 0.8.26 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (684) hide show
  1. package/bin/cli.js +60 -13
  2. package/dist/_virtual/rolldown_runtime.js +39 -0
  3. package/dist/ai/agents/agent.d.ts +3 -3
  4. package/dist/ai/agents/agent.d.ts.map +1 -1
  5. package/dist/ai/agents/agent.js +76 -73
  6. package/dist/ai/agents/index.js +3 -3
  7. package/dist/ai/agents/types.d.ts +3 -3
  8. package/dist/ai/agents/types.d.ts.map +1 -1
  9. package/dist/ai/agents/types.js +1 -3
  10. package/dist/ai/index.js +3 -2
  11. package/dist/ai/providers/rtzr/api.js +25 -25
  12. package/dist/ai/providers/rtzr/error.js +25 -26
  13. package/dist/ai/providers/rtzr/index.js +5 -5
  14. package/dist/ai/providers/rtzr/model.d.ts +1 -1
  15. package/dist/ai/providers/rtzr/model.d.ts.map +1 -1
  16. package/dist/ai/providers/rtzr/model.js +117 -133
  17. package/dist/ai/providers/rtzr/options.d.ts.map +1 -1
  18. package/dist/ai/providers/rtzr/options.js +35 -41
  19. package/dist/ai/providers/rtzr/provider.d.ts +1 -1
  20. package/dist/ai/providers/rtzr/provider.d.ts.map +1 -1
  21. package/dist/ai/providers/rtzr/provider.js +53 -51
  22. package/dist/ai/providers/rtzr/utils.d.ts.map +1 -1
  23. package/dist/ai/providers/rtzr/utils.js +84 -84
  24. package/dist/api/base-frame.d.ts +2 -2
  25. package/dist/api/base-frame.d.ts.map +1 -1
  26. package/dist/api/base-frame.js +29 -19
  27. package/dist/api/caster.d.ts +1 -1
  28. package/dist/api/caster.d.ts.map +1 -1
  29. package/dist/api/caster.js +51 -61
  30. package/dist/api/code-converters.d.ts +4 -3
  31. package/dist/api/code-converters.d.ts.map +1 -1
  32. package/dist/api/code-converters.js +226 -249
  33. package/dist/api/config.d.ts +17 -17
  34. package/dist/api/config.d.ts.map +1 -1
  35. package/dist/api/config.js +37 -30
  36. package/dist/api/context.d.ts +10 -10
  37. package/dist/api/context.d.ts.map +1 -1
  38. package/dist/api/context.js +8 -2
  39. package/dist/api/decorators.d.ts +8 -8
  40. package/dist/api/decorators.d.ts.map +1 -1
  41. package/dist/api/decorators.js +245 -268
  42. package/dist/api/index.js +39 -7
  43. package/dist/api/secret.js +22 -15
  44. package/dist/api/sonamu.d.ts +15 -15
  45. package/dist/api/sonamu.d.ts.map +1 -1
  46. package/dist/api/sonamu.js +1012 -1131
  47. package/dist/api/validator.js +88 -79
  48. package/dist/auth/auth-generator.d.ts.map +1 -1
  49. package/dist/auth/auth-generator.js +203 -200
  50. package/dist/auth/better-auth-entities.d.ts +2 -2
  51. package/dist/auth/better-auth-entities.d.ts.map +1 -1
  52. package/dist/auth/better-auth-entities.js +369 -429
  53. package/dist/auth/index.js +21 -6
  54. package/dist/auth/knex-adapter.d.ts +2 -2
  55. package/dist/auth/knex-adapter.d.ts.map +1 -1
  56. package/dist/auth/knex-adapter.js +153 -157
  57. package/dist/auth/plugins/entity-definitions/admin.d.ts +1 -1
  58. package/dist/auth/plugins/entity-definitions/admin.d.ts.map +1 -1
  59. package/dist/auth/plugins/entity-definitions/admin.js +58 -56
  60. package/dist/auth/plugins/entity-definitions/anonymous.d.ts +1 -1
  61. package/dist/auth/plugins/entity-definitions/anonymous.d.ts.map +1 -1
  62. package/dist/auth/plugins/entity-definitions/anonymous.js +20 -20
  63. package/dist/auth/plugins/entity-definitions/api-key.d.ts +1 -1
  64. package/dist/auth/plugins/entity-definitions/api-key.d.ts.map +1 -1
  65. package/dist/auth/plugins/entity-definitions/api-key.js +185 -196
  66. package/dist/auth/plugins/entity-definitions/index.d.ts +1 -1
  67. package/dist/auth/plugins/entity-definitions/index.d.ts.map +1 -1
  68. package/dist/auth/plugins/entity-definitions/index.js +26 -29
  69. package/dist/auth/plugins/entity-definitions/jwt.d.ts +1 -1
  70. package/dist/auth/plugins/entity-definitions/jwt.d.ts.map +1 -1
  71. package/dist/auth/plugins/entity-definitions/jwt.js +62 -64
  72. package/dist/auth/plugins/entity-definitions/organization.d.ts +1 -1
  73. package/dist/auth/plugins/entity-definitions/organization.d.ts.map +1 -1
  74. package/dist/auth/plugins/entity-definitions/organization.js +362 -421
  75. package/dist/auth/plugins/entity-definitions/passkey.d.ts +1 -1
  76. package/dist/auth/plugins/entity-definitions/passkey.d.ts.map +1 -1
  77. package/dist/auth/plugins/entity-definitions/passkey.js +115 -126
  78. package/dist/auth/plugins/entity-definitions/phone-number.d.ts +1 -1
  79. package/dist/auth/plugins/entity-definitions/phone-number.d.ts.map +1 -1
  80. package/dist/auth/plugins/entity-definitions/phone-number.js +31 -40
  81. package/dist/auth/plugins/entity-definitions/sso.d.ts +1 -1
  82. package/dist/auth/plugins/entity-definitions/sso.d.ts.map +1 -1
  83. package/dist/auth/plugins/entity-definitions/sso.js +94 -107
  84. package/dist/auth/plugins/entity-definitions/two-factor.d.ts +1 -1
  85. package/dist/auth/plugins/entity-definitions/two-factor.d.ts.map +1 -1
  86. package/dist/auth/plugins/entity-definitions/two-factor.js +78 -92
  87. package/dist/auth/plugins/entity-definitions/types.d.ts +1 -1
  88. package/dist/auth/plugins/entity-definitions/types.d.ts.map +1 -1
  89. package/dist/auth/plugins/entity-definitions/types.js +1 -10
  90. package/dist/auth/plugins/entity-definitions/username.d.ts +1 -1
  91. package/dist/auth/plugins/entity-definitions/username.d.ts.map +1 -1
  92. package/dist/auth/plugins/entity-definitions/username.js +31 -40
  93. package/dist/auth/plugins/index.js +12 -3
  94. package/dist/auth/plugins/wrappers/admin.d.ts +2 -2
  95. package/dist/auth/plugins/wrappers/admin.d.ts.map +1 -1
  96. package/dist/auth/plugins/wrappers/admin.js +28 -29
  97. package/dist/auth/plugins/wrappers/anonymous.d.ts +2 -1
  98. package/dist/auth/plugins/wrappers/anonymous.d.ts.map +1 -1
  99. package/dist/auth/plugins/wrappers/anonymous.js +23 -22
  100. package/dist/auth/plugins/wrappers/api-key.d.ts +2 -1
  101. package/dist/auth/plugins/wrappers/api-key.d.ts.map +1 -1
  102. package/dist/auth/plugins/wrappers/api-key.js +39 -34
  103. package/dist/auth/plugins/wrappers/index.js +11 -11
  104. package/dist/auth/plugins/wrappers/jwt.d.ts +2 -1
  105. package/dist/auth/plugins/wrappers/jwt.d.ts.map +1 -1
  106. package/dist/auth/plugins/wrappers/jwt.js +31 -26
  107. package/dist/auth/plugins/wrappers/organization.d.ts +2 -1
  108. package/dist/auth/plugins/wrappers/organization.d.ts.map +1 -1
  109. package/dist/auth/plugins/wrappers/organization.js +65 -62
  110. package/dist/auth/plugins/wrappers/passkey.d.ts +2 -1
  111. package/dist/auth/plugins/wrappers/passkey.d.ts.map +1 -1
  112. package/dist/auth/plugins/wrappers/passkey.js +33 -28
  113. package/dist/auth/plugins/wrappers/phone-number.d.ts.map +1 -1
  114. package/dist/auth/plugins/wrappers/phone-number.js +26 -23
  115. package/dist/auth/plugins/wrappers/sso.d.ts.map +1 -1
  116. package/dist/auth/plugins/wrappers/sso.js +37 -31
  117. package/dist/auth/plugins/wrappers/two-factor.d.ts.map +1 -1
  118. package/dist/auth/plugins/wrappers/two-factor.js +31 -28
  119. package/dist/auth/plugins/wrappers/username.d.ts.map +1 -1
  120. package/dist/auth/plugins/wrappers/username.js +23 -23
  121. package/dist/bin/build-config.js +31 -31
  122. package/dist/bin/cli.js +1063 -1204
  123. package/dist/bin/fixture.d.ts.map +1 -1
  124. package/dist/bin/fixture.js +266 -259
  125. package/dist/bin/hmr-hook-register.d.ts.map +1 -1
  126. package/dist/bin/hmr-hook-register.js +19 -18
  127. package/dist/bin/test-command.d.ts.map +1 -1
  128. package/dist/bin/test-command.js +180 -177
  129. package/dist/bin/ts-loader-register.js +13 -6
  130. package/dist/bin/ts-loader-registration.d.ts.map +1 -1
  131. package/dist/bin/ts-loader-registration.js +28 -38
  132. package/dist/cache/cache-manager.d.ts +1 -1
  133. package/dist/cache/cache-manager.d.ts.map +1 -1
  134. package/dist/cache/cache-manager.js +20 -15
  135. package/dist/cache/decorator.d.ts +1 -1
  136. package/dist/cache/decorator.d.ts.map +1 -1
  137. package/dist/cache/decorator.js +84 -76
  138. package/dist/cache/drivers.js +21 -34
  139. package/dist/cache/index.js +10 -7
  140. package/dist/cache/types.d.ts +2 -2
  141. package/dist/cache/types.d.ts.map +1 -1
  142. package/dist/cache/types.js +1 -6
  143. package/dist/cache-control/cache-control.d.ts +2 -2
  144. package/dist/cache-control/cache-control.d.ts.map +1 -1
  145. package/dist/cache-control/cache-control.js +106 -122
  146. package/dist/cache-control/types.d.ts +2 -2
  147. package/dist/cache-control/types.d.ts.map +1 -1
  148. package/dist/cache-control/types.js +1 -19
  149. package/dist/compress/compress.d.ts +1 -1
  150. package/dist/compress/compress.d.ts.map +1 -1
  151. package/dist/compress/compress.js +58 -56
  152. package/dist/compress/index.js +7 -2
  153. package/dist/compress/types.js +1 -11
  154. package/dist/cone/cone-generator.d.ts +1 -1
  155. package/dist/cone/cone-generator.d.ts.map +1 -1
  156. package/dist/cone/cone-generator.js +216 -219
  157. package/dist/database/_batch_update.d.ts +1 -1
  158. package/dist/database/_batch_update.d.ts.map +1 -1
  159. package/dist/database/_batch_update.js +107 -102
  160. package/dist/database/base-model.d.ts +8 -9
  161. package/dist/database/base-model.d.ts.map +1 -1
  162. package/dist/database/base-model.js +371 -392
  163. package/dist/database/base-model.types.d.ts +5 -5
  164. package/dist/database/base-model.types.d.ts.map +1 -1
  165. package/dist/database/base-model.types.js +1 -20
  166. package/dist/database/db.d.ts +5 -2
  167. package/dist/database/db.d.ts.map +1 -1
  168. package/dist/database/db.js +185 -171
  169. package/dist/database/knex.d.ts +1 -1
  170. package/dist/database/knex.d.ts.map +1 -1
  171. package/dist/database/knex.js +48 -42
  172. package/dist/database/puri-subset.types.d.ts +6 -7
  173. package/dist/database/puri-subset.types.d.ts.map +1 -1
  174. package/dist/database/puri-subset.types.js +1 -16
  175. package/dist/database/puri-wrapper.d.ts +6 -6
  176. package/dist/database/puri-wrapper.d.ts.map +1 -1
  177. package/dist/database/puri-wrapper.js +99 -101
  178. package/dist/database/puri.d.ts +4 -5
  179. package/dist/database/puri.d.ts.map +1 -1
  180. package/dist/database/puri.js +1021 -1227
  181. package/dist/database/puri.types.d.ts +6 -6
  182. package/dist/database/puri.types.d.ts.map +1 -1
  183. package/dist/database/puri.types.js +15 -6
  184. package/dist/database/transaction-context.d.ts +2 -2
  185. package/dist/database/transaction-context.d.ts.map +1 -1
  186. package/dist/database/transaction-context.js +22 -13
  187. package/dist/database/upsert-builder.d.ts +3 -3
  188. package/dist/database/upsert-builder.d.ts.map +1 -1
  189. package/dist/database/upsert-builder.js +405 -465
  190. package/dist/dict/en.js +72 -74
  191. package/dist/dict/index.js +13 -13
  192. package/dist/dict/ko.js +72 -74
  193. package/dist/dict/rc-keys.js +150 -168
  194. package/dist/dict/sd.d.ts +3 -1
  195. package/dist/dict/sd.d.ts.map +1 -1
  196. package/dist/dict/sd.js +54 -40
  197. package/dist/dict/sonamu-dictionary.d.ts +1 -1
  198. package/dist/dict/sonamu-dictionary.d.ts.map +1 -1
  199. package/dist/dict/sonamu-dictionary.js +887 -955
  200. package/dist/dict/types.js +1 -7
  201. package/dist/dict/utils.js +26 -24
  202. package/dist/entity/entity-manager.d.ts +9 -9
  203. package/dist/entity/entity-manager.d.ts.map +1 -1
  204. package/dist/entity/entity-manager.js +226 -223
  205. package/dist/entity/entity-template-cone.d.ts +1 -1
  206. package/dist/entity/entity-template-cone.d.ts.map +1 -1
  207. package/dist/entity/entity-template-cone.js +152 -151
  208. package/dist/entity/entity.d.ts.map +1 -1
  209. package/dist/entity/entity.js +952 -1089
  210. package/dist/exceptions/error-handler.d.ts +1 -1
  211. package/dist/exceptions/error-handler.d.ts.map +1 -1
  212. package/dist/exceptions/error-handler.js +32 -27
  213. package/dist/exceptions/so-exceptions.d.ts +1 -1
  214. package/dist/exceptions/so-exceptions.d.ts.map +1 -1
  215. package/dist/exceptions/so-exceptions.js +61 -68
  216. package/dist/filter/index.js +9 -3
  217. package/dist/filter/types.js +92 -88
  218. package/dist/filter/utils.d.ts +1 -1
  219. package/dist/filter/utils.d.ts.map +1 -1
  220. package/dist/filter/utils.js +147 -161
  221. package/dist/index.js +87 -40
  222. package/dist/logger/category.d.ts.map +1 -1
  223. package/dist/logger/category.js +30 -29
  224. package/dist/logger/configure.d.ts.map +1 -1
  225. package/dist/logger/configure.js +83 -107
  226. package/dist/migration/code-generation.d.ts +2 -2
  227. package/dist/migration/code-generation.d.ts.map +1 -1
  228. package/dist/migration/code-generation.js +1385 -1578
  229. package/dist/migration/migration-set.d.ts +1 -1
  230. package/dist/migration/migration-set.d.ts.map +1 -1
  231. package/dist/migration/migration-set.js +177 -227
  232. package/dist/migration/migrator.d.ts +4 -3
  233. package/dist/migration/migrator.d.ts.map +1 -1
  234. package/dist/migration/migrator.js +340 -345
  235. package/dist/migration/postgresql-schema-reader.d.ts +2 -2
  236. package/dist/migration/postgresql-schema-reader.d.ts.map +1 -1
  237. package/dist/migration/postgresql-schema-reader.js +506 -564
  238. package/dist/migration/slack-confirm.d.ts +2 -2
  239. package/dist/migration/slack-confirm.d.ts.map +1 -1
  240. package/dist/migration/slack-confirm.js +205 -193
  241. package/dist/migration/types.d.ts +2 -2
  242. package/dist/migration/types.d.ts.map +1 -1
  243. package/dist/migration/types.js +1 -3
  244. package/dist/naite/messaging-types.d.ts +1 -0
  245. package/dist/naite/messaging-types.d.ts.map +1 -1
  246. package/dist/naite/messaging-types.js +1 -7
  247. package/dist/naite/naite-reporter.d.ts +2 -2
  248. package/dist/naite/naite-reporter.d.ts.map +1 -1
  249. package/dist/naite/naite-reporter.js +127 -120
  250. package/dist/naite/naite.d.ts +3 -2
  251. package/dist/naite/naite.d.ts.map +1 -1
  252. package/dist/naite/naite.js +266 -300
  253. package/dist/ssr/index.d.ts +2 -2
  254. package/dist/ssr/index.d.ts.map +1 -1
  255. package/dist/ssr/index.js +13 -3
  256. package/dist/ssr/registry.d.ts +1 -1
  257. package/dist/ssr/registry.d.ts.map +1 -1
  258. package/dist/ssr/registry.js +45 -37
  259. package/dist/ssr/renderer.d.ts +4 -4
  260. package/dist/ssr/renderer.d.ts.map +1 -1
  261. package/dist/ssr/renderer.js +84 -91
  262. package/dist/ssr/types.d.ts +2 -2
  263. package/dist/ssr/types.d.ts.map +1 -1
  264. package/dist/ssr/types.js +1 -3
  265. package/dist/storage/base-file.js +54 -41
  266. package/dist/storage/buffered-file.d.ts +2 -2
  267. package/dist/storage/buffered-file.d.ts.map +1 -1
  268. package/dist/storage/buffered-file.js +51 -44
  269. package/dist/storage/drivers.d.ts +2 -2
  270. package/dist/storage/drivers.d.ts.map +1 -1
  271. package/dist/storage/drivers.js +12 -7
  272. package/dist/storage/index.js +14 -7
  273. package/dist/storage/s3-driver.d.ts +2 -2
  274. package/dist/storage/s3-driver.d.ts.map +1 -1
  275. package/dist/storage/s3-driver.js +52 -48
  276. package/dist/storage/storage-manager.d.ts +2 -2
  277. package/dist/storage/storage-manager.d.ts.map +1 -1
  278. package/dist/storage/storage-manager.js +33 -25
  279. package/dist/storage/types.d.ts +2 -2
  280. package/dist/storage/types.d.ts.map +1 -1
  281. package/dist/storage/types.js +1 -5
  282. package/dist/storage/uploaded-file.d.ts +1 -1
  283. package/dist/storage/uploaded-file.d.ts.map +1 -1
  284. package/dist/storage/uploaded-file.js +45 -35
  285. package/dist/stream/index.js +7 -2
  286. package/dist/stream/sse.d.ts +2 -2
  287. package/dist/stream/sse.d.ts.map +1 -1
  288. package/dist/stream/sse.js +72 -67
  289. package/dist/syncer/api-parser.d.ts +1 -1
  290. package/dist/syncer/api-parser.d.ts.map +1 -1
  291. package/dist/syncer/api-parser.js +224 -245
  292. package/dist/syncer/checksum.d.ts +1 -1
  293. package/dist/syncer/checksum.d.ts.map +1 -1
  294. package/dist/syncer/checksum.js +86 -72
  295. package/dist/syncer/code-generator.d.ts +2 -2
  296. package/dist/syncer/code-generator.d.ts.map +1 -1
  297. package/dist/syncer/code-generator.js +154 -160
  298. package/dist/syncer/entity-operations.d.ts +1 -1
  299. package/dist/syncer/entity-operations.d.ts.map +1 -1
  300. package/dist/syncer/entity-operations.js +63 -54
  301. package/dist/syncer/file-patterns.d.ts +1 -1
  302. package/dist/syncer/file-patterns.d.ts.map +1 -1
  303. package/dist/syncer/file-patterns.js +38 -38
  304. package/dist/syncer/index.js +19 -8
  305. package/dist/syncer/module-loader.d.ts +5 -5
  306. package/dist/syncer/module-loader.d.ts.map +1 -1
  307. package/dist/syncer/module-loader.js +83 -78
  308. package/dist/syncer/syncer-actions.d.ts +2 -2
  309. package/dist/syncer/syncer-actions.d.ts.map +1 -1
  310. package/dist/syncer/syncer-actions.js +76 -91
  311. package/dist/syncer/syncer.d.ts +7 -6
  312. package/dist/syncer/syncer.d.ts.map +1 -1
  313. package/dist/syncer/syncer.js +426 -492
  314. package/dist/tasks/decorator.d.ts +3 -3
  315. package/dist/tasks/decorator.d.ts.map +1 -1
  316. package/dist/tasks/decorator.js +32 -28
  317. package/dist/tasks/step-wrapper.d.ts +1 -1
  318. package/dist/tasks/step-wrapper.d.ts.map +1 -1
  319. package/dist/tasks/step-wrapper.js +42 -41
  320. package/dist/tasks/workflow-manager.d.ts +2 -2
  321. package/dist/tasks/workflow-manager.d.ts.map +1 -1
  322. package/dist/tasks/workflow-manager.js +192 -221
  323. package/dist/template/entity-converter.d.ts +1 -1
  324. package/dist/template/entity-converter.d.ts.map +1 -1
  325. package/dist/template/entity-converter.js +103 -103
  326. package/dist/template/helpers.d.ts.map +1 -1
  327. package/dist/template/helpers.js +163 -163
  328. package/dist/template/implementations/entity.template.d.ts +1 -1
  329. package/dist/template/implementations/entity.template.d.ts.map +1 -1
  330. package/dist/template/implementations/entity.template.js +76 -85
  331. package/dist/template/implementations/entry-server.template.d.ts +1 -1
  332. package/dist/template/implementations/entry-server.template.d.ts.map +1 -1
  333. package/dist/template/implementations/entry-server.template.js +32 -27
  334. package/dist/template/implementations/generated.template.d.ts +1 -1
  335. package/dist/template/implementations/generated.template.d.ts.map +1 -1
  336. package/dist/template/implementations/generated.template.js +254 -275
  337. package/dist/template/implementations/generated_http.template.d.ts +2 -2
  338. package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
  339. package/dist/template/implementations/generated_http.template.js +114 -133
  340. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
  341. package/dist/template/implementations/generated_sso.template.js +249 -275
  342. package/dist/template/implementations/init_types.template.d.ts +1 -1
  343. package/dist/template/implementations/init_types.template.d.ts.map +1 -1
  344. package/dist/template/implementations/init_types.template.js +40 -34
  345. package/dist/template/implementations/model.template.d.ts +1 -1
  346. package/dist/template/implementations/model.template.d.ts.map +1 -1
  347. package/dist/template/implementations/model.template.js +56 -53
  348. package/dist/template/implementations/model_test.template.d.ts +1 -1
  349. package/dist/template/implementations/model_test.template.d.ts.map +1 -1
  350. package/dist/template/implementations/model_test.template.js +32 -24
  351. package/dist/template/implementations/queries.template.d.ts +1 -1
  352. package/dist/template/implementations/queries.template.d.ts.map +1 -1
  353. package/dist/template/implementations/queries.template.js +84 -89
  354. package/dist/template/implementations/sd.template.d.ts +1 -1
  355. package/dist/template/implementations/sd.template.d.ts.map +1 -1
  356. package/dist/template/implementations/sd.template.js +137 -144
  357. package/dist/template/implementations/services.template.d.ts +1 -1
  358. package/dist/template/implementations/services.template.d.ts.map +1 -1
  359. package/dist/template/implementations/services.template.js +164 -189
  360. package/dist/template/implementations/view_form.template.d.ts +1 -1
  361. package/dist/template/implementations/view_form.template.d.ts.map +1 -1
  362. package/dist/template/implementations/view_form.template.js +258 -285
  363. package/dist/template/implementations/view_id_all_select.template.d.ts +1 -1
  364. package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -1
  365. package/dist/template/implementations/view_id_all_select.template.js +31 -25
  366. package/dist/template/implementations/view_list.template.d.ts +1 -1
  367. package/dist/template/implementations/view_list.template.d.ts.map +1 -1
  368. package/dist/template/implementations/view_list.template.js +304 -355
  369. package/dist/template/implementations/view_search_input.template.d.ts +1 -1
  370. package/dist/template/implementations/view_search_input.template.d.ts.map +1 -1
  371. package/dist/template/implementations/view_search_input.template.js +31 -27
  372. package/dist/template/index.js +21 -7
  373. package/dist/template/template-manager.d.ts +1 -1
  374. package/dist/template/template-manager.d.ts.map +1 -1
  375. package/dist/template/template-manager.js +132 -123
  376. package/dist/template/template-types.js +8 -6
  377. package/dist/template/template.d.ts +2 -2
  378. package/dist/template/template.d.ts.map +1 -1
  379. package/dist/template/template.js +73 -68
  380. package/dist/template/zod-converter.d.ts.map +1 -1
  381. package/dist/template/zod-converter.js +603 -657
  382. package/dist/testing/_relation-graph.d.ts +1 -1
  383. package/dist/testing/_relation-graph.d.ts.map +1 -1
  384. package/dist/testing/_relation-graph.js +93 -88
  385. package/dist/testing/bootstrap.d.ts +22 -13
  386. package/dist/testing/bootstrap.d.ts.map +1 -1
  387. package/dist/testing/bootstrap.js +114 -114
  388. package/dist/testing/data-explorer.d.ts +3 -3
  389. package/dist/testing/data-explorer.d.ts.map +1 -1
  390. package/dist/testing/data-explorer.js +237 -265
  391. package/dist/testing/dev-test-routes.d.ts +2 -2
  392. package/dist/testing/dev-test-routes.d.ts.map +1 -1
  393. package/dist/testing/dev-test-routes.js +258 -249
  394. package/dist/testing/dev-vitest-manager.d.ts +1 -1
  395. package/dist/testing/dev-vitest-manager.d.ts.map +1 -1
  396. package/dist/testing/dev-vitest-manager.js +514 -539
  397. package/dist/testing/faker-mappings.js +422 -420
  398. package/dist/testing/fixture-generator.d.ts +3 -3
  399. package/dist/testing/fixture-generator.d.ts.map +1 -1
  400. package/dist/testing/fixture-generator.js +1216 -1346
  401. package/dist/testing/fixture-loader.js +26 -25
  402. package/dist/testing/fixture-manager.d.ts +3 -3
  403. package/dist/testing/fixture-manager.d.ts.map +1 -1
  404. package/dist/testing/fixture-manager.js +706 -776
  405. package/dist/testing/global-setup.js +53 -49
  406. package/dist/testing/index.js +19 -11
  407. package/dist/testing/naite-vitest-reporter.js +18 -13
  408. package/dist/testing/parallel-db-manager.d.ts +1 -1
  409. package/dist/testing/parallel-db-manager.d.ts.map +1 -1
  410. package/dist/testing/parallel-db-manager.js +63 -78
  411. package/dist/testing/vitest-helpers.d.ts +1 -1
  412. package/dist/testing/vitest-helpers.d.ts.map +1 -1
  413. package/dist/testing/vitest-helpers.js +37 -33
  414. package/dist/types/types.d.ts +28 -28
  415. package/dist/types/types.d.ts.map +1 -1
  416. package/dist/types/types.js +764 -890
  417. package/dist/ui/ai-api.d.ts +1 -1
  418. package/dist/ui/ai-api.d.ts.map +1 -1
  419. package/dist/ui/ai-api.js +52 -42
  420. package/dist/ui/ai-client.d.ts +1 -2
  421. package/dist/ui/ai-client.d.ts.map +1 -1
  422. package/dist/ui/ai-client.js +353 -388
  423. package/dist/ui/api.d.ts +1 -1
  424. package/dist/ui/api.d.ts.map +1 -1
  425. package/dist/ui/api.js +903 -1145
  426. package/dist/ui/cdd-service.d.ts +1 -1
  427. package/dist/ui/cdd-service.d.ts.map +1 -1
  428. package/dist/ui/cdd-service.js +406 -407
  429. package/dist/ui/cdd-types.js +1 -3
  430. package/dist/ui-web/assets/index-C-Zz-wYg.css +1 -0
  431. package/dist/ui-web/assets/index-DejDON8K.js +238 -0
  432. package/dist/ui-web/index.html +3 -3
  433. package/dist/utils/async-utils.js +57 -45
  434. package/dist/utils/console-util.d.ts.map +1 -1
  435. package/dist/utils/console-util.js +104 -87
  436. package/dist/utils/controller.js +26 -19
  437. package/dist/utils/esm-utils.js +49 -38
  438. package/dist/utils/formatter.d.ts +1 -2
  439. package/dist/utils/formatter.d.ts.map +1 -1
  440. package/dist/utils/formatter.js +89 -115
  441. package/dist/utils/fs-utils.d.ts.map +1 -1
  442. package/dist/utils/fs-utils.js +68 -65
  443. package/dist/utils/lodash-able.js +11 -4
  444. package/dist/utils/model.d.ts +1 -1
  445. package/dist/utils/model.d.ts.map +1 -1
  446. package/dist/utils/model.js +21 -19
  447. package/dist/utils/object-utils.js +148 -186
  448. package/dist/utils/path-utils.js +67 -57
  449. package/dist/utils/process-utils.d.ts.map +1 -1
  450. package/dist/utils/process-utils.js +37 -31
  451. package/dist/utils/sql-parser.d.ts +1 -1
  452. package/dist/utils/sql-parser.d.ts.map +1 -1
  453. package/dist/utils/sql-parser.js +40 -40
  454. package/dist/utils/type-utils.js +44 -43
  455. package/dist/utils/utils.d.ts +2 -3
  456. package/dist/utils/utils.d.ts.map +1 -1
  457. package/dist/utils/utils.js +81 -93
  458. package/dist/utils/zod-error.d.ts +1 -1
  459. package/dist/utils/zod-error.d.ts.map +1 -1
  460. package/dist/utils/zod-error.js +24 -17
  461. package/dist/vector/chunking.d.ts +1 -1
  462. package/dist/vector/chunking.d.ts.map +1 -1
  463. package/dist/vector/chunking.js +100 -94
  464. package/dist/vector/config.d.ts +1 -1
  465. package/dist/vector/config.d.ts.map +1 -1
  466. package/dist/vector/config.js +76 -78
  467. package/dist/vector/embedding.d.ts +1 -1
  468. package/dist/vector/embedding.d.ts.map +1 -1
  469. package/dist/vector/embedding.js +128 -125
  470. package/dist/vector/index.js +5 -5
  471. package/dist/vector/types.js +1 -5
  472. package/package.json +31 -36
  473. package/src/ai/agents/agent.ts +12 -5
  474. package/src/ai/agents/types.ts +5 -5
  475. package/src/ai/providers/rtzr/model.ts +8 -10
  476. package/src/ai/providers/rtzr/options.ts +2 -1
  477. package/src/ai/providers/rtzr/provider.ts +5 -3
  478. package/src/ai/providers/rtzr/utils.ts +2 -7
  479. package/src/api/__tests__/config.test.ts +15 -8
  480. package/src/api/base-frame.ts +5 -3
  481. package/src/api/caster.ts +7 -6
  482. package/src/api/code-converters.ts +23 -26
  483. package/src/api/config.ts +23 -17
  484. package/src/api/context.ts +18 -11
  485. package/src/api/decorators.ts +17 -18
  486. package/src/api/sonamu.ts +44 -49
  487. package/src/auth/auth-generator.ts +4 -6
  488. package/src/auth/better-auth-entities.ts +3 -2
  489. package/src/auth/knex-adapter.ts +6 -5
  490. package/src/auth/plugins/entity-definitions/admin.ts +1 -1
  491. package/src/auth/plugins/entity-definitions/anonymous.ts +1 -1
  492. package/src/auth/plugins/entity-definitions/api-key.ts +1 -1
  493. package/src/auth/plugins/entity-definitions/index.ts +1 -1
  494. package/src/auth/plugins/entity-definitions/jwt.ts +1 -1
  495. package/src/auth/plugins/entity-definitions/organization.ts +1 -1
  496. package/src/auth/plugins/entity-definitions/passkey.ts +1 -1
  497. package/src/auth/plugins/entity-definitions/phone-number.ts +1 -1
  498. package/src/auth/plugins/entity-definitions/sso.ts +1 -1
  499. package/src/auth/plugins/entity-definitions/two-factor.ts +1 -1
  500. package/src/auth/plugins/entity-definitions/types.ts +1 -1
  501. package/src/auth/plugins/entity-definitions/username.ts +1 -1
  502. package/src/auth/plugins/wrappers/admin.ts +3 -1
  503. package/src/auth/plugins/wrappers/anonymous.ts +3 -1
  504. package/src/auth/plugins/wrappers/api-key.ts +3 -1
  505. package/src/auth/plugins/wrappers/jwt.ts +3 -1
  506. package/src/auth/plugins/wrappers/organization.ts +3 -1
  507. package/src/auth/plugins/wrappers/passkey.ts +3 -1
  508. package/src/auth/plugins/wrappers/phone-number.ts +3 -1
  509. package/src/auth/plugins/wrappers/sso.ts +2 -1
  510. package/src/auth/plugins/wrappers/two-factor.ts +3 -1
  511. package/src/auth/plugins/wrappers/username.ts +3 -1
  512. package/src/bin/__tests__/ts-loader-register.test.ts +7 -12
  513. package/src/bin/build-config.ts +3 -3
  514. package/src/bin/cli.ts +27 -25
  515. package/src/bin/fixture.ts +4 -2
  516. package/src/bin/hmr-hook-register.ts +1 -0
  517. package/src/bin/test-command.ts +4 -2
  518. package/src/bin/ts-loader-registration.ts +6 -22
  519. package/src/cache/cache-manager.ts +2 -1
  520. package/src/cache/decorator.ts +2 -2
  521. package/src/cache/types.ts +3 -3
  522. package/src/cache-control/cache-control.ts +3 -2
  523. package/src/cache-control/types.ts +2 -2
  524. package/src/compress/compress.ts +1 -1
  525. package/src/cone/cone-generator.ts +5 -3
  526. package/src/database/_batch_update.ts +1 -1
  527. package/src/database/base-model.ts +20 -14
  528. package/src/database/base-model.types.ts +12 -11
  529. package/src/database/db.ts +56 -21
  530. package/src/database/knex.ts +2 -2
  531. package/src/database/puri-subset.test-d.ts +33 -32
  532. package/src/database/puri-subset.types.ts +6 -7
  533. package/src/database/puri-wrapper.ts +29 -26
  534. package/src/database/puri.ts +36 -34
  535. package/src/database/puri.types.test-d.ts +6 -5
  536. package/src/database/puri.types.ts +9 -12
  537. package/src/database/transaction-context.ts +2 -2
  538. package/src/database/upsert-builder.ts +17 -10
  539. package/src/dict/sd.ts +17 -4
  540. package/src/dict/sonamu-dictionary.ts +23 -17
  541. package/src/entity/entity-manager.ts +9 -7
  542. package/src/entity/entity-template-cone.ts +10 -3
  543. package/src/entity/entity.ts +20 -16
  544. package/src/exceptions/error-handler.ts +2 -1
  545. package/src/exceptions/so-exceptions.ts +1 -1
  546. package/src/filter/utils.ts +3 -2
  547. package/src/logger/category.ts +1 -0
  548. package/src/logger/configure.ts +5 -5
  549. package/src/migration/__tests__/code-generation.search-text.test.ts +2 -3
  550. package/src/migration/code-generation.ts +26 -25
  551. package/src/migration/migration-set.ts +16 -18
  552. package/src/migration/migrator.ts +38 -33
  553. package/src/migration/postgresql-schema-reader.ts +12 -12
  554. package/src/migration/slack-confirm.ts +5 -4
  555. package/src/migration/types.ts +2 -2
  556. package/src/naite/messaging-types.ts +1 -1
  557. package/src/naite/naite-reporter.ts +5 -3
  558. package/src/naite/naite.ts +12 -7
  559. package/src/shared/app.shared.ts.txt +2 -2
  560. package/src/shared/web.shared.ts.txt +2 -2
  561. package/src/skills/AGENTS.md +19 -18
  562. package/src/skills/commands/sonamu-skills.md +9 -9
  563. package/src/skills/sonamu/SKILL.md +111 -104
  564. package/src/skills/sonamu/ai-agents.md +27 -26
  565. package/src/skills/sonamu/api.md +81 -69
  566. package/src/skills/sonamu/auth-migration.md +13 -27
  567. package/src/skills/sonamu/auth-plugins.md +41 -31
  568. package/src/skills/sonamu/auth.md +30 -24
  569. package/src/skills/sonamu/cdd.md +26 -17
  570. package/src/skills/sonamu/cone.md +50 -50
  571. package/src/skills/sonamu/config.md +74 -51
  572. package/src/skills/sonamu/create-sonamu.md +31 -19
  573. package/src/skills/sonamu/database.md +43 -26
  574. package/src/skills/sonamu/entity-basic.md +61 -61
  575. package/src/skills/sonamu/entity-relations.md +84 -80
  576. package/src/skills/sonamu/entity-validation-checklist.md +19 -15
  577. package/src/skills/sonamu/fixture-cli.md +52 -30
  578. package/src/skills/sonamu/framework-change.md +9 -7
  579. package/src/skills/sonamu/frontend.md +64 -82
  580. package/src/skills/sonamu/i18n.md +45 -37
  581. package/src/skills/sonamu/migration.md +54 -31
  582. package/src/skills/sonamu/model.md +98 -66
  583. package/src/skills/sonamu/naite.md +34 -32
  584. package/src/skills/sonamu/project-init.md +28 -8
  585. package/src/skills/sonamu/puri.md +82 -91
  586. package/src/skills/sonamu/scaffolding.md +44 -32
  587. package/src/skills/sonamu/skill-contribution.md +50 -45
  588. package/src/skills/sonamu/subset.md +13 -13
  589. package/src/skills/sonamu/tasks.md +73 -58
  590. package/src/skills/sonamu/testing-devrunner.md +56 -36
  591. package/src/skills/sonamu/testing.md +23 -58
  592. package/src/skills/sonamu/upsert.md +32 -31
  593. package/src/skills/sonamu/vector.md +37 -36
  594. package/src/ssr/index.ts +2 -12
  595. package/src/ssr/registry.ts +1 -1
  596. package/src/ssr/renderer.ts +7 -5
  597. package/src/ssr/types.ts +2 -2
  598. package/src/storage/buffered-file.ts +4 -2
  599. package/src/storage/drivers.ts +3 -2
  600. package/src/storage/s3-driver.ts +7 -4
  601. package/src/storage/storage-manager.ts +3 -2
  602. package/src/storage/types.ts +3 -2
  603. package/src/storage/uploaded-file.ts +1 -1
  604. package/src/stream/sse.ts +2 -2
  605. package/src/syncer/api-parser.ts +8 -5
  606. package/src/syncer/checksum.ts +9 -5
  607. package/src/syncer/code-generator.ts +16 -8
  608. package/src/syncer/entity-operations.ts +5 -3
  609. package/src/syncer/file-patterns.ts +2 -1
  610. package/src/syncer/module-loader.ts +9 -6
  611. package/src/syncer/syncer-actions.ts +5 -3
  612. package/src/syncer/syncer.ts +18 -24
  613. package/src/tasks/decorator.ts +10 -8
  614. package/src/tasks/step-wrapper.ts +1 -1
  615. package/src/tasks/workflow-manager.ts +18 -15
  616. package/src/template/__tests__/generated.template.search-text.test.ts +1 -0
  617. package/src/template/entity-converter.ts +4 -2
  618. package/src/template/generated.template.test-d.ts +2 -1
  619. package/src/template/helpers.ts +5 -2
  620. package/src/template/implementations/entity.template.ts +9 -8
  621. package/src/template/implementations/entry-server.template.ts +1 -1
  622. package/src/template/implementations/generated.template.ts +21 -29
  623. package/src/template/implementations/generated_http.template.ts +9 -6
  624. package/src/template/implementations/generated_sso.template.ts +6 -4
  625. package/src/template/implementations/init_types.template.ts +3 -2
  626. package/src/template/implementations/model.template.ts +4 -2
  627. package/src/template/implementations/model_test.template.ts +3 -2
  628. package/src/template/implementations/queries.template.ts +6 -14
  629. package/src/template/implementations/sd.template.ts +4 -2
  630. package/src/template/implementations/services.template.ts +7 -11
  631. package/src/template/implementations/view_form.template.ts +5 -3
  632. package/src/template/implementations/view_id_all_select.template.ts +3 -2
  633. package/src/template/implementations/view_list.template.ts +7 -5
  634. package/src/template/implementations/view_search_input.template.ts +3 -2
  635. package/src/template/template-manager.ts +4 -3
  636. package/src/template/template.ts +4 -3
  637. package/src/template/zod-converter.ts +10 -7
  638. package/src/testing/__tests__/dev-test-routes.test.ts +3 -2
  639. package/src/testing/__tests__/dev-vitest-manager.test.ts +1 -0
  640. package/src/testing/_relation-graph.ts +2 -2
  641. package/src/testing/bootstrap.ts +55 -27
  642. package/src/testing/data-explorer.ts +5 -4
  643. package/src/testing/dev-test-routes.ts +8 -5
  644. package/src/testing/dev-vitest-manager.ts +13 -12
  645. package/src/testing/fixture-generator.ts +11 -17
  646. package/src/testing/fixture-manager.ts +21 -17
  647. package/src/testing/parallel-db-manager.ts +2 -1
  648. package/src/testing/vitest-helpers.ts +2 -1
  649. package/src/types/__tests__/entity-json-schema-search-text.test.ts +1 -0
  650. package/src/types/types.ts +8 -8
  651. package/src/typings/knex.d.ts +4 -4
  652. package/src/ui/ai-api.ts +5 -3
  653. package/src/ui/ai-client.ts +6 -5
  654. package/src/ui/api.ts +25 -23
  655. package/src/ui/cdd-service.ts +12 -11
  656. package/src/utils/console-util.ts +3 -1
  657. package/src/utils/formatter.ts +94 -102
  658. package/src/utils/fs-utils.ts +2 -1
  659. package/src/utils/model.ts +2 -2
  660. package/src/utils/object-utils.ts +3 -3
  661. package/src/utils/process-utils.ts +2 -1
  662. package/src/utils/sql-parser.ts +10 -1
  663. package/src/utils/type-utils.ts +3 -3
  664. package/src/utils/utils.ts +9 -7
  665. package/src/utils/zod-error.ts +1 -1
  666. package/src/vector/chunking.ts +1 -1
  667. package/src/vector/config.ts +1 -1
  668. package/src/vector/embedding.ts +11 -9
  669. package/tsdown.api.config.ts +50 -0
  670. package/.swcrc.project-default +0 -18
  671. package/dist/api/__tests__/config.test.js +0 -189
  672. package/dist/bin/__tests__/test-command.test.js +0 -112
  673. package/dist/bin/__tests__/ts-loader-register.test.js +0 -45
  674. package/dist/database/puri-subset.test-d.js +0 -89
  675. package/dist/database/puri.types.test-d.js +0 -129
  676. package/dist/migration/__tests__/code-generation.search-text.test.js +0 -435
  677. package/dist/template/__tests__/generated.template.search-text.test.js +0 -99
  678. package/dist/template/generated.template.test-d.js +0 -24
  679. package/dist/testing/__tests__/dev-test-routes.test.js +0 -144
  680. package/dist/testing/__tests__/dev-vitest-manager.test.js +0 -152
  681. package/dist/types/__tests__/entity-json-schema-search-text.test.js +0 -256
  682. package/dist/typings/knex.d.js +0 -3
  683. package/dist/ui-web/assets/index-CKo0Z2Iu.css +0 -1
  684. package/dist/ui-web/assets/index-DK-2aacv.js +0 -257
@@ -1,1231 +1,1025 @@
1
- /** biome-ignore-all lint/suspicious/noThenProperty: Puri는 thenable 인터페이스를 구현하고 있습니다. */ /** biome-ignore-all lint/suspicious/noExplicitAny: Puri는 다양한 타입을 사용하고 있습니다. */ import assert from "assert";
2
- import chalk from "chalk";
1
+ import { __esmMin } from "../_virtual/rolldown_runtime.js";
2
+ import { EntityManager, init_entity_manager } from "../entity/entity-manager.js";
3
+ import { Naite, init_naite } from "../naite/naite.js";
4
+ import { FUZZY_OPERATORS, init_puri_types } from "./puri.types.js";
3
5
  import inflection from "inflection";
4
- import { EntityManager } from "../entity/entity-manager.js";
5
- import { Naite } from "../naite/naite.js";
6
- import { FUZZY_OPERATORS } from "./puri.types.js";
6
+ import assert from "assert";
7
+ import chalk from "chalk";
8
+
9
+ //#region src/database/puri.ts
7
10
  function normalizeFuzzyOperator(operator) {
8
- const normalized = operator?.trim() ?? "<%";
9
- const fuzzyOperator = FUZZY_OPERATORS.find((candidate)=>candidate === normalized);
10
- if (!fuzzyOperator) {
11
- throw new Error(`Invalid fuzzy operator: ${operator ?? ""}`);
12
- }
13
- return fuzzyOperator;
14
- }
15
- export class Puri {
16
- knex;
17
- knexQuery;
18
- tableSpec = null;
19
- constructor(knex, tableNameOrSource){
20
- this.knex = knex;
21
- if (typeof tableNameOrSource === "string") {
22
- // Case: new Puri(knex, "users")
23
- this.knexQuery = this.knex(tableNameOrSource).from(tableNameOrSource);
24
- this.tableSpec = this.safeGetTableSpec(tableNameOrSource);
25
- } else if (typeof tableNameOrSource === "object") {
26
- const entries = Object.entries(tableNameOrSource);
27
- if (entries.length !== 1) {
28
- throw new Error("Table spec must have exactly one entry");
29
- }
30
- assert(entries[0]);
31
- const [alias, source] = entries[0];
32
- if (typeof source === "string") {
33
- this.knexQuery = this.knex(source).from({
34
- [alias]: source
35
- });
36
- this.tableSpec = this.safeGetTableSpec(source);
37
- } else if (source instanceof Puri) {
38
- const subqueryBuilder = source.rawQuery();
39
- this.knexQuery = this.knex.from(subqueryBuilder.as(alias));
40
- } else {
41
- throw new Error("Invalid table specification");
42
- }
43
- } else {
44
- throw new Error("Invalid table specification");
45
- }
46
- }
47
- safeGetTableSpec(tableName) {
48
- try {
49
- return EntityManager.getTableSpec(tableName);
50
- } catch {
51
- return null;
52
- }
53
- }
54
- // Static SQL helper functions for SELECT
55
- static count(column = "*") {
56
- return {
57
- _type: "sql_expression",
58
- _return: "number",
59
- _sql: `COUNT(??)::integer`,
60
- _params: [
61
- column
62
- ]
63
- };
64
- }
65
- static sum(column) {
66
- return {
67
- _type: "sql_expression",
68
- _return: "number",
69
- _sql: `SUM(??)`,
70
- _params: [
71
- column
72
- ]
73
- };
74
- }
75
- static avg(column) {
76
- return {
77
- _type: "sql_expression",
78
- _return: "number",
79
- _sql: `AVG(??)`,
80
- _params: [
81
- column
82
- ]
83
- };
84
- }
85
- static max(column) {
86
- return {
87
- _type: "sql_expression",
88
- _return: "number",
89
- _sql: `MAX(??)`,
90
- _params: [
91
- column
92
- ]
93
- };
94
- }
95
- static min(column) {
96
- return {
97
- _type: "sql_expression",
98
- _return: "number",
99
- _sql: `MIN(??)`,
100
- _params: [
101
- column
102
- ]
103
- };
104
- }
105
- static concat(...args) {
106
- return {
107
- _type: "sql_expression",
108
- _return: "string",
109
- _sql: `CONCAT(${args.map(()=>"?").join(", ")})`,
110
- _params: args
111
- };
112
- }
113
- static upper(column) {
114
- return {
115
- _type: "sql_expression",
116
- _return: "string",
117
- _sql: "UPPER(??)",
118
- _params: [
119
- column
120
- ]
121
- };
122
- }
123
- static lower(column) {
124
- return {
125
- _type: "sql_expression",
126
- _return: "string",
127
- _sql: "LOWER(??)",
128
- _params: [
129
- column
130
- ]
131
- };
132
- }
133
- static wordSimilarity(column, query) {
134
- if (typeof column === "string") {
135
- return {
136
- _type: "sql_expression",
137
- _return: "number",
138
- _sql: "word_similarity(?, ??)",
139
- _params: [
140
- query,
141
- column
142
- ]
143
- };
144
- }
145
- return {
146
- _type: "sql_expression",
147
- _return: "number",
148
- _sql: `word_similarity(?, ${column._sql})`,
149
- _params: [
150
- query,
151
- ...column._params
152
- ]
153
- };
154
- }
155
- static similarity(column, query) {
156
- if (typeof column === "string") {
157
- return {
158
- _type: "sql_expression",
159
- _return: "number",
160
- _sql: "similarity(??, ?)",
161
- _params: [
162
- column,
163
- query
164
- ]
165
- };
166
- }
167
- return {
168
- _type: "sql_expression",
169
- _return: "number",
170
- _sql: `similarity(${column._sql}, ?)`,
171
- _params: [
172
- ...column._params,
173
- query
174
- ]
175
- };
176
- }
177
- static strictWordSimilarity(column, query) {
178
- if (typeof column === "string") {
179
- return {
180
- _type: "sql_expression",
181
- _return: "number",
182
- _sql: `strict_word_similarity(?, ??)`,
183
- _params: [
184
- query,
185
- column
186
- ]
187
- };
188
- }
189
- return {
190
- _type: "sql_expression",
191
- _return: "number",
192
- _sql: `strict_word_similarity(?, ${column._sql})`,
193
- _params: [
194
- query,
195
- ...column._params
196
- ]
197
- };
198
- }
199
- // Raw functions for SELECT
200
- static rawString(sql, params = []) {
201
- return {
202
- _type: "sql_expression",
203
- _return: "string",
204
- _sql: sql,
205
- _params: params
206
- };
207
- }
208
- static rawStringArray(sql, params = []) {
209
- return {
210
- _type: "sql_expression",
211
- _return: "string[]",
212
- _sql: sql,
213
- _params: params
214
- };
215
- }
216
- static rawNumber(sql, params = []) {
217
- return {
218
- _type: "sql_expression",
219
- _return: "number",
220
- _sql: sql,
221
- _params: params
222
- };
223
- }
224
- static rawBoolean(sql, params = []) {
225
- return {
226
- _type: "sql_expression",
227
- _return: "boolean",
228
- _sql: sql,
229
- _params: params
230
- };
231
- }
232
- static rawDate(sql, params = []) {
233
- return {
234
- _type: "sql_expression",
235
- _return: "date",
236
- _sql: sql,
237
- _params: params
238
- };
239
- }
240
- /**
241
- * FTS 검색어 하이라이팅
242
- *
243
- * @example
244
- * .select({
245
- * title: Puri.highlight("posts.title", search),
246
- * content: Puri.highlight("posts.content", search, {
247
- * startSel: "<mark>",
248
- * stopSel: "</mark>",
249
- * maxFragments: 3,
250
- * }),
251
- * })
252
- */ static tsHighlight(column, query, _options) {
253
- const { parser = "websearch_to_tsquery", config = "simple", ...options } = _options ?? {};
254
- const hlOptionParts = Object.entries(options).map(([key, value])=>{
255
- return `${inflection.camelize(key)}=${value}`;
256
- });
257
- const hlOptions = hlOptionParts.length > 0 ? `, '${hlOptionParts.join(", ")}'` : "";
258
- return {
259
- _type: "sql_expression",
260
- _return: "string",
261
- _sql: `ts_headline(?, ??, ${parser}(?, ?)${hlOptions})`,
262
- _params: [
263
- config,
264
- column,
265
- config,
266
- query
267
- ]
268
- };
269
- }
270
- // ts_rank
271
- static tsRank(column, query, options) {
272
- return Puri._tsRank("ts_rank", column, query, options);
273
- }
274
- // ts_rank_cd
275
- static tsRankCd(column, query, options) {
276
- return Puri._tsRank("ts_rank_cd", column, query, options);
277
- }
278
- static toTsVector(column, config = "simple") {
279
- return {
280
- _type: "sql_expression",
281
- _return: "tsvector",
282
- _sql: `to_tsvector(?, ??)`,
283
- _params: [
284
- config,
285
- column
286
- ]
287
- };
288
- }
289
- static _tsRank(type, column, query, options) {
290
- const { parser = "websearch_to_tsquery", config = "simple", normalization, weights } = options ?? {};
291
- const params = [];
292
- let sqlTemplate = `${type}(`;
293
- if (weights) {
294
- sqlTemplate += `ARRAY[${weights.map(()=>"?").join(", ")}]::float4[], `;
295
- params.push(...weights);
296
- }
297
- if (typeof column === "string") {
298
- sqlTemplate += `??, ${parser}(?, ?)`;
299
- params.push(column, config, query);
300
- } else {
301
- sqlTemplate += `${column._sql}, ${parser}(?, ?)`;
302
- params.push(...column._params, config, query);
303
- }
304
- if (normalization) {
305
- sqlTemplate += ", ?";
306
- params.push(normalization);
307
- }
308
- sqlTemplate += ")";
309
- return {
310
- _type: "sql_expression",
311
- _return: "number",
312
- _sql: sqlTemplate,
313
- _params: params
314
- };
315
- }
316
- /**
317
- * PGroonga FullText 인덱스 검색 점수
318
- *
319
- * @example
320
- * .select({
321
- * score: Puri.score(),
322
- * })
323
- */ static score() {
324
- return Puri.rawNumber("pgroonga_score(tableoid, ctid)");
325
- }
326
- static highlight(columnOrColumns, query) {
327
- const queryArr = Array.isArray(query) ? query : [
328
- query
329
- ];
330
- const queryClause = `ARRAY[${queryArr.map(()=>"?").join(", ")}]`;
331
- // 단일 컬럼인 경우
332
- if (typeof columnOrColumns === "string") {
333
- return Puri.rawString(`pgroonga_highlight_html(??, ${queryClause})`, [
334
- columnOrColumns,
335
- ...queryArr
336
- ]);
337
- }
338
- // 컬럼 배열인 경우
339
- return Puri.rawStringArray(`pgroonga_highlight_html(ARRAY[${columnOrColumns.map(()=>"??").join(", ")}], ${queryClause})`, [
340
- ...columnOrColumns,
341
- ...queryArr
342
- ]);
343
- }
344
- // SELECT (overwrite)
345
- select(selectObj) {
346
- // 중첩 객체를 flat하게 변환
347
- const flatSelect = this.flattenSelect(selectObj);
348
- const selectClauses = [];
349
- for (const [alias, columnOrFunction] of Object.entries(flatSelect)){
350
- if (typeof columnOrFunction === "object" && columnOrFunction._type === "sql_expression") {
351
- // SQL 함수인 경우
352
- selectClauses.push(this.knex.raw(`${columnOrFunction._sql} AS "${alias}"`, columnOrFunction._params));
353
- } else {
354
- // 일반 컬럼인 경우
355
- const columnPath = columnOrFunction;
356
- if (alias === columnPath) {
357
- // alias와 컬럼명이 같으면 alias 생략
358
- selectClauses.push(columnPath);
359
- } else {
360
- // alias 지정
361
- selectClauses.push(`${columnPath} AS ${alias}`);
362
- }
363
- }
364
- }
365
- this.knexQuery.select(selectClauses);
366
- return this;
367
- }
368
- /**
369
- * 중첩 객체를 flat 객체로 변환
370
- * 예: { parent: { id: "parent.id", name: "parent.name" } }
371
- * → { parent__id: "parent.id", parent__name: "parent.name" }
372
- */ flattenSelect(selectObj, prefix = "") {
373
- const flatSelect = {};
374
- for (const [key, value] of Object.entries(selectObj)){
375
- const fullKey = prefix ? `${prefix}__${key}` : key;
376
- if (typeof value === "object" && value !== null && !("_type" in value)) {
377
- // 중첩 객체인 경우 - 재귀 처리
378
- const nested = this.flattenSelect(value, fullKey);
379
- Object.assign(flatSelect, nested);
380
- } else {
381
- // 일반 값인 경우 (컬럼 경로 또는 SqlExpression)
382
- flatSelect[fullKey] = value;
383
- }
384
- }
385
- return flatSelect;
386
- }
387
- // SELECT (select는 overwrite, appendSelect는 append)
388
- appendSelect(selectObj) {
389
- // 중첩 객체를 flat하게 변환
390
- const flatSelect = this.flattenSelect(selectObj);
391
- const selectClauses = [];
392
- for (const [alias, columnOrFunction] of Object.entries(flatSelect)){
393
- if (typeof columnOrFunction === "object" && columnOrFunction._type === "sql_expression") {
394
- selectClauses.push(this.knex.raw(`${columnOrFunction._sql} AS ${alias}`, columnOrFunction._params));
395
- } else {
396
- const columnPath = columnOrFunction;
397
- if (alias === columnPath) {
398
- selectClauses.push(columnPath);
399
- } else {
400
- selectClauses.push(this.knex.ref(columnPath).as(alias));
401
- }
402
- }
403
- }
404
- this.knexQuery.select(selectClauses);
405
- return this;
406
- }
407
- // SELECT *
408
- selectAll() {
409
- this.knexQuery.select("*");
410
- return this;
411
- }
412
- distinct(...columns) {
413
- this.knexQuery.distinct(...columns);
414
- return this;
415
- }
416
- // CLEAR
417
- clear(statement) {
418
- this.knexQuery.clear(statement);
419
- return this;
420
- }
421
- // knex에 없어서 직접 구현함
422
- clearJoin(alias) {
423
- this.knexQuery._statements = this.knexQuery._statements.filter((s)=>{
424
- if ("joinType" in s) {
425
- const [_alias, _table] = Object.entries(s.table)[0];
426
- return _alias !== alias;
427
- } else {
428
- return true;
429
- }
430
- });
431
- return this;
432
- }
433
- // JOIN 실제 구현
434
- join(tableNameOrSpec, ...args) {
435
- return this.__commonJoin("join", tableNameOrSpec, ...args);
436
- }
437
- // LEFT JOIN 실제 구현
438
- leftJoin(tableNameOrSpec, ...args) {
439
- return this.__commonJoin("leftJoin", tableNameOrSpec, ...args);
440
- }
441
- __commonJoin(joinType, tableNameOrSpec, ...args) {
442
- if (typeof tableNameOrSpec === "string") {
443
- // Case 1: join("posts", ...)
444
- const tableName = tableNameOrSpec;
445
- if (args.length === 1 && typeof args[0] === "function") {
446
- // join("posts", callback)
447
- const callback = args[0];
448
- this.knexQuery[joinType](tableName, (joinClause)=>{
449
- callback(new JoinClauseGroup(joinClause));
450
- });
451
- } else {
452
- // join("posts", left, right)
453
- const [left, right] = args;
454
- this.knexQuery[joinType](tableName, left, right);
455
- }
456
- } else if (typeof tableNameOrSpec === "object") {
457
- // Case 2: join({ alias: "table" }, ...) or join({ alias: subquery }, ...)
458
- const entries = Object.entries(tableNameOrSpec);
459
- if (entries.length !== 1) {
460
- throw new Error("Table spec must have exactly one entry");
461
- }
462
- assert(entries[0]);
463
- const [[alias, spec]] = entries;
464
- if (typeof spec === "string") {
465
- // 테이블: join({ p: "posts" }, ...)
466
- if (args.length === 1 && typeof args[0] === "function") {
467
- // Callback
468
- const callback = args[0];
469
- this.knexQuery[joinType]({
470
- [alias]: spec
471
- }, (joinClause)=>{
472
- callback(new JoinClauseGroup(joinClause));
473
- });
474
- } else {
475
- // Simple
476
- const [left, right] = args;
477
- this.knexQuery[joinType]({
478
- [alias]: spec
479
- }, left, right);
480
- }
481
- } else if (spec instanceof Puri) {
482
- // 서브쿼리: join({ sq: subquery }, ...)
483
- if (args.length === 1 && typeof args[0] === "function") {
484
- // Callback
485
- const callback = args[0];
486
- this.knexQuery[joinType](spec.rawQuery().as(alias), (joinClause)=>{
487
- callback(new JoinClauseGroup(joinClause));
488
- });
489
- } else {
490
- // Simple
491
- const [left, right] = args;
492
- this.knexQuery[joinType](spec.rawQuery().as(alias), left, right);
493
- }
494
- } else {
495
- throw new Error("Invalid table specification");
496
- }
497
- } else {
498
- throw new Error("Invalid arguments");
499
- }
500
- return this;
501
- }
502
- // WHERE: 컬럼 - 사용: .where("u.id", "like", "%test%")
503
- where(...args) {
504
- const [columnOrConditions, operatorOrValue, value] = args;
505
- if (typeof columnOrConditions === "object") {
506
- this.knexQuery.where(columnOrConditions);
507
- } else if (typeof value === "undefined") {
508
- if (operatorOrValue === null) {
509
- this.knexQuery.whereNull(columnOrConditions);
510
- return this;
511
- }
512
- this.knexQuery.where(columnOrConditions, operatorOrValue);
513
- } else if (typeof value !== "undefined") {
514
- if (value === null) {
515
- if (operatorOrValue === "!=") {
516
- this.knexQuery.whereNotNull(columnOrConditions);
517
- return this;
518
- } else if (operatorOrValue === "=") {
519
- this.knexQuery.whereNull(columnOrConditions);
520
- return this;
521
- }
522
- }
523
- this.knexQuery.where(columnOrConditions, operatorOrValue, value);
524
- } else {
525
- this.knexQuery.where(columnOrConditions);
526
- }
527
- return this;
528
- }
529
- // WHERE IN
530
- whereIn(column, values) {
531
- this.knexQuery.whereIn(column, values);
532
- return this;
533
- }
534
- // WHERE NOT IN
535
- whereNotIn(column, values) {
536
- this.knexQuery.whereNotIn(column, values);
537
- return this;
538
- }
539
- // WHERE MATCH
540
- whereMatch(column, value) {
541
- this.knexQuery.whereRaw(`MATCH (${String(column)}) AGAINST (?)`, [
542
- value
543
- ]);
544
- return this;
545
- }
546
- /**
547
- * PGroonga FullText 인덱스 검색
548
- * - 사용할 PGroonga 인덱스와 동일한 컬럼 구성으로 검색해야 인덱스가 사용됩니다.
549
- *
550
- * 단일 컬럼 검색:
551
- * ```sql
552
- * WHERE name &@~ 'search'
553
- * ```
554
- *
555
- * 복합 컬럼 검색:
556
- * ```sql
557
- * WHERE ARRAY[name::text, description::text] &@~ 'search'
558
- * ```
559
- */ whereSearch(column, value, options) {
560
- const { weights } = options ?? {};
561
- const columnExpr = Array.isArray(column) ? `ARRAY[${column.map((c)=>`${c}::text`).join(",")}]` : column;
562
- const pgroongaCondition = `pgroonga_condition(?${weights?.length ? `, weights => ARRAY[${weights.join(",")}]` : ""})`;
563
- this.knexQuery.whereRaw(`${columnExpr} &@~ ${pgroongaCondition}`, [
564
- value
565
- ]);
566
- return this;
567
- }
568
- // WHERE FULLTEXT
569
- whereTsSearch(column, value, options) {
570
- const opts = typeof options === "string" ? {
571
- config: options
572
- } : options ?? {};
573
- const parser = opts.parser ?? "websearch_to_tsquery";
574
- const config = opts.config ?? "simple";
575
- const columnExpr = typeof column === "object" && column._type === "sql_expression" ? column._sql : String(column);
576
- this.knexQuery.whereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [
577
- config,
578
- value
579
- ]);
580
- return this;
581
- }
582
- whereFuzzy(column, value, options) {
583
- const operator = normalizeFuzzyOperator(options?.operator);
584
- if (operator === "%") {
585
- if (typeof column === "object") {
586
- this.knexQuery.whereRaw(`${column._sql} ${operator} ?`, [
587
- ...column._params,
588
- value
589
- ]);
590
- } else {
591
- this.knexQuery.whereRaw(`?? ${operator} ?`, [
592
- column,
593
- value
594
- ]);
595
- }
596
- return this;
597
- }
598
- if (typeof column === "object") {
599
- this.knexQuery.whereRaw(`? ${operator} ${column._sql}`, [
600
- value,
601
- ...column._params
602
- ]);
603
- } else {
604
- this.knexQuery.whereRaw(`? ${operator} ??`, [
605
- value,
606
- column
607
- ]);
608
- }
609
- return this;
610
- }
611
- // WHERE RAW
612
- whereRaw(sql, bindings) {
613
- this.knexQuery.whereRaw(sql, bindings);
614
- return this;
615
- }
616
- // WHERE 괄호 그룹핑
617
- whereGroup(callback) {
618
- this.knexQuery.where((builder)=>{
619
- const group = new WhereGroup(builder);
620
- callback(group);
621
- });
622
- return this;
623
- }
624
- orWhereGroup(callback) {
625
- this.knexQuery.orWhere((builder)=>{
626
- const group = new WhereGroup(builder);
627
- callback(group);
628
- });
629
- return this;
630
- }
631
- orderBy(column, direction = "asc") {
632
- if (typeof column === "object") {
633
- this.knexQuery.orderByRaw(`${column._sql} ${direction}`, column._params);
634
- } else {
635
- this.knexQuery.orderBy(column, direction);
636
- }
637
- return this;
638
- }
639
- /**
640
- * 벡터 유사도 검색 설정
641
- *
642
- * - SELECT에 similarity 컬럼 추가
643
- * - WHERE col IS NOT NULL 추가
644
- * - threshold가 있으면 WHERE 조건 추가
645
- * - 기존 ORDER BY를 clear하고 원시 연산자로 정렬 (HNSW 인덱스 최적화)
646
- *
647
- * @param column 벡터 컬럼 경로
648
- * @param embedding 쿼리 임베딩 벡터
649
- * @param options method, threshold, as 등 옵션
650
- *
651
- * @example
652
- * ```typescript
653
- * // cosine similarity (기본값)
654
- * qb.vectorSimilarity("columnName", queryVector, {
655
- * method: "cosine",
656
- * threshold: 0.5
657
- * });
658
- *
659
- * // L2 distance
660
- * qb.vectorSimilarity("columnName", queryVector, {
661
- * method: "l2",
662
- * threshold: 1.5 // 거리가 1.5 이하인 결과만
663
- * });
664
- *
665
- * // Inner product
666
- * qb.vectorSimilarity("columnName", queryVector, {
667
- * method: "inner_product",
668
- * threshold: 0.7
669
- * });
670
- * ```
671
- */ vectorSimilarity(column, embedding, options = {}) {
672
- const { method = "cosine", threshold, distinctOn } = options;
673
- if (!Array.isArray(embedding) || embedding.length === 0 || embedding.some((v)=>!Number.isFinite(v))) {
674
- throw new Error("Invalid embedding vector: expected a non-empty array of finite numbers");
675
- }
676
- const vectorLiteral = JSON.stringify(embedding.map((v)=>Number(v)));
677
- const operator = {
678
- cosine: "<=>",
679
- l2: "<->",
680
- inner_product: "<#>"
681
- }[method];
682
- // method별 연산자 및 similarity 계산식
683
- // - cosine: <=> (cosine distance, 0~2), similarity = 1 - distance
684
- // - l2: <-> (euclidean distance), similarity = distance (낮을수록 유사)
685
- // - inner_product: <#> (negative inner product), similarity = -distance (높을수록 유사)
686
- const similarityExpr = method === "cosine" ? this.knex.raw(`1 - (?? ${operator} ?::vector) as similarity`, [
687
- column,
688
- vectorLiteral
689
- ]) : method === "l2" ? this.knex.raw(`?? ${operator} ?::vector as similarity`, [
690
- column,
691
- vectorLiteral
692
- ]) : this.knex.raw(`-(?? ${operator} ?::vector) as similarity`, [
693
- column,
694
- vectorLiteral
695
- ]);
696
- // WHERE NOT NULL
697
- this.knexQuery.whereNotNull(column);
698
- // 기존 ORDER BY clear
699
- this.knexQuery.clear("order");
700
- if (distinctOn) {
701
- // DISTINCT ON은 SELECT 절의 맨 앞에 와야 하므로, 기존 select(subset 필드들)를 보존 후 clear하고 다시 추가
702
- const existingSubsetCols = this.knexQuery._statements.filter((s)=>s.grouping === "columns").flatMap((s)=>s.value);
703
- this.knexQuery.clear("select");
704
- this.knexQuery.select(this.knex.raw(`DISTINCT ON (??) ??`, [
705
- distinctOn,
706
- distinctOn
707
- ]));
708
- existingSubsetCols.map((col)=>this.knexQuery.select(col));
709
- this.knexQuery.select(similarityExpr);
710
- this.knexQuery.orderByRaw(`??, ?? ${operator} ?::vector`, [
711
- distinctOn,
712
- column,
713
- vectorLiteral
714
- ]);
715
- this.knexQuery = this.knex.from(this.knexQuery.as("distinct_vectors")).select("*").orderBy("similarity", "desc");
716
- } else {
717
- this.knexQuery.select(similarityExpr);
718
- this.knexQuery.orderByRaw(`?? ${operator} ?::vector`, [
719
- column,
720
- vectorLiteral
721
- ]);
722
- }
723
- // threshold
724
- if (typeof threshold === "number") {
725
- if (!Number.isFinite(threshold)) {
726
- throw new Error(`Invalid vectorSimilarity threshold: ${threshold}`);
727
- }
728
- if (distinctOn) {
729
- const thresholdOp = method === "l2" ? "<=" : ">=";
730
- this.knexQuery.where("similarity", thresholdOp, threshold);
731
- } else {
732
- const thresholdValue = method === "cosine" ? 1 - threshold : method === "inner_product" ? -threshold : threshold;
733
- this.knexQuery.whereRaw(`?? ${operator} ?::vector <= ?`, [
734
- column,
735
- vectorLiteral,
736
- thresholdValue
737
- ]);
738
- }
739
- }
740
- return this;
741
- }
742
- // 기본 쿼리 메서드들
743
- limit(count) {
744
- if (count < 0) {
745
- throw new Error("Invalid limit: must be >= 0");
746
- }
747
- this.knexQuery.limit(count);
748
- return this;
749
- }
750
- offset(count) {
751
- if (count < 0) {
752
- throw new Error("Invalid offset: must be >= 0");
753
- }
754
- this.knexQuery.offset(count);
755
- return this;
756
- }
757
- groupBy(...columns) {
758
- this.knexQuery.groupBy(...columns);
759
- return this;
760
- }
761
- // HAVING 구현
762
- having(...conditions) {
763
- if (conditions.length === 1) {
764
- // having("COUNT(*) > 10")
765
- this.knexQuery.having(this.knex.raw(conditions[0]));
766
- } else if (conditions.length === 3) {
767
- // having("count", ">", 10)
768
- this.knexQuery.having(this.knex.raw(conditions[0]), conditions[1], this.knex.raw(conditions[2]));
769
- } else {
770
- throw new Error("Invalid having arguments");
771
- }
772
- return this;
773
- }
774
- // 실행 메서드들 - thenable 구현
775
- then(onfulfilled, onrejected) {
776
- Naite.t("puri:executed-query", this.toQuery());
777
- return this.knexQuery.then(onfulfilled, onrejected);
778
- }
779
- catch(onrejected) {
780
- return this.knexQuery.catch(onrejected);
781
- }
782
- finally(onfinally) {
783
- return this.knexQuery.finally(onfinally);
784
- }
785
- // 하나만 쿼리
786
- first() {
787
- this.knexQuery.first();
788
- return new ResolvedPuri(this.knexQuery, this.knex);
789
- }
790
- // 쿼리한 레코드에서 특정 컬럼만 추출한 배열 리턴
791
- pluck(column) {
792
- this.knexQuery.pluck(column);
793
- return new ResolvedPuri(this.knexQuery, this.knex);
794
- }
795
- // INSERT 실제 구현
796
- insert(rawData) {
797
- // JSON 컬럼 stringify 로직을 메서드로 분리하여 중복 제거
798
- const refinedData = this.refineJsonColumns(rawData);
799
- this.knexQuery.insert(refinedData);
800
- return new ResolvedPuri(this.knexQuery, this.knex);
801
- }
802
- // UPDATE
803
- update(rawData) {
804
- // JSON 컬럼 stringify 로직을 메서드로 분리하여 중복 제거
805
- const refinedData = this.refineJsonColumns(rawData);
806
- this.knexQuery.update(refinedData);
807
- return new ResolvedPuri(this.knexQuery, this.knex);
808
- }
809
- /**
810
- * JSON 컬럼에 대해 stringify 처리를 수행하는 내부 메서드입니다.
811
- * object 또는 object 배열을 받고, JSON 컬럼이 있으면 직렬화하여 반환합니다.
812
- * 직접 값을 변경하므로 side effect가 있습니다.
813
- */ refineJsonColumns(data) {
814
- // tableSpec이나 jsonColumns 없는 경우 바로 반환
815
- if (!this.tableSpec || !this.tableSpec.jsonColumns.length) {
816
- return data;
817
- }
818
- // 등록된 TableSpec을 통해 JSON컬럼 목록을 가져와 JSON.stringify 처리
819
- const jsonColumns = this.tableSpec.jsonColumns;
820
- if (Array.isArray(data)) {
821
- for (const item of data){
822
- for (const column of jsonColumns){
823
- const value = item[column];
824
- if (value !== undefined && value !== null) {
825
- item[column] = JSON.stringify(value);
826
- }
827
- }
828
- }
829
- } else {
830
- for (const column of jsonColumns){
831
- const value = data[column];
832
- if (value !== undefined && value !== null) {
833
- data[column] = JSON.stringify(value);
834
- }
835
- }
836
- }
837
- return data;
838
- }
839
- // Increment
840
- increment(column, value) {
841
- if (value <= 0) {
842
- throw new Error("Increment value must be greater than 0");
843
- }
844
- this.knexQuery.increment(column, value);
845
- return new ResolvedPuri(this.knexQuery, this.knex);
846
- }
847
- // Decrement
848
- decrement(column, value) {
849
- if (value <= 0) {
850
- throw new Error("Decrement value must be greater than 0");
851
- }
852
- this.knexQuery.decrement(column, value);
853
- return new ResolvedPuri(this.knexQuery, this.knex);
854
- }
855
- // DELETE
856
- delete() {
857
- this.knexQuery.delete();
858
- return new ResolvedPuri(this.knexQuery, this.knex);
859
- }
860
- // 확인 쿼리 리턴
861
- toQuery() {
862
- return this.knexQuery.toQuery();
863
- }
864
- // 쿼리 디버깅 로그 출력
865
- debug() {
866
- console.log(`${chalk.cyan("[Puri Debug]")} ${chalk.yellow(this.toQuery())}`);
867
- return this;
868
- }
869
- clone() {
870
- // 'dual'은 더미 테이블이며, 바로 아래 줄에서 knexQuery가 덮어씌워집니다.
871
- const newPuri = new Puri(this.knex, "dual");
872
- newPuri.knexQuery = this.knexQuery.clone();
873
- return newPuri;
874
- }
875
- formatSQL(unformatted) {
876
- // SQL 예약어 목록
877
- const keywords = [
878
- "SELECT",
879
- "FROM",
880
- "WHERE",
881
- "INSERT",
882
- "INTO",
883
- "VALUES",
884
- "UPDATE",
885
- "DELETE",
886
- "CREATE",
887
- "TABLE",
888
- "ALTER",
889
- "DROP",
890
- "JOIN",
891
- "ON",
892
- "INNER",
893
- "LEFT",
894
- "RIGHT",
895
- "FULL",
896
- "OUTER",
897
- "GROUP",
898
- "BY",
899
- "ORDER",
900
- "HAVING",
901
- "DISTINCT",
902
- "LIMIT",
903
- "OFFSET",
904
- "AS",
905
- "AND",
906
- "OR",
907
- "NOT",
908
- "IN",
909
- "LIKE",
910
- "IS",
911
- "NULL",
912
- "CASE",
913
- "WHEN",
914
- "THEN",
915
- "ELSE",
916
- "END",
917
- "UNION",
918
- "ALL",
919
- "EXISTS",
920
- "BETWEEN"
921
- ];
922
- let formatted = unformatted;
923
- // 예약어를 대문자로 변환
924
- keywords.forEach((keyword)=>{
925
- const regex = new RegExp(`\\b${keyword}\\b`, "gi");
926
- formatted = formatted.replace(regex, keyword.toUpperCase());
927
- });
928
- // 주요 절 앞에 줄바꿈 추가
929
- const majorClauses = [
930
- "SELECT",
931
- "FROM",
932
- "WHERE",
933
- "GROUP BY",
934
- "ORDER BY",
935
- "HAVING",
936
- "LIMIT",
937
- "UNION"
938
- ];
939
- majorClauses.forEach((clause)=>{
940
- const regex = new RegExp(`\\s+(${clause})\\s+`, "gi");
941
- formatted = formatted.replace(regex, `\n${clause.toUpperCase()} `);
942
- });
943
- // JOIN 절 처리
944
- formatted = formatted.replace(/\s+((?:INNER|LEFT|RIGHT|FULL OUTER)\s+)?JOIN\s+/gi, "\n$1JOIN ");
945
- // AND, OR 조건 처리
946
- formatted = formatted.replace(/\s+(AND|OR)\s+/gi, "\n $1 ");
947
- // 괄호 처리 및 들여쓰기
948
- const lines = formatted.split("\n");
949
- const indentedLines = [];
950
- let indentLevel = 0;
951
- for (const line of lines){
952
- const trimmedLine = line.trim();
953
- if (!trimmedLine) continue;
954
- // 닫는 괄호가 있으면 들여쓰기 레벨 감소
955
- const closingParens = (trimmedLine.match(/\)/g) || []).length;
956
- const openingParens = (trimmedLine.match(/\(/g) || []).length;
957
- if (closingParens > 0 && openingParens === 0) {
958
- indentLevel = Math.max(0, indentLevel - closingParens);
959
- }
960
- // 현재 들여쓰기 적용
961
- const indent = " ".repeat(indentLevel);
962
- indentedLines.push(indent + trimmedLine);
963
- // 여는 괄호가 있으면 들여쓰기 레벨 증가
964
- if (openingParens > closingParens) {
965
- indentLevel += openingParens - closingParens;
966
- }
967
- }
968
- return indentedLines.join("\n").trim();
969
- }
970
- raw(sql) {
971
- return this.knex.raw(sql);
972
- }
973
- // Knex 쿼리 빌더 직접 접근
974
- rawQuery() {
975
- return this.knexQuery;
976
- }
977
- }
978
- export class WhereGroup {
979
- builder;
980
- constructor(builder){
981
- this.builder = builder;
982
- }
983
- where(...args) {
984
- this.builder.where(args[0], ...args.slice(1));
985
- return this;
986
- }
987
- whereIn(...args) {
988
- this.builder.whereIn(args[0], args[1]);
989
- return this;
990
- }
991
- whereNotIn(...args) {
992
- this.builder.whereNotIn(args[0], args[1]);
993
- return this;
994
- }
995
- orWhere(...args) {
996
- this.builder.orWhere(args[0], ...args.slice(1));
997
- return this;
998
- }
999
- orWhereIn(...args) {
1000
- this.builder.orWhereIn(args[0], args[1]);
1001
- return this;
1002
- }
1003
- orWhereNotIn(...args) {
1004
- this.builder.orWhereNotIn(args[0], args[1]);
1005
- return this;
1006
- }
1007
- whereMatch(...args) {
1008
- this.builder.whereRaw(`MATCH (${String(args[0])}) AGAINST (?)`, [
1009
- args[1]
1010
- ]);
1011
- return this;
1012
- }
1013
- orWhereMatch(...args) {
1014
- this.builder.orWhereRaw(`MATCH (${String(args[0])}) AGAINST (?)`, [
1015
- args[1]
1016
- ]);
1017
- return this;
1018
- }
1019
- whereSearch(...args) {
1020
- const { weights } = args[2] ?? {};
1021
- const columnExpr = Array.isArray(args[0]) ? `ARRAY[${args[0].map((c)=>`${c}::text`).join(",")}]` : args[0];
1022
- const pgroongaCondition = `pgroonga_condition(?${weights?.length ? `, weights => ARRAY[${weights.join(",")}]` : ""})`;
1023
- this.builder.whereRaw(`${columnExpr} &@~ ${pgroongaCondition}`, [
1024
- args[1]
1025
- ]);
1026
- return this;
1027
- }
1028
- orWhereSearch(...args) {
1029
- const { weights } = args[2] ?? {};
1030
- const columnExpr = Array.isArray(args[0]) ? `ARRAY[${args[0].map((c)=>`${c}::text`).join(",")}]` : args[0];
1031
- const pgroongaCondition = `pgroonga_condition(?${weights?.length ? `, weights => ARRAY[${weights.join(",")}]` : ""})`;
1032
- this.builder.orWhereRaw(`${columnExpr} &@~ ${pgroongaCondition}`, [
1033
- args[1]
1034
- ]);
1035
- return this;
1036
- }
1037
- whereTsSearch(...args) {
1038
- const opts = typeof args[2] === "string" ? {
1039
- config: args[2]
1040
- } : args[2] ?? {};
1041
- const parser = opts.parser ?? "websearch_to_tsquery";
1042
- const config = opts.config ?? "simple";
1043
- const columnExpr = typeof args[0] === "object" && args[0]._type === "sql_expression" ? args[0]._sql : String(args[0]);
1044
- this.builder.whereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [
1045
- config,
1046
- args[1]
1047
- ]);
1048
- return this;
1049
- }
1050
- orWhereTsSearch(...args) {
1051
- const opts = typeof args[2] === "string" ? {
1052
- config: args[2]
1053
- } : args[2] ?? {};
1054
- const parser = opts.parser ?? "websearch_to_tsquery";
1055
- const config = opts.config ?? "simple";
1056
- const columnExpr = typeof args[0] === "object" && args[0]._type === "sql_expression" ? args[0]._sql : String(args[0]);
1057
- this.builder.orWhereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [
1058
- config,
1059
- args[1]
1060
- ]);
1061
- return this;
1062
- }
1063
- whereFuzzy(...args) {
1064
- const operator = normalizeFuzzyOperator(args[2]?.operator);
1065
- if (operator === "%") {
1066
- if (typeof args[0] === "object") {
1067
- this.builder.whereRaw(`${args[0]._sql} ${operator} ?`, [
1068
- ...args[0]._params,
1069
- args[1]
1070
- ]);
1071
- } else {
1072
- this.builder.whereRaw(`?? ${operator} ?`, [
1073
- args[0],
1074
- args[1]
1075
- ]);
1076
- }
1077
- return this;
1078
- }
1079
- if (typeof args[0] === "object") {
1080
- this.builder.whereRaw(`? ${operator} ${args[0]._sql}`, [
1081
- args[1],
1082
- ...args[0]._params
1083
- ]);
1084
- } else {
1085
- this.builder.whereRaw(`? ${operator} ??`, [
1086
- args[1],
1087
- args[0]
1088
- ]);
1089
- }
1090
- return this;
1091
- }
1092
- orWhereFuzzy(...args) {
1093
- const operator = normalizeFuzzyOperator(args[2]?.operator);
1094
- if (operator === "%") {
1095
- if (typeof args[0] === "object") {
1096
- this.builder.orWhereRaw(`${args[0]._sql} ${operator} ?`, [
1097
- ...args[0]._params,
1098
- args[1]
1099
- ]);
1100
- } else {
1101
- this.builder.orWhereRaw(`?? ${operator} ?`, [
1102
- args[0],
1103
- args[1]
1104
- ]);
1105
- }
1106
- return this;
1107
- }
1108
- if (typeof args[0] === "object") {
1109
- this.builder.orWhereRaw(`? ${operator} ${args[0]._sql}`, [
1110
- args[1],
1111
- ...args[0]._params
1112
- ]);
1113
- } else {
1114
- this.builder.orWhereRaw(`? ${operator} ??`, [
1115
- args[1],
1116
- args[0]
1117
- ]);
1118
- }
1119
- return this;
1120
- }
1121
- whereGroup(callback) {
1122
- this.builder.where((subBuilder)=>{
1123
- const subGroup = new WhereGroup(subBuilder);
1124
- callback(subGroup);
1125
- });
1126
- return this;
1127
- }
1128
- orWhereGroup(callback) {
1129
- this.builder.orWhere((subBuilder)=>{
1130
- const subGroup = new WhereGroup(subBuilder);
1131
- callback(subGroup);
1132
- });
1133
- return this;
1134
- }
1135
- }
1136
- // JOIN 절 그룹에는 Left와 Right에 대한 순서가 필요하지 않으므로, 모든 경우의 수를 계산해야함.
1137
- export class JoinClauseGroup {
1138
- callback;
1139
- constructor(callback){
1140
- this.callback = callback;
1141
- }
1142
- // ON(AND) 구현
1143
- on(...args) {
1144
- this.callback.on(...args);
1145
- return this;
1146
- }
1147
- // ON(OR) 구현
1148
- orOn(...args) {
1149
- this.callback.orOn(...args);
1150
- return this;
1151
- }
1152
- onVal(...args) {
1153
- this.callback.onVal(...args);
1154
- return this;
1155
- }
1156
- andOnVal(...args) {
1157
- this.callback.andOnVal(...args);
1158
- return this;
1159
- }
1160
- orOnVal(...args) {
1161
- this.callback.orOnVal(...args);
1162
- return this;
1163
- }
1164
- }
1165
- /*
1166
- TResolved: 쿼리 실행 후 반환될 결과 타입
1167
- TReturning: RETURNING 절에 사용될 타입
1168
- */ export class ResolvedPuri {
1169
- knexQuery;
1170
- knex;
1171
- constructor(knexQuery, knex){
1172
- this.knexQuery = knexQuery;
1173
- this.knex = knex;
1174
- }
1175
- [Symbol.toStringTag] = "Promise";
1176
- toQuery() {
1177
- return this.knexQuery.toQuery();
1178
- }
1179
- debug() {
1180
- console.log(`${chalk.cyan("[Puri Debug]")} ${chalk.yellow(this.toQuery())}`);
1181
- return this;
1182
- }
1183
- then(onfulfilled, onrejected) {
1184
- Naite.t("puri:executed-query", this.toQuery());
1185
- return this.knexQuery.then(onfulfilled, onrejected);
1186
- }
1187
- catch(onrejected) {
1188
- return this.knexQuery.catch(onrejected);
1189
- }
1190
- finally(onfinally) {
1191
- return this.knexQuery.finally(onfinally);
1192
- }
1193
- // ON CONFLICT - 컬럼 기반
1194
- onConflict(columns, action) {
1195
- const target = Array.isArray(columns) ? columns : [
1196
- columns
1197
- ];
1198
- if (!action || action === "nothing") {
1199
- // DO NOTHING
1200
- this.knexQuery.onConflict(target).ignore();
1201
- } else {
1202
- // DO UPDATE
1203
- const { update } = action;
1204
- // action.update 배열 형태 : ["name", "email"]
1205
- if (Array.isArray(update)) {
1206
- this.knexQuery.onConflict(target).merge(update);
1207
- } else {
1208
- // action.update 객체 형태: { name: "John", count: raw(...) }
1209
- const mergeObj = {};
1210
- for (const [key, value] of Object.entries(update)){
1211
- if (value && typeof value === "object" && "_type" in value && value._type === "sql_expression") {
1212
- // SqlExpression → knex.raw()로 변환
1213
- mergeObj[key] = this.knex.raw(value._sql);
1214
- } else {
1215
- // 일반 값
1216
- mergeObj[key] = value;
1217
- }
1218
- }
1219
- this.knexQuery.onConflict(target).merge(mergeObj);
1220
- }
1221
- }
1222
- return this;
1223
- }
1224
- // RETURNING 구현
1225
- returning(columnOrColumns) {
1226
- this.knexQuery.returning(columnOrColumns);
1227
- return new ResolvedPuri(this.knexQuery, this.knex);
1228
- }
11
+ const normalized = operator?.trim() ?? "<%";
12
+ const fuzzyOperator = FUZZY_OPERATORS.find((candidate) => candidate === normalized);
13
+ if (!fuzzyOperator) {
14
+ throw new Error(`Invalid fuzzy operator: ${operator ?? ""}`);
15
+ }
16
+ return fuzzyOperator;
1229
17
  }
18
+ var Puri, WhereGroup, JoinClauseGroup, ResolvedPuri;
19
+ var init_puri = __esmMin((() => {
20
+ init_entity_manager();
21
+ init_naite();
22
+ init_puri_types();
23
+ Puri = class Puri {
24
+ knexQuery;
25
+ tableSpec = null;
26
+ constructor(knex, tableNameOrSource) {
27
+ this.knex = knex;
28
+ if (typeof tableNameOrSource === "string") {
29
+ this.knexQuery = this.knex(tableNameOrSource).from(tableNameOrSource);
30
+ this.tableSpec = this.safeGetTableSpec(tableNameOrSource);
31
+ } else if (typeof tableNameOrSource === "object") {
32
+ const entries = Object.entries(tableNameOrSource);
33
+ if (entries.length !== 1) {
34
+ throw new Error("Table spec must have exactly one entry");
35
+ }
36
+ assert(entries[0]);
37
+ const [alias, source] = entries[0];
38
+ if (typeof source === "string") {
39
+ this.knexQuery = this.knex(source).from({ [alias]: source });
40
+ this.tableSpec = this.safeGetTableSpec(source);
41
+ } else if (source instanceof Puri) {
42
+ const subqueryBuilder = source.rawQuery();
43
+ this.knexQuery = this.knex.from(subqueryBuilder.as(alias));
44
+ } else {
45
+ throw new Error("Invalid table specification");
46
+ }
47
+ } else {
48
+ throw new Error("Invalid table specification");
49
+ }
50
+ }
51
+ safeGetTableSpec(tableName) {
52
+ try {
53
+ return EntityManager.getTableSpec(tableName);
54
+ } catch {
55
+ return null;
56
+ }
57
+ }
58
+ static count(column = "*") {
59
+ return {
60
+ _type: "sql_expression",
61
+ _return: "number",
62
+ _sql: `COUNT(??)::integer`,
63
+ _params: [column]
64
+ };
65
+ }
66
+ static sum(column) {
67
+ return {
68
+ _type: "sql_expression",
69
+ _return: "number",
70
+ _sql: `SUM(??)`,
71
+ _params: [column]
72
+ };
73
+ }
74
+ static avg(column) {
75
+ return {
76
+ _type: "sql_expression",
77
+ _return: "number",
78
+ _sql: `AVG(??)`,
79
+ _params: [column]
80
+ };
81
+ }
82
+ static max(column) {
83
+ return {
84
+ _type: "sql_expression",
85
+ _return: "number",
86
+ _sql: `MAX(??)`,
87
+ _params: [column]
88
+ };
89
+ }
90
+ static min(column) {
91
+ return {
92
+ _type: "sql_expression",
93
+ _return: "number",
94
+ _sql: `MIN(??)`,
95
+ _params: [column]
96
+ };
97
+ }
98
+ static concat(...args) {
99
+ return {
100
+ _type: "sql_expression",
101
+ _return: "string",
102
+ _sql: `CONCAT(${args.map(() => "?").join(", ")})`,
103
+ _params: args
104
+ };
105
+ }
106
+ static upper(column) {
107
+ return {
108
+ _type: "sql_expression",
109
+ _return: "string",
110
+ _sql: "UPPER(??)",
111
+ _params: [column]
112
+ };
113
+ }
114
+ static lower(column) {
115
+ return {
116
+ _type: "sql_expression",
117
+ _return: "string",
118
+ _sql: "LOWER(??)",
119
+ _params: [column]
120
+ };
121
+ }
122
+ static wordSimilarity(column, query) {
123
+ if (typeof column === "string") {
124
+ return {
125
+ _type: "sql_expression",
126
+ _return: "number",
127
+ _sql: "word_similarity(?, ??)",
128
+ _params: [query, column]
129
+ };
130
+ }
131
+ return {
132
+ _type: "sql_expression",
133
+ _return: "number",
134
+ _sql: `word_similarity(?, ${column._sql})`,
135
+ _params: [query, ...column._params]
136
+ };
137
+ }
138
+ static similarity(column, query) {
139
+ if (typeof column === "string") {
140
+ return {
141
+ _type: "sql_expression",
142
+ _return: "number",
143
+ _sql: "similarity(??, ?)",
144
+ _params: [column, query]
145
+ };
146
+ }
147
+ return {
148
+ _type: "sql_expression",
149
+ _return: "number",
150
+ _sql: `similarity(${column._sql}, ?)`,
151
+ _params: [...column._params, query]
152
+ };
153
+ }
154
+ static strictWordSimilarity(column, query) {
155
+ if (typeof column === "string") {
156
+ return {
157
+ _type: "sql_expression",
158
+ _return: "number",
159
+ _sql: `strict_word_similarity(?, ??)`,
160
+ _params: [query, column]
161
+ };
162
+ }
163
+ return {
164
+ _type: "sql_expression",
165
+ _return: "number",
166
+ _sql: `strict_word_similarity(?, ${column._sql})`,
167
+ _params: [query, ...column._params]
168
+ };
169
+ }
170
+ static rawString(sql, params = []) {
171
+ return {
172
+ _type: "sql_expression",
173
+ _return: "string",
174
+ _sql: sql,
175
+ _params: params
176
+ };
177
+ }
178
+ static rawStringArray(sql, params = []) {
179
+ return {
180
+ _type: "sql_expression",
181
+ _return: "string[]",
182
+ _sql: sql,
183
+ _params: params
184
+ };
185
+ }
186
+ static rawNumber(sql, params = []) {
187
+ return {
188
+ _type: "sql_expression",
189
+ _return: "number",
190
+ _sql: sql,
191
+ _params: params
192
+ };
193
+ }
194
+ static rawBoolean(sql, params = []) {
195
+ return {
196
+ _type: "sql_expression",
197
+ _return: "boolean",
198
+ _sql: sql,
199
+ _params: params
200
+ };
201
+ }
202
+ static rawDate(sql, params = []) {
203
+ return {
204
+ _type: "sql_expression",
205
+ _return: "date",
206
+ _sql: sql,
207
+ _params: params
208
+ };
209
+ }
210
+ /**
211
+ * FTS 검색어 하이라이팅
212
+ *
213
+ * @example
214
+ * .select({
215
+ * title: Puri.highlight("posts.title", search),
216
+ * content: Puri.highlight("posts.content", search, {
217
+ * startSel: "<mark>",
218
+ * stopSel: "</mark>",
219
+ * maxFragments: 3,
220
+ * }),
221
+ * })
222
+ */
223
+ static tsHighlight(column, query, _options) {
224
+ const { parser = "websearch_to_tsquery", config = "simple", ...options } = _options ?? {};
225
+ const hlOptionParts = Object.entries(options).map(([key, value]) => {
226
+ return `${inflection.camelize(key)}=${value}`;
227
+ });
228
+ const hlOptions = hlOptionParts.length > 0 ? `, '${hlOptionParts.join(", ")}'` : "";
229
+ return {
230
+ _type: "sql_expression",
231
+ _return: "string",
232
+ _sql: `ts_headline(?, ??, ${parser}(?, ?)${hlOptions})`,
233
+ _params: [
234
+ config,
235
+ column,
236
+ config,
237
+ query
238
+ ]
239
+ };
240
+ }
241
+ static tsRank(column, query, options) {
242
+ return Puri._tsRank("ts_rank", column, query, options);
243
+ }
244
+ static tsRankCd(column, query, options) {
245
+ return Puri._tsRank("ts_rank_cd", column, query, options);
246
+ }
247
+ static toTsVector(column, config = "simple") {
248
+ return {
249
+ _type: "sql_expression",
250
+ _return: "tsvector",
251
+ _sql: `to_tsvector(?, ??)`,
252
+ _params: [config, column]
253
+ };
254
+ }
255
+ static _tsRank(type, column, query, options) {
256
+ const { parser = "websearch_to_tsquery", config = "simple", normalization, weights } = options ?? {};
257
+ const params = [];
258
+ let sqlTemplate = `${type}(`;
259
+ if (weights) {
260
+ sqlTemplate += `ARRAY[${weights.map(() => "?").join(", ")}]::float4[], `;
261
+ params.push(...weights);
262
+ }
263
+ if (typeof column === "string") {
264
+ sqlTemplate += `??, ${parser}(?, ?)`;
265
+ params.push(column, config, query);
266
+ } else {
267
+ sqlTemplate += `${column._sql}, ${parser}(?, ?)`;
268
+ params.push(...column._params, config, query);
269
+ }
270
+ if (normalization) {
271
+ sqlTemplate += ", ?";
272
+ params.push(normalization);
273
+ }
274
+ sqlTemplate += ")";
275
+ return {
276
+ _type: "sql_expression",
277
+ _return: "number",
278
+ _sql: sqlTemplate,
279
+ _params: params
280
+ };
281
+ }
282
+ /**
283
+ * PGroonga FullText 인덱스 검색 점수
284
+ *
285
+ * @example
286
+ * .select({
287
+ * score: Puri.score(),
288
+ * })
289
+ */
290
+ static score() {
291
+ return Puri.rawNumber("pgroonga_score(tableoid, ctid)");
292
+ }
293
+ static highlight(columnOrColumns, query) {
294
+ const queryArr = Array.isArray(query) ? query : [query];
295
+ const queryClause = `ARRAY[${queryArr.map(() => "?").join(", ")}]`;
296
+ if (typeof columnOrColumns === "string") {
297
+ return Puri.rawString(`pgroonga_highlight_html(??, ${queryClause})`, [columnOrColumns, ...queryArr]);
298
+ }
299
+ return Puri.rawStringArray(`pgroonga_highlight_html(ARRAY[${columnOrColumns.map(() => "??").join(", ")}], ${queryClause})`, [...columnOrColumns, ...queryArr]);
300
+ }
301
+ select(selectObj) {
302
+ const flatSelect = this.flattenSelect(selectObj);
303
+ const selectClauses = [];
304
+ for (const [alias, columnOrFunction] of Object.entries(flatSelect)) {
305
+ if (typeof columnOrFunction === "object" && columnOrFunction._type === "sql_expression") {
306
+ selectClauses.push(this.knex.raw(`${columnOrFunction._sql} AS "${alias}"`, columnOrFunction._params));
307
+ } else {
308
+ const columnPath = columnOrFunction;
309
+ if (alias === columnPath) {
310
+ selectClauses.push(columnPath);
311
+ } else {
312
+ selectClauses.push(`${columnPath} AS ${alias}`);
313
+ }
314
+ }
315
+ }
316
+ this.knexQuery.select(selectClauses);
317
+ return this;
318
+ }
319
+ /**
320
+ * 중첩 객체를 flat 객체로 변환
321
+ * 예: { parent: { id: "parent.id", name: "parent.name" } }
322
+ * → { parent__id: "parent.id", parent__name: "parent.name" }
323
+ */
324
+ flattenSelect(selectObj, prefix = "") {
325
+ const flatSelect = {};
326
+ for (const [key, value] of Object.entries(selectObj)) {
327
+ const fullKey = prefix ? `${prefix}__${key}` : key;
328
+ if (typeof value === "object" && value !== null && !("_type" in value)) {
329
+ const nested = this.flattenSelect(value, fullKey);
330
+ Object.assign(flatSelect, nested);
331
+ } else {
332
+ flatSelect[fullKey] = value;
333
+ }
334
+ }
335
+ return flatSelect;
336
+ }
337
+ appendSelect(selectObj) {
338
+ const flatSelect = this.flattenSelect(selectObj);
339
+ const selectClauses = [];
340
+ for (const [alias, columnOrFunction] of Object.entries(flatSelect)) {
341
+ if (typeof columnOrFunction === "object" && columnOrFunction._type === "sql_expression") {
342
+ selectClauses.push(this.knex.raw(`${columnOrFunction._sql} AS ${alias}`, columnOrFunction._params));
343
+ } else {
344
+ const columnPath = columnOrFunction;
345
+ if (alias === columnPath) {
346
+ selectClauses.push(columnPath);
347
+ } else {
348
+ selectClauses.push(this.knex.ref(columnPath).as(alias));
349
+ }
350
+ }
351
+ }
352
+ this.knexQuery.select(selectClauses);
353
+ return this;
354
+ }
355
+ selectAll() {
356
+ this.knexQuery.select("*");
357
+ return this;
358
+ }
359
+ distinct(...columns) {
360
+ this.knexQuery.distinct(...columns);
361
+ return this;
362
+ }
363
+ clear(statement) {
364
+ this.knexQuery.clear(statement);
365
+ return this;
366
+ }
367
+ clearJoin(alias) {
368
+ this.knexQuery._statements = this.knexQuery._statements.filter((s) => {
369
+ if ("joinType" in s) {
370
+ const [_alias, _table] = Object.entries(s.table)[0];
371
+ return _alias !== alias;
372
+ } else {
373
+ return true;
374
+ }
375
+ });
376
+ return this;
377
+ }
378
+ join(tableNameOrSpec, ...args) {
379
+ return this.__commonJoin("join", tableNameOrSpec, ...args);
380
+ }
381
+ leftJoin(tableNameOrSpec, ...args) {
382
+ return this.__commonJoin("leftJoin", tableNameOrSpec, ...args);
383
+ }
384
+ __commonJoin(joinType, tableNameOrSpec, ...args) {
385
+ if (typeof tableNameOrSpec === "string") {
386
+ const tableName = tableNameOrSpec;
387
+ if (args.length === 1 && typeof args[0] === "function") {
388
+ const callback = args[0];
389
+ this.knexQuery[joinType](tableName, (joinClause) => {
390
+ callback(new JoinClauseGroup(joinClause));
391
+ });
392
+ } else {
393
+ const [left, right] = args;
394
+ this.knexQuery[joinType](tableName, left, right);
395
+ }
396
+ } else if (typeof tableNameOrSpec === "object") {
397
+ const entries = Object.entries(tableNameOrSpec);
398
+ if (entries.length !== 1) {
399
+ throw new Error("Table spec must have exactly one entry");
400
+ }
401
+ assert(entries[0]);
402
+ const [[alias, spec]] = entries;
403
+ if (typeof spec === "string") {
404
+ if (args.length === 1 && typeof args[0] === "function") {
405
+ const callback = args[0];
406
+ this.knexQuery[joinType]({ [alias]: spec }, (joinClause) => {
407
+ callback(new JoinClauseGroup(joinClause));
408
+ });
409
+ } else {
410
+ const [left, right] = args;
411
+ this.knexQuery[joinType]({ [alias]: spec }, left, right);
412
+ }
413
+ } else if (spec instanceof Puri) {
414
+ if (args.length === 1 && typeof args[0] === "function") {
415
+ const callback = args[0];
416
+ this.knexQuery[joinType](spec.rawQuery().as(alias), (joinClause) => {
417
+ callback(new JoinClauseGroup(joinClause));
418
+ });
419
+ } else {
420
+ const [left, right] = args;
421
+ this.knexQuery[joinType](spec.rawQuery().as(alias), left, right);
422
+ }
423
+ } else {
424
+ throw new Error("Invalid table specification");
425
+ }
426
+ } else {
427
+ throw new Error("Invalid arguments");
428
+ }
429
+ return this;
430
+ }
431
+ where(...args) {
432
+ const [columnOrConditions, operatorOrValue, value] = args;
433
+ if (typeof columnOrConditions === "object") {
434
+ this.knexQuery.where(columnOrConditions);
435
+ } else if (typeof value === "undefined") {
436
+ if (operatorOrValue === null) {
437
+ this.knexQuery.whereNull(columnOrConditions);
438
+ return this;
439
+ }
440
+ this.knexQuery.where(columnOrConditions, operatorOrValue);
441
+ } else if (typeof value !== "undefined") {
442
+ if (value === null) {
443
+ if (operatorOrValue === "!=") {
444
+ this.knexQuery.whereNotNull(columnOrConditions);
445
+ return this;
446
+ } else if (operatorOrValue === "=") {
447
+ this.knexQuery.whereNull(columnOrConditions);
448
+ return this;
449
+ }
450
+ }
451
+ this.knexQuery.where(columnOrConditions, operatorOrValue, value);
452
+ } else {
453
+ this.knexQuery.where(columnOrConditions);
454
+ }
455
+ return this;
456
+ }
457
+ whereIn(column, values) {
458
+ this.knexQuery.whereIn(column, values);
459
+ return this;
460
+ }
461
+ whereNotIn(column, values) {
462
+ this.knexQuery.whereNotIn(column, values);
463
+ return this;
464
+ }
465
+ whereMatch(column, value) {
466
+ this.knexQuery.whereRaw(`MATCH (${String(column)}) AGAINST (?)`, [value]);
467
+ return this;
468
+ }
469
+ /**
470
+ * PGroonga FullText 인덱스 검색
471
+ * - 사용할 PGroonga 인덱스와 동일한 컬럼 구성으로 검색해야 인덱스가 사용됩니다.
472
+ *
473
+ * 단일 컬럼 검색:
474
+ * ```sql
475
+ * WHERE name &@~ 'search'
476
+ * ```
477
+ *
478
+ * 복합 컬럼 검색:
479
+ * ```sql
480
+ * WHERE ARRAY[name::text, description::text] &@~ 'search'
481
+ * ```
482
+ */
483
+ whereSearch(column, value, options) {
484
+ const { weights } = options ?? {};
485
+ const columnExpr = Array.isArray(column) ? `ARRAY[${column.map((c) => `${c}::text`).join(",")}]` : column;
486
+ const pgroongaCondition = `pgroonga_condition(?${weights?.length ? `, weights => ARRAY[${weights.join(",")}]` : ""})`;
487
+ this.knexQuery.whereRaw(`${columnExpr} &@~ ${pgroongaCondition}`, [value]);
488
+ return this;
489
+ }
490
+ whereTsSearch(column, value, options) {
491
+ const opts = typeof options === "string" ? { config: options } : options ?? {};
492
+ const parser = opts.parser ?? "websearch_to_tsquery";
493
+ const config = opts.config ?? "simple";
494
+ const columnExpr = typeof column === "object" && column._type === "sql_expression" ? column._sql : String(column);
495
+ this.knexQuery.whereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [config, value]);
496
+ return this;
497
+ }
498
+ whereFuzzy(column, value, options) {
499
+ const operator = normalizeFuzzyOperator(options?.operator);
500
+ if (operator === "%") {
501
+ if (typeof column === "object") {
502
+ this.knexQuery.whereRaw(`${column._sql} ${operator} ?`, [...column._params, value]);
503
+ } else {
504
+ this.knexQuery.whereRaw(`?? ${operator} ?`, [column, value]);
505
+ }
506
+ return this;
507
+ }
508
+ if (typeof column === "object") {
509
+ this.knexQuery.whereRaw(`? ${operator} ${column._sql}`, [value, ...column._params]);
510
+ } else {
511
+ this.knexQuery.whereRaw(`? ${operator} ??`, [value, column]);
512
+ }
513
+ return this;
514
+ }
515
+ whereRaw(sql, bindings) {
516
+ this.knexQuery.whereRaw(sql, bindings);
517
+ return this;
518
+ }
519
+ whereGroup(callback) {
520
+ this.knexQuery.where((builder) => {
521
+ const group = new WhereGroup(builder);
522
+ callback(group);
523
+ });
524
+ return this;
525
+ }
526
+ orWhereGroup(callback) {
527
+ this.knexQuery.orWhere((builder) => {
528
+ const group = new WhereGroup(builder);
529
+ callback(group);
530
+ });
531
+ return this;
532
+ }
533
+ orderBy(column, direction = "asc") {
534
+ if (typeof column === "object") {
535
+ this.knexQuery.orderByRaw(`${column._sql} ${direction}`, column._params);
536
+ } else {
537
+ this.knexQuery.orderBy(column, direction);
538
+ }
539
+ return this;
540
+ }
541
+ /**
542
+ * 벡터 유사도 검색 설정
543
+ *
544
+ * - SELECT에 similarity 컬럼 추가
545
+ * - WHERE col IS NOT NULL 추가
546
+ * - threshold가 있으면 WHERE 조건 추가
547
+ * - 기존 ORDER BY를 clear하고 원시 연산자로 정렬 (HNSW 인덱스 최적화)
548
+ *
549
+ * @param column 벡터 컬럼 경로
550
+ * @param embedding 쿼리 임베딩 벡터
551
+ * @param options method, threshold, as 등 옵션
552
+ *
553
+ * @example
554
+ * ```typescript
555
+ * // cosine similarity (기본값)
556
+ * qb.vectorSimilarity("columnName", queryVector, {
557
+ * method: "cosine",
558
+ * threshold: 0.5
559
+ * });
560
+ *
561
+ * // L2 distance
562
+ * qb.vectorSimilarity("columnName", queryVector, {
563
+ * method: "l2",
564
+ * threshold: 1.5 // 거리가 1.5 이하인 결과만
565
+ * });
566
+ *
567
+ * // Inner product
568
+ * qb.vectorSimilarity("columnName", queryVector, {
569
+ * method: "inner_product",
570
+ * threshold: 0.7
571
+ * });
572
+ * ```
573
+ */
574
+ vectorSimilarity(column, embedding, options = {}) {
575
+ const { method = "cosine", threshold, distinctOn } = options;
576
+ if (!Array.isArray(embedding) || embedding.length === 0 || embedding.some((v) => !Number.isFinite(v))) {
577
+ throw new Error("Invalid embedding vector: expected a non-empty array of finite numbers");
578
+ }
579
+ const vectorLiteral = JSON.stringify(embedding.map((v) => Number(v)));
580
+ const operator = {
581
+ cosine: "<=>",
582
+ l2: "<->",
583
+ inner_product: "<#>"
584
+ }[method];
585
+ const similarityExpr = method === "cosine" ? this.knex.raw(`1 - (?? ${operator} ?::vector) as similarity`, [column, vectorLiteral]) : method === "l2" ? this.knex.raw(`?? ${operator} ?::vector as similarity`, [column, vectorLiteral]) : this.knex.raw(`-(?? ${operator} ?::vector) as similarity`, [column, vectorLiteral]);
586
+ this.knexQuery.whereNotNull(column);
587
+ this.knexQuery.clear("order");
588
+ if (distinctOn) {
589
+ const existingSubsetCols = this.knexQuery._statements.filter((s) => s.grouping === "columns").flatMap((s) => s.value);
590
+ this.knexQuery.clear("select");
591
+ this.knexQuery.select(this.knex.raw(`DISTINCT ON (??) ??`, [distinctOn, distinctOn]));
592
+ existingSubsetCols.map((col) => this.knexQuery.select(col));
593
+ this.knexQuery.select(similarityExpr);
594
+ this.knexQuery.orderByRaw(`??, ?? ${operator} ?::vector`, [
595
+ distinctOn,
596
+ column,
597
+ vectorLiteral
598
+ ]);
599
+ this.knexQuery = this.knex.from(this.knexQuery.as("distinct_vectors")).select("*").orderBy("similarity", "desc");
600
+ } else {
601
+ this.knexQuery.select(similarityExpr);
602
+ this.knexQuery.orderByRaw(`?? ${operator} ?::vector`, [column, vectorLiteral]);
603
+ }
604
+ if (typeof threshold === "number") {
605
+ if (!Number.isFinite(threshold)) {
606
+ throw new Error(`Invalid vectorSimilarity threshold: ${threshold}`);
607
+ }
608
+ if (distinctOn) {
609
+ const thresholdOp = method === "l2" ? "<=" : ">=";
610
+ this.knexQuery.where("similarity", thresholdOp, threshold);
611
+ } else {
612
+ const thresholdValue = method === "cosine" ? 1 - threshold : method === "inner_product" ? -threshold : threshold;
613
+ this.knexQuery.whereRaw(`?? ${operator} ?::vector <= ?`, [
614
+ column,
615
+ vectorLiteral,
616
+ thresholdValue
617
+ ]);
618
+ }
619
+ }
620
+ return this;
621
+ }
622
+ limit(count) {
623
+ if (count < 0) {
624
+ throw new Error("Invalid limit: must be >= 0");
625
+ }
626
+ this.knexQuery.limit(count);
627
+ return this;
628
+ }
629
+ offset(count) {
630
+ if (count < 0) {
631
+ throw new Error("Invalid offset: must be >= 0");
632
+ }
633
+ this.knexQuery.offset(count);
634
+ return this;
635
+ }
636
+ groupBy(...columns) {
637
+ this.knexQuery.groupBy(...columns);
638
+ return this;
639
+ }
640
+ having(...conditions) {
641
+ if (conditions.length === 1) {
642
+ this.knexQuery.having(this.knex.raw(conditions[0]));
643
+ } else if (conditions.length === 3) {
644
+ this.knexQuery.having(this.knex.raw(conditions[0]), conditions[1], this.knex.raw(conditions[2]));
645
+ } else {
646
+ throw new Error("Invalid having arguments");
647
+ }
648
+ return this;
649
+ }
650
+ then(onfulfilled, onrejected) {
651
+ Naite.t("puri:executed-query", this.toQuery());
652
+ return this.knexQuery.then(onfulfilled, onrejected);
653
+ }
654
+ catch(onrejected) {
655
+ return this.knexQuery.catch(onrejected);
656
+ }
657
+ finally(onfinally) {
658
+ return this.knexQuery.finally(onfinally);
659
+ }
660
+ first() {
661
+ this.knexQuery.first();
662
+ return new ResolvedPuri(this.knexQuery, this.knex);
663
+ }
664
+ pluck(column) {
665
+ this.knexQuery.pluck(column);
666
+ return new ResolvedPuri(this.knexQuery, this.knex);
667
+ }
668
+ insert(rawData) {
669
+ const refinedData = this.refineJsonColumns(rawData);
670
+ this.knexQuery.insert(refinedData);
671
+ return new ResolvedPuri(this.knexQuery, this.knex);
672
+ }
673
+ update(rawData) {
674
+ const refinedData = this.refineJsonColumns(rawData);
675
+ this.knexQuery.update(refinedData);
676
+ return new ResolvedPuri(this.knexQuery, this.knex);
677
+ }
678
+ /**
679
+ * JSON 컬럼에 대해 stringify 처리를 수행하는 내부 메서드입니다.
680
+ * object 또는 object 배열을 받고, JSON 컬럼이 있으면 직렬화하여 반환합니다.
681
+ * 직접 값을 변경하므로 side effect가 있습니다.
682
+ */
683
+ refineJsonColumns(data) {
684
+ if (!this.tableSpec || !this.tableSpec.jsonColumns.length) {
685
+ return data;
686
+ }
687
+ const jsonColumns = this.tableSpec.jsonColumns;
688
+ if (Array.isArray(data)) {
689
+ for (const item of data) {
690
+ for (const column of jsonColumns) {
691
+ const value = item[column];
692
+ if (value !== undefined && value !== null) {
693
+ item[column] = JSON.stringify(value);
694
+ }
695
+ }
696
+ }
697
+ } else {
698
+ for (const column of jsonColumns) {
699
+ const value = data[column];
700
+ if (value !== undefined && value !== null) {
701
+ data[column] = JSON.stringify(value);
702
+ }
703
+ }
704
+ }
705
+ return data;
706
+ }
707
+ increment(column, value) {
708
+ if (value <= 0) {
709
+ throw new Error("Increment value must be greater than 0");
710
+ }
711
+ this.knexQuery.increment(column, value);
712
+ return new ResolvedPuri(this.knexQuery, this.knex);
713
+ }
714
+ decrement(column, value) {
715
+ if (value <= 0) {
716
+ throw new Error("Decrement value must be greater than 0");
717
+ }
718
+ this.knexQuery.decrement(column, value);
719
+ return new ResolvedPuri(this.knexQuery, this.knex);
720
+ }
721
+ delete() {
722
+ this.knexQuery.delete();
723
+ return new ResolvedPuri(this.knexQuery, this.knex);
724
+ }
725
+ toQuery() {
726
+ return this.knexQuery.toQuery();
727
+ }
728
+ debug() {
729
+ console.log(`${chalk.cyan("[Puri Debug]")} ${chalk.yellow(this.toQuery())}`);
730
+ return this;
731
+ }
732
+ clone() {
733
+ const newPuri = new Puri(this.knex, "dual");
734
+ newPuri.knexQuery = this.knexQuery.clone();
735
+ return newPuri;
736
+ }
737
+ formatSQL(unformatted) {
738
+ const keywords = [
739
+ "SELECT",
740
+ "FROM",
741
+ "WHERE",
742
+ "INSERT",
743
+ "INTO",
744
+ "VALUES",
745
+ "UPDATE",
746
+ "DELETE",
747
+ "CREATE",
748
+ "TABLE",
749
+ "ALTER",
750
+ "DROP",
751
+ "JOIN",
752
+ "ON",
753
+ "INNER",
754
+ "LEFT",
755
+ "RIGHT",
756
+ "FULL",
757
+ "OUTER",
758
+ "GROUP",
759
+ "BY",
760
+ "ORDER",
761
+ "HAVING",
762
+ "DISTINCT",
763
+ "LIMIT",
764
+ "OFFSET",
765
+ "AS",
766
+ "AND",
767
+ "OR",
768
+ "NOT",
769
+ "IN",
770
+ "LIKE",
771
+ "IS",
772
+ "NULL",
773
+ "CASE",
774
+ "WHEN",
775
+ "THEN",
776
+ "ELSE",
777
+ "END",
778
+ "UNION",
779
+ "ALL",
780
+ "EXISTS",
781
+ "BETWEEN"
782
+ ];
783
+ let formatted = unformatted;
784
+ keywords.forEach((keyword) => {
785
+ const regex = new RegExp(`\\b${keyword}\\b`, "gi");
786
+ formatted = formatted.replace(regex, keyword.toUpperCase());
787
+ });
788
+ const majorClauses = [
789
+ "SELECT",
790
+ "FROM",
791
+ "WHERE",
792
+ "GROUP BY",
793
+ "ORDER BY",
794
+ "HAVING",
795
+ "LIMIT",
796
+ "UNION"
797
+ ];
798
+ majorClauses.forEach((clause) => {
799
+ const regex = new RegExp(`\\s+(${clause})\\s+`, "gi");
800
+ formatted = formatted.replace(regex, `\n${clause.toUpperCase()} `);
801
+ });
802
+ formatted = formatted.replace(/\s+((?:INNER|LEFT|RIGHT|FULL OUTER)\s+)?JOIN\s+/gi, "\n$1JOIN ");
803
+ formatted = formatted.replace(/\s+(AND|OR)\s+/gi, "\n $1 ");
804
+ const lines = formatted.split("\n");
805
+ const indentedLines = [];
806
+ let indentLevel = 0;
807
+ for (const line of lines) {
808
+ const trimmedLine = line.trim();
809
+ if (!trimmedLine) continue;
810
+ const closingParens = (trimmedLine.match(/\)/g) || []).length;
811
+ const openingParens = (trimmedLine.match(/\(/g) || []).length;
812
+ if (closingParens > 0 && openingParens === 0) {
813
+ indentLevel = Math.max(0, indentLevel - closingParens);
814
+ }
815
+ const indent = " ".repeat(indentLevel);
816
+ indentedLines.push(indent + trimmedLine);
817
+ if (openingParens > closingParens) {
818
+ indentLevel += openingParens - closingParens;
819
+ }
820
+ }
821
+ return indentedLines.join("\n").trim();
822
+ }
823
+ raw(sql) {
824
+ return this.knex.raw(sql);
825
+ }
826
+ rawQuery() {
827
+ return this.knexQuery;
828
+ }
829
+ };
830
+ WhereGroup = class WhereGroup {
831
+ constructor(builder) {
832
+ this.builder = builder;
833
+ }
834
+ where(...args) {
835
+ this.builder.where(args[0], ...args.slice(1));
836
+ return this;
837
+ }
838
+ whereIn(...args) {
839
+ this.builder.whereIn(args[0], args[1]);
840
+ return this;
841
+ }
842
+ whereNotIn(...args) {
843
+ this.builder.whereNotIn(args[0], args[1]);
844
+ return this;
845
+ }
846
+ orWhere(...args) {
847
+ this.builder.orWhere(args[0], ...args.slice(1));
848
+ return this;
849
+ }
850
+ orWhereIn(...args) {
851
+ this.builder.orWhereIn(args[0], args[1]);
852
+ return this;
853
+ }
854
+ orWhereNotIn(...args) {
855
+ this.builder.orWhereNotIn(args[0], args[1]);
856
+ return this;
857
+ }
858
+ whereMatch(...args) {
859
+ this.builder.whereRaw(`MATCH (${String(args[0])}) AGAINST (?)`, [args[1]]);
860
+ return this;
861
+ }
862
+ orWhereMatch(...args) {
863
+ this.builder.orWhereRaw(`MATCH (${String(args[0])}) AGAINST (?)`, [args[1]]);
864
+ return this;
865
+ }
866
+ whereSearch(...args) {
867
+ const { weights } = args[2] ?? {};
868
+ const columnExpr = Array.isArray(args[0]) ? `ARRAY[${args[0].map((c) => `${c}::text`).join(",")}]` : args[0];
869
+ const pgroongaCondition = `pgroonga_condition(?${weights?.length ? `, weights => ARRAY[${weights.join(",")}]` : ""})`;
870
+ this.builder.whereRaw(`${columnExpr} &@~ ${pgroongaCondition}`, [args[1]]);
871
+ return this;
872
+ }
873
+ orWhereSearch(...args) {
874
+ const { weights } = args[2] ?? {};
875
+ const columnExpr = Array.isArray(args[0]) ? `ARRAY[${args[0].map((c) => `${c}::text`).join(",")}]` : args[0];
876
+ const pgroongaCondition = `pgroonga_condition(?${weights?.length ? `, weights => ARRAY[${weights.join(",")}]` : ""})`;
877
+ this.builder.orWhereRaw(`${columnExpr} &@~ ${pgroongaCondition}`, [args[1]]);
878
+ return this;
879
+ }
880
+ whereTsSearch(...args) {
881
+ const opts = typeof args[2] === "string" ? { config: args[2] } : args[2] ?? {};
882
+ const parser = opts.parser ?? "websearch_to_tsquery";
883
+ const config = opts.config ?? "simple";
884
+ const columnExpr = typeof args[0] === "object" && args[0]._type === "sql_expression" ? args[0]._sql : String(args[0]);
885
+ this.builder.whereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [config, args[1]]);
886
+ return this;
887
+ }
888
+ orWhereTsSearch(...args) {
889
+ const opts = typeof args[2] === "string" ? { config: args[2] } : args[2] ?? {};
890
+ const parser = opts.parser ?? "websearch_to_tsquery";
891
+ const config = opts.config ?? "simple";
892
+ const columnExpr = typeof args[0] === "object" && args[0]._type === "sql_expression" ? args[0]._sql : String(args[0]);
893
+ this.builder.orWhereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [config, args[1]]);
894
+ return this;
895
+ }
896
+ whereFuzzy(...args) {
897
+ const operator = normalizeFuzzyOperator(args[2]?.operator);
898
+ if (operator === "%") {
899
+ if (typeof args[0] === "object") {
900
+ this.builder.whereRaw(`${args[0]._sql} ${operator} ?`, [...args[0]._params, args[1]]);
901
+ } else {
902
+ this.builder.whereRaw(`?? ${operator} ?`, [args[0], args[1]]);
903
+ }
904
+ return this;
905
+ }
906
+ if (typeof args[0] === "object") {
907
+ this.builder.whereRaw(`? ${operator} ${args[0]._sql}`, [args[1], ...args[0]._params]);
908
+ } else {
909
+ this.builder.whereRaw(`? ${operator} ??`, [args[1], args[0]]);
910
+ }
911
+ return this;
912
+ }
913
+ orWhereFuzzy(...args) {
914
+ const operator = normalizeFuzzyOperator(args[2]?.operator);
915
+ if (operator === "%") {
916
+ if (typeof args[0] === "object") {
917
+ this.builder.orWhereRaw(`${args[0]._sql} ${operator} ?`, [...args[0]._params, args[1]]);
918
+ } else {
919
+ this.builder.orWhereRaw(`?? ${operator} ?`, [args[0], args[1]]);
920
+ }
921
+ return this;
922
+ }
923
+ if (typeof args[0] === "object") {
924
+ this.builder.orWhereRaw(`? ${operator} ${args[0]._sql}`, [args[1], ...args[0]._params]);
925
+ } else {
926
+ this.builder.orWhereRaw(`? ${operator} ??`, [args[1], args[0]]);
927
+ }
928
+ return this;
929
+ }
930
+ whereGroup(callback) {
931
+ this.builder.where((subBuilder) => {
932
+ const subGroup = new WhereGroup(subBuilder);
933
+ callback(subGroup);
934
+ });
935
+ return this;
936
+ }
937
+ orWhereGroup(callback) {
938
+ this.builder.orWhere((subBuilder) => {
939
+ const subGroup = new WhereGroup(subBuilder);
940
+ callback(subGroup);
941
+ });
942
+ return this;
943
+ }
944
+ };
945
+ JoinClauseGroup = class {
946
+ constructor(callback) {
947
+ this.callback = callback;
948
+ }
949
+ on(...args) {
950
+ this.callback.on(...args);
951
+ return this;
952
+ }
953
+ orOn(...args) {
954
+ this.callback.orOn(...args);
955
+ return this;
956
+ }
957
+ onVal(...args) {
958
+ this.callback.onVal(...args);
959
+ return this;
960
+ }
961
+ andOnVal(...args) {
962
+ this.callback.andOnVal(...args);
963
+ return this;
964
+ }
965
+ orOnVal(...args) {
966
+ this.callback.orOnVal(...args);
967
+ return this;
968
+ }
969
+ };
970
+ ResolvedPuri = class ResolvedPuri {
971
+ constructor(knexQuery, knex) {
972
+ this.knexQuery = knexQuery;
973
+ this.knex = knex;
974
+ }
975
+ [Symbol.toStringTag] = "Promise";
976
+ toQuery() {
977
+ return this.knexQuery.toQuery();
978
+ }
979
+ debug() {
980
+ console.log(`${chalk.cyan("[Puri Debug]")} ${chalk.yellow(this.toQuery())}`);
981
+ return this;
982
+ }
983
+ then(onfulfilled, onrejected) {
984
+ Naite.t("puri:executed-query", this.toQuery());
985
+ return this.knexQuery.then(onfulfilled, onrejected);
986
+ }
987
+ catch(onrejected) {
988
+ return this.knexQuery.catch(onrejected);
989
+ }
990
+ finally(onfinally) {
991
+ return this.knexQuery.finally(onfinally);
992
+ }
993
+ onConflict(columns, action) {
994
+ const target = Array.isArray(columns) ? columns : [columns];
995
+ if (!action || action === "nothing") {
996
+ this.knexQuery.onConflict(target).ignore();
997
+ } else {
998
+ const { update } = action;
999
+ if (Array.isArray(update)) {
1000
+ this.knexQuery.onConflict(target).merge(update);
1001
+ } else {
1002
+ const mergeObj = {};
1003
+ for (const [key, value] of Object.entries(update)) {
1004
+ if (value && typeof value === "object" && "_type" in value && value._type === "sql_expression") {
1005
+ mergeObj[key] = this.knex.raw(value._sql);
1006
+ } else {
1007
+ mergeObj[key] = value;
1008
+ }
1009
+ }
1010
+ this.knexQuery.onConflict(target).merge(mergeObj);
1011
+ }
1012
+ }
1013
+ return this;
1014
+ }
1015
+ returning(columnOrColumns) {
1016
+ this.knexQuery.returning(columnOrColumns);
1017
+ return new ResolvedPuri(this.knexQuery, this.knex);
1018
+ }
1019
+ };
1020
+ }));
1230
1021
 
1231
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYXRhYmFzZS9wdXJpLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKiBiaW9tZS1pZ25vcmUtYWxsIGxpbnQvc3VzcGljaW91cy9ub1RoZW5Qcm9wZXJ0eTogUHVyaeuKlCB0aGVuYWJsZSDsnbjthLDtjpjsnbTsiqTrpbwg6rWs7ZiE7ZWY6rOgIOyeiOyKteuLiOuLpC4gKi9cbi8qKiBiaW9tZS1pZ25vcmUtYWxsIGxpbnQvc3VzcGljaW91cy9ub0V4cGxpY2l0QW55OiBQdXJp64qUIOuLpOyWke2VnCDtg4DsnoXsnYQg7IKs7Jqp7ZWY6rOgIOyeiOyKteuLiOuLpC4gKi9cblxuaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgY2hhbGsgZnJvbSBcImNoYWxrXCI7XG5pbXBvcnQgaW5mbGVjdGlvbiBmcm9tIFwiaW5mbGVjdGlvblwiO1xuaW1wb3J0IHR5cGUgeyBLbmV4IH0gZnJvbSBcImtuZXhcIjtcbmltcG9ydCB7IEVudGl0eU1hbmFnZXIsIHR5cGUgVGFibGVTcGVjIH0gZnJvbSBcIi4uL2VudGl0eS9lbnRpdHktbWFuYWdlclwiO1xuaW1wb3J0IHsgTmFpdGUgfSBmcm9tIFwiLi4vbmFpdGUvbmFpdGVcIjtcbmltcG9ydCB0eXBlIHtcbiAgQXZhaWxhYmxlQ29sdW1ucyxcbiAgQ29sdW1uS2V5cyxcbiAgQ29tcGFyaXNvbk9wZXJhdG9yLFxuICBFeHBhbmQsXG4gIEV4dHJhY3RDb2x1bW5UeXBlLFxuICBGdWxsdGV4dENvbHVtbnMsXG4gIEZ1enp5T3BlcmF0b3IsXG4gIEluc2VydERhdGEsXG4gIEluc2VydFJlc3VsdCxcbiAgTGVmdEpvaW5lZE1hcmtlcixcbiAgTGVmdEpvaW5NYXJrZXJGb3IsXG4gIE51bWVyaWNDb2x1bW5zLFxuICBPbkNvbmZsaWN0QWN0aW9uLFxuICBQYXJzZVNlbGVjdE9iamVjdCxcbiAgUmVzdWx0QXZhaWxhYmxlQ29sdW1ucyxcbiAgU2VsZWN0QWxsUmVzdWx0LFxuICBTZWxlY3RPYmplY3QsXG4gIFNpbmdsZVRhYmxlVmFsdWUsXG4gIFNxbEV4cHJlc3Npb24sXG4gIFRzSGlnaGxpZ2h0T3B0aW9ucyxcbiAgVHNRdWVyeUNvbmZpZyxcbiAgVHNRdWVyeU9wdGlvbnMsXG4gIFRzUmFua09wdGlvbnMsXG4gIFZlY3RvckNvbHVtbnMsXG4gIFdoZXJlQ29uZGl0aW9uLFxuICBXaGVyZU9wZXJhdG9yLFxufSBmcm9tIFwiLi9wdXJpLnR5cGVzXCI7XG5pbXBvcnQgeyBGVVpaWV9PUEVSQVRPUlMgfSBmcm9tIFwiLi9wdXJpLnR5cGVzXCI7XG5pbXBvcnQgdHlwZSB7IENsZWFyU3RhdGVtZW50cyB9IGZyb20gXCIuL3B1cmktc3Vic2V0LnR5cGVzXCI7XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZUZ1enp5T3BlcmF0b3Iob3BlcmF0b3I/OiBzdHJpbmcpOiBGdXp6eU9wZXJhdG9yIHtcbiAgY29uc3Qgbm9ybWFsaXplZCA9IG9wZXJhdG9yPy50cmltKCkgPz8gXCI8JVwiO1xuICBjb25zdCBmdXp6eU9wZXJhdG9yID0gRlVaWllfT1BFUkFUT1JTLmZpbmQoKGNhbmRpZGF0ZSkgPT4gY2FuZGlkYXRlID09PSBub3JtYWxpemVkKTtcblxuICBpZiAoIWZ1enp5T3BlcmF0b3IpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgZnV6enkgb3BlcmF0b3I6ICR7b3BlcmF0b3IgPz8gXCJcIn1gKTtcbiAgfVxuXG4gIHJldHVybiBmdXp6eU9wZXJhdG9yO1xufVxuXG5leHBvcnQgY2xhc3MgUHVyaTxUU2NoZW1hLCBUVGFibGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgYW55PiwgVFJlc3VsdD4ge1xuICBwcml2YXRlIGtuZXhRdWVyeTogS25leC5RdWVyeUJ1aWxkZXI7XG4gIHByaXZhdGUgdGFibGVTcGVjOiBUYWJsZVNwZWMgfCBudWxsID0gbnVsbDtcblxuICAvLyDsg53shLHsnpAg7Iuc6re464uI7LKY65OkXG4gIGNvbnN0cnVjdG9yKGtuZXg6IEtuZXgsIHRhYmxlTmFtZTogc3RyaW5nKTtcbiAgY29uc3RydWN0b3Ioa25leDogS25leCwgdGFibGVTb3VyY2U6IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IFB1cmk8VFNjaGVtYSwgYW55LCBhbnk+Pik7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHB1YmxpYyBrbmV4OiBLbmV4LFxuICAgIHRhYmxlTmFtZU9yU291cmNlOiBhbnksXG4gICkge1xuICAgIGlmICh0eXBlb2YgdGFibGVOYW1lT3JTb3VyY2UgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIC8vIENhc2U6IG5ldyBQdXJpKGtuZXgsIFwidXNlcnNcIilcbiAgICAgIHRoaXMua25leFF1ZXJ5ID0gdGhpcy5rbmV4KHRhYmxlTmFtZU9yU291cmNlKS5mcm9tKHRhYmxlTmFtZU9yU291cmNlKTtcbiAgICAgIHRoaXMudGFibGVTcGVjID0gdGhpcy5zYWZlR2V0VGFibGVTcGVjKHRhYmxlTmFtZU9yU291cmNlKTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiB0YWJsZU5hbWVPclNvdXJjZSA9PT0gXCJvYmplY3RcIikge1xuICAgICAgY29uc3QgZW50cmllcyA9IE9iamVjdC5lbnRyaWVzKHRhYmxlTmFtZU9yU291cmNlKTtcbiAgICAgIGlmIChlbnRyaWVzLmxlbmd0aCAhPT0gMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUYWJsZSBzcGVjIG11c3QgaGF2ZSBleGFjdGx5IG9uZSBlbnRyeVwiKTtcbiAgICAgIH1cbiAgICAgIGFzc2VydChlbnRyaWVzWzBdKTtcbiAgICAgIGNvbnN0IFthbGlhcywgc291cmNlXSA9IGVudHJpZXNbMF07XG4gICAgICBpZiAodHlwZW9mIHNvdXJjZSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICB0aGlzLmtuZXhRdWVyeSA9IHRoaXMua25leChzb3VyY2UpLmZyb20oeyBbYWxpYXNdOiBzb3VyY2UgfSk7XG4gICAgICAgIHRoaXMudGFibGVTcGVjID0gdGhpcy5zYWZlR2V0VGFibGVTcGVjKHNvdXJjZSk7XG4gICAgICB9IGVsc2UgaWYgKHNvdXJjZSBpbnN0YW5jZW9mIFB1cmkpIHtcbiAgICAgICAgY29uc3Qgc3VicXVlcnlCdWlsZGVyID0gc291cmNlLnJhd1F1ZXJ5KCk7XG4gICAgICAgIHRoaXMua25leFF1ZXJ5ID0gdGhpcy5rbmV4LmZyb20oc3VicXVlcnlCdWlsZGVyLmFzKGFsaWFzKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIHRhYmxlIHNwZWNpZmljYXRpb25cIik7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgdGFibGUgc3BlY2lmaWNhdGlvblwiKTtcbiAgICB9XG4gIH1cblxuICBzYWZlR2V0VGFibGVTcGVjKHRhYmxlTmFtZTogc3RyaW5nKTogVGFibGVTcGVjIHwgbnVsbCB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBFbnRpdHlNYW5hZ2VyLmdldFRhYmxlU3BlYyh0YWJsZU5hbWUpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG5cbiAgLy8gU3RhdGljIFNRTCBoZWxwZXIgZnVuY3Rpb25zIGZvciBTRUxFQ1RcbiAgc3RhdGljIGNvdW50KGNvbHVtbjogc3RyaW5nID0gXCIqXCIpOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICBfc3FsOiBgQ09VTlQoPz8pOjppbnRlZ2VyYCxcbiAgICAgIF9wYXJhbXM6IFtjb2x1bW5dLFxuICAgIH07XG4gIH1cbiAgc3RhdGljIHN1bShjb2x1bW46IHN0cmluZyk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgIF9zcWw6IGBTVU0oPz8pYCxcbiAgICAgIF9wYXJhbXM6IFtjb2x1bW5dLFxuICAgIH07XG4gIH1cbiAgc3RhdGljIGF2Zyhjb2x1bW46IHN0cmluZyk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgIF9zcWw6IGBBVkcoPz8pYCxcbiAgICAgIF9wYXJhbXM6IFtjb2x1bW5dLFxuICAgIH07XG4gIH1cbiAgc3RhdGljIG1heChjb2x1bW46IHN0cmluZyk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgIF9zcWw6IGBNQVgoPz8pYCxcbiAgICAgIF9wYXJhbXM6IFtjb2x1bW5dLFxuICAgIH07XG4gIH1cbiAgc3RhdGljIG1pbihjb2x1bW46IHN0cmluZyk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgIF9zcWw6IGBNSU4oPz8pYCxcbiAgICAgIF9wYXJhbXM6IFtjb2x1bW5dLFxuICAgIH07XG4gIH1cbiAgc3RhdGljIGNvbmNhdCguLi5hcmdzOiBzdHJpbmdbXSk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJzdHJpbmdcIixcbiAgICAgIF9zcWw6IGBDT05DQVQoJHthcmdzLm1hcCgoKSA9PiBcIj9cIikuam9pbihcIiwgXCIpfSlgLFxuICAgICAgX3BhcmFtczogYXJncyxcbiAgICB9O1xuICB9XG4gIHN0YXRpYyB1cHBlcihjb2x1bW46IHN0cmluZyk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJzdHJpbmdcIixcbiAgICAgIF9zcWw6IFwiVVBQRVIoPz8pXCIsXG4gICAgICBfcGFyYW1zOiBbY29sdW1uXSxcbiAgICB9O1xuICB9XG4gIHN0YXRpYyBsb3dlcihjb2x1bW46IHN0cmluZyk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJzdHJpbmdcIixcbiAgICAgIF9zcWw6IFwiTE9XRVIoPz8pXCIsXG4gICAgICBfcGFyYW1zOiBbY29sdW1uXSxcbiAgICB9O1xuICB9XG5cbiAgc3RhdGljIHdvcmRTaW1pbGFyaXR5KFxuICAgIGNvbHVtbjogc3RyaW5nIHwgU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPixcbiAgICBxdWVyeTogc3RyaW5nLFxuICApOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICBpZiAodHlwZW9mIGNvbHVtbiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgICAgX3NxbDogXCJ3b3JkX3NpbWlsYXJpdHkoPywgPz8pXCIsXG4gICAgICAgIF9wYXJhbXM6IFtxdWVyeSwgY29sdW1uXSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsXG4gICAgICBfcmV0dXJuOiBcIm51bWJlclwiLFxuICAgICAgX3NxbDogYHdvcmRfc2ltaWxhcml0eSg/LCAke2NvbHVtbi5fc3FsfSlgLFxuICAgICAgX3BhcmFtczogW3F1ZXJ5LCAuLi5jb2x1bW4uX3BhcmFtc10sXG4gICAgfTtcbiAgfVxuXG4gIHN0YXRpYyBzaW1pbGFyaXR5KFxuICAgIGNvbHVtbjogc3RyaW5nIHwgU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPixcbiAgICBxdWVyeTogc3RyaW5nLFxuICApOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICBpZiAodHlwZW9mIGNvbHVtbiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgICAgX3NxbDogXCJzaW1pbGFyaXR5KD8/LCA/KVwiLFxuICAgICAgICBfcGFyYW1zOiBbY29sdW1uLCBxdWVyeV0sXG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgIF9zcWw6IGBzaW1pbGFyaXR5KCR7Y29sdW1uLl9zcWx9LCA/KWAsXG4gICAgICBfcGFyYW1zOiBbLi4uY29sdW1uLl9wYXJhbXMsIHF1ZXJ5XSxcbiAgICB9O1xuICB9XG5cbiAgc3RhdGljIHN0cmljdFdvcmRTaW1pbGFyaXR5KFxuICAgIGNvbHVtbjogc3RyaW5nIHwgU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPixcbiAgICBxdWVyeTogc3RyaW5nLFxuICApOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICBpZiAodHlwZW9mIGNvbHVtbiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgICAgX3NxbDogYHN0cmljdF93b3JkX3NpbWlsYXJpdHkoPywgPz8pYCxcbiAgICAgICAgX3BhcmFtczogW3F1ZXJ5LCBjb2x1bW5dLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICBfc3FsOiBgc3RyaWN0X3dvcmRfc2ltaWxhcml0eSg/LCAke2NvbHVtbi5fc3FsfSlgLFxuICAgICAgX3BhcmFtczogW3F1ZXJ5LCAuLi5jb2x1bW4uX3BhcmFtc10sXG4gICAgfTtcbiAgfVxuXG4gIC8vIFJhdyBmdW5jdGlvbnMgZm9yIFNFTEVDVFxuICBzdGF0aWMgcmF3U3RyaW5nKHNxbDogc3RyaW5nLCBwYXJhbXM6IHVua25vd25bXSA9IFtdKTogU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPiB7XG4gICAgcmV0dXJuIHsgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIiwgX3JldHVybjogXCJzdHJpbmdcIiwgX3NxbDogc3FsLCBfcGFyYW1zOiBwYXJhbXMgfTtcbiAgfVxuXG4gIHN0YXRpYyByYXdTdHJpbmdBcnJheShzcWw6IHN0cmluZywgcGFyYW1zOiB1bmtub3duW10gPSBbXSk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdbXVwiPiB7XG4gICAgcmV0dXJuIHsgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIiwgX3JldHVybjogXCJzdHJpbmdbXVwiLCBfc3FsOiBzcWwsIF9wYXJhbXM6IHBhcmFtcyB9O1xuICB9XG5cbiAgc3RhdGljIHJhd051bWJlcihzcWw6IHN0cmluZywgcGFyYW1zOiB1bmtub3duW10gPSBbXSk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIHJldHVybiB7IF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsIF9yZXR1cm46IFwibnVtYmVyXCIsIF9zcWw6IHNxbCwgX3BhcmFtczogcGFyYW1zIH07XG4gIH1cblxuICBzdGF0aWMgcmF3Qm9vbGVhbihzcWw6IHN0cmluZywgcGFyYW1zOiB1bmtub3duW10gPSBbXSk6IFNxbEV4cHJlc3Npb248XCJib29sZWFuXCI+IHtcbiAgICByZXR1cm4geyBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLCBfcmV0dXJuOiBcImJvb2xlYW5cIiwgX3NxbDogc3FsLCBfcGFyYW1zOiBwYXJhbXMgfTtcbiAgfVxuXG4gIHN0YXRpYyByYXdEYXRlKHNxbDogc3RyaW5nLCBwYXJhbXM6IHVua25vd25bXSA9IFtdKTogU3FsRXhwcmVzc2lvbjxcImRhdGVcIj4ge1xuICAgIHJldHVybiB7IF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsIF9yZXR1cm46IFwiZGF0ZVwiLCBfc3FsOiBzcWwsIF9wYXJhbXM6IHBhcmFtcyB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEZUUyDqsoDsg4nslrQg7ZWY7J2065287J207YyFXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIC5zZWxlY3Qoe1xuICAgKiAgIHRpdGxlOiBQdXJpLmhpZ2hsaWdodChcInBvc3RzLnRpdGxlXCIsIHNlYXJjaCksXG4gICAqICAgY29udGVudDogUHVyaS5oaWdobGlnaHQoXCJwb3N0cy5jb250ZW50XCIsIHNlYXJjaCwge1xuICAgKiAgICAgc3RhcnRTZWw6IFwiPG1hcms+XCIsXG4gICAqICAgICBzdG9wU2VsOiBcIjwvbWFyaz5cIixcbiAgICogICAgIG1heEZyYWdtZW50czogMyxcbiAgICogICB9KSxcbiAgICogfSlcbiAgICovXG4gIHN0YXRpYyB0c0hpZ2hsaWdodChcbiAgICBjb2x1bW46IHN0cmluZyxcbiAgICBxdWVyeTogc3RyaW5nLFxuICAgIF9vcHRpb25zPzogVHNIaWdobGlnaHRPcHRpb25zLFxuICApOiBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+IHtcbiAgICBjb25zdCB7IHBhcnNlciA9IFwid2Vic2VhcmNoX3RvX3RzcXVlcnlcIiwgY29uZmlnID0gXCJzaW1wbGVcIiwgLi4ub3B0aW9ucyB9ID0gX29wdGlvbnMgPz8ge307XG5cbiAgICBjb25zdCBobE9wdGlvblBhcnRzID0gT2JqZWN0LmVudHJpZXMob3B0aW9ucykubWFwKChba2V5LCB2YWx1ZV0pID0+IHtcbiAgICAgIHJldHVybiBgJHtpbmZsZWN0aW9uLmNhbWVsaXplKGtleSl9PSR7dmFsdWV9YDtcbiAgICB9KTtcblxuICAgIGNvbnN0IGhsT3B0aW9ucyA9IGhsT3B0aW9uUGFydHMubGVuZ3RoID4gMCA/IGAsICcke2hsT3B0aW9uUGFydHMuam9pbihcIiwgXCIpfSdgIDogXCJcIjtcblxuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJzdHJpbmdcIixcbiAgICAgIF9zcWw6IGB0c19oZWFkbGluZSg/LCA/PywgJHtwYXJzZXJ9KD8sID8pJHtobE9wdGlvbnN9KWAsXG4gICAgICBfcGFyYW1zOiBbY29uZmlnLCBjb2x1bW4sIGNvbmZpZywgcXVlcnldLFxuICAgIH07XG4gIH1cblxuICAvLyB0c19yYW5rXG4gIHN0YXRpYyB0c1JhbmsoXG4gICAgY29sdW1uOiBzdHJpbmcgfCBTcWxFeHByZXNzaW9uPFwidHN2ZWN0b3JcIj4sXG4gICAgcXVlcnk6IHN0cmluZyxcbiAgICBvcHRpb25zPzogVHNSYW5rT3B0aW9ucyxcbiAgKTogU3FsRXhwcmVzc2lvbjxcIm51bWJlclwiPiB7XG4gICAgcmV0dXJuIFB1cmkuX3RzUmFuayhcInRzX3JhbmtcIiwgY29sdW1uLCBxdWVyeSwgb3B0aW9ucyk7XG4gIH1cblxuICAvLyB0c19yYW5rX2NkXG4gIHN0YXRpYyB0c1JhbmtDZChcbiAgICBjb2x1bW46IHN0cmluZyB8IFNxbEV4cHJlc3Npb248XCJ0c3ZlY3RvclwiPixcbiAgICBxdWVyeTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBUc1JhbmtPcHRpb25zLFxuICApOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4gUHVyaS5fdHNSYW5rKFwidHNfcmFua19jZFwiLCBjb2x1bW4sIHF1ZXJ5LCBvcHRpb25zKTtcbiAgfVxuXG4gIHN0YXRpYyB0b1RzVmVjdG9yKGNvbHVtbjogc3RyaW5nLCBjb25maWc6IHN0cmluZyA9IFwic2ltcGxlXCIpOiBTcWxFeHByZXNzaW9uPFwidHN2ZWN0b3JcIj4ge1xuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJ0c3ZlY3RvclwiLFxuICAgICAgX3NxbDogYHRvX3RzdmVjdG9yKD8sID8/KWAsXG4gICAgICBfcGFyYW1zOiBbY29uZmlnLCBjb2x1bW5dLFxuICAgIH07XG4gIH1cblxuICBzdGF0aWMgX3RzUmFuayhcbiAgICB0eXBlOiBcInRzX3JhbmtcIiB8IFwidHNfcmFua19jZFwiLFxuICAgIGNvbHVtbjogc3RyaW5nIHwgU3FsRXhwcmVzc2lvbjxcInRzdmVjdG9yXCI+LFxuICAgIHF1ZXJ5OiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IFRzUmFua09wdGlvbnMsXG4gICk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIGNvbnN0IHtcbiAgICAgIHBhcnNlciA9IFwid2Vic2VhcmNoX3RvX3RzcXVlcnlcIixcbiAgICAgIGNvbmZpZyA9IFwic2ltcGxlXCIsXG4gICAgICBub3JtYWxpemF0aW9uLFxuICAgICAgd2VpZ2h0cyxcbiAgICB9ID0gb3B0aW9ucyA/PyB7fTtcblxuICAgIGNvbnN0IHBhcmFtcyA9IFtdO1xuICAgIGxldCBzcWxUZW1wbGF0ZSA9IGAke3R5cGV9KGA7XG5cbiAgICBpZiAod2VpZ2h0cykge1xuICAgICAgc3FsVGVtcGxhdGUgKz0gYEFSUkFZWyR7d2VpZ2h0cy5tYXAoKCkgPT4gXCI/XCIpLmpvaW4oXCIsIFwiKX1dOjpmbG9hdDRbXSwgYDtcbiAgICAgIHBhcmFtcy5wdXNoKC4uLndlaWdodHMpO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgY29sdW1uID09PSBcInN0cmluZ1wiKSB7XG4gICAgICBzcWxUZW1wbGF0ZSArPSBgPz8sICR7cGFyc2VyfSg/LCA/KWA7XG4gICAgICBwYXJhbXMucHVzaChjb2x1bW4sIGNvbmZpZywgcXVlcnkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBzcWxUZW1wbGF0ZSArPSBgJHtjb2x1bW4uX3NxbH0sICR7cGFyc2VyfSg/LCA/KWA7XG4gICAgICBwYXJhbXMucHVzaCguLi5jb2x1bW4uX3BhcmFtcywgY29uZmlnLCBxdWVyeSk7XG4gICAgfVxuXG4gICAgaWYgKG5vcm1hbGl6YXRpb24pIHtcbiAgICAgIHNxbFRlbXBsYXRlICs9IFwiLCA/XCI7XG4gICAgICBwYXJhbXMucHVzaChub3JtYWxpemF0aW9uKTtcbiAgICB9XG5cbiAgICBzcWxUZW1wbGF0ZSArPSBcIilcIjtcblxuICAgIHJldHVybiB7IF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsIF9yZXR1cm46IFwibnVtYmVyXCIsIF9zcWw6IHNxbFRlbXBsYXRlLCBfcGFyYW1zOiBwYXJhbXMgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQR3Jvb25nYSBGdWxsVGV4dCDsnbjrjbHsiqQg6rKA7IOJIOygkOyImFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiAuc2VsZWN0KHtcbiAgICogICBzY29yZTogUHVyaS5zY29yZSgpLFxuICAgKiB9KVxuICAgKi9cbiAgc3RhdGljIHNjb3JlKCk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIHJldHVybiBQdXJpLnJhd051bWJlcihcInBncm9vbmdhX3Njb3JlKHRhYmxlb2lkLCBjdGlkKVwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQR3Jvb25nYSBGdWxsVGV4dCDsnbjrjbHsiqQg6rKA7IOJIO2VmOydtOudvOydtO2MhVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiAuc2VsZWN0KHtcbiAgICogICB0aXRsZTogUHVyaS5oaWdobGlnaHQoXCJwb3N0cy50aXRsZVwiLCBzZWFyY2gpLFxuICAgKiB9KVxuICAgKi9cbiAgc3RhdGljIGhpZ2hsaWdodChjb2x1bW46IHN0cmluZywgcXVlcnk6IHN0cmluZyB8IHN0cmluZ1tdKTogU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPjtcbiAgc3RhdGljIGhpZ2hsaWdodChjb2x1bW5zOiBzdHJpbmdbXSwgcXVlcnk6IHN0cmluZyB8IHN0cmluZ1tdKTogU3FsRXhwcmVzc2lvbjxcInN0cmluZ1tdXCI+O1xuXG4gIHN0YXRpYyBoaWdobGlnaHQoXG4gICAgY29sdW1uT3JDb2x1bW5zOiBzdHJpbmcgfCBzdHJpbmdbXSxcbiAgICBxdWVyeTogc3RyaW5nIHwgc3RyaW5nW10sXG4gICk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4gfCBTcWxFeHByZXNzaW9uPFwic3RyaW5nW11cIj4ge1xuICAgIGNvbnN0IHF1ZXJ5QXJyID0gQXJyYXkuaXNBcnJheShxdWVyeSkgPyBxdWVyeSA6IFtxdWVyeV07XG4gICAgY29uc3QgcXVlcnlDbGF1c2UgPSBgQVJSQVlbJHtxdWVyeUFyci5tYXAoKCkgPT4gXCI/XCIpLmpvaW4oXCIsIFwiKX1dYDtcblxuICAgIC8vIOuLqOydvCDsu6zrn7zsnbgg6rK97JqwXG4gICAgaWYgKHR5cGVvZiBjb2x1bW5PckNvbHVtbnMgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHJldHVybiBQdXJpLnJhd1N0cmluZyhgcGdyb29uZ2FfaGlnaGxpZ2h0X2h0bWwoPz8sICR7cXVlcnlDbGF1c2V9KWAsIFtcbiAgICAgICAgY29sdW1uT3JDb2x1bW5zLFxuICAgICAgICAuLi5xdWVyeUFycixcbiAgICAgIF0pO1xuICAgIH1cblxuICAgIC8vIOy7rOufvCDrsLDsl7Tsnbgg6rK97JqwXG4gICAgcmV0dXJuIFB1cmkucmF3U3RyaW5nQXJyYXkoXG4gICAgICBgcGdyb29uZ2FfaGlnaGxpZ2h0X2h0bWwoQVJSQVlbJHtjb2x1bW5PckNvbHVtbnMubWFwKCgpID0+IFwiPz9cIikuam9pbihcIiwgXCIpfV0sICR7cXVlcnlDbGF1c2V9KWAsXG4gICAgICBbLi4uY29sdW1uT3JDb2x1bW5zLCAuLi5xdWVyeUFycl0sXG4gICAgKTtcbiAgfVxuXG4gIC8vIFNFTEVDVCAob3ZlcndyaXRlKVxuICBzZWxlY3Q8VFNlbGVjdCBleHRlbmRzIFNlbGVjdE9iamVjdDxUVGFibGVzPj4oXG4gICAgc2VsZWN0T2JqOiBUU2VsZWN0LFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMsIFBhcnNlU2VsZWN0T2JqZWN0PFRUYWJsZXMsIFRTZWxlY3Q+PiB7XG4gICAgLy8g7KSR7LKpIOqwneyytOulvCBmbGF07ZWY6rKMIOuzgO2ZmFxuICAgIGNvbnN0IGZsYXRTZWxlY3QgPSB0aGlzLmZsYXR0ZW5TZWxlY3Qoc2VsZWN0T2JqKTtcblxuICAgIGNvbnN0IHNlbGVjdENsYXVzZXM6IChzdHJpbmcgfCBLbmV4LlJhdylbXSA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBbYWxpYXMsIGNvbHVtbk9yRnVuY3Rpb25dIG9mIE9iamVjdC5lbnRyaWVzKGZsYXRTZWxlY3QpKSB7XG4gICAgICBpZiAodHlwZW9mIGNvbHVtbk9yRnVuY3Rpb24gPT09IFwib2JqZWN0XCIgJiYgY29sdW1uT3JGdW5jdGlvbi5fdHlwZSA9PT0gXCJzcWxfZXhwcmVzc2lvblwiKSB7XG4gICAgICAgIC8vIFNRTCDtlajsiJjsnbgg6rK97JqwXG4gICAgICAgIHNlbGVjdENsYXVzZXMucHVzaChcbiAgICAgICAgICB0aGlzLmtuZXgucmF3KGAke2NvbHVtbk9yRnVuY3Rpb24uX3NxbH0gQVMgXCIke2FsaWFzfVwiYCwgY29sdW1uT3JGdW5jdGlvbi5fcGFyYW1zKSxcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIOydvOuwmCDsu6zrn7zsnbgg6rK97JqwXG4gICAgICAgIGNvbnN0IGNvbHVtblBhdGggPSBjb2x1bW5PckZ1bmN0aW9uIGFzIHN0cmluZztcbiAgICAgICAgaWYgKGFsaWFzID09PSBjb2x1bW5QYXRoKSB7XG4gICAgICAgICAgLy8gYWxpYXPsmYAg7Lus65+866qF7J20IOqwmeycvOuptCBhbGlhcyDsg53rnrVcbiAgICAgICAgICBzZWxlY3RDbGF1c2VzLnB1c2goY29sdW1uUGF0aCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gYWxpYXMg7KeA7KCVXG4gICAgICAgICAgc2VsZWN0Q2xhdXNlcy5wdXNoKGAke2NvbHVtblBhdGh9IEFTICR7YWxpYXN9YCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmtuZXhRdWVyeS5zZWxlY3Qoc2VsZWN0Q2xhdXNlcyk7XG4gICAgcmV0dXJuIHRoaXMgYXMgYW55O1xuICB9XG5cbiAgLyoqXG4gICAqIOykkeyyqSDqsJ3ssrTrpbwgZmxhdCDqsJ3ssrTroZwg67OA7ZmYXG4gICAqIOyYiDogeyBwYXJlbnQ6IHsgaWQ6IFwicGFyZW50LmlkXCIsIG5hbWU6IFwicGFyZW50Lm5hbWVcIiB9IH1cbiAgICogICDihpIgeyBwYXJlbnRfX2lkOiBcInBhcmVudC5pZFwiLCBwYXJlbnRfX25hbWU6IFwicGFyZW50Lm5hbWVcIiB9XG4gICAqL1xuICBwcml2YXRlIGZsYXR0ZW5TZWxlY3Qoc2VsZWN0T2JqOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LCBwcmVmaXggPSBcIlwiKTogUmVjb3JkPHN0cmluZywgYW55PiB7XG4gICAgY29uc3QgZmxhdFNlbGVjdDogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuXG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2VsZWN0T2JqKSkge1xuICAgICAgY29uc3QgZnVsbEtleSA9IHByZWZpeCA/IGAke3ByZWZpeH1fXyR7a2V5fWAgOiBrZXk7XG5cbiAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwib2JqZWN0XCIgJiYgdmFsdWUgIT09IG51bGwgJiYgIShcIl90eXBlXCIgaW4gdmFsdWUpKSB7XG4gICAgICAgIC8vIOykkeyyqSDqsJ3ssrTsnbgg6rK97JqwIC0g7J6s6reAIOyymOumrFxuICAgICAgICBjb25zdCBuZXN0ZWQgPSB0aGlzLmZsYXR0ZW5TZWxlY3QodmFsdWUsIGZ1bGxLZXkpO1xuICAgICAgICBPYmplY3QuYXNzaWduKGZsYXRTZWxlY3QsIG5lc3RlZCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyDsnbzrsJgg6rCS7J24IOqyveyasCAo7Lus65+8IOqyveuhnCDrmJDripQgU3FsRXhwcmVzc2lvbilcbiAgICAgICAgZmxhdFNlbGVjdFtmdWxsS2V5XSA9IHZhbHVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBmbGF0U2VsZWN0O1xuICB9XG5cbiAgLy8gU0VMRUNUIChzZWxlY3TripQgb3ZlcndyaXRlLCBhcHBlbmRTZWxlY3TripQgYXBwZW5kKVxuICBhcHBlbmRTZWxlY3Q8VFNlbGVjdCBleHRlbmRzIFNlbGVjdE9iamVjdDxUVGFibGVzPj4oXG4gICAgc2VsZWN0T2JqOiBUU2VsZWN0LFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMsIFRSZXN1bHQgJiBQYXJzZVNlbGVjdE9iamVjdDxUVGFibGVzLCBUU2VsZWN0Pj4ge1xuICAgIC8vIOykkeyyqSDqsJ3ssrTrpbwgZmxhdO2VmOqyjCDrs4DtmZhcbiAgICBjb25zdCBmbGF0U2VsZWN0ID0gdGhpcy5mbGF0dGVuU2VsZWN0KHNlbGVjdE9iaik7XG5cbiAgICBjb25zdCBzZWxlY3RDbGF1c2VzOiAoc3RyaW5nIHwgS25leC5SYXcpW10gPSBbXTtcblxuICAgIGZvciAoY29uc3QgW2FsaWFzLCBjb2x1bW5PckZ1bmN0aW9uXSBvZiBPYmplY3QuZW50cmllcyhmbGF0U2VsZWN0KSkge1xuICAgICAgaWYgKHR5cGVvZiBjb2x1bW5PckZ1bmN0aW9uID09PSBcIm9iamVjdFwiICYmIGNvbHVtbk9yRnVuY3Rpb24uX3R5cGUgPT09IFwic3FsX2V4cHJlc3Npb25cIikge1xuICAgICAgICBzZWxlY3RDbGF1c2VzLnB1c2goXG4gICAgICAgICAgdGhpcy5rbmV4LnJhdyhgJHtjb2x1bW5PckZ1bmN0aW9uLl9zcWx9IEFTICR7YWxpYXN9YCwgY29sdW1uT3JGdW5jdGlvbi5fcGFyYW1zKSxcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGNvbHVtblBhdGggPSBjb2x1bW5PckZ1bmN0aW9uIGFzIHN0cmluZztcbiAgICAgICAgaWYgKGFsaWFzID09PSBjb2x1bW5QYXRoKSB7XG4gICAgICAgICAgc2VsZWN0Q2xhdXNlcy5wdXNoKGNvbHVtblBhdGgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNlbGVjdENsYXVzZXMucHVzaCh0aGlzLmtuZXgucmVmKGNvbHVtblBhdGgpLmFzKGFsaWFzKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmtuZXhRdWVyeS5zZWxlY3Qoc2VsZWN0Q2xhdXNlcyk7XG4gICAgcmV0dXJuIHRoaXMgYXMgYW55O1xuICB9XG5cbiAgLy8gU0VMRUNUICpcbiAgc2VsZWN0QWxsKCk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcywgU2VsZWN0QWxsUmVzdWx0PFRUYWJsZXM+PiB7XG4gICAgdGhpcy5rbmV4UXVlcnkuc2VsZWN0KFwiKlwiKTtcbiAgICByZXR1cm4gdGhpcyBhcyBhbnk7XG4gIH1cblxuICAvLyBESVNUSU5DVFxuICBkaXN0aW5jdDxUQ29sdW1ucyBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KC4uLmNvbHVtbnM6IFRDb2x1bW5zW10pOiB0aGlzO1xuICBkaXN0aW5jdCguLi5jb2x1bW5zOiBzdHJpbmdbXSk6IHRoaXMge1xuICAgIHRoaXMua25leFF1ZXJ5LmRpc3RpbmN0KC4uLihjb2x1bW5zIGFzIHN0cmluZ1tdKSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyBDTEVBUlxuICBjbGVhcihzdGF0ZW1lbnQ6IENsZWFyU3RhdGVtZW50cyk6IHRoaXMge1xuICAgIHRoaXMua25leFF1ZXJ5LmNsZWFyKHN0YXRlbWVudCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyBrbmV47JeQIOyXhuyWtOyEnCDsp4HsoJEg6rWs7ZiE7ZWoXG4gIGNsZWFySm9pbihhbGlhczogc3RyaW5nKTogdGhpcyB7XG4gICAgKHRoaXMua25leFF1ZXJ5IGFzIGFueSkuX3N0YXRlbWVudHMgPSAodGhpcy5rbmV4UXVlcnkgYXMgYW55KS5fc3RhdGVtZW50cy5maWx0ZXIoKHM6IGFueSkgPT4ge1xuICAgICAgaWYgKFwiam9pblR5cGVcIiBpbiBzKSB7XG4gICAgICAgIGNvbnN0IFtfYWxpYXMsIF90YWJsZV0gPSBPYmplY3QuZW50cmllcyhzLnRhYmxlKVswXTtcbiAgICAgICAgcmV0dXJuIF9hbGlhcyAhPT0gYWxpYXM7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIEpPSU46IOyEnOu4jOy/vOumrCArIEFsaWFzXG4gIGpvaW48VEpvaW5BbGlhcyBleHRlbmRzIHN0cmluZywgVFN1YlJlc3VsdD4oXG4gICAgdGFibGVTcGVjOiB7IFtLIGluIFRKb2luQWxpYXNdOiBQdXJpPFRTY2hlbWEsIGFueSwgVFN1YlJlc3VsdD4gfSxcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+LFxuICAgIHJpZ2h0OiBgJHtUSm9pbkFsaWFzfS4ke0NvbHVtbktleXM8VFN1YlJlc3VsdD59YCxcbiAgKTogUHVyaTxcbiAgICBUU2NoZW1hLFxuICAgIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5BbGlhcywgVFN1YlJlc3VsdD4sIC8vIOyEnOu4jOy/vOumrOydmCBUUmVzdWx0XG4gICAgVFJlc3VsdFxuICA+O1xuICAvLyBKT0lOOiDthYzsnbTruJQgKyBBbGlhc1xuICBqb2luPFRKb2luVGFibGUgZXh0ZW5kcyBrZXlvZiBUU2NoZW1hLCBUSm9pbkFsaWFzIGV4dGVuZHMgc3RyaW5nPihcbiAgICB0YWJsZVNwZWM6IHsgW0sgaW4gVEpvaW5BbGlhc106IFRKb2luVGFibGUgfSxcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+LFxuICAgIHJpZ2h0OiBgJHtUSm9pbkFsaWFzfS4ke0NvbHVtbktleXM8VFNjaGVtYVtUSm9pblRhYmxlXT59YCxcbiAgKTogUHVyaTxcbiAgICBUU2NoZW1hLFxuICAgIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5BbGlhcywgVFNjaGVtYVtUSm9pblRhYmxlXT4sIC8vIFRUYWJsZXMg7ZmV7J6lIVxuICAgIFRSZXN1bHRcbiAgPjtcbiAgLy8gSk9JTjog7YWM7J2067iU66qFXG4gIGpvaW48VEpvaW5UYWJsZSBleHRlbmRzIGtleW9mIFRTY2hlbWE+KFxuICAgIHRhYmxlTmFtZTogVEpvaW5UYWJsZSxcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+LFxuICAgIHJpZ2h0OiBgJHtUSm9pblRhYmxlICYgc3RyaW5nfS4ke0NvbHVtbktleXM8VFNjaGVtYVtUSm9pblRhYmxlXT59YCxcbiAgKTogUHVyaTxcbiAgICBUU2NoZW1hLFxuICAgIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5UYWJsZSwgVFNjaGVtYVtUSm9pblRhYmxlXT4sIC8vIO2FjOydtOu4lOuqheydtCDtgqRcbiAgICBUUmVzdWx0XG4gID47XG4gIC8vIEpPSU46IOyEnOu4jOy/vOumrCArIEFsaWFzICsg7L2c67CxXG4gIGpvaW48VEpvaW5BbGlhcyBleHRlbmRzIHN0cmluZywgVFN1YlJlc3VsdD4oXG4gICAgdGFibGVTcGVjOiB7IFtLIGluIFRKb2luQWxpYXNdOiBQdXJpPFRTY2hlbWEsIGFueSwgVFN1YlJlc3VsdD4gfSxcbiAgICBjYWxsYmFjazogKGo6IEpvaW5DbGF1c2VHcm91cDxUVGFibGVzLCBSZWNvcmQ8VEpvaW5BbGlhcywgVFN1YlJlc3VsdD4+KSA9PiB2b2lkLFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5BbGlhcywgVFN1YlJlc3VsdD4sIFRSZXN1bHQ+O1xuICAvLyBKT0lOOiDthYzsnbTruJQgKyBBbGlhcyArIOy9nOuwsVxuICBqb2luPFRKb2luVGFibGUgZXh0ZW5kcyBrZXlvZiBUU2NoZW1hLCBUSm9pbkFsaWFzIGV4dGVuZHMgc3RyaW5nPihcbiAgICB0YWJsZVNwZWM6IHsgW0sgaW4gVEpvaW5BbGlhc106IFRKb2luVGFibGUgfSxcbiAgICBjYWxsYmFjazogKGo6IEpvaW5DbGF1c2VHcm91cDxUVGFibGVzLCBSZWNvcmQ8VEpvaW5BbGlhcywgVFNjaGVtYVtUSm9pblRhYmxlXT4+KSA9PiB2b2lkLFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5BbGlhcywgVFNjaGVtYVtUSm9pblRhYmxlXT4sIFRSZXN1bHQ+O1xuICAvLyBKT0lOOiDthYzsnbTruJTrqoUgKyDsvZzrsLFcbiAgam9pbjxUSm9pblRhYmxlIGV4dGVuZHMga2V5b2YgVFNjaGVtYT4oXG4gICAgdGFibGVOYW1lOiBUSm9pblRhYmxlLFxuICAgIGNhbGxiYWNrOiAoajogSm9pbkNsYXVzZUdyb3VwPFRUYWJsZXMsIFJlY29yZDxUSm9pblRhYmxlLCBUU2NoZW1hW1RKb2luVGFibGVdPj4pID0+IHZvaWQsXG4gICk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcyAmIFJlY29yZDxUSm9pblRhYmxlLCBUU2NoZW1hW1RKb2luVGFibGVdPiwgVFJlc3VsdD47XG4gIC8vIEpPSU4g7Iuk7KCcIOq1rO2YhFxuICBqb2luKHRhYmxlTmFtZU9yU3BlYzogYW55LCAuLi5hcmdzOiBhbnlbXSk6IGFueSB7XG4gICAgcmV0dXJuIHRoaXMuX19jb21tb25Kb2luKFwiam9pblwiLCB0YWJsZU5hbWVPclNwZWMsIC4uLmFyZ3MpO1xuICB9XG5cbiAgLy8gTEVGVCBKT0lOOiDshJzruIzsv7zrpqwgKyBBbGlhc1xuICBsZWZ0Sm9pbjxUSm9pbkFsaWFzIGV4dGVuZHMgc3RyaW5nLCBUU3ViUmVzdWx0PihcbiAgICB0YWJsZVNwZWM6IHsgW0sgaW4gVEpvaW5BbGlhc106IFB1cmk8VFNjaGVtYSwgYW55LCBUU3ViUmVzdWx0PiB9LFxuICAgIGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4sXG4gICAgcmlnaHQ6IGAke1RKb2luQWxpYXN9LiR7Q29sdW1uS2V5czxUU3ViUmVzdWx0Pn1gLFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5BbGlhcywgVFN1YlJlc3VsdCAmIExlZnRKb2luZWRNYXJrZXI+LCBUUmVzdWx0PjsgLy8g7ISc67iM7L+866as7J2YIFRSZXN1bHRcbiAgLy8gTEVGVCBKT0lOOiDthYzsnbTruJQgKyBBbGlhc1xuICAvLyBGSyBudWxsYWJsZSDsl6zrtoDsl5Ag65Sw6528IOyekOuPmeycvOuhnCBMZWZ0Sm9pbmVkTWFya2VyIOqysOyglVxuICBsZWZ0Sm9pbjxcbiAgICBUSm9pblRhYmxlIGV4dGVuZHMga2V5b2YgVFNjaGVtYSxcbiAgICBUSm9pbkFsaWFzIGV4dGVuZHMgc3RyaW5nLFxuICAgIFRMZWZ0IGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPixcbiAgPihcbiAgICB0YWJsZVNwZWM6IHsgW0sgaW4gVEpvaW5BbGlhc106IFRKb2luVGFibGUgfSxcbiAgICBsZWZ0OiBUTGVmdCxcbiAgICByaWdodDogYCR7VEpvaW5BbGlhc30uJHtDb2x1bW5LZXlzPFRTY2hlbWFbVEpvaW5UYWJsZV0+fWAsXG4gICk6IFB1cmk8XG4gICAgVFNjaGVtYSxcbiAgICBUVGFibGVzICYgUmVjb3JkPFRKb2luQWxpYXMsIFRTY2hlbWFbVEpvaW5UYWJsZV0gJiBMZWZ0Sm9pbk1hcmtlckZvcjxUVGFibGVzLCBUTGVmdD4+LFxuICAgIFRSZXN1bHRcbiAgPjtcbiAgLy8gTEVGVCBKT0lOOiDthYzsnbTruJTrqoVcbiAgbGVmdEpvaW48VEpvaW5UYWJsZSBleHRlbmRzIGtleW9mIFRTY2hlbWEsIFRMZWZ0IGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgdGFibGVOYW1lOiBUSm9pblRhYmxlLFxuICAgIGxlZnQ6IFRMZWZ0LFxuICAgIHJpZ2h0OiBgJHtUSm9pblRhYmxlICYgc3RyaW5nfS4ke0NvbHVtbktleXM8VFNjaGVtYVtUSm9pblRhYmxlXT59YCxcbiAgKTogUHVyaTxcbiAgICBUU2NoZW1hLFxuICAgIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5UYWJsZSwgVFNjaGVtYVtUSm9pblRhYmxlXSAmIExlZnRKb2luTWFya2VyRm9yPFRUYWJsZXMsIFRMZWZ0Pj4sXG4gICAgVFJlc3VsdFxuICA+O1xuICAvLyBMRUZUIEpPSU46IOyEnOu4jOy/vOumrCArIEFsaWFzICsg7L2c67CxXG4gIGxlZnRKb2luPFRKb2luQWxpYXMgZXh0ZW5kcyBzdHJpbmcsIFRTdWJSZXN1bHQ+KFxuICAgIHRhYmxlU3BlYzogeyBbSyBpbiBUSm9pbkFsaWFzXTogUHVyaTxUU2NoZW1hLCBhbnksIFRTdWJSZXN1bHQ+IH0sXG4gICAgY2FsbGJhY2s6IChqOiBKb2luQ2xhdXNlR3JvdXA8VFRhYmxlcywgUmVjb3JkPFRKb2luQWxpYXMsIFRTdWJSZXN1bHQ+PikgPT4gdm9pZCxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzICYgUmVjb3JkPFRKb2luQWxpYXMsIFRTdWJSZXN1bHQgJiBMZWZ0Sm9pbmVkTWFya2VyPiwgVFJlc3VsdD47XG4gIC8vIExFRlQgSk9JTjog7YWM7J2067iUICsgQWxpYXMgKyDsvZzrsLFcbiAgbGVmdEpvaW48VEpvaW5UYWJsZSBleHRlbmRzIGtleW9mIFRTY2hlbWEsIFRKb2luQWxpYXMgZXh0ZW5kcyBzdHJpbmc+KFxuICAgIHRhYmxlU3BlYzogeyBbSyBpbiBUSm9pbkFsaWFzXTogVEpvaW5UYWJsZSB9LFxuICAgIGNhbGxiYWNrOiAoajogSm9pbkNsYXVzZUdyb3VwPFRUYWJsZXMsIFJlY29yZDxUSm9pbkFsaWFzLCBUU2NoZW1hW1RKb2luVGFibGVdPj4pID0+IHZvaWQsXG4gICk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcyAmIFJlY29yZDxUSm9pbkFsaWFzLCBUU2NoZW1hW1RKb2luVGFibGVdICYgTGVmdEpvaW5lZE1hcmtlcj4sIFRSZXN1bHQ+O1xuICAvLyBMRUZUIEpPSU46IO2FjOydtOu4lOuqhSArIOy9nOuwsVxuICBsZWZ0Sm9pbjxUSm9pblRhYmxlIGV4dGVuZHMga2V5b2YgVFNjaGVtYT4oXG4gICAgdGFibGVOYW1lOiBUSm9pblRhYmxlLFxuICAgIGNhbGxiYWNrOiAoajogSm9pbkNsYXVzZUdyb3VwPFRUYWJsZXMsIFJlY29yZDxUSm9pblRhYmxlLCBUU2NoZW1hW1RKb2luVGFibGVdPj4pID0+IHZvaWQsXG4gICk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcyAmIFJlY29yZDxUSm9pblRhYmxlLCBUU2NoZW1hW1RKb2luVGFibGVdICYgTGVmdEpvaW5lZE1hcmtlcj4sIFRSZXN1bHQ+O1xuICAvLyBMRUZUIEpPSU4g7Iuk7KCcIOq1rO2YhFxuICBsZWZ0Sm9pbih0YWJsZU5hbWVPclNwZWM6IGFueSwgLi4uYXJnczogYW55W10pOiBhbnkge1xuICAgIHJldHVybiB0aGlzLl9fY29tbW9uSm9pbihcImxlZnRKb2luXCIsIHRhYmxlTmFtZU9yU3BlYywgLi4uYXJncyk7XG4gIH1cblxuICBfX2NvbW1vbkpvaW4oam9pblR5cGU6IFwiam9pblwiIHwgXCJsZWZ0Sm9pblwiLCB0YWJsZU5hbWVPclNwZWM6IGFueSwgLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICBpZiAodHlwZW9mIHRhYmxlTmFtZU9yU3BlYyA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgLy8gQ2FzZSAxOiBqb2luKFwicG9zdHNcIiwgLi4uKVxuICAgICAgY29uc3QgdGFibGVOYW1lID0gdGFibGVOYW1lT3JTcGVjO1xuXG4gICAgICBpZiAoYXJncy5sZW5ndGggPT09IDEgJiYgdHlwZW9mIGFyZ3NbMF0gPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAvLyBqb2luKFwicG9zdHNcIiwgY2FsbGJhY2spXG4gICAgICAgIGNvbnN0IGNhbGxiYWNrID0gYXJnc1swXTtcbiAgICAgICAgdGhpcy5rbmV4UXVlcnlbam9pblR5cGVdKHRhYmxlTmFtZSwgKGpvaW5DbGF1c2UpID0+IHtcbiAgICAgICAgICBjYWxsYmFjayhuZXcgSm9pbkNsYXVzZUdyb3VwKGpvaW5DbGF1c2UpKTtcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBqb2luKFwicG9zdHNcIiwgbGVmdCwgcmlnaHQpXG4gICAgICAgIGNvbnN0IFtsZWZ0LCByaWdodF0gPSBhcmdzO1xuICAgICAgICB0aGlzLmtuZXhRdWVyeVtqb2luVHlwZV0odGFibGVOYW1lLCBsZWZ0LCByaWdodCk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgdGFibGVOYW1lT3JTcGVjID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAvLyBDYXNlIDI6IGpvaW4oeyBhbGlhczogXCJ0YWJsZVwiIH0sIC4uLikgb3Igam9pbih7IGFsaWFzOiBzdWJxdWVyeSB9LCAuLi4pXG4gICAgICBjb25zdCBlbnRyaWVzID0gT2JqZWN0LmVudHJpZXModGFibGVOYW1lT3JTcGVjKTtcbiAgICAgIGlmIChlbnRyaWVzLmxlbmd0aCAhPT0gMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUYWJsZSBzcGVjIG11c3QgaGF2ZSBleGFjdGx5IG9uZSBlbnRyeVwiKTtcbiAgICAgIH1cbiAgICAgIGFzc2VydChlbnRyaWVzWzBdKTtcbiAgICAgIGNvbnN0IFtbYWxpYXMsIHNwZWNdXSA9IGVudHJpZXM7XG5cbiAgICAgIGlmICh0eXBlb2Ygc3BlYyA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAvLyDthYzsnbTruJQ6IGpvaW4oeyBwOiBcInBvc3RzXCIgfSwgLi4uKVxuICAgICAgICBpZiAoYXJncy5sZW5ndGggPT09IDEgJiYgdHlwZW9mIGFyZ3NbMF0gPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgIC8vIENhbGxiYWNrXG4gICAgICAgICAgY29uc3QgY2FsbGJhY2sgPSBhcmdzWzBdO1xuICAgICAgICAgIHRoaXMua25leFF1ZXJ5W2pvaW5UeXBlXSh7IFthbGlhc106IHNwZWMgfSwgKGpvaW5DbGF1c2UpID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKG5ldyBKb2luQ2xhdXNlR3JvdXAoam9pbkNsYXVzZSkpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIFNpbXBsZVxuICAgICAgICAgIGNvbnN0IFtsZWZ0LCByaWdodF0gPSBhcmdzO1xuICAgICAgICAgIHRoaXMua25leFF1ZXJ5W2pvaW5UeXBlXSh7IFthbGlhc106IHNwZWMgfSwgbGVmdCwgcmlnaHQpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHNwZWMgaW5zdGFuY2VvZiBQdXJpKSB7XG4gICAgICAgIC8vIOyEnOu4jOy/vOumrDogam9pbih7IHNxOiBzdWJxdWVyeSB9LCAuLi4pXG4gICAgICAgIGlmIChhcmdzLmxlbmd0aCA9PT0gMSAmJiB0eXBlb2YgYXJnc1swXSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgLy8gQ2FsbGJhY2tcbiAgICAgICAgICBjb25zdCBjYWxsYmFjayA9IGFyZ3NbMF07XG4gICAgICAgICAgdGhpcy5rbmV4UXVlcnlbam9pblR5cGVdKHNwZWMucmF3UXVlcnkoKS5hcyhhbGlhcyksIChqb2luQ2xhdXNlKSA9PiB7XG4gICAgICAgICAgICBjYWxsYmFjayhuZXcgSm9pbkNsYXVzZUdyb3VwKGpvaW5DbGF1c2UpKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBTaW1wbGVcbiAgICAgICAgICBjb25zdCBbbGVmdCwgcmlnaHRdID0gYXJncztcbiAgICAgICAgICB0aGlzLmtuZXhRdWVyeVtqb2luVHlwZV0oc3BlYy5yYXdRdWVyeSgpLmFzKGFsaWFzKSwgbGVmdCwgcmlnaHQpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIHRhYmxlIHNwZWNpZmljYXRpb25cIik7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgYXJndW1lbnRzXCIpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gV0hFUkU6IOqwneyytCAtIOyCrOyaqTogLndoZXJlKHsgXCJ1LmlkXCI6IDEsIFwidS5zdGF0dXNcIjogXCJhY3RpdmVcIiB9KVxuICB3aGVyZShjb25kaXRpb25zOiBXaGVyZUNvbmRpdGlvbjxUVGFibGVzPik6IHRoaXM7XG4gIC8vIFdIRVJFOiDsu6zrn7wgLSDsgqzsmqk6IC53aGVyZShcInUuaWRcIiwgMSksIC53aGVyZShcInUuaWRcIiwgbnVsbClcbiAgd2hlcmU8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIC8vIFdIRVJFOiDsu6zrn7wgLSDsgqzsmqk6IC53aGVyZShcInUuaWRcIiwgXCI+XCIsIDEwKSwgLndoZXJlKFwidS5pZFwiLCBcIiE9XCIsIG51bGwpXG4gIHdoZXJlPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgb3BlcmF0b3I6IFdoZXJlT3BlcmF0b3IsXG4gICAgdmFsdWU6IEV4dHJhY3RDb2x1bW5UeXBlPFRUYWJsZXMsIFRDb2x1bW4gJiBzdHJpbmc+LFxuICApOiB0aGlzO1xuICAvLyBXSEVSRTogU1FMIO2RnO2YhOyLnSAtIOyCrOyaqTogLndoZXJlKHB1cmkucmF3KFwiQ09OQ0FUKHUubmFtZSwgdS5lbWFpbClcIiksIFwibGlrZVwiLCBcIiV0ZXN0JVwiKVxuICB3aGVyZTxUQ29sdW1uIGV4dGVuZHMgS25leC5SYXc+KGNvbHVtbjogVENvbHVtbiwgb3BlcmF0b3I6IFdoZXJlT3BlcmF0b3IsIHZhbHVlOiBhbnkpOiB0aGlzO1xuICAvLyBXSEVSRTog7Lus65+8IC0g7IKs7JqpOiAud2hlcmUoXCJ1LmlkXCIsIFwibGlrZVwiLCBcIiV0ZXN0JVwiKVxuICB3aGVyZSguLi5hcmdzOiBbY29sdW1uT3JDb25kaXRpb25zOiBhbnksIG9wZXJhdG9yT3JWYWx1ZT86IGFueSwgdmFsdWU/OiBhbnldKTogdGhpcyB7XG4gICAgY29uc3QgW2NvbHVtbk9yQ29uZGl0aW9ucywgb3BlcmF0b3JPclZhbHVlLCB2YWx1ZV0gPSBhcmdzO1xuICAgIGlmICh0eXBlb2YgY29sdW1uT3JDb25kaXRpb25zID09PSBcIm9iamVjdFwiKSB7XG4gICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZShjb2x1bW5PckNvbmRpdGlvbnMpO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIHZhbHVlID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICBpZiAob3BlcmF0b3JPclZhbHVlID09PSBudWxsKSB7XG4gICAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlTnVsbChjb2x1bW5PckNvbmRpdGlvbnMpO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH1cbiAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlKGNvbHVtbk9yQ29uZGl0aW9ucywgb3BlcmF0b3JPclZhbHVlKTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgaWYgKHZhbHVlID09PSBudWxsKSB7XG4gICAgICAgIGlmIChvcGVyYXRvck9yVmFsdWUgPT09IFwiIT1cIikge1xuICAgICAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlTm90TnVsbChjb2x1bW5PckNvbmRpdGlvbnMpO1xuICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9IGVsc2UgaWYgKG9wZXJhdG9yT3JWYWx1ZSA9PT0gXCI9XCIpIHtcbiAgICAgICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZU51bGwoY29sdW1uT3JDb25kaXRpb25zKTtcbiAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgdGhpcy5rbmV4UXVlcnkud2hlcmUoY29sdW1uT3JDb25kaXRpb25zLCBvcGVyYXRvck9yVmFsdWUsIHZhbHVlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5rbmV4UXVlcnkud2hlcmUoY29sdW1uT3JDb25kaXRpb25zKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyBXSEVSRSBJTlxuICB3aGVyZUluPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWVzOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPltdLFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMsIFRSZXN1bHQ+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS53aGVyZUluKGNvbHVtbiwgdmFsdWVzKTtcbiAgICByZXR1cm4gdGhpcyBhcyBhbnk7XG4gIH1cblxuICAvLyBXSEVSRSBOT1QgSU5cbiAgd2hlcmVOb3RJbjxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIHZhbHVlczogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz5bXSxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzLCBUUmVzdWx0PiB7XG4gICAgdGhpcy5rbmV4UXVlcnkud2hlcmVOb3RJbihjb2x1bW4sIHZhbHVlcyk7XG4gICAgcmV0dXJuIHRoaXMgYXMgYW55O1xuICB9XG5cbiAgLy8gV0hFUkUgTUFUQ0hcbiAgd2hlcmVNYXRjaDxUQ29sdW1uIGV4dGVuZHMgRnVsbHRleHRDb2x1bW5zPFRUYWJsZXM+Pihjb2x1bW46IFRDb2x1bW4sIHZhbHVlOiBzdHJpbmcpOiB0aGlzIHtcbiAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhgTUFUQ0ggKCR7U3RyaW5nKGNvbHVtbil9KSBBR0FJTlNUICg/KWAsIFt2YWx1ZV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIFBHcm9vbmdhIEZ1bGxUZXh0IOyduOuNseyKpCDqsoDsg4lcbiAgICogLSDsgqzsmqntlaAgUEdyb29uZ2Eg7J24642x7Iqk7JmAIOuPmeydvO2VnCDsu6zrn7wg6rWs7ISx7Jy866GcIOqygOyDie2VtOyVvCDsnbjrjbHsiqTqsIAg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiDri6jsnbwg7Lus65+8IOqygOyDiTpcbiAgICogYGBgc3FsXG4gICAqIFdIRVJFIG5hbWUgJkB+ICdzZWFyY2gnXG4gICAqIGBgYFxuICAgKlxuICAgKiDrs7Xtlakg7Lus65+8IOqygOyDiTpcbiAgICogYGBgc3FsXG4gICAqIFdIRVJFIEFSUkFZW25hbWU6OnRleHQsIGRlc2NyaXB0aW9uOjp0ZXh0XSAmQH4gJ3NlYXJjaCdcbiAgICogYGBgXG4gICAqL1xuICB3aGVyZVNlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uIHwgVENvbHVtbltdLFxuICAgIHZhbHVlOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHtcbiAgICAgIHdlaWdodHM/OiBudW1iZXJbXTsgLy8g7KCV7IiYIOuwsOyXtFxuICAgIH0sXG4gICk6IHRoaXMge1xuICAgIGNvbnN0IHsgd2VpZ2h0cyB9ID0gb3B0aW9ucyA/PyB7fTtcbiAgICBjb25zdCBjb2x1bW5FeHByID0gQXJyYXkuaXNBcnJheShjb2x1bW4pXG4gICAgICA/IGBBUlJBWVske2NvbHVtbi5tYXAoKGMpID0+IGAke2N9Ojp0ZXh0YCkuam9pbihcIixcIil9XWBcbiAgICAgIDogY29sdW1uO1xuICAgIGNvbnN0IHBncm9vbmdhQ29uZGl0aW9uID0gYHBncm9vbmdhX2NvbmRpdGlvbig/JHt3ZWlnaHRzPy5sZW5ndGggPyBgLCB3ZWlnaHRzID0+IEFSUkFZWyR7d2VpZ2h0cy5qb2luKFwiLFwiKX1dYCA6IFwiXCJ9KWA7XG5cbiAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhgJHtjb2x1bW5FeHByfSAmQH4gJHtwZ3Jvb25nYUNvbmRpdGlvbn1gLCBbdmFsdWVdKTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gV0hFUkUgRlVMTFRFWFRcbiAgd2hlcmVUc1NlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPiB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBUc1F1ZXJ5T3B0aW9ucyB8IFRzUXVlcnlDb25maWcsXG4gICk6IHRoaXMge1xuICAgIGNvbnN0IG9wdHMgPVxuICAgICAgdHlwZW9mIG9wdGlvbnMgPT09IFwic3RyaW5nXCIgPyAoeyBjb25maWc6IG9wdGlvbnMgfSBhcyBUc1F1ZXJ5T3B0aW9ucykgOiAob3B0aW9ucyA/PyB7fSk7XG5cbiAgICBjb25zdCBwYXJzZXIgPSBvcHRzLnBhcnNlciA/PyBcIndlYnNlYXJjaF90b190c3F1ZXJ5XCI7XG4gICAgY29uc3QgY29uZmlnID0gb3B0cy5jb25maWcgPz8gXCJzaW1wbGVcIjtcbiAgICBjb25zdCBjb2x1bW5FeHByID1cbiAgICAgIHR5cGVvZiBjb2x1bW4gPT09IFwib2JqZWN0XCIgJiYgY29sdW1uLl90eXBlID09PSBcInNxbF9leHByZXNzaW9uXCJcbiAgICAgICAgPyBjb2x1bW4uX3NxbFxuICAgICAgICA6IFN0cmluZyhjb2x1bW4pO1xuXG4gICAgdGhpcy5rbmV4UXVlcnkud2hlcmVSYXcoYCR7Y29sdW1uRXhwcn0gQEAgJHtwYXJzZXJ9KD8sID8pYCwgW2NvbmZpZywgdmFsdWVdKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHdoZXJlRnV6enk8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4gfCBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICBvcHRpb25zPzoge1xuICAgICAgb3BlcmF0b3I/OiBGdXp6eU9wZXJhdG9yO1xuICAgIH0sXG4gICk6IHRoaXMge1xuICAgIGNvbnN0IG9wZXJhdG9yID0gbm9ybWFsaXplRnV6enlPcGVyYXRvcihvcHRpb25zPy5vcGVyYXRvcik7XG5cbiAgICBpZiAob3BlcmF0b3IgPT09IFwiJVwiKSB7XG4gICAgICBpZiAodHlwZW9mIGNvbHVtbiA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhgJHtjb2x1bW4uX3NxbH0gJHtvcGVyYXRvcn0gP2AsIFsuLi5jb2x1bW4uX3BhcmFtcywgdmFsdWVdKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlUmF3KGA/PyAke29wZXJhdG9yfSA/YCwgW2NvbHVtbiwgdmFsdWVdKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgY29sdW1uID09PSBcIm9iamVjdFwiKSB7XG4gICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhgPyAke29wZXJhdG9yfSAke2NvbHVtbi5fc3FsfWAsIFt2YWx1ZSwgLi4uY29sdW1uLl9wYXJhbXNdKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5rbmV4UXVlcnkud2hlcmVSYXcoYD8gJHtvcGVyYXRvcn0gPz9gLCBbdmFsdWUsIGNvbHVtbl0pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIFdIRVJFIFJBV1xuICB3aGVyZVJhdyhzcWw6IHN0cmluZywgYmluZGluZ3M/OiByZWFkb25seSB1bmtub3duW10pOiB0aGlzIHtcbiAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhzcWwsIGJpbmRpbmdzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIFdIRVJFIOq0hO2YuCDqt7jro7ntlZFcbiAgd2hlcmVHcm91cChjYWxsYmFjazogKGc6IFdoZXJlR3JvdXA8VFRhYmxlcz4pID0+IHZvaWQpOiB0aGlzIHtcbiAgICB0aGlzLmtuZXhRdWVyeS53aGVyZSgoYnVpbGRlcikgPT4ge1xuICAgICAgY29uc3QgZ3JvdXAgPSBuZXcgV2hlcmVHcm91cDxUVGFibGVzPihidWlsZGVyKTtcbiAgICAgIGNhbGxiYWNrKGdyb3VwKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBvcldoZXJlR3JvdXAoY2FsbGJhY2s6IChnOiBXaGVyZUdyb3VwPFRUYWJsZXM+KSA9PiB2b2lkKTogdGhpcyB7XG4gICAgdGhpcy5rbmV4UXVlcnkub3JXaGVyZSgoYnVpbGRlcikgPT4ge1xuICAgICAgY29uc3QgZ3JvdXAgPSBuZXcgV2hlcmVHcm91cDxUVGFibGVzPihidWlsZGVyKTtcbiAgICAgIGNhbGxiYWNrKGdyb3VwKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIE9SREVSIEJZIChTcWxFeHByZXNzaW9u7Jy866Gc64+EIO2VoCDsiJgg7J6I7Ja07JW8IO2VqClcbiAgb3JkZXJCeTxUQ29sdW1uIGV4dGVuZHMgUmVzdWx0QXZhaWxhYmxlQ29sdW1uczxUVGFibGVzLCBUUmVzdWx0Pj4oXG4gICAgY29sdW1uOiBUQ29sdW1uIHwgU3FsRXhwcmVzc2lvbjxcIm51bWJlclwiPiB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4sXG4gICAgZGlyZWN0aW9uOiBcImFzY1wiIHwgXCJkZXNjXCIsXG4gICk6IHRoaXM7XG4gIG9yZGVyQnkoXG4gICAgY29sdW1uOiBzdHJpbmcgfCBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHwgU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPixcbiAgICBkaXJlY3Rpb246IFwiYXNjXCIgfCBcImRlc2NcIiA9IFwiYXNjXCIsXG4gICk6IHRoaXMge1xuICAgIGlmICh0eXBlb2YgY29sdW1uID09PSBcIm9iamVjdFwiKSB7XG4gICAgICB0aGlzLmtuZXhRdWVyeS5vcmRlckJ5UmF3KGAke2NvbHVtbi5fc3FsfSAke2RpcmVjdGlvbn1gLCBjb2x1bW4uX3BhcmFtcyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMua25leFF1ZXJ5Lm9yZGVyQnkoY29sdW1uLCBkaXJlY3Rpb24pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiDrsqHthLAg7Jyg7IKs64+EIOqygOyDiSDshKTsoJVcbiAgICpcbiAgICogLSBTRUxFQ1Tsl5Agc2ltaWxhcml0eSDsu6zrn7wg7LaU6rCAXG4gICAqIC0gV0hFUkUgY29sIElTIE5PVCBOVUxMIOy2lOqwgFxuICAgKiAtIHRocmVzaG9sZOqwgCDsnojsnLzrqbQgV0hFUkUg7KGw6rG0IOy2lOqwgFxuICAgKiAtIOq4sOyhtCBPUkRFUiBCWeulvCBjbGVhcu2VmOqzoCDsm5Dsi5wg7Jew7IKw7J6Q66GcIOygleugrCAoSE5TVyDsnbjrjbHsiqQg7LWc7KCB7ZmUKVxuICAgKlxuICAgKiBAcGFyYW0gY29sdW1uIOuyoe2EsCDsu6zrn7wg6rK966GcXG4gICAqIEBwYXJhbSBlbWJlZGRpbmcg7L+866asIOyehOuyoOuUqSDrsqHthLBcbiAgICogQHBhcmFtIG9wdGlvbnMgbWV0aG9kLCB0aHJlc2hvbGQsIGFzIOuTsSDsmLXshZhcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiAvLyBjb3NpbmUgc2ltaWxhcml0eSAo6riw67O46rCSKVxuICAgKiBxYi52ZWN0b3JTaW1pbGFyaXR5KFwiY29sdW1uTmFtZVwiLCBxdWVyeVZlY3Rvciwge1xuICAgKiAgIG1ldGhvZDogXCJjb3NpbmVcIixcbiAgICogICB0aHJlc2hvbGQ6IDAuNVxuICAgKiB9KTtcbiAgICpcbiAgICogLy8gTDIgZGlzdGFuY2VcbiAgICogcWIudmVjdG9yU2ltaWxhcml0eShcImNvbHVtbk5hbWVcIiwgcXVlcnlWZWN0b3IsIHtcbiAgICogICBtZXRob2Q6IFwibDJcIixcbiAgICogICB0aHJlc2hvbGQ6IDEuNSAgLy8g6rGw66as6rCAIDEuNSDsnbTtlZjsnbgg6rKw6rO866eMXG4gICAqIH0pO1xuICAgKlxuICAgKiAvLyBJbm5lciBwcm9kdWN0XG4gICAqIHFiLnZlY3RvclNpbWlsYXJpdHkoXCJjb2x1bW5OYW1lXCIsIHF1ZXJ5VmVjdG9yLCB7XG4gICAqICAgbWV0aG9kOiBcImlubmVyX3Byb2R1Y3RcIixcbiAgICogICB0aHJlc2hvbGQ6IDAuN1xuICAgKiB9KTtcbiAgICogYGBgXG4gICAqL1xuICB2ZWN0b3JTaW1pbGFyaXR5KFxuICAgIGNvbHVtbjogVmVjdG9yQ29sdW1uczxUVGFibGVzPixcbiAgICBlbWJlZGRpbmc6IG51bWJlcltdLFxuICAgIG9wdGlvbnM6IHtcbiAgICAgIG1ldGhvZD86IFwiY29zaW5lXCIgfCBcImwyXCIgfCBcImlubmVyX3Byb2R1Y3RcIjtcbiAgICAgIHRocmVzaG9sZD86IG51bWJlcjtcbiAgICAgIGRpc3RpbmN0T24/OiBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+O1xuICAgIH0gPSB7fSxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzLCBUUmVzdWx0ICYgeyBzaW1pbGFyaXR5OiBudW1iZXIgfT4ge1xuICAgIGNvbnN0IHsgbWV0aG9kID0gXCJjb3NpbmVcIiwgdGhyZXNob2xkLCBkaXN0aW5jdE9uIH0gPSBvcHRpb25zO1xuXG4gICAgaWYgKFxuICAgICAgIUFycmF5LmlzQXJyYXkoZW1iZWRkaW5nKSB8fFxuICAgICAgZW1iZWRkaW5nLmxlbmd0aCA9PT0gMCB8fFxuICAgICAgZW1iZWRkaW5nLnNvbWUoKHYpID0+ICFOdW1iZXIuaXNGaW5pdGUodikpXG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIGVtYmVkZGluZyB2ZWN0b3I6IGV4cGVjdGVkIGEgbm9uLWVtcHR5IGFycmF5IG9mIGZpbml0ZSBudW1iZXJzXCIpO1xuICAgIH1cblxuICAgIGNvbnN0IHZlY3RvckxpdGVyYWwgPSBKU09OLnN0cmluZ2lmeShlbWJlZGRpbmcubWFwKCh2KSA9PiBOdW1iZXIodikpKTtcbiAgICBjb25zdCBvcGVyYXRvciA9IHsgY29zaW5lOiBcIjw9PlwiLCBsMjogXCI8LT5cIiwgaW5uZXJfcHJvZHVjdDogXCI8Iz5cIiB9W21ldGhvZF07XG5cbiAgICAvLyBtZXRob2Trs4Qg7Jew7IKw7J6QIOuwjyBzaW1pbGFyaXR5IOqzhOyCsOyLnVxuICAgIC8vIC0gY29zaW5lOiA8PT4gKGNvc2luZSBkaXN0YW5jZSwgMH4yKSwgc2ltaWxhcml0eSA9IDEgLSBkaXN0YW5jZVxuICAgIC8vIC0gbDI6IDwtPiAoZXVjbGlkZWFuIGRpc3RhbmNlKSwgc2ltaWxhcml0eSA9IGRpc3RhbmNlICjrgq7snYTsiJjroZ0g7Jyg7IKsKVxuICAgIC8vIC0gaW5uZXJfcHJvZHVjdDogPCM+IChuZWdhdGl2ZSBpbm5lciBwcm9kdWN0KSwgc2ltaWxhcml0eSA9IC1kaXN0YW5jZSAo64aS7J2E7IiY66GdIOycoOyCrClcbiAgICBjb25zdCBzaW1pbGFyaXR5RXhwciA9XG4gICAgICBtZXRob2QgPT09IFwiY29zaW5lXCJcbiAgICAgICAgPyB0aGlzLmtuZXgucmF3KGAxIC0gKD8/ICR7b3BlcmF0b3J9ID86OnZlY3RvcikgYXMgc2ltaWxhcml0eWAsIFtjb2x1bW4sIHZlY3RvckxpdGVyYWxdKVxuICAgICAgICA6IG1ldGhvZCA9PT0gXCJsMlwiXG4gICAgICAgICAgPyB0aGlzLmtuZXgucmF3KGA/PyAke29wZXJhdG9yfSA/Ojp2ZWN0b3IgYXMgc2ltaWxhcml0eWAsIFtjb2x1bW4sIHZlY3RvckxpdGVyYWxdKVxuICAgICAgICAgIDogdGhpcy5rbmV4LnJhdyhgLSg/PyAke29wZXJhdG9yfSA/Ojp2ZWN0b3IpIGFzIHNpbWlsYXJpdHlgLCBbY29sdW1uLCB2ZWN0b3JMaXRlcmFsXSk7XG5cbiAgICAvLyBXSEVSRSBOT1QgTlVMTFxuICAgIHRoaXMua25leFF1ZXJ5LndoZXJlTm90TnVsbChjb2x1bW4pO1xuXG4gICAgLy8g6riw7KG0IE9SREVSIEJZIGNsZWFyXG4gICAgdGhpcy5rbmV4UXVlcnkuY2xlYXIoXCJvcmRlclwiKTtcbiAgICBpZiAoZGlzdGluY3RPbikge1xuICAgICAgLy8gRElTVElOQ1QgT07snYAgU0VMRUNUIOygiOydmCDrp6gg7JWe7JeQIOyZgOyVvCDtlZjrr4DroZwsIOq4sOyhtCBzZWxlY3Qoc3Vic2V0IO2VhOuTnOuTpCnrpbwg67O07KG0IO2bhCBjbGVhcu2VmOqzoCDri6Tsi5wg7LaU6rCAXG4gICAgICBjb25zdCBleGlzdGluZ1N1YnNldENvbHMgPSAodGhpcy5rbmV4UXVlcnkgYXMgYW55KS5fc3RhdGVtZW50c1xuICAgICAgICAuZmlsdGVyKChzOiBhbnkpID0+IHMuZ3JvdXBpbmcgPT09IFwiY29sdW1uc1wiKVxuICAgICAgICAuZmxhdE1hcCgoczogYW55KSA9PiBzLnZhbHVlKTtcbiAgICAgIHRoaXMua25leFF1ZXJ5LmNsZWFyKFwic2VsZWN0XCIpO1xuICAgICAgdGhpcy5rbmV4UXVlcnkuc2VsZWN0KHRoaXMua25leC5yYXcoYERJU1RJTkNUIE9OICg/PykgPz9gLCBbZGlzdGluY3RPbiwgZGlzdGluY3RPbl0pKTtcbiAgICAgIGV4aXN0aW5nU3Vic2V0Q29scy5tYXAoKGNvbDogYW55KSA9PiB0aGlzLmtuZXhRdWVyeS5zZWxlY3QoY29sKSk7XG4gICAgICB0aGlzLmtuZXhRdWVyeS5zZWxlY3Qoc2ltaWxhcml0eUV4cHIpO1xuICAgICAgdGhpcy5rbmV4UXVlcnkub3JkZXJCeVJhdyhgPz8sID8/ICR7b3BlcmF0b3J9ID86OnZlY3RvcmAsIFtcbiAgICAgICAgZGlzdGluY3RPbixcbiAgICAgICAgY29sdW1uLFxuICAgICAgICB2ZWN0b3JMaXRlcmFsLFxuICAgICAgXSk7XG5cbiAgICAgIHRoaXMua25leFF1ZXJ5ID0gdGhpcy5rbmV4XG4gICAgICAgIC5mcm9tKHRoaXMua25leFF1ZXJ5LmFzKFwiZGlzdGluY3RfdmVjdG9yc1wiKSlcbiAgICAgICAgLnNlbGVjdChcIipcIilcbiAgICAgICAgLm9yZGVyQnkoXCJzaW1pbGFyaXR5XCIsIFwiZGVzY1wiKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5rbmV4UXVlcnkuc2VsZWN0KHNpbWlsYXJpdHlFeHByKTtcbiAgICAgIHRoaXMua25leFF1ZXJ5Lm9yZGVyQnlSYXcoYD8/ICR7b3BlcmF0b3J9ID86OnZlY3RvcmAsIFtjb2x1bW4sIHZlY3RvckxpdGVyYWxdKTtcbiAgICB9XG5cbiAgICAvLyB0aHJlc2hvbGRcbiAgICBpZiAodHlwZW9mIHRocmVzaG9sZCA9PT0gXCJudW1iZXJcIikge1xuICAgICAgaWYgKCFOdW1iZXIuaXNGaW5pdGUodGhyZXNob2xkKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgdmVjdG9yU2ltaWxhcml0eSB0aHJlc2hvbGQ6ICR7dGhyZXNob2xkfWApO1xuICAgICAgfVxuXG4gICAgICBpZiAoZGlzdGluY3RPbikge1xuICAgICAgICBjb25zdCB0aHJlc2hvbGRPcCA9IG1ldGhvZCA9PT0gXCJsMlwiID8gXCI8PVwiIDogXCI+PVwiO1xuICAgICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZShcInNpbWlsYXJpdHlcIiwgdGhyZXNob2xkT3AsIHRocmVzaG9sZCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCB0aHJlc2hvbGRWYWx1ZSA9XG4gICAgICAgICAgbWV0aG9kID09PSBcImNvc2luZVwiID8gMSAtIHRocmVzaG9sZCA6IG1ldGhvZCA9PT0gXCJpbm5lcl9wcm9kdWN0XCIgPyAtdGhyZXNob2xkIDogdGhyZXNob2xkO1xuICAgICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhgPz8gJHtvcGVyYXRvcn0gPzo6dmVjdG9yIDw9ID9gLCBbXG4gICAgICAgICAgY29sdW1uLFxuICAgICAgICAgIHZlY3RvckxpdGVyYWwsXG4gICAgICAgICAgdGhyZXNob2xkVmFsdWUsXG4gICAgICAgIF0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzIGFzIGFueTtcbiAgfVxuXG4gIC8vIOq4sOuzuCDsv7zrpqwg66mU7ISc65Oc65OkXG4gIGxpbWl0KGNvdW50OiBudW1iZXIpOiB0aGlzIHtcbiAgICBpZiAoY291bnQgPCAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIGxpbWl0OiBtdXN0IGJlID49IDBcIik7XG4gICAgfVxuICAgIHRoaXMua25leFF1ZXJ5LmxpbWl0KGNvdW50KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIG9mZnNldChjb3VudDogbnVtYmVyKTogdGhpcyB7XG4gICAgaWYgKGNvdW50IDwgMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBvZmZzZXQ6IG11c3QgYmUgPj0gMFwiKTtcbiAgICB9XG4gICAgdGhpcy5rbmV4UXVlcnkub2Zmc2V0KGNvdW50KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIEdST1VQIEJZXG4gIGdyb3VwQnk8VENvbHVtbnMgZXh0ZW5kcyBSZXN1bHRBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXMsIFRSZXN1bHQ+PiguLi5jb2x1bW5zOiBUQ29sdW1uc1tdKTogdGhpcztcbiAgZ3JvdXBCeSguLi5jb2x1bW5zOiBzdHJpbmdbXSk6IHRoaXMge1xuICAgIHRoaXMua25leFF1ZXJ5Lmdyb3VwQnkoLi4uKGNvbHVtbnMgYXMgc3RyaW5nW10pKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIEhBVklOR1xuICBoYXZpbmcoY29uZGl0aW9uOiBzdHJpbmcpOiB0aGlzO1xuICBoYXZpbmc8VENvbHVtbiBleHRlbmRzIFJlc3VsdEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcywgVFJlc3VsdD4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICBvcGVyYXRvcjogQ29tcGFyaXNvbk9wZXJhdG9yLFxuICAgIHZhbHVlOiBhbnksXG4gICk6IHRoaXM7XG4gIC8vIEhBVklORyDqtaztmIRcbiAgaGF2aW5nKC4uLmNvbmRpdGlvbnM6IGFueVtdKTogdGhpcyB7XG4gICAgaWYgKGNvbmRpdGlvbnMubGVuZ3RoID09PSAxKSB7XG4gICAgICAvLyBoYXZpbmcoXCJDT1VOVCgqKSA+IDEwXCIpXG4gICAgICB0aGlzLmtuZXhRdWVyeS5oYXZpbmcodGhpcy5rbmV4LnJhdyhjb25kaXRpb25zWzBdKSk7XG4gICAgfSBlbHNlIGlmIChjb25kaXRpb25zLmxlbmd0aCA9PT0gMykge1xuICAgICAgLy8gaGF2aW5nKFwiY291bnRcIiwgXCI+XCIsIDEwKVxuICAgICAgdGhpcy5rbmV4UXVlcnkuaGF2aW5nKFxuICAgICAgICB0aGlzLmtuZXgucmF3KGNvbmRpdGlvbnNbMF0pLFxuICAgICAgICBjb25kaXRpb25zWzFdLFxuICAgICAgICB0aGlzLmtuZXgucmF3KGNvbmRpdGlvbnNbMl0pLFxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBoYXZpbmcgYXJndW1lbnRzXCIpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIOyLpO2WiSDrqZTshJzrk5zrk6QgLSB0aGVuYWJsZSDqtaztmIRcbiAgdGhlbjxUUmVzdWx0MSA9IEV4cGFuZDxUUmVzdWx0PltdLCBUUmVzdWx0MiA9IG5ldmVyPihcbiAgICBvbmZ1bGZpbGxlZD86ICgodmFsdWU6IEV4cGFuZDxUUmVzdWx0PltdKSA9PiBUUmVzdWx0MSB8IFByb21pc2VMaWtlPFRSZXN1bHQxPikgfCBudWxsLFxuICAgIG9ucmVqZWN0ZWQ/OiAoKHJlYXNvbjogYW55KSA9PiBUUmVzdWx0MiB8IFByb21pc2VMaWtlPFRSZXN1bHQyPikgfCBudWxsLFxuICApOiBQcm9taXNlPFRSZXN1bHQxIHwgVFJlc3VsdDI+IHtcbiAgICBOYWl0ZS50KFwicHVyaTpleGVjdXRlZC1xdWVyeVwiLCB0aGlzLnRvUXVlcnkoKSk7XG4gICAgcmV0dXJuIHRoaXMua25leFF1ZXJ5LnRoZW4ob25mdWxmaWxsZWQgYXMgYW55LCBvbnJlamVjdGVkKTtcbiAgfVxuICBjYXRjaDxUUmVzdWx0MiA9IG5ldmVyPihcbiAgICBvbnJlamVjdGVkPzogKChyZWFzb246IGFueSkgPT4gVFJlc3VsdDIgfCBQcm9taXNlTGlrZTxUUmVzdWx0Mj4pIHwgbnVsbCxcbiAgKTogUHJvbWlzZTxUUmVzdWx0IHwgVFJlc3VsdDI+IHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkuY2F0Y2gob25yZWplY3RlZCk7XG4gIH1cbiAgZmluYWxseShvbmZpbmFsbHk/OiAoKCkgPT4gdm9pZCkgfCBudWxsKTogUHJvbWlzZTxUUmVzdWx0PiB7XG4gICAgcmV0dXJuIHRoaXMua25leFF1ZXJ5LmZpbmFsbHkob25maW5hbGx5KTtcbiAgfVxuXG4gIC8vIO2VmOuCmOunjCDsv7zrpqxcbiAgZmlyc3QoKTogUmVzb2x2ZWRQdXJpPEV4cGFuZDxUUmVzdWx0PiwgbmV2ZXI+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS5maXJzdCgpO1xuICAgIHJldHVybiBuZXcgUmVzb2x2ZWRQdXJpKHRoaXMua25leFF1ZXJ5LCB0aGlzLmtuZXgpO1xuICB9XG5cbiAgLy8g7L+866as7ZWcIOugiOy9lOuTnOyXkOyEnCDtirnsoJUg7Lus65+866eMIOy2lOy2nO2VnCDrsLDsl7Qg66as7YS0XG4gIHBsdWNrPFRDb2x1bW4gZXh0ZW5kcyBrZXlvZiBUUmVzdWx0IHwgUmVzdWx0QXZhaWxhYmxlQ29sdW1uczxUVGFibGVzLCBUUmVzdWx0Pj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICApOiBSZXNvbHZlZFB1cmk8XG4gICAgVENvbHVtbiBleHRlbmRzIGtleW9mIFRSZXN1bHRcbiAgICAgID8gVFJlc3VsdFtUQ29sdW1uXVtdXG4gICAgICA6IEV4dHJhY3RDb2x1bW5UeXBlPFRUYWJsZXMsIFRDb2x1bW4gJiBzdHJpbmc+W10sXG4gICAgbmV2ZXJcbiAgPiB7XG4gICAgdGhpcy5rbmV4UXVlcnkucGx1Y2soY29sdW1uIGFzIHN0cmluZyk7XG4gICAgcmV0dXJuIG5ldyBSZXNvbHZlZFB1cmkodGhpcy5rbmV4UXVlcnksIHRoaXMua25leCk7XG4gIH1cblxuICAvLyBJTlNFUlQgOiDri6jsnbwg6rCd7LK0XG4gIGluc2VydChcbiAgICBkYXRhOiBJbnNlcnREYXRhPFNpbmdsZVRhYmxlVmFsdWU8VFRhYmxlcz4+LFxuICApOiBSZXNvbHZlZFB1cmk8SW5zZXJ0UmVzdWx0LCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PjtcbiAgLy8gSU5TRVJUOiDrsLDsl7RcbiAgaW5zZXJ0KFxuICAgIGRhdGE6IEluc2VydERhdGE8U2luZ2xlVGFibGVWYWx1ZTxUVGFibGVzPj5bXSxcbiAgKTogUmVzb2x2ZWRQdXJpPEluc2VydFJlc3VsdCwgU2luZ2xlVGFibGVWYWx1ZTxUVGFibGVzPj47XG4gIC8vIElOU0VSVCDsi6TsoJwg6rWs7ZiEXG4gIGluc2VydChcbiAgICByYXdEYXRhOiBJbnNlcnREYXRhPFNpbmdsZVRhYmxlVmFsdWU8VFRhYmxlcz4+IHwgSW5zZXJ0RGF0YTxTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PltdLFxuICApOiBSZXNvbHZlZFB1cmk8SW5zZXJ0UmVzdWx0LCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgLy8gSlNPTiDsu6zrn7wgc3RyaW5naWZ5IOuhnOyngeydhCDrqZTshJzrk5zroZwg67aE66as7ZWY7JesIOykkeuztSDsoJzqsbBcbiAgICBjb25zdCByZWZpbmVkRGF0YSA9IHRoaXMucmVmaW5lSnNvbkNvbHVtbnMocmF3RGF0YSk7XG4gICAgdGhpcy5rbmV4UXVlcnkuaW5zZXJ0KHJlZmluZWREYXRhKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxuXG4gIC8vIFVQREFURVxuICB1cGRhdGUocmF3RGF0YTogV2hlcmVDb25kaXRpb248VFRhYmxlcz4pOiBSZXNvbHZlZFB1cmk8bnVtYmVyLCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgLy8gSlNPTiDsu6zrn7wgc3RyaW5naWZ5IOuhnOyngeydhCDrqZTshJzrk5zroZwg67aE66as7ZWY7JesIOykkeuztSDsoJzqsbBcbiAgICBjb25zdCByZWZpbmVkRGF0YSA9IHRoaXMucmVmaW5lSnNvbkNvbHVtbnMocmF3RGF0YSk7XG4gICAgdGhpcy5rbmV4UXVlcnkudXBkYXRlKHJlZmluZWREYXRhKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBKU09OIOy7rOufvOyXkCDrjIDtlbQgc3RyaW5naWZ5IOyymOumrOulvCDsiJjtlontlZjripQg64K067aAIOuplOyEnOuTnOyeheuLiOuLpC5cbiAgICogb2JqZWN0IOuYkOuKlCBvYmplY3Qg67Cw7Je07J2EIOuwm+qzoCwgSlNPTiDsu6zrn7zsnbQg7J6I7Jy866m0IOyngeugrO2ZlO2VmOyXrCDrsJjtmZjtlanri4jri6QuXG4gICAqIOyngeygkSDqsJLsnYQg67OA6rK97ZWY66+A66GcIHNpZGUgZWZmZWN06rCAIOyeiOyKteuLiOuLpC5cbiAgICovXG4gIHByaXZhdGUgcmVmaW5lSnNvbkNvbHVtbnMoXG4gICAgZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdLFxuICApOiB0eXBlb2YgZGF0YSB7XG4gICAgLy8gdGFibGVTcGVj7J2064KYIGpzb25Db2x1bW5zIOyXhuuKlCDqsr3smrAg67CU66GcIOuwmO2ZmFxuICAgIGlmICghdGhpcy50YWJsZVNwZWMgfHwgIXRoaXMudGFibGVTcGVjLmpzb25Db2x1bW5zLmxlbmd0aCkge1xuICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfVxuXG4gICAgLy8g65Ox66Gd65CcIFRhYmxlU3BlY+ydhCDthrXtlbQgSlNPTuy7rOufvCDrqqnroZ3snYQg6rCA7KC47JmAIEpTT04uc3RyaW5naWZ5IOyymOumrFxuICAgIGNvbnN0IGpzb25Db2x1bW5zID0gdGhpcy50YWJsZVNwZWMuanNvbkNvbHVtbnM7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkoZGF0YSkpIHtcbiAgICAgIGZvciAoY29uc3QgaXRlbSBvZiBkYXRhKSB7XG4gICAgICAgIGZvciAoY29uc3QgY29sdW1uIG9mIGpzb25Db2x1bW5zKSB7XG4gICAgICAgICAgY29uc3QgdmFsdWUgPSBpdGVtW2NvbHVtbl07XG4gICAgICAgICAgaWYgKHZhbHVlICE9PSB1bmRlZmluZWQgJiYgdmFsdWUgIT09IG51bGwpIHtcbiAgICAgICAgICAgIGl0ZW1bY29sdW1uXSA9IEpTT04uc3RyaW5naWZ5KHZhbHVlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgZm9yIChjb25zdCBjb2x1bW4gb2YganNvbkNvbHVtbnMpIHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSBkYXRhW2NvbHVtbl07XG4gICAgICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkICYmIHZhbHVlICE9PSBudWxsKSB7XG4gICAgICAgICAgZGF0YVtjb2x1bW5dID0gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBkYXRhO1xuICB9XG5cbiAgLy8gSW5jcmVtZW50XG4gIGluY3JlbWVudDxUQ29sdW1uIGV4dGVuZHMgTnVtZXJpY0NvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogbnVtYmVyLFxuICApOiBSZXNvbHZlZFB1cmk8bnVtYmVyLCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgaWYgKHZhbHVlIDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkluY3JlbWVudCB2YWx1ZSBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwXCIpO1xuICAgIH1cbiAgICB0aGlzLmtuZXhRdWVyeS5pbmNyZW1lbnQoY29sdW1uLCB2YWx1ZSk7XG4gICAgcmV0dXJuIG5ldyBSZXNvbHZlZFB1cmkodGhpcy5rbmV4UXVlcnksIHRoaXMua25leCk7XG4gIH1cbiAgLy8gRGVjcmVtZW50XG4gIGRlY3JlbWVudDxUQ29sdW1uIGV4dGVuZHMgTnVtZXJpY0NvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogbnVtYmVyLFxuICApOiBSZXNvbHZlZFB1cmk8bnVtYmVyLCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgaWYgKHZhbHVlIDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkRlY3JlbWVudCB2YWx1ZSBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwXCIpO1xuICAgIH1cbiAgICB0aGlzLmtuZXhRdWVyeS5kZWNyZW1lbnQoY29sdW1uLCB2YWx1ZSk7XG4gICAgcmV0dXJuIG5ldyBSZXNvbHZlZFB1cmkodGhpcy5rbmV4UXVlcnksIHRoaXMua25leCk7XG4gIH1cblxuICAvLyBERUxFVEVcbiAgZGVsZXRlKCk6IFJlc29sdmVkUHVyaTxudW1iZXIsIFNpbmdsZVRhYmxlVmFsdWU8VFRhYmxlcz4+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS5kZWxldGUoKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxuXG4gIC8vIO2ZleyduCDsv7zrpqwg66as7YS0XG4gIHRvUXVlcnkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkudG9RdWVyeSgpO1xuICB9XG5cbiAgLy8g7L+866asIOuUlOuyhOq5hSDroZzqt7gg7Lac66ClXG4gIGRlYnVnKCk6IHRoaXMge1xuICAgIGNvbnNvbGUubG9nKGAke2NoYWxrLmN5YW4oXCJbUHVyaSBEZWJ1Z11cIil9ICR7Y2hhbGsueWVsbG93KHRoaXMudG9RdWVyeSgpKX1gKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGNsb25lKCk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcywgVFJlc3VsdD4ge1xuICAgIC8vICdkdWFsJ+ydgCDrjZTrr7gg7YWM7J2067iU7J2066mwLCDrsJTroZwg7JWE656YIOykhOyXkOyEnCBrbmV4UXVlcnnqsIAg642u7Ja07JSM7JuM7KeR64uI64ukLlxuICAgIGNvbnN0IG5ld1B1cmkgPSBuZXcgUHVyaTxUU2NoZW1hLCBUVGFibGVzLCBUUmVzdWx0Pih0aGlzLmtuZXgsIFwiZHVhbFwiKTtcbiAgICBuZXdQdXJpLmtuZXhRdWVyeSA9IHRoaXMua25leFF1ZXJ5LmNsb25lKCk7XG4gICAgcmV0dXJuIG5ld1B1cmk7XG4gIH1cblxuICBmb3JtYXRTUUwodW5mb3JtYXR0ZWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgLy8gU1FMIOyYiOyVveyWtCDrqqnroZ1cbiAgICBjb25zdCBrZXl3b3JkcyA9IFtcbiAgICAgIFwiU0VMRUNUXCIsXG4gICAgICBcIkZST01cIixcbiAgICAgIFwiV0hFUkVcIixcbiAgICAgIFwiSU5TRVJUXCIsXG4gICAgICBcIklOVE9cIixcbiAgICAgIFwiVkFMVUVTXCIsXG4gICAgICBcIlVQREFURVwiLFxuICAgICAgXCJERUxFVEVcIixcbiAgICAgIFwiQ1JFQVRFXCIsXG4gICAgICBcIlRBQkxFXCIsXG4gICAgICBcIkFMVEVSXCIsXG4gICAgICBcIkRST1BcIixcbiAgICAgIFwiSk9JTlwiLFxuICAgICAgXCJPTlwiLFxuICAgICAgXCJJTk5FUlwiLFxuICAgICAgXCJMRUZUXCIsXG4gICAgICBcIlJJR0hUXCIsXG4gICAgICBcIkZVTExcIixcbiAgICAgIFwiT1VURVJcIixcbiAgICAgIFwiR1JPVVBcIixcbiAgICAgIFwiQllcIixcbiAgICAgIFwiT1JERVJcIixcbiAgICAgIFwiSEFWSU5HXCIsXG4gICAgICBcIkRJU1RJTkNUXCIsXG4gICAgICBcIkxJTUlUXCIsXG4gICAgICBcIk9GRlNFVFwiLFxuICAgICAgXCJBU1wiLFxuICAgICAgXCJBTkRcIixcbiAgICAgIFwiT1JcIixcbiAgICAgIFwiTk9UXCIsXG4gICAgICBcIklOXCIsXG4gICAgICBcIkxJS0VcIixcbiAgICAgIFwiSVNcIixcbiAgICAgIFwiTlVMTFwiLFxuICAgICAgXCJDQVNFXCIsXG4gICAgICBcIldIRU5cIixcbiAgICAgIFwiVEhFTlwiLFxuICAgICAgXCJFTFNFXCIsXG4gICAgICBcIkVORFwiLFxuICAgICAgXCJVTklPTlwiLFxuICAgICAgXCJBTExcIixcbiAgICAgIFwiRVhJU1RTXCIsXG4gICAgICBcIkJFVFdFRU5cIixcbiAgICBdO1xuXG4gICAgbGV0IGZvcm1hdHRlZCA9IHVuZm9ybWF0dGVkO1xuXG4gICAgLy8g7JiI7JW97Ja066W8IOuMgOusuOyekOuhnCDrs4DtmZhcbiAgICBrZXl3b3Jkcy5mb3JFYWNoKChrZXl3b3JkKSA9PiB7XG4gICAgICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoYFxcXFxiJHtrZXl3b3JkfVxcXFxiYCwgXCJnaVwiKTtcbiAgICAgIGZvcm1hdHRlZCA9IGZvcm1hdHRlZC5yZXBsYWNlKHJlZ2V4LCBrZXl3b3JkLnRvVXBwZXJDYXNlKCkpO1xuICAgIH0pO1xuXG4gICAgLy8g7KO87JqUIOygiCDslZ7sl5Ag7KSE67CU6r+IIOy2lOqwgFxuICAgIGNvbnN0IG1ham9yQ2xhdXNlcyA9IFtcbiAgICAgIFwiU0VMRUNUXCIsXG4gICAgICBcIkZST01cIixcbiAgICAgIFwiV0hFUkVcIixcbiAgICAgIFwiR1JPVVAgQllcIixcbiAgICAgIFwiT1JERVIgQllcIixcbiAgICAgIFwiSEFWSU5HXCIsXG4gICAgICBcIkxJTUlUXCIsXG4gICAgICBcIlVOSU9OXCIsXG4gICAgXTtcbiAgICBtYWpvckNsYXVzZXMuZm9yRWFjaCgoY2xhdXNlKSA9PiB7XG4gICAgICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoYFxcXFxzKygke2NsYXVzZX0pXFxcXHMrYCwgXCJnaVwiKTtcbiAgICAgIGZvcm1hdHRlZCA9IGZvcm1hdHRlZC5yZXBsYWNlKHJlZ2V4LCBgXFxuJHtjbGF1c2UudG9VcHBlckNhc2UoKX0gYCk7XG4gICAgfSk7XG5cbiAgICAvLyBKT0lOIOygiCDsspjrpqxcbiAgICBmb3JtYXR0ZWQgPSBmb3JtYXR0ZWQucmVwbGFjZSgvXFxzKygoPzpJTk5FUnxMRUZUfFJJR0hUfEZVTEwgT1VURVIpXFxzKyk/Sk9JTlxccysvZ2ksIFwiXFxuJDFKT0lOIFwiKTtcblxuICAgIC8vIEFORCwgT1Ig7KGw6rG0IOyymOumrFxuICAgIGZvcm1hdHRlZCA9IGZvcm1hdHRlZC5yZXBsYWNlKC9cXHMrKEFORHxPUilcXHMrL2dpLCBcIlxcbiAgJDEgXCIpO1xuXG4gICAgLy8g6rSE7Zi4IOyymOumrCDrsI8g65Ok7Jes7JOw6riwXG4gICAgY29uc3QgbGluZXMgPSBmb3JtYXR0ZWQuc3BsaXQoXCJcXG5cIik7XG4gICAgY29uc3QgaW5kZW50ZWRMaW5lcyA9IFtdO1xuICAgIGxldCBpbmRlbnRMZXZlbCA9IDA7XG5cbiAgICBmb3IgKGNvbnN0IGxpbmUgb2YgbGluZXMpIHtcbiAgICAgIGNvbnN0IHRyaW1tZWRMaW5lID0gbGluZS50cmltKCk7XG4gICAgICBpZiAoIXRyaW1tZWRMaW5lKSBjb250aW51ZTtcblxuICAgICAgLy8g64ur64qUIOq0hO2YuOqwgCDsnojsnLzrqbQg65Ok7Jes7JOw6riwIOugiOuyqCDqsJDshoxcbiAgICAgIGNvbnN0IGNsb3NpbmdQYXJlbnMgPSAodHJpbW1lZExpbmUubWF0Y2goL1xcKS9nKSB8fCBbXSkubGVuZ3RoO1xuICAgICAgY29uc3Qgb3BlbmluZ1BhcmVucyA9ICh0cmltbWVkTGluZS5tYXRjaCgvXFwoL2cpIHx8IFtdKS5sZW5ndGg7XG5cbiAgICAgIGlmIChjbG9zaW5nUGFyZW5zID4gMCAmJiBvcGVuaW5nUGFyZW5zID09PSAwKSB7XG4gICAgICAgIGluZGVudExldmVsID0gTWF0aC5tYXgoMCwgaW5kZW50TGV2ZWwgLSBjbG9zaW5nUGFyZW5zKTtcbiAgICAgIH1cblxuICAgICAgLy8g7ZiE7J6sIOuTpOyXrOyTsOq4sCDsoIHsmqlcbiAgICAgIGNvbnN0IGluZGVudCA9IFwiICBcIi5yZXBlYXQoaW5kZW50TGV2ZWwpO1xuICAgICAgaW5kZW50ZWRMaW5lcy5wdXNoKGluZGVudCArIHRyaW1tZWRMaW5lKTtcblxuICAgICAgLy8g7Jes64qUIOq0hO2YuOqwgCDsnojsnLzrqbQg65Ok7Jes7JOw6riwIOugiOuyqCDspp3qsIBcbiAgICAgIGlmIChvcGVuaW5nUGFyZW5zID4gY2xvc2luZ1BhcmVucykge1xuICAgICAgICBpbmRlbnRMZXZlbCArPSBvcGVuaW5nUGFyZW5zIC0gY2xvc2luZ1BhcmVucztcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gaW5kZW50ZWRMaW5lcy5qb2luKFwiXFxuXCIpLnRyaW0oKTtcbiAgfVxuXG4gIHJhdyhzcWw6IHN0cmluZyk6IEtuZXguUmF3IHtcbiAgICByZXR1cm4gdGhpcy5rbmV4LnJhdyhzcWwpO1xuICB9XG5cbiAgLy8gS25leCDsv7zrpqwg67mM642UIOyngeygkSDsoJHqt7xcbiAgcmF3UXVlcnkoKTogS25leC5RdWVyeUJ1aWxkZXIge1xuICAgIHJldHVybiB0aGlzLmtuZXhRdWVyeTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgV2hlcmVHcm91cDxUVGFibGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGJ1aWxkZXI6IEtuZXguUXVlcnlCdWlsZGVyKSB7fVxuXG4gIC8vIHdoZXJlIOuplOyEnOuTnOuTpFxuICB3aGVyZShjb25kaXRpb25zOiBXaGVyZUNvbmRpdGlvbjxUVGFibGVzPik6IHRoaXM7XG4gIHdoZXJlPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWU6IEV4dHJhY3RDb2x1bW5UeXBlPFRUYWJsZXMsIFRDb2x1bW4gJiBzdHJpbmc+LFxuICApOiB0aGlzO1xuICB3aGVyZTxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIG9wZXJhdG9yOiBXaGVyZU9wZXJhdG9yLFxuICAgIHZhbHVlOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgd2hlcmUoLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIud2hlcmUoYXJnc1swXSwgLi4uYXJncy5zbGljZSgxKSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyB3aGVyZUluIC8gd2hlcmVOb3RJbiDrqZTshJzrk5zrk6RcbiAgd2hlcmVJbjxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIHZhbHVlczogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz5bXSxcbiAgKTogdGhpcztcbiAgd2hlcmVJbiguLi5hcmdzOiBhbnlbXSk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci53aGVyZUluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgd2hlcmVOb3RJbjxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIHZhbHVlczogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz5bXSxcbiAgKTogdGhpcztcbiAgd2hlcmVOb3RJbiguLi5hcmdzOiBhbnlbXSk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci53aGVyZU5vdEluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gb3JXaGVyZSDrqZTshJzrk5zrk6RcbiAgb3JXaGVyZShjb25kaXRpb25zOiBXaGVyZUNvbmRpdGlvbjxUVGFibGVzPik6IHRoaXM7XG4gIG9yV2hlcmU8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIG9yV2hlcmU8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICBvcGVyYXRvcjogV2hlcmVPcGVyYXRvcixcbiAgICB2YWx1ZTogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIG9yV2hlcmUoLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZShhcmdzWzBdLCAuLi5hcmdzLnNsaWNlKDEpKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIG9yV2hlcmVJbiAvIG9yV2hlcmVOb3RJbiDrqZTshJzrk5zrk6RcbiAgb3JXaGVyZUluPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWVzOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPltdLFxuICApOiB0aGlzO1xuICBvcldoZXJlSW4oLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZUluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgb3JXaGVyZU5vdEluPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWVzOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPltdLFxuICApOiB0aGlzO1xuICBvcldoZXJlTm90SW4oLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZU5vdEluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gV0hFUkUgTUFUQ0hcbiAgd2hlcmVNYXRjaDxUQ29sdW1uIGV4dGVuZHMgRnVsbHRleHRDb2x1bW5zPFRUYWJsZXM+Pihjb2x1bW46IFRDb2x1bW4sIHZhbHVlOiBzdHJpbmcpOiB0aGlzO1xuICB3aGVyZU1hdGNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgdGhpcy5idWlsZGVyLndoZXJlUmF3KGBNQVRDSCAoJHtTdHJpbmcoYXJnc1swXSl9KSBBR0FJTlNUICg/KWAsIFthcmdzWzFdXSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBvcldoZXJlTWF0Y2g8VENvbHVtbiBleHRlbmRzIEZ1bGx0ZXh0Q29sdW1uczxUVGFibGVzPj4oY29sdW1uOiBUQ29sdW1uLCB2YWx1ZTogc3RyaW5nKTogdGhpcztcbiAgb3JXaGVyZU1hdGNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgdGhpcy5idWlsZGVyLm9yV2hlcmVSYXcoYE1BVENIICgke1N0cmluZyhhcmdzWzBdKX0pIEFHQUlOU1QgKD8pYCwgW2FyZ3NbMV1dKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIFdIRVJFIFNFQVJDSFxuICB3aGVyZVNlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uIHwgVENvbHVtbltdLFxuICAgIHZhbHVlOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHtcbiAgICAgIHdlaWdodHM/OiBudW1iZXJbXTsgLy8g7KCV7IiYIOuwsOyXtFxuICAgIH0sXG4gICk6IHRoaXM7XG4gIHdoZXJlU2VhcmNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgY29uc3QgeyB3ZWlnaHRzIH0gPSBhcmdzWzJdID8/IHt9O1xuICAgIGNvbnN0IGNvbHVtbkV4cHIgPSBBcnJheS5pc0FycmF5KGFyZ3NbMF0pXG4gICAgICA/IGBBUlJBWVske2FyZ3NbMF0ubWFwKChjKSA9PiBgJHtjfTo6dGV4dGApLmpvaW4oXCIsXCIpfV1gXG4gICAgICA6IGFyZ3NbMF07XG4gICAgY29uc3QgcGdyb29uZ2FDb25kaXRpb24gPSBgcGdyb29uZ2FfY29uZGl0aW9uKD8ke3dlaWdodHM/Lmxlbmd0aCA/IGAsIHdlaWdodHMgPT4gQVJSQVlbJHt3ZWlnaHRzLmpvaW4oXCIsXCIpfV1gIDogXCJcIn0pYDtcbiAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYCR7Y29sdW1uRXhwcn0gJkB+ICR7cGdyb29uZ2FDb25kaXRpb259YCwgW2FyZ3NbMV1dKTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgb3JXaGVyZVNlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uIHwgVENvbHVtbltdLFxuICAgIHZhbHVlOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHtcbiAgICAgIHdlaWdodHM/OiBudW1iZXJbXTsgLy8g7KCV7IiYIOuwsOyXtFxuICAgIH0sXG4gICk6IHRoaXM7XG4gIG9yV2hlcmVTZWFyY2goLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICBjb25zdCB7IHdlaWdodHMgfSA9IGFyZ3NbMl0gPz8ge307XG4gICAgY29uc3QgY29sdW1uRXhwciA9IEFycmF5LmlzQXJyYXkoYXJnc1swXSlcbiAgICAgID8gYEFSUkFZWyR7YXJnc1swXS5tYXAoKGMpID0+IGAke2N9Ojp0ZXh0YCkuam9pbihcIixcIil9XWBcbiAgICAgIDogYXJnc1swXTtcbiAgICBjb25zdCBwZ3Jvb25nYUNvbmRpdGlvbiA9IGBwZ3Jvb25nYV9jb25kaXRpb24oPyR7d2VpZ2h0cz8ubGVuZ3RoID8gYCwgd2VpZ2h0cyA9PiBBUlJBWVske3dlaWdodHMuam9pbihcIixcIil9XWAgOiBcIlwifSlgO1xuICAgIHRoaXMuYnVpbGRlci5vcldoZXJlUmF3KGAke2NvbHVtbkV4cHJ9ICZAfiAke3Bncm9vbmdhQ29uZGl0aW9ufWAsIFthcmdzWzFdXSk7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIFdIRVJFIEZVTExURVhUXG4gIHdoZXJlVHNTZWFyY2g8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4gfCBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICBvcHRpb25zPzogVHNRdWVyeU9wdGlvbnMgfCBUc1F1ZXJ5Q29uZmlnLFxuICApOiB0aGlzO1xuICB3aGVyZVRzU2VhcmNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgY29uc3Qgb3B0cyA9XG4gICAgICB0eXBlb2YgYXJnc1syXSA9PT0gXCJzdHJpbmdcIiA/ICh7IGNvbmZpZzogYXJnc1syXSB9IGFzIFRzUXVlcnlPcHRpb25zKSA6IChhcmdzWzJdID8/IHt9KTtcblxuICAgIGNvbnN0IHBhcnNlciA9IG9wdHMucGFyc2VyID8/IFwid2Vic2VhcmNoX3RvX3RzcXVlcnlcIjtcbiAgICBjb25zdCBjb25maWcgPSBvcHRzLmNvbmZpZyA/PyBcInNpbXBsZVwiO1xuICAgIGNvbnN0IGNvbHVtbkV4cHIgPVxuICAgICAgdHlwZW9mIGFyZ3NbMF0gPT09IFwib2JqZWN0XCIgJiYgYXJnc1swXS5fdHlwZSA9PT0gXCJzcWxfZXhwcmVzc2lvblwiXG4gICAgICAgID8gYXJnc1swXS5fc3FsXG4gICAgICAgIDogU3RyaW5nKGFyZ3NbMF0pO1xuXG4gICAgdGhpcy5idWlsZGVyLndoZXJlUmF3KGAke2NvbHVtbkV4cHJ9IEBAICR7cGFyc2VyfSg/LCA/KWAsIFtjb25maWcsIGFyZ3NbMV1dKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIG9yV2hlcmVUc1NlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPiB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBUc1F1ZXJ5T3B0aW9ucyB8IFRzUXVlcnlDb25maWcsXG4gICk6IHRoaXM7XG4gIG9yV2hlcmVUc1NlYXJjaCguLi5hcmdzOiBhbnlbXSk6IHRoaXMge1xuICAgIGNvbnN0IG9wdHMgPVxuICAgICAgdHlwZW9mIGFyZ3NbMl0gPT09IFwic3RyaW5nXCIgPyAoeyBjb25maWc6IGFyZ3NbMl0gfSBhcyBUc1F1ZXJ5T3B0aW9ucykgOiAoYXJnc1syXSA/PyB7fSk7XG5cbiAgICBjb25zdCBwYXJzZXIgPSBvcHRzLnBhcnNlciA/PyBcIndlYnNlYXJjaF90b190c3F1ZXJ5XCI7XG4gICAgY29uc3QgY29uZmlnID0gb3B0cy5jb25maWcgPz8gXCJzaW1wbGVcIjtcbiAgICBjb25zdCBjb2x1bW5FeHByID1cbiAgICAgIHR5cGVvZiBhcmdzWzBdID09PSBcIm9iamVjdFwiICYmIGFyZ3NbMF0uX3R5cGUgPT09IFwic3FsX2V4cHJlc3Npb25cIlxuICAgICAgICA/IGFyZ3NbMF0uX3NxbFxuICAgICAgICA6IFN0cmluZyhhcmdzWzBdKTtcblxuICAgIHRoaXMuYnVpbGRlci5vcldoZXJlUmF3KGAke2NvbHVtbkV4cHJ9IEBAICR7cGFyc2VyfSg/LCA/KWAsIFtjb25maWcsIGFyZ3NbMV1dKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHdoZXJlRnV6enk8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4gfCBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICBvcHRpb25zPzoge1xuICAgICAgb3BlcmF0b3I/OiBGdXp6eU9wZXJhdG9yO1xuICAgIH0sXG4gICk6IHRoaXM7XG4gIHdoZXJlRnV6enkoLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICBjb25zdCBvcGVyYXRvciA9IG5vcm1hbGl6ZUZ1enp5T3BlcmF0b3IoYXJnc1syXT8ub3BlcmF0b3IpO1xuXG4gICAgaWYgKG9wZXJhdG9yID09PSBcIiVcIikge1xuICAgICAgaWYgKHR5cGVvZiBhcmdzWzBdID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgIHRoaXMuYnVpbGRlci53aGVyZVJhdyhgJHthcmdzWzBdLl9zcWx9ICR7b3BlcmF0b3J9ID9gLCBbLi4uYXJnc1swXS5fcGFyYW1zLCBhcmdzWzFdXSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYD8/ICR7b3BlcmF0b3J9ID9gLCBbYXJnc1swXSwgYXJnc1sxXV0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBhcmdzWzBdID09PSBcIm9iamVjdFwiKSB7XG4gICAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYD8gJHtvcGVyYXRvcn0gJHthcmdzWzBdLl9zcWx9YCwgW2FyZ3NbMV0sIC4uLmFyZ3NbMF0uX3BhcmFtc10pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYD8gJHtvcGVyYXRvcn0gPz9gLCBbYXJnc1sxXSwgYXJnc1swXV0pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIG9yV2hlcmVGdXp6eTxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPiB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7XG4gICAgICBvcGVyYXRvcj86IEZ1enp5T3BlcmF0b3I7XG4gICAgfSxcbiAgKTogdGhpcztcbiAgb3JXaGVyZUZ1enp5KC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgY29uc3Qgb3BlcmF0b3IgPSBub3JtYWxpemVGdXp6eU9wZXJhdG9yKGFyZ3NbMl0/Lm9wZXJhdG9yKTtcblxuICAgIGlmIChvcGVyYXRvciA9PT0gXCIlXCIpIHtcbiAgICAgIGlmICh0eXBlb2YgYXJnc1swXSA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZVJhdyhgJHthcmdzWzBdLl9zcWx9ICR7b3BlcmF0b3J9ID9gLCBbLi4uYXJnc1swXS5fcGFyYW1zLCBhcmdzWzFdXSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZVJhdyhgPz8gJHtvcGVyYXRvcn0gP2AsIFthcmdzWzBdLCBhcmdzWzFdXSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGFyZ3NbMF0gPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRoaXMuYnVpbGRlci5vcldoZXJlUmF3KGA/ICR7b3BlcmF0b3J9ICR7YXJnc1swXS5fc3FsfWAsIFthcmdzWzFdLCAuLi5hcmdzWzBdLl9wYXJhbXNdKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5idWlsZGVyLm9yV2hlcmVSYXcoYD8gJHtvcGVyYXRvcn0gPz9gLCBbYXJnc1sxXSwgYXJnc1swXV0pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIOykkeyyqSDqt7jro7lcbiAgd2hlcmVHcm91cChjYWxsYmFjazogKGc6IFdoZXJlR3JvdXA8VFRhYmxlcz4pID0+IHZvaWQpOiB0aGlzO1xuICB3aGVyZUdyb3VwKGNhbGxiYWNrOiAoZzogV2hlcmVHcm91cDxUVGFibGVzPikgPT4gdm9pZCk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci53aGVyZSgoc3ViQnVpbGRlcikgPT4ge1xuICAgICAgY29uc3Qgc3ViR3JvdXAgPSBuZXcgV2hlcmVHcm91cDxUVGFibGVzPihzdWJCdWlsZGVyKTtcbiAgICAgIGNhbGxiYWNrKHN1Ykdyb3VwKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBvcldoZXJlR3JvdXAoY2FsbGJhY2s6IChnOiBXaGVyZUdyb3VwPFRUYWJsZXM+KSA9PiB2b2lkKTogdGhpcztcbiAgb3JXaGVyZUdyb3VwKGNhbGxiYWNrOiAoZzogV2hlcmVHcm91cDxUVGFibGVzPikgPT4gdm9pZCk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci5vcldoZXJlKChzdWJCdWlsZGVyKSA9PiB7XG4gICAgICBjb25zdCBzdWJHcm91cCA9IG5ldyBXaGVyZUdyb3VwPFRUYWJsZXM+KHN1YkJ1aWxkZXIpO1xuICAgICAgY2FsbGJhY2soc3ViR3JvdXApO1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG5cbi8vIEpPSU4g7KCIIOq3uOujueyXkOuKlCBMZWZ07JmAIFJpZ2h07JeQIOuMgO2VnCDsiJzshJzqsIAg7ZWE7JqU7ZWY7KeAIOyViuycvOuvgOuhnCwg66qo65OgIOqyveyasOydmCDsiJjrpbwg6rOE7IKw7ZW07JW87ZWoLlxuZXhwb3J0IGNsYXNzIEpvaW5DbGF1c2VHcm91cDxcbiAgVExlZnQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICBUUmlnaHQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuPiB7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgY2FsbGJhY2s6IEtuZXguSm9pbkNsYXVzZSkge31cblxuICAvLyBPTihBTkQpOiDsu6zrn7wgPSDsu6zrn7xcbiAgb24obGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4pOiB0aGlzO1xuICBvbihsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0Pik6IHRoaXM7XG4gIC8vIE9OKEFORCk6IOy7rOufvCA9IOqwklxuICBvbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0PixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICAgIHJpZ2h0OiBFeHRyYWN0Q29sdW1uVHlwZTxUUmlnaHQsIEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIC8vIE9OKEFORCk6IOy7rOufvCAo7Jew7IKw7J6QKSDsu6zrn7xcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICApOiB0aGlzO1xuICBvbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICk6IHRoaXM7XG4gIC8vIE9OKEFORCk6IOy7rOufvCAo7Jew7IKw7J6QKSDqsJJcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICAgIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsXG4gICAgcmlnaHQ6IEV4dHJhY3RDb2x1bW5UeXBlPFRSaWdodCwgQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgLy8gT04oQU5EKTog7L2c67CxXG4gIG9uKGNhbGxiYWNrOiAobmVzdGVkOiBKb2luQ2xhdXNlR3JvdXA8VExlZnQsIFRSaWdodD4pID0+IHZvaWQpOiB0aGlzO1xuICBvbihjYWxsYmFjazogKG5lc3RlZDogSm9pbkNsYXVzZUdyb3VwPFRSaWdodCwgVExlZnQ+KSA9PiB2b2lkKTogdGhpcztcbiAgLy8gT04oQU5EKSDqtaztmIRcbiAgb24oLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICB0aGlzLmNhbGxiYWNrLm9uKC4uLihhcmdzIGFzIFtzdHJpbmcsIHN0cmluZ10pKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIE9OKE9SKTog7Lus65+8ID0g7Lus65+8XG4gIG9yT24obGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4pOiB0aGlzO1xuICBvck9uKGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgcmlnaHQ6IEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+KTogdGhpcztcbiAgLy8gT04oT1IpOiDsu6zrn7wgPSDqsJJcbiAgb3JPbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0PixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb3JPbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sXG4gICAgcmlnaHQ6IEV4dHJhY3RDb2x1bW5UeXBlPFRSaWdodCwgQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgLy8gT04oT1IpOiDsu6zrn7wgKOyXsOyCsOyekCkg7Lus65+8XG4gIG9yT24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICApOiB0aGlzO1xuICBvck9uKFxuICAgIGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PixcbiAgICBvcGVyYXRvcjogQ29tcGFyaXNvbk9wZXJhdG9yLFxuICAgIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0PixcbiAgKTogdGhpcztcbiAgLy8gT04oT1IpOiDsu6zrn7wgKOyXsOyCsOyekCkg6rCSXG4gIG9yT24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb3JPbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VFJpZ2h0LCBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4gJiBzdHJpbmc+LFxuICApOiB0aGlzO1xuICAvLyBPTihPUik6IOy9nOuwsVxuICBvck9uKGNhbGxiYWNrOiAobmVzdGVkOiBKb2luQ2xhdXNlR3JvdXA8VExlZnQsIFRSaWdodD4pID0+IHZvaWQpOiB0aGlzO1xuICBvck9uKGNhbGxiYWNrOiAobmVzdGVkOiBKb2luQ2xhdXNlR3JvdXA8VFJpZ2h0LCBUTGVmdD4pID0+IHZvaWQpOiB0aGlzO1xuICAvLyBPTihPUikg6rWs7ZiEXG4gIG9yT24oLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICB0aGlzLmNhbGxiYWNrLm9yT24oLi4uKGFyZ3MgYXMgW3N0cmluZywgc3RyaW5nXSkpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gT04gVkFMKEFORCk6IOy7rOufvCA9IOqwkiAo6rCS7J2EIOy7rOufvCDssLjsobDqsIAg7JWE64uMIO2MjOudvOuvuO2EsOuhnCDrsJTsnbjrlKkpXG4gIG9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBvblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBvblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0Piwgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvciwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9uVmFsKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgKHRoaXMuY2FsbGJhY2sgYXMgYW55KS5vblZhbCguLi5hcmdzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIEFORCBPTiBWQUw6IG9uVmFs7J2YIOuqheyLnOyggSBhbGlhcyAoS25leCDtmLjtmZgpXG4gIGFuZE9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBhbmRPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIGFuZE9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBhbmRPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0Piwgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvciwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIGFuZE9uVmFsKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgKHRoaXMuY2FsbGJhY2sgYXMgYW55KS5hbmRPblZhbCguLi5hcmdzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIE9SIE9OIFZBTDogT1Ig7KGw6rG07Jy866GcIOqwkiDrsJTsnbjrlKlcbiAgb3JPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+LCB2YWx1ZTogYW55KTogdGhpcztcbiAgb3JPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9yT25WYWwoY29sdW1uOiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0Piwgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvciwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9yT25WYWwoY29sdW1uOiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBvck9uVmFsKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgKHRoaXMuY2FsbGJhY2sgYXMgYW55KS5vck9uVmFsKC4uLmFyZ3MpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG5cbi8qXG4gIFRSZXNvbHZlZDog7L+866asIOyLpO2WiSDtm4Qg67CY7ZmY65CgIOqysOqzvCDtg4DsnoVcbiAgVFJldHVybmluZzogUkVUVVJOSU5HIOygiOyXkCDsgqzsmqnrkKAg7YOA7J6FXG4qL1xuZXhwb3J0IGNsYXNzIFJlc29sdmVkUHVyaTxUUmVzb2x2ZWQsIFRSZXR1cm5pbmc+IGltcGxlbWVudHMgUHJvbWlzZTxUUmVzb2x2ZWQ+IHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIGtuZXhRdWVyeTogS25leC5RdWVyeUJ1aWxkZXIsXG4gICAgcHJpdmF0ZSBrbmV4OiBLbmV4LFxuICApIHt9XG5cbiAgW1N5bWJvbC50b1N0cmluZ1RhZ106IHN0cmluZyA9IFwiUHJvbWlzZVwiO1xuXG4gIHRvUXVlcnkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkudG9RdWVyeSgpO1xuICB9XG5cbiAgZGVidWcoKTogdGhpcyB7XG4gICAgY29uc29sZS5sb2coYCR7Y2hhbGsuY3lhbihcIltQdXJpIERlYnVnXVwiKX0gJHtjaGFsay55ZWxsb3codGhpcy50b1F1ZXJ5KCkpfWApO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgdGhlbjxUUmVzdWx0MSA9IFRSZXNvbHZlZCwgVFJlc3VsdDIgPSBuZXZlcj4oXG4gICAgb25mdWxmaWxsZWQ/OiAoKHZhbHVlOiBUUmVzb2x2ZWQpID0+IFRSZXN1bHQxIHwgUHJvbWlzZUxpa2U8VFJlc3VsdDE+KSB8IG51bGwsXG4gICAgb25yZWplY3RlZD86ICgocmVhc29uOiBhbnkpID0+IFRSZXN1bHQyIHwgUHJvbWlzZUxpa2U8VFJlc3VsdDI+KSB8IG51bGwsXG4gICk6IFByb21pc2U8VFJlc3VsdDEgfCBUUmVzdWx0Mj4ge1xuICAgIE5haXRlLnQoXCJwdXJpOmV4ZWN1dGVkLXF1ZXJ5XCIsIHRoaXMudG9RdWVyeSgpKTtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkudGhlbihvbmZ1bGZpbGxlZCBhcyBhbnksIG9ucmVqZWN0ZWQpO1xuICB9XG5cbiAgY2F0Y2g8VFJlc3VsdDIgPSBuZXZlcj4oXG4gICAgb25yZWplY3RlZD86ICgocmVhc29uOiBhbnkpID0+IFRSZXN1bHQyIHwgUHJvbWlzZUxpa2U8VFJlc3VsdDI+KSB8IG51bGwsXG4gICk6IFByb21pc2U8VFJlc29sdmVkIHwgVFJlc3VsdDI+IHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkuY2F0Y2gob25yZWplY3RlZCk7XG4gIH1cblxuICBmaW5hbGx5KG9uZmluYWxseT86ICgoKSA9PiB2b2lkKSB8IG51bGwpOiBQcm9taXNlPFRSZXNvbHZlZD4ge1xuICAgIHJldHVybiB0aGlzLmtuZXhRdWVyeS5maW5hbGx5KG9uZmluYWxseSk7XG4gIH1cblxuICAvLyBPTiBDT05GTElDVCAtIOy7rOufvCDquLDrsJhcbiAgb25Db25mbGljdDxUVGFibGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgVFJldHVybmluZz4+KFxuICAgIGNvbHVtbnM6IHN0cmluZyB8IHN0cmluZ1tdLFxuICAgIGFjdGlvbj86IE9uQ29uZmxpY3RBY3Rpb248VFRhYmxlcz4sXG4gICk6IHRoaXMge1xuICAgIGNvbnN0IHRhcmdldCA9IEFycmF5LmlzQXJyYXkoY29sdW1ucykgPyBjb2x1bW5zIDogW2NvbHVtbnNdO1xuXG4gICAgaWYgKCFhY3Rpb24gfHwgYWN0aW9uID09PSBcIm5vdGhpbmdcIikge1xuICAgICAgLy8gRE8gTk9USElOR1xuICAgICAgdGhpcy5rbmV4UXVlcnkub25Db25mbGljdCh0YXJnZXQpLmlnbm9yZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBETyBVUERBVEVcbiAgICAgIGNvbnN0IHsgdXBkYXRlIH0gPSBhY3Rpb247XG5cbiAgICAgIC8vIGFjdGlvbi51cGRhdGUg67Cw7Je0IO2Yle2DnCA6IFtcIm5hbWVcIiwgXCJlbWFpbFwiXVxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkodXBkYXRlKSkge1xuICAgICAgICB0aGlzLmtuZXhRdWVyeS5vbkNvbmZsaWN0KHRhcmdldCkubWVyZ2UodXBkYXRlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGFjdGlvbi51cGRhdGUg6rCd7LK0IO2Yle2DnDogeyBuYW1lOiBcIkpvaG5cIiwgY291bnQ6IHJhdyguLi4pIH1cbiAgICAgICAgY29uc3QgbWVyZ2VPYmo6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcblxuICAgICAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyh1cGRhdGUpKSB7XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgdmFsdWUgJiZcbiAgICAgICAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIiAmJlxuICAgICAgICAgICAgXCJfdHlwZVwiIGluIHZhbHVlICYmXG4gICAgICAgICAgICB2YWx1ZS5fdHlwZSA9PT0gXCJzcWxfZXhwcmVzc2lvblwiXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICAvLyBTcWxFeHByZXNzaW9uIOKGkiBrbmV4LnJhdygp66GcIOuzgO2ZmFxuICAgICAgICAgICAgbWVyZ2VPYmpba2V5XSA9IHRoaXMua25leC5yYXcoKHZhbHVlIGFzIFNxbEV4cHJlc3Npb248YW55PikuX3NxbCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIOydvOuwmCDqsJJcbiAgICAgICAgICAgIG1lcmdlT2JqW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmtuZXhRdWVyeS5vbkNvbmZsaWN0KHRhcmdldCkubWVyZ2UobWVyZ2VPYmopO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gUkVUVVJOSU5HOiBcIipcIiAtIOyghOyytCDsu6zrn7xcbiAgcmV0dXJuaW5nKGNvbHVtbjogXCIqXCIpOiBSZXNvbHZlZFB1cmk8VFJldHVybmluZ1tdLCBuZXZlcj47XG4gIC8vIFJFVFVSTklORzog64uo7J28IOy7rOufvFxuICByZXR1cm5pbmc8VENvbHVtbiBleHRlbmRzIENvbHVtbktleXM8VFJldHVybmluZz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgKTogUmVzb2x2ZWRQdXJpPFBpY2s8VFJldHVybmluZywgVENvbHVtbj5bXSwgbmV2ZXI+O1xuICAvLyBSRVRVUk5JTkc6IOuzteyImCDsu6zrn7wgKOuwsOyXtClcbiAgcmV0dXJuaW5nPFRDb2x1bW4gZXh0ZW5kcyBDb2x1bW5LZXlzPFRSZXR1cm5pbmc+PihcbiAgICBjb2x1bW5zOiBUQ29sdW1uW10sXG4gICk6IFJlc29sdmVkUHVyaTxQaWNrPFRSZXR1cm5pbmcsIFRDb2x1bW4+W10sIG5ldmVyPjtcbiAgLy8gUkVUVVJOSU5HIOq1rO2YhFxuICByZXR1cm5pbmcoY29sdW1uT3JDb2x1bW5zOiBzdHJpbmcgfCBzdHJpbmdbXSk6IFJlc29sdmVkUHVyaTxhbnlbXSwgbmV2ZXI+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS5yZXR1cm5pbmcoY29sdW1uT3JDb2x1bW5zKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxufVxuIl0sIm5hbWVzIjpbImFzc2VydCIsImNoYWxrIiwiaW5mbGVjdGlvbiIsIkVudGl0eU1hbmFnZXIiLCJOYWl0ZSIsIkZVWlpZX09QRVJBVE9SUyIsIm5vcm1hbGl6ZUZ1enp5T3BlcmF0b3IiLCJvcGVyYXRvciIsIm5vcm1hbGl6ZWQiLCJ0cmltIiwiZnV6enlPcGVyYXRvciIsImZpbmQiLCJjYW5kaWRhdGUiLCJFcnJvciIsIlB1cmkiLCJrbmV4UXVlcnkiLCJ0YWJsZVNwZWMiLCJrbmV4IiwidGFibGVOYW1lT3JTb3VyY2UiLCJmcm9tIiwic2FmZUdldFRhYmxlU3BlYyIsImVudHJpZXMiLCJPYmplY3QiLCJsZW5ndGgiLCJhbGlhcyIsInNvdXJjZSIsInN1YnF1ZXJ5QnVpbGRlciIsInJhd1F1ZXJ5IiwiYXMiLCJ0YWJsZU5hbWUiLCJnZXRUYWJsZVNwZWMiLCJjb3VudCIsImNvbHVtbiIsIl90eXBlIiwiX3JldHVybiIsIl9zcWwiLCJfcGFyYW1zIiwic3VtIiwiYXZnIiwibWF4IiwibWluIiwiY29uY2F0IiwiYXJncyIsIm1hcCIsImpvaW4iLCJ1cHBlciIsImxvd2VyIiwid29yZFNpbWlsYXJpdHkiLCJxdWVyeSIsInNpbWlsYXJpdHkiLCJzdHJpY3RXb3JkU2ltaWxhcml0eSIsInJhd1N0cmluZyIsInNxbCIsInBhcmFtcyIsInJhd1N0cmluZ0FycmF5IiwicmF3TnVtYmVyIiwicmF3Qm9vbGVhbiIsInJhd0RhdGUiLCJ0c0hpZ2hsaWdodCIsIl9vcHRpb25zIiwicGFyc2VyIiwiY29uZmlnIiwib3B0aW9ucyIsImhsT3B0aW9uUGFydHMiLCJrZXkiLCJ2YWx1ZSIsImNhbWVsaXplIiwiaGxPcHRpb25zIiwidHNSYW5rIiwiX3RzUmFuayIsInRzUmFua0NkIiwidG9Uc1ZlY3RvciIsInR5cGUiLCJub3JtYWxpemF0aW9uIiwid2VpZ2h0cyIsInNxbFRlbXBsYXRlIiwicHVzaCIsInNjb3JlIiwiaGlnaGxpZ2h0IiwiY29sdW1uT3JDb2x1bW5zIiwicXVlcnlBcnIiLCJBcnJheSIsImlzQXJyYXkiLCJxdWVyeUNsYXVzZSIsInNlbGVjdCIsInNlbGVjdE9iaiIsImZsYXRTZWxlY3QiLCJmbGF0dGVuU2VsZWN0Iiwic2VsZWN0Q2xhdXNlcyIsImNvbHVtbk9yRnVuY3Rpb24iLCJyYXciLCJjb2x1bW5QYXRoIiwicHJlZml4IiwiZnVsbEtleSIsIm5lc3RlZCIsImFzc2lnbiIsImFwcGVuZFNlbGVjdCIsInJlZiIsInNlbGVjdEFsbCIsImRpc3RpbmN0IiwiY29sdW1ucyIsImNsZWFyIiwic3RhdGVtZW50IiwiY2xlYXJKb2luIiwiX3N0YXRlbWVudHMiLCJmaWx0ZXIiLCJzIiwiX2FsaWFzIiwiX3RhYmxlIiwidGFibGUiLCJ0YWJsZU5hbWVPclNwZWMiLCJfX2NvbW1vbkpvaW4iLCJsZWZ0Sm9pbiIsImpvaW5UeXBlIiwiY2FsbGJhY2siLCJqb2luQ2xhdXNlIiwiSm9pbkNsYXVzZUdyb3VwIiwibGVmdCIsInJpZ2h0Iiwic3BlYyIsIndoZXJlIiwiY29sdW1uT3JDb25kaXRpb25zIiwib3BlcmF0b3JPclZhbHVlIiwid2hlcmVOdWxsIiwid2hlcmVOb3ROdWxsIiwid2hlcmVJbiIsInZhbHVlcyIsIndoZXJlTm90SW4iLCJ3aGVyZU1hdGNoIiwid2hlcmVSYXciLCJTdHJpbmciLCJ3aGVyZVNlYXJjaCIsImNvbHVtbkV4cHIiLCJjIiwicGdyb29uZ2FDb25kaXRpb24iLCJ3aGVyZVRzU2VhcmNoIiwib3B0cyIsIndoZXJlRnV6enkiLCJiaW5kaW5ncyIsIndoZXJlR3JvdXAiLCJidWlsZGVyIiwiZ3JvdXAiLCJXaGVyZUdyb3VwIiwib3JXaGVyZUdyb3VwIiwib3JXaGVyZSIsIm9yZGVyQnkiLCJkaXJlY3Rpb24iLCJvcmRlckJ5UmF3IiwidmVjdG9yU2ltaWxhcml0eSIsImVtYmVkZGluZyIsIm1ldGhvZCIsInRocmVzaG9sZCIsImRpc3RpbmN0T24iLCJzb21lIiwidiIsIk51bWJlciIsImlzRmluaXRlIiwidmVjdG9yTGl0ZXJhbCIsIkpTT04iLCJzdHJpbmdpZnkiLCJjb3NpbmUiLCJsMiIsImlubmVyX3Byb2R1Y3QiLCJzaW1pbGFyaXR5RXhwciIsImV4aXN0aW5nU3Vic2V0Q29scyIsImdyb3VwaW5nIiwiZmxhdE1hcCIsImNvbCIsInRocmVzaG9sZE9wIiwidGhyZXNob2xkVmFsdWUiLCJsaW1pdCIsIm9mZnNldCIsImdyb3VwQnkiLCJoYXZpbmciLCJjb25kaXRpb25zIiwidGhlbiIsIm9uZnVsZmlsbGVkIiwib25yZWplY3RlZCIsInQiLCJ0b1F1ZXJ5IiwiY2F0Y2giLCJmaW5hbGx5Iiwib25maW5hbGx5IiwiZmlyc3QiLCJSZXNvbHZlZFB1cmkiLCJwbHVjayIsImluc2VydCIsInJhd0RhdGEiLCJyZWZpbmVkRGF0YSIsInJlZmluZUpzb25Db2x1bW5zIiwidXBkYXRlIiwiZGF0YSIsImpzb25Db2x1bW5zIiwiaXRlbSIsInVuZGVmaW5lZCIsImluY3JlbWVudCIsImRlY3JlbWVudCIsImRlbGV0ZSIsImRlYnVnIiwiY29uc29sZSIsImxvZyIsImN5YW4iLCJ5ZWxsb3ciLCJjbG9uZSIsIm5ld1B1cmkiLCJmb3JtYXRTUUwiLCJ1bmZvcm1hdHRlZCIsImtleXdvcmRzIiwiZm9ybWF0dGVkIiwiZm9yRWFjaCIsImtleXdvcmQiLCJyZWdleCIsIlJlZ0V4cCIsInJlcGxhY2UiLCJ0b1VwcGVyQ2FzZSIsIm1ham9yQ2xhdXNlcyIsImNsYXVzZSIsImxpbmVzIiwic3BsaXQiLCJpbmRlbnRlZExpbmVzIiwiaW5kZW50TGV2ZWwiLCJsaW5lIiwidHJpbW1lZExpbmUiLCJjbG9zaW5nUGFyZW5zIiwibWF0Y2giLCJvcGVuaW5nUGFyZW5zIiwiTWF0aCIsImluZGVudCIsInJlcGVhdCIsInNsaWNlIiwib3JXaGVyZUluIiwib3JXaGVyZU5vdEluIiwib3JXaGVyZU1hdGNoIiwib3JXaGVyZVJhdyIsIm9yV2hlcmVTZWFyY2giLCJvcldoZXJlVHNTZWFyY2giLCJvcldoZXJlRnV6enkiLCJzdWJCdWlsZGVyIiwic3ViR3JvdXAiLCJvbiIsIm9yT24iLCJvblZhbCIsImFuZE9uVmFsIiwib3JPblZhbCIsIlN5bWJvbCIsInRvU3RyaW5nVGFnIiwib25Db25mbGljdCIsImFjdGlvbiIsInRhcmdldCIsImln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
1022
+ //#endregion
1023
+ init_puri();
1024
+ export { JoinClauseGroup, Puri, ResolvedPuri, WhereGroup, init_puri };
1025
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVyaS5qcyIsIm5hbWVzIjpbImtuZXg6IEtuZXgiLCJzZWxlY3RDbGF1c2VzOiAoc3RyaW5nIHwgS25leC5SYXcpW10iLCJmbGF0U2VsZWN0OiBSZWNvcmQ8c3RyaW5nLCBhbnk+IiwiYnVpbGRlcjogS25leC5RdWVyeUJ1aWxkZXIiLCJjYWxsYmFjazogS25leC5Kb2luQ2xhdXNlIiwia25leFF1ZXJ5OiBLbmV4LlF1ZXJ5QnVpbGRlciIsIm1lcmdlT2JqOiBSZWNvcmQ8c3RyaW5nLCBhbnk+Il0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2RhdGFiYXNlL3B1cmkudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyogb3hsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueSAqLyAvLyBQdXJp64qUIOuLpOyWke2VnCDtg4DsnoXsnYQg7IKs7Jqp7ZWY6rOgIOyeiOyKteuLiOuLpC5cblxuaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5cbmltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIjtcbmltcG9ydCBpbmZsZWN0aW9uIGZyb20gXCJpbmZsZWN0aW9uXCI7XG5pbXBvcnQgeyB0eXBlIEtuZXggfSBmcm9tIFwia25leFwiO1xuXG5pbXBvcnQgeyBFbnRpdHlNYW5hZ2VyIH0gZnJvbSBcIi4uL2VudGl0eS9lbnRpdHktbWFuYWdlclwiO1xuaW1wb3J0IHsgdHlwZSBUYWJsZVNwZWMgfSBmcm9tIFwiLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyBOYWl0ZSB9IGZyb20gXCIuLi9uYWl0ZS9uYWl0ZVwiO1xuaW1wb3J0IHsgdHlwZSBDbGVhclN0YXRlbWVudHMgfSBmcm9tIFwiLi9wdXJpLXN1YnNldC50eXBlc1wiO1xuaW1wb3J0IHtcbiAgdHlwZSBBdmFpbGFibGVDb2x1bW5zLFxuICB0eXBlIENvbHVtbktleXMsXG4gIHR5cGUgQ29tcGFyaXNvbk9wZXJhdG9yLFxuICB0eXBlIEV4cGFuZCxcbiAgdHlwZSBFeHRyYWN0Q29sdW1uVHlwZSxcbiAgdHlwZSBGdWxsdGV4dENvbHVtbnMsXG4gIHR5cGUgRnV6enlPcGVyYXRvcixcbiAgdHlwZSBJbnNlcnREYXRhLFxuICB0eXBlIEluc2VydFJlc3VsdCxcbiAgdHlwZSBMZWZ0Sm9pbmVkTWFya2VyLFxuICB0eXBlIExlZnRKb2luTWFya2VyRm9yLFxuICB0eXBlIE51bWVyaWNDb2x1bW5zLFxuICB0eXBlIE9uQ29uZmxpY3RBY3Rpb24sXG4gIHR5cGUgUGFyc2VTZWxlY3RPYmplY3QsXG4gIHR5cGUgUmVzdWx0QXZhaWxhYmxlQ29sdW1ucyxcbiAgdHlwZSBTZWxlY3RBbGxSZXN1bHQsXG4gIHR5cGUgU2VsZWN0T2JqZWN0LFxuICB0eXBlIFNpbmdsZVRhYmxlVmFsdWUsXG4gIHR5cGUgU3FsRXhwcmVzc2lvbixcbiAgdHlwZSBUc0hpZ2hsaWdodE9wdGlvbnMsXG4gIHR5cGUgVHNRdWVyeUNvbmZpZyxcbiAgdHlwZSBUc1F1ZXJ5T3B0aW9ucyxcbiAgdHlwZSBUc1JhbmtPcHRpb25zLFxuICB0eXBlIFZlY3RvckNvbHVtbnMsXG4gIHR5cGUgV2hlcmVDb25kaXRpb24sXG4gIHR5cGUgV2hlcmVPcGVyYXRvcixcbn0gZnJvbSBcIi4vcHVyaS50eXBlc1wiO1xuaW1wb3J0IHsgRlVaWllfT1BFUkFUT1JTIH0gZnJvbSBcIi4vcHVyaS50eXBlc1wiO1xuXG5mdW5jdGlvbiBub3JtYWxpemVGdXp6eU9wZXJhdG9yKG9wZXJhdG9yPzogc3RyaW5nKTogRnV6enlPcGVyYXRvciB7XG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSBvcGVyYXRvcj8udHJpbSgpID8/IFwiPCVcIjtcbiAgY29uc3QgZnV6enlPcGVyYXRvciA9IEZVWlpZX09QRVJBVE9SUy5maW5kKChjYW5kaWRhdGUpID0+IGNhbmRpZGF0ZSA9PT0gbm9ybWFsaXplZCk7XG5cbiAgaWYgKCFmdXp6eU9wZXJhdG9yKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGZ1enp5IG9wZXJhdG9yOiAke29wZXJhdG9yID8/IFwiXCJ9YCk7XG4gIH1cblxuICByZXR1cm4gZnV6enlPcGVyYXRvcjtcbn1cblxuZXhwb3J0IGNsYXNzIFB1cmk8VFNjaGVtYSwgVFRhYmxlcyBleHRlbmRzIFJlY29yZDxzdHJpbmcsIGFueT4sIFRSZXN1bHQ+IHtcbiAgcHJpdmF0ZSBrbmV4UXVlcnk6IEtuZXguUXVlcnlCdWlsZGVyO1xuICBwcml2YXRlIHRhYmxlU3BlYzogVGFibGVTcGVjIHwgbnVsbCA9IG51bGw7XG5cbiAgLy8g7IOd7ISx7J6QIOyLnOq3uOuLiOyymOuTpFxuICBjb25zdHJ1Y3RvcihrbmV4OiBLbmV4LCB0YWJsZU5hbWU6IHN0cmluZyk7XG4gIGNvbnN0cnVjdG9yKGtuZXg6IEtuZXgsIHRhYmxlU291cmNlOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBQdXJpPFRTY2hlbWEsIGFueSwgYW55Pj4pO1xuICBjb25zdHJ1Y3RvcihcbiAgICBwdWJsaWMga25leDogS25leCxcbiAgICB0YWJsZU5hbWVPclNvdXJjZTogYW55LFxuICApIHtcbiAgICBpZiAodHlwZW9mIHRhYmxlTmFtZU9yU291cmNlID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAvLyBDYXNlOiBuZXcgUHVyaShrbmV4LCBcInVzZXJzXCIpXG4gICAgICB0aGlzLmtuZXhRdWVyeSA9IHRoaXMua25leCh0YWJsZU5hbWVPclNvdXJjZSkuZnJvbSh0YWJsZU5hbWVPclNvdXJjZSk7XG4gICAgICB0aGlzLnRhYmxlU3BlYyA9IHRoaXMuc2FmZUdldFRhYmxlU3BlYyh0YWJsZU5hbWVPclNvdXJjZSk7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgdGFibGVOYW1lT3JTb3VyY2UgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIGNvbnN0IGVudHJpZXMgPSBPYmplY3QuZW50cmllcyh0YWJsZU5hbWVPclNvdXJjZSk7XG4gICAgICBpZiAoZW50cmllcy5sZW5ndGggIT09IDEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVGFibGUgc3BlYyBtdXN0IGhhdmUgZXhhY3RseSBvbmUgZW50cnlcIik7XG4gICAgICB9XG4gICAgICBhc3NlcnQoZW50cmllc1swXSk7XG4gICAgICBjb25zdCBbYWxpYXMsIHNvdXJjZV0gPSBlbnRyaWVzWzBdO1xuICAgICAgaWYgKHR5cGVvZiBzb3VyY2UgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgdGhpcy5rbmV4UXVlcnkgPSB0aGlzLmtuZXgoc291cmNlKS5mcm9tKHsgW2FsaWFzXTogc291cmNlIH0pO1xuICAgICAgICB0aGlzLnRhYmxlU3BlYyA9IHRoaXMuc2FmZUdldFRhYmxlU3BlYyhzb3VyY2UpO1xuICAgICAgfSBlbHNlIGlmIChzb3VyY2UgaW5zdGFuY2VvZiBQdXJpKSB7XG4gICAgICAgIGNvbnN0IHN1YnF1ZXJ5QnVpbGRlciA9IHNvdXJjZS5yYXdRdWVyeSgpO1xuICAgICAgICB0aGlzLmtuZXhRdWVyeSA9IHRoaXMua25leC5mcm9tKHN1YnF1ZXJ5QnVpbGRlci5hcyhhbGlhcykpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCB0YWJsZSBzcGVjaWZpY2F0aW9uXCIpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIHRhYmxlIHNwZWNpZmljYXRpb25cIik7XG4gICAgfVxuICB9XG5cbiAgc2FmZUdldFRhYmxlU3BlYyh0YWJsZU5hbWU6IHN0cmluZyk6IFRhYmxlU3BlYyB8IG51bGwge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gRW50aXR5TWFuYWdlci5nZXRUYWJsZVNwZWModGFibGVOYW1lKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8vIFN0YXRpYyBTUUwgaGVscGVyIGZ1bmN0aW9ucyBmb3IgU0VMRUNUXG4gIHN0YXRpYyBjb3VudChjb2x1bW46IHN0cmluZyA9IFwiKlwiKTogU3FsRXhwcmVzc2lvbjxcIm51bWJlclwiPiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsXG4gICAgICBfcmV0dXJuOiBcIm51bWJlclwiLFxuICAgICAgX3NxbDogYENPVU5UKD8/KTo6aW50ZWdlcmAsXG4gICAgICBfcGFyYW1zOiBbY29sdW1uXSxcbiAgICB9O1xuICB9XG4gIHN0YXRpYyBzdW0oY29sdW1uOiBzdHJpbmcpOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICBfc3FsOiBgU1VNKD8/KWAsXG4gICAgICBfcGFyYW1zOiBbY29sdW1uXSxcbiAgICB9O1xuICB9XG4gIHN0YXRpYyBhdmcoY29sdW1uOiBzdHJpbmcpOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICBfc3FsOiBgQVZHKD8/KWAsXG4gICAgICBfcGFyYW1zOiBbY29sdW1uXSxcbiAgICB9O1xuICB9XG4gIHN0YXRpYyBtYXgoY29sdW1uOiBzdHJpbmcpOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICBfc3FsOiBgTUFYKD8/KWAsXG4gICAgICBfcGFyYW1zOiBbY29sdW1uXSxcbiAgICB9O1xuICB9XG4gIHN0YXRpYyBtaW4oY29sdW1uOiBzdHJpbmcpOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICBfc3FsOiBgTUlOKD8/KWAsXG4gICAgICBfcGFyYW1zOiBbY29sdW1uXSxcbiAgICB9O1xuICB9XG4gIHN0YXRpYyBjb25jYXQoLi4uYXJnczogc3RyaW5nW10pOiBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwic3RyaW5nXCIsXG4gICAgICBfc3FsOiBgQ09OQ0FUKCR7YXJncy5tYXAoKCkgPT4gXCI/XCIpLmpvaW4oXCIsIFwiKX0pYCxcbiAgICAgIF9wYXJhbXM6IGFyZ3MsXG4gICAgfTtcbiAgfVxuICBzdGF0aWMgdXBwZXIoY29sdW1uOiBzdHJpbmcpOiBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwic3RyaW5nXCIsXG4gICAgICBfc3FsOiBcIlVQUEVSKD8/KVwiLFxuICAgICAgX3BhcmFtczogW2NvbHVtbl0sXG4gICAgfTtcbiAgfVxuICBzdGF0aWMgbG93ZXIoY29sdW1uOiBzdHJpbmcpOiBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwic3RyaW5nXCIsXG4gICAgICBfc3FsOiBcIkxPV0VSKD8/KVwiLFxuICAgICAgX3BhcmFtczogW2NvbHVtbl0sXG4gICAgfTtcbiAgfVxuXG4gIHN0YXRpYyB3b3JkU2ltaWxhcml0eShcbiAgICBjb2x1bW46IHN0cmluZyB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4sXG4gICAgcXVlcnk6IHN0cmluZyxcbiAgKTogU3FsRXhwcmVzc2lvbjxcIm51bWJlclwiPiB7XG4gICAgaWYgKHR5cGVvZiBjb2x1bW4gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsXG4gICAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICAgIF9zcWw6IFwid29yZF9zaW1pbGFyaXR5KD8sID8/KVwiLFxuICAgICAgICBfcGFyYW1zOiBbcXVlcnksIGNvbHVtbl0sXG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLFxuICAgICAgX3JldHVybjogXCJudW1iZXJcIixcbiAgICAgIF9zcWw6IGB3b3JkX3NpbWlsYXJpdHkoPywgJHtjb2x1bW4uX3NxbH0pYCxcbiAgICAgIF9wYXJhbXM6IFtxdWVyeSwgLi4uY29sdW1uLl9wYXJhbXNdLFxuICAgIH07XG4gIH1cblxuICBzdGF0aWMgc2ltaWxhcml0eShcbiAgICBjb2x1bW46IHN0cmluZyB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4sXG4gICAgcXVlcnk6IHN0cmluZyxcbiAgKTogU3FsRXhwcmVzc2lvbjxcIm51bWJlclwiPiB7XG4gICAgaWYgKHR5cGVvZiBjb2x1bW4gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsXG4gICAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICAgIF9zcWw6IFwic2ltaWxhcml0eSg/PywgPylcIixcbiAgICAgICAgX3BhcmFtczogW2NvbHVtbiwgcXVlcnldLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICBfc3FsOiBgc2ltaWxhcml0eSgke2NvbHVtbi5fc3FsfSwgPylgLFxuICAgICAgX3BhcmFtczogWy4uLmNvbHVtbi5fcGFyYW1zLCBxdWVyeV0sXG4gICAgfTtcbiAgfVxuXG4gIHN0YXRpYyBzdHJpY3RXb3JkU2ltaWxhcml0eShcbiAgICBjb2x1bW46IHN0cmluZyB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4sXG4gICAgcXVlcnk6IHN0cmluZyxcbiAgKTogU3FsRXhwcmVzc2lvbjxcIm51bWJlclwiPiB7XG4gICAgaWYgKHR5cGVvZiBjb2x1bW4gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsXG4gICAgICAgIF9yZXR1cm46IFwibnVtYmVyXCIsXG4gICAgICAgIF9zcWw6IGBzdHJpY3Rfd29yZF9zaW1pbGFyaXR5KD8sID8/KWAsXG4gICAgICAgIF9wYXJhbXM6IFtxdWVyeSwgY29sdW1uXSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsXG4gICAgICBfcmV0dXJuOiBcIm51bWJlclwiLFxuICAgICAgX3NxbDogYHN0cmljdF93b3JkX3NpbWlsYXJpdHkoPywgJHtjb2x1bW4uX3NxbH0pYCxcbiAgICAgIF9wYXJhbXM6IFtxdWVyeSwgLi4uY29sdW1uLl9wYXJhbXNdLFxuICAgIH07XG4gIH1cblxuICAvLyBSYXcgZnVuY3Rpb25zIGZvciBTRUxFQ1RcbiAgc3RhdGljIHJhd1N0cmluZyhzcWw6IHN0cmluZywgcGFyYW1zOiB1bmtub3duW10gPSBbXSk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4ge1xuICAgIHJldHVybiB7IF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsIF9yZXR1cm46IFwic3RyaW5nXCIsIF9zcWw6IHNxbCwgX3BhcmFtczogcGFyYW1zIH07XG4gIH1cblxuICBzdGF0aWMgcmF3U3RyaW5nQXJyYXkoc3FsOiBzdHJpbmcsIHBhcmFtczogdW5rbm93bltdID0gW10pOiBTcWxFeHByZXNzaW9uPFwic3RyaW5nW11cIj4ge1xuICAgIHJldHVybiB7IF90eXBlOiBcInNxbF9leHByZXNzaW9uXCIsIF9yZXR1cm46IFwic3RyaW5nW11cIiwgX3NxbDogc3FsLCBfcGFyYW1zOiBwYXJhbXMgfTtcbiAgfVxuXG4gIHN0YXRpYyByYXdOdW1iZXIoc3FsOiBzdHJpbmcsIHBhcmFtczogdW5rbm93bltdID0gW10pOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4geyBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLCBfcmV0dXJuOiBcIm51bWJlclwiLCBfc3FsOiBzcWwsIF9wYXJhbXM6IHBhcmFtcyB9O1xuICB9XG5cbiAgc3RhdGljIHJhd0Jvb2xlYW4oc3FsOiBzdHJpbmcsIHBhcmFtczogdW5rbm93bltdID0gW10pOiBTcWxFeHByZXNzaW9uPFwiYm9vbGVhblwiPiB7XG4gICAgcmV0dXJuIHsgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIiwgX3JldHVybjogXCJib29sZWFuXCIsIF9zcWw6IHNxbCwgX3BhcmFtczogcGFyYW1zIH07XG4gIH1cblxuICBzdGF0aWMgcmF3RGF0ZShzcWw6IHN0cmluZywgcGFyYW1zOiB1bmtub3duW10gPSBbXSk6IFNxbEV4cHJlc3Npb248XCJkYXRlXCI+IHtcbiAgICByZXR1cm4geyBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLCBfcmV0dXJuOiBcImRhdGVcIiwgX3NxbDogc3FsLCBfcGFyYW1zOiBwYXJhbXMgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGVFMg6rKA7IOJ7Ja0IO2VmOydtOudvOydtO2MhVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiAuc2VsZWN0KHtcbiAgICogICB0aXRsZTogUHVyaS5oaWdobGlnaHQoXCJwb3N0cy50aXRsZVwiLCBzZWFyY2gpLFxuICAgKiAgIGNvbnRlbnQ6IFB1cmkuaGlnaGxpZ2h0KFwicG9zdHMuY29udGVudFwiLCBzZWFyY2gsIHtcbiAgICogICAgIHN0YXJ0U2VsOiBcIjxtYXJrPlwiLFxuICAgKiAgICAgc3RvcFNlbDogXCI8L21hcms+XCIsXG4gICAqICAgICBtYXhGcmFnbWVudHM6IDMsXG4gICAqICAgfSksXG4gICAqIH0pXG4gICAqL1xuICBzdGF0aWMgdHNIaWdobGlnaHQoXG4gICAgY29sdW1uOiBzdHJpbmcsXG4gICAgcXVlcnk6IHN0cmluZyxcbiAgICBfb3B0aW9ucz86IFRzSGlnaGxpZ2h0T3B0aW9ucyxcbiAgKTogU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPiB7XG4gICAgY29uc3QgeyBwYXJzZXIgPSBcIndlYnNlYXJjaF90b190c3F1ZXJ5XCIsIGNvbmZpZyA9IFwic2ltcGxlXCIsIC4uLm9wdGlvbnMgfSA9IF9vcHRpb25zID8/IHt9O1xuXG4gICAgY29uc3QgaGxPcHRpb25QYXJ0cyA9IE9iamVjdC5lbnRyaWVzKG9wdGlvbnMpLm1hcCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICByZXR1cm4gYCR7aW5mbGVjdGlvbi5jYW1lbGl6ZShrZXkpfT0ke3ZhbHVlfWA7XG4gICAgfSk7XG5cbiAgICBjb25zdCBobE9wdGlvbnMgPSBobE9wdGlvblBhcnRzLmxlbmd0aCA+IDAgPyBgLCAnJHtobE9wdGlvblBhcnRzLmpvaW4oXCIsIFwiKX0nYCA6IFwiXCI7XG5cbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwic3RyaW5nXCIsXG4gICAgICBfc3FsOiBgdHNfaGVhZGxpbmUoPywgPz8sICR7cGFyc2VyfSg/LCA/KSR7aGxPcHRpb25zfSlgLFxuICAgICAgX3BhcmFtczogW2NvbmZpZywgY29sdW1uLCBjb25maWcsIHF1ZXJ5XSxcbiAgICB9O1xuICB9XG5cbiAgLy8gdHNfcmFua1xuICBzdGF0aWMgdHNSYW5rKFxuICAgIGNvbHVtbjogc3RyaW5nIHwgU3FsRXhwcmVzc2lvbjxcInRzdmVjdG9yXCI+LFxuICAgIHF1ZXJ5OiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IFRzUmFua09wdGlvbnMsXG4gICk6IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4ge1xuICAgIHJldHVybiBQdXJpLl90c1JhbmsoXCJ0c19yYW5rXCIsIGNvbHVtbiwgcXVlcnksIG9wdGlvbnMpO1xuICB9XG5cbiAgLy8gdHNfcmFua19jZFxuICBzdGF0aWMgdHNSYW5rQ2QoXG4gICAgY29sdW1uOiBzdHJpbmcgfCBTcWxFeHByZXNzaW9uPFwidHN2ZWN0b3JcIj4sXG4gICAgcXVlcnk6IHN0cmluZyxcbiAgICBvcHRpb25zPzogVHNSYW5rT3B0aW9ucyxcbiAgKTogU3FsRXhwcmVzc2lvbjxcIm51bWJlclwiPiB7XG4gICAgcmV0dXJuIFB1cmkuX3RzUmFuayhcInRzX3JhbmtfY2RcIiwgY29sdW1uLCBxdWVyeSwgb3B0aW9ucyk7XG4gIH1cblxuICBzdGF0aWMgdG9Uc1ZlY3Rvcihjb2x1bW46IHN0cmluZywgY29uZmlnOiBzdHJpbmcgPSBcInNpbXBsZVwiKTogU3FsRXhwcmVzc2lvbjxcInRzdmVjdG9yXCI+IHtcbiAgICByZXR1cm4ge1xuICAgICAgX3R5cGU6IFwic3FsX2V4cHJlc3Npb25cIixcbiAgICAgIF9yZXR1cm46IFwidHN2ZWN0b3JcIixcbiAgICAgIF9zcWw6IGB0b190c3ZlY3Rvcig/LCA/PylgLFxuICAgICAgX3BhcmFtczogW2NvbmZpZywgY29sdW1uXSxcbiAgICB9O1xuICB9XG5cbiAgc3RhdGljIF90c1JhbmsoXG4gICAgdHlwZTogXCJ0c19yYW5rXCIgfCBcInRzX3JhbmtfY2RcIixcbiAgICBjb2x1bW46IHN0cmluZyB8IFNxbEV4cHJlc3Npb248XCJ0c3ZlY3RvclwiPixcbiAgICBxdWVyeTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBUc1JhbmtPcHRpb25zLFxuICApOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICBjb25zdCB7XG4gICAgICBwYXJzZXIgPSBcIndlYnNlYXJjaF90b190c3F1ZXJ5XCIsXG4gICAgICBjb25maWcgPSBcInNpbXBsZVwiLFxuICAgICAgbm9ybWFsaXphdGlvbixcbiAgICAgIHdlaWdodHMsXG4gICAgfSA9IG9wdGlvbnMgPz8ge307XG5cbiAgICBjb25zdCBwYXJhbXMgPSBbXTtcbiAgICBsZXQgc3FsVGVtcGxhdGUgPSBgJHt0eXBlfShgO1xuXG4gICAgaWYgKHdlaWdodHMpIHtcbiAgICAgIHNxbFRlbXBsYXRlICs9IGBBUlJBWVske3dlaWdodHMubWFwKCgpID0+IFwiP1wiKS5qb2luKFwiLCBcIil9XTo6ZmxvYXQ0W10sIGA7XG4gICAgICBwYXJhbXMucHVzaCguLi53ZWlnaHRzKTtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGNvbHVtbiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgc3FsVGVtcGxhdGUgKz0gYD8/LCAke3BhcnNlcn0oPywgPylgO1xuICAgICAgcGFyYW1zLnB1c2goY29sdW1uLCBjb25maWcsIHF1ZXJ5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3FsVGVtcGxhdGUgKz0gYCR7Y29sdW1uLl9zcWx9LCAke3BhcnNlcn0oPywgPylgO1xuICAgICAgcGFyYW1zLnB1c2goLi4uY29sdW1uLl9wYXJhbXMsIGNvbmZpZywgcXVlcnkpO1xuICAgIH1cblxuICAgIGlmIChub3JtYWxpemF0aW9uKSB7XG4gICAgICBzcWxUZW1wbGF0ZSArPSBcIiwgP1wiO1xuICAgICAgcGFyYW1zLnB1c2gobm9ybWFsaXphdGlvbik7XG4gICAgfVxuXG4gICAgc3FsVGVtcGxhdGUgKz0gXCIpXCI7XG5cbiAgICByZXR1cm4geyBfdHlwZTogXCJzcWxfZXhwcmVzc2lvblwiLCBfcmV0dXJuOiBcIm51bWJlclwiLCBfc3FsOiBzcWxUZW1wbGF0ZSwgX3BhcmFtczogcGFyYW1zIH07XG4gIH1cblxuICAvKipcbiAgICogUEdyb29uZ2EgRnVsbFRleHQg7J24642x7IqkIOqygOyDiSDsoJDsiJhcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogLnNlbGVjdCh7XG4gICAqICAgc2NvcmU6IFB1cmkuc2NvcmUoKSxcbiAgICogfSlcbiAgICovXG4gIHN0YXRpYyBzY29yZSgpOiBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHtcbiAgICByZXR1cm4gUHVyaS5yYXdOdW1iZXIoXCJwZ3Jvb25nYV9zY29yZSh0YWJsZW9pZCwgY3RpZClcIik7XG4gIH1cblxuICAvKipcbiAgICogUEdyb29uZ2EgRnVsbFRleHQg7J24642x7IqkIOqygOyDiSDtlZjsnbTrnbzsnbTtjIVcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogLnNlbGVjdCh7XG4gICAqICAgdGl0bGU6IFB1cmkuaGlnaGxpZ2h0KFwicG9zdHMudGl0bGVcIiwgc2VhcmNoKSxcbiAgICogfSlcbiAgICovXG4gIHN0YXRpYyBoaWdobGlnaHQoY29sdW1uOiBzdHJpbmcsIHF1ZXJ5OiBzdHJpbmcgfCBzdHJpbmdbXSk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj47XG4gIHN0YXRpYyBoaWdobGlnaHQoY29sdW1uczogc3RyaW5nW10sIHF1ZXJ5OiBzdHJpbmcgfCBzdHJpbmdbXSk6IFNxbEV4cHJlc3Npb248XCJzdHJpbmdbXVwiPjtcblxuICBzdGF0aWMgaGlnaGxpZ2h0KFxuICAgIGNvbHVtbk9yQ29sdW1uczogc3RyaW5nIHwgc3RyaW5nW10sXG4gICAgcXVlcnk6IHN0cmluZyB8IHN0cmluZ1tdLFxuICApOiBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+IHwgU3FsRXhwcmVzc2lvbjxcInN0cmluZ1tdXCI+IHtcbiAgICBjb25zdCBxdWVyeUFyciA9IEFycmF5LmlzQXJyYXkocXVlcnkpID8gcXVlcnkgOiBbcXVlcnldO1xuICAgIGNvbnN0IHF1ZXJ5Q2xhdXNlID0gYEFSUkFZWyR7cXVlcnlBcnIubWFwKCgpID0+IFwiP1wiKS5qb2luKFwiLCBcIil9XWA7XG5cbiAgICAvLyDri6jsnbwg7Lus65+87J24IOqyveyasFxuICAgIGlmICh0eXBlb2YgY29sdW1uT3JDb2x1bW5zID09PSBcInN0cmluZ1wiKSB7XG4gICAgICByZXR1cm4gUHVyaS5yYXdTdHJpbmcoYHBncm9vbmdhX2hpZ2hsaWdodF9odG1sKD8/LCAke3F1ZXJ5Q2xhdXNlfSlgLCBbXG4gICAgICAgIGNvbHVtbk9yQ29sdW1ucyxcbiAgICAgICAgLi4ucXVlcnlBcnIsXG4gICAgICBdKTtcbiAgICB9XG5cbiAgICAvLyDsu6zrn7wg67Cw7Je07J24IOqyveyasFxuICAgIHJldHVybiBQdXJpLnJhd1N0cmluZ0FycmF5KFxuICAgICAgYHBncm9vbmdhX2hpZ2hsaWdodF9odG1sKEFSUkFZWyR7Y29sdW1uT3JDb2x1bW5zLm1hcCgoKSA9PiBcIj8/XCIpLmpvaW4oXCIsIFwiKX1dLCAke3F1ZXJ5Q2xhdXNlfSlgLFxuICAgICAgWy4uLmNvbHVtbk9yQ29sdW1ucywgLi4ucXVlcnlBcnJdLFxuICAgICk7XG4gIH1cblxuICAvLyBTRUxFQ1QgKG92ZXJ3cml0ZSlcbiAgc2VsZWN0PFRTZWxlY3QgZXh0ZW5kcyBTZWxlY3RPYmplY3Q8VFRhYmxlcz4+KFxuICAgIHNlbGVjdE9iajogVFNlbGVjdCxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzLCBQYXJzZVNlbGVjdE9iamVjdDxUVGFibGVzLCBUU2VsZWN0Pj4ge1xuICAgIC8vIOykkeyyqSDqsJ3ssrTrpbwgZmxhdO2VmOqyjCDrs4DtmZhcbiAgICBjb25zdCBmbGF0U2VsZWN0ID0gdGhpcy5mbGF0dGVuU2VsZWN0KHNlbGVjdE9iaik7XG5cbiAgICBjb25zdCBzZWxlY3RDbGF1c2VzOiAoc3RyaW5nIHwgS25leC5SYXcpW10gPSBbXTtcblxuICAgIGZvciAoY29uc3QgW2FsaWFzLCBjb2x1bW5PckZ1bmN0aW9uXSBvZiBPYmplY3QuZW50cmllcyhmbGF0U2VsZWN0KSkge1xuICAgICAgaWYgKHR5cGVvZiBjb2x1bW5PckZ1bmN0aW9uID09PSBcIm9iamVjdFwiICYmIGNvbHVtbk9yRnVuY3Rpb24uX3R5cGUgPT09IFwic3FsX2V4cHJlc3Npb25cIikge1xuICAgICAgICAvLyBTUUwg7ZWo7IiY7J24IOqyveyasFxuICAgICAgICBzZWxlY3RDbGF1c2VzLnB1c2goXG4gICAgICAgICAgdGhpcy5rbmV4LnJhdyhgJHtjb2x1bW5PckZ1bmN0aW9uLl9zcWx9IEFTIFwiJHthbGlhc31cImAsIGNvbHVtbk9yRnVuY3Rpb24uX3BhcmFtcyksXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyDsnbzrsJgg7Lus65+87J24IOqyveyasFxuICAgICAgICBjb25zdCBjb2x1bW5QYXRoID0gY29sdW1uT3JGdW5jdGlvbiBhcyBzdHJpbmc7XG4gICAgICAgIGlmIChhbGlhcyA9PT0gY29sdW1uUGF0aCkge1xuICAgICAgICAgIC8vIGFsaWFz7JmAIOy7rOufvOuqheydtCDqsJnsnLzrqbQgYWxpYXMg7IOd6561XG4gICAgICAgICAgc2VsZWN0Q2xhdXNlcy5wdXNoKGNvbHVtblBhdGgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIGFsaWFzIOyngOyglVxuICAgICAgICAgIHNlbGVjdENsYXVzZXMucHVzaChgJHtjb2x1bW5QYXRofSBBUyAke2FsaWFzfWApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5rbmV4UXVlcnkuc2VsZWN0KHNlbGVjdENsYXVzZXMpO1xuICAgIHJldHVybiB0aGlzIGFzIGFueTtcbiAgfVxuXG4gIC8qKlxuICAgKiDspJHssqkg6rCd7LK066W8IGZsYXQg6rCd7LK066GcIOuzgO2ZmFxuICAgKiDsmIg6IHsgcGFyZW50OiB7IGlkOiBcInBhcmVudC5pZFwiLCBuYW1lOiBcInBhcmVudC5uYW1lXCIgfSB9XG4gICAqICAg4oaSIHsgcGFyZW50X19pZDogXCJwYXJlbnQuaWRcIiwgcGFyZW50X19uYW1lOiBcInBhcmVudC5uYW1lXCIgfVxuICAgKi9cbiAgcHJpdmF0ZSBmbGF0dGVuU2VsZWN0KHNlbGVjdE9iajogUmVjb3JkPHN0cmluZywgYW55PiwgcHJlZml4ID0gXCJcIik6IFJlY29yZDxzdHJpbmcsIGFueT4ge1xuICAgIGNvbnN0IGZsYXRTZWxlY3Q6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcblxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHNlbGVjdE9iaikpIHtcbiAgICAgIGNvbnN0IGZ1bGxLZXkgPSBwcmVmaXggPyBgJHtwcmVmaXh9X18ke2tleX1gIDoga2V5O1xuXG4gICAgICBpZiAodHlwZW9mIHZhbHVlID09PSBcIm9iamVjdFwiICYmIHZhbHVlICE9PSBudWxsICYmICEoXCJfdHlwZVwiIGluIHZhbHVlKSkge1xuICAgICAgICAvLyDspJHssqkg6rCd7LK07J24IOqyveyasCAtIOyerOq3gCDsspjrpqxcbiAgICAgICAgY29uc3QgbmVzdGVkID0gdGhpcy5mbGF0dGVuU2VsZWN0KHZhbHVlLCBmdWxsS2V5KTtcbiAgICAgICAgT2JqZWN0LmFzc2lnbihmbGF0U2VsZWN0LCBuZXN0ZWQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8g7J2867CYIOqwkuyduCDqsr3smrAgKOy7rOufvCDqsr3roZwg65iQ64qUIFNxbEV4cHJlc3Npb24pXG4gICAgICAgIGZsYXRTZWxlY3RbZnVsbEtleV0gPSB2YWx1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmxhdFNlbGVjdDtcbiAgfVxuXG4gIC8vIFNFTEVDVCAoc2VsZWN064qUIG92ZXJ3cml0ZSwgYXBwZW5kU2VsZWN064qUIGFwcGVuZClcbiAgYXBwZW5kU2VsZWN0PFRTZWxlY3QgZXh0ZW5kcyBTZWxlY3RPYmplY3Q8VFRhYmxlcz4+KFxuICAgIHNlbGVjdE9iajogVFNlbGVjdCxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzLCBUUmVzdWx0ICYgUGFyc2VTZWxlY3RPYmplY3Q8VFRhYmxlcywgVFNlbGVjdD4+IHtcbiAgICAvLyDspJHssqkg6rCd7LK066W8IGZsYXTtlZjqsowg67OA7ZmYXG4gICAgY29uc3QgZmxhdFNlbGVjdCA9IHRoaXMuZmxhdHRlblNlbGVjdChzZWxlY3RPYmopO1xuXG4gICAgY29uc3Qgc2VsZWN0Q2xhdXNlczogKHN0cmluZyB8IEtuZXguUmF3KVtdID0gW107XG5cbiAgICBmb3IgKGNvbnN0IFthbGlhcywgY29sdW1uT3JGdW5jdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMoZmxhdFNlbGVjdCkpIHtcbiAgICAgIGlmICh0eXBlb2YgY29sdW1uT3JGdW5jdGlvbiA9PT0gXCJvYmplY3RcIiAmJiBjb2x1bW5PckZ1bmN0aW9uLl90eXBlID09PSBcInNxbF9leHByZXNzaW9uXCIpIHtcbiAgICAgICAgc2VsZWN0Q2xhdXNlcy5wdXNoKFxuICAgICAgICAgIHRoaXMua25leC5yYXcoYCR7Y29sdW1uT3JGdW5jdGlvbi5fc3FsfSBBUyAke2FsaWFzfWAsIGNvbHVtbk9yRnVuY3Rpb24uX3BhcmFtcyksXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBjb2x1bW5QYXRoID0gY29sdW1uT3JGdW5jdGlvbiBhcyBzdHJpbmc7XG4gICAgICAgIGlmIChhbGlhcyA9PT0gY29sdW1uUGF0aCkge1xuICAgICAgICAgIHNlbGVjdENsYXVzZXMucHVzaChjb2x1bW5QYXRoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzZWxlY3RDbGF1c2VzLnB1c2godGhpcy5rbmV4LnJlZihjb2x1bW5QYXRoKS5hcyhhbGlhcykpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5rbmV4UXVlcnkuc2VsZWN0KHNlbGVjdENsYXVzZXMpO1xuICAgIHJldHVybiB0aGlzIGFzIGFueTtcbiAgfVxuXG4gIC8vIFNFTEVDVCAqXG4gIHNlbGVjdEFsbCgpOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMsIFNlbGVjdEFsbFJlc3VsdDxUVGFibGVzPj4ge1xuICAgIHRoaXMua25leFF1ZXJ5LnNlbGVjdChcIipcIik7XG4gICAgcmV0dXJuIHRoaXMgYXMgYW55O1xuICB9XG5cbiAgLy8gRElTVElOQ1RcbiAgZGlzdGluY3Q8VENvbHVtbnMgZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PiguLi5jb2x1bW5zOiBUQ29sdW1uc1tdKTogdGhpcztcbiAgZGlzdGluY3QoLi4uY29sdW1uczogc3RyaW5nW10pOiB0aGlzIHtcbiAgICB0aGlzLmtuZXhRdWVyeS5kaXN0aW5jdCguLi5jb2x1bW5zKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIENMRUFSXG4gIGNsZWFyKHN0YXRlbWVudDogQ2xlYXJTdGF0ZW1lbnRzKTogdGhpcyB7XG4gICAgdGhpcy5rbmV4UXVlcnkuY2xlYXIoc3RhdGVtZW50KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIGtuZXjsl5Ag7JeG7Ja07IScIOyngeygkSDqtaztmITtlahcbiAgY2xlYXJKb2luKGFsaWFzOiBzdHJpbmcpOiB0aGlzIHtcbiAgICAodGhpcy5rbmV4UXVlcnkgYXMgYW55KS5fc3RhdGVtZW50cyA9ICh0aGlzLmtuZXhRdWVyeSBhcyBhbnkpLl9zdGF0ZW1lbnRzLmZpbHRlcigoczogYW55KSA9PiB7XG4gICAgICBpZiAoXCJqb2luVHlwZVwiIGluIHMpIHtcbiAgICAgICAgY29uc3QgW19hbGlhcywgX3RhYmxlXSA9IE9iamVjdC5lbnRyaWVzKHMudGFibGUpWzBdO1xuICAgICAgICByZXR1cm4gX2FsaWFzICE9PSBhbGlhcztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gSk9JTjog7ISc67iM7L+866asICsgQWxpYXNcbiAgam9pbjxUSm9pbkFsaWFzIGV4dGVuZHMgc3RyaW5nLCBUU3ViUmVzdWx0PihcbiAgICB0YWJsZVNwZWM6IHsgW0sgaW4gVEpvaW5BbGlhc106IFB1cmk8VFNjaGVtYSwgYW55LCBUU3ViUmVzdWx0PiB9LFxuICAgIGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4sXG4gICAgcmlnaHQ6IGAke1RKb2luQWxpYXN9LiR7Q29sdW1uS2V5czxUU3ViUmVzdWx0Pn1gLFxuICApOiBQdXJpPFxuICAgIFRTY2hlbWEsXG4gICAgVFRhYmxlcyAmIFJlY29yZDxUSm9pbkFsaWFzLCBUU3ViUmVzdWx0PiwgLy8g7ISc67iM7L+866as7J2YIFRSZXN1bHRcbiAgICBUUmVzdWx0XG4gID47XG4gIC8vIEpPSU46IO2FjOydtOu4lCArIEFsaWFzXG4gIGpvaW48VEpvaW5UYWJsZSBleHRlbmRzIGtleW9mIFRTY2hlbWEsIFRKb2luQWxpYXMgZXh0ZW5kcyBzdHJpbmc+KFxuICAgIHRhYmxlU3BlYzogeyBbSyBpbiBUSm9pbkFsaWFzXTogVEpvaW5UYWJsZSB9LFxuICAgIGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4sXG4gICAgcmlnaHQ6IGAke1RKb2luQWxpYXN9LiR7Q29sdW1uS2V5czxUU2NoZW1hW1RKb2luVGFibGVdPn1gLFxuICApOiBQdXJpPFxuICAgIFRTY2hlbWEsXG4gICAgVFRhYmxlcyAmIFJlY29yZDxUSm9pbkFsaWFzLCBUU2NoZW1hW1RKb2luVGFibGVdPiwgLy8gVFRhYmxlcyDtmZXsnqUhXG4gICAgVFJlc3VsdFxuICA+O1xuICAvLyBKT0lOOiDthYzsnbTruJTrqoVcbiAgam9pbjxUSm9pblRhYmxlIGV4dGVuZHMga2V5b2YgVFNjaGVtYT4oXG4gICAgdGFibGVOYW1lOiBUSm9pblRhYmxlLFxuICAgIGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4sXG4gICAgcmlnaHQ6IGAke1RKb2luVGFibGUgJiBzdHJpbmd9LiR7Q29sdW1uS2V5czxUU2NoZW1hW1RKb2luVGFibGVdPn1gLFxuICApOiBQdXJpPFxuICAgIFRTY2hlbWEsXG4gICAgVFRhYmxlcyAmIFJlY29yZDxUSm9pblRhYmxlLCBUU2NoZW1hW1RKb2luVGFibGVdPiwgLy8g7YWM7J2067iU66qF7J20IO2CpFxuICAgIFRSZXN1bHRcbiAgPjtcbiAgLy8gSk9JTjog7ISc67iM7L+866asICsgQWxpYXMgKyDsvZzrsLFcbiAgam9pbjxUSm9pbkFsaWFzIGV4dGVuZHMgc3RyaW5nLCBUU3ViUmVzdWx0PihcbiAgICB0YWJsZVNwZWM6IHsgW0sgaW4gVEpvaW5BbGlhc106IFB1cmk8VFNjaGVtYSwgYW55LCBUU3ViUmVzdWx0PiB9LFxuICAgIGNhbGxiYWNrOiAoajogSm9pbkNsYXVzZUdyb3VwPFRUYWJsZXMsIFJlY29yZDxUSm9pbkFsaWFzLCBUU3ViUmVzdWx0Pj4pID0+IHZvaWQsXG4gICk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcyAmIFJlY29yZDxUSm9pbkFsaWFzLCBUU3ViUmVzdWx0PiwgVFJlc3VsdD47XG4gIC8vIEpPSU46IO2FjOydtOu4lCArIEFsaWFzICsg7L2c67CxXG4gIGpvaW48VEpvaW5UYWJsZSBleHRlbmRzIGtleW9mIFRTY2hlbWEsIFRKb2luQWxpYXMgZXh0ZW5kcyBzdHJpbmc+KFxuICAgIHRhYmxlU3BlYzogeyBbSyBpbiBUSm9pbkFsaWFzXTogVEpvaW5UYWJsZSB9LFxuICAgIGNhbGxiYWNrOiAoajogSm9pbkNsYXVzZUdyb3VwPFRUYWJsZXMsIFJlY29yZDxUSm9pbkFsaWFzLCBUU2NoZW1hW1RKb2luVGFibGVdPj4pID0+IHZvaWQsXG4gICk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcyAmIFJlY29yZDxUSm9pbkFsaWFzLCBUU2NoZW1hW1RKb2luVGFibGVdPiwgVFJlc3VsdD47XG4gIC8vIEpPSU46IO2FjOydtOu4lOuqhSArIOy9nOuwsVxuICBqb2luPFRKb2luVGFibGUgZXh0ZW5kcyBrZXlvZiBUU2NoZW1hPihcbiAgICB0YWJsZU5hbWU6IFRKb2luVGFibGUsXG4gICAgY2FsbGJhY2s6IChqOiBKb2luQ2xhdXNlR3JvdXA8VFRhYmxlcywgUmVjb3JkPFRKb2luVGFibGUsIFRTY2hlbWFbVEpvaW5UYWJsZV0+PikgPT4gdm9pZCxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzICYgUmVjb3JkPFRKb2luVGFibGUsIFRTY2hlbWFbVEpvaW5UYWJsZV0+LCBUUmVzdWx0PjtcbiAgLy8gSk9JTiDsi6TsoJwg6rWs7ZiEXG4gIGpvaW4odGFibGVOYW1lT3JTcGVjOiBhbnksIC4uLmFyZ3M6IGFueVtdKTogYW55IHtcbiAgICByZXR1cm4gdGhpcy5fX2NvbW1vbkpvaW4oXCJqb2luXCIsIHRhYmxlTmFtZU9yU3BlYywgLi4uYXJncyk7XG4gIH1cblxuICAvLyBMRUZUIEpPSU46IOyEnOu4jOy/vOumrCArIEFsaWFzXG4gIGxlZnRKb2luPFRKb2luQWxpYXMgZXh0ZW5kcyBzdHJpbmcsIFRTdWJSZXN1bHQ+KFxuICAgIHRhYmxlU3BlYzogeyBbSyBpbiBUSm9pbkFsaWFzXTogUHVyaTxUU2NoZW1hLCBhbnksIFRTdWJSZXN1bHQ+IH0sXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPixcbiAgICByaWdodDogYCR7VEpvaW5BbGlhc30uJHtDb2x1bW5LZXlzPFRTdWJSZXN1bHQ+fWAsXG4gICk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcyAmIFJlY29yZDxUSm9pbkFsaWFzLCBUU3ViUmVzdWx0ICYgTGVmdEpvaW5lZE1hcmtlcj4sIFRSZXN1bHQ+OyAvLyDshJzruIzsv7zrpqzsnZggVFJlc3VsdFxuICAvLyBMRUZUIEpPSU46IO2FjOydtOu4lCArIEFsaWFzXG4gIC8vIEZLIG51bGxhYmxlIOyXrOu2gOyXkCDrlLDrnbwg7J6Q64+Z7Jy866GcIExlZnRKb2luZWRNYXJrZXIg6rKw7KCVXG4gIGxlZnRKb2luPFxuICAgIFRKb2luVGFibGUgZXh0ZW5kcyBrZXlvZiBUU2NoZW1hLFxuICAgIFRKb2luQWxpYXMgZXh0ZW5kcyBzdHJpbmcsXG4gICAgVExlZnQgZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+LFxuICA+KFxuICAgIHRhYmxlU3BlYzogeyBbSyBpbiBUSm9pbkFsaWFzXTogVEpvaW5UYWJsZSB9LFxuICAgIGxlZnQ6IFRMZWZ0LFxuICAgIHJpZ2h0OiBgJHtUSm9pbkFsaWFzfS4ke0NvbHVtbktleXM8VFNjaGVtYVtUSm9pblRhYmxlXT59YCxcbiAgKTogUHVyaTxcbiAgICBUU2NoZW1hLFxuICAgIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5BbGlhcywgVFNjaGVtYVtUSm9pblRhYmxlXSAmIExlZnRKb2luTWFya2VyRm9yPFRUYWJsZXMsIFRMZWZ0Pj4sXG4gICAgVFJlc3VsdFxuICA+O1xuICAvLyBMRUZUIEpPSU46IO2FjOydtOu4lOuqhVxuICBsZWZ0Sm9pbjxUSm9pblRhYmxlIGV4dGVuZHMga2V5b2YgVFNjaGVtYSwgVExlZnQgZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICB0YWJsZU5hbWU6IFRKb2luVGFibGUsXG4gICAgbGVmdDogVExlZnQsXG4gICAgcmlnaHQ6IGAke1RKb2luVGFibGUgJiBzdHJpbmd9LiR7Q29sdW1uS2V5czxUU2NoZW1hW1RKb2luVGFibGVdPn1gLFxuICApOiBQdXJpPFxuICAgIFRTY2hlbWEsXG4gICAgVFRhYmxlcyAmIFJlY29yZDxUSm9pblRhYmxlLCBUU2NoZW1hW1RKb2luVGFibGVdICYgTGVmdEpvaW5NYXJrZXJGb3I8VFRhYmxlcywgVExlZnQ+PixcbiAgICBUUmVzdWx0XG4gID47XG4gIC8vIExFRlQgSk9JTjog7ISc67iM7L+866asICsgQWxpYXMgKyDsvZzrsLFcbiAgbGVmdEpvaW48VEpvaW5BbGlhcyBleHRlbmRzIHN0cmluZywgVFN1YlJlc3VsdD4oXG4gICAgdGFibGVTcGVjOiB7IFtLIGluIFRKb2luQWxpYXNdOiBQdXJpPFRTY2hlbWEsIGFueSwgVFN1YlJlc3VsdD4gfSxcbiAgICBjYWxsYmFjazogKGo6IEpvaW5DbGF1c2VHcm91cDxUVGFibGVzLCBSZWNvcmQ8VEpvaW5BbGlhcywgVFN1YlJlc3VsdD4+KSA9PiB2b2lkLFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMgJiBSZWNvcmQ8VEpvaW5BbGlhcywgVFN1YlJlc3VsdCAmIExlZnRKb2luZWRNYXJrZXI+LCBUUmVzdWx0PjtcbiAgLy8gTEVGVCBKT0lOOiDthYzsnbTruJQgKyBBbGlhcyArIOy9nOuwsVxuICBsZWZ0Sm9pbjxUSm9pblRhYmxlIGV4dGVuZHMga2V5b2YgVFNjaGVtYSwgVEpvaW5BbGlhcyBleHRlbmRzIHN0cmluZz4oXG4gICAgdGFibGVTcGVjOiB7IFtLIGluIFRKb2luQWxpYXNdOiBUSm9pblRhYmxlIH0sXG4gICAgY2FsbGJhY2s6IChqOiBKb2luQ2xhdXNlR3JvdXA8VFRhYmxlcywgUmVjb3JkPFRKb2luQWxpYXMsIFRTY2hlbWFbVEpvaW5UYWJsZV0+PikgPT4gdm9pZCxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzICYgUmVjb3JkPFRKb2luQWxpYXMsIFRTY2hlbWFbVEpvaW5UYWJsZV0gJiBMZWZ0Sm9pbmVkTWFya2VyPiwgVFJlc3VsdD47XG4gIC8vIExFRlQgSk9JTjog7YWM7J2067iU66qFICsg7L2c67CxXG4gIGxlZnRKb2luPFRKb2luVGFibGUgZXh0ZW5kcyBrZXlvZiBUU2NoZW1hPihcbiAgICB0YWJsZU5hbWU6IFRKb2luVGFibGUsXG4gICAgY2FsbGJhY2s6IChqOiBKb2luQ2xhdXNlR3JvdXA8VFRhYmxlcywgUmVjb3JkPFRKb2luVGFibGUsIFRTY2hlbWFbVEpvaW5UYWJsZV0+PikgPT4gdm9pZCxcbiAgKTogUHVyaTxUU2NoZW1hLCBUVGFibGVzICYgUmVjb3JkPFRKb2luVGFibGUsIFRTY2hlbWFbVEpvaW5UYWJsZV0gJiBMZWZ0Sm9pbmVkTWFya2VyPiwgVFJlc3VsdD47XG4gIC8vIExFRlQgSk9JTiDsi6TsoJwg6rWs7ZiEXG4gIGxlZnRKb2luKHRhYmxlTmFtZU9yU3BlYzogYW55LCAuLi5hcmdzOiBhbnlbXSk6IGFueSB7XG4gICAgcmV0dXJuIHRoaXMuX19jb21tb25Kb2luKFwibGVmdEpvaW5cIiwgdGFibGVOYW1lT3JTcGVjLCAuLi5hcmdzKTtcbiAgfVxuXG4gIF9fY29tbW9uSm9pbihqb2luVHlwZTogXCJqb2luXCIgfCBcImxlZnRKb2luXCIsIHRhYmxlTmFtZU9yU3BlYzogYW55LCAuLi5hcmdzOiBhbnlbXSk6IHRoaXMge1xuICAgIGlmICh0eXBlb2YgdGFibGVOYW1lT3JTcGVjID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAvLyBDYXNlIDE6IGpvaW4oXCJwb3N0c1wiLCAuLi4pXG4gICAgICBjb25zdCB0YWJsZU5hbWUgPSB0YWJsZU5hbWVPclNwZWM7XG5cbiAgICAgIGlmIChhcmdzLmxlbmd0aCA9PT0gMSAmJiB0eXBlb2YgYXJnc1swXSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgIC8vIGpvaW4oXCJwb3N0c1wiLCBjYWxsYmFjaylcbiAgICAgICAgY29uc3QgY2FsbGJhY2sgPSBhcmdzWzBdO1xuICAgICAgICB0aGlzLmtuZXhRdWVyeVtqb2luVHlwZV0odGFibGVOYW1lLCAoam9pbkNsYXVzZSkgPT4ge1xuICAgICAgICAgIGNhbGxiYWNrKG5ldyBKb2luQ2xhdXNlR3JvdXAoam9pbkNsYXVzZSkpO1xuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGpvaW4oXCJwb3N0c1wiLCBsZWZ0LCByaWdodClcbiAgICAgICAgY29uc3QgW2xlZnQsIHJpZ2h0XSA9IGFyZ3M7XG4gICAgICAgIHRoaXMua25leFF1ZXJ5W2pvaW5UeXBlXSh0YWJsZU5hbWUsIGxlZnQsIHJpZ2h0KTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHR5cGVvZiB0YWJsZU5hbWVPclNwZWMgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIC8vIENhc2UgMjogam9pbih7IGFsaWFzOiBcInRhYmxlXCIgfSwgLi4uKSBvciBqb2luKHsgYWxpYXM6IHN1YnF1ZXJ5IH0sIC4uLilcbiAgICAgIGNvbnN0IGVudHJpZXMgPSBPYmplY3QuZW50cmllcyh0YWJsZU5hbWVPclNwZWMpO1xuICAgICAgaWYgKGVudHJpZXMubGVuZ3RoICE9PSAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlRhYmxlIHNwZWMgbXVzdCBoYXZlIGV4YWN0bHkgb25lIGVudHJ5XCIpO1xuICAgICAgfVxuICAgICAgYXNzZXJ0KGVudHJpZXNbMF0pO1xuICAgICAgY29uc3QgW1thbGlhcywgc3BlY11dID0gZW50cmllcztcblxuICAgICAgaWYgKHR5cGVvZiBzcGVjID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIC8vIO2FjOydtOu4lDogam9pbih7IHA6IFwicG9zdHNcIiB9LCAuLi4pXG4gICAgICAgIGlmIChhcmdzLmxlbmd0aCA9PT0gMSAmJiB0eXBlb2YgYXJnc1swXSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgLy8gQ2FsbGJhY2tcbiAgICAgICAgICBjb25zdCBjYWxsYmFjayA9IGFyZ3NbMF07XG4gICAgICAgICAgdGhpcy5rbmV4UXVlcnlbam9pblR5cGVdKHsgW2FsaWFzXTogc3BlYyB9LCAoam9pbkNsYXVzZSkgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2sobmV3IEpvaW5DbGF1c2VHcm91cChqb2luQ2xhdXNlKSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gU2ltcGxlXG4gICAgICAgICAgY29uc3QgW2xlZnQsIHJpZ2h0XSA9IGFyZ3M7XG4gICAgICAgICAgdGhpcy5rbmV4UXVlcnlbam9pblR5cGVdKHsgW2FsaWFzXTogc3BlYyB9LCBsZWZ0LCByaWdodCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoc3BlYyBpbnN0YW5jZW9mIFB1cmkpIHtcbiAgICAgICAgLy8g7ISc67iM7L+866asOiBqb2luKHsgc3E6IHN1YnF1ZXJ5IH0sIC4uLilcbiAgICAgICAgaWYgKGFyZ3MubGVuZ3RoID09PSAxICYmIHR5cGVvZiBhcmdzWzBdID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAvLyBDYWxsYmFja1xuICAgICAgICAgIGNvbnN0IGNhbGxiYWNrID0gYXJnc1swXTtcbiAgICAgICAgICB0aGlzLmtuZXhRdWVyeVtqb2luVHlwZV0oc3BlYy5yYXdRdWVyeSgpLmFzKGFsaWFzKSwgKGpvaW5DbGF1c2UpID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKG5ldyBKb2luQ2xhdXNlR3JvdXAoam9pbkNsYXVzZSkpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIFNpbXBsZVxuICAgICAgICAgIGNvbnN0IFtsZWZ0LCByaWdodF0gPSBhcmdzO1xuICAgICAgICAgIHRoaXMua25leFF1ZXJ5W2pvaW5UeXBlXShzcGVjLnJhd1F1ZXJ5KCkuYXMoYWxpYXMpLCBsZWZ0LCByaWdodCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgdGFibGUgc3BlY2lmaWNhdGlvblwiKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBhcmd1bWVudHNcIik7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyBXSEVSRTog6rCd7LK0IC0g7IKs7JqpOiAud2hlcmUoeyBcInUuaWRcIjogMSwgXCJ1LnN0YXR1c1wiOiBcImFjdGl2ZVwiIH0pXG4gIHdoZXJlKGNvbmRpdGlvbnM6IFdoZXJlQ29uZGl0aW9uPFRUYWJsZXM+KTogdGhpcztcbiAgLy8gV0hFUkU6IOy7rOufvCAtIOyCrOyaqTogLndoZXJlKFwidS5pZFwiLCAxKSwgLndoZXJlKFwidS5pZFwiLCBudWxsKVxuICB3aGVyZTxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIHZhbHVlOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgLy8gV0hFUkU6IOy7rOufvCAtIOyCrOyaqTogLndoZXJlKFwidS5pZFwiLCBcIj5cIiwgMTApLCAud2hlcmUoXCJ1LmlkXCIsIFwiIT1cIiwgbnVsbClcbiAgd2hlcmU8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICBvcGVyYXRvcjogV2hlcmVPcGVyYXRvcixcbiAgICB2YWx1ZTogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIC8vIFdIRVJFOiBTUUwg7ZGc7ZiE7IudIC0g7IKs7JqpOiAud2hlcmUocHVyaS5yYXcoXCJDT05DQVQodS5uYW1lLCB1LmVtYWlsKVwiKSwgXCJsaWtlXCIsIFwiJXRlc3QlXCIpXG4gIHdoZXJlPFRDb2x1bW4gZXh0ZW5kcyBLbmV4LlJhdz4oY29sdW1uOiBUQ29sdW1uLCBvcGVyYXRvcjogV2hlcmVPcGVyYXRvciwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIC8vIFdIRVJFOiDsu6zrn7wgLSDsgqzsmqk6IC53aGVyZShcInUuaWRcIiwgXCJsaWtlXCIsIFwiJXRlc3QlXCIpXG4gIHdoZXJlKC4uLmFyZ3M6IFtjb2x1bW5PckNvbmRpdGlvbnM6IGFueSwgb3BlcmF0b3JPclZhbHVlPzogYW55LCB2YWx1ZT86IGFueV0pOiB0aGlzIHtcbiAgICBjb25zdCBbY29sdW1uT3JDb25kaXRpb25zLCBvcGVyYXRvck9yVmFsdWUsIHZhbHVlXSA9IGFyZ3M7XG4gICAgaWYgKHR5cGVvZiBjb2x1bW5PckNvbmRpdGlvbnMgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlKGNvbHVtbk9yQ29uZGl0aW9ucyk7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgdmFsdWUgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgIGlmIChvcGVyYXRvck9yVmFsdWUgPT09IG51bGwpIHtcbiAgICAgICAgdGhpcy5rbmV4UXVlcnkud2hlcmVOdWxsKGNvbHVtbk9yQ29uZGl0aW9ucyk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgfVxuICAgICAgdGhpcy5rbmV4UXVlcnkud2hlcmUoY29sdW1uT3JDb25kaXRpb25zLCBvcGVyYXRvck9yVmFsdWUpO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIHZhbHVlICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICBpZiAodmFsdWUgPT09IG51bGwpIHtcbiAgICAgICAgaWYgKG9wZXJhdG9yT3JWYWx1ZSA9PT0gXCIhPVwiKSB7XG4gICAgICAgICAgdGhpcy5rbmV4UXVlcnkud2hlcmVOb3ROdWxsKGNvbHVtbk9yQ29uZGl0aW9ucyk7XG4gICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0gZWxzZSBpZiAob3BlcmF0b3JPclZhbHVlID09PSBcIj1cIikge1xuICAgICAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlTnVsbChjb2x1bW5PckNvbmRpdGlvbnMpO1xuICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZShjb2x1bW5PckNvbmRpdGlvbnMsIG9wZXJhdG9yT3JWYWx1ZSwgdmFsdWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZShjb2x1bW5PckNvbmRpdGlvbnMpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIFdIRVJFIElOXG4gIHdoZXJlSW48VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZXM6IEV4dHJhY3RDb2x1bW5UeXBlPFRUYWJsZXMsIFRDb2x1bW4gJiBzdHJpbmc+W10sXG4gICk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcywgVFJlc3VsdD4ge1xuICAgIHRoaXMua25leFF1ZXJ5LndoZXJlSW4oY29sdW1uLCB2YWx1ZXMpO1xuICAgIHJldHVybiB0aGlzIGFzIGFueTtcbiAgfVxuXG4gIC8vIFdIRVJFIE5PVCBJTlxuICB3aGVyZU5vdEluPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWVzOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPltdLFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMsIFRSZXN1bHQ+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS53aGVyZU5vdEluKGNvbHVtbiwgdmFsdWVzKTtcbiAgICByZXR1cm4gdGhpcyBhcyBhbnk7XG4gIH1cblxuICAvLyBXSEVSRSBNQVRDSFxuICB3aGVyZU1hdGNoPFRDb2x1bW4gZXh0ZW5kcyBGdWxsdGV4dENvbHVtbnM8VFRhYmxlcz4+KGNvbHVtbjogVENvbHVtbiwgdmFsdWU6IHN0cmluZyk6IHRoaXMge1xuICAgIHRoaXMua25leFF1ZXJ5LndoZXJlUmF3KGBNQVRDSCAoJHtTdHJpbmcoY29sdW1uKX0pIEFHQUlOU1QgKD8pYCwgW3ZhbHVlXSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogUEdyb29uZ2EgRnVsbFRleHQg7J24642x7IqkIOqygOyDiVxuICAgKiAtIOyCrOyaqe2VoCBQR3Jvb25nYSDsnbjrjbHsiqTsmYAg64+Z7J287ZWcIOy7rOufvCDqtazshLHsnLzroZwg6rKA7IOJ7ZW07JW8IOyduOuNseyKpOqwgCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIOuLqOydvCDsu6zrn7wg6rKA7IOJOlxuICAgKiBgYGBzcWxcbiAgICogV0hFUkUgbmFtZSAmQH4gJ3NlYXJjaCdcbiAgICogYGBgXG4gICAqXG4gICAqIOuzte2VqSDsu6zrn7wg6rKA7IOJOlxuICAgKiBgYGBzcWxcbiAgICogV0hFUkUgQVJSQVlbbmFtZTo6dGV4dCwgZGVzY3JpcHRpb246OnRleHRdICZAfiAnc2VhcmNoJ1xuICAgKiBgYGBcbiAgICovXG4gIHdoZXJlU2VhcmNoPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4gfCBUQ29sdW1uW10sXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICBvcHRpb25zPzoge1xuICAgICAgd2VpZ2h0cz86IG51bWJlcltdOyAvLyDsoJXsiJgg67Cw7Je0XG4gICAgfSxcbiAgKTogdGhpcyB7XG4gICAgY29uc3QgeyB3ZWlnaHRzIH0gPSBvcHRpb25zID8/IHt9O1xuICAgIGNvbnN0IGNvbHVtbkV4cHIgPSBBcnJheS5pc0FycmF5KGNvbHVtbilcbiAgICAgID8gYEFSUkFZWyR7Y29sdW1uLm1hcCgoYykgPT4gYCR7Y306OnRleHRgKS5qb2luKFwiLFwiKX1dYFxuICAgICAgOiBjb2x1bW47XG4gICAgY29uc3QgcGdyb29uZ2FDb25kaXRpb24gPSBgcGdyb29uZ2FfY29uZGl0aW9uKD8ke3dlaWdodHM/Lmxlbmd0aCA/IGAsIHdlaWdodHMgPT4gQVJSQVlbJHt3ZWlnaHRzLmpvaW4oXCIsXCIpfV1gIDogXCJcIn0pYDtcblxuICAgIHRoaXMua25leFF1ZXJ5LndoZXJlUmF3KGAke2NvbHVtbkV4cHJ9ICZAfiAke3Bncm9vbmdhQ29uZGl0aW9ufWAsIFt2YWx1ZV0pO1xuXG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyBXSEVSRSBGVUxMVEVYVFxuICB3aGVyZVRzU2VhcmNoPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+IHwgU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIHZhbHVlOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IFRzUXVlcnlPcHRpb25zIHwgVHNRdWVyeUNvbmZpZyxcbiAgKTogdGhpcyB7XG4gICAgY29uc3Qgb3B0cyA9XG4gICAgICB0eXBlb2Ygb3B0aW9ucyA9PT0gXCJzdHJpbmdcIiA/ICh7IGNvbmZpZzogb3B0aW9ucyB9IGFzIFRzUXVlcnlPcHRpb25zKSA6IChvcHRpb25zID8/IHt9KTtcblxuICAgIGNvbnN0IHBhcnNlciA9IG9wdHMucGFyc2VyID8/IFwid2Vic2VhcmNoX3RvX3RzcXVlcnlcIjtcbiAgICBjb25zdCBjb25maWcgPSBvcHRzLmNvbmZpZyA/PyBcInNpbXBsZVwiO1xuICAgIGNvbnN0IGNvbHVtbkV4cHIgPVxuICAgICAgdHlwZW9mIGNvbHVtbiA9PT0gXCJvYmplY3RcIiAmJiBjb2x1bW4uX3R5cGUgPT09IFwic3FsX2V4cHJlc3Npb25cIlxuICAgICAgICA/IGNvbHVtbi5fc3FsXG4gICAgICAgIDogU3RyaW5nKGNvbHVtbik7XG5cbiAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhgJHtjb2x1bW5FeHByfSBAQCAke3BhcnNlcn0oPywgPylgLCBbY29uZmlnLCB2YWx1ZV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgd2hlcmVGdXp6eTxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPiB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7XG4gICAgICBvcGVyYXRvcj86IEZ1enp5T3BlcmF0b3I7XG4gICAgfSxcbiAgKTogdGhpcyB7XG4gICAgY29uc3Qgb3BlcmF0b3IgPSBub3JtYWxpemVGdXp6eU9wZXJhdG9yKG9wdGlvbnM/Lm9wZXJhdG9yKTtcblxuICAgIGlmIChvcGVyYXRvciA9PT0gXCIlXCIpIHtcbiAgICAgIGlmICh0eXBlb2YgY29sdW1uID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlUmF3KGAke2NvbHVtbi5fc3FsfSAke29wZXJhdG9yfSA/YCwgWy4uLmNvbHVtbi5fcGFyYW1zLCB2YWx1ZV0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5rbmV4UXVlcnkud2hlcmVSYXcoYD8/ICR7b3BlcmF0b3J9ID9gLCBbY29sdW1uLCB2YWx1ZV0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBjb2x1bW4gPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlUmF3KGA/ICR7b3BlcmF0b3J9ICR7Y29sdW1uLl9zcWx9YCwgW3ZhbHVlLCAuLi5jb2x1bW4uX3BhcmFtc10pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmtuZXhRdWVyeS53aGVyZVJhdyhgPyAke29wZXJhdG9yfSA/P2AsIFt2YWx1ZSwgY29sdW1uXSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gV0hFUkUgUkFXXG4gIHdoZXJlUmF3KHNxbDogc3RyaW5nLCBiaW5kaW5ncz86IHJlYWRvbmx5IHVua25vd25bXSk6IHRoaXMge1xuICAgIHRoaXMua25leFF1ZXJ5LndoZXJlUmF3KHNxbCwgYmluZGluZ3MpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gV0hFUkUg6rSE7Zi4IOq3uOujue2VkVxuICB3aGVyZUdyb3VwKGNhbGxiYWNrOiAoZzogV2hlcmVHcm91cDxUVGFibGVzPikgPT4gdm9pZCk6IHRoaXMge1xuICAgIHRoaXMua25leFF1ZXJ5LndoZXJlKChidWlsZGVyKSA9PiB7XG4gICAgICBjb25zdCBncm91cCA9IG5ldyBXaGVyZUdyb3VwPFRUYWJsZXM+KGJ1aWxkZXIpO1xuICAgICAgY2FsbGJhY2soZ3JvdXApO1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIG9yV2hlcmVHcm91cChjYWxsYmFjazogKGc6IFdoZXJlR3JvdXA8VFRhYmxlcz4pID0+IHZvaWQpOiB0aGlzIHtcbiAgICB0aGlzLmtuZXhRdWVyeS5vcldoZXJlKChidWlsZGVyKSA9PiB7XG4gICAgICBjb25zdCBncm91cCA9IG5ldyBXaGVyZUdyb3VwPFRUYWJsZXM+KGJ1aWxkZXIpO1xuICAgICAgY2FsbGJhY2soZ3JvdXApO1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gT1JERVIgQlkgKFNxbEV4cHJlc3Npb27snLzroZzrj4Qg7ZWgIOyImCDsnojslrTslbwg7ZWoKVxuICBvcmRlckJ5PFRDb2x1bW4gZXh0ZW5kcyBSZXN1bHRBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXMsIFRSZXN1bHQ+PihcbiAgICBjb2x1bW46IFRDb2x1bW4gfCBTcWxFeHByZXNzaW9uPFwibnVtYmVyXCI+IHwgU3FsRXhwcmVzc2lvbjxcInN0cmluZ1wiPixcbiAgICBkaXJlY3Rpb246IFwiYXNjXCIgfCBcImRlc2NcIixcbiAgKTogdGhpcztcbiAgb3JkZXJCeShcbiAgICBjb2x1bW46IHN0cmluZyB8IFNxbEV4cHJlc3Npb248XCJudW1iZXJcIj4gfCBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+LFxuICAgIGRpcmVjdGlvbjogXCJhc2NcIiB8IFwiZGVzY1wiID0gXCJhc2NcIixcbiAgKTogdGhpcyB7XG4gICAgaWYgKHR5cGVvZiBjb2x1bW4gPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRoaXMua25leFF1ZXJ5Lm9yZGVyQnlSYXcoYCR7Y29sdW1uLl9zcWx9ICR7ZGlyZWN0aW9ufWAsIGNvbHVtbi5fcGFyYW1zKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5rbmV4UXVlcnkub3JkZXJCeShjb2x1bW4sIGRpcmVjdGlvbik7XG4gICAgfVxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIOuyoe2EsCDsnKDsgqzrj4Qg6rKA7IOJIOyEpOyglVxuICAgKlxuICAgKiAtIFNFTEVDVOyXkCBzaW1pbGFyaXR5IOy7rOufvCDstpTqsIBcbiAgICogLSBXSEVSRSBjb2wgSVMgTk9UIE5VTEwg7LaU6rCAXG4gICAqIC0gdGhyZXNob2xk6rCAIOyeiOycvOuptCBXSEVSRSDsobDqsbQg7LaU6rCAXG4gICAqIC0g6riw7KG0IE9SREVSIEJZ66W8IGNsZWFy7ZWY6rOgIOybkOyLnCDsl7DsgrDsnpDroZwg7KCV66CsIChITlNXIOyduOuNseyKpCDstZzsoIHtmZQpXG4gICAqXG4gICAqIEBwYXJhbSBjb2x1bW4g67Kh7YSwIOy7rOufvCDqsr3roZxcbiAgICogQHBhcmFtIGVtYmVkZGluZyDsv7zrpqwg7J6E67Kg65SpIOuyoe2EsFxuICAgKiBAcGFyYW0gb3B0aW9ucyBtZXRob2QsIHRocmVzaG9sZCwgYXMg65OxIOyYteyFmFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIC8vIGNvc2luZSBzaW1pbGFyaXR5ICjquLDrs7jqsJIpXG4gICAqIHFiLnZlY3RvclNpbWlsYXJpdHkoXCJjb2x1bW5OYW1lXCIsIHF1ZXJ5VmVjdG9yLCB7XG4gICAqICAgbWV0aG9kOiBcImNvc2luZVwiLFxuICAgKiAgIHRocmVzaG9sZDogMC41XG4gICAqIH0pO1xuICAgKlxuICAgKiAvLyBMMiBkaXN0YW5jZVxuICAgKiBxYi52ZWN0b3JTaW1pbGFyaXR5KFwiY29sdW1uTmFtZVwiLCBxdWVyeVZlY3Rvciwge1xuICAgKiAgIG1ldGhvZDogXCJsMlwiLFxuICAgKiAgIHRocmVzaG9sZDogMS41ICAvLyDqsbDrpqzqsIAgMS41IOydtO2VmOyduCDqsrDqs7zrp4xcbiAgICogfSk7XG4gICAqXG4gICAqIC8vIElubmVyIHByb2R1Y3RcbiAgICogcWIudmVjdG9yU2ltaWxhcml0eShcImNvbHVtbk5hbWVcIiwgcXVlcnlWZWN0b3IsIHtcbiAgICogICBtZXRob2Q6IFwiaW5uZXJfcHJvZHVjdFwiLFxuICAgKiAgIHRocmVzaG9sZDogMC43XG4gICAqIH0pO1xuICAgKiBgYGBcbiAgICovXG4gIHZlY3RvclNpbWlsYXJpdHkoXG4gICAgY29sdW1uOiBWZWN0b3JDb2x1bW5zPFRUYWJsZXM+LFxuICAgIGVtYmVkZGluZzogbnVtYmVyW10sXG4gICAgb3B0aW9uczoge1xuICAgICAgbWV0aG9kPzogXCJjb3NpbmVcIiB8IFwibDJcIiB8IFwiaW5uZXJfcHJvZHVjdFwiO1xuICAgICAgdGhyZXNob2xkPzogbnVtYmVyO1xuICAgICAgZGlzdGluY3RPbj86IEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz47XG4gICAgfSA9IHt9LFxuICApOiBQdXJpPFRTY2hlbWEsIFRUYWJsZXMsIFRSZXN1bHQgJiB7IHNpbWlsYXJpdHk6IG51bWJlciB9PiB7XG4gICAgY29uc3QgeyBtZXRob2QgPSBcImNvc2luZVwiLCB0aHJlc2hvbGQsIGRpc3RpbmN0T24gfSA9IG9wdGlvbnM7XG5cbiAgICBpZiAoXG4gICAgICAhQXJyYXkuaXNBcnJheShlbWJlZGRpbmcpIHx8XG4gICAgICBlbWJlZGRpbmcubGVuZ3RoID09PSAwIHx8XG4gICAgICBlbWJlZGRpbmcuc29tZSgodikgPT4gIU51bWJlci5pc0Zpbml0ZSh2KSlcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgZW1iZWRkaW5nIHZlY3RvcjogZXhwZWN0ZWQgYSBub24tZW1wdHkgYXJyYXkgb2YgZmluaXRlIG51bWJlcnNcIik7XG4gICAgfVxuXG4gICAgY29uc3QgdmVjdG9yTGl0ZXJhbCA9IEpTT04uc3RyaW5naWZ5KGVtYmVkZGluZy5tYXAoKHYpID0+IE51bWJlcih2KSkpO1xuICAgIGNvbnN0IG9wZXJhdG9yID0geyBjb3NpbmU6IFwiPD0+XCIsIGwyOiBcIjwtPlwiLCBpbm5lcl9wcm9kdWN0OiBcIjwjPlwiIH1bbWV0aG9kXTtcblxuICAgIC8vIG1ldGhvZOuzhCDsl7DsgrDsnpAg67CPIHNpbWlsYXJpdHkg6rOE7IKw7IudXG4gICAgLy8gLSBjb3NpbmU6IDw9PiAoY29zaW5lIGRpc3RhbmNlLCAwfjIpLCBzaW1pbGFyaXR5ID0gMSAtIGRpc3RhbmNlXG4gICAgLy8gLSBsMjogPC0+IChldWNsaWRlYW4gZGlzdGFuY2UpLCBzaW1pbGFyaXR5ID0gZGlzdGFuY2UgKOuCruydhOyImOuhnSDsnKDsgqwpXG4gICAgLy8gLSBpbm5lcl9wcm9kdWN0OiA8Iz4gKG5lZ2F0aXZlIGlubmVyIHByb2R1Y3QpLCBzaW1pbGFyaXR5ID0gLWRpc3RhbmNlICjrhpLsnYTsiJjroZ0g7Jyg7IKsKVxuICAgIGNvbnN0IHNpbWlsYXJpdHlFeHByID1cbiAgICAgIG1ldGhvZCA9PT0gXCJjb3NpbmVcIlxuICAgICAgICA/IHRoaXMua25leC5yYXcoYDEgLSAoPz8gJHtvcGVyYXRvcn0gPzo6dmVjdG9yKSBhcyBzaW1pbGFyaXR5YCwgW2NvbHVtbiwgdmVjdG9yTGl0ZXJhbF0pXG4gICAgICAgIDogbWV0aG9kID09PSBcImwyXCJcbiAgICAgICAgICA/IHRoaXMua25leC5yYXcoYD8/ICR7b3BlcmF0b3J9ID86OnZlY3RvciBhcyBzaW1pbGFyaXR5YCwgW2NvbHVtbiwgdmVjdG9yTGl0ZXJhbF0pXG4gICAgICAgICAgOiB0aGlzLmtuZXgucmF3KGAtKD8/ICR7b3BlcmF0b3J9ID86OnZlY3RvcikgYXMgc2ltaWxhcml0eWAsIFtjb2x1bW4sIHZlY3RvckxpdGVyYWxdKTtcblxuICAgIC8vIFdIRVJFIE5PVCBOVUxMXG4gICAgdGhpcy5rbmV4UXVlcnkud2hlcmVOb3ROdWxsKGNvbHVtbik7XG5cbiAgICAvLyDquLDsobQgT1JERVIgQlkgY2xlYXJcbiAgICB0aGlzLmtuZXhRdWVyeS5jbGVhcihcIm9yZGVyXCIpO1xuICAgIGlmIChkaXN0aW5jdE9uKSB7XG4gICAgICAvLyBESVNUSU5DVCBPTuydgCBTRUxFQ1Qg7KCI7J2YIOunqCDslZ7sl5Ag7JmA7JW8IO2VmOuvgOuhnCwg6riw7KG0IHNlbGVjdChzdWJzZXQg7ZWE65Oc65OkKeulvCDrs7TsobQg7ZuEIGNsZWFy7ZWY6rOgIOuLpOyLnCDstpTqsIBcbiAgICAgIGNvbnN0IGV4aXN0aW5nU3Vic2V0Q29scyA9ICh0aGlzLmtuZXhRdWVyeSBhcyBhbnkpLl9zdGF0ZW1lbnRzXG4gICAgICAgIC5maWx0ZXIoKHM6IGFueSkgPT4gcy5ncm91cGluZyA9PT0gXCJjb2x1bW5zXCIpXG4gICAgICAgIC5mbGF0TWFwKChzOiBhbnkpID0+IHMudmFsdWUpO1xuICAgICAgdGhpcy5rbmV4UXVlcnkuY2xlYXIoXCJzZWxlY3RcIik7XG4gICAgICB0aGlzLmtuZXhRdWVyeS5zZWxlY3QodGhpcy5rbmV4LnJhdyhgRElTVElOQ1QgT04gKD8/KSA/P2AsIFtkaXN0aW5jdE9uLCBkaXN0aW5jdE9uXSkpO1xuICAgICAgZXhpc3RpbmdTdWJzZXRDb2xzLm1hcCgoY29sOiBhbnkpID0+IHRoaXMua25leFF1ZXJ5LnNlbGVjdChjb2wpKTtcbiAgICAgIHRoaXMua25leFF1ZXJ5LnNlbGVjdChzaW1pbGFyaXR5RXhwcik7XG4gICAgICB0aGlzLmtuZXhRdWVyeS5vcmRlckJ5UmF3KGA/PywgPz8gJHtvcGVyYXRvcn0gPzo6dmVjdG9yYCwgW1xuICAgICAgICBkaXN0aW5jdE9uLFxuICAgICAgICBjb2x1bW4sXG4gICAgICAgIHZlY3RvckxpdGVyYWwsXG4gICAgICBdKTtcblxuICAgICAgdGhpcy5rbmV4UXVlcnkgPSB0aGlzLmtuZXhcbiAgICAgICAgLmZyb20odGhpcy5rbmV4UXVlcnkuYXMoXCJkaXN0aW5jdF92ZWN0b3JzXCIpKVxuICAgICAgICAuc2VsZWN0KFwiKlwiKVxuICAgICAgICAub3JkZXJCeShcInNpbWlsYXJpdHlcIiwgXCJkZXNjXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmtuZXhRdWVyeS5zZWxlY3Qoc2ltaWxhcml0eUV4cHIpO1xuICAgICAgdGhpcy5rbmV4UXVlcnkub3JkZXJCeVJhdyhgPz8gJHtvcGVyYXRvcn0gPzo6dmVjdG9yYCwgW2NvbHVtbiwgdmVjdG9yTGl0ZXJhbF0pO1xuICAgIH1cblxuICAgIC8vIHRocmVzaG9sZFxuICAgIGlmICh0eXBlb2YgdGhyZXNob2xkID09PSBcIm51bWJlclwiKSB7XG4gICAgICBpZiAoIU51bWJlci5pc0Zpbml0ZSh0aHJlc2hvbGQpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB2ZWN0b3JTaW1pbGFyaXR5IHRocmVzaG9sZDogJHt0aHJlc2hvbGR9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChkaXN0aW5jdE9uKSB7XG4gICAgICAgIGNvbnN0IHRocmVzaG9sZE9wID0gbWV0aG9kID09PSBcImwyXCIgPyBcIjw9XCIgOiBcIj49XCI7XG4gICAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlKFwic2ltaWxhcml0eVwiLCB0aHJlc2hvbGRPcCwgdGhyZXNob2xkKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHRocmVzaG9sZFZhbHVlID1cbiAgICAgICAgICBtZXRob2QgPT09IFwiY29zaW5lXCIgPyAxIC0gdGhyZXNob2xkIDogbWV0aG9kID09PSBcImlubmVyX3Byb2R1Y3RcIiA/IC10aHJlc2hvbGQgOiB0aHJlc2hvbGQ7XG4gICAgICAgIHRoaXMua25leFF1ZXJ5LndoZXJlUmF3KGA/PyAke29wZXJhdG9yfSA/Ojp2ZWN0b3IgPD0gP2AsIFtcbiAgICAgICAgICBjb2x1bW4sXG4gICAgICAgICAgdmVjdG9yTGl0ZXJhbCxcbiAgICAgICAgICB0aHJlc2hvbGRWYWx1ZSxcbiAgICAgICAgXSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMgYXMgYW55O1xuICB9XG5cbiAgLy8g6riw67O4IOy/vOumrCDrqZTshJzrk5zrk6RcbiAgbGltaXQoY291bnQ6IG51bWJlcik6IHRoaXMge1xuICAgIGlmIChjb3VudCA8IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgbGltaXQ6IG11c3QgYmUgPj0gMFwiKTtcbiAgICB9XG4gICAgdGhpcy5rbmV4UXVlcnkubGltaXQoY291bnQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgb2Zmc2V0KGNvdW50OiBudW1iZXIpOiB0aGlzIHtcbiAgICBpZiAoY291bnQgPCAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIG9mZnNldDogbXVzdCBiZSA+PSAwXCIpO1xuICAgIH1cbiAgICB0aGlzLmtuZXhRdWVyeS5vZmZzZXQoY291bnQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gR1JPVVAgQllcbiAgZ3JvdXBCeTxUQ29sdW1ucyBleHRlbmRzIFJlc3VsdEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcywgVFJlc3VsdD4+KC4uLmNvbHVtbnM6IFRDb2x1bW5zW10pOiB0aGlzO1xuICBncm91cEJ5KC4uLmNvbHVtbnM6IHN0cmluZ1tdKTogdGhpcyB7XG4gICAgdGhpcy5rbmV4UXVlcnkuZ3JvdXBCeSguLi5jb2x1bW5zKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIEhBVklOR1xuICBoYXZpbmcoY29uZGl0aW9uOiBzdHJpbmcpOiB0aGlzO1xuICBoYXZpbmc8VENvbHVtbiBleHRlbmRzIFJlc3VsdEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcywgVFJlc3VsdD4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICBvcGVyYXRvcjogQ29tcGFyaXNvbk9wZXJhdG9yLFxuICAgIHZhbHVlOiBhbnksXG4gICk6IHRoaXM7XG4gIC8vIEhBVklORyDqtaztmIRcbiAgaGF2aW5nKC4uLmNvbmRpdGlvbnM6IGFueVtdKTogdGhpcyB7XG4gICAgaWYgKGNvbmRpdGlvbnMubGVuZ3RoID09PSAxKSB7XG4gICAgICAvLyBoYXZpbmcoXCJDT1VOVCgqKSA+IDEwXCIpXG4gICAgICB0aGlzLmtuZXhRdWVyeS5oYXZpbmcodGhpcy5rbmV4LnJhdyhjb25kaXRpb25zWzBdKSk7XG4gICAgfSBlbHNlIGlmIChjb25kaXRpb25zLmxlbmd0aCA9PT0gMykge1xuICAgICAgLy8gaGF2aW5nKFwiY291bnRcIiwgXCI+XCIsIDEwKVxuICAgICAgdGhpcy5rbmV4UXVlcnkuaGF2aW5nKFxuICAgICAgICB0aGlzLmtuZXgucmF3KGNvbmRpdGlvbnNbMF0pLFxuICAgICAgICBjb25kaXRpb25zWzFdLFxuICAgICAgICB0aGlzLmtuZXgucmF3KGNvbmRpdGlvbnNbMl0pLFxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBoYXZpbmcgYXJndW1lbnRzXCIpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIOyLpO2WiSDrqZTshJzrk5zrk6QgLSB0aGVuYWJsZSDqtaztmIRcbiAgdGhlbjxUUmVzdWx0MSA9IEV4cGFuZDxUUmVzdWx0PltdLCBUUmVzdWx0MiA9IG5ldmVyPihcbiAgICBvbmZ1bGZpbGxlZD86ICgodmFsdWU6IEV4cGFuZDxUUmVzdWx0PltdKSA9PiBUUmVzdWx0MSB8IFByb21pc2VMaWtlPFRSZXN1bHQxPikgfCBudWxsLFxuICAgIG9ucmVqZWN0ZWQ/OiAoKHJlYXNvbjogYW55KSA9PiBUUmVzdWx0MiB8IFByb21pc2VMaWtlPFRSZXN1bHQyPikgfCBudWxsLFxuICApOiBQcm9taXNlPFRSZXN1bHQxIHwgVFJlc3VsdDI+IHtcbiAgICBOYWl0ZS50KFwicHVyaTpleGVjdXRlZC1xdWVyeVwiLCB0aGlzLnRvUXVlcnkoKSk7XG4gICAgcmV0dXJuIHRoaXMua25leFF1ZXJ5LnRoZW4ob25mdWxmaWxsZWQgYXMgYW55LCBvbnJlamVjdGVkKTtcbiAgfVxuICBjYXRjaDxUUmVzdWx0MiA9IG5ldmVyPihcbiAgICBvbnJlamVjdGVkPzogKChyZWFzb246IGFueSkgPT4gVFJlc3VsdDIgfCBQcm9taXNlTGlrZTxUUmVzdWx0Mj4pIHwgbnVsbCxcbiAgKTogUHJvbWlzZTxUUmVzdWx0IHwgVFJlc3VsdDI+IHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkuY2F0Y2gob25yZWplY3RlZCk7XG4gIH1cbiAgZmluYWxseShvbmZpbmFsbHk/OiAoKCkgPT4gdm9pZCkgfCBudWxsKTogUHJvbWlzZTxUUmVzdWx0PiB7XG4gICAgcmV0dXJuIHRoaXMua25leFF1ZXJ5LmZpbmFsbHkob25maW5hbGx5KTtcbiAgfVxuXG4gIC8vIO2VmOuCmOunjCDsv7zrpqxcbiAgZmlyc3QoKTogUmVzb2x2ZWRQdXJpPEV4cGFuZDxUUmVzdWx0PiwgbmV2ZXI+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS5maXJzdCgpO1xuICAgIHJldHVybiBuZXcgUmVzb2x2ZWRQdXJpKHRoaXMua25leFF1ZXJ5LCB0aGlzLmtuZXgpO1xuICB9XG5cbiAgLy8g7L+866as7ZWcIOugiOy9lOuTnOyXkOyEnCDtirnsoJUg7Lus65+866eMIOy2lOy2nO2VnCDrsLDsl7Qg66as7YS0XG4gIHBsdWNrPFRDb2x1bW4gZXh0ZW5kcyBrZXlvZiBUUmVzdWx0IHwgUmVzdWx0QXZhaWxhYmxlQ29sdW1uczxUVGFibGVzLCBUUmVzdWx0Pj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICApOiBSZXNvbHZlZFB1cmk8XG4gICAgVENvbHVtbiBleHRlbmRzIGtleW9mIFRSZXN1bHRcbiAgICAgID8gVFJlc3VsdFtUQ29sdW1uXVtdXG4gICAgICA6IEV4dHJhY3RDb2x1bW5UeXBlPFRUYWJsZXMsIFRDb2x1bW4gJiBzdHJpbmc+W10sXG4gICAgbmV2ZXJcbiAgPiB7XG4gICAgdGhpcy5rbmV4UXVlcnkucGx1Y2soY29sdW1uIGFzIHN0cmluZyk7XG4gICAgcmV0dXJuIG5ldyBSZXNvbHZlZFB1cmkodGhpcy5rbmV4UXVlcnksIHRoaXMua25leCk7XG4gIH1cblxuICAvLyBJTlNFUlQgOiDri6jsnbwg6rCd7LK0XG4gIGluc2VydChcbiAgICBkYXRhOiBJbnNlcnREYXRhPFNpbmdsZVRhYmxlVmFsdWU8VFRhYmxlcz4+LFxuICApOiBSZXNvbHZlZFB1cmk8SW5zZXJ0UmVzdWx0LCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PjtcbiAgLy8gSU5TRVJUOiDrsLDsl7RcbiAgaW5zZXJ0KFxuICAgIGRhdGE6IEluc2VydERhdGE8U2luZ2xlVGFibGVWYWx1ZTxUVGFibGVzPj5bXSxcbiAgKTogUmVzb2x2ZWRQdXJpPEluc2VydFJlc3VsdCwgU2luZ2xlVGFibGVWYWx1ZTxUVGFibGVzPj47XG4gIC8vIElOU0VSVCDsi6TsoJwg6rWs7ZiEXG4gIGluc2VydChcbiAgICByYXdEYXRhOiBJbnNlcnREYXRhPFNpbmdsZVRhYmxlVmFsdWU8VFRhYmxlcz4+IHwgSW5zZXJ0RGF0YTxTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PltdLFxuICApOiBSZXNvbHZlZFB1cmk8SW5zZXJ0UmVzdWx0LCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgLy8gSlNPTiDsu6zrn7wgc3RyaW5naWZ5IOuhnOyngeydhCDrqZTshJzrk5zroZwg67aE66as7ZWY7JesIOykkeuztSDsoJzqsbBcbiAgICBjb25zdCByZWZpbmVkRGF0YSA9IHRoaXMucmVmaW5lSnNvbkNvbHVtbnMocmF3RGF0YSk7XG4gICAgdGhpcy5rbmV4UXVlcnkuaW5zZXJ0KHJlZmluZWREYXRhKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxuXG4gIC8vIFVQREFURVxuICB1cGRhdGUocmF3RGF0YTogV2hlcmVDb25kaXRpb248VFRhYmxlcz4pOiBSZXNvbHZlZFB1cmk8bnVtYmVyLCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgLy8gSlNPTiDsu6zrn7wgc3RyaW5naWZ5IOuhnOyngeydhCDrqZTshJzrk5zroZwg67aE66as7ZWY7JesIOykkeuztSDsoJzqsbBcbiAgICBjb25zdCByZWZpbmVkRGF0YSA9IHRoaXMucmVmaW5lSnNvbkNvbHVtbnMocmF3RGF0YSk7XG4gICAgdGhpcy5rbmV4UXVlcnkudXBkYXRlKHJlZmluZWREYXRhKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBKU09OIOy7rOufvOyXkCDrjIDtlbQgc3RyaW5naWZ5IOyymOumrOulvCDsiJjtlontlZjripQg64K067aAIOuplOyEnOuTnOyeheuLiOuLpC5cbiAgICogb2JqZWN0IOuYkOuKlCBvYmplY3Qg67Cw7Je07J2EIOuwm+qzoCwgSlNPTiDsu6zrn7zsnbQg7J6I7Jy866m0IOyngeugrO2ZlO2VmOyXrCDrsJjtmZjtlanri4jri6QuXG4gICAqIOyngeygkSDqsJLsnYQg67OA6rK97ZWY66+A66GcIHNpZGUgZWZmZWN06rCAIOyeiOyKteuLiOuLpC5cbiAgICovXG4gIHByaXZhdGUgcmVmaW5lSnNvbkNvbHVtbnMoXG4gICAgZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdLFxuICApOiB0eXBlb2YgZGF0YSB7XG4gICAgLy8gdGFibGVTcGVj7J2064KYIGpzb25Db2x1bW5zIOyXhuuKlCDqsr3smrAg67CU66GcIOuwmO2ZmFxuICAgIGlmICghdGhpcy50YWJsZVNwZWMgfHwgIXRoaXMudGFibGVTcGVjLmpzb25Db2x1bW5zLmxlbmd0aCkge1xuICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfVxuXG4gICAgLy8g65Ox66Gd65CcIFRhYmxlU3BlY+ydhCDthrXtlbQgSlNPTuy7rOufvCDrqqnroZ3snYQg6rCA7KC47JmAIEpTT04uc3RyaW5naWZ5IOyymOumrFxuICAgIGNvbnN0IGpzb25Db2x1bW5zID0gdGhpcy50YWJsZVNwZWMuanNvbkNvbHVtbnM7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkoZGF0YSkpIHtcbiAgICAgIGZvciAoY29uc3QgaXRlbSBvZiBkYXRhKSB7XG4gICAgICAgIGZvciAoY29uc3QgY29sdW1uIG9mIGpzb25Db2x1bW5zKSB7XG4gICAgICAgICAgY29uc3QgdmFsdWUgPSBpdGVtW2NvbHVtbl07XG4gICAgICAgICAgaWYgKHZhbHVlICE9PSB1bmRlZmluZWQgJiYgdmFsdWUgIT09IG51bGwpIHtcbiAgICAgICAgICAgIGl0ZW1bY29sdW1uXSA9IEpTT04uc3RyaW5naWZ5KHZhbHVlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgZm9yIChjb25zdCBjb2x1bW4gb2YganNvbkNvbHVtbnMpIHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSBkYXRhW2NvbHVtbl07XG4gICAgICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkICYmIHZhbHVlICE9PSBudWxsKSB7XG4gICAgICAgICAgZGF0YVtjb2x1bW5dID0gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBkYXRhO1xuICB9XG5cbiAgLy8gSW5jcmVtZW50XG4gIGluY3JlbWVudDxUQ29sdW1uIGV4dGVuZHMgTnVtZXJpY0NvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogbnVtYmVyLFxuICApOiBSZXNvbHZlZFB1cmk8bnVtYmVyLCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgaWYgKHZhbHVlIDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkluY3JlbWVudCB2YWx1ZSBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwXCIpO1xuICAgIH1cbiAgICB0aGlzLmtuZXhRdWVyeS5pbmNyZW1lbnQoY29sdW1uLCB2YWx1ZSk7XG4gICAgcmV0dXJuIG5ldyBSZXNvbHZlZFB1cmkodGhpcy5rbmV4UXVlcnksIHRoaXMua25leCk7XG4gIH1cbiAgLy8gRGVjcmVtZW50XG4gIGRlY3JlbWVudDxUQ29sdW1uIGV4dGVuZHMgTnVtZXJpY0NvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogbnVtYmVyLFxuICApOiBSZXNvbHZlZFB1cmk8bnVtYmVyLCBTaW5nbGVUYWJsZVZhbHVlPFRUYWJsZXM+PiB7XG4gICAgaWYgKHZhbHVlIDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkRlY3JlbWVudCB2YWx1ZSBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwXCIpO1xuICAgIH1cbiAgICB0aGlzLmtuZXhRdWVyeS5kZWNyZW1lbnQoY29sdW1uLCB2YWx1ZSk7XG4gICAgcmV0dXJuIG5ldyBSZXNvbHZlZFB1cmkodGhpcy5rbmV4UXVlcnksIHRoaXMua25leCk7XG4gIH1cblxuICAvLyBERUxFVEVcbiAgZGVsZXRlKCk6IFJlc29sdmVkUHVyaTxudW1iZXIsIFNpbmdsZVRhYmxlVmFsdWU8VFRhYmxlcz4+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS5kZWxldGUoKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxuXG4gIC8vIO2ZleyduCDsv7zrpqwg66as7YS0XG4gIHRvUXVlcnkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkudG9RdWVyeSgpO1xuICB9XG5cbiAgLy8g7L+866asIOuUlOuyhOq5hSDroZzqt7gg7Lac66ClXG4gIGRlYnVnKCk6IHRoaXMge1xuICAgIGNvbnNvbGUubG9nKGAke2NoYWxrLmN5YW4oXCJbUHVyaSBEZWJ1Z11cIil9ICR7Y2hhbGsueWVsbG93KHRoaXMudG9RdWVyeSgpKX1gKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGNsb25lKCk6IFB1cmk8VFNjaGVtYSwgVFRhYmxlcywgVFJlc3VsdD4ge1xuICAgIC8vICdkdWFsJ+ydgCDrjZTrr7gg7YWM7J2067iU7J2066mwLCDrsJTroZwg7JWE656YIOykhOyXkOyEnCBrbmV4UXVlcnnqsIAg642u7Ja07JSM7JuM7KeR64uI64ukLlxuICAgIGNvbnN0IG5ld1B1cmkgPSBuZXcgUHVyaTxUU2NoZW1hLCBUVGFibGVzLCBUUmVzdWx0Pih0aGlzLmtuZXgsIFwiZHVhbFwiKTtcbiAgICBuZXdQdXJpLmtuZXhRdWVyeSA9IHRoaXMua25leFF1ZXJ5LmNsb25lKCk7XG4gICAgcmV0dXJuIG5ld1B1cmk7XG4gIH1cblxuICBmb3JtYXRTUUwodW5mb3JtYXR0ZWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgLy8gU1FMIOyYiOyVveyWtCDrqqnroZ1cbiAgICBjb25zdCBrZXl3b3JkcyA9IFtcbiAgICAgIFwiU0VMRUNUXCIsXG4gICAgICBcIkZST01cIixcbiAgICAgIFwiV0hFUkVcIixcbiAgICAgIFwiSU5TRVJUXCIsXG4gICAgICBcIklOVE9cIixcbiAgICAgIFwiVkFMVUVTXCIsXG4gICAgICBcIlVQREFURVwiLFxuICAgICAgXCJERUxFVEVcIixcbiAgICAgIFwiQ1JFQVRFXCIsXG4gICAgICBcIlRBQkxFXCIsXG4gICAgICBcIkFMVEVSXCIsXG4gICAgICBcIkRST1BcIixcbiAgICAgIFwiSk9JTlwiLFxuICAgICAgXCJPTlwiLFxuICAgICAgXCJJTk5FUlwiLFxuICAgICAgXCJMRUZUXCIsXG4gICAgICBcIlJJR0hUXCIsXG4gICAgICBcIkZVTExcIixcbiAgICAgIFwiT1VURVJcIixcbiAgICAgIFwiR1JPVVBcIixcbiAgICAgIFwiQllcIixcbiAgICAgIFwiT1JERVJcIixcbiAgICAgIFwiSEFWSU5HXCIsXG4gICAgICBcIkRJU1RJTkNUXCIsXG4gICAgICBcIkxJTUlUXCIsXG4gICAgICBcIk9GRlNFVFwiLFxuICAgICAgXCJBU1wiLFxuICAgICAgXCJBTkRcIixcbiAgICAgIFwiT1JcIixcbiAgICAgIFwiTk9UXCIsXG4gICAgICBcIklOXCIsXG4gICAgICBcIkxJS0VcIixcbiAgICAgIFwiSVNcIixcbiAgICAgIFwiTlVMTFwiLFxuICAgICAgXCJDQVNFXCIsXG4gICAgICBcIldIRU5cIixcbiAgICAgIFwiVEhFTlwiLFxuICAgICAgXCJFTFNFXCIsXG4gICAgICBcIkVORFwiLFxuICAgICAgXCJVTklPTlwiLFxuICAgICAgXCJBTExcIixcbiAgICAgIFwiRVhJU1RTXCIsXG4gICAgICBcIkJFVFdFRU5cIixcbiAgICBdO1xuXG4gICAgbGV0IGZvcm1hdHRlZCA9IHVuZm9ybWF0dGVkO1xuXG4gICAgLy8g7JiI7JW97Ja066W8IOuMgOusuOyekOuhnCDrs4DtmZhcbiAgICBrZXl3b3Jkcy5mb3JFYWNoKChrZXl3b3JkKSA9PiB7XG4gICAgICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoYFxcXFxiJHtrZXl3b3JkfVxcXFxiYCwgXCJnaVwiKTtcbiAgICAgIGZvcm1hdHRlZCA9IGZvcm1hdHRlZC5yZXBsYWNlKHJlZ2V4LCBrZXl3b3JkLnRvVXBwZXJDYXNlKCkpO1xuICAgIH0pO1xuXG4gICAgLy8g7KO87JqUIOygiCDslZ7sl5Ag7KSE67CU6r+IIOy2lOqwgFxuICAgIGNvbnN0IG1ham9yQ2xhdXNlcyA9IFtcbiAgICAgIFwiU0VMRUNUXCIsXG4gICAgICBcIkZST01cIixcbiAgICAgIFwiV0hFUkVcIixcbiAgICAgIFwiR1JPVVAgQllcIixcbiAgICAgIFwiT1JERVIgQllcIixcbiAgICAgIFwiSEFWSU5HXCIsXG4gICAgICBcIkxJTUlUXCIsXG4gICAgICBcIlVOSU9OXCIsXG4gICAgXTtcbiAgICBtYWpvckNsYXVzZXMuZm9yRWFjaCgoY2xhdXNlKSA9PiB7XG4gICAgICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoYFxcXFxzKygke2NsYXVzZX0pXFxcXHMrYCwgXCJnaVwiKTtcbiAgICAgIGZvcm1hdHRlZCA9IGZvcm1hdHRlZC5yZXBsYWNlKHJlZ2V4LCBgXFxuJHtjbGF1c2UudG9VcHBlckNhc2UoKX0gYCk7XG4gICAgfSk7XG5cbiAgICAvLyBKT0lOIOygiCDsspjrpqxcbiAgICBmb3JtYXR0ZWQgPSBmb3JtYXR0ZWQucmVwbGFjZSgvXFxzKygoPzpJTk5FUnxMRUZUfFJJR0hUfEZVTEwgT1VURVIpXFxzKyk/Sk9JTlxccysvZ2ksIFwiXFxuJDFKT0lOIFwiKTtcblxuICAgIC8vIEFORCwgT1Ig7KGw6rG0IOyymOumrFxuICAgIGZvcm1hdHRlZCA9IGZvcm1hdHRlZC5yZXBsYWNlKC9cXHMrKEFORHxPUilcXHMrL2dpLCBcIlxcbiAgJDEgXCIpO1xuXG4gICAgLy8g6rSE7Zi4IOyymOumrCDrsI8g65Ok7Jes7JOw6riwXG4gICAgY29uc3QgbGluZXMgPSBmb3JtYXR0ZWQuc3BsaXQoXCJcXG5cIik7XG4gICAgY29uc3QgaW5kZW50ZWRMaW5lcyA9IFtdO1xuICAgIGxldCBpbmRlbnRMZXZlbCA9IDA7XG5cbiAgICBmb3IgKGNvbnN0IGxpbmUgb2YgbGluZXMpIHtcbiAgICAgIGNvbnN0IHRyaW1tZWRMaW5lID0gbGluZS50cmltKCk7XG4gICAgICBpZiAoIXRyaW1tZWRMaW5lKSBjb250aW51ZTtcblxuICAgICAgLy8g64ur64qUIOq0hO2YuOqwgCDsnojsnLzrqbQg65Ok7Jes7JOw6riwIOugiOuyqCDqsJDshoxcbiAgICAgIGNvbnN0IGNsb3NpbmdQYXJlbnMgPSAodHJpbW1lZExpbmUubWF0Y2goL1xcKS9nKSB8fCBbXSkubGVuZ3RoO1xuICAgICAgY29uc3Qgb3BlbmluZ1BhcmVucyA9ICh0cmltbWVkTGluZS5tYXRjaCgvXFwoL2cpIHx8IFtdKS5sZW5ndGg7XG5cbiAgICAgIGlmIChjbG9zaW5nUGFyZW5zID4gMCAmJiBvcGVuaW5nUGFyZW5zID09PSAwKSB7XG4gICAgICAgIGluZGVudExldmVsID0gTWF0aC5tYXgoMCwgaW5kZW50TGV2ZWwgLSBjbG9zaW5nUGFyZW5zKTtcbiAgICAgIH1cblxuICAgICAgLy8g7ZiE7J6sIOuTpOyXrOyTsOq4sCDsoIHsmqlcbiAgICAgIGNvbnN0IGluZGVudCA9IFwiICBcIi5yZXBlYXQoaW5kZW50TGV2ZWwpO1xuICAgICAgaW5kZW50ZWRMaW5lcy5wdXNoKGluZGVudCArIHRyaW1tZWRMaW5lKTtcblxuICAgICAgLy8g7Jes64qUIOq0hO2YuOqwgCDsnojsnLzrqbQg65Ok7Jes7JOw6riwIOugiOuyqCDspp3qsIBcbiAgICAgIGlmIChvcGVuaW5nUGFyZW5zID4gY2xvc2luZ1BhcmVucykge1xuICAgICAgICBpbmRlbnRMZXZlbCArPSBvcGVuaW5nUGFyZW5zIC0gY2xvc2luZ1BhcmVucztcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gaW5kZW50ZWRMaW5lcy5qb2luKFwiXFxuXCIpLnRyaW0oKTtcbiAgfVxuXG4gIHJhdyhzcWw6IHN0cmluZyk6IEtuZXguUmF3IHtcbiAgICByZXR1cm4gdGhpcy5rbmV4LnJhdyhzcWwpO1xuICB9XG5cbiAgLy8gS25leCDsv7zrpqwg67mM642UIOyngeygkSDsoJHqt7xcbiAgcmF3UXVlcnkoKTogS25leC5RdWVyeUJ1aWxkZXIge1xuICAgIHJldHVybiB0aGlzLmtuZXhRdWVyeTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgV2hlcmVHcm91cDxUVGFibGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGJ1aWxkZXI6IEtuZXguUXVlcnlCdWlsZGVyKSB7fVxuXG4gIC8vIHdoZXJlIOuplOyEnOuTnOuTpFxuICB3aGVyZShjb25kaXRpb25zOiBXaGVyZUNvbmRpdGlvbjxUVGFibGVzPik6IHRoaXM7XG4gIHdoZXJlPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWU6IEV4dHJhY3RDb2x1bW5UeXBlPFRUYWJsZXMsIFRDb2x1bW4gJiBzdHJpbmc+LFxuICApOiB0aGlzO1xuICB3aGVyZTxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIG9wZXJhdG9yOiBXaGVyZU9wZXJhdG9yLFxuICAgIHZhbHVlOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgd2hlcmUoLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIud2hlcmUoYXJnc1swXSwgLi4uYXJncy5zbGljZSgxKSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyB3aGVyZUluIC8gd2hlcmVOb3RJbiDrqZTshJzrk5zrk6RcbiAgd2hlcmVJbjxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIHZhbHVlczogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz5bXSxcbiAgKTogdGhpcztcbiAgd2hlcmVJbiguLi5hcmdzOiBhbnlbXSk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci53aGVyZUluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgd2hlcmVOb3RJbjxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uLFxuICAgIHZhbHVlczogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz5bXSxcbiAgKTogdGhpcztcbiAgd2hlcmVOb3RJbiguLi5hcmdzOiBhbnlbXSk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci53aGVyZU5vdEluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gb3JXaGVyZSDrqZTshJzrk5zrk6RcbiAgb3JXaGVyZShjb25kaXRpb25zOiBXaGVyZUNvbmRpdGlvbjxUVGFibGVzPik6IHRoaXM7XG4gIG9yV2hlcmU8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIG9yV2hlcmU8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICBvcGVyYXRvcjogV2hlcmVPcGVyYXRvcixcbiAgICB2YWx1ZTogRXh0cmFjdENvbHVtblR5cGU8VFRhYmxlcywgVENvbHVtbiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIG9yV2hlcmUoLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZShhcmdzWzBdLCAuLi5hcmdzLnNsaWNlKDEpKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIG9yV2hlcmVJbiAvIG9yV2hlcmVOb3RJbiDrqZTshJzrk5zrk6RcbiAgb3JXaGVyZUluPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWVzOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPltdLFxuICApOiB0aGlzO1xuICBvcldoZXJlSW4oLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZUluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgb3JXaGVyZU5vdEluPFRDb2x1bW4gZXh0ZW5kcyBBdmFpbGFibGVDb2x1bW5zPFRUYWJsZXM+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWVzOiBFeHRyYWN0Q29sdW1uVHlwZTxUVGFibGVzLCBUQ29sdW1uICYgc3RyaW5nPltdLFxuICApOiB0aGlzO1xuICBvcldoZXJlTm90SW4oLi4uYXJnczogYW55W10pOiBXaGVyZUdyb3VwPFRUYWJsZXM+IHtcbiAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZU5vdEluKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gV0hFUkUgTUFUQ0hcbiAgd2hlcmVNYXRjaDxUQ29sdW1uIGV4dGVuZHMgRnVsbHRleHRDb2x1bW5zPFRUYWJsZXM+Pihjb2x1bW46IFRDb2x1bW4sIHZhbHVlOiBzdHJpbmcpOiB0aGlzO1xuICB3aGVyZU1hdGNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgdGhpcy5idWlsZGVyLndoZXJlUmF3KGBNQVRDSCAoJHtTdHJpbmcoYXJnc1swXSl9KSBBR0FJTlNUICg/KWAsIFthcmdzWzFdXSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBvcldoZXJlTWF0Y2g8VENvbHVtbiBleHRlbmRzIEZ1bGx0ZXh0Q29sdW1uczxUVGFibGVzPj4oY29sdW1uOiBUQ29sdW1uLCB2YWx1ZTogc3RyaW5nKTogdGhpcztcbiAgb3JXaGVyZU1hdGNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgdGhpcy5idWlsZGVyLm9yV2hlcmVSYXcoYE1BVENIICgke1N0cmluZyhhcmdzWzBdKX0pIEFHQUlOU1QgKD8pYCwgW2FyZ3NbMV1dKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIFdIRVJFIFNFQVJDSFxuICB3aGVyZVNlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uIHwgVENvbHVtbltdLFxuICAgIHZhbHVlOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHtcbiAgICAgIHdlaWdodHM/OiBudW1iZXJbXTsgLy8g7KCV7IiYIOuwsOyXtFxuICAgIH0sXG4gICk6IHRoaXM7XG4gIHdoZXJlU2VhcmNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgY29uc3QgeyB3ZWlnaHRzIH0gPSBhcmdzWzJdID8/IHt9O1xuICAgIGNvbnN0IGNvbHVtbkV4cHIgPSBBcnJheS5pc0FycmF5KGFyZ3NbMF0pXG4gICAgICA/IGBBUlJBWVske2FyZ3NbMF0ubWFwKChjKSA9PiBgJHtjfTo6dGV4dGApLmpvaW4oXCIsXCIpfV1gXG4gICAgICA6IGFyZ3NbMF07XG4gICAgY29uc3QgcGdyb29uZ2FDb25kaXRpb24gPSBgcGdyb29uZ2FfY29uZGl0aW9uKD8ke3dlaWdodHM/Lmxlbmd0aCA/IGAsIHdlaWdodHMgPT4gQVJSQVlbJHt3ZWlnaHRzLmpvaW4oXCIsXCIpfV1gIDogXCJcIn0pYDtcbiAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYCR7Y29sdW1uRXhwcn0gJkB+ICR7cGdyb29uZ2FDb25kaXRpb259YCwgW2FyZ3NbMV1dKTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgb3JXaGVyZVNlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPj4oXG4gICAgY29sdW1uOiBUQ29sdW1uIHwgVENvbHVtbltdLFxuICAgIHZhbHVlOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHtcbiAgICAgIHdlaWdodHM/OiBudW1iZXJbXTsgLy8g7KCV7IiYIOuwsOyXtFxuICAgIH0sXG4gICk6IHRoaXM7XG4gIG9yV2hlcmVTZWFyY2goLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICBjb25zdCB7IHdlaWdodHMgfSA9IGFyZ3NbMl0gPz8ge307XG4gICAgY29uc3QgY29sdW1uRXhwciA9IEFycmF5LmlzQXJyYXkoYXJnc1swXSlcbiAgICAgID8gYEFSUkFZWyR7YXJnc1swXS5tYXAoKGMpID0+IGAke2N9Ojp0ZXh0YCkuam9pbihcIixcIil9XWBcbiAgICAgIDogYXJnc1swXTtcbiAgICBjb25zdCBwZ3Jvb25nYUNvbmRpdGlvbiA9IGBwZ3Jvb25nYV9jb25kaXRpb24oPyR7d2VpZ2h0cz8ubGVuZ3RoID8gYCwgd2VpZ2h0cyA9PiBBUlJBWVske3dlaWdodHMuam9pbihcIixcIil9XWAgOiBcIlwifSlgO1xuICAgIHRoaXMuYnVpbGRlci5vcldoZXJlUmF3KGAke2NvbHVtbkV4cHJ9ICZAfiAke3Bncm9vbmdhQ29uZGl0aW9ufWAsIFthcmdzWzFdXSk7XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIFdIRVJFIEZVTExURVhUXG4gIHdoZXJlVHNTZWFyY2g8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4gfCBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICBvcHRpb25zPzogVHNRdWVyeU9wdGlvbnMgfCBUc1F1ZXJ5Q29uZmlnLFxuICApOiB0aGlzO1xuICB3aGVyZVRzU2VhcmNoKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgY29uc3Qgb3B0cyA9XG4gICAgICB0eXBlb2YgYXJnc1syXSA9PT0gXCJzdHJpbmdcIiA/ICh7IGNvbmZpZzogYXJnc1syXSB9IGFzIFRzUXVlcnlPcHRpb25zKSA6IChhcmdzWzJdID8/IHt9KTtcblxuICAgIGNvbnN0IHBhcnNlciA9IG9wdHMucGFyc2VyID8/IFwid2Vic2VhcmNoX3RvX3RzcXVlcnlcIjtcbiAgICBjb25zdCBjb25maWcgPSBvcHRzLmNvbmZpZyA/PyBcInNpbXBsZVwiO1xuICAgIGNvbnN0IGNvbHVtbkV4cHIgPVxuICAgICAgdHlwZW9mIGFyZ3NbMF0gPT09IFwib2JqZWN0XCIgJiYgYXJnc1swXS5fdHlwZSA9PT0gXCJzcWxfZXhwcmVzc2lvblwiXG4gICAgICAgID8gYXJnc1swXS5fc3FsXG4gICAgICAgIDogU3RyaW5nKGFyZ3NbMF0pO1xuXG4gICAgdGhpcy5idWlsZGVyLndoZXJlUmF3KGAke2NvbHVtbkV4cHJ9IEBAICR7cGFyc2VyfSg/LCA/KWAsIFtjb25maWcsIGFyZ3NbMV1dKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIG9yV2hlcmVUc1NlYXJjaDxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPiB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBUc1F1ZXJ5T3B0aW9ucyB8IFRzUXVlcnlDb25maWcsXG4gICk6IHRoaXM7XG4gIG9yV2hlcmVUc1NlYXJjaCguLi5hcmdzOiBhbnlbXSk6IHRoaXMge1xuICAgIGNvbnN0IG9wdHMgPVxuICAgICAgdHlwZW9mIGFyZ3NbMl0gPT09IFwic3RyaW5nXCIgPyAoeyBjb25maWc6IGFyZ3NbMl0gfSBhcyBUc1F1ZXJ5T3B0aW9ucykgOiAoYXJnc1syXSA/PyB7fSk7XG5cbiAgICBjb25zdCBwYXJzZXIgPSBvcHRzLnBhcnNlciA/PyBcIndlYnNlYXJjaF90b190c3F1ZXJ5XCI7XG4gICAgY29uc3QgY29uZmlnID0gb3B0cy5jb25maWcgPz8gXCJzaW1wbGVcIjtcbiAgICBjb25zdCBjb2x1bW5FeHByID1cbiAgICAgIHR5cGVvZiBhcmdzWzBdID09PSBcIm9iamVjdFwiICYmIGFyZ3NbMF0uX3R5cGUgPT09IFwic3FsX2V4cHJlc3Npb25cIlxuICAgICAgICA/IGFyZ3NbMF0uX3NxbFxuICAgICAgICA6IFN0cmluZyhhcmdzWzBdKTtcblxuICAgIHRoaXMuYnVpbGRlci5vcldoZXJlUmF3KGAke2NvbHVtbkV4cHJ9IEBAICR7cGFyc2VyfSg/LCA/KWAsIFtjb25maWcsIGFyZ3NbMV1dKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHdoZXJlRnV6enk8VENvbHVtbiBleHRlbmRzIEF2YWlsYWJsZUNvbHVtbnM8VFRhYmxlcz4gfCBTcWxFeHByZXNzaW9uPFwic3RyaW5nXCI+PihcbiAgICBjb2x1bW46IFRDb2x1bW4sXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICBvcHRpb25zPzoge1xuICAgICAgb3BlcmF0b3I/OiBGdXp6eU9wZXJhdG9yO1xuICAgIH0sXG4gICk6IHRoaXM7XG4gIHdoZXJlRnV6enkoLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICBjb25zdCBvcGVyYXRvciA9IG5vcm1hbGl6ZUZ1enp5T3BlcmF0b3IoYXJnc1syXT8ub3BlcmF0b3IpO1xuXG4gICAgaWYgKG9wZXJhdG9yID09PSBcIiVcIikge1xuICAgICAgaWYgKHR5cGVvZiBhcmdzWzBdID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgIHRoaXMuYnVpbGRlci53aGVyZVJhdyhgJHthcmdzWzBdLl9zcWx9ICR7b3BlcmF0b3J9ID9gLCBbLi4uYXJnc1swXS5fcGFyYW1zLCBhcmdzWzFdXSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYD8/ICR7b3BlcmF0b3J9ID9gLCBbYXJnc1swXSwgYXJnc1sxXV0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBhcmdzWzBdID09PSBcIm9iamVjdFwiKSB7XG4gICAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYD8gJHtvcGVyYXRvcn0gJHthcmdzWzBdLl9zcWx9YCwgW2FyZ3NbMV0sIC4uLmFyZ3NbMF0uX3BhcmFtc10pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmJ1aWxkZXIud2hlcmVSYXcoYD8gJHtvcGVyYXRvcn0gPz9gLCBbYXJnc1sxXSwgYXJnc1swXV0pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIG9yV2hlcmVGdXp6eTxUQ29sdW1uIGV4dGVuZHMgQXZhaWxhYmxlQ29sdW1uczxUVGFibGVzPiB8IFNxbEV4cHJlc3Npb248XCJzdHJpbmdcIj4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgICB2YWx1ZTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7XG4gICAgICBvcGVyYXRvcj86IEZ1enp5T3BlcmF0b3I7XG4gICAgfSxcbiAgKTogdGhpcztcbiAgb3JXaGVyZUZ1enp5KC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgY29uc3Qgb3BlcmF0b3IgPSBub3JtYWxpemVGdXp6eU9wZXJhdG9yKGFyZ3NbMl0/Lm9wZXJhdG9yKTtcblxuICAgIGlmIChvcGVyYXRvciA9PT0gXCIlXCIpIHtcbiAgICAgIGlmICh0eXBlb2YgYXJnc1swXSA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZVJhdyhgJHthcmdzWzBdLl9zcWx9ICR7b3BlcmF0b3J9ID9gLCBbLi4uYXJnc1swXS5fcGFyYW1zLCBhcmdzWzFdXSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmJ1aWxkZXIub3JXaGVyZVJhdyhgPz8gJHtvcGVyYXRvcn0gP2AsIFthcmdzWzBdLCBhcmdzWzFdXSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGFyZ3NbMF0gPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRoaXMuYnVpbGRlci5vcldoZXJlUmF3KGA/ICR7b3BlcmF0b3J9ICR7YXJnc1swXS5fc3FsfWAsIFthcmdzWzFdLCAuLi5hcmdzWzBdLl9wYXJhbXNdKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5idWlsZGVyLm9yV2hlcmVSYXcoYD8gJHtvcGVyYXRvcn0gPz9gLCBbYXJnc1sxXSwgYXJnc1swXV0pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIOykkeyyqSDqt7jro7lcbiAgd2hlcmVHcm91cChjYWxsYmFjazogKGc6IFdoZXJlR3JvdXA8VFRhYmxlcz4pID0+IHZvaWQpOiB0aGlzO1xuICB3aGVyZUdyb3VwKGNhbGxiYWNrOiAoZzogV2hlcmVHcm91cDxUVGFibGVzPikgPT4gdm9pZCk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci53aGVyZSgoc3ViQnVpbGRlcikgPT4ge1xuICAgICAgY29uc3Qgc3ViR3JvdXAgPSBuZXcgV2hlcmVHcm91cDxUVGFibGVzPihzdWJCdWlsZGVyKTtcbiAgICAgIGNhbGxiYWNrKHN1Ykdyb3VwKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBvcldoZXJlR3JvdXAoY2FsbGJhY2s6IChnOiBXaGVyZUdyb3VwPFRUYWJsZXM+KSA9PiB2b2lkKTogdGhpcztcbiAgb3JXaGVyZUdyb3VwKGNhbGxiYWNrOiAoZzogV2hlcmVHcm91cDxUVGFibGVzPikgPT4gdm9pZCk6IFdoZXJlR3JvdXA8VFRhYmxlcz4ge1xuICAgIHRoaXMuYnVpbGRlci5vcldoZXJlKChzdWJCdWlsZGVyKSA9PiB7XG4gICAgICBjb25zdCBzdWJHcm91cCA9IG5ldyBXaGVyZUdyb3VwPFRUYWJsZXM+KHN1YkJ1aWxkZXIpO1xuICAgICAgY2FsbGJhY2soc3ViR3JvdXApO1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG5cbi8vIEpPSU4g7KCIIOq3uOujueyXkOuKlCBMZWZ07JmAIFJpZ2h07JeQIOuMgO2VnCDsiJzshJzqsIAg7ZWE7JqU7ZWY7KeAIOyViuycvOuvgOuhnCwg66qo65OgIOqyveyasOydmCDsiJjrpbwg6rOE7IKw7ZW07JW87ZWoLlxuZXhwb3J0IGNsYXNzIEpvaW5DbGF1c2VHcm91cDxcbiAgVExlZnQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICBUUmlnaHQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuPiB7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgY2FsbGJhY2s6IEtuZXguSm9pbkNsYXVzZSkge31cblxuICAvLyBPTihBTkQpOiDsu6zrn7wgPSDsu6zrn7xcbiAgb24obGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4pOiB0aGlzO1xuICBvbihsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0Pik6IHRoaXM7XG4gIC8vIE9OKEFORCk6IOy7rOufvCA9IOqwklxuICBvbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0PixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICAgIHJpZ2h0OiBFeHRyYWN0Q29sdW1uVHlwZTxUUmlnaHQsIEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiAmIHN0cmluZz4sXG4gICk6IHRoaXM7XG4gIC8vIE9OKEFORCk6IOy7rOufvCAo7Jew7IKw7J6QKSDsu6zrn7xcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICApOiB0aGlzO1xuICBvbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICk6IHRoaXM7XG4gIC8vIE9OKEFORCk6IOy7rOufvCAo7Jew7IKw7J6QKSDqsJJcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICAgIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsXG4gICAgcmlnaHQ6IEV4dHJhY3RDb2x1bW5UeXBlPFRSaWdodCwgQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgLy8gT04oQU5EKTog7L2c67CxXG4gIG9uKGNhbGxiYWNrOiAobmVzdGVkOiBKb2luQ2xhdXNlR3JvdXA8VExlZnQsIFRSaWdodD4pID0+IHZvaWQpOiB0aGlzO1xuICBvbihjYWxsYmFjazogKG5lc3RlZDogSm9pbkNsYXVzZUdyb3VwPFRSaWdodCwgVExlZnQ+KSA9PiB2b2lkKTogdGhpcztcbiAgLy8gT04oQU5EKSDqtaztmIRcbiAgb24oLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICB0aGlzLmNhbGxiYWNrLm9uKC4uLihhcmdzIGFzIFtzdHJpbmcsIHN0cmluZ10pKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIE9OKE9SKTog7Lus65+8ID0g7Lus65+8XG4gIG9yT24obGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4pOiB0aGlzO1xuICBvck9uKGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgcmlnaHQ6IEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+KTogdGhpcztcbiAgLy8gT04oT1IpOiDsu6zrn7wgPSDqsJJcbiAgb3JPbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0PixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb3JPbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sXG4gICAgcmlnaHQ6IEV4dHJhY3RDb2x1bW5UeXBlPFRSaWdodCwgQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgLy8gT04oT1IpOiDsu6zrn7wgKOyXsOyCsOyekCkg7Lus65+8XG4gIG9yT24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogQXZhaWxhYmxlQ29sdW1uczxUUmlnaHQ+LFxuICApOiB0aGlzO1xuICBvck9uKFxuICAgIGxlZnQ6IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PixcbiAgICBvcGVyYXRvcjogQ29tcGFyaXNvbk9wZXJhdG9yLFxuICAgIHJpZ2h0OiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0PixcbiAgKTogdGhpcztcbiAgLy8gT04oT1IpOiDsu6zrn7wgKOyXsOyCsOyekCkg6rCSXG4gIG9yT24oXG4gICAgbGVmdDogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VExlZnQsIEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+ICYgc3RyaW5nPixcbiAgKTogdGhpcztcbiAgb3JPbihcbiAgICBsZWZ0OiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sXG4gICAgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvcixcbiAgICByaWdodDogRXh0cmFjdENvbHVtblR5cGU8VFJpZ2h0LCBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4gJiBzdHJpbmc+LFxuICApOiB0aGlzO1xuICAvLyBPTihPUik6IOy9nOuwsVxuICBvck9uKGNhbGxiYWNrOiAobmVzdGVkOiBKb2luQ2xhdXNlR3JvdXA8VExlZnQsIFRSaWdodD4pID0+IHZvaWQpOiB0aGlzO1xuICBvck9uKGNhbGxiYWNrOiAobmVzdGVkOiBKb2luQ2xhdXNlR3JvdXA8VFJpZ2h0LCBUTGVmdD4pID0+IHZvaWQpOiB0aGlzO1xuICAvLyBPTihPUikg6rWs7ZiEXG4gIG9yT24oLi4uYXJnczogYW55W10pOiB0aGlzIHtcbiAgICB0aGlzLmNhbGxiYWNrLm9yT24oLi4uKGFyZ3MgYXMgW3N0cmluZywgc3RyaW5nXSkpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gT04gVkFMKEFORCk6IOy7rOufvCA9IOqwkiAo6rCS7J2EIOy7rOufvCDssLjsobDqsIAg7JWE64uMIO2MjOudvOuvuO2EsOuhnCDrsJTsnbjrlKkpXG4gIG9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBvblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBvblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0Piwgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvciwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9uVmFsKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgKHRoaXMuY2FsbGJhY2sgYXMgYW55KS5vblZhbCguLi5hcmdzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIEFORCBPTiBWQUw6IG9uVmFs7J2YIOuqheyLnOyggSBhbGlhcyAoS25leCDtmLjtmZgpXG4gIGFuZE9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBhbmRPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIGFuZE9uVmFsKGNvbHVtbjogQXZhaWxhYmxlQ29sdW1uczxUTGVmdD4sIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBhbmRPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0Piwgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvciwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIGFuZE9uVmFsKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgKHRoaXMuY2FsbGJhY2sgYXMgYW55KS5hbmRPblZhbCguLi5hcmdzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIE9SIE9OIFZBTDogT1Ig7KGw6rG07Jy866GcIOqwkiDrsJTsnbjrlKlcbiAgb3JPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VExlZnQ+LCB2YWx1ZTogYW55KTogdGhpcztcbiAgb3JPblZhbChjb2x1bW46IEF2YWlsYWJsZUNvbHVtbnM8VFJpZ2h0PiwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9yT25WYWwoY29sdW1uOiBBdmFpbGFibGVDb2x1bW5zPFRMZWZ0Piwgb3BlcmF0b3I6IENvbXBhcmlzb25PcGVyYXRvciwgdmFsdWU6IGFueSk6IHRoaXM7XG4gIG9yT25WYWwoY29sdW1uOiBBdmFpbGFibGVDb2x1bW5zPFRSaWdodD4sIG9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IsIHZhbHVlOiBhbnkpOiB0aGlzO1xuICBvck9uVmFsKC4uLmFyZ3M6IGFueVtdKTogdGhpcyB7XG4gICAgKHRoaXMuY2FsbGJhY2sgYXMgYW55KS5vck9uVmFsKC4uLmFyZ3MpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG5cbi8qXG4gIFRSZXNvbHZlZDog7L+866asIOyLpO2WiSDtm4Qg67CY7ZmY65CgIOqysOqzvCDtg4DsnoVcbiAgVFJldHVybmluZzogUkVUVVJOSU5HIOygiOyXkCDsgqzsmqnrkKAg7YOA7J6FXG4qL1xuZXhwb3J0IGNsYXNzIFJlc29sdmVkUHVyaTxUUmVzb2x2ZWQsIFRSZXR1cm5pbmc+IGltcGxlbWVudHMgUHJvbWlzZTxUUmVzb2x2ZWQ+IHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIGtuZXhRdWVyeTogS25leC5RdWVyeUJ1aWxkZXIsXG4gICAgcHJpdmF0ZSBrbmV4OiBLbmV4LFxuICApIHt9XG5cbiAgW1N5bWJvbC50b1N0cmluZ1RhZ106IHN0cmluZyA9IFwiUHJvbWlzZVwiO1xuXG4gIHRvUXVlcnkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkudG9RdWVyeSgpO1xuICB9XG5cbiAgZGVidWcoKTogdGhpcyB7XG4gICAgY29uc29sZS5sb2coYCR7Y2hhbGsuY3lhbihcIltQdXJpIERlYnVnXVwiKX0gJHtjaGFsay55ZWxsb3codGhpcy50b1F1ZXJ5KCkpfWApO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgdGhlbjxUUmVzdWx0MSA9IFRSZXNvbHZlZCwgVFJlc3VsdDIgPSBuZXZlcj4oXG4gICAgb25mdWxmaWxsZWQ/OiAoKHZhbHVlOiBUUmVzb2x2ZWQpID0+IFRSZXN1bHQxIHwgUHJvbWlzZUxpa2U8VFJlc3VsdDE+KSB8IG51bGwsXG4gICAgb25yZWplY3RlZD86ICgocmVhc29uOiBhbnkpID0+IFRSZXN1bHQyIHwgUHJvbWlzZUxpa2U8VFJlc3VsdDI+KSB8IG51bGwsXG4gICk6IFByb21pc2U8VFJlc3VsdDEgfCBUUmVzdWx0Mj4ge1xuICAgIE5haXRlLnQoXCJwdXJpOmV4ZWN1dGVkLXF1ZXJ5XCIsIHRoaXMudG9RdWVyeSgpKTtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkudGhlbihvbmZ1bGZpbGxlZCBhcyBhbnksIG9ucmVqZWN0ZWQpO1xuICB9XG5cbiAgY2F0Y2g8VFJlc3VsdDIgPSBuZXZlcj4oXG4gICAgb25yZWplY3RlZD86ICgocmVhc29uOiBhbnkpID0+IFRSZXN1bHQyIHwgUHJvbWlzZUxpa2U8VFJlc3VsdDI+KSB8IG51bGwsXG4gICk6IFByb21pc2U8VFJlc29sdmVkIHwgVFJlc3VsdDI+IHtcbiAgICByZXR1cm4gdGhpcy5rbmV4UXVlcnkuY2F0Y2gob25yZWplY3RlZCk7XG4gIH1cblxuICBmaW5hbGx5KG9uZmluYWxseT86ICgoKSA9PiB2b2lkKSB8IG51bGwpOiBQcm9taXNlPFRSZXNvbHZlZD4ge1xuICAgIHJldHVybiB0aGlzLmtuZXhRdWVyeS5maW5hbGx5KG9uZmluYWxseSk7XG4gIH1cblxuICAvLyBPTiBDT05GTElDVCAtIOy7rOufvCDquLDrsJhcbiAgb25Db25mbGljdDxUVGFibGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgVFJldHVybmluZz4+KFxuICAgIGNvbHVtbnM6IHN0cmluZyB8IHN0cmluZ1tdLFxuICAgIGFjdGlvbj86IE9uQ29uZmxpY3RBY3Rpb248VFRhYmxlcz4sXG4gICk6IHRoaXMge1xuICAgIGNvbnN0IHRhcmdldCA9IEFycmF5LmlzQXJyYXkoY29sdW1ucykgPyBjb2x1bW5zIDogW2NvbHVtbnNdO1xuXG4gICAgaWYgKCFhY3Rpb24gfHwgYWN0aW9uID09PSBcIm5vdGhpbmdcIikge1xuICAgICAgLy8gRE8gTk9USElOR1xuICAgICAgdGhpcy5rbmV4UXVlcnkub25Db25mbGljdCh0YXJnZXQpLmlnbm9yZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBETyBVUERBVEVcbiAgICAgIGNvbnN0IHsgdXBkYXRlIH0gPSBhY3Rpb247XG5cbiAgICAgIC8vIGFjdGlvbi51cGRhdGUg67Cw7Je0IO2Yle2DnCA6IFtcIm5hbWVcIiwgXCJlbWFpbFwiXVxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkodXBkYXRlKSkge1xuICAgICAgICB0aGlzLmtuZXhRdWVyeS5vbkNvbmZsaWN0KHRhcmdldCkubWVyZ2UodXBkYXRlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGFjdGlvbi51cGRhdGUg6rCd7LK0IO2Yle2DnDogeyBuYW1lOiBcIkpvaG5cIiwgY291bnQ6IHJhdyguLi4pIH1cbiAgICAgICAgY29uc3QgbWVyZ2VPYmo6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcblxuICAgICAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyh1cGRhdGUpKSB7XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgdmFsdWUgJiZcbiAgICAgICAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIiAmJlxuICAgICAgICAgICAgXCJfdHlwZVwiIGluIHZhbHVlICYmXG4gICAgICAgICAgICB2YWx1ZS5fdHlwZSA9PT0gXCJzcWxfZXhwcmVzc2lvblwiXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICAvLyBTcWxFeHByZXNzaW9uIOKGkiBrbmV4LnJhdygp66GcIOuzgO2ZmFxuICAgICAgICAgICAgbWVyZ2VPYmpba2V5XSA9IHRoaXMua25leC5yYXcoKHZhbHVlIGFzIFNxbEV4cHJlc3Npb248YW55PikuX3NxbCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIOydvOuwmCDqsJJcbiAgICAgICAgICAgIG1lcmdlT2JqW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmtuZXhRdWVyeS5vbkNvbmZsaWN0KHRhcmdldCkubWVyZ2UobWVyZ2VPYmopO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gUkVUVVJOSU5HOiBcIipcIiAtIOyghOyytCDsu6zrn7xcbiAgcmV0dXJuaW5nKGNvbHVtbjogXCIqXCIpOiBSZXNvbHZlZFB1cmk8VFJldHVybmluZ1tdLCBuZXZlcj47XG4gIC8vIFJFVFVSTklORzog64uo7J28IOy7rOufvFxuICByZXR1cm5pbmc8VENvbHVtbiBleHRlbmRzIENvbHVtbktleXM8VFJldHVybmluZz4+KFxuICAgIGNvbHVtbjogVENvbHVtbixcbiAgKTogUmVzb2x2ZWRQdXJpPFBpY2s8VFJldHVybmluZywgVENvbHVtbj5bXSwgbmV2ZXI+O1xuICAvLyBSRVRVUk5JTkc6IOuzteyImCDsu6zrn7wgKOuwsOyXtClcbiAgcmV0dXJuaW5nPFRDb2x1bW4gZXh0ZW5kcyBDb2x1bW5LZXlzPFRSZXR1cm5pbmc+PihcbiAgICBjb2x1bW5zOiBUQ29sdW1uW10sXG4gICk6IFJlc29sdmVkUHVyaTxQaWNrPFRSZXR1cm5pbmcsIFRDb2x1bW4+W10sIG5ldmVyPjtcbiAgLy8gUkVUVVJOSU5HIOq1rO2YhFxuICByZXR1cm5pbmcoY29sdW1uT3JDb2x1bW5zOiBzdHJpbmcgfCBzdHJpbmdbXSk6IFJlc29sdmVkUHVyaTxhbnlbXSwgbmV2ZXI+IHtcbiAgICB0aGlzLmtuZXhRdWVyeS5yZXR1cm5pbmcoY29sdW1uT3JDb2x1bW5zKTtcbiAgICByZXR1cm4gbmV3IFJlc29sdmVkUHVyaSh0aGlzLmtuZXhRdWVyeSwgdGhpcy5rbmV4KTtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUEwQ0EsU0FBUyx1QkFBdUIsVUFBa0M7Q0FDaEUsTUFBTSxhQUFhLFVBQVUsTUFBTSxJQUFJO0NBQ3ZDLE1BQU0sZ0JBQWdCLGdCQUFnQixNQUFNLGNBQWMsY0FBYyxXQUFXO0FBRW5GLEtBQUksQ0FBQyxlQUFlO0FBQ2xCLFFBQU0sSUFBSSxNQUFNLDJCQUEyQixZQUFZLEtBQUs7O0FBRzlELFFBQU87Ozs7c0JBMUNnRDthQUVsQjtrQkE4QlE7Q0FhbEMsT0FBYixNQUFhLEtBQTREO0VBQ3ZFLEFBQVE7RUFDUixBQUFRLFlBQThCO0VBS3RDLFlBQ0UsQUFBT0EsTUFDUCxtQkFDQTtHQUZPO0FBR1AsT0FBSSxPQUFPLHNCQUFzQixVQUFVO0FBRXpDLFNBQUssWUFBWSxLQUFLLEtBQUssa0JBQWtCLENBQUMsS0FBSyxrQkFBa0I7QUFDckUsU0FBSyxZQUFZLEtBQUssaUJBQWlCLGtCQUFrQjtjQUNoRCxPQUFPLHNCQUFzQixVQUFVO0lBQ2hELE1BQU0sVUFBVSxPQUFPLFFBQVEsa0JBQWtCO0FBQ2pELFFBQUksUUFBUSxXQUFXLEdBQUc7QUFDeEIsV0FBTSxJQUFJLE1BQU0seUNBQXlDOztBQUUzRCxXQUFPLFFBQVEsR0FBRztJQUNsQixNQUFNLENBQUMsT0FBTyxVQUFVLFFBQVE7QUFDaEMsUUFBSSxPQUFPLFdBQVcsVUFBVTtBQUM5QixVQUFLLFlBQVksS0FBSyxLQUFLLE9BQU8sQ0FBQyxLQUFLLEdBQUcsUUFBUSxRQUFRLENBQUM7QUFDNUQsVUFBSyxZQUFZLEtBQUssaUJBQWlCLE9BQU87ZUFDckMs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