sonamu 0.10.11 → 0.10.13

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 (519) hide show
  1. package/dist/ai/agents/agent.d.ts +1 -1
  2. package/dist/ai/agents/agent.d.ts.map +1 -1
  3. package/dist/ai/agents/agent.js +5 -6
  4. package/dist/ai/agents/types.d.ts +1 -1
  5. package/dist/ai/agents/types.d.ts.map +1 -1
  6. package/dist/ai/providers/rtzr/api.js +18 -18
  7. package/dist/ai/providers/rtzr/error.d.ts.map +1 -1
  8. package/dist/ai/providers/rtzr/error.js +17 -15
  9. package/dist/ai/providers/rtzr/model.d.ts.map +1 -1
  10. package/dist/ai/providers/rtzr/model.js +3 -2
  11. package/dist/ai/providers/rtzr/options.d.ts.map +1 -1
  12. package/dist/ai/providers/rtzr/options.js +16 -16
  13. package/dist/ai/providers/rtzr/provider.d.ts.map +1 -1
  14. package/dist/ai/providers/rtzr/provider.js +9 -9
  15. package/dist/ai/providers/rtzr/utils.d.ts.map +1 -1
  16. package/dist/ai/providers/rtzr/utils.js +1 -1
  17. package/dist/api/caster.d.ts.map +1 -1
  18. package/dist/api/caster.js +17 -17
  19. package/dist/api/code-converters.d.ts +4 -2
  20. package/dist/api/code-converters.d.ts.map +1 -1
  21. package/dist/api/code-converters.js +100 -19
  22. package/dist/api/config.d.ts +16 -1
  23. package/dist/api/config.d.ts.map +1 -1
  24. package/dist/api/config.js +28 -21
  25. package/dist/api/context.d.ts +2 -2
  26. package/dist/api/context.d.ts.map +1 -1
  27. package/dist/api/context.js +1 -1
  28. package/dist/api/decorators.d.ts.map +1 -1
  29. package/dist/api/decorators.js +18 -11
  30. package/dist/api/http-validator.d.ts +36 -0
  31. package/dist/api/http-validator.d.ts.map +1 -0
  32. package/dist/api/http-validator.js +72 -0
  33. package/dist/api/index.js +6 -4
  34. package/dist/api/sonamu.d.ts +59 -20
  35. package/dist/api/sonamu.d.ts.map +1 -1
  36. package/dist/api/sonamu.js +250 -106
  37. package/dist/api/websocket-helpers.d.ts +7 -5
  38. package/dist/api/websocket-helpers.d.ts.map +1 -1
  39. package/dist/api/websocket-helpers.js +6 -6
  40. package/dist/auth/audit-log/builders.d.ts.map +1 -1
  41. package/dist/auth/audit-log/builders.js +1 -1
  42. package/dist/auth/audit-log/client-ip.d.ts +1 -1
  43. package/dist/auth/audit-log/client-ip.d.ts.map +1 -1
  44. package/dist/auth/audit-log/client-ip.js +4 -2
  45. package/dist/auth/audit-log/events.d.ts +5 -1
  46. package/dist/auth/audit-log/events.d.ts.map +1 -1
  47. package/dist/auth/audit-log/events.js +1 -1
  48. package/dist/auth/audit-log/plugin.d.ts +0 -8
  49. package/dist/auth/audit-log/plugin.d.ts.map +1 -1
  50. package/dist/auth/audit-log/plugin.js +48 -52
  51. package/dist/auth/audit-log-ingestor.d.ts.map +1 -1
  52. package/dist/auth/audit-log-ingestor.js +16 -12
  53. package/dist/auth/auth-generator.d.ts.map +1 -1
  54. package/dist/auth/auth-generator.js +1 -1
  55. package/dist/auth/better-auth-request.d.ts.map +1 -1
  56. package/dist/auth/better-auth-request.js +6 -5
  57. package/dist/auth/knex-adapter.js +1 -1
  58. package/dist/auth/plugins/entity-definitions/index.d.ts +13 -1
  59. package/dist/auth/plugins/entity-definitions/index.d.ts.map +1 -1
  60. package/dist/auth/plugins/entity-definitions/index.js +1 -1
  61. package/dist/auth/plugins/wrappers/admin.d.ts +1 -1
  62. package/dist/bin/build-config.d.ts +25 -0
  63. package/dist/bin/build-config.d.ts.map +1 -1
  64. package/dist/bin/build-config.js +105 -2
  65. package/dist/bin/cli.js +133 -29
  66. package/dist/bin/compiler-policy.d.ts +3 -0
  67. package/dist/bin/compiler-policy.d.ts.map +1 -0
  68. package/dist/bin/compiler-policy.js +24 -0
  69. package/dist/bin/fixture.d.ts.map +1 -1
  70. package/dist/bin/fixture.js +5 -3
  71. package/dist/bin/test-command.d.ts +22 -1
  72. package/dist/bin/test-command.d.ts.map +1 -1
  73. package/dist/bin/test-command.js +18 -10
  74. package/dist/bin/ts-loader-registration.d.ts +7 -1
  75. package/dist/bin/ts-loader-registration.d.ts.map +1 -1
  76. package/dist/bin/ts-loader-registration.js +13 -4
  77. package/dist/cache/decorator.d.ts.map +1 -1
  78. package/dist/cache/decorator.js +11 -4
  79. package/dist/compress/compress.d.ts.map +1 -1
  80. package/dist/compress/compress.js +1 -1
  81. package/dist/cone/cone-generator.d.ts +14 -1
  82. package/dist/cone/cone-generator.d.ts.map +1 -1
  83. package/dist/cone/cone-generator.js +13 -9
  84. package/dist/database/_batch_update.js +1 -1
  85. package/dist/database/base-model.d.ts +22 -10
  86. package/dist/database/base-model.d.ts.map +1 -1
  87. package/dist/database/base-model.js +26 -16
  88. package/dist/database/base-model.types.d.ts +15 -3
  89. package/dist/database/base-model.types.d.ts.map +1 -1
  90. package/dist/database/db.d.ts +12 -2
  91. package/dist/database/db.d.ts.map +1 -1
  92. package/dist/database/db.js +10 -7
  93. package/dist/database/knex.d.ts.map +1 -1
  94. package/dist/database/knex.js +17 -14
  95. package/dist/database/puri.d.ts +11 -9
  96. package/dist/database/puri.d.ts.map +1 -1
  97. package/dist/database/puri.js +93 -79
  98. package/dist/database/puri.types.d.ts +21 -21
  99. package/dist/database/puri.types.d.ts.map +1 -1
  100. package/dist/database/puri.types.js +1 -1
  101. package/dist/database/upsert-builder.d.ts +12 -10
  102. package/dist/database/upsert-builder.d.ts.map +1 -1
  103. package/dist/database/upsert-builder.js +20 -12
  104. package/dist/dict/sd.d.ts.map +1 -1
  105. package/dist/dict/sd.js +1 -1
  106. package/dist/dict/sonamu-dictionary.d.ts.map +1 -1
  107. package/dist/dict/sonamu-dictionary.js +1 -1
  108. package/dist/dict/utils.d.ts.map +1 -1
  109. package/dist/dict/utils.js +7 -2
  110. package/dist/entity/entity-manager.d.ts +13 -4
  111. package/dist/entity/entity-manager.d.ts.map +1 -1
  112. package/dist/entity/entity-manager.js +19 -11
  113. package/dist/entity/entity-template-cone.d.ts +73 -5
  114. package/dist/entity/entity-template-cone.d.ts.map +1 -1
  115. package/dist/entity/entity-template-cone.js +4 -2
  116. package/dist/entity/entity.d.ts +6 -2
  117. package/dist/entity/entity.d.ts.map +1 -1
  118. package/dist/entity/entity.js +30 -28
  119. package/dist/env.d.ts +3 -1
  120. package/dist/env.d.ts.map +1 -1
  121. package/dist/env.js +1 -1
  122. package/dist/exceptions/error-handler.d.ts.map +1 -1
  123. package/dist/exceptions/error-handler.js +7 -2
  124. package/dist/exceptions/so-exceptions.d.ts +24 -20
  125. package/dist/exceptions/so-exceptions.d.ts.map +1 -1
  126. package/dist/exceptions/so-exceptions.js +4 -2
  127. package/dist/filter/utils.d.ts +7 -2
  128. package/dist/filter/utils.d.ts.map +1 -1
  129. package/dist/filter/utils.js +8 -6
  130. package/dist/index.d.ts +3 -0
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +13 -7
  133. package/dist/logger/configure.d.ts.map +1 -1
  134. package/dist/logger/configure.js +10 -10
  135. package/dist/migration/code-generation.d.ts.map +1 -1
  136. package/dist/migration/code-generation.js +50 -46
  137. package/dist/migration/index-where-predicate.d.ts.map +1 -1
  138. package/dist/migration/index-where-predicate.js +22 -8
  139. package/dist/migration/migration-set.d.ts.map +1 -1
  140. package/dist/migration/migration-set.js +1 -1
  141. package/dist/migration/migrator.d.ts +61 -36
  142. package/dist/migration/migrator.d.ts.map +1 -1
  143. package/dist/migration/migrator.js +276 -167
  144. package/dist/migration/postgresql-schema-reader.d.ts.map +1 -1
  145. package/dist/migration/postgresql-schema-reader.js +51 -36
  146. package/dist/migration/slack-confirm.d.ts.map +1 -1
  147. package/dist/migration/slack-confirm.js +1 -1
  148. package/dist/migration/types.d.ts +54 -0
  149. package/dist/migration/types.d.ts.map +1 -1
  150. package/dist/naite/naite-reporter.js +2 -2
  151. package/dist/naite/naite.d.ts +74 -15
  152. package/dist/naite/naite.d.ts.map +1 -1
  153. package/dist/naite/naite.js +5 -19
  154. package/dist/runtime-type.d.ts +6 -0
  155. package/dist/runtime-type.d.ts.map +1 -0
  156. package/dist/runtime-type.js +26 -0
  157. package/dist/ssr/hmr-opt-out.d.ts +26 -0
  158. package/dist/ssr/hmr-opt-out.d.ts.map +1 -0
  159. package/dist/ssr/hmr-opt-out.js +59 -0
  160. package/dist/ssr/renderer.d.ts.map +1 -1
  161. package/dist/ssr/renderer.js +4 -1
  162. package/dist/storage/base-file.js +14 -14
  163. package/dist/storage/buffered-file.d.ts +2 -2
  164. package/dist/storage/buffered-file.d.ts.map +1 -1
  165. package/dist/storage/buffered-file.js +12 -12
  166. package/dist/storage/s3-driver.d.ts.map +1 -1
  167. package/dist/storage/s3-driver.js +1 -1
  168. package/dist/storage/uploaded-file.d.ts +2 -2
  169. package/dist/storage/uploaded-file.d.ts.map +1 -1
  170. package/dist/storage/uploaded-file.js +8 -8
  171. package/dist/stream/sse.js +11 -11
  172. package/dist/stream/ws-core.d.ts +1 -1
  173. package/dist/stream/ws-core.d.ts.map +1 -1
  174. package/dist/stream/ws-delivery.d.ts +1 -1
  175. package/dist/stream/ws-delivery.d.ts.map +1 -1
  176. package/dist/stream/ws-delivery.js +6 -4
  177. package/dist/stream/ws-local-connection-store.d.ts.map +1 -1
  178. package/dist/stream/ws-local-connection-store.js +4 -2
  179. package/dist/stream/ws-presence-store.js +1 -1
  180. package/dist/stream/ws-registry.d.ts +4 -4
  181. package/dist/stream/ws-registry.d.ts.map +1 -1
  182. package/dist/stream/ws-registry.js +4 -2
  183. package/dist/stream/ws-telemetry.d.ts +16 -12
  184. package/dist/stream/ws-telemetry.d.ts.map +1 -1
  185. package/dist/stream/ws-telemetry.js +22 -18
  186. package/dist/stream/ws.d.ts +18 -12
  187. package/dist/stream/ws.d.ts.map +1 -1
  188. package/dist/stream/ws.js +26 -22
  189. package/dist/syncer/api-parser.js +1 -1
  190. package/dist/syncer/checksum.d.ts.map +1 -1
  191. package/dist/syncer/checksum.js +7 -8
  192. package/dist/syncer/code-generator.d.ts.map +1 -1
  193. package/dist/syncer/code-generator.js +13 -14
  194. package/dist/syncer/entity-operations.d.ts.map +1 -1
  195. package/dist/syncer/entity-operations.js +5 -6
  196. package/dist/syncer/file-copy.d.ts +5 -0
  197. package/dist/syncer/file-copy.d.ts.map +1 -0
  198. package/dist/syncer/file-copy.js +36 -0
  199. package/dist/syncer/file-patterns.d.ts +1 -0
  200. package/dist/syncer/file-patterns.d.ts.map +1 -1
  201. package/dist/syncer/file-patterns.js +5 -2
  202. package/dist/syncer/file-tracking.d.ts.map +1 -1
  203. package/dist/syncer/file-tracking.js +5 -4
  204. package/dist/syncer/filesystem-dependencies.d.ts +15 -0
  205. package/dist/syncer/filesystem-dependencies.d.ts.map +1 -0
  206. package/dist/syncer/filesystem-dependencies.js +53 -0
  207. package/dist/syncer/module-loader.d.ts +1 -1
  208. package/dist/syncer/module-loader.d.ts.map +1 -1
  209. package/dist/syncer/module-loader.js +6 -4
  210. package/dist/syncer/syncer-actions.d.ts +4 -0
  211. package/dist/syncer/syncer-actions.d.ts.map +1 -1
  212. package/dist/syncer/syncer-actions.js +34 -17
  213. package/dist/syncer/syncer.d.ts +17 -6
  214. package/dist/syncer/syncer.d.ts.map +1 -1
  215. package/dist/syncer/syncer.js +71 -29
  216. package/dist/syncer/watcher.d.ts.map +1 -1
  217. package/dist/syncer/watcher.js +3 -3
  218. package/dist/tasks/decorator.d.ts +6 -6
  219. package/dist/tasks/decorator.d.ts.map +1 -1
  220. package/dist/tasks/decorator.js +4 -4
  221. package/dist/tasks/step-wrapper.d.ts +6 -4
  222. package/dist/tasks/step-wrapper.d.ts.map +1 -1
  223. package/dist/tasks/step-wrapper.js +5 -5
  224. package/dist/tasks/workflow-manager.d.ts.map +1 -1
  225. package/dist/tasks/workflow-manager.js +13 -7
  226. package/dist/template/entity-converter.d.ts +1 -1
  227. package/dist/template/entity-converter.d.ts.map +1 -1
  228. package/dist/template/entity-converter.js +2 -2
  229. package/dist/template/helpers.d.ts +8 -6
  230. package/dist/template/helpers.d.ts.map +1 -1
  231. package/dist/template/helpers.js +1 -1
  232. package/dist/template/implementations/generated.template.d.ts.map +1 -1
  233. package/dist/template/implementations/generated.template.js +4 -4
  234. package/dist/template/implementations/generated_http.template.d.ts +7 -4
  235. package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
  236. package/dist/template/implementations/generated_http.template.js +21 -21
  237. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
  238. package/dist/template/implementations/generated_sso.template.js +6 -3
  239. package/dist/template/implementations/http_validators.template.d.ts +18 -0
  240. package/dist/template/implementations/http_validators.template.d.ts.map +1 -0
  241. package/dist/template/implementations/http_validators.template.js +127 -0
  242. package/dist/template/implementations/model.template.d.ts.map +1 -1
  243. package/dist/template/implementations/model.template.js +1 -1
  244. package/dist/template/implementations/queries.template.js +1 -1
  245. package/dist/template/implementations/sd.template.d.ts.map +1 -1
  246. package/dist/template/implementations/sd.template.js +79 -39
  247. package/dist/template/implementations/services.template.d.ts.map +1 -1
  248. package/dist/template/implementations/services.template.js +6 -4
  249. package/dist/template/implementations/view_form.template.d.ts +6 -1
  250. package/dist/template/implementations/view_form.template.d.ts.map +1 -1
  251. package/dist/template/implementations/view_form.template.js +23 -15
  252. package/dist/template/implementations/view_list.template.d.ts.map +1 -1
  253. package/dist/template/implementations/view_list.template.js +11 -6
  254. package/dist/template/template-manager.d.ts.map +1 -1
  255. package/dist/template/template-manager.js +9 -7
  256. package/dist/template/template-types.d.ts +12 -5
  257. package/dist/template/template-types.d.ts.map +1 -1
  258. package/dist/template/template-types.js +1 -1
  259. package/dist/template/template.d.ts +2 -2
  260. package/dist/template/template.d.ts.map +1 -1
  261. package/dist/template/template.js +6 -4
  262. package/dist/template/zod-converter.d.ts +0 -19
  263. package/dist/template/zod-converter.d.ts.map +1 -1
  264. package/dist/template/zod-converter.js +100 -84
  265. package/dist/testing/_relation-graph.d.ts.map +1 -1
  266. package/dist/testing/_relation-graph.js +2 -1
  267. package/dist/testing/bootstrap.d.ts.map +1 -1
  268. package/dist/testing/bootstrap.js +9 -6
  269. package/dist/testing/data-explorer.d.ts +32 -7
  270. package/dist/testing/data-explorer.d.ts.map +1 -1
  271. package/dist/testing/data-explorer.js +77 -31
  272. package/dist/testing/dev-test-routes.d.ts +8 -1
  273. package/dist/testing/dev-test-routes.d.ts.map +1 -1
  274. package/dist/testing/dev-test-routes.js +125 -108
  275. package/dist/testing/dev-vitest-manager.d.ts +54 -8
  276. package/dist/testing/dev-vitest-manager.d.ts.map +1 -1
  277. package/dist/testing/dev-vitest-manager.js +24 -9
  278. package/dist/testing/faker-mappings.d.ts +412 -1
  279. package/dist/testing/faker-mappings.d.ts.map +1 -1
  280. package/dist/testing/faker-mappings.js +1 -1
  281. package/dist/testing/filesystem.d.ts +2 -0
  282. package/dist/testing/filesystem.d.ts.map +1 -0
  283. package/dist/testing/filesystem.js +7 -0
  284. package/dist/testing/fixture-generator.d.ts +25 -8
  285. package/dist/testing/fixture-generator.d.ts.map +1 -1
  286. package/dist/testing/fixture-generator.js +132 -73
  287. package/dist/testing/fixture-loader.d.ts +3 -1
  288. package/dist/testing/fixture-loader.d.ts.map +1 -1
  289. package/dist/testing/fixture-loader.js +1 -20
  290. package/dist/testing/fixture-manager.d.ts +8 -7
  291. package/dist/testing/fixture-manager.d.ts.map +1 -1
  292. package/dist/testing/fixture-manager.js +91 -59
  293. package/dist/testing/global-setup.d.ts.map +1 -1
  294. package/dist/testing/global-setup.js +5 -2
  295. package/dist/testing/index.d.ts +2 -0
  296. package/dist/testing/index.d.ts.map +1 -1
  297. package/dist/testing/index.js +6 -3
  298. package/dist/types/types.d.ts +101 -99
  299. package/dist/types/types.d.ts.map +1 -1
  300. package/dist/types/types.js +234 -225
  301. package/dist/ui/ai-api.d.ts.map +1 -1
  302. package/dist/ui/ai-api.js +1 -1
  303. package/dist/ui/ai-client.d.ts.map +1 -1
  304. package/dist/ui/ai-client.js +28 -18
  305. package/dist/ui/api.d.ts.map +1 -1
  306. package/dist/ui/api.js +146 -210
  307. package/dist/ui/async-route.d.ts +3 -0
  308. package/dist/ui/async-route.d.ts.map +1 -0
  309. package/dist/ui/async-route.js +12 -0
  310. package/dist/ui/cdd-service.d.ts +9 -7
  311. package/dist/ui/cdd-service.d.ts.map +1 -1
  312. package/dist/ui/cdd-service.js +7 -5
  313. package/dist/ui/migrations-api.d.ts +3 -0
  314. package/dist/ui/migrations-api.d.ts.map +1 -0
  315. package/dist/ui/migrations-api.js +215 -0
  316. package/dist/ui-web/assets/index-D3QNH-Dv.css +1 -0
  317. package/dist/ui-web/assets/index-DV1AAq6W.js +178 -0
  318. package/dist/ui-web/index.html +2 -2
  319. package/dist/utils/formatter.d.ts.map +1 -1
  320. package/dist/utils/formatter.js +7 -5
  321. package/dist/utils/fs-utils.d.ts +3 -3
  322. package/dist/utils/fs-utils.d.ts.map +1 -1
  323. package/dist/utils/fs-utils.js +6 -6
  324. package/dist/utils/model.d.ts +3 -5
  325. package/dist/utils/model.d.ts.map +1 -1
  326. package/dist/utils/model.js +1 -1
  327. package/dist/utils/object-utils.d.ts +1 -1
  328. package/dist/utils/object-utils.d.ts.map +1 -1
  329. package/dist/utils/object-utils.js +17 -16
  330. package/dist/utils/process-utils.d.ts.map +1 -1
  331. package/dist/utils/process-utils.js +4 -2
  332. package/dist/utils/runtime-value.d.ts +13 -0
  333. package/dist/utils/runtime-value.d.ts.map +1 -0
  334. package/dist/utils/runtime-value.js +40 -0
  335. package/dist/utils/sql-parser.d.ts +8 -1
  336. package/dist/utils/sql-parser.d.ts.map +1 -1
  337. package/dist/utils/sql-parser.js +6 -3
  338. package/dist/utils/type-utils.d.ts.map +1 -1
  339. package/dist/utils/type-utils.js +10 -8
  340. package/dist/utils/utils.d.ts +2 -2
  341. package/dist/utils/utils.d.ts.map +1 -1
  342. package/dist/utils/utils.js +11 -8
  343. package/dist/utils/zod-error.d.ts.map +1 -1
  344. package/dist/utils/zod-error.js +7 -4
  345. package/dist/vector/chunking.d.ts.map +1 -1
  346. package/dist/vector/chunking.js +1 -1
  347. package/dist/vector/embedding.d.ts.map +1 -1
  348. package/dist/vector/embedding.js +1 -1
  349. package/dist/vector/types.d.ts +3 -2
  350. package/dist/vector/types.d.ts.map +1 -1
  351. package/package.json +11 -7
  352. package/src/ai/agents/agent.ts +5 -5
  353. package/src/ai/agents/types.ts +1 -1
  354. package/src/ai/providers/rtzr/__tests__/model.test.ts +2 -2
  355. package/src/ai/providers/rtzr/error.ts +5 -3
  356. package/src/ai/providers/rtzr/model.ts +3 -2
  357. package/src/ai/providers/rtzr/options.ts +10 -5
  358. package/src/ai/providers/rtzr/provider.ts +10 -10
  359. package/src/ai/providers/rtzr/utils.ts +3 -1
  360. package/src/api/__tests__/config.test.ts +11 -21
  361. package/src/api/__tests__/sonamu.http-validator.test.ts +512 -0
  362. package/src/api/__tests__/sonamu.websocket.test.ts +51 -41
  363. package/src/api/__tests__/zod-compiler-policy.test.ts +95 -0
  364. package/src/api/caster.ts +6 -8
  365. package/src/api/code-converters.ts +136 -36
  366. package/src/api/config.ts +62 -4
  367. package/src/api/context.ts +3 -3
  368. package/src/api/decorators.ts +28 -17
  369. package/src/api/http-validator.ts +149 -0
  370. package/src/api/sonamu.ts +459 -152
  371. package/src/api/websocket-helpers.ts +24 -17
  372. package/src/auth/audit-log/builders.ts +3 -2
  373. package/src/auth/audit-log/client-ip.ts +4 -2
  374. package/src/auth/audit-log/events.ts +15 -1
  375. package/src/auth/audit-log/plugin.ts +129 -200
  376. package/src/auth/audit-log-ingestor.ts +19 -15
  377. package/src/auth/auth-generator.ts +10 -5
  378. package/src/auth/better-auth-request.ts +4 -3
  379. package/src/auth/knex-adapter.ts +8 -2
  380. package/src/auth/plugins/entity-definitions/index.ts +6 -5
  381. package/src/bin/__tests__/http-validator-benchmark.test.ts +94 -0
  382. package/src/bin/__tests__/test-command.test.ts +9 -15
  383. package/src/bin/__tests__/ts-loader-register.test.ts +15 -17
  384. package/src/bin/__tests__/zod-compiler-build.test.ts +307 -0
  385. package/src/bin/build-config.ts +167 -0
  386. package/src/bin/cli.ts +155 -38
  387. package/src/bin/compiler-policy.ts +35 -0
  388. package/src/bin/fixture.ts +14 -3
  389. package/src/bin/test-command.ts +74 -29
  390. package/src/bin/ts-loader-registration.ts +22 -4
  391. package/src/cache/decorator.ts +10 -3
  392. package/src/compress/compress.ts +17 -4
  393. package/src/cone/cone-generator.ts +34 -6
  394. package/src/database/__tests__/db.test.ts +1 -0
  395. package/src/database/__tests__/puri.test.ts +16 -15
  396. package/src/database/__tests__/transaction-scope.test.ts +5 -0
  397. package/src/database/_batch_update.ts +1 -0
  398. package/src/database/base-model.ts +81 -50
  399. package/src/database/base-model.types.ts +6 -6
  400. package/src/database/db.ts +29 -19
  401. package/src/database/knex.ts +30 -17
  402. package/src/database/puri-subset.test-d.ts +17 -0
  403. package/src/database/puri.ts +181 -143
  404. package/src/database/puri.types.test-d.ts +31 -1
  405. package/src/database/puri.types.ts +23 -21
  406. package/src/database/upsert-builder.ts +75 -53
  407. package/src/dict/sd.ts +15 -5
  408. package/src/dict/sonamu-dictionary.ts +6 -6
  409. package/src/dict/utils.ts +9 -1
  410. package/src/entity/entity-manager.ts +26 -9
  411. package/src/entity/entity-template-cone.ts +5 -10
  412. package/src/entity/entity.ts +50 -34
  413. package/src/env.ts +7 -3
  414. package/src/exceptions/error-handler.ts +17 -2
  415. package/src/exceptions/so-exceptions.ts +26 -20
  416. package/src/filter/utils.ts +21 -11
  417. package/src/index.ts +3 -0
  418. package/src/logger/configure.ts +26 -18
  419. package/src/migration/__tests__/migrator.test.ts +50 -57
  420. package/src/migration/code-generation.ts +132 -104
  421. package/src/migration/index-where-predicate.ts +51 -24
  422. package/src/migration/migration-set.ts +11 -5
  423. package/src/migration/migrator.ts +392 -244
  424. package/src/migration/postgresql-schema-reader.ts +52 -47
  425. package/src/migration/slack-confirm.ts +17 -15
  426. package/src/migration/types.ts +57 -0
  427. package/src/naite/naite-reporter.ts +1 -1
  428. package/src/naite/naite.ts +97 -24
  429. package/src/runtime-type.ts +34 -0
  430. package/src/ssr/hmr-opt-out.ts +78 -0
  431. package/src/ssr/renderer.ts +6 -0
  432. package/src/storage/base-file.ts +13 -13
  433. package/src/storage/buffered-file.ts +11 -11
  434. package/src/storage/s3-driver.ts +4 -1
  435. package/src/storage/uploaded-file.ts +8 -8
  436. package/src/stream/__tests__/ws-contracts.test.ts +4 -2
  437. package/src/stream/__tests__/ws-telemetry.test.ts +1 -1
  438. package/src/stream/__tests__/ws.test.ts +30 -6
  439. package/src/stream/sse.ts +12 -11
  440. package/src/stream/ws-core.ts +1 -1
  441. package/src/stream/ws-delivery.ts +16 -7
  442. package/src/stream/ws-local-connection-store.ts +2 -3
  443. package/src/stream/ws-presence-store.ts +6 -1
  444. package/src/stream/ws-registry.ts +16 -7
  445. package/src/stream/ws-telemetry.ts +66 -43
  446. package/src/stream/ws.ts +73 -39
  447. package/src/syncer/__tests__/api-parser.websocket-type-ref.test.ts +3 -2
  448. package/src/syncer/__tests__/http-validator-registry.test.ts +137 -0
  449. package/src/syncer/api-parser.ts +67 -27
  450. package/src/syncer/checksum.ts +17 -11
  451. package/src/syncer/code-generator.ts +25 -17
  452. package/src/syncer/entity-operations.ts +3 -5
  453. package/src/syncer/file-copy.ts +46 -0
  454. package/src/syncer/file-patterns.ts +11 -8
  455. package/src/syncer/file-tracking.ts +3 -4
  456. package/src/syncer/filesystem-dependencies.ts +73 -0
  457. package/src/syncer/module-loader.ts +8 -4
  458. package/src/syncer/syncer-actions.ts +56 -18
  459. package/src/syncer/syncer.ts +116 -43
  460. package/src/syncer/watcher.ts +8 -4
  461. package/src/tasks/decorator.ts +20 -12
  462. package/src/tasks/step-wrapper.ts +19 -9
  463. package/src/tasks/workflow-manager.ts +15 -9
  464. package/src/template/__tests__/http_validators.template.test.ts +160 -0
  465. package/src/template/__tests__/services.template.mutation.test.ts +24 -23
  466. package/src/template/__tests__/services.template.websocket.test.ts +21 -25
  467. package/src/template/entity-converter.ts +5 -2
  468. package/src/template/helpers.ts +8 -9
  469. package/src/template/implementations/generated.template.ts +5 -4
  470. package/src/template/implementations/generated_http.template.ts +61 -15
  471. package/src/template/implementations/generated_sso.template.ts +15 -4
  472. package/src/template/implementations/http_validators.template.ts +175 -0
  473. package/src/template/implementations/model.template.ts +3 -1
  474. package/src/template/implementations/sd.template.ts +81 -41
  475. package/src/template/implementations/services.template.ts +2 -2
  476. package/src/template/implementations/view_form.template.ts +56 -39
  477. package/src/template/implementations/view_list.template.ts +31 -23
  478. package/src/template/template-manager.ts +15 -13
  479. package/src/template/template-types.ts +13 -5
  480. package/src/template/template.ts +4 -3
  481. package/src/template/zod-converter.ts +206 -91
  482. package/src/testing/__tests__/dev-test-routes.test.ts +85 -25
  483. package/src/testing/__tests__/dev-vitest-manager.test.ts +15 -15
  484. package/src/testing/_relation-graph.ts +4 -1
  485. package/src/testing/bootstrap.ts +12 -5
  486. package/src/testing/data-explorer.ts +102 -53
  487. package/src/testing/dev-test-routes.ts +87 -50
  488. package/src/testing/dev-vitest-manager.ts +88 -32
  489. package/src/testing/faker-mappings.ts +2 -2
  490. package/src/testing/filesystem.ts +1 -0
  491. package/src/testing/fixture-generator.ts +191 -131
  492. package/src/testing/fixture-loader.ts +5 -1
  493. package/src/testing/fixture-manager.ts +129 -90
  494. package/src/testing/global-setup.ts +7 -3
  495. package/src/testing/index.ts +5 -0
  496. package/src/types/__tests__/entity-json-schema-search-text.test.ts +9 -3
  497. package/src/types/types.ts +184 -158
  498. package/src/ui/ai-api.ts +9 -7
  499. package/src/ui/ai-client.ts +61 -56
  500. package/src/ui/api.ts +726 -770
  501. package/src/ui/async-route.ts +4 -0
  502. package/src/ui/cdd-service.ts +35 -12
  503. package/src/ui/migrations-api.ts +381 -0
  504. package/src/utils/formatter.ts +7 -3
  505. package/src/utils/fs-utils.ts +5 -5
  506. package/src/utils/model.ts +4 -5
  507. package/src/utils/object-utils.ts +32 -22
  508. package/src/utils/process-utils.ts +4 -1
  509. package/src/utils/runtime-value.ts +43 -0
  510. package/src/utils/sql-parser.ts +13 -6
  511. package/src/utils/type-utils.ts +9 -7
  512. package/src/utils/utils.ts +19 -21
  513. package/src/utils/zod-error.ts +4 -2
  514. package/src/vector/chunking.ts +6 -1
  515. package/src/vector/embedding.ts +2 -1
  516. package/src/vector/types.ts +4 -2
  517. package/tsdown.api.config.ts +5 -2
  518. package/dist/ui-web/assets/index-CJf8uJYf.js +0 -176
  519. package/dist/ui-web/assets/index-GMMIVGja.css +0 -1
@@ -1,4 +1,5 @@
1
1
  import { __esmMin } from "../_virtual/_rolldown/runtime.js";
2
+ import { init_runtime_value, isObjectValue, isStringValue } from "../utils/runtime-value.js";
2
3
  import { getSonamuEnvironment, init_env } from "../env.js";
3
4
  import { createKnexInstance, init_knex } from "../database/knex.js";
4
5
  import { DB, init_db } from "../database/db.js";
@@ -12,12 +13,16 @@ import { Naite, init_naite } from "../naite/naite.js";
12
13
  import { PostgreSQLSchemaReader, init_postgresql_schema_reader } from "./postgresql-schema-reader.js";
13
14
  import { generateAlterCode, generateCreateCode, init_code_generation } from "./code-generation.js";
14
15
  import { getMigrationSetFromEntity, init_migration_set } from "./migration-set.js";
15
- import { group, sum, unique } from "radashi";
16
+ import { SlackConfirm, init_slack_confirm } from "./slack-confirm.js";
17
+ import { group, unique } from "radashi";
16
18
  import assert from "assert";
17
19
  import path from "path";
18
20
  import chalk from "chalk";
19
- import { mkdir, readdir, unlink, writeFile } from "fs/promises";
21
+ import { mkdir, readdir, writeFile } from "fs/promises";
20
22
  //#region src/migration/migrator.ts
23
+ function padDatePart(number, size = 2) {
24
+ return number.toString().padStart(size, "0");
25
+ }
21
26
  /**
22
27
  * 주어진 Promise가 ms 안에 완료되지 않으면 onTimeout 에러로 reject한다.
23
28
  * 원본 Promise 자체는 계속 진행되므로, 호출측에서 커넥션 정리(destroy)를 책임진다.
@@ -34,7 +39,7 @@ function withTimeout(promise, ms, onTimeout) {
34
39
  });
35
40
  });
36
41
  }
37
- var MIGRATION_CONN_TIMEOUT_MS, Migrator;
42
+ var MigrationTargetExecutionError, MIGRATION_CONN_TIMEOUT_MS, LOCAL_DB_HOSTS, Migrator;
38
43
  var init_migrator = __esmMin((() => {
39
44
  init_sonamu();
40
45
  init_db();
@@ -46,34 +51,143 @@ var init_migrator = __esmMin((() => {
46
51
  init_naite();
47
52
  init_controller();
48
53
  init_fs_utils();
54
+ init_runtime_value();
49
55
  init_code_generation();
50
56
  init_migration_set();
51
57
  init_postgresql_schema_reader();
58
+ init_slack_confirm();
59
+ MigrationTargetExecutionError = class extends Error {
60
+ connKey;
61
+ constructor(connKey, cause) {
62
+ super(cause instanceof Error ? cause.message : String(cause));
63
+ this.connKey = connKey;
64
+ this.name = "MigrationTargetExecutionError";
65
+ }
66
+ };
52
67
  MIGRATION_CONN_TIMEOUT_MS = 5e3;
68
+ LOCAL_DB_HOSTS = /* @__PURE__ */ new Set([
69
+ "localhost",
70
+ "127.0.0.1",
71
+ "0.0.0.0",
72
+ "::1"
73
+ ]);
53
74
  Migrator = class {
54
75
  isMissingMigrationTableError(error) {
55
- if (typeof error !== "object" || error === null) return false;
76
+ if (!isObjectValue(error) || error === null) return false;
56
77
  const maybePostgresError = error;
57
- return maybePostgresError.code === "42P01" && typeof maybePostgresError.message === "string" && maybePostgresError.message.includes("knex_migrations");
78
+ return maybePostgresError.code === "42P01" && isStringValue(maybePostgresError.message) && maybePostgresError.message.includes("knex_migrations");
58
79
  }
80
+ /** 현재 실행 환경에서 허용된 마이그레이션 대상 키를 반환합니다. */
59
81
  getMigrationTargetKeys() {
60
82
  const connKeys = Object.keys(Sonamu.dbConfig).filter((key) => !key.endsWith("_readonly"));
61
83
  if (isLocal()) return connKeys;
62
84
  const environment = getSonamuEnvironment();
63
85
  return connKeys.filter((key) => key === environment);
64
86
  }
65
- async runMigrationsSequentially(conns, action) {
87
+ async runMigrationsSequentially(conns, action, options) {
66
88
  const results = [];
67
89
  for (const { connKey, knex } of conns) {
68
- const [batchNo, applied] = action === "apply" ? await knex.migrate.latest() : await knex.migrate.rollback();
90
+ const progress = this.createProgressHooks(action, connKey, options);
91
+ let migrationResult;
92
+ try {
93
+ migrationResult = action === "apply" ? await knex.migrate.latest(progress) : await knex.migrate.rollback(progress);
94
+ } catch (caught) {
95
+ throw new MigrationTargetExecutionError(connKey, caught);
96
+ }
97
+ const [batchNo, applied] = migrationResult;
69
98
  results.push({
70
99
  connKey,
71
100
  batchNo,
72
101
  applied
73
102
  });
103
+ this.emitProgress(options, {
104
+ type: "target-complete",
105
+ action,
106
+ connKey,
107
+ batchNo,
108
+ files: applied
109
+ });
74
110
  }
75
111
  return results;
76
112
  }
113
+ migrationName(migration) {
114
+ if (isStringValue(migration)) return path.basename(migration);
115
+ if (isObjectValue(migration) && migration !== null) {
116
+ const candidate = migration;
117
+ if (isStringValue(candidate.file)) return path.basename(candidate.file);
118
+ if (isStringValue(candidate.name)) return path.basename(candidate.name);
119
+ }
120
+ return String(migration);
121
+ }
122
+ emitProgress(options, event) {
123
+ try {
124
+ options?.onProgress?.(event);
125
+ } catch (error) {
126
+ console.warn("Migration progress observer failed:", error);
127
+ }
128
+ }
129
+ createProgressHooks(action, connKey, options) {
130
+ let files = [];
131
+ const emitFile = (type, migration) => {
132
+ const file = this.migrationName(migration);
133
+ const index = Math.max(files.indexOf(file), 0);
134
+ this.emitProgress(options, {
135
+ type,
136
+ action,
137
+ connKey,
138
+ file,
139
+ index,
140
+ total: files.length
141
+ });
142
+ };
143
+ return {
144
+ beforeAll: async (_knex, migrations) => {
145
+ files = migrations.map((migration) => this.migrationName(migration));
146
+ this.emitProgress(options, {
147
+ type: "target-start",
148
+ action,
149
+ connKey,
150
+ files
151
+ });
152
+ },
153
+ beforeEach: async (_knex, migrations) => {
154
+ migrations.forEach((migration) => emitFile("file-start", migration));
155
+ },
156
+ afterEach: async (_knex, migrations) => {
157
+ migrations.forEach((migration) => emitFile("file-executed", migration));
158
+ }
159
+ };
160
+ }
161
+ assertMigrationTarget(connKey) {
162
+ if (!this.getMigrationTargetKeys().includes(connKey)) throw new Error(`Migration target is not allowed in NODE_ENV=${getSonamuEnvironment()}: ${String(connKey)}`);
163
+ }
164
+ /**
165
+ * 마이그레이션 대상 커넥션의 정적 메타데이터를 반환합니다.
166
+ * DB에 연결하지 않으므로 CLI와 Web이 상태 조회 전에 즉시 사용할 수 있습니다.
167
+ *
168
+ * @category 분리형 마이그레이션 API
169
+ */
170
+ getConnections() {
171
+ const slackConfirm = new SlackConfirm();
172
+ return this.getMigrationTargetKeys().map((connKey) => {
173
+ const connection = Sonamu.dbConfig[connKey].connection;
174
+ const host = connection.host ?? "localhost";
175
+ return {
176
+ connKey,
177
+ name: String(connKey),
178
+ host,
179
+ port: connection.port ?? 5432,
180
+ database: connection.database ?? "",
181
+ remote: !LOCAL_DB_HOSTS.has(host.toLowerCase()),
182
+ requiresApproval: slackConfirm.isTargetRequiresApproval(connKey)
183
+ };
184
+ });
185
+ }
186
+ /**
187
+ * 소스에 존재하는 마이그레이션 파일 목록을 반환합니다.
188
+ *
189
+ * @category 분리형 마이그레이션 API
190
+ */
77
191
  async getMigrationCodes() {
78
192
  const srcMigrationsDir = path.join(Sonamu.apiRootPath, "src", "migrations");
79
193
  if (!await exists(srcMigrationsDir)) await mkdir(srcMigrationsDir, { recursive: true });
@@ -85,127 +199,156 @@ var init_migrator = __esmMin((() => {
85
199
  return codes;
86
200
  }
87
201
  /**
88
- * 타겟별 마이그레이션 상태와 코드 생성/준비 상태를 구해옵니다.
89
- * 실제로 DB에 접근도 하고 마이그레이션 코드 파일도 확인하고,
90
- * 필요하다면 적용할 수 있는 코드를 생성까지 해옵니다.
202
+ * 커넥션 하나의 현재 버전과 pending 목록을 독립적으로 조회합니다.
203
+ * 여러 대상은 호출자가 병렬로 조립할 수 있습니다.
91
204
  *
92
- * CLI와 Sonamu UI에서 사용됩니다.
93
- *
94
- * @returns
205
+ * @category 분리형 마이그레이션 API
95
206
  */
96
- async getStatus() {
207
+ async getConnectionStatus(connKey) {
208
+ this.assertMigrationTarget(connKey);
209
+ const startedAt = performance.now();
97
210
  const codes = await this.getMigrationCodes();
98
- Naite.t("migrator:getStatus:codes", codes);
99
- const connKeys = this.getMigrationTargetKeys();
100
- let migrationStatusError;
101
- const statuses = await Promise.all(connKeys.map(async (connKey) => {
102
- const knexOptions = Sonamu.dbConfig[connKey];
103
- const connection = knexOptions.connection;
104
- const tConn = createKnexInstance({
105
- ...knexOptions,
106
- connection: {
107
- ...connection,
108
- connectionTimeoutMillis: MIGRATION_CONN_TIMEOUT_MS
109
- },
110
- pool: {
111
- ...knexOptions.pool,
112
- min: 0,
113
- acquireTimeoutMillis: MIGRATION_CONN_TIMEOUT_MS,
114
- createTimeoutMillis: MIGRATION_CONN_TIMEOUT_MS,
115
- propagateCreateError: true
116
- }
117
- });
118
- const connString = `pg://${connection.user ?? ""}@${connection.host}:${connection.port}/${connection.database}`;
119
- try {
120
- try {
121
- await withTimeout(tConn.raw("select 1"), MIGRATION_CONN_TIMEOUT_MS, () => /* @__PURE__ */ new Error(`DB 연결 시간 초과 (${MIGRATION_CONN_TIMEOUT_MS}ms) — ${connection.host}:${connection.port}/${connection.database}`));
122
- } catch (err) {
123
- console.warn(chalk.yellow(`${connKey}의 마이그레이션 상태를 가져오는 데에 실패하였습니다. 데이터베이스에 연결할 수 없습니다.\n시도한 연결 설정:\n${JSON.stringify(knexOptions.connection, null, 2)}\n발생한 에러:\n${err}\n`));
124
- migrationStatusError = err instanceof Error ? err.message : String(err);
125
- return {
126
- name: connKey,
127
- connKey,
128
- connString,
129
- currentVersion: "error",
130
- status: "error",
131
- pending: []
132
- };
133
- }
134
- const status = await (async () => {
135
- try {
136
- return await tConn.migrate.status();
137
- } catch (err) {
138
- if (this.isMissingMigrationTableError(err)) return codes.length;
139
- console.warn(chalk.yellow(`${connKey}의 마이그레이션 상태를 가져오는 데에 실패하였습니다. 데이터베이스가 올바르게 구성되지 않은 것 같습니다. 확인하시고 다시 시도해주세요.\n시도한 연결 설정:\n${JSON.stringify(knexOptions.connection, null, 2)}\n발생한 에러:\n${err}\n`));
140
- migrationStatusError = err instanceof Error ? err.message : String(err);
141
- return "error";
142
- }
143
- })();
144
- const pending = await (async () => {
145
- try {
146
- const [, fdList] = await tConn.migrate.list();
147
- return fdList.map((fd) => fd.file.replace(".ts", ""));
148
- } catch (err) {
149
- if (this.isMissingMigrationTableError(err)) return codes.map((code) => code.name);
150
- migrationStatusError = err instanceof Error ? err.message : String(err);
151
- return [];
152
- }
153
- })();
154
- const currentVersion = await (async () => {
155
- try {
156
- return await tConn.migrate.currentVersion();
157
- } catch (_err) {
158
- if (this.isMissingMigrationTableError(_err)) return "none";
159
- migrationStatusError = _err instanceof Error ? _err.message : String(_err);
160
- return "error";
161
- }
162
- })();
163
- Naite.t("migrator:getStatus:status", status);
164
- return {
165
- name: connKey,
166
- connKey,
167
- connString,
168
- currentVersion,
169
- status,
170
- pending
171
- };
172
- } finally {
173
- await withTimeout(tConn.destroy(), MIGRATION_CONN_TIMEOUT_MS, () => /* @__PURE__ */ new Error("connection destroy timeout")).catch(() => {});
211
+ const knexOptions = Sonamu.dbConfig[connKey];
212
+ const connection = knexOptions.connection;
213
+ const tConn = createKnexInstance({
214
+ ...knexOptions,
215
+ connection: {
216
+ ...connection,
217
+ connectionTimeoutMillis: MIGRATION_CONN_TIMEOUT_MS
218
+ },
219
+ pool: {
220
+ ...knexOptions.pool,
221
+ min: 0,
222
+ acquireTimeoutMillis: MIGRATION_CONN_TIMEOUT_MS,
223
+ createTimeoutMillis: MIGRATION_CONN_TIMEOUT_MS,
224
+ propagateCreateError: true
174
225
  }
175
- }));
176
- Naite.t("migrator:getStatus:conns", statuses);
177
- const preparedCodes = await (async () => {
178
- const status0conn = statuses.find((status) => status.status === 0);
179
- if (status0conn === void 0) {
180
- console.warn(chalk.yellow(`While trying to prepare migration codes, we found that there is no database to compare migrations. We need at least one database where every migration is applied(status === 0). You might want to apply your existing migrations to one of the databases.`));
226
+ });
227
+ try {
228
+ await withTimeout(tConn.raw("select 1"), MIGRATION_CONN_TIMEOUT_MS, () => {
229
+ return /* @__PURE__ */ new Error(`DB 연결 시간 초과 (${MIGRATION_CONN_TIMEOUT_MS}ms) — ${connection.host}:${connection.port}/${connection.database}`);
230
+ });
231
+ let error;
232
+ const status = await tConn.migrate.status().catch((caught) => {
233
+ if (this.isMissingMigrationTableError(caught)) return codes.length;
234
+ error = caught instanceof Error ? caught.message : String(caught);
235
+ return "error";
236
+ });
237
+ const pending = await tConn.migrate.list().then(([, files]) => files.map(({ file }) => file.replace(/\.ts$/, "")), (cause) => {
238
+ if (this.isMissingMigrationTableError(cause)) return codes.map(({ name }) => name);
239
+ error ??= cause instanceof Error ? cause.message : String(cause);
181
240
  return [];
182
- }
183
- const compareDBconn = createKnexInstance(Sonamu.dbConfig[status0conn.connKey]);
184
- try {
185
- return await this.compareMigrations(compareDBconn);
186
- } finally {
187
- await compareDBconn.destroy();
188
- }
189
- })();
241
+ });
242
+ const currentVersion = await tConn.migrate.currentVersion().catch((cause) => {
243
+ if (this.isMissingMigrationTableError(cause)) return "none";
244
+ error ??= cause instanceof Error ? cause.message : String(cause);
245
+ return "error";
246
+ });
247
+ Naite.t("migrator:getStatus:status", status);
248
+ const connectionStatus = {
249
+ connKey,
250
+ currentVersion,
251
+ status,
252
+ pending,
253
+ latencyMs: performance.now() - startedAt
254
+ };
255
+ if (error !== void 0) connectionStatus.error = error;
256
+ return connectionStatus;
257
+ } catch (caught) {
258
+ const error = caught instanceof Error ? caught.message : String(caught);
259
+ console.warn(chalk.yellow(`${String(connKey)}의 마이그레이션 상태를 가져오는 데에 실패하였습니다.\n${error}`));
260
+ return {
261
+ connKey,
262
+ currentVersion: "error",
263
+ status: "error",
264
+ pending: [],
265
+ latencyMs: performance.now() - startedAt,
266
+ error
267
+ };
268
+ } finally {
269
+ await withTimeout(tConn.destroy(), MIGRATION_CONN_TIMEOUT_MS, () => {
270
+ return /* @__PURE__ */ new Error("connection destroy timeout");
271
+ }).catch(() => {});
272
+ }
273
+ }
274
+ /**
275
+ * 최신 상태인 기준 DB와 엔티티 정의를 비교해 생성 예정 코드를 반환합니다.
276
+ *
277
+ * @category 분리형 마이그레이션 API
278
+ */
279
+ async getPreparedCodes(compareConnKey) {
280
+ const status = await this.getConnectionStatus(compareConnKey);
281
+ if (status.status !== 0 || status.error !== void 0) throw new Error(`Migration comparison requires an up-to-date database: ${String(compareConnKey)}`);
282
+ return this.compareWithConnection(compareConnKey);
283
+ }
284
+ async compareWithConnection(compareConnKey) {
285
+ const compareDB = createKnexInstance(Sonamu.dbConfig[compareConnKey]);
286
+ try {
287
+ return await this.compareMigrations(compareDB);
288
+ } finally {
289
+ await compareDB.destroy();
290
+ }
291
+ }
292
+ /**
293
+ * @deprecated 신규 UI에서는 커넥션별 조회 API를 사용합니다.
294
+ * 기존 CLI와 스크립트 호환을 위해 전체 상태를 조립합니다.
295
+ * @category 호환용 마이그레이션 API
296
+ */
297
+ async getStatus() {
298
+ const [codes, connections] = await Promise.all([this.getMigrationCodes(), Promise.resolve(this.getConnections())]);
299
+ Naite.t("migrator:getStatus:codes", codes);
300
+ const connectionStatuses = await Promise.all(connections.map(({ connKey }) => this.getConnectionStatus(connKey)));
301
+ const conns = connections.map((connection, index) => {
302
+ const status = connectionStatuses[index];
303
+ assert(status !== void 0);
304
+ const configured = Sonamu.dbConfig[connection.connKey].connection;
305
+ return {
306
+ name: connection.name,
307
+ connKey: connection.connKey,
308
+ connString: `pg://${configured.user ?? ""}@${configured.host}:${configured.port}/${configured.database}`,
309
+ currentVersion: status.currentVersion,
310
+ status: status.status,
311
+ pending: status.pending
312
+ };
313
+ });
314
+ Naite.t("migrator:getStatus:conns", conns);
315
+ const compareConn = connectionStatuses.find(({ status, error }) => status === 0 && error === void 0);
316
+ const preparedCodes = compareConn === void 0 ? [] : await this.compareWithConnection(compareConn.connKey);
190
317
  Naite.t("migrator:getStatus:preparedCodes", preparedCodes);
191
318
  return {
192
- conns: statuses,
319
+ conns,
193
320
  codes,
194
321
  preparedCodes,
195
- error: migrationStatusError
322
+ error: connectionStatuses.find(({ error }) => error !== void 0)?.error
196
323
  };
197
324
  }
198
325
  /**
199
- * 마이그레이션을 적용하거나 롤백합니다.
200
- * Sonamu UI에서 마이그레이션 작업을 수행할 때 사용됩니다.
326
+ * 대상 DB에 pending 마이그레이션을 적용합니다.
327
+ * CLI와 Web은 같은 메서드를 사용하며, Web은 `onProgress`를 stream으로 변환합니다.
201
328
  *
202
- * CLI와 Sonamu UI에서 사용됩니다.
329
+ * @category 분리형 마이그레이션 API
330
+ */
331
+ async apply(targets, options) {
332
+ return this.runActionWithProgress("apply", targets, options);
333
+ }
334
+ /**
335
+ * 대상 DB에서 가장 최근 migration batch를 롤백합니다.
336
+ * CLI와 Web은 같은 메서드를 사용하며, Web은 `onProgress`를 stream으로 변환합니다.
203
337
  *
204
- * @param action 작업 유형 (apply/rollback)
205
- * @param targets 작업 대상 DB 설정 키 (keyof SonamuDBConfig)
206
- * @returns 작업 결과
338
+ * @category 분리형 마이그레이션 API
339
+ */
340
+ async rollback(targets, options) {
341
+ return this.runActionWithProgress("rollback", targets, options);
342
+ }
343
+ /**
344
+ * @deprecated action 문자열 대신 {@link apply} 또는 {@link rollback}을 직접 사용합니다.
345
+ * 기존 외부 호출의 하위 호환만을 위해 유지합니다.
346
+ * @category 호환용 마이그레이션 API
207
347
  */
208
348
  async runAction(action, targets) {
349
+ return action === "apply" ? this.apply(targets) : this.rollback(targets);
350
+ }
351
+ async runActionWithProgress(action, targets, options) {
209
352
  Naite.t("migrator:runAction:action", action);
210
353
  Naite.t("migrator:runAction:targets", targets);
211
354
  const allowedTargets = new Set(this.getMigrationTargetKeys());
@@ -214,18 +357,13 @@ var init_migrator = __esmMin((() => {
214
357
  const configs = unique(targets.map((target) => ({
215
358
  connKey: target,
216
359
  options: Sonamu.dbConfig[target]
217
- })).filter((c) => c.options !== void 0), ({ options }) => `${options.connection.host}:${options.connection.port ?? 5432}/${options.connection.database}`);
360
+ })).filter((c) => c.options !== void 0), ({ options: dbOptions }) => `${dbOptions.connection.host}:${dbOptions.connection.port ?? 5432}/${dbOptions.connection.database}`);
218
361
  const conns = await Promise.all(configs.map(async (config) => ({
219
362
  connKey: config.connKey,
220
363
  knex: createKnexInstance(config.options)
221
364
  })));
222
365
  try {
223
- const result = await (async () => {
224
- switch (action) {
225
- case "apply": return this.runMigrationsSequentially(conns, "apply");
226
- case "rollback": return this.runMigrationsSequentially(conns, "rollback");
227
- }
228
- })();
366
+ const result = await this.runMigrationsSequentially(conns, action, options);
229
367
  Naite.t("migrator:runAction:result", result);
230
368
  return result;
231
369
  } finally {
@@ -234,45 +372,9 @@ var init_migrator = __esmMin((() => {
234
372
  }));
235
373
  }
236
374
  }
237
- /**
238
- * 삭제 가능한 마이그레이션 코드 파일을 검증합니다.
239
- *
240
- * @param conns 마이그레이션 상태 배열
241
- * @param codeNames 삭제할 마이그레이션 코드 파일 이름 배열
242
- * @returns 삭제 가능 여부 및 적용된 마이그레이션 코드 파일 이름
243
- */
244
- validateDeletable(conns, codeNames) {
245
- const appliedCodes = codeNames.filter((codeName) => conns.some((conn) => !conn.pending.includes(codeName)));
246
- return {
247
- canDelete: appliedCodes.length === 0,
248
- appliedCodes
249
- };
250
- }
251
- /**
252
- * 마이그레이션 코드 파일을 삭제합니다.
253
- *
254
- * Sonamu UI에서 사용됩니다.
255
- *
256
- * @param codeNames 삭제할 마이그레이션 코드 파일 이름 배열
257
- * @returns 삭제된 마이그레이션 코드 파일 개수
258
- */
259
- async delCodes(codeNames) {
260
- const { conns } = await this.getStatus();
261
- const { canDelete, appliedCodes } = this.validateDeletable(conns, codeNames);
262
- if (!canDelete) throw new Error(`You cannot delete a migration file if there is already applied. Applied codes: ${appliedCodes.join(", ")}`);
263
- return sum(await Promise.all(codeNames.map(async (codeName) => {
264
- const filePath = `${Sonamu.apiRootPath}/src/migrations/${codeName}.ts`;
265
- if (await exists(filePath)) {
266
- await unlink(filePath);
267
- return 1;
268
- }
269
- return 0;
270
- })));
271
- }
272
375
  genDateTag(index, baseDate = /* @__PURE__ */ new Date()) {
273
376
  const date = new Date(baseDate.getTime() + index * 1e3);
274
- const pad = (num, size = 2) => num.toString().padStart(size, "0");
275
- return date.getFullYear().toString() + pad(date.getMonth() + 1) + pad(date.getDate()) + pad(date.getHours()) + pad(date.getMinutes()) + pad(date.getSeconds());
377
+ return date.getFullYear().toString() + padDatePart(date.getMonth() + 1) + padDatePart(date.getDate()) + padDatePart(date.getHours()) + padDatePart(date.getMinutes()) + padDatePart(date.getSeconds());
276
378
  }
277
379
  /**
278
380
  * 마이그레이션 코드 파일을 생성합니다.
@@ -281,8 +383,8 @@ var init_migrator = __esmMin((() => {
281
383
  *
282
384
  * @returns 생성된 마이그레이션 코드 파일 개수
283
385
  */
284
- async generatePreparedCodes() {
285
- const { preparedCodes } = await this.getStatus();
386
+ async generatePreparedCodes(compareConnKey) {
387
+ const preparedCodes = compareConnKey === void 0 ? (await this.getStatus()).preparedCodes : await this.getPreparedCodes(compareConnKey);
286
388
  Naite.t("migrator:generatePreparedCodes:preparedCodes", preparedCodes);
287
389
  if (preparedCodes.length === 0) {
288
390
  console.log(chalk.green("\n현재 모두 싱크된 상태입니다."));
@@ -328,13 +430,12 @@ var init_migrator = __esmMin((() => {
328
430
  return codes;
329
431
  }
330
432
  /**
331
- * Shadow DB 테스트를 진행합니다.
332
- *
333
- * Sonamu UI에서 사용됩니다.
433
+ * test DB의 snapshot으로 임시 Shadow DB를 만들고 전체 마이그레이션을 검증합니다.
434
+ * CLI와 Web은 `onProgress` 유무만 달리해 같은 실행 의미를 공유할 수 있습니다.
334
435
  *
335
- * @returns Shadow DB 테스트 결과
436
+ * @category 분리형 마이그레이션 API
336
437
  */
337
- async runShadowTest() {
438
+ async runShadowTest(options) {
338
439
  const baseTestConn = Sonamu.dbConfig.test.connection;
339
440
  const workerId = process.env.SONAMU_WORKER_DB === "true" ? process.env.VITEST_POOL_ID : null;
340
441
  const templateDatabase = workerId !== null ? `${baseTestConn.database}_${workerId ?? "1"}` : baseTestConn.database;
@@ -373,11 +474,19 @@ var init_migrator = __esmMin((() => {
373
474
  }
374
475
  });
375
476
  try {
376
- const [batchNo, applied] = await sdb.migrate.latest();
477
+ const progress = this.createProgressHooks("shadow", "shadow", options);
478
+ const [batchNo, applied] = await sdb.migrate.latest(progress);
377
479
  !isTest() && console.log(chalk.green("Shadow DB 테스트에 성공했습니다!"), {
378
480
  batchNo,
379
481
  applied
380
482
  });
483
+ this.emitProgress(options, {
484
+ type: "target-complete",
485
+ action: "shadow",
486
+ connKey: "shadow",
487
+ batchNo,
488
+ files: applied
489
+ });
381
490
  return [{
382
491
  connKey: "shadow",
383
492
  batchNo,
@@ -385,7 +494,7 @@ var init_migrator = __esmMin((() => {
385
494
  }];
386
495
  } catch (e) {
387
496
  console.error(e);
388
- throw new ServiceUnavailableException(SD("sonamu.error.shadowDbTestFailed"));
497
+ throw new MigrationTargetExecutionError("shadow", new ServiceUnavailableException(SD("sonamu.error.shadowDbTestFailed")));
389
498
  } finally {
390
499
  await sdb.destroy();
391
500
  }
@@ -404,6 +513,6 @@ var init_migrator = __esmMin((() => {
404
513
  }));
405
514
  //#endregion
406
515
  init_migrator();
407
- export { Migrator, init_migrator };
516
+ export { MigrationTargetExecutionError, Migrator, init_migrator };
408
517
 
409
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlncmF0b3IuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL21pZ3JhdGlvbi9taWdyYXRvci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCB7IG1rZGlyLCByZWFkZGlyLCB1bmxpbmssIHdyaXRlRmlsZSB9IGZyb20gXCJmcy9wcm9taXNlc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcblxuaW1wb3J0IGNoYWxrIGZyb20gXCJjaGFsa1wiO1xuaW1wb3J0IHsgdHlwZSBLbmV4IH0gZnJvbSBcImtuZXhcIjtcbmltcG9ydCB7IGdyb3VwLCBzdW0sIHVuaXF1ZSB9IGZyb20gXCJyYWRhc2hpXCI7XG5cbmltcG9ydCB7IFNvbmFtdSB9IGZyb20gXCIuLi9hcGkvc29uYW11XCI7XG5pbXBvcnQgeyBEQiB9IGZyb20gXCIuLi9kYXRhYmFzZS9kYlwiO1xuaW1wb3J0IHsgdHlwZSBTb25hbXVEQkNvbmZpZyB9IGZyb20gXCIuLi9kYXRhYmFzZS9kYlwiO1xuaW1wb3J0IHsgY3JlYXRlS25leEluc3RhbmNlIH0gZnJvbSBcIi4uL2RhdGFiYXNlL2tuZXhcIjtcbmltcG9ydCB7IFNEIH0gZnJvbSBcIi4uL2RpY3Qvc2RcIjtcbmltcG9ydCB7IEVudGl0eU1hbmFnZXIgfSBmcm9tIFwiLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyBnZXRTb25hbXVFbnZpcm9ubWVudCB9IGZyb20gXCIuLi9lbnZcIjtcbmltcG9ydCB7IFNlcnZpY2VVbmF2YWlsYWJsZUV4Y2VwdGlvbiB9IGZyb20gXCIuLi9leGNlcHRpb25zL3NvLWV4Y2VwdGlvbnNcIjtcbmltcG9ydCB7IE5haXRlIH0gZnJvbSBcIi4uL25haXRlL25haXRlXCI7XG5pbXBvcnQgeyB0eXBlIEdlbk1pZ3JhdGlvbkNvZGUsIHR5cGUgTWlncmF0aW9uU2V0IH0gZnJvbSBcIi4uL3R5cGVzL3R5cGVzXCI7XG5pbXBvcnQgeyBpc0xvY2FsLCBpc1Rlc3QgfSBmcm9tIFwiLi4vdXRpbHMvY29udHJvbGxlclwiO1xuaW1wb3J0IHsgZXhpc3RzIH0gZnJvbSBcIi4uL3V0aWxzL2ZzLXV0aWxzXCI7XG5pbXBvcnQgeyBnZW5lcmF0ZUFsdGVyQ29kZSwgZ2VuZXJhdGVDcmVhdGVDb2RlIH0gZnJvbSBcIi4vY29kZS1nZW5lcmF0aW9uXCI7XG5pbXBvcnQgeyBnZXRNaWdyYXRpb25TZXRGcm9tRW50aXR5IH0gZnJvbSBcIi4vbWlncmF0aW9uLXNldFwiO1xuaW1wb3J0IHsgUG9zdGdyZVNRTFNjaGVtYVJlYWRlciB9IGZyb20gXCIuL3Bvc3RncmVzcWwtc2NoZW1hLXJlYWRlclwiO1xuaW1wb3J0IHsgdHlwZSBDb25uU3RyaW5nLCB0eXBlIE1pZ3JhdGlvbkNvZGUsIHR5cGUgTWlncmF0aW9uU3RhdHVzIH0gZnJvbSBcIi4vdHlwZXNcIjtcblxuZXhwb3J0IHR5cGUgTWlncmF0aW9uUmVzdWx0ID0ge1xuICBjb25uS2V5OiBzdHJpbmc7XG4gIGJhdGNoTm86IG51bWJlcjtcbiAgYXBwbGllZDogc3RyaW5nW107XG59W107XG5cbi8vIOuniOydtOq3uOugiOydtOyFmCDsg4Htg5wg7KGw7ZqMIOyLnCBEQiDsl7DqsrAg7ZmV7J24IO2DgOyehOyVhOybgyhtcykuXG4vLyBjcmVhdGVLbmV4SW5zdGFuY2XsnZgg7Luk64Sl7IWYIO2ajeuTnSDtg4DsnoTslYTsm4MoMzDstIgp7JeQIHN0YXR1cy9saXN0L2N1cnJlbnRWZXJzaW9u7J20XG4vLyDqsIHqsIEg6rG466as66m0IENMSS9VSeqwgCDstZzrjIAg7IiY7IutIOy0iCBoYW5n7ZWc64ukLiDsoJXsg4Eg7J2R64u17J2AIOyImOuwsSBtc+ydtOuvgOuhnCA17LSI66m0IOy2qeu2hO2VmOuLpC5cbmNvbnN0IE1JR1JBVElPTl9DT05OX1RJTUVPVVRfTVMgPSA1MDAwO1xuXG4vKipcbiAqIOyjvOyWtOynhCBQcm9taXNl6rCAIG1zIOyViOyXkCDsmYTro4zrkJjsp4Ag7JWK7Jy866m0IG9uVGltZW91dCDsl5Drn6zroZwgcmVqZWN07ZWc64ukLlxuICog7JuQ67O4IFByb21pc2Ug7J6Q7LK064qUIOqzhOyGjSDsp4TtlonrkJjrr4DroZwsIO2YuOy2nOy4oeyXkOyEnCDsu6TrhKXshZgg7KCV66asKGRlc3Ryb3kp66W8IOyxheyehOynhOuLpC5cbiAqL1xuZnVuY3Rpb24gd2l0aFRpbWVvdXQ8VD4ocHJvbWlzZTogUHJvbWlzZTxUPiwgbXM6IG51bWJlciwgb25UaW1lb3V0OiAoKSA9PiBFcnJvcik6IFByb21pc2U8VD4ge1xuICByZXR1cm4gbmV3IFByb21pc2U8VD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IHRpbWVyID0gc2V0VGltZW91dCgoKSA9PiByZWplY3Qob25UaW1lb3V0KCkpLCBtcyk7XG4gICAgcHJvbWlzZS50aGVuKFxuICAgICAgKHZhbHVlKSA9PiB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lcik7XG4gICAgICAgIHJlc29sdmUodmFsdWUpO1xuICAgICAgfSxcbiAgICAgIChlcnJvcikgPT4ge1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSxcbiAgICApO1xuICB9KTtcbn1cblxuZXhwb3J0IGNsYXNzIE1pZ3JhdG9yIHtcbiAgcHJpdmF0ZSBpc01pc3NpbmdNaWdyYXRpb25UYWJsZUVycm9yKGVycm9yOiB1bmtub3duKTogYm9vbGVhbiB7XG4gICAgaWYgKHR5cGVvZiBlcnJvciAhPT0gXCJvYmplY3RcIiB8fCBlcnJvciA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGNvbnN0IG1heWJlUG9zdGdyZXNFcnJvciA9IGVycm9yIGFzIHsgY29kZT86IHVua25vd247IG1lc3NhZ2U/OiB1bmtub3duIH07XG4gICAgcmV0dXJuIChcbiAgICAgIG1heWJlUG9zdGdyZXNFcnJvci5jb2RlID09PSBcIjQyUDAxXCIgJiZcbiAgICAgIHR5cGVvZiBtYXliZVBvc3RncmVzRXJyb3IubWVzc2FnZSA9PT0gXCJzdHJpbmdcIiAmJlxuICAgICAgbWF5YmVQb3N0Z3Jlc0Vycm9yLm1lc3NhZ2UuaW5jbHVkZXMoXCJrbmV4X21pZ3JhdGlvbnNcIilcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRNaWdyYXRpb25UYXJnZXRLZXlzKCk6IChrZXlvZiBTb25hbXVEQkNvbmZpZylbXSB7XG4gICAgY29uc3QgY29ubktleXMgPSBPYmplY3Qua2V5cyhTb25hbXUuZGJDb25maWcpLmZpbHRlcihcbiAgICAgIChrZXkpID0+ICFrZXkuZW5kc1dpdGgoXCJfcmVhZG9ubHlcIiksXG4gICAgKSBhcyAoa2V5b2YgU29uYW11REJDb25maWcpW107XG5cbiAgICBpZiAoaXNMb2NhbCgpKSB7XG4gICAgICByZXR1cm4gY29ubktleXM7XG4gICAgfVxuXG4gICAgY29uc3QgZW52aXJvbm1lbnQgPSBnZXRTb25hbXVFbnZpcm9ubWVudCgpO1xuICAgIHJldHVybiBjb25uS2V5cy5maWx0ZXIoKGtleSkgPT4ga2V5ID09PSBlbnZpcm9ubWVudCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJ1bk1pZ3JhdGlvbnNTZXF1ZW50aWFsbHkoXG4gICAgY29ubnM6IHsgY29ubktleToga2V5b2YgU29uYW11REJDb25maWc7IGtuZXg6IEtuZXggfVtdLFxuICAgIGFjdGlvbjogXCJhcHBseVwiIHwgXCJyb2xsYmFja1wiLFxuICApOiBQcm9taXNlPE1pZ3JhdGlvblJlc3VsdD4ge1xuICAgIGNvbnN0IHJlc3VsdHM6IE1pZ3JhdGlvblJlc3VsdCA9IFtdO1xuXG4gICAgZm9yIChjb25zdCB7IGNvbm5LZXksIGtuZXggfSBvZiBjb25ucykge1xuICAgICAgY29uc3QgW2JhdGNoTm8sIGFwcGxpZWRdID1cbiAgICAgICAgYWN0aW9uID09PSBcImFwcGx5XCIgPyBhd2FpdCBrbmV4Lm1pZ3JhdGUubGF0ZXN0KCkgOiBhd2FpdCBrbmV4Lm1pZ3JhdGUucm9sbGJhY2soKTtcblxuICAgICAgcmVzdWx0cy5wdXNoKHtcbiAgICAgICAgY29ubktleSxcbiAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgYXBwbGllZCxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBnZXRNaWdyYXRpb25Db2RlcygpOiBQcm9taXNlPE1pZ3JhdGlvbkNvZGVbXT4ge1xuICAgIGNvbnN0IHNyY01pZ3JhdGlvbnNEaXIgPSBwYXRoLmpvaW4oU29uYW11LmFwaVJvb3RQYXRoLCBcInNyY1wiLCBcIm1pZ3JhdGlvbnNcIik7IC8vIOydtOqxtCDtmZjqsr3sl5Ag6rSA6rOE7JeG7J20IO2VreyDgSBzcmPsl5DshJwg7LC+7JWE7JW8IO2VtOyalC5cblxuICAgIGlmICghKGF3YWl0IGV4aXN0cyhzcmNNaWdyYXRpb25zRGlyKSkpIHtcbiAgICAgIGF3YWl0IG1rZGlyKHNyY01pZ3JhdGlvbnNEaXIsIHtcbiAgICAgICAgcmVjdXJzaXZlOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29uc3QgY29kZXMgPSAoYXdhaXQgcmVhZGRpcihzcmNNaWdyYXRpb25zRGlyKSlcbiAgICAgIC5maWx0ZXIoKGYpID0+IGYuZW5kc1dpdGgoXCIudHNcIikpXG4gICAgICAubWFwKChmKSA9PiAoe1xuICAgICAgICBuYW1lOiBmLnJlcGxhY2UoXCIudHNcIiwgXCJcIiksXG4gICAgICAgIHBhdGg6IHBhdGguam9pbihzcmNNaWdyYXRpb25zRGlyLCBmKSxcbiAgICAgIH0pKVxuICAgICAgLnRvU29ydGVkKChhLCBiKSA9PiAoYS5uYW1lIDwgYi5uYW1lID8gMSA6IC0xKSk7IC8vIOydtOumhCDrgrTrprzssKjsiJwg7KCV66CsKOy1nOyLoOyInClcblxuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpnZXRNaWdyYXRpb25Db2RlczpyZXN1bHRzXCIsIGNvZGVzKTtcbiAgICByZXR1cm4gY29kZXM7XG4gIH1cblxuICAvKipcbiAgICog7YOA6rKf67OEIOuniOydtOq3uOugiOydtOyFmCDsg4Htg5zsmYAg7L2U65OcIOyDneyEsS/spIDruYQg7IOB7YOc66W8IOq1rO2VtOyYteuLiOuLpC5cbiAgICog7Iuk7KCc66GcIERC7JeQIOygkeq3vOuPhCDtlZjqs6Ag66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbzrj4Qg7ZmV7J247ZWY6rOgLFxuICAgKiDtlYTsmpTtlZjri6TrqbQg7KCB7Jqp7ZWgIOyImCDsnojripQg7L2U65Oc66W8IOyDneyEseq5jOyngCDtlbTsmLXri4jri6QuXG4gICAqXG4gICAqIENMSeyZgCBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcmV0dXJuc1xuICAgKi9cbiAgYXN5bmMgZ2V0U3RhdHVzKCk6IFByb21pc2U8TWlncmF0aW9uU3RhdHVzPiB7XG4gICAgY29uc3QgY29kZXMgPSBhd2FpdCB0aGlzLmdldE1pZ3JhdGlvbkNvZGVzKCk7XG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOmdldFN0YXR1czpjb2Rlc1wiLCBjb2Rlcyk7XG5cbiAgICBjb25zdCBjb25uS2V5cyA9IHRoaXMuZ2V0TWlncmF0aW9uVGFyZ2V0S2V5cygpO1xuXG4gICAgbGV0IG1pZ3JhdGlvblN0YXR1c0Vycm9yOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgICBjb25zdCBzdGF0dXNlcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgY29ubktleXMubWFwKGFzeW5jIChjb25uS2V5KSA9PiB7XG4gICAgICAgIGNvbnN0IGtuZXhPcHRpb25zID0gU29uYW11LmRiQ29uZmlnW2Nvbm5LZXldO1xuICAgICAgICBjb25zdCBjb25uZWN0aW9uID0ga25leE9wdGlvbnMuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZztcbiAgICAgICAgLy8g7IOB7YOcIOyhsO2ajOyaqSDsu6TrhKXshZjsnYAgZmFpbC1mYXN066GcIOunjOuToOuLpDog67aI7Ya1IERC7JeQ7IScIOy7pOuEpeyFmCDtmo3rk53snYQg66y07ZWc7KCVXG4gICAgICAgIC8vIOyerOyLnOuPhO2VmOupsCBDTEkg7ZSE66Gc7IS47Iqk6rCAIOyiheujjOuQmOyngCDslYrripQg6rKD7J2EIOunieuKlOuLpC5cbiAgICAgICAgLy8gLSBjb25uZWN0aW9uVGltZW91dE1pbGxpczog7IaM7LyTIOyXsOqysCDsnpDssrTrpbwgNey0iCDslYjsl5Ag7Y+s6riwIOKGkiDshozsvJPsnbQg7KCV66as65CY7Ja0IO2UhOuhnOyEuOyKpOqwgCDsooXro4zrkKhcbiAgICAgICAgLy8gLSBwcm9wYWdhdGVDcmVhdGVFcnJvcjog7LKrIOyXsOqysCDsi6TtjKjrpbwg7KaJ7IucIOyghO2MjCjtkoAg7J6s7Iuc64+EIOyXhuydtCDrsJTroZwg7Iuk7YyoKVxuICAgICAgICBjb25zdCB0Q29ubiA9IGNyZWF0ZUtuZXhJbnN0YW5jZSh7XG4gICAgICAgICAgLi4ua25leE9wdGlvbnMsXG4gICAgICAgICAgY29ubmVjdGlvbjoge1xuICAgICAgICAgICAgLi4uKGNvbm5lY3Rpb24gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pLFxuICAgICAgICAgICAgY29ubmVjdGlvblRpbWVvdXRNaWxsaXM6IE1JR1JBVElPTl9DT05OX1RJTUVPVVRfTVMsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBwb29sOiB7XG4gICAgICAgICAgICAuLi5rbmV4T3B0aW9ucy5wb29sLFxuICAgICAgICAgICAgbWluOiAwLFxuICAgICAgICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IE1JR1JBVElPTl9DT05OX1RJTUVPVVRfTVMsXG4gICAgICAgICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBNSUdSQVRJT05fQ09OTl9USU1FT1VUX01TLFxuICAgICAgICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IHRydWUsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IGNvbm5TdHJpbmcgPVxuICAgICAgICAgIGBwZzovLyR7Y29ubmVjdGlvbi51c2VyID8/IFwiXCJ9QCR7Y29ubmVjdGlvbi5ob3N0fToke2Nvbm5lY3Rpb24ucG9ydH0vJHtjb25uZWN0aW9uLmRhdGFiYXNlfWAgYXMgQ29ublN0cmluZztcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIC8vIERCIOyXsOqysCDtmZXsnbg6IOu2iO2GtSBEQuyXkOyEnCBzdGF0dXMvbGlzdC9jdXJyZW50VmVyc2lvbuydtCDsu6TrhKXshZgg7ZqN65OdXG4gICAgICAgICAgLy8g7YOA7J6E7JWE7JuD6rmM7KeAIGhhbmftlZjripQg6rKD7J2EIOunieq4sCDsnITtlbQsIOuovOyggCA17LSIIOyViOyXkCDsnZHri7XtlZjripTsp4Ag7ZmV7J247ZWc64ukLlxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCB3aXRoVGltZW91dChcbiAgICAgICAgICAgICAgdENvbm4ucmF3KFwic2VsZWN0IDFcIiksXG4gICAgICAgICAgICAgIE1JR1JBVElPTl9DT05OX1RJTUVPVVRfTVMsXG4gICAgICAgICAgICAgICgpID0+XG4gICAgICAgICAgICAgICAgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgICAgYERCIOyXsOqysCDsi5zqsIQg7LSI6rO8ICgke01JR1JBVElPTl9DT05OX1RJTUVPVVRfTVN9bXMpIOKAlCAke2Nvbm5lY3Rpb24uaG9zdH06JHtjb25uZWN0aW9uLnBvcnR9LyR7Y29ubmVjdGlvbi5kYXRhYmFzZX1gLFxuICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgICBjaGFsay55ZWxsb3coXG4gICAgICAgICAgICAgICAgYCR7Y29ubktleX3snZgg66eI7J206re466CI7J207IWYIOyDge2DnOulvCDqsIDsoLjsmKTripQg642w7JeQIOyLpO2MqO2VmOyYgOyKteuLiOuLpC4g642w7J207YSw67Kg7J207Iqk7JeQIOyXsOqysO2VoCDsiJgg7JeG7Iq164uI64ukLlxcbuyLnOuPhO2VnCDsl7DqsrAg7ISk7KCVOlxcbiR7SlNPTi5zdHJpbmdpZnkoa25leE9wdGlvbnMuY29ubmVjdGlvbiwgbnVsbCwgMil9XFxu67Cc7IOd7ZWcIOyXkOufrDpcXG4ke2Vycn1cXG5gLFxuICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIG1pZ3JhdGlvblN0YXR1c0Vycm9yID0gZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgbmFtZTogY29ubktleSxcbiAgICAgICAgICAgICAgY29ubktleSxcbiAgICAgICAgICAgICAgY29ublN0cmluZyxcbiAgICAgICAgICAgICAgY3VycmVudFZlcnNpb246IFwiZXJyb3JcIiBhcyBjb25zdCxcbiAgICAgICAgICAgICAgc3RhdHVzOiBcImVycm9yXCIgYXMgY29uc3QsXG4gICAgICAgICAgICAgIHBlbmRpbmc6IFtdIGFzIHN0cmluZ1tdLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCBzdGF0dXM6IG51bWJlciB8IFwiZXJyb3JcIiA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICByZXR1cm4gYXdhaXQgdENvbm4ubWlncmF0ZS5zdGF0dXMoKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICBpZiAodGhpcy5pc01pc3NpbmdNaWdyYXRpb25UYWJsZUVycm9yKGVycikpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gY29kZXMubGVuZ3RoO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICAgICAgICAgIGAke2Nvbm5LZXl97J2YIOuniOydtOq3uOugiOydtOyFmCDsg4Htg5zrpbwg6rCA7KC47Jik64qUIOuNsOyXkCDsi6TtjKjtlZjsmIDsirXri4jri6QuIOuNsOydtO2EsOuyoOydtOyKpOqwgCDsmKzrsJTrpbTqsowg6rWs7ISx65CY7KeAIOyViuydgCDqsoMg6rCZ7Iq164uI64ukLiDtmZXsnbjtlZjsi5zqs6Ag64uk7IucIOyLnOuPhO2VtOyjvOyEuOyalC5cXG7si5zrj4TtlZwg7Jew6rKwIOyEpOyglTpcXG4ke0pTT04uc3RyaW5naWZ5KGtuZXhPcHRpb25zLmNvbm5lY3Rpb24sIG51bGwsIDIpfVxcbuuwnOyDne2VnCDsl5Drn6w6XFxuJHtlcnJ9XFxuYCxcbiAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICBtaWdyYXRpb25TdGF0dXNFcnJvciA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcbiAgICAgICAgICAgICAgcmV0dXJuIFwiZXJyb3JcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KSgpO1xuICAgICAgICAgIGNvbnN0IHBlbmRpbmc6IHN0cmluZ1tdID0gYXdhaXQgKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIGNvbnN0IFssIGZkTGlzdF0gPSBhd2FpdCB0Q29ubi5taWdyYXRlLmxpc3QoKTtcbiAgICAgICAgICAgICAgcmV0dXJuIGZkTGlzdC5tYXAoKGZkOiB7IGZpbGU6IHN0cmluZyB9KSA9PiBmZC5maWxlLnJlcGxhY2UoXCIudHNcIiwgXCJcIikpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgIGlmICh0aGlzLmlzTWlzc2luZ01pZ3JhdGlvblRhYmxlRXJyb3IoZXJyKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBjb2Rlcy5tYXAoKGNvZGUpID0+IGNvZGUubmFtZSk7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBtaWdyYXRpb25TdGF0dXNFcnJvciA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcbiAgICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pKCk7XG4gICAgICAgICAgY29uc3QgY3VycmVudFZlcnNpb246IHN0cmluZyB8IFwiZXJyb3JcIiA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICByZXR1cm4gYXdhaXQgdENvbm4ubWlncmF0ZS5jdXJyZW50VmVyc2lvbigpO1xuICAgICAgICAgICAgfSBjYXRjaCAoX2Vycikge1xuICAgICAgICAgICAgICBpZiAodGhpcy5pc01pc3NpbmdNaWdyYXRpb25UYWJsZUVycm9yKF9lcnIpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwibm9uZVwiO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgbWlncmF0aW9uU3RhdHVzRXJyb3IgPSBfZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBfZXJyLm1lc3NhZ2UgOiBTdHJpbmcoX2Vycik7XG4gICAgICAgICAgICAgIHJldHVybiBcImVycm9yXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSkoKTtcbiAgICAgICAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOnN0YXR1c1wiLCBzdGF0dXMpO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIG5hbWU6IGNvbm5LZXksXG4gICAgICAgICAgICBjb25uS2V5LFxuICAgICAgICAgICAgY29ublN0cmluZyxcbiAgICAgICAgICAgIGN1cnJlbnRWZXJzaW9uLFxuICAgICAgICAgICAgc3RhdHVzOiBzdGF0dXMsXG4gICAgICAgICAgICBwZW5kaW5nLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgLy8g67aI7Ya1IERC7J2YIOy7pOuEpeyFmCDsoJXrpqzqsIAg7Luk64Sl7IWYIO2ajeuTnSDtg4DsnoTslYTsm4PquYzsp4AgaGFuZ+2VmOyngCDslYrrj4TroZ0g6rCQ7Iu864ukLlxuICAgICAgICAgIGF3YWl0IHdpdGhUaW1lb3V0KFxuICAgICAgICAgICAgdENvbm4uZGVzdHJveSgpLFxuICAgICAgICAgICAgTUlHUkFUSU9OX0NPTk5fVElNRU9VVF9NUyxcbiAgICAgICAgICAgICgpID0+IG5ldyBFcnJvcihcImNvbm5lY3Rpb24gZGVzdHJveSB0aW1lb3V0XCIpLFxuICAgICAgICAgICkuY2F0Y2goKCkgPT4ge30pO1xuICAgICAgICB9XG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOmdldFN0YXR1czpjb25uc1wiLCBzdGF0dXNlcyk7XG5cbiAgICBjb25zdCBwcmVwYXJlZENvZGVzOiBHZW5NaWdyYXRpb25Db2RlW10gPSBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3Qgc3RhdHVzMGNvbm4gPSBzdGF0dXNlcy5maW5kKChzdGF0dXMpID0+IHN0YXR1cy5zdGF0dXMgPT09IDApO1xuICAgICAgaWYgKHN0YXR1czBjb25uID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICAgIGBXaGlsZSB0cnlpbmcgdG8gcHJlcGFyZSBtaWdyYXRpb24gY29kZXMsIHdlIGZvdW5kIHRoYXQgdGhlcmUgaXMgbm8gZGF0YWJhc2UgdG8gY29tcGFyZSBtaWdyYXRpb25zLiBXZSBuZWVkIGF0IGxlYXN0IG9uZSBkYXRhYmFzZSB3aGVyZSBldmVyeSBtaWdyYXRpb24gaXMgYXBwbGllZChzdGF0dXMgPT09IDApLiBZb3UgbWlnaHQgd2FudCB0byBhcHBseSB5b3VyIGV4aXN0aW5nIG1pZ3JhdGlvbnMgdG8gb25lIG9mIHRoZSBkYXRhYmFzZXMuYCxcbiAgICAgICAgICApLFxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gW107XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNvbXBhcmVEQmNvbm4gPSBjcmVhdGVLbmV4SW5zdGFuY2UoU29uYW11LmRiQ29uZmlnW3N0YXR1czBjb25uLmNvbm5LZXldKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmNvbXBhcmVNaWdyYXRpb25zKGNvbXBhcmVEQmNvbm4pO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYXdhaXQgY29tcGFyZURCY29ubi5kZXN0cm95KCk7XG4gICAgICB9XG4gICAgfSkoKTtcblxuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpnZXRTdGF0dXM6cHJlcGFyZWRDb2Rlc1wiLCBwcmVwYXJlZENvZGVzKTtcblxuICAgIHJldHVybiB7XG4gICAgICBjb25uczogc3RhdHVzZXMsXG4gICAgICBjb2RlcyxcbiAgICAgIHByZXBhcmVkQ29kZXMsXG4gICAgICBlcnJvcjogbWlncmF0aW9uU3RhdHVzRXJyb3IsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiDrp4jsnbTqt7jroIjsnbTshZjsnYQg7KCB7Jqp7ZWY6rGw64KYIOuhpOuwse2VqeuLiOuLpC5cbiAgICogU29uYW11IFVJ7JeQ7IScIOuniOydtOq3uOugiOydtOyFmCDsnpHsl4XsnYQg7IiY7ZaJ7ZWgIOuVjCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIENMSeyZgCBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcGFyYW0gYWN0aW9uIOyekeyXhSDsnKDtmJUgKGFwcGx5L3JvbGxiYWNrKVxuICAgKiBAcGFyYW0gdGFyZ2V0cyDsnpHsl4Ug64yA7IOBIERCIOyEpOyglSDtgqQgKGtleW9mIFNvbmFtdURCQ29uZmlnKVxuICAgKiBAcmV0dXJucyDsnpHsl4Ug6rKw6rO8XG4gICAqL1xuICBhc3luYyBydW5BY3Rpb24oXG4gICAgYWN0aW9uOiBcImFwcGx5XCIgfCBcInJvbGxiYWNrXCIsXG4gICAgdGFyZ2V0czogKGtleW9mIFNvbmFtdURCQ29uZmlnKVtdLFxuICApOiBQcm9taXNlPE1pZ3JhdGlvblJlc3VsdD4ge1xuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpydW5BY3Rpb246YWN0aW9uXCIsIGFjdGlvbik7XG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOnJ1bkFjdGlvbjp0YXJnZXRzXCIsIHRhcmdldHMpO1xuXG4gICAgY29uc3QgYWxsb3dlZFRhcmdldHMgPSBuZXcgU2V0KHRoaXMuZ2V0TWlncmF0aW9uVGFyZ2V0S2V5cygpKTtcbiAgICBjb25zdCBkaXNhbGxvd2VkVGFyZ2V0cyA9IHRhcmdldHMuZmlsdGVyKCh0YXJnZXQpID0+ICFhbGxvd2VkVGFyZ2V0cy5oYXModGFyZ2V0KSk7XG4gICAgaWYgKGRpc2FsbG93ZWRUYXJnZXRzLmxlbmd0aCA+IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYE1pZ3JhdGlvbiB0YXJnZXRzIGFyZSBub3QgYWxsb3dlZCBpbiBOT0RFX0VOVj0ke2dldFNvbmFtdUVudmlyb25tZW50KCl9OiAke2Rpc2FsbG93ZWRUYXJnZXRzLmpvaW4oXCIsIFwiKX1gLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBnZXQgdW5pcSBrbmV4IGNvbmZpZ3NcbiAgICBjb25zdCBjb25maWdzID0gdW5pcXVlKFxuICAgICAgdGFyZ2V0c1xuICAgICAgICAubWFwKCh0YXJnZXQpID0+ICh7XG4gICAgICAgICAgY29ubktleTogdGFyZ2V0LFxuICAgICAgICAgIG9wdGlvbnM6IFNvbmFtdS5kYkNvbmZpZ1t0YXJnZXRdLFxuICAgICAgICB9KSlcbiAgICAgICAgLmZpbHRlcigoYykgPT4gYy5vcHRpb25zICE9PSB1bmRlZmluZWQpLFxuICAgICAgKHsgb3B0aW9ucyB9KSA9PlxuICAgICAgICBgJHsob3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnKS5ob3N0fToke1xuICAgICAgICAgIChvcHRpb25zLmNvbm5lY3Rpb24gYXMgS25leC5QZ0Nvbm5lY3Rpb25Db25maWcpLnBvcnQgPz8gNTQzMlxuICAgICAgICB9LyR7KG9wdGlvbnMuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZykuZGF0YWJhc2V9YCxcbiAgICApO1xuXG4gICAgLy8gZ2V0IGNvbm5lY3Rpb25zXG4gICAgY29uc3QgY29ubnMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIGNvbmZpZ3MubWFwKGFzeW5jIChjb25maWcpID0+ICh7XG4gICAgICAgIGNvbm5LZXk6IGNvbmZpZy5jb25uS2V5LFxuICAgICAgICBrbmV4OiBjcmVhdGVLbmV4SW5zdGFuY2UoY29uZmlnLm9wdGlvbnMpLFxuICAgICAgfSkpLFxuICAgICk7XG5cbiAgICB0cnkge1xuICAgICAgLy8gYWN0aW9uXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgICAgICBzd2l0Y2ggKGFjdGlvbikge1xuICAgICAgICAgIGNhc2UgXCJhcHBseVwiOlxuICAgICAgICAgICAgcmV0dXJuIHRoaXMucnVuTWlncmF0aW9uc1NlcXVlbnRpYWxseShjb25ucywgXCJhcHBseVwiKTtcbiAgICAgICAgICBjYXNlIFwicm9sbGJhY2tcIjpcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJ1bk1pZ3JhdGlvbnNTZXF1ZW50aWFsbHkoY29ubnMsIFwicm9sbGJhY2tcIik7XG4gICAgICAgIH1cbiAgICAgIH0pKCk7XG5cbiAgICAgIE5haXRlLnQoXCJtaWdyYXRvcjpydW5BY3Rpb246cmVzdWx0XCIsIHJlc3VsdCk7XG5cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBjb25ucy5tYXAoKHsga25leCB9KSA9PiB7XG4gICAgICAgICAgcmV0dXJuIGtuZXguZGVzdHJveSgpO1xuICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIOyCreygnCDqsIDriqXtlZwg66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbzsnYQg6rKA7Kad7ZWp64uI64ukLlxuICAgKlxuICAgKiBAcGFyYW0gY29ubnMg66eI7J206re466CI7J207IWYIOyDge2DnCDrsLDsl7RcbiAgICogQHBhcmFtIGNvZGVOYW1lcyDsgq3soJztlaAg66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbwg7J2066aEIOuwsOyXtFxuICAgKiBAcmV0dXJucyDsgq3soJwg6rCA64qlIOyXrOu2gCDrsI8g7KCB7Jqp65CcIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J28IOydtOumhFxuICAgKi9cbiAgdmFsaWRhdGVEZWxldGFibGUoY29ubnM6IE1pZ3JhdGlvblN0YXR1c1tcImNvbm5zXCJdLCBjb2RlTmFtZXM6IHN0cmluZ1tdKSB7XG4gICAgY29uc3QgYXBwbGllZENvZGVzID0gY29kZU5hbWVzLmZpbHRlcigoY29kZU5hbWUpID0+XG4gICAgICBjb25ucy5zb21lKChjb25uKSA9PiAhY29ubi5wZW5kaW5nLmluY2x1ZGVzKGNvZGVOYW1lKSksXG4gICAgKTtcblxuICAgIHJldHVybiB7XG4gICAgICBjYW5EZWxldGU6IGFwcGxpZWRDb2Rlcy5sZW5ndGggPT09IDAsXG4gICAgICBhcHBsaWVkQ29kZXMsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvOydhCDsgq3soJztlanri4jri6QuXG4gICAqXG4gICAqIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEBwYXJhbSBjb2RlTmFtZXMg7IKt7KCc7ZWgIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J28IOydtOumhCDrsLDsl7RcbiAgICogQHJldHVybnMg7IKt7KCc65CcIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J28IOqwnOyImFxuICAgKi9cbiAgYXN5bmMgZGVsQ29kZXMoY29kZU5hbWVzOiBzdHJpbmdbXSk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgY29uc3QgeyBjb25ucyB9ID0gYXdhaXQgdGhpcy5nZXRTdGF0dXMoKTtcbiAgICBjb25zdCB7IGNhbkRlbGV0ZSwgYXBwbGllZENvZGVzIH0gPSB0aGlzLnZhbGlkYXRlRGVsZXRhYmxlKGNvbm5zLCBjb2RlTmFtZXMpO1xuICAgIGlmICghY2FuRGVsZXRlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBZb3UgY2Fubm90IGRlbGV0ZSBhIG1pZ3JhdGlvbiBmaWxlIGlmIHRoZXJlIGlzIGFscmVhZHkgYXBwbGllZC4gQXBwbGllZCBjb2RlczogJHthcHBsaWVkQ29kZXMuam9pbihcIiwgXCIpfWAsXG4gICAgICApO1xuICAgIH1cblxuICAgIHJldHVybiBzdW0oXG4gICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgY29kZU5hbWVzLm1hcChhc3luYyAoY29kZU5hbWUpID0+IHtcbiAgICAgICAgICBjb25zdCBmaWxlUGF0aCA9IGAke1NvbmFtdS5hcGlSb290UGF0aH0vc3JjL21pZ3JhdGlvbnMvJHtjb2RlTmFtZX0udHNgO1xuICAgICAgICAgIGlmIChhd2FpdCBleGlzdHMoZmlsZVBhdGgpKSB7XG4gICAgICAgICAgICBhd2FpdCB1bmxpbmsoZmlsZVBhdGgpO1xuICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICB9KSxcbiAgICAgICksXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2VuRGF0ZVRhZyhpbmRleDogbnVtYmVyLCBiYXNlRGF0ZTogRGF0ZSA9IG5ldyBEYXRlKCkpOiBzdHJpbmcge1xuICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShiYXNlRGF0ZS5nZXRUaW1lKCkgKyBpbmRleCAqIDEwMDApO1xuICAgIGNvbnN0IHBhZCA9IChudW06IG51bWJlciwgc2l6ZTogbnVtYmVyID0gMikgPT4gbnVtLnRvU3RyaW5nKCkucGFkU3RhcnQoc2l6ZSwgXCIwXCIpO1xuICAgIHJldHVybiAoXG4gICAgICBkYXRlLmdldEZ1bGxZZWFyKCkudG9TdHJpbmcoKSArXG4gICAgICBwYWQoZGF0ZS5nZXRNb250aCgpICsgMSkgK1xuICAgICAgcGFkKGRhdGUuZ2V0RGF0ZSgpKSArXG4gICAgICBwYWQoZGF0ZS5nZXRIb3VycygpKSArXG4gICAgICBwYWQoZGF0ZS5nZXRNaW51dGVzKCkpICtcbiAgICAgIHBhZChkYXRlLmdldFNlY29uZHMoKSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J287J2EIOyDneyEse2VqeuLiOuLpC5cbiAgICpcbiAgICogU29uYW11IFVJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQHJldHVybnMg7IOd7ISx65CcIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J28IOqwnOyImFxuICAgKi9cbiAgYXN5bmMgZ2VuZXJhdGVQcmVwYXJlZENvZGVzKCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgY29uc3QgeyBwcmVwYXJlZENvZGVzIH0gPSBhd2FpdCB0aGlzLmdldFN0YXR1cygpO1xuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpnZW5lcmF0ZVByZXBhcmVkQ29kZXM6cHJlcGFyZWRDb2Rlc1wiLCBwcmVwYXJlZENvZGVzKTtcbiAgICBpZiAocHJlcGFyZWRDb2Rlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKFwiXFxu7ZiE7J6sIOuqqOuRkCDsi7HtgazrkJwg7IOB7YOc7J6F64uI64ukLlwiKSk7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG5cbiAgICAvLyDsi6TsoJwg7L2U65OcIOyDneyEsVxuICAgIGNvbnN0IG1pZ3JhdGlvbnNEaXIgPSBgJHtTb25hbXUuYXBpUm9vdFBhdGh9L3NyYy9taWdyYXRpb25zYDtcblxuICAgIGZvciAoY29uc3QgW2luZGV4LCBwY29kZV0gb2YgcHJlcGFyZWRDb2Rlcy5lbnRyaWVzKCkpIHtcbiAgICAgIGlmIChwY29kZS5mb3JtYXR0ZWQpIHtcbiAgICAgICAgY29uc3QgZGF0ZVRhZyA9IHRoaXMuZ2VuRGF0ZVRhZyhpbmRleCk7XG4gICAgICAgIGNvbnN0IGZpbGVQYXRoID0gYCR7bWlncmF0aW9uc0Rpcn0vJHtkYXRlVGFnfV8ke3Bjb2RlLnRpdGxlfS50c2A7XG4gICAgICAgIGF3YWl0IHdyaXRlRmlsZShmaWxlUGF0aCwgcGNvZGUuZm9ybWF0dGVkKTtcbiAgICAgICAgIWlzVGVzdCgpICYmIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKGBNSUdSQVRJT04gQ1JFQVRFRCAke2ZpbGVQYXRofWApKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcHJlcGFyZWRDb2Rlcy5sZW5ndGg7XG4gIH1cblxuICBhc3luYyBjb21wYXJlTWlncmF0aW9ucyhjb21wYXJlREI6IEtuZXgpOiBQcm9taXNlPEdlbk1pZ3JhdGlvbkNvZGVbXT4ge1xuICAgIC8vIEVudGl0eSDsiJztmoztlZjsl6wg7Iux7YGsXG4gICAgY29uc3QgZW50aXR5SWRzID0gRW50aXR5TWFuYWdlci5nZXRBbGxJZHMoKTtcblxuICAgIC8vIOyhsOyduO2FjOydtOu4lCDtj6ztlajtlZjsl6wgRW50aXR57JeQ7IScIE1pZ3JhdGlvblNldCDstpTstpxcbiAgICBjb25zdCBlbnRpdHlTZXRzV2l0aEpvaW5UYWJsZSA9IGVudGl0eUlkc1xuICAgICAgLmZpbHRlcigoZW50aXR5SWQpID0+IEVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKS5wcm9wcy5sZW5ndGggPiAwKVxuICAgICAgLm1hcCgoZW50aXR5SWQpID0+IGdldE1pZ3JhdGlvblNldEZyb21FbnRpdHkoRW50aXR5TWFuYWdlci5nZXQoZW50aXR5SWQpKSk7XG5cbiAgICAvLyDsobDsnbjthYzsnbTruJTrp4wg7LaU7LacXG4gICAgY29uc3Qgam9pblRhYmxlc1dpdGhEdXAgPSBlbnRpdHlTZXRzV2l0aEpvaW5UYWJsZS5mbGF0TWFwKChlbnRpdHlTZXQpID0+IGVudGl0eVNldC5qb2luVGFibGVzKTtcbiAgICAvLyDspJHrs7Ug7KCc6rGwICjspJHrs7Xsnbgg6rK97JqwIGluZGV4ZXPrpbwg67OR7ZWpKVxuICAgIGNvbnN0IGpvaW5UYWJsZXMgPSBPYmplY3QudmFsdWVzKGdyb3VwKGpvaW5UYWJsZXNXaXRoRHVwLCAoanQpID0+IGp0LnRhYmxlKSkubWFwKCh0YWJsZXMpID0+IHtcbiAgICAgIGFzc2VydCh0YWJsZXMgIT09IHVuZGVmaW5lZCwgXCJ0YWJsZXMgaXMgdW5kZWZpbmVkXCIpO1xuICAgICAgaWYgKHRhYmxlcy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgcmV0dXJuIHRhYmxlc1swXTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB7XG4gICAgICAgIC4uLnRhYmxlc1swXSxcbiAgICAgICAgaW5kZXhlczogdW5pcXVlKFxuICAgICAgICAgIHRhYmxlcy5mbGF0TWFwKCh0KSA9PiB0LmluZGV4ZXMpLFxuICAgICAgICAgIChpbmRleCkgPT4gW2luZGV4LnR5cGUsIC4uLmluZGV4LmNvbHVtbnNdLmpvaW4oXCItXCIpLFxuICAgICAgICApLFxuICAgICAgfTtcbiAgICB9KTtcblxuICAgIC8vIOyhsOyduO2FjOydtOu4lCDtj6ztlajtlZjsl6wgTWlncmF0aW9uU2V0IOuwsOyXtFxuICAgIGNvbnN0IGVudGl0eVNldHM6IE1pZ3JhdGlvblNldFtdID0gWy4uLmVudGl0eVNldHNXaXRoSm9pblRhYmxlLCAuLi5qb2luVGFibGVzXTtcblxuICAgIGNvbnN0IGNvZGVzOiBHZW5NaWdyYXRpb25Db2RlW10gPSBbXTtcbiAgICBjb25zdCBiYXRjaFNpemUgPSA0O1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBlbnRpdHlTZXRzLmxlbmd0aDsgaSArPSBiYXRjaFNpemUpIHtcbiAgICAgIGNvbnN0IGJhdGNoQ29kZXMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgZW50aXR5U2V0cy5zbGljZShpLCBpICsgYmF0Y2hTaXplKS5tYXAoYXN5bmMgKGVudGl0eVNldCkgPT4ge1xuICAgICAgICAgIGNvbnN0IGRiU2V0ID0gYXdhaXQgUG9zdGdyZVNRTFNjaGVtYVJlYWRlci5nZXRNaWdyYXRpb25TZXRGcm9tREIoXG4gICAgICAgICAgICBjb21wYXJlREIsXG4gICAgICAgICAgICBlbnRpdHlTZXQudGFibGUsXG4gICAgICAgICAgKTtcbiAgICAgICAgICBOYWl0ZS50KGBtaWdyYXRvcjpjb21wYXJlTWlncmF0aW9uczplbnRpdHlTZXQ6JHtlbnRpdHlTZXQudGFibGV9YCwgZW50aXR5U2V0KTtcbiAgICAgICAgICBOYWl0ZS50KGBtaWdyYXRvcjpjb21wYXJlTWlncmF0aW9uczpkYlNldDoke2VudGl0eVNldC50YWJsZX1gLCBkYlNldCk7XG5cbiAgICAgICAgICBpZiAoZGJTZXQgPT09IG51bGwpIHtcbiAgICAgICAgICAgIC8vIOq4sOyhtCDthYzsnbTruJQg7JeG7J2MLCDsg4jroZwg7YWM7J2067iUIOyDneyEsVxuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IGdlbmVyYXRlQ3JlYXRlQ29kZShlbnRpdHlTZXQpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyDquLDsobQg7YWM7J2067iUIOyhtOyerO2VmOuKlCDsvIDsnbTsiqRcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBnZW5lcmF0ZUFsdGVyQ29kZShlbnRpdHlTZXQsIGRiU2V0LCBjb21wYXJlREIpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSksXG4gICAgICApO1xuXG4gICAgICBjb2Rlcy5wdXNoKC4uLmJhdGNoQ29kZXMuZmxhdCgpKTtcbiAgICB9XG5cbiAgICAvLyBub3JtYWwg7YOA7J6F7J20IOyVnuycvOuhnCwgZm9yZWlnbuydtCDrkqTroZxcbiAgICBjb2Rlcy5zb3J0KChjb2RlQSwgY29kZUIpID0+IHtcbiAgICAgIGlmIChjb2RlQS50eXBlID09PSBcImZvcmVpZ25cIiAmJiBjb2RlQi50eXBlID09PSBcIm5vcm1hbFwiKSB7XG4gICAgICAgIHJldHVybiAxO1xuICAgICAgfSBlbHNlIGlmIChjb2RlQS50eXBlID09PSBcIm5vcm1hbFwiICYmIGNvZGVCLnR5cGUgPT09IFwiZm9yZWlnblwiKSB7XG4gICAgICAgIHJldHVybiAtMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGNvZGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNoYWRvdyBEQiDthYzsiqTtirjrpbwg7KeE7ZaJ7ZWp64uI64ukLlxuICAgKlxuICAgKiBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcmV0dXJucyBTaGFkb3cgREIg7YWM7Iqk7Yq4IOqysOqzvFxuICAgKi9cbiAgYXN5bmMgcnVuU2hhZG93VGVzdCgpOiBQcm9taXNlPE1pZ3JhdGlvblJlc3VsdD4ge1xuICAgIGNvbnN0IGJhc2VUZXN0Q29ubiA9IFNvbmFtdS5kYkNvbmZpZy50ZXN0LmNvbm5lY3Rpb24gYXMgS25leC5QZ0Nvbm5lY3Rpb25Db25maWc7XG4gICAgY29uc3Qgd29ya2VySWQgPSBwcm9jZXNzLmVudi5TT05BTVVfV09SS0VSX0RCID09PSBcInRydWVcIiA/IHByb2Nlc3MuZW52LlZJVEVTVF9QT09MX0lEIDogbnVsbDtcbiAgICBjb25zdCB0ZW1wbGF0ZURhdGFiYXNlID1cbiAgICAgIHdvcmtlcklkICE9PSBudWxsID8gYCR7YmFzZVRlc3RDb25uLmRhdGFiYXNlfV8ke3dvcmtlcklkID8/IFwiMVwifWAgOiBiYXNlVGVzdENvbm4uZGF0YWJhc2U7XG4gICAgY29uc3QgdGRiQ29ubiA9IHsgLi4uYmFzZVRlc3RDb25uLCBkYXRhYmFzZTogdGVtcGxhdGVEYXRhYmFzZSB9O1xuICAgIGNvbnN0IHNoYWRvd0RhdGFiYXNlID0gYCR7dGVtcGxhdGVEYXRhYmFzZX1fX21pZ3JhdGlvbl9zaGFkb3dgO1xuXG4gICAgLy8g7YWM7Iqk7Yq4IOyDge2ZqeyXkOyEnOuKlCDtirjrnpzsnq3shZjsnYQg7LSI6riw7ZmU7ZWY6rOgLCDsg4gg642w7J207YSw67Kg7J207IqkIOy7pOuEpeyFmOydhCDqsIDsoLjsmYDslbwg7ZWoXG4gICAgaWYgKGlzVGVzdCgpKSB7XG4gICAgICBhd2FpdCBEQi5jbGVhclRlc3RUcmFuc2FjdGlvbigpO1xuICAgICAgYXdhaXQgREIuZGVzdHJveSgpO1xuICAgIH1cblxuICAgIC8vIOq4sOyhtCBTaGFkb3cgREIg7IKt7KCcIO2bhCBTaGFkb3cgREIg7IOd7ISxXG4gICAgY29uc3QgdGRiID0gY3JlYXRlS25leEluc3RhbmNlKHtcbiAgICAgIC4uLlNvbmFtdS5kYkNvbmZpZy50ZXN0LFxuICAgICAgY29ubmVjdGlvbjoge1xuICAgICAgICAuLi5iYXNlVGVzdENvbm4sXG4gICAgICAgIGRhdGFiYXNlOiBcInBvc3RncmVzXCIsXG4gICAgICB9LFxuICAgIH0pO1xuICAgIHRyeSB7XG4gICAgICAhaXNUZXN0KCkgJiYgY29uc29sZS5sb2coY2hhbGsubWFnZW50YShgJHtzaGFkb3dEYXRhYmFzZX0g7IKt7KCcYCkpO1xuICAgICAgYXdhaXQgdGRiLnJhdyhgRFJPUCBEQVRBQkFTRSBJRiBFWElTVFMgJHtzaGFkb3dEYXRhYmFzZX1gKTtcbiAgICAgIGF3YWl0IHRkYi5yYXcoYFxuICAgICAgICBTRUxFQ1QgcGdfdGVybWluYXRlX2JhY2tlbmQocGdfc3RhdF9hY3Rpdml0eS5waWQpXG4gICAgICAgIEZST00gcGdfc3RhdF9hY3Rpdml0eVxuICAgICAgICBXSEVSRSBkYXRuYW1lID0gJyR7dGRiQ29ubi5kYXRhYmFzZX0nXG4gICAgICAgICAgQU5EIHBpZCA8PiBwZ19iYWNrZW5kX3BpZCgpO1xuICAgICAgYCk7XG4gICAgICBhd2FpdCB0ZGIucmF3KGBDUkVBVEUgREFUQUJBU0UgJHtzaGFkb3dEYXRhYmFzZX0gVEVNUExBVEUgJHt0ZGJDb25uLmRhdGFiYXNlfWApO1xuXG4gICAgICAvLyBTaGFkb3cgRELsl5Ag7Jew6rKwXG4gICAgICBjb25zdCBzZGIgPSBjcmVhdGVLbmV4SW5zdGFuY2Uoe1xuICAgICAgICAuLi5Tb25hbXUuZGJDb25maWcudGVzdCxcbiAgICAgICAgY29ubmVjdGlvbjoge1xuICAgICAgICAgIC4uLnRkYkNvbm4sXG4gICAgICAgICAgZGF0YWJhc2U6IHNoYWRvd0RhdGFiYXNlLFxuICAgICAgICAgIHBhc3N3b3JkOiB0ZGJDb25uLnBhc3N3b3JkLFxuICAgICAgICB9LFxuICAgICAgfSk7XG5cbiAgICAgIC8vIHNoYWRvdyBEQiDthYzsiqTtirgg7KeE7ZaJXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBbYmF0Y2hObywgYXBwbGllZF0gPSBhd2FpdCBzZGIubWlncmF0ZS5sYXRlc3QoKTtcbiAgICAgICAgIWlzVGVzdCgpICYmXG4gICAgICAgICAgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oXCJTaGFkb3cgREIg7YWM7Iqk7Yq47JeQIOyEseqzte2WiOyKteuLiOuLpCFcIiksIHtcbiAgICAgICAgICAgIGJhdGNoTm8sXG4gICAgICAgICAgICBhcHBsaWVkLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgY29ubktleTogXCJzaGFkb3dcIixcbiAgICAgICAgICAgIGJhdGNoTm8sXG4gICAgICAgICAgICBhcHBsaWVkLFxuICAgICAgICAgIH0sXG4gICAgICAgIF07XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZSk7XG4gICAgICAgIHRocm93IG5ldyBTZXJ2aWNlVW5hdmFpbGFibGVFeGNlcHRpb24oU0QoXCJzb25hbXUuZXJyb3Iuc2hhZG93RGJUZXN0RmFpbGVkXCIpKTtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIGF3YWl0IHNkYi5kZXN0cm95KCk7XG4gICAgICB9XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIC8vIFNoYWRvdyBEQiDsgq3soJxcbiAgICAgICFpc1Rlc3QoKSAmJiBjb25zb2xlLmxvZyhjaGFsay5tYWdlbnRhKGAke3NoYWRvd0RhdGFiYXNlfSDsgq3soJxgKSk7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB0ZGIucmF3KGBEUk9QIERBVEFCQVNFIElGIEVYSVNUUyAke3NoYWRvd0RhdGFiYXNlfWApO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiU2hhZG93IERCIOygleumrCDsi6TtjKg6XCIsIGUpOyAvLyDsnbTqsowg7JeG7Jy866m0IOyhsOyaqe2eiCDriITsiJhcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIGF3YWl0IHRkYi5kZXN0cm95KCk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQXdDQSxTQUFTLFlBQWUsU0FBcUIsSUFBWSxXQUFvQztDQUMzRixPQUFPLElBQUksU0FBWSxTQUFTLFdBQVc7RUFDekMsTUFBTSxRQUFRLGlCQUFpQixPQUFPLFVBQVUsQ0FBQyxHQUFHLEVBQUU7RUFDdEQsUUFBUSxNQUNMLFVBQVU7R0FDVCxhQUFhLEtBQUs7R0FDbEIsUUFBUSxLQUFLO0VBQ2YsSUFDQyxVQUFVO0dBQ1QsYUFBYSxLQUFLO0dBQ2xCLE9BQU8sS0FBSztFQUNkLENBQ0Y7Q0FDRixDQUFDO0FBQ0g7OzthQTlDc0M7U0FDSDtXQUVrQjtTQUN0QjtxQkFDeUI7VUFDWDtvQkFDNEI7WUFDbkM7aUJBRWU7ZUFDWDtzQkFDK0I7b0JBQ2Q7K0JBQ1E7Q0FZN0QsNEJBQTRCO0NBc0JyQixXQUFiLE1BQXNCO0VBQ3BCLDZCQUFxQyxPQUF5QjtHQUM1RCxJQUFJLE9BQU8sVUFBVSxZQUFZLFVBQVUsTUFDekMsT0FBTztHQUdULE1BQU0scUJBQXFCO0dBQzNCLE9BQ0UsbUJBQW1CLFNBQVMsV0FDNUIsT0FBTyxtQkFBbUIsWUFBWSxZQUN0QyxtQkFBbUIsUUFBUSxTQUFTLGlCQUFpQjtFQUV6RDtFQUVBLHlCQUEyRDtHQUN6RCxNQUFNLFdBQVcsT0FBTyxLQUFLLE9BQU8sUUFBUSxD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
518
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlncmF0b3IuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL21pZ3JhdGlvbi9taWdyYXRvci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCB7IG1rZGlyLCByZWFkZGlyLCB3cml0ZUZpbGUgfSBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5cbmltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIjtcbmltcG9ydCB7IHR5cGUgS25leCB9IGZyb20gXCJrbmV4XCI7XG5pbXBvcnQgeyBncm91cCwgdW5pcXVlIH0gZnJvbSBcInJhZGFzaGlcIjtcblxuaW1wb3J0IHsgU29uYW11IH0gZnJvbSBcIi4uL2FwaS9zb25hbXVcIjtcbmltcG9ydCB7IERCIH0gZnJvbSBcIi4uL2RhdGFiYXNlL2RiXCI7XG5pbXBvcnQgeyB0eXBlIFNvbmFtdURCQ29uZmlnIH0gZnJvbSBcIi4uL2RhdGFiYXNlL2RiXCI7XG5pbXBvcnQgeyBjcmVhdGVLbmV4SW5zdGFuY2UgfSBmcm9tIFwiLi4vZGF0YWJhc2Uva25leFwiO1xuaW1wb3J0IHsgU0QgfSBmcm9tIFwiLi4vZGljdC9zZFwiO1xuaW1wb3J0IHsgRW50aXR5TWFuYWdlciB9IGZyb20gXCIuLi9lbnRpdHkvZW50aXR5LW1hbmFnZXJcIjtcbmltcG9ydCB7IGdldFNvbmFtdUVudmlyb25tZW50IH0gZnJvbSBcIi4uL2VudlwiO1xuaW1wb3J0IHsgU2VydmljZVVuYXZhaWxhYmxlRXhjZXB0aW9uIH0gZnJvbSBcIi4uL2V4Y2VwdGlvbnMvc28tZXhjZXB0aW9uc1wiO1xuaW1wb3J0IHsgTmFpdGUgfSBmcm9tIFwiLi4vbmFpdGUvbmFpdGVcIjtcbmltcG9ydCB7IHR5cGUgR2VuTWlncmF0aW9uQ29kZSwgdHlwZSBNaWdyYXRpb25TZXQgfSBmcm9tIFwiLi4vdHlwZXMvdHlwZXNcIjtcbmltcG9ydCB7IGlzTG9jYWwsIGlzVGVzdCB9IGZyb20gXCIuLi91dGlscy9jb250cm9sbGVyXCI7XG5pbXBvcnQgeyBleGlzdHMgfSBmcm9tIFwiLi4vdXRpbHMvZnMtdXRpbHNcIjtcbmltcG9ydCB7IGlzT2JqZWN0VmFsdWUsIGlzU3RyaW5nVmFsdWUgfSBmcm9tIFwiLi4vdXRpbHMvcnVudGltZS12YWx1ZVwiO1xuaW1wb3J0IHsgZ2VuZXJhdGVBbHRlckNvZGUsIGdlbmVyYXRlQ3JlYXRlQ29kZSB9IGZyb20gXCIuL2NvZGUtZ2VuZXJhdGlvblwiO1xuaW1wb3J0IHsgZ2V0TWlncmF0aW9uU2V0RnJvbUVudGl0eSB9IGZyb20gXCIuL21pZ3JhdGlvbi1zZXRcIjtcbmltcG9ydCB7IFBvc3RncmVTUUxTY2hlbWFSZWFkZXIgfSBmcm9tIFwiLi9wb3N0Z3Jlc3FsLXNjaGVtYS1yZWFkZXJcIjtcbmltcG9ydCB7IFNsYWNrQ29uZmlybSB9IGZyb20gXCIuL3NsYWNrLWNvbmZpcm1cIjtcbmltcG9ydCB7XG4gIHR5cGUgQ29ublN0cmluZyxcbiAgdHlwZSBNaWdyYXRpb25BY3Rpb24sXG4gIHR5cGUgTWlncmF0aW9uQ29kZSxcbiAgdHlwZSBNaWdyYXRpb25Db25uZWN0aW9uTWV0YSxcbiAgdHlwZSBNaWdyYXRpb25Db25uZWN0aW9uU3RhdHVzLFxuICB0eXBlIE1pZ3JhdGlvblByb2dyZXNzRXZlbnQsXG4gIHR5cGUgTWlncmF0aW9uUnVuT3B0aW9ucyxcbiAgdHlwZSBNaWdyYXRpb25TdGF0dXMsXG4gIHR5cGUgTWlncmF0aW9uVGFyZ2V0LFxufSBmcm9tIFwiLi90eXBlc1wiO1xuXG5leHBvcnQgdHlwZSBNaWdyYXRpb25SZXN1bHQgPSB7XG4gIGNvbm5LZXk6IHN0cmluZztcbiAgYmF0Y2hObzogbnVtYmVyO1xuICBhcHBsaWVkOiBzdHJpbmdbXTtcbn1bXTtcblxuZnVuY3Rpb24gcGFkRGF0ZVBhcnQobnVtYmVyOiBudW1iZXIsIHNpemU6IG51bWJlciA9IDIpOiBzdHJpbmcge1xuICByZXR1cm4gbnVtYmVyLnRvU3RyaW5nKCkucGFkU3RhcnQoc2l6ZSwgXCIwXCIpO1xufVxuXG5leHBvcnQgY2xhc3MgTWlncmF0aW9uVGFyZ2V0RXhlY3V0aW9uRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHB1YmxpYyByZWFkb25seSBjb25uS2V5OiBNaWdyYXRpb25UYXJnZXQgfCBcInNoYWRvd1wiLFxuICAgIGNhdXNlOiB1bmtub3duLFxuICApIHtcbiAgICBzdXBlcihjYXVzZSBpbnN0YW5jZW9mIEVycm9yID8gY2F1c2UubWVzc2FnZSA6IFN0cmluZyhjYXVzZSkpO1xuICAgIHRoaXMubmFtZSA9IFwiTWlncmF0aW9uVGFyZ2V0RXhlY3V0aW9uRXJyb3JcIjtcbiAgfVxufVxuXG4vLyDrp4jsnbTqt7jroIjsnbTshZgg7IOB7YOcIOyhsO2ajCDsi5wgREIg7Jew6rKwIO2ZleyduCDtg4DsnoTslYTsm4MobXMpLlxuLy8gY3JlYXRlS25leEluc3RhbmNl7J2YIOy7pOuEpeyFmCDtmo3rk50g7YOA7J6E7JWE7JuDKDMw7LSIKeyXkCBzdGF0dXMvbGlzdC9jdXJyZW50VmVyc2lvbuydtFxuLy8g6rCB6rCBIOqxuOumrOuptCBDTEkvVUnqsIAg7LWc64yAIOyImOyLrSDstIggaGFuZ+2VnOuLpC4g7KCV7IOBIOydkeuLteydgCDsiJjrsLEgbXPsnbTrr4DroZwgNey0iOuptCDstqnrtoTtlZjri6QuXG5jb25zdCBNSUdSQVRJT05fQ09OTl9USU1FT1VUX01TID0gNTAwMDtcbmNvbnN0IExPQ0FMX0RCX0hPU1RTID0gbmV3IFNldChbXCJsb2NhbGhvc3RcIiwgXCIxMjcuMC4wLjFcIiwgXCIwLjAuMC4wXCIsIFwiOjoxXCJdKTtcblxuLyoqXG4gKiDso7zslrTsp4QgUHJvbWlzZeqwgCBtcyDslYjsl5Ag7JmE66OM65CY7KeAIOyViuycvOuptCBvblRpbWVvdXQg7JeQ65+s66GcIHJlamVjdO2VnOuLpC5cbiAqIOybkOuzuCBQcm9taXNlIOyekOyytOuKlCDqs4Tsho0g7KeE7ZaJ65CY66+A66GcLCDtmLjstpzsuKHsl5DshJwg7Luk64Sl7IWYIOygleumrChkZXN0cm95KeulvCDssYXsnoTsp4Tri6QuXG4gKi9cbmZ1bmN0aW9uIHdpdGhUaW1lb3V0PFQ+KHByb21pc2U6IFByb21pc2U8VD4sIG1zOiBudW1iZXIsIG9uVGltZW91dDogKCkgPT4gRXJyb3IpOiBQcm9taXNlPFQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlPFQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBjb25zdCB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4gcmVqZWN0KG9uVGltZW91dCgpKSwgbXMpO1xuICAgIHByb21pc2UudGhlbihcbiAgICAgICh2YWx1ZSkgPT4ge1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgICAgICByZXNvbHZlKHZhbHVlKTtcbiAgICAgIH0sXG4gICAgICAoZXJyb3IpID0+IHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgIH0sXG4gICAgKTtcbiAgfSk7XG59XG5cbi8qKlxuICogTm90ZSAyMDI2LTA4LTI2LCDrs5HspIBcbiAqIOydtCDtgbTrnpjsiqTsl5DshJwgZGVwcmVjYXRlZCDrtpnslrTsnojripQg7Lmc6rWs65Ok7J2AIO2YhCBDTEnrpbwg7JyE7ZWcIO2VmOychCDtmLjtmZjsnbTri4gsXG4gKiBDTEkg66as7Yyp7Yag66eBIOyLnOygkOyXkOyEnCDsoJzqsbDtlbTso7zshZTrj4Qg66y067Cp7ZWp64uI64ukLlxuICovXG5leHBvcnQgY2xhc3MgTWlncmF0b3Ige1xuICBwcml2YXRlIGlzTWlzc2luZ01pZ3JhdGlvblRhYmxlRXJyb3I8VmFsdWU+KGVycm9yOiBWYWx1ZSk6IGJvb2xlYW4ge1xuICAgIGlmICghaXNPYmplY3RWYWx1ZShlcnJvcikgfHwgZXJyb3IgPT09IG51bGwpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCBtYXliZVBvc3RncmVzRXJyb3IgPVxuICAgICAgLyogU0FGRVRZOiBLbmV47JmAIFBvc3RncmVTUUwg7Iqk7YKk66eIIOyhsO2ajCDqs4Tslb3snbQg7J20IOqwkuydmCDtg4DsnoXsnYQg67O07J6l7ZWc64ukLiAqLyBlcnJvciBhcyB7XG4gICAgICAgIGNvZGU/OiB1bmtub3duO1xuICAgICAgICBtZXNzYWdlPzogdW5rbm93bjtcbiAgICAgIH07XG4gICAgcmV0dXJuIChcbiAgICAgIG1heWJlUG9zdGdyZXNFcnJvci5jb2RlID09PSBcIjQyUDAxXCIgJiZcbiAgICAgIGlzU3RyaW5nVmFsdWUobWF5YmVQb3N0Z3Jlc0Vycm9yLm1lc3NhZ2UpICYmXG4gICAgICBtYXliZVBvc3RncmVzRXJyb3IubWVzc2FnZS5pbmNsdWRlcyhcImtuZXhfbWlncmF0aW9uc1wiKVxuICAgICk7XG4gIH1cblxuICAvKiog7ZiE7J6sIOyLpO2WiSDtmZjqsr3sl5DshJwg7ZeI7Jqp65CcIOuniOydtOq3uOugiOydtOyFmCDrjIDsg4Eg7YKk66W8IOuwmO2ZmO2VqeuLiOuLpC4gKi9cbiAgZ2V0TWlncmF0aW9uVGFyZ2V0S2V5cygpOiBNaWdyYXRpb25UYXJnZXRbXSB7XG4gICAgY29uc3QgY29ubktleXMgPVxuICAgICAgLyogU0FGRVRZOiBLbmV47JmAIFBvc3RncmVTUUwg7Iqk7YKk66eIIOyhsO2ajCDqs4Tslb3snbQg7J20IOqwkuydmCDtg4DsnoXsnYQg67O07J6l7ZWc64ukLiAqLyBPYmplY3Qua2V5cyhcbiAgICAgICAgU29uYW11LmRiQ29uZmlnLFxuICAgICAgKS5maWx0ZXIoKGtleSkgPT4gIWtleS5lbmRzV2l0aChcIl9yZWFkb25seVwiKSkgYXMgKGtleW9mIFNvbmFtdURCQ29uZmlnKVtdO1xuXG4gICAgaWYgKGlzTG9jYWwoKSkge1xuICAgICAgcmV0dXJuIGNvbm5LZXlzO1xuICAgIH1cblxuICAgIGNvbnN0IGVudmlyb25tZW50ID0gZ2V0U29uYW11RW52aXJvbm1lbnQoKTtcbiAgICByZXR1cm4gY29ubktleXMuZmlsdGVyKChrZXkpID0+IGtleSA9PT0gZW52aXJvbm1lbnQpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBydW5NaWdyYXRpb25zU2VxdWVudGlhbGx5KFxuICAgIGNvbm5zOiB7IGNvbm5LZXk6IGtleW9mIFNvbmFtdURCQ29uZmlnOyBrbmV4OiBLbmV4IH1bXSxcbiAgICBhY3Rpb246IFwiYXBwbHlcIiB8IFwicm9sbGJhY2tcIixcbiAgICBvcHRpb25zPzogTWlncmF0aW9uUnVuT3B0aW9ucyxcbiAgKTogUHJvbWlzZTxNaWdyYXRpb25SZXN1bHQ+IHtcbiAgICBjb25zdCByZXN1bHRzOiBNaWdyYXRpb25SZXN1bHQgPSBbXTtcblxuICAgIGZvciAoY29uc3QgeyBjb25uS2V5LCBrbmV4IH0gb2YgY29ubnMpIHtcbiAgICAgIGNvbnN0IHByb2dyZXNzID0gdGhpcy5jcmVhdGVQcm9ncmVzc0hvb2tzKGFjdGlvbiwgY29ubktleSwgb3B0aW9ucyk7XG4gICAgICBsZXQgbWlncmF0aW9uUmVzdWx0OiBbbnVtYmVyLCBzdHJpbmdbXV07XG4gICAgICB0cnkge1xuICAgICAgICBtaWdyYXRpb25SZXN1bHQgPVxuICAgICAgICAgIGFjdGlvbiA9PT0gXCJhcHBseVwiXG4gICAgICAgICAgICA/IGF3YWl0IGtuZXgubWlncmF0ZS5sYXRlc3QocHJvZ3Jlc3MpXG4gICAgICAgICAgICA6IGF3YWl0IGtuZXgubWlncmF0ZS5yb2xsYmFjayhwcm9ncmVzcyk7XG4gICAgICB9IGNhdGNoIChjYXVnaHQpIHtcbiAgICAgICAgLy8gbGlmZWN5Y2xlIGhvb2sg7J207KCE7J2YIOyXsOqysMK3bG9ja8K366qp66GdIOyhsO2ajCDsi6TtjKjrj4Qg7Iuk7KCcIOuMgOyDgSBEQuyXkCDqt4Dsho3tlanri4jri6QuXG4gICAgICAgIHRocm93IG5ldyBNaWdyYXRpb25UYXJnZXRFeGVjdXRpb25FcnJvcihjb25uS2V5LCBjYXVnaHQpO1xuICAgICAgfVxuICAgICAgY29uc3QgW2JhdGNoTm8sIGFwcGxpZWRdID0gbWlncmF0aW9uUmVzdWx0O1xuXG4gICAgICByZXN1bHRzLnB1c2goe1xuICAgICAgICBjb25uS2V5LFxuICAgICAgICBiYXRjaE5vLFxuICAgICAgICBhcHBsaWVkLFxuICAgICAgfSk7XG4gICAgICB0aGlzLmVtaXRQcm9ncmVzcyhvcHRpb25zLCB7XG4gICAgICAgIHR5cGU6IFwidGFyZ2V0LWNvbXBsZXRlXCIsXG4gICAgICAgIGFjdGlvbixcbiAgICAgICAgY29ubktleSxcbiAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgZmlsZXM6IGFwcGxpZWQsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfVxuXG4gIHByaXZhdGUgbWlncmF0aW9uTmFtZTxWYWx1ZT4obWlncmF0aW9uOiBWYWx1ZSk6IHN0cmluZyB7XG4gICAgaWYgKGlzU3RyaW5nVmFsdWUobWlncmF0aW9uKSkge1xuICAgICAgcmV0dXJuIHBhdGguYmFzZW5hbWUobWlncmF0aW9uKTtcbiAgICB9XG4gICAgaWYgKGlzT2JqZWN0VmFsdWUobWlncmF0aW9uKSAmJiBtaWdyYXRpb24gIT09IG51bGwpIHtcbiAgICAgIGNvbnN0IGNhbmRpZGF0ZSA9XG4gICAgICAgIC8qIFNBRkVUWTogS25leOyZgCBQb3N0Z3JlU1FMIOyKpO2CpOuniCDsobDtmowg6rOE7JW97J20IOydtCDqsJLsnZgg7YOA7J6F7J2EIOuztOyepe2VnOuLpC4gKi8gbWlncmF0aW9uIGFzIHtcbiAgICAgICAgICBmaWxlPzogdW5rbm93bjtcbiAgICAgICAgICBuYW1lPzogdW5rbm93bjtcbiAgICAgICAgfTtcbiAgICAgIGlmIChpc1N0cmluZ1ZhbHVlKGNhbmRpZGF0ZS5maWxlKSkge1xuICAgICAgICByZXR1cm4gcGF0aC5iYXNlbmFtZShjYW5kaWRhdGUuZmlsZSk7XG4gICAgICB9XG4gICAgICBpZiAoaXNTdHJpbmdWYWx1ZShjYW5kaWRhdGUubmFtZSkpIHtcbiAgICAgICAgcmV0dXJuIHBhdGguYmFzZW5hbWUoY2FuZGlkYXRlLm5hbWUpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gU3RyaW5nKG1pZ3JhdGlvbik7XG4gIH1cblxuICBwcml2YXRlIGVtaXRQcm9ncmVzcyhvcHRpb25zOiBNaWdyYXRpb25SdW5PcHRpb25zIHwgdW5kZWZpbmVkLCBldmVudDogTWlncmF0aW9uUHJvZ3Jlc3NFdmVudCkge1xuICAgIHRyeSB7XG4gICAgICBvcHRpb25zPy5vblByb2dyZXNzPy4oZXZlbnQpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAvLyDsp4TtlonrpaAg7IaM67mE7J6Q7J2YIOyLpO2MqOqwgCDsnbTrr7gg7Iuc7J6R7ZWcIERCIOyekeyXheqzvCDsoJXrpqzrpbwg67Cp7ZW07ZWY66m0IOyViCDrkKnri4jri6QuXG4gICAgICBjb25zb2xlLndhcm4oXCJNaWdyYXRpb24gcHJvZ3Jlc3Mgb2JzZXJ2ZXIgZmFpbGVkOlwiLCBlcnJvcik7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVQcm9ncmVzc0hvb2tzKFxuICAgIGFjdGlvbjogTWlncmF0aW9uQWN0aW9uLFxuICAgIGNvbm5LZXk6IE1pZ3JhdGlvblRhcmdldCB8IFwic2hhZG93XCIsXG4gICAgb3B0aW9ucz86IE1pZ3JhdGlvblJ1bk9wdGlvbnMsXG4gICk6IEtuZXguTWlncmF0b3JDb25maWdXaXRoTGlmZWN5Y2xlSG9va3Mge1xuICAgIGxldCBmaWxlczogc3RyaW5nW10gPSBbXTtcbiAgICBjb25zdCBlbWl0RmlsZSA9IDxWYWx1ZT4odHlwZTogXCJmaWxlLXN0YXJ0XCIgfCBcImZpbGUtZXhlY3V0ZWRcIiwgbWlncmF0aW9uOiBWYWx1ZSkgPT4ge1xuICAgICAgY29uc3QgZmlsZSA9IHRoaXMubWlncmF0aW9uTmFtZShtaWdyYXRpb24pO1xuICAgICAgY29uc3QgaW5kZXggPSBNYXRoLm1heChmaWxlcy5pbmRleE9mKGZpbGUpLCAwKTtcbiAgICAgIHRoaXMuZW1pdFByb2dyZXNzKG9wdGlvbnMsIHtcbiAgICAgICAgdHlwZSxcbiAgICAgICAgYWN0aW9uLFxuICAgICAgICBjb25uS2V5LFxuICAgICAgICBmaWxlLFxuICAgICAgICBpbmRleCxcbiAgICAgICAgdG90YWw6IGZpbGVzLmxlbmd0aCxcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICByZXR1cm4ge1xuICAgICAgYmVmb3JlQWxsOiBhc3luYyAoX2tuZXgsIG1pZ3JhdGlvbnMpID0+IHtcbiAgICAgICAgZmlsZXMgPSBtaWdyYXRpb25zLm1hcCgobWlncmF0aW9uKSA9PiB0aGlzLm1pZ3JhdGlvbk5hbWUobWlncmF0aW9uKSk7XG4gICAgICAgIHRoaXMuZW1pdFByb2dyZXNzKG9wdGlvbnMsIHsgdHlwZTogXCJ0YXJnZXQtc3RhcnRcIiwgYWN0aW9uLCBjb25uS2V5LCBmaWxlcyB9KTtcbiAgICAgIH0sXG4gICAgICBiZWZvcmVFYWNoOiBhc3luYyAoX2tuZXgsIG1pZ3JhdGlvbnMpID0+IHtcbiAgICAgICAgbWlncmF0aW9ucy5mb3JFYWNoKChtaWdyYXRpb24pID0+IGVtaXRGaWxlKFwiZmlsZS1zdGFydFwiLCBtaWdyYXRpb24pKTtcbiAgICAgIH0sXG4gICAgICBhZnRlckVhY2g6IGFzeW5jIChfa25leCwgbWlncmF0aW9ucykgPT4ge1xuICAgICAgICBtaWdyYXRpb25zLmZvckVhY2goKG1pZ3JhdGlvbikgPT4gZW1pdEZpbGUoXCJmaWxlLWV4ZWN1dGVkXCIsIG1pZ3JhdGlvbikpO1xuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3NlcnRNaWdyYXRpb25UYXJnZXQoY29ubktleTogTWlncmF0aW9uVGFyZ2V0KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmdldE1pZ3JhdGlvblRhcmdldEtleXMoKS5pbmNsdWRlcyhjb25uS2V5KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgTWlncmF0aW9uIHRhcmdldCBpcyBub3QgYWxsb3dlZCBpbiBOT0RFX0VOVj0ke2dldFNvbmFtdUVudmlyb25tZW50KCl9OiAke1N0cmluZyhjb25uS2V5KX1gLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICog66eI7J206re466CI7J207IWYIOuMgOyDgSDsu6TrhKXshZjsnZgg7KCV7KCBIOuplO2DgOuNsOydtO2EsOulvCDrsJjtmZjtlanri4jri6QuXG4gICAqIERC7JeQIOyXsOqysO2VmOyngCDslYrsnLzrr4DroZwgQ0xJ7JmAIFdlYuydtCDsg4Htg5wg7KGw7ZqMIOyghOyXkCDsponsi5wg7IKs7Jqp7ZWgIOyImCDsnojsirXri4jri6QuXG4gICAqXG4gICAqIEBjYXRlZ29yeSDrtoTrpqztmJUg66eI7J206re466CI7J207IWYIEFQSVxuICAgKi9cbiAgZ2V0Q29ubmVjdGlvbnMoKTogTWlncmF0aW9uQ29ubmVjdGlvbk1ldGFbXSB7XG4gICAgY29uc3Qgc2xhY2tDb25maXJtID0gbmV3IFNsYWNrQ29uZmlybSgpO1xuICAgIHJldHVybiB0aGlzLmdldE1pZ3JhdGlvblRhcmdldEtleXMoKS5tYXAoKGNvbm5LZXkpID0+IHtcbiAgICAgIGNvbnN0IGNvbm5lY3Rpb24gPVxuICAgICAgICAvKiBTQUZFVFk6IEtuZXjsmYAgUG9zdGdyZVNRTCDsiqTtgqTrp4gg7KGw7ZqMIOqzhOyVveydtCDsnbQg6rCS7J2YIO2DgOyeheydhCDrs7TsnqXtlZzri6QuICovIFNvbmFtdS5kYkNvbmZpZ1tcbiAgICAgICAgICBjb25uS2V5XG4gICAgICAgIF0uY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZztcbiAgICAgIGNvbnN0IGhvc3QgPSBjb25uZWN0aW9uLmhvc3QgPz8gXCJsb2NhbGhvc3RcIjtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNvbm5LZXksXG4gICAgICAgIG5hbWU6IFN0cmluZyhjb25uS2V5KSxcbiAgICAgICAgaG9zdCxcbiAgICAgICAgcG9ydDogY29ubmVjdGlvbi5wb3J0ID8/IDU0MzIsXG4gICAgICAgIGRhdGFiYXNlOiBjb25uZWN0aW9uLmRhdGFiYXNlID8/IFwiXCIsXG4gICAgICAgIHJlbW90ZTogIUxPQ0FMX0RCX0hPU1RTLmhhcyhob3N0LnRvTG93ZXJDYXNlKCkpLFxuICAgICAgICByZXF1aXJlc0FwcHJvdmFsOiBzbGFja0NvbmZpcm0uaXNUYXJnZXRSZXF1aXJlc0FwcHJvdmFsKGNvbm5LZXkpLFxuICAgICAgfTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiDshozsiqTsl5Ag7KG07J6s7ZWY64qUIOuniOydtOq3uOugiOydtOyFmCDtjIzsnbwg66qp66Gd7J2EIOuwmO2ZmO2VqeuLiOuLpC5cbiAgICpcbiAgICogQGNhdGVnb3J5IOu2hOumrO2YlSDrp4jsnbTqt7jroIjsnbTshZggQVBJXG4gICAqL1xuICBhc3luYyBnZXRNaWdyYXRpb25Db2RlcygpOiBQcm9taXNlPE1pZ3JhdGlvbkNvZGVbXT4ge1xuICAgIGNvbnN0IHNyY01pZ3JhdGlvbnNEaXIgPSBwYXRoLmpvaW4oU29uYW11LmFwaVJvb3RQYXRoLCBcInNyY1wiLCBcIm1pZ3JhdGlvbnNcIik7IC8vIOydtOqxtCDtmZjqsr3sl5Ag6rSA6rOE7JeG7J20IO2VreyDgSBzcmPsl5DshJwg7LC+7JWE7JW8IO2VtOyalC5cblxuICAgIGlmICghKGF3YWl0IGV4aXN0cyhzcmNNaWdyYXRpb25zRGlyKSkpIHtcbiAgICAgIGF3YWl0IG1rZGlyKHNyY01pZ3JhdGlvbnNEaXIsIHtcbiAgICAgICAgcmVjdXJzaXZlOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29uc3QgY29kZXMgPSAoYXdhaXQgcmVhZGRpcihzcmNNaWdyYXRpb25zRGlyKSlcbiAgICAgIC5maWx0ZXIoKGYpID0+IGYuZW5kc1dpdGgoXCIudHNcIikpXG4gICAgICAubWFwKChmKSA9PiAoe1xuICAgICAgICBuYW1lOiBmLnJlcGxhY2UoXCIudHNcIiwgXCJcIiksXG4gICAgICAgIHBhdGg6IHBhdGguam9pbihzcmNNaWdyYXRpb25zRGlyLCBmKSxcbiAgICAgIH0pKVxuICAgICAgLnRvU29ydGVkKChhLCBiKSA9PiAoYS5uYW1lIDwgYi5uYW1lID8gMSA6IC0xKSk7IC8vIOydtOumhCDrgrTrprzssKjsiJwg7KCV66CsKOy1nOyLoOyInClcblxuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpnZXRNaWdyYXRpb25Db2RlczpyZXN1bHRzXCIsIGNvZGVzKTtcbiAgICByZXR1cm4gY29kZXM7XG4gIH1cblxuICAvKipcbiAgICog7Luk64Sl7IWYIO2VmOuCmOydmCDtmITsnqwg67KE7KCE6rO8IHBlbmRpbmcg66qp66Gd7J2EIOuPheumveyggeycvOuhnCDsobDtmoztlanri4jri6QuXG4gICAqIOyXrOufrCDrjIDsg4HsnYAg7Zi47Lac7J6Q6rCAIOuzkeugrOuhnCDsobDrpr3tlaAg7IiYIOyeiOyKteuLiOuLpC5cbiAgICpcbiAgICogQGNhdGVnb3J5IOu2hOumrO2YlSDrp4jsnbTqt7jroIjsnbTshZggQVBJXG4gICAqL1xuICBhc3luYyBnZXRDb25uZWN0aW9uU3RhdHVzKGNvbm5LZXk6IE1pZ3JhdGlvblRhcmdldCk6IFByb21pc2U8TWlncmF0aW9uQ29ubmVjdGlvblN0YXR1cz4ge1xuICAgIHRoaXMuYXNzZXJ0TWlncmF0aW9uVGFyZ2V0KGNvbm5LZXkpO1xuICAgIGNvbnN0IHN0YXJ0ZWRBdCA9IHBlcmZvcm1hbmNlLm5vdygpO1xuICAgIGNvbnN0IGNvZGVzID0gYXdhaXQgdGhpcy5nZXRNaWdyYXRpb25Db2RlcygpO1xuICAgIGNvbnN0IGtuZXhPcHRpb25zID0gU29uYW11LmRiQ29uZmlnW2Nvbm5LZXldO1xuICAgIGNvbnN0IGNvbm5lY3Rpb24gPVxuICAgICAgLyogU0FGRVRZOiBLbmV47JmAIFBvc3RncmVTUUwg7Iqk7YKk66eIIOyhsO2ajCDqs4Tslb3snbQg7J20IOqwkuydmCDtg4DsnoXsnYQg67O07J6l7ZWc64ukLiAqLyBrbmV4T3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnO1xuICAgIC8vIFNBRkVUWTogS25leOqwgCDsoJzqs7XtlZwgUG9zdGdyZVNRTCDsl7DqsrAg6rWs7ISx7J2EIOuzteyCrO2VtCB0aW1lb3V0IO2VhOuTnOunjCDrja7slrTsk7Tri6QuXG4gICAgY29uc3QgdENvbm4gPSBjcmVhdGVLbmV4SW5zdGFuY2Uoe1xuICAgICAgLi4ua25leE9wdGlvbnMsXG4gICAgICBjb25uZWN0aW9uOiB7XG4gICAgICAgIC4uLmNvbm5lY3Rpb24sXG4gICAgICAgIGNvbm5lY3Rpb25UaW1lb3V0TWlsbGlzOiBNSUdSQVRJT05fQ09OTl9USU1FT1VUX01TLFxuICAgICAgfSxcbiAgICAgIHBvb2w6IHtcbiAgICAgICAgLi4ua25leE9wdGlvbnMucG9vbCxcbiAgICAgICAgbWluOiAwLFxuICAgICAgICBhY3F1aXJlVGltZW91dE1pbGxpczogTUlHUkFUSU9OX0NPTk5fVElNRU9VVF9NUyxcbiAgICAgICAgY3JlYXRlVGltZW91dE1pbGxpczogTUlHUkFUSU9OX0NPTk5fVElNRU9VVF9NUyxcbiAgICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IHRydWUsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHdpdGhUaW1lb3V0KHRDb25uLnJhdyhcInNlbGVjdCAxXCIpLCBNSUdSQVRJT05fQ09OTl9USU1FT1VUX01TLCAoKSA9PiB7XG4gICAgICAgIHJldHVybiBuZXcgRXJyb3IoXG4gICAgICAgICAgYERCIOyXsOqysCDsi5zqsIQg7LSI6rO8ICgke01JR1JBVElPTl9DT05OX1RJTUVPVVRfTVN9bXMpIOKAlCAke2Nvbm5lY3Rpb24uaG9zdH06JHtjb25uZWN0aW9uLnBvcnR9LyR7Y29ubmVjdGlvbi5kYXRhYmFzZX1gLFxuICAgICAgICApO1xuICAgICAgfSk7XG5cbiAgICAgIGxldCBlcnJvcjogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgICAgY29uc3Qgc3RhdHVzOiBudW1iZXIgfCBcImVycm9yXCIgPSBhd2FpdCB0Q29ubi5taWdyYXRlLnN0YXR1cygpLmNhdGNoKChjYXVnaHQpID0+IHtcbiAgICAgICAgaWYgKHRoaXMuaXNNaXNzaW5nTWlncmF0aW9uVGFibGVFcnJvcihjYXVnaHQpKSB7XG4gICAgICAgICAgcmV0dXJuIGNvZGVzLmxlbmd0aDtcbiAgICAgICAgfVxuICAgICAgICBlcnJvciA9IGNhdWdodCBpbnN0YW5jZW9mIEVycm9yID8gY2F1Z2h0Lm1lc3NhZ2UgOiBTdHJpbmcoY2F1Z2h0KTtcbiAgICAgICAgcmV0dXJuIFwiZXJyb3JcIiBhcyBjb25zdDtcbiAgICAgIH0pO1xuICAgICAgY29uc3QgcGVuZGluZzogc3RyaW5nW10gPSBhd2FpdCB0Q29ubi5taWdyYXRlLmxpc3QoKS50aGVuKFxuICAgICAgICAoWywgZmlsZXNdOiBbdW5rbm93bltdLCB7IGZpbGU6IHN0cmluZyB9W11dKSA9PlxuICAgICAgICAgIGZpbGVzLm1hcCgoeyBmaWxlIH0pID0+IGZpbGUucmVwbGFjZSgvXFwudHMkLywgXCJcIikpLFxuICAgICAgICAoY2F1c2U6IHVua25vd24pID0+IHtcbiAgICAgICAgICBpZiAodGhpcy5pc01pc3NpbmdNaWdyYXRpb25UYWJsZUVycm9yKGNhdXNlKSkge1xuICAgICAgICAgICAgcmV0dXJuIGNvZGVzLm1hcCgoeyBuYW1lIH0pID0+IG5hbWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBlcnJvciA/Pz0gY2F1c2UgaW5zdGFuY2VvZiBFcnJvciA/IGNhdXNlLm1lc3NhZ2UgOiBTdHJpbmcoY2F1c2UpO1xuICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfSxcbiAgICAgICk7XG4gICAgICBjb25zdCBjdXJyZW50VmVyc2lvbjogc3RyaW5nIHwgXCJub25lXCIgfCBcImVycm9yXCIgPSBhd2FpdCB0Q29ubi5taWdyYXRlXG4gICAgICAgIC5jdXJyZW50VmVyc2lvbigpXG4gICAgICAgIC5jYXRjaCgoY2F1c2U6IHVua25vd24pID0+IHtcbiAgICAgICAgICBpZiAodGhpcy5pc01pc3NpbmdNaWdyYXRpb25UYWJsZUVycm9yKGNhdXNlKSkge1xuICAgICAgICAgICAgcmV0dXJuIFwibm9uZVwiIGFzIGNvbnN0O1xuICAgICAgICAgIH1cbiAgICAgICAgICBlcnJvciA/Pz0gY2F1c2UgaW5zdGFuY2VvZiBFcnJvciA/IGNhdXNlLm1lc3NhZ2UgOiBTdHJpbmcoY2F1c2UpO1xuICAgICAgICAgIHJldHVybiBcImVycm9yXCIgYXMgY29uc3Q7XG4gICAgICAgIH0pO1xuICAgICAgTmFpdGUudChcIm1pZ3JhdG9yOmdldFN0YXR1czpzdGF0dXNcIiwgc3RhdHVzKTtcbiAgICAgIGNvbnN0IGNvbm5lY3Rpb25TdGF0dXM6IE1pZ3JhdGlvbkNvbm5lY3Rpb25TdGF0dXMgPSB7XG4gICAgICAgIGNvbm5LZXksXG4gICAgICAgIGN1cnJlbnRWZXJzaW9uLFxuICAgICAgICBzdGF0dXMsXG4gICAgICAgIHBlbmRpbmcsXG4gICAgICAgIGxhdGVuY3lNczogcGVyZm9ybWFuY2Uubm93KCkgLSBzdGFydGVkQXQsXG4gICAgICB9O1xuICAgICAgaWYgKGVycm9yICE9PSB1bmRlZmluZWQpIGNvbm5lY3Rpb25TdGF0dXMuZXJyb3IgPSBlcnJvcjtcbiAgICAgIHJldHVybiBjb25uZWN0aW9uU3RhdHVzO1xuICAgIH0gY2F0Y2ggKGNhdWdodCkge1xuICAgICAgY29uc3QgZXJyb3IgPSBjYXVnaHQgaW5zdGFuY2VvZiBFcnJvciA/IGNhdWdodC5tZXNzYWdlIDogU3RyaW5nKGNhdWdodCk7XG4gICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICBgJHtTdHJpbmcoY29ubktleSl97J2YIOuniOydtOq3uOugiOydtOyFmCDsg4Htg5zrpbwg6rCA7KC47Jik64qUIOuNsOyXkCDsi6TtjKjtlZjsmIDsirXri4jri6QuXFxuJHtlcnJvcn1gLFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNvbm5LZXksXG4gICAgICAgIGN1cnJlbnRWZXJzaW9uOiBcImVycm9yXCIsXG4gICAgICAgIHN0YXR1czogXCJlcnJvclwiLFxuICAgICAgICBwZW5kaW5nOiBbXSxcbiAgICAgICAgbGF0ZW5jeU1zOiBwZXJmb3JtYW5jZS5ub3coKSAtIHN0YXJ0ZWRBdCxcbiAgICAgICAgZXJyb3IsXG4gICAgICB9O1xuICAgIH0gZmluYWxseSB7XG4gICAgICBhd2FpdCB3aXRoVGltZW91dCh0Q29ubi5kZXN0cm95KCksIE1JR1JBVElPTl9DT05OX1RJTUVPVVRfTVMsICgpID0+IHtcbiAgICAgICAgcmV0dXJuIG5ldyBFcnJvcihcImNvbm5lY3Rpb24gZGVzdHJveSB0aW1lb3V0XCIpO1xuICAgICAgfSkuY2F0Y2goKCkgPT4ge30pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiDstZzsi6Ag7IOB7YOc7J24IOq4sOykgCBEQuyZgCDsl5Tti7Dti7Ag7KCV7J2Y66W8IOu5hOq1kO2VtCDsg53shLEg7JiI7KCVIOy9lOuTnOulvCDrsJjtmZjtlanri4jri6QuXG4gICAqXG4gICAqIEBjYXRlZ29yeSDrtoTrpqztmJUg66eI7J206re466CI7J207IWYIEFQSVxuICAgKi9cbiAgYXN5bmMgZ2V0UHJlcGFyZWRDb2Rlcyhjb21wYXJlQ29ubktleTogTWlncmF0aW9uVGFyZ2V0KTogUHJvbWlzZTxHZW5NaWdyYXRpb25Db2RlW10+IHtcbiAgICBjb25zdCBzdGF0dXMgPSBhd2FpdCB0aGlzLmdldENvbm5lY3Rpb25TdGF0dXMoY29tcGFyZUNvbm5LZXkpO1xuICAgIGlmIChzdGF0dXMuc3RhdHVzICE9PSAwIHx8IHN0YXR1cy5lcnJvciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBNaWdyYXRpb24gY29tcGFyaXNvbiByZXF1aXJlcyBhbiB1cC10by1kYXRlIGRhdGFiYXNlOiAke1N0cmluZyhjb21wYXJlQ29ubktleSl9YCxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuY29tcGFyZVdpdGhDb25uZWN0aW9uKGNvbXBhcmVDb25uS2V5KTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgY29tcGFyZVdpdGhDb25uZWN0aW9uKGNvbXBhcmVDb25uS2V5OiBNaWdyYXRpb25UYXJnZXQpIHtcbiAgICBjb25zdCBjb21wYXJlREIgPSBjcmVhdGVLbmV4SW5zdGFuY2UoU29uYW11LmRiQ29uZmlnW2NvbXBhcmVDb25uS2V5XSk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLmNvbXBhcmVNaWdyYXRpb25zKGNvbXBhcmVEQik7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGF3YWl0IGNvbXBhcmVEQi5kZXN0cm95KCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXByZWNhdGVkIOyLoOq3nCBVSeyXkOyEnOuKlCDsu6TrhKXshZjrs4Qg7KGw7ZqMIEFQSeulvCDsgqzsmqntlanri4jri6QuXG4gICAqIOq4sOyhtCBDTEnsmYAg7Iqk7YGs66a97Yq4IO2YuO2ZmOydhCDsnITtlbQg7KCE7LK0IOyDge2DnOulvCDsobDrpr3tlanri4jri6QuXG4gICAqIEBjYXRlZ29yeSDtmLjtmZjsmqkg66eI7J206re466CI7J207IWYIEFQSVxuICAgKi9cbiAgYXN5bmMgZ2V0U3RhdHVzKCk6IFByb21pc2U8TWlncmF0aW9uU3RhdHVzPiB7XG4gICAgY29uc3QgW2NvZGVzLCBjb25uZWN0aW9uc10gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICB0aGlzLmdldE1pZ3JhdGlvbkNvZGVzKCksXG4gICAgICBQcm9taXNlLnJlc29sdmUodGhpcy5nZXRDb25uZWN0aW9ucygpKSxcbiAgICBdKTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOmNvZGVzXCIsIGNvZGVzKTtcblxuICAgIGNvbnN0IGNvbm5lY3Rpb25TdGF0dXNlcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgY29ubmVjdGlvbnMubWFwKCh7IGNvbm5LZXkgfSkgPT4gdGhpcy5nZXRDb25uZWN0aW9uU3RhdHVzKGNvbm5LZXkpKSxcbiAgICApO1xuICAgIGNvbnN0IGNvbm5zID0gY29ubmVjdGlvbnMubWFwKChjb25uZWN0aW9uLCBpbmRleCkgPT4ge1xuICAgICAgY29uc3Qgc3RhdHVzID0gY29ubmVjdGlvblN0YXR1c2VzW2luZGV4XTtcbiAgICAgIGFzc2VydChzdGF0dXMgIT09IHVuZGVmaW5lZCk7XG4gICAgICBjb25zdCBjb25maWd1cmVkID1cbiAgICAgICAgLyogU0FGRVRZOiBLbmV47JmAIFBvc3RncmVTUUwg7Iqk7YKk66eIIOyhsO2ajCDqs4Tslb3snbQg7J20IOqwkuydmCDtg4DsnoXsnYQg67O07J6l7ZWc64ukLiAqLyBTb25hbXUuZGJDb25maWdbXG4gICAgICAgICAgY29ubmVjdGlvbi5jb25uS2V5XG4gICAgICAgIF0uY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZztcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG5hbWU6IGNvbm5lY3Rpb24ubmFtZSxcbiAgICAgICAgY29ubktleTogY29ubmVjdGlvbi5jb25uS2V5LFxuICAgICAgICBjb25uU3RyaW5nOlxuICAgICAgICAgIC8qIFNBRkVUWTogS25leOyZgCBQb3N0Z3JlU1FMIOyKpO2CpOuniCDsobDtmowg6rOE7JW97J20IOydtCDqsJLsnZgg7YOA7J6F7J2EIOuztOyepe2VnOuLpC4gKi8gYHBnOi8vJHtjb25maWd1cmVkLnVzZXIgPz8gXCJcIn1AJHtjb25maWd1cmVkLmhvc3R9OiR7Y29uZmlndXJlZC5wb3J0fS8ke2NvbmZpZ3VyZWQuZGF0YWJhc2V9YCBhcyBDb25uU3RyaW5nLFxuICAgICAgICBjdXJyZW50VmVyc2lvbjogc3RhdHVzLmN1cnJlbnRWZXJzaW9uLFxuICAgICAgICBzdGF0dXM6IHN0YXR1cy5zdGF0dXMsXG4gICAgICAgIHBlbmRpbmc6IHN0YXR1cy5wZW5kaW5nLFxuICAgICAgfTtcbiAgICB9KTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOmNvbm5zXCIsIGNvbm5zKTtcblxuICAgIGNvbnN0IGNvbXBhcmVDb25uID0gY29ubmVjdGlvblN0YXR1c2VzLmZpbmQoXG4gICAgICAoeyBzdGF0dXMsIGVycm9yIH0pID0+IHN0YXR1cyA9PT0gMCAmJiBlcnJvciA9PT0gdW5kZWZpbmVkLFxuICAgICk7XG4gICAgY29uc3QgcHJlcGFyZWRDb2RlcyA9XG4gICAgICBjb21wYXJlQ29ubiA9PT0gdW5kZWZpbmVkID8gW10gOiBhd2FpdCB0aGlzLmNvbXBhcmVXaXRoQ29ubmVjdGlvbihjb21wYXJlQ29ubi5jb25uS2V5KTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOnByZXBhcmVkQ29kZXNcIiwgcHJlcGFyZWRDb2Rlcyk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgY29ubnMsXG4gICAgICBjb2RlcyxcbiAgICAgIHByZXBhcmVkQ29kZXMsXG4gICAgICBlcnJvcjogY29ubmVjdGlvblN0YXR1c2VzLmZpbmQoKHsgZXJyb3IgfSkgPT4gZXJyb3IgIT09IHVuZGVmaW5lZCk/LmVycm9yLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICog64yA7IOBIERC7JeQIHBlbmRpbmcg66eI7J206re466CI7J207IWY7J2EIOyggeyaqe2VqeuLiOuLpC5cbiAgICogQ0xJ7JmAIFdlYuydgCDqsJnsnYAg66mU7ISc65Oc66W8IOyCrOyaqe2VmOupsCwgV2Vi7J2AIGBvblByb2dyZXNzYOulvCBzdHJlYW3snLzroZwg67OA7ZmY7ZWp64uI64ukLlxuICAgKlxuICAgKiBAY2F0ZWdvcnkg67aE66as7ZiVIOuniOydtOq3uOugiOydtOyFmCBBUElcbiAgICovXG4gIGFzeW5jIGFwcGx5KHRhcmdldHM6IE1pZ3JhdGlvblRhcmdldFtdLCBvcHRpb25zPzogTWlncmF0aW9uUnVuT3B0aW9ucyk6IFByb21pc2U8TWlncmF0aW9uUmVzdWx0PiB7XG4gICAgcmV0dXJuIHRoaXMucnVuQWN0aW9uV2l0aFByb2dyZXNzKFwiYXBwbHlcIiwgdGFyZ2V0cywgb3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICog64yA7IOBIERC7JeQ7IScIOqwgOyepSDstZzqt7wgbWlncmF0aW9uIGJhdGNo66W8IOuhpOuwse2VqeuLiOuLpC5cbiAgICogQ0xJ7JmAIFdlYuydgCDqsJnsnYAg66mU7ISc65Oc66W8IOyCrOyaqe2VmOupsCwgV2Vi7J2AIGBvblByb2dyZXNzYOulvCBzdHJlYW3snLzroZwg67OA7ZmY7ZWp64uI64ukLlxuICAgKlxuICAgKiBAY2F0ZWdvcnkg67aE66as7ZiVIOuniOydtOq3uOugiOydtOyFmCBBUElcbiAgICovXG4gIGFzeW5jIHJvbGxiYWNrKFxuICAgIHRhcmdldHM6IE1pZ3JhdGlvblRhcmdldFtdLFxuICAgIG9wdGlvbnM/OiBNaWdyYXRpb25SdW5PcHRpb25zLFxuICApOiBQcm9taXNlPE1pZ3JhdGlvblJlc3VsdD4ge1xuICAgIHJldHVybiB0aGlzLnJ1bkFjdGlvbldpdGhQcm9ncmVzcyhcInJvbGxiYWNrXCIsIHRhcmdldHMsIG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXByZWNhdGVkIGFjdGlvbiDrrLjsnpDsl7Qg64yA7IugIHtAbGluayBhcHBseX0g65iQ64qUIHtAbGluayByb2xsYmFja33snYQg7KeB7KCRIOyCrOyaqe2VqeuLiOuLpC5cbiAgICog6riw7KG0IOyZuOu2gCDtmLjstpzsnZgg7ZWY7JyEIO2YuO2ZmOunjOydhCDsnITtlbQg7Jyg7KeA7ZWp64uI64ukLlxuICAgKiBAY2F0ZWdvcnkg7Zi47ZmY7JqpIOuniOydtOq3uOugiOydtOyFmCBBUElcbiAgICovXG4gIGFzeW5jIHJ1bkFjdGlvbihcbiAgICBhY3Rpb246IFwiYXBwbHlcIiB8IFwicm9sbGJhY2tcIixcbiAgICB0YXJnZXRzOiAoa2V5b2YgU29uYW11REJDb25maWcpW10sXG4gICk6IFByb21pc2U8TWlncmF0aW9uUmVzdWx0PiB7XG4gICAgcmV0dXJuIGFjdGlvbiA9PT0gXCJhcHBseVwiID8gdGhpcy5hcHBseSh0YXJnZXRzKSA6IHRoaXMucm9sbGJhY2sodGFyZ2V0cyk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJ1bkFjdGlvbldpdGhQcm9ncmVzcyhcbiAgICBhY3Rpb246IFwiYXBwbHlcIiB8IFwicm9sbGJhY2tcIixcbiAgICB0YXJnZXRzOiBNaWdyYXRpb25UYXJnZXRbXSxcbiAgICBvcHRpb25zPzogTWlncmF0aW9uUnVuT3B0aW9ucyxcbiAgKTogUHJvbWlzZTxNaWdyYXRpb25SZXN1bHQ+IHtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6cnVuQWN0aW9uOmFjdGlvblwiLCBhY3Rpb24pO1xuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpydW5BY3Rpb246dGFyZ2V0c1wiLCB0YXJnZXRzKTtcblxuICAgIGNvbnN0IGFsbG93ZWRUYXJnZXRzID0gbmV3IFNldCh0aGlzLmdldE1pZ3JhdGlvblRhcmdldEtleXMoKSk7XG4gICAgY29uc3QgZGlzYWxsb3dlZFRhcmdldHMgPSB0YXJnZXRzLmZpbHRlcigodGFyZ2V0KSA9PiAhYWxsb3dlZFRhcmdldHMuaGFzKHRhcmdldCkpO1xuICAgIGlmIChkaXNhbGxvd2VkVGFyZ2V0cy5sZW5ndGggPiAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBNaWdyYXRpb24gdGFyZ2V0cyBhcmUgbm90IGFsbG93ZWQgaW4gTk9ERV9FTlY9JHtnZXRTb25hbXVFbnZpcm9ubWVudCgpfTogJHtkaXNhbGxvd2VkVGFyZ2V0cy5qb2luKFwiLCBcIil9YCxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gZ2V0IHVuaXEga25leCBjb25maWdzXG4gICAgY29uc3QgY29uZmlncyA9IHVuaXF1ZShcbiAgICAgIHRhcmdldHNcbiAgICAgICAgLm1hcCgodGFyZ2V0KSA9PiAoe1xuICAgICAgICAgIGNvbm5LZXk6IHRhcmdldCxcbiAgICAgICAgICBvcHRpb25zOiBTb25hbXUuZGJDb25maWdbdGFyZ2V0XSxcbiAgICAgICAgfSkpXG4gICAgICAgIC5maWx0ZXIoKGMpID0+IGMub3B0aW9ucyAhPT0gdW5kZWZpbmVkKSxcbiAgICAgICh7IG9wdGlvbnM6IGRiT3B0aW9ucyB9KSA9PlxuICAgICAgICBgJHsvKiBTQUZFVFk6IEtuZXjsmYAgUG9zdGdyZVNRTCDsiqTtgqTrp4gg7KGw7ZqMIOqzhOyVveydtCDsnbQg6rCS7J2YIO2DgOyeheydhCDrs7TsnqXtlZzri6QuICovIChkYk9wdGlvbnMuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZykuaG9zdH06JHtcbiAgICAgICAgICAvKiBTQUZFVFk6IEtuZXjsmYAgUG9zdGdyZVNRTCDsiqTtgqTrp4gg7KGw7ZqMIOqzhOyVveydtCDsnbQg6rCS7J2YIO2DgOyeheydhCDrs7TsnqXtlZzri6QuICovIChcbiAgICAgICAgICAgIGRiT3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnXG4gICAgICAgICAgKS5wb3J0ID8/IDU0MzJcbiAgICAgICAgfS8key8qIFNBRkVUWTogS25leOyZgCBQb3N0Z3JlU1FMIOyKpO2CpOuniCDsobDtmowg6rOE7JW97J20IOydtCDqsJLsnZgg7YOA7J6F7J2EIOuztOyepe2VnOuLpC4gKi8gKGRiT3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnKS5kYXRhYmFzZX1gLFxuICAgICk7XG5cbiAgICAvLyBnZXQgY29ubmVjdGlvbnNcbiAgICBjb25zdCBjb25ucyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgY29uZmlncy5tYXAoYXN5bmMgKGNvbmZpZykgPT4gKHtcbiAgICAgICAgY29ubktleTogY29uZmlnLmNvbm5LZXksXG4gICAgICAgIGtuZXg6IGNyZWF0ZUtuZXhJbnN0YW5jZShjb25maWcub3B0aW9ucyksXG4gICAgICB9KSksXG4gICAgKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnJ1bk1pZ3JhdGlvbnNTZXF1ZW50aWFsbHkoY29ubnMsIGFjdGlvbiwgb3B0aW9ucyk7XG5cbiAgICAgIE5haXRlLnQoXCJtaWdyYXRvcjpydW5BY3Rpb246cmVzdWx0XCIsIHJlc3VsdCk7XG5cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBjb25ucy5tYXAoKHsga25leCB9KSA9PiB7XG4gICAgICAgICAgcmV0dXJuIGtuZXguZGVzdHJveSgpO1xuICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZW5EYXRlVGFnKGluZGV4OiBudW1iZXIsIGJhc2VEYXRlOiBEYXRlID0gbmV3IERhdGUoKSk6IHN0cmluZyB7XG4gICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKGJhc2VEYXRlLmdldFRpbWUoKSArIGluZGV4ICogMTAwMCk7XG4gICAgcmV0dXJuIChcbiAgICAgIGRhdGUuZ2V0RnVsbFllYXIoKS50b1N0cmluZygpICtcbiAgICAgIHBhZERhdGVQYXJ0KGRhdGUuZ2V0TW9udGgoKSArIDEpICtcbiAgICAgIHBhZERhdGVQYXJ0KGRhdGUuZ2V0RGF0ZSgpKSArXG4gICAgICBwYWREYXRlUGFydChkYXRlLmdldEhvdXJzKCkpICtcbiAgICAgIHBhZERhdGVQYXJ0KGRhdGUuZ2V0TWludXRlcygpKSArXG4gICAgICBwYWREYXRlUGFydChkYXRlLmdldFNlY29uZHMoKSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J287J2EIOyDneyEse2VqeuLiOuLpC5cbiAgICpcbiAgICogU29uYW11IFVJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQHJldHVybnMg7IOd7ISx65CcIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J28IOqwnOyImFxuICAgKi9cbiAgYXN5bmMgZ2VuZXJhdGVQcmVwYXJlZENvZGVzKGNvbXBhcmVDb25uS2V5PzogTWlncmF0aW9uVGFyZ2V0KTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCBwcmVwYXJlZENvZGVzID1cbiAgICAgIGNvbXBhcmVDb25uS2V5ID09PSB1bmRlZmluZWRcbiAgICAgICAgPyAoYXdhaXQgdGhpcy5nZXRTdGF0dXMoKSkucHJlcGFyZWRDb2Rlc1xuICAgICAgICA6IGF3YWl0IHRoaXMuZ2V0UHJlcGFyZWRDb2Rlcyhjb21wYXJlQ29ubktleSk7XG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOmdlbmVyYXRlUHJlcGFyZWRDb2RlczpwcmVwYXJlZENvZGVzXCIsIHByZXBhcmVkQ29kZXMpO1xuICAgIGlmIChwcmVwYXJlZENvZGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oXCJcXG7tmITsnqwg66qo65GQIOyLse2BrOuQnCDsg4Htg5zsnoXri4jri6QuXCIpKTtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cblxuICAgIC8vIOyLpOygnCDsvZTrk5wg7IOd7ISxXG4gICAgY29uc3QgbWlncmF0aW9uc0RpciA9IGAke1NvbmFtdS5hcGlSb290UGF0aH0vc3JjL21pZ3JhdGlvbnNgO1xuXG4gICAgZm9yIChjb25zdCBbaW5kZXgsIHBjb2RlXSBvZiBwcmVwYXJlZENvZGVzLmVudHJpZXMoKSkge1xuICAgICAgaWYgKHBjb2RlLmZvcm1hdHRlZCkge1xuICAgICAgICBjb25zdCBkYXRlVGFnID0gdGhpcy5nZW5EYXRlVGFnKGluZGV4KTtcbiAgICAgICAgY29uc3QgZmlsZVBhdGggPSBgJHttaWdyYXRpb25zRGlyfS8ke2RhdGVUYWd9XyR7cGNvZGUudGl0bGV9LnRzYDtcbiAgICAgICAgYXdhaXQgd3JpdGVGaWxlKGZpbGVQYXRoLCBwY29kZS5mb3JtYXR0ZWQpO1xuICAgICAgICAhaXNUZXN0KCkgJiYgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oYE1JR1JBVElPTiBDUkVBVEVEICR7ZmlsZVBhdGh9YCkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBwcmVwYXJlZENvZGVzLmxlbmd0aDtcbiAgfVxuXG4gIGFzeW5jIGNvbXBhcmVNaWdyYXRpb25zKGNvbXBhcmVEQjogS25leCk6IFByb21pc2U8R2VuTWlncmF0aW9uQ29kZVtdPiB7XG4gICAgLy8gRW50aXR5IOyInO2ajO2VmOyXrCDsi7HtgaxcbiAgICBjb25zdCBlbnRpdHlJZHMgPSBFbnRpdHlNYW5hZ2VyLmdldEFsbElkcygpO1xuXG4gICAgLy8g7KGw7J247YWM7J2067iUIO2PrO2VqO2VmOyXrCBFbnRpdHnsl5DshJwgTWlncmF0aW9uU2V0IOy2lOy2nFxuICAgIGNvbnN0IGVudGl0eVNldHNXaXRoSm9pblRhYmxlID0gZW50aXR5SWRzXG4gICAgICAuZmlsdGVyKChlbnRpdHlJZCkgPT4gRW50aXR5TWFuYWdlci5nZXQoZW50aXR5SWQpLnByb3BzLmxlbmd0aCA+IDApXG4gICAgICAubWFwKChlbnRpdHlJZCkgPT4gZ2V0TWlncmF0aW9uU2V0RnJvbUVudGl0eShFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCkpKTtcblxuICAgIC8vIOyhsOyduO2FjOydtOu4lOunjCDstpTstpxcbiAgICBjb25zdCBqb2luVGFibGVzV2l0aER1cCA9IGVudGl0eVNldHNXaXRoSm9pblRhYmxlLmZsYXRNYXAoKGVudGl0eVNldCkgPT4gZW50aXR5U2V0LmpvaW5UYWJsZXMpO1xuICAgIC8vIOykkeuztSDsoJzqsbAgKOykkeuzteyduCDqsr3smrAgaW5kZXhlc+ulvCDrs5HtlakpXG4gICAgY29uc3Qgam9pblRhYmxlcyA9IE9iamVjdC52YWx1ZXMoZ3JvdXAoam9pblRhYmxlc1dpdGhEdXAsIChqdCkgPT4ganQudGFibGUpKS5tYXAoKHRhYmxlcykgPT4ge1xuICAgICAgYXNzZXJ0KHRhYmxlcyAhPT0gdW5kZWZpbmVkLCBcInRhYmxlcyBpcyB1bmRlZmluZWRcIik7XG4gICAgICBpZiAodGFibGVzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICByZXR1cm4gdGFibGVzWzBdO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgLi4udGFibGVzWzBdLFxuICAgICAgICBpbmRleGVzOiB1bmlxdWUoXG4gICAgICAgICAgdGFibGVzLmZsYXRNYXAoKHQpID0+IHQuaW5kZXhlcyksXG4gICAgICAgICAgKGluZGV4KSA9PiBbaW5kZXgudHlwZSwgLi4uaW5kZXguY29sdW1uc10uam9pbihcIi1cIiksXG4gICAgICAgICksXG4gICAgICB9O1xuICAgIH0pO1xuXG4gICAgLy8g7KGw7J247YWM7J2067iUIO2PrO2VqO2VmOyXrCBNaWdyYXRpb25TZXQg67Cw7Je0XG4gICAgY29uc3QgZW50aXR5U2V0czogTWlncmF0aW9uU2V0W10gPSBbLi4uZW50aXR5U2V0c1dpdGhKb2luVGFibGUsIC4uLmpvaW5UYWJsZXNdO1xuXG4gICAgY29uc3QgY29kZXM6IEdlbk1pZ3JhdGlvbkNvZGVbXSA9IFtdO1xuICAgIGNvbnN0IGJhdGNoU2l6ZSA9IDQ7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGVudGl0eVNldHMubGVuZ3RoOyBpICs9IGJhdGNoU2l6ZSkge1xuICAgICAgY29uc3QgYmF0Y2hDb2RlcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBlbnRpdHlTZXRzLnNsaWNlKGksIGkgKyBiYXRjaFNpemUpLm1hcChhc3luYyAoZW50aXR5U2V0KSA9PiB7XG4gICAgICAgICAgY29uc3QgZGJTZXQgPSBhd2FpdCBQb3N0Z3JlU1FMU2NoZW1hUmVhZGVyLmdldE1pZ3JhdGlvblNldEZyb21EQihcbiAgICAgICAgICAgIGNvbXBhcmVEQixcbiAgICAgICAgICAgIGVudGl0eVNldC50YWJsZSxcbiAgICAgICAgICApO1xuICAgICAgICAgIE5haXRlLnQoYG1pZ3JhdG9yOmNvbXBhcmVNaWdyYXRpb25zOmVudGl0eVNldDoke2VudGl0eVNldC50YWJsZX1gLCBlbnRpdHlTZXQpO1xuICAgICAgICAgIE5haXRlLnQoYG1pZ3JhdG9yOmNvbXBhcmVNaWdyYXRpb25zOmRiU2V0OiR7ZW50aXR5U2V0LnRhYmxlfWAsIGRiU2V0KTtcblxuICAgICAgICAgIGlmIChkYlNldCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgLy8g6riw7KG0IO2FjOydtOu4lCDsl4bsnYwsIOyDiOuhnCDthYzsnbTruJQg7IOd7ISxXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZ2VuZXJhdGVDcmVhdGVDb2RlKGVudGl0eVNldCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIOq4sOyhtCDthYzsnbTruJQg7KG07J6s7ZWY64qUIOy8gOydtOyKpFxuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IGdlbmVyYXRlQWx0ZXJDb2RlKGVudGl0eVNldCwgZGJTZXQsIGNvbXBhcmVEQik7XG4gICAgICAgICAgfVxuICAgICAgICB9KSxcbiAgICAgICk7XG5cbiAgICAgIGNvZGVzLnB1c2goLi4uYmF0Y2hDb2Rlcy5mbGF0KCkpO1xuICAgIH1cblxuICAgIC8vIG5vcm1hbCDtg4DsnoXsnbQg7JWe7Jy866GcLCBmb3JlaWdu7J20IOuSpOuhnFxuICAgIGNvZGVzLnNvcnQoKGNvZGVBLCBjb2RlQikgPT4ge1xuICAgICAgaWYgKGNvZGVBLnR5cGUgPT09IFwiZm9yZWlnblwiICYmIGNvZGVCLnR5cGUgPT09IFwibm9ybWFsXCIpIHtcbiAgICAgICAgcmV0dXJuIDE7XG4gICAgICB9IGVsc2UgaWYgKGNvZGVBLnR5cGUgPT09IFwibm9ybWFsXCIgJiYgY29kZUIudHlwZSA9PT0gXCJmb3JlaWduXCIpIHtcbiAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIDA7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICByZXR1cm4gY29kZXM7XG4gIH1cblxuICAvKipcbiAgICogdGVzdCBEQuydmCBzbmFwc2hvdOycvOuhnCDsnoTsi5wgU2hhZG93IERC66W8IOunjOuTpOqzoCDsoITssrQg66eI7J206re466CI7J207IWY7J2EIOqygOymne2VqeuLiOuLpC5cbiAgICogQ0xJ7JmAIFdlYuydgCBgb25Qcm9ncmVzc2Ag7Jyg66y066eMIOuLrOumrO2VtCDqsJnsnYAg7Iuk7ZaJIOydmOuvuOulvCDqs7XsnKDtlaAg7IiYIOyeiOyKteuLiOuLpC5cbiAgICpcbiAgICogQGNhdGVnb3J5IOu2hOumrO2YlSDrp4jsnbTqt7jroIjsnbTshZggQVBJXG4gICAqL1xuICBhc3luYyBydW5TaGFkb3dUZXN0KG9wdGlvbnM/OiBNaWdyYXRpb25SdW5PcHRpb25zKTogUHJvbWlzZTxNaWdyYXRpb25SZXN1bHQ+IHtcbiAgICBjb25zdCBiYXNlVGVzdENvbm4gPVxuICAgICAgLyogU0FGRVRZOiBLbmV47JmAIFBvc3RncmVTUUwg7Iqk7YKk66eIIOyhsO2ajCDqs4Tslb3snbQg7J20IOqwkuydmCDtg4DsnoXsnYQg67O07J6l7ZWc64ukLiAqLyBTb25hbXUuZGJDb25maWdcbiAgICAgICAgLnRlc3QuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZztcbiAgICBjb25zdCB3b3JrZXJJZCA9IHByb2Nlc3MuZW52LlNPTkFNVV9XT1JLRVJfREIgPT09IFwidHJ1ZVwiID8gcHJvY2Vzcy5lbnYuVklURVNUX1BPT0xfSUQgOiBudWxsO1xuICAgIGNvbnN0IHRlbXBsYXRlRGF0YWJhc2UgPVxuICAgICAgd29ya2VySWQgIT09IG51bGwgPyBgJHtiYXNlVGVzdENvbm4uZGF0YWJhc2V9XyR7d29ya2VySWQgPz8gXCIxXCJ9YCA6IGJhc2VUZXN0Q29ubi5kYXRhYmFzZTtcbiAgICBjb25zdCB0ZGJDb25uID0geyAuLi5iYXNlVGVzdENvbm4sIGRhdGFiYXNlOiB0ZW1wbGF0ZURhdGFiYXNlIH07XG4gICAgY29uc3Qgc2hhZG93RGF0YWJhc2UgPSBgJHt0ZW1wbGF0ZURhdGFiYXNlfV9fbWlncmF0aW9uX3NoYWRvd2A7XG5cbiAgICAvLyDthYzsiqTtirgg7IOB7Zmp7JeQ7ISc64qUIO2KuOuenOyereyFmOydhCDstIjquLDtmZTtlZjqs6AsIOyDiCDrjbDsnbTthLDrsqDsnbTsiqQg7Luk64Sl7IWY7J2EIOqwgOyguOyZgOyVvCDtlahcbiAgICBpZiAoaXNUZXN0KCkpIHtcbiAgICAgIGF3YWl0IERCLmNsZWFyVGVzdFRyYW5zYWN0aW9uKCk7XG4gICAgICBhd2FpdCBEQi5kZXN0cm95KCk7XG4gICAgfVxuXG4gICAgLy8g6riw7KG0IFNoYWRvdyBEQiDsgq3soJwg7ZuEIFNoYWRvdyBEQiDsg53shLFcbiAgICBjb25zdCB0ZGIgPSBjcmVhdGVLbmV4SW5zdGFuY2Uoe1xuICAgICAgLi4uU29uYW11LmRiQ29uZmlnLnRlc3QsXG4gICAgICBjb25uZWN0aW9uOiB7XG4gICAgICAgIC4uLmJhc2VUZXN0Q29ubixcbiAgICAgICAgZGF0YWJhc2U6IFwicG9zdGdyZXNcIixcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgdHJ5IHtcbiAgICAgICFpc1Rlc3QoKSAmJiBjb25zb2xlLmxvZyhjaGFsay5tYWdlbnRhKGAke3NoYWRvd0RhdGFiYXNlfSDsgq3soJxgKSk7XG4gICAgICBhd2FpdCB0ZGIucmF3KGBEUk9QIERBVEFCQVNFIElGIEVYSVNUUyAke3NoYWRvd0RhdGFiYXNlfWApO1xuICAgICAgYXdhaXQgdGRiLnJhdyhgXG4gICAgICAgIFNFTEVDVCBwZ190ZXJtaW5hdGVfYmFja2VuZChwZ19zdGF0X2FjdGl2aXR5LnBpZClcbiAgICAgICAgRlJPTSBwZ19zdGF0X2FjdGl2aXR5XG4gICAgICAgIFdIRVJFIGRhdG5hbWUgPSAnJHt0ZGJDb25uLmRhdGFiYXNlfSdcbiAgICAgICAgICBBTkQgcGlkIDw+IHBnX2JhY2tlbmRfcGlkKCk7XG4gICAgICBgKTtcbiAgICAgIGF3YWl0IHRkYi5yYXcoYENSRUFURSBEQVRBQkFTRSAke3NoYWRvd0RhdGFiYXNlfSBURU1QTEFURSAke3RkYkNvbm4uZGF0YWJhc2V9YCk7XG5cbiAgICAgIC8vIFNoYWRvdyBEQuyXkCDsl7DqsrBcbiAgICAgIGNvbnN0IHNkYiA9IGNyZWF0ZUtuZXhJbnN0YW5jZSh7XG4gICAgICAgIC4uLlNvbmFtdS5kYkNvbmZpZy50ZXN0LFxuICAgICAgICBjb25uZWN0aW9uOiB7XG4gICAgICAgICAgLi4udGRiQ29ubixcbiAgICAgICAgICBkYXRhYmFzZTogc2hhZG93RGF0YWJhc2UsXG4gICAgICAgICAgcGFzc3dvcmQ6IHRkYkNvbm4ucGFzc3dvcmQsXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgLy8gc2hhZG93IERCIO2FjOyKpO2KuCDsp4TtlolcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHByb2dyZXNzID0gdGhpcy5jcmVhdGVQcm9ncmVzc0hvb2tzKFwic2hhZG93XCIsIFwic2hhZG93XCIsIG9wdGlvbnMpO1xuICAgICAgICBjb25zdCBbYmF0Y2hObywgYXBwbGllZF0gPSBhd2FpdCBzZGIubWlncmF0ZS5sYXRlc3QocHJvZ3Jlc3MpO1xuICAgICAgICAhaXNUZXN0KCkgJiZcbiAgICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihcIlNoYWRvdyBEQiDthYzsiqTtirjsl5Ag7ISx6rO17ZaI7Iq164uI64ukIVwiKSwge1xuICAgICAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgICAgIGFwcGxpZWQsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5lbWl0UHJvZ3Jlc3Mob3B0aW9ucywge1xuICAgICAgICAgIHR5cGU6IFwidGFyZ2V0LWNvbXBsZXRlXCIsXG4gICAgICAgICAgYWN0aW9uOiBcInNoYWRvd1wiLFxuICAgICAgICAgIGNvbm5LZXk6IFwic2hhZG93XCIsXG4gICAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgICBmaWxlczogYXBwbGllZCxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBjb25uS2V5OiBcInNoYWRvd1wiLFxuICAgICAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgICAgIGFwcGxpZWQsXG4gICAgICAgICAgfSxcbiAgICAgICAgXTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihlKTtcbiAgICAgICAgdGhyb3cgbmV3IE1pZ3JhdGlvblRhcmdldEV4ZWN1dGlvbkVycm9yKFxuICAgICAgICAgIFwic2hhZG93XCIsXG4gICAgICAgICAgbmV3IFNlcnZpY2VVbmF2YWlsYWJsZUV4Y2VwdGlvbihTRChcInNvbmFtdS5lcnJvci5zaGFkb3dEYlRlc3RGYWlsZWRcIikpLFxuICAgICAgICApO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYXdhaXQgc2RiLmRlc3Ryb3koKTtcbiAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgLy8gU2hhZG93IERCIOyCreygnFxuICAgICAgIWlzVGVzdCgpICYmIGNvbnNvbGUubG9nKGNoYWxrLm1hZ2VudGEoYCR7c2hhZG93RGF0YWJhc2V9IOyCreygnGApKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRkYi5yYXcoYERST1AgREFUQUJBU0UgSUYgRVhJU1RTICR7c2hhZG93RGF0YWJhc2V9YCk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJTaGFkb3cgREIg7KCV66asIOyLpO2MqDpcIiwgZSk7IC8vIOydtOqyjCDsl4bsnLzrqbQg7KGw7Jqp7Z6IIOuIhOyImFxuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYXdhaXQgdGRiLmRlc3Ryb3koKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQTJDQSxTQUFTLFlBQVksUUFBZ0IsT0FBZSxHQUFXO0NBQzdELE9BQU8sT0FBTyxTQUFTLENBQUMsQ0FBQyxTQUFTLE1BQU0sR0FBRztBQUM3Qzs7Ozs7QUFzQkEsU0FBUyxZQUFlLFNBQXFCLElBQVksV0FBb0M7Q0FDM0YsT0FBTyxJQUFJLFNBQVksU0FBUyxXQUFXO0VBQ3pDLE1BQU0sUUFBUSxpQkFBaUIsT0FBTyxVQUFVLENBQUMsR0FBRyxFQUFFO0VBQ3RELFFBQVEsTUFDTCxVQUFVO0dBQ1QsYUFBYSxLQUFLO0dBQ2xCLFFBQVEsS0FBSztFQUNmLElBQ0MsVUFBVTtHQUNULGFBQWEsS0FBSztHQUNsQixPQUFPLEtBQUs7RUFDZCxDQUNGO0NBQ0YsQ0FBQztBQUNIOzs7YUF6RXNDO1NBQ0g7V0FFa0I7U0FDdEI7cUJBQ3lCO1VB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