sonamu 0.5.7 → 0.7.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 (529) hide show
  1. package/.swcrc.project-default +18 -0
  2. package/bin/cli.js +24 -0
  3. package/dist/ai/agents/agent.d.ts +11 -0
  4. package/dist/ai/agents/agent.d.ts.map +1 -0
  5. package/dist/ai/agents/agent.js +65 -0
  6. package/dist/ai/agents/index.d.ts +3 -0
  7. package/dist/ai/agents/index.d.ts.map +1 -0
  8. package/dist/ai/agents/index.js +4 -0
  9. package/dist/ai/agents/types.d.ts +43 -0
  10. package/dist/ai/agents/types.d.ts.map +1 -0
  11. package/dist/ai/agents/types.js +3 -0
  12. package/dist/ai/index.d.ts +2 -0
  13. package/dist/ai/index.d.ts.map +1 -0
  14. package/dist/ai/index.js +3 -0
  15. package/dist/ai/providers/rtzr/api.d.ts +22 -0
  16. package/dist/ai/providers/rtzr/api.d.ts.map +1 -0
  17. package/dist/ai/providers/rtzr/api.js +28 -0
  18. package/dist/ai/providers/rtzr/error.d.ts +18 -0
  19. package/dist/ai/providers/rtzr/error.d.ts.map +1 -0
  20. package/dist/ai/providers/rtzr/error.js +29 -0
  21. package/dist/ai/providers/rtzr/index.d.ts +5 -0
  22. package/dist/ai/providers/rtzr/index.d.ts.map +1 -0
  23. package/dist/ai/providers/rtzr/index.js +6 -0
  24. package/dist/ai/providers/rtzr/model.d.ts +52 -0
  25. package/dist/ai/providers/rtzr/model.d.ts.map +1 -0
  26. package/dist/ai/providers/rtzr/model.js +137 -0
  27. package/dist/ai/providers/rtzr/options.d.ts +7 -0
  28. package/dist/ai/providers/rtzr/options.d.ts.map +1 -0
  29. package/dist/ai/providers/rtzr/options.js +47 -0
  30. package/dist/ai/providers/rtzr/provider.d.ts +18 -0
  31. package/dist/ai/providers/rtzr/provider.d.ts.map +1 -0
  32. package/dist/ai/providers/rtzr/provider.js +54 -0
  33. package/dist/ai/providers/rtzr/utils.d.ts +19 -0
  34. package/dist/ai/providers/rtzr/utils.d.ts.map +1 -0
  35. package/dist/ai/providers/rtzr/utils.js +88 -0
  36. package/dist/api/base-frame.d.ts +2 -2
  37. package/dist/api/base-frame.d.ts.map +1 -1
  38. package/dist/api/base-frame.js +13 -2
  39. package/dist/api/caster.d.ts.map +1 -1
  40. package/dist/api/caster.js +71 -2
  41. package/dist/api/code-converters.d.ts +58 -14
  42. package/dist/api/code-converters.d.ts.map +1 -1
  43. package/dist/api/code-converters.js +258 -2
  44. package/dist/api/config.d.ts +90 -0
  45. package/dist/api/config.d.ts.map +1 -0
  46. package/dist/api/config.js +25 -0
  47. package/dist/api/context.d.ts +4 -2
  48. package/dist/api/context.d.ts.map +1 -1
  49. package/dist/api/context.js +3 -2
  50. package/dist/api/decorators.d.ts +20 -6
  51. package/dist/api/decorators.d.ts.map +1 -1
  52. package/dist/api/decorators.js +235 -2
  53. package/dist/api/index.d.ts +2 -2
  54. package/dist/api/index.d.ts.map +1 -1
  55. package/dist/api/index.js +9 -2
  56. package/dist/api/sonamu.d.ts +10 -24
  57. package/dist/api/sonamu.d.ts.map +1 -1
  58. package/dist/api/sonamu.js +514 -2
  59. package/dist/api/validator.d.ts +6 -0
  60. package/dist/api/validator.d.ts.map +1 -0
  61. package/dist/api/validator.js +81 -0
  62. package/dist/bin/build-config.d.ts +6 -1
  63. package/dist/bin/build-config.d.ts.map +1 -1
  64. package/dist/bin/build-config.js +15 -2
  65. package/dist/bin/cli.js +519 -2
  66. package/dist/bin/hot-hook-register.d.ts +11 -0
  67. package/dist/bin/hot-hook-register.d.ts.map +1 -0
  68. package/dist/bin/hot-hook-register.js +21 -0
  69. package/dist/bin/loader-register.d.ts +2 -0
  70. package/dist/bin/loader-register.d.ts.map +1 -0
  71. package/dist/bin/loader-register.js +34 -0
  72. package/dist/database/_batch_update.d.ts +5 -3
  73. package/dist/database/_batch_update.d.ts.map +1 -1
  74. package/dist/database/_batch_update.js +95 -2
  75. package/dist/database/base-model.d.ts +96 -10
  76. package/dist/database/base-model.d.ts.map +1 -1
  77. package/dist/database/base-model.js +390 -2
  78. package/dist/database/base-model.types.d.ts +93 -0
  79. package/dist/database/base-model.types.d.ts.map +1 -0
  80. package/dist/database/base-model.types.js +10 -0
  81. package/dist/database/code-generator.d.ts +1 -1
  82. package/dist/database/code-generator.d.ts.map +1 -1
  83. package/dist/database/code-generator.js +54 -2
  84. package/dist/database/db.d.ts +6 -21
  85. package/dist/database/db.d.ts.map +1 -1
  86. package/dist/database/db.js +129 -2
  87. package/dist/database/puri-subset.test-d.js +81 -0
  88. package/dist/database/puri-subset.types.d.ts +123 -0
  89. package/dist/database/puri-subset.types.d.ts.map +1 -0
  90. package/dist/database/puri-subset.types.js +16 -0
  91. package/dist/database/puri-wrapper.d.ts +13 -11
  92. package/dist/database/puri-wrapper.d.ts.map +1 -1
  93. package/dist/database/puri-wrapper.js +109 -2
  94. package/dist/database/puri.d.ts +41 -23
  95. package/dist/database/puri.d.ts.map +1 -1
  96. package/dist/database/puri.js +601 -2
  97. package/dist/database/puri.types.d.ts +25 -6
  98. package/dist/database/puri.types.d.ts.map +1 -1
  99. package/dist/database/puri.types.js +6 -2
  100. package/dist/database/transaction-context.d.ts +1 -1
  101. package/dist/database/transaction-context.d.ts.map +1 -1
  102. package/dist/database/transaction-context.js +14 -2
  103. package/dist/database/upsert-builder.d.ts +9 -3
  104. package/dist/database/upsert-builder.d.ts.map +1 -1
  105. package/dist/database/upsert-builder.js +365 -2
  106. package/dist/entity/entity-manager.d.ts +167 -2
  107. package/dist/entity/entity-manager.d.ts.map +1 -1
  108. package/dist/entity/entity-manager.js +130 -2
  109. package/dist/entity/entity.d.ts +5 -3
  110. package/dist/entity/entity.d.ts.map +1 -1
  111. package/dist/entity/entity.js +750 -2
  112. package/dist/exceptions/error-handler.d.ts +1 -1
  113. package/dist/exceptions/error-handler.d.ts.map +1 -1
  114. package/dist/exceptions/error-handler.js +29 -2
  115. package/dist/exceptions/so-exceptions.d.ts +1 -1
  116. package/dist/exceptions/so-exceptions.d.ts.map +1 -1
  117. package/dist/exceptions/so-exceptions.js +85 -2
  118. package/dist/file-storage/driver.d.ts +1 -1
  119. package/dist/file-storage/driver.d.ts.map +1 -1
  120. package/dist/file-storage/driver.js +79 -2
  121. package/dist/file-storage/file-storage.js +75 -2
  122. package/dist/index.d.ts +18 -9
  123. package/dist/index.d.ts.map +1 -1
  124. package/dist/index.js +34 -2
  125. package/dist/migration/code-generation.d.ts +1 -1
  126. package/dist/migration/code-generation.d.ts.map +1 -1
  127. package/dist/migration/code-generation.js +614 -2
  128. package/dist/migration/migration-set.d.ts +2 -10
  129. package/dist/migration/migration-set.d.ts.map +1 -1
  130. package/dist/migration/migration-set.js +213 -2
  131. package/dist/migration/migrator.d.ts +24 -82
  132. package/dist/migration/migrator.d.ts.map +1 -1
  133. package/dist/migration/migrator.js +330 -2
  134. package/dist/migration/postgresql-schema-reader.d.ts +51 -0
  135. package/dist/migration/postgresql-schema-reader.d.ts.map +1 -0
  136. package/dist/migration/postgresql-schema-reader.js +245 -0
  137. package/dist/migration/types.d.ts +6 -38
  138. package/dist/migration/types.d.ts.map +1 -1
  139. package/dist/migration/types.js +3 -2
  140. package/dist/naite/messaging-types.d.ts +43 -0
  141. package/dist/naite/messaging-types.d.ts.map +1 -0
  142. package/dist/naite/messaging-types.js +7 -0
  143. package/dist/naite/naite-reporter.d.ts +41 -0
  144. package/dist/naite/naite-reporter.d.ts.map +1 -0
  145. package/dist/naite/naite-reporter.js +102 -0
  146. package/dist/naite/naite.d.ts +95 -0
  147. package/dist/naite/naite.d.ts.map +1 -0
  148. package/dist/naite/naite.js +316 -0
  149. package/dist/stream/index.js +3 -2
  150. package/dist/stream/sse.d.ts +2 -2
  151. package/dist/stream/sse.d.ts.map +1 -1
  152. package/dist/stream/sse.js +38 -2
  153. package/dist/syncer/api-parser.d.ts +10 -0
  154. package/dist/syncer/api-parser.d.ts.map +1 -0
  155. package/dist/syncer/api-parser.js +240 -0
  156. package/dist/syncer/checksum.d.ts +21 -0
  157. package/dist/syncer/checksum.d.ts.map +1 -0
  158. package/dist/syncer/checksum.js +98 -0
  159. package/dist/syncer/code-generator.d.ts +20 -0
  160. package/dist/syncer/code-generator.d.ts.map +1 -0
  161. package/dist/syncer/code-generator.js +161 -0
  162. package/dist/syncer/entity-operations.d.ts +17 -0
  163. package/dist/syncer/entity-operations.d.ts.map +1 -0
  164. package/dist/syncer/entity-operations.js +59 -0
  165. package/dist/syncer/file-patterns.d.ts +29 -0
  166. package/dist/syncer/file-patterns.d.ts.map +1 -0
  167. package/dist/syncer/file-patterns.js +38 -0
  168. package/dist/syncer/index.d.ts +6 -0
  169. package/dist/syncer/index.d.ts.map +1 -1
  170. package/dist/syncer/index.js +9 -2
  171. package/dist/syncer/module-loader.d.ts +35 -0
  172. package/dist/syncer/module-loader.d.ts.map +1 -0
  173. package/dist/syncer/module-loader.js +87 -0
  174. package/dist/syncer/syncer.d.ts +98 -106
  175. package/dist/syncer/syncer.d.ts.map +1 -1
  176. package/dist/syncer/syncer.js +422 -2
  177. package/dist/template/entity-converter.d.ts +14 -0
  178. package/dist/template/entity-converter.d.ts.map +1 -0
  179. package/dist/template/entity-converter.js +108 -0
  180. package/dist/template/helpers.d.ts +23 -0
  181. package/dist/template/helpers.d.ts.map +1 -0
  182. package/dist/template/helpers.js +64 -0
  183. package/dist/{templates → template/implementations}/entity.template.d.ts +3 -3
  184. package/dist/template/implementations/entity.template.d.ts.map +1 -0
  185. package/dist/template/implementations/entity.template.js +86 -0
  186. package/dist/{templates → template/implementations}/generated.template.d.ts +3 -4
  187. package/dist/template/implementations/generated.template.d.ts.map +1 -0
  188. package/dist/template/implementations/generated.template.js +249 -0
  189. package/dist/{templates → template/implementations}/generated_http.template.d.ts +3 -4
  190. package/dist/template/implementations/generated_http.template.d.ts.map +1 -0
  191. package/dist/template/implementations/generated_http.template.js +131 -0
  192. package/dist/{templates → template/implementations}/generated_sso.template.d.ts +4 -5
  193. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -0
  194. package/dist/template/implementations/generated_sso.template.js +134 -0
  195. package/dist/{templates → template/implementations}/init_types.template.d.ts +3 -3
  196. package/dist/template/implementations/init_types.template.d.ts.map +1 -0
  197. package/dist/template/implementations/init_types.template.js +38 -0
  198. package/dist/template/implementations/model.template.d.ts +17 -0
  199. package/dist/template/implementations/model.template.d.ts.map +1 -0
  200. package/dist/template/implementations/model.template.js +181 -0
  201. package/dist/{templates → template/implementations}/model_test.template.d.ts +3 -3
  202. package/dist/template/implementations/model_test.template.d.ts.map +1 -0
  203. package/dist/template/implementations/model_test.template.js +35 -0
  204. package/dist/{templates → template/implementations}/service.template.d.ts +6 -6
  205. package/dist/template/implementations/service.template.d.ts.map +1 -0
  206. package/dist/template/implementations/service.template.js +201 -0
  207. package/dist/{templates → template/implementations}/view_enums_buttonset.template.d.ts +3 -3
  208. package/dist/template/implementations/view_enums_buttonset.template.d.ts.map +1 -0
  209. package/dist/template/implementations/view_enums_buttonset.template.js +31 -0
  210. package/dist/{templates → template/implementations}/view_enums_dropdown.template.d.ts +3 -4
  211. package/dist/template/implementations/view_enums_dropdown.template.d.ts.map +1 -0
  212. package/dist/template/implementations/view_enums_dropdown.template.js +50 -0
  213. package/dist/{templates → template/implementations}/view_enums_select.template.d.ts +3 -3
  214. package/dist/template/implementations/view_enums_select.template.d.ts.map +1 -0
  215. package/dist/template/implementations/view_enums_select.template.js +55 -0
  216. package/dist/{templates → template/implementations}/view_form.template.d.ts +5 -5
  217. package/dist/template/implementations/view_form.template.d.ts.map +1 -0
  218. package/dist/template/implementations/view_form.template.js +337 -0
  219. package/dist/{templates → template/implementations}/view_id_all_select.template.d.ts +3 -3
  220. package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -0
  221. package/dist/template/implementations/view_id_all_select.template.js +31 -0
  222. package/dist/{templates → template/implementations}/view_id_async_select.template.d.ts +3 -3
  223. package/dist/template/implementations/view_id_async_select.template.d.ts.map +1 -0
  224. package/dist/template/implementations/view_id_async_select.template.js +105 -0
  225. package/dist/{templates → template/implementations}/view_list.template.d.ts +5 -13
  226. package/dist/template/implementations/view_list.template.d.ts.map +1 -0
  227. package/dist/template/implementations/view_list.template.js +475 -0
  228. package/dist/template/implementations/view_list_columns.template.d.ts +17 -0
  229. package/dist/template/implementations/view_list_columns.template.d.ts.map +1 -0
  230. package/dist/template/implementations/view_list_columns.template.js +49 -0
  231. package/dist/{templates → template/implementations}/view_search_input.template.d.ts +3 -3
  232. package/dist/template/implementations/view_search_input.template.d.ts.map +1 -0
  233. package/dist/template/implementations/view_search_input.template.js +64 -0
  234. package/dist/template/index.d.ts +7 -0
  235. package/dist/template/index.d.ts.map +1 -0
  236. package/dist/template/index.js +8 -0
  237. package/dist/template/template-manager.d.ts +56 -0
  238. package/dist/template/template-manager.d.ts.map +1 -0
  239. package/dist/template/template-manager.js +125 -0
  240. package/dist/template/template-types.d.ts +16 -0
  241. package/dist/template/template-types.d.ts.map +1 -0
  242. package/dist/template/template-types.js +7 -0
  243. package/dist/template/template.d.ts +49 -0
  244. package/dist/template/template.d.ts.map +1 -0
  245. package/dist/template/template.js +60 -0
  246. package/dist/template/zod-converter.d.ts +51 -0
  247. package/dist/template/zod-converter.d.ts.map +1 -0
  248. package/dist/template/zod-converter.js +449 -0
  249. package/dist/testing/_relation-graph.d.ts +1 -1
  250. package/dist/testing/_relation-graph.d.ts.map +1 -1
  251. package/dist/testing/_relation-graph.js +89 -2
  252. package/dist/testing/fixture-manager.d.ts +42 -11
  253. package/dist/testing/fixture-manager.d.ts.map +1 -1
  254. package/dist/testing/fixture-manager.js +623 -2
  255. package/dist/types/types.d.ts +747 -143
  256. package/dist/types/types.d.ts.map +1 -1
  257. package/dist/types/types.js +546 -2
  258. package/dist/typings/knex.d.js +3 -2
  259. package/dist/utils/async-utils.d.ts +7 -0
  260. package/dist/utils/async-utils.d.ts.map +1 -1
  261. package/dist/utils/async-utils.js +57 -2
  262. package/dist/utils/console-util.d.ts +2 -0
  263. package/dist/utils/console-util.d.ts.map +1 -0
  264. package/dist/utils/console-util.js +6 -0
  265. package/dist/utils/controller.d.ts +1 -0
  266. package/dist/utils/controller.d.ts.map +1 -1
  267. package/dist/utils/controller.js +29 -2
  268. package/dist/utils/esm-utils.d.ts +39 -0
  269. package/dist/utils/esm-utils.d.ts.map +1 -0
  270. package/dist/utils/esm-utils.js +49 -0
  271. package/dist/utils/formatter.d.ts +3 -0
  272. package/dist/utils/formatter.d.ts.map +1 -0
  273. package/dist/utils/formatter.js +110 -0
  274. package/dist/utils/fs-utils.d.ts +1 -1
  275. package/dist/utils/fs-utils.d.ts.map +1 -1
  276. package/dist/utils/fs-utils.js +17 -2
  277. package/dist/utils/lodash-able.d.ts.map +1 -1
  278. package/dist/utils/lodash-able.js +6 -2
  279. package/dist/utils/model.js +22 -2
  280. package/dist/utils/object-utils.d.ts +44 -0
  281. package/dist/utils/object-utils.d.ts.map +1 -0
  282. package/dist/utils/object-utils.js +191 -0
  283. package/dist/utils/path-utils.d.ts +89 -0
  284. package/dist/utils/path-utils.d.ts.map +1 -0
  285. package/dist/utils/path-utils.js +60 -0
  286. package/dist/utils/process-utils.d.ts +13 -0
  287. package/dist/utils/process-utils.d.ts.map +1 -0
  288. package/dist/utils/process-utils.js +36 -0
  289. package/dist/utils/sql-parser.d.ts +5 -1
  290. package/dist/utils/sql-parser.d.ts.map +1 -1
  291. package/dist/utils/sql-parser.js +46 -2
  292. package/dist/utils/type-utils.d.ts +23 -0
  293. package/dist/utils/type-utils.d.ts.map +1 -0
  294. package/dist/utils/type-utils.js +45 -0
  295. package/dist/utils/utils.d.ts +10 -7
  296. package/dist/utils/utils.d.ts.map +1 -1
  297. package/dist/utils/utils.js +72 -2
  298. package/dist/utils/zod-error.d.ts +1 -1
  299. package/dist/utils/zod-error.d.ts.map +1 -1
  300. package/dist/utils/zod-error.js +19 -2
  301. package/package.json +65 -27
  302. package/src/ai/agents/agent.ts +87 -0
  303. package/src/ai/agents/index.ts +2 -0
  304. package/src/ai/agents/types.ts +47 -0
  305. package/src/ai/index.ts +1 -0
  306. package/src/ai/providers/rtzr/api.ts +37 -0
  307. package/src/ai/providers/rtzr/error.ts +34 -0
  308. package/src/ai/providers/rtzr/index.ts +4 -0
  309. package/src/ai/providers/rtzr/model.ts +201 -0
  310. package/src/ai/providers/rtzr/options.ts +49 -0
  311. package/src/ai/providers/rtzr/provider.ts +91 -0
  312. package/src/ai/providers/rtzr/utils.ts +127 -0
  313. package/src/api/base-frame.ts +4 -2
  314. package/src/api/caster.ts +17 -23
  315. package/src/api/code-converters.ts +178 -535
  316. package/src/api/config.ts +125 -0
  317. package/src/api/context.ts +7 -17
  318. package/src/api/decorators.ts +176 -46
  319. package/src/api/index.ts +2 -2
  320. package/src/api/sonamu.ts +190 -167
  321. package/src/api/validator.ts +83 -0
  322. package/src/bin/build-config.ts +8 -1
  323. package/src/bin/cli.ts +258 -124
  324. package/src/bin/hot-hook-register.ts +22 -0
  325. package/src/bin/loader-register.ts +38 -0
  326. package/src/database/_batch_update.ts +46 -31
  327. package/src/database/base-model.ts +390 -182
  328. package/src/database/base-model.types.ts +155 -0
  329. package/src/database/code-generator.ts +13 -32
  330. package/src/database/db.ts +40 -96
  331. package/src/database/puri-subset.test-d.ts +471 -0
  332. package/src/database/puri-subset.types.ts +195 -0
  333. package/src/database/puri-wrapper.ts +58 -67
  334. package/src/database/puri.ts +229 -148
  335. package/src/database/puri.types.ts +76 -30
  336. package/src/database/transaction-context.ts +1 -1
  337. package/src/database/upsert-builder.ts +262 -132
  338. package/src/entity/entity-manager.ts +48 -36
  339. package/src/entity/entity.ts +330 -248
  340. package/src/exceptions/error-handler.ts +3 -3
  341. package/src/exceptions/so-exceptions.ts +11 -11
  342. package/src/file-storage/driver.ts +5 -5
  343. package/src/file-storage/file-storage.ts +2 -2
  344. package/src/index.ts +18 -10
  345. package/src/migration/code-generation.ts +185 -172
  346. package/src/migration/migration-set.ts +80 -293
  347. package/src/migration/migrator.ts +199 -571
  348. package/src/migration/mysql-schema-reader.ts.txt +272 -0
  349. package/src/migration/postgresql-schema-reader.ts +310 -0
  350. package/src/migration/types.ts +6 -39
  351. package/src/naite/messaging-types.ts +51 -0
  352. package/src/naite/naite-reporter.ts +128 -0
  353. package/src/naite/naite.ts +415 -0
  354. package/src/shared/web.shared.ts.txt +20 -24
  355. package/src/stream/sse.ts +5 -5
  356. package/src/syncer/api-parser.ts +282 -0
  357. package/src/syncer/checksum.ts +140 -0
  358. package/src/syncer/code-generator.ts +198 -0
  359. package/src/syncer/entity-operations.ts +65 -0
  360. package/src/syncer/file-patterns.ts +56 -0
  361. package/src/syncer/index.ts +6 -0
  362. package/src/syncer/module-loader.ts +128 -0
  363. package/src/syncer/syncer.ts +389 -1453
  364. package/src/template/entity-converter.ts +114 -0
  365. package/src/template/helpers.ts +81 -0
  366. package/src/{templates → template/implementations}/entity.template.ts +7 -7
  367. package/src/{templates → template/implementations}/generated.template.ts +101 -101
  368. package/src/{templates → template/implementations}/generated_http.template.ts +27 -57
  369. package/src/template/implementations/generated_sso.template.ts +151 -0
  370. package/src/{templates → template/implementations}/init_types.template.ts +5 -7
  371. package/src/{templates → template/implementations}/model.template.ts +52 -43
  372. package/src/{templates → template/implementations}/model_test.template.ts +5 -5
  373. package/src/{templates → template/implementations}/service.template.ts +66 -82
  374. package/src/{templates → template/implementations}/view_enums_buttonset.template.ts +3 -3
  375. package/src/{templates → template/implementations}/view_enums_dropdown.template.ts +4 -20
  376. package/src/{templates → template/implementations}/view_enums_select.template.ts +4 -4
  377. package/src/{templates → template/implementations}/view_form.template.ts +40 -83
  378. package/src/{templates → template/implementations}/view_id_all_select.template.ts +3 -3
  379. package/src/{templates → template/implementations}/view_id_async_select.template.ts +10 -24
  380. package/src/{templates → template/implementations}/view_list.template.ts +60 -152
  381. package/src/{templates → template/implementations}/view_list_columns.template.ts +5 -11
  382. package/src/{templates → template/implementations}/view_search_input.template.ts +3 -3
  383. package/src/template/index.ts +6 -0
  384. package/src/template/template-manager.ts +166 -0
  385. package/src/template/template-types.ts +16 -0
  386. package/src/template/template.ts +105 -0
  387. package/src/template/zod-converter.ts +525 -0
  388. package/src/testing/_relation-graph.ts +18 -11
  389. package/src/testing/fixture-manager.ts +472 -359
  390. package/src/types/types.ts +553 -308
  391. package/src/typings/knex.d.ts +7 -9
  392. package/src/utils/async-utils.ts +23 -10
  393. package/src/utils/console-util.ts +4 -0
  394. package/src/utils/controller.ts +3 -0
  395. package/src/utils/esm-utils.ts +59 -0
  396. package/src/utils/formatter.ts +109 -0
  397. package/src/utils/fs-utils.ts +1 -1
  398. package/src/utils/lodash-able.ts +1 -4
  399. package/src/utils/object-utils.ts +217 -0
  400. package/src/utils/path-utils.ts +99 -0
  401. package/src/utils/process-utils.ts +46 -0
  402. package/src/utils/sql-parser.ts +23 -5
  403. package/src/utils/type-utils.ts +83 -0
  404. package/src/utils/utils.ts +66 -43
  405. package/src/utils/zod-error.ts +3 -4
  406. package/dist/api/base-frame.js.map +0 -1
  407. package/dist/api/caster.js.map +0 -1
  408. package/dist/api/code-converters.js.map +0 -1
  409. package/dist/api/context.js.map +0 -1
  410. package/dist/api/decorators.js.map +0 -1
  411. package/dist/api/index.js.map +0 -1
  412. package/dist/api/sonamu.js.map +0 -1
  413. package/dist/bin/build-config.js.map +0 -1
  414. package/dist/bin/cli-wrapper.d.ts +0 -3
  415. package/dist/bin/cli-wrapper.d.ts.map +0 -1
  416. package/dist/bin/cli-wrapper.js +0 -3
  417. package/dist/bin/cli-wrapper.js.map +0 -1
  418. package/dist/bin/cli.js.map +0 -1
  419. package/dist/database/_batch_update.js.map +0 -1
  420. package/dist/database/base-model.js.map +0 -1
  421. package/dist/database/code-generator.js.map +0 -1
  422. package/dist/database/db.js.map +0 -1
  423. package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts +0 -2
  424. package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts.map +0 -1
  425. package/dist/database/knex-plugins/knex-on-duplicate-update.js +0 -2
  426. package/dist/database/knex-plugins/knex-on-duplicate-update.js.map +0 -1
  427. package/dist/database/puri-wrapper.js.map +0 -1
  428. package/dist/database/puri.js.map +0 -1
  429. package/dist/database/puri.types.js.map +0 -1
  430. package/dist/database/transaction-context.js.map +0 -1
  431. package/dist/database/upsert-builder.js.map +0 -1
  432. package/dist/entity/entity-manager.js.map +0 -1
  433. package/dist/entity/entity-utils.d.ts +0 -61
  434. package/dist/entity/entity-utils.d.ts.map +0 -1
  435. package/dist/entity/entity-utils.js +0 -2
  436. package/dist/entity/entity-utils.js.map +0 -1
  437. package/dist/entity/entity.js.map +0 -1
  438. package/dist/exceptions/error-handler.js.map +0 -1
  439. package/dist/exceptions/so-exceptions.js.map +0 -1
  440. package/dist/file-storage/driver.js.map +0 -1
  441. package/dist/file-storage/file-storage.js.map +0 -1
  442. package/dist/index.js.map +0 -1
  443. package/dist/migration/code-generation.js.map +0 -1
  444. package/dist/migration/migration-set.js.map +0 -1
  445. package/dist/migration/migrator.js.map +0 -1
  446. package/dist/migration/types.js.map +0 -1
  447. package/dist/stream/index.js.map +0 -1
  448. package/dist/stream/sse.js.map +0 -1
  449. package/dist/syncer/index.js.map +0 -1
  450. package/dist/syncer/syncer.js.map +0 -1
  451. package/dist/templates/base-template.d.ts +0 -13
  452. package/dist/templates/base-template.d.ts.map +0 -1
  453. package/dist/templates/base-template.js +0 -2
  454. package/dist/templates/base-template.js.map +0 -1
  455. package/dist/templates/entity.template.d.ts.map +0 -1
  456. package/dist/templates/entity.template.js +0 -2
  457. package/dist/templates/entity.template.js.map +0 -1
  458. package/dist/templates/generated.template.d.ts.map +0 -1
  459. package/dist/templates/generated.template.js +0 -2
  460. package/dist/templates/generated.template.js.map +0 -1
  461. package/dist/templates/generated_http.template.d.ts.map +0 -1
  462. package/dist/templates/generated_http.template.js +0 -2
  463. package/dist/templates/generated_http.template.js.map +0 -1
  464. package/dist/templates/generated_sso.template.d.ts.map +0 -1
  465. package/dist/templates/generated_sso.template.js +0 -2
  466. package/dist/templates/generated_sso.template.js.map +0 -1
  467. package/dist/templates/index.d.ts +0 -2
  468. package/dist/templates/index.d.ts.map +0 -1
  469. package/dist/templates/index.js +0 -2
  470. package/dist/templates/index.js.map +0 -1
  471. package/dist/templates/init_types.template.d.ts.map +0 -1
  472. package/dist/templates/init_types.template.js +0 -2
  473. package/dist/templates/init_types.template.js.map +0 -1
  474. package/dist/templates/model.template.d.ts +0 -17
  475. package/dist/templates/model.template.d.ts.map +0 -1
  476. package/dist/templates/model.template.js +0 -2
  477. package/dist/templates/model.template.js.map +0 -1
  478. package/dist/templates/model_test.template.d.ts.map +0 -1
  479. package/dist/templates/model_test.template.js +0 -2
  480. package/dist/templates/model_test.template.js.map +0 -1
  481. package/dist/templates/service.template.d.ts.map +0 -1
  482. package/dist/templates/service.template.js +0 -2
  483. package/dist/templates/service.template.js.map +0 -1
  484. package/dist/templates/view_enums_buttonset.template.d.ts.map +0 -1
  485. package/dist/templates/view_enums_buttonset.template.js +0 -2
  486. package/dist/templates/view_enums_buttonset.template.js.map +0 -1
  487. package/dist/templates/view_enums_dropdown.template.d.ts.map +0 -1
  488. package/dist/templates/view_enums_dropdown.template.js +0 -2
  489. package/dist/templates/view_enums_dropdown.template.js.map +0 -1
  490. package/dist/templates/view_enums_select.template.d.ts.map +0 -1
  491. package/dist/templates/view_enums_select.template.js +0 -2
  492. package/dist/templates/view_enums_select.template.js.map +0 -1
  493. package/dist/templates/view_form.template.d.ts.map +0 -1
  494. package/dist/templates/view_form.template.js +0 -2
  495. package/dist/templates/view_form.template.js.map +0 -1
  496. package/dist/templates/view_id_all_select.template.d.ts.map +0 -1
  497. package/dist/templates/view_id_all_select.template.js +0 -2
  498. package/dist/templates/view_id_all_select.template.js.map +0 -1
  499. package/dist/templates/view_id_async_select.template.d.ts.map +0 -1
  500. package/dist/templates/view_id_async_select.template.js +0 -2
  501. package/dist/templates/view_id_async_select.template.js.map +0 -1
  502. package/dist/templates/view_list.template.d.ts.map +0 -1
  503. package/dist/templates/view_list.template.js +0 -2
  504. package/dist/templates/view_list.template.js.map +0 -1
  505. package/dist/templates/view_list_columns.template.d.ts +0 -17
  506. package/dist/templates/view_list_columns.template.d.ts.map +0 -1
  507. package/dist/templates/view_list_columns.template.js +0 -2
  508. package/dist/templates/view_list_columns.template.js.map +0 -1
  509. package/dist/templates/view_search_input.template.d.ts.map +0 -1
  510. package/dist/templates/view_search_input.template.js +0 -2
  511. package/dist/templates/view_search_input.template.js.map +0 -1
  512. package/dist/testing/_relation-graph.js.map +0 -1
  513. package/dist/testing/fixture-manager.js.map +0 -1
  514. package/dist/types/types.js.map +0 -1
  515. package/dist/typings/knex.d.js.map +0 -1
  516. package/dist/utils/async-utils.js.map +0 -1
  517. package/dist/utils/controller.js.map +0 -1
  518. package/dist/utils/fs-utils.js.map +0 -1
  519. package/dist/utils/lodash-able.js.map +0 -1
  520. package/dist/utils/model.js.map +0 -1
  521. package/dist/utils/sql-parser.js.map +0 -1
  522. package/dist/utils/utils.js.map +0 -1
  523. package/dist/utils/zod-error.js.map +0 -1
  524. package/src/bin/cli-wrapper.ts +0 -75
  525. package/src/database/knex-plugins/knex-on-duplicate-update.ts +0 -45
  526. package/src/entity/entity-utils.ts +0 -291
  527. package/src/templates/base-template.ts +0 -19
  528. package/src/templates/generated_sso.template.ts +0 -138
  529. package/src/templates/index.ts +0 -1
@@ -1,2 +1,623 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get FixtureManager(){return FixtureManager},get FixtureManagerClass(){return FixtureManagerClass}});var _chalk=/*#__PURE__*/_interop_require_default(require("chalk"));var _lodash=/*#__PURE__*/_interop_require_default(require("lodash"));var _api=require("../api");var _entitymanager=require("../entity/entity-manager");var _types=require("../types/types");var _inflection=/*#__PURE__*/_interop_require_default(require("inflection"));var _fs=require("fs");var _relationgraph=require("./_relation-graph");var _knex=/*#__PURE__*/_interop_require_default(require("knex"));var _basemodel=require("../database/base-model");function _array_like_to_array(arr,len){if(len==null||len>arr.length)len=arr.length;for(var i=0,arr2=new Array(len);i<len;i++)arr2[i]=arr[i];return arr2}function _array_with_holes(arr){if(Array.isArray(arr))return arr}function _array_without_holes(arr){if(Array.isArray(arr))return _array_like_to_array(arr)}function _async_iterator(iterable){var method,async,sync,retry=2;for("undefined"!=typeof Symbol&&(async=Symbol.asyncIterator,sync=Symbol.iterator);retry--;){if(async&&null!=(method=iterable[async]))return method.call(iterable);if(sync&&null!=(method=iterable[sync]))return new AsyncFromSyncIterator(method.call(iterable));async="@@asyncIterator",sync="@@iterator"}throw new TypeError("Object is not async iterable")}function AsyncFromSyncIterator(s){function AsyncFromSyncIteratorContinuation(r){if(Object(r)!==r)return Promise.reject(new TypeError(r+" is not an object."));var done=r.done;return Promise.resolve(r.value).then(function(value){return{value:value,done:done}})}return AsyncFromSyncIterator=function(s){this.s=s,this.n=s.next},AsyncFromSyncIterator.prototype={s:null,n:null,next:function(){return AsyncFromSyncIteratorContinuation(this.n.apply(this.s,arguments))},return:function(value){var ret=this.s.return;return void 0===ret?Promise.resolve({value:value,done:!0}):AsyncFromSyncIteratorContinuation(ret.apply(this.s,arguments))},throw:function(value){var thr=this.s.return;return void 0===thr?Promise.reject(value):AsyncFromSyncIteratorContinuation(thr.apply(this.s,arguments))}},new AsyncFromSyncIterator(s)}function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg);var value=info.value}catch(error){reject(error);return}if(info.done){resolve(value)}else{Promise.resolve(value).then(_next,_throw)}}function _async_to_generator(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err)}_next(undefined)})}}function _class_call_check(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function")}}function _defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value"in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor)}}function _create_class(Constructor,protoProps,staticProps){if(protoProps)_defineProperties(Constructor.prototype,protoProps);if(staticProps)_defineProperties(Constructor,staticProps);return Constructor}function _define_property(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}function _instanceof(left,right){if(right!=null&&typeof Symbol!=="undefined"&&right[Symbol.hasInstance]){return!!right[Symbol.hasInstance](left)}else{return left instanceof right}}function _interop_require_default(obj){return obj&&obj.__esModule?obj:{default:obj}}function _iterable_to_array(iter){if(typeof Symbol!=="undefined"&&iter[Symbol.iterator]!=null||iter["@@iterator"]!=null)return Array.from(iter)}function _iterable_to_array_limit(arr,i){var _i=arr==null?null:typeof Symbol!=="undefined"&&arr[Symbol.iterator]||arr["@@iterator"];if(_i==null)return;var _arr=[];var _n=true;var _d=false;var _s,_e;try{for(_i=_i.call(arr);!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break}}catch(err){_d=true;_e=err}finally{try{if(!_n&&_i["return"]!=null)_i["return"]()}finally{if(_d)throw _e}}return _arr}function _non_iterable_rest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _non_iterable_spread(){throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _sliced_to_array(arr,i){return _array_with_holes(arr)||_iterable_to_array_limit(arr,i)||_unsupported_iterable_to_array(arr,i)||_non_iterable_rest()}function _to_consumable_array(arr){return _array_without_holes(arr)||_iterable_to_array(arr)||_unsupported_iterable_to_array(arr)||_non_iterable_spread()}function _type_of(obj){"@swc/helpers - typeof";return obj&&typeof Symbol!=="undefined"&&obj.constructor===Symbol?"symbol":typeof obj}function _unsupported_iterable_to_array(o,minLen){if(!o)return;if(typeof o==="string")return _array_like_to_array(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);if(n==="Object"&&o.constructor)n=o.constructor.name;if(n==="Map"||n==="Set")return Array.from(n);if(n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _array_like_to_array(o,minLen)}function _ts_generator(thisArg,body){var f,y,t,_={label:0,sent:function(){if(t[0]&1)throw t[1];return t[1]},trys:[],ops:[]},g=Object.create((typeof Iterator==="function"?Iterator:Object).prototype);return g.next=verb(0),g["throw"]=verb(1),g["return"]=verb(2),typeof Symbol==="function"&&(g[Symbol.iterator]=function(){return this}),g;function verb(n){return function(v){return step([n,v])}}function step(op){if(f)throw new TypeError("Generator is already executing.");while(g&&(g=0,op[0]&&(_=0)),_)try{if(f=1,y&&(t=op[0]&2?y["return"]:op[0]?y["throw"]||((t=y["return"])&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;if(y=0,t)op=[op[0]&2,t.value];switch(op[0]){case 0:case 1:t=op;break;case 4:_.label++;return{value:op[1],done:false};case 5:_.label++;y=op[1];op=[0];continue;case 7:op=_.ops.pop();_.trys.pop();continue;default:if(!(t=_.trys,t=t.length>0&&t[t.length-1])&&(op[0]===6||op[0]===2)){_=0;continue}if(op[0]===3&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(op[0]===6&&_.label<t[1]){_.label=t[1];t=op;break}if(t&&_.label<t[2]){_.label=t[2];_.ops.push(op);break}if(t[2])_.ops.pop();_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e];y=0}finally{f=t=0}if(op[0]&5)throw op[1];return{value:op[0]?op[1]:void 0,done:true}}}function _ts_values(o){var s=typeof Symbol==="function"&&Symbol.iterator,m=s&&o[s],i=0;if(m)return m.call(o);if(o&&typeof o.length==="number")return{next:function(){if(o&&i>=o.length)o=void 0;return{value:o&&o[i++],done:!o}}};throw new TypeError(s?"Object is not iterable.":"Symbol.iterator is not defined.")}var FixtureManagerClass=/*#__PURE__*/function(){"use strict";function FixtureManagerClass(){_class_call_check(this,FixtureManagerClass);_define_property(this,"_tdb",null);_define_property(this,"_fdb",null);_define_property(this,"cachedTableNames",null);_define_property(this,"relationGraph",new _relationgraph.RelationGraph);_define_property(this,"visitedRecords",new Set)}_create_class(FixtureManagerClass,[{key:"tdb",get:function get(){if(this._tdb===null){throw new Error("FixtureManager has not been initialized")}return this._tdb},set:function set(tdb){this._tdb=tdb}},{key:"fdb",get:function get(){if(this._fdb===null){throw new Error("FixtureManager has not been initialized")}return this._fdb},set:function set(fdb){this._fdb=fdb}},{key:"init",value:function init(){if(this._tdb!==null){return}if(_api.Sonamu.dbConfig.test&&_api.Sonamu.dbConfig.production_master){var tConn=_api.Sonamu.dbConfig.test.connection;var pConn=_api.Sonamu.dbConfig.production_master.connection;var _tConn_host,_tConn_port,_pConn_host,_pConn_port;if("".concat((_tConn_host=tConn.host)!==null&&_tConn_host!==void 0?_tConn_host:"localhost",":").concat((_tConn_port=tConn.port)!==null&&_tConn_port!==void 0?_tConn_port:3306,"/").concat(tConn.database)==="".concat((_pConn_host=pConn.host)!==null&&_pConn_host!==void 0?_pConn_host:"localhost",":").concat((_pConn_port=pConn.port)!==null&&_pConn_port!==void 0?_pConn_port:3306,"/").concat(pConn.database)){throw new Error("테스트DB와 프로덕션DB에 동일한 데이터베이스가 사용되었습니다.")}}this.tdb=(0,_knex.default)(_api.Sonamu.dbConfig.test);this.fdb=(0,_knex.default)(_api.Sonamu.dbConfig.fixture_local)}},{key:"cleanAndSeed",value:function cleanAndSeed(usingTables){return _async_to_generator(function(){var _this,tableNames,tableListStr,_ref,fdbChecksumRows,_ref1,tdbChecksumRows,fdbChecksums,tdbChecksums,changedTables;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this;return[4,function(){return _async_to_generator(function(){var _ref,tables,tableNames;return _ts_generator(this,function(_state){switch(_state.label){case 0:if(usingTables){return[2,usingTables]}if(this.cachedTableNames){return[2,this.cachedTableNames]}return[4,this.tdb.raw("SHOW TABLE STATUS WHERE Engine IS NOT NULL AND Name != 'migrations'")];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),tables=_ref[0];tableNames=tables.map(function(tableInfo){return tableInfo["Name"]});this.cachedTableNames=tableNames;return[2,tableNames]}})}).call(_this)}()];case 1:tableNames=_state.sent();tableListStr=tableNames.join(", ");return[4,this.fdb.raw("CHECKSUM TABLE ".concat(tableListStr))];case 2:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),fdbChecksumRows=_ref[0];return[4,this.tdb.raw("CHECKSUM TABLE ".concat(tableListStr))];case 3:_ref1=_sliced_to_array.apply(void 0,[_state.sent(),1]),tdbChecksumRows=_ref1[0];fdbChecksums=new Map(fdbChecksumRows.map(function(row){return[row.Table.split(".").pop(),row.Checksum]}));tdbChecksums=new Map(tdbChecksumRows.map(function(row){return[row.Table.split(".").pop(),row.Checksum]}));changedTables=tableNames.filter(function(tableName){return fdbChecksums.get(tableName)!==tdbChecksums.get(tableName)});return[4,this.tdb.transaction(function(trx){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,trx.raw("SET FOREIGN_KEY_CHECKS = 0")];case 1:_state.sent();return[4,Promise.all(changedTables.map(function(tableName){return _async_to_generator(function(){var rawQuery;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,trx.raw("SET FOREIGN_KEY_CHECKS = 0")];case 1:_state.sent();return[4,trx(tableName).truncate()];case 2:_state.sent();rawQuery="INSERT INTO ".concat(_api.Sonamu.dbConfig.test.connection.database,".").concat(tableName,"\n SELECT * FROM ").concat(_api.Sonamu.dbConfig.fixture_local.connection.database,".").concat(tableName);return[4,trx.raw(rawQuery)];case 3:_state.sent();return[2]}})})()}))];case 2:_state.sent();return[4,trx.raw("SET FOREIGN_KEY_CHECKS = 1")];case 3:_state.sent();return[2]}})})()})];case 4:_state.sent();return[2]}})}).call(this)}},{key:"getChecksum",value:function getChecksum(db,tableName){return _async_to_generator(function(){var _ref,_ref_,checksumRow;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,db.raw("CHECKSUM TABLE ".concat(tableName))];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),_ref_=_sliced_to_array(_ref[0],1),checksumRow=_ref_[0];return[2,checksumRow.Checksum]}})})()}},{key:"sync",value:function sync(){return _async_to_generator(function(){var _this,frdb,_ref,tables,tableNames;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this;frdb=(0,_knex.default)(_api.Sonamu.dbConfig.fixture_remote);return[4,this.fdb.raw("SHOW TABLE STATUS WHERE Engine IS NOT NULL")];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),tables=_ref[0];tableNames=tables.map(function(table){return table.Name});console.log(_chalk.default.magenta("SYNC..."));return[4,Promise.all(tableNames.map(function(tableName){return _async_to_generator(function(){var remoteChecksum,localChecksum;return _ts_generator(this,function(_state){switch(_state.label){case 0:if(tableName.startsWith("knex_migrations")){return[2]}return[4,this.getChecksum(frdb,tableName)];case 1:remoteChecksum=_state.sent();return[4,this.getChecksum(this.fdb,tableName)];case 2:localChecksum=_state.sent();if(!(remoteChecksum!==localChecksum))return[3,4];return[4,this.fdb.transaction(function(transaction){return _async_to_generator(function(){var rows;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,transaction.raw("SET FOREIGN_KEY_CHECKS = 0")];case 1:_state.sent();return[4,transaction(tableName).truncate()];case 2:_state.sent();return[4,frdb(tableName)];case 3:rows=_state.sent();if(rows.length===0){return[2]}console.log(_chalk.default.blue(tableName),rows.length);return[4,transaction.insert(rows.map(function(row){return Object.fromEntries(Object.entries(row).map(function(param){var _param=_sliced_to_array(param,2),key=_param[0],value=_param[1];if(value===null){return[key,null]}else if(typeof value==="boolean"){return[key,value?1:0]}else if((typeof value==="undefined"?"undefined":_type_of(value))==="object"&&!_instanceof(value,Date)){return[key,JSON.stringify(value)]}else{return[key,value]}}))})).into(tableName)];case 4:_state.sent();console.log("OK");return[4,transaction.raw("SET FOREIGN_KEY_CHECKS = 1")];case 5:_state.sent();return[2]}})})()})];case 3:_state.sent();_state.label=4;case 4:return[2]}})}).call(_this)}))];case 2:_state.sent();console.log(_chalk.default.magenta("DONE!"));return[4,frdb.destroy()];case 3:_state.sent();return[2]}})}).call(this)}},{key:"importFixture",value:function importFixture(entityId,ids){return _async_to_generator(function(){var _this,queries,_,wdb,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_iterator,_step,query,_ref,rsh,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this;this.visitedRecords.clear();_=_lodash.default.uniq;return[4,Promise.all(ids.map(function(id){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.getImportQueries(entityId,"id",id)];case 1:return[2,_state.sent()]}})}).call(_this)}))];case 1:queries=_.apply(_lodash.default,[_state.sent().flat()]);wdb=_basemodel.BaseModel.getDB("w");_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=2;case 2:_state.trys.push([2,7,8,9]);_iterator=queries[Symbol.iterator]();_state.label=3;case 3:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,6];query=_step.value;return[4,wdb.raw(query)];case 4:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),rsh=_ref[0];console.log({query:query,info:rsh.info});_state.label=5;case 5:_iteratorNormalCompletion=true;return[3,3];case 6:return[3,9];case 7:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,9];case 8:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 9:return[2]}})}).call(this)}},{key:"getImportQueries",value:function getImportQueries(entityId,field,id){return _async_to_generator(function(){var _this,recordKey,entity,wdb,_ref,row,fixtureDatabase,realDatabase,selfQuery,args,relQueries;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this;recordKey="".concat(entityId,"#").concat(field,"#").concat(id);if(this.visitedRecords.has(recordKey)){return[2,[]]}this.visitedRecords.add(recordKey);console.log({entityId:entityId,field:field,id:id});entity=_entitymanager.EntityManager.get(entityId);wdb=_basemodel.BaseModel.getDB("w");return[4,wdb(entity.table).where(field,id).limit(1)];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),row=_ref[0];if(row===undefined){throw new Error("".concat(entityId,"#").concat(id," row를 찾을 수 없습니다."))}fixtureDatabase=_api.Sonamu.dbConfig.fixture_remote.connection.database;realDatabase=_api.Sonamu.dbConfig.production_master.connection.database;selfQuery="INSERT IGNORE INTO `".concat(fixtureDatabase,"`.`").concat(entity.table,"` (SELECT * FROM `").concat(realDatabase,"`.`").concat(entity.table,"` WHERE `id` = ").concat(id,")");args=Object.entries(entity.relations).filter(function(param){var _param=_sliced_to_array(param,2),relation=_param[1];return(0,_types.isBelongsToOneRelationProp)(relation)||(0,_types.isOneToOneRelationProp)(relation)&&relation.customJoinClause===undefined}).map(function(param){var _param=_sliced_to_array(param,2),relation=_param[1];var _$field;var _$id;if((0,_types.isOneToOneRelationProp)(relation)&&!relation.hasJoinColumn){var _relatedEntity_props_find;var relatedEntity=_entitymanager.EntityManager.get(relation.with);var relatedIdColumnName=(_relatedEntity_props_find=relatedEntity.props.find(function(p){return(0,_types.isRelationProp)(p)&&p.with===entity.id}))===null||_relatedEntity_props_find===void 0?void 0:_relatedEntity_props_find.name;if(!relatedIdColumnName){throw new Error("".concat(relatedEntity.id,"의 ").concat(entity.id," 관계 프롭을 찾을 수 없습니다."))}_$field="".concat(relatedIdColumnName,"_id");_$id=row["id"]}else{_$field="id";_$id=row["".concat(relation.name,"_id")]}return{entityId:relation.with,field:_$field,id:_$id}}).filter(function(arg){return arg.id!==null});return[4,Promise.all(args.map(function(args){return _async_to_generator(function(){return _ts_generator(this,function(_state){return[2,this.getImportQueries(args.entityId,args.field,args.id)]})}).call(_this)}))];case 2:relQueries=_state.sent();return[2,_to_consumable_array(_lodash.default.uniq(relQueries.reverse().flat())).concat([selfQuery])]}})}).call(this)}},{key:"destroy",value:function destroy(){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:if(!this._tdb)return[3,2];return[4,this._tdb.destroy()];case 1:_state.sent();this._tdb=null;_state.label=2;case 2:if(!this._fdb)return[3,4];return[4,this._fdb.destroy()];case 3:_state.sent();this._fdb=null;_state.label=4;case 4:return[4,_basemodel.BaseModel.destroy()];case 5:_state.sent();return[2]}})}).call(this)}},{key:"getFixtures",value:function getFixtures(sourceDBName,targetDBName,searchOptions){return _async_to_generator(function(){var _entity_props_find,sourceDB,targetDB,entityId,field,value,searchType,entity,column,query,rows,fixtures,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_this,_loop,_iterator,_step,err,_iteratorAbruptCompletion,_didIteratorError1,_iteratorError1,_iterator1,_step1,_value,fixture,entity1,row,_ref,record,uniqueRow,_ref1,record1,err1;return _ts_generator(this,function(_state){switch(_state.label){case 0:sourceDB=(0,_knex.default)(_api.Sonamu.dbConfig[sourceDBName]);targetDB=(0,_knex.default)(_api.Sonamu.dbConfig[targetDBName]);entityId=searchOptions.entityId,field=searchOptions.field,value=searchOptions.value,searchType=searchOptions.searchType;entity=_entitymanager.EntityManager.get(entityId);column=((_entity_props_find=entity.props.find(function(prop){return prop.name===field}))===null||_entity_props_find===void 0?void 0:_entity_props_find.type)==="relation"?"".concat(field,"_id"):field;query=sourceDB(entity.table);if(searchType==="equals"){query=query.where(column,value)}else if(searchType==="like"){query=query.where(column,"like","%".concat(value,"%"))}return[4,query];case 1:rows=_state.sent();if(rows.length===0){throw new Error("No records found")}fixtures=[];_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=2;case 2:_state.trys.push([2,7,8,9]);_loop=function(){var row,_fixtures,initialRecordsLength,newRecords,currentFixtureRecord;return _ts_generator(this,function(_state){switch(_state.label){case 0:row=_step.value;initialRecordsLength=fixtures.length;return[4,_this.createFixtureRecord(entity,row)];case 1:newRecords=_state.sent();(_fixtures=fixtures).push.apply(_fixtures,_to_consumable_array(newRecords));currentFixtureRecord=fixtures.find(function(r){return r.fixtureId==="".concat(entityId,"#").concat(row.id)});if(currentFixtureRecord){currentFixtureRecord.fetchedRecords=fixtures.filter(function(r){return r.fixtureId!==currentFixtureRecord.fixtureId}).slice(initialRecordsLength).map(function(r){return r.fixtureId})}return[2]}})};_iterator=rows[Symbol.iterator]();_state.label=3;case 3:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,6];_this=this;return[5,_ts_values(_loop())];case 4:_state.sent();_state.label=5;case 5:_iteratorNormalCompletion=true;return[3,3];case 6:return[3,9];case 7:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,9];case 8:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 9:_iteratorAbruptCompletion=false,_didIteratorError1=false;_state.label=10;case 10:_state.trys.push([10,20,21,26]);_iterator1=_async_iterator(fixtures);_state.label=11;case 11:return[4,_iterator1.next()];case 12:if(!(_iteratorAbruptCompletion=!(_step1=_state.sent()).done))return[3,19];_value=_step1.value;fixture=_value;entity1=_entitymanager.EntityManager.get(fixture.entityId);return[4,targetDB(entity1.table).where("id",fixture.id).first()];case 13:row=_state.sent();if(!row)return[3,15];return[4,this.createFixtureRecord(entity1,row,{singleRecord:true,_db:targetDB})];case 14:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),record=_ref[0];fixture.target=record;return[3,18];case 15:return[4,this.checkUniqueViolation(targetDB,entity1,fixture)];case 16:uniqueRow=_state.sent();if(!uniqueRow)return[3,18];return[4,this.createFixtureRecord(entity1,uniqueRow,{singleRecord:true,_db:targetDB})];case 17:_ref1=_sliced_to_array.apply(void 0,[_state.sent(),1]),record1=_ref1[0];fixture.unique=record1;_state.label=18;case 18:_iteratorAbruptCompletion=false;return[3,11];case 19:return[3,26];case 20:err1=_state.sent();_didIteratorError1=true;_iteratorError1=err1;return[3,26];case 21:_state.trys.push([21,,24,25]);if(!(_iteratorAbruptCompletion&&_iterator1.return!=null))return[3,23];return[4,_iterator1.return()];case 22:_state.sent();_state.label=23;case 23:return[3,25];case 24:if(_didIteratorError1){throw _iteratorError1}return[7];case 25:return[7];case 26:return[2,_lodash.default.uniqBy(fixtures,function(f){return f.fixtureId})]}})}).call(this)}},{key:"createFixtureRecord",value:function createFixtureRecord(entity,row,options){return _async_to_generator(function(){var records,visitedEntities,create;return _ts_generator(this,function(_state){switch(_state.label){case 0:records=[];visitedEntities=new Set;create=function(entity,row){return _async_to_generator(function(){var fixtureId,record,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_iterator,_step,prop,_options__db,db,relatedEntity,throughTable,fromColumn,toColumn,relatedIds,relatedEntity1,relatedIds1,relatedEntity2,relatedProp,relatedRow,relatedId,relatedEntity3,relatedRow1,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:fixtureId="".concat(entity.id,"#").concat(row.id);if(visitedEntities.has(fixtureId)){return[2]}visitedEntities.add(fixtureId);record={fixtureId:fixtureId,entityId:entity.id,id:row.id,columns:{},fetchedRecords:[],belongsRecords:[]};_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=1;case 1:_state.trys.push([1,14,15,16]);_iterator=entity.props[Symbol.iterator]();_state.label=2;case 2:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,13];prop=_step.value;if((0,_types.isVirtualProp)(prop)){return[3,12]}record.columns[prop.name]={prop:prop,value:row[prop.name]};db=(_options__db=options===null||options===void 0?void 0:options._db)!==null&&_options__db!==void 0?_options__db:_basemodel.BaseModel.getDB("w");if(!(0,_types.isManyToManyRelationProp)(prop))return[3,4];relatedEntity=_entitymanager.EntityManager.get(prop.with);throughTable=prop.joinTable;fromColumn="".concat(_inflection.default.singularize(entity.table),"_id");toColumn="".concat(_inflection.default.singularize(relatedEntity.table),"_id");return[4,db(throughTable).where(fromColumn,row.id).pluck(toColumn)];case 3:relatedIds=_state.sent();record.columns[prop.name].value=relatedIds;return[3,12];case 4:if(!(0,_types.isHasManyRelationProp)(prop))return[3,6];relatedEntity1=_entitymanager.EntityManager.get(prop.with);return[4,db(relatedEntity1.table).where(prop.joinColumn,row.id).pluck("id")];case 5:relatedIds1=_state.sent();record.columns[prop.name].value=relatedIds1;return[3,12];case 6:if(!((0,_types.isOneToOneRelationProp)(prop)&&!prop.hasJoinColumn))return[3,9];relatedEntity2=_entitymanager.EntityManager.get(prop.with);relatedProp=relatedEntity2.props.find(function(p){return(0,_types.isRelationProp)(p)&&p.with===entity.id});if(!relatedProp)return[3,8];return[4,db(relatedEntity2.table).where("id",row.id).first()];case 7:relatedRow=_state.sent();record.columns[prop.name].value=relatedRow===null||relatedRow===void 0?void 0:relatedRow.id;_state.label=8;case 8:return[3,12];case 9:if(!(0,_types.isRelationProp)(prop))return[3,12];relatedId=row["".concat(prop.name,"_id")];record.columns[prop.name].value=relatedId;if(relatedId){record.belongsRecords.push("".concat(prop.with,"#").concat(relatedId))}if(!(!(options===null||options===void 0?void 0:options.singleRecord)&&relatedId))return[3,12];relatedEntity3=_entitymanager.EntityManager.get(prop.with);return[4,db(relatedEntity3.table).where("id",relatedId).first()];case 10:relatedRow1=_state.sent();if(!relatedRow1)return[3,12];return[4,create(relatedEntity3,relatedRow1)];case 11:_state.sent();_state.label=12;case 12:_iteratorNormalCompletion=true;return[3,2];case 13:return[3,16];case 14:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,16];case 15:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 16:records.push(record);return[2]}})})()};return[4,create(entity,row)];case 1:_state.sent();return[2,records]}})})()}},{key:"insertFixtures",value:function insertFixtures(dbName,_fixtures){return _async_to_generator(function(){var _this,fixtures,insertionOrder,db,records,_iteratorAbruptCompletion,_didIteratorError,_iteratorError,_iterator,_step,_value,r,entity,record,err1;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this;fixtures=_lodash.default.uniqBy(_fixtures,function(f){return f.fixtureId});this.relationGraph.buildGraph(fixtures);insertionOrder=this.relationGraph.getInsertionOrder();db=(0,_knex.default)(_api.Sonamu.dbConfig[dbName]);return[4,db.transaction(function(trx){return _async_to_generator(function(){var _iteratorNormalCompletion,_didIteratorError,_iteratorError,_this,_loop,_iterator,_step,err,_iteratorNormalCompletion1,_didIteratorError1,_iteratorError1,_this1,_loop1,_iterator1,_step1,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,trx.raw("SET FOREIGN_KEY_CHECKS = 0")];case 1:_state.sent();_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=2;case 2:_state.trys.push([2,7,8,9]);_loop=function(){var fixtureId,fixture,result;return _ts_generator(this,function(_state){switch(_state.label){case 0:fixtureId=_step.value;fixture=fixtures.find(function(f){return f.fixtureId===fixtureId});return[4,_this.insertFixture(trx,fixture)];case 1:result=_state.sent();if(result.id!==fixture.id){console.log(_chalk.default.yellow("Unique constraint violation: ".concat(fixture.entityId,"#").concat(fixture.id," -> ").concat(fixture.entityId,"#").concat(result.id)));fixtures.forEach(function(f){Object.values(f.columns).forEach(function(column){if(column.prop.type==="relation"&&column.prop.with===result.entityId&&column.value===fixture.id){column.value=result.id}})});fixture.id=result.id}return[2]}})};_iterator=insertionOrder[Symbol.iterator]();_state.label=3;case 3:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,6];_this=this;return[5,_ts_values(_loop())];case 4:_state.sent();_state.label=5;case 5:_iteratorNormalCompletion=true;return[3,3];case 6:return[3,9];case 7:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,9];case 8:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 9:_iteratorNormalCompletion1=true,_didIteratorError1=false,_iteratorError1=undefined;_state.label=10;case 10:_state.trys.push([10,15,16,17]);_loop1=function(){var fixtureId,fixture;return _ts_generator(this,function(_state){switch(_state.label){case 0:fixtureId=_step1.value;fixture=fixtures.find(function(f){return f.fixtureId===fixtureId});return[4,_this1.handleManyToManyRelations(trx,fixture,fixtures)];case 1:_state.sent();return[2]}})};_iterator1=insertionOrder[Symbol.iterator]();_state.label=11;case 11:if(!!(_iteratorNormalCompletion1=(_step1=_iterator1.next()).done))return[3,14];_this1=this;return[5,_ts_values(_loop1())];case 12:_state.sent();_state.label=13;case 13:_iteratorNormalCompletion1=true;return[3,11];case 14:return[3,17];case 15:err=_state.sent();_didIteratorError1=true;_iteratorError1=err;return[3,17];case 16:try{if(!_iteratorNormalCompletion1&&_iterator1.return!=null){_iterator1.return()}}finally{if(_didIteratorError1){throw _iteratorError1}}return[7];case 17:return[4,trx.raw("SET FOREIGN_KEY_CHECKS = 1")];case 18:_state.sent();return[2]}})}).call(_this)})];case 1:_state.sent();records=[];_iteratorAbruptCompletion=false,_didIteratorError=false;_state.label=2;case 2:_state.trys.push([2,8,9,14]);_iterator=_async_iterator(fixtures);_state.label=3;case 3:return[4,_iterator.next()];case 4:if(!(_iteratorAbruptCompletion=!(_step=_state.sent()).done))return[3,7];_value=_step.value;r=_value;entity=_entitymanager.EntityManager.get(r.entityId);return[4,db(entity.table).where("id",r.id).first()];case 5:record=_state.sent();records.push({entityId:r.entityId,data:record});_state.label=6;case 6:_iteratorAbruptCompletion=false;return[3,3];case 7:return[3,14];case 8:err1=_state.sent();_didIteratorError=true;_iteratorError=err1;return[3,14];case 9:_state.trys.push([9,,12,13]);if(!(_iteratorAbruptCompletion&&_iterator.return!=null))return[3,11];return[4,_iterator.return()];case 10:_state.sent();_state.label=11;case 11:return[3,13];case 12:if(_didIteratorError){throw _iteratorError}return[7];case 13:return[7];case 14:return[2,_lodash.default.uniqBy(records,function(r){return"".concat(r.entityId,"#").concat(r.data.id)})]}})}).call(this)}},{key:"prepareInsertData",value:function prepareInsertData(fixture){var insertData={};var _iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;try{for(var _iterator=Object.entries(fixture.columns)[Symbol.iterator](),_step;!(_iteratorNormalCompletion=(_step=_iterator.next()).done);_iteratorNormalCompletion=true){var _step_value=_sliced_to_array(_step.value,2),propName=_step_value[0],column=_step_value[1];if((0,_types.isVirtualProp)(column.prop)){continue}var prop=column.prop;if(!(0,_types.isRelationProp)(prop)){if(prop.type==="json"){insertData[propName]=JSON.stringify(column.value)}else if(prop.type==="timestamp"||prop.type==="datetime"){insertData[propName]=new Date(column.value)}else{insertData[propName]=column.value}}else if((0,_types.isBelongsToOneRelationProp)(prop)||(0,_types.isOneToOneRelationProp)(prop)&&prop.hasJoinColumn){insertData["".concat(propName,"_id")]=column.value}}}catch(err){_didIteratorError=true;_iteratorError=err}finally{try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}}return insertData}},{key:"insertFixture",value:function insertFixture(db,fixture){return _async_to_generator(function(){var insertData,entity,uniqueFound,found,q,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:insertData=this.prepareInsertData(fixture);entity=_entitymanager.EntityManager.get(fixture.entityId);_state.label=1;case 1:_state.trys.push([1,5,,6]);return[4,this.checkUniqueViolation(db,entity,fixture)];case 2:uniqueFound=_state.sent();if(uniqueFound){return[2,{entityId:fixture.entityId,id:uniqueFound.id}]}return[4,db(entity.table).where("id",fixture.id).first()];case 3:found=_state.sent();if(found&&!fixture.override){return[2,{entityId:fixture.entityId,id:found.id}]}q=db.insert(insertData).into(entity.table);return[4,q.onDuplicateUpdate.apply(q,Object.keys(insertData))];case 4:_state.sent();return[2,{entityId:fixture.entityId,id:fixture.id}];case 5:err=_state.sent();console.log(err);throw err;case 6:return[2]}})}).call(this)}},{key:"handleManyToManyRelations",value:function handleManyToManyRelations(db,fixture,fixtures){return _async_to_generator(function(){var _iteratorNormalCompletion,_didIteratorError,_iteratorError,_loop,_iterator,_step,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=1;case 1:_state.trys.push([1,6,7,8]);_loop=function(){var _step_value,column,prop,joinTable,relatedIds,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_loop,_iterator,_step1,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:_step_value=_sliced_to_array(_step.value,2),column=_step_value[1];prop=column.prop;if(!(0,_types.isManyToManyRelationProp)(prop))return[3,8];joinTable=prop.joinTable;relatedIds=column.value;_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=1;case 1:_state.trys.push([1,6,7,8]);_loop=function(){var relatedId,entity,relatedEntity,_obj,_ref,found,_obj1,newIds;return _ts_generator(this,function(_state){switch(_state.label){case 0:relatedId=_step1.value;if(!fixtures.find(function(f){return f.fixtureId==="".concat(prop.with,"#").concat(relatedId)})){return[2,"continue"]}entity=_entitymanager.EntityManager.get(fixture.entityId);relatedEntity=_entitymanager.EntityManager.get(prop.with);if(!entity||!relatedEntity){throw new Error("Entity not found: ".concat(fixture.entityId,", ").concat(prop.with))}return[4,db(joinTable).where((_obj={},_define_property(_obj,"".concat(_inflection.default.singularize(entity.table),"_id"),fixture.id),_define_property(_obj,"".concat(_inflection.default.singularize(relatedEntity.table),"_id"),relatedId),_obj)).limit(1)];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),found=_ref[0];if(found){return[2,"continue"]}return[4,db(joinTable).insert((_obj1={},_define_property(_obj1,"".concat(_inflection.default.singularize(entity.table),"_id"),fixture.id),_define_property(_obj1,"".concat(_inflection.default.singularize(relatedEntity.table),"_id"),relatedId),_obj1))];case 2:newIds=_state.sent();console.log(_chalk.default.green("Inserted into ".concat(joinTable,": ").concat(entity.table,"(").concat(fixture.id,") - ").concat(relatedEntity.table,"(").concat(relatedId,") ID: ").concat(newIds)));return[2]}})};_iterator=relatedIds[Symbol.iterator]();_state.label=2;case 2:if(!!(_iteratorNormalCompletion=(_step1=_iterator.next()).done))return[3,5];return[5,_ts_values(_loop())];case 3:_state.sent();_state.label=4;case 4:_iteratorNormalCompletion=true;return[3,2];case 5:return[3,8];case 6:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,8];case 7:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 8:return[2]}})};_iterator=Object.entries(fixture.columns)[Symbol.iterator]();_state.label=2;case 2:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,5];return[5,_ts_values(_loop())];case 3:_state.sent();_state.label=4;case 4:_iteratorNormalCompletion=true;return[3,2];case 5:return[3,8];case 6:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,8];case 7:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 8:return[2]}})})()}},{key:"addFixtureLoader",value:function addFixtureLoader(code){return _async_to_generator(function(){var path,content,fixtureLoaderStart,fixtureLoaderEnd,newContent;return _ts_generator(this,function(_state){path=_api.Sonamu.apiRootPath+"/src/testing/fixture.ts";content=(0,_fs.readFileSync)(path).toString();fixtureLoaderStart=content.indexOf("const fixtureLoader = {");fixtureLoaderEnd=content.indexOf("};",fixtureLoaderStart);if(fixtureLoaderStart!==-1&&fixtureLoaderEnd!==-1){newContent=content.slice(0,fixtureLoaderEnd)+" "+code+"\n"+content.slice(fixtureLoaderEnd);(0,_fs.writeFileSync)(path,newContent)}else{throw new Error("Failed to find fixtureLoader in fixture.ts")}return[2]})})()}},{key:"checkUniqueViolation",value:function checkUniqueViolation(db,entity,fixture){return _async_to_generator(function(){var _uniqueIndexes,uniqueIndexes,uniqueQuery,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_loop,_iterator,_step,_ref,uniqueFound;return _ts_generator(this,function(_state){switch(_state.label){case 0:_uniqueIndexes=entity.indexes.filter(function(i){return i.type==="unique"});uniqueIndexes=_uniqueIndexes.filter(function(index){return index.columns.every(function(column){return!column.startsWith("".concat(entity.table,"__"))})});if(uniqueIndexes.length===0){return[2,null]}uniqueQuery=db(entity.table);_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;try{_loop=function(){var index=_step.value;var containsNull=index.columns.some(function(column){var field=column.split("_id")[0];return fixture.columns[field].value===null});if(containsNull){return"continue"}uniqueQuery=uniqueQuery.orWhere(function(qb){var _iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;try{for(var _iterator=index.columns[Symbol.iterator](),_step;!(_iteratorNormalCompletion=(_step=_iterator.next()).done);_iteratorNormalCompletion=true){var column=_step.value;var field=column.split("_id")[0];if(Array.isArray(fixture.columns[field].value)){qb.whereIn(column,fixture.columns[field].value)}else{qb.andWhere(column,fixture.columns[field].value)}}}catch(err){_didIteratorError=true;_iteratorError=err}finally{try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}}})};for(_iterator=uniqueIndexes[Symbol.iterator]();!(_iteratorNormalCompletion=(_step=_iterator.next()).done);_iteratorNormalCompletion=true)_loop()}catch(err){_didIteratorError=true;_iteratorError=err}finally{try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}}return[4,uniqueQuery];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]),uniqueFound=_ref[0];return[2,uniqueFound]}})})()}}]);return FixtureManagerClass}();var FixtureManager=new FixtureManagerClass;
2
- //# sourceMappingURL=fixture-manager.js.map
1
+ import assert from "assert";
2
+ import chalk from "chalk";
3
+ import { execSync } from "child_process";
4
+ import { readFileSync, writeFileSync } from "fs";
5
+ import inflection from "inflection";
6
+ import knex from "knex";
7
+ import { unique } from "radashi";
8
+ import { inspect } from "util";
9
+ import { Sonamu } from "../api/index.js";
10
+ import { BaseModel } from "../database/base-model.js";
11
+ import { UpsertBuilder } from "../database/upsert-builder.js";
12
+ import { EntityManager } from "../entity/entity-manager.js";
13
+ import { isBelongsToOneRelationProp, isHasManyRelationProp, isManyToManyRelationProp, isOneToOneRelationProp, isRelationProp, isVirtualProp } from "../types/types.js";
14
+ import { RelationGraph } from "./_relation-graph.js";
15
+ export class FixtureManagerClass {
16
+ _tdb = null;
17
+ set tdb(tdb) {
18
+ this._tdb = tdb;
19
+ }
20
+ get tdb() {
21
+ if (this._tdb === null) {
22
+ throw new Error("FixtureManager has not been initialized");
23
+ }
24
+ return this._tdb;
25
+ }
26
+ _fdb = null;
27
+ set fdb(fdb) {
28
+ this._fdb = fdb;
29
+ }
30
+ get fdb() {
31
+ if (this._fdb === null) {
32
+ throw new Error("FixtureManager has not been initialized");
33
+ }
34
+ return this._fdb;
35
+ }
36
+ cachedTableNames = null;
37
+ relationGraph = new RelationGraph();
38
+ // UpsertBuilder 기반 import를 위한 상태
39
+ builder = new UpsertBuilder();
40
+ fixtureRefMap = new Map();
41
+ uuidToFixtureId = new Map();
42
+ skippedFixtures = new Map();
43
+ init() {
44
+ if (this._tdb !== null) {
45
+ return;
46
+ }
47
+ if (Sonamu.dbConfig.test && Sonamu.dbConfig.production_master) {
48
+ const tConn = Sonamu.dbConfig.test.connection;
49
+ const pConn = Sonamu.dbConfig.production_master.connection;
50
+ if (`${tConn.host ?? "localhost"}:${tConn.port ?? 5432}/${tConn.database}` === `${pConn.host ?? "localhost"}:${pConn.port ?? 5432}/${pConn.database}`) {
51
+ throw new Error(`테스트DB와 프로덕션DB에 동일한 데이터베이스가 사용되었습니다.`);
52
+ }
53
+ }
54
+ this.tdb = knex(Sonamu.dbConfig.test);
55
+ this.fdb = knex(Sonamu.dbConfig.fixture_remote);
56
+ }
57
+ async getChecksum(db, tableName) {
58
+ const [[checksumRow]] = await db.raw(`CHECKSUM TABLE ${tableName}`);
59
+ return checksumRow.Checksum;
60
+ }
61
+ /**
62
+ 이제 FixtureManager.sync() 는 checksum 비교 없이 create database template 으로 수행합니다.
63
+ */ async sync() {
64
+ const fixtureConn = Sonamu.dbConfig.fixture_remote.connection;
65
+ const testConn = Sonamu.dbConfig.test.connection;
66
+ // PostgreSQL 패스워드 환경변수 설정
67
+ const pgEnv = {
68
+ PGPASSWORD: testConn.password || ""
69
+ };
70
+ // 1. 연결 강제 종료
71
+ execSync(`psql -h ${testConn.host} -p ${testConn.port ?? 5432} -U ${testConn.user} -d postgres -c "
72
+ SELECT pg_terminate_backend(pg_stat_activity.pid)
73
+ FROM pg_stat_activity
74
+ WHERE datname = '${testConn.database}'
75
+ AND pid <> pg_backend_pid();
76
+ "`, {
77
+ stdio: "inherit",
78
+ env: {
79
+ ...process.env,
80
+ ...pgEnv
81
+ }
82
+ });
83
+ execSync(`psql -h ${fixtureConn.host} -p ${fixtureConn.port ?? 5432} -U ${fixtureConn.user} -d postgres -c "
84
+ SELECT pg_terminate_backend(pg_stat_activity.pid)
85
+ FROM pg_stat_activity
86
+ WHERE datname = '${fixtureConn.database}'
87
+ AND pid <> pg_backend_pid();
88
+ "`, {
89
+ stdio: "inherit",
90
+ env: {
91
+ ...process.env,
92
+ ...pgEnv
93
+ }
94
+ });
95
+ // 2. DROP DATABASE (별도 실행!)
96
+ execSync(`psql -h ${testConn.host} -p ${testConn.port ?? 5432} -U ${testConn.user} -d postgres -c "DROP DATABASE IF EXISTS \\"${testConn.database}\\""`, {
97
+ stdio: "inherit",
98
+ env: {
99
+ ...process.env,
100
+ ...pgEnv
101
+ }
102
+ });
103
+ // 3. CREATE DATABASE
104
+ execSync(`psql -h ${testConn.host} -p ${testConn.port ?? 5432} -U ${testConn.user} -d postgres -c "CREATE DATABASE \\"${testConn.database}\\" TEMPLATE \\"${fixtureConn.database}\\""`, {
105
+ stdio: "inherit",
106
+ env: {
107
+ ...process.env,
108
+ ...pgEnv
109
+ }
110
+ });
111
+ }
112
+ visitedRecords = new Set();
113
+ async importFixture(entityId, ids) {
114
+ // 방문 기록 초기화 (새로운 import 작업 시작)
115
+ this.visitedRecords.clear();
116
+ const queries = unique((await Promise.all(ids.map(async (id)=>{
117
+ return await this.getImportQueries(entityId, "id", id);
118
+ }))).flat());
119
+ const wdb = BaseModel.getDB("w");
120
+ for (const query of queries){
121
+ const [rsh] = await wdb.raw(query);
122
+ console.log({
123
+ query,
124
+ info: rsh.info
125
+ });
126
+ }
127
+ }
128
+ async getImportQueries(entityId, field, id) {
129
+ const recordKey = `${entityId}#${field}#${id}`;
130
+ // 순환 참조 방지: 이미 방문한 레코드는 스킵
131
+ if (this.visitedRecords.has(recordKey)) {
132
+ return [];
133
+ }
134
+ this.visitedRecords.add(recordKey);
135
+ console.log({
136
+ entityId,
137
+ field,
138
+ id
139
+ });
140
+ const entity = EntityManager.get(entityId);
141
+ const wdb = BaseModel.getDB("w");
142
+ // 여기서 실DB의 row 가져옴
143
+ const [row] = await wdb(entity.table).where(field, id).limit(1);
144
+ if (row === undefined) {
145
+ throw new Error(`${entityId}#${id} row를 찾을 수 없습니다.`);
146
+ }
147
+ // 픽스쳐DB, 실DB
148
+ const fixtureDatabase = Sonamu.dbConfig.fixture_remote.connection.database;
149
+ const realDatabase = Sonamu.dbConfig.production_master.connection.database;
150
+ const selfQuery = `INSERT IGNORE INTO \`${fixtureDatabase}\`.\`${entity.table}\` (SELECT * FROM \`${realDatabase}\`.\`${entity.table}\` WHERE \`id\` = ${id})`;
151
+ const args = Object.entries(entity.relations).filter(([, relation])=>isBelongsToOneRelationProp(relation) || isOneToOneRelationProp(relation) && relation.customJoinClause === undefined).map(([, relation])=>{
152
+ /*
153
+ BelongsToOne인 경우
154
+ Category / 'id' / row[category_id] 호출
155
+ OneToOne에 joinColumn === true 인 경우
156
+ Profile / 'id' / row[profile_id] 호출
157
+ OneToOne에 joinColumn === false 인 경우
158
+ Profile / 'profile_id' / row['id'] 호출
159
+ */ let field;
160
+ let id;
161
+ if (isOneToOneRelationProp(relation) && !relation.hasJoinColumn) {
162
+ const relatedEntity = EntityManager.get(relation.with);
163
+ const relatedIdColumnName = relatedEntity.props.find((p)=>isRelationProp(p) && p.with === entity.id)?.name;
164
+ if (!relatedIdColumnName) {
165
+ throw new Error(`${relatedEntity.id}의 ${entity.id} 관계 프롭을 찾을 수 없습니다.`);
166
+ }
167
+ field = `${relatedIdColumnName}_id`;
168
+ id = row.id;
169
+ } else {
170
+ field = "id";
171
+ id = row[`${relation.name}_id`];
172
+ }
173
+ return {
174
+ entityId: relation.with,
175
+ field,
176
+ id
177
+ };
178
+ }).filter((arg)=>arg.id !== null);
179
+ const relQueries = await Promise.all(args.map(async (args)=>{
180
+ return this.getImportQueries(args.entityId, args.field, args.id);
181
+ }));
182
+ return [
183
+ ...unique(relQueries.reverse().flat()),
184
+ selfQuery
185
+ ];
186
+ }
187
+ async destroy() {
188
+ if (this._tdb) {
189
+ await this._tdb.destroy();
190
+ this._tdb = null;
191
+ }
192
+ if (this._fdb) {
193
+ await this._fdb.destroy();
194
+ this._fdb = null;
195
+ }
196
+ await BaseModel.destroy();
197
+ }
198
+ async getFixtures(sourceDBName, targetDBName, searchOptions, duplicateCheck) {
199
+ const sourceDB = knex(Sonamu.dbConfig[sourceDBName]);
200
+ const targetDB = knex(Sonamu.dbConfig[targetDBName]);
201
+ const { entityId, field, value, searchType } = searchOptions;
202
+ const entity = EntityManager.get(entityId);
203
+ const column = entity.props.find((prop)=>prop.name === field)?.type === "relation" ? `${field}_id` : field;
204
+ let query = sourceDB(entity.table);
205
+ if (searchType === "equals") {
206
+ query = query.where(column, value);
207
+ } else if (searchType === "like") {
208
+ query = query.where(column, "like", `%${value}%`);
209
+ }
210
+ const rows = await query;
211
+ if (rows.length === 0) {
212
+ throw new Error("No records found");
213
+ }
214
+ const fixtures = [];
215
+ for (const row of rows){
216
+ const initialRecordsLength = fixtures.length;
217
+ const newRecords = await this.createFixtureRecord(entity, row, {
218
+ _db: sourceDB
219
+ });
220
+ fixtures.push(...newRecords);
221
+ const currentFixtureRecord = fixtures.find((r)=>r.fixtureId === `${entityId}#${row.id}`);
222
+ if (currentFixtureRecord) {
223
+ // 현재 fixture로부터 생성된 fetchedRecords 설정
224
+ currentFixtureRecord.fetchedRecords = fixtures.filter((r)=>r.fixtureId !== currentFixtureRecord.fixtureId).slice(initialRecordsLength).map((r)=>r.fixtureId);
225
+ }
226
+ }
227
+ for await (const fixture of fixtures){
228
+ const entity = EntityManager.get(fixture.entityId);
229
+ // 사용자 지정 컬럼 기준 중복 확인 → target
230
+ const customColumns = duplicateCheck?.columns?.[fixture.entityId];
231
+ if (customColumns && customColumns.length > 0) {
232
+ const customDuplicateRow = await this.checkDuplicateByColumns(targetDB, entity, fixture, customColumns);
233
+ if (customDuplicateRow) {
234
+ const [record] = await this.createFixtureRecord(entity, customDuplicateRow, {
235
+ singleRecord: true,
236
+ _db: targetDB
237
+ });
238
+ fixture.target = record;
239
+ }
240
+ }
241
+ // Unique index 기준 중복 확인 → fixture.unique
242
+ const uniqueRow = await this.checkUniqueViolation(targetDB, entity, fixture);
243
+ if (uniqueRow) {
244
+ const [record] = await this.createFixtureRecord(entity, uniqueRow, {
245
+ singleRecord: true,
246
+ _db: targetDB
247
+ });
248
+ fixture.unique = record;
249
+ }
250
+ }
251
+ await targetDB.destroy();
252
+ await sourceDB.destroy();
253
+ return unique(fixtures, (f)=>f.fixtureId);
254
+ }
255
+ async createFixtureRecord(entity, row, options) {
256
+ const records = [];
257
+ const visitedEntities = new Set();
258
+ const create = async (entity, row)=>{
259
+ const fixtureId = `${entity.id}#${row.id}`;
260
+ if (visitedEntities.has(fixtureId)) {
261
+ return;
262
+ }
263
+ visitedEntities.add(fixtureId);
264
+ const record = {
265
+ fixtureId,
266
+ entityId: entity.id,
267
+ id: row.id,
268
+ columns: {},
269
+ fetchedRecords: [],
270
+ belongsRecords: []
271
+ };
272
+ for (const prop of entity.props){
273
+ if (isVirtualProp(prop)) {
274
+ continue;
275
+ }
276
+ record.columns[prop.name] = {
277
+ prop: prop,
278
+ value: row[prop.name]
279
+ };
280
+ const db = options?._db ?? BaseModel.getDB("w");
281
+ if (isManyToManyRelationProp(prop)) {
282
+ const relatedEntity = EntityManager.get(prop.with);
283
+ const throughTable = prop.joinTable;
284
+ const fromColumn = `${inflection.singularize(entity.table)}_id`;
285
+ const toColumn = `${inflection.singularize(relatedEntity.table)}_id`;
286
+ const relatedIds = await db(throughTable).where(fromColumn, row.id).pluck(toColumn);
287
+ record.columns[prop.name].value = relatedIds;
288
+ } else if (isHasManyRelationProp(prop)) {
289
+ const relatedEntity = EntityManager.get(prop.with);
290
+ const relatedIds = await db(relatedEntity.table).where(prop.joinColumn, row.id).pluck("id");
291
+ record.columns[prop.name].value = relatedIds;
292
+ } else if (isOneToOneRelationProp(prop) && !prop.hasJoinColumn) {
293
+ const relatedEntity = EntityManager.get(prop.with);
294
+ const relatedProp = relatedEntity.props.find((p)=>isRelationProp(p) && p.with === entity.id);
295
+ if (relatedProp) {
296
+ const relatedRow = await db(relatedEntity.table).where("id", row.id).first();
297
+ record.columns[prop.name].value = relatedRow?.id;
298
+ }
299
+ } else if (isRelationProp(prop)) {
300
+ const relatedId = row[`${prop.name}_id`];
301
+ record.columns[prop.name].value = relatedId;
302
+ if (relatedId) {
303
+ record.belongsRecords.push(`${prop.with}#${relatedId}`);
304
+ }
305
+ if (!options?.singleRecord && relatedId) {
306
+ const relatedEntity = EntityManager.get(prop.with);
307
+ const relatedRow = await db(relatedEntity.table).where("id", relatedId).first();
308
+ if (relatedRow) {
309
+ await create(relatedEntity, relatedRow);
310
+ }
311
+ }
312
+ }
313
+ }
314
+ records.push(record);
315
+ };
316
+ await create(entity, row);
317
+ return records;
318
+ }
319
+ /**
320
+ * 1. RelationGraph로 fixture 단위 삽입 순서 계산 (self-reference 포함)
321
+ * 2. 순서대로 UpsertBuilder에 등록 (UBRef로 참조 관계 표현)
322
+ * 3. 테이블별 upsert 실행 (ID는 DB가 자동 할당)
323
+ */ async insertFixtures(dbName, _fixtures) {
324
+ const fixtures = unique(_fixtures, (f)=>f.fixtureId);
325
+ // 초기화
326
+ this.builder = new UpsertBuilder();
327
+ this.fixtureRefMap = new Map();
328
+ this.uuidToFixtureId = new Map();
329
+ this.skippedFixtures = new Map();
330
+ const db = knex(Sonamu.dbConfig[dbName]);
331
+ const results = [];
332
+ try {
333
+ // 1. RelationGraph로 fixture 단위 삽입 순서 계산
334
+ this.relationGraph.buildGraph(fixtures);
335
+ const insertionOrder = this.relationGraph.getInsertionOrder();
336
+ // 2. 순서대로 UpsertBuilder에 등록 (override 체크)
337
+ for (const fixtureId of insertionOrder){
338
+ const fixture = fixtures.find((f)=>f.fixtureId === fixtureId);
339
+ if (!fixture) continue;
340
+ const hasTarget = !!fixture.target;
341
+ const hasUnique = !!fixture.unique;
342
+ const hasDuplicate = hasTarget || hasUnique;
343
+ // 중복이 있고 override=false인 경우: 스킵
344
+ if (hasDuplicate && !fixture.override) {
345
+ // 기존 레코드 ID 저장 (unique 우선, 없으면 target)
346
+ const existingId = fixture.unique?.id ?? fixture.target?.id;
347
+ assert(existingId);
348
+ this.skippedFixtures.set(fixtureId, {
349
+ entityId: fixture.entityId,
350
+ existingId
351
+ });
352
+ console.log(chalk.yellow(`Skipped ${fixture.entityId}#${fixture.id} (existing: #${existingId}, override: false)`));
353
+ continue;
354
+ }
355
+ this.registerFixture(fixture);
356
+ console.log(chalk.blue(`Registered ${fixture.entityId}#${fixture.id}${fixture.override ? ` (override existing: #${fixture.target?.id})` : ""}`));
357
+ }
358
+ // 3. 테이블별 upsert 실행
359
+ const tableOrder = this.getTableOrder(fixtures);
360
+ await db.transaction(async (trx)=>{
361
+ const insertedIdsByTable = new Map();
362
+ for (const tableName of tableOrder){
363
+ if (!this.builder.hasTable(tableName)) continue;
364
+ // upsert 실행 전 uuid 목록 저장
365
+ const table = this.builder.getTable(tableName);
366
+ const uuids = table.rows.map((row)=>row.uuid);
367
+ console.log(chalk.blue(`Upserting ${tableName} with ${uuids.length} rows`));
368
+ await this.builder.upsert(trx, tableName);
369
+ // upsert된 row들의 uuid -> id 매핑 구축
370
+ if (uuids.length > 0) {
371
+ const uuidToId = new Map();
372
+ const rows = await trx(tableName).select("uuid", "id").whereIn("uuid", uuids);
373
+ for (const row of rows){
374
+ uuidToId.set(row.uuid, row.id);
375
+ }
376
+ insertedIdsByTable.set(tableName, uuidToId);
377
+ }
378
+ }
379
+ // 4. ManyToMany 관계 처리
380
+ await this.processManyToManyRelations(trx, fixtures, insertedIdsByTable);
381
+ // 5. 결과 수집
382
+ for (const fixture of fixtures){
383
+ const entity = EntityManager.get(fixture.entityId);
384
+ // 스킵된 fixture는 기존 레코드 정보로 결과 추가
385
+ const skipped = this.skippedFixtures.get(fixture.fixtureId);
386
+ if (skipped) {
387
+ results.push({
388
+ entityId: fixture.entityId,
389
+ data: await trx(entity.table).where("id", skipped.existingId).first()
390
+ });
391
+ continue;
392
+ }
393
+ const ref = this.fixtureRefMap.get(fixture.fixtureId);
394
+ if (ref) {
395
+ const uuidToId = insertedIdsByTable.get(entity.table);
396
+ const insertedId = uuidToId?.get(ref.uuid);
397
+ if (insertedId !== undefined) {
398
+ results.push({
399
+ entityId: fixture.entityId,
400
+ data: await trx(entity.table).where("id", insertedId).first()
401
+ });
402
+ console.log(chalk.green(`Inserted into ${entity.table}: #${fixture.id} -> #${insertedId}`));
403
+ }
404
+ }
405
+ }
406
+ });
407
+ } finally{
408
+ await db.destroy();
409
+ }
410
+ return unique(results, (r)=>`${r.entityId}#${r.data.id}`);
411
+ }
412
+ /**
413
+ * FixtureRecord를 UpsertBuilder에 등록
414
+ */ registerFixture(fixture) {
415
+ const entity = EntityManager.get(fixture.entityId);
416
+ const row = {};
417
+ // Override 모드 판단: target 또는 unique가 있고 override=true인 경우
418
+ const existingRecord = fixture.target ?? fixture.unique;
419
+ const isOverrideMode = fixture.override && existingRecord;
420
+ for (const [propName, column] of Object.entries(fixture.columns)){
421
+ const prop = column.prop;
422
+ if (isVirtualProp(prop)) {
423
+ continue;
424
+ }
425
+ // id/uuid 처리: Override 모드일 때만 기존 값 사용
426
+ if (propName === "id" || propName === "uuid") {
427
+ if (isOverrideMode && existingRecord) {
428
+ // Override: 기존 레코드의 값 사용 → UPDATE
429
+ row[propName] = existingRecord.columns[propName]?.value;
430
+ }
431
+ continue;
432
+ }
433
+ if (isRelationProp(prop)) {
434
+ if (isBelongsToOneRelationProp(prop) || isOneToOneRelationProp(prop) && prop.hasJoinColumn) {
435
+ const relatedId = column.value;
436
+ if (relatedId !== null && relatedId !== undefined) {
437
+ const relatedFixtureId = `${prop.with}#${relatedId}`;
438
+ // 먼저 skip된 fixture인지 확인
439
+ const skippedExistingId = this.skippedFixtures.get(relatedFixtureId)?.existingId;
440
+ if (skippedExistingId !== undefined) {
441
+ // skip된 fixture → target DB의 기존 레코드 id 사용
442
+ row[`${propName}_id`] = skippedExistingId;
443
+ } else {
444
+ const relatedRef = this.fixtureRefMap.get(relatedFixtureId);
445
+ if (relatedRef) {
446
+ // 이미 등록된 fixture 참조 → UBRef 사용
447
+ row[`${propName}_id`] = relatedRef;
448
+ } else {
449
+ // fixtures에 포함되지 않은 레코드 → ID 그대로 사용
450
+ row[`${propName}_id`] = relatedId;
451
+ }
452
+ }
453
+ } else {
454
+ row[`${propName}_id`] = null;
455
+ }
456
+ }
457
+ // HasMany, ManyToMany는 별도 처리
458
+ } else {
459
+ // 일반 컬럼
460
+ row[propName] = this.convertColumnValue(prop, column.value);
461
+ }
462
+ }
463
+ console.log(chalk.blue(`Registering ${entity.table} - ${inspect(row, false, null, true)}`));
464
+ const ref = this.builder.register(entity.table, row);
465
+ this.fixtureRefMap.set(fixture.fixtureId, ref);
466
+ this.uuidToFixtureId.set(ref.uuid, fixture.fixtureId);
467
+ return ref;
468
+ }
469
+ /**
470
+ * 컬럼 값 변환
471
+ */ convertColumnValue(prop, value) {
472
+ if (value === null || value === undefined) {
473
+ return null;
474
+ }
475
+ switch(prop.type){
476
+ case "json":
477
+ // UpsertBuilder.register에서 JSON.stringify 처리하므로 object 그대로 전달
478
+ return value;
479
+ case "date":
480
+ if (typeof value === "string" || typeof value === "number") {
481
+ return new Date(value);
482
+ }
483
+ return value;
484
+ default:
485
+ return value;
486
+ }
487
+ }
488
+ /**
489
+ * 테이블 순서 추출 (fixtures에 포함된 테이블만)
490
+ */ getTableOrder(fixtures) {
491
+ const tables = [];
492
+ const seen = new Set();
493
+ for (const fixture of fixtures){
494
+ const entity = EntityManager.get(fixture.entityId);
495
+ if (!seen.has(entity.table)) {
496
+ seen.add(entity.table);
497
+ tables.push(entity.table);
498
+ }
499
+ }
500
+ return tables;
501
+ }
502
+ async processManyToManyRelations(trx, fixtures, insertedIdsByTable) {
503
+ for (const fixture of fixtures){
504
+ const entity = EntityManager.get(fixture.entityId);
505
+ const sourceRef = this.fixtureRefMap.get(fixture.fixtureId);
506
+ if (!sourceRef) continue;
507
+ const sourceUuidToId = insertedIdsByTable.get(entity.table);
508
+ const sourceId = sourceUuidToId?.get(sourceRef.uuid);
509
+ if (sourceId === undefined) continue;
510
+ for (const [, column] of Object.entries(fixture.columns)){
511
+ const prop = column.prop;
512
+ if (isManyToManyRelationProp(prop) && Array.isArray(column.value)) {
513
+ // 선택되지 않은 ManyToMany 관계는 저장하지 않음
514
+ const targetTable = EntityManager.get(prop.with);
515
+ if (this.builder.hasTable(targetTable.table) === false) continue;
516
+ const relatedIds = column.value;
517
+ if (relatedIds.length === 0) continue;
518
+ const joinTable = prop.joinTable;
519
+ const relatedEntity = EntityManager.get(prop.with);
520
+ const sourceColumn = `${inflection.singularize(entity.table)}_id`;
521
+ const targetColumn = `${inflection.singularize(relatedEntity.table)}_id`;
522
+ for (const relatedId of relatedIds){
523
+ const relatedFixtureId = `${prop.with}#${relatedId}`;
524
+ const relatedRef = this.fixtureRefMap.get(relatedFixtureId);
525
+ let targetId;
526
+ if (relatedRef) {
527
+ const relatedUuidToId = insertedIdsByTable.get(relatedEntity.table);
528
+ const resolvedId = relatedUuidToId?.get(relatedRef.uuid);
529
+ if (resolvedId === undefined) {
530
+ console.warn(`Related fixture ${relatedFixtureId} not found in insertedIds, skipping`);
531
+ continue;
532
+ }
533
+ targetId = resolvedId;
534
+ } else {
535
+ targetId = relatedId;
536
+ }
537
+ // JoinTable에 삽입
538
+ const [found] = await trx(joinTable).where({
539
+ [sourceColumn]: sourceId,
540
+ [targetColumn]: targetId
541
+ }).limit(1);
542
+ if (!found) {
543
+ await trx(joinTable).insert({
544
+ [sourceColumn]: sourceId,
545
+ [targetColumn]: targetId
546
+ });
547
+ console.log(chalk.green(`Inserted into ${joinTable}: ${entity.table}(${sourceId}) - ${relatedEntity.table}(${targetId})`));
548
+ }
549
+ }
550
+ }
551
+ }
552
+ }
553
+ }
554
+ async checkUniqueViolation(db, entity, fixture) {
555
+ const _uniqueIndexes = entity.indexes?.filter((i)=>i.type === "unique") ?? [];
556
+ const uniqueIndexes = _uniqueIndexes.filter((index)=>index.columns.every((column)=>!column.startsWith(`${entity.table}__`)));
557
+ if (uniqueIndexes.length === 0) {
558
+ return null;
559
+ }
560
+ let uniqueQuery = db(entity.table);
561
+ let hasCondition = false;
562
+ for (const index of uniqueIndexes){
563
+ // 컬럼 중 하나라도 null이면 유니크 제약을 위반하지 않기 때문에 해당 인덱스는 무시
564
+ const containsNull = index.columns.some((column)=>{
565
+ const field = column.replace(/_id$/, "");
566
+ return fixture.columns[field]?.value === null;
567
+ });
568
+ if (containsNull) {
569
+ continue;
570
+ }
571
+ uniqueQuery = uniqueQuery.orWhere((qb)=>{
572
+ for (const column of index.columns){
573
+ const field = column.replace(/_id$/, "");
574
+ if (Array.isArray(fixture.columns[field]?.value)) {
575
+ qb.whereIn(column, fixture.columns[field].value);
576
+ } else {
577
+ qb.andWhere(column, fixture.columns[field]?.value);
578
+ }
579
+ }
580
+ });
581
+ hasCondition = true;
582
+ }
583
+ if (!hasCondition) {
584
+ return null;
585
+ }
586
+ const [uniqueFound] = await uniqueQuery;
587
+ return uniqueFound;
588
+ }
589
+ async checkDuplicateByColumns(db, entity, fixture, columns) {
590
+ if (columns.length === 0) {
591
+ return null;
592
+ }
593
+ const whereClause = {};
594
+ for (const column of columns){
595
+ // relation 필드인 경우 _id 붙이기
596
+ const prop = entity.props.find((p)=>p.name === column);
597
+ const dbColumn = prop && isRelationProp(prop) ? `${column}_id` : column;
598
+ const value = fixture.columns[column]?.value;
599
+ // null 값이 포함된 경우 중복 확인 스킵
600
+ if (value === null || value === undefined) {
601
+ return null;
602
+ }
603
+ whereClause[dbColumn] = value;
604
+ }
605
+ const [found] = await db(entity.table).where(whereClause).limit(1);
606
+ return found;
607
+ }
608
+ async addFixtureLoader(code) {
609
+ const path = `${Sonamu.apiRootPath}/src/testing/fixture.ts`;
610
+ const content = readFileSync(path).toString();
611
+ const fixtureLoaderStart = content.indexOf("const fixtureLoader = {");
612
+ const fixtureLoaderEnd = content.indexOf("};", fixtureLoaderStart);
613
+ if (fixtureLoaderStart !== -1 && fixtureLoaderEnd !== -1) {
614
+ const newContent = `${content.slice(0, fixtureLoaderEnd)} ${code}\n${content.slice(fixtureLoaderEnd)}`;
615
+ writeFileSync(path, newContent);
616
+ } else {
617
+ throw new Error("Failed to find fixtureLoader in fixture.ts");
618
+ }
619
+ }
620
+ }
621
+ export const FixtureManager = new FixtureManagerClass();
622
+
623
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0aW5nL2ZpeHR1cmUtbWFuYWdlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIjtcbmltcG9ydCB7IGV4ZWNTeW5jIH0gZnJvbSBcImNoaWxkX3Byb2Nlc3NcIjtcbmltcG9ydCB7IHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gXCJmc1wiO1xuaW1wb3J0IGluZmxlY3Rpb24gZnJvbSBcImluZmxlY3Rpb25cIjtcbmltcG9ydCBrbmV4LCB7IHR5cGUgS25leCB9IGZyb20gXCJrbmV4XCI7XG5pbXBvcnQgeyB1bmlxdWUgfSBmcm9tIFwicmFkYXNoaVwiO1xuaW1wb3J0IHsgaW5zcGVjdCB9IGZyb20gXCJ1dGlsXCI7XG5pbXBvcnQgeyBTb25hbXUgfSBmcm9tIFwiLi4vYXBpXCI7XG5pbXBvcnQgeyBCYXNlTW9kZWwgfSBmcm9tIFwiLi4vZGF0YWJhc2UvYmFzZS1tb2RlbFwiO1xuaW1wb3J0IHR5cGUgeyBTb25hbXVEQkNvbmZpZyB9IGZyb20gXCIuLi9kYXRhYmFzZS9kYlwiO1xuaW1wb3J0IHsgdHlwZSBVQlJlZiwgVXBzZXJ0QnVpbGRlciB9IGZyb20gXCIuLi9kYXRhYmFzZS91cHNlcnQtYnVpbGRlclwiO1xuaW1wb3J0IHR5cGUgeyBFbnRpdHkgfSBmcm9tIFwiLi4vZW50aXR5L2VudGl0eVwiO1xuaW1wb3J0IHsgRW50aXR5TWFuYWdlciB9IGZyb20gXCIuLi9lbnRpdHkvZW50aXR5LW1hbmFnZXJcIjtcbmltcG9ydCB7XG4gIHR5cGUgRW50aXR5UHJvcCxcbiAgdHlwZSBGaXh0dXJlSW1wb3J0UmVzdWx0LFxuICB0eXBlIEZpeHR1cmVSZWNvcmQsXG4gIHR5cGUgRml4dHVyZVNlYXJjaE9wdGlvbnMsXG4gIGlzQmVsb25nc1RvT25lUmVsYXRpb25Qcm9wLFxuICBpc0hhc01hbnlSZWxhdGlvblByb3AsXG4gIGlzTWFueVRvTWFueVJlbGF0aW9uUHJvcCxcbiAgaXNPbmVUb09uZVJlbGF0aW9uUHJvcCxcbiAgaXNSZWxhdGlvblByb3AsXG4gIGlzVmlydHVhbFByb3AsXG4gIHR5cGUgTWFueVRvTWFueVJlbGF0aW9uUHJvcCxcbn0gZnJvbSBcIi4uL3R5cGVzL3R5cGVzXCI7XG5pbXBvcnQgeyBSZWxhdGlvbkdyYXBoIH0gZnJvbSBcIi4vX3JlbGF0aW9uLWdyYXBoXCI7XG5cbi8qKiDsgqzsmqnsnpAg7KeA7KCVIOykkeuztSDtmZXsnbgg7Lus65+8IChlbnRpdHlJZOuzhOuhnCDsp4DsoJUpICovXG5leHBvcnQgaW50ZXJmYWNlIER1cGxpY2F0ZUNoZWNrT3B0aW9ucyB7XG4gIGNvbHVtbnM/OiB7XG4gICAgW2VudGl0eUlkOiBzdHJpbmddOiBzdHJpbmdbXTtcbiAgfTtcbn1cblxuZXhwb3J0IGNsYXNzIEZpeHR1cmVNYW5hZ2VyQ2xhc3Mge1xuICBwcml2YXRlIF90ZGI6IEtuZXggfCBudWxsID0gbnVsbDtcbiAgc2V0IHRkYih0ZGI6IEtuZXgpIHtcbiAgICB0aGlzLl90ZGIgPSB0ZGI7XG4gIH1cbiAgZ2V0IHRkYigpOiBLbmV4IHtcbiAgICBpZiAodGhpcy5fdGRiID09PSBudWxsKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJGaXh0dXJlTWFuYWdlciBoYXMgbm90IGJlZW4gaW5pdGlhbGl6ZWRcIik7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl90ZGI7XG4gIH1cblxuICBwcml2YXRlIF9mZGI6IEtuZXggfCBudWxsID0gbnVsbDtcbiAgc2V0IGZkYihmZGI6IEtuZXgpIHtcbiAgICB0aGlzLl9mZGIgPSBmZGI7XG4gIH1cbiAgZ2V0IGZkYigpOiBLbmV4IHtcbiAgICBpZiAodGhpcy5fZmRiID09PSBudWxsKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJGaXh0dXJlTWFuYWdlciBoYXMgbm90IGJlZW4gaW5pdGlhbGl6ZWRcIik7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9mZGI7XG4gIH1cbiAgY2FjaGVkVGFibGVOYW1lczogc3RyaW5nW10gfCBudWxsID0gbnVsbDtcblxuICBwcml2YXRlIHJlbGF0aW9uR3JhcGggPSBuZXcgUmVsYXRpb25HcmFwaCgpO1xuXG4gIC8vIFVwc2VydEJ1aWxkZXIg6riw67CYIGltcG9ydOulvCDsnITtlZwg7IOB7YOcXG4gIHByaXZhdGUgYnVpbGRlcjogVXBzZXJ0QnVpbGRlciA9IG5ldyBVcHNlcnRCdWlsZGVyKCk7XG4gIHByaXZhdGUgZml4dHVyZVJlZk1hcDogTWFwPHN0cmluZywgVUJSZWY+ID0gbmV3IE1hcCgpO1xuICBwcml2YXRlIHV1aWRUb0ZpeHR1cmVJZDogTWFwPHN0cmluZywgc3RyaW5nPiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBza2lwcGVkRml4dHVyZXM6IE1hcDxzdHJpbmcsIHsgZW50aXR5SWQ6IHN0cmluZzsgZXhpc3RpbmdJZDogbnVtYmVyIH0+ID0gbmV3IE1hcCgpO1xuXG4gIGluaXQoKSB7XG4gICAgaWYgKHRoaXMuX3RkYiAhPT0gbnVsbCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoU29uYW11LmRiQ29uZmlnLnRlc3QgJiYgU29uYW11LmRiQ29uZmlnLnByb2R1Y3Rpb25fbWFzdGVyKSB7XG4gICAgICBjb25zdCB0Q29ubiA9IFNvbmFtdS5kYkNvbmZpZy50ZXN0LmNvbm5lY3Rpb24gYXMgS25leC5Db25uZWN0aW9uQ29uZmlnICYge1xuICAgICAgICBwb3J0PzogbnVtYmVyO1xuICAgICAgfTtcbiAgICAgIGNvbnN0IHBDb25uID0gU29uYW11LmRiQ29uZmlnLnByb2R1Y3Rpb25fbWFzdGVyLmNvbm5lY3Rpb24gYXMgS25leC5Db25uZWN0aW9uQ29uZmlnICYge1xuICAgICAgICBwb3J0PzogbnVtYmVyO1xuICAgICAgfTtcbiAgICAgIGlmIChcbiAgICAgICAgYCR7dENvbm4uaG9zdCA/PyBcImxvY2FsaG9zdFwifToke3RDb25uLnBvcnQgPz8gNTQzMn0vJHt0Q29ubi5kYXRhYmFzZX1gID09PVxuICAgICAgICBgJHtwQ29ubi5ob3N0ID8/IFwibG9jYWxob3N0XCJ9OiR7cENvbm4ucG9ydCA/PyA1NDMyfS8ke3BDb25uLmRhdGFiYXNlfWBcbiAgICAgICkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYO2FjOyKpO2KuERC7JmAIO2UhOuhnOuNleyFmERC7JeQIOuPmeydvO2VnCDrjbDsnbTthLDrsqDsnbTsiqTqsIAg7IKs7Jqp65CY7JeI7Iq164uI64ukLmApO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMudGRiID0ga25leChTb25hbXUuZGJDb25maWcudGVzdCk7XG4gICAgdGhpcy5mZGIgPSBrbmV4KFNvbmFtdS5kYkNvbmZpZy5maXh0dXJlX3JlbW90ZSk7XG4gIH1cblxuICBhc3luYyBnZXRDaGVja3N1bShkYjogS25leCwgdGFibGVOYW1lOiBzdHJpbmcpIHtcbiAgICBjb25zdCBbW2NoZWNrc3VtUm93XV0gPSBhd2FpdCBkYi5yYXcoYENIRUNLU1VNIFRBQkxFICR7dGFibGVOYW1lfWApO1xuICAgIHJldHVybiBjaGVja3N1bVJvdy5DaGVja3N1bTtcbiAgfVxuXG4gIC8qKlxuICAgIOydtOygnCBGaXh0dXJlTWFuYWdlci5zeW5jKCkg64qUIGNoZWNrc3VtIOu5hOq1kCDsl4bsnbQgY3JlYXRlIGRhdGFiYXNlIHRlbXBsYXRlIOycvOuhnCDsiJjtlontlanri4jri6QuXG4gICovXG4gIGFzeW5jIHN5bmMoKSB7XG4gICAgY29uc3QgZml4dHVyZUNvbm4gPSBTb25hbXUuZGJDb25maWcuZml4dHVyZV9yZW1vdGUuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZztcbiAgICBjb25zdCB0ZXN0Q29ubiA9IFNvbmFtdS5kYkNvbmZpZy50ZXN0LmNvbm5lY3Rpb24gYXMgS25leC5QZ0Nvbm5lY3Rpb25Db25maWc7XG5cbiAgICAvLyBQb3N0Z3JlU1FMIO2MqOyKpOybjOuTnCDtmZjqsr3rs4DsiJgg7ISk7KCVXG4gICAgY29uc3QgcGdFbnYgPSB7IFBHUEFTU1dPUkQ6IHRlc3RDb25uLnBhc3N3b3JkIHx8IFwiXCIgfTtcblxuICAgIC8vIDEuIOyXsOqysCDqsJXsoJwg7KKF66OMXG4gICAgZXhlY1N5bmMoXG4gICAgICBgcHNxbCAtaCAke3Rlc3RDb25uLmhvc3R9IC1wICR7dGVzdENvbm4ucG9ydCA/PyA1NDMyfSAtVSAke3Rlc3RDb25uLnVzZXJ9IC1kIHBvc3RncmVzIC1jIFwiXG4gICAgICBTRUxFQ1QgcGdfdGVybWluYXRlX2JhY2tlbmQocGdfc3RhdF9hY3Rpdml0eS5waWQpXG4gICAgICBGUk9NIHBnX3N0YXRfYWN0aXZpdHlcbiAgICAgIFdIRVJFIGRhdG5hbWUgPSAnJHt0ZXN0Q29ubi5kYXRhYmFzZX0nXG4gICAgICAgIEFORCBwaWQgPD4gcGdfYmFja2VuZF9waWQoKTtcbiAgICBcImAsXG4gICAgICB7IHN0ZGlvOiBcImluaGVyaXRcIiwgZW52OiB7IC4uLnByb2Nlc3MuZW52LCAuLi5wZ0VudiB9IGFzIE5vZGVKUy5Qcm9jZXNzRW52IH0sXG4gICAgKTtcblxuICAgIGV4ZWNTeW5jKFxuICAgICAgYHBzcWwgLWggJHtmaXh0dXJlQ29ubi5ob3N0fSAtcCAke2ZpeHR1cmVDb25uLnBvcnQgPz8gNTQzMn0gLVUgJHtmaXh0dXJlQ29ubi51c2VyfSAtZCBwb3N0Z3JlcyAtYyBcIlxuICAgICAgICBTRUxFQ1QgcGdfdGVybWluYXRlX2JhY2tlbmQocGdfc3RhdF9hY3Rpdml0eS5waWQpXG4gICAgICAgIEZST00gcGdfc3RhdF9hY3Rpdml0eVxuICAgICAgICBXSEVSRSBkYXRuYW1lID0gJyR7Zml4dHVyZUNvbm4uZGF0YWJhc2V9J1xuICAgICAgICAgIEFORCBwaWQgPD4gcGdfYmFja2VuZF9waWQoKTtcbiAgICAgIFwiYCxcbiAgICAgIHsgc3RkaW86IFwiaW5oZXJpdFwiLCBlbnY6IHsgLi4ucHJvY2Vzcy5lbnYsIC4uLnBnRW52IH0gYXMgTm9kZUpTLlByb2Nlc3NFbnYgfSxcbiAgICApO1xuXG4gICAgLy8gMi4gRFJPUCBEQVRBQkFTRSAo67OE64+EIOyLpO2WiSEpXG4gICAgZXhlY1N5bmMoXG4gICAgICBgcHNxbCAtaCAke3Rlc3RDb25uLmhvc3R9IC1wICR7dGVzdENvbm4ucG9ydCA/PyA1NDMyfSAtVSAke3Rlc3RDb25uLnVzZXJ9IC1kIHBvc3RncmVzIC1jIFwiRFJPUCBEQVRBQkFTRSBJRiBFWElTVFMgXFxcXFwiJHt0ZXN0Q29ubi5kYXRhYmFzZX1cXFxcXCJcImAsXG4gICAgICB7IHN0ZGlvOiBcImluaGVyaXRcIiwgZW52OiB7IC4uLnByb2Nlc3MuZW52LCAuLi5wZ0VudiB9IGFzIE5vZGVKUy5Qcm9jZXNzRW52IH0sXG4gICAgKTtcblxuICAgIC8vIDMuIENSRUFURSBEQVRBQkFTRVxuICAgIGV4ZWNTeW5jKFxuICAgICAgYHBzcWwgLWggJHt0ZXN0Q29ubi5ob3N0fSAtcCAke3Rlc3RDb25uLnBvcnQgPz8gNTQzMn0gLVUgJHt0ZXN0Q29ubi51c2VyfSAtZCBwb3N0Z3JlcyAtYyBcIkNSRUFURSBEQVRBQkFTRSBcXFxcXCIke3Rlc3RDb25uLmRhdGFiYXNlfVxcXFxcIiBURU1QTEFURSBcXFxcXCIke2ZpeHR1cmVDb25uLmRhdGFiYXNlfVxcXFxcIlwiYCxcbiAgICAgIHsgc3RkaW86IFwiaW5oZXJpdFwiLCBlbnY6IHsgLi4ucHJvY2Vzcy5lbnYsIC4uLnBnRW52IH0gYXMgTm9kZUpTLlByb2Nlc3NFbnYgfSxcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSB2aXNpdGVkUmVjb3JkcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBhc3luYyBpbXBvcnRGaXh0dXJlKGVudGl0eUlkOiBzdHJpbmcsIGlkczogbnVtYmVyW10pIHtcbiAgICAvLyDrsKnrrLgg6riw66GdIOy0iOq4sO2ZlCAo7IOI66Gc7Jq0IGltcG9ydCDsnpHsl4Ug7Iuc7J6RKVxuICAgIHRoaXMudmlzaXRlZFJlY29yZHMuY2xlYXIoKTtcblxuICAgIGNvbnN0IHF1ZXJpZXMgPSB1bmlxdWUoXG4gICAgICAoXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICAgIGlkcy5tYXAoYXN5bmMgKGlkKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5nZXRJbXBvcnRRdWVyaWVzKGVudGl0eUlkLCBcImlkXCIsIGlkKTtcbiAgICAgICAgICB9KSxcbiAgICAgICAgKVxuICAgICAgKS5mbGF0KCksXG4gICAgKTtcblxuICAgIGNvbnN0IHdkYiA9IEJhc2VNb2RlbC5nZXREQihcIndcIik7XG4gICAgZm9yIChjb25zdCBxdWVyeSBvZiBxdWVyaWVzKSB7XG4gICAgICBjb25zdCBbcnNoXSA9IGF3YWl0IHdkYi5yYXcocXVlcnkpO1xuICAgICAgY29uc29sZS5sb2coe1xuICAgICAgICBxdWVyeSxcbiAgICAgICAgaW5mbzogcnNoLmluZm8sXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBnZXRJbXBvcnRRdWVyaWVzKGVudGl0eUlkOiBzdHJpbmcsIGZpZWxkOiBzdHJpbmcsIGlkOiBudW1iZXIpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgY29uc3QgcmVjb3JkS2V5ID0gYCR7ZW50aXR5SWR9IyR7ZmllbGR9IyR7aWR9YDtcblxuICAgIC8vIOyInO2ZmCDssLjsobAg67Cp7KeAOiDsnbTrr7gg67Cp66y47ZWcIOugiOy9lOuTnOuKlCDsiqTtgrVcbiAgICBpZiAodGhpcy52aXNpdGVkUmVjb3Jkcy5oYXMocmVjb3JkS2V5KSkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgICB0aGlzLnZpc2l0ZWRSZWNvcmRzLmFkZChyZWNvcmRLZXkpO1xuXG4gICAgY29uc29sZS5sb2coeyBlbnRpdHlJZCwgZmllbGQsIGlkIH0pO1xuICAgIGNvbnN0IGVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKTtcbiAgICBjb25zdCB3ZGIgPSBCYXNlTW9kZWwuZ2V0REIoXCJ3XCIpO1xuXG4gICAgLy8g7Jes6riw7IScIOyLpERC7J2YIHJvdyDqsIDsoLjsmLRcbiAgICBjb25zdCBbcm93XSA9IGF3YWl0IHdkYihlbnRpdHkudGFibGUpLndoZXJlKGZpZWxkLCBpZCkubGltaXQoMSk7XG4gICAgaWYgKHJvdyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7ZW50aXR5SWR9IyR7aWR9IHJvd+ulvCDssL7snYQg7IiYIOyXhuyKteuLiOuLpC5gKTtcbiAgICB9XG5cbiAgICAvLyDtlL3siqTss5BEQiwg7IukREJcbiAgICBjb25zdCBmaXh0dXJlRGF0YWJhc2UgPSAoU29uYW11LmRiQ29uZmlnLmZpeHR1cmVfcmVtb3RlLmNvbm5lY3Rpb24gYXMgS25leC5Db25uZWN0aW9uQ29uZmlnKVxuICAgICAgLmRhdGFiYXNlO1xuICAgIGNvbnN0IHJlYWxEYXRhYmFzZSA9IChTb25hbXUuZGJDb25maWcucHJvZHVjdGlvbl9tYXN0ZXIuY29ubmVjdGlvbiBhcyBLbmV4LkNvbm5lY3Rpb25Db25maWcpXG4gICAgICAuZGF0YWJhc2U7XG5cbiAgICBjb25zdCBzZWxmUXVlcnkgPSBgSU5TRVJUIElHTk9SRSBJTlRPIFxcYCR7Zml4dHVyZURhdGFiYXNlfVxcYC5cXGAke2VudGl0eS50YWJsZX1cXGAgKFNFTEVDVCAqIEZST00gXFxgJHtyZWFsRGF0YWJhc2V9XFxgLlxcYCR7ZW50aXR5LnRhYmxlfVxcYCBXSEVSRSBcXGBpZFxcYCA9ICR7aWR9KWA7XG5cbiAgICBjb25zdCBhcmdzID0gT2JqZWN0LmVudHJpZXMoZW50aXR5LnJlbGF0aW9ucylcbiAgICAgIC5maWx0ZXIoXG4gICAgICAgIChbLCByZWxhdGlvbl0pID0+XG4gICAgICAgICAgaXNCZWxvbmdzVG9PbmVSZWxhdGlvblByb3AocmVsYXRpb24pIHx8XG4gICAgICAgICAgKGlzT25lVG9PbmVSZWxhdGlvblByb3AocmVsYXRpb24pICYmIHJlbGF0aW9uLmN1c3RvbUpvaW5DbGF1c2UgPT09IHVuZGVmaW5lZCksXG4gICAgICApXG4gICAgICAubWFwKChbLCByZWxhdGlvbl0pID0+IHtcbiAgICAgICAgLypcbiAgICAgICAgQmVsb25nc1RvT25l7J24IOqyveyasFxuICAgICAgICAgIENhdGVnb3J5IC8gJ2lkJyAvIHJvd1tjYXRlZ29yeV9pZF0g7Zi47LacXG4gICAgICAgIE9uZVRvT25l7JeQIGpvaW5Db2x1bW4gPT09IHRydWUg7J24IOqyveyasFxuICAgICAgICAgIFByb2ZpbGUgLyAnaWQnIC8gcm93W3Byb2ZpbGVfaWRdIO2YuOy2nFxuICAgICAgICBPbmVUb09uZeyXkCBqb2luQ29sdW1uID09PSBmYWxzZSDsnbgg6rK97JqwXG4gICAgICAgICAgUHJvZmlsZSAvICdwcm9maWxlX2lkJyAvIHJvd1snaWQnXSDtmLjstpxcbiAgICAgICAgKi9cbiAgICAgICAgbGV0IGZpZWxkOiBzdHJpbmc7XG4gICAgICAgIGxldCBpZDogbnVtYmVyO1xuICAgICAgICBpZiAoaXNPbmVUb09uZVJlbGF0aW9uUHJvcChyZWxhdGlvbikgJiYgIXJlbGF0aW9uLmhhc0pvaW5Db2x1bW4pIHtcbiAgICAgICAgICBjb25zdCByZWxhdGVkRW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQocmVsYXRpb24ud2l0aCk7XG4gICAgICAgICAgY29uc3QgcmVsYXRlZElkQ29sdW1uTmFtZSA9IHJlbGF0ZWRFbnRpdHkucHJvcHMuZmluZChcbiAgICAgICAgICAgIChwKSA9PiBpc1JlbGF0aW9uUHJvcChwKSAmJiBwLndpdGggPT09IGVudGl0eS5pZCxcbiAgICAgICAgICApPy5uYW1lO1xuICAgICAgICAgIGlmICghcmVsYXRlZElkQ29sdW1uTmFtZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke3JlbGF0ZWRFbnRpdHkuaWR97J2YICR7ZW50aXR5LmlkfSDqtIDqs4Qg7ZSE66Gt7J2EIOywvuydhCDsiJgg7JeG7Iq164uI64ukLmApO1xuICAgICAgICAgIH1cbiAgICAgICAgICBmaWVsZCA9IGAke3JlbGF0ZWRJZENvbHVtbk5hbWV9X2lkYDtcbiAgICAgICAgICBpZCA9IHJvdy5pZDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBmaWVsZCA9IFwiaWRcIjtcbiAgICAgICAgICBpZCA9IHJvd1tgJHtyZWxhdGlvbi5uYW1lfV9pZGBdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZW50aXR5SWQ6IHJlbGF0aW9uLndpdGgsXG4gICAgICAgICAgZmllbGQsXG4gICAgICAgICAgaWQsXG4gICAgICAgIH07XG4gICAgICB9KVxuICAgICAgLmZpbHRlcigoYXJnKSA9PiBhcmcuaWQgIT09IG51bGwpO1xuXG4gICAgY29uc3QgcmVsUXVlcmllcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgYXJncy5tYXAoYXN5bmMgKGFyZ3MpID0+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0SW1wb3J0UXVlcmllcyhhcmdzLmVudGl0eUlkLCBhcmdzLmZpZWxkLCBhcmdzLmlkKTtcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICByZXR1cm4gWy4uLnVuaXF1ZShyZWxRdWVyaWVzLnJldmVyc2UoKS5mbGF0KCkpLCBzZWxmUXVlcnldO1xuICB9XG5cbiAgYXN5bmMgZGVzdHJveSgpIHtcbiAgICBpZiAodGhpcy5fdGRiKSB7XG4gICAgICBhd2FpdCB0aGlzLl90ZGIuZGVzdHJveSgpO1xuICAgICAgdGhpcy5fdGRiID0gbnVsbDtcbiAgICB9XG4gICAgaWYgKHRoaXMuX2ZkYikge1xuICAgICAgYXdhaXQgdGhpcy5fZmRiLmRlc3Ryb3koKTtcbiAgICAgIHRoaXMuX2ZkYiA9IG51bGw7XG4gICAgfVxuICAgIGF3YWl0IEJhc2VNb2RlbC5kZXN0cm95KCk7XG4gIH1cblxuICBhc3luYyBnZXRGaXh0dXJlcyhcbiAgICBzb3VyY2VEQk5hbWU6IGtleW9mIFNvbmFtdURCQ29uZmlnLFxuICAgIHRhcmdldERCTmFtZToga2V5b2YgU29uYW11REJDb25maWcsXG4gICAgc2VhcmNoT3B0aW9uczogRml4dHVyZVNlYXJjaE9wdGlvbnMsXG4gICAgZHVwbGljYXRlQ2hlY2s/OiBEdXBsaWNhdGVDaGVja09wdGlvbnMsXG4gICkge1xuICAgIGNvbnN0IHNvdXJjZURCID0ga25leChTb25hbXUuZGJDb25maWdbc291cmNlREJOYW1lXSk7XG4gICAgY29uc3QgdGFyZ2V0REIgPSBrbmV4KFNvbmFtdS5kYkNvbmZpZ1t0YXJnZXREQk5hbWVdKTtcblxuICAgIGNvbnN0IHsgZW50aXR5SWQsIGZpZWxkLCB2YWx1ZSwgc2VhcmNoVHlwZSB9ID0gc2VhcmNoT3B0aW9ucztcblxuICAgIGNvbnN0IGVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKTtcbiAgICBjb25zdCBjb2x1bW4gPVxuICAgICAgZW50aXR5LnByb3BzLmZpbmQoKHByb3ApID0+IHByb3AubmFtZSA9PT0gZmllbGQpPy50eXBlID09PSBcInJlbGF0aW9uXCIgPyBgJHtmaWVsZH1faWRgIDogZmllbGQ7XG5cbiAgICBsZXQgcXVlcnkgPSBzb3VyY2VEQihlbnRpdHkudGFibGUpO1xuICAgIGlmIChzZWFyY2hUeXBlID09PSBcImVxdWFsc1wiKSB7XG4gICAgICBxdWVyeSA9IHF1ZXJ5LndoZXJlKGNvbHVtbiwgdmFsdWUpO1xuICAgIH0gZWxzZSBpZiAoc2VhcmNoVHlwZSA9PT0gXCJsaWtlXCIpIHtcbiAgICAgIHF1ZXJ5ID0gcXVlcnkud2hlcmUoY29sdW1uLCBcImxpa2VcIiwgYCUke3ZhbHVlfSVgKTtcbiAgICB9XG5cbiAgICBjb25zdCByb3dzID0gYXdhaXQgcXVlcnk7XG4gICAgaWYgKHJvd3MubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJObyByZWNvcmRzIGZvdW5kXCIpO1xuICAgIH1cblxuICAgIGNvbnN0IGZpeHR1cmVzOiBGaXh0dXJlUmVjb3JkW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IHJvdyBvZiByb3dzKSB7XG4gICAgICBjb25zdCBpbml0aWFsUmVjb3Jkc0xlbmd0aCA9IGZpeHR1cmVzLmxlbmd0aDtcbiAgICAgIGNvbnN0IG5ld1JlY29yZHMgPSBhd2FpdCB0aGlzLmNyZWF0ZUZpeHR1cmVSZWNvcmQoZW50aXR5LCByb3csIHtcbiAgICAgICAgX2RiOiBzb3VyY2VEQixcbiAgICAgIH0pO1xuICAgICAgZml4dHVyZXMucHVzaCguLi5uZXdSZWNvcmRzKTtcbiAgICAgIGNvbnN0IGN1cnJlbnRGaXh0dXJlUmVjb3JkID0gZml4dHVyZXMuZmluZCgocikgPT4gci5maXh0dXJlSWQgPT09IGAke2VudGl0eUlkfSMke3Jvdy5pZH1gKTtcblxuICAgICAgaWYgKGN1cnJlbnRGaXh0dXJlUmVjb3JkKSB7XG4gICAgICAgIC8vIO2YhOyerCBmaXh0dXJl66Gc67aA7YSwIOyDneyEseuQnCBmZXRjaGVkUmVjb3JkcyDshKTsoJVcbiAgICAgICAgY3VycmVudEZpeHR1cmVSZWNvcmQuZmV0Y2hlZFJlY29yZHMgPSBmaXh0dXJlc1xuICAgICAgICAgIC5maWx0ZXIoKHIpID0+IHIuZml4dHVyZUlkICE9PSBjdXJyZW50Rml4dHVyZVJlY29yZC5maXh0dXJlSWQpXG4gICAgICAgICAgLnNsaWNlKGluaXRpYWxSZWNvcmRzTGVuZ3RoKVxuICAgICAgICAgIC5tYXAoKHIpID0+IHIuZml4dHVyZUlkKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgYXdhaXQgKGNvbnN0IGZpeHR1cmUgb2YgZml4dHVyZXMpIHtcbiAgICAgIGNvbnN0IGVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KGZpeHR1cmUuZW50aXR5SWQpO1xuXG4gICAgICAvLyDsgqzsmqnsnpAg7KeA7KCVIOy7rOufvCDquLDspIAg7KSR67O1IO2ZleyduCDihpIgdGFyZ2V0XG4gICAgICBjb25zdCBjdXN0b21Db2x1bW5zID0gZHVwbGljYXRlQ2hlY2s/LmNvbHVtbnM/LltmaXh0dXJlLmVudGl0eUlkXTtcbiAgICAgIGlmIChjdXN0b21Db2x1bW5zICYmIGN1c3RvbUNvbHVtbnMubGVuZ3RoID4gMCkge1xuICAgICAgICBjb25zdCBjdXN0b21EdXBsaWNhdGVSb3cgPSBhd2FpdCB0aGlzLmNoZWNrRHVwbGljYXRlQnlDb2x1bW5zKFxuICAgICAgICAgIHRhcmdldERCLFxuICAgICAgICAgIGVudGl0eSxcbiAgICAgICAgICBmaXh0dXJlLFxuICAgICAgICAgIGN1c3RvbUNvbHVtbnMsXG4gICAgICAgICk7XG4gICAgICAgIGlmIChjdXN0b21EdXBsaWNhdGVSb3cpIHtcbiAgICAgICAgICBjb25zdCBbcmVjb3JkXSA9IGF3YWl0IHRoaXMuY3JlYXRlRml4dHVyZVJlY29yZChlbnRpdHksIGN1c3RvbUR1cGxpY2F0ZVJvdywge1xuICAgICAgICAgICAgc2luZ2xlUmVjb3JkOiB0cnVlLFxuICAgICAgICAgICAgX2RiOiB0YXJnZXREQixcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBmaXh0dXJlLnRhcmdldCA9IHJlY29yZDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBVbmlxdWUgaW5kZXgg6riw7KSAIOykkeuztSDtmZXsnbgg4oaSIGZpeHR1cmUudW5pcXVlXG4gICAgICBjb25zdCB1bmlxdWVSb3cgPSBhd2FpdCB0aGlzLmNoZWNrVW5pcXVlVmlvbGF0aW9uKHRhcmdldERCLCBlbnRpdHksIGZpeHR1cmUpO1xuICAgICAgaWYgKHVuaXF1ZVJvdykge1xuICAgICAgICBjb25zdCBbcmVjb3JkXSA9IGF3YWl0IHRoaXMuY3JlYXRlRml4dHVyZVJlY29yZChlbnRpdHksIHVuaXF1ZVJvdywge1xuICAgICAgICAgIHNpbmdsZVJlY29yZDogdHJ1ZSxcbiAgICAgICAgICBfZGI6IHRhcmdldERCLFxuICAgICAgICB9KTtcbiAgICAgICAgZml4dHVyZS51bmlxdWUgPSByZWNvcmQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgYXdhaXQgdGFyZ2V0REIuZGVzdHJveSgpO1xuICAgIGF3YWl0IHNvdXJjZURCLmRlc3Ryb3koKTtcblxuICAgIHJldHVybiB1bmlxdWUoZml4dHVyZXMsIChmKSA9PiBmLmZpeHR1cmVJZCk7XG4gIH1cblxuICBhc3luYyBjcmVhdGVGaXh0dXJlUmVjb3JkKFxuICAgIGVudGl0eTogRW50aXR5LFxuICAgIHJvdzoge1xuICAgICAgaWQ6IG51bWJlcjtcbiAgICAgIFtrZXk6IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBudWxsO1xuICAgIH0sXG4gICAgb3B0aW9ucz86IHtcbiAgICAgIHNpbmdsZVJlY29yZD86IGJvb2xlYW47XG4gICAgICBfZGI/OiBLbmV4O1xuICAgIH0sXG4gICk6IFByb21pc2U8Rml4dHVyZVJlY29yZFtdPiB7XG4gICAgY29uc3QgcmVjb3JkczogRml4dHVyZVJlY29yZFtdID0gW107XG4gICAgY29uc3QgdmlzaXRlZEVudGl0aWVzID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgICBjb25zdCBjcmVhdGUgPSBhc3luYyAoXG4gICAgICBlbnRpdHk6IEVudGl0eSxcbiAgICAgIHJvdzoge1xuICAgICAgICBpZDogbnVtYmVyO1xuICAgICAgICBba2V5OiBzdHJpbmddOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgbnVsbDtcbiAgICAgIH0sXG4gICAgKSA9PiB7XG4gICAgICBjb25zdCBmaXh0dXJlSWQgPSBgJHtlbnRpdHkuaWR9IyR7cm93LmlkfWA7XG4gICAgICBpZiAodmlzaXRlZEVudGl0aWVzLmhhcyhmaXh0dXJlSWQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHZpc2l0ZWRFbnRpdGllcy5hZGQoZml4dHVyZUlkKTtcblxuICAgICAgY29uc3QgcmVjb3JkOiBGaXh0dXJlUmVjb3JkID0ge1xuICAgICAgICBmaXh0dXJlSWQsXG4gICAgICAgIGVudGl0eUlkOiBlbnRpdHkuaWQsXG4gICAgICAgIGlkOiByb3cuaWQsXG4gICAgICAgIGNvbHVtbnM6IHt9LFxuICAgICAgICBmZXRjaGVkUmVjb3JkczogW10sXG4gICAgICAgIGJlbG9uZ3NSZWNvcmRzOiBbXSxcbiAgICAgIH07XG5cbiAgICAgIGZvciAoY29uc3QgcHJvcCBvZiBlbnRpdHkucHJvcHMpIHtcbiAgICAgICAgaWYgKGlzVmlydHVhbFByb3AocHJvcCkpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlY29yZC5jb2x1bW5zW3Byb3AubmFtZV0gPSB7XG4gICAgICAgICAgcHJvcDogcHJvcCxcbiAgICAgICAgICB2YWx1ZTogcm93W3Byb3AubmFtZV0sXG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgZGIgPSBvcHRpb25zPy5fZGIgPz8gQmFzZU1vZGVsLmdldERCKFwid1wiKTtcbiAgICAgICAgaWYgKGlzTWFueVRvTWFueVJlbGF0aW9uUHJvcChwcm9wKSkge1xuICAgICAgICAgIGNvbnN0IHJlbGF0ZWRFbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChwcm9wLndpdGgpO1xuICAgICAgICAgIGNvbnN0IHRocm91Z2hUYWJsZSA9IHByb3Auam9pblRhYmxlO1xuICAgICAgICAgIGNvbnN0IGZyb21Db2x1bW4gPSBgJHtpbmZsZWN0aW9uLnNpbmd1bGFyaXplKGVudGl0eS50YWJsZSl9X2lkYDtcbiAgICAgICAgICBjb25zdCB0b0NvbHVtbiA9IGAke2luZmxlY3Rpb24uc2luZ3VsYXJpemUocmVsYXRlZEVudGl0eS50YWJsZSl9X2lkYDtcblxuICAgICAgICAgIGNvbnN0IHJlbGF0ZWRJZHMgPSBhd2FpdCBkYih0aHJvdWdoVGFibGUpLndoZXJlKGZyb21Db2x1bW4sIHJvdy5pZCkucGx1Y2sodG9Db2x1bW4pO1xuICAgICAgICAgIHJlY29yZC5jb2x1bW5zW3Byb3AubmFtZV0udmFsdWUgPSByZWxhdGVkSWRzO1xuICAgICAgICB9IGVsc2UgaWYgKGlzSGFzTWFueVJlbGF0aW9uUHJvcChwcm9wKSkge1xuICAgICAgICAgIGNvbnN0IHJlbGF0ZWRFbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChwcm9wLndpdGgpO1xuICAgICAgICAgIGNvbnN0IHJlbGF0ZWRJZHMgPSBhd2FpdCBkYihyZWxhdGVkRW50aXR5LnRhYmxlKVxuICAgICAgICAgICAgLndoZXJlKHByb3Auam9pbkNvbHVtbiwgcm93LmlkKVxuICAgICAgICAgICAgLnBsdWNrKFwiaWRcIik7XG4gICAgICAgICAgcmVjb3JkLmNvbHVtbnNbcHJvcC5uYW1lXS52YWx1ZSA9IHJlbGF0ZWRJZHM7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNPbmVUb09uZVJlbGF0aW9uUHJvcChwcm9wKSAmJiAhcHJvcC5oYXNKb2luQ29sdW1uKSB7XG4gICAgICAgICAgY29uc3QgcmVsYXRlZEVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KHByb3Aud2l0aCk7XG4gICAgICAgICAgY29uc3QgcmVsYXRlZFByb3AgPSByZWxhdGVkRW50aXR5LnByb3BzLmZpbmQoXG4gICAgICAgICAgICAocCkgPT4gaXNSZWxhdGlvblByb3AocCkgJiYgcC53aXRoID09PSBlbnRpdHkuaWQsXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAocmVsYXRlZFByb3ApIHtcbiAgICAgICAgICAgIGNvbnN0IHJlbGF0ZWRSb3cgPSBhd2FpdCBkYihyZWxhdGVkRW50aXR5LnRhYmxlKS53aGVyZShcImlkXCIsIHJvdy5pZCkuZmlyc3QoKTtcbiAgICAgICAgICAgIHJlY29yZC5jb2x1bW5zW3Byb3AubmFtZV0udmFsdWUgPSByZWxhdGVkUm93Py5pZDtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoaXNSZWxhdGlvblByb3AocHJvcCkpIHtcbiAgICAgICAgICBjb25zdCByZWxhdGVkSWQgPSByb3dbYCR7cHJvcC5uYW1lfV9pZGBdO1xuICAgICAgICAgIHJlY29yZC5jb2x1bW5zW3Byb3AubmFtZV0udmFsdWUgPSByZWxhdGVkSWQ7XG4gICAgICAgICAgaWYgKHJlbGF0ZWRJZCkge1xuICAgICAgICAgICAgcmVjb3JkLmJlbG9uZ3NSZWNvcmRzLnB1c2goYCR7cHJvcC53aXRofSMke3JlbGF0ZWRJZH1gKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKCFvcHRpb25zPy5zaW5nbGVSZWNvcmQgJiYgcmVsYXRlZElkKSB7XG4gICAgICAgICAgICBjb25zdCByZWxhdGVkRW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQocHJvcC53aXRoKTtcbiAgICAgICAgICAgIGNvbnN0IHJlbGF0ZWRSb3cgPSBhd2FpdCBkYihyZWxhdGVkRW50aXR5LnRhYmxlKS53aGVyZShcImlkXCIsIHJlbGF0ZWRJZCkuZmlyc3QoKTtcbiAgICAgICAgICAgIGlmIChyZWxhdGVkUm93KSB7XG4gICAgICAgICAgICAgIGF3YWl0IGNyZWF0ZShyZWxhdGVkRW50aXR5LCByZWxhdGVkUm93KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmVjb3Jkcy5wdXNoKHJlY29yZCk7XG4gICAgfTtcblxuICAgIGF3YWl0IGNyZWF0ZShlbnRpdHksIHJvdyk7XG5cbiAgICByZXR1cm4gcmVjb3JkcztcbiAgfVxuXG4gIC8qKlxuICAgKiAxLiBSZWxhdGlvbkdyYXBo66GcIGZpeHR1cmUg64uo7JyEIOyCveyehSDsiJzshJwg6rOE7IKwIChzZWxmLXJlZmVyZW5jZSDtj6ztlagpXG4gICAqIDIuIOyInOyEnOuMgOuhnCBVcHNlcnRCdWlsZGVy7JeQIOuTseuhnSAoVUJSZWbroZwg7LC47KGwIOq0gOqzhCDtkZztmIQpXG4gICAqIDMuIO2FjOydtOu4lOuzhCB1cHNlcnQg7Iuk7ZaJIChJROuKlCBEQuqwgCDsnpDrj5kg7ZWg64u5KVxuICAgKi9cbiAgYXN5bmMgaW5zZXJ0Rml4dHVyZXMoXG4gICAgZGJOYW1lOiBrZXlvZiBTb25hbXVEQkNvbmZpZyxcbiAgICBfZml4dHVyZXM6IEZpeHR1cmVSZWNvcmRbXSxcbiAgKTogUHJvbWlzZTxGaXh0dXJlSW1wb3J0UmVzdWx0W10+IHtcbiAgICBjb25zdCBmaXh0dXJlcyA9IHVuaXF1ZShfZml4dHVyZXMsIChmKSA9PiBmLmZpeHR1cmVJZCk7XG5cbiAgICAvLyDstIjquLDtmZRcbiAgICB0aGlzLmJ1aWxkZXIgPSBuZXcgVXBzZXJ0QnVpbGRlcigpO1xuICAgIHRoaXMuZml4dHVyZVJlZk1hcCA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLnV1aWRUb0ZpeHR1cmVJZCA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLnNraXBwZWRGaXh0dXJlcyA9IG5ldyBNYXAoKTtcblxuICAgIGNvbnN0IGRiID0ga25leChTb25hbXUuZGJDb25maWdbZGJOYW1lXSk7XG4gICAgY29uc3QgcmVzdWx0czogRml4dHVyZUltcG9ydFJlc3VsdFtdID0gW107XG5cbiAgICB0cnkge1xuICAgICAgLy8gMS4gUmVsYXRpb25HcmFwaOuhnCBmaXh0dXJlIOuLqOychCDsgr3snoUg7Iic7IScIOqzhOyCsFxuICAgICAgdGhpcy5yZWxhdGlvbkdyYXBoLmJ1aWxkR3JhcGgoZml4dHVyZXMpO1xuICAgICAgY29uc3QgaW5zZXJ0aW9uT3JkZXIgPSB0aGlzLnJlbGF0aW9uR3JhcGguZ2V0SW5zZXJ0aW9uT3JkZXIoKTtcblxuICAgICAgLy8gMi4g7Iic7ISc64yA66GcIFVwc2VydEJ1aWxkZXLsl5Ag65Ox66GdIChvdmVycmlkZSDssrTtgawpXG4gICAgICBmb3IgKGNvbnN0IGZpeHR1cmVJZCBvZiBpbnNlcnRpb25PcmRlcikge1xuICAgICAgICBjb25zdCBmaXh0dXJlID0gZml4dHVyZXMuZmluZCgoZikgPT4gZi5maXh0dXJlSWQgPT09IGZpeHR1cmVJZCk7XG4gICAgICAgIGlmICghZml4dHVyZSkgY29udGludWU7XG5cbiAgICAgICAgY29uc3QgaGFzVGFyZ2V0ID0gISFmaXh0dXJlLnRhcmdldDtcbiAgICAgICAgY29uc3QgaGFzVW5pcXVlID0gISFmaXh0dXJlLnVuaXF1ZTtcbiAgICAgICAgY29uc3QgaGFzRHVwbGljYXRlID0gaGFzVGFyZ2V0IHx8IGhhc1VuaXF1ZTtcblxuICAgICAgICAvLyDspJHrs7XsnbQg7J6I6rOgIG92ZXJyaWRlPWZhbHNl7J24IOqyveyasDog7Iqk7YK1XG4gICAgICAgIGlmIChoYXNEdXBsaWNhdGUgJiYgIWZpeHR1cmUub3ZlcnJpZGUpIHtcbiAgICAgICAgICAvLyDquLDsobQg66CI7L2U65OcIElEIOyggOyepSAodW5pcXVlIOyasOyEoCwg7JeG7Jy866m0IHRhcmdldClcbiAgICAgICAgICBjb25zdCBleGlzdGluZ0lkID0gZml4dHVyZS51bmlxdWU/LmlkID8/IGZpeHR1cmUudGFyZ2V0Py5pZDtcbiAgICAgICAgICBhc3NlcnQoZXhpc3RpbmdJZCk7XG4gICAgICAgICAgdGhpcy5za2lwcGVkRml4dHVyZXMuc2V0KGZpeHR1cmVJZCwge1xuICAgICAgICAgICAgZW50aXR5SWQ6IGZpeHR1cmUuZW50aXR5SWQsXG4gICAgICAgICAgICBleGlzdGluZ0lkLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICBjaGFsay55ZWxsb3coXG4gICAgICAgICAgICAgIGBTa2lwcGVkICR7Zml4dHVyZS5lbnRpdHlJZH0jJHtmaXh0dXJlLmlkfSAoZXhpc3Rpbmc6ICMke2V4aXN0aW5nSWR9LCBvdmVycmlkZTogZmFsc2UpYCxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVnaXN0ZXJGaXh0dXJlKGZpeHR1cmUpO1xuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICBjaGFsay5ibHVlKFxuICAgICAgICAgICAgYFJlZ2lzdGVyZWQgJHtmaXh0dXJlLmVudGl0eUlkfSMke2ZpeHR1cmUuaWR9JHtmaXh0dXJlLm92ZXJyaWRlID8gYCAob3ZlcnJpZGUgZXhpc3Rpbmc6ICMke2ZpeHR1cmUudGFyZ2V0Py5pZH0pYCA6IFwiXCJ9YCxcbiAgICAgICAgICApLFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyAzLiDthYzsnbTruJTrs4QgdXBzZXJ0IOyLpO2WiVxuICAgICAgY29uc3QgdGFibGVPcmRlciA9IHRoaXMuZ2V0VGFibGVPcmRlcihmaXh0dXJlcyk7XG5cbiAgICAgIGF3YWl0IGRiLnRyYW5zYWN0aW9uKGFzeW5jICh0cngpID0+IHtcbiAgICAgICAgY29uc3QgaW5zZXJ0ZWRJZHNCeVRhYmxlID0gbmV3IE1hcDxzdHJpbmcsIE1hcDxzdHJpbmcsIG51bWJlcj4+KCk7XG5cbiAgICAgICAgZm9yIChjb25zdCB0YWJsZU5hbWUgb2YgdGFibGVPcmRlcikge1xuICAgICAgICAgIGlmICghdGhpcy5idWlsZGVyLmhhc1RhYmxlKHRhYmxlTmFtZSkpIGNvbnRpbnVlO1xuXG4gICAgICAgICAgLy8gdXBzZXJ0IOyLpO2WiSDsoIQgdXVpZCDrqqnroZ0g7KCA7J6lXG4gICAgICAgICAgY29uc3QgdGFibGUgPSB0aGlzLmJ1aWxkZXIuZ2V0VGFibGUodGFibGVOYW1lKTtcbiAgICAgICAgICBjb25zdCB1dWlkcyA9IHRhYmxlLnJvd3MubWFwKChyb3cpID0+IHJvdy51dWlkIGFzIHN0cmluZyk7XG5cbiAgICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5ibHVlKGBVcHNlcnRpbmcgJHt0YWJsZU5hbWV9IHdpdGggJHt1dWlkcy5sZW5ndGh9IHJvd3NgKSk7XG4gICAgICAgICAgYXdhaXQgdGhpcy5idWlsZGVyLnVwc2VydCh0cngsIHRhYmxlTmFtZSk7XG5cbiAgICAgICAgICAvLyB1cHNlcnTrkJwgcm9365Ok7J2YIHV1aWQgLT4gaWQg66ek7ZWRIOq1rOy2lVxuICAgICAgICAgIGlmICh1dWlkcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBjb25zdCB1dWlkVG9JZCA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG4gICAgICAgICAgICBjb25zdCByb3dzID0gYXdhaXQgdHJ4KHRhYmxlTmFtZSkuc2VsZWN0KFwidXVpZFwiLCBcImlkXCIpLndoZXJlSW4oXCJ1dWlkXCIsIHV1aWRzKTtcblxuICAgICAgICAgICAgZm9yIChjb25zdCByb3cgb2Ygcm93cykge1xuICAgICAgICAgICAgICB1dWlkVG9JZC5zZXQocm93LnV1aWQsIHJvdy5pZCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGluc2VydGVkSWRzQnlUYWJsZS5zZXQodGFibGVOYW1lLCB1dWlkVG9JZCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gNC4gTWFueVRvTWFueSDqtIDqs4Qg7LKY66asXG4gICAgICAgIGF3YWl0IHRoaXMucHJvY2Vzc01hbnlUb01hbnlSZWxhdGlvbnModHJ4LCBmaXh0dXJlcywgaW5zZXJ0ZWRJZHNCeVRhYmxlKTtcblxuICAgICAgICAvLyA1LiDqsrDqs7wg7IiY7KeRXG4gICAgICAgIGZvciAoY29uc3QgZml4dHVyZSBvZiBmaXh0dXJlcykge1xuICAgICAgICAgIGNvbnN0IGVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KGZpeHR1cmUuZW50aXR5SWQpO1xuXG4gICAgICAgICAgLy8g7Iqk7YK165CcIGZpeHR1cmXripQg6riw7KG0IOugiOy9lOuTnCDsoJXrs7TroZwg6rKw6rO8IOy2lOqwgFxuICAgICAgICAgIGNvbnN0IHNraXBwZWQgPSB0aGlzLnNraXBwZWRGaXh0dXJlcy5nZXQoZml4dHVyZS5maXh0dXJlSWQpO1xuICAgICAgICAgIGlmIChza2lwcGVkKSB7XG4gICAgICAgICAgICByZXN1bHRzLnB1c2goe1xuICAgICAgICAgICAgICBlbnRpdHlJZDogZml4dHVyZS5lbnRpdHlJZCxcbiAgICAgICAgICAgICAgZGF0YTogYXdhaXQgdHJ4KGVudGl0eS50YWJsZSkud2hlcmUoXCJpZFwiLCBza2lwcGVkLmV4aXN0aW5nSWQpLmZpcnN0KCksXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IHJlZiA9IHRoaXMuZml4dHVyZVJlZk1hcC5nZXQoZml4dHVyZS5maXh0dXJlSWQpO1xuICAgICAgICAgIGlmIChyZWYpIHtcbiAgICAgICAgICAgIGNvbnN0IHV1aWRUb0lkID0gaW5zZXJ0ZWRJZHNCeVRhYmxlLmdldChlbnRpdHkudGFibGUpO1xuICAgICAgICAgICAgY29uc3QgaW5zZXJ0ZWRJZCA9IHV1aWRUb0lkPy5nZXQocmVmLnV1aWQpO1xuXG4gICAgICAgICAgICBpZiAoaW5zZXJ0ZWRJZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgIHJlc3VsdHMucHVzaCh7XG4gICAgICAgICAgICAgICAgZW50aXR5SWQ6IGZpeHR1cmUuZW50aXR5SWQsXG4gICAgICAgICAgICAgICAgZGF0YTogYXdhaXQgdHJ4KGVudGl0eS50YWJsZSkud2hlcmUoXCJpZFwiLCBpbnNlcnRlZElkKS5maXJzdCgpLFxuICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgICBjaGFsay5ncmVlbihgSW5zZXJ0ZWQgaW50byAke2VudGl0eS50YWJsZX06ICMke2ZpeHR1cmUuaWR9IC0+ICMke2luc2VydGVkSWR9YCksXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgYXdhaXQgZGIuZGVzdHJveSgpO1xuICAgIH1cblxuICAgIHJldHVybiB1bmlxdWUocmVzdWx0cywgKHIpID0+IGAke3IuZW50aXR5SWR9IyR7ci5kYXRhLmlkfWApO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpeHR1cmVSZWNvcmTrpbwgVXBzZXJ0QnVpbGRlcuyXkCDrk7HroZ1cbiAgICovXG4gIHByaXZhdGUgcmVnaXN0ZXJGaXh0dXJlKGZpeHR1cmU6IEZpeHR1cmVSZWNvcmQpOiBVQlJlZiB7XG4gICAgY29uc3QgZW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQoZml4dHVyZS5lbnRpdHlJZCk7XG4gICAgY29uc3Qgcm93OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuXG4gICAgLy8gT3ZlcnJpZGUg66qo65OcIO2MkOuLqDogdGFyZ2V0IOuYkOuKlCB1bmlxdWXqsIAg7J6I6rOgIG92ZXJyaWRlPXRydWXsnbgg6rK97JqwXG4gICAgY29uc3QgZXhpc3RpbmdSZWNvcmQgPSBmaXh0dXJlLnRhcmdldCA/PyBmaXh0dXJlLnVuaXF1ZTtcbiAgICBjb25zdCBpc092ZXJyaWRlTW9kZSA9IGZpeHR1cmUub3ZlcnJpZGUgJiYgZXhpc3RpbmdSZWNvcmQ7XG5cbiAgICBmb3IgKGNvbnN0IFtwcm9wTmFtZSwgY29sdW1uXSBvZiBPYmplY3QuZW50cmllcyhmaXh0dXJlLmNvbHVtbnMpKSB7XG4gICAgICBjb25zdCBwcm9wID0gY29sdW1uLnByb3A7XG5cbiAgICAgIGlmIChpc1ZpcnR1YWxQcm9wKHByb3ApKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICAvLyBpZC91dWlkIOyymOumrDogT3ZlcnJpZGUg66qo65Oc7J28IOuVjOunjCDquLDsobQg6rCSIOyCrOyaqVxuICAgICAgaWYgKHByb3BOYW1lID09PSBcImlkXCIgfHwgcHJvcE5hbWUgPT09IFwidXVpZFwiKSB7XG4gICAgICAgIGlmIChpc092ZXJyaWRlTW9kZSAmJiBleGlzdGluZ1JlY29yZCkge1xuICAgICAgICAgIC8vIE92ZXJyaWRlOiDquLDsobQg66CI7L2U65Oc7J2YIOqwkiDsgqzsmqkg4oaSIFVQREFURVxuICAgICAgICAgIHJvd1twcm9wTmFtZV0gPSBleGlzdGluZ1JlY29yZC5jb2x1bW5zW3Byb3BOYW1lXT8udmFsdWU7XG4gICAgICAgIH1cbiAgICAgICAgLy8g7IOIIOugiOy9lOuTnDog7KCc7Jm4IOKGkiBJTlNFUlQgKERCL1Vwc2VydEJ1aWxkZXLqsIAg7IOd7ISxKVxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzUmVsYXRpb25Qcm9wKHByb3ApKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBpc0JlbG9uZ3NUb09uZVJlbGF0aW9uUHJvcChwcm9wKSB8fFxuICAgICAgICAgIChpc09uZVRvT25lUmVsYXRpb25Qcm9wKHByb3ApICYmIHByb3AuaGFzSm9pbkNvbHVtbilcbiAgICAgICAgKSB7XG4gICAgICAgICAgY29uc3QgcmVsYXRlZElkID0gY29sdW1uLnZhbHVlIGFzIG51bWJlciB8IG51bGw7XG4gICAgICAgICAgaWYgKHJlbGF0ZWRJZCAhPT0gbnVsbCAmJiByZWxhdGVkSWQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgY29uc3QgcmVsYXRlZEZpeHR1cmVJZCA9IGAke3Byb3Aud2l0aH0jJHtyZWxhdGVkSWR9YDtcblxuICAgICAgICAgICAgLy8g66i87KCAIHNraXDrkJwgZml4dHVyZeyduOyngCDtmZXsnbhcbiAgICAgICAgICAgIGNvbnN0IHNraXBwZWRFeGlzdGluZ0lkID0gdGhpcy5za2lwcGVkRml4dHVyZXMuZ2V0KHJlbGF0ZWRGaXh0dXJlSWQpPy5leGlzdGluZ0lkO1xuICAgICAgICAgICAgaWYgKHNraXBwZWRFeGlzdGluZ0lkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgLy8gc2tpcOuQnCBmaXh0dXJlIOKGkiB0YXJnZXQgRELsnZgg6riw7KG0IOugiOy9lOuTnCBpZCDsgqzsmqlcbiAgICAgICAgICAgICAgcm93W2Ake3Byb3BOYW1lfV9pZGBdID0gc2tpcHBlZEV4aXN0aW5nSWQ7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBjb25zdCByZWxhdGVkUmVmID0gdGhpcy5maXh0dXJlUmVmTWFwLmdldChyZWxhdGVkRml4dHVyZUlkKTtcbiAgICAgICAgICAgICAgaWYgKHJlbGF0ZWRSZWYpIHtcbiAgICAgICAgICAgICAgICAvLyDsnbTrr7gg65Ox66Gd65CcIGZpeHR1cmUg7LC47KGwIOKGkiBVQlJlZiDsgqzsmqlcbiAgICAgICAgICAgICAgICByb3dbYCR7cHJvcE5hbWV9X2lkYF0gPSByZWxhdGVkUmVmO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIGZpeHR1cmVz7JeQIO2PrO2VqOuQmOyngCDslYrsnYAg66CI7L2U65OcIOKGkiBJRCDqt7jrjIDroZwg7IKs7JqpXG4gICAgICAgICAgICAgICAgcm93W2Ake3Byb3BOYW1lfV9pZGBdID0gcmVsYXRlZElkO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJvd1tgJHtwcm9wTmFtZX1faWRgXSA9IG51bGw7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIEhhc01hbnksIE1hbnlUb01hbnnripQg67OE64+EIOyymOumrFxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8g7J2867CYIOy7rOufvFxuICAgICAgICByb3dbcHJvcE5hbWVdID0gdGhpcy5jb252ZXJ0Q29sdW1uVmFsdWUocHJvcCBhcyBFbnRpdHlQcm9wLCBjb2x1bW4udmFsdWUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnNvbGUubG9nKGNoYWxrLmJsdWUoYFJlZ2lzdGVyaW5nICR7ZW50aXR5LnRhYmxlfSAtICR7aW5zcGVjdChyb3csIGZhbHNlLCBudWxsLCB0cnVlKX1gKSk7XG4gICAgY29uc3QgcmVmID0gdGhpcy5idWlsZGVyLnJlZ2lzdGVyKGVudGl0eS50YWJsZSwgcm93KTtcbiAgICB0aGlzLmZpeHR1cmVSZWZNYXAuc2V0KGZpeHR1cmUuZml4dHVyZUlkLCByZWYpO1xuICAgIHRoaXMudXVpZFRvRml4dHVyZUlkLnNldChyZWYudXVpZCwgZml4dHVyZS5maXh0dXJlSWQpO1xuXG4gICAgcmV0dXJuIHJlZjtcbiAgfVxuXG4gIC8qKlxuICAgKiDsu6zrn7wg6rCSIOuzgO2ZmFxuICAgKi9cbiAgcHJpdmF0ZSBjb252ZXJ0Q29sdW1uVmFsdWUocHJvcDogRW50aXR5UHJvcCwgdmFsdWU6IHVua25vd24pOiB1bmtub3duIHtcbiAgICBpZiAodmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgc3dpdGNoIChwcm9wLnR5cGUpIHtcbiAgICAgIGNhc2UgXCJqc29uXCI6XG4gICAgICAgIC8vIFVwc2VydEJ1aWxkZXIucmVnaXN0ZXLsl5DshJwgSlNPTi5zdHJpbmdpZnkg7LKY66as7ZWY66+A66GcIG9iamVjdCDqt7jrjIDroZwg7KCE64usXG4gICAgICAgIHJldHVybiB2YWx1ZTtcblxuICAgICAgY2FzZSBcImRhdGVcIjpcbiAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiB8fCB0eXBlb2YgdmFsdWUgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICByZXR1cm4gbmV3IERhdGUodmFsdWUpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB2YWx1ZTtcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiDthYzsnbTruJQg7Iic7IScIOy2lOy2nCAoZml4dHVyZXPsl5Ag7Y+s7ZWo65CcIO2FjOydtOu4lOunjClcbiAgICovXG4gIHByaXZhdGUgZ2V0VGFibGVPcmRlcihmaXh0dXJlczogRml4dHVyZVJlY29yZFtdKTogc3RyaW5nW10ge1xuICAgIGNvbnN0IHRhYmxlczogc3RyaW5nW10gPSBbXTtcbiAgICBjb25zdCBzZWVuID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgICBmb3IgKGNvbnN0IGZpeHR1cmUgb2YgZml4dHVyZXMpIHtcbiAgICAgIGNvbnN0IGVudGl0eSA9IEVudGl0eU1hbmFnZXIuZ2V0KGZpeHR1cmUuZW50aXR5SWQpO1xuICAgICAgaWYgKCFzZWVuLmhhcyhlbnRpdHkudGFibGUpKSB7XG4gICAgICAgIHNlZW4uYWRkKGVudGl0eS50YWJsZSk7XG4gICAgICAgIHRhYmxlcy5wdXNoKGVudGl0eS50YWJsZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRhYmxlcztcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcHJvY2Vzc01hbnlUb01hbnlSZWxhdGlvbnMoXG4gICAgdHJ4OiBLbmV4LlRyYW5zYWN0aW9uLFxuICAgIGZpeHR1cmVzOiBGaXh0dXJlUmVjb3JkW10sXG4gICAgaW5zZXJ0ZWRJZHNCeVRhYmxlOiBNYXA8c3RyaW5nLCBNYXA8c3RyaW5nLCBudW1iZXI+PixcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgZm9yIChjb25zdCBmaXh0dXJlIG9mIGZpeHR1cmVzKSB7XG4gICAgICBjb25zdCBlbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChmaXh0dXJlLmVudGl0eUlkKTtcbiAgICAgIGNvbnN0IHNvdXJjZVJlZiA9IHRoaXMuZml4dHVyZVJlZk1hcC5nZXQoZml4dHVyZS5maXh0dXJlSWQpO1xuXG4gICAgICBpZiAoIXNvdXJjZVJlZikgY29udGludWU7XG5cbiAgICAgIGNvbnN0IHNvdXJjZVV1aWRUb0lkID0gaW5zZXJ0ZWRJZHNCeVRhYmxlLmdldChlbnRpdHkudGFibGUpO1xuICAgICAgY29uc3Qgc291cmNlSWQgPSBzb3VyY2VVdWlkVG9JZD8uZ2V0KHNvdXJjZVJlZi51dWlkKTtcblxuICAgICAgaWYgKHNvdXJjZUlkID09PSB1bmRlZmluZWQpIGNvbnRpbnVlO1xuXG4gICAgICBmb3IgKGNvbnN0IFssIGNvbHVtbl0gb2YgT2JqZWN0LmVudHJpZXMoZml4dHVyZS5jb2x1bW5zKSkge1xuICAgICAgICBjb25zdCBwcm9wID0gY29sdW1uLnByb3A7XG5cbiAgICAgICAgaWYgKGlzTWFueVRvTWFueVJlbGF0aW9uUHJvcChwcm9wKSAmJiBBcnJheS5pc0FycmF5KGNvbHVtbi52YWx1ZSkpIHtcbiAgICAgICAgICAvLyDshKDtg53rkJjsp4Ag7JWK7J2AIE1hbnlUb01hbnkg6rSA6rOE64qUIOyggOyepe2VmOyngCDslYrsnYxcbiAgICAgICAgICBjb25zdCB0YXJnZXRUYWJsZSA9IEVudGl0eU1hbmFnZXIuZ2V0KHByb3Aud2l0aCk7XG4gICAgICAgICAgaWYgKHRoaXMuYnVpbGRlci5oYXNUYWJsZSh0YXJnZXRUYWJsZS50YWJsZSkgPT09IGZhbHNlKSBjb250aW51ZTtcblxuICAgICAgICAgIGNvbnN0IHJlbGF0ZWRJZHMgPSBjb2x1bW4udmFsdWUgYXMgbnVtYmVyW107XG4gICAgICAgICAgaWYgKHJlbGF0ZWRJZHMubGVuZ3RoID09PSAwKSBjb250aW51ZTtcblxuICAgICAgICAgIGNvbnN0IGpvaW5UYWJsZSA9IChwcm9wIGFzIE1hbnlUb01hbnlSZWxhdGlvblByb3ApLmpvaW5UYWJsZTtcbiAgICAgICAgICBjb25zdCByZWxhdGVkRW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQocHJvcC53aXRoKTtcblxuICAgICAgICAgIGNvbnN0IHNvdXJjZUNvbHVtbiA9IGAke2luZmxlY3Rpb24uc2luZ3VsYXJpemUoZW50aXR5LnRhYmxlKX1faWRgO1xuICAgICAgICAgIGNvbnN0IHRhcmdldENvbHVtbiA9IGAke2luZmxlY3Rpb24uc2luZ3VsYXJpemUocmVsYXRlZEVudGl0eS50YWJsZSl9X2lkYDtcblxuICAgICAgICAgIGZvciAoY29uc3QgcmVsYXRlZElkIG9mIHJlbGF0ZWRJZHMpIHtcbiAgICAgICAgICAgIGNvbnN0IHJlbGF0ZWRGaXh0dXJlSWQgPSBgJHtwcm9wLndpdGh9IyR7cmVsYXRlZElkfWA7XG4gICAgICAgICAgICBjb25zdCByZWxhdGVkUmVmID0gdGhpcy5maXh0dXJlUmVmTWFwLmdldChyZWxhdGVkRml4dHVyZUlkKTtcblxuICAgICAgICAgICAgbGV0IHRhcmdldElkOiBudW1iZXI7XG5cbiAgICAgICAgICAgIGlmIChyZWxhdGVkUmVmKSB7XG4gICAgICAgICAgICAgIGNvbnN0IHJlbGF0ZWRVdWlkVG9JZCA9IGluc2VydGVkSWRzQnlUYWJsZS5nZXQocmVsYXRlZEVudGl0eS50YWJsZSk7XG4gICAgICAgICAgICAgIGNvbnN0IHJlc29sdmVkSWQgPSByZWxhdGVkVXVpZFRvSWQ/LmdldChyZWxhdGVkUmVmLnV1aWQpO1xuXG4gICAgICAgICAgICAgIGlmIChyZXNvbHZlZElkID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICAgICAgICBgUmVsYXRlZCBmaXh0dXJlICR7cmVsYXRlZEZpeHR1cmVJZH0gbm90IGZvdW5kIGluIGluc2VydGVkSWRzLCBza2lwcGluZ2AsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB0YXJnZXRJZCA9IHJlc29sdmVkSWQ7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB0YXJnZXRJZCA9IHJlbGF0ZWRJZDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gSm9pblRhYmxl7JeQIOyCveyehVxuICAgICAgICAgICAgY29uc3QgW2ZvdW5kXSA9IGF3YWl0IHRyeChqb2luVGFibGUpXG4gICAgICAgICAgICAgIC53aGVyZSh7XG4gICAgICAgICAgICAgICAgW3NvdXJjZUNvbHVtbl06IHNvdXJjZUlkLFxuICAgICAgICAgICAgICAgIFt0YXJnZXRDb2x1bW5dOiB0YXJnZXRJZCxcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgLmxpbWl0KDEpO1xuXG4gICAgICAgICAgICBpZiAoIWZvdW5kKSB7XG4gICAgICAgICAgICAgIGF3YWl0IHRyeChqb2luVGFibGUpLmluc2VydCh7XG4gICAgICAgICAgICAgICAgW3NvdXJjZUNvbHVtbl06IHNvdXJjZUlkLFxuICAgICAgICAgICAgICAgIFt0YXJnZXRDb2x1bW5dOiB0YXJnZXRJZCxcbiAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgICAgY2hhbGsuZ3JlZW4oXG4gICAgICAgICAgICAgICAgICBgSW5zZXJ0ZWQgaW50byAke2pvaW5UYWJsZX06ICR7ZW50aXR5LnRhYmxlfSgke3NvdXJjZUlkfSkgLSAke3JlbGF0ZWRFbnRpdHkudGFibGV9KCR7dGFyZ2V0SWR9KWAsXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGNoZWNrVW5pcXVlVmlvbGF0aW9uKGRiOiBLbmV4LCBlbnRpdHk6IEVudGl0eSwgZml4dHVyZTogRml4dHVyZVJlY29yZCkge1xuICAgIGNvbnN0IF91bmlxdWVJbmRleGVzID0gZW50aXR5LmluZGV4ZXM/LmZpbHRlcigoaSkgPT4gaS50eXBlID09PSBcInVuaXF1ZVwiKSA/PyBbXTtcblxuICAgIGNvbnN0IHVuaXF1ZUluZGV4ZXMgPSBfdW5pcXVlSW5kZXhlcy5maWx0ZXIoKGluZGV4KSA9PlxuICAgICAgaW5kZXguY29sdW1ucy5ldmVyeSgoY29sdW1uKSA9PiAhY29sdW1uLnN0YXJ0c1dpdGgoYCR7ZW50aXR5LnRhYmxlfV9fYCkpLFxuICAgICk7XG4gICAgaWYgKHVuaXF1ZUluZGV4ZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBsZXQgdW5pcXVlUXVlcnkgPSBkYihlbnRpdHkudGFibGUpO1xuICAgIGxldCBoYXNDb25kaXRpb24gPSBmYWxzZTtcblxuICAgIGZvciAoY29uc3QgaW5kZXggb2YgdW5pcXVlSW5kZXhlcykge1xuICAgICAgLy8g7Lus65+8IOykkSDtlZjrgpjrnbzrj4QgbnVsbOydtOuptCDsnKDri4jtgawg7KCc7JW97J2EIOychOuwmO2VmOyngCDslYrquLAg65WM66y47JeQIO2VtOuLuSDsnbjrjbHsiqTripQg66y07IucXG4gICAgICBjb25zdCBjb250YWluc051bGwgPSBpbmRleC5jb2x1bW5zLnNvbWUoKGNvbHVtbikgPT4ge1xuICAgICAgICBjb25zdCBmaWVsZCA9IGNvbHVtbi5yZXBsYWNlKC9faWQkLywgXCJcIik7XG4gICAgICAgIHJldHVybiBmaXh0dXJlLmNvbHVtbnNbZmllbGRdPy52YWx1ZSA9PT0gbnVsbDtcbiAgICAgIH0pO1xuICAgICAgaWYgKGNvbnRhaW5zTnVsbCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgdW5pcXVlUXVlcnkgPSB1bmlxdWVRdWVyeS5vcldoZXJlKChxYikgPT4ge1xuICAgICAgICBmb3IgKGNvbnN0IGNvbHVtbiBvZiBpbmRleC5jb2x1bW5zKSB7XG4gICAgICAgICAgY29uc3QgZmllbGQgPSBjb2x1bW4ucmVwbGFjZSgvX2lkJC8sIFwiXCIpO1xuXG4gICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoZml4dHVyZS5jb2x1bW5zW2ZpZWxkXT8udmFsdWUpKSB7XG4gICAgICAgICAgICBxYi53aGVyZUluKGNvbHVtbiwgZml4dHVyZS5jb2x1bW5zW2ZpZWxkXS52YWx1ZSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHFiLmFuZFdoZXJlKGNvbHVtbiwgZml4dHVyZS5jb2x1bW5zW2ZpZWxkXT8udmFsdWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICBoYXNDb25kaXRpb24gPSB0cnVlO1xuICAgIH1cblxuICAgIGlmICghaGFzQ29uZGl0aW9uKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBjb25zdCBbdW5pcXVlRm91bmRdID0gYXdhaXQgdW5pcXVlUXVlcnk7XG4gICAgcmV0dXJuIHVuaXF1ZUZvdW5kO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjaGVja0R1cGxpY2F0ZUJ5Q29sdW1ucyhcbiAgICBkYjogS25leCxcbiAgICBlbnRpdHk6IEVudGl0eSxcbiAgICBmaXh0dXJlOiBGaXh0dXJlUmVjb3JkLFxuICAgIGNvbHVtbnM6IHN0cmluZ1tdLFxuICApIHtcbiAgICBpZiAoY29sdW1ucy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IHdoZXJlQ2xhdXNlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuXG4gICAgZm9yIChjb25zdCBjb2x1bW4gb2YgY29sdW1ucykge1xuICAgICAgLy8gcmVsYXRpb24g7ZWE65Oc7J24IOqyveyasCBfaWQg67aZ7J206riwXG4gICAgICBjb25zdCBwcm9wID0gZW50aXR5LnByb3BzLmZpbmQoKHApID0+IHAubmFtZSA9PT0gY29sdW1uKTtcbiAgICAgIGNvbnN0IGRiQ29sdW1uID0gcHJvcCAmJiBpc1JlbGF0aW9uUHJvcChwcm9wKSA/IGAke2NvbHVtbn1faWRgIDogY29sdW1uO1xuICAgICAgY29uc3QgdmFsdWUgPSBmaXh0dXJlLmNvbHVtbnNbY29sdW1uXT8udmFsdWU7XG5cbiAgICAgIC8vIG51bGwg6rCS7J20IO2PrO2VqOuQnCDqsr3smrAg7KSR67O1IO2ZleyduCDsiqTtgrVcbiAgICAgIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICB3aGVyZUNsYXVzZVtkYkNvbHVtbl0gPSB2YWx1ZTtcbiAgICB9XG5cbiAgICBjb25zdCBbZm91bmRdID0gYXdhaXQgZGIoZW50aXR5LnRhYmxlKS53aGVyZSh3aGVyZUNsYXVzZSkubGltaXQoMSk7XG4gICAgcmV0dXJuIGZvdW5kO1xuICB9XG5cbiAgYXN5bmMgYWRkRml4dHVyZUxvYWRlcihjb2RlOiBzdHJpbmcpIHtcbiAgICBjb25zdCBwYXRoID0gYCR7U29uYW11LmFwaVJvb3RQYXRofS9zcmMvdGVzdGluZy9maXh0dXJlLnRzYDtcbiAgICBjb25zdCBjb250ZW50ID0gcmVhZEZpbGVTeW5jKHBhdGgpLnRvU3RyaW5nKCk7XG5cbiAgICBjb25zdCBmaXh0dXJlTG9hZGVyU3RhcnQgPSBjb250ZW50LmluZGV4T2YoXCJjb25zdCBmaXh0dXJlTG9hZGVyID0ge1wiKTtcbiAgICBjb25zdCBmaXh0dXJlTG9hZGVyRW5kID0gY29udGVudC5pbmRleE9mKFwifTtcIiwgZml4dHVyZUxvYWRlclN0YXJ0KTtcblxuICAgIGlmIChmaXh0dXJlTG9hZGVyU3RhcnQgIT09IC0xICYmIGZpeHR1cmVMb2FkZXJFbmQgIT09IC0xKSB7XG4gICAgICBjb25zdCBuZXdDb250ZW50ID0gYCR7Y29udGVudC5zbGljZSgwLCBmaXh0dXJlTG9hZGVyRW5kKX0gICR7Y29kZX1cXG4ke2NvbnRlbnQuc2xpY2UoZml4dHVyZUxvYWRlckVuZCl9YDtcblxuICAgICAgd3JpdGVGaWxlU3luYyhwYXRoLCBuZXdDb250ZW50KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRmFpbGVkIHRvIGZpbmQgZml4dHVyZUxvYWRlciBpbiBmaXh0dXJlLnRzXCIpO1xuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgY29uc3QgRml4dHVyZU1hbmFnZXIgPSBuZXcgRml4dHVyZU1hbmFnZXJDbGFzcygpO1xuIl0sIm5hbWVzIjpbImFzc2VydCIsImNoYWxrIiwiZXhlY1N5bmMiLCJyZWFkRmlsZVN5bmMiLCJ3cml0ZUZpbGVTeW5jIiwiaW5mbGVjdGlvbiIsImtuZXgiLCJ1bmlxdWUiLCJpbnNwZWN0IiwiU29uYW11IiwiQmFzZU1vZGVsIiwiVXBzZXJ0QnVpbGRlciIsIkVudGl0eU1hbmFnZXIiLCJpc0JlbG9uZ3NUb09uZVJlbGF0aW9uUHJvcCIsImlzSGFzTWFueVJlbGF0aW9uUHJvcCIsImlzTWFueVRvTWFueVJlbGF0aW9uUHJvcCIsImlzT25lVG9PbmVSZWxhdGlvblByb3AiLCJpc1JlbGF0aW9uUHJvcCIsImlzVmlydHVhbFByb3AiLCJSZWxhdGlvbkdyYXBoIiwiRml4dHVyZU1hbmFnZXJDbGFzcyIsIl90ZGIiLCJ0ZGIiLCJFcnJvciIsIl9mZGIiLCJmZGIiLCJjYWNoZWRUYWJsZU5hbWVzIiwicmVsYXRpb25HcmFwaCIsImJ1aWxkZXIiLCJmaXh0dXJlUmVmTWFwIiwiTWFwIiwidXVpZFRvRml4dHVyZUlkIiwic2tpcHBlZEZpeHR1cmVzIiwiaW5pdCIsImRiQ29uZmlnIiwidGVzdCIsInByb2R1Y3Rpb25fbWFzdGVyIiwidENvbm4iLCJjb25uZWN0aW9uIiwicENvbm4iLCJob3N0IiwicG9ydCIsImRhdGFiYXNlIiwiZml4dHVyZV9yZW1vdGUiLCJnZXRDaGVja3N1bSIsImRiIiwidGFibGVOYW1lIiwiY2hlY2tzdW1Sb3ciLCJyYXciLCJDaGVja3N1bSIsInN5bmMiLCJmaXh0dXJlQ29ubiIsInRlc3RDb25uIiwicGdFbnYiLCJQR1BBU1NXT1JEIiwicGFzc3dvcmQiLCJ1c2VyIiwic3RkaW8iLCJlbnYiLCJwcm9jZXNzIiwidmlzaXRlZFJlY29yZHMiLCJTZXQiLCJpbXBvcnRGaXh0dXJlIiwiZW50aXR5SWQiLCJpZHMiLCJjbGVhciIsInF1ZXJpZXMiLCJQcm9taXNlIiwiYWxsIiwibWFwIiwiaWQiLCJnZXRJbXBvcnRRdWVyaWVzIiwiZmxhdCIsIndkYiIsImdldERCIiwicXVlcnkiLCJyc2giLCJjb25zb2xlIiwibG9nIiwiaW5mbyIsImZpZWxkIiwicmVjb3JkS2V5IiwiaGFzIiwiYWRkIiwiZW50aXR5IiwiZ2V0Iiwicm93IiwidGFibGUiLCJ3aGVyZSIsImxpbWl0IiwidW5kZWZpbmVkIiwiZml4dHVyZURhdGFiYXNlIiwicmVhbERhdGFiYXNlIiwic2VsZlF1ZXJ5IiwiYXJncyIsIk9iamVjdCIsImVudHJpZXMiLCJyZWxhdGlvbnMiLCJmaWx0ZXIiLCJyZWxhdGlvbiIsImN1c3RvbUpvaW5DbGF1c2UiLCJoYXNKb2luQ29sdW1uIiwicmVsYXRlZEVudGl0eSIsIndpdGgiLCJyZWxhdGVkSWRDb2x1bW5OYW1lIiwicHJvcHMiLCJmaW5kIiwicCIsIm5hbWUiLCJhcmciLCJyZWxRdWVyaWVzIiwicmV2ZXJzZSIsImRlc3Ryb3kiLCJnZXRGaXh0dXJlcyIsInNvdXJjZURCTmFtZSIsInRhcmdldERCTmFtZSIsInNlYXJjaE9wdGlvbnMiLCJkdXBsaWNhdGVDaGVjayIsInNvdXJjZURCIiwidGFyZ2V0REIiLCJ2YWx1ZSIsInNlYXJjaFR5cGUiLCJjb2x1bW4iLCJwcm9wIiwidHlwZSIsInJvd3MiLCJsZW5ndGgiLCJmaXh0dXJlcyIsImluaXRpYWxSZWNvcmRzTGVuZ3RoIiwibmV3UmVjb3JkcyIsImNyZWF0ZUZpeHR1cmVSZWNvcmQiLCJfZGIiLCJwdXNoIiwiY3VycmVudEZpeHR1cmVSZWNvcmQiLCJyIiwiZml4dHVyZUlkIiwiZmV0Y2hlZFJlY29yZHMiLCJzbGljZSIsImZpeHR1cmUiLCJjdXN0b21Db2x1bW5zIiwiY29sdW1ucyIsImN1c3RvbUR1cGxpY2F0ZVJvdyIsImNoZWNrRHVwbGljYXRlQnlDb2x1bW5zIiwicmVjb3JkIiwic2luZ2xlUmVjb3JkIiwidGFyZ2V0IiwidW5pcXVlUm93IiwiY2hlY2tVbmlxdWVWaW9sYXRpb24iLCJmIiwib3B0aW9ucyIsInJlY29yZHMiLCJ2aXNpdGVkRW50aXRpZXMiLCJjcmVhdGUiLCJiZWxvbmdzUmVjb3JkcyIsInRocm91Z2hUYWJsZSIsImpvaW5UYWJsZSIsImZyb21Db2x1bW4iLCJzaW5ndWxhcml6ZSIsInRvQ29sdW1uIiwicmVsYXRlZElkcyIsInBsdWNrIiwiam9pbkNvbHVtbiIsInJlbGF0ZWRQcm9wIiwicmVsYXRlZFJvdyIsImZpcnN0IiwicmVsYXRlZElkIiwiaW5zZXJ0Rml4dHVyZXMiLCJkYk5hbWUiLCJfZml4dHVyZXMiLCJyZXN1bHRzIiwiYnVpbGRHcmFwaCIsImluc2VydGlvbk9yZGVyIiwiZ2V0SW5zZXJ0aW9uT3JkZXIiLCJoYXNUYXJnZXQiLCJoYXNVbmlxdWUiLCJoYXNEdXBsaWNhdGUiLCJvdmVycmlkZSIsImV4aXN0aW5nSWQiLCJzZXQiLCJ5ZWxsb3ciLCJyZWdpc3RlckZpeHR1cmUiLCJibHVlIiwidGFibGVPcmRlciIsImdldFRhYmxlT3JkZXIiLCJ0cmFuc2FjdGlvbiIsInRyeCIsImluc2VydGVkSWRzQnlUYWJsZSIsImhhc1RhYmxlIiwiZ2V0VGFibGUiLCJ1dWlkcyIsInV1aWQiLCJ1cHNlcnQiLCJ1dWlkVG9JZCIsInNlbGVjdCIsIndoZXJlSW4iLCJwcm9jZXNzTWFueVRvTWFueVJlbGF0aW9ucyIsInNraXBwZWQiLCJkYXRhIiwicmVmIiwiaW5zZXJ0ZWRJZCIsImdyZWVuIiwiZXhpc3RpbmdSZWNvcmQiLCJpc092ZXJyaWRlTW9kZSIsInByb3BOYW1lIiwicmVsYXRlZEZpeHR1cmVJZCIsInNraXBwZWRFeGlzdGluZ0lkIiwicmVsYXRlZFJlZiIsImNvbnZlcnRDb2x1bW5WYWx1ZSIsInJlZ2lzdGVyIiwiRGF0ZSIsInRhYmxlcyIsInNlZW4iLCJzb3VyY2VSZWYiLCJzb3VyY2VVdWlkVG9JZCIsInNvdXJjZUlkIiwiQXJyYXkiLCJpc0FycmF5IiwidGFyZ2V0VGFibGUiLCJzb3VyY2VDb2x1bW4iLCJ0YXJnZXRDb2x1bW4iLCJ0YXJnZXRJZCIsInJlbGF0ZWRVdWlkVG9JZCIsInJlc29sdmVkSWQiLCJ3YXJuIiwiZm91bmQiLCJpbnNlcnQiLCJfdW5pcXVlSW5kZXhlcyIsImluZGV4ZXMiLCJpIiwidW5pcXVlSW5kZXhlcyIsImluZGV4IiwiZXZlcnkiLCJzdGFydHNXaXRoIiwidW5pcXVlUXVlcnkiLCJoYXNDb25kaXRpb24iLCJjb250YWluc051bGwiLCJzb21lIiwicmVwbGFjZSIsIm9yV2hlcmUiLCJxYiIsImFuZFdoZXJlIiwidW5pcXVlRm91bmQiLCJ3aGVyZUNsYXVzZSIsImRiQ29sdW1uIiwiYWRkRml4dHVyZUxvYWRlciIsImNvZGUiLCJwYXRoIiwiYXBpUm9vdFBhdGgiLCJjb250ZW50IiwidG9TdHJpbmciLCJmaXh0dXJlTG9hZGVyU3RhcnQiLCJpbmRleE9mIiwiZml4dHVyZUxvYWRlckVuZCIsIm5ld0NvbnRlbnQiLCJGaXh0dXJlTWFuYWdlciJdLCJtYXBwaW5ncyI6IkFBQUEsT0FBT0EsWUFBWSxTQUFTO0FBQzVCLE9BQU9DLFdBQVcsUUFBUTtBQUMxQixTQUFTQyxRQUFRLFFBQVEsZ0JBQWdCO0FBQ3pDLFNBQVNDLFlBQVksRUFBRUMsYUFBYSxRQUFRLEtBQUs7QUFDakQsT0FBT0MsZ0JBQWdCLGFBQWE7QUFDcEMsT0FBT0MsVUFBeUIsT0FBTztBQUN2QyxTQUFTQyxNQUFNLFFBQVEsVUFBVTtBQUNqQyxTQUFTQyxPQUFPLFFBQVEsT0FBTztBQUMvQixTQUFTQyxNQUFNLFFBQVEsa0JBQVM7QUFDaEMsU0FBU0MsU0FBUyxRQUFRLDRCQUF5QjtBQUVuRCxTQUFxQkMsYUFBYSxRQUFR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