sonamu 0.8.26 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (684) hide show
  1. package/bin/cli.js +60 -13
  2. package/dist/_virtual/rolldown_runtime.js +39 -0
  3. package/dist/ai/agents/agent.d.ts +3 -3
  4. package/dist/ai/agents/agent.d.ts.map +1 -1
  5. package/dist/ai/agents/agent.js +76 -73
  6. package/dist/ai/agents/index.js +3 -3
  7. package/dist/ai/agents/types.d.ts +3 -3
  8. package/dist/ai/agents/types.d.ts.map +1 -1
  9. package/dist/ai/agents/types.js +1 -3
  10. package/dist/ai/index.js +3 -2
  11. package/dist/ai/providers/rtzr/api.js +25 -25
  12. package/dist/ai/providers/rtzr/error.js +25 -26
  13. package/dist/ai/providers/rtzr/index.js +5 -5
  14. package/dist/ai/providers/rtzr/model.d.ts +1 -1
  15. package/dist/ai/providers/rtzr/model.d.ts.map +1 -1
  16. package/dist/ai/providers/rtzr/model.js +117 -133
  17. package/dist/ai/providers/rtzr/options.d.ts.map +1 -1
  18. package/dist/ai/providers/rtzr/options.js +35 -41
  19. package/dist/ai/providers/rtzr/provider.d.ts +1 -1
  20. package/dist/ai/providers/rtzr/provider.d.ts.map +1 -1
  21. package/dist/ai/providers/rtzr/provider.js +53 -51
  22. package/dist/ai/providers/rtzr/utils.d.ts.map +1 -1
  23. package/dist/ai/providers/rtzr/utils.js +84 -84
  24. package/dist/api/base-frame.d.ts +2 -2
  25. package/dist/api/base-frame.d.ts.map +1 -1
  26. package/dist/api/base-frame.js +29 -19
  27. package/dist/api/caster.d.ts +1 -1
  28. package/dist/api/caster.d.ts.map +1 -1
  29. package/dist/api/caster.js +51 -61
  30. package/dist/api/code-converters.d.ts +4 -3
  31. package/dist/api/code-converters.d.ts.map +1 -1
  32. package/dist/api/code-converters.js +226 -249
  33. package/dist/api/config.d.ts +17 -17
  34. package/dist/api/config.d.ts.map +1 -1
  35. package/dist/api/config.js +37 -30
  36. package/dist/api/context.d.ts +10 -10
  37. package/dist/api/context.d.ts.map +1 -1
  38. package/dist/api/context.js +8 -2
  39. package/dist/api/decorators.d.ts +8 -8
  40. package/dist/api/decorators.d.ts.map +1 -1
  41. package/dist/api/decorators.js +245 -268
  42. package/dist/api/index.js +39 -7
  43. package/dist/api/secret.js +22 -15
  44. package/dist/api/sonamu.d.ts +15 -15
  45. package/dist/api/sonamu.d.ts.map +1 -1
  46. package/dist/api/sonamu.js +1012 -1131
  47. package/dist/api/validator.js +88 -79
  48. package/dist/auth/auth-generator.d.ts.map +1 -1
  49. package/dist/auth/auth-generator.js +203 -200
  50. package/dist/auth/better-auth-entities.d.ts +2 -2
  51. package/dist/auth/better-auth-entities.d.ts.map +1 -1
  52. package/dist/auth/better-auth-entities.js +369 -429
  53. package/dist/auth/index.js +21 -6
  54. package/dist/auth/knex-adapter.d.ts +2 -2
  55. package/dist/auth/knex-adapter.d.ts.map +1 -1
  56. package/dist/auth/knex-adapter.js +153 -157
  57. package/dist/auth/plugins/entity-definitions/admin.d.ts +1 -1
  58. package/dist/auth/plugins/entity-definitions/admin.d.ts.map +1 -1
  59. package/dist/auth/plugins/entity-definitions/admin.js +58 -56
  60. package/dist/auth/plugins/entity-definitions/anonymous.d.ts +1 -1
  61. package/dist/auth/plugins/entity-definitions/anonymous.d.ts.map +1 -1
  62. package/dist/auth/plugins/entity-definitions/anonymous.js +20 -20
  63. package/dist/auth/plugins/entity-definitions/api-key.d.ts +1 -1
  64. package/dist/auth/plugins/entity-definitions/api-key.d.ts.map +1 -1
  65. package/dist/auth/plugins/entity-definitions/api-key.js +185 -196
  66. package/dist/auth/plugins/entity-definitions/index.d.ts +1 -1
  67. package/dist/auth/plugins/entity-definitions/index.d.ts.map +1 -1
  68. package/dist/auth/plugins/entity-definitions/index.js +26 -29
  69. package/dist/auth/plugins/entity-definitions/jwt.d.ts +1 -1
  70. package/dist/auth/plugins/entity-definitions/jwt.d.ts.map +1 -1
  71. package/dist/auth/plugins/entity-definitions/jwt.js +62 -64
  72. package/dist/auth/plugins/entity-definitions/organization.d.ts +1 -1
  73. package/dist/auth/plugins/entity-definitions/organization.d.ts.map +1 -1
  74. package/dist/auth/plugins/entity-definitions/organization.js +362 -421
  75. package/dist/auth/plugins/entity-definitions/passkey.d.ts +1 -1
  76. package/dist/auth/plugins/entity-definitions/passkey.d.ts.map +1 -1
  77. package/dist/auth/plugins/entity-definitions/passkey.js +115 -126
  78. package/dist/auth/plugins/entity-definitions/phone-number.d.ts +1 -1
  79. package/dist/auth/plugins/entity-definitions/phone-number.d.ts.map +1 -1
  80. package/dist/auth/plugins/entity-definitions/phone-number.js +31 -40
  81. package/dist/auth/plugins/entity-definitions/sso.d.ts +1 -1
  82. package/dist/auth/plugins/entity-definitions/sso.d.ts.map +1 -1
  83. package/dist/auth/plugins/entity-definitions/sso.js +94 -107
  84. package/dist/auth/plugins/entity-definitions/two-factor.d.ts +1 -1
  85. package/dist/auth/plugins/entity-definitions/two-factor.d.ts.map +1 -1
  86. package/dist/auth/plugins/entity-definitions/two-factor.js +78 -92
  87. package/dist/auth/plugins/entity-definitions/types.d.ts +1 -1
  88. package/dist/auth/plugins/entity-definitions/types.d.ts.map +1 -1
  89. package/dist/auth/plugins/entity-definitions/types.js +1 -10
  90. package/dist/auth/plugins/entity-definitions/username.d.ts +1 -1
  91. package/dist/auth/plugins/entity-definitions/username.d.ts.map +1 -1
  92. package/dist/auth/plugins/entity-definitions/username.js +31 -40
  93. package/dist/auth/plugins/index.js +12 -3
  94. package/dist/auth/plugins/wrappers/admin.d.ts +2 -2
  95. package/dist/auth/plugins/wrappers/admin.d.ts.map +1 -1
  96. package/dist/auth/plugins/wrappers/admin.js +28 -29
  97. package/dist/auth/plugins/wrappers/anonymous.d.ts +2 -1
  98. package/dist/auth/plugins/wrappers/anonymous.d.ts.map +1 -1
  99. package/dist/auth/plugins/wrappers/anonymous.js +23 -22
  100. package/dist/auth/plugins/wrappers/api-key.d.ts +2 -1
  101. package/dist/auth/plugins/wrappers/api-key.d.ts.map +1 -1
  102. package/dist/auth/plugins/wrappers/api-key.js +39 -34
  103. package/dist/auth/plugins/wrappers/index.js +11 -11
  104. package/dist/auth/plugins/wrappers/jwt.d.ts +2 -1
  105. package/dist/auth/plugins/wrappers/jwt.d.ts.map +1 -1
  106. package/dist/auth/plugins/wrappers/jwt.js +31 -26
  107. package/dist/auth/plugins/wrappers/organization.d.ts +2 -1
  108. package/dist/auth/plugins/wrappers/organization.d.ts.map +1 -1
  109. package/dist/auth/plugins/wrappers/organization.js +65 -62
  110. package/dist/auth/plugins/wrappers/passkey.d.ts +2 -1
  111. package/dist/auth/plugins/wrappers/passkey.d.ts.map +1 -1
  112. package/dist/auth/plugins/wrappers/passkey.js +33 -28
  113. package/dist/auth/plugins/wrappers/phone-number.d.ts.map +1 -1
  114. package/dist/auth/plugins/wrappers/phone-number.js +26 -23
  115. package/dist/auth/plugins/wrappers/sso.d.ts.map +1 -1
  116. package/dist/auth/plugins/wrappers/sso.js +37 -31
  117. package/dist/auth/plugins/wrappers/two-factor.d.ts.map +1 -1
  118. package/dist/auth/plugins/wrappers/two-factor.js +31 -28
  119. package/dist/auth/plugins/wrappers/username.d.ts.map +1 -1
  120. package/dist/auth/plugins/wrappers/username.js +23 -23
  121. package/dist/bin/build-config.js +31 -31
  122. package/dist/bin/cli.js +1063 -1204
  123. package/dist/bin/fixture.d.ts.map +1 -1
  124. package/dist/bin/fixture.js +266 -259
  125. package/dist/bin/hmr-hook-register.d.ts.map +1 -1
  126. package/dist/bin/hmr-hook-register.js +19 -18
  127. package/dist/bin/test-command.d.ts.map +1 -1
  128. package/dist/bin/test-command.js +180 -177
  129. package/dist/bin/ts-loader-register.js +13 -6
  130. package/dist/bin/ts-loader-registration.d.ts.map +1 -1
  131. package/dist/bin/ts-loader-registration.js +28 -38
  132. package/dist/cache/cache-manager.d.ts +1 -1
  133. package/dist/cache/cache-manager.d.ts.map +1 -1
  134. package/dist/cache/cache-manager.js +20 -15
  135. package/dist/cache/decorator.d.ts +1 -1
  136. package/dist/cache/decorator.d.ts.map +1 -1
  137. package/dist/cache/decorator.js +84 -76
  138. package/dist/cache/drivers.js +21 -34
  139. package/dist/cache/index.js +10 -7
  140. package/dist/cache/types.d.ts +2 -2
  141. package/dist/cache/types.d.ts.map +1 -1
  142. package/dist/cache/types.js +1 -6
  143. package/dist/cache-control/cache-control.d.ts +2 -2
  144. package/dist/cache-control/cache-control.d.ts.map +1 -1
  145. package/dist/cache-control/cache-control.js +106 -122
  146. package/dist/cache-control/types.d.ts +2 -2
  147. package/dist/cache-control/types.d.ts.map +1 -1
  148. package/dist/cache-control/types.js +1 -19
  149. package/dist/compress/compress.d.ts +1 -1
  150. package/dist/compress/compress.d.ts.map +1 -1
  151. package/dist/compress/compress.js +58 -56
  152. package/dist/compress/index.js +7 -2
  153. package/dist/compress/types.js +1 -11
  154. package/dist/cone/cone-generator.d.ts +1 -1
  155. package/dist/cone/cone-generator.d.ts.map +1 -1
  156. package/dist/cone/cone-generator.js +216 -219
  157. package/dist/database/_batch_update.d.ts +1 -1
  158. package/dist/database/_batch_update.d.ts.map +1 -1
  159. package/dist/database/_batch_update.js +107 -102
  160. package/dist/database/base-model.d.ts +8 -9
  161. package/dist/database/base-model.d.ts.map +1 -1
  162. package/dist/database/base-model.js +371 -392
  163. package/dist/database/base-model.types.d.ts +5 -5
  164. package/dist/database/base-model.types.d.ts.map +1 -1
  165. package/dist/database/base-model.types.js +1 -20
  166. package/dist/database/db.d.ts +5 -2
  167. package/dist/database/db.d.ts.map +1 -1
  168. package/dist/database/db.js +185 -171
  169. package/dist/database/knex.d.ts +1 -1
  170. package/dist/database/knex.d.ts.map +1 -1
  171. package/dist/database/knex.js +48 -42
  172. package/dist/database/puri-subset.types.d.ts +6 -7
  173. package/dist/database/puri-subset.types.d.ts.map +1 -1
  174. package/dist/database/puri-subset.types.js +1 -16
  175. package/dist/database/puri-wrapper.d.ts +6 -6
  176. package/dist/database/puri-wrapper.d.ts.map +1 -1
  177. package/dist/database/puri-wrapper.js +99 -101
  178. package/dist/database/puri.d.ts +4 -5
  179. package/dist/database/puri.d.ts.map +1 -1
  180. package/dist/database/puri.js +1021 -1227
  181. package/dist/database/puri.types.d.ts +6 -6
  182. package/dist/database/puri.types.d.ts.map +1 -1
  183. package/dist/database/puri.types.js +15 -6
  184. package/dist/database/transaction-context.d.ts +2 -2
  185. package/dist/database/transaction-context.d.ts.map +1 -1
  186. package/dist/database/transaction-context.js +22 -13
  187. package/dist/database/upsert-builder.d.ts +3 -3
  188. package/dist/database/upsert-builder.d.ts.map +1 -1
  189. package/dist/database/upsert-builder.js +405 -465
  190. package/dist/dict/en.js +72 -74
  191. package/dist/dict/index.js +13 -13
  192. package/dist/dict/ko.js +72 -74
  193. package/dist/dict/rc-keys.js +150 -168
  194. package/dist/dict/sd.d.ts +3 -1
  195. package/dist/dict/sd.d.ts.map +1 -1
  196. package/dist/dict/sd.js +54 -40
  197. package/dist/dict/sonamu-dictionary.d.ts +1 -1
  198. package/dist/dict/sonamu-dictionary.d.ts.map +1 -1
  199. package/dist/dict/sonamu-dictionary.js +887 -955
  200. package/dist/dict/types.js +1 -7
  201. package/dist/dict/utils.js +26 -24
  202. package/dist/entity/entity-manager.d.ts +9 -9
  203. package/dist/entity/entity-manager.d.ts.map +1 -1
  204. package/dist/entity/entity-manager.js +226 -223
  205. package/dist/entity/entity-template-cone.d.ts +1 -1
  206. package/dist/entity/entity-template-cone.d.ts.map +1 -1
  207. package/dist/entity/entity-template-cone.js +152 -151
  208. package/dist/entity/entity.d.ts.map +1 -1
  209. package/dist/entity/entity.js +952 -1089
  210. package/dist/exceptions/error-handler.d.ts +1 -1
  211. package/dist/exceptions/error-handler.d.ts.map +1 -1
  212. package/dist/exceptions/error-handler.js +32 -27
  213. package/dist/exceptions/so-exceptions.d.ts +1 -1
  214. package/dist/exceptions/so-exceptions.d.ts.map +1 -1
  215. package/dist/exceptions/so-exceptions.js +61 -68
  216. package/dist/filter/index.js +9 -3
  217. package/dist/filter/types.js +92 -88
  218. package/dist/filter/utils.d.ts +1 -1
  219. package/dist/filter/utils.d.ts.map +1 -1
  220. package/dist/filter/utils.js +147 -161
  221. package/dist/index.js +87 -40
  222. package/dist/logger/category.d.ts.map +1 -1
  223. package/dist/logger/category.js +30 -29
  224. package/dist/logger/configure.d.ts.map +1 -1
  225. package/dist/logger/configure.js +83 -107
  226. package/dist/migration/code-generation.d.ts +2 -2
  227. package/dist/migration/code-generation.d.ts.map +1 -1
  228. package/dist/migration/code-generation.js +1385 -1578
  229. package/dist/migration/migration-set.d.ts +1 -1
  230. package/dist/migration/migration-set.d.ts.map +1 -1
  231. package/dist/migration/migration-set.js +177 -227
  232. package/dist/migration/migrator.d.ts +4 -3
  233. package/dist/migration/migrator.d.ts.map +1 -1
  234. package/dist/migration/migrator.js +340 -345
  235. package/dist/migration/postgresql-schema-reader.d.ts +2 -2
  236. package/dist/migration/postgresql-schema-reader.d.ts.map +1 -1
  237. package/dist/migration/postgresql-schema-reader.js +506 -564
  238. package/dist/migration/slack-confirm.d.ts +2 -2
  239. package/dist/migration/slack-confirm.d.ts.map +1 -1
  240. package/dist/migration/slack-confirm.js +205 -193
  241. package/dist/migration/types.d.ts +2 -2
  242. package/dist/migration/types.d.ts.map +1 -1
  243. package/dist/migration/types.js +1 -3
  244. package/dist/naite/messaging-types.d.ts +1 -0
  245. package/dist/naite/messaging-types.d.ts.map +1 -1
  246. package/dist/naite/messaging-types.js +1 -7
  247. package/dist/naite/naite-reporter.d.ts +2 -2
  248. package/dist/naite/naite-reporter.d.ts.map +1 -1
  249. package/dist/naite/naite-reporter.js +127 -120
  250. package/dist/naite/naite.d.ts +3 -2
  251. package/dist/naite/naite.d.ts.map +1 -1
  252. package/dist/naite/naite.js +266 -300
  253. package/dist/ssr/index.d.ts +2 -2
  254. package/dist/ssr/index.d.ts.map +1 -1
  255. package/dist/ssr/index.js +13 -3
  256. package/dist/ssr/registry.d.ts +1 -1
  257. package/dist/ssr/registry.d.ts.map +1 -1
  258. package/dist/ssr/registry.js +45 -37
  259. package/dist/ssr/renderer.d.ts +4 -4
  260. package/dist/ssr/renderer.d.ts.map +1 -1
  261. package/dist/ssr/renderer.js +84 -91
  262. package/dist/ssr/types.d.ts +2 -2
  263. package/dist/ssr/types.d.ts.map +1 -1
  264. package/dist/ssr/types.js +1 -3
  265. package/dist/storage/base-file.js +54 -41
  266. package/dist/storage/buffered-file.d.ts +2 -2
  267. package/dist/storage/buffered-file.d.ts.map +1 -1
  268. package/dist/storage/buffered-file.js +51 -44
  269. package/dist/storage/drivers.d.ts +2 -2
  270. package/dist/storage/drivers.d.ts.map +1 -1
  271. package/dist/storage/drivers.js +12 -7
  272. package/dist/storage/index.js +14 -7
  273. package/dist/storage/s3-driver.d.ts +2 -2
  274. package/dist/storage/s3-driver.d.ts.map +1 -1
  275. package/dist/storage/s3-driver.js +52 -48
  276. package/dist/storage/storage-manager.d.ts +2 -2
  277. package/dist/storage/storage-manager.d.ts.map +1 -1
  278. package/dist/storage/storage-manager.js +33 -25
  279. package/dist/storage/types.d.ts +2 -2
  280. package/dist/storage/types.d.ts.map +1 -1
  281. package/dist/storage/types.js +1 -5
  282. package/dist/storage/uploaded-file.d.ts +1 -1
  283. package/dist/storage/uploaded-file.d.ts.map +1 -1
  284. package/dist/storage/uploaded-file.js +45 -35
  285. package/dist/stream/index.js +7 -2
  286. package/dist/stream/sse.d.ts +2 -2
  287. package/dist/stream/sse.d.ts.map +1 -1
  288. package/dist/stream/sse.js +72 -67
  289. package/dist/syncer/api-parser.d.ts +1 -1
  290. package/dist/syncer/api-parser.d.ts.map +1 -1
  291. package/dist/syncer/api-parser.js +224 -245
  292. package/dist/syncer/checksum.d.ts +1 -1
  293. package/dist/syncer/checksum.d.ts.map +1 -1
  294. package/dist/syncer/checksum.js +86 -72
  295. package/dist/syncer/code-generator.d.ts +2 -2
  296. package/dist/syncer/code-generator.d.ts.map +1 -1
  297. package/dist/syncer/code-generator.js +154 -160
  298. package/dist/syncer/entity-operations.d.ts +1 -1
  299. package/dist/syncer/entity-operations.d.ts.map +1 -1
  300. package/dist/syncer/entity-operations.js +63 -54
  301. package/dist/syncer/file-patterns.d.ts +1 -1
  302. package/dist/syncer/file-patterns.d.ts.map +1 -1
  303. package/dist/syncer/file-patterns.js +38 -38
  304. package/dist/syncer/index.js +19 -8
  305. package/dist/syncer/module-loader.d.ts +5 -5
  306. package/dist/syncer/module-loader.d.ts.map +1 -1
  307. package/dist/syncer/module-loader.js +83 -78
  308. package/dist/syncer/syncer-actions.d.ts +2 -2
  309. package/dist/syncer/syncer-actions.d.ts.map +1 -1
  310. package/dist/syncer/syncer-actions.js +76 -91
  311. package/dist/syncer/syncer.d.ts +7 -6
  312. package/dist/syncer/syncer.d.ts.map +1 -1
  313. package/dist/syncer/syncer.js +426 -492
  314. package/dist/tasks/decorator.d.ts +3 -3
  315. package/dist/tasks/decorator.d.ts.map +1 -1
  316. package/dist/tasks/decorator.js +32 -28
  317. package/dist/tasks/step-wrapper.d.ts +1 -1
  318. package/dist/tasks/step-wrapper.d.ts.map +1 -1
  319. package/dist/tasks/step-wrapper.js +42 -41
  320. package/dist/tasks/workflow-manager.d.ts +2 -2
  321. package/dist/tasks/workflow-manager.d.ts.map +1 -1
  322. package/dist/tasks/workflow-manager.js +192 -221
  323. package/dist/template/entity-converter.d.ts +1 -1
  324. package/dist/template/entity-converter.d.ts.map +1 -1
  325. package/dist/template/entity-converter.js +103 -103
  326. package/dist/template/helpers.d.ts.map +1 -1
  327. package/dist/template/helpers.js +163 -163
  328. package/dist/template/implementations/entity.template.d.ts +1 -1
  329. package/dist/template/implementations/entity.template.d.ts.map +1 -1
  330. package/dist/template/implementations/entity.template.js +76 -85
  331. package/dist/template/implementations/entry-server.template.d.ts +1 -1
  332. package/dist/template/implementations/entry-server.template.d.ts.map +1 -1
  333. package/dist/template/implementations/entry-server.template.js +32 -27
  334. package/dist/template/implementations/generated.template.d.ts +1 -1
  335. package/dist/template/implementations/generated.template.d.ts.map +1 -1
  336. package/dist/template/implementations/generated.template.js +254 -275
  337. package/dist/template/implementations/generated_http.template.d.ts +2 -2
  338. package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
  339. package/dist/template/implementations/generated_http.template.js +114 -133
  340. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
  341. package/dist/template/implementations/generated_sso.template.js +249 -275
  342. package/dist/template/implementations/init_types.template.d.ts +1 -1
  343. package/dist/template/implementations/init_types.template.d.ts.map +1 -1
  344. package/dist/template/implementations/init_types.template.js +40 -34
  345. package/dist/template/implementations/model.template.d.ts +1 -1
  346. package/dist/template/implementations/model.template.d.ts.map +1 -1
  347. package/dist/template/implementations/model.template.js +56 -53
  348. package/dist/template/implementations/model_test.template.d.ts +1 -1
  349. package/dist/template/implementations/model_test.template.d.ts.map +1 -1
  350. package/dist/template/implementations/model_test.template.js +32 -24
  351. package/dist/template/implementations/queries.template.d.ts +1 -1
  352. package/dist/template/implementations/queries.template.d.ts.map +1 -1
  353. package/dist/template/implementations/queries.template.js +84 -89
  354. package/dist/template/implementations/sd.template.d.ts +1 -1
  355. package/dist/template/implementations/sd.template.d.ts.map +1 -1
  356. package/dist/template/implementations/sd.template.js +137 -144
  357. package/dist/template/implementations/services.template.d.ts +1 -1
  358. package/dist/template/implementations/services.template.d.ts.map +1 -1
  359. package/dist/template/implementations/services.template.js +164 -189
  360. package/dist/template/implementations/view_form.template.d.ts +1 -1
  361. package/dist/template/implementations/view_form.template.d.ts.map +1 -1
  362. package/dist/template/implementations/view_form.template.js +258 -285
  363. package/dist/template/implementations/view_id_all_select.template.d.ts +1 -1
  364. package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -1
  365. package/dist/template/implementations/view_id_all_select.template.js +31 -25
  366. package/dist/template/implementations/view_list.template.d.ts +1 -1
  367. package/dist/template/implementations/view_list.template.d.ts.map +1 -1
  368. package/dist/template/implementations/view_list.template.js +304 -355
  369. package/dist/template/implementations/view_search_input.template.d.ts +1 -1
  370. package/dist/template/implementations/view_search_input.template.d.ts.map +1 -1
  371. package/dist/template/implementations/view_search_input.template.js +31 -27
  372. package/dist/template/index.js +21 -7
  373. package/dist/template/template-manager.d.ts +1 -1
  374. package/dist/template/template-manager.d.ts.map +1 -1
  375. package/dist/template/template-manager.js +132 -123
  376. package/dist/template/template-types.js +8 -6
  377. package/dist/template/template.d.ts +2 -2
  378. package/dist/template/template.d.ts.map +1 -1
  379. package/dist/template/template.js +73 -68
  380. package/dist/template/zod-converter.d.ts.map +1 -1
  381. package/dist/template/zod-converter.js +603 -657
  382. package/dist/testing/_relation-graph.d.ts +1 -1
  383. package/dist/testing/_relation-graph.d.ts.map +1 -1
  384. package/dist/testing/_relation-graph.js +93 -88
  385. package/dist/testing/bootstrap.d.ts +22 -13
  386. package/dist/testing/bootstrap.d.ts.map +1 -1
  387. package/dist/testing/bootstrap.js +114 -114
  388. package/dist/testing/data-explorer.d.ts +3 -3
  389. package/dist/testing/data-explorer.d.ts.map +1 -1
  390. package/dist/testing/data-explorer.js +237 -265
  391. package/dist/testing/dev-test-routes.d.ts +2 -2
  392. package/dist/testing/dev-test-routes.d.ts.map +1 -1
  393. package/dist/testing/dev-test-routes.js +258 -249
  394. package/dist/testing/dev-vitest-manager.d.ts +1 -1
  395. package/dist/testing/dev-vitest-manager.d.ts.map +1 -1
  396. package/dist/testing/dev-vitest-manager.js +514 -539
  397. package/dist/testing/faker-mappings.js +422 -420
  398. package/dist/testing/fixture-generator.d.ts +3 -3
  399. package/dist/testing/fixture-generator.d.ts.map +1 -1
  400. package/dist/testing/fixture-generator.js +1216 -1346
  401. package/dist/testing/fixture-loader.js +26 -25
  402. package/dist/testing/fixture-manager.d.ts +3 -3
  403. package/dist/testing/fixture-manager.d.ts.map +1 -1
  404. package/dist/testing/fixture-manager.js +706 -776
  405. package/dist/testing/global-setup.js +53 -49
  406. package/dist/testing/index.js +19 -11
  407. package/dist/testing/naite-vitest-reporter.js +18 -13
  408. package/dist/testing/parallel-db-manager.d.ts +1 -1
  409. package/dist/testing/parallel-db-manager.d.ts.map +1 -1
  410. package/dist/testing/parallel-db-manager.js +63 -78
  411. package/dist/testing/vitest-helpers.d.ts +1 -1
  412. package/dist/testing/vitest-helpers.d.ts.map +1 -1
  413. package/dist/testing/vitest-helpers.js +37 -33
  414. package/dist/types/types.d.ts +28 -28
  415. package/dist/types/types.d.ts.map +1 -1
  416. package/dist/types/types.js +764 -890
  417. package/dist/ui/ai-api.d.ts +1 -1
  418. package/dist/ui/ai-api.d.ts.map +1 -1
  419. package/dist/ui/ai-api.js +52 -42
  420. package/dist/ui/ai-client.d.ts +1 -2
  421. package/dist/ui/ai-client.d.ts.map +1 -1
  422. package/dist/ui/ai-client.js +353 -388
  423. package/dist/ui/api.d.ts +1 -1
  424. package/dist/ui/api.d.ts.map +1 -1
  425. package/dist/ui/api.js +903 -1145
  426. package/dist/ui/cdd-service.d.ts +1 -1
  427. package/dist/ui/cdd-service.d.ts.map +1 -1
  428. package/dist/ui/cdd-service.js +406 -407
  429. package/dist/ui/cdd-types.js +1 -3
  430. package/dist/ui-web/assets/index-C-Zz-wYg.css +1 -0
  431. package/dist/ui-web/assets/index-DejDON8K.js +238 -0
  432. package/dist/ui-web/index.html +3 -3
  433. package/dist/utils/async-utils.js +57 -45
  434. package/dist/utils/console-util.d.ts.map +1 -1
  435. package/dist/utils/console-util.js +104 -87
  436. package/dist/utils/controller.js +26 -19
  437. package/dist/utils/esm-utils.js +49 -38
  438. package/dist/utils/formatter.d.ts +1 -2
  439. package/dist/utils/formatter.d.ts.map +1 -1
  440. package/dist/utils/formatter.js +89 -115
  441. package/dist/utils/fs-utils.d.ts.map +1 -1
  442. package/dist/utils/fs-utils.js +68 -65
  443. package/dist/utils/lodash-able.js +11 -4
  444. package/dist/utils/model.d.ts +1 -1
  445. package/dist/utils/model.d.ts.map +1 -1
  446. package/dist/utils/model.js +21 -19
  447. package/dist/utils/object-utils.js +148 -186
  448. package/dist/utils/path-utils.js +67 -57
  449. package/dist/utils/process-utils.d.ts.map +1 -1
  450. package/dist/utils/process-utils.js +37 -31
  451. package/dist/utils/sql-parser.d.ts +1 -1
  452. package/dist/utils/sql-parser.d.ts.map +1 -1
  453. package/dist/utils/sql-parser.js +40 -40
  454. package/dist/utils/type-utils.js +44 -43
  455. package/dist/utils/utils.d.ts +2 -3
  456. package/dist/utils/utils.d.ts.map +1 -1
  457. package/dist/utils/utils.js +81 -93
  458. package/dist/utils/zod-error.d.ts +1 -1
  459. package/dist/utils/zod-error.d.ts.map +1 -1
  460. package/dist/utils/zod-error.js +24 -17
  461. package/dist/vector/chunking.d.ts +1 -1
  462. package/dist/vector/chunking.d.ts.map +1 -1
  463. package/dist/vector/chunking.js +100 -94
  464. package/dist/vector/config.d.ts +1 -1
  465. package/dist/vector/config.d.ts.map +1 -1
  466. package/dist/vector/config.js +76 -78
  467. package/dist/vector/embedding.d.ts +1 -1
  468. package/dist/vector/embedding.d.ts.map +1 -1
  469. package/dist/vector/embedding.js +128 -125
  470. package/dist/vector/index.js +5 -5
  471. package/dist/vector/types.js +1 -5
  472. package/package.json +31 -36
  473. package/src/ai/agents/agent.ts +12 -5
  474. package/src/ai/agents/types.ts +5 -5
  475. package/src/ai/providers/rtzr/model.ts +8 -10
  476. package/src/ai/providers/rtzr/options.ts +2 -1
  477. package/src/ai/providers/rtzr/provider.ts +5 -3
  478. package/src/ai/providers/rtzr/utils.ts +2 -7
  479. package/src/api/__tests__/config.test.ts +15 -8
  480. package/src/api/base-frame.ts +5 -3
  481. package/src/api/caster.ts +7 -6
  482. package/src/api/code-converters.ts +23 -26
  483. package/src/api/config.ts +23 -17
  484. package/src/api/context.ts +18 -11
  485. package/src/api/decorators.ts +17 -18
  486. package/src/api/sonamu.ts +44 -49
  487. package/src/auth/auth-generator.ts +4 -6
  488. package/src/auth/better-auth-entities.ts +3 -2
  489. package/src/auth/knex-adapter.ts +6 -5
  490. package/src/auth/plugins/entity-definitions/admin.ts +1 -1
  491. package/src/auth/plugins/entity-definitions/anonymous.ts +1 -1
  492. package/src/auth/plugins/entity-definitions/api-key.ts +1 -1
  493. package/src/auth/plugins/entity-definitions/index.ts +1 -1
  494. package/src/auth/plugins/entity-definitions/jwt.ts +1 -1
  495. package/src/auth/plugins/entity-definitions/organization.ts +1 -1
  496. package/src/auth/plugins/entity-definitions/passkey.ts +1 -1
  497. package/src/auth/plugins/entity-definitions/phone-number.ts +1 -1
  498. package/src/auth/plugins/entity-definitions/sso.ts +1 -1
  499. package/src/auth/plugins/entity-definitions/two-factor.ts +1 -1
  500. package/src/auth/plugins/entity-definitions/types.ts +1 -1
  501. package/src/auth/plugins/entity-definitions/username.ts +1 -1
  502. package/src/auth/plugins/wrappers/admin.ts +3 -1
  503. package/src/auth/plugins/wrappers/anonymous.ts +3 -1
  504. package/src/auth/plugins/wrappers/api-key.ts +3 -1
  505. package/src/auth/plugins/wrappers/jwt.ts +3 -1
  506. package/src/auth/plugins/wrappers/organization.ts +3 -1
  507. package/src/auth/plugins/wrappers/passkey.ts +3 -1
  508. package/src/auth/plugins/wrappers/phone-number.ts +3 -1
  509. package/src/auth/plugins/wrappers/sso.ts +2 -1
  510. package/src/auth/plugins/wrappers/two-factor.ts +3 -1
  511. package/src/auth/plugins/wrappers/username.ts +3 -1
  512. package/src/bin/__tests__/ts-loader-register.test.ts +7 -12
  513. package/src/bin/build-config.ts +3 -3
  514. package/src/bin/cli.ts +27 -25
  515. package/src/bin/fixture.ts +4 -2
  516. package/src/bin/hmr-hook-register.ts +1 -0
  517. package/src/bin/test-command.ts +4 -2
  518. package/src/bin/ts-loader-registration.ts +6 -22
  519. package/src/cache/cache-manager.ts +2 -1
  520. package/src/cache/decorator.ts +2 -2
  521. package/src/cache/types.ts +3 -3
  522. package/src/cache-control/cache-control.ts +3 -2
  523. package/src/cache-control/types.ts +2 -2
  524. package/src/compress/compress.ts +1 -1
  525. package/src/cone/cone-generator.ts +5 -3
  526. package/src/database/_batch_update.ts +1 -1
  527. package/src/database/base-model.ts +20 -14
  528. package/src/database/base-model.types.ts +12 -11
  529. package/src/database/db.ts +56 -21
  530. package/src/database/knex.ts +2 -2
  531. package/src/database/puri-subset.test-d.ts +33 -32
  532. package/src/database/puri-subset.types.ts +6 -7
  533. package/src/database/puri-wrapper.ts +29 -26
  534. package/src/database/puri.ts +36 -34
  535. package/src/database/puri.types.test-d.ts +6 -5
  536. package/src/database/puri.types.ts +9 -12
  537. package/src/database/transaction-context.ts +2 -2
  538. package/src/database/upsert-builder.ts +17 -10
  539. package/src/dict/sd.ts +17 -4
  540. package/src/dict/sonamu-dictionary.ts +23 -17
  541. package/src/entity/entity-manager.ts +9 -7
  542. package/src/entity/entity-template-cone.ts +10 -3
  543. package/src/entity/entity.ts +20 -16
  544. package/src/exceptions/error-handler.ts +2 -1
  545. package/src/exceptions/so-exceptions.ts +1 -1
  546. package/src/filter/utils.ts +3 -2
  547. package/src/logger/category.ts +1 -0
  548. package/src/logger/configure.ts +5 -5
  549. package/src/migration/__tests__/code-generation.search-text.test.ts +2 -3
  550. package/src/migration/code-generation.ts +26 -25
  551. package/src/migration/migration-set.ts +16 -18
  552. package/src/migration/migrator.ts +38 -33
  553. package/src/migration/postgresql-schema-reader.ts +12 -12
  554. package/src/migration/slack-confirm.ts +5 -4
  555. package/src/migration/types.ts +2 -2
  556. package/src/naite/messaging-types.ts +1 -1
  557. package/src/naite/naite-reporter.ts +5 -3
  558. package/src/naite/naite.ts +12 -7
  559. package/src/shared/app.shared.ts.txt +2 -2
  560. package/src/shared/web.shared.ts.txt +2 -2
  561. package/src/skills/AGENTS.md +19 -18
  562. package/src/skills/commands/sonamu-skills.md +9 -9
  563. package/src/skills/sonamu/SKILL.md +111 -104
  564. package/src/skills/sonamu/ai-agents.md +27 -26
  565. package/src/skills/sonamu/api.md +81 -69
  566. package/src/skills/sonamu/auth-migration.md +13 -27
  567. package/src/skills/sonamu/auth-plugins.md +41 -31
  568. package/src/skills/sonamu/auth.md +30 -24
  569. package/src/skills/sonamu/cdd.md +26 -17
  570. package/src/skills/sonamu/cone.md +50 -50
  571. package/src/skills/sonamu/config.md +74 -51
  572. package/src/skills/sonamu/create-sonamu.md +31 -19
  573. package/src/skills/sonamu/database.md +43 -26
  574. package/src/skills/sonamu/entity-basic.md +61 -61
  575. package/src/skills/sonamu/entity-relations.md +84 -80
  576. package/src/skills/sonamu/entity-validation-checklist.md +19 -15
  577. package/src/skills/sonamu/fixture-cli.md +52 -30
  578. package/src/skills/sonamu/framework-change.md +9 -7
  579. package/src/skills/sonamu/frontend.md +64 -82
  580. package/src/skills/sonamu/i18n.md +45 -37
  581. package/src/skills/sonamu/migration.md +54 -31
  582. package/src/skills/sonamu/model.md +98 -66
  583. package/src/skills/sonamu/naite.md +34 -32
  584. package/src/skills/sonamu/project-init.md +28 -8
  585. package/src/skills/sonamu/puri.md +82 -91
  586. package/src/skills/sonamu/scaffolding.md +44 -32
  587. package/src/skills/sonamu/skill-contribution.md +50 -45
  588. package/src/skills/sonamu/subset.md +13 -13
  589. package/src/skills/sonamu/tasks.md +73 -58
  590. package/src/skills/sonamu/testing-devrunner.md +56 -36
  591. package/src/skills/sonamu/testing.md +23 -58
  592. package/src/skills/sonamu/upsert.md +32 -31
  593. package/src/skills/sonamu/vector.md +37 -36
  594. package/src/ssr/index.ts +2 -12
  595. package/src/ssr/registry.ts +1 -1
  596. package/src/ssr/renderer.ts +7 -5
  597. package/src/ssr/types.ts +2 -2
  598. package/src/storage/buffered-file.ts +4 -2
  599. package/src/storage/drivers.ts +3 -2
  600. package/src/storage/s3-driver.ts +7 -4
  601. package/src/storage/storage-manager.ts +3 -2
  602. package/src/storage/types.ts +3 -2
  603. package/src/storage/uploaded-file.ts +1 -1
  604. package/src/stream/sse.ts +2 -2
  605. package/src/syncer/api-parser.ts +8 -5
  606. package/src/syncer/checksum.ts +9 -5
  607. package/src/syncer/code-generator.ts +16 -8
  608. package/src/syncer/entity-operations.ts +5 -3
  609. package/src/syncer/file-patterns.ts +2 -1
  610. package/src/syncer/module-loader.ts +9 -6
  611. package/src/syncer/syncer-actions.ts +5 -3
  612. package/src/syncer/syncer.ts +18 -24
  613. package/src/tasks/decorator.ts +10 -8
  614. package/src/tasks/step-wrapper.ts +1 -1
  615. package/src/tasks/workflow-manager.ts +18 -15
  616. package/src/template/__tests__/generated.template.search-text.test.ts +1 -0
  617. package/src/template/entity-converter.ts +4 -2
  618. package/src/template/generated.template.test-d.ts +2 -1
  619. package/src/template/helpers.ts +5 -2
  620. package/src/template/implementations/entity.template.ts +9 -8
  621. package/src/template/implementations/entry-server.template.ts +1 -1
  622. package/src/template/implementations/generated.template.ts +21 -29
  623. package/src/template/implementations/generated_http.template.ts +9 -6
  624. package/src/template/implementations/generated_sso.template.ts +6 -4
  625. package/src/template/implementations/init_types.template.ts +3 -2
  626. package/src/template/implementations/model.template.ts +4 -2
  627. package/src/template/implementations/model_test.template.ts +3 -2
  628. package/src/template/implementations/queries.template.ts +6 -14
  629. package/src/template/implementations/sd.template.ts +4 -2
  630. package/src/template/implementations/services.template.ts +7 -11
  631. package/src/template/implementations/view_form.template.ts +5 -3
  632. package/src/template/implementations/view_id_all_select.template.ts +3 -2
  633. package/src/template/implementations/view_list.template.ts +7 -5
  634. package/src/template/implementations/view_search_input.template.ts +3 -2
  635. package/src/template/template-manager.ts +4 -3
  636. package/src/template/template.ts +4 -3
  637. package/src/template/zod-converter.ts +10 -7
  638. package/src/testing/__tests__/dev-test-routes.test.ts +3 -2
  639. package/src/testing/__tests__/dev-vitest-manager.test.ts +1 -0
  640. package/src/testing/_relation-graph.ts +2 -2
  641. package/src/testing/bootstrap.ts +55 -27
  642. package/src/testing/data-explorer.ts +5 -4
  643. package/src/testing/dev-test-routes.ts +8 -5
  644. package/src/testing/dev-vitest-manager.ts +13 -12
  645. package/src/testing/fixture-generator.ts +11 -17
  646. package/src/testing/fixture-manager.ts +21 -17
  647. package/src/testing/parallel-db-manager.ts +2 -1
  648. package/src/testing/vitest-helpers.ts +2 -1
  649. package/src/types/__tests__/entity-json-schema-search-text.test.ts +1 -0
  650. package/src/types/types.ts +8 -8
  651. package/src/typings/knex.d.ts +4 -4
  652. package/src/ui/ai-api.ts +5 -3
  653. package/src/ui/ai-client.ts +6 -5
  654. package/src/ui/api.ts +25 -23
  655. package/src/ui/cdd-service.ts +12 -11
  656. package/src/utils/console-util.ts +3 -1
  657. package/src/utils/formatter.ts +94 -102
  658. package/src/utils/fs-utils.ts +2 -1
  659. package/src/utils/model.ts +2 -2
  660. package/src/utils/object-utils.ts +3 -3
  661. package/src/utils/process-utils.ts +2 -1
  662. package/src/utils/sql-parser.ts +10 -1
  663. package/src/utils/type-utils.ts +3 -3
  664. package/src/utils/utils.ts +9 -7
  665. package/src/utils/zod-error.ts +1 -1
  666. package/src/vector/chunking.ts +1 -1
  667. package/src/vector/config.ts +1 -1
  668. package/src/vector/embedding.ts +11 -9
  669. package/tsdown.api.config.ts +50 -0
  670. package/.swcrc.project-default +0 -18
  671. package/dist/api/__tests__/config.test.js +0 -189
  672. package/dist/bin/__tests__/test-command.test.js +0 -112
  673. package/dist/bin/__tests__/ts-loader-register.test.js +0 -45
  674. package/dist/database/puri-subset.test-d.js +0 -89
  675. package/dist/database/puri.types.test-d.js +0 -129
  676. package/dist/migration/__tests__/code-generation.search-text.test.js +0 -435
  677. package/dist/template/__tests__/generated.template.search-text.test.js +0 -99
  678. package/dist/template/generated.template.test-d.js +0 -24
  679. package/dist/testing/__tests__/dev-test-routes.test.js +0 -144
  680. package/dist/testing/__tests__/dev-vitest-manager.test.js +0 -152
  681. package/dist/types/__tests__/entity-json-schema-search-text.test.js +0 -256
  682. package/dist/typings/knex.d.js +0 -3
  683. package/dist/ui-web/assets/index-CKo0Z2Iu.css +0 -1
  684. package/dist/ui-web/assets/index-DK-2aacv.js +0 -257
@@ -1,1092 +1,955 @@
1
- import assert from "assert";
2
- import { writeFile } from "node:fs/promises";
1
+ import { __esmMin } from "../_virtual/rolldown_runtime.js";
2
+ import { exists, init_fs_utils } from "../utils/fs-utils.js";
3
+ import { assertDefined, init_utils, nonNullable } from "../utils/utils.js";
4
+ import { Sonamu, init_sonamu } from "../api/sonamu.js";
5
+ import { getEnumDefValues, getSubsetFields, init_types, isBelongsToOneRelationProp, isEnumProp, isHasManyRelationProp, isInternalSubsetField, isManyToManyRelationProp, isOneToOneRelationProp, isRelationProp, isVirtualCodeProp, isVirtualProp, normalizeSubsetField } from "../types/types.js";
6
+ import { importMembers, init_esm_utils } from "../utils/esm-utils.js";
7
+ import { init_path_utils, runtimePath } from "../utils/path-utils.js";
8
+ import { EntityManager, init_entity_manager } from "./entity-manager.js";
9
+ import { formatCode, init_formatter } from "../utils/formatter.js";
3
10
  import inflection from "inflection";
4
- import path from "path";
11
+ import { z as z$1 } from "zod";
5
12
  import { group, unique } from "radashi";
6
- import { z } from "zod";
7
- import { Sonamu } from "../api/sonamu.js";
8
- import { getEnumDefValues, getSubsetFields, isBelongsToOneRelationProp, isEnumProp, isHasManyRelationProp, isInternalSubsetField, isManyToManyRelationProp, isOneToOneRelationProp, isRelationProp, isVirtualCodeProp, isVirtualProp, normalizeSubsetField } from "../types/types.js";
9
- import { importMembers } from "../utils/esm-utils.js";
10
- import { formatCode } from "../utils/formatter.js";
11
- import { exists } from "../utils/fs-utils.js";
12
- import { runtimePath } from "../utils/path-utils.js";
13
- import { assertDefined, nonNullable } from "../utils/utils.js";
14
- import { EntityManager } from "./entity-manager.js";
15
- export class Entity {
16
- id;
17
- parentId;
18
- table;
19
- title;
20
- cone;
21
- names;
22
- props;
23
- propsDict;
24
- relations;
25
- indexes;
26
- subsets;
27
- subsetsInternal;
28
- types = {};
29
- enums = {};
30
- enumLabels = {};
31
- enumCones = {};
32
- subsetCones = {};
33
- constructor({ id, parentId, table, title, cone, props, indexes, subsets, enums }){
34
- // id
35
- this.id = id;
36
- this.parentId = parentId;
37
- this.title = title ?? this.id;
38
- this.table = table ?? inflection.underscore(inflection.pluralize(id));
39
- this.cone = cone;
40
- // props
41
- if (props) {
42
- this.props = props.map((prop)=>{
43
- if (isEnumProp(prop)) {
44
- if (prop.id.includes("$Model")) {
45
- prop.id = prop.id.replace("$Model", id);
46
- }
47
- }
48
- return prop;
49
- });
50
- this.propsDict = Object.fromEntries(props.map((prop)=>{
51
- return [
52
- prop.name,
53
- prop
54
- ];
55
- }));
56
- // relations
57
- this.relations = Object.fromEntries(props.filter((prop)=>isRelationProp(prop)).map((prop)=>[
58
- prop.name,
59
- prop
60
- ]));
61
- } else {
62
- this.props = [];
63
- this.propsDict = {};
64
- this.relations = {};
65
- }
66
- // indexes
67
- this.indexes = indexes ?? [];
68
- // subsets: SubsetDef에서 SubsetField[] 추출하여 subsets(일반) subsetsInternal(internal)로 분리
69
- this.subsets = {};
70
- this.subsetsInternal = {};
71
- for (const [key, subsetDef] of Object.entries(subsets ?? {})){
72
- const fields = getSubsetFields(subsetDef);
73
- this.subsets[key] = fields.filter((f)=>!isInternalSubsetField(f)).map(normalizeSubsetField);
74
- this.subsetsInternal[key] = fields.filter(isInternalSubsetField).map(normalizeSubsetField);
75
- // cone 추출
76
- if (!Array.isArray(subsetDef) && "cone" in subsetDef && subsetDef.cone) {
77
- this.subsetCones[key] = subsetDef.cone;
78
- }
79
- }
80
- // enums: EnumDef에서 values와 cone를 추출하여 처리
81
- this.enumLabels = Object.fromEntries(Object.entries(enums ?? {}).map(([key, enumDef])=>{
82
- // cone 추출
83
- if ("values" in enumDef && "cone" in enumDef && enumDef.cone) {
84
- this.enumCones[key] = enumDef.cone;
85
- }
86
- return [
87
- key,
88
- getEnumDefValues(enumDef)
89
- ];
90
- }));
91
- this.enums = Object.fromEntries(Object.entries(this.enumLabels).map(([key, enumLabel])=>{
92
- return [
93
- key,
94
- z.enum(Object.keys(enumLabel))
95
- ];
96
- }));
97
- // names
98
- this.names = {
99
- parentFs: inflection.dasherize(inflection.underscore(parentId ?? id)).toLowerCase(),
100
- fs: inflection.dasherize(inflection.underscore(id)).toLowerCase(),
101
- module: id
102
- };
103
- }
104
- /**
105
- * 쿼리용 서브셋 필드를 반환합니다 (subsets + subsetsInternal 합침)
106
- */ getSubsetFieldsForQuery(subsetKey) {
107
- return [
108
- ...this.subsets[subsetKey] ?? [],
109
- ...this.subsetsInternal[subsetKey] ?? []
110
- ];
111
- }
112
- /**
113
- * 주어진 이름(subsetKey)의 subset을 실제로 가져오는 Puri 코드 구현체 string을 반환합니다.
114
- */ getPuriSubsetQuery(subsetKey) {
115
- const subset = this.getSubsetFieldsForQuery(subsetKey);
116
- const subsetQuery = this.resolveSubsetQuery("", subset);
117
- const lines = [];
118
- // from
119
- lines.push(`return qbWrapper`);
120
- lines.push(`.from("${this.table}")`);
121
- // join
122
- for (const join of subsetQuery.joins){
123
- // join 메서드 결정: inner join, outer → leftJoin
124
- // FK nullable 여부는 leftJoin 타입 시그니처에서 자동으로 판단됨
125
- const joinMethod = join.join === "inner" ? "join" : "leftJoin";
126
- if ("custom" in join) {
127
- // custom join clause는 raw 사용
128
- lines.push(`.${joinMethod}({ ${join.as}: "${join.table}" }, qbWrapper.knex.raw(\`${join.custom}\`))`);
129
- } else {
130
- lines.push(`.${joinMethod}({ ${join.as}: "${join.table}" }, "${join.from}", "${join.to}")`);
131
- }
132
- }
133
- // select - 입체적 구조로 생성
134
- const selectObj = this.buildNestedSelectObject(subsetQuery.select);
135
- lines.push(`.select(${this.stringifyNestedSelectObject(selectObj)});`);
136
- return lines.join("\n");
137
- }
138
- /**
139
- * *.entity.json의 subset에 들어있는 필드 배열을 받아서,
140
- * Puri의 SelectObject 타입으로 변환합니다.
141
- *
142
- * 예: ["users.id", "parent.id", "parent.name"]
143
- * → { id: "users.id", parent: { id: "parent.id", name: "parent.name" } }
144
- *
145
- * 언더바가 아닌 중첩 객체로 변환함에 유의하세요.
146
- * 이렇게 중첩 객체로 변환하여 select에 넘겨주면 ParseSelectObject 타입이 join된 객체의 타입을 잘 잡아줄 수 있습니다.
147
- * 즉, enhancer에서 row를 받았을 때 hydrate된 객체 자체의 nullity와 그 안쪽 필드의 nullity가 fk nullable 여부에 따라 잘 추론됩니다.
148
- */ buildNestedSelectObject(selectItems) {
149
- const result = {};
150
- for (const selectItem of selectItems){
151
- // "users.id" 또는 "users.id as user__id" 형태 파싱
152
- const match = selectItem.match(/^(.+?)(?: as (.+))?$/);
153
- if (!match) continue;
154
- const [, column, alias] = match;
155
- const columnValue = `"${column.trim()}"`;
156
- if (!alias || !alias.includes("__")) {
157
- // alias가 없거나 __를 포함하지 않으면 최상위 필드
158
- const key = alias ?? assertDefined(column.split(".").pop());
159
- result[key] = columnValue;
160
- } else {
161
- // alias가 __를 포함하면 입체 구조로 그룹화
162
- const parts = alias.split("__");
163
- let current = result;
164
- // 마지막 파트 전까지 중첩 객체 생성
165
- for(let i = 0; i < parts.length - 1; i++){
166
- const part = parts[i];
167
- if (part in current) {
168
- if (typeof current[part] === "string") {
169
- // 입력이 ["user", "user__id"] 같은 경우!
170
- // 애초에 말도 안 되지만 안전하게 예외를 던집니다.
171
- throw new Error(`Conflict detected in select items: parent path "${parts.slice(0, i + 1).join("__")}" is already set as a field, cannot nest "${alias}" under it.`);
172
- }
173
- } else {
174
- current[part] = {};
175
- }
176
- current = current[part];
177
- }
178
- // 마지막 파트에 값 설정
179
- const lastPart = parts[parts.length - 1];
180
- current[lastPart] = columnValue;
181
- }
182
- }
183
- return result;
184
- }
185
- /**
186
- * JSON.stringify와 유사한 일을 합니다.
187
- * 다만 주어진 객체를 JSON이 아닌 TypeScript 객체 리터럴 스트링으로 만들어줍니다.
188
- * key에 따옴표가 없어요.
189
- * 출력 예시:
190
- * ```typescript
191
- * {
192
- * id: "users.id",
193
- * parent: {
194
- * id: "parent.id",
195
- * name: "parent.name",
196
- * },
197
- * }
198
- * ```
199
- * @param obj 변환할 객체
200
- * @param indent 들여쓰기 레벨
201
- * @param withBraces true면 중괄호 포함, false면 내용만 반환
202
- */ stringifyNestedSelectObject(// biome-ignore lint/suspicious/noExplicitAny: 중첩 오브젝트의 값은 string일 수도 있고 또다른 오브젝트일 수도 있는데, 이를 재귀 타입으로 나타낼 수 없어 any로 처리합니다.
203
- obj, indent = 0, withBraces = true) {
204
- const spaces = " ".repeat(indent);
205
- const innerSpaces = " ".repeat(indent + 1);
206
- const entries = Object.entries(obj);
207
- if (entries.length === 0) return withBraces ? "{}" : "";
208
- const lines = entries.map(([key, value])=>{
209
- if (typeof value === "string") {
210
- // 컬럼 경로 (이미 따옴표 포함)
211
- return `${innerSpaces}${key}: ${value},`;
212
- } else {
213
- // 중첩 객체 (항상 중괄호 포함)
214
- return `${innerSpaces}${key}: ${this.stringifyNestedSelectObject(value, indent + 1, true)},`;
215
- }
216
- });
217
- if (withBraces) {
218
- return `{\n${lines.join("\n")}\n${spaces}}`;
219
- } else {
220
- // 중괄호 없이 내용만 반환 (앞뒤 개행 제외)
221
- return lines.join("\n");
222
- }
223
- }
224
- getPuriLoaderQuery(subsetKey) {
225
- const subset = this.getSubsetFieldsForQuery(subsetKey);
226
- const { loaders } = this.resolveSubsetQuery("", subset);
227
- const lines = [
228
- `[`
229
- ];
230
- // 재귀적으로 loader 생성하는 헬퍼 함수
231
- const generateLoaderCode = (loaders)=>{
232
- const loaderLines = [];
233
- for (const loader of loaders){
234
- const { toTable, toCol, through, fromTable } = loader.manyJoin;
235
- // fromTable의 Entity를 가져와서 PK 타입 확인
236
- const fromEntity = EntityManager.getByTable(fromTable);
237
- const fromIdsType = fromEntity.getPkArrayType();
238
- loaderLines.push("{", `as: "${loader.as}",`, `refId: "${loader.manyJoin.idField}",`, `qb: (qbWrapper: PuriWrapper<DatabaseSchemaExtend>, fromIds: number[] | string[]) => {`);
239
- if (through === undefined) {
240
- // HasMany
241
- loaderLines.push(//
242
- "return qbWrapper", `.from("${toTable}")`);
243
- loader.oneJoins.forEach((join)=>{
244
- // FK nullable 여부는 leftJoin 타입 시그니처에서 자동으로 판단됨
245
- const joinMethod = join.join === "inner" ? "join" : "leftJoin";
246
- if ("custom" in join) {
247
- // custom join clause는 callback 형태의 on 메서드로 처리합니다.
248
- loaderLines.push(`.${joinMethod}({ ${join.as}: "${join.table}" }, (j) => {`, `j.on(Puri.rawString("${join.custom}"));`, "})");
249
- } else {
250
- loaderLines.push(`.${joinMethod}({ ${join.as}: "${join.table}" }, "${join.from}", "${join.to}")`);
251
- }
252
- });
253
- // 입체적 select 구조 생성 (refId 포함)
254
- const selectObj = this.buildNestedSelectObject(loader.select);
255
- selectObj.refId = `"${toTable}.${toCol}"`;
256
- loaderLines.push(`.whereIn("${toTable}.${toCol}", fromIds as ${fromIdsType})`, `.select(${this.stringifyNestedSelectObject(selectObj)});`);
257
- } else {
258
- // ManyToMany
259
- loaderLines.push("return qbWrapper", `.from("${through.table}")`, `.join("${toTable}", "${through.table}.${through.toCol}", "${toTable}.${toCol}")`);
260
- loader.oneJoins.forEach((join)=>{
261
- // FK nullable 여부는 leftJoin 타입 시그니처에서 자동으로 판단됨
262
- const joinMethod = join.join === "inner" ? "join" : "leftJoin";
263
- if ("custom" in join) {
264
- // custom join clause는 callback 형태의 on 메서드로 처리합니다.
265
- loaderLines.push(`.${joinMethod}({ ${join.as}: "${join.table}" }, (j) => {`, `j.on(Puri.rawString("${join.custom}"));`, "})");
266
- } else {
267
- loaderLines.push(`.${joinMethod}({ ${join.as}: "${join.table}" }, "${join.from}", "${join.to}")`);
268
- }
269
- });
270
- // 입체적 select 구조 생성 (refId 포함)
271
- const selectObj = this.buildNestedSelectObject(loader.select);
272
- selectObj.refId = `"${through.table}.${through.fromCol}"`;
273
- loaderLines.push(`.whereIn("${through.table}.${through.fromCol}", fromIds as ${fromIdsType})`, `.select(${this.stringifyNestedSelectObject(selectObj)});`);
274
- }
275
- loaderLines.push(`},`);
276
- // 중첩 loaders 처리
277
- if (loader.loaders && loader.loaders.length > 0) {
278
- loaderLines.push("loaders: [", ...generateLoaderCode(loader.loaders), "],");
279
- }
280
- loaderLines.push("},");
281
- }
282
- return loaderLines;
283
- };
284
- lines.push(...generateLoaderCode(loaders));
285
- lines.push(`]`);
286
- return lines.join("\n");
287
- }
288
- /*
289
- subset SELECT/JOIN/LOADER 결과 리턴
290
- */ getSubsetQuery(subsetKey) {
291
- const subset = this.getSubsetFieldsForQuery(subsetKey);
292
- const result = this.resolveSubsetQuery("", subset);
293
- return result;
294
- }
295
- /*
296
- */ resolveSubsetQuery(prefix, fields, isAlreadyOuterJoined = false) {
297
- // prefix 치환 (prefix는 ToOneRelation이 복수로 붙은 경우 모두 __로 변경됨)
298
- prefix = prefix.replace(/\./g, "__");
299
- // 서브셋을 1뎁스만 분리하여 그룹핑
300
- const subsetGroup = group(fields, (field)=>{
301
- if (field.includes(".")) {
302
- const [rel] = field.split(".");
303
- return rel;
304
- } else {
305
- return "";
306
- }
307
- });
308
- const result = Object.keys(subsetGroup).reduce((r, groupKey)=>{
309
- const fields = subsetGroup[groupKey];
310
- assert(fields !== undefined, "fields is undefined");
311
- // 현재 테이블 필드셋은 select, virtual에 추가하고 리턴
312
- if (groupKey === "") {
313
- const realFields = fields.filter((field)=>!isVirtualProp(this.propsDict[field]));
314
- // virtualType: "code" (또는 undefined)인 virtual prop만 r.virtual에 추가
315
- // virtualType: "query"인 경우 사용자가 appendSelect로 직접 추가하므로 제외
316
- const virtualCodeFields = fields.filter((field)=>isVirtualCodeProp(this.propsDict[field]));
317
- if (prefix === "") {
318
- // 현재 테이블인 경우
319
- r.select = r.select.concat(realFields.map((field)=>this.getFullFieldName(field)));
320
- r.virtual = r.virtual.concat(virtualCodeFields);
321
- } else {
322
- // 넘어온 테이블인 경우
323
- r.select = r.select.concat(realFields.map((field)=>`${prefix}.${field} as ${prefix}__${field}`));
324
- }
325
- return r;
326
- }
327
- const relation = this.relations[groupKey];
328
- if (relation === undefined) {
329
- throw new Error(`존재하지 않는 relation 참조 ${groupKey}`);
330
- }
331
- const relEntity = EntityManager.get(relation.with);
332
- if (isOneToOneRelationProp(relation) || isBelongsToOneRelationProp(relation)) {
333
- // -One Relation: JOIN 으로 처리
334
- const relFields = fields.map((field)=>field.split(".").slice(1).join("."));
335
- // -One Relation에서 id 필드만 참조하는 경우 릴레이션 넘기지 않고 리턴
336
- if (relFields.length === 1 && relFields[0] === "id") {
337
- if (prefix === "") {
338
- r.select = r.select.concat(`${this.table}.${groupKey}_id`);
339
- } else {
340
- r.select = r.select.concat(`${prefix}.${groupKey}_id as ${prefix}__${groupKey}_id`);
341
- }
342
- return r;
343
- }
344
- // innerOrOuter
345
- const innerOrOuter = (()=>{
346
- if (isAlreadyOuterJoined) {
347
- return "outer";
348
- }
349
- if (isOneToOneRelationProp(relation)) {
350
- if (relation.hasJoinColumn === true && (relation.nullable ?? false) === false) {
351
- return "inner";
352
- } else {
353
- return "outer";
354
- }
355
- } else {
356
- if (relation.nullable) {
357
- return "outer";
358
- } else {
359
- return "inner";
360
- }
361
- }
362
- })();
363
- const relSubsetQuery = relEntity.resolveSubsetQuery(`${prefix !== "" ? `${prefix}.` : ""}${groupKey}`, relFields, innerOrOuter === "outer");
364
- r.select = r.select.concat(relSubsetQuery.select);
365
- r.virtual = r.virtual.concat(relSubsetQuery.virtual);
366
- const joinAs = prefix === "" ? groupKey : `${prefix}__${groupKey}`;
367
- const fromTable = prefix === "" ? this.table : prefix;
368
- let joinClause;
369
- if (relation.customJoinClause) {
370
- joinClause = {
371
- custom: relation.customJoinClause
372
- };
373
- } else {
374
- let from, to;
375
- if (isOneToOneRelationProp(relation)) {
376
- if (relation.hasJoinColumn) {
377
- from = `${fromTable}.${relation.name}_id`;
378
- to = `${joinAs}.id`;
379
- } else {
380
- from = `${fromTable}.id`;
381
- to = `${joinAs}.${inflection.underscore(this.names.fs.replace(/-/g, "_"))}_id`;
382
- }
383
- } else {
384
- from = `${fromTable}.${relation.name}_id`;
385
- to = `${joinAs}.id`;
386
- }
387
- joinClause = {
388
- from,
389
- to
390
- };
391
- }
392
- r.joins.push({
393
- as: joinAs,
394
- join: innerOrOuter,
395
- table: relEntity.table,
396
- ...joinClause
397
- });
398
- // BelongsToOne 밑에 HasMany가 붙은 경우
399
- if (relSubsetQuery.loaders.length > 0) {
400
- const convertedLoaders = relSubsetQuery.loaders.map((loader)=>{
401
- const newAs = [
402
- groupKey,
403
- loader.as
404
- ].join("__");
405
- return {
406
- as: newAs,
407
- table: loader.table,
408
- manyJoin: loader.manyJoin,
409
- oneJoins: loader.oneJoins,
410
- select: loader.select,
411
- loaders: loader.loaders
412
- };
413
- });
414
- r.loaders = [
415
- ...r.loaders,
416
- ...convertedLoaders
417
- ];
418
- }
419
- r.joins = r.joins.concat(relSubsetQuery.joins);
420
- } else if (isHasManyRelationProp(relation) || isManyToManyRelationProp(relation)) {
421
- // -Many Relation: Loader 로 처리
422
- const relFields = fields.map((field)=>field.split(".").slice(1).join("."));
423
- const relSubsetQuery = relEntity.resolveSubsetQuery("", relFields);
424
- let manyJoin;
425
- if (isHasManyRelationProp(relation)) {
426
- const fromCol = relation?.fromColumn ?? "id";
427
- manyJoin = {
428
- fromTable: this.table,
429
- fromCol,
430
- idField: prefix === "" ? `${fromCol}` : `${prefix}__${fromCol}`,
431
- toTable: relEntity.table,
432
- toCol: relation.joinColumn
433
- };
434
- } else if (isManyToManyRelationProp(relation)) {
435
- manyJoin = {
436
- fromTable: this.table,
437
- fromCol: "id",
438
- idField: prefix === "" ? `id` : `${prefix}__id`,
439
- through: {
440
- table: relation.joinTable,
441
- fromCol: `${inflection.singularize(this.table)}_id`,
442
- toCol: `${inflection.singularize(relEntity.table)}_id`
443
- },
444
- toTable: relEntity.table,
445
- toCol: "id"
446
- };
447
- } else {
448
- throw new Error();
449
- }
450
- r.loaders.push({
451
- as: groupKey,
452
- table: relEntity.table,
453
- manyJoin,
454
- oneJoins: relSubsetQuery.joins,
455
- select: relSubsetQuery.select,
456
- loaders: relSubsetQuery.loaders
457
- });
458
- }
459
- return r;
460
- }, {
461
- select: [],
462
- virtual: [],
463
- joins: [],
464
- loaders: []
465
- });
466
- return result;
467
- }
468
- /*
469
- FieldExpr[] 을 EntityPropNode[] 로 변환
470
- */ fieldExprsToPropNodes(fieldExprs, entity = this) {
471
- const groups = fieldExprs.reduce((result, fieldExpr)=>{
472
- let key, value, elseExpr;
473
- if (fieldExpr.includes(".")) {
474
- [key, ...elseExpr] = fieldExpr.split(".");
475
- value = elseExpr.join(".");
476
- } else {
477
- key = "";
478
- value = fieldExpr;
479
- }
480
- result[key] = (result[key] ?? []).concat(value);
481
- return result;
482
- }, {});
483
- return Object.keys(groups).flatMap((key)=>{
484
- const group = groups[key];
485
- // 일반 prop 처리
486
- if (key === "") {
487
- return group.map((propName)=>{
488
- const prop = entity.props.find((p)=>p.name === propName);
489
- if (prop === undefined) {
490
- throw new Error(`${entity.id} -- 잘못된 FieldExpr '${propName}' (사용 가능한 props: ${entity.props.map((p)=>p.name).join(", ")})`);
491
- }
492
- return {
493
- nodeType: "plain",
494
- prop
495
- };
496
- });
497
- }
498
- // relation prop 처리
499
- const prop = entity.propsDict[key];
500
- if (!isRelationProp(prop)) {
501
- throw new Error(`잘못된 FieldExpr ${key}.${group[0]}`);
502
- }
503
- const relEntity = EntityManager.get(prop.with);
504
- // relation -One 에 id 필드 하나인 경우
505
- if (isBelongsToOneRelationProp(prop) || isOneToOneRelationProp(prop)) {
506
- if (group.length === 1 && (group[0] === "id" || group[0] === "id?")) {
507
- // id 하나만 있는지 체크해서, 하나만 있으면 상위 prop으로 id를 리턴
508
- const idProp = relEntity.propsDict.id;
509
- return {
510
- nodeType: "plain",
511
- prop: {
512
- ...idProp,
513
- name: `${key}_id`,
514
- nullable: prop.nullable
515
- }
516
- };
517
- }
518
- }
519
- // -One 그외의 경우 object로 리턴
520
- // -Many의 경우 array로 리턴
521
- // Recursive 로 뎁스 처리
522
- const children = this.fieldExprsToPropNodes(group, relEntity);
523
- const nodeType = isBelongsToOneRelationProp(prop) || isOneToOneRelationProp(prop) ? "object" : "array";
524
- return {
525
- nodeType,
526
- prop,
527
- children
528
- };
529
- });
530
- }
531
- getFieldExprs(prefix = "", maxDepth = 3, froms = []) {
532
- return this.props.flatMap((prop)=>{
533
- const propName = [
534
- prefix,
535
- prop.name
536
- ].filter((v)=>v !== "").join(".");
537
- if (propName === prefix) {
538
- return null;
539
- }
540
- if (isRelationProp(prop)) {
541
- if (maxDepth < 0) {
542
- return null;
543
- }
544
- if (froms.includes(prop.with)) {
545
- // 역방향 relation인 경우 제외
546
- return null;
547
- }
548
- // 정방향 relation인 경우 recursive 콜
549
- const relMd = EntityManager.get(prop.with);
550
- return relMd.getFieldExprs(propName, maxDepth - 1, [
551
- ...froms,
552
- this.id
553
- ]);
554
- }
555
- return propName;
556
- }).filter((f)=>f !== null);
557
- }
558
- /**
559
- * Relation prop이 현재 테이블에 FK 컬럼을 생성하는지 확인
560
- *(BelongsToOne 또는 OneToOne(hasJoinColumn=true)인 경우 FK 생성)
561
- */ hasForeignKey(prop) {
562
- return prop.relationType === "BelongsToOne" || prop.relationType === "OneToOne" && prop.hasJoinColumn === true;
563
- }
564
- getTableColumns() {
565
- return this.props.map((prop)=>{
566
- if (prop.type === "relation") {
567
- if (this.hasForeignKey(prop)) {
568
- return {
569
- name: `${prop.name}_id`,
570
- type: "int_unsigned"
571
- };
572
- } else {
573
- return null;
574
- }
575
- }
576
- return {
577
- name: prop.name,
578
- type: prop.type
579
- };
580
- }).filter(nonNullable);
581
- }
582
- /**
583
- * Entity에 정의된 모든 vector 타입 컬럼 반환
584
- */ getVectorColumns() {
585
- return this.props.filter((p)=>p.type === "vector");
586
- }
587
- /**
588
- * 특정 vector 컬럼 반환
589
- * @param columnName - 컬럼명 (생략 시 첫 번째 vector 컬럼)
590
- */ getVectorColumn(columnName) {
591
- const vectorProps = this.getVectorColumns();
592
- if (columnName) {
593
- return vectorProps.find((p)=>p.name === columnName);
594
- }
595
- return vectorProps[0];
596
- }
597
- /**
598
- * 필터링 가능한 props 반환
599
- *
600
- * - 일반 prop
601
- * - FK를 생성하는 relation (BelongsToOne, OneToOne with hasJoinColumn)
602
- * → {name}_id 형태의 가상 integer prop으로 변환
603
- */ getFilterableProps() {
604
- return this.props.flatMap((prop)=>{
605
- // Virtual prop 제외
606
- if (isVirtualProp(prop)) {
607
- return [];
608
- }
609
- // Relation prop 처리
610
- if (isRelationProp(prop)) {
611
- // FK를 생성하는 relation만 포함
612
- if (this.hasForeignKey(prop)) {
613
- return {
614
- name: `${prop.name}_id`,
615
- type: "integer",
616
- nullable: prop.nullable
617
- };
618
- }
619
- return [];
620
- }
621
- // 일반 prop 처리
622
- return prop;
623
- });
624
- }
625
- async registerModulePaths() {
626
- const basePath = `${this.names.parentFs}`;
627
- // base-scheme
628
- EntityManager.setModulePath(`${this.id}BaseSchema`, `sonamu.generated`);
629
- // subset
630
- if (Object.keys(this.subsets).length > 0) {
631
- EntityManager.setModulePath(`${this.id}SubsetKey`, `sonamu.generated`);
632
- EntityManager.setModulePath(`${this.id}SubsetMapping`, `sonamu.generated`);
633
- for (const subsetKey of Object.keys(this.subsets)){
634
- EntityManager.setModulePath(`${this.id}Subset${subsetKey.toUpperCase()}`, `sonamu.generated`);
635
- }
636
- }
637
- // enums
638
- for (const enumId of Object.keys(this.enumLabels)){
639
- EntityManager.setModulePath(enumId, `sonamu.generated`);
640
- }
641
- // types
642
- const typesModulePath = `${basePath}/${this.names.parentFs}.types`;
643
- const typesFilePath = path.join(Sonamu.apiRootPath, runtimePath(`dist/application/${typesModulePath}.js`));
644
- if (await exists(typesFilePath)) {
645
- const importedMembers = await importMembers(typesFilePath);
646
- this.types = Object.fromEntries(importedMembers.map(({ name, value })=>{
647
- EntityManager.setModulePath(name, typesModulePath);
648
- return [
649
- name,
650
- value
651
- ];
652
- }));
653
- }
654
- }
655
- registerTableSpecs() {
656
- // 조인 테이블 인덱스 제외 (컬럼 이름에 '.'이 포함된 경우)
657
- const uniqueIndexes = this.indexes.filter((idx)=>idx.type === "unique").filter((idx)=>idx.columns.every((col)=>!col.name.includes(".")));
658
- EntityManager.setTableSpec({
659
- name: this.table,
660
- uniqueIndexes,
661
- jsonColumns: this.props.filter((p)=>p.type === "json").map((p)=>p.name)
662
- });
663
- }
664
- toJson() {
665
- // subsets와 subsetsInternal을 SubsetDef 형태로 복원 (cone 포함)
666
- const subsets = {};
667
- for (const key of Object.keys(this.subsets)){
668
- const normalFields = this.subsets[key];
669
- const internalFields = (this.subsetsInternal[key] ?? []).map((field)=>({
670
- field,
671
- internal: true
672
- }));
673
- const fields = [
674
- ...normalFields,
675
- ...internalFields
676
- ];
677
- // cone이 있으면 새로운 객체 형태로, 없으면 배열 형태로
678
- if (this.subsetCones[key]) {
679
- subsets[key] = {
680
- fields,
681
- cone: this.subsetCones[key]
682
- };
683
- } else {
684
- subsets[key] = fields;
685
- }
686
- }
687
- // enums를 EnumDef 형태로 복원 (cone 포함)
688
- const enums = {};
689
- for (const [key, values] of Object.entries(this.enumLabels)){
690
- // cone이 있으면 새로운 객체 형태로, 없으면 Record 형태로
691
- if (this.enumCones[key]) {
692
- enums[key] = {
693
- values,
694
- cone: this.enumCones[key]
695
- };
696
- } else {
697
- enums[key] = values;
698
- }
699
- }
700
- return {
701
- id: this.id,
702
- parentId: this.parentId,
703
- table: this.table,
704
- title: this.title,
705
- cone: this.cone,
706
- props: this.props,
707
- indexes: this.indexes,
708
- subsets,
709
- enums
710
- };
711
- }
712
- async save() {
713
- // sort: subsets
714
- const subsetRows = this.getSubsetRows();
715
- this.subsets = Object.fromEntries(Object.entries(this.subsets).map(([subsetKey])=>{
716
- return [
717
- subsetKey,
718
- this.subsetRowsToSubsetFields(subsetRows, subsetKey, false)
719
- ];
720
- }));
721
- this.subsetsInternal = Object.fromEntries(Object.entries(this.subsetsInternal).map(([subsetKey])=>{
722
- return [
723
- subsetKey,
724
- this.subsetRowsToSubsetFields(subsetRows, subsetKey, true)
725
- ];
726
- }));
727
- // save
728
- const jsonPath = path.join(Sonamu.apiRootPath, `src/application/${this.names.parentFs}/${this.names.fs}.entity.json`);
729
- const json = this.toJson();
730
- await writeFile(jsonPath, formatCode(JSON.stringify(json), "json", jsonPath));
731
- // reload
732
- await EntityManager.register(json);
733
- }
734
- /**
735
- * 템플릿 cone 메타데이터를 생성합니다.
736
- *
737
- * LLM을 사용하지 않고 faker-mappings.ts를 활용하여 기본 cone을 생성합니다.
738
- * stub entity 생성 시 자동으로 호출되어 최소한의 cone 메타데이터를 제공합니다.
739
- *
740
- * @param locale - 생성 시 사용할 locale (기본값: Sonamu.config.i18n.defaultLocale 또는 "ko")
741
- */ async generateTemplateCones(locale) {
742
- const { generateTemplateCones } = await import("./entity-template-cone.js");
743
- const configLocale = Sonamu.config.i18n?.defaultLocale;
744
- const effectiveLocale = locale || (configLocale === "ko" || configLocale === "en" || configLocale === "ja" ? configLocale : "ko");
745
- const result = generateTemplateCones(this.toJson(), effectiveLocale);
746
- // 결과를 Entity에 적용 (applyCones와 동일한 방식)
747
- if (result.entityCone) {
748
- this.cone = result.entityCone;
749
- }
750
- for (const [propName, cone] of Object.entries(result.propCones)){
751
- const prop = this.props.find((p)=>p.name === propName);
752
- if (prop) {
753
- prop.cone = cone;
754
- }
755
- }
756
- this.enumCones = {
757
- ...this.enumCones,
758
- ...result.enumCones
759
- };
760
- this.subsetCones = {
761
- ...this.subsetCones,
762
- ...result.subsetCones
763
- };
764
- await this.save();
765
- }
766
- /**
767
- * LLM을 사용하여 cone 메타데이터를 생성합니다.
768
- *
769
- * @param options.preserveExisting - 기존 cone 보존 여부 (기본값: true)
770
- * @param options.onlyEmpty - fixtureHint가 없는 cone만 생성 (기본값: false)
771
- * @param options.locale - 생성 시 사용할 locale (기본값: "ko")
772
- */ async generateCones(options) {
773
- const { generateCones } = await import("../cone/cone-generator.js");
774
- const context = {
775
- entity: this.toJson(),
776
- locale: options?.locale || "ko",
777
- existingCones: options?.preserveExisting !== false ? this.collectExistingCones() : undefined,
778
- onlyEmpty: options?.onlyEmpty ?? false
779
- };
780
- const result = await generateCones(context);
781
- this.applyCones(result);
782
- await this.save();
783
- return result;
784
- }
785
- /**
786
- * 기존 cone들을 수집합니다 (entity, props, enums, subsets).
787
- *
788
- * @returns 키가 "entity:id", "prop:name", "enum:enumId", "subset:key" 형식인 cone 맵
789
- */ collectExistingCones() {
790
- const cones = {};
791
- if (this.cone) {
792
- cones[`entity:${this.id}`] = this.cone;
793
- }
794
- for (const prop of this.props){
795
- if (prop.cone) {
796
- cones[`prop:${prop.name}`] = prop.cone;
797
- }
798
- }
799
- for (const [enumId, cone] of Object.entries(this.enumCones)){
800
- cones[`enum:${enumId}`] = cone;
801
- }
802
- for (const [subsetKey, cone] of Object.entries(this.subsetCones)){
803
- cones[`subset:${subsetKey}`] = cone;
804
- }
805
- return cones;
806
- }
807
- /**
808
- * 생성된 cone들을 Entity에 적용합니다.
809
- *
810
- * @param result - LLM으로 생성된 cone 결과
811
- */ applyCones(result) {
812
- if (result.entityCone) {
813
- this.cone = result.entityCone;
814
- }
815
- for (const [propName, cone] of Object.entries(result.propCones)){
816
- const prop = this.props.find((p)=>p.name === propName);
817
- if (prop) {
818
- prop.cone = cone;
819
- }
820
- }
821
- this.enumCones = {
822
- ...this.enumCones,
823
- ...result.enumCones
824
- };
825
- this.subsetCones = {
826
- ...this.subsetCones,
827
- ...result.subsetCones
828
- };
829
- }
830
- getSubsetRows(_subsets, _subsetsInternal, prefixes = []) {
831
- if (prefixes.length > 10) {
832
- return [];
833
- }
834
- const subsets = _subsets ?? this.subsets;
835
- const subsetsInternal = _subsetsInternal ?? this.subsetsInternal;
836
- const subsetKeys = Object.keys(subsets);
837
- const allFields = unique(subsetKeys.flatMap((key)=>subsets[key]));
838
- // internal 필드도 allFields에 포함 (relation 탐색용)
839
- const allInternalFields = unique(subsetKeys.flatMap((key)=>subsetsInternal[key] ?? []));
840
- const combinedFields = unique([
841
- ...allFields,
842
- ...allInternalFields
843
- ]);
844
- return this.props.map((prop)=>{
845
- if (prop.type === "relation" && combinedFields.find((f)=>f.startsWith(`${[
846
- ...prefixes,
847
- prop.name
848
- ].join(".")}.`))) {
849
- const relEntity = EntityManager.get(prop.with);
850
- const children = relEntity.getSubsetRows(subsets, subsetsInternal, [
851
- ...prefixes,
852
- `${prop.name}`
853
- ]);
854
- return {
855
- field: prop.name,
856
- children,
857
- relationEntity: prop.with,
858
- prefixes,
859
- isOpen: children.length > 0,
860
- has: Object.fromEntries(subsetKeys.map((subsetKey)=>{
861
- return [
862
- subsetKey,
863
- children.every((child)=>child.has[subsetKey] === true)
864
- ];
865
- })),
866
- isInternal: Object.fromEntries(subsetKeys.map((subsetKey)=>{
867
- return [
868
- subsetKey,
869
- children.every((child)=>child.isInternal[subsetKey] === true)
870
- ];
871
- }))
872
- };
873
- }
874
- const field = [
875
- ...prefixes,
876
- prop.name
877
- ].join(".");
878
- return {
879
- field: prop.name,
880
- children: [],
881
- relationEntity: prop.type === "relation" ? prop.with : undefined,
882
- prefixes,
883
- has: Object.fromEntries(subsetKeys.map((subsetKey)=>{
884
- const subsetFields = subsets[subsetKey];
885
- const has = subsetFields.some((f)=>{
886
- return f === field || f.startsWith(`${field}.`);
887
- });
888
- return [
889
- subsetKey,
890
- has
891
- ];
892
- })),
893
- isInternal: Object.fromEntries(subsetKeys.map((subsetKey)=>{
894
- const internalFields = subsetsInternal[subsetKey] ?? [];
895
- const isInternal = internalFields.some((f)=>{
896
- return f === field || f.startsWith(`${field}.`);
897
- });
898
- return [
899
- subsetKey,
900
- isInternal
901
- ];
902
- }))
903
- };
904
- });
905
- }
906
- subsetRowsToSubsetFields(subsetRows, subsetKey, internal = false) {
907
- const hasKey = internal ? "isInternal" : "has";
908
- return subsetRows.map((subsetRow)=>{
909
- if (subsetRow.children.length > 0) {
910
- return this.subsetRowsToSubsetFields(subsetRow.children, subsetKey, internal);
911
- } else if (subsetRow[hasKey][subsetKey]) {
912
- return subsetRow.prefixes.concat(subsetRow.field).join(".");
913
- } else {
914
- return null;
915
- }
916
- }).filter(nonNullable).flat();
917
- }
918
- async createProp(prop, at) {
919
- if (!at) {
920
- this.props.push(prop);
921
- } else {
922
- this.props.splice(at, 0, prop);
923
- }
924
- await this.save();
925
- }
926
- analyzeSubsetField(subsetField) {
927
- const arr = subsetField.split(".");
928
- let entityId = this.id;
929
- const result = [];
930
- for(let i = 0; i < arr.length; i++){
931
- const propName = arr[i];
932
- result.push({
933
- entityId,
934
- propName
935
- });
936
- const prop = EntityManager.get(entityId).props.find((p)=>p.name === propName);
937
- if (!prop) {
938
- throw new Error(`${entityId}의 잘못된 서브셋키 ${subsetField}`);
939
- }
940
- if (isRelationProp(prop)) {
941
- entityId = prop.with;
942
- }
943
- }
944
- return result;
945
- }
946
- async modifyProp(newProp, at) {
947
- // 이전 프롭 이름 저장
948
- const oldName = this.props[at].name;
949
- // 저장할 엔티티
950
- const entities = [
951
- this
952
- ];
953
- // 이름이 바뀐 경우
954
- if (oldName !== newProp.name) {
955
- // 전체 엔티티에서 현재 수정된 프롭을 참조하고 있는 모든 서브셋필드 찾아서 수정
956
- const allEntityIds = EntityManager.getAllIds();
957
- for (const relEntityId of allEntityIds){
958
- const relEntity = EntityManager.get(relEntityId);
959
- const relEntitySubsetKeys = Object.keys(relEntity.subsets);
960
- for (const subsetKey of relEntitySubsetKeys){
961
- const subset = relEntity.subsets[subsetKey];
962
- // 서브셋 필드를 순회하며, 엔티티-프롭 단위로 분석한 후 현재 엔티티-프롭과 일치하는 경우 수정 처리
963
- const modifiedSubsetFields = subset.map((subsetField)=>{
964
- const analyzed = relEntity.analyzeSubsetField(subsetField);
965
- const modified = analyzed.map((a)=>a.propName === oldName && a.entityId === this.id ? {
966
- ...a,
967
- propName: newProp.name
968
- } : a);
969
- // 분석한 필드를 다시 서브셋 필드로 복구
970
- return modified.map((a)=>a.propName).join(".");
971
- });
972
- if (subset.join(",") !== modifiedSubsetFields.join(",")) {
973
- relEntity.subsets[subsetKey] = modifiedSubsetFields;
974
- entities.push(relEntity);
975
- }
976
- }
977
- }
978
- }
979
- // 프롭 수정
980
- this.props[at] = newProp;
981
- await Promise.all(entities.map(async (entity)=>entity.save()));
982
- }
983
- async delProp(at) {
984
- // 이전 프롭 이름 저장
985
- const oldName = this.props[at].name;
986
- // 저장할 엔티티
987
- const entities = [
988
- this
989
- ];
990
- // 전체 엔티티에서 현재 삭제된 프롭을 참조하고 있는 모든 서브셋필드 찾아서 제외
991
- const allEntityIds = EntityManager.getAllIds();
992
- for (const relEntityId of allEntityIds){
993
- const relEntity = EntityManager.get(relEntityId);
994
- const relEntitySubsetKeys = Object.keys(relEntity.subsets);
995
- for (const subsetKey of relEntitySubsetKeys){
996
- const subset = relEntity.subsets[subsetKey];
997
- // 서브셋 필드를 순회하며, 엔티티-프롭 단위로 분석한 후 현재 엔티티-프롭과 일치하는 경우 이후의 필드를 제외
998
- const modifiedSubsetFields = subset.map((subsetField)=>{
999
- const analyzed = relEntity.analyzeSubsetField(subsetField);
1000
- if (analyzed.find((a)=>a.propName === oldName && a.entityId === this.id)) {
1001
- return null;
1002
- } else {
1003
- return subsetField;
1004
- }
1005
- }).filter(nonNullable);
1006
- if (subset.join(",") !== modifiedSubsetFields.join(",")) {
1007
- relEntity.subsets[subsetKey] = modifiedSubsetFields;
1008
- entities.push(relEntity);
1009
- }
1010
- }
1011
- }
1012
- // 현재 엔티티의 인덱스에서 제외
1013
- for (const index of EntityManager.get(this.id).indexes){
1014
- index.columns = index.columns.filter((col)=>col.name !== oldName);
1015
- }
1016
- // 프롭 삭제
1017
- this.props.splice(at, 1);
1018
- await Promise.all(entities.map(async (entity)=>entity.save()));
1019
- }
1020
- getEntityIdFromSubsetField(subsetField) {
1021
- if (subsetField.includes(".") === false) {
1022
- return this.id;
1023
- }
1024
- // 서브셋 필드의 마지막은 프롭이므로 제외
1025
- const arr = subsetField.split(".").slice(0, -1);
1026
- // 서브셋 필드를 내려가면서 마지막으로 relation된 엔티티를 찾음
1027
- const lastEntityId = arr.reduce((entityId, field)=>{
1028
- const relProp = EntityManager.get(entityId).props.find((p)=>p.name === field);
1029
- if (!relProp || relProp.type !== "relation") {
1030
- console.debug({
1031
- arr,
1032
- thisId: this.id,
1033
- entityId,
1034
- field
1035
- });
1036
- throw new Error(`잘못된 서브셋키 ${subsetField}`);
1037
- }
1038
- return relProp.with;
1039
- }, this.id);
1040
- return lastEntityId;
1041
- }
1042
- async moveProp(at, to) {
1043
- const prop = this.props[at];
1044
- const newProps = [
1045
- ...this.props
1046
- ];
1047
- newProps.splice(to, 0, prop);
1048
- newProps.splice(at < to ? at : at + 1, 1);
1049
- this.props = newProps;
1050
- await this.save();
1051
- }
1052
- /**
1053
- * 필드명을 "테이블명.필드명" 형식으로 변환
1054
- */ getFullFieldName(field) {
1055
- if (field.includes(".")) {
1056
- return field;
1057
- }
1058
- return `${this.table}.${field}`;
1059
- }
1060
- /**
1061
- * 엔티티의 PK 타입을 반환합니다.
1062
- * id 필드의 타입을 기준으로 "integer" | "string" | "uuid"를 반환합니다.
1063
- */ getPkType() {
1064
- const idProp = this.propsDict.id;
1065
- if (!idProp) {
1066
- throw new Error(`Entity ${this.id}에 id 필드가 없습니다`);
1067
- }
1068
- if (idProp.type === "string" || idProp.type === "uuid") {
1069
- return idProp.type;
1070
- }
1071
- return "integer";
1072
- }
1073
- /**
1074
- * 엔티티의 PK prop을 반환합니다.
1075
- * length 등 세부 정보에 접근할 때 사용합니다.
1076
- */ getPkProp() {
1077
- const idProp = this.propsDict.id;
1078
- if (!idProp) {
1079
- throw new Error(`Entity ${this.id}에 id 필드가 없습니다`);
1080
- }
1081
- return idProp;
1082
- }
1083
- /**
1084
- * 엔티티의 PK 배열 타입을 반환합니다.
1085
- * LoaderQuery의 fromIds 타입으로 사용됩니다.
1086
- */ getPkArrayType() {
1087
- const pkType = this.getPkType();
1088
- return pkType === "integer" ? "number[]" : "string[]";
1089
- }
1090
- }
13
+ import assert from "assert";
14
+ import { writeFile } from "fs/promises";
15
+ import path from "path";
16
+
17
+ //#region src/entity/entity.ts
18
+ var Entity;
19
+ var init_entity = __esmMin((() => {
20
+ init_sonamu();
21
+ init_types();
22
+ init_esm_utils();
23
+ init_formatter();
24
+ init_fs_utils();
25
+ init_path_utils();
26
+ init_utils();
27
+ init_entity_manager();
28
+ Entity = class {
29
+ id;
30
+ parentId;
31
+ table;
32
+ title;
33
+ cone;
34
+ names;
35
+ props;
36
+ propsDict;
37
+ relations;
38
+ indexes;
39
+ subsets;
40
+ subsetsInternal;
41
+ types = {};
42
+ enums = {};
43
+ enumLabels = {};
44
+ enumCones = {};
45
+ subsetCones = {};
46
+ constructor({ id, parentId, table, title, cone, props, indexes, subsets, enums }) {
47
+ this.id = id;
48
+ this.parentId = parentId;
49
+ this.title = title ?? this.id;
50
+ this.table = table ?? inflection.underscore(inflection.pluralize(id));
51
+ this.cone = cone;
52
+ if (props) {
53
+ this.props = props.map((prop) => {
54
+ if (isEnumProp(prop)) {
55
+ if (prop.id.includes("$Model")) {
56
+ prop.id = prop.id.replace("$Model", id);
57
+ }
58
+ }
59
+ return prop;
60
+ });
61
+ this.propsDict = Object.fromEntries(props.map((prop) => {
62
+ return [prop.name, prop];
63
+ }));
64
+ this.relations = Object.fromEntries(props.filter((prop) => isRelationProp(prop)).map((prop) => [prop.name, prop]));
65
+ } else {
66
+ this.props = [];
67
+ this.propsDict = {};
68
+ this.relations = {};
69
+ }
70
+ this.indexes = indexes ?? [];
71
+ this.subsets = {};
72
+ this.subsetsInternal = {};
73
+ for (const [key, subsetDef] of Object.entries(subsets ?? {})) {
74
+ const fields = getSubsetFields(subsetDef);
75
+ this.subsets[key] = fields.filter((f) => !isInternalSubsetField(f)).map(normalizeSubsetField);
76
+ this.subsetsInternal[key] = fields.filter(isInternalSubsetField).map(normalizeSubsetField);
77
+ if (!Array.isArray(subsetDef) && "cone" in subsetDef && subsetDef.cone) {
78
+ this.subsetCones[key] = subsetDef.cone;
79
+ }
80
+ }
81
+ this.enumLabels = Object.fromEntries(Object.entries(enums ?? {}).map(([key, enumDef]) => {
82
+ if ("values" in enumDef && "cone" in enumDef && enumDef.cone) {
83
+ this.enumCones[key] = enumDef.cone;
84
+ }
85
+ return [key, getEnumDefValues(enumDef)];
86
+ }));
87
+ this.enums = Object.fromEntries(Object.entries(this.enumLabels).map(([key, enumLabel]) => {
88
+ return [key, z$1.enum(Object.keys(enumLabel))];
89
+ }));
90
+ this.names = {
91
+ parentFs: inflection.dasherize(inflection.underscore(parentId ?? id)).toLowerCase(),
92
+ fs: inflection.dasherize(inflection.underscore(id)).toLowerCase(),
93
+ module: id
94
+ };
95
+ }
96
+ /**
97
+ * 쿼리용 서브셋 필드를 반환합니다 (subsets + subsetsInternal 합침)
98
+ */
99
+ getSubsetFieldsForQuery(subsetKey) {
100
+ return [...this.subsets[subsetKey] ?? [], ...this.subsetsInternal[subsetKey] ?? []];
101
+ }
102
+ /**
103
+ * 주어진 이름(subsetKey)의 subset을 실제로 가져오는 Puri 코드 구현체 string을 반환합니다.
104
+ */
105
+ getPuriSubsetQuery(subsetKey) {
106
+ const subset = this.getSubsetFieldsForQuery(subsetKey);
107
+ const subsetQuery = this.resolveSubsetQuery("", subset);
108
+ const lines = [];
109
+ lines.push(`return qbWrapper`);
110
+ lines.push(`.from("${this.table}")`);
111
+ for (const join$1 of subsetQuery.joins) {
112
+ const joinMethod = join$1.join === "inner" ? "join" : "leftJoin";
113
+ if ("custom" in join$1) {
114
+ lines.push(`.${joinMethod}({ ${join$1.as}: "${join$1.table}" }, qbWrapper.knex.raw(\`${join$1.custom}\`))`);
115
+ } else {
116
+ lines.push(`.${joinMethod}({ ${join$1.as}: "${join$1.table}" }, "${join$1.from}", "${join$1.to}")`);
117
+ }
118
+ }
119
+ const selectObj = this.buildNestedSelectObject(subsetQuery.select);
120
+ lines.push(`.select(${this.stringifyNestedSelectObject(selectObj)});`);
121
+ return lines.join("\n");
122
+ }
123
+ /**
124
+ * *.entity.json의 subset에 들어있는 필드 배열을 받아서,
125
+ * Puri의 SelectObject 타입으로 변환합니다.
126
+ *
127
+ * 예: ["users.id", "parent.id", "parent.name"]
128
+ * → { id: "users.id", parent: { id: "parent.id", name: "parent.name" } }
129
+ *
130
+ * 언더바가 아닌 중첩 객체로 변환함에 유의하세요.
131
+ * 이렇게 중첩 객체로 변환하여 select에 넘겨주면 ParseSelectObject 타입이 join된 객체의 타입을 잘 잡아줄 수 있습니다.
132
+ * 즉, enhancer에서 row를 받았을 hydrate된 객체 자체의 nullity와 그 안쪽 필드의 nullity가 fk nullable 여부에 따라 잘 추론됩니다.
133
+ */
134
+ buildNestedSelectObject(selectItems) {
135
+ const result = {};
136
+ for (const selectItem of selectItems) {
137
+ const match = selectItem.match(/^(.+?)(?: as (.+))?$/);
138
+ if (!match) continue;
139
+ const [, column, alias] = match;
140
+ const columnValue = `"${column.trim()}"`;
141
+ if (!alias || !alias.includes("__")) {
142
+ const key = alias ?? assertDefined(column.split(".").pop());
143
+ result[key] = columnValue;
144
+ } else {
145
+ const parts = alias.split("__");
146
+ let current = result;
147
+ for (let i = 0; i < parts.length - 1; i++) {
148
+ const part = parts[i];
149
+ if (part in current) {
150
+ if (typeof current[part] === "string") {
151
+ throw new Error(`Conflict detected in select items: parent path "${parts.slice(0, i + 1).join("__")}" is already set as a field, cannot nest "${alias}" under it.`);
152
+ }
153
+ } else {
154
+ current[part] = {};
155
+ }
156
+ current = current[part];
157
+ }
158
+ const lastPart = parts[parts.length - 1];
159
+ current[lastPart] = columnValue;
160
+ }
161
+ }
162
+ return result;
163
+ }
164
+ /**
165
+ * JSON.stringify와 유사한 일을 합니다.
166
+ * 다만 주어진 객체를 JSON이 아닌 TypeScript 객체 리터럴 스트링으로 만들어줍니다.
167
+ * key에 따옴표가 없어요.
168
+ * 출력 예시:
169
+ * ```typescript
170
+ * {
171
+ * id: "users.id",
172
+ * parent: {
173
+ * id: "parent.id",
174
+ * name: "parent.name",
175
+ * },
176
+ * }
177
+ * ```
178
+ * @param obj 변환할 객체
179
+ * @param indent 들여쓰기 레벨
180
+ * @param withBraces true면 중괄호 포함, false면 내용만 반환
181
+ */
182
+ stringifyNestedSelectObject(obj, indent = 0, withBraces = true) {
183
+ const spaces = " ".repeat(indent);
184
+ const innerSpaces = " ".repeat(indent + 1);
185
+ const entries = Object.entries(obj);
186
+ if (entries.length === 0) return withBraces ? "{}" : "";
187
+ const lines = entries.map(([key, value]) => {
188
+ if (typeof value === "string") {
189
+ return `${innerSpaces}${key}: ${value},`;
190
+ } else {
191
+ return `${innerSpaces}${key}: ${this.stringifyNestedSelectObject(value, indent + 1, true)},`;
192
+ }
193
+ });
194
+ if (withBraces) {
195
+ return `{\n${lines.join("\n")}\n${spaces}}`;
196
+ } else {
197
+ return lines.join("\n");
198
+ }
199
+ }
200
+ getPuriLoaderQuery(subsetKey) {
201
+ const subset = this.getSubsetFieldsForQuery(subsetKey);
202
+ const { loaders } = this.resolveSubsetQuery("", subset);
203
+ const lines = [`[`];
204
+ const generateLoaderCode = (loaders$1) => {
205
+ const loaderLines = [];
206
+ for (const loader of loaders$1) {
207
+ const { toTable, toCol, through, fromTable } = loader.manyJoin;
208
+ const fromEntity = EntityManager.getByTable(fromTable);
209
+ const fromIdsType = fromEntity.getPkArrayType();
210
+ loaderLines.push("{", `as: "${loader.as}",`, `refId: "${loader.manyJoin.idField}",`, `qb: (qbWrapper: PuriWrapper<DatabaseSchemaExtend>, fromIds: number[] | string[]) => {`);
211
+ if (through === undefined) {
212
+ loaderLines.push("return qbWrapper", `.from("${toTable}")`);
213
+ loader.oneJoins.forEach((join$1) => {
214
+ const joinMethod = join$1.join === "inner" ? "join" : "leftJoin";
215
+ if ("custom" in join$1) {
216
+ loaderLines.push(`.${joinMethod}({ ${join$1.as}: "${join$1.table}" }, (j) => {`, `j.on(Puri.rawString("${join$1.custom}"));`, "})");
217
+ } else {
218
+ loaderLines.push(`.${joinMethod}({ ${join$1.as}: "${join$1.table}" }, "${join$1.from}", "${join$1.to}")`);
219
+ }
220
+ });
221
+ const selectObj = this.buildNestedSelectObject(loader.select);
222
+ selectObj.refId = `"${toTable}.${toCol}"`;
223
+ loaderLines.push(`.whereIn("${toTable}.${toCol}", fromIds as ${fromIdsType})`, `.select(${this.stringifyNestedSelectObject(selectObj)});`);
224
+ } else {
225
+ loaderLines.push("return qbWrapper", `.from("${through.table}")`, `.join("${toTable}", "${through.table}.${through.toCol}", "${toTable}.${toCol}")`);
226
+ loader.oneJoins.forEach((join$1) => {
227
+ const joinMethod = join$1.join === "inner" ? "join" : "leftJoin";
228
+ if ("custom" in join$1) {
229
+ loaderLines.push(`.${joinMethod}({ ${join$1.as}: "${join$1.table}" }, (j) => {`, `j.on(Puri.rawString("${join$1.custom}"));`, "})");
230
+ } else {
231
+ loaderLines.push(`.${joinMethod}({ ${join$1.as}: "${join$1.table}" }, "${join$1.from}", "${join$1.to}")`);
232
+ }
233
+ });
234
+ const selectObj = this.buildNestedSelectObject(loader.select);
235
+ selectObj.refId = `"${through.table}.${through.fromCol}"`;
236
+ loaderLines.push(`.whereIn("${through.table}.${through.fromCol}", fromIds as ${fromIdsType})`, `.select(${this.stringifyNestedSelectObject(selectObj)});`);
237
+ }
238
+ loaderLines.push(`},`);
239
+ if (loader.loaders && loader.loaders.length > 0) {
240
+ loaderLines.push("loaders: [", ...generateLoaderCode(loader.loaders), "],");
241
+ }
242
+ loaderLines.push("},");
243
+ }
244
+ return loaderLines;
245
+ };
246
+ lines.push(...generateLoaderCode(loaders));
247
+ lines.push(`]`);
248
+ return lines.join("\n");
249
+ }
250
+ getSubsetQuery(subsetKey) {
251
+ const subset = this.getSubsetFieldsForQuery(subsetKey);
252
+ const result = this.resolveSubsetQuery("", subset);
253
+ return result;
254
+ }
255
+ resolveSubsetQuery(prefix, fields, isAlreadyOuterJoined = false) {
256
+ prefix = prefix.replace(/\./g, "__");
257
+ const subsetGroup = group(fields, (field) => {
258
+ if (field.includes(".")) {
259
+ const [rel] = field.split(".");
260
+ return rel;
261
+ } else {
262
+ return "";
263
+ }
264
+ });
265
+ const result = Object.keys(subsetGroup).reduce((r, groupKey) => {
266
+ const fields$1 = subsetGroup[groupKey];
267
+ assert(fields$1 !== undefined, "fields is undefined");
268
+ if (groupKey === "") {
269
+ const realFields = fields$1.filter((field) => !isVirtualProp(this.propsDict[field]));
270
+ const virtualCodeFields = fields$1.filter((field) => isVirtualCodeProp(this.propsDict[field]));
271
+ if (prefix === "") {
272
+ r.select = r.select.concat(realFields.map((field) => this.getFullFieldName(field)));
273
+ r.virtual = r.virtual.concat(virtualCodeFields);
274
+ } else {
275
+ r.select = r.select.concat(realFields.map((field) => `${prefix}.${field} as ${prefix}__${field}`));
276
+ }
277
+ return r;
278
+ }
279
+ const relation = this.relations[groupKey];
280
+ if (relation === undefined) {
281
+ throw new Error(`존재하지 않는 relation 참조 ${groupKey}`);
282
+ }
283
+ const relEntity = EntityManager.get(relation.with);
284
+ if (isOneToOneRelationProp(relation) || isBelongsToOneRelationProp(relation)) {
285
+ const relFields = fields$1.map((field) => field.split(".").slice(1).join("."));
286
+ if (relFields.length === 1 && relFields[0] === "id") {
287
+ if (prefix === "") {
288
+ r.select = r.select.concat(`${this.table}.${groupKey}_id`);
289
+ } else {
290
+ r.select = r.select.concat(`${prefix}.${groupKey}_id as ${prefix}__${groupKey}_id`);
291
+ }
292
+ return r;
293
+ }
294
+ const innerOrOuter = (() => {
295
+ if (isAlreadyOuterJoined) {
296
+ return "outer";
297
+ }
298
+ if (isOneToOneRelationProp(relation)) {
299
+ if (relation.hasJoinColumn && !(relation.nullable ?? false)) {
300
+ return "inner";
301
+ } else {
302
+ return "outer";
303
+ }
304
+ } else {
305
+ if (relation.nullable) {
306
+ return "outer";
307
+ } else {
308
+ return "inner";
309
+ }
310
+ }
311
+ })();
312
+ const relSubsetQuery = relEntity.resolveSubsetQuery(`${prefix !== "" ? `${prefix}.` : ""}${groupKey}`, relFields, innerOrOuter === "outer");
313
+ r.select = r.select.concat(relSubsetQuery.select);
314
+ r.virtual = r.virtual.concat(relSubsetQuery.virtual);
315
+ const joinAs = prefix === "" ? groupKey : `${prefix}__${groupKey}`;
316
+ const fromTable = prefix === "" ? this.table : prefix;
317
+ let joinClause;
318
+ if (relation.customJoinClause) {
319
+ joinClause = { custom: relation.customJoinClause };
320
+ } else {
321
+ let from, to;
322
+ if (isOneToOneRelationProp(relation)) {
323
+ if (relation.hasJoinColumn) {
324
+ from = `${fromTable}.${relation.name}_id`;
325
+ to = `${joinAs}.id`;
326
+ } else {
327
+ from = `${fromTable}.id`;
328
+ to = `${joinAs}.${inflection.underscore(this.names.fs.replace(/-/g, "_"))}_id`;
329
+ }
330
+ } else {
331
+ from = `${fromTable}.${relation.name}_id`;
332
+ to = `${joinAs}.id`;
333
+ }
334
+ joinClause = {
335
+ from,
336
+ to
337
+ };
338
+ }
339
+ r.joins.push({
340
+ as: joinAs,
341
+ join: innerOrOuter,
342
+ table: relEntity.table,
343
+ ...joinClause
344
+ });
345
+ if (relSubsetQuery.loaders.length > 0) {
346
+ const convertedLoaders = relSubsetQuery.loaders.map((loader) => {
347
+ const newAs = [groupKey, loader.as].join("__");
348
+ return {
349
+ as: newAs,
350
+ table: loader.table,
351
+ manyJoin: loader.manyJoin,
352
+ oneJoins: loader.oneJoins,
353
+ select: loader.select,
354
+ loaders: loader.loaders
355
+ };
356
+ });
357
+ r.loaders = [...r.loaders, ...convertedLoaders];
358
+ }
359
+ r.joins = r.joins.concat(relSubsetQuery.joins);
360
+ } else if (isHasManyRelationProp(relation) || isManyToManyRelationProp(relation)) {
361
+ const relFields = fields$1.map((field) => field.split(".").slice(1).join("."));
362
+ const relSubsetQuery = relEntity.resolveSubsetQuery("", relFields);
363
+ let manyJoin;
364
+ if (isHasManyRelationProp(relation)) {
365
+ const fromCol = relation?.fromColumn ?? "id";
366
+ manyJoin = {
367
+ fromTable: this.table,
368
+ fromCol,
369
+ idField: prefix === "" ? `${fromCol}` : `${prefix}__${fromCol}`,
370
+ toTable: relEntity.table,
371
+ toCol: relation.joinColumn
372
+ };
373
+ } else if (isManyToManyRelationProp(relation)) {
374
+ manyJoin = {
375
+ fromTable: this.table,
376
+ fromCol: "id",
377
+ idField: prefix === "" ? `id` : `${prefix}__id`,
378
+ through: {
379
+ table: relation.joinTable,
380
+ fromCol: `${inflection.singularize(this.table)}_id`,
381
+ toCol: `${inflection.singularize(relEntity.table)}_id`
382
+ },
383
+ toTable: relEntity.table,
384
+ toCol: "id"
385
+ };
386
+ } else {
387
+ throw new Error();
388
+ }
389
+ r.loaders.push({
390
+ as: groupKey,
391
+ table: relEntity.table,
392
+ manyJoin,
393
+ oneJoins: relSubsetQuery.joins,
394
+ select: relSubsetQuery.select,
395
+ loaders: relSubsetQuery.loaders
396
+ });
397
+ }
398
+ return r;
399
+ }, {
400
+ select: [],
401
+ virtual: [],
402
+ joins: [],
403
+ loaders: []
404
+ });
405
+ return result;
406
+ }
407
+ fieldExprsToPropNodes(fieldExprs, entity = this) {
408
+ const groups = fieldExprs.reduce((result, fieldExpr) => {
409
+ let key, value, elseExpr;
410
+ if (fieldExpr.includes(".")) {
411
+ [key, ...elseExpr] = fieldExpr.split(".");
412
+ value = elseExpr.join(".");
413
+ } else {
414
+ key = "";
415
+ value = fieldExpr;
416
+ }
417
+ result[key] = (result[key] ?? []).concat(value);
418
+ return result;
419
+ }, {});
420
+ return Object.keys(groups).flatMap((key) => {
421
+ const group$1 = groups[key];
422
+ if (key === "") {
423
+ return group$1.map((propName) => {
424
+ const prop$1 = entity.props.find((p) => p.name === propName);
425
+ if (prop$1 === undefined) {
426
+ throw new Error(`${entity.id} -- 잘못된 FieldExpr '${propName}' (사용 가능한 props: ${entity.props.map((p) => p.name).join(", ")})`);
427
+ }
428
+ return {
429
+ nodeType: "plain",
430
+ prop: prop$1
431
+ };
432
+ });
433
+ }
434
+ const prop = entity.propsDict[key];
435
+ if (!isRelationProp(prop)) {
436
+ throw new Error(`잘못된 FieldExpr ${key}.${group$1[0]}`);
437
+ }
438
+ const relEntity = EntityManager.get(prop.with);
439
+ if (isBelongsToOneRelationProp(prop) || isOneToOneRelationProp(prop)) {
440
+ if (group$1.length === 1 && (group$1[0] === "id" || group$1[0] === "id?")) {
441
+ const idProp = relEntity.propsDict.id;
442
+ return {
443
+ nodeType: "plain",
444
+ prop: {
445
+ ...idProp,
446
+ name: `${key}_id`,
447
+ nullable: prop.nullable
448
+ }
449
+ };
450
+ }
451
+ }
452
+ const children = this.fieldExprsToPropNodes(group$1, relEntity);
453
+ const nodeType = isBelongsToOneRelationProp(prop) || isOneToOneRelationProp(prop) ? "object" : "array";
454
+ return {
455
+ nodeType,
456
+ prop,
457
+ children
458
+ };
459
+ });
460
+ }
461
+ getFieldExprs(prefix = "", maxDepth = 3, froms = []) {
462
+ return this.props.flatMap((prop) => {
463
+ const propName = [prefix, prop.name].filter((v) => v !== "").join(".");
464
+ if (propName === prefix) {
465
+ return null;
466
+ }
467
+ if (isRelationProp(prop)) {
468
+ if (maxDepth < 0) {
469
+ return null;
470
+ }
471
+ if (froms.includes(prop.with)) {
472
+ return null;
473
+ }
474
+ const relMd = EntityManager.get(prop.with);
475
+ return relMd.getFieldExprs(propName, maxDepth - 1, [...froms, this.id]);
476
+ }
477
+ return propName;
478
+ }).filter((f) => f !== null);
479
+ }
480
+ /**
481
+ * Relation prop이 현재 테이블에 FK 컬럼을 생성하는지 확인
482
+ *(BelongsToOne 또는 OneToOne(hasJoinColumn=true)인 경우 FK 생성)
483
+ */
484
+ hasForeignKey(prop) {
485
+ return prop.relationType === "BelongsToOne" || prop.relationType === "OneToOne" && prop.hasJoinColumn;
486
+ }
487
+ getTableColumns() {
488
+ return this.props.map((prop) => {
489
+ if (prop.type === "relation") {
490
+ if (this.hasForeignKey(prop)) {
491
+ return {
492
+ name: `${prop.name}_id`,
493
+ type: "int_unsigned"
494
+ };
495
+ } else {
496
+ return null;
497
+ }
498
+ }
499
+ return {
500
+ name: prop.name,
501
+ type: prop.type
502
+ };
503
+ }).filter(nonNullable);
504
+ }
505
+ /**
506
+ * Entity에 정의된 모든 vector 타입 컬럼 반환
507
+ */
508
+ getVectorColumns() {
509
+ return this.props.filter((p) => p.type === "vector");
510
+ }
511
+ /**
512
+ * 특정 vector 컬럼 반환
513
+ * @param columnName - 컬럼명 (생략 번째 vector 컬럼)
514
+ */
515
+ getVectorColumn(columnName) {
516
+ const vectorProps = this.getVectorColumns();
517
+ if (columnName) {
518
+ return vectorProps.find((p) => p.name === columnName);
519
+ }
520
+ return vectorProps[0];
521
+ }
522
+ /**
523
+ * 필터링 가능한 props 반환
524
+ *
525
+ * - 일반 prop
526
+ * - FK를 생성하는 relation (BelongsToOne, OneToOne with hasJoinColumn)
527
+ * → {name}_id 형태의 가상 integer prop으로 변환
528
+ */
529
+ getFilterableProps() {
530
+ return this.props.flatMap((prop) => {
531
+ if (isVirtualProp(prop)) {
532
+ return [];
533
+ }
534
+ if (isRelationProp(prop)) {
535
+ if (this.hasForeignKey(prop)) {
536
+ return {
537
+ name: `${prop.name}_id`,
538
+ type: "integer",
539
+ nullable: prop.nullable
540
+ };
541
+ }
542
+ return [];
543
+ }
544
+ return prop;
545
+ });
546
+ }
547
+ async registerModulePaths() {
548
+ const basePath = `${this.names.parentFs}`;
549
+ EntityManager.setModulePath(`${this.id}BaseSchema`, `sonamu.generated`);
550
+ if (Object.keys(this.subsets).length > 0) {
551
+ EntityManager.setModulePath(`${this.id}SubsetKey`, `sonamu.generated`);
552
+ EntityManager.setModulePath(`${this.id}SubsetMapping`, `sonamu.generated`);
553
+ for (const subsetKey of Object.keys(this.subsets)) {
554
+ EntityManager.setModulePath(`${this.id}Subset${subsetKey.toUpperCase()}`, `sonamu.generated`);
555
+ }
556
+ }
557
+ for (const enumId of Object.keys(this.enumLabels)) {
558
+ EntityManager.setModulePath(enumId, `sonamu.generated`);
559
+ }
560
+ const typesModulePath = `${basePath}/${this.names.parentFs}.types`;
561
+ const typesFilePath = path.join(Sonamu.apiRootPath, runtimePath(`dist/application/${typesModulePath}.js`));
562
+ if (await exists(typesFilePath)) {
563
+ const importedMembers = await importMembers(typesFilePath);
564
+ this.types = Object.fromEntries(importedMembers.map(({ name, value }) => {
565
+ EntityManager.setModulePath(name, typesModulePath);
566
+ return [name, value];
567
+ }));
568
+ }
569
+ }
570
+ registerTableSpecs() {
571
+ const uniqueIndexes = this.indexes.filter((idx) => idx.type === "unique").filter((idx) => idx.columns.every((col) => !col.name.includes(".")));
572
+ EntityManager.setTableSpec({
573
+ name: this.table,
574
+ uniqueIndexes,
575
+ jsonColumns: this.props.filter((p) => p.type === "json").map((p) => p.name)
576
+ });
577
+ }
578
+ toJson() {
579
+ const subsets = {};
580
+ for (const key of Object.keys(this.subsets)) {
581
+ const normalFields = this.subsets[key];
582
+ const internalFields = (this.subsetsInternal[key] ?? []).map((field) => ({
583
+ field,
584
+ internal: true
585
+ }));
586
+ const fields = [...normalFields, ...internalFields];
587
+ if (this.subsetCones[key]) {
588
+ subsets[key] = {
589
+ fields,
590
+ cone: this.subsetCones[key]
591
+ };
592
+ } else {
593
+ subsets[key] = fields;
594
+ }
595
+ }
596
+ const enums = {};
597
+ for (const [key, values] of Object.entries(this.enumLabels)) {
598
+ if (this.enumCones[key]) {
599
+ enums[key] = {
600
+ values,
601
+ cone: this.enumCones[key]
602
+ };
603
+ } else {
604
+ enums[key] = values;
605
+ }
606
+ }
607
+ return {
608
+ id: this.id,
609
+ parentId: this.parentId,
610
+ table: this.table,
611
+ title: this.title,
612
+ cone: this.cone,
613
+ props: this.props,
614
+ indexes: this.indexes,
615
+ subsets,
616
+ enums
617
+ };
618
+ }
619
+ async save() {
620
+ const subsetRows = this.getSubsetRows();
621
+ this.subsets = Object.fromEntries(Object.entries(this.subsets).map(([subsetKey]) => {
622
+ return [subsetKey, this.subsetRowsToSubsetFields(subsetRows, subsetKey, false)];
623
+ }));
624
+ this.subsetsInternal = Object.fromEntries(Object.entries(this.subsetsInternal).map(([subsetKey]) => {
625
+ return [subsetKey, this.subsetRowsToSubsetFields(subsetRows, subsetKey, true)];
626
+ }));
627
+ const jsonPath = path.join(Sonamu.apiRootPath, `src/application/${this.names.parentFs}/${this.names.fs}.entity.json`);
628
+ const json = this.toJson();
629
+ await writeFile(jsonPath, await formatCode(JSON.stringify(json), "json", jsonPath));
630
+ await EntityManager.register(json);
631
+ }
632
+ /**
633
+ * 템플릿 cone 메타데이터를 생성합니다.
634
+ *
635
+ * LLM을 사용하지 않고 faker-mappings.ts를 활용하여 기본 cone을 생성합니다.
636
+ * stub entity 생성 시 자동으로 호출되어 최소한의 cone 메타데이터를 제공합니다.
637
+ *
638
+ * @param locale - 생성 시 사용할 locale (기본값: Sonamu.config.i18n.defaultLocale 또는 "ko")
639
+ */
640
+ async generateTemplateCones(locale) {
641
+ const { generateTemplateCones } = await import("./entity-template-cone.js");
642
+ const configLocale = Sonamu.config.i18n?.defaultLocale;
643
+ const effectiveLocale = locale || (configLocale === "ko" || configLocale === "en" || configLocale === "ja" ? configLocale : "ko");
644
+ const result = generateTemplateCones(this.toJson(), effectiveLocale);
645
+ if (result.entityCone) {
646
+ this.cone = result.entityCone;
647
+ }
648
+ for (const [propName, cone] of Object.entries(result.propCones)) {
649
+ const prop = this.props.find((p) => p.name === propName);
650
+ if (prop) {
651
+ prop.cone = cone;
652
+ }
653
+ }
654
+ this.enumCones = {
655
+ ...this.enumCones,
656
+ ...result.enumCones
657
+ };
658
+ this.subsetCones = {
659
+ ...this.subsetCones,
660
+ ...result.subsetCones
661
+ };
662
+ await this.save();
663
+ }
664
+ /**
665
+ * LLM을 사용하여 cone 메타데이터를 생성합니다.
666
+ *
667
+ * @param options.preserveExisting - 기존 cone 보존 여부 (기본값: true)
668
+ * @param options.onlyEmpty - fixtureHint가 없는 cone만 생성 (기본값: false)
669
+ * @param options.locale - 생성 시 사용할 locale (기본값: "ko")
670
+ */
671
+ async generateCones(options) {
672
+ const { generateCones } = await import("../cone/cone-generator.js");
673
+ const context = {
674
+ entity: this.toJson(),
675
+ locale: options?.locale || "ko",
676
+ existingCones: options?.preserveExisting !== false ? this.collectExistingCones() : undefined,
677
+ onlyEmpty: options?.onlyEmpty ?? false
678
+ };
679
+ const result = await generateCones(context);
680
+ this.applyCones(result);
681
+ await this.save();
682
+ return result;
683
+ }
684
+ /**
685
+ * 기존 cone들을 수집합니다 (entity, props, enums, subsets).
686
+ *
687
+ * @returns 키가 "entity:id", "prop:name", "enum:enumId", "subset:key" 형식인 cone 맵
688
+ */
689
+ collectExistingCones() {
690
+ const cones = {};
691
+ if (this.cone) {
692
+ cones[`entity:${this.id}`] = this.cone;
693
+ }
694
+ for (const prop of this.props) {
695
+ if (prop.cone) {
696
+ cones[`prop:${prop.name}`] = prop.cone;
697
+ }
698
+ }
699
+ for (const [enumId, cone] of Object.entries(this.enumCones)) {
700
+ cones[`enum:${enumId}`] = cone;
701
+ }
702
+ for (const [subsetKey, cone] of Object.entries(this.subsetCones)) {
703
+ cones[`subset:${subsetKey}`] = cone;
704
+ }
705
+ return cones;
706
+ }
707
+ /**
708
+ * 생성된 cone들을 Entity에 적용합니다.
709
+ *
710
+ * @param result - LLM으로 생성된 cone 결과
711
+ */
712
+ applyCones(result) {
713
+ if (result.entityCone) {
714
+ this.cone = result.entityCone;
715
+ }
716
+ for (const [propName, cone] of Object.entries(result.propCones)) {
717
+ const prop = this.props.find((p) => p.name === propName);
718
+ if (prop) {
719
+ prop.cone = cone;
720
+ }
721
+ }
722
+ this.enumCones = {
723
+ ...this.enumCones,
724
+ ...result.enumCones
725
+ };
726
+ this.subsetCones = {
727
+ ...this.subsetCones,
728
+ ...result.subsetCones
729
+ };
730
+ }
731
+ getSubsetRows(_subsets, _subsetsInternal, prefixes = []) {
732
+ if (prefixes.length > 10) {
733
+ return [];
734
+ }
735
+ const subsets = _subsets ?? this.subsets;
736
+ const subsetsInternal = _subsetsInternal ?? this.subsetsInternal;
737
+ const subsetKeys = Object.keys(subsets);
738
+ const allFields = unique(subsetKeys.flatMap((key) => subsets[key]));
739
+ const allInternalFields = unique(subsetKeys.flatMap((key) => subsetsInternal[key] ?? []));
740
+ const combinedFields = unique([...allFields, ...allInternalFields]);
741
+ return this.props.map((prop) => {
742
+ if (prop.type === "relation" && combinedFields.find((f) => f.startsWith(`${[...prefixes, prop.name].join(".")}.`))) {
743
+ const relEntity = EntityManager.get(prop.with);
744
+ const children = relEntity.getSubsetRows(subsets, subsetsInternal, [...prefixes, `${prop.name}`]);
745
+ return {
746
+ field: prop.name,
747
+ children,
748
+ relationEntity: prop.with,
749
+ prefixes,
750
+ isOpen: children.length > 0,
751
+ has: Object.fromEntries(subsetKeys.map((subsetKey) => {
752
+ return [subsetKey, children.every((child) => child.has[subsetKey])];
753
+ })),
754
+ isInternal: Object.fromEntries(subsetKeys.map((subsetKey) => {
755
+ return [subsetKey, children.every((child) => child.isInternal[subsetKey])];
756
+ }))
757
+ };
758
+ }
759
+ const field = [...prefixes, prop.name].join(".");
760
+ return {
761
+ field: prop.name,
762
+ children: [],
763
+ relationEntity: prop.type === "relation" ? prop.with : undefined,
764
+ prefixes,
765
+ has: Object.fromEntries(subsetKeys.map((subsetKey) => {
766
+ const subsetFields = subsets[subsetKey];
767
+ const has = subsetFields.some((f) => {
768
+ return f === field || f.startsWith(`${field}.`);
769
+ });
770
+ return [subsetKey, has];
771
+ })),
772
+ isInternal: Object.fromEntries(subsetKeys.map((subsetKey) => {
773
+ const internalFields = subsetsInternal[subsetKey] ?? [];
774
+ const isInternal = internalFields.some((f) => {
775
+ return f === field || f.startsWith(`${field}.`);
776
+ });
777
+ return [subsetKey, isInternal];
778
+ }))
779
+ };
780
+ });
781
+ }
782
+ subsetRowsToSubsetFields(subsetRows, subsetKey, internal = false) {
783
+ const hasKey = internal ? "isInternal" : "has";
784
+ return subsetRows.map((subsetRow) => {
785
+ if (subsetRow.children.length > 0) {
786
+ return this.subsetRowsToSubsetFields(subsetRow.children, subsetKey, internal);
787
+ } else if (subsetRow[hasKey][subsetKey]) {
788
+ return subsetRow.prefixes.concat(subsetRow.field).join(".");
789
+ } else {
790
+ return null;
791
+ }
792
+ }).filter(nonNullable).flat();
793
+ }
794
+ async createProp(prop, at) {
795
+ if (!at) {
796
+ this.props.push(prop);
797
+ } else {
798
+ this.props.splice(at, 0, prop);
799
+ }
800
+ await this.save();
801
+ }
802
+ analyzeSubsetField(subsetField) {
803
+ const arr = subsetField.split(".");
804
+ let entityId = this.id;
805
+ const result = [];
806
+ for (let i = 0; i < arr.length; i++) {
807
+ const propName = arr[i];
808
+ result.push({
809
+ entityId,
810
+ propName
811
+ });
812
+ const prop = EntityManager.get(entityId).props.find((p) => p.name === propName);
813
+ if (!prop) {
814
+ throw new Error(`${entityId}의 잘못된 서브셋키 ${subsetField}`);
815
+ }
816
+ if (isRelationProp(prop)) {
817
+ entityId = prop.with;
818
+ }
819
+ }
820
+ return result;
821
+ }
822
+ async modifyProp(newProp, at) {
823
+ const oldName = this.props[at].name;
824
+ const entities = [this];
825
+ if (oldName !== newProp.name) {
826
+ const allEntityIds = EntityManager.getAllIds();
827
+ for (const relEntityId of allEntityIds) {
828
+ const relEntity = EntityManager.get(relEntityId);
829
+ const relEntitySubsetKeys = Object.keys(relEntity.subsets);
830
+ for (const subsetKey of relEntitySubsetKeys) {
831
+ const subset = relEntity.subsets[subsetKey];
832
+ const modifiedSubsetFields = subset.map((subsetField) => {
833
+ const analyzed = relEntity.analyzeSubsetField(subsetField);
834
+ const modified = analyzed.map((a) => a.propName === oldName && a.entityId === this.id ? {
835
+ ...a,
836
+ propName: newProp.name
837
+ } : a);
838
+ return modified.map((a) => a.propName).join(".");
839
+ });
840
+ if (subset.join(",") !== modifiedSubsetFields.join(",")) {
841
+ relEntity.subsets[subsetKey] = modifiedSubsetFields;
842
+ entities.push(relEntity);
843
+ }
844
+ }
845
+ }
846
+ }
847
+ this.props[at] = newProp;
848
+ await Promise.all(entities.map(async (entity) => entity.save()));
849
+ }
850
+ async delProp(at) {
851
+ const oldName = this.props[at].name;
852
+ const entities = [this];
853
+ const allEntityIds = EntityManager.getAllIds();
854
+ for (const relEntityId of allEntityIds) {
855
+ const relEntity = EntityManager.get(relEntityId);
856
+ const relEntitySubsetKeys = Object.keys(relEntity.subsets);
857
+ for (const subsetKey of relEntitySubsetKeys) {
858
+ const subset = relEntity.subsets[subsetKey];
859
+ const modifiedSubsetFields = subset.map((subsetField) => {
860
+ const analyzed = relEntity.analyzeSubsetField(subsetField);
861
+ if (analyzed.find((a) => a.propName === oldName && a.entityId === this.id)) {
862
+ return null;
863
+ } else {
864
+ return subsetField;
865
+ }
866
+ }).filter(nonNullable);
867
+ if (subset.join(",") !== modifiedSubsetFields.join(",")) {
868
+ relEntity.subsets[subsetKey] = modifiedSubsetFields;
869
+ entities.push(relEntity);
870
+ }
871
+ }
872
+ }
873
+ for (const index of EntityManager.get(this.id).indexes) {
874
+ index.columns = index.columns.filter((col) => col.name !== oldName);
875
+ }
876
+ this.props.splice(at, 1);
877
+ await Promise.all(entities.map(async (entity) => entity.save()));
878
+ }
879
+ getEntityIdFromSubsetField(subsetField) {
880
+ if (!subsetField.includes(".")) {
881
+ return this.id;
882
+ }
883
+ const arr = subsetField.split(".").slice(0, -1);
884
+ const lastEntityId = arr.reduce((entityId, field) => {
885
+ const relProp = EntityManager.get(entityId).props.find((p) => p.name === field);
886
+ if (!relProp || relProp.type !== "relation") {
887
+ console.debug({
888
+ arr,
889
+ thisId: this.id,
890
+ entityId,
891
+ field
892
+ });
893
+ throw new Error(`잘못된 서브셋키 ${subsetField}`);
894
+ }
895
+ return relProp.with;
896
+ }, this.id);
897
+ return lastEntityId;
898
+ }
899
+ async moveProp(at, to) {
900
+ const prop = this.props[at];
901
+ const newProps = [...this.props];
902
+ newProps.splice(to, 0, prop);
903
+ newProps.splice(at < to ? at : at + 1, 1);
904
+ this.props = newProps;
905
+ await this.save();
906
+ }
907
+ /**
908
+ * 필드명을 "테이블명.필드명" 형식으로 변환
909
+ */
910
+ getFullFieldName(field) {
911
+ if (field.includes(".")) {
912
+ return field;
913
+ }
914
+ return `${this.table}.${field}`;
915
+ }
916
+ /**
917
+ * 엔티티의 PK 타입을 반환합니다.
918
+ * id 필드의 타입을 기준으로 "integer" | "string" | "uuid"를 반환합니다.
919
+ */
920
+ getPkType() {
921
+ const idProp = this.propsDict.id;
922
+ if (!idProp) {
923
+ throw new Error(`Entity ${this.id}에 id 필드가 없습니다`);
924
+ }
925
+ if (idProp.type === "string" || idProp.type === "uuid") {
926
+ return idProp.type;
927
+ }
928
+ return "integer";
929
+ }
930
+ /**
931
+ * 엔티티의 PK prop을 반환합니다.
932
+ * length 등 세부 정보에 접근할 때 사용합니다.
933
+ */
934
+ getPkProp() {
935
+ const idProp = this.propsDict.id;
936
+ if (!idProp) {
937
+ throw new Error(`Entity ${this.id}에 id 필드가 없습니다`);
938
+ }
939
+ return idProp;
940
+ }
941
+ /**
942
+ * 엔티티의 PK 배열 타입을 반환합니다.
943
+ * LoaderQuery의 fromIds 타입으로 사용됩니다.
944
+ */
945
+ getPkArrayType() {
946
+ const pkType = this.getPkType();
947
+ return pkType === "integer" ? "number[]" : "string[]";
948
+ }
949
+ };
950
+ }));
1091
951
 
1092
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9lbnRpdHkvZW50aXR5LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuaW1wb3J0IHsgd3JpdGVGaWxlIH0gZnJvbSBcImZzL3Byb21pc2VzXCI7XG5pbXBvcnQgaW5mbGVjdGlvbiBmcm9tIFwiaW5mbGVjdGlvblwiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IGdyb3VwLCB1bmlxdWUgfSBmcm9tIFwicmFkYXNoaVwiO1xuaW1wb3J0IHsgeiB9IGZyb20gXCJ6b2RcIjtcbmltcG9ydCB7IFNvbmFtdSB9IGZyb20gXCIuLi9hcGkvc29uYW11XCI7XG5pbXBvcnQge1xuICB0eXBlIENvbmUsXG4gIHR5cGUgRW50aXR5SW5kZXgsXG4gIHR5cGUgRW50aXR5SnNvbixcbiAgdHlwZSBFbnRpdHlQcm9wLFxuICB0eXBlIEVudGl0eVByb3BOb2RlLFxuICB0eXBlIEVudGl0eVN1YnNldFJvdyxcbiAgZ2V0RW51bURlZlZhbHVlcyxcbiAgZ2V0U3Vic2V0RmllbGRzLFxuICBpc0JlbG9uZ3NUb09uZVJlbGF0aW9uUHJvcCxcbiAgaXNFbnVtUHJvcCxcbiAgaXNIYXNNYW55UmVsYXRpb25Qcm9wLFxuICBpc0ludGVybmFsU3Vic2V0RmllbGQsXG4gIGlzTWFueVRvTWFueVJlbGF0aW9uUHJvcCxcbiAgaXNPbmVUb09uZVJlbGF0aW9uUHJvcCxcbiAgaXNSZWxhdGlvblByb3AsXG4gIGlzVmlydHVhbENvZGVQcm9wLFxuICBpc1ZpcnR1YWxQcm9wLFxuICBub3JtYWxpemVTdWJzZXRGaWVsZCxcbiAgdHlwZSBSZWxhdGlvblByb3AsXG4gIHR5cGUgU3Vic2V0RmllbGQsXG4gIHR5cGUgU3Vic2V0UXVlcnksXG59IGZyb20gXCIuLi90eXBlcy90eXBlc1wiO1xuaW1wb3J0IHsgaW1wb3J0TWVtYmVycyB9IGZyb20gXCIuLi91dGlscy9lc20tdXRpbHNcIjtcbmltcG9ydCB7IGZvcm1hdENvZGUgfSBmcm9tIFwiLi4vdXRpbHMvZm9ybWF0dGVyXCI7XG5pbXBvcnQgeyBleGlzdHMgfSBmcm9tIFwiLi4vdXRpbHMvZnMtdXRpbHNcIjtcbmltcG9ydCB7IHJ1bnRpbWVQYXRoIH0gZnJvbSBcIi4uL3V0aWxzL3BhdGgtdXRpbHNcIjtcbmltcG9ydCB7IGFzc2VydERlZmluZWQsIG5vbk51bGxhYmxlIH0gZnJvbSBcIi4uL3V0aWxzL3V0aWxzXCI7XG5pbXBvcnQgeyBFbnRpdHlNYW5hZ2VyIH0gZnJvbSBcIi4vZW50aXR5LW1hbmFnZXJcIjtcblxuZXhwb3J0IGNsYXNzIEVudGl0eSB7XG4gIGlkOiBzdHJpbmc7XG4gIHBhcmVudElkPzogc3RyaW5nO1xuICB0YWJsZTogc3RyaW5nO1xuICB0aXRsZTogc3RyaW5nO1xuICBjb25lPzogQ29uZTtcbiAgbmFtZXM6IHtcbiAgICBwYXJlbnRGczogc3RyaW5nO1xuICAgIGZzOiBzdHJpbmc7XG4gICAgbW9kdWxlOiBzdHJpbmc7XG4gIH07XG4gIHByb3BzOiBFbnRpdHlQcm9wW107XG4gIHByb3BzRGljdDoge1xuICAgIFtrZXk6IHN0cmluZ106IEVudGl0eVByb3A7XG4gIH07XG4gIHJlbGF0aW9uczoge1xuICAgIFtrZXk6IHN0cmluZ106IFJlbGF0aW9uUHJvcDtcbiAgfTtcbiAgaW5kZXhlczogRW50aXR5SW5kZXhbXTtcbiAgc3Vic2V0czoge1xuICAgIFtrZXk6IHN0cmluZ106IHN0cmluZ1tdO1xuICB9O1xuICBzdWJzZXRzSW50ZXJuYWw6IHtcbiAgICBba2V5OiBzdHJpbmddOiBzdHJpbmdbXTtcbiAgfTtcbiAgdHlwZXM6IHtcbiAgICBbbmFtZTogc3RyaW5nXTogei5ab2RUeXBlQW55O1xuICB9ID0ge307XG4gIGVudW1zOiB7XG4gICAgW2VudW1JZDogc3RyaW5nXTogei5ab2RFbnVtPFJlYWRvbmx5PFJlY29yZDxzdHJpbmcsIHN0cmluZz4+PjtcbiAgfSA9IHt9O1xuICBlbnVtTGFiZWxzOiB7XG4gICAgW2VudW1JZDogc3RyaW5nXToge1xuICAgICAgW2tleTogc3RyaW5nXTogc3RyaW5nO1xuICAgIH07XG4gIH0gPSB7fTtcbiAgZW51bUNvbmVzOiB7XG4gICAgW2VudW1JZDogc3RyaW5nXTogQ29uZTtcbiAgfSA9IHt9O1xuICBzdWJzZXRDb25lczoge1xuICAgIFtzdWJzZXRLZXk6IHN0cmluZ106IENvbmU7XG4gIH0gPSB7fTtcblxuICBjb25zdHJ1Y3Rvcih7IGlkLCBwYXJlbnRJZCwgdGFibGUsIHRpdGxlLCBjb25lLCBwcm9wcywgaW5kZXhlcywgc3Vic2V0cywgZW51bXMgfTogRW50aXR5SnNvbikge1xuICAgIC8vIGlkXG4gICAgdGhpcy5pZCA9IGlkO1xuICAgIHRoaXMucGFyZW50SWQgPSBwYXJlbnRJZDtcbiAgICB0aGlzLnRpdGxlID0gdGl0bGUgPz8gdGhpcy5pZDtcbiAgICB0aGlzLnRhYmxlID0gdGFibGUgPz8gaW5mbGVjdGlvbi51bmRlcnNjb3JlKGluZmxlY3Rpb24ucGx1cmFsaXplKGlkKSk7XG4gICAgdGhpcy5jb25lID0gY29uZTtcblxuICAgIC8vIHByb3BzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICB0aGlzLnByb3BzID0gcHJvcHMubWFwKChwcm9wKSA9PiB7XG4gICAgICAgIGlmIChpc0VudW1Qcm9wKHByb3ApKSB7XG4gICAgICAgICAgaWYgKHByb3AuaWQuaW5jbHVkZXMoXCIkTW9kZWxcIikpIHtcbiAgICAgICAgICAgIHByb3AuaWQgPSBwcm9wLmlkLnJlcGxhY2UoXCIkTW9kZWxcIiwgaWQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcHJvcDtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5wcm9wc0RpY3QgPSBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgICAgIHByb3BzLm1hcCgocHJvcCkgPT4ge1xuICAgICAgICAgIHJldHVybiBbcHJvcC5uYW1lLCBwcm9wXTtcbiAgICAgICAgfSksXG4gICAgICApO1xuXG4gICAgICAvLyByZWxhdGlvbnNcbiAgICAgIHRoaXMucmVsYXRpb25zID0gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgICBwcm9wcy5maWx0ZXIoKHByb3ApID0+IGlzUmVsYXRpb25Qcm9wKHByb3ApKS5tYXAoKHByb3ApID0+IFtwcm9wLm5hbWUsIHByb3BdKSxcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMucHJvcHMgPSBbXTtcbiAgICAgIHRoaXMucHJvcHNEaWN0ID0ge307XG4gICAgICB0aGlzLnJlbGF0aW9ucyA9IHt9O1xuICAgIH1cblxuICAgIC8vIGluZGV4ZXNcbiAgICB0aGlzLmluZGV4ZXMgPSBpbmRleGVzID8/IFtdO1xuXG4gICAgLy8gc3Vic2V0czogU3Vic2V0RGVm7JeQ7IScIFN1YnNldEZpZWxkW13rpbwg7LaU7Lac7ZWY7JesIHN1YnNldHMo7J2867CYKeyZgCBzdWJzZXRzSW50ZXJuYWwoaW50ZXJuYWwp66GcIOu2hOumrFxuICAgIHRoaXMuc3Vic2V0cyA9IHt9O1xuICAgIHRoaXMuc3Vic2V0c0ludGVybmFsID0ge307XG4gICAgZm9yIChjb25zdCBba2V5LCBzdWJzZXREZWZdIG9mIE9iamVjdC5lbnRyaWVzKHN1YnNldHMgPz8ge30pKSB7XG4gICAgICBjb25zdCBmaWVsZHMgPSBnZXRTdWJzZXRGaWVsZHMoc3Vic2V0RGVmKTtcbiAgICAgIHRoaXMuc3Vic2V0c1trZXldID0gZmllbGRzLmZpbHRlcigoZikgPT4gIWlzSW50ZXJuYWxTdWJzZXRGaWVsZChmKSkubWFwKG5vcm1hbGl6ZVN1YnNldEZpZWxkKTtcbiAgICAgIHRoaXMuc3Vic2V0c0ludGVybmFsW2tleV0gPSBmaWVsZHMuZmlsdGVyKGlzSW50ZXJuYWxTdWJzZXRGaWVsZCkubWFwKG5vcm1hbGl6ZVN1YnNldEZpZWxkKTtcblxuICAgICAgLy8gY29uZSDstpTstpxcbiAgICAgIGlmICghQXJyYXkuaXNBcnJheShzdWJzZXREZWYpICYmIFwiY29uZVwiIGluIHN1YnNldERlZiAmJiBzdWJzZXREZWYuY29uZSkge1xuICAgICAgICB0aGlzLnN1YnNldENvbmVzW2tleV0gPSBzdWJzZXREZWYuY29uZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBlbnVtczogRW51bURlZuyXkOyEnCB2YWx1ZXPsmYAgY29uZeulvCDstpTstpztlZjsl6wg7LKY66asXG4gICAgdGhpcy5lbnVtTGFiZWxzID0gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgT2JqZWN0LmVudHJpZXMoZW51bXMgPz8ge30pLm1hcCgoW2tleSwgZW51bURlZl0pID0+IHtcbiAgICAgICAgLy8gY29uZSDstpTstpxcbiAgICAgICAgaWYgKFwidmFsdWVzXCIgaW4gZW51bURlZiAmJiBcImNvbmVcIiBpbiBlbnVtRGVmICYmIGVudW1EZWYuY29uZSkge1xuICAgICAgICAgIHRoaXMuZW51bUNvbmVzW2tleV0gPSBlbnVtRGVmLmNvbmUgYXMgQ29uZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gW2tleSwgZ2V0RW51bURlZlZhbHVlcyhlbnVtRGVmKV07XG4gICAgICB9KSxcbiAgICApO1xuICAgIHRoaXMuZW51bXMgPSBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgICBPYmplY3QuZW50cmllcyh0aGlzLmVudW1MYWJlbHMpLm1hcCgoW2tleSwgZW51bUxhYmVsXSkgPT4ge1xuICAgICAgICByZXR1cm4gW2tleSwgei5lbnVtKE9iamVjdC5rZXlzKGVudW1MYWJlbCkgYXMgdW5rbm93biBhcyByZWFkb25seSBbc3RyaW5nLCAuLi5zdHJpbmdbXV0pXTtcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICAvLyBuYW1lc1xuICAgIHRoaXMubmFtZXMgPSB7XG4gICAgICBwYXJlbnRGczogaW5mbGVjdGlvbi5kYXNoZXJpemUoaW5mbGVjdGlvbi51bmRlcnNjb3JlKHBhcmVudElkID8/IGlkKSkudG9Mb3dlckNhc2UoKSxcbiAgICAgIGZzOiBpbmZsZWN0aW9uLmRhc2hlcml6ZShpbmZsZWN0aW9uLnVuZGVyc2NvcmUoaWQpKS50b0xvd2VyQ2FzZSgpLFxuICAgICAgbW9kdWxlOiBpZCxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIOy/vOumrOyaqSDshJzruIzshYsg7ZWE65Oc66W8IOuwmO2ZmO2VqeuLiOuLpCAoc3Vic2V0cyArIHN1YnNldHNJbnRlcm5hbCDtlansuagpXG4gICAqL1xuICBnZXRTdWJzZXRGaWVsZHNGb3JRdWVyeShzdWJzZXRLZXk6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gWy4uLih0aGlzLnN1YnNldHNbc3Vic2V0S2V5XSA/PyBbXSksIC4uLih0aGlzLnN1YnNldHNJbnRlcm5hbFtzdWJzZXRLZXldID8/IFtdKV07XG4gIH1cblxuICAvKipcbiAgICog7KO87Ja07KeEIOydtOumhChzdWJzZXRLZXkp7J2YIHN1YnNldOydhCDsi6TsoJzroZwg6rCA7KC47Jik64qUIFB1cmkg7L2U65OcIOq1rO2YhOyytCBzdHJpbmfsnYQg67CY7ZmY7ZWp64uI64ukLlxuICAgKi9cbiAgZ2V0UHVyaVN1YnNldFF1ZXJ5KHN1YnNldEtleTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBzdWJzZXQgPSB0aGlzLmdldFN1YnNldEZpZWxkc0ZvclF1ZXJ5KHN1YnNldEtleSk7XG4gICAgY29uc3Qgc3Vic2V0UXVlcnkgPSB0aGlzLnJlc29sdmVTdWJzZXRRdWVyeShcIlwiLCBzdWJzZXQpO1xuXG4gICAgY29uc3QgbGluZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICAvLyBmcm9tXG4gICAgbGluZXMucHVzaChgcmV0dXJuIHFiV3JhcHBlcmApO1xuICAgIGxpbmVzLnB1c2goYC5mcm9tKFwiJHt0aGlzLnRhYmxlfVwiKWApO1xuXG4gICAgLy8gam9pblxuICAgIGZvciAoY29uc3Qgam9pbiBvZiBzdWJzZXRRdWVyeS5qb2lucykge1xuICAgICAgLy8gam9pbiDrqZTshJzrk5wg6rKw7KCVOiBpbm5lciDihpIgam9pbiwgb3V0ZXIg4oaSIGxlZnRKb2luXG4gICAgICAvLyBGSyBudWxsYWJsZSDsl6zrtoDripQgbGVmdEpvaW4g7YOA7J6FIOyLnOq3uOuLiOyymOyXkOyEnCDsnpDrj5nsnLzroZwg7YyQ64uo65CoXG4gICAgICBjb25zdCBqb2luTWV0aG9kID0gam9pbi5qb2luID09PSBcImlubmVyXCIgPyBcImpvaW5cIiA6IFwibGVmdEpvaW5cIjtcblxuICAgICAgaWYgKFwiY3VzdG9tXCIgaW4gam9pbikge1xuICAgICAgICAvLyBjdXN0b20gam9pbiBjbGF1c2XripQgcmF3IOyCrOyaqVxuICAgICAgICBsaW5lcy5wdXNoKFxuICAgICAgICAgIGAuJHtqb2luTWV0aG9kfSh7ICR7am9pbi5hc306IFwiJHtqb2luLnRhYmxlfVwiIH0sIHFiV3JhcHBlci5rbmV4LnJhdyhcXGAke2pvaW4uY3VzdG9tfVxcYCkpYCxcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxpbmVzLnB1c2goYC4ke2pvaW5NZXRob2R9KHsgJHtqb2luLmFzfTogXCIke2pvaW4udGFibGV9XCIgfSwgXCIke2pvaW4uZnJvbX1cIiwgXCIke2pvaW4udG99XCIpYCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gc2VsZWN0IC0g7J6F7LK07KCBIOq1rOyhsOuhnCDsg53shLFcbiAgICBjb25zdCBzZWxlY3RPYmogPSB0aGlzLmJ1aWxkTmVzdGVkU2VsZWN0T2JqZWN0KHN1YnNldFF1ZXJ5LnNlbGVjdCk7XG4gICAgbGluZXMucHVzaChgLnNlbGVjdCgke3RoaXMuc3RyaW5naWZ5TmVzdGVkU2VsZWN0T2JqZWN0KHNlbGVjdE9iail9KTtgKTtcblxuICAgIHJldHVybiBsaW5lcy5qb2luKFwiXFxuXCIpO1xuICB9XG5cbiAgLyoqXG4gICAqICouZW50aXR5Lmpzb27snZggc3Vic2V07JeQIOuTpOyWtOyeiOuKlCDtlYTrk5wg67Cw7Je07J2EIOuwm+yVhOyEnCxcbiAgICogUHVyaeydmCBTZWxlY3RPYmplY3Qg7YOA7J6F7Jy866GcIOuzgO2ZmO2VqeuLiOuLpC5cbiAgICpcbiAgICog7JiIOiBbXCJ1c2Vycy5pZFwiLCBcInBhcmVudC5pZFwiLCBcInBhcmVudC5uYW1lXCJdXG4gICAqICAg4oaSIHsgaWQ6IFwidXNlcnMuaWRcIiwgcGFyZW50OiB7IGlkOiBcInBhcmVudC5pZFwiLCBuYW1lOiBcInBhcmVudC5uYW1lXCIgfSB9XG4gICAqXG4gICAqIOyWuOuNlOuwlOqwgCDslYTri4wg7KSR7LKpIOqwneyytOuhnCDrs4DtmZjtlajsl5Ag7Jyg7J2Y7ZWY7IS47JqULlxuICAgKiDsnbTroIfqsowg7KSR7LKpIOqwneyytOuhnCDrs4DtmZjtlZjsl6wgc2VsZWN07JeQIOuEmOqyqOyjvOuptCBQYXJzZVNlbGVjdE9iamVjdCDtg4DsnoXsnbQgam9pbuuQnCDqsJ3ssrTsnZgg7YOA7J6F7J2EIOyemCDsnqHslYTspIQg7IiYIOyeiOyKteuLiOuLpC5cbiAgICog7KaJLCBlbmhhbmNlcuyXkOyEnCByb3frpbwg67Cb7JWY7J2EIOuVjCBoeWRyYXRl65CcIOqwneyytCDsnpDssrTsnZggbnVsbGl0eeyZgCDqt7gg7JWI7Kq9IO2VhOuTnOydmCBudWxsaXR56rCAIGZrIG51bGxhYmxlIOyXrOu2gOyXkCDrlLDrnbwg7J6YIOy2lOuhoOuQqeuLiOuLpC5cbiAgICovXG4gIHByaXZhdGUgYnVpbGROZXN0ZWRTZWxlY3RPYmplY3QoXG4gICAgc2VsZWN0SXRlbXM6IHN0cmluZ1tdLFxuICAgIC8vIGJpb21lLWlnbm9yZSBsaW50L3N1c3BpY2lvdXMvbm9FeHBsaWNpdEFueTog67CY7ZmYIOyYpOu4jOygne2KuOydmCDqsJLsnYAgc3RyaW5n7J28IOyImOuPhCDsnojqs6Ag65iQ64uk66W4IOyYpOu4jOygne2KuOydvCDsiJjrj4Qg7J6I64qU642wLCDsnbTrpbwg7J6s6reAIO2DgOyeheycvOuhnCDrgpjtg4Drgrwg7IiYIOyXhuyWtCBhbnnroZwg7LKY66as7ZWp64uI64ukLlxuICApOiBSZWNvcmQ8c3RyaW5nLCBhbnk+IHtcbiAgICBjb25zdCByZXN1bHQ6IFJldHVyblR5cGU8dHlwZW9mIHRoaXMuYnVpbGROZXN0ZWRTZWxlY3RPYmplY3Q+ID0ge307XG5cbiAgICBmb3IgKGNvbnN0IHNlbGVjdEl0ZW0gb2Ygc2VsZWN0SXRlbXMpIHtcbiAgICAgIC8vIFwidXNlcnMuaWRcIiDrmJDripQgXCJ1c2Vycy5pZCBhcyB1c2VyX19pZFwiIO2Yle2DnCDtjIzsi7FcbiAgICAgIGNvbnN0IG1hdGNoID0gc2VsZWN0SXRlbS5tYXRjaCgvXiguKz8pKD86IGFzICguKykpPyQvKTtcbiAgICAgIGlmICghbWF0Y2gpIGNvbnRpbnVlO1xuXG4gICAgICBjb25zdCBbLCBjb2x1bW4sIGFsaWFzXSA9IG1hdGNoO1xuICAgICAgY29uc3QgY29sdW1uVmFsdWUgPSBgXCIke2NvbHVtbi50cmltKCl9XCJgO1xuXG4gICAgICBpZiAoIWFsaWFzIHx8ICFhbGlhcy5pbmNsdWRlcyhcIl9fXCIpKSB7XG4gICAgICAgIC8vIGFsaWFz6rCAIOyXhuqxsOuCmCBfX+ulvCDtj6ztlajtlZjsp4Ag7JWK7Jy866m0IOy1nOyDgeychCDtlYTrk5xcbiAgICAgICAgY29uc3Qga2V5ID0gYWxpYXMgPz8gYXNzZXJ0RGVmaW5lZChjb2x1bW4uc3BsaXQoXCIuXCIpLnBvcCgpKTtcbiAgICAgICAgcmVzdWx0W2tleV0gPSBjb2x1bW5WYWx1ZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGFsaWFz6rCAIF9f66W8IO2PrO2VqO2VmOuptCDsnoXssrQg6rWs7KGw66GcIOq3uOujue2ZlFxuICAgICAgICBjb25zdCBwYXJ0cyA9IGFsaWFzLnNwbGl0KFwiX19cIik7XG4gICAgICAgIGxldCBjdXJyZW50ID0gcmVzdWx0O1xuXG4gICAgICAgIC8vIOuniOyngOuniSDtjIztirgg7KCE6rmM7KeAIOykkeyyqSDqsJ3ssrQg7IOd7ISxXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcGFydHMubGVuZ3RoIC0gMTsgaSsrKSB7XG4gICAgICAgICAgY29uc3QgcGFydCA9IHBhcnRzW2ldO1xuICAgICAgICAgIGlmIChwYXJ0IGluIGN1cnJlbnQpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgY3VycmVudFtwYXJ0XSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgICAvLyDsnoXroKXsnbQgW1widXNlclwiLCBcInVzZXJfX2lkXCJdIOqwmeydgCDqsr3smrAhXG4gICAgICAgICAgICAgIC8vIOyVoOy0iOyXkCDrp5Drj4Qg7JWIIOuQmOyngOunjCDslYjsoITtlZjqsowg7JiI7Jm466W8IOuNmOynkeuLiOuLpC5cbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgIGBDb25mbGljdCBkZXRlY3RlZCBpbiBzZWxlY3QgaXRlbXM6IHBhcmVudCBwYXRoIFwiJHtwYXJ0cy5zbGljZSgwLCBpICsgMSkuam9pbihcIl9fXCIpfVwiIGlzIGFscmVhZHkgc2V0IGFzIGEgZmllbGQsIGNhbm5vdCBuZXN0IFwiJHthbGlhc31cIiB1bmRlciBpdC5gLFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjdXJyZW50W3BhcnRdID0ge307XG4gICAgICAgICAgfVxuICAgICAgICAgIGN1cnJlbnQgPSBjdXJyZW50W3BhcnRdO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8g66eI7KeA66eJIO2MjO2KuOyXkCDqsJIg7ISk7KCVXG4gICAgICAgIGNvbnN0IGxhc3RQYXJ0ID0gcGFydHNbcGFydHMubGVuZ3RoIC0gMV07XG4gICAgICAgIGN1cnJlbnRbbGFzdFBhcnRdID0gY29sdW1uVmFsdWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBKU09OLnN0cmluZ2lmeeyZgCDsnKDsgqztlZwg7J287J2EIO2VqeuLiOuLpC5cbiAgICog64uk66eMIOyjvOyWtOynhCDqsJ3ssrTrpbwgSlNPTuydtCDslYTri4wgVHlwZVNjcmlwdCDqsJ3ssrQg66as7YSw65+0IOyKpO2KuOungeycvOuhnCDrp4zrk6TslrTspI3ri4jri6QuXG4gICAqIGtleeyXkCDrlLDsmLTtkZzqsIAg7JeG7Ja07JqULlxuICAgKiDstpzroKUg7JiI7IucOlxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIHtcbiAgICogICBpZDogXCJ1c2Vycy5pZFwiLFxuICAgKiAgIHBhcmVudDoge1xuICAgKiAgICAgaWQ6IFwicGFyZW50LmlkXCIsXG4gICAqICAgICBuYW1lOiBcInBhcmVudC5uYW1lXCIsXG4gICAqICAgfSxcbiAgICogfVxuICAgKiBgYGBcbiAgICogQHBhcmFtIG9iaiDrs4DtmZjtlaAg6rCd7LK0XG4gICAqIEBwYXJhbSBpbmRlbnQg65Ok7Jes7JOw6riwIOugiOuyqFxuICAgKiBAcGFyYW0gd2l0aEJyYWNlcyB0cnVl66m0IOykkeq0hO2YuCDtj6ztlagsIGZhbHNl66m0IOuCtOyaqeunjCDrsJjtmZhcbiAgICovXG4gIHByaXZhdGUgc3RyaW5naWZ5TmVzdGVkU2VsZWN0T2JqZWN0KFxuICAgIC8vIGJpb21lLWlnbm9yZSBsaW50L3N1c3BpY2lvdXMvbm9FeHBsaWNpdEFueTog7KSR7LKpIOyYpOu4jOygne2KuOydmCDqsJLsnYAgc3RyaW5n7J28IOyImOuPhCDsnojqs6Ag65iQ64uk66W4IOyYpOu4jOygne2KuOydvCDsiJjrj4Qg7J6I64qU642wLCDsnbTrpbwg7J6s6reAIO2DgOyeheycvOuhnCDrgpjtg4Drgrwg7IiYIOyXhuyWtCBhbnnroZwg7LKY66as7ZWp64uI64ukLlxuICAgIG9iajogUmVjb3JkPHN0cmluZywgYW55PixcbiAgICBpbmRlbnQ6IG51bWJlciA9IDAsXG4gICAgd2l0aEJyYWNlczogYm9vbGVhbiA9IHRydWUsXG4gICk6IHN0cmluZyB7XG4gICAgY29uc3Qgc3BhY2VzID0gXCIgIFwiLnJlcGVhdChpbmRlbnQpO1xuICAgIGNvbnN0IGlubmVyU3BhY2VzID0gXCIgIFwiLnJlcGVhdChpbmRlbnQgKyAxKTtcblxuICAgIGNvbnN0IGVudHJpZXMgPSBPYmplY3QuZW50cmllcyhvYmopO1xuICAgIGlmIChlbnRyaWVzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHdpdGhCcmFjZXMgPyBcInt9XCIgOiBcIlwiO1xuXG4gICAgY29uc3QgbGluZXMgPSBlbnRyaWVzLm1hcCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICBpZiAodHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIC8vIOy7rOufvCDqsr3roZwgKOydtOuvuCDrlLDsmLTtkZwg7Y+s7ZWoKVxuICAgICAgICByZXR1cm4gYCR7aW5uZXJTcGFjZXN9JHtrZXl9OiAke3ZhbHVlfSxgO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8g7KSR7LKpIOqwneyytCAo7ZWt7IOBIOykkeq0hO2YuCDtj6ztlagpXG4gICAgICAgIHJldHVybiBgJHtpbm5lclNwYWNlc30ke2tleX06ICR7dGhpcy5zdHJpbmdpZnlOZXN0ZWRTZWxlY3RPYmplY3QodmFsdWUsIGluZGVudCArIDEsIHRydWUpfSxgO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgaWYgKHdpdGhCcmFjZXMpIHtcbiAgICAgIHJldHVybiBge1xcbiR7bGluZXMuam9pbihcIlxcblwiKX1cXG4ke3NwYWNlc319YDtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8g7KSR6rSE7Zi4IOyXhuydtCDrgrTsmqnrp4wg67CY7ZmYICjslZ7rkqQg6rCc7ZaJIOygnOyZuClcbiAgICAgIHJldHVybiBsaW5lcy5qb2luKFwiXFxuXCIpO1xuICAgIH1cbiAgfVxuXG4gIGdldFB1cmlMb2FkZXJRdWVyeShzdWJzZXRLZXk6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3Qgc3Vic2V0ID0gdGhpcy5nZXRTdWJzZXRGaWVsZHNGb3JRdWVyeShzdWJzZXRLZXkpO1xuICAgIGNvbnN0IHsgbG9hZGVycyB9ID0gdGhpcy5yZXNvbHZlU3Vic2V0UXVlcnkoXCJcIiwgc3Vic2V0KTtcblxuICAgIGNvbnN0IGxpbmVzOiBzdHJpbmdbXSA9IFtgW2BdO1xuXG4gICAgLy8g7J6s6reA7KCB7Jy866GcIGxvYWRlciDsg53shLHtlZjripQg7Zes7Y28IO2VqOyImFxuICAgIGNvbnN0IGdlbmVyYXRlTG9hZGVyQ29kZSA9IChsb2FkZXJzOiBTdWJzZXRRdWVyeVtcImxvYWRlcnNcIl0pOiBzdHJpbmdbXSA9PiB7XG4gICAgICBjb25zdCBsb2FkZXJMaW5lczogc3RyaW5nW10gPSBbXTtcblxuICAgICAgZm9yIChjb25zdCBsb2FkZXIgb2YgbG9hZGVycykge1xuICAgICAgICBjb25zdCB7IHRvVGFibGUsIHRvQ29sLCB0aHJvdWdoLCBmcm9tVGFibGUgfSA9IGxvYWRlci5tYW55Sm9pbjtcblxuICAgICAgICAvLyBmcm9tVGFibGXsnZggRW50aXR566W8IOqwgOyguOyZgOyEnCBQSyDtg4DsnoUg7ZmV7J24XG4gICAgICAgIGNvbnN0IGZyb21FbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldEJ5VGFibGUoZnJvbVRhYmxlKTtcbiAgICAgICAgY29uc3QgZnJvbUlkc1R5cGUgPSBmcm9tRW50aXR5LmdldFBrQXJyYXlUeXBlKCk7XG5cbiAgICAgICAgbG9hZGVyTGluZXMucHVzaChcbiAgICAgICAgICBcIntcIixcbiAgICAgICAgICBgYXM6IFwiJHtsb2FkZXIuYXN9XCIsYCxcbiAgICAgICAgICBgcmVmSWQ6IFwiJHtsb2FkZXIubWFueUpvaW4uaWRGaWVsZH1cIixgLFxuICAgICAgICAgIGBxYjogKHFiV3JhcHBlcjogUHVyaVdyYXBwZXI8RGF0YWJhc2VTY2hlbWFFeHRlbmQ+LCBmcm9tSWRzOiBudW1iZXJbXSB8IHN0cmluZ1tdKSA9PiB7YCxcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAodGhyb3VnaCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgLy8gSGFzTWFueVxuICAgICAgICAgIGxvYWRlckxpbmVzLnB1c2goXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgXCJyZXR1cm4gcWJXcmFwcGVyXCIsXG4gICAgICAgICAgICBgLmZyb20oXCIke3RvVGFibGV9XCIpYCxcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgbG9hZGVyLm9uZUpvaW5zLmZvckVhY2goKGpvaW46IFN1YnNldFF1ZXJ5W1wiam9pbnNcIl1bbnVtYmVyXSkgPT4ge1xuICAgICAgICAgICAgLy8gRksgbnVsbGFibGUg7Jes67aA64qUIGxlZnRKb2luIO2DgOyehSDsi5zqt7jri4jsspjsl5DshJwg7J6Q64+Z7Jy866GcIO2MkOuLqOuQqFxuICAgICAgICAgICAgY29uc3Qgam9pbk1ldGhvZCA9IGpvaW4uam9pbiA9PT0gXCJpbm5lclwiID8gXCJqb2luXCIgOiBcImxlZnRKb2luXCI7XG4gICAgICAgICAgICBpZiAoXCJjdXN0b21cIiBpbiBqb2luKSB7XG4gICAgICAgICAgICAgIC8vIGN1c3RvbSBqb2luIGNsYXVzZeuKlCBjYWxsYmFjayDtmJXtg5zsnZggb24g66mU7ISc65Oc66GcIOyymOumrO2VqeuLiOuLpC5cbiAgICAgICAgICAgICAgbG9hZGVyTGluZXMucHVzaChcbiAgICAgICAgICAgICAgICBgLiR7am9pbk1ldGhvZH0oeyAke2pvaW4uYXN9OiBcIiR7am9pbi50YWJsZX1cIiB9LCAoaikgPT4ge2AsXG4gICAgICAgICAgICAgICAgYGoub24oUHVyaS5yYXdTdHJpbmcoXCIke2pvaW4uY3VzdG9tfVwiKSk7YCxcbiAgICAgICAgICAgICAgICBcIn0pXCIsXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBsb2FkZXJMaW5lcy5wdXNoKFxuICAgICAgICAgICAgICAgIGAuJHtqb2luTWV0aG9kfSh7ICR7am9pbi5hc306IFwiJHtqb2luLnRhYmxlfVwiIH0sIFwiJHtqb2luLmZyb219XCIsIFwiJHtqb2luLnRvfVwiKWAsXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICAvLyDsnoXssrTsoIEgc2VsZWN0IOq1rOyhsCDsg53shLEgKHJlZklkIO2PrO2VqClcbiAgICAgICAgICBjb25zdCBzZWxlY3RPYmogPSB0aGlzLmJ1aWxkTmVzdGVkU2VsZWN0T2JqZWN0KGxvYWRlci5zZWxlY3QpO1xuICAgICAgICAgIHNlbGVjdE9iai5yZWZJZCA9IGBcIiR7dG9UYWJsZX0uJHt0b0NvbH1cImA7XG4gICAgICAgICAgbG9hZGVyTGluZXMucHVzaChcbiAgICAgICAgICAgIGAud2hlcmVJbihcIiR7dG9UYWJsZX0uJHt0b0NvbH1cIiwgZnJvbUlkcyBhcyAke2Zyb21JZHNUeXBlfSlgLFxuICAgICAgICAgICAgYC5zZWxlY3QoJHt0aGlzLnN0cmluZ2lmeU5lc3RlZFNlbGVjdE9iamVjdChzZWxlY3RPYmopfSk7YCxcbiAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIE1hbnlUb01hbnlcbiAgICAgICAgICBsb2FkZXJMaW5lcy5wdXNoKFxuICAgICAgICAgICAgXCJyZXR1cm4gcWJXcmFwcGVyXCIsXG4gICAgICAgICAgICBgLmZyb20oXCIke3Rocm91Z2gudGFibGV9XCIpYCxcbiAgICAgICAgICAgIGAuam9pbihcIiR7dG9UYWJsZX1cIiwgXCIke3Rocm91Z2gudGFibGV9LiR7dGhyb3VnaC50b0NvbH1cIiwgXCIke3RvVGFibGV9LiR7dG9Db2x9XCIpYCxcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgbG9hZGVyLm9uZUpvaW5zLmZvckVhY2goKGpvaW46IFN1YnNldFF1ZXJ5W1wiam9pbnNcIl1bbnVtYmVyXSkgPT4ge1xuICAgICAgICAgICAgLy8gRksgbnVsbGFibGUg7Jes67aA64qUIGxlZnRKb2luIO2DgOyehSDsi5zqt7jri4jsspjsl5DshJwg7J6Q64+Z7Jy866GcIO2MkOuLqOuQqFxuICAgICAgICAgICAgY29uc3Qgam9pbk1ldGhvZCA9IGpvaW4uam9pbiA9PT0gXCJpbm5lclwiID8gXCJqb2luXCIgOiBcImxlZnRKb2luXCI7XG4gICAgICAgICAgICBpZiAoXCJjdXN0b21cIiBpbiBqb2luKSB7XG4gICAgICAgICAgICAgIC8vIGN1c3RvbSBqb2luIGNsYXVzZeuKlCBjYWxsYmFjayDtmJXtg5zsnZggb24g66mU7ISc65Oc66GcIOyymOumrO2VqeuLiOuLpC5cbiAgICAgICAgICAgICAgbG9hZGVyTGluZXMucHVzaChcbiAgICAgICAgICAgICAgICBgLiR7am9pbk1ldGhvZH0oeyAke2pvaW4uYXN9OiBcIiR7am9pbi50YWJsZX1cIiB9LCAoaikgPT4ge2AsXG4gICAgICAgICAgICAgICAgYGoub24oUHVyaS5yYXdTdHJpbmcoXCIke2pvaW4uY3VzdG9tfVwiKSk7YCxcbiAgICAgICAgICAgICAgICBcIn0pXCIsXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBsb2FkZXJMaW5lcy5wdXNoKFxuICAgICAgICAgICAgICAgIGAuJHtqb2luTWV0aG9kfSh7ICR7am9pbi5hc306IFwiJHtqb2luLnRhYmxlfVwiIH0sIFwiJHtqb2luLmZyb219XCIsIFwiJHtqb2luLnRvfVwiKWAsXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICAvLyDsnoXssrTsoIEgc2VsZWN0IOq1rOyhsCDsg53shLEgKHJlZklkIO2PrO2VqClcbiAgICAgICAgICBjb25zdCBzZWxlY3RPYmogPSB0aGlzLmJ1aWxkTmVzdGVkU2VsZWN0T2JqZWN0KGxvYWRlci5zZWxlY3QpO1xuICAgICAgICAgIHNlbGVjdE9iai5yZWZJZCA9IGBcIiR7dGhyb3VnaC50YWJsZX0uJHt0aHJvdWdoLmZyb21Db2x9XCJgO1xuICAgICAgICAgIGxvYWRlckxpbmVzLnB1c2goXG4gICAgICAgICAgICBgLndoZXJlSW4oXCIke3Rocm91Z2gudGFibGV9LiR7dGhyb3VnaC5mcm9tQ29sfVwiLCBmcm9tSWRzIGFzICR7ZnJvbUlkc1R5cGV9KWAsXG4gICAgICAgICAgICBgLnNlbGVjdCgke3RoaXMuc3RyaW5naWZ5TmVzdGVkU2VsZWN0T2JqZWN0KHNlbGVjdE9iail9KTtgLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBsb2FkZXJMaW5lcy5wdXNoKGB9LGApO1xuXG4gICAgICAgIC8vIOykkeyyqSBsb2FkZXJzIOyymOumrFxuICAgICAgICBpZiAobG9hZGVyLmxvYWRlcnMgJiYgbG9hZGVyLmxvYWRlcnMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGxvYWRlckxpbmVzLnB1c2goXCJsb2FkZXJzOiBbXCIsIC4uLmdlbmVyYXRlTG9hZGVyQ29kZShsb2FkZXIubG9hZGVycyksIFwiXSxcIik7XG4gICAgICAgIH1cblxuICAgICAgICBsb2FkZXJMaW5lcy5wdXNoKFwifSxcIik7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBsb2FkZXJMaW5lcztcbiAgICB9O1xuXG4gICAgbGluZXMucHVzaCguLi5nZW5lcmF0ZUxvYWRlckNvZGUobG9hZGVycykpO1xuICAgIGxpbmVzLnB1c2goYF1gKTtcblxuICAgIHJldHVybiBsaW5lcy5qb2luKFwiXFxuXCIpO1xuICB9XG5cbiAgLypcbiAgICBzdWJzZXQgU0VMRUNUL0pPSU4vTE9BREVSIOqysOqzvCDrpqzthLRcbiAgKi9cbiAgZ2V0U3Vic2V0UXVlcnkoc3Vic2V0S2V5OiBzdHJpbmcpOiBTdWJzZXRRdWVyeSB7XG4gICAgY29uc3Qgc3Vic2V0ID0gdGhpcy5nZXRTdWJzZXRGaWVsZHNGb3JRdWVyeShzdWJzZXRLZXkpO1xuXG4gICAgY29uc3QgcmVzdWx0OiBTdWJzZXRRdWVyeSA9IHRoaXMucmVzb2x2ZVN1YnNldFF1ZXJ5KFwiXCIsIHN1YnNldCk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qXG4gICAqL1xuICByZXNvbHZlU3Vic2V0UXVlcnkoXG4gICAgcHJlZml4OiBzdHJpbmcsXG4gICAgZmllbGRzOiBzdHJpbmdbXSxcbiAgICBpc0FscmVhZHlPdXRlckpvaW5lZDogYm9vbGVhbiA9IGZhbHNlLFxuICApOiBTdWJzZXRRdWVyeSB7XG4gICAgLy8gcHJlZml4IOy5mO2ZmCAocHJlZml464qUIFRvT25lUmVsYXRpb27snbQg67O17IiY66GcIOu2meydgCDqsr3smrAg66qo65GQIF9f66GcIOuzgOqyveuQqClcbiAgICBwcmVmaXggPSBwcmVmaXgucmVwbGFjZSgvXFwuL2csIFwiX19cIik7XG5cbiAgICAvLyDshJzruIzshYvsnYQgMeuOgeyKpOunjCDrtoTrpqztlZjsl6wg6re466O57ZWRXG4gICAgY29uc3Qgc3Vic2V0R3JvdXAgPSBncm91cChmaWVsZHMsIChmaWVsZCkgPT4ge1xuICAgICAgaWYgKGZpZWxkLmluY2x1ZGVzKFwiLlwiKSkge1xuICAgICAgICBjb25zdCBbcmVsXSA9IGZpZWxkLnNwbGl0KFwiLlwiKTtcbiAgICAgICAgcmV0dXJuIHJlbDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBcIlwiO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgY29uc3QgcmVzdWx0ID0gT2JqZWN0LmtleXMoc3Vic2V0R3JvdXApLnJlZHVjZShcbiAgICAgIChyLCBncm91cEtleSkgPT4ge1xuICAgICAgICBjb25zdCBmaWVsZHMgPSBzdWJzZXRHcm91cFtncm91cEtleV07XG4gICAgICAgIGFzc2VydChmaWVsZHMgIT09IHVuZGVmaW5lZCwgXCJmaWVsZHMgaXMgdW5kZWZpbmVkXCIpO1xuXG4gICAgICAgIC8vIO2YhOyerCDthYzsnbTruJQg7ZWE65Oc7IWL7J2AIHNlbGVjdCwgdmlydHVhbOyXkCDstpTqsIDtlZjqs6Ag66as7YS0XG4gICAgICAgIGlmIChncm91cEtleSA9PT0gXCJcIikge1xuICAgICAgICAgIGNvbnN0IHJlYWxGaWVsZHMgPSBmaWVsZHMuZmlsdGVyKChmaWVsZCkgPT4gIWlzVmlydHVhbFByb3AodGhpcy5wcm9wc0RpY3RbZmllbGRdKSk7XG4gICAgICAgICAgLy8gdmlydHVhbFR5cGU6IFwiY29kZVwiICjrmJDripQgdW5kZWZpbmVkKeyduCB2aXJ0dWFsIHByb3Drp4wgci52aXJ0dWFs7JeQIOy2lOqwgFxuICAgICAgICAgIC8vIHZpcnR1YWxUeXBlOiBcInF1ZXJ5XCLsnbgg6rK97JqwIOyCrOyaqeyekOqwgCBhcHBlbmRTZWxlY3TroZwg7KeB7KCRIOy2lOqwgO2VmOuvgOuhnCDsoJzsmbhcbiAgICAgICAgICBjb25zdCB2aXJ0dWFsQ29kZUZpZWxkcyA9IGZpZWxkcy5maWx0ZXIoKGZpZWxkKSA9PlxuICAgICAgICAgICAgaXNWaXJ0dWFsQ29kZVByb3AodGhpcy5wcm9wc0RpY3RbZmllbGRdKSxcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgaWYgKHByZWZpeCA9PT0gXCJcIikge1xuICAgICAgICAgICAgLy8g7ZiE7J6sIO2FjOydtOu4lOyduCDqsr3smrBcbiAgICAgICAgICAgIHIuc2VsZWN0ID0gci5zZWxlY3QuY29uY2F0KHJlYWxGaWVsZHMubWFwKChmaWVsZCkgPT4gdGhpcy5nZXRGdWxsRmllbGROYW1lKGZpZWxkKSkpO1xuICAgICAgICAgICAgci52aXJ0dWFsID0gci52aXJ0dWFsLmNvbmNhdCh2aXJ0dWFsQ29kZUZpZWxkcyk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIOuEmOyWtOyYqCDthYzsnbTruJTsnbgg6rK97JqwXG4gICAgICAgICAgICByLnNlbGVjdCA9IHIuc2VsZWN0LmNvbmNhdChcbiAgICAgICAgICAgICAgcmVhbEZpZWxkcy5tYXAoKGZpZWxkKSA9PiBgJHtwcmVmaXh9LiR7ZmllbGR9IGFzICR7cHJlZml4fV9fJHtmaWVsZH1gKSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIHI7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZWxhdGlvbiA9IHRoaXMucmVsYXRpb25zW2dyb3VwS2V5XTtcbiAgICAgICAgaWYgKHJlbGF0aW9uID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYOyhtOyerO2VmOyngCDslYrripQgcmVsYXRpb24g7LC47KGwICR7Z3JvdXBLZXl9YCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcmVsRW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQocmVsYXRpb24ud2l0aCk7XG5cbiAgICAgICAgaWYgKGlzT25lVG9PbmVSZWxhdGlvblByb3AocmVsYXRpb24pIHx8IGlzQmVsb25nc1RvT25lUmVsYXRpb25Qcm9wKHJlbGF0aW9uKSkge1xuICAgICAgICAgIC8vIC1PbmUgUmVsYXRpb246IEpPSU4g7Jy866GcIOyymOumrFxuICAgICAgICAgIGNvbnN0IHJlbEZpZWxkcyA9IGZpZWxkcy5tYXAoKGZpZWxkKSA9PiBmaWVsZC5zcGxpdChcIi5cIikuc2xpY2UoMSkuam9pbihcIi5cIikpO1xuXG4gICAgICAgICAgLy8gLU9uZSBSZWxhdGlvbuyXkOyEnCBpZCDtlYTrk5zrp4wg7LC47KGw7ZWY64qUIOqyveyasCDrprTroIjsnbTshZgg64SY6riw7KeAIOyViuqzoCDrpqzthLRcbiAgICAgICAgICBpZiAocmVsRmllbGRzLmxlbmd0aCA9PT0gMSAmJiByZWxGaWVsZHNbMF0gPT09IFwiaWRcIikge1xuICAgICAgICAgICAgaWYgKHByZWZpeCA9PT0gXCJcIikge1xuICAgICAgICAgICAgICByLnNlbGVjdCA9IHIuc2VsZWN0LmNvbmNhdChgJHt0aGlzLnRhYmxlfS4ke2dyb3VwS2V5fV9pZGApO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgci5zZWxlY3QgPSByLnNlbGVjdC5jb25jYXQoYCR7cHJlZml4fS4ke2dyb3VwS2V5fV9pZCBhcyAke3ByZWZpeH1fXyR7Z3JvdXBLZXl9X2lkYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBpbm5lck9yT3V0ZXJcbiAgICAgICAgICBjb25zdCBpbm5lck9yT3V0ZXIgPSAoKCkgPT4ge1xuICAgICAgICAgICAgaWYgKGlzQWxyZWFkeU91dGVySm9pbmVkKSB7XG4gICAgICAgICAgICAgIHJldHVybiBcIm91dGVyXCI7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChpc09uZVRvT25lUmVsYXRpb25Qcm9wKHJlbGF0aW9uKSkge1xuICAgICAgICAgICAgICBpZiAocmVsYXRpb24uaGFzSm9pbkNvbHVtbiA9PT0gdHJ1ZSAmJiAocmVsYXRpb24ubnVsbGFibGUgPz8gZmFsc2UpID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBcImlubmVyXCI7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwib3V0ZXJcIjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgaWYgKHJlbGF0aW9uLm51bGxhYmxlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwib3V0ZXJcIjtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJpbm5lclwiO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSkoKTtcbiAgICAgICAgICBjb25zdCByZWxTdWJzZXRRdWVyeSA9IHJlbEVudGl0eS5yZXNvbHZlU3Vic2V0UXVlcnkoXG4gICAgICAgICAgICBgJHtwcmVmaXggIT09IFwiXCIgPyBgJHtwcmVmaXh9LmAgOiBcIlwifSR7Z3JvdXBLZXl9YCxcbiAgICAgICAgICAgIHJlbEZpZWxkcyxcbiAgICAgICAgICAgIGlubmVyT3JPdXRlciA9PT0gXCJvdXRlclwiLFxuICAgICAgICAgICk7XG4gICAgICAgICAgci5zZWxlY3QgPSByLnNlbGVjdC5jb25jYXQocmVsU3Vic2V0UXVlcnkuc2VsZWN0KTtcbiAgICAgICAgICByLnZpcnR1YWwgPSByLnZpcnR1YWwuY29uY2F0KHJlbFN1YnNldFF1ZXJ5LnZpcnR1YWwpO1xuXG4gICAgICAgICAgY29uc3Qgam9pbkFzID0gcHJlZml4ID09PSBcIlwiID8gZ3JvdXBLZXkgOiBgJHtwcmVmaXh9X18ke2dyb3VwS2V5fWA7XG4gICAgICAgICAgY29uc3QgZnJvbVRhYmxlID0gcHJlZml4ID09PSBcIlwiID8gdGhpcy50YWJsZSA6IHByZWZpeDtcblxuICAgICAgICAgIGxldCBqb2luQ2xhdXNlOlxuICAgICAgICAgICAgfCB7XG4gICAgICAgICAgICAgICAgZnJvbTogc3RyaW5nO1xuICAgICAgICAgICAgICAgIHRvOiBzdHJpbmc7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHwge1xuICAgICAgICAgICAgICAgIGN1c3RvbTogc3RyaW5nO1xuICAgICAgICAgICAgICB9O1xuICAgICAgICAgIGlmIChyZWxhdGlvbi5jdXN0b21Kb2luQ2xhdXNlKSB7XG4gICAgICAgICAgICBqb2luQ2xhdXNlID0ge1xuICAgICAgICAgICAgICBjdXN0b206IHJlbGF0aW9uLmN1c3RvbUpvaW5DbGF1c2UsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsZXQgZnJvbTogc3RyaW5nLCB0bzogc3RyaW5nO1xuICAgICAgICAgICAgaWYgKGlzT25lVG9PbmVSZWxhdGlvblByb3AocmVsYXRpb24pKSB7XG4gICAgICAgICAgICAgIGlmIChyZWxhdGlvbi5oYXNKb2luQ29sdW1uKSB7XG4gICAgICAgICAgICAgICAgZnJvbSA9IGAke2Zyb21UYWJsZX0uJHtyZWxhdGlvbi5uYW1lfV9pZGA7XG4gICAgICAgICAgICAgICAgdG8gPSBgJHtqb2luQXN9LmlkYDtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBmcm9tID0gYCR7ZnJvbVRhYmxlfS5pZGA7XG4gICAgICAgICAgICAgICAgdG8gPSBgJHtqb2luQXN9LiR7aW5mbGVjdGlvbi51bmRlcnNjb3JlKHRoaXMubmFtZXMuZnMucmVwbGFjZSgvLS9nLCBcIl9cIikpfV9pZGA7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGZyb20gPSBgJHtmcm9tVGFibGV9LiR7cmVsYXRpb24ubmFtZX1faWRgO1xuICAgICAgICAgICAgICB0byA9IGAke2pvaW5Bc30uaWRgO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgam9pbkNsYXVzZSA9IHtcbiAgICAgICAgICAgICAgZnJvbSxcbiAgICAgICAgICAgICAgdG8sXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHIuam9pbnMucHVzaCh7XG4gICAgICAgICAgICBhczogam9pbkFzLFxuICAgICAgICAgICAgam9pbjogaW5uZXJPck91dGVyLFxuICAgICAgICAgICAgdGFibGU6IHJlbEVudGl0eS50YWJsZSxcbiAgICAgICAgICAgIC4uLmpvaW5DbGF1c2UsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICAvLyBCZWxvbmdzVG9PbmUg67CR7JeQIEhhc01hbnnqsIAg67aZ7J2AIOqyveyasFxuICAgICAgICAgIGlmIChyZWxTdWJzZXRRdWVyeS5sb2FkZXJzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGNvbnN0IGNvbnZlcnRlZExvYWRlcnMgPSByZWxTdWJzZXRRdWVyeS5sb2FkZXJzLm1hcCgobG9hZGVyKSA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IG5ld0FzID0gW2dyb3VwS2V5LCBsb2FkZXIuYXNdLmpvaW4oXCJfX1wiKTtcbiAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBhczogbmV3QXMsXG4gICAgICAgICAgICAgICAgdGFibGU6IGxvYWRlci50YWJsZSxcbiAgICAgICAgICAgICAgICBtYW55Sm9pbjogbG9hZGVyLm1hbnlKb2luLFxuICAgICAgICAgICAgICAgIG9uZUpvaW5zOiBsb2FkZXIub25lSm9pbnMsXG4gICAgICAgICAgICAgICAgc2VsZWN0OiBsb2FkZXIuc2VsZWN0LFxuICAgICAgICAgICAgICAgIGxvYWRlcnM6IGxvYWRlci5sb2FkZXJzLFxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHIubG9hZGVycyA9IFsuLi5yLmxvYWRlcnMsIC4uLmNvbnZlcnRlZExvYWRlcnNdO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHIuam9pbnMgPSByLmpvaW5zLmNvbmNhdChyZWxTdWJzZXRRdWVyeS5qb2lucyk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNIYXNNYW55UmVsYXRpb25Qcm9wKHJlbGF0aW9uKSB8fCBpc01hbnlUb01hbnlSZWxhdGlvblByb3AocmVsYXRpb24pKSB7XG4gICAgICAgICAgLy8gLU1hbnkgUmVsYXRpb246IExvYWRlciDroZwg7LKY66asXG4gICAgICAgICAgY29uc3QgcmVsRmllbGRzID0gZmllbGRzLm1hcCgoZmllbGQpID0+IGZpZWxkLnNwbGl0KFwiLlwiKS5zbGljZSgxKS5qb2luKFwiLlwiKSk7XG4gICAgICAgICAgY29uc3QgcmVsU3Vic2V0UXVlcnkgPSByZWxFbnRpdHkucmVzb2x2ZVN1YnNldFF1ZXJ5KFwiXCIsIHJlbEZpZWxkcyk7XG5cbiAgICAgICAgICBsZXQgbWFueUpvaW46IFN1YnNldFF1ZXJ5W1wibG9hZGVyc1wiXVtudW1iZXJdW1wibWFueUpvaW5cIl07XG4gICAgICAgICAgaWYgKGlzSGFzTWFueVJlbGF0aW9uUHJvcChyZWxhdGlvbikpIHtcbiAgICAgICAgICAgIGNvbnN0IGZyb21Db2wgPSByZWxhdGlvbj8uZnJvbUNvbHVtbiA/PyBcImlkXCI7XG4gICAgICAgICAgICBtYW55Sm9pbiA9IHtcbiAgICAgICAgICAgICAgZnJvbVRhYmxlOiB0aGlzLnRhYmxlLFxuICAgICAgICAgICAgICBmcm9tQ29sLFxuICAgICAgICAgICAgICBpZEZpZWxkOiBwcmVmaXggPT09IFwiXCIgPyBgJHtmcm9tQ29sfWAgOiBgJHtwcmVmaXh9X18ke2Zyb21Db2x9YCxcbiAgICAgICAgICAgICAgdG9UYWJsZTogcmVsRW50aXR5LnRhYmxlLFxuICAgICAgICAgICAgICB0b0NvbDogcmVsYXRpb24uam9pbkNvbHVtbixcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfSBlbHNlIGlmIChpc01hbnlUb01hbnlSZWxhdGlvblByb3AocmVsYXRpb24pKSB7XG4gICAgICAgICAgICBtYW55Sm9pbiA9IHtcbiAgICAgICAgICAgICAgZnJvbVRhYmxlOiB0aGlzLnRhYmxlLFxuICAgICAgICAgICAgICBmcm9tQ29sOiBcImlkXCIsXG4gICAgICAgICAgICAgIGlkRmllbGQ6IHByZWZpeCA9PT0gXCJcIiA/IGBpZGAgOiBgJHtwcmVmaXh9X19pZGAsXG4gICAgICAgICAgICAgIHRocm91Z2g6IHtcbiAgICAgICAgICAgICAgICB0YWJsZTogcmVsYXRpb24uam9pblRhYmxlLFxuICAgICAgICAgICAgICAgIGZyb21Db2w6IGAke2luZmxlY3Rpb24uc2luZ3VsYXJpemUodGhpcy50YWJsZSl9X2lkYCxcbiAgICAgICAgICAgICAgICB0b0NvbDogYCR7aW5mbGVjdGlvbi5zaW5ndWxhcml6ZShyZWxFbnRpdHkudGFibGUpfV9pZGAsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIHRvVGFibGU6IHJlbEVudGl0eS50YWJsZSxcbiAgICAgICAgICAgICAgdG9Db2w6IFwiaWRcIixcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcigpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHIubG9hZGVycy5wdXNoKHtcbiAgICAgICAgICAgIGFzOiBncm91cEtleSxcbiAgICAgICAgICAgIHRhYmxlOiByZWxFbnRpdHkudGFibGUsXG4gICAgICAgICAgICBtYW55Sm9pbixcbiAgICAgICAgICAgIG9uZUpvaW5zOiByZWxTdWJzZXRRdWVyeS5qb2lucyxcbiAgICAgICAgICAgIHNlbGVjdDogcmVsU3Vic2V0UXVlcnkuc2VsZWN0LFxuICAgICAgICAgICAgbG9hZGVyczogcmVsU3Vic2V0UXVlcnkubG9hZGVycyxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByO1xuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgc2VsZWN0OiBbXSxcbiAgICAgICAgdmlydHVhbDogW10sXG4gICAgICAgIGpvaW5zOiBbXSxcbiAgICAgICAgbG9hZGVyczogW10sXG4gICAgICB9IGFzIFN1YnNldFF1ZXJ5LFxuICAgICk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qXG4gICAgRmllbGRFeHByW10g7J2EIEVudGl0eVByb3BOb2RlW10g66GcIOuzgO2ZmFxuICAqL1xuICBmaWVsZEV4cHJzVG9Qcm9wTm9kZXMoZmllbGRFeHByczogc3RyaW5nW10sIGVudGl0eTogRW50aXR5ID0gdGhpcyk6IEVudGl0eVByb3BOb2RlW10ge1xuICAgIGNvbnN0IGdyb3VwcyA9IGZpZWxkRXhwcnMucmVkdWNlKFxuICAgICAgKHJlc3VsdCwgZmllbGRFeHByKSA9PiB7XG4gICAgICAgIGxldCBrZXk6IHN0cmluZywgdmFsdWU6IHN0cmluZywgZWxzZUV4cHI6IHN0cmluZ1tdO1xuICAgICAgICBpZiAoZmllbGRFeHByLmluY2x1ZGVzKFwiLlwiKSkge1xuICAgICAgICAgIFtrZXksIC4uLmVsc2VFeHByXSA9IGZpZWxkRXhwci5zcGxpdChcIi5cIik7XG4gICAgICAgICAgdmFsdWUgPSBlbHNlRXhwci5qb2luKFwiLlwiKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBrZXkgPSBcIlwiO1xuICAgICAgICAgIHZhbHVlID0gZmllbGRFeHByO1xuICAgICAgICB9XG4gICAgICAgIHJlc3VsdFtrZXldID0gKHJlc3VsdFtrZXldID8/IFtdKS5jb25jYXQodmFsdWUpO1xuXG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICB9LFxuICAgICAge30gYXMge1xuICAgICAgICBbazogc3RyaW5nXTogc3RyaW5nW107XG4gICAgICB9LFxuICAgICk7XG5cbiAgICByZXR1cm4gT2JqZWN0LmtleXMoZ3JvdXBzKS5mbGF0TWFwPEVudGl0eVByb3BOb2RlLCBFbnRpdHlQcm9wTm9kZVtdPigoa2V5KSA9PiB7XG4gICAgICBjb25zdCBncm91cCA9IGdyb3Vwc1trZXldO1xuXG4gICAgICAvLyDsnbzrsJggcHJvcCDsspjrpqxcbiAgICAgIGlmIChrZXkgPT09IFwiXCIpIHtcbiAgICAgICAgcmV0dXJuIGdyb3VwLm1hcCgocHJvcE5hbWUpID0+IHtcbiAgICAgICAgICBjb25zdCBwcm9wID0gZW50aXR5LnByb3BzLmZpbmQoKHApID0+IHAubmFtZSA9PT0gcHJvcE5hbWUpO1xuICAgICAgICAgIGlmIChwcm9wID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgYCR7ZW50aXR5LmlkfSAtLSDsnpjrqrvrkJwgRmllbGRFeHByICcke3Byb3BOYW1lfScgKOyCrOyaqSDqsIDriqXtlZwgcHJvcHM6ICR7ZW50aXR5LnByb3BzLm1hcCgocCkgPT4gcC5uYW1lKS5qb2luKFwiLCBcIil9KWAsXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgbm9kZVR5cGU6IFwicGxhaW5cIiBhcyBjb25zdCxcbiAgICAgICAgICAgIHByb3AsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIC8vIHJlbGF0aW9uIHByb3Ag7LKY66asXG4gICAgICBjb25zdCBwcm9wID0gZW50aXR5LnByb3BzRGljdFtrZXldO1xuICAgICAgaWYgKCFpc1JlbGF0aW9uUHJvcChwcm9wKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYOyemOuqu+uQnCBGaWVsZEV4cHIgJHtrZXl9LiR7Z3JvdXBbMF19YCk7XG4gICAgICB9XG4gICAgICBjb25zdCByZWxFbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChwcm9wLndpdGgpO1xuXG4gICAgICAvLyByZWxhdGlvbiAtT25lIOyXkCBpZCDtlYTrk5wg7ZWY64KY7J24IOqyveyasFxuICAgICAgaWYgKGlzQmVsb25nc1RvT25lUmVsYXRpb25Qcm9wKHByb3ApIHx8IGlzT25lVG9PbmVSZWxhdGlvblByb3AocHJvcCkpIHtcbiAgICAgICAgaWYgKGdyb3VwLmxlbmd0aCA9PT0gMSAmJiAoZ3JvdXBbMF0gPT09IFwiaWRcIiB8fCBncm91cFswXSA9PT0gXCJpZD9cIikpIHtcbiAgICAgICAgICAvLyBpZCDtlZjrgpjrp4wg7J6I64qU7KeAIOyytO2BrO2VtOyEnCwg7ZWY64KY66eMIOyeiOycvOuptCDsg4HsnIQgcHJvcOycvOuhnCBpZOulvCDrpqzthLRcbiAgICAgICAgICBjb25zdCBpZFByb3AgPSByZWxFbnRpdHkucHJvcHNEaWN0LmlkO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBub2RlVHlwZTogXCJwbGFpblwiIGFzIGNvbnN0LFxuICAgICAgICAgICAgcHJvcDoge1xuICAgICAgICAgICAgICAuLi5pZFByb3AsXG4gICAgICAgICAgICAgIG5hbWU6IGAke2tleX1faWRgLFxuICAgICAgICAgICAgICBudWxsYWJsZTogcHJvcC5udWxsYWJsZSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyAtT25lIOq3uOyZuOydmCDqsr3smrAgb2JqZWN066GcIOumrO2EtFxuICAgICAgLy8gLU1hbnnsnZgg6rK97JqwIGFycmF566GcIOumrO2EtFxuICAgICAgLy8gUmVjdXJzaXZlIOuhnCDrjoHsiqQg7LKY66asXG4gICAgICBjb25zdCBjaGlsZHJlbiA9IHRoaXMuZmllbGRFeHByc1RvUHJvcE5vZGVzKGdyb3VwLCByZWxFbnRpdHkpO1xuICAgICAgY29uc3Qgbm9kZVR5cGUgPVxuICAgICAgICBpc0JlbG9uZ3NUb09uZVJlbGF0aW9uUHJvcChwcm9wKSB8fCBpc09uZVRvT25lUmVsYXRpb25Qcm9wKHByb3ApXG4gICAgICAgICAgPyAoXCJvYmplY3RcIiBhcyBjb25zdClcbiAgICAgICAgICA6IChcImFycmF5XCIgYXMgY29uc3QpO1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBub2RlVHlwZSxcbiAgICAgICAgcHJvcCxcbiAgICAgICAgY2hpbGRyZW4sXG4gICAgICB9O1xuICAgIH0pO1xuICB9XG5cbiAgZ2V0RmllbGRFeHBycyhwcmVmaXggPSBcIlwiLCBtYXhEZXB0aDogbnVtYmVyID0gMywgZnJvbXM6IHN0cmluZ1tdID0gW10pOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIHRoaXMucHJvcHNcbiAgICAgIC5mbGF0TWFwKChwcm9wKSA9PiB7XG4gICAgICAgIGNvbnN0IHByb3BOYW1lID0gW3ByZWZpeCwgcHJvcC5uYW1lXS5maWx0ZXIoKHYpID0+IHYgIT09IFwiXCIpLmpvaW4oXCIuXCIpO1xuICAgICAgICBpZiAocHJvcE5hbWUgPT09IHByZWZpeCkge1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICAgIGlmIChpc1JlbGF0aW9uUHJvcChwcm9wKSkge1xuICAgICAgICAgIGlmIChtYXhEZXB0aCA8IDApIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoZnJvbXMuaW5jbHVkZXMocHJvcC53aXRoKSkge1xuICAgICAgICAgICAgLy8g7Jet67Cp7ZalIHJlbGF0aW9u7J24IOqyveyasCDsoJzsmbhcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyDsoJXrsKntlqUgcmVsYXRpb27snbgg6rK97JqwIHJlY3Vyc2l2ZSDsvZxcbiAgICAgICAgICBjb25zdCByZWxNZCA9IEVudGl0eU1hbmFnZXIuZ2V0KHByb3Aud2l0aCk7XG4gICAgICAgICAgcmV0dXJuIHJlbE1kLmdldEZpZWxkRXhwcnMocHJvcE5hbWUsIG1heERlcHRoIC0gMSwgWy4uLmZyb21zLCB0aGlzLmlkXSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHByb3BOYW1lO1xuICAgICAgfSlcbiAgICAgIC5maWx0ZXIoKGYpID0+IGYgIT09IG51bGwpIGFzIHN0cmluZ1tdO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbGF0aW9uIHByb3DsnbQg7ZiE7J6sIO2FjOydtOu4lOyXkCBGSyDsu6zrn7zsnYQg7IOd7ISx7ZWY64qU7KeAIO2ZleyduFxuICAgKihCZWxvbmdzVG9PbmUg65iQ64qUIE9uZVRvT25lKGhhc0pvaW5Db2x1bW49dHJ1ZSnsnbgg6rK97JqwIEZLIOyDneyEsSlcbiAgICovXG4gIHByaXZhdGUgaGFzRm9yZWlnbktleShwcm9wOiBSZWxhdGlvblByb3ApOiBib29sZWFuIHtcbiAgICByZXR1cm4gKFxuICAgICAgcHJvcC5yZWxhdGlvblR5cGUgPT09IFwiQmVsb25nc1RvT25lXCIgfHxcbiAgICAgIChwcm9wLnJlbGF0aW9uVHlwZSA9PT0gXCJPbmVUb09uZVwiICYmIHByb3AuaGFzSm9pbkNvbHVtbiA9PT0gdHJ1ZSlcbiAgICApO1xuICB9XG5cbiAgZ2V0VGFibGVDb2x1bW5zKCk6IHsgbmFtZTogc3RyaW5nOyB0eXBlOiBzdHJpbmcgfVtdIHtcbiAgICByZXR1cm4gdGhpcy5wcm9wc1xuICAgICAgLm1hcCgocHJvcCkgPT4ge1xuICAgICAgICBpZiAocHJvcC50eXBlID09PSBcInJlbGF0aW9uXCIpIHtcbiAgICAgICAgICBpZiAodGhpcy5oYXNGb3JlaWduS2V5KHByb3ApKSB7XG4gICAgICAgICAgICByZXR1cm4geyBuYW1lOiBgJHtwcm9wLm5hbWV9X2lkYCwgdHlwZTogXCJpbnRfdW5zaWduZWRcIiB9O1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHsgbmFtZTogcHJvcC5uYW1lLCB0eXBlOiBwcm9wLnR5cGUgfTtcbiAgICAgIH0pXG4gICAgICAuZmlsdGVyKG5vbk51bGxhYmxlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbnRpdHnsl5Ag7KCV7J2Y65CcIOuqqOuToCB2ZWN0b3Ig7YOA7J6FIOy7rOufvCDrsJjtmZhcbiAgICovXG4gIGdldFZlY3RvckNvbHVtbnMoKTogRW50aXR5UHJvcFtdIHtcbiAgICByZXR1cm4gdGhpcy5wcm9wcy5maWx0ZXIoKHApID0+IHAudHlwZSA9PT0gXCJ2ZWN0b3JcIik7XG4gIH1cblxuICAvKipcbiAgICog7Yq57KCVIHZlY3RvciDsu6zrn7wg67CY7ZmYXG4gICAqIEBwYXJhbSBjb2x1bW5OYW1lIC0g7Lus65+866qFICjsg53rnrUg7IucIOyyqyDrsojsp7ggdmVjdG9yIOy7rOufvClcbiAgICovXG4gIGdldFZlY3RvckNvbHVtbihjb2x1bW5OYW1lPzogc3RyaW5nKTogRW50aXR5UHJvcCB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgdmVjdG9yUHJvcHMgPSB0aGlzLmdldFZlY3RvckNvbHVtbnMoKTtcbiAgICBpZiAoY29sdW1uTmFtZSkge1xuICAgICAgcmV0dXJuIHZlY3RvclByb3BzLmZpbmQoKHApID0+IHAubmFtZSA9PT0gY29sdW1uTmFtZSk7XG4gICAgfVxuICAgIHJldHVybiB2ZWN0b3JQcm9wc1swXTtcbiAgfVxuXG4gIC8qKlxuICAgKiDtlYTthLDrp4Eg6rCA64ql7ZWcIHByb3BzIOuwmO2ZmFxuICAgKlxuICAgKiAtIOydvOuwmCBwcm9wXG4gICAqIC0gRkvrpbwg7IOd7ISx7ZWY64qUIHJlbGF0aW9uIChCZWxvbmdzVG9PbmUsIE9uZVRvT25lIHdpdGggaGFzSm9pbkNvbHVtbilcbiAgICogICDihpIge25hbWV9X2lkIO2Yle2DnOydmCDqsIDsg4EgaW50ZWdlciBwcm9w7Jy866GcIOuzgO2ZmFxuICAgKi9cbiAgZ2V0RmlsdGVyYWJsZVByb3BzKCk6IEVudGl0eVByb3BbXSB7XG4gICAgcmV0dXJuIHRoaXMucHJvcHMuZmxhdE1hcCgocHJvcCk6IEVudGl0eVByb3AgfCBFbnRpdHlQcm9wW10gPT4ge1xuICAgICAgLy8gVmlydHVhbCBwcm9wIOygnOyZuFxuICAgICAgaWYgKGlzVmlydHVhbFByb3AocHJvcCkpIHtcbiAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgfVxuXG4gICAgICAvLyBSZWxhdGlvbiBwcm9wIOyymOumrFxuICAgICAgaWYgKGlzUmVsYXRpb25Qcm9wKHByb3ApKSB7XG4gICAgICAgIC8vIEZL66W8IOyDneyEse2VmOuKlCByZWxhdGlvbuunjCDtj6ztlahcbiAgICAgICAgaWYgKHRoaXMuaGFzRm9yZWlnbktleShwcm9wKSkge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBuYW1lOiBgJHtwcm9wLm5hbWV9X2lkYCxcbiAgICAgICAgICAgIHR5cGU6IFwiaW50ZWdlclwiLFxuICAgICAgICAgICAgbnVsbGFibGU6IHByb3AubnVsbGFibGUsXG4gICAgICAgICAgfSBhcyBFbnRpdHlQcm9wO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cblxuICAgICAgLy8g7J2867CYIHByb3Ag7LKY66asXG4gICAgICByZXR1cm4gcHJvcDtcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIHJlZ2lzdGVyTW9kdWxlUGF0aHMoKSB7XG4gICAgY29uc3QgYmFzZVBhdGggPSBgJHt0aGlzLm5hbWVzLnBhcmVudEZzfWA7XG5cbiAgICAvLyBiYXNlLXNjaGVtZVxuICAgIEVudGl0eU1hbmFnZXIuc2V0TW9kdWxlUGF0aChgJHt0aGlzLmlkfUJhc2VTY2hlbWFgLCBgc29uYW11LmdlbmVyYXRlZGApO1xuXG4gICAgLy8gc3Vic2V0XG4gICAgaWYgKE9iamVjdC5rZXlzKHRoaXMuc3Vic2V0cykubGVuZ3RoID4gMCkge1xuICAgICAgRW50aXR5TWFuYWdlci5zZXRNb2R1bGVQYXRoKGAke3RoaXMuaWR9U3Vic2V0S2V5YCwgYHNvbmFtdS5nZW5lcmF0ZWRgKTtcbiAgICAgIEVudGl0eU1hbmFnZXIuc2V0TW9kdWxlUGF0aChgJHt0aGlzLmlkfVN1YnNldE1hcHBpbmdgLCBgc29uYW11LmdlbmVyYXRlZGApO1xuICAgICAgZm9yIChjb25zdCBzdWJzZXRLZXkgb2YgT2JqZWN0LmtleXModGhpcy5zdWJzZXRzKSkge1xuICAgICAgICBFbnRpdHlNYW5hZ2VyLnNldE1vZHVsZVBhdGgoXG4gICAgICAgICAgYCR7dGhpcy5pZH1TdWJzZXQke3N1YnNldEtleS50b1VwcGVyQ2FzZSgpfWAsXG4gICAgICAgICAgYHNvbmFtdS5nZW5lcmF0ZWRgLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIGVudW1zXG4gICAgZm9yIChjb25zdCBlbnVtSWQgb2YgT2JqZWN0LmtleXModGhpcy5lbnVtTGFiZWxzKSkge1xuICAgICAgRW50aXR5TWFuYWdlci5zZXRNb2R1bGVQYXRoKGVudW1JZCwgYHNvbmFtdS5nZW5lcmF0ZWRgKTtcbiAgICB9XG5cbiAgICAvLyB0eXBlc1xuICAgIGNvbnN0IHR5cGVzTW9kdWxlUGF0aCA9IGAke2Jhc2VQYXRofS8ke3RoaXMubmFtZXMucGFyZW50RnN9LnR5cGVzYDtcbiAgICBjb25zdCB0eXBlc0ZpbGVQYXRoID0gcGF0aC5qb2luKFxuICAgICAgU29uYW11LmFwaVJvb3RQYXRoLFxuICAgICAgcnVudGltZVBhdGgoYGRpc3QvYXBwbGljYXRpb24vJHt0eXBlc01vZHVsZVBhdGh9LmpzYCksXG4gICAgKTtcblxuICAgIGlmIChhd2FpdCBleGlzdHModHlwZXNGaWxlUGF0aCkpIHtcbiAgICAgIGNvbnN0IGltcG9ydGVkTWVtYmVycyA9IGF3YWl0IGltcG9ydE1lbWJlcnM8ei5ab2RUeXBlQW55Pih0eXBlc0ZpbGVQYXRoKTtcbiAgICAgIHRoaXMudHlwZXMgPSBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgICAgIGltcG9ydGVkTWVtYmVycy5tYXAoKHsgbmFtZSwgdmFsdWUgfSkgPT4ge1xuICAgICAgICAgIEVudGl0eU1hbmFnZXIuc2V0TW9kdWxlUGF0aChuYW1lLCB0eXBlc01vZHVsZVBhdGgpO1xuICAgICAgICAgIHJldHVybiBbbmFtZSwgdmFsdWVdO1xuICAgICAgICB9KSxcbiAgICAgICkgYXMgeyBbbmFtZTogc3RyaW5nXTogei5ab2RUeXBlQW55IH07XG4gICAgfVxuICB9XG5cbiAgcmVnaXN0ZXJUYWJsZVNwZWNzKCk6IHZvaWQge1xuICAgIC8vIOyhsOyduCDthYzsnbTruJQg7J24642x7IqkIOygnOyZuCAo7Lus65+8IOydtOumhOyXkCAnLifsnbQg7Y+s7ZWo65CcIOqyveyasClcbiAgICBjb25zdCB1bmlxdWVJbmRleGVzID0gdGhpcy5pbmRleGVzXG4gICAgICAuZmlsdGVyKChpZHgpID0+IGlkeC50eXBlID09PSBcInVuaXF1ZVwiKVxuICAgICAgLmZpbHRlcigoaWR4KSA9PiBpZHguY29sdW1ucy5ldmVyeSgoY29sKSA9PiAhY29sLm5hbWUuaW5jbHVkZXMoXCIuXCIpKSk7XG5cbiAgICBFbnRpdHlNYW5hZ2VyLnNldFRhYmxlU3BlYyh7XG4gICAgICBuYW1lOiB0aGlzLnRhYmxlLFxuICAgICAgdW5pcXVlSW5kZXhlcyxcbiAgICAgIGpzb25Db2x1bW5zOiB0aGlzLnByb3BzLmZpbHRlcigocCkgPT4gcC50eXBlID09PSBcImpzb25cIikubWFwKChwKSA9PiBwLm5hbWUpLFxuICAgIH0pO1xuICB9XG5cbiAgdG9Kc29uKCk6IEVudGl0eUpzb24ge1xuICAgIC8vIHN1YnNldHPsmYAgc3Vic2V0c0ludGVybmFs7J2EIFN1YnNldERlZiDtmJXtg5zroZwg67O17JuQIChjb25lIO2PrO2VqClcbiAgICBjb25zdCBzdWJzZXRzOiB7IFtrZXk6IHN0cmluZ106IGltcG9ydChcIi4uL3R5cGVzL3R5cGVzXCIpLlN1YnNldERlZiB9ID0ge307XG4gICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXModGhpcy5zdWJzZXRzKSkge1xuICAgICAgY29uc3Qgbm9ybWFsRmllbGRzOiBTdWJzZXRGaWVsZFtdID0gdGhpcy5zdWJzZXRzW2tleV07XG4gICAgICBjb25zdCBpbnRlcm5hbEZpZWxkczogU3Vic2V0RmllbGRbXSA9ICh0aGlzLnN1YnNldHNJbnRlcm5hbFtrZXldID8/IFtdKS5tYXAoKGZpZWxkKSA9PiAoe1xuICAgICAgICBmaWVsZCxcbiAgICAgICAgaW50ZXJuYWw6IHRydWUsXG4gICAgICB9KSk7XG4gICAgICBjb25zdCBmaWVsZHMgPSBbLi4ubm9ybWFsRmllbGRzLCAuLi5pbnRlcm5hbEZpZWxkc107XG5cbiAgICAgIC8vIGNvbmXsnbQg7J6I7Jy866m0IOyDiOuhnOyatCDqsJ3ssrQg7ZiV7YOc66GcLCDsl4bsnLzrqbQg67Cw7Je0IO2Yle2DnOuhnFxuICAgICAgaWYgKHRoaXMuc3Vic2V0Q29uZXNba2V5XSkge1xuICAgICAgICBzdWJzZXRzW2tleV0gPSB7XG4gICAgICAgICAgZmllbGRzLFxuICAgICAgICAgIGNvbmU6IHRoaXMuc3Vic2V0Q29uZXNba2V5XSxcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHN1YnNldHNba2V5XSA9IGZpZWxkcztcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBlbnVtc+ulvCBFbnVtRGVmIO2Yle2DnOuhnCDrs7Xsm5AgKGNvbmUg7Y+s7ZWoKVxuICAgIGNvbnN0IGVudW1zOiB7IFtrZXk6IHN0cmluZ106IGltcG9ydChcIi4uL3R5cGVzL3R5cGVzXCIpLkVudW1EZWYgfSA9IHt9O1xuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVzXSBvZiBPYmplY3QuZW50cmllcyh0aGlzLmVudW1MYWJlbHMpKSB7XG4gICAgICAvLyBjb25l7J20IOyeiOycvOuptCDsg4jroZzsmrQg6rCd7LK0IO2Yle2DnOuhnCwg7JeG7Jy866m0IFJlY29yZCDtmJXtg5zroZxcbiAgICAgIGlmICh0aGlzLmVudW1Db25lc1trZXldKSB7XG4gICAgICAgIGVudW1zW2tleV0gPSB7XG4gICAgICAgICAgdmFsdWVzLFxuICAgICAgICAgIGNvbmU6IHRoaXMuZW51bUNvbmVzW2tleV0sXG4gICAgICAgIH07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBlbnVtc1trZXldID0gdmFsdWVzO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBpZDogdGhpcy5pZCxcbiAgICAgIHBhcmVudElkOiB0aGlzLnBhcmVudElkLFxuICAgICAgdGFibGU6IHRoaXMudGFibGUsXG4gICAgICB0aXRsZTogdGhpcy50aXRsZSxcbiAgICAgIGNvbmU6IHRoaXMuY29uZSxcbiAgICAgIHByb3BzOiB0aGlzLnByb3BzLFxuICAgICAgaW5kZXhlczogdGhpcy5pbmRleGVzLFxuICAgICAgc3Vic2V0cyxcbiAgICAgIGVudW1zLFxuICAgIH07XG4gIH1cblxuICBhc3luYyBzYXZlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIHNvcnQ6IHN1YnNldHNcbiAgICBjb25zdCBzdWJzZXRSb3dzID0gdGhpcy5nZXRTdWJzZXRSb3dzKCk7XG4gICAgdGhpcy5zdWJzZXRzID0gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgT2JqZWN0LmVudHJpZXModGhpcy5zdWJzZXRzKS5tYXAoKFtzdWJzZXRLZXldKSA9PiB7XG4gICAgICAgIHJldHVybiBbc3Vic2V0S2V5LCB0aGlzLnN1YnNldFJvd3NUb1N1YnNldEZpZWxkcyhzdWJzZXRSb3dzLCBzdWJzZXRLZXksIGZhbHNlKV07XG4gICAgICB9KSxcbiAgICApO1xuICAgIHRoaXMuc3Vic2V0c0ludGVybmFsID0gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgT2JqZWN0LmVudHJpZXModGhpcy5zdWJzZXRzSW50ZXJuYWwpLm1hcCgoW3N1YnNldEtleV0pID0+IHtcbiAgICAgICAgcmV0dXJuIFtzdWJzZXRLZXksIHRoaXMuc3Vic2V0Um93c1RvU3Vic2V0RmllbGRzKHN1YnNldFJvd3MsIHN1YnNldEtleSwgdHJ1ZSldO1xuICAgICAgfSksXG4gICAgKTtcblxuICAgIC8vIHNhdmVcbiAgICBjb25zdCBqc29uUGF0aCA9IHBhdGguam9pbihcbiAgICAgIFNvbmFtdS5hcGlSb290UGF0aCxcbiAgICAgIGBzcmMvYXBwbGljYXRpb24vJHt0aGlzLm5hbWVzLnBhcmVudEZzfS8ke3RoaXMubmFtZXMuZnN9LmVudGl0eS5qc29uYCxcbiAgICApO1xuICAgIGNvbnN0IGpzb24gPSB0aGlzLnRvSnNvbigpO1xuICAgIGF3YWl0IHdyaXRlRmlsZShqc29uUGF0aCwgZm9ybWF0Q29kZShKU09OLnN0cmluZ2lmeShqc29uKSwgXCJqc29uXCIsIGpzb25QYXRoKSk7XG5cbiAgICAvLyByZWxvYWRcbiAgICBhd2FpdCBFbnRpdHlNYW5hZ2VyLnJlZ2lzdGVyKGpzb24pO1xuICB9XG5cbiAgLyoqXG4gICAqIO2FnO2UjOumvyBjb25lIOuplO2DgOuNsOydtO2EsOulvCDsg53shLHtlanri4jri6QuXG4gICAqXG4gICAqIExMTeydhCDsgqzsmqntlZjsp4Ag7JWK6rOgIGZha2VyLW1hcHBpbmdzLnRz66W8IO2ZnOyaqe2VmOyXrCDquLDrs7ggY29uZeydhCDsg53shLHtlanri4jri6QuXG4gICAqIHN0dWIgZW50aXR5IOyDneyEsSDsi5wg7J6Q64+Z7Jy866GcIO2YuOy2nOuQmOyWtCDstZzshoztlZzsnZggY29uZSDrqZTtg4DrjbDsnbTthLDrpbwg7KCc6rO17ZWp64uI64ukLlxuICAgKlxuICAgKiBAcGFyYW0gbG9jYWxlIC0g7IOd7ISxIOyLnCDsgqzsmqntlaAgbG9jYWxlICjquLDrs7jqsJI6IFNvbmFtdS5jb25maWcuaTE4bi5kZWZhdWx0TG9jYWxlIOuYkOuKlCBcImtvXCIpXG4gICAqL1xuICBhc3luYyBnZW5lcmF0ZVRlbXBsYXRlQ29uZXMobG9jYWxlPzogXCJrb1wiIHwgXCJlblwiIHwgXCJqYVwiKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBnZW5lcmF0ZVRlbXBsYXRlQ29uZXMgfSA9IGF3YWl0IGltcG9ydChcIi4vZW50aXR5LXRlbXBsYXRlLWNvbmVcIik7XG4gICAgY29uc3QgY29uZmlnTG9jYWxlID0gU29uYW11LmNvbmZpZy5pMThuPy5kZWZhdWx0TG9jYWxlO1xuICAgIGNvbnN0IGVmZmVjdGl2ZUxvY2FsZSA9XG4gICAgICBsb2NhbGUgfHxcbiAgICAgIChjb25maWdMb2NhbGUgPT09IFwia29cIiB8fCBjb25maWdMb2NhbGUgPT09IFwiZW5cIiB8fCBjb25maWdMb2NhbGUgPT09IFwiamFcIlxuICAgICAgICA/IGNvbmZpZ0xvY2FsZVxuICAgICAgICA6IFwia29cIik7XG4gICAgY29uc3QgcmVzdWx0ID0gZ2VuZXJhdGVUZW1wbGF0ZUNvbmVzKHRoaXMudG9Kc29uKCksIGVmZmVjdGl2ZUxvY2FsZSk7XG5cbiAgICAvLyDqsrDqs7zrpbwgRW50aXR57JeQIOyggeyaqSAoYXBwbHlDb25lc+yZgCDrj5nsnbztlZwg67Cp7IudKVxuICAgIGlmIChyZXN1bHQuZW50aXR5Q29uZSkge1xuICAgICAgdGhpcy5jb25lID0gcmVzdWx0LmVudGl0eUNvbmU7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBbcHJvcE5hbWUsIGNvbmVdIG9mIE9iamVjdC5lbnRyaWVzKHJlc3VsdC5wcm9wQ29uZXMpKSB7XG4gICAgICBjb25zdCBwcm9wID0gdGhpcy5wcm9wcy5maW5kKChwKSA9PiBwLm5hbWUgPT09IHByb3BOYW1lKTtcbiAgICAgIGlmIChwcm9wKSB7XG4gICAgICAgIChwcm9wIGFzIHsgY29uZT86IENvbmUgfSkuY29uZSA9IGNvbmU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5lbnVtQ29uZXMgPSB7IC4uLnRoaXMuZW51bUNvbmVzLCAuLi5yZXN1bHQuZW51bUNvbmVzIH07XG4gICAgdGhpcy5zdWJzZXRDb25lcyA9IHsgLi4udGhpcy5zdWJzZXRDb25lcywgLi4ucmVzdWx0LnN1YnNldENvbmVzIH07XG5cbiAgICBhd2FpdCB0aGlzLnNhdmUoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMTE3snYQg7IKs7Jqp7ZWY7JesIGNvbmUg66mU7YOA642w7J207YSw66W8IOyDneyEse2VqeuLiOuLpC5cbiAgICpcbiAgICogQHBhcmFtIG9wdGlvbnMucHJlc2VydmVFeGlzdGluZyAtIOq4sOyhtCBjb25lIOuztOyhtCDsl6zrtoAgKOq4sOuzuOqwkjogdHJ1ZSlcbiAgICogQHBhcmFtIG9wdGlvbnMub25seUVtcHR5IC0gZml4dHVyZUhpbnTqsIAg7JeG64qUIGNvbmXrp4wg7IOd7ISxICjquLDrs7jqsJI6IGZhbHNlKVxuICAgKiBAcGFyYW0gb3B0aW9ucy5sb2NhbGUgLSDsg53shLEg7IucIOyCrOyaqe2VoCBsb2NhbGUgKOq4sOuzuOqwkjogXCJrb1wiKVxuICAgKi9cbiAgYXN5bmMgZ2VuZXJhdGVDb25lcyhvcHRpb25zPzoge1xuICAgIHByZXNlcnZlRXhpc3Rpbmc/OiBib29sZWFuO1xuICAgIG9ubHlFbXB0eT86IGJvb2xlYW47XG4gICAgbG9jYWxlPzogXCJrb1wiIHwgXCJlblwiIHwgXCJqYVwiO1xuICB9KTogUHJvbWlzZTxpbXBvcnQoXCIuLi9jb25lL2NvbmUtZ2VuZXJhdG9yXCIpLkNvbmVHZW5lcmF0aW9uUmVzdWx0PiB7XG4gICAgY29uc3QgeyBnZW5lcmF0ZUNvbmVzIH0gPSBhd2FpdCBpbXBvcnQoXCIuLi9jb25lL2NvbmUtZ2VuZXJhdG9yXCIpO1xuICAgIGNvbnN0IGNvbnRleHQ6IGltcG9ydChcIi4uL2NvbmUvY29uZS1nZW5lcmF0b3JcIikuQ29uZUdlbmVyYXRpb25Db250ZXh0ID0ge1xuICAgICAgZW50aXR5OiB0aGlzLnRvSnNvbigpLFxuICAgICAgbG9jYWxlOiBvcHRpb25zPy5sb2NhbGUgfHwgXCJrb1wiLFxuICAgICAgZXhpc3RpbmdDb25lczogb3B0aW9ucz8ucHJlc2VydmVFeGlzdGluZyAhPT0gZmFsc2UgPyB0aGlzLmNvbGxlY3RFeGlzdGluZ0NvbmVzKCkgOiB1bmRlZmluZWQsXG4gICAgICBvbmx5RW1wdHk6IG9wdGlvbnM/Lm9ubHlFbXB0eSA/PyBmYWxzZSxcbiAgICB9O1xuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZ2VuZXJhdGVDb25lcyhjb250ZXh0KTtcbiAgICB0aGlzLmFwcGx5Q29uZXMocmVzdWx0KTtcbiAgICBhd2FpdCB0aGlzLnNhdmUoKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqXG4gICAqIOq4sOyhtCBjb25l65Ok7J2EIOyImOynke2VqeuLiOuLpCAoZW50aXR5LCBwcm9wcywgZW51bXMsIHN1YnNldHMpLlxuICAgKlxuICAgKiBAcmV0dXJucyDtgqTqsIAgXCJlbnRpdHk6aWRcIiwgXCJwcm9wOm5hbWVcIiwgXCJlbnVtOmVudW1JZFwiLCBcInN1YnNldDprZXlcIiDtmJXsi53snbggY29uZSDrp7VcbiAgICovXG4gIHByaXZhdGUgY29sbGVjdEV4aXN0aW5nQ29uZXMoKTogUmVjb3JkPHN0cmluZywgQ29uZT4ge1xuICAgIGNvbnN0IGNvbmVzOiBSZWNvcmQ8c3RyaW5nLCBDb25lPiA9IHt9O1xuXG4gICAgaWYgKHRoaXMuY29uZSkge1xuICAgICAgY29uZXNbYGVudGl0eToke3RoaXMuaWR9YF0gPSB0aGlzLmNvbmU7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBwcm9wIG9mIHRoaXMucHJvcHMpIHtcbiAgICAgIGlmIChwcm9wLmNvbmUpIHtcbiAgICAgICAgY29uZXNbYHByb3A6JHtwcm9wLm5hbWV9YF0gPSBwcm9wLmNvbmU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBbZW51bUlkLCBjb25lXSBvZiBPYmplY3QuZW50cmllcyh0aGlzLmVudW1Db25lcykpIHtcbiAgICAgIGNvbmVzW2BlbnVtOiR7ZW51bUlkfWBdID0gY29uZTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IFtzdWJzZXRLZXksIGNvbmVdIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMuc3Vic2V0Q29uZXMpKSB7XG4gICAgICBjb25lc1tgc3Vic2V0OiR7c3Vic2V0S2V5fWBdID0gY29uZTtcbiAgICB9XG5cbiAgICByZXR1cm4gY29uZXM7XG4gIH1cblxuICAvKipcbiAgICog7IOd7ISx65CcIGNvbmXrk6TsnYQgRW50aXR57JeQIOyggeyaqe2VqeuLiOuLpC5cbiAgICpcbiAgICogQHBhcmFtIHJlc3VsdCAtIExMTeycvOuhnCDsg53shLHrkJwgY29uZSDqsrDqs7xcbiAgICovXG4gIHByaXZhdGUgYXBwbHlDb25lcyhyZXN1bHQ6IGltcG9ydChcIi4uL2NvbmUvY29uZS1nZW5lcmF0b3JcIikuQ29uZUdlbmVyYXRpb25SZXN1bHQpOiB2b2lkIHtcbiAgICBpZiAocmVzdWx0LmVudGl0eUNvbmUpIHtcbiAgICAgIHRoaXMuY29uZSA9IHJlc3VsdC5lbnRpdHlDb25lO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgW3Byb3BOYW1lLCBjb25lXSBvZiBPYmplY3QuZW50cmllcyhyZXN1bHQucHJvcENvbmVzKSkge1xuICAgICAgY29uc3QgcHJvcCA9IHRoaXMucHJvcHMuZmluZCgocCkgPT4gcC5uYW1lID09PSBwcm9wTmFtZSk7XG4gICAgICBpZiAocHJvcCkge1xuICAgICAgICAocHJvcCBhcyB7IGNvbmU/OiBDb25lIH0pLmNvbmUgPSBjb25lO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuZW51bUNvbmVzID0geyAuLi50aGlzLmVudW1Db25lcywgLi4ucmVzdWx0LmVudW1Db25lcyB9O1xuICAgIHRoaXMuc3Vic2V0Q29uZXMgPSB7IC4uLnRoaXMuc3Vic2V0Q29uZXMsIC4uLnJlc3VsdC5zdWJzZXRDb25lcyB9O1xuICB9XG5cbiAgZ2V0U3Vic2V0Um93cyhcbiAgICBfc3Vic2V0cz86IHsgW2tleTogc3RyaW5nXTogc3RyaW5nW10gfSxcbiAgICBfc3Vic2V0c0ludGVybmFsPzogeyBba2V5OiBzdHJpbmddOiBzdHJpbmdbXSB9LFxuICAgIHByZWZpeGVzOiBzdHJpbmdbXSA9IFtdLFxuICApOiBFbnRpdHlTdWJzZXRSb3dbXSB7XG4gICAgaWYgKHByZWZpeGVzLmxlbmd0aCA+IDEwKSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuXG4gICAgY29uc3Qgc3Vic2V0cyA9IF9zdWJzZXRzID8/IHRoaXMuc3Vic2V0cztcbiAgICBjb25zdCBzdWJzZXRzSW50ZXJuYWwgPSBfc3Vic2V0c0ludGVybmFsID8/IHRoaXMuc3Vic2V0c0ludGVybmFsO1xuICAgIGNvbnN0IHN1YnNldEtleXMgPSBPYmplY3Qua2V5cyhzdWJzZXRzKTtcbiAgICBjb25zdCBhbGxGaWVsZHMgPSB1bmlxdWUoc3Vic2V0S2V5cy5mbGF0TWFwKChrZXkpID0+IHN1YnNldHNba2V5XSkpO1xuICAgIC8vIGludGVybmFsIO2VhOuTnOuPhCBhbGxGaWVsZHPsl5Ag7Y+s7ZWoIChyZWxhdGlvbiDtg5Dsg4nsmqkpXG4gICAgY29uc3QgYWxsSW50ZXJuYWxGaWVsZHMgPSB1bmlxdWUoc3Vic2V0S2V5cy5mbGF0TWFwKChrZXkpID0+IHN1YnNldHNJbnRlcm5hbFtrZXldID8/IFtdKSk7XG4gICAgY29uc3QgY29tYmluZWRGaWVsZHMgPSB1bmlxdWUoWy4uLmFsbEZpZWxkcywgLi4uYWxsSW50ZXJuYWxGaWVsZHNdKTtcblxuICAgIHJldHVybiB0aGlzLnByb3BzLm1hcCgocHJvcCkgPT4ge1xuICAgICAgaWYgKFxuICAgICAgICBwcm9wLnR5cGUgPT09IFwicmVsYXRpb25cIiAmJlxuICAgICAgICBjb21iaW5lZEZpZWxkcy5maW5kKChmKSA9PiBmLnN0YXJ0c1dpdGgoYCR7Wy4uLnByZWZpeGVzLCBwcm9wLm5hbWVdLmpvaW4oXCIuXCIpfS5gKSlcbiAgICAgICkge1xuICAgICAgICBjb25zdCByZWxFbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChwcm9wLndpdGgpO1xuICAgICAgICBjb25zdCBjaGlsZHJlbiA9IHJlbEVudGl0eS5nZXRTdWJzZXRSb3dzKHN1YnNldHMsIHN1YnNldHNJbnRlcm5hbCwgW1xuICAgICAgICAgIC4uLnByZWZpeGVzLFxuICAgICAgICAgIGAke3Byb3AubmFtZX1gLFxuICAgICAgICBdKTtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGZpZWxkOiBwcm9wLm5hbWUsXG4gICAgICAgICAgY2hpbGRyZW4sXG4gICAgICAgICAgcmVsYXRpb25FbnRpdHk6IHByb3Aud2l0aCxcbiAgICAgICAgICBwcmVmaXhlcyxcbiAgICAgICAgICBpc09wZW46IGNoaWxkcmVuLmxlbmd0aCA+IDAsXG4gICAgICAgICAgaGFzOiBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgICAgICAgICBzdWJzZXRLZXlzLm1hcCgoc3Vic2V0S2V5KSA9PiB7XG4gICAgICAgICAgICAgIHJldHVybiBbc3Vic2V0S2V5LCBjaGlsZHJlbi5ldmVyeSgoY2hpbGQpID0+IGNoaWxkLmhhc1tzdWJzZXRLZXldID09PSB0cnVlKV07XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApLFxuICAgICAgICAgIGlzSW50ZXJuYWw6IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgICAgICAgIHN1YnNldEtleXMubWFwKChzdWJzZXRLZXkpID0+IHtcbiAgICAgICAgICAgICAgcmV0dXJuIFtzdWJzZXRLZXksIGNoaWxkcmVuLmV2ZXJ5KChjaGlsZCkgPT4gY2hpbGQuaXNJbnRlcm5hbFtzdWJzZXRLZXldID09PSB0cnVlKV07XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApLFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBmaWVsZCA9IFsuLi5wcmVmaXhlcywgcHJvcC5uYW1lXS5qb2luKFwiLlwiKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGZpZWxkOiBwcm9wLm5hbWUsXG4gICAgICAgIGNoaWxkcmVuOiBbXSxcbiAgICAgICAgcmVsYXRpb25FbnRpdHk6IHByb3AudHlwZSA9PT0gXCJyZWxhdGlvblwiID8gcHJvcC53aXRoIDogdW5kZWZpbmVkLFxuICAgICAgICBwcmVmaXhlcyxcbiAgICAgICAgaGFzOiBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgICAgICAgc3Vic2V0S2V5cy5tYXAoKHN1YnNldEtleSkgPT4ge1xuICAgICAgICAgICAgY29uc3Qgc3Vic2V0RmllbGRzID0gc3Vic2V0c1tzdWJzZXRLZXldO1xuICAgICAgICAgICAgY29uc3QgaGFzID0gc3Vic2V0RmllbGRzLnNvbWUoKGYpID0+IHtcbiAgICAgICAgICAgICAgcmV0dXJuIGYgPT09IGZpZWxkIHx8IGYuc3RhcnRzV2l0aChgJHtmaWVsZH0uYCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBbc3Vic2V0S2V5LCBoYXNdO1xuICAgICAgICAgIH0pLFxuICAgICAgICApLFxuICAgICAgICBpc0ludGVybmFsOiBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgICAgICAgc3Vic2V0S2V5cy5tYXAoKHN1YnNldEtleSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgaW50ZXJuYWxGaWVsZHMgPSBzdWJzZXRzSW50ZXJuYWxbc3Vic2V0S2V5XSA/PyBbXTtcbiAgICAgICAgICAgIGNvbnN0IGlzSW50ZXJuYWwgPSBpbnRlcm5hbEZpZWxkcy5zb21lKChmKSA9PiB7XG4gICAgICAgICAgICAgIHJldHVybiBmID09PSBmaWVsZCB8fCBmLnN0YXJ0c1dpdGgoYCR7ZmllbGR9LmApO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gW3N1YnNldEtleSwgaXNJbnRlcm5hbF07XG4gICAgICAgICAgfSksXG4gICAgICAgICksXG4gICAgICB9O1xuICAgIH0pO1xuICB9XG5cbiAgc3Vic2V0Um93c1RvU3Vic2V0RmllbGRzKFxuICAgIHN1YnNldFJvd3M6IEVudGl0eVN1YnNldFJvd1tdLFxuICAgIHN1YnNldEtleTogc3RyaW5nLFxuICAgIGludGVybmFsOiBib29sZWFuID0gZmFsc2UsXG4gICk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCBoYXNLZXkgPSBpbnRlcm5hbCA/IFwiaXNJbnRlcm5hbFwiIDogXCJoYXNcIjtcbiAgICByZXR1cm4gc3Vic2V0Um93c1xuICAgICAgLm1hcCgoc3Vic2V0Um93KSA9PiB7XG4gICAgICAgIGlmIChzdWJzZXRSb3cuY2hpbGRyZW4ubGVuZ3RoID4gMCkge1xuICAgICAgICAgIHJldHVybiB0aGlzLnN1YnNldFJvd3NUb1N1YnNldEZpZWxkcyhzdWJzZXRSb3cuY2hpbGRyZW4sIHN1YnNldEtleSwgaW50ZXJuYWwpO1xuICAgICAgICB9IGVsc2UgaWYgKHN1YnNldFJvd1toYXNLZXldW3N1YnNldEtleV0pIHtcbiAgICAgICAgICByZXR1cm4gc3Vic2V0Um93LnByZWZpeGVzLmNvbmNhdChzdWJzZXRSb3cuZmllbGQpLmpvaW4oXCIuXCIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICB9KVxuICAgICAgLmZpbHRlcihub25OdWxsYWJsZSlcbiAgICAgIC5mbGF0KCk7XG4gIH1cblxuICBhc3luYyBjcmVhdGVQcm9wKHByb3A6IEVudGl0eVByb3AsIGF0PzogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCFhdCkge1xuICAgICAgdGhpcy5wcm9wcy5wdXNoKHByb3ApO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnByb3BzLnNwbGljZShhdCwgMCwgcHJvcCk7XG4gICAgfVxuICAgIGF3YWl0IHRoaXMuc2F2ZSgpO1xuICB9XG5cbiAgYW5hbHl6ZVN1YnNldEZpZWxkKHN1YnNldEZpZWxkOiBzdHJpbmcpOiB7XG4gICAgZW50aXR5SWQ6IHN0cmluZztcbiAgICBwcm9wTmFtZTogc3RyaW5nO1xuICB9W10ge1xuICAgIGNvbnN0IGFyciA9IHN1YnNldEZpZWxkLnNwbGl0KFwiLlwiKTtcblxuICAgIGxldCBlbnRpdHlJZCA9IHRoaXMuaWQ7XG4gICAgY29uc3QgcmVzdWx0OiB7XG4gICAgICBlbnRpdHlJZDogc3RyaW5nO1xuICAgICAgcHJvcE5hbWU6IHN0cmluZztcbiAgICB9W10gPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGFyci5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgcHJvcE5hbWUgPSBhcnJbaV07XG4gICAgICByZXN1bHQucHVzaCh7XG4gICAgICAgIGVudGl0eUlkLFxuICAgICAgICBwcm9wTmFtZSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBwcm9wID0gRW50aXR5TWFuYWdlci5nZXQoZW50aXR5SWQpLnByb3BzLmZpbmQoKHApID0+IHAubmFtZSA9PT0gcHJvcE5hbWUpO1xuICAgICAgaWYgKCFwcm9wKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgJHtlbnRpdHlJZH3snZgg7J6Y66q765CcIOyEnOu4jOyFi+2CpCAke3N1YnNldEZpZWxkfWApO1xuICAgICAgfVxuICAgICAgaWYgKGlzUmVsYXRpb25Qcm9wKHByb3ApKSB7XG4gICAgICAgIGVudGl0eUlkID0gcHJvcC53aXRoO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgYXN5bmMgbW9kaWZ5UHJvcChuZXdQcm9wOiBFbnRpdHlQcm9wLCBhdDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8g7J207KCEIO2UhOuhrSDsnbTrpoQg7KCA7J6lXG4gICAgY29uc3Qgb2xkTmFtZSA9IHRoaXMucHJvcHNbYXRdLm5hbWU7XG5cbiAgICAvLyDsoIDsnqXtlaAg7JeU7Yuw7YuwXG4gICAgY29uc3QgZW50aXRpZXM6IEVudGl0eVtdID0gW3RoaXNdO1xuXG4gICAgLy8g7J2066aE7J20IOuwlOuAkCDqsr3smrBcbiAgICBpZiAob2xkTmFtZSAhPT0gbmV3UHJvcC5uYW1lKSB7XG4gICAgICAvLyDsoITssrQg7JeU7Yuw7Yuw7JeQ7IScIO2YhOyerCDsiJjsoJXrkJwg7ZSE66Gt7J2EIOywuOyhsO2VmOqzoCDsnojripQg66qo65OgIOyEnOu4jOyFi+2VhOuTnCDssL7slYTshJwg7IiY7KCVXG4gICAgICBjb25zdCBhbGxFbnRpdHlJZHMgPSBFbnRpdHlNYW5hZ2VyLmdldEFsbElkcygpO1xuICAgICAgZm9yIChjb25zdCByZWxFbnRpdHlJZCBvZiBhbGxFbnRpdHlJZHMpIHtcbiAgICAgICAgY29uc3QgcmVsRW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQocmVsRW50aXR5SWQpO1xuICAgICAgICBjb25zdCByZWxFbnRpdHlTdWJzZXRLZXlzID0gT2JqZWN0LmtleXMocmVsRW50aXR5LnN1YnNldHMpO1xuICAgICAgICBmb3IgKGNvbnN0IHN1YnNldEtleSBvZiByZWxFbnRpdHlTdWJzZXRLZXlzKSB7XG4gICAgICAgICAgY29uc3Qgc3Vic2V0ID0gcmVsRW50aXR5LnN1YnNldHNbc3Vic2V0S2V5XTtcblxuICAgICAgICAgIC8vIOyEnOu4jOyFiyDtlYTrk5zrpbwg7Iic7ZqM7ZWY66mwLCDsl5Tti7Dti7At7ZSE66GtIOuLqOychOuhnCDrtoTshJ3tlZwg7ZuEIO2YhOyerCDsl5Tti7Dti7At7ZSE66Gt6rO8IOydvOy5mO2VmOuKlCDqsr3smrAg7IiY7KCVIOyymOumrFxuICAgICAgICAgIGNvbnN0IG1vZGlmaWVkU3Vic2V0RmllbGRzID0gc3Vic2V0Lm1hcCgoc3Vic2V0RmllbGQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGFuYWx5emVkID0gcmVsRW50aXR5LmFuYWx5emVTdWJzZXRGaWVsZChzdWJzZXRGaWVsZCk7XG4gICAgICAgICAgICBjb25zdCBtb2RpZmllZCA9IGFuYWx5emVkLm1hcCgoYSkgPT5cbiAgICAgICAgICAgICAgYS5wcm9wTmFtZSA9PT0gb2xkTmFtZSAmJiBhLmVudGl0eUlkID09PSB0aGlzLmlkXG4gICAgICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgICAgIC4uLmEsXG4gICAgICAgICAgICAgICAgICAgIHByb3BOYW1lOiBuZXdQcm9wLm5hbWUsXG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgOiBhLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIC8vIOu2hOyEne2VnCDtlYTrk5zrpbwg64uk7IucIOyEnOu4jOyFiyDtlYTrk5zroZwg67O16rWsXG4gICAgICAgICAgICByZXR1cm4gbW9kaWZpZWQubWFwKChhKSA9PiBhLnByb3BOYW1lKS5qb2luKFwiLlwiKTtcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGlmIChzdWJzZXQuam9pbihcIixcIikgIT09IG1vZGlmaWVkU3Vic2V0RmllbGRzLmpvaW4oXCIsXCIpKSB7XG4gICAgICAgICAgICByZWxFbnRpdHkuc3Vic2V0c1tzdWJzZXRLZXldID0gbW9kaWZpZWRTdWJzZXRGaWVsZHM7XG4gICAgICAgICAgICBlbnRpdGllcy5wdXNoKHJlbEVudGl0eSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8g7ZSE66GtIOyImOyglVxuICAgIHRoaXMucHJvcHNbYXRdID0gbmV3UHJvcDtcblxuICAgIGF3YWl0IFByb21pc2UuYWxsKGVudGl0aWVzLm1hcChhc3luYyAoZW50aXR5KSA9PiBlbnRpdHkuc2F2ZSgpKSk7XG4gIH1cblxuICBhc3luYyBkZWxQcm9wKGF0OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyDsnbTsoIQg7ZSE66GtIOydtOumhCDsoIDsnqVcbiAgICBjb25zdCBvbGROYW1lID0gdGhpcy5wcm9wc1thdF0ubmFtZTtcblxuICAgIC8vIOyggOyepe2VoCDsl5Tti7Dti7BcbiAgICBjb25zdCBlbnRpdGllczogRW50aXR5W10gPSBbdGhpc107XG5cbiAgICAvLyDsoITssrQg7JeU7Yuw7Yuw7JeQ7IScIO2YhOyerCDsgq3soJzrkJwg7ZSE66Gt7J2EIOywuOyhsO2VmOqzoCDsnojripQg66qo65OgIOyEnOu4jOyFi+2VhOuTnCDssL7slYTshJwg7KCc7Jm4XG4gICAgY29uc3QgYWxsRW50aXR5SWRzID0gRW50aXR5TWFuYWdlci5nZXRBbGxJZHMoKTtcbiAgICBmb3IgKGNvbnN0IHJlbEVudGl0eUlkIG9mIGFsbEVudGl0eUlkcykge1xuICAgICAgY29uc3QgcmVsRW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQocmVsRW50aXR5SWQpO1xuICAgICAgY29uc3QgcmVsRW50aXR5U3Vic2V0S2V5cyA9IE9iamVjdC5rZXlzKHJlbEVudGl0eS5zdWJzZXRzKTtcbiAgICAgIGZvciAoY29uc3Qgc3Vic2V0S2V5IG9mIHJlbEVudGl0eVN1YnNldEtleXMpIHtcbiAgICAgICAgY29uc3Qgc3Vic2V0ID0gcmVsRW50aXR5LnN1YnNldHNbc3Vic2V0S2V5XTtcbiAgICAgICAgLy8g7ISc67iM7IWLIO2VhOuTnOulvCDsiJztmoztlZjrqbAsIOyXlO2LsO2LsC3tlITroa0g64uo7JyE66GcIOu2hOyEne2VnCDtm4Qg7ZiE7J6sIOyXlO2LsO2LsC3tlITroa3qs7wg7J287LmY7ZWY64qUIOqyveyasCDsnbTtm4TsnZgg7ZWE65Oc66W8IOygnOyZuFxuICAgICAgICBjb25zdCBtb2RpZmllZFN1YnNldEZpZWxkcyA9IHN1YnNldFxuICAgICAgICAgIC5tYXAoKHN1YnNldEZpZWxkKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBhbmFseXplZCA9IHJlbEVudGl0eS5hbmFseXplU3Vic2V0RmllbGQoc3Vic2V0RmllbGQpO1xuICAgICAgICAgICAgaWYgKGFuYWx5emVkLmZpbmQoKGEpID0+IGEucHJvcE5hbWUgPT09IG9sZE5hbWUgJiYgYS5lbnRpdHlJZCA9PT0gdGhpcy5pZCkpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICByZXR1cm4gc3Vic2V0RmllbGQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSlcbiAgICAgICAgICAuZmlsdGVyKG5vbk51bGxhYmxlKTtcblxuICAgICAgICBpZiAoc3Vic2V0LmpvaW4oXCIsXCIpICE9PSBtb2RpZmllZFN1YnNldEZpZWxkcy5qb2luKFwiLFwiKSkge1xuICAgICAgICAgIHJlbEVudGl0eS5zdWJzZXRzW3N1YnNldEtleV0gPSBtb2RpZmllZFN1YnNldEZpZWxkcztcbiAgICAgICAgICBlbnRpdGllcy5wdXNoKHJlbEVudGl0eSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyDtmITsnqwg7JeU7Yuw7Yuw7J2YIOyduOuNseyKpOyXkOyEnCDsoJzsmbhcbiAgICBmb3IgKGNvbnN0IGluZGV4IG9mIEVudGl0eU1hbmFnZXIuZ2V0KHRoaXMuaWQpLmluZGV4ZXMpIHtcbiAgICAgIGluZGV4LmNvbHVtbnMgPSBpbmRleC5jb2x1bW5zLmZpbHRlcigoY29sKSA9PiBjb2wubmFtZSAhPT0gb2xkTmFtZSk7XG4gICAgfVxuXG4gICAgLy8g7ZSE66GtIOyCreygnFxuICAgIHRoaXMucHJvcHMuc3BsaWNlKGF0LCAxKTtcblxuICAgIGF3YWl0IFByb21pc2UuYWxsKGVudGl0aWVzLm1hcChhc3luYyAoZW50aXR5KSA9PiBlbnRpdHkuc2F2ZSgpKSk7XG4gIH1cblxuICBnZXRFbnRpdHlJZEZyb21TdWJzZXRGaWVsZChzdWJzZXRGaWVsZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBpZiAoc3Vic2V0RmllbGQuaW5jbHVkZXMoXCIuXCIpID09PSBmYWxzZSkge1xuICAgICAgcmV0dXJuIHRoaXMuaWQ7XG4gICAgfVxuXG4gICAgLy8g7ISc67iM7IWLIO2VhOuTnOydmCDrp4jsp4Drp4nsnYAg7ZSE66Gt7J2066+A66GcIOygnOyZuFxuICAgIGNvbnN0IGFyciA9IHN1YnNldEZpZWxkLnNwbGl0KFwiLlwiKS5zbGljZSgwLCAtMSk7XG5cbiAgICAvLyDshJzruIzshYsg7ZWE65Oc66W8IOuCtOugpOqwgOuptOyEnCDrp4jsp4Drp4nsnLzroZwgcmVsYXRpb27rkJwg7JeU7Yuw7Yuw66W8IOywvuydjFxuICAgIGNvbnN0IGxhc3RFbnRpdHlJZCA9IGFyci5yZWR1Y2UoKGVudGl0eUlkLCBmaWVsZCkgPT4ge1xuICAgICAgY29uc3QgcmVsUHJvcCA9IEVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKS5wcm9wcy5maW5kKChwKSA9PiBwLm5hbWUgPT09IGZpZWxkKTtcbiAgICAgIGlmICghcmVsUHJvcCB8fCByZWxQcm9wLnR5cGUgIT09IFwicmVsYXRpb25cIikge1xuICAgICAgICBjb25zb2xlLmRlYnVnKHsgYXJyLCB0aGlzSWQ6IHRoaXMuaWQsIGVudGl0eUlkLCBmaWVsZCB9KTtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGDsnpjrqrvrkJwg7ISc67iM7IWL7YKkICR7c3Vic2V0RmllbGR9YCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVsUHJvcC53aXRoO1xuICAgIH0sIHRoaXMuaWQpO1xuICAgIHJldHVybiBsYXN0RW50aXR5SWQ7XG4gIH1cblxuICBhc3luYyBtb3ZlUHJvcChhdDogbnVtYmVyLCB0bzogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcHJvcCA9IHRoaXMucHJvcHNbYXRdO1xuICAgIGNvbnN0IG5ld1Byb3BzID0gWy4uLnRoaXMucHJvcHNdO1xuICAgIG5ld1Byb3BzLnNwbGljZSh0bywgMCwgcHJvcCk7XG4gICAgbmV3UHJvcHMuc3BsaWNlKGF0IDwgdG8gPyBhdCA6IGF0ICsgMSwgMSk7XG4gICAgdGhpcy5wcm9wcyA9IG5ld1Byb3BzO1xuXG4gICAgYXdhaXQgdGhpcy5zYXZlKCk7XG4gIH1cblxuICAvKipcbiAgICog7ZWE65Oc66qF7J2EIFwi7YWM7J2067iU66qFLu2VhOuTnOuqhVwiIO2YleyLneycvOuhnCDrs4DtmZhcbiAgICovXG4gIGdldEZ1bGxGaWVsZE5hbWUoZmllbGQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgaWYgKGZpZWxkLmluY2x1ZGVzKFwiLlwiKSkge1xuICAgICAgcmV0dXJuIGZpZWxkO1xuICAgIH1cbiAgICByZXR1cm4gYCR7dGhpcy50YWJsZX0uJHtmaWVsZH1gO1xuICB9XG5cbiAgLyoqXG4gICAqIOyXlO2LsO2LsOydmCBQSyDtg4DsnoXsnYQg67CY7ZmY7ZWp64uI64ukLlxuICAgKiBpZCDtlYTrk5zsnZgg7YOA7J6F7J2EIOq4sOykgOycvOuhnCBcImludGVnZXJcIiB8IFwic3RyaW5nXCIgfCBcInV1aWRcIuulvCDrsJjtmZjtlanri4jri6QuXG4gICAqL1xuICBnZXRQa1R5cGUoKTogXCJpbnRlZ2VyXCIgfCBcInN0cmluZ1wiIHwgXCJ1dWlkXCIge1xuICAgIGNvbnN0IGlkUHJvcCA9IHRoaXMucHJvcHNEaWN0LmlkO1xuICAgIGlmICghaWRQcm9wKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEVudGl0eSAke3RoaXMuaWR97JeQIGlkIO2VhOuTnOqwgCDsl4bsirXri4jri6RgKTtcbiAgICB9XG4gICAgaWYgKGlkUHJvcC50eXBlID09PSBcInN0cmluZ1wiIHx8IGlkUHJvcC50eXBlID09PSBcInV1aWRcIikge1xuICAgICAgcmV0dXJuIGlkUHJvcC50eXBlO1xuICAgIH1cbiAgICByZXR1cm4gXCJpbnRlZ2VyXCI7XG4gIH1cblxuICAvKipcbiAgICog7JeU7Yuw7Yuw7J2YIFBLIHByb3DsnYQg67CY7ZmY7ZWp64uI64ukLlxuICAgKiBsZW5ndGgg65OxIOyEuOu2gCDsoJXrs7Tsl5Ag7KCR6re87ZWgIOuVjCDsgqzsmqntlanri4jri6QuXG4gICAqL1xuICBnZXRQa1Byb3AoKTogRW50aXR5UHJvcCB7XG4gICAgY29uc3QgaWRQcm9wID0gdGhpcy5wcm9wc0RpY3QuaWQ7XG4gICAgaWYgKCFpZFByb3ApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRW50aXR5ICR7dGhpcy5pZH3sl5AgaWQg7ZWE65Oc6rCAIOyXhuyKteuLiOuLpGApO1xuICAgIH1cbiAgICByZXR1cm4gaWRQcm9wO1xuICB9XG5cbiAgLyoqXG4gICAqIOyXlO2LsO2LsOydmCBQSyDrsLDsl7Qg7YOA7J6F7J2EIOuwmO2ZmO2VqeuLiOuLpC5cbiAgICogTG9hZGVyUXVlcnnsnZggZnJvbUlkcyDtg4DsnoXsnLzroZwg7IKs7Jqp65Cp64uI64ukLlxuICAgKi9cbiAgZ2V0UGtBcnJheVR5cGUoKTogc3RyaW5nIHtcbiAgICBjb25zdCBwa1R5cGUgPSB0aGlzLmdldFBrVHlwZSgpO1xuICAgIHJldHVybiBwa1R5cGUgPT09IFwiaW50ZWdlclwiID8gXCJudW1iZXJbXVwiIDogXCJzdHJpbmdbXVwiO1xuICB9XG59XG4iXSwibmFtZXMiOlsiYXNzZXJ0Iiwid3JpdGVGaWxlIiwiaW5mbGVjdGlvbiIsInBhdGgiLCJncm91cCIsInVuaXF1ZSIsInoiLCJTb25hbXUiLCJnZXRFbnVtRGVmVmFsdWVzIiwiZ2V0U3Vic2V0RmllbGRzIiwiaXNCZWxvbmdzVG9PbmVSZWxhdGlvblByb3AiLCJpc0VudW1Qcm9wIiwiaXNIYXNNYW55UmVsYXRpb25Qcm9wIiwiaXNJbnRlcm5hbFN1YnNldEZpZWxkIiwiaXNNYW55VG9NYW55UmVsYXRpb25Qcm9wIiwiaXNPbmVUb09uZVJlbGF0aW9uUHJvcCIsImlzUmVsYXRpb25Qcm9wIiwiaXNWaXJ0dWFsQ29kZVByb3AiLCJpc1ZpcnR1YWxQcm9wIiwibm9ybWFsaXplU3Vic2V0RmllbGQiLCJpbXBvcnRNZW1iZXJzIiwiZm9ybWF0Q29kZSIsImV4aXN0cyIsInJ1bnRpbWVQYXRoIiwiYXNzZXJ0RGVmaW5lZCIsIm5vbk51bGxhYmxlIiwiRW50aXR5TWFuYWdlciIsIkVudGl0eSIsImlkIiwicGFyZW50SWQiLCJ0YWJsZSIsInRpdGxlIiwiY29uZSIsIm5hbWVzIiwicHJvcHMiLCJwcm9wc0RpY3QiLCJyZWxhdGlvbnMiLCJpbmRleGVzIiwic3Vic2V0cyIsInN1YnNldHNJbnRlcm5hbCIsInR5cGVzIiwiZW51bXMiLCJlbnVtTGFiZWxzIiwiZW51bUNvbmVzIiwic3Vic2V0Q29uZXMiLCJ1bmRlcnNjb3JlIiwicGx1cmFsaXplIiwibWFwIiwicHJvcCIsImluY2x1ZGVzIiwicmVwbGFjZSIsIk9iamVjdCIsImZyb21FbnRyaWVzIiwibmFtZSIsImZpbHRlciIsImtleSIsInN1YnNldERlZiIsImVudHJpZXMiLCJmaWVsZHMiLCJmIiwiQXJyYXkiLCJpc0FycmF5IiwiZW51bURlZiIsImVudW1MYWJlbCIsImVudW0iLCJrZXlzIiwicGFyZW50RnMiLCJkYXNoZXJpemUiLCJ0b0xvd2VyQ2FzZSIsImZzIiwibW9kdWxlIiwiZ2V0U3Vic2V0RmllbGRzRm9yUXVlcnkiLCJzdWJzZXRLZXkiLCJnZXRQdXJpU3Vic2V0UXVlcnkiLCJzdWJzZXQiLCJzdWJzZXRRdWVyeSIsInJlc29sdmVTdWJzZXRRdWVyeSIsImxpbmVzIiwicHVzaCIsImpvaW4iLCJqb2lucyIsImpvaW5NZXRob2QiLCJhcyIsImN1c3RvbSIsImZyb20iLCJ0byIsInNlbGVjdE9iaiIsImJ1aWxkTmVzdGVkU2VsZWN0T2JqZWN0Iiwic2VsZWN0Iiwic3RyaW5naWZ5TmVzdGVkU2VsZWN0T2JqZWN0Iiwic2VsZWN0SXRlbXMiLCJyZXN1bHQiLCJzZWxlY3RJdGVtIiwibWF0Y2giLCJjb2x1bW4iLCJhbGlhcyIsImNvbHVtblZhbHVlIiwidHJpbSIsInNwbGl0IiwicG9wIiwicGFydHMiLCJjdXJyZW50IiwiaSIsImxlbmd0aCIsInBhcnQiLCJFcnJvciIsInNsaWNlIiwibGFzdFBhcnQiLCJvYmoiLCJpbmRlbnQiLCJ3aXRoQnJhY2VzIiwic3BhY2VzIiwicmVwZWF0IiwiaW5uZXJTcGFjZXMiLCJ2YWx1ZSIsImdldFB1cmlMb2FkZXJRdWVyeSIsImxvYWRlcnMiLCJnZW5lcmF0ZUxvYWRlckNvZGUiLCJsb2FkZXJMaW5lcyIsImxvYWRlciIsInRvVGFibGUiLCJ0b0NvbCIsInRocm91Z2giLCJmcm9tVGFibGUiLCJtYW55Sm9pbiIsImZyb21FbnRpdHkiLCJnZXRCeVRhYmxlIiwiZnJvbUlkc1R5cGUiLCJnZXRQa0FycmF5VHlwZSIsImlkRmllbGQiLCJ1bmRlZmluZWQiLCJvbmVKb2lucyIsImZvckVhY2giLCJyZWZJZCIsImZyb21Db2wiLCJnZXRTdWJzZXRRdWVyeSIsInByZWZpeCIsImlzQWxyZWFkeU91dGVySm9pbmVkIiwic3Vic2V0R3JvdXAiLCJmaWVsZCIsInJlbCIsInJlZHVjZSIsInIiLCJncm91cEtleSIsInJlYWxGaWVsZHMiLCJ2aXJ0dWFsQ29kZUZpZWxkcyIsImNvbmNhdCIsImdldEZ1bGxGaWVsZE5hbWUiLCJ2aXJ0dWFsIiwicmVsYXRpb24iLCJyZWxFbnRpdHkiLCJnZXQiLCJ3aXRoIiwicmVsRmllbGRzIiwiaW5uZXJPck91dGVyIiwiaGFzSm9pbkNvbHVtbiIsIm51bGxhYmxlIiwicmVsU3Vic2V0UXVlcnkiLCJqb2luQXMiLCJqb2luQ2xhdXNlIiwiY3VzdG9tSm9pbkNsYXVzZSIsImNvbnZlcnRlZExvYWRlcnMiLCJuZXdBcyIsImZyb21Db2x1bW4iLCJqb2luQ29sdW1uIiwiam9pblRhYmxlIiwic2luZ3VsYXJpemUiLCJmaWVsZEV4cHJzVG9Qcm9wTm9kZXMiLCJmaWVsZEV4cHJzIiwiZW50aXR5IiwiZ3JvdXBzIiwiZmllbGRFeHByIiwiZWxzZUV4cHIiLCJmbGF0TWFwIiwicHJvcE5hbWUiLCJmaW5kIiwicCIsIm5vZGVUeXBlIiwiaWRQcm9wIiwiY2hpbGRyZW4iLCJnZXRGaWVsZEV4cHJzIiwibWF4RGVwdGgiLCJmcm9tcyIsInYiLCJyZWxNZCIsImhhc0ZvcmVpZ25LZXkiLCJyZWxhdGlvblR5cGUiLCJnZXRUYWJsZUNvbHVtbnMiLCJ0eXBlIiwiZ2V0VmVjdG9yQ29sdW1ucyIsImdldFZlY3RvckNvbHVtbiIsImNvbHVtbk5hbWUiLCJ2ZWN0b3JQcm9wcyIsImdldEZpbHRlcmFibGVQcm9wcyIsInJlZ2lzdGVyTW9kdWxlUGF0aHMiLCJiYXNlUGF0aCIsInNldE1vZHVsZVBhdGgiLCJ0b1VwcGVyQ2FzZSIsImVudW1JZCIsInR5cGVzTW9kdWxlUGF0aCIsInR5cGVzRmlsZVBhdGgiLCJhcGlSb290UGF0aCIsImltcG9ydGVkTWVtYmVycyIsInJlZ2lzdGVyVGFibGVTcGVjcyIsInVuaXF1ZUluZGV4ZXMiLCJpZHgiLCJjb2x1bW5zIiwiZXZlcnkiLCJjb2wiLCJzZXRUYWJsZVNwZWMiLCJqc29uQ29sdW1ucyIsInRvSnNvbiIsIm5vcm1hbEZpZWxkcyIsImludGVybmFsRmllbGRzIiwiaW50ZXJuYWwiLCJ2YWx1ZXMiLCJzYXZlIiwic3Vic2V0Um93cyIsImdldFN1YnNldFJvd3MiLCJzdWJzZXRSb3dzVG9TdWJzZXRGaWVsZHMiLCJqc29uUGF0aCIsImpzb24iLCJKU09OIiwic3RyaW5naWZ5IiwicmVnaXN0ZXIiLCJnZW5lcmF0ZVRlbXBsYXRlQ29uZXMiLCJsb2NhbGUiLCJjb25maWdMb2NhbGUiLCJjb25maWciLCJpMThuIiwiZGVmYXVsdExvY2FsZSIsImVmZmVjdGl2ZUxvY2FsZSIsImVudGl0eUNvbmUiLCJwcm9wQ29uZXMiLCJnZW5lcmF0ZUNvbmVzIiwib3B0aW9ucyIsImNvbnRleHQiLCJleGlzdGluZ0NvbmVzIiwicHJlc2VydmVFeGlzdGluZyIsImNvbGxlY3RFeGlzdGluZ0NvbmVzIiwib25seUVtcHR5IiwiYXBwbHlDb25lcyIsImNvbmVzIiwiX3N1YnNldHMiLCJfc3Vic2V0c0ludGVybmFsIiwicHJlZml4ZXMiLCJzdWJzZXRLZXlzIiwiYWxsRmllbGRzIiwiYWxsSW50ZXJuYWxGaWVsZHMiLCJjb21iaW5lZEZpZWxkcyIsInN0YXJ0c1dpdGgiLCJyZWxhdGlvbkVudGl0eSIsImlzT3BlbiIsImhhcyIsImNoaWxkIiwiaXNJbnRlcm5hbCIsInN1YnNldEZpZWxkcyIsInNvbWUiLCJoYXNLZXkiLCJzdWJzZXRSb3ciLCJmbGF0IiwiY3JlYXRlUHJvcCIsImF0Iiwic3BsaWNlIiwiYW5hbHl6ZVN1YnNldEZpZWxkIiwic3Vic2V0RmllbGQiLCJhcnIiLCJlbnRpdHlJZCIsIm1vZGlmeVByb3AiLCJuZXdQcm9wIiwib2xkTmFtZSIsImVudGl0aWVzIiwiYWxsRW50aXR5SWRzIiwiZ2V0QWxsSWRzIiwicmVsRW50aXR5SWQiLCJyZWxFbnRpdHlTdWJzZXRLZXlzIiwibW9kaWZpZWRTdWJzZXRGaWVsZHMiLCJhbmFseXplZCIsIm1vZGlmaWVkIiwiYSIsIlByb21pc2UiLCJhbGwiLCJkZWxQcm9wIiwiaW5kZXgiLCJnZXRFbnRpdHlJZEZyb21TdWJzZXRGaWVsZCIsImxhc3RFbnRpdHlJZCIsInJlbFByb3AiLCJjb25zb2xlIiwiZGVidWciLCJ0aGlzSWQiLCJtb3ZlUHJvcCIsIm5ld1Byb3BzIiwiZ2V0UGtUeXBlIiwiZ2V0UGtQcm9wIiwicGtUeXBlIl0sIm1hcHBpbmdzIjoiQUFBQSxPQUFPQSxZQUFZLFNBQVM7QUFDNUIsU0FBU0MsU0FBUyxRQUFRLG1CQUFjO0FBQ3hDLE9BQU9DLGdCQUFnQixhQUFhO0FBQ3BDLE9BQU9DLFVBQVUsT0FBTztBQUN4QixTQUFTQyxLQUFLLEVBQUVDLE1BQU0sUUFBUSxVQUFVO0FBQ3hDLFNBQVNDLENBQUMsUUFBUSxNQUFNO0FBQ3hCLFNBQVNDLE1BQU0sUUFBUSxtQkFBZ0I7QUFDdkMs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
952
+ //#endregion
953
+ init_entity();
954
+ export { Entity, init_entity };
955
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5LmpzIiwibmFtZXMiOlsieiIsImxpbmVzOiBzdHJpbmdbXSIsImpvaW4iLCJyZXN1bHQ6IFJldHVyblR5cGU8dHlwZW9mIHRoaXMuYnVpbGROZXN0ZWRTZWxlY3RPYmplY3Q+IiwibG9hZGVyTGluZXM6IHN0cmluZ1tdIiwibG9hZGVycyIsInJlc3VsdDogU3Vic2V0UXVlcnkiLCJmaWVsZHMiLCJqb2luQ2xhdXNlOlxuICAgICAgICAgICAgfCB7XG4gICAgICAgICAgICAgICAgZnJvbTogc3RyaW5nO1xuICAgICAgICAgICAgICAgIHRvOiBzdHJpbmc7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHwge1xuICAgICAgICAgICAgICAgIGN1c3RvbTogc3RyaW5nO1xuICAgICAgICAgICAgICB9IiwiZnJvbTogc3RyaW5nIiwidG86IHN0cmluZyIsIm1hbnlKb2luOiBTdWJzZXRRdWVyeVtcImxvYWRlcnNcIl1bbnVtYmVyXVtcIm1hbnlKb2luXCJdIiwia2V5OiBzdHJpbmciLCJ2YWx1ZTogc3RyaW5nIiwiZWxzZUV4cHI6IHN0cmluZ1tdIiwiZ3JvdXAiLCJwcm9wIiwic3Vic2V0czogeyBba2V5OiBzdHJpbmddOiBpbXBvcnQoXCIuLi90eXBlcy90eXBlc1wiKS5TdWJzZXREZWYgfSIsIm5vcm1hbEZpZWxkczogU3Vic2V0RmllbGRbXSIsImludGVybmFsRmllbGRzOiBTdWJzZXRGaWVsZFtdIiwiZW51bXM6IHsgW2tleTogc3RyaW5nXTogaW1wb3J0KFwiLi4vdHlwZXMvdHlwZXNcIikuRW51bURlZiB9IiwiY29udGV4dDogaW1wb3J0KFwiLi4vY29uZS9jb25lLWdlbmVyYXRvclwiKS5Db25lR2VuZXJhdGlvbkNvbnRleHQiLCJjb25lczogUmVjb3JkPHN0cmluZywgQ29uZT4iLCJyZXN1bHQ6IHtcbiAgICAgIGVudGl0eUlkOiBzdHJpbmc7XG4gICAgICBwcm9wTmFtZTogc3RyaW5nO1xuICAgIH1bXSIsImVudGl0aWVzOiBFbnRpdHlbXSJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9lbnRpdHkvZW50aXR5LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuaW1wb3J0IHsgd3JpdGVGaWxlIH0gZnJvbSBcImZzL3Byb21pc2VzXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuXG5pbXBvcnQgaW5mbGVjdGlvbiBmcm9tIFwiaW5mbGVjdGlvblwiO1xuaW1wb3J0IHsgZ3JvdXAsIHVuaXF1ZSB9IGZyb20gXCJyYWRhc2hpXCI7XG5pbXBvcnQgeyB6IH0gZnJvbSBcInpvZFwiO1xuXG5pbXBvcnQgeyBTb25hbXUgfSBmcm9tIFwiLi4vYXBpL3NvbmFtdVwiO1xuaW1wb3J0IHtcbiAgZ2V0RW51bURlZlZhbHVlcyxcbiAgZ2V0U3Vic2V0RmllbGRzLFxuICBpc0JlbG9uZ3NUb09uZVJlbGF0aW9uUHJvcCxcbiAgaXNFbnVtUHJvcCxcbiAgaXNIYXNNYW55UmVsYXRpb25Qcm9wLFxuICBpc0ludGVybmFsU3Vic2V0RmllbGQsXG4gIGlzTWFueVRvTWFueVJlbGF0aW9uUHJvcCxcbiAgaXNPbmVUb09uZVJlbGF0aW9uUHJvcCxcbiAgaXNSZWxhdGlvblByb3AsXG4gIGlzVmlydHVhbENvZGVQcm9wLFxuICBpc1ZpcnR1YWxQcm9wLFxuICBub3JtYWxpemVTdWJzZXRGaWVsZCxcbn0gZnJvbSBcIi4uL3R5cGVzL3R5cGVzXCI7XG5pbXBvcnQge1xuICB0eXBlIENvbmUsXG4gIHR5cGUgRW50aXR5SW5kZXgsXG4gIHR5cGUgRW50aXR5SnNvbixcbiAgdHlwZSBFbnRpdHlQcm9wLFxuICB0eXBlIEVudGl0eVByb3BOb2RlLFxuICB0eXBlIEVudGl0eVN1YnNldFJvdyxcbiAgdHlwZSBSZWxhdGlvblByb3AsXG4gIHR5cGUgU3Vic2V0RmllbGQsXG4gIHR5cGUgU3Vic2V0UXVlcnksXG59IGZyb20gXCIuLi90eXBlcy90eXBlc1wiO1xuaW1wb3J0IHsgaW1wb3J0TWVtYmVycyB9IGZyb20gXCIuLi91dGlscy9lc20tdXRpbHNcIjtcbmltcG9ydCB7IGZvcm1hdENvZGUgfSBmcm9tIFwiLi4vdXRpbHMvZm9ybWF0dGVyXCI7XG5pbXBvcnQgeyBleGlzdHMgfSBmcm9tIFwiLi4vdXRpbHMvZnMtdXRpbHNcIjtcbmltcG9ydCB7IHJ1bnRpbWVQYXRoIH0gZnJvbSBcIi4uL3V0aWxzL3BhdGgtdXRpbHNcIjtcbmltcG9ydCB7IGFzc2VydERlZmluZWQsIG5vbk51bGxhYmxlIH0gZnJvbSBcIi4uL3V0aWxzL3V0aWxzXCI7XG5pbXBvcnQgeyBFbnRpdHlNYW5hZ2VyIH0gZnJvbSBcIi4vZW50aXR5LW1hbmFnZXJcIjtcblxuZXhwb3J0IGNsYXNzIEVudGl0eSB7XG4gIGlkOiBzdHJpbmc7XG4gIHBhcmVudElkPzogc3RyaW5nO1xuICB0YWJsZTogc3RyaW5nO1xuICB0aXRsZTogc3RyaW5nO1xuICBjb25lPzogQ29uZTtcbiAgbmFtZXM6IHtcbiAgICBwYXJlbnRGczogc3RyaW5nO1xuICAgIGZzOiBzdHJpbmc7XG4gICAgbW9kdWxlOiBzdHJpbmc7XG4gIH07XG4gIHByb3BzOiBFbnRpdHlQcm9wW107XG4gIHByb3BzRGljdDoge1xuICAgIFtrZXk6IHN0cmluZ106IEVudGl0eVByb3A7XG4gIH07XG4gIHJlbGF0aW9uczoge1xuICAgIFtrZXk6IHN0cmluZ106IFJlbGF0aW9uUHJvcDtcbiAgfTtcbiAgaW5kZXhlczogRW50aXR5SW5kZXhbXTtcbiAgc3Vic2V0czoge1xuICAgIFtrZXk6IHN0cmluZ106IHN0cmluZ1tdO1xuICB9O1xuICBzdWJzZXRzSW50ZXJuYWw6IHtcbiAgICBba2V5OiBzdHJpbmddOiBzdHJpbmdbXTtcbiAgfTtcbiAgdHlwZXM6IHtcbiAgICBbbmFtZTogc3RyaW5nXTogei5ab2RUeXBlQW55O1xuICB9ID0ge307XG4gIGVudW1zOiB7XG4gICAgW2VudW1JZDogc3RyaW5nXTogei5ab2RFbnVtPFJlYWRvbmx5PFJlY29yZDxzdHJpbmcsIHN0cmluZz4+PjtcbiAgfSA9IHt9O1xuICBlbnVtTGFiZWxzOiB7XG4gICAgW2VudW1JZDogc3RyaW5nXToge1xuICAgICAgW2tleTogc3RyaW5nXTogc3RyaW5nO1xuICAgIH07XG4gIH0gPSB7fTtcbiAgZW51bUNvbmVzOiB7XG4gICAgW2VudW1JZDogc3RyaW5nXTogQ29uZTtcbiAgfSA9IHt9O1xuICBzdWJzZXRDb25lczoge1xuICAgIFtzdWJzZXRLZXk6IHN0cmluZ106IENvbmU7XG4gIH0gPSB7fTtcblxuICBjb25zdHJ1Y3Rvcih7IGlkLCBwYXJlbnRJZCwgdGFibGUsIHRpdGxlLCBjb25lLCBwcm9wcywgaW5kZXhlcywgc3Vic2V0cywgZW51bXMgfTogRW50aXR5SnNvbikge1xuICAgIC8vIGlkXG4gICAgdGhpcy5pZCA9IGlkO1xuICAgIHRoaXMucGFyZW50SWQgPSBwYXJlbnRJZDtcbiAgICB0aGlzLnRpdGxlID0gdGl0bGUgPz8gdGhpcy5pZDtcbiAgICB0aGlzLnRhYmxlID0gdGFibGUgPz8gaW5mbGVjdGlvbi51bmRlcnNjb3JlKGluZmxlY3Rpb24ucGx1cmFsaXplKGlkKSk7XG4gICAgdGhpcy5jb25lID0gY29uZTtcblxuICAgIC8vIHByb3BzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICB0aGlzLnByb3BzID0gcHJvcHMubWFwKChwcm9wKSA9PiB7XG4gICAgICAgIGlmIChpc0VudW1Qcm9wKHByb3ApKSB7XG4gICAgICAgICAgaWYgKHByb3AuaWQuaW5jbHVkZXMoXCIkTW9kZWxcIikpIHtcbiAgICAgICAgICAgIHByb3AuaWQgPSBwcm9wLmlkLnJlcGxhY2UoXCIkTW9kZWxcIiwgaWQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcHJvcDtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5wcm9wc0RpY3QgPSBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgICAgIHByb3BzLm1hcCgocHJvcCkgPT4ge1xuICAgICAgICAgIHJldHVybiBbcHJvcC5uYW1lLCBwcm9wXTtcbiAgICAgICAgfSksXG4gICAgICApO1xuXG4gICAgICAvLyByZWxhdGlvbnNcbiAgICAgIHRoaXMucmVsYXRpb25zID0gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgICBwcm9wcy5maWx0ZXIoKHByb3ApID0+IGlzUmVsYXRpb25Qcm9wKHByb3ApKS5tYXAoKHByb3ApID0+IFtwcm9wLm5hbWUsIHByb3BdKSxcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMucHJvcHMgPSBbXTtcbiAgICAgIHRoaXMucHJvcHNEaWN0ID0ge307XG4gICAgICB0aGlzLnJlbGF0aW9ucyA9IHt9O1xuICAgIH1cblxuICAgIC8vIGluZGV4ZXNcbiAgICB0aGlzLmluZGV4ZXMgPSBpbmRleGVzID8/IFtdO1xuXG4gICAgLy8gc3Vic2V0czogU3Vic2V0RGVm7JeQ7IScIFN1YnNldEZpZWxkW13rpbwg7LaU7Lac7ZWY7JesIHN1YnNldHMo7J2867CYKeyZgCBzdWJzZXRzSW50ZXJuYWwoaW50ZXJuYWwp66GcIOu2hOumrFxuICAgIHRoaXMuc3Vic2V0cyA9IHt9O1xuICAgIHRoaXMuc3Vic2V0c0ludGVybmFsID0ge307XG4gICAgZm9yIChjb25zdCBba2V5LCBzdWJzZXREZWZdIG9mIE9iamVjdC5lbnRyaWVzKHN1YnNldHMgPz8ge30pKSB7XG4gICAgICBjb25zdCBmaWVsZHMgPSBnZXRTdWJzZXRGaWVsZHMoc3Vic2V0RGVmKTtcbiAgICAgIHRoaXMuc3Vic2V0c1trZXldID0gZmllbGRzLmZpbHRlcigoZikgPT4gIWlzSW50ZXJuYWxTdWJzZXRGaWVsZChmKSkubWFwKG5vcm1hbGl6ZVN1YnNldEZpZWxkKTtcbiAgICAgIHRoaXMuc3Vic2V0c0ludGVybmFsW2tleV0gPSBmaWVsZHMuZmlsdGVyKGlzSW50ZXJuYWxTdWJzZXRGaWVsZCkubWFwKG5vcm1hbGl6ZVN1YnNldEZpZWxkKTtcblxuICAgICAgLy8gY29uZSDstpTstpxcbiAgICAgIGlmICghQXJyYXkuaXNBcnJheShzdWJzZXREZWYpICYmIFwiY29uZVwiIGluIHN1YnNldERlZiAmJiBzdWJzZXREZWYuY29uZSkge1xuICAgICAgICB0aGlzLnN1YnNldENvbmVzW2tleV0gPSBzdWJzZXREZWYuY29uZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBlbnVtczogRW51bURlZuyXkOyEnCB2YWx1ZXPsmYAgY29uZeulvCDstpTstpztlZjsl6wg7LKY66asXG4gICAgdGhpcy5lbnVtTGFiZWxzID0gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgT2JqZWN0LmVudHJpZXMoZW51bXMgPz8ge30pLm1hcCgoW2tleSwgZW51bURlZl0pID0+IHtcbiAgICAgICAgLy8gY29uZSDstpTstpxcbiAgICAgICAgaWYgKFwidmFsdWVzXCIgaW4gZW51bURlZiAmJiBcImNvbmVcIiBpbiBlbnVtRGVmICYmIGVudW1EZWYuY29uZSkge1xuICAgICAgICAgIHRoaXMuZW51bUNvbmVzW2tleV0gPSBlbnVtRGVmLmNvbmUgYXMgQ29uZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gW2tleSwgZ2V0RW51bURlZlZhbHVlcyhlbnVtRGVmKV07XG4gICAgICB9KSxcbiAgICApO1xuICAgIHRoaXMuZW51bXMgPSBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgICBPYmplY3QuZW50cmllcyh0aGlzLmVudW1MYWJlbHMpLm1hcCgoW2tleSwgZW51bUxhYmVsXSkgPT4ge1xuICAgICAgICByZXR1cm4gW2tleSwgei5lbnVtKE9iamVjdC5rZXlzKGVudW1MYWJlbCkgYXMgdW5rbm93biBhcyByZWFkb25seSBbc3RyaW5nLCAuLi5zdHJpbmdbXV0pXTtcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICAvLyBuYW1lc1xuICAgIHRoaXMubmFtZXMgPSB7XG4gICAgICBwYXJlbnRGczogaW5mbGVjdGlvbi5kYXNoZXJpemUoaW5mbGVjdGlvbi51bmRlcnNjb3JlKHBhcmVudElkID8/IGlkKSkudG9Mb3dlckNhc2UoKSxcbiAgICAgIGZzOiBpbmZsZWN0aW9uLmRhc2hlcml6ZShpbmZsZWN0aW9uLnVuZGVyc2NvcmUoaWQpKS50b0xvd2VyQ2FzZSgpLFxuICAgICAgbW9kdWxlOiBpZCxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIOy/vOumrOyaqSDshJzruIzshYsg7ZWE65Oc66W8IOuwmO2ZmO2VqeuLiOuLpCAoc3Vic2V0cyArIHN1YnNldHNJbnRlcm5hbCDtlansuagpXG4gICAqL1xuICBnZXRTdWJzZXRGaWVsZHNGb3JRdWVyeShzdWJzZXRLZXk6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gWy4uLih0aGlzLnN1YnNldHNbc3Vic2V0S2V5XSA/PyBbXSksIC4uLih0aGlzLnN1YnNldHNJbnRlcm5hbFtzdWJzZXRLZXldID8/IFtdKV07XG4gIH1cblxuICAvKipcbiAgICog7KO87Ja07KeEIOydtOumhChzdWJzZXRLZXkp7J2YIHN1YnNldOydhCDsi6TsoJzroZwg6rCA7KC47Jik64qUIFB1cmkg7L2U65OcIOq1rO2YhOyytCBzdHJpbmfsnYQg67CY7ZmY7ZWp64uI64ukLlxuICAgKi9cbiAgZ2V0UHVyaVN1YnNldFF1ZXJ5KHN1YnNldEtleTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBzdWJzZXQgPSB0aGlzLmdldFN1YnNldEZpZWxkc0ZvclF1ZXJ5KHN1YnNldEtleSk7XG4gICAgY29uc3Qgc3Vic2V0UXVlcnkgPSB0aGlzLnJlc29sdmVTdWJzZXRRdWVyeShcIlwiLCBzdWJzZXQpO1xuXG4gICAgY29uc3QgbGluZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICAvLyBmcm9tXG4gICAgbGluZXMucHVzaChgcmV0dXJuIHFiV3JhcHBlcmApO1xuICAgIGxpbmVzLnB1c2goYC5mcm9tKFwiJHt0aGlzLnRhYmxlfVwiKWApO1xuXG4gICAgLy8gam9pblxuICAgIGZvciAoY29uc3Qgam9pbiBvZiBzdWJzZXRRdWVyeS5qb2lucykge1xuICAgICAgLy8gam9pbiDrqZTshJzrk5wg6rKw7KCVOiBpbm5lciDihpIgam9pbiwgb3V0ZXIg4oaSIGxlZnRKb2luXG4gICAgICAvLyBGSyBudWxsYWJsZSDsl6zrtoDripQgbGVmdEpvaW4g7YOA7J6FIOyLnOq3uOuLiOyymOyXkOyEnCDsnpDrj5nsnLzroZwg7YyQ64uo65CoXG4gICAgICBjb25zdCBqb2luTWV0aG9kID0gam9pbi5qb2luID09PSBcImlubmVyXCIgPyBcImpvaW5cIiA6IFwibGVmdEpvaW5cIjtcblxuICAgICAgaWYgKFwiY3VzdG9tXCIgaW4gam9pbikge1xuICAgICAgICAvLyBjdXN0b20gam9pbiBjbGF1c2XripQgcmF3IOyCrOyaqVxuICAgICAgICBsaW5lcy5wdXNoKFxuICAgICAgICAgIGAuJHtqb2luTWV0aG9kfSh7ICR7am9pbi5hc306IFwiJHtqb2luLnRhYmxlfVwiIH0sIHFiV3JhcHBlci5rbmV4LnJhdyhcXGAke2pvaW4uY3VzdG9tfVxcYCkpYCxcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxpbmVzLnB1c2goYC4ke2pvaW5NZXRob2R9KHsgJHtqb2luLmFzfTogXCIke2pvaW4udGFibGV9XCIgfSwgXCIke2pvaW4uZnJvbX1cIiwgXCIke2pvaW4udG99XCIpYCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gc2VsZWN0IC0g7J6F7LK07KCBIOq1rOyhsOuhnCDsg53shLFcbiAgICBjb25zdCBzZWxlY3RPYmogPSB0aGlzLmJ1aWxkTmVzdGVkU2VsZWN0T2JqZWN0KHN1YnNldFF1ZXJ5LnNlbGVjdCk7XG4gICAgbGluZXMucHVzaChgLnNlbGVjdCgke3RoaXMuc3RyaW5naWZ5TmVzdGVkU2VsZWN0T2JqZWN0KHNlbGVjdE9iail9KTtgKTtcblxuICAgIHJldHVybiBsaW5lcy5qb2luKFwiXFxuXCIpO1xuICB9XG5cbiAgLyoqXG4gICAqICouZW50aXR5Lmpzb27snZggc3Vic2V07JeQIOuTpOyWtOyeiOuKlCDtlYTrk5wg67Cw7Je07J2EIOuwm+yVhOyEnCxcbiAgICogUHVyaeydmCBTZWxlY3RPYmplY3Qg7YOA7J6F7Jy866GcIOuzgO2ZmO2VqeuLiOuLpC5cbiAgICpcbiAgICog7JiIOiBbXCJ1c2Vycy5pZFwiLCBcInBhcmVudC5pZFwiLCBcInBhcmVudC5uYW1lXCJdXG4gICAqICAg4oaSIHsgaWQ6IFwidXNlcnMuaWRcIiwgcGFyZW50OiB7IGlkOiBcInBhcmVudC5pZFwiLCBuYW1lOiBcInBhcmVudC5uYW1lXCIgfSB9XG4gICAqXG4gICAqIOyWuOuNlOuwlOqwgCDslYTri4wg7KSR7LKpIOqwneyytOuhnCDrs4DtmZjtlajsl5Ag7Jyg7J2Y7ZWY7IS47JqULlxuICAgKiDsnbTroIfqsowg7KSR7LKpIOqwneyytOuhnCDrs4DtmZjtlZjsl6wgc2VsZWN07JeQIOuEmOqyqOyjvOuptCBQYXJzZVNlbGVjdE9iamVjdCDtg4DsnoXsnbQgam9pbuuQnCDqsJ3ssrTsnZgg7YOA7J6F7J2EIOyemCDsnqHslYTspIQg7IiYIOyeiOyKteuLiOuLpC5cbiAgICog7KaJLCBlbmhhbmNlcuyXkOyEnCByb3frpbwg67Cb7JWY7J2EIOuVjCBoeWRyYXRl65CcIOqwneyytCDsnpDssrTsnZggbnVsbGl0eeyZgCDqt7gg7JWI7Kq9IO2VhOuTnOydmCBudWxsaXR56rCAIGZrIG51bGxhYmxlIOyXrOu2gOyXkCDrlLDrnbwg7J6YIOy2lOuhoOuQqeuLiOuLpC5cbiAgICovXG4gIHByaXZhdGUgYnVpbGROZXN0ZWRTZWxlY3RPYmplY3QoXG4gICAgc2VsZWN0SXRlbXM6IHN0cmluZ1tdLFxuICAgIC8vIG94bGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55IC0tIOuwmO2ZmCDsmKTruIzsoJ3tirjsnZgg6rCS7J2AIHN0cmluZ+ydvCDsiJjrj4Qg7J6I6rOgIOuYkOuLpOuluCDsmKTruIzsoJ3tirjsnbwg7IiY64+EIOyeiOuKlOuNsCwg7J2066W8IOyerOq3gCDtg4DsnoXsnLzroZwg64KY7YOA64K8IOyImCDsl4bslrQgYW5566GcIOyymOumrO2VqeuLiOuLpC5cbiAgKTogUmVjb3JkPHN0cmluZywgYW55PiB7XG4gICAgY29uc3QgcmVzdWx0OiBSZXR1cm5UeXBlPHR5cGVvZiB0aGlzLmJ1aWxkTmVzdGVkU2VsZWN0T2JqZWN0PiA9IHt9O1xuXG4gICAgZm9yIChjb25zdCBzZWxlY3RJdGVtIG9mIHNlbGVjdEl0ZW1zKSB7XG4gICAgICAvLyBcInVzZXJzLmlkXCIg65iQ64qUIFwidXNlcnMuaWQgYXMgdXNlcl9faWRcIiDtmJXtg5wg7YyM7IuxXG4gICAgICBjb25zdCBtYXRjaCA9IHNlbGVjdEl0ZW0ubWF0Y2goL14oLis/KSg/OiBhcyAoLispKT8kLyk7XG4gICAgICBpZiAoIW1hdGNoKSBjb250aW51ZTtcblxuICAgICAgY29uc3QgWywgY29sdW1uLCBhbGlhc10gPSBtYXRjaDtcbiAgICAgIGNvbnN0IGNvbHVtblZhbHVlID0gYFwiJHtjb2x1bW4udHJpbSgpfVwiYDtcblxuICAgICAgaWYgKCFhbGlhcyB8fCAhYWxpYXMuaW5jbHVkZXMoXCJfX1wiKSkge1xuICAgICAgICAvLyBhbGlhc+qwgCDsl4bqsbDrgpggX1/rpbwg7Y+s7ZWo7ZWY7KeAIOyViuycvOuptCDstZzsg4HsnIQg7ZWE65OcXG4gICAgICAgIGNvbnN0IGtleSA9IGFsaWFzID8/IGFzc2VydERlZmluZWQoY29sdW1uLnNwbGl0KFwiLlwiKS5wb3AoKSk7XG4gICAgICAgIHJlc3VsdFtrZXldID0gY29sdW1uVmFsdWU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBhbGlhc+qwgCBfX+ulvCDtj6ztlajtlZjrqbQg7J6F7LK0IOq1rOyhsOuhnCDqt7jro7ntmZRcbiAgICAgICAgY29uc3QgcGFydHMgPSBhbGlhcy5zcGxpdChcIl9fXCIpO1xuICAgICAgICBsZXQgY3VycmVudCA9IHJlc3VsdDtcblxuICAgICAgICAvLyDrp4jsp4Drp4kg7YyM7Yq4IOyghOq5jOyngCDspJHssqkg6rCd7LK0IOyDneyEsVxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBhcnRzLmxlbmd0aCAtIDE7IGkrKykge1xuICAgICAgICAgIGNvbnN0IHBhcnQgPSBwYXJ0c1tpXTtcbiAgICAgICAgICBpZiAocGFydCBpbiBjdXJyZW50KSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIGN1cnJlbnRbcGFydF0gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgICAgLy8g7J6F66Cl7J20IFtcInVzZXJcIiwgXCJ1c2VyX19pZFwiXSDqsJnsnYAg6rK97JqwIVxuICAgICAgICAgICAgICAvLyDslaDstIjsl5Ag66eQ64+EIOyViCDrkJjsp4Drp4wg7JWI7KCE7ZWY6rKMIOyYiOyZuOulvCDrjZjsp5Hri4jri6QuXG4gICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICBgQ29uZmxpY3QgZGV0ZWN0ZWQgaW4gc2VsZWN0IGl0ZW1zOiBwYXJlbnQgcGF0aCBcIiR7cGFydHMuc2xpY2UoMCwgaSArIDEpLmpvaW4oXCJfX1wiKX1cIiBpcyBhbHJlYWR5IHNldCBhcyBhIGZpZWxkLCBjYW5ub3QgbmVzdCBcIiR7YWxpYXN9XCIgdW5kZXIgaXQuYCxcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY3VycmVudFtwYXJ0XSA9IHt9O1xuICAgICAgICAgIH1cbiAgICAgICAgICBjdXJyZW50ID0gY3VycmVudFtwYXJ0XTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIOuniOyngOuniSDtjIztirjsl5Ag6rCSIOyEpOyglVxuICAgICAgICBjb25zdCBsYXN0UGFydCA9IHBhcnRzW3BhcnRzLmxlbmd0aCAtIDFdO1xuICAgICAgICBjdXJyZW50W2xhc3RQYXJ0XSA9IGNvbHVtblZhbHVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICogSlNPTi5zdHJpbmdpZnnsmYAg7Jyg7IKs7ZWcIOydvOydhCDtlanri4jri6QuXG4gICAqIOuLpOunjCDso7zslrTsp4Qg6rCd7LK066W8IEpTT07snbQg7JWE64uMIFR5cGVTY3JpcHQg6rCd7LK0IOumrO2EsOuftCDsiqTtirjrp4HsnLzroZwg66eM65Ok7Ja07KSN64uI64ukLlxuICAgKiBrZXnsl5Ag65Sw7Ji07ZGc6rCAIOyXhuyWtOyalC5cbiAgICog7Lac66ClIOyYiOyLnDpcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiB7XG4gICAqICAgaWQ6IFwidXNlcnMuaWRcIixcbiAgICogICBwYXJlbnQ6IHtcbiAgICogICAgIGlkOiBcInBhcmVudC5pZFwiLFxuICAgKiAgICAgbmFtZTogXCJwYXJlbnQubmFtZVwiLFxuICAgKiAgIH0sXG4gICAqIH1cbiAgICogYGBgXG4gICAqIEBwYXJhbSBvYmog67OA7ZmY7ZWgIOqwneyytFxuICAgKiBAcGFyYW0gaW5kZW50IOuTpOyXrOyTsOq4sCDroIjrsqhcbiAgICogQHBhcmFtIHdpdGhCcmFjZXMgdHJ1ZeuptCDspJHqtITtmLgg7Y+s7ZWoLCBmYWxzZeuptCDrgrTsmqnrp4wg67CY7ZmYXG4gICAqL1xuICBwcml2YXRlIHN0cmluZ2lmeU5lc3RlZFNlbGVjdE9iamVjdChcbiAgICAvLyBveGxpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueSAtLSDspJHssqkg7Jik67iM7KCd7Yq47J2YIOqwkuydgCBzdHJpbmfsnbwg7IiY64+EIOyeiOqzoCDrmJDri6Trpbgg7Jik67iM7KCd7Yq47J28IOyImOuPhCDsnojripTrjbAsIOydtOulvCDsnqzqt4Ag7YOA7J6F7Jy866GcIOuCmO2DgOuCvCDsiJgg7JeG7Ja0IGFueeuhnCDsspjrpqztlanri4jri6QuXG4gICAgb2JqOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICAgIGluZGVudDogbnVtYmVyID0gMCxcbiAgICB3aXRoQnJhY2VzOiBib29sZWFuID0gdHJ1ZSxcbiAgKTogc3RyaW5nIHtcbiAgICBjb25zdCBzcGFjZXMgPSBcIiAgXCIucmVwZWF0KGluZGVudCk7XG4gICAgY29uc3QgaW5uZXJTcGFjZXMgPSBcIiAgXCIucmVwZWF0KGluZGVudCArIDEpO1xuXG4gICAgY29uc3QgZW50cmllcyA9IE9iamVjdC5lbnRyaWVzKG9iaik7XG4gICAgaWYgKGVudHJpZXMubGVuZ3RoID09PSAwKSByZXR1cm4gd2l0aEJyYWNlcyA/IFwie31cIiA6IFwiXCI7XG5cbiAgICBjb25zdCBsaW5lcyA9IGVudHJpZXMubWFwKChba2V5LCB2YWx1ZV0pID0+IHtcbiAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgLy8g7Lus65+8IOqyveuhnCAo7J2066+4IOuUsOyYtO2RnCDtj6ztlagpXG4gICAgICAgIHJldHVybiBgJHtpbm5lclNwYWNlc30ke2tleX06ICR7dmFsdWV9LGA7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyDspJHssqkg6rCd7LK0ICjtla3sg4Eg7KSR6rSE7Zi4IO2PrO2VqClcbiAgICAgICAgcmV0dXJuIGAke2lubmVyU3BhY2VzfSR7a2V5fTogJHt0aGlzLnN0cmluZ2lmeU5lc3RlZFNlbGVjdE9iamVjdCh2YWx1ZSwgaW5kZW50ICsgMSwgdHJ1ZSl9LGA7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBpZiAod2l0aEJyYWNlcykge1xuICAgICAgcmV0dXJuIGB7XFxuJHtsaW5lcy5qb2luKFwiXFxuXCIpfVxcbiR7c3BhY2VzfX1gO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyDspJHqtITtmLgg7JeG7J20IOuCtOyaqeunjCDrsJjtmZggKOyVnuuSpCDqsJztlokg7KCc7Jm4KVxuICAgICAgcmV0dXJuIGxpbmVzLmpvaW4oXCJcXG5cIik7XG4gICAgfVxuICB9XG5cbiAgZ2V0UHVyaUxvYWRlclF1ZXJ5KHN1YnNldEtleTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBzdWJzZXQgPSB0aGlzLmdldFN1YnNldEZpZWxkc0ZvclF1ZXJ5KHN1YnNldEtleSk7XG4gICAgY29uc3QgeyBsb2FkZXJzIH0gPSB0aGlzLnJlc29sdmVTdWJzZXRRdWVyeShcIlwiLCBzdWJzZXQpO1xuXG4gICAgY29uc3QgbGluZXM6IHN0cmluZ1tdID0gW2BbYF07XG5cbiAgICAvLyDsnqzqt4DsoIHsnLzroZwgbG9hZGVyIOyDneyEse2VmOuKlCDtl6ztjbwg7ZWo7IiYXG4gICAgY29uc3QgZ2VuZXJhdGVMb2FkZXJDb2RlID0gKGxvYWRlcnM6IFN1YnNldFF1ZXJ5W1wibG9hZGVyc1wiXSk6IHN0cmluZ1tdID0+IHtcbiAgICAgIGNvbnN0IGxvYWRlckxpbmVzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgICBmb3IgKGNvbnN0IGxvYWRlciBvZiBsb2FkZXJzKSB7XG4gICAgICAgIGNvbnN0IHsgdG9UYWJsZSwgdG9Db2wsIHRocm91Z2gsIGZyb21UYWJsZSB9ID0gbG9hZGVyLm1hbnlKb2luO1xuXG4gICAgICAgIC8vIGZyb21UYWJsZeydmCBFbnRpdHnrpbwg6rCA7KC47JmA7IScIFBLIO2DgOyehSDtmZXsnbhcbiAgICAgICAgY29uc3QgZnJvbUVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0QnlUYWJsZShmcm9tVGFibGUpO1xuICAgICAgICBjb25zdCBmcm9tSWRzVHlwZSA9IGZyb21FbnRpdHkuZ2V0UGtBcnJheVR5cGUoKTtcblxuICAgICAgICBsb2FkZXJMaW5lcy5wdXNoKFxuICAgICAgICAgIFwie1wiLFxuICAgICAgICAgIGBhczogXCIke2xvYWRlci5hc31cIixgLFxuICAgICAgICAgIGByZWZJZDogXCIke2xvYWRlci5tYW55Sm9pbi5pZEZpZWxkfVwiLGAsXG4gICAgICAgICAgYHFiOiAocWJXcmFwcGVyOiBQdXJpV3JhcHBlcjxEYXRhYmFzZVNjaGVtYUV4dGVuZD4sIGZyb21JZHM6IG51bWJlcltdIHwgc3RyaW5nW10pID0+IHtgLFxuICAgICAgICApO1xuXG4gICAgICAgIGlmICh0aHJvdWdoID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAvLyBIYXNNYW55XG4gICAgICAgICAgbG9hZGVyTGluZXMucHVzaChcbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICBcInJldHVybiBxYldyYXBwZXJcIixcbiAgICAgICAgICAgIGAuZnJvbShcIiR7dG9UYWJsZX1cIilgLFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBsb2FkZXIub25lSm9pbnMuZm9yRWFjaCgoam9pbjogU3Vic2V0UXVlcnlbXCJqb2luc1wiXVtudW1iZXJdKSA9PiB7XG4gICAgICAgICAgICAvLyBGSyBudWxsYWJsZSDsl6zrtoDripQgbGVmdEpvaW4g7YOA7J6FIOyLnOq3uOuLiOyymOyXkOyEnCDsnpDrj5nsnLzroZwg7YyQ64uo65CoXG4gICAgICAgICAgICBjb25zdCBqb2luTWV0aG9kID0gam9pbi5qb2luID09PSBcImlubmVyXCIgPyBcImpvaW5cIiA6IFwibGVmdEpvaW5cIjtcbiAgICAgICAgICAgIGlmIChcImN1c3RvbVwiIGluIGpvaW4pIHtcbiAgICAgICAgICAgICAgLy8gY3VzdG9tIGpvaW4gY2xhdXNl64qUIGNhbGxiYWNrIO2Yle2DnOydmCBvbiDrqZTshJzrk5zroZwg7LKY66as7ZWp64uI64ukLlxuICAgICAgICAgICAgICBsb2FkZXJMaW5lcy5wdXNoKFxuICAgICAgICAgICAgICAgIGAuJHtqb2luTWV0aG9kfSh7ICR7am9pbi5hc306IFwiJHtqb2luLnRhYmxlfVwiIH0sIChqKSA9PiB7YCxcbiAgICAgICAgICAgICAgICBgai5vbihQdXJpLnJhd1N0cmluZyhcIiR7am9pbi5jdXN0b219XCIpKTtgLFxuICAgICAgICAgICAgICAgIFwifSlcIixcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGxvYWRlckxpbmVzLnB1c2goXG4gICAgICAgICAgICAgICAgYC4ke2pvaW5NZXRob2R9KHsgJHtqb2luLmFzfTogXCIke2pvaW4udGFibGV9XCIgfSwgXCIke2pvaW4uZnJvbX1cIiwgXCIke2pvaW4udG99XCIpYCxcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIC8vIOyeheyytOyggSBzZWxlY3Qg6rWs7KGwIOyDneyEsSAocmVmSWQg7Y+s7ZWoKVxuICAgICAgICAgIGNvbnN0IHNlbGVjdE9iaiA9IHRoaXMuYnVpbGROZXN0ZWRTZWxlY3RPYmplY3QobG9hZGVyLnNlbGVjdCk7XG4gICAgICAgICAgc2VsZWN0T2JqLnJlZklkID0gYFwiJHt0b1RhYmxlfS4ke3RvQ29sfVwiYDtcbiAgICAgICAgICBsb2FkZXJMaW5lcy5wdXNoKFxuICAgICAgICAgICAgYC53aGVyZUluKFwiJHt0b1RhYmxlfS4ke3RvQ29sfVwiLCBmcm9tSWRzIGFzICR7ZnJvbUlkc1R5cGV9KWAsXG4gICAgICAgICAgICBgLnNlbGVjdCgke3RoaXMuc3RyaW5naWZ5TmVzdGVkU2VsZWN0T2JqZWN0KHNlbGVjdE9iail9KTtgLFxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gTWFueVRvTWFueVxuICAgICAgICAgIGxvYWRlckxpbmVzLnB1c2goXG4gICAgICAgICAgICBcInJldHVybiBxYldyYXBwZXJcIixcbiAgICAgICAgICAgIGAuZnJvbShcIiR7dGhyb3VnaC50YWJsZX1cIilgLFxuICAgICAgICAgICAgYC5qb2luKFwiJHt0b1RhYmxlfVwiLCBcIiR7dGhyb3VnaC50YWJsZX0uJHt0aHJvdWdoLnRvQ29sfVwiLCBcIiR7dG9UYWJsZX0uJHt0b0NvbH1cIilgLFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBsb2FkZXIub25lSm9pbnMuZm9yRWFjaCgoam9pbjogU3Vic2V0UXVlcnlbXCJqb2luc1wiXVtudW1iZXJdKSA9PiB7XG4gICAgICAgICAgICAvLyBGSyBudWxsYWJsZSDsl6zrtoDripQgbGVmdEpvaW4g7YOA7J6FIOyLnOq3uOuLiOyymOyXkOyEnCDsnpDrj5nsnLzroZwg7YyQ64uo65CoXG4gICAgICAgICAgICBjb25zdCBqb2luTWV0aG9kID0gam9pbi5qb2luID09PSBcImlubmVyXCIgPyBcImpvaW5cIiA6IFwibGVmdEpvaW5cIjtcbiAgICAgICAgICAgIGlmIChcImN1c3RvbVwiIGluIGpvaW4pIHtcbiAgICAgICAgICAgICAgLy8gY3VzdG9tIGpvaW4gY2xhdXNl64qUIGNhbGxiYWNrIO2Yle2DnOydmCBvbiDrqZTshJzrk5zroZwg7LKY66as7ZWp64uI64ukLlxuICAgICAgICAgICAgICBsb2FkZXJMaW5lcy5wdXNoKFxuICAgICAgICAgICAgICAgIGAuJHtqb2luTWV0aG9kfSh7ICR7am9pbi5hc306IFwiJHtqb2luLnRhYmxlfVwiIH0sIChqKSA9PiB7YCxcbiAgICAgICAgICAgICAgICBgai5vbihQdXJpLnJhd1N0cmluZyhcIiR7am9pbi5jdXN0b219XCIpKTtgLFxuICAgICAgICAgICAgICAgIFwifSlcIixcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGxvYWRlckxpbmVzLnB1c2goXG4gICAgICAgICAgICAgICAgYC4ke2pvaW5NZXRob2R9KHsgJHtqb2luLmFzfTogXCIke2pvaW4udGFibGV9XCIgfSwgXCIke2pvaW4uZnJvbX1cIiwgXCIke2pvaW4udG99XCIpYCxcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIC8vIOyeheyytOyggSBzZWxlY3Qg6rWs7KGwIOyDneyEsSAocmVmSWQg7Y+s7ZWoKVxuICAgICAgICAgIGNvbnN0IHNlbGVjdE9iaiA9IHRoaXMuYnVpbGROZXN0ZWRTZWxlY3RPYmplY3QobG9hZGVyLnNlbGVjdCk7XG4gICAgICAgICAgc2VsZWN0T2JqLnJlZklkID0gYFwiJHt0aHJvdWdoLnRhYmxlfS4ke3Rocm91Z2guZnJvbUNvbH1cImA7XG4gICAgICAgICAgbG9hZGVyTGluZXMucHVzaChcbiAgICAgICAgICAgIGAud2hlcmVJbihcIiR7dGhyb3VnaC50YWJsZX0uJHt0aHJvdWdoLmZyb21Db2x9XCIsIGZyb21JZHMgYXMgJHtmcm9tSWRzVHlwZX0pYCxcbiAgICAgICAgICAgIGAuc2VsZWN0KCR7dGhpcy5zdHJpbmdpZnlOZXN0ZWRTZWxlY3RPYmplY3Qoc2VsZWN0T2JqKX0pO2AsXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxvYWRlckxpbmVzLnB1c2goYH0sYCk7XG5cbiAgICAgICAgLy8g7KSR7LKpIGxvYWRlcnMg7LKY66asXG4gICAgICAgIGlmIChsb2FkZXIubG9hZGVycyAmJiBsb2FkZXIubG9hZGVycy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgbG9hZGVyTGluZXMucHVzaChcImxvYWRlcnM6IFtcIiwgLi4uZ2VuZXJhdGVMb2FkZXJDb2RlKGxvYWRlci5sb2FkZXJzKSwgXCJdLFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxvYWRlckxpbmVzLnB1c2goXCJ9LFwiKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGxvYWRlckxpbmVzO1xuICAgIH07XG5cbiAgICBsaW5lcy5wdXNoKC4uLmdlbmVyYXRlTG9hZGVyQ29kZShsb2FkZXJzKSk7XG4gICAgbGluZXMucHVzaChgXWApO1xuXG4gICAgcmV0dXJuIGxpbmVzLmpvaW4oXCJcXG5cIik7XG4gIH1cblxuICAvKlxuICAgIHN1YnNldCBTRUxFQ1QvSk9JTi9MT0FERVIg6rKw6rO8IOumrO2EtFxuICAqL1xuICBnZXRTdWJzZXRRdWVyeShzdWJzZXRLZXk6IHN0cmluZyk6IFN1YnNldFF1ZXJ5IHtcbiAgICBjb25zdCBzdWJzZXQgPSB0aGlzLmdldFN1YnNldEZpZWxkc0ZvclF1ZXJ5KHN1YnNldEtleSk7XG5cbiAgICBjb25zdCByZXN1bHQ6IFN1YnNldFF1ZXJ5ID0gdGhpcy5yZXNvbHZlU3Vic2V0UXVlcnkoXCJcIiwgc3Vic2V0KTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLypcbiAgICovXG4gIHJlc29sdmVTdWJzZXRRdWVyeShcbiAgICBwcmVmaXg6IHN0cmluZyxcbiAgICBmaWVsZHM6IHN0cmluZ1tdLFxuICAgIGlzQWxyZWFkeU91dGVySm9pbmVkOiBib29sZWFuID0gZmFsc2UsXG4gICk6IFN1YnNldFF1ZXJ5IHtcbiAgICAvLyBwcmVmaXgg7LmY7ZmYIChwcmVmaXjripQgVG9PbmVSZWxhdGlvbuydtCDrs7XsiJjroZwg67aZ7J2AIOqyveyasCDrqqjrkZAgX1/roZwg67OA6rK965CoKVxuICAgIHByZWZpeCA9IHByZWZpeC5yZXBsYWNlKC9cXC4vZywgXCJfX1wiKTtcblxuICAgIC8vIOyEnOu4jOyFi+ydhCAx646B7Iqk66eMIOu2hOumrO2VmOyXrCDqt7jro7ntlZFcbiAgICBjb25zdCBzdWJzZXRHcm91cCA9IGdyb3VwKGZpZWxkcywgKGZpZWxkKSA9PiB7XG4gICAgICBpZiAoZmllbGQuaW5jbHVkZXMoXCIuXCIpKSB7XG4gICAgICAgIGNvbnN0IFtyZWxdID0gZmllbGQuc3BsaXQoXCIuXCIpO1xuICAgICAgICByZXR1cm4gcmVsO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIFwiXCI7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBjb25zdCByZXN1bHQgPSBPYmplY3Qua2V5cyhzdWJzZXRHcm91cCkucmVkdWNlKFxuICAgICAgKHIsIGdyb3VwS2V5KSA9PiB7XG4gICAgICAgIGNvbnN0IGZpZWxkcyA9IHN1YnNldEdyb3VwW2dyb3VwS2V5XTtcbiAgICAgICAgYXNzZXJ0KGZpZWxkcyAhPT0gdW5kZWZpbmVkLCBcImZpZWxkcyBpcyB1bmRlZmluZWRcIik7XG5cbiAgICAgICAgLy8g7ZiE7J6sIO2FjOydtOu4lCDtlYTrk5zshYvsnYAgc2VsZWN0LCB2aXJ0dWFs7JeQIOy2lOqwgO2VmOqzoCDrpqzthLRcbiAgICAgICAgaWYgKGdyb3VwS2V5ID09PSBcIlwiKSB7XG4gICAgICAgICAgY29uc3QgcmVhbEZpZWxkcyA9IGZpZWxkcy5maWx0ZXIoKGZpZWxkKSA9PiAhaXNWaXJ0dWFsUHJvcCh0aGlzLnByb3BzRGljdFtmaWVsZF0pKTtcbiAgICAgICAgICAvLyB2aXJ0dWFsVHlwZTogXCJjb2RlXCIgKOuYkOuKlCB1bmRlZmluZWQp7J24IHZpcnR1YWwgcHJvcOunjCByLnZpcnR1YWzsl5Ag7LaU6rCAXG4gICAgICAgICAgLy8gdmlydHVhbFR5cGU6IFwicXVlcnlcIuyduCDqsr3smrAg7IKs7Jqp7J6Q6rCAIGFwcGVuZFNlbGVjdOuhnCDsp4HsoJEg7LaU6rCA7ZWY66+A66GcIOygnOyZuFxuICAgICAgICAgIGNvbnN0IHZpcnR1YWxDb2RlRmllbGRzID0gZmllbGRzLmZpbHRlcigoZmllbGQpID0+XG4gICAgICAgICAgICBpc1ZpcnR1YWxDb2RlUHJvcCh0aGlzLnByb3BzRGljdFtmaWVsZF0pLFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBpZiAocHJlZml4ID09PSBcIlwiKSB7XG4gICAgICAgICAgICAvLyDtmITsnqwg7YWM7J2067iU7J24IOqyveyasFxuICAgICAgICAgICAgci5zZWxlY3QgPSByLnNlbGVjdC5jb25jYXQocmVhbEZpZWxkcy5tYXAoKGZpZWxkKSA9PiB0aGlzLmdldEZ1bGxGaWVsZE5hbWUoZmllbGQpKSk7XG4gICAgICAgICAgICByLnZpcnR1YWwgPSByLnZpcnR1YWwuY29uY2F0KHZpcnR1YWxDb2RlRmllbGRzKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8g64SY7Ja07JioIO2FjOydtOu4lOyduCDqsr3smrBcbiAgICAgICAgICAgIHIuc2VsZWN0ID0gci5zZWxlY3QuY29uY2F0KFxuICAgICAgICAgICAgICByZWFsRmllbGRzLm1hcCgoZmllbGQpID0+IGAke3ByZWZpeH0uJHtmaWVsZH0gYXMgJHtwcmVmaXh9X18ke2ZpZWxkfWApLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gcjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJlbGF0aW9uID0gdGhpcy5yZWxhdGlvbnNbZ3JvdXBLZXldO1xuICAgICAgICBpZiAocmVsYXRpb24gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihg7KG07J6s7ZWY7KeAIOyViuuKlCByZWxhdGlvbiDssLjsobAgJHtncm91cEtleX1gKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCByZWxFbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChyZWxhdGlvbi53aXRoKTtcblxuICAgICAgICBpZiAoaXNPbmVUb09uZVJlbGF0aW9uUHJvcChyZWxhdGlvbikgfHwgaXNCZWxvbmdzVG9PbmVSZWxhdGlvblByb3AocmVsYXRpb24pKSB7XG4gICAgICAgICAgLy8gLU9uZSBSZWxhdGlvbjogSk9JTiDsnLzroZwg7LKY66asXG4gICAgICAgICAgY29uc3QgcmVsRmllbGRzID0gZmllbGRzLm1hcCgoZmllbGQpID0+IGZpZWxkLnNwbGl0KFwiLlwiKS5zbGljZSgxKS5qb2luKFwiLlwiKSk7XG5cbiAgICAgICAgICAvLyAtT25lIFJlbGF0aW9u7JeQ7IScIGlkIO2VhOuTnOunjCDssLjsobDtlZjripQg6rK97JqwIOumtOugiOydtOyFmCDrhJjquLDsp4Ag7JWK6rOgIOumrO2EtFxuICAgICAgICAgIGlmIChyZWxGaWVsZHMubGVuZ3RoID09PSAxICYmIHJlbEZpZWxkc1swXSA9PT0gXCJpZFwiKSB7XG4gICAgICAgICAgICBpZiAocHJlZml4ID09PSBcIlwiKSB7XG4gICAgICAgICAgICAgIHIuc2VsZWN0ID0gci5zZWxlY3QuY29uY2F0KGAke3RoaXMudGFibGV9LiR7Z3JvdXBLZXl9X2lkYCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICByLnNlbGVjdCA9IHIuc2VsZWN0LmNvbmNhdChgJHtwcmVmaXh9LiR7Z3JvdXBLZXl9X2lkIGFzICR7cHJlZml4fV9fJHtncm91cEtleX1faWRgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIGlubmVyT3JPdXRlclxuICAgICAgICAgIGNvbnN0IGlubmVyT3JPdXRlciA9ICgoKSA9PiB7XG4gICAgICAgICAgICBpZiAoaXNBbHJlYWR5T3V0ZXJKb2luZWQpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIFwib3V0ZXJcIjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGlzT25lVG9PbmVSZWxhdGlvblByb3AocmVsYXRpb24pKSB7XG4gICAgICAgICAgICAgIGlmIChyZWxhdGlvbi5oYXNKb2luQ29sdW1uICYmICEocmVsYXRpb24ubnVsbGFibGUgPz8gZmFsc2UpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwiaW5uZXJcIjtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJvdXRlclwiO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBpZiAocmVsYXRpb24ubnVsbGFibGUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJvdXRlclwiO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBcImlubmVyXCI7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KSgpO1xuICAgICAgICAgIGNvbnN0IHJlbFN1YnNldFF1ZXJ5ID0gcmVsRW50aXR5LnJlc29sdmVTdWJzZXRRdWVyeShcbiAgICAgICAgICAgIGAke3ByZWZpeCAhPT0gXCJcIiA/IGAke3ByZWZpeH0uYCA6IFwiXCJ9JHtncm91cEtleX1gLFxuICAgICAgICAgICAgcmVsRmllbGRzLFxuICAgICAgICAgICAgaW5uZXJPck91dGVyID09PSBcIm91dGVyXCIsXG4gICAgICAgICAgKTtcbiAgICAgICAgICByLnNlbGVjdCA9IHIuc2VsZWN0LmNvbmNhdChyZWxTdWJzZXRRdWVyeS5zZWxlY3QpO1xuICAgICAgICAgIHIudmlydHVhbCA9IHIudmlydHVhbC5jb25jYXQocmVsU3Vic2V0UXVlcnkudmlydHVhbCk7XG5cbiAgICAgICAgICBjb25zdCBqb2luQXMgPSBwcmVmaXggPT09IFwiXCIgPyBncm91cEtleSA6IGAke3ByZWZpeH1fXyR7Z3JvdXBLZXl9YDtcbiAgICAgICAgICBjb25zdCBmcm9tVGFibGUgPSBwcmVmaXggPT09IFwiXCIgPyB0aGlzLnRhYmxlIDogcHJlZml4O1xuXG4gICAgICAgICAgbGV0IGpvaW5DbGF1c2U6XG4gICAgICAgICAgICB8IHtcbiAgICAgICAgICAgICAgICBmcm9tOiBzdHJpbmc7XG4gICAgICAgICAgICAgICAgdG86IHN0cmluZztcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfCB7XG4gICAgICAgICAgICAgICAgY3VzdG9tOiBzdHJpbmc7XG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgaWYgKHJlbGF0aW9uLmN1c3RvbUpvaW5DbGF1c2UpIHtcbiAgICAgICAgICAgIGpvaW5DbGF1c2UgPSB7XG4gICAgICAgICAgICAgIGN1c3RvbTogcmVsYXRpb24uY3VzdG9tSm9pbkNsYXVzZSxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGxldCBmcm9tOiBzdHJpbmcsIHRvOiBzdHJpbmc7XG4gICAgICAgICAgICBpZiAoaXNPbmVUb09uZVJlbGF0aW9uUHJvcChyZWxhdGlvbikpIHtcbiAgICAgICAgICAgICAgaWYgKHJlbGF0aW9uLmhhc0pvaW5Db2x1bW4pIHtcbiAgICAgICAgICAgICAgICBmcm9tID0gYCR7ZnJvbVRhYmxlfS4ke3JlbGF0aW9uLm5hbWV9X2lkYDtcbiAgICAgICAgICAgICAgICB0byA9IGAke2pvaW5Bc30uaWRgO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGZyb20gPSBgJHtmcm9tVGFibGV9LmlkYDtcbiAgICAgICAgICAgICAgICB0byA9IGAke2pvaW5Bc30uJHtpbmZsZWN0aW9uLnVuZGVyc2NvcmUodGhpcy5uYW1lcy5mcy5yZXBsYWNlKC8tL2csIFwiX1wiKSl9X2lkYDtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgZnJvbSA9IGAke2Zyb21UYWJsZX0uJHtyZWxhdGlvbi5uYW1lfV9pZGA7XG4gICAgICAgICAgICAgIHRvID0gYCR7am9pbkFzfS5pZGA7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBqb2luQ2xhdXNlID0ge1xuICAgICAgICAgICAgICBmcm9tLFxuICAgICAgICAgICAgICB0byxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgci5qb2lucy5wdXNoKHtcbiAgICAgICAgICAgIGFzOiBqb2luQXMsXG4gICAgICAgICAgICBqb2luOiBpbm5lck9yT3V0ZXIsXG4gICAgICAgICAgICB0YWJsZTogcmVsRW50aXR5LnRhYmxlLFxuICAgICAgICAgICAgLi4uam9pbkNsYXVzZSxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIC8vIEJlbG9uZ3NUb09uZSDrsJHsl5AgSGFzTWFueeqwgCDrtpnsnYAg6rK97JqwXG4gICAgICAgICAgaWYgKHJlbFN1YnNldFF1ZXJ5LmxvYWRlcnMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgY29uc3QgY29udmVydGVkTG9hZGVycyA9IHJlbFN1YnNldFF1ZXJ5LmxvYWRlcnMubWFwKChsb2FkZXIpID0+IHtcbiAgICAgICAgICAgICAgY29uc3QgbmV3QXMgPSBbZ3JvdXBLZXksIGxvYWRlci5hc10uam9pbihcIl9fXCIpO1xuICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGFzOiBuZXdBcyxcbiAgICAgICAgICAgICAgICB0YWJsZTogbG9hZGVyLnRhYmxlLFxuICAgICAgICAgICAgICAgIG1hbnlKb2luOiBsb2FkZXIubWFueUpvaW4sXG4gICAgICAgICAgICAgICAgb25lSm9pbnM6IGxvYWRlci5vbmVKb2lucyxcbiAgICAgICAgICAgICAgICBzZWxlY3Q6IGxvYWRlci5zZWxlY3QsXG4gICAgICAgICAgICAgICAgbG9hZGVyczogbG9hZGVyLmxvYWRlcnMsXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgci5sb2FkZXJzID0gWy4uLnIubG9hZGVycywgLi4uY29udmVydGVkTG9hZGVyc107XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgci5qb2lucyA9IHIuam9pbnMuY29uY2F0KHJlbFN1YnNldFF1ZXJ5LmpvaW5zKTtcbiAgICAgICAgfSBlbHNlIGlmIChpc0hhc01hbnlSZWxhdGlvblByb3AocmVsYXRpb24pIHx8IGlzTWFueVRvTWFueVJlbGF0aW9uUHJvcChyZWxhdGlvbikpIHtcbiAgICAgICAgICAvLyAtTWFueSBSZWxhdGlvbjogTG9hZGVyIOuhnCDsspjrpqxcbiAgICAgICAgICBjb25zdCByZWxGaWVsZHMgPSBmaWVsZHMubWFwKChmaWVsZCkgPT4gZmllbGQuc3BsaXQoXCIuXCIpLnNsaWNlKDEpLmpvaW4oXCIuXCIpKTtcbiAgICAgICAgICBjb25zdCByZWxTdWJzZXRRdWVyeSA9IHJlbEVudGl0eS5yZXNvbHZlU3Vic2V0UXVlcnkoXCJcIiwgcmVsRmllbGRzKTtcblxuICAgICAgICAgIGxldCBtYW55Sm9pbjogU3Vic2V0UXVlcnlbXCJsb2FkZXJzXCJdW251bWJlcl1bXCJtYW55Sm9pblwiXTtcbiAgICAgICAgICBpZiAoaXNIYXNNYW55UmVsYXRpb25Qcm9wKHJlbGF0aW9uKSkge1xuICAgICAgICAgICAgY29uc3QgZnJvbUNvbCA9IHJlbGF0aW9uPy5mcm9tQ29sdW1uID8/IFwiaWRcIjtcbiAgICAgICAgICAgIG1hbnlKb2luID0ge1xuICAgICAgICAgICAgICBmcm9tVGFibGU6IHRoaXMudGFibGUsXG4gICAgICAgICAgICAgIGZyb21Db2wsXG4gICAgICAgICAgICAgIGlkRmllbGQ6IHByZWZpeCA9PT0gXCJcIiA/IGAke2Zyb21Db2x9YCA6IGAke3ByZWZpeH1fXyR7ZnJvbUNvbH1gLFxuICAgICAgICAgICAgICB0b1RhYmxlOiByZWxFbnRpdHkudGFibGUsXG4gICAgICAgICAgICAgIHRvQ29sOiByZWxhdGlvbi5qb2luQ29sdW1uLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9IGVsc2UgaWYgKGlzTWFueVRvTWFueVJlbGF0aW9uUHJvcChyZWxhdGlvbikpIHtcbiAgICAgICAgICAgIG1hbnlKb2luID0ge1xuICAgICAgICAgICAgICBmcm9tVGFibGU6IHRoaXMudGFibGUsXG4gICAgICAgICAgICAgIGZyb21Db2w6IFwiaWRcIixcbiAgICAgICAgICAgICAgaWRGaWVsZDogcHJlZml4ID09PSBcIlwiID8gYGlkYCA6IGAke3ByZWZpeH1fX2lkYCxcbiAgICAgICAgICAgICAgdGhyb3VnaDoge1xuICAgICAgICAgICAgICAgIHRhYmxlOiByZWxhdGlvbi5qb2luVGFibGUsXG4gICAgICAgICAgICAgICAgZnJvbUNvbDogYCR7aW5mbGVjdGlvbi5zaW5ndWxhcml6ZSh0aGlzLnRhYmxlKX1faWRgLFxuICAgICAgICAgICAgICAgIHRvQ29sOiBgJHtpbmZsZWN0aW9uLnNpbmd1bGFyaXplKHJlbEVudGl0eS50YWJsZSl9X2lkYCxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgdG9UYWJsZTogcmVsRW50aXR5LnRhYmxlLFxuICAgICAgICAgICAgICB0b0NvbDogXCJpZFwiLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgci5sb2FkZXJzLnB1c2goe1xuICAgICAgICAgICAgYXM6IGdyb3VwS2V5LFxuICAgICAgICAgICAgdGFibGU6IHJlbEVudGl0eS50YWJsZSxcbiAgICAgICAgICAgIG1hbnlKb2luLFxuICAgICAgICAgICAgb25lSm9pbnM6IHJlbFN1YnNldFF1ZXJ5LmpvaW5zLFxuICAgICAgICAgICAgc2VsZWN0OiByZWxTdWJzZXRRdWVyeS5zZWxlY3QsXG4gICAgICAgICAgICBsb2FkZXJzOiByZWxTdWJzZXRRdWVyeS5sb2FkZXJzLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHI7XG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBzZWxlY3Q6IFtdLFxuICAgICAgICB2aXJ0dWFsOiBbXSxcbiAgICAgICAgam9pbnM6IFtdLFxuICAgICAgICBsb2FkZXJzOiBbXSxcbiAgICAgIH0gYXMgU3Vic2V0UXVlcnksXG4gICAgKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLypcbiAgICBGaWVsZEV4cHJbXSDsnYQgRW50aXR5UHJvcE5vZGVbXSDroZwg67OA7ZmYXG4gICovXG4gIGZpZWxkRXhwcnNUb1Byb3BOb2RlcyhmaWVsZEV4cHJzOiBzdHJpbmdbXSwgZW50aXR5OiBFbnRpdHkgPSB0aGlzKTogRW50aXR5UHJvcE5vZGVbXSB7XG4gICAgY29uc3QgZ3JvdXBzID0gZmllbGRFeHBycy5yZWR1Y2UoXG4gICAgICAocmVzdWx0LCBmaWVsZEV4cHIpID0+IHtcbiAgICAgICAgbGV0IGtleTogc3RyaW5nLCB2YWx1ZTogc3RyaW5nLCBlbHNlRXhwcjogc3RyaW5nW107XG4gICAgICAgIGlmIChmaWVsZEV4cHIuaW5jbHVkZXMoXCIuXCIpKSB7XG4gICAgICAgICAgW2tleSwgLi4uZWxzZUV4cHJdID0gZmllbGRFeHByLnNwbGl0KFwiLlwiKTtcbiAgICAgICAgICB2YWx1ZSA9IGVsc2VFeHByLmpvaW4oXCIuXCIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGtleSA9IFwiXCI7XG4gICAgICAgICAgdmFsdWUgPSBmaWVsZEV4cHI7XG4gICAgICAgIH1cbiAgICAgICAgcmVzdWx0W2tleV0gPSAocmVzdWx0W2tleV0gPz8gW10pLmNvbmNhdCh2YWx1ZSk7XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH0sXG4gICAgICB7fSBhcyB7XG4gICAgICAgIFtrOiBzdHJpbmddOiBzdHJpbmdbXTtcbiAgICAgIH0sXG4gICAgKTtcblxuICAgIHJldHVybiBPYmplY3Qua2V5cyhncm91cHMpLmZsYXRNYXA8RW50aXR5UHJvcE5vZGUsIEVudGl0eVByb3BOb2RlW10+KChrZXkpID0+IHtcbiAgICAgIGNvbnN0IGdyb3VwID0gZ3JvdXBzW2tleV07XG5cbiAgICAgIC8vIOydvOuwmCBwcm9wIOyymOumrFxuICAgICAgaWYgKGtleSA9PT0gXCJcIikge1xuICAgICAgICByZXR1cm4gZ3JvdXAubWFwKChwcm9wTmFtZSkgPT4ge1xuICAgICAgICAgIGNvbnN0IHByb3AgPSBlbnRpdHkucHJvcHMuZmluZCgocCkgPT4gcC5uYW1lID09PSBwcm9wTmFtZSk7XG4gICAgICAgICAgaWYgKHByb3AgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICBgJHtlbnRpdHkuaWR9IC0tIOyemOuqu+uQnCBGaWVsZEV4cHIgJyR7cHJvcE5hbWV9JyAo7IKs7JqpIOqwgOuKpe2VnCBwcm9wczogJHtlbnRpdHkucHJvcHMubWFwKChwKSA9PiBwLm5hbWUpLmpvaW4oXCIsIFwiKX0pYCxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBub2RlVHlwZTogXCJwbGFpblwiIGFzIGNvbnN0LFxuICAgICAgICAgICAgcHJvcCxcbiAgICAgICAgICB9O1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgLy8gcmVsYXRpb24gcHJvcCDsspjrpqxcbiAgICAgIGNvbnN0IHByb3AgPSBlbnRpdHkucHJvcHNEaWN0W2tleV07XG4gICAgICBpZiAoIWlzUmVsYXRpb25Qcm9wKHByb3ApKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihg7J6Y66q765CcIEZpZWxkRXhwciAke2tleX0uJHtncm91cFswXX1gKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHJlbEVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KHByb3Aud2l0aCk7XG5cbiAgICAgIC8vIHJlbGF0aW9uIC1PbmUg7JeQIGlkIO2VhOuTnCDtlZjrgpjsnbgg6rK97JqwXG4gICAgICBpZiAoaXNCZWxvbmdzVG9PbmVSZWxhdGlvblByb3AocHJvcCkgfHwgaXNPbmVUb09uZVJlbGF0aW9uUHJvcChwcm9wKSkge1xuICAgICAgICBpZiAoZ3JvdXAubGVuZ3RoID09PSAxICYmIChncm91cFswXSA9PT0gXCJpZFwiIHx8IGdyb3VwWzBdID09PSBcImlkP1wiKSkge1xuICAgICAgICAgIC8vIGlkIO2VmOuCmOunjCDsnojripTsp4Ag7LK07YGs7ZW07IScLCDtlZjrgpjrp4wg7J6I7Jy866m0IOyDgeychCBwcm9w7Jy866GcIGlk66W8IOumrO2EtFxuICAgICAgICAgIGNvbnN0IGlkUHJvcCA9IHJlbEVudGl0eS5wcm9wc0RpY3QuaWQ7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIG5vZGVUeXBlOiBcInBsYWluXCIgYXMgY29uc3QsXG4gICAgICAgICAgICBwcm9wOiB7XG4gICAgICAgICAgICAgIC4uLmlkUHJvcCxcbiAgICAgICAgICAgICAgbmFtZTogYCR7a2V5fV9pZGAsXG4gICAgICAgICAgICAgIG51bGxhYmxlOiBwcm9wLm51bGxhYmxlLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIC1PbmUg6re47Jm47J2YIOqyveyasCBvYmplY3TroZwg66as7YS0XG4gICAgICAvLyAtTWFueeydmCDqsr3smrAgYXJyYXnroZwg66as7YS0XG4gICAgICAvLyBSZWN1cnNpdmUg66GcIOuOgeyKpCDsspjrpqxcbiAgICAgIGNvbnN0IGNoaWxkcmVuID0gdGhpcy5maWVsZEV4cHJzVG9Qcm9wTm9kZXMoZ3JvdXAsIHJlbEVudGl0eSk7XG4gICAgICBjb25zdCBub2RlVHlwZSA9XG4gICAgICAgIGlzQmVsb25nc1RvT25lUmVsYXRpb25Qcm9wKHByb3ApIHx8IGlzT25lVG9PbmVSZWxhdGlvblByb3AocHJvcClcbiAgICAgICAgICA/IChcIm9iamVjdFwiIGFzIGNvbnN0KVxuICAgICAgICAgIDogKFwiYXJyYXlcIiBhcyBjb25zdCk7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIG5vZGVUeXBlLFxuICAgICAgICBwcm9wLFxuICAgICAgICBjaGlsZHJlbixcbiAgICAgIH07XG4gICAgfSk7XG4gIH1cblxuICBnZXRGaWVsZEV4cHJzKHByZWZpeCA9IFwiXCIsIG1heERlcHRoOiBudW1iZXIgPSAzLCBmcm9tczogc3RyaW5nW10gPSBbXSk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gdGhpcy5wcm9wc1xuICAgICAgLmZsYXRNYXAoKHByb3ApID0+IHtcbiAgICAgICAgY29uc3QgcHJvcE5hbWUgPSBbcHJlZml4LCBwcm9wLm5hbWVdLmZpbHRlcigodikgPT4gdiAhPT0gXCJcIikuam9pbihcIi5cIik7XG4gICAgICAgIGlmIChwcm9wTmFtZSA9PT0gcHJlZml4KSB7XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGlzUmVsYXRpb25Qcm9wKHByb3ApKSB7XG4gICAgICAgICAgaWYgKG1heERlcHRoIDwgMCkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChmcm9tcy5pbmNsdWRlcyhwcm9wLndpdGgpKSB7XG4gICAgICAgICAgICAvLyDsl63rsKntlqUgcmVsYXRpb27snbgg6rK97JqwIOygnOyZuFxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIOygleuwqe2WpSByZWxhdGlvbuyduCDqsr3smrAgcmVjdXJzaXZlIOy9nFxuICAgICAgICAgIGNvbnN0IHJlbE1kID0gRW50aXR5TWFuYWdlci5nZXQocHJvcC53aXRoKTtcbiAgICAgICAgICByZXR1cm4gcmVsTWQuZ2V0RmllbGRFeHBycyhwcm9wTmFtZSwgbWF4RGVwdGggLSAxLCBbLi4uZnJvbXMsIHRoaXMuaWRdKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcHJvcE5hbWU7XG4gICAgICB9KVxuICAgICAgLmZpbHRlcigoZikgPT4gZiAhPT0gbnVsbCk7XG4gIH1cblxuICAvKipcbiAgICogUmVsYXRpb24gcHJvcOydtCDtmITsnqwg7YWM7J2067iU7JeQIEZLIOy7rOufvOydhCDsg53shLHtlZjripTsp4Ag7ZmV7J24XG4gICAqKEJlbG9uZ3NUb09uZSDrmJDripQgT25lVG9PbmUoaGFzSm9pbkNvbHVtbj10cnVlKeyduCDqsr3smrAgRksg7IOd7ISxKVxuICAgKi9cbiAgcHJpdmF0ZSBoYXNGb3JlaWduS2V5KHByb3A6IFJlbGF0aW9uUHJvcCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAoXG4gICAgICBwcm9wLnJlbGF0aW9uVHlwZSA9PT0gXCJCZWxvbmdzVG9PbmVcIiB8fFxuICAgICAgKHByb3AucmVsYXRpb25UeXBlID09PSBcIk9uZVRvT25lXCIgJiYgcHJvcC5oYXNKb2luQ29sdW1uKVxuICAgICk7XG4gIH1cblxuICBnZXRUYWJsZUNvbHVtbnMoKTogeyBuYW1lOiBzdHJpbmc7IHR5cGU6IHN0cmluZyB9W10ge1xuICAgIHJldHVybiB0aGlzLnByb3BzXG4gICAgICAubWFwKChwcm9wKSA9PiB7XG4gICAgICAgIGlmIChwcm9wLnR5cGUgPT09IFwicmVsYXRpb25cIikge1xuICAgICAgICAgIGlmICh0aGlzLmhhc0ZvcmVpZ25LZXkocHJvcCkpIHtcbiAgICAgICAgICAgIHJldHVybiB7IG5hbWU6IGAke3Byb3AubmFtZX1faWRgLCB0eXBlOiBcImludF91bnNpZ25lZFwiIH07XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyBuYW1lOiBwcm9wLm5hbWUsIHR5cGU6IHByb3AudHlwZSB9O1xuICAgICAgfSlcbiAgICAgIC5maWx0ZXIobm9uTnVsbGFibGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIEVudGl0eeyXkCDsoJXsnZjrkJwg66qo65OgIHZlY3RvciDtg4DsnoUg7Lus65+8IOuwmO2ZmFxuICAgKi9cbiAgZ2V0VmVjdG9yQ29sdW1ucygpOiBFbnRpdHlQcm9wW10ge1xuICAgIHJldHVybiB0aGlzLnByb3BzLmZpbHRlcigocCkgPT4gcC50eXBlID09PSBcInZlY3RvclwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDtirnsoJUgdmVjdG9yIOy7rOufvCDrsJjtmZhcbiAgICogQHBhcmFtIGNvbHVtbk5hbWUgLSDsu6zrn7zrqoUgKOyDneuetSDsi5wg7LKrIOuyiOynuCB2ZWN0b3Ig7Lus65+8KVxuICAgKi9cbiAgZ2V0VmVjdG9yQ29sdW1uKGNvbHVtbk5hbWU/OiBzdHJpbmcpOiBFbnRpdHlQcm9wIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCB2ZWN0b3JQcm9wcyA9IHRoaXMuZ2V0VmVjdG9yQ29sdW1ucygpO1xuICAgIGlmIChjb2x1bW5OYW1lKSB7XG4gICAgICByZXR1cm4gdmVjdG9yUHJvcHMuZmluZCgocCkgPT4gcC5uYW1lID09PSBjb2x1bW5OYW1lKTtcbiAgICB9XG4gICAgcmV0dXJuIHZlY3RvclByb3BzWzBdO1xuICB9XG5cbiAgLyoqXG4gICAqIO2VhO2EsOungSDqsIDriqXtlZwgcHJvcHMg67CY7ZmYXG4gICAqXG4gICAqIC0g7J2867CYIHByb3BcbiAgICogLSBGS+ulvCDsg53shLHtlZjripQgcmVsYXRpb24gKEJlbG9uZ3NUb09uZSwgT25lVG9PbmUgd2l0aCBoYXNKb2luQ29sdW1uKVxuICAgKiAgIOKGkiB7bmFtZX1faWQg7ZiV7YOc7J2YIOqwgOyDgSBpbnRlZ2VyIHByb3DsnLzroZwg67OA7ZmYXG4gICAqL1xuICBnZXRGaWx0ZXJhYmxlUHJvcHMoKTogRW50aXR5UHJvcFtdIHtcbiAgICByZXR1cm4gdGhpcy5wcm9wcy5mbGF0TWFwKChwcm9wKTogRW50aXR5UHJvcCB8IEVudGl0eVByb3BbXSA9PiB7XG4gICAgICAvLyBWaXJ0dWFsIHByb3Ag7KCc7Jm4XG4gICAgICBpZiAoaXNWaXJ0dWFsUHJvcChwcm9wKSkge1xuICAgICAgICByZXR1cm4gW107XG4gICAgICB9XG5cbiAgICAgIC8vIFJlbGF0aW9uIHByb3Ag7LKY66asXG4gICAgICBpZiAoaXNSZWxhdGlvblByb3AocHJvcCkpIHtcbiAgICAgICAgLy8gRkvrpbwg7IOd7ISx7ZWY64qUIHJlbGF0aW9u66eMIO2PrO2VqFxuICAgICAgICBpZiAodGhpcy5oYXNGb3JlaWduS2V5KHByb3ApKSB7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIG5hbWU6IGAke3Byb3AubmFtZX1faWRgLFxuICAgICAgICAgICAgdHlwZTogXCJpbnRlZ2VyXCIsXG4gICAgICAgICAgICBudWxsYWJsZTogcHJvcC5udWxsYWJsZSxcbiAgICAgICAgICB9IGFzIEVudGl0eVByb3A7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgfVxuXG4gICAgICAvLyDsnbzrsJggcHJvcCDsspjrpqxcbiAgICAgIHJldHVybiBwcm9wO1xuICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgcmVnaXN0ZXJNb2R1bGVQYXRocygpIHtcbiAgICBjb25zdCBiYXNlUGF0aCA9IGAke3RoaXMubmFtZXMucGFyZW50RnN9YDtcblxuICAgIC8vIGJhc2Utc2NoZW1lXG4gICAgRW50aXR5TWFuYWdlci5zZXRNb2R1bGVQYXRoKGAke3RoaXMuaWR9QmFzZVNjaGVtYWAsIGBzb25hbXUuZ2VuZXJhdGVkYCk7XG5cbiAgICAvLyBzdWJzZXRcbiAgICBpZiAoT2JqZWN0LmtleXModGhpcy5zdWJzZXRzKS5sZW5ndGggPiAwKSB7XG4gICAgICBFbnRpdHlNYW5hZ2VyLnNldE1vZHVsZVBhdGgoYCR7dGhpcy5pZH1TdWJzZXRLZXlgLCBgc29uYW11LmdlbmVyYXRlZGApO1xuICAgICAgRW50aXR5TWFuYWdlci5zZXRNb2R1bGVQYXRoKGAke3RoaXMuaWR9U3Vic2V0TWFwcGluZ2AsIGBzb25hbXUuZ2VuZXJhdGVkYCk7XG4gICAgICBmb3IgKGNvbnN0IHN1YnNldEtleSBvZiBPYmplY3Qua2V5cyh0aGlzLnN1YnNldHMpKSB7XG4gICAgICAgIEVudGl0eU1hbmFnZXIuc2V0TW9kdWxlUGF0aChcbiAgICAgICAgICBgJHt0aGlzLmlkfVN1YnNldCR7c3Vic2V0S2V5LnRvVXBwZXJDYXNlKCl9YCxcbiAgICAgICAgICBgc29uYW11LmdlbmVyYXRlZGAsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gZW51bXNcbiAgICBmb3IgKGNvbnN0IGVudW1JZCBvZiBPYmplY3Qua2V5cyh0aGlzLmVudW1MYWJlbHMpKSB7XG4gICAgICBFbnRpdHlNYW5hZ2VyLnNldE1vZHVsZVBhdGgoZW51bUlkLCBgc29uYW11LmdlbmVyYXRlZGApO1xuICAgIH1cblxuICAgIC8vIHR5cGVzXG4gICAgY29uc3QgdHlwZXNNb2R1bGVQYXRoID0gYCR7YmFzZVBhdGh9LyR7dGhpcy5uYW1lcy5wYXJlbnRGc30udHlwZXNgO1xuICAgIGNvbnN0IHR5cGVzRmlsZVBhdGggPSBwYXRoLmpvaW4oXG4gICAgICBTb25hbXUuYXBpUm9vdFBhdGgsXG4gICAgICBydW50aW1lUGF0aChgZGlzdC9hcHBsaWNhdGlvbi8ke3R5cGVzTW9kdWxlUGF0aH0uanNgKSxcbiAgICApO1xuXG4gICAgaWYgKGF3YWl0IGV4aXN0cyh0eXBlc0ZpbGVQYXRoKSkge1xuICAgICAgY29uc3QgaW1wb3J0ZWRNZW1iZXJzID0gYXdhaXQgaW1wb3J0TWVtYmVyczx6LlpvZFR5cGVBbnk+KHR5cGVzRmlsZVBhdGgpO1xuICAgICAgdGhpcy50eXBlcyA9IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgICAgaW1wb3J0ZWRNZW1iZXJzLm1hcCgoeyBuYW1lLCB2YWx1ZSB9KSA9PiB7XG4gICAgICAgICAgRW50aXR5TWFuYWdlci5zZXRNb2R1bGVQYXRoKG5hbWUsIHR5cGVzTW9kdWxlUGF0aCk7XG4gICAgICAgICAgcmV0dXJuIFtuYW1lLCB2YWx1ZV07XG4gICAgICAgIH0pLFxuICAgICAgKSBhcyB7IFtuYW1lOiBzdHJpbmddOiB6LlpvZFR5cGVBbnkgfTtcbiAgICB9XG4gIH1cblxuICByZWdpc3RlclRhYmxlU3BlY3MoKTogdm9pZCB7XG4gICAgLy8g7KGw7J24IO2FjOydtOu4lCDsnbjrjbHsiqQg7KCc7Jm4ICjsu6zrn7wg7J2066aE7JeQICcuJ+ydtCDtj6ztlajrkJwg6rK97JqwKVxuICAgIGNvbnN0IHVuaXF1ZUluZGV4ZXMgPSB0aGlzLmluZGV4ZXNcbiAgICAgIC5maWx0ZXIoKGlkeCkgPT4gaWR4LnR5cGUgPT09IFwidW5pcXVlXCIpXG4gICAgICAuZmlsdGVyKChpZHgpID0+IGlkeC5jb2x1bW5zLmV2ZXJ5KChjb2wpID0+ICFjb2wubmFtZS5pbmNsdWRlcyhcIi5cIikpKTtcblxuICAgIEVudGl0eU1hbmFnZXIuc2V0VGFibGVTcGVjKHtcbiAgICAgIG5hbWU6IHRoaXMudGFibGUsXG4gICAgICB1bmlxdWVJbmRleGVzLFxuICAgICAganNvbkNvbHVtbnM6IHRoaXMucHJvcHMuZmlsdGVyKChwKSA9PiBwLnR5cGUgPT09IFwianNvblwiKS5tYXAoKHApID0+IHAubmFtZSksXG4gICAgfSk7XG4gIH1cblxuICB0b0pzb24oKTogRW50aXR5SnNvbiB7XG4gICAgLy8gc3Vic2V0c+yZgCBzdWJzZXRzSW50ZXJuYWzsnYQgU3Vic2V0RGVmIO2Yle2DnOuhnCDrs7Xsm5AgKGNvbmUg7Y+s7ZWoKVxuICAgIGNvbnN0IHN1YnNldHM6IHsgW2tleTogc3RyaW5nXTogaW1wb3J0KFwiLi4vdHlwZXMvdHlwZXNcIikuU3Vic2V0RGVmIH0gPSB7fTtcbiAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyh0aGlzLnN1YnNldHMpKSB7XG4gICAgICBjb25zdCBub3JtYWxGaWVsZHM6IFN1YnNldEZpZWxkW10gPSB0aGlzLnN1YnNldHNba2V5XTtcbiAgICAgIGNvbnN0IGludGVybmFsRmllbGRzOiBTdWJzZXRGaWVsZFtdID0gKHRoaXMuc3Vic2V0c0ludGVybmFsW2tleV0gPz8gW10pLm1hcCgoZmllbGQpID0+ICh7XG4gICAgICAgIGZpZWxkLFxuICAgICAgICBpbnRlcm5hbDogdHJ1ZSxcbiAgICAgIH0pKTtcbiAgICAgIGNvbnN0IGZpZWxkcyA9IFsuLi5ub3JtYWxGaWVsZHMsIC4uLmludGVybmFsRmllbGRzXTtcblxuICAgICAgLy8gY29uZeydtCDsnojsnLzrqbQg7IOI66Gc7Jq0IOqwneyytCDtmJXtg5zroZwsIOyXhuycvOuptCDrsLDsl7Qg7ZiV7YOc66GcXG4gICAgICBpZiAodGhpcy5zdWJzZXRDb25lc1trZXldKSB7XG4gICAgICAgIHN1YnNldHNba2V5XSA9IHtcbiAgICAgICAgICBmaWVsZHMsXG4gICAgICAgICAgY29uZTogdGhpcy5zdWJzZXRDb25lc1trZXldLFxuICAgICAgICB9O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3Vic2V0c1trZXldID0gZmllbGRzO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIGVudW1z66W8IEVudW1EZWYg7ZiV7YOc66GcIOuzteybkCAoY29uZSDtj6ztlagpXG4gICAgY29uc3QgZW51bXM6IHsgW2tleTogc3RyaW5nXTogaW1wb3J0KFwiLi4vdHlwZXMvdHlwZXNcIikuRW51bURlZiB9ID0ge307XG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZXNdIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMuZW51bUxhYmVscykpIHtcbiAgICAgIC8vIGNvbmXsnbQg7J6I7Jy866m0IOyDiOuhnOyatCDqsJ3ssrQg7ZiV7YOc66GcLCDsl4bsnLzrqbQgUmVjb3JkIO2Yle2DnOuhnFxuICAgICAgaWYgKHRoaXMuZW51bUNvbmVzW2tleV0pIHtcbiAgICAgICAgZW51bXNba2V5XSA9IHtcbiAgICAgICAgICB2YWx1ZXMsXG4gICAgICAgICAgY29uZTogdGhpcy5lbnVtQ29uZXNba2V5XSxcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGVudW1zW2tleV0gPSB2YWx1ZXM7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiB0aGlzLmlkLFxuICAgICAgcGFyZW50SWQ6IHRoaXMucGFyZW50SWQsXG4gICAgICB0YWJsZTogdGhpcy50YWJsZSxcbiAgICAgIHRpdGxlOiB0aGlzLnRpdGxlLFxuICAgICAgY29uZTogdGhpcy5jb25lLFxuICAgICAgcHJvcHM6IHRoaXMucHJvcHMsXG4gICAgICBpbmRleGVzOiB0aGlzLmluZGV4ZXMsXG4gICAgICBzdWJzZXRzLFxuICAgICAgZW51bXMsXG4gICAgfTtcbiAgfVxuXG4gIGFzeW5jIHNhdmUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gc29ydDogc3Vic2V0c1xuICAgIGNvbnN0IHN1YnNldFJvd3MgPSB0aGlzLmdldFN1YnNldFJvd3MoKTtcbiAgICB0aGlzLnN1YnNldHMgPSBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgICBPYmplY3QuZW50cmllcyh0aGlzLnN1YnNldHMpLm1hcCgoW3N1YnNldEtleV0pID0+IHtcbiAgICAgICAgcmV0dXJuIFtzdWJzZXRLZXksIHRoaXMuc3Vic2V0Um93c1RvU3Vic2V0RmllbGRzKHN1YnNldFJvd3MsIHN1YnNldEtleSwgZmFsc2UpXTtcbiAgICAgIH0pLFxuICAgICk7XG4gICAgdGhpcy5zdWJzZXRzSW50ZXJuYWwgPSBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgICBPYmplY3QuZW50cmllcyh0aGlzLnN1YnNldHNJbnRlcm5hbCkubWFwKChbc3Vic2V0S2V5XSkgPT4ge1xuICAgICAgICByZXR1cm4gW3N1YnNldEtleSwgdGhpcy5zdWJzZXRSb3dzVG9TdWJzZXRGaWVsZHMoc3Vic2V0Um93cywgc3Vic2V0S2V5LCB0cnVlKV07XG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgLy8gc2F2ZVxuICAgIGNvbnN0IGpzb25QYXRoID0gcGF0aC5qb2luKFxuICAgICAgU29uYW11LmFwaVJvb3RQYXRoLFxuICAgICAgYHNyYy9hcHBsaWNhdGlvbi8ke3RoaXMubmFtZXMucGFyZW50RnN9LyR7dGhpcy5uYW1lcy5mc30uZW50aXR5Lmpzb25gLFxuICAgICk7XG4gICAgY29uc3QganNvbiA9IHRoaXMudG9Kc29uKCk7XG4gICAgYXdhaXQgd3JpdGVGaWxlKGpzb25QYXRoLCBhd2FpdCBmb3JtYXRDb2RlKEpTT04uc3RyaW5naWZ5KGpzb24pLCBcImpzb25cIiwganNvblBhdGgpKTtcblxuICAgIC8vIHJlbG9hZFxuICAgIGF3YWl0IEVudGl0eU1hbmFnZXIucmVnaXN0ZXIoanNvbik7XG4gIH1cblxuICAvKipcbiAgICog7YWc7ZSM66a/IGNvbmUg66mU7YOA642w7J207YSw66W8IOyDneyEse2VqeuLiOuLpC5cbiAgICpcbiAgICogTExN7J2EIOyCrOyaqe2VmOyngCDslYrqs6AgZmFrZXItbWFwcGluZ3MudHPrpbwg7Zmc7Jqp7ZWY7JesIOq4sOuzuCBjb25l7J2EIOyDneyEse2VqeuLiOuLpC5cbiAgICogc3R1YiBlbnRpdHkg7IOd7ISxIOyLnCDsnpDrj5nsnLzroZwg7Zi47Lac65CY7Ja0IOy1nOyGjO2VnOydmCBjb25lIOuplO2DgOuNsOydtO2EsOulvCDsoJzqs7Xtlanri4jri6QuXG4gICAqXG4gICAqIEBwYXJhbSBsb2NhbGUgLSDsg53shLEg7IucIOyCrOyaqe2VoCBsb2NhbGUgKOq4sOuzuOqwkjogU29uYW11LmNvbmZpZy5pMThuLmRlZmF1bHRMb2NhbGUg65iQ64qUIFwia29cIilcbiAgICovXG4gIGFzeW5jIGdlbmVyYXRlVGVtcGxhdGVDb25lcyhsb2NhbGU/OiBcImtvXCIgfCBcImVuXCIgfCBcImphXCIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IGdlbmVyYXRlVGVtcGxhdGVDb25lcyB9ID0gYXdhaXQgaW1wb3J0KFwiLi9lbnRpdHktdGVtcGxhdGUtY29uZVwiKTtcbiAgICBjb25zdCBjb25maWdMb2NhbGUgPSBTb25hbXUuY29uZmlnLmkxOG4/LmRlZmF1bHRMb2NhbGU7XG4gICAgY29uc3QgZWZmZWN0aXZlTG9jYWxlID1cbiAgICAgIGxvY2FsZSB8fFxuICAgICAgKGNvbmZpZ0xvY2FsZSA9PT0gXCJrb1wiIHx8IGNvbmZpZ0xvY2FsZSA9PT0gXCJlblwiIHx8IGNvbmZpZ0xvY2FsZSA9PT0gXCJqYVwiXG4gICAgICAgID8gY29uZmlnTG9jYWxlXG4gICAgICAgIDogXCJrb1wiKTtcbiAgICBjb25zdCByZXN1bHQgPSBnZW5lcmF0ZVRlbXBsYXRlQ29uZXModGhpcy50b0pzb24oKSwgZWZmZWN0aXZlTG9jYWxlKTtcblxuICAgIC8vIOqysOqzvOulvCBFbnRpdHnsl5Ag7KCB7JqpIChhcHBseUNvbmVz7JmAIOuPmeydvO2VnCDrsKnsi50pXG4gICAgaWYgKHJlc3VsdC5lbnRpdHlDb25lKSB7XG4gICAgICB0aGlzLmNvbmUgPSByZXN1bHQuZW50aXR5Q29uZTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IFtwcm9wTmFtZSwgY29uZV0gb2YgT2JqZWN0LmVudHJpZXMocmVzdWx0LnByb3BDb25lcykpIHtcbiAgICAgIGNvbnN0IHByb3AgPSB0aGlzLnByb3BzLmZpbmQoKHApID0+IHAubmFtZSA9PT0gcHJvcE5hbWUpO1xuICAgICAgaWYgKHByb3ApIHtcbiAgICAgICAgKHByb3AgYXMgeyBjb25lPzogQ29uZSB9KS5jb25lID0gY29uZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmVudW1Db25lcyA9IHsgLi4udGhpcy5lbnVtQ29uZXMsIC4uLnJlc3VsdC5lbnVtQ29uZXMgfTtcbiAgICB0aGlzLnN1YnNldENvbmVzID0geyAuLi50aGlzLnN1YnNldENvbmVzLCAuLi5yZXN1bHQuc3Vic2V0Q29uZXMgfTtcblxuICAgIGF3YWl0IHRoaXMuc2F2ZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIExMTeydhCDsgqzsmqntlZjsl6wgY29uZSDrqZTtg4DrjbDsnbTthLDrpbwg7IOd7ISx7ZWp64uI64ukLlxuICAgKlxuICAgKiBAcGFyYW0gb3B0aW9ucy5wcmVzZXJ2ZUV4aXN0aW5nIC0g6riw7KG0IGNvbmUg67O07KG0IOyXrOu2gCAo6riw67O46rCSOiB0cnVlKVxuICAgKiBAcGFyYW0gb3B0aW9ucy5vbmx5RW1wdHkgLSBmaXh0dXJlSGludOqwgCDsl4bripQgY29uZeunjCDsg53shLEgKOq4sOuzuOqwkjogZmFsc2UpXG4gICAqIEBwYXJhbSBvcHRpb25zLmxvY2FsZSAtIOyDneyEsSDsi5wg7IKs7Jqp7ZWgIGxvY2FsZSAo6riw67O46rCSOiBcImtvXCIpXG4gICAqL1xuICBhc3luYyBnZW5lcmF0ZUNvbmVzKG9wdGlvbnM/OiB7XG4gICAgcHJlc2VydmVFeGlzdGluZz86IGJvb2xlYW47XG4gICAgb25seUVtcHR5PzogYm9vbGVhbjtcbiAgICBsb2NhbGU/OiBcImtvXCIgfCBcImVuXCIgfCBcImphXCI7XG4gIH0pOiBQcm9taXNlPGltcG9ydChcIi4uL2NvbmUvY29uZS1nZW5lcmF0b3JcIikuQ29uZUdlbmVyYXRpb25SZXN1bHQ+IHtcbiAgICBjb25zdCB7IGdlbmVyYXRlQ29uZXMgfSA9IGF3YWl0IGltcG9ydChcIi4uL2NvbmUvY29uZS1nZW5lcmF0b3JcIik7XG4gICAgY29uc3QgY29udGV4dDogaW1wb3J0KFwiLi4vY29uZS9jb25lLWdlbmVyYXRvclwiKS5Db25lR2VuZXJhdGlvbkNvbnRleHQgPSB7XG4gICAgICBlbnRpdHk6IHRoaXMudG9Kc29uKCksXG4gICAgICBsb2NhbGU6IG9wdGlvbnM/LmxvY2FsZSB8fCBcImtvXCIsXG4gICAgICBleGlzdGluZ0NvbmVzOiBvcHRpb25zPy5wcmVzZXJ2ZUV4aXN0aW5nICE9PSBmYWxzZSA/IHRoaXMuY29sbGVjdEV4aXN0aW5nQ29uZXMoKSA6IHVuZGVmaW5lZCxcbiAgICAgIG9ubHlFbXB0eTogb3B0aW9ucz8ub25seUVtcHR5ID8/IGZhbHNlLFxuICAgIH07XG5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBnZW5lcmF0ZUNvbmVzKGNvbnRleHQpO1xuICAgIHRoaXMuYXBwbHlDb25lcyhyZXN1bHQpO1xuICAgIGF3YWl0IHRoaXMuc2F2ZSgpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICog6riw7KG0IGNvbmXrk6TsnYQg7IiY7KeR7ZWp64uI64ukIChlbnRpdHksIHByb3BzLCBlbnVtcywgc3Vic2V0cykuXG4gICAqXG4gICAqIEByZXR1cm5zIO2CpOqwgCBcImVudGl0eTppZFwiLCBcInByb3A6bmFtZVwiLCBcImVudW06ZW51bUlkXCIsIFwic3Vic2V0OmtleVwiIO2YleyLneyduCBjb25lIOuntVxuICAgKi9cbiAgcHJpdmF0ZSBjb2xsZWN0RXhpc3RpbmdDb25lcygpOiBSZWNvcmQ8c3RyaW5nLCBDb25lPiB7XG4gICAgY29uc3QgY29uZXM6IFJlY29yZDxzdHJpbmcsIENvbmU+ID0ge307XG5cbiAgICBpZiAodGhpcy5jb25lKSB7XG4gICAgICBjb25lc1tgZW50aXR5OiR7dGhpcy5pZH1gXSA9IHRoaXMuY29uZTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IHByb3Agb2YgdGhpcy5wcm9wcykge1xuICAgICAgaWYgKHByb3AuY29uZSkge1xuICAgICAgICBjb25lc1tgcHJvcDoke3Byb3AubmFtZX1gXSA9IHByb3AuY29uZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IFtlbnVtSWQsIGNvbmVdIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMuZW51bUNvbmVzKSkge1xuICAgICAgY29uZXNbYGVudW06JHtlbnVtSWR9YF0gPSBjb25lO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgW3N1YnNldEtleSwgY29uZV0gb2YgT2JqZWN0LmVudHJpZXModGhpcy5zdWJzZXRDb25lcykpIHtcbiAgICAgIGNvbmVzW2BzdWJzZXQ6JHtzdWJzZXRLZXl9YF0gPSBjb25lO1xuICAgIH1cblxuICAgIHJldHVybiBjb25lcztcbiAgfVxuXG4gIC8qKlxuICAgKiDsg53shLHrkJwgY29uZeuTpOydhCBFbnRpdHnsl5Ag7KCB7Jqp7ZWp64uI64ukLlxuICAgKlxuICAgKiBAcGFyYW0gcmVzdWx0IC0gTExN7Jy866GcIOyDneyEseuQnCBjb25lIOqysOqzvFxuICAgKi9cbiAgcHJpdmF0ZSBhcHBseUNvbmVzKHJlc3VsdDogaW1wb3J0KFwiLi4vY29uZS9jb25lLWdlbmVyYXRvclwiKS5Db25lR2VuZXJhdGlvblJlc3VsdCk6IHZvaWQge1xuICAgIGlmIChyZXN1bHQuZW50aXR5Q29uZSkge1xuICAgICAgdGhpcy5jb25lID0gcmVzdWx0LmVudGl0eUNvbmU7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBbcHJvcE5hbWUsIGNvbmVdIG9mIE9iamVjdC5lbnRyaWVzKHJlc3VsdC5wcm9wQ29uZXMpKSB7XG4gICAgICBjb25zdCBwcm9wID0gdGhpcy5wcm9wcy5maW5kKChwKSA9PiBwLm5hbWUgPT09IHByb3BOYW1lKTtcbiAgICAgIGlmIChwcm9wKSB7XG4gICAgICAgIChwcm9wIGFzIHsgY29uZT86IENvbmUgfSkuY29uZSA9IGNvbmU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5lbnVtQ29uZXMgPSB7IC4uLnRoaXMuZW51bUNvbmVzLCAuLi5yZXN1bHQuZW51bUNvbmVzIH07XG4gICAgdGhpcy5zdWJzZXRDb25lcyA9IHsgLi4udGhpcy5zdWJzZXRDb25lcywgLi4ucmVzdWx0LnN1YnNldENvbmVzIH07XG4gIH1cblxuICBnZXRTdWJzZXRSb3dzKFxuICAgIF9zdWJzZXRzPzogeyBba2V5OiBzdHJpbmddOiBzdHJpbmdbXSB9LFxuICAgIF9zdWJzZXRzSW50ZXJuYWw/OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZ1tdIH0sXG4gICAgcHJlZml4ZXM6IHN0cmluZ1tdID0gW10sXG4gICk6IEVudGl0eVN1YnNldFJvd1tdIHtcbiAgICBpZiAocHJlZml4ZXMubGVuZ3RoID4gMTApIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICBjb25zdCBzdWJzZXRzID0gX3N1YnNldHMgPz8gdGhpcy5zdWJzZXRzO1xuICAgIGNvbnN0IHN1YnNldHNJbnRlcm5hbCA9IF9zdWJzZXRzSW50ZXJuYWwgPz8gdGhpcy5zdWJzZXRzSW50ZXJuYWw7XG4gICAgY29uc3Qgc3Vic2V0S2V5cyA9IE9iamVjdC5rZXlzKHN1YnNldHMpO1xuICAgIGNvbnN0IGFsbEZpZWxkcyA9IHVuaXF1ZShzdWJzZXRLZXlzLmZsYXRNYXAoKGtleSkgPT4gc3Vic2V0c1trZXldKSk7XG4gICAgLy8gaW50ZXJuYWwg7ZWE65Oc64+EIGFsbEZpZWxkc+yXkCDtj6ztlaggKHJlbGF0aW9uIO2DkOyDieyaqSlcbiAgICBjb25zdCBhbGxJbnRlcm5hbEZpZWxkcyA9IHVuaXF1ZShzdWJzZXRLZXlzLmZsYXRNYXAoKGtleSkgPT4gc3Vic2V0c0ludGVybmFsW2tleV0gPz8gW10pKTtcbiAgICBjb25zdCBjb21iaW5lZEZpZWxkcyA9IHVuaXF1ZShbLi4uYWxsRmllbGRzLCAuLi5hbGxJbnRlcm5hbEZpZWxkc10pO1xuXG4gICAgcmV0dXJuIHRoaXMucHJvcHMubWFwKChwcm9wKSA9PiB7XG4gICAgICBpZiAoXG4gICAgICAgIHByb3AudHlwZSA9PT0gXCJyZWxhdGlvblwiICYmXG4gICAgICAgIGNvbWJpbmVkRmllbGRzLmZpbmQoKGYpID0+IGYuc3RhcnRzV2l0aChgJHtbLi4ucHJlZml4ZXMsIHByb3AubmFtZV0uam9pbihcIi5cIil9LmApKVxuICAgICAgKSB7XG4gICAgICAgIGNvbnN0IHJlbEVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KHByb3Aud2l0aCk7XG4gICAgICAgIGNvbnN0IGNoaWxkcmVuID0gcmVsRW50aXR5LmdldFN1YnNldFJvd3Moc3Vic2V0cywgc3Vic2V0c0ludGVybmFsLCBbXG4gICAgICAgICAgLi4ucHJlZml4ZXMsXG4gICAgICAgICAgYCR7cHJvcC5uYW1lfWAsXG4gICAgICAgIF0pO1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZmllbGQ6IHByb3AubmFtZSxcbiAgICAgICAgICBjaGlsZHJlbixcbiAgICAgICAgICByZWxhdGlvbkVudGl0eTogcHJvcC53aXRoLFxuICAgICAgICAgIHByZWZpeGVzLFxuICAgICAgICAgIGlzT3BlbjogY2hpbGRyZW4ubGVuZ3RoID4gMCxcbiAgICAgICAgICBoYXM6IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgICAgICAgIHN1YnNldEtleXMubWFwKChzdWJzZXRLZXkpID0+IHtcbiAgICAgICAgICAgICAgcmV0dXJuIFtzdWJzZXRLZXksIGNoaWxkcmVuLmV2ZXJ5KChjaGlsZCkgPT4gY2hpbGQuaGFzW3N1YnNldEtleV0pXTtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICksXG4gICAgICAgICAgaXNJbnRlcm5hbDogT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgICAgICAgc3Vic2V0S2V5cy5tYXAoKHN1YnNldEtleSkgPT4ge1xuICAgICAgICAgICAgICByZXR1cm4gW3N1YnNldEtleSwgY2hpbGRyZW4uZXZlcnkoKGNoaWxkKSA9PiBjaGlsZC5pc0ludGVybmFsW3N1YnNldEtleV0pXTtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICksXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGZpZWxkID0gWy4uLnByZWZpeGVzLCBwcm9wLm5hbWVdLmpvaW4oXCIuXCIpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZmllbGQ6IHByb3AubmFtZSxcbiAgICAgICAgY2hpbGRyZW46IFtdLFxuICAgICAgICByZWxhdGlvbkVudGl0eTogcHJvcC50eXBlID09PSBcInJlbGF0aW9uXCIgPyBwcm9wLndpdGggOiB1bmRlZmluZWQsXG4gICAgICAgIHByZWZpeGVzLFxuICAgICAgICBoYXM6IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgICAgICBzdWJzZXRLZXlzLm1hcCgoc3Vic2V0S2V5KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBzdWJzZXRGaWVsZHMgPSBzdWJzZXRzW3N1YnNldEtleV07XG4gICAgICAgICAgICBjb25zdCBoYXMgPSBzdWJzZXRGaWVsZHMuc29tZSgoZikgPT4ge1xuICAgICAgICAgICAgICByZXR1cm4gZiA9PT0gZmllbGQgfHwgZi5zdGFydHNXaXRoKGAke2ZpZWxkfS5gKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIFtzdWJzZXRLZXksIGhhc107XG4gICAgICAgICAgfSksXG4gICAgICAgICksXG4gICAgICAgIGlzSW50ZXJuYWw6IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgICAgICBzdWJzZXRLZXlzLm1hcCgoc3Vic2V0S2V5KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBpbnRlcm5hbEZpZWxkcyA9IHN1YnNldHNJbnRlcm5hbFtzdWJzZXRLZXldID8/IFtdO1xuICAgICAgICAgICAgY29uc3QgaXNJbnRlcm5hbCA9IGludGVybmFsRmllbGRzLnNvbWUoKGYpID0+IHtcbiAgICAgICAgICAgICAgcmV0dXJuIGYgPT09IGZpZWxkIHx8IGYuc3RhcnRzV2l0aChgJHtmaWVsZH0uYCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBbc3Vic2V0S2V5LCBpc0ludGVybmFsXTtcbiAgICAgICAgICB9KSxcbiAgICAgICAgKSxcbiAgICAgIH07XG4gICAgfSk7XG4gIH1cblxuICBzdWJzZXRSb3dzVG9TdWJzZXRGaWVsZHMoXG4gICAgc3Vic2V0Um93czogRW50aXR5U3Vic2V0Um93W10sXG4gICAgc3Vic2V0S2V5OiBzdHJpbmcsXG4gICAgaW50ZXJuYWw6IGJvb2xlYW4gPSBmYWxzZSxcbiAgKTogc3RyaW5nW10ge1xuICAgIGNvbnN0IGhhc0tleSA9IGludGVybmFsID8gXCJpc0ludGVybmFsXCIgOiBcImhhc1wiO1xuICAgIHJldHVybiBzdWJzZXRSb3dzXG4gICAgICAubWFwKChzdWJzZXRSb3cpID0+IHtcbiAgICAgICAgaWYgKHN1YnNldFJvdy5jaGlsZHJlbi5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMuc3Vic2V0Um93c1RvU3Vic2V0RmllbGRzKHN1YnNldFJvdy5jaGlsZHJlbiwgc3Vic2V0S2V5LCBpbnRlcm5hbCk7XG4gICAgICAgIH0gZWxzZSBpZiAoc3Vic2V0Um93W2hhc0tleV1bc3Vic2V0S2V5XSkge1xuICAgICAgICAgIHJldHVybiBzdWJzZXRSb3cucHJlZml4ZXMuY29uY2F0KHN1YnNldFJvdy5maWVsZCkuam9pbihcIi5cIik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgICAuZmlsdGVyKG5vbk51bGxhYmxlKVxuICAgICAgLmZsYXQoKTtcbiAgfVxuXG4gIGFzeW5jIGNyZWF0ZVByb3AocHJvcDogRW50aXR5UHJvcCwgYXQ/OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIWF0KSB7XG4gICAgICB0aGlzLnByb3BzLnB1c2gocHJvcCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMucHJvcHMuc3BsaWNlKGF0LCAwLCBwcm9wKTtcbiAgICB9XG4gICAgYXdhaXQgdGhpcy5zYXZlKCk7XG4gIH1cblxuICBhbmFseXplU3Vic2V0RmllbGQoc3Vic2V0RmllbGQ6IHN0cmluZyk6IHtcbiAgICBlbnRpdHlJZDogc3RyaW5nO1xuICAgIHByb3BOYW1lOiBzdHJpbmc7XG4gIH1bXSB7XG4gICAgY29uc3QgYXJyID0gc3Vic2V0RmllbGQuc3BsaXQoXCIuXCIpO1xuXG4gICAgbGV0IGVudGl0eUlkID0gdGhpcy5pZDtcbiAgICBjb25zdCByZXN1bHQ6IHtcbiAgICAgIGVudGl0eUlkOiBzdHJpbmc7XG4gICAgICBwcm9wTmFtZTogc3RyaW5nO1xuICAgIH1bXSA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBwcm9wTmFtZSA9IGFycltpXTtcbiAgICAgIHJlc3VsdC5wdXNoKHtcbiAgICAgICAgZW50aXR5SWQsXG4gICAgICAgIHByb3BOYW1lLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IHByb3AgPSBFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCkucHJvcHMuZmluZCgocCkgPT4gcC5uYW1lID09PSBwcm9wTmFtZSk7XG4gICAgICBpZiAoIXByb3ApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke2VudGl0eUlkfeydmCDsnpjrqrvrkJwg7ISc67iM7IWL7YKkICR7c3Vic2V0RmllbGR9YCk7XG4gICAgICB9XG4gICAgICBpZiAoaXNSZWxhdGlvblByb3AocHJvcCkpIHtcbiAgICAgICAgZW50aXR5SWQgPSBwcm9wLndpdGg7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICBhc3luYyBtb2RpZnlQcm9wKG5ld1Byb3A6IEVudGl0eVByb3AsIGF0OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyDsnbTsoIQg7ZSE66GtIOydtOumhCDsoIDsnqVcbiAgICBjb25zdCBvbGROYW1lID0gdGhpcy5wcm9wc1thdF0ubmFtZTtcblxuICAgIC8vIOyggOyepe2VoCDsl5Tti7Dti7BcbiAgICBjb25zdCBlbnRpdGllczogRW50aXR5W10gPSBbdGhpc107XG5cbiAgICAvLyDsnbTrpoTsnbQg67CU64CQIOqyveyasFxuICAgIGlmIChvbGROYW1lICE9PSBuZXdQcm9wLm5hbWUpIHtcbiAgICAgIC8vIOyghOyytCDsl5Tti7Dti7Dsl5DshJwg7ZiE7J6sIOyImOygleuQnCDtlITroa3snYQg7LC47KGw7ZWY6rOgIOyeiOuKlCDrqqjrk6Ag7ISc67iM7IWL7ZWE65OcIOywvuyVhOyEnCDsiJjsoJVcbiAgICAgIGNvbnN0IGFsbEVudGl0eUlkcyA9IEVudGl0eU1hbmFnZXIuZ2V0QWxsSWRzKCk7XG4gICAgICBmb3IgKGNvbnN0IHJlbEVudGl0eUlkIG9mIGFsbEVudGl0eUlkcykge1xuICAgICAgICBjb25zdCByZWxFbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChyZWxFbnRpdHlJZCk7XG4gICAgICAgIGNvbnN0IHJlbEVudGl0eVN1YnNldEtleXMgPSBPYmplY3Qua2V5cyhyZWxFbnRpdHkuc3Vic2V0cyk7XG4gICAgICAgIGZvciAoY29uc3Qgc3Vic2V0S2V5IG9mIHJlbEVudGl0eVN1YnNldEtleXMpIHtcbiAgICAgICAgICBjb25zdCBzdWJzZXQgPSByZWxFbnRpdHkuc3Vic2V0c1tzdWJzZXRLZXldO1xuXG4gICAgICAgICAgLy8g7ISc67iM7IWLIO2VhOuTnOulvCDsiJztmoztlZjrqbAsIOyXlO2LsO2LsC3tlITroa0g64uo7JyE66GcIOu2hOyEne2VnCDtm4Qg7ZiE7J6sIOyXlO2LsO2LsC3tlITroa3qs7wg7J287LmY7ZWY64qUIOqyveyasCDsiJjsoJUg7LKY66asXG4gICAgICAgICAgY29uc3QgbW9kaWZpZWRTdWJzZXRGaWVsZHMgPSBzdWJzZXQubWFwKChzdWJzZXRGaWVsZCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgYW5hbHl6ZWQgPSByZWxFbnRpdHkuYW5hbHl6ZVN1YnNldEZpZWxkKHN1YnNldEZpZWxkKTtcbiAgICAgICAgICAgIGNvbnN0IG1vZGlmaWVkID0gYW5hbHl6ZWQubWFwKChhKSA9PlxuICAgICAgICAgICAgICBhLnByb3BOYW1lID09PSBvbGROYW1lICYmIGEuZW50aXR5SWQgPT09IHRoaXMuaWRcbiAgICAgICAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgICAgICAgLi4uYSxcbiAgICAgICAgICAgICAgICAgICAgcHJvcE5hbWU6IG5ld1Byb3AubmFtZSxcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICA6IGEsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgLy8g67aE7ISd7ZWcIO2VhOuTnOulvCDri6Tsi5wg7ISc67iM7IWLIO2VhOuTnOuhnCDrs7XqtaxcbiAgICAgICAgICAgIHJldHVybiBtb2RpZmllZC5tYXAoKGEpID0+IGEucHJvcE5hbWUpLmpvaW4oXCIuXCIpO1xuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgaWYgKHN1YnNldC5qb2luKFwiLFwiKSAhPT0gbW9kaWZpZWRTdWJzZXRGaWVsZHMuam9pbihcIixcIikpIHtcbiAgICAgICAgICAgIHJlbEVudGl0eS5zdWJzZXRzW3N1YnNldEtleV0gPSBtb2RpZmllZFN1YnNldEZpZWxkcztcbiAgICAgICAgICAgIGVudGl0aWVzLnB1c2gocmVsRW50aXR5KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyDtlITroa0g7IiY7KCVXG4gICAgdGhpcy5wcm9wc1thdF0gPSBuZXdQcm9wO1xuXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoZW50aXRpZXMubWFwKGFzeW5jIChlbnRpdHkpID0+IGVudGl0eS5zYXZlKCkpKTtcbiAgfVxuXG4gIGFzeW5jIGRlbFByb3AoYXQ6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIOydtOyghCDtlITroa0g7J2066aEIOyggOyepVxuICAgIGNvbnN0IG9sZE5hbWUgPSB0aGlzLnByb3BzW2F0XS5uYW1lO1xuXG4gICAgLy8g7KCA7J6l7ZWgIOyXlO2LsO2LsFxuICAgIGNvbnN0IGVudGl0aWVzOiBFbnRpdHlbXSA9IFt0aGlzXTtcblxuICAgIC8vIOyghOyytCDsl5Tti7Dti7Dsl5DshJwg7ZiE7J6sIOyCreygnOuQnCDtlITroa3snYQg7LC47KGw7ZWY6rOgIOyeiOuKlCDrqqjrk6Ag7ISc67iM7IWL7ZWE65OcIOywvuyVhOyEnCDsoJzsmbhcbiAgICBjb25zdCBhbGxFbnRpdHlJZHMgPSBFbnRpdHlNYW5hZ2VyLmdldEFsbElkcygpO1xuICAgIGZvciAoY29uc3QgcmVsRW50aXR5SWQgb2YgYWxsRW50aXR5SWRzKSB7XG4gICAgICBjb25zdCByZWxFbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChyZWxFbnRpdHlJZCk7XG4gICAgICBjb25zdCByZWxFbnRpdHlTdWJzZXRLZXlzID0gT2JqZWN0LmtleXMocmVsRW50aXR5LnN1YnNldHMpO1xuICAgICAgZm9yIChjb25zdCBzdWJzZXRLZXkgb2YgcmVsRW50aXR5U3Vic2V0S2V5cykge1xuICAgICAgICBjb25zdCBzdWJzZXQgPSByZWxFbnRpdHkuc3Vic2V0c1tzdWJzZXRLZXldO1xuICAgICAgICAvLyDshJzruIzshYsg7ZWE65Oc66W8IOyInO2ajO2VmOupsCwg7JeU7Yuw7YuwLe2UhOuhrSDri6jsnITroZwg67aE7ISd7ZWcIO2bhCDtmITsnqwg7JeU7Yuw7YuwLe2UhOuhreqzvCDsnbzsuZjtlZjripQg6rK97JqwIOydtO2bhOydmCDtlYTrk5zrpbwg7KCc7Jm4XG4gICAgICAgIGNvbnN0IG1vZGlmaWVkU3Vic2V0RmllbGRzID0gc3Vic2V0XG4gICAgICAgICAgLm1hcCgoc3Vic2V0RmllbGQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGFuYWx5emVkID0gcmVsRW50aXR5LmFuYWx5emVTdWJzZXRGaWVsZChzdWJzZXRGaWVsZCk7XG4gICAgICAgICAgICBpZiAoYW5hbHl6ZWQuZmluZCgoYSkgPT4gYS5wcm9wTmFtZSA9PT0gb2xkTmFtZSAmJiBhLmVudGl0eUlkID09PSB0aGlzLmlkKSkge1xuICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHJldHVybiBzdWJzZXRGaWVsZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KVxuICAgICAgICAgIC5maWx0ZXIobm9uTnVsbGFibGUpO1xuXG4gICAgICAgIGlmIChzdWJzZXQuam9pbihcIixcIikgIT09IG1vZGlmaWVkU3Vic2V0RmllbGRzLmpvaW4oXCIsXCIpKSB7XG4gICAgICAgICAgcmVsRW50aXR5LnN1YnNldHNbc3Vic2V0S2V5XSA9IG1vZGlmaWVkU3Vic2V0RmllbGRzO1xuICAgICAgICAgIGVudGl0aWVzLnB1c2gocmVsRW50aXR5KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIO2YhOyerCDsl5Tti7Dti7DsnZgg7J24642x7Iqk7JeQ7IScIOygnOyZuFxuICAgIGZvciAoY29uc3QgaW5kZXggb2YgRW50aXR5TWFuYWdlci5nZXQodGhpcy5pZCkuaW5kZXhlcykge1xuICAgICAgaW5kZXguY29sdW1ucyA9IGluZGV4LmNvbHVtbnMuZmlsdGVyKChjb2wpID0+IGNvbC5uYW1lICE9PSBvbGROYW1lKTtcbiAgICB9XG5cbiAgICAvLyDtlITroa0g7IKt7KCcXG4gICAgdGhpcy5wcm9wcy5zcGxpY2UoYXQsIDEpO1xuXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoZW50aXRpZXMubWFwKGFzeW5jIChlbnRpdHkpID0+IGVudGl0eS5zYXZlKCkpKTtcbiAgfVxuXG4gIGdldEVudGl0eUlkRnJvbVN1YnNldEZpZWxkKHN1YnNldEZpZWxkOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmICghc3Vic2V0RmllbGQuaW5jbHVkZXMoXCIuXCIpKSB7XG4gICAgICByZXR1cm4gdGhpcy5pZDtcbiAgICB9XG5cbiAgICAvLyDshJzruIzshYsg7ZWE65Oc7J2YIOuniOyngOunieydgCDtlITroa3snbTrr4DroZwg7KCc7Jm4XG4gICAgY29uc3QgYXJyID0gc3Vic2V0RmllbGQuc3BsaXQoXCIuXCIpLnNsaWNlKDAsIC0xKTtcblxuICAgIC8vIOyEnOu4jOyFiyDtlYTrk5zrpbwg64K066Ck6rCA66m07IScIOuniOyngOunieycvOuhnCByZWxhdGlvbuuQnCDsl5Tti7Dti7Drpbwg7LC+7J2MXG4gICAgY29uc3QgbGFzdEVudGl0eUlkID0gYXJyLnJlZHVjZSgoZW50aXR5SWQsIGZpZWxkKSA9PiB7XG4gICAgICBjb25zdCByZWxQcm9wID0gRW50aXR5TWFuYWdlci5nZXQoZW50aXR5SWQpLnByb3BzLmZpbmQoKHApID0+IHAubmFtZSA9PT0gZmllbGQpO1xuICAgICAgaWYgKCFyZWxQcm9wIHx8IHJlbFByb3AudHlwZSAhPT0gXCJyZWxhdGlvblwiKSB7XG4gICAgICAgIGNvbnNvbGUuZGVidWcoeyBhcnIsIHRoaXNJZDogdGhpcy5pZCwgZW50aXR5SWQsIGZpZWxkIH0pO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYOyemOuqu+uQnCDshJzruIzshYvtgqQgJHtzdWJzZXRGaWVsZH1gKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZWxQcm9wLndpdGg7XG4gICAgfSwgdGhpcy5pZCk7XG4gICAgcmV0dXJuIGxhc3RFbnRpdHlJZDtcbiAgfVxuXG4gIGFzeW5jIG1vdmVQcm9wKGF0OiBudW1iZXIsIHRvOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBwcm9wID0gdGhpcy5wcm9wc1thdF07XG4gICAgY29uc3QgbmV3UHJvcHMgPSBbLi4udGhpcy5wcm9wc107XG4gICAgbmV3UHJvcHMuc3BsaWNlKHRvLCAwLCBwcm9wKTtcbiAgICBuZXdQcm9wcy5zcGxpY2UoYXQgPCB0byA/IGF0IDogYXQgKyAxLCAxKTtcbiAgICB0aGlzLnByb3BzID0gbmV3UHJvcHM7XG5cbiAgICBhd2FpdCB0aGlzLnNhdmUoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDtlYTrk5zrqoXsnYQgXCLthYzsnbTruJTrqoUu7ZWE65Oc66qFXCIg7ZiV7Iud7Jy866GcIOuzgO2ZmFxuICAgKi9cbiAgZ2V0RnVsbEZpZWxkTmFtZShmaWVsZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBpZiAoZmllbGQuaW5jbHVkZXMoXCIuXCIpKSB7XG4gICAgICByZXR1cm4gZmllbGQ7XG4gICAgfVxuICAgIHJldHVybiBgJHt0aGlzLnRhYmxlfS4ke2ZpZWxkfWA7XG4gIH1cblxuICAvKipcbiAgICog7JeU7Yuw7Yuw7J2YIFBLIO2DgOyeheydhCDrsJjtmZjtlanri4jri6QuXG4gICAqIGlkIO2VhOuTnOydmCDtg4DsnoXsnYQg6riw7KSA7Jy866GcIFwiaW50ZWdlclwiIHwgXCJzdHJpbmdcIiB8IFwidXVpZFwi66W8IOuwmO2ZmO2VqeuLiOuLpC5cbiAgICovXG4gIGdldFBrVHlwZSgpOiBcImludGVnZXJcIiB8IFwic3RyaW5nXCIgfCBcInV1aWRcIiB7XG4gICAgY29uc3QgaWRQcm9wID0gdGhpcy5wcm9wc0RpY3QuaWQ7XG4gICAgaWYgKCFpZFByb3ApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRW50aXR5ICR7dGhpcy5pZH3sl5AgaWQg7ZWE65Oc6rCAIOyXhuyKteuLiOuLpGApO1xuICAgIH1cbiAgICBpZiAoaWRQcm9wLnR5cGUgPT09IFwic3RyaW5nXCIgfHwgaWRQcm9wLnR5cGUgPT09IFwidXVpZFwiKSB7XG4gICAgICByZXR1cm4gaWRQcm9wLnR5cGU7XG4gICAgfVxuICAgIHJldHVybiBcImludGVnZXJcIjtcbiAgfVxuXG4gIC8qKlxuICAgKiDsl5Tti7Dti7DsnZggUEsgcHJvcOydhCDrsJjtmZjtlanri4jri6QuXG4gICAqIGxlbmd0aCDrk7Eg7IS467aAIOygleuztOyXkCDsoJHqt7ztlaAg65WMIOyCrOyaqe2VqeuLiOuLpC5cbiAgICovXG4gIGdldFBrUHJvcCgpOiBFbnRpdHlQcm9wIHtcbiAgICBjb25zdCBpZFByb3AgPSB0aGlzLnByb3BzRGljdC5pZDtcbiAgICBpZiAoIWlkUHJvcCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFbnRpdHkgJHt0aGlzLmlkfeyXkCBpZCDtlYTrk5zqsIAg7JeG7Iq164uI64ukYCk7XG4gICAgfVxuICAgIHJldHVybiBpZFByb3A7XG4gIH1cblxuICAvKipcbiAgICog7JeU7Yuw7Yuw7J2YIFBLIOuwsOyXtCDtg4DsnoXsnYQg67CY7ZmY7ZWp64uI64ukLlxuICAgKiBMb2FkZXJRdWVyeeydmCBmcm9tSWRzIO2DgOyeheycvOuhnCDsgqzsmqnrkKnri4jri6QuXG4gICAqL1xuICBnZXRQa0FycmF5VHlwZSgpOiBzdHJpbmcge1xuICAgIGNvbnN0IHBrVHlwZSA9IHRoaXMuZ2V0UGtUeXBlKCk7XG4gICAgcmV0dXJuIHBrVHlwZSA9PT0gXCJpbnRlZ2VyXCIgPyBcIm51bWJlcltdXCIgOiBcInN0cmluZ1tdXCI7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7OztjQVF1QzthQWNmO2lCQVkyQjtpQkFDSDtnQkFDTDtrQkFDTzthQUNVO3NCQUNYO0NBRXBDLFNBQWIsTUFBb0I7RUFDbEI7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBS0E7RUFDQTtFQUdBO0VBR0E7RUFDQTtFQUdBO0VBR0EsUUFFSSxFQUFFO0VBQ04sUUFFSSxFQUFF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