sonamu 0.5.6 → 0.6.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 (365) hide show
  1. package/dist/api/base-frame.js +12 -2
  2. package/dist/api/caster.js +66 -2
  3. package/dist/api/code-converters.js +489 -2
  4. package/dist/api/config.d.ts +76 -0
  5. package/dist/api/config.d.ts.map +1 -0
  6. package/dist/api/config.js +32 -0
  7. package/dist/api/context.d.ts +1 -0
  8. package/dist/api/context.d.ts.map +1 -1
  9. package/dist/api/context.js +3 -2
  10. package/dist/api/decorators.d.ts +1 -0
  11. package/dist/api/decorators.d.ts.map +1 -1
  12. package/dist/api/decorators.js +142 -2
  13. package/dist/api/index.js +9 -2
  14. package/dist/api/sonamu.d.ts +8 -22
  15. package/dist/api/sonamu.d.ts.map +1 -1
  16. package/dist/api/sonamu.js +482 -2
  17. package/dist/bin/build-config.d.ts +2 -1
  18. package/dist/bin/build-config.d.ts.map +1 -1
  19. package/dist/bin/build-config.js +12 -2
  20. package/dist/bin/cli-wrapper.js +71 -2
  21. package/dist/bin/cli.js +418 -2
  22. package/dist/bin/hot-hook-register.d.ts +11 -0
  23. package/dist/bin/hot-hook-register.d.ts.map +1 -0
  24. package/dist/bin/hot-hook-register.js +21 -0
  25. package/dist/database/_batch_update.js +78 -2
  26. package/dist/database/base-model.js +247 -2
  27. package/dist/database/code-generator.js +53 -2
  28. package/dist/database/db.d.ts +5 -16
  29. package/dist/database/db.d.ts.map +1 -1
  30. package/dist/database/db.js +132 -2
  31. package/dist/database/knex-plugins/knex-on-duplicate-update.js +39 -2
  32. package/dist/database/puri-wrapper.d.ts +22 -10
  33. package/dist/database/puri-wrapper.d.ts.map +1 -1
  34. package/dist/database/puri-wrapper.js +109 -2
  35. package/dist/database/puri.d.ts +105 -73
  36. package/dist/database/puri.d.ts.map +1 -1
  37. package/dist/database/puri.js +539 -2
  38. package/dist/database/puri.types.d.ts +33 -42
  39. package/dist/database/puri.types.d.ts.map +1 -1
  40. package/dist/database/puri.types.js +3 -2
  41. package/dist/database/transaction-context.d.ts +3 -3
  42. package/dist/database/transaction-context.d.ts.map +1 -1
  43. package/dist/database/transaction-context.js +14 -2
  44. package/dist/database/upsert-builder.js +215 -2
  45. package/dist/entity/entity-manager.d.ts +3 -1
  46. package/dist/entity/entity-manager.d.ts.map +1 -1
  47. package/dist/entity/entity-manager.js +114 -2
  48. package/dist/entity/entity-utils.js +210 -2
  49. package/dist/entity/entity.d.ts.map +1 -1
  50. package/dist/entity/entity.js +651 -2
  51. package/dist/exceptions/error-handler.js +29 -2
  52. package/dist/exceptions/so-exceptions.js +85 -2
  53. package/dist/file-storage/driver.js +79 -2
  54. package/dist/file-storage/file-storage.js +75 -2
  55. package/dist/index.d.ts +2 -0
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +28 -2
  58. package/dist/migration/code-generation.js +558 -2
  59. package/dist/migration/migration-set.js +364 -2
  60. package/dist/migration/migrator.d.ts +0 -9
  61. package/dist/migration/migrator.d.ts.map +1 -1
  62. package/dist/migration/migrator.js +510 -2
  63. package/dist/migration/types.js +3 -2
  64. package/dist/naite/naite.d.ts +12 -0
  65. package/dist/naite/naite.d.ts.map +1 -0
  66. package/dist/naite/naite.js +72 -0
  67. package/dist/stream/index.js +3 -2
  68. package/dist/stream/sse.js +38 -2
  69. package/dist/syncer/api-parser.d.ts +20 -0
  70. package/dist/syncer/api-parser.d.ts.map +1 -0
  71. package/dist/syncer/api-parser.js +229 -0
  72. package/dist/syncer/checksum.d.ts +21 -0
  73. package/dist/syncer/checksum.d.ts.map +1 -0
  74. package/dist/syncer/checksum.js +98 -0
  75. package/dist/syncer/code-generator.d.ts +20 -0
  76. package/dist/syncer/code-generator.d.ts.map +1 -0
  77. package/dist/syncer/code-generator.js +141 -0
  78. package/dist/syncer/entity-operations.d.ts +17 -0
  79. package/dist/syncer/entity-operations.d.ts.map +1 -0
  80. package/dist/syncer/entity-operations.js +58 -0
  81. package/dist/syncer/file-patterns.d.ts +29 -0
  82. package/dist/syncer/file-patterns.d.ts.map +1 -0
  83. package/dist/syncer/file-patterns.js +38 -0
  84. package/dist/syncer/index.d.ts +6 -0
  85. package/dist/syncer/index.d.ts.map +1 -1
  86. package/dist/syncer/index.js +9 -2
  87. package/dist/syncer/module-loader.d.ts +35 -0
  88. package/dist/syncer/module-loader.d.ts.map +1 -0
  89. package/dist/syncer/module-loader.js +82 -0
  90. package/dist/syncer/syncer.d.ts +93 -108
  91. package/dist/syncer/syncer.d.ts.map +1 -1
  92. package/dist/syncer/syncer.js +375 -2
  93. package/dist/template/entity-converter.d.ts +14 -0
  94. package/dist/template/entity-converter.d.ts.map +1 -0
  95. package/dist/template/entity-converter.js +101 -0
  96. package/dist/template/helpers.d.ts +23 -0
  97. package/dist/template/helpers.d.ts.map +1 -0
  98. package/dist/template/helpers.js +64 -0
  99. package/dist/{templates → template/implementations}/entity.template.d.ts +3 -3
  100. package/dist/template/implementations/entity.template.d.ts.map +1 -0
  101. package/dist/template/implementations/entity.template.js +87 -0
  102. package/dist/{templates → template/implementations}/generated.template.d.ts +3 -3
  103. package/dist/template/implementations/generated.template.d.ts.map +1 -0
  104. package/dist/template/implementations/generated.template.js +232 -0
  105. package/dist/{templates → template/implementations}/generated_http.template.d.ts +3 -3
  106. package/dist/template/implementations/generated_http.template.d.ts.map +1 -0
  107. package/dist/template/implementations/generated_http.template.js +131 -0
  108. package/dist/{templates → template/implementations}/generated_sso.template.d.ts +3 -3
  109. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -0
  110. package/dist/template/implementations/generated_sso.template.js +105 -0
  111. package/dist/{templates → template/implementations}/init_types.template.d.ts +3 -3
  112. package/dist/template/implementations/init_types.template.d.ts.map +1 -0
  113. package/dist/template/implementations/init_types.template.js +38 -0
  114. package/dist/template/implementations/model.template.d.ts +17 -0
  115. package/dist/template/implementations/model.template.d.ts.map +1 -0
  116. package/dist/template/implementations/model.template.js +171 -0
  117. package/dist/{templates → template/implementations}/model_test.template.d.ts +3 -3
  118. package/dist/template/implementations/model_test.template.d.ts.map +1 -0
  119. package/dist/template/implementations/model_test.template.js +35 -0
  120. package/dist/{templates → template/implementations}/service.template.d.ts +6 -6
  121. package/dist/template/implementations/service.template.d.ts.map +1 -0
  122. package/dist/template/implementations/service.template.js +193 -0
  123. package/dist/{templates → template/implementations}/view_enums_buttonset.template.d.ts +3 -3
  124. package/dist/template/implementations/view_enums_buttonset.template.d.ts.map +1 -0
  125. package/dist/template/implementations/view_enums_buttonset.template.js +31 -0
  126. package/dist/{templates → template/implementations}/view_enums_dropdown.template.d.ts +3 -4
  127. package/dist/template/implementations/view_enums_dropdown.template.d.ts.map +1 -0
  128. package/dist/template/implementations/view_enums_dropdown.template.js +50 -0
  129. package/dist/{templates → template/implementations}/view_enums_select.template.d.ts +3 -3
  130. package/dist/template/implementations/view_enums_select.template.d.ts.map +1 -0
  131. package/dist/template/implementations/view_enums_select.template.js +55 -0
  132. package/dist/{templates → template/implementations}/view_form.template.d.ts +5 -5
  133. package/dist/template/implementations/view_form.template.d.ts.map +1 -0
  134. package/dist/template/implementations/view_form.template.js +337 -0
  135. package/dist/{templates → template/implementations}/view_id_all_select.template.d.ts +3 -3
  136. package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -0
  137. package/dist/template/implementations/view_id_all_select.template.js +31 -0
  138. package/dist/{templates → template/implementations}/view_id_async_select.template.d.ts +3 -3
  139. package/dist/template/implementations/view_id_async_select.template.d.ts.map +1 -0
  140. package/dist/template/implementations/view_id_async_select.template.js +105 -0
  141. package/dist/{templates → template/implementations}/view_list.template.d.ts +5 -13
  142. package/dist/template/implementations/view_list.template.d.ts.map +1 -0
  143. package/dist/template/implementations/view_list.template.js +465 -0
  144. package/dist/{templates → template/implementations}/view_list_columns.template.d.ts +3 -3
  145. package/dist/template/implementations/view_list_columns.template.d.ts.map +1 -0
  146. package/dist/template/implementations/view_list_columns.template.js +49 -0
  147. package/dist/{templates → template/implementations}/view_search_input.template.d.ts +3 -3
  148. package/dist/template/implementations/view_search_input.template.d.ts.map +1 -0
  149. package/dist/template/implementations/view_search_input.template.js +64 -0
  150. package/dist/template/index.d.ts +5 -0
  151. package/dist/template/index.d.ts.map +1 -0
  152. package/dist/template/index.js +6 -0
  153. package/dist/template/template.d.ts +39 -0
  154. package/dist/template/template.d.ts.map +1 -0
  155. package/dist/template/template.js +47 -0
  156. package/dist/template/zod-converter.d.ts +18 -0
  157. package/dist/template/zod-converter.d.ts.map +1 -0
  158. package/dist/template/zod-converter.js +166 -0
  159. package/dist/testing/_relation-graph.js +80 -2
  160. package/dist/testing/fixture-manager.d.ts.map +1 -1
  161. package/dist/testing/fixture-manager.js +521 -2
  162. package/dist/types/types.d.ts +39 -40
  163. package/dist/types/types.d.ts.map +1 -1
  164. package/dist/types/types.js +289 -2
  165. package/dist/typings/knex.d.js +3 -2
  166. package/dist/utils/async-utils.d.ts +7 -0
  167. package/dist/utils/async-utils.d.ts.map +1 -1
  168. package/dist/utils/async-utils.js +57 -2
  169. package/dist/utils/console-util.d.ts +2 -0
  170. package/dist/utils/console-util.d.ts.map +1 -0
  171. package/dist/utils/console-util.js +6 -0
  172. package/dist/utils/controller.js +26 -2
  173. package/dist/utils/esm-utils.d.ts +45 -0
  174. package/dist/utils/esm-utils.d.ts.map +1 -0
  175. package/dist/utils/esm-utils.js +56 -0
  176. package/dist/utils/fs-utils.js +17 -2
  177. package/dist/utils/lodash-able.js +6 -2
  178. package/dist/utils/model.js +22 -2
  179. package/dist/utils/path-utils.d.ts +89 -0
  180. package/dist/utils/path-utils.d.ts.map +1 -0
  181. package/dist/utils/path-utils.js +60 -0
  182. package/dist/utils/process-utils.d.ts +13 -0
  183. package/dist/utils/process-utils.d.ts.map +1 -0
  184. package/dist/utils/process-utils.js +36 -0
  185. package/dist/utils/sql-parser.js +35 -2
  186. package/dist/utils/utils.d.ts +4 -7
  187. package/dist/utils/utils.d.ts.map +1 -1
  188. package/dist/utils/utils.js +33 -2
  189. package/dist/utils/zod-error.d.ts.map +1 -1
  190. package/dist/utils/zod-error.js +19 -2
  191. package/package.json +21 -9
  192. package/src/api/code-converters.ts +2 -2
  193. package/src/api/config.ts +142 -0
  194. package/src/api/context.ts +1 -0
  195. package/src/api/decorators.ts +15 -5
  196. package/src/api/sonamu.ts +102 -87
  197. package/src/bin/build-config.ts +2 -1
  198. package/src/bin/cli-wrapper.ts +10 -3
  199. package/src/bin/cli.ts +108 -56
  200. package/src/bin/hot-hook-register.ts +22 -0
  201. package/src/database/base-model.ts +1 -1
  202. package/src/database/code-generator.ts +1 -1
  203. package/src/database/db.ts +53 -60
  204. package/src/database/puri-wrapper.ts +104 -26
  205. package/src/database/puri.ts +477 -580
  206. package/src/database/puri.types.ts +111 -201
  207. package/src/database/transaction-context.ts +4 -4
  208. package/src/database/upsert-builder.ts +1 -1
  209. package/src/entity/entity-manager.ts +19 -15
  210. package/src/entity/entity.ts +4 -3
  211. package/src/index.ts +2 -0
  212. package/src/migration/code-generation.ts +1 -1
  213. package/src/migration/migration-set.ts +1 -1
  214. package/src/migration/migrator.ts +23 -152
  215. package/src/naite/naite.ts +70 -0
  216. package/src/syncer/api-parser.ts +299 -0
  217. package/src/syncer/checksum.ts +152 -0
  218. package/src/syncer/code-generator.ts +202 -0
  219. package/src/syncer/entity-operations.ts +68 -0
  220. package/src/syncer/file-patterns.ts +56 -0
  221. package/src/syncer/index.ts +6 -0
  222. package/src/syncer/module-loader.ts +125 -0
  223. package/src/syncer/syncer.ts +363 -1420
  224. package/src/template/entity-converter.ts +123 -0
  225. package/src/template/helpers.ts +84 -0
  226. package/src/{templates → template/implementations}/entity.template.ts +4 -4
  227. package/src/{templates → template/implementations}/generated.template.ts +9 -9
  228. package/src/{templates → template/implementations}/generated_http.template.ts +9 -6
  229. package/src/{templates → template/implementations}/generated_sso.template.ts +7 -7
  230. package/src/{templates → template/implementations}/init_types.template.ts +4 -4
  231. package/src/{templates → template/implementations}/model.template.ts +9 -9
  232. package/src/{templates → template/implementations}/model_test.template.ts +5 -5
  233. package/src/{templates → template/implementations}/service.template.ts +29 -12
  234. package/src/{templates → template/implementations}/view_enums_buttonset.template.ts +3 -3
  235. package/src/{templates → template/implementations}/view_enums_dropdown.template.ts +5 -21
  236. package/src/{templates → template/implementations}/view_enums_select.template.ts +4 -4
  237. package/src/{templates → template/implementations}/view_form.template.ts +11 -13
  238. package/src/{templates → template/implementations}/view_id_all_select.template.ts +3 -3
  239. package/src/{templates → template/implementations}/view_id_async_select.template.ts +3 -3
  240. package/src/{templates → template/implementations}/view_list.template.ts +13 -64
  241. package/src/{templates → template/implementations}/view_list_columns.template.ts +3 -3
  242. package/src/{templates → template/implementations}/view_search_input.template.ts +3 -3
  243. package/src/template/index.ts +4 -0
  244. package/src/template/template.ts +86 -0
  245. package/src/template/zod-converter.ts +219 -0
  246. package/src/testing/fixture-manager.ts +8 -1
  247. package/src/types/types.ts +39 -62
  248. package/src/utils/async-utils.ts +17 -0
  249. package/src/utils/console-util.ts +4 -0
  250. package/src/utils/esm-utils.ts +69 -0
  251. package/src/utils/path-utils.ts +102 -0
  252. package/src/utils/process-utils.ts +46 -0
  253. package/src/utils/sql-parser.ts +1 -1
  254. package/src/utils/utils.ts +14 -40
  255. package/src/utils/zod-error.ts +0 -1
  256. package/dist/api/base-frame.js.map +0 -1
  257. package/dist/api/caster.js.map +0 -1
  258. package/dist/api/code-converters.js.map +0 -1
  259. package/dist/api/context.js.map +0 -1
  260. package/dist/api/decorators.js.map +0 -1
  261. package/dist/api/index.js.map +0 -1
  262. package/dist/api/sonamu.js.map +0 -1
  263. package/dist/bin/build-config.js.map +0 -1
  264. package/dist/bin/cli-wrapper.js.map +0 -1
  265. package/dist/bin/cli.js.map +0 -1
  266. package/dist/database/_batch_update.js.map +0 -1
  267. package/dist/database/base-model.js.map +0 -1
  268. package/dist/database/code-generator.js.map +0 -1
  269. package/dist/database/db.js.map +0 -1
  270. package/dist/database/knex-plugins/knex-on-duplicate-update.js.map +0 -1
  271. package/dist/database/puri-wrapper.js.map +0 -1
  272. package/dist/database/puri.js.map +0 -1
  273. package/dist/database/puri.types.js.map +0 -1
  274. package/dist/database/transaction-context.js.map +0 -1
  275. package/dist/database/upsert-builder.js.map +0 -1
  276. package/dist/entity/entity-manager.js.map +0 -1
  277. package/dist/entity/entity-utils.js.map +0 -1
  278. package/dist/entity/entity.js.map +0 -1
  279. package/dist/exceptions/error-handler.js.map +0 -1
  280. package/dist/exceptions/so-exceptions.js.map +0 -1
  281. package/dist/file-storage/driver.js.map +0 -1
  282. package/dist/file-storage/file-storage.js.map +0 -1
  283. package/dist/index.js.map +0 -1
  284. package/dist/migration/code-generation.js.map +0 -1
  285. package/dist/migration/migration-set.js.map +0 -1
  286. package/dist/migration/migrator.js.map +0 -1
  287. package/dist/migration/types.js.map +0 -1
  288. package/dist/stream/index.js.map +0 -1
  289. package/dist/stream/sse.js.map +0 -1
  290. package/dist/syncer/index.js.map +0 -1
  291. package/dist/syncer/syncer.js.map +0 -1
  292. package/dist/templates/base-template.d.ts +0 -13
  293. package/dist/templates/base-template.d.ts.map +0 -1
  294. package/dist/templates/base-template.js +0 -2
  295. package/dist/templates/base-template.js.map +0 -1
  296. package/dist/templates/entity.template.d.ts.map +0 -1
  297. package/dist/templates/entity.template.js +0 -2
  298. package/dist/templates/entity.template.js.map +0 -1
  299. package/dist/templates/generated.template.d.ts.map +0 -1
  300. package/dist/templates/generated.template.js +0 -2
  301. package/dist/templates/generated.template.js.map +0 -1
  302. package/dist/templates/generated_http.template.d.ts.map +0 -1
  303. package/dist/templates/generated_http.template.js +0 -2
  304. package/dist/templates/generated_http.template.js.map +0 -1
  305. package/dist/templates/generated_sso.template.d.ts.map +0 -1
  306. package/dist/templates/generated_sso.template.js +0 -2
  307. package/dist/templates/generated_sso.template.js.map +0 -1
  308. package/dist/templates/index.d.ts +0 -2
  309. package/dist/templates/index.d.ts.map +0 -1
  310. package/dist/templates/index.js +0 -2
  311. package/dist/templates/index.js.map +0 -1
  312. package/dist/templates/init_types.template.d.ts.map +0 -1
  313. package/dist/templates/init_types.template.js +0 -2
  314. package/dist/templates/init_types.template.js.map +0 -1
  315. package/dist/templates/model.template.d.ts +0 -17
  316. package/dist/templates/model.template.d.ts.map +0 -1
  317. package/dist/templates/model.template.js +0 -2
  318. package/dist/templates/model.template.js.map +0 -1
  319. package/dist/templates/model_test.template.d.ts.map +0 -1
  320. package/dist/templates/model_test.template.js +0 -2
  321. package/dist/templates/model_test.template.js.map +0 -1
  322. package/dist/templates/service.template.d.ts.map +0 -1
  323. package/dist/templates/service.template.js +0 -2
  324. package/dist/templates/service.template.js.map +0 -1
  325. package/dist/templates/view_enums_buttonset.template.d.ts.map +0 -1
  326. package/dist/templates/view_enums_buttonset.template.js +0 -2
  327. package/dist/templates/view_enums_buttonset.template.js.map +0 -1
  328. package/dist/templates/view_enums_dropdown.template.d.ts.map +0 -1
  329. package/dist/templates/view_enums_dropdown.template.js +0 -2
  330. package/dist/templates/view_enums_dropdown.template.js.map +0 -1
  331. package/dist/templates/view_enums_select.template.d.ts.map +0 -1
  332. package/dist/templates/view_enums_select.template.js +0 -2
  333. package/dist/templates/view_enums_select.template.js.map +0 -1
  334. package/dist/templates/view_form.template.d.ts.map +0 -1
  335. package/dist/templates/view_form.template.js +0 -2
  336. package/dist/templates/view_form.template.js.map +0 -1
  337. package/dist/templates/view_id_all_select.template.d.ts.map +0 -1
  338. package/dist/templates/view_id_all_select.template.js +0 -2
  339. package/dist/templates/view_id_all_select.template.js.map +0 -1
  340. package/dist/templates/view_id_async_select.template.d.ts.map +0 -1
  341. package/dist/templates/view_id_async_select.template.js +0 -2
  342. package/dist/templates/view_id_async_select.template.js.map +0 -1
  343. package/dist/templates/view_list.template.d.ts.map +0 -1
  344. package/dist/templates/view_list.template.js +0 -2
  345. package/dist/templates/view_list.template.js.map +0 -1
  346. package/dist/templates/view_list_columns.template.d.ts.map +0 -1
  347. package/dist/templates/view_list_columns.template.js +0 -2
  348. package/dist/templates/view_list_columns.template.js.map +0 -1
  349. package/dist/templates/view_search_input.template.d.ts.map +0 -1
  350. package/dist/templates/view_search_input.template.js +0 -2
  351. package/dist/templates/view_search_input.template.js.map +0 -1
  352. package/dist/testing/_relation-graph.js.map +0 -1
  353. package/dist/testing/fixture-manager.js.map +0 -1
  354. package/dist/types/types.js.map +0 -1
  355. package/dist/typings/knex.d.js.map +0 -1
  356. package/dist/utils/async-utils.js.map +0 -1
  357. package/dist/utils/controller.js.map +0 -1
  358. package/dist/utils/fs-utils.js.map +0 -1
  359. package/dist/utils/lodash-able.js.map +0 -1
  360. package/dist/utils/model.js.map +0 -1
  361. package/dist/utils/sql-parser.js.map +0 -1
  362. package/dist/utils/utils.js.map +0 -1
  363. package/dist/utils/zod-error.js.map +0 -1
  364. package/src/templates/base-template.ts +0 -19
  365. package/src/templates/index.ts +0 -1
@@ -1,2 +1,510 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"Migrator",{enumerable:true,get:function(){return Migrator}});var _lodash=/*#__PURE__*/_interop_require_default(require("lodash"));var _knex=/*#__PURE__*/_interop_require_default(require("knex"));var _chalk=/*#__PURE__*/_interop_require_default(require("chalk"));var _luxon=require("luxon");var _promises=require("fs/promises");var _fsutils=require("../utils/fs-utils");var _prompts=/*#__PURE__*/_interop_require_default(require("prompts"));var _child_process=require("child_process");var _path=/*#__PURE__*/_interop_require_default(require("path"));var _entitymanager=require("../entity/entity-manager");var _api=require("../api");var _soexceptions=require("../exceptions/so-exceptions");var _codegeneration=require("./code-generation");var _migrationset=require("./migration-set");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 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 _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 _object_spread(target){for(var i=1;i<arguments.length;i++){var source=arguments[i]!=null?arguments[i]:{};var ownKeys=Object.keys(source);if(typeof Object.getOwnPropertySymbols==="function"){ownKeys=ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym){return Object.getOwnPropertyDescriptor(source,sym).enumerable}))}ownKeys.forEach(function(key){_define_property(target,key,source[key])})}return target}function ownKeys(object,enumerableOnly){var keys=Object.keys(object);if(Object.getOwnPropertySymbols){var symbols=Object.getOwnPropertySymbols(object);if(enumerableOnly){symbols=symbols.filter(function(sym){return Object.getOwnPropertyDescriptor(object,sym).enumerable})}keys.push.apply(keys,symbols)}return keys}function _object_spread_props(target,source){source=source!=null?source:{};if(Object.getOwnPropertyDescriptors){Object.defineProperties(target,Object.getOwnPropertyDescriptors(source))}else{ownKeys(Object(source)).forEach(function(key){Object.defineProperty(target,key,Object.getOwnPropertyDescriptor(source,key))})}return target}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 _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}}}var Migrator=/*#__PURE__*/function(){"use strict";function Migrator(options){_class_call_check(this,Migrator);_define_property(this,"options",void 0);_define_property(this,"targets",void 0);this.options=options;var dbConfig=_api.Sonamu.dbConfig;if(this.options.mode==="dev"){var devDB=(0,_knex.default)(dbConfig.development_master);var testDB=(0,_knex.default)(dbConfig.test);var fixtureLocalDB=(0,_knex.default)(dbConfig.fixture_local);var applyDBs=[devDB,testDB,fixtureLocalDB];if(dbConfig.fixture_local.connection.host!==dbConfig.fixture_remote.connection.host||dbConfig.fixture_local.connection.database!==dbConfig.fixture_remote.connection.database){var fixtureRemoteDB=(0,_knex.default)(dbConfig.fixture_remote);applyDBs.push(fixtureRemoteDB)}this.targets={compare:devDB,pending:devDB,shadow:testDB,apply:applyDBs}}else if(this.options.mode==="deploy"){var productionDB=(0,_knex.default)(dbConfig.production_master);var testDB1=(0,_knex.default)(dbConfig.test);this.targets={pending:productionDB,shadow:testDB1,apply:[productionDB]}}else{throw new Error("잘못된 모드 ".concat(this.options.mode," 입력"))}}_create_class(Migrator,[{key:"getMigrationCodes",value:function getMigrationCodes(){return _async_to_generator(function(){var srcMigrationsDir,distMigrationsDir,srcMigrations,distMigrations,normal,onlyTs,onlyJs;return _ts_generator(this,function(_state){switch(_state.label){case 0:srcMigrationsDir="".concat(_api.Sonamu.apiRootPath,"/src/migrations");distMigrationsDir="".concat(_api.Sonamu.apiRootPath,"/dist/migrations");return[4,(0,_fsutils.exists)(srcMigrationsDir)];case 1:if(!!_state.sent())return[3,3];return[4,(0,_promises.mkdir)(srcMigrationsDir,{recursive:true})];case 2:_state.sent();_state.label=3;case 3:return[4,(0,_fsutils.exists)(distMigrationsDir)];case 4:if(!!_state.sent())return[3,6];return[4,(0,_promises.mkdir)(distMigrationsDir,{recursive:true})];case 5:_state.sent();_state.label=6;case 6:return[4,(0,_promises.readdir)(srcMigrationsDir)];case 7:srcMigrations=_state.sent().filter(function(f){return f.endsWith(".ts")}).map(function(f){return f.split(".")[0]});return[4,(0,_promises.readdir)(distMigrationsDir)];case 8:distMigrations=_state.sent().filter(function(f){return f.endsWith(".js")}).map(function(f){return f.split(".")[0]});normal=_lodash.default.intersection(srcMigrations,distMigrations).map(function(filename){return{name:filename,path:_path.default.join(srcMigrationsDir,filename)+".ts"}}).sort(function(a,b){return a>b?1:-1});onlyTs=_lodash.default.difference(srcMigrations,distMigrations).map(function(filename){return{name:filename,path:_path.default.join(srcMigrationsDir,filename)+".ts"}});onlyJs=_lodash.default.difference(distMigrations,srcMigrations).map(function(filename){return{name:filename,path:_path.default.join(distMigrationsDir,filename)+".js"}});return[2,{normal:normal,onlyTs:onlyTs,onlyJs:onlyJs}]}})})()}},{key:"getStatus",value:function getStatus(){return _async_to_generator(function(){var _this,_ref,normal,onlyTs,onlyJs,connKeys,statuses,preparedCodes;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this;return[4,this.getMigrationCodes()];case 1:_ref=_state.sent(),normal=_ref.normal,onlyTs=_ref.onlyTs,onlyJs=_ref.onlyJs;if(onlyTs.length>0){console.debug({onlyTs:onlyTs});throw new _soexceptions.ServiceUnavailableException("There are un-compiled TS migration files.\nPlease compile them first. You might want to run a development server with HMR.\n\n".concat(onlyTs.map(function(f){return f.name}).join("\n")))}if(!(onlyJs.length>0))return[3,3];console.debug({onlyJs:onlyJs});return[4,Promise.all(onlyJs.map(function(f){return _async_to_generator(function(){return _ts_generator(this,function(_state){(0,_child_process.execSync)("rm -f ".concat(f.path.replace("/src/","/dist/").replace(".ts",".js")));return[2]})})()}))];case 2:_state.sent();_state.label=3;case 3:connKeys=Object.keys(_api.Sonamu.dbConfig).filter(function(key){return key.endsWith("_slave")===false});return[4,Promise.all(connKeys.map(function(connKey){return _async_to_generator(function(){var knexOptions,tConn,status,pending,currentVersion,connection,_connection_user;return _ts_generator(this,function(_state){switch(_state.label){case 0:knexOptions=_api.Sonamu.dbConfig[connKey];tConn=(0,_knex.default)(knexOptions);return[4,function(){return _async_to_generator(function(){var err;return _ts_generator(this,function(_state){switch(_state.label){case 0:_state.trys.push([0,2,,3]);return[4,tConn.migrate.status()];case 1:return[2,_state.sent()];case 2:err=_state.sent();console.warn(_chalk.default.yellow("".concat(connKey,"의 마이그레이션 상태를 가져오는 데에 실패하였습니다. 데이터베이스가 올바르게 구성되지 않은 것 같습니다. 확인하시고 다시 시도해주세요.\n시도한 연결 설정:\n").concat(JSON.stringify(knexOptions.connection,null,2),"\n발생한 에러:\n").concat(err,"\n")));return[2,"error"];case 3:return[2]}})})()}()];case 1:status=_state.sent();return[4,function(){return _async_to_generator(function(){var _ref,fdList,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:_state.trys.push([0,2,,3]);return[4,tConn.migrate.list()];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),2]),fdList=_ref[1];return[2,fdList.map(function(fd){return fd.file.replace(".js","")})];case 2:err=_state.sent();return[2,[]];case 3:return[2]}})})()}()];case 2:pending=_state.sent();return[4,function(){return _async_to_generator(function(){var err;return _ts_generator(this,function(_state){switch(_state.label){case 0:_state.trys.push([0,2,,3]);return[4,tConn.migrate.currentVersion()];case 1:return[2,_state.sent()];case 2:err=_state.sent();return[2,"error"];case 3:return[2]}})})()}()];case 3:currentVersion=_state.sent();connection=knexOptions.connection;return[4,tConn.destroy()];case 4:_state.sent();return[2,{name:connKey.replace("_master",""),connKey:connKey,connString:"mysql2://".concat((_connection_user=connection.user)!==null&&_connection_user!==void 0?_connection_user:"","@").concat(connection.host,":").concat(connection.port,"/").concat(connection.database),currentVersion:currentVersion,status:status,pending:pending}]}})})()}))];case 4:statuses=_state.sent();return[4,function(){return _async_to_generator(function(){var status0conn,compareDBconn,genCodes;return _ts_generator(this,function(_state){switch(_state.label){case 0:status0conn=statuses.find(function(status){return status.status===0});if(status0conn===undefined){return[2,[]]}compareDBconn=(0,_knex.default)(_api.Sonamu.dbConfig[status0conn.connKey]);return[4,this.compareMigrations(compareDBconn)];case 1:genCodes=_state.sent();return[4,compareDBconn.destroy()];case 2:_state.sent();return[2,genCodes]}})}).call(_this)}()];case 5:preparedCodes=_state.sent();return[2,{conns:statuses,codes:normal,preparedCodes:preparedCodes}]}})}).call(this)}},{key:"runAction",value:function runAction(action,targets){return _async_to_generator(function(){var configs,conns,result;return _ts_generator(this,function(_state){switch(_state.label){case 0:configs=_lodash.default.uniqBy(targets.map(function(target){return{connKey:target,options:_api.Sonamu.dbConfig[target]}}).filter(function(c){return c.options!==undefined}),function(param){var options=param.options;var _options_connection_port;return"".concat(options.connection.host,":").concat((_options_connection_port=options.connection.port)!==null&&_options_connection_port!==void 0?_options_connection_port:3306,"/").concat(options.connection.database)});return[4,Promise.all(configs.map(function(config){return _async_to_generator(function(){return _ts_generator(this,function(_state){return[2,{connKey:config.connKey,knex:(0,_knex.default)(config.options)}]})})()}))];case 1:conns=_state.sent();return[4,function(){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(action){case"apply":return[2,Promise.all(conns.map(function(param){var connKey=param.connKey,knex=param.knex;return _async_to_generator(function(){var _ref,batchNo,applied;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,knex.migrate.latest()];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),2]),batchNo=_ref[0],applied=_ref[1];return[2,{connKey:connKey,batchNo:batchNo,applied:applied}]}})})()}))];case"rollback":return[2,Promise.all(conns.map(function(param){var connKey=param.connKey,knex=param.knex;return _async_to_generator(function(){var _ref,batchNo,applied;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,knex.migrate.rollback()];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),2]),batchNo=_ref[0],applied=_ref[1];return[2,{connKey:connKey,batchNo:batchNo,applied:applied}]}})})()}))]}return[2]})})()}()];case 2:result=_state.sent();return[4,Promise.all(conns.map(function(param){var knex=param.knex;return knex.destroy()}))];case 3:_state.sent();return[2,result]}})})()}},{key:"delCodes",value:function delCodes(codeNames){return _async_to_generator(function(){var conns,delFiles,res;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.getStatus()];case 1:conns=_state.sent().conns;if(conns.some(function(conn){return codeNames.some(function(codeName){return conn.pending.includes(codeName)===false})})){throw new Error("You cannot delete a migration file if there is already applied.")}delFiles=codeNames.map(function(codeName){return["".concat(_api.Sonamu.apiRootPath,"/src/migrations/").concat(codeName,".ts"),"".concat(_api.Sonamu.apiRootPath,"/dist/migrations/").concat(codeName,".js")]}).flat();return[4,Promise.all(delFiles.map(function(delFile){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,(0,_fsutils.exists)(delFile)];case 1:if(!_state.sent())return[3,3];console.log(_chalk.default.red("DELETE: ".concat(delFile)));return[4,(0,_promises.unlink)(delFile)];case 2:_state.sent();return[2,delFiles.includes(".ts")?1:0];case 3:return[2,0]}})})()}))];case 2:res=_state.sent();return[2,_lodash.default.sum(res)]}})}).call(this)}},{key:"generatePreparedCodes",value:function generatePreparedCodes(){return _async_to_generator(function(){var preparedCodes,migrationsDir,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_iterator,_step,_step_value,index,pcode,dateTag,filePath,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.getStatus()];case 1:preparedCodes=_state.sent().preparedCodes;if(preparedCodes.length===0){console.log(_chalk.default.green("\n현재 모두 싱크된 상태입니다."));return[2,0]}migrationsDir="".concat(_api.Sonamu.apiRootPath,"/src/migrations");_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=2;case 2:_state.trys.push([2,7,8,9]);_iterator=preparedCodes.entries()[Symbol.iterator]();_state.label=3;case 3:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,6];_step_value=_sliced_to_array(_step.value,2),index=_step_value[0],pcode=_step_value[1];if(!pcode.formatted)return[3,5];dateTag=_luxon.DateTime.local().plus({seconds:index}).toFormat("yyyyMMddHHmmss");filePath="".concat(migrationsDir,"/").concat(dateTag,"_").concat(pcode.title,".ts");return[4,(0,_promises.writeFile)(filePath,pcode.formatted)];case 4:_state.sent();console.log(_chalk.default.green("MIGRTAION CREATED ".concat(filePath)));_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,preparedCodes.length]}})}).call(this)}},{key:"clearPendingList",value:function clearPendingList(){return _async_to_generator(function(){var _ref,pendingList,migrationsDir,delList,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_iterator,_step,p,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.targets.pending.migrate.list()];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),2]),pendingList=_ref[1];migrationsDir="".concat(_api.Sonamu.apiRootPath,"/src/migrations");delList=pendingList.map(function(df){return _path.default.join(migrationsDir,df.file).replace(".js",".ts")});_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=2;case 2:_state.trys.push([2,8,9,10]);_iterator=delList[Symbol.iterator]();_state.label=3;case 3:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,7];p=_step.value;return[4,(0,_fsutils.exists)(p)];case 4:if(!_state.sent())return[3,6];return[4,(0,_promises.unlink)(p)];case 5:_state.sent();_state.label=6;case 6:_iteratorNormalCompletion=true;return[3,3];case 7:return[3,10];case 8:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,10];case 9:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 10:return[4,this.cleanUpDist(true)];case 11:_state.sent();return[2]}})}).call(this)}},{key:"check",value:function check(){return _async_to_generator(function(){var codes;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.compareMigrations(this.targets.compare)];case 1:codes=_state.sent();if(codes.length===0){console.log(_chalk.default.green("\n현재 모두 싱크된 상태입니다."));return[2]}console.table(codes,["type","title"]);console.log(codes[0]);return[2]}})}).call(this)}},{key:"run",value:function run(){return _async_to_generator(function(){var _ref,pendingList,answer,codes,answer1,migrationsDir,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_iterator,_step,_step_value,index,code,dateTag,filePath,err;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.targets.pending.migrate.list()];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),2]),pendingList=_ref[1];if(!(pendingList.length>0))return[3,5];console.log(_chalk.default.red("pending 된 마이그레이션이 존재합니다."),pendingList.map(function(pending){return pending.file}));return[4,(0,_prompts.default)({type:"confirm",name:"value",message:"Shadow DB 테스트를 진행하시겠습니까?",initial:true})];case 2:answer=_state.sent();if(answer.value===false){return[2]}console.time(_chalk.default.blue("Migrator - runShadowTest"));return[4,this.runShadowTest()];case 3:_state.sent();console.timeEnd(_chalk.default.blue("Migrator - runShadowTest"));return[4,Promise.all(this.targets.apply.map(function(applyDb){return _async_to_generator(function(){var label,_ref;return _ts_generator(this,function(_state){switch(_state.label){case 0:label=_chalk.default.green("APPLIED ".concat(applyDb.client.connectionSettings.host," ").concat(applyDb.client.database()));console.time(label);return[4,applyDb.migrate.latest()];case 1:_ref=_sliced_to_array.apply(void 0,[_state.sent(),1]);console.timeEnd(label);return[2]}})})()}))];case 4:_state.sent();_state.label=5;case 5:return[4,this.compareMigrations(this.targets.compare)];case 6:codes=_state.sent();if(codes.length===0){console.log(_chalk.default.green("\n현재 모두 싱크된 상태입니다."));return[2]}console.table(codes,["type","title"]);return[4,(0,_prompts.default)({type:"confirm",name:"value",message:"마이그레이션 코드를 생성하시겠습니까?",initial:false})];case 7:answer1=_state.sent();if(answer1.value===false){return[2]}migrationsDir="".concat(_api.Sonamu.apiRootPath,"/src/migrations");_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=8;case 8:_state.trys.push([8,13,14,15]);_iterator=codes.entries()[Symbol.iterator]();_state.label=9;case 9:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,12];_step_value=_sliced_to_array(_step.value,2),index=_step_value[0],code=_step_value[1];if(!code.formatted)return[3,11];dateTag=_luxon.DateTime.local().plus({seconds:index}).toFormat("yyyyMMddHHmmss");filePath="".concat(migrationsDir,"/").concat(dateTag,"_").concat(code.title,".ts");return[4,(0,_promises.writeFile)(filePath,code.formatted)];case 10:_state.sent();console.log(_chalk.default.green("MIGRTAION CREATED ".concat(filePath)));_state.label=11;case 11:_iteratorNormalCompletion=true;return[3,9];case 12:return[3,15];case 13:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,15];case 14:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 15:return[2]}})}).call(this)}},{key:"rollback",value:function rollback(){return _async_to_generator(function(){var rollbackAllResult;return _ts_generator(this,function(_state){switch(_state.label){case 0:console.time(_chalk.default.red("rollback:"));return[4,Promise.all(this.targets.apply.map(function(db){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,db.migrate.forceFreeMigrationsLock()];case 1:_state.sent();return[2,db.migrate.rollback(undefined,false)]}})})()}))];case 1:rollbackAllResult=_state.sent();console.dir({rollbackAllResult:rollbackAllResult},{depth:null});console.timeEnd(_chalk.default.red("rollback:"));return[2]}})}).call(this)}},{key:"cleanUpDist",value:function cleanUpDist(){var force=arguments.length>0&&arguments[0]!==void 0?arguments[0]:false;return _async_to_generator(function(){var files,_tmp,diffOnSrc,diffOnDist,answer,filesToRm,_iteratorNormalCompletion,_didIteratorError,_iteratorError,_iterator,_step,filePath,err;function getFilesUnder(dir){return _async_to_generator(function(){var migrationPath;return _ts_generator(this,function(_state){switch(_state.label){case 0:migrationPath=_path.default.join(_api.Sonamu.apiRootPath,dir,"migrations");return[4,(0,_fsutils.exists)(migrationPath)];case 1:if(!!_state.sent())return[3,3];return[4,(0,_promises.mkdir)(migrationPath,{recursive:true})];case 2:_state.sent();_state.label=3;case 3:return[4,(0,_promises.readdir)(migrationPath)];case 4:return[2,_state.sent().filter(function(filename){return filename.startsWith(".")===false})]}})})()}return _ts_generator(this,function(_state){switch(_state.label){case 0:_tmp={};return[4,getFilesUnder("src")];case 1:_tmp.src=_state.sent();return[4,getFilesUnder("dist")];case 2:files=(_tmp.dist=_state.sent(),_tmp);diffOnSrc=_lodash.default.differenceBy(files.src,files.dist,function(filename){return filename.split(".")[0]});if(diffOnSrc.length>0){throw new Error("컴파일 되지 않은 파일이 있습니다.\n"+diffOnSrc.join("\n"))}diffOnDist=_lodash.default.differenceBy(files.dist,files.src,function(filename){return filename.split(".")[0]});if(!(diffOnDist.length>0))return[3,13];console.log(_chalk.default.red("원본 ts파일을 찾을 수 없는 js파일이 있습니다."));console.log(diffOnDist);if(!!force)return[3,4];return[4,(0,_prompts.default)({type:"confirm",name:"value",message:"삭제를 진행하시겠습니까?",initial:true})];case 3:answer=_state.sent();if(answer.value===false){return[2]}_state.label=4;case 4:filesToRm=diffOnDist.map(function(filename){return _path.default.join(_api.Sonamu.apiRootPath,"dist","migrations",filename)});_iteratorNormalCompletion=true,_didIteratorError=false,_iteratorError=undefined;_state.label=5;case 5:_state.trys.push([5,10,11,12]);_iterator=filesToRm[Symbol.iterator]();_state.label=6;case 6:if(!!(_iteratorNormalCompletion=(_step=_iterator.next()).done))return[3,9];filePath=_step.value;return[4,(0,_promises.unlink)(filePath)];case 7:_state.sent();_state.label=8;case 8:_iteratorNormalCompletion=true;return[3,6];case 9:return[3,12];case 10:err=_state.sent();_didIteratorError=true;_iteratorError=err;return[3,12];case 11:try{if(!_iteratorNormalCompletion&&_iterator.return!=null){_iterator.return()}}finally{if(_didIteratorError){throw _iteratorError}}return[7];case 12:console.log(_chalk.default.green("".concat(filesToRm.length,"건 삭제되었습니다!")));_state.label=13;case 13:return[2]}})})()}},{key:"runShadowTest",value:function runShadowTest(){return _async_to_generator(function(){var tdb,tdbConn,shadowDatabase,tmpSqlPath,_tdbConn_port,_tdbConn_port1,sdb,_ref,batchNo,applied,e;return _ts_generator(this,function(_state){switch(_state.label){case 0:tdb=(0,_knex.default)(_api.Sonamu.dbConfig.test);tdbConn=_api.Sonamu.dbConfig.test.connection;shadowDatabase=tdbConn.database+"__migration_shadow";tmpSqlPath="/tmp/".concat(shadowDatabase,".sql");console.log(_chalk.default.magenta("".concat(tdbConn.database,"의 데이터 ").concat(tmpSqlPath,"로 덤프")));(0,_child_process.execSync)("mysqldump -h".concat(tdbConn.host," -P").concat((_tdbConn_port=tdbConn.port)!==null&&_tdbConn_port!==void 0?_tdbConn_port:3306," -u").concat(tdbConn.user," -p'").concat(tdbConn.password,"' ").concat(tdbConn.database," --single-transaction --no-create-db --triggers > ").concat(tmpSqlPath,";"));(0,_child_process.execSync)("sed -i'' -e 's/`".concat(tdbConn.database,"`/`").concat(shadowDatabase,"`/g' ").concat(tmpSqlPath,";"));console.log(_chalk.default.magenta("".concat(shadowDatabase," 리셋")));return[4,tdb.raw("DROP DATABASE IF EXISTS `".concat(shadowDatabase,"`;"))];case 1:_state.sent();return[4,tdb.raw("CREATE DATABASE `".concat(shadowDatabase,"`;"))];case 2:_state.sent();console.log(_chalk.default.magenta("".concat(shadowDatabase," 데이터베이스 생성")));(0,_child_process.execSync)("mysql -h".concat(tdbConn.host," -P").concat((_tdbConn_port1=tdbConn.port)!==null&&_tdbConn_port1!==void 0?_tdbConn_port1:3306," -u").concat(tdbConn.user," -p'").concat(tdbConn.password,"' ").concat(shadowDatabase," < ").concat(tmpSqlPath,";"));sdb=(0,_knex.default)(_object_spread_props(_object_spread({},_api.Sonamu.dbConfig.test),{connection:_object_spread_props(_object_spread({},tdbConn),{database:shadowDatabase,password:tdbConn.password})}));_state.label=3;case 3:_state.trys.push([3,6,7,9]);return[4,sdb.migrate.latest()];case 4:_ref=_sliced_to_array.apply(void 0,[_state.sent(),2]),batchNo=_ref[0],applied=_ref[1];console.log(_chalk.default.green("Shadow DB 테스트에 성공했습니다!"),{batchNo:batchNo,applied:applied});console.log(_chalk.default.magenta("".concat(shadowDatabase," 삭제")));return[4,tdb.raw("DROP DATABASE IF EXISTS `".concat(shadowDatabase,"`;"))];case 5:_state.sent();return[2,[{connKey:"shadow",batchNo:batchNo,applied:applied}]];case 6:e=_state.sent();console.error(e);throw new _soexceptions.ServiceUnavailableException("Shadow DB 테스트 진행 중 에러");case 7:return[4,tdb.destroy()];case 8:_state.sent();return[7];case 9:return[2]}})})()}},{key:"resetAll",value:function resetAll(){return _async_to_generator(function(){var answer,rollbackAllResult,migrationsDir;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,(0,_prompts.default)({type:"confirm",name:"value",message:"모든 DB를 롤백하고 전체 마이그레이션 파일을 삭제하시겠습니까?",initial:false})];case 1:answer=_state.sent();if(answer.value===false){return[2]}console.time(_chalk.default.red("rollback-all:"));return[4,Promise.all(this.targets.apply.map(function(db){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,db.migrate.forceFreeMigrationsLock()];case 1:_state.sent();return[2,db.migrate.rollback(undefined,true)]}})})()}))];case 2:rollbackAllResult=_state.sent();console.log({rollbackAllResult:rollbackAllResult});console.timeEnd(_chalk.default.red("rollback-all:"));migrationsDir="".concat(_api.Sonamu.apiRootPath,"/src/migrations");console.time(_chalk.default.red("delete migration files"));(0,_child_process.execSync)("rm -f ".concat(migrationsDir,"/*"));(0,_child_process.execSync)("rm -f ".concat(migrationsDir.replace("/src/","/dist/"),"/*"));console.timeEnd(_chalk.default.red("delete migration files"));return[2]}})}).call(this)}},{key:"compareMigrations",value:function compareMigrations(compareDB){return _async_to_generator(function(){var entityIds,entitySetsWithJoinTable,joinTablesWithDup,joinTables,entitySets,codes;return _ts_generator(this,function(_state){switch(_state.label){case 0:entityIds=_entitymanager.EntityManager.getAllIds();entitySetsWithJoinTable=entityIds.filter(function(entityId){return _entitymanager.EntityManager.get(entityId).props.length>0}).map(function(entityId){return(0,_migrationset.getMigrationSetFromEntity)(_entitymanager.EntityManager.get(entityId))});joinTablesWithDup=entitySetsWithJoinTable.map(function(entitySet){return entitySet.joinTables}).flat();joinTables=Object.values(_lodash.default.groupBy(joinTablesWithDup,function(jt){return jt.table})).map(function(tables){if(tables.length===1){return tables[0]}return _object_spread_props(_object_spread({},tables[0]),{indexes:_lodash.default.uniqBy(tables.flatMap(function(t){return t.indexes}),function(index){return[index.type].concat(_to_consumable_array(index.columns.sort())).join("-")})})});entitySets=_to_consumable_array(entitySetsWithJoinTable).concat(_to_consumable_array(joinTables));return[4,Promise.all(entitySets.map(function(entitySet){return _async_to_generator(function(){var dbSet;return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,(0,_migrationset.getMigrationSetFromDB)(compareDB,entitySet.table)];case 1:dbSet=_state.sent();if(!(dbSet===null))return[3,3];return[4,(0,_codegeneration.generateCreateCode)(entitySet)];case 2:return[2,_state.sent()];case 3:return[4,(0,_codegeneration.generateAlterCode)(entitySet,dbSet)];case 4:return[2,_state.sent()];case 5:return[2]}})})()}))];case 1:codes=_state.sent().flat();codes.sort(function(codeA,codeB){if(codeA.type==="foreign"&&codeB.type=="normal"){return 1}else if(codeA.type==="normal"&&codeB.type==="foreign"){return-1}else{return 0}});return[2,codes]}})})()}},{key:"destroy",value:function destroy(){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,Promise.all(this.targets.apply.map(function(db){return db.destroy()}))];case 1:_state.sent();return[2]}})}).call(this)}}]);return Migrator}();
2
- //# sourceMappingURL=migrator.js.map
1
+ import * as _ from "lodash-es";
2
+ import knex from "knex";
3
+ import chalk from "chalk";
4
+ import { DateTime } from "luxon";
5
+ import { mkdir, readdir, unlink, writeFile } from "node:fs/promises";
6
+ import { exists } from "../utils/fs-utils.js";
7
+ import prompts from "prompts";
8
+ import { execSync } from "child_process";
9
+ import path from "path";
10
+ import { EntityManager } from "../entity/entity-manager.js";
11
+ import { Sonamu } from "../api/index.js";
12
+ import { ServiceUnavailableException } from "../exceptions/so-exceptions.js";
13
+ import { generateCreateCode, generateAlterCode } from "./code-generation.js";
14
+ import { getMigrationSetFromDB } from "./migration-set.js";
15
+ import { getMigrationSetFromEntity } from "./migration-set.js";
16
+ export class Migrator {
17
+ options;
18
+ targets;
19
+ constructor(options){
20
+ this.options = options;
21
+ const { dbConfig } = Sonamu;
22
+ if (this.options.mode === "dev") {
23
+ const devDB = knex(dbConfig.development_master);
24
+ const testDB = knex(dbConfig.test);
25
+ const fixtureLocalDB = knex(dbConfig.fixture_local);
26
+ const applyDBs = [
27
+ devDB,
28
+ testDB,
29
+ fixtureLocalDB
30
+ ];
31
+ if (dbConfig.fixture_local.connection.host !== dbConfig.fixture_remote.connection.host || dbConfig.fixture_local.connection.database !== dbConfig.fixture_remote.connection.database) {
32
+ const fixtureRemoteDB = knex(dbConfig.fixture_remote);
33
+ applyDBs.push(fixtureRemoteDB);
34
+ }
35
+ this.targets = {
36
+ compare: devDB,
37
+ pending: devDB,
38
+ shadow: testDB,
39
+ apply: applyDBs
40
+ };
41
+ } else if (this.options.mode === "deploy") {
42
+ const productionDB = knex(dbConfig.production_master);
43
+ const testDB = knex(dbConfig.test);
44
+ this.targets = {
45
+ pending: productionDB,
46
+ shadow: testDB,
47
+ apply: [
48
+ productionDB
49
+ ]
50
+ };
51
+ } else {
52
+ throw new Error(`잘못된 모드 ${this.options.mode} 입력`);
53
+ }
54
+ }
55
+ async getMigrationCodes() {
56
+ const srcMigrationsDir = path.join(Sonamu.apiRootPath, "src", "migrations"); // 이건 환경에 관계없이 항상 src에서 찾아야 해요.
57
+ if (!await exists(srcMigrationsDir)) {
58
+ await mkdir(srcMigrationsDir, {
59
+ recursive: true
60
+ });
61
+ }
62
+ const codes = (await readdir(srcMigrationsDir)).filter((f)=>f.endsWith(".ts")).map((f)=>({
63
+ name: f.replace(".ts", ""),
64
+ path: path.join(srcMigrationsDir, f)
65
+ })).sort((a, b)=>a.name < b.name ? 1 : -1); // 이름 내림차순 정렬(최신순)
66
+ return codes;
67
+ }
68
+ /**
69
+ * 타겟별 마이그레이션 상태와 코드 생성/준비 상태를 구해옵니다.
70
+ * 실제로 DB에 접근도 하고 마이그레이션 코드 파일도 확인하고,
71
+ * 필요하다면 적용할 수 있는 코드를 생성까지 해옵니다.
72
+ *
73
+ * CLI와 Sonamu UI에서 사용됩니다.
74
+ *
75
+ * @returns
76
+ */ async getStatus() {
77
+ const codes = await this.getMigrationCodes();
78
+ const connKeys = Object.keys(Sonamu.dbConfig).filter((key)=>key.endsWith("_slave") === false);
79
+ const statuses = await Promise.all(connKeys.map(async (connKey)=>{
80
+ const knexOptions = Sonamu.dbConfig[connKey];
81
+ const tConn = knex(knexOptions);
82
+ const status = await (async ()=>{
83
+ try {
84
+ return await tConn.migrate.status();
85
+ } catch (err) {
86
+ console.warn(chalk.yellow(`${connKey}의 마이그레이션 상태를 가져오는 데에 실패하였습니다. 데이터베이스가 올바르게 구성되지 않은 것 같습니다. 확인하시고 다시 시도해주세요.\n시도한 연결 설정:\n${JSON.stringify(knexOptions.connection, null, 2)}\n발생한 에러:\n${err}\n`));
87
+ return "error" /*클라이언트에서 에러 체크에 사용하는 리터럴입니다.*/ ;
88
+ }
89
+ })();
90
+ const pending = await (async ()=>{
91
+ try {
92
+ const [, fdList] = await tConn.migrate.list();
93
+ return fdList.map((fd)=>fd.file.replace(".ts", ""));
94
+ } catch (err) {
95
+ return [];
96
+ }
97
+ })();
98
+ const currentVersion = await (async ()=>{
99
+ try {
100
+ return await tConn.migrate.currentVersion();
101
+ } catch (err) {
102
+ return "error";
103
+ }
104
+ })();
105
+ const connection = knexOptions.connection;
106
+ await tConn.destroy();
107
+ return {
108
+ name: connKey.replace("_master", ""),
109
+ connKey,
110
+ connString: `mysql2://${connection.user ?? ""}@${connection.host}:${connection.port}/${connection.database}`,
111
+ currentVersion,
112
+ status,
113
+ pending
114
+ };
115
+ }));
116
+ const preparedCodes = await (async ()=>{
117
+ const status0conn = statuses.find((status)=>status.status === 0);
118
+ if (status0conn === undefined) {
119
+ console.warn(chalk.yellow(`While trying to prepare migration codes, we found that there is no database to compare migrations. We need at least one database where every migration is applied(status === 0). You might want to apply your existing migrations to one of the databases.`));
120
+ return [];
121
+ }
122
+ const compareDBconn = knex(Sonamu.dbConfig[status0conn.connKey]);
123
+ const genCodes = await this.compareMigrations(compareDBconn);
124
+ await compareDBconn.destroy();
125
+ return genCodes;
126
+ })();
127
+ return {
128
+ conns: statuses,
129
+ codes,
130
+ preparedCodes
131
+ };
132
+ /*
133
+ DB 마이그레이션 상태 확인
134
+ 1. 전체 DB설정에 대해서 현재 마이그레이션 상태 확인
135
+ - connKey: string
136
+ - status: number
137
+ - currentVersion: string
138
+ - list: { file: string; directory: string }[]
139
+
140
+ */ }
141
+ /**
142
+ * 마이그레이션을 적용하거나 롤백합니다.
143
+ * Sonamu UI에서 마이그레이션 작업을 수행할 때 사용됩니다.
144
+ *
145
+ * CLI와 Sonamu UI에서 사용됩니다.
146
+ *
147
+ * @param action 작업 유형 (apply/rollback)
148
+ * @param targets 작업 대상 DB 설정 키 (keyof SonamuDBConfig)
149
+ * @returns 작업 결과
150
+ */ async runAction(action, targets) {
151
+ // get uniq knex configs
152
+ const configs = _.uniqBy(targets.map((target)=>({
153
+ connKey: target,
154
+ options: Sonamu.dbConfig[target]
155
+ })).filter((c)=>c.options !== undefined), ({ options })=>`${options.connection.host}:${options.connection.port ?? 3306}/${options.connection.database}`);
156
+ // get connections
157
+ const conns = await Promise.all(configs.map(async (config)=>({
158
+ connKey: config.connKey,
159
+ knex: knex(config.options)
160
+ })));
161
+ // action
162
+ const result = await (async ()=>{
163
+ switch(action){
164
+ case "apply":
165
+ return Promise.all(conns.map(async ({ connKey, knex })=>{
166
+ const [batchNo, applied] = await knex.migrate.latest();
167
+ return {
168
+ connKey,
169
+ batchNo,
170
+ applied
171
+ };
172
+ }));
173
+ case "rollback":
174
+ return Promise.all(conns.map(async ({ connKey, knex })=>{
175
+ const [batchNo, applied] = await knex.migrate.rollback();
176
+ return {
177
+ connKey,
178
+ batchNo,
179
+ applied
180
+ };
181
+ }));
182
+ }
183
+ })();
184
+ // destroy
185
+ await Promise.all(conns.map(({ knex })=>{
186
+ return knex.destroy();
187
+ }));
188
+ return result;
189
+ }
190
+ /**
191
+ * 마이그레이션 코드 파일을 삭제합니다.
192
+ *
193
+ * Sonamu UI에서 사용됩니다.
194
+ *
195
+ * @param codeNames 삭제할 마이그레이션 코드 파일 이름 배열
196
+ * @returns 삭제된 마이그레이션 코드 파일 개수
197
+ */ async delCodes(codeNames) {
198
+ const { conns } = await this.getStatus();
199
+ if (conns.some((conn)=>{
200
+ return codeNames.some((codeName)=>conn.pending.includes(codeName) === false);
201
+ })) {
202
+ throw new Error("You cannot delete a migration file if there is already applied.");
203
+ }
204
+ const delFiles = codeNames.map((codeName)=>`${Sonamu.apiRootPath}/src/migrations/${codeName}.ts`);
205
+ const res = await Promise.all(delFiles.map(async (delFile)=>{
206
+ if (await exists(delFile)) {
207
+ console.log(chalk.red(`DELETE: ${delFile}`));
208
+ await unlink(delFile);
209
+ return delFiles.includes(".ts") ? 1 : 0;
210
+ }
211
+ return 0;
212
+ }));
213
+ return _.sum(res);
214
+ }
215
+ /**
216
+ * 마이그레이션 코드 파일을 생성합니다.
217
+ *
218
+ * Sonamu UI에서 사용됩니다.
219
+ *
220
+ * @returns 생성된 마이그레이션 코드 파일 개수
221
+ */ async generatePreparedCodes() {
222
+ const { preparedCodes } = await this.getStatus();
223
+ if (preparedCodes.length === 0) {
224
+ console.log(chalk.green("\n현재 모두 싱크된 상태입니다."));
225
+ return 0;
226
+ }
227
+ // 실제 코드 생성
228
+ const migrationsDir = `${Sonamu.apiRootPath}/src/migrations`;
229
+ for (const [index, pcode] of preparedCodes.entries()){
230
+ if (pcode.formatted) {
231
+ const dateTag = DateTime.local().plus({
232
+ seconds: index
233
+ }).toFormat("yyyyMMddHHmmss");
234
+ const filePath = `${migrationsDir}/${dateTag}_${pcode.title}.ts`;
235
+ await writeFile(filePath, pcode.formatted);
236
+ console.log(chalk.green(`MIGRTAION CREATED ${filePath}`));
237
+ }
238
+ }
239
+ return preparedCodes.length;
240
+ }
241
+ /**
242
+ * pending 마이그레이션 목록을 삭제합니다.
243
+ *
244
+ * CLI에서 사용됩니다.
245
+ */ async clearPendingList() {
246
+ const [, pendingList] = await this.targets.pending.migrate.list();
247
+ const migrationsDir = `${Sonamu.apiRootPath}/src/migrations`;
248
+ const delList = pendingList.map((df)=>{
249
+ return path.join(migrationsDir, df.file);
250
+ });
251
+ for (let p of delList){
252
+ if (await exists(p)) {
253
+ await unlink(p);
254
+ }
255
+ }
256
+ }
257
+ /**
258
+ * 마이그레이션 코드 파일을 확인합니다.
259
+ *
260
+ * CLI에서 사용됩니다.
261
+ */ async check() {
262
+ const codes = await this.compareMigrations(this.targets.compare);
263
+ if (codes.length === 0) {
264
+ console.log(chalk.green("\n현재 모두 싱크된 상태입니다."));
265
+ return;
266
+ }
267
+ // 현재 생성된 코드 표기
268
+ console.table(codes, [
269
+ "type",
270
+ "title"
271
+ ]);
272
+ console.log(codes[0]);
273
+ }
274
+ /**
275
+ * 마이그레이션을 수행합니다.
276
+ *
277
+ * runAction이 인자로 들어온 타겟들에 대해 주어진 동작(apply/rollback)을 수행한다면,
278
+ * 이 함수는 생성자로 들어온 connection(knex)들에 대해 마이그레이션을 수행합니다.
279
+ *
280
+ * CLI에서 사용됩니다.
281
+ */ async run() {
282
+ // pending 마이그레이션 확인
283
+ const [, pendingList] = await this.targets.pending.migrate.list();
284
+ if (pendingList.length > 0) {
285
+ console.log(chalk.red("pending 된 마이그레이션이 존재합니다."), pendingList.map((pending)=>pending.file));
286
+ // pending이 있는 경우 Shadow DB 테스트 진행 여부 컨펌
287
+ const answer = await prompts({
288
+ type: "confirm",
289
+ name: "value",
290
+ message: "Shadow DB 테스트를 진행하시겠습니까?",
291
+ initial: true
292
+ });
293
+ if (answer.value === false) {
294
+ return;
295
+ }
296
+ console.time(chalk.blue("Migrator - runShadowTest"));
297
+ await this.runShadowTest();
298
+ console.timeEnd(chalk.blue("Migrator - runShadowTest"));
299
+ await Promise.all(this.targets.apply.map(async (applyDb)=>{
300
+ const label = chalk.green(`APPLIED ${applyDb.client.connectionSettings.host} ${applyDb.client.database()}`);
301
+ console.time(label);
302
+ const [, ] = await applyDb.migrate.latest();
303
+ console.timeEnd(label);
304
+ }));
305
+ }
306
+ // Entity-DB간 비교하여 코드 생성 리턴
307
+ const codes = await this.compareMigrations(this.targets.compare);
308
+ if (codes.length === 0) {
309
+ console.log(chalk.green("\n현재 모두 싱크된 상태입니다."));
310
+ return;
311
+ }
312
+ // 현재 생성된 코드 표기
313
+ console.table(codes, [
314
+ "type",
315
+ "title"
316
+ ]);
317
+ /* DEBUG: 디버깅용 코드
318
+ codes.map((code) => console.log(code.formatted));
319
+ process.exit();
320
+ */ // 실제 파일 생성 프롬프트
321
+ const answer = await prompts({
322
+ type: "confirm",
323
+ name: "value",
324
+ message: "마이그레이션 코드를 생성하시겠습니까?",
325
+ initial: false
326
+ });
327
+ if (answer.value === false) {
328
+ return;
329
+ }
330
+ // 실제 코드 생성
331
+ const migrationsDir = `${Sonamu.apiRootPath}/src/migrations`;
332
+ for (const [index, code] of codes.entries()){
333
+ if (code.formatted) {
334
+ const dateTag = DateTime.local().plus({
335
+ seconds: index
336
+ }).toFormat("yyyyMMddHHmmss");
337
+ const filePath = `${migrationsDir}/${dateTag}_${code.title}.ts`;
338
+ await writeFile(filePath, code.formatted);
339
+ console.log(chalk.green(`MIGRTAION CREATED ${filePath}`));
340
+ }
341
+ }
342
+ }
343
+ /**
344
+ * 타겟으로 지정된 DB를 롤백합니다.
345
+ *
346
+ * runAction이 인자로 들어온 타겟들에 대해 주어진 동작(apply/rollback)을 수행한다면,
347
+ * 이 함수는 생성자로 들어온 connection(knex)들에 대해 롤백을 수행합니다.
348
+ *
349
+ * CLI에서 사용됩니다.
350
+ */ async rollback() {
351
+ console.time(chalk.red("rollback:"));
352
+ const rollbackAllResult = await Promise.all(this.targets.apply.map(async (db)=>{
353
+ await db.migrate.forceFreeMigrationsLock();
354
+ return db.migrate.rollback(undefined, false);
355
+ }));
356
+ console.dir({
357
+ rollbackAllResult
358
+ }, {
359
+ depth: null
360
+ });
361
+ console.timeEnd(chalk.red("rollback:"));
362
+ }
363
+ /**
364
+ * Shadow DB 테스트를 진행합니다.
365
+ *
366
+ * Sonamu UI에서 사용됩니다.
367
+ *
368
+ * @returns Shadow DB 테스트 결과
369
+ */ async runShadowTest() {
370
+ // ShadowDB 생성 후 테스트 진행
371
+ const tdb = knex(Sonamu.dbConfig.test);
372
+ const tdbConn = Sonamu.dbConfig.test.connection;
373
+ const shadowDatabase = tdbConn.database + "__migration_shadow";
374
+ const tmpSqlPath = `/tmp/${shadowDatabase}.sql`;
375
+ // 테스트DB 덤프 후 Database명 치환
376
+ console.log(chalk.magenta(`${tdbConn.database}의 데이터 ${tmpSqlPath}로 덤프`));
377
+ execSync(`mysqldump -h${tdbConn.host} -P${tdbConn.port ?? 3306} -u${tdbConn.user} -p'${tdbConn.password}' ${tdbConn.database} --single-transaction --no-create-db --triggers > ${tmpSqlPath};`);
378
+ execSync(`sed -i'' -e 's/\`${tdbConn.database}\`/\`${shadowDatabase}\`/g' ${tmpSqlPath};`);
379
+ // 기존 ShadowDB 리셋
380
+ console.log(chalk.magenta(`${shadowDatabase} 리셋`));
381
+ await tdb.raw(`DROP DATABASE IF EXISTS \`${shadowDatabase}\`;`);
382
+ await tdb.raw(`CREATE DATABASE \`${shadowDatabase}\`;`);
383
+ // ShadowDB 테이블 + 데이터 생성
384
+ console.log(chalk.magenta(`${shadowDatabase} 데이터베이스 생성`));
385
+ execSync(`mysql -h${tdbConn.host} -P${tdbConn.port ?? 3306} -u${tdbConn.user} -p'${tdbConn.password}' ${shadowDatabase} < ${tmpSqlPath};`);
386
+ // shadow db 테스트 진행
387
+ const sdb = knex({
388
+ ...Sonamu.dbConfig.test,
389
+ connection: {
390
+ ...tdbConn,
391
+ database: shadowDatabase,
392
+ password: tdbConn.password
393
+ }
394
+ });
395
+ // shadow db 테스트 진행
396
+ try {
397
+ const [batchNo, applied] = await sdb.migrate.latest();
398
+ console.log(chalk.green("Shadow DB 테스트에 성공했습니다!"), {
399
+ batchNo,
400
+ applied
401
+ });
402
+ // 생성한 Shadow DB 삭제
403
+ console.log(chalk.magenta(`${shadowDatabase} 삭제`));
404
+ await tdb.raw(`DROP DATABASE IF EXISTS \`${shadowDatabase}\`;`);
405
+ return [
406
+ {
407
+ connKey: "shadow",
408
+ batchNo,
409
+ applied
410
+ }
411
+ ];
412
+ } catch (e) {
413
+ console.error(e);
414
+ throw new ServiceUnavailableException("Shadow DB 테스트 진행 중 에러");
415
+ } finally{
416
+ await tdb.destroy();
417
+ }
418
+ }
419
+ /**
420
+ * 모든 DB를 롤백하고 전체 마이그레이션 파일을 삭제합니다.
421
+ *
422
+ * CLI에서 사용됩니다.
423
+ *
424
+ * @returns
425
+ */ async resetAll() {
426
+ const answer = await prompts({
427
+ type: "confirm",
428
+ name: "value",
429
+ message: "모든 DB를 롤백하고 전체 마이그레이션 파일을 삭제하시겠습니까?",
430
+ initial: false
431
+ });
432
+ if (answer.value === false) {
433
+ return;
434
+ }
435
+ console.time(chalk.red("rollback-all:"));
436
+ const rollbackAllResult = await Promise.all(this.targets.apply.map(async (db)=>{
437
+ await db.migrate.forceFreeMigrationsLock();
438
+ return db.migrate.rollback(undefined, true);
439
+ }));
440
+ console.log({
441
+ rollbackAllResult
442
+ });
443
+ console.timeEnd(chalk.red("rollback-all:"));
444
+ const migrationsDir = `${Sonamu.apiRootPath}/src/migrations`;
445
+ console.time(chalk.red("delete migration files"));
446
+ execSync(`rm -f ${migrationsDir}/*`);
447
+ execSync(`rm -f ${migrationsDir.replace("/src/", "/dist/")}/*`);
448
+ console.timeEnd(chalk.red("delete migration files"));
449
+ }
450
+ async compareMigrations(compareDB) {
451
+ // Entity 순회하여 싱크
452
+ const entityIds = EntityManager.getAllIds();
453
+ // 조인테이블 포함하여 Entity에서 MigrationSet 추출
454
+ const entitySetsWithJoinTable = entityIds.filter((entityId)=>EntityManager.get(entityId).props.length > 0).map((entityId)=>getMigrationSetFromEntity(EntityManager.get(entityId)));
455
+ // 조인테이블만 추출
456
+ const joinTablesWithDup = entitySetsWithJoinTable.map((entitySet)=>entitySet.joinTables).flat();
457
+ // 중복 제거 (중복인 경우 indexes를 병합)
458
+ const joinTables = Object.values(_.groupBy(joinTablesWithDup, (jt)=>jt.table)).map((tables)=>{
459
+ if (tables.length === 1) {
460
+ return tables[0];
461
+ }
462
+ return {
463
+ ...tables[0],
464
+ indexes: _.uniqBy(tables.flatMap((t)=>t.indexes), (index)=>[
465
+ index.type,
466
+ ...index.columns.sort()
467
+ ].join("-"))
468
+ };
469
+ });
470
+ // 조인테이블 포함하여 MigrationSet 배열
471
+ const entitySets = [
472
+ ...entitySetsWithJoinTable,
473
+ ...joinTables
474
+ ];
475
+ const codes = (await Promise.all(entitySets.map(async (entitySet)=>{
476
+ const dbSet = await getMigrationSetFromDB(compareDB, entitySet.table);
477
+ if (dbSet === null) {
478
+ // 기존 테이블 없음, 새로 테이블 생성
479
+ return await generateCreateCode(entitySet);
480
+ } else {
481
+ // 기존 테이블 존재하는 케이스
482
+ return await generateAlterCode(entitySet, dbSet);
483
+ }
484
+ }))).flat();
485
+ // normal 타입이 앞으로, foreign이 뒤로
486
+ codes.sort((codeA, codeB)=>{
487
+ if (codeA.type === "foreign" && codeB.type == "normal") {
488
+ return 1;
489
+ } else if (codeA.type === "normal" && codeB.type === "foreign") {
490
+ return -1;
491
+ } else {
492
+ return 0;
493
+ }
494
+ });
495
+ return codes;
496
+ }
497
+ /**
498
+ * 마이그레이션 대상 커넥션을 종료합니다.
499
+ *
500
+ * CLI에서 사용됩니다.
501
+ *
502
+ * @returns {Promise<void>} 종료 결과
503
+ */ async destroy() {
504
+ await Promise.all(this.targets.apply.map((db)=>{
505
+ return db.destroy();
506
+ }));
507
+ }
508
+ }
509
+
510
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWdyYXRpb24vbWlncmF0b3IudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgXyBmcm9tIFwibG9kYXNoLWVzXCI7XG5pbXBvcnQga25leCwgeyBLbmV4IH0gZnJvbSBcImtuZXhcIjtcbmltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIjtcbmltcG9ydCB7IERhdGVUaW1lIH0gZnJvbSBcImx1eG9uXCI7XG5pbXBvcnQgeyBta2RpciwgcmVhZGRpciwgdW5saW5rLCB3cml0ZUZpbGUgfSBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCB7IGV4aXN0cyB9IGZyb20gXCIuLi91dGlscy9mcy11dGlsc1wiO1xuaW1wb3J0IHByb21wdHMgZnJvbSBcInByb21wdHNcIjtcbmltcG9ydCB7IGV4ZWNTeW5jIH0gZnJvbSBcImNoaWxkX3Byb2Nlc3NcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBHZW5NaWdyYXRpb25Db2RlLCBNaWdyYXRpb25TZXQgfSBmcm9tIFwiLi4vdHlwZXMvdHlwZXNcIjtcbmltcG9ydCB7IEVudGl0eU1hbmFnZXIgfSBmcm9tIFwiLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyBTb25hbXUgfSBmcm9tIFwiLi4vYXBpXCI7XG5pbXBvcnQgeyBTZXJ2aWNlVW5hdmFpbGFibGVFeGNlcHRpb24gfSBmcm9tIFwiLi4vZXhjZXB0aW9ucy9zby1leGNlcHRpb25zXCI7XG5pbXBvcnQgeyBTb25hbXVEQkNvbmZpZyB9IGZyb20gXCIuLi9kYXRhYmFzZS9kYlwiO1xuaW1wb3J0IHsgZ2VuZXJhdGVDcmVhdGVDb2RlLCBnZW5lcmF0ZUFsdGVyQ29kZSB9IGZyb20gXCIuL2NvZGUtZ2VuZXJhdGlvblwiO1xuaW1wb3J0IHsgTWlncmF0aW9uU3RhdHVzLCBNaWdyYXRpb25Db2RlLCBDb25uU3RyaW5nIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IGdldE1pZ3JhdGlvblNldEZyb21EQiB9IGZyb20gXCIuL21pZ3JhdGlvbi1zZXRcIjtcbmltcG9ydCB7IGdldE1pZ3JhdGlvblNldEZyb21FbnRpdHkgfSBmcm9tIFwiLi9taWdyYXRpb24tc2V0XCI7XG5cbnR5cGUgTWlncmF0b3JNb2RlID0gXCJkZXZcIiB8IFwiZGVwbG95XCI7XG5leHBvcnQgdHlwZSBNaWdyYXRvck9wdGlvbnMgPSB7XG4gIHJlYWRvbmx5IG1vZGU6IE1pZ3JhdG9yTW9kZTtcbn07XG5cbmV4cG9ydCBjbGFzcyBNaWdyYXRvciB7XG4gIHRhcmdldHM6IHtcbiAgICBjb21wYXJlPzogS25leDtcbiAgICBwZW5kaW5nOiBLbmV4O1xuICAgIHNoYWRvdzogS25leDtcbiAgICBhcHBseTogS25leFtdO1xuICB9O1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogTWlncmF0b3JPcHRpb25zKSB7XG4gICAgY29uc3QgeyBkYkNvbmZpZyB9ID0gU29uYW11O1xuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5tb2RlID09PSBcImRldlwiKSB7XG4gICAgICBjb25zdCBkZXZEQiA9IGtuZXgoZGJDb25maWcuZGV2ZWxvcG1lbnRfbWFzdGVyKTtcbiAgICAgIGNvbnN0IHRlc3REQiA9IGtuZXgoZGJDb25maWcudGVzdCk7XG4gICAgICBjb25zdCBmaXh0dXJlTG9jYWxEQiA9IGtuZXgoZGJDb25maWcuZml4dHVyZV9sb2NhbCk7XG5cbiAgICAgIGNvbnN0IGFwcGx5REJzID0gW2RldkRCLCB0ZXN0REIsIGZpeHR1cmVMb2NhbERCXTtcbiAgICAgIGlmIChcbiAgICAgICAgKGRiQ29uZmlnLmZpeHR1cmVfbG9jYWwuY29ubmVjdGlvbiBhcyBLbmV4Lk15U3FsMkNvbm5lY3Rpb25Db25maWcpXG4gICAgICAgICAgLmhvc3QgIT09XG4gICAgICAgICAgKGRiQ29uZmlnLmZpeHR1cmVfcmVtb3RlLmNvbm5lY3Rpb24gYXMgS25leC5NeVNxbDJDb25uZWN0aW9uQ29uZmlnKVxuICAgICAgICAgICAgLmhvc3QgfHxcbiAgICAgICAgKGRiQ29uZmlnLmZpeHR1cmVfbG9jYWwuY29ubmVjdGlvbiBhcyBLbmV4Lk15U3FsMkNvbm5lY3Rpb25Db25maWcpXG4gICAgICAgICAgLmRhdGFiYXNlICE9PVxuICAgICAgICAgIChkYkNvbmZpZy5maXh0dXJlX3JlbW90ZS5jb25uZWN0aW9uIGFzIEtuZXguTXlTcWwyQ29ubmVjdGlvbkNvbmZpZylcbiAgICAgICAgICAgIC5kYXRhYmFzZVxuICAgICAgKSB7XG4gICAgICAgIGNvbnN0IGZpeHR1cmVSZW1vdGVEQiA9IGtuZXgoZGJDb25maWcuZml4dHVyZV9yZW1vdGUpO1xuICAgICAgICBhcHBseURCcy5wdXNoKGZpeHR1cmVSZW1vdGVEQik7XG4gICAgICB9XG5cbiAgICAgIHRoaXMudGFyZ2V0cyA9IHtcbiAgICAgICAgY29tcGFyZTogZGV2REIsXG4gICAgICAgIHBlbmRpbmc6IGRldkRCLFxuICAgICAgICBzaGFkb3c6IHRlc3REQixcbiAgICAgICAgYXBwbHk6IGFwcGx5REJzLFxuICAgICAgfTtcbiAgICB9IGVsc2UgaWYgKHRoaXMub3B0aW9ucy5tb2RlID09PSBcImRlcGxveVwiKSB7XG4gICAgICBjb25zdCBwcm9kdWN0aW9uREIgPSBrbmV4KGRiQ29uZmlnLnByb2R1Y3Rpb25fbWFzdGVyKTtcbiAgICAgIGNvbnN0IHRlc3REQiA9IGtuZXgoZGJDb25maWcudGVzdCk7XG5cbiAgICAgIHRoaXMudGFyZ2V0cyA9IHtcbiAgICAgICAgcGVuZGluZzogcHJvZHVjdGlvbkRCLFxuICAgICAgICBzaGFkb3c6IHRlc3REQixcbiAgICAgICAgYXBwbHk6IFtwcm9kdWN0aW9uREJdLFxuICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGDsnpjrqrvrkJwg66qo65OcICR7dGhpcy5vcHRpb25zLm1vZGV9IOyeheugpWApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZ2V0TWlncmF0aW9uQ29kZXMoKTogUHJvbWlzZTxNaWdyYXRpb25Db2RlW10+IHtcbiAgICBjb25zdCBzcmNNaWdyYXRpb25zRGlyID0gcGF0aC5qb2luKFNvbmFtdS5hcGlSb290UGF0aCwgXCJzcmNcIiwgXCJtaWdyYXRpb25zXCIpOyAvLyDsnbTqsbQg7ZmY6rK97JeQIOq0gOqzhOyXhuydtCDtla3sg4Egc3Jj7JeQ7IScIOywvuyVhOyVvCDtlbTsmpQuXG5cbiAgICBpZiAoIShhd2FpdCBleGlzdHMoc3JjTWlncmF0aW9uc0RpcikpKSB7XG4gICAgICBhd2FpdCBta2RpcihzcmNNaWdyYXRpb25zRGlyLCB7XG4gICAgICAgIHJlY3Vyc2l2ZTogdHJ1ZSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IGNvZGVzID0gKGF3YWl0IHJlYWRkaXIoc3JjTWlncmF0aW9uc0RpcikpXG4gICAgICAuZmlsdGVyKChmKSA9PiBmLmVuZHNXaXRoKFwiLnRzXCIpKVxuICAgICAgLm1hcCgoZikgPT4gKHtcbiAgICAgICAgbmFtZTogZi5yZXBsYWNlKFwiLnRzXCIsIFwiXCIpLFxuICAgICAgICBwYXRoOiBwYXRoLmpvaW4oc3JjTWlncmF0aW9uc0RpciwgZiksXG4gICAgICB9KSlcbiAgICAgIC5zb3J0KChhLCBiKSA9PiAoYS5uYW1lIDwgYi5uYW1lID8gMSA6IC0xKSk7IC8vIOydtOumhCDrgrTrprzssKjsiJwg7KCV66CsKOy1nOyLoOyInClcblxuICAgIHJldHVybiBjb2RlcztcbiAgfVxuXG4gIC8qKlxuICAgKiDtg4Dqsp/rs4Qg66eI7J206re466CI7J207IWYIOyDge2DnOyZgCDsvZTrk5wg7IOd7ISxL+ykgOu5hCDsg4Htg5zrpbwg6rWs7ZW07Ji164uI64ukLlxuICAgKiDsi6TsoJzroZwgRELsl5Ag7KCR6re864+EIO2VmOqzoCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvOuPhCDtmZXsnbjtlZjqs6AsXG4gICAqIO2VhOyalO2VmOuLpOuptCDsoIHsmqntlaAg7IiYIOyeiOuKlCDsvZTrk5zrpbwg7IOd7ISx6rmM7KeAIO2VtOyYteuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JmAIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEByZXR1cm5zXG4gICAqL1xuICBhc3luYyBnZXRTdGF0dXMoKTogUHJvbWlzZTxNaWdyYXRpb25TdGF0dXM+IHtcbiAgICBjb25zdCBjb2RlcyA9IGF3YWl0IHRoaXMuZ2V0TWlncmF0aW9uQ29kZXMoKTtcblxuICAgIGNvbnN0IGNvbm5LZXlzID0gT2JqZWN0LmtleXMoU29uYW11LmRiQ29uZmlnKS5maWx0ZXIoXG4gICAgICAoa2V5KSA9PiBrZXkuZW5kc1dpdGgoXCJfc2xhdmVcIikgPT09IGZhbHNlXG4gICAgKSBhcyAoa2V5b2YgdHlwZW9mIFNvbmFtdS5kYkNvbmZpZylbXTtcblxuICAgIGNvbnN0IHN0YXR1c2VzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBjb25uS2V5cy5tYXAoYXN5bmMgKGNvbm5LZXkpID0+IHtcbiAgICAgICAgY29uc3Qga25leE9wdGlvbnMgPSBTb25hbXUuZGJDb25maWdbY29ubktleV07XG4gICAgICAgIGNvbnN0IHRDb25uID0ga25leChrbmV4T3B0aW9ucyk7XG5cbiAgICAgICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgKGFzeW5jICgpID0+IHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRDb25uLm1pZ3JhdGUuc3RhdHVzKCk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICAgICAgICBgJHtjb25uS2V5feydmCDrp4jsnbTqt7jroIjsnbTshZgg7IOB7YOc66W8IOqwgOyguOyYpOuKlCDrjbDsl5Ag7Iuk7Yyo7ZWY7JiA7Iq164uI64ukLiDrjbDsnbTthLDrsqDsnbTsiqTqsIAg7Jis67CU66W06rKMIOq1rOyEseuQmOyngCDslYrsnYAg6rKDIOqwmeyKteuLiOuLpC4g7ZmV7J247ZWY7Iuc6rOgIOuLpOyLnCDsi5zrj4TtlbTso7zshLjsmpQuXFxu7Iuc64+E7ZWcIOyXsOqysCDshKTsoJU6XFxuJHtKU09OLnN0cmluZ2lmeShrbmV4T3B0aW9ucy5jb25uZWN0aW9uLCBudWxsLCAyKX1cXG7rsJzsg53tlZwg7JeQ65+sOlxcbiR7ZXJyfVxcbmBcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiBcImVycm9yXCIgLyrtgbTrnbzsnbTslrjtirjsl5DshJwg7JeQ65+sIOyytO2BrOyXkCDsgqzsmqntlZjripQg66as7YSw65+07J6F64uI64ukLiovO1xuICAgICAgICAgIH1cbiAgICAgICAgfSkoKTtcbiAgICAgICAgY29uc3QgcGVuZGluZyA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IFssIGZkTGlzdF0gPSBhd2FpdCB0Q29ubi5taWdyYXRlLmxpc3QoKTtcbiAgICAgICAgICAgIHJldHVybiBmZExpc3QubWFwKChmZDogeyBmaWxlOiBzdHJpbmcgfSkgPT5cbiAgICAgICAgICAgICAgZmQuZmlsZS5yZXBsYWNlKFwiLnRzXCIsIFwiXCIpXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICAgIH1cbiAgICAgICAgfSkoKTtcbiAgICAgICAgY29uc3QgY3VycmVudFZlcnNpb24gPSBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgdENvbm4ubWlncmF0ZS5jdXJyZW50VmVyc2lvbigpO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgcmV0dXJuIFwiZXJyb3JcIjtcbiAgICAgICAgICB9XG4gICAgICAgIH0pKCk7XG5cbiAgICAgICAgY29uc3QgY29ubmVjdGlvbiA9XG4gICAgICAgICAga25leE9wdGlvbnMuY29ubmVjdGlvbiBhcyBLbmV4Lk15U3FsMkNvbm5lY3Rpb25Db25maWc7XG5cbiAgICAgICAgYXdhaXQgdENvbm4uZGVzdHJveSgpO1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgbmFtZTogY29ubktleS5yZXBsYWNlKFwiX21hc3RlclwiLCBcIlwiKSxcbiAgICAgICAgICBjb25uS2V5LFxuICAgICAgICAgIGNvbm5TdHJpbmc6IGBteXNxbDI6Ly8ke2Nvbm5lY3Rpb24udXNlciA/PyBcIlwifUAke2Nvbm5lY3Rpb24uaG9zdH06JHtcbiAgICAgICAgICAgIGNvbm5lY3Rpb24ucG9ydFxuICAgICAgICAgIH0vJHtjb25uZWN0aW9uLmRhdGFiYXNlfWAgYXMgQ29ublN0cmluZyxcbiAgICAgICAgICBjdXJyZW50VmVyc2lvbixcbiAgICAgICAgICBzdGF0dXMsXG4gICAgICAgICAgcGVuZGluZyxcbiAgICAgICAgfTtcbiAgICAgIH0pXG4gICAgKTtcblxuICAgIGNvbnN0IHByZXBhcmVkQ29kZXM6IEdlbk1pZ3JhdGlvbkNvZGVbXSA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBzdGF0dXMwY29ubiA9IHN0YXR1c2VzLmZpbmQoKHN0YXR1cykgPT4gc3RhdHVzLnN0YXR1cyA9PT0gMCk7XG4gICAgICBpZiAoc3RhdHVzMGNvbm4gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgY2hhbGsueWVsbG93KFxuICAgICAgICAgICAgYFdoaWxlIHRyeWluZyB0byBwcmVwYXJlIG1pZ3JhdGlvbiBjb2Rlcywgd2UgZm91bmQgdGhhdCB0aGVyZSBpcyBubyBkYXRhYmFzZSB0byBjb21wYXJlIG1pZ3JhdGlvbnMuIFdlIG5lZWQgYXQgbGVhc3Qgb25lIGRhdGFiYXNlIHdoZXJlIGV2ZXJ5IG1pZ3JhdGlvbiBpcyBhcHBsaWVkKHN0YXR1cyA9PT0gMCkuIFlvdSBtaWdodCB3YW50IHRvIGFwcGx5IHlvdXIgZXhpc3RpbmcgbWlncmF0aW9ucyB0byBvbmUgb2YgdGhlIGRhdGFiYXNlcy5gXG4gICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gW107XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNvbXBhcmVEQmNvbm4gPSBrbmV4KFNvbmFtdS5kYkNvbmZpZ1tzdGF0dXMwY29ubi5jb25uS2V5XSk7XG4gICAgICBjb25zdCBnZW5Db2RlcyA9IGF3YWl0IHRoaXMuY29tcGFyZU1pZ3JhdGlvbnMoY29tcGFyZURCY29ubik7XG5cbiAgICAgIGF3YWl0IGNvbXBhcmVEQmNvbm4uZGVzdHJveSgpO1xuXG4gICAgICByZXR1cm4gZ2VuQ29kZXM7XG4gICAgfSkoKTtcblxuICAgIHJldHVybiB7XG4gICAgICBjb25uczogc3RhdHVzZXMsXG4gICAgICBjb2RlcyxcbiAgICAgIHByZXBhcmVkQ29kZXMsXG4gICAgfTtcbiAgICAvKlxuICAgIERCIOuniOydtOq3uOugiOydtOyFmCDsg4Htg5wg7ZmV7J24XG4gICAgMS4g7KCE7LK0IERC7ISk7KCV7JeQIOuMgO2VtOyEnCDtmITsnqwg66eI7J206re466CI7J207IWYIOyDge2DnCDtmZXsnbhcbiAgICAtIGNvbm5LZXk6IHN0cmluZ1xuICAgIC0gc3RhdHVzOiBudW1iZXJcbiAgICAtIGN1cnJlbnRWZXJzaW9uOiBzdHJpbmdcbiAgICAtIGxpc3Q6IHsgZmlsZTogc3RyaW5nOyBkaXJlY3Rvcnk6IHN0cmluZyB9W11cbiAgICBcbiAgICAqL1xuICB9XG5cbiAgLyoqXG4gICAqIOuniOydtOq3uOugiOydtOyFmOydhCDsoIHsmqntlZjqsbDrgpgg66Gk67Cx7ZWp64uI64ukLlxuICAgKiBTb25hbXUgVUnsl5DshJwg66eI7J206re466CI7J207IWYIOyekeyXheydhCDsiJjtlontlaAg65WMIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JmAIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEBwYXJhbSBhY3Rpb24g7J6R7JeFIOycoO2YlSAoYXBwbHkvcm9sbGJhY2spXG4gICAqIEBwYXJhbSB0YXJnZXRzIOyekeyXhSDrjIDsg4EgREIg7ISk7KCVIO2CpCAoa2V5b2YgU29uYW11REJDb25maWcpXG4gICAqIEByZXR1cm5zIOyekeyXhSDqsrDqs7xcbiAgICovXG4gIGFzeW5jIHJ1bkFjdGlvbihcbiAgICBhY3Rpb246IFwiYXBwbHlcIiB8IFwicm9sbGJhY2tcIixcbiAgICB0YXJnZXRzOiAoa2V5b2YgU29uYW11REJDb25maWcpW11cbiAgKTogUHJvbWlzZTxcbiAgICB7XG4gICAgICBjb25uS2V5OiBzdHJpbmc7XG4gICAgICBiYXRjaE5vOiBudW1iZXI7XG4gICAgICBhcHBsaWVkOiBzdHJpbmdbXTtcbiAgICB9W11cbiAgPiB7XG4gICAgLy8gZ2V0IHVuaXEga25leCBjb25maWdzXG4gICAgY29uc3QgY29uZmlncyA9IF8udW5pcUJ5KFxuICAgICAgdGFyZ2V0c1xuICAgICAgICAubWFwKCh0YXJnZXQpID0+ICh7XG4gICAgICAgICAgY29ubktleTogdGFyZ2V0LFxuICAgICAgICAgIG9wdGlvbnM6IFNvbmFtdS5kYkNvbmZpZ1t0YXJnZXQgYXMga2V5b2YgdHlwZW9mIFNvbmFtdS5kYkNvbmZpZ10sXG4gICAgICAgIH0pKVxuICAgICAgICAuZmlsdGVyKChjKSA9PiBjLm9wdGlvbnMgIT09IHVuZGVmaW5lZCksXG4gICAgICAoeyBvcHRpb25zIH0pID0+XG4gICAgICAgIGAkeyhvcHRpb25zLmNvbm5lY3Rpb24gYXMgS25leC5NeVNxbDJDb25uZWN0aW9uQ29uZmlnKS5ob3N0fToke1xuICAgICAgICAgIChvcHRpb25zLmNvbm5lY3Rpb24gYXMgS25leC5NeVNxbDJDb25uZWN0aW9uQ29uZmlnKS5wb3J0ID8/IDMzMDZcbiAgICAgICAgfS8keyhvcHRpb25zLmNvbm5lY3Rpb24gYXMgS25leC5NeVNxbDJDb25uZWN0aW9uQ29uZmlnKS5kYXRhYmFzZX1gXG4gICAgKTtcblxuICAgIC8vIGdldCBjb25uZWN0aW9uc1xuICAgIGNvbnN0IGNvbm5zID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBjb25maWdzLm1hcChhc3luYyAoY29uZmlnKSA9PiAoe1xuICAgICAgICBjb25uS2V5OiBjb25maWcuY29ubktleSxcbiAgICAgICAga25leDoga25leChjb25maWcub3B0aW9ucyksXG4gICAgICB9KSlcbiAgICApO1xuXG4gICAgLy8gYWN0aW9uXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgKGFzeW5jICgpID0+IHtcbiAgICAgIHN3aXRjaCAoYWN0aW9uKSB7XG4gICAgICAgIGNhc2UgXCJhcHBseVwiOlxuICAgICAgICAgIHJldHVybiBQcm9taXNlLmFsbChcbiAgICAgICAgICAgIGNvbm5zLm1hcChhc3luYyAoeyBjb25uS2V5LCBrbmV4IH0pID0+IHtcbiAgICAgICAgICAgICAgY29uc3QgW2JhdGNoTm8sIGFwcGxpZWRdID0gYXdhaXQga25leC5taWdyYXRlLmxhdGVzdCgpO1xuICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGNvbm5LZXksXG4gICAgICAgICAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgICAgICAgICBhcHBsaWVkLFxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICApO1xuICAgICAgICBjYXNlIFwicm9sbGJhY2tcIjpcbiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICBjb25ucy5tYXAoYXN5bmMgKHsgY29ubktleSwga25leCB9KSA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IFtiYXRjaE5vLCBhcHBsaWVkXSA9IGF3YWl0IGtuZXgubWlncmF0ZS5yb2xsYmFjaygpO1xuICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGNvbm5LZXksXG4gICAgICAgICAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgICAgICAgICBhcHBsaWVkLFxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICApO1xuICAgICAgfVxuICAgIH0pKCk7XG5cbiAgICAvLyBkZXN0cm95XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBjb25ucy5tYXAoKHsga25leCB9KSA9PiB7XG4gICAgICAgIHJldHVybiBrbmV4LmRlc3Ryb3koKTtcbiAgICAgIH0pXG4gICAgKTtcblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICog66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbzsnYQg7IKt7KCc7ZWp64uI64ukLlxuICAgKlxuICAgKiBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcGFyYW0gY29kZU5hbWVzIOyCreygnO2VoCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDsnbTrpoQg67Cw7Je0XG4gICAqIEByZXR1cm5zIOyCreygnOuQnCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDqsJzsiJhcbiAgICovXG4gIGFzeW5jIGRlbENvZGVzKGNvZGVOYW1lczogc3RyaW5nW10pOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgY29ubnMgfSA9IGF3YWl0IHRoaXMuZ2V0U3RhdHVzKCk7XG4gICAgaWYgKFxuICAgICAgY29ubnMuc29tZSgoY29ubikgPT4ge1xuICAgICAgICByZXR1cm4gY29kZU5hbWVzLnNvbWUoXG4gICAgICAgICAgKGNvZGVOYW1lKSA9PiBjb25uLnBlbmRpbmcuaW5jbHVkZXMoY29kZU5hbWUpID09PSBmYWxzZVxuICAgICAgICApO1xuICAgICAgfSlcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJZb3UgY2Fubm90IGRlbGV0ZSBhIG1pZ3JhdGlvbiBmaWxlIGlmIHRoZXJlIGlzIGFscmVhZHkgYXBwbGllZC5cIlxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCBkZWxGaWxlcyA9IGNvZGVOYW1lcy5tYXAoXG4gICAgICAoY29kZU5hbWUpID0+IGAke1NvbmFtdS5hcGlSb290UGF0aH0vc3JjL21pZ3JhdGlvbnMvJHtjb2RlTmFtZX0udHNgXG4gICAgKTtcblxuICAgIGNvbnN0IHJlcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgZGVsRmlsZXMubWFwKGFzeW5jIChkZWxGaWxlKSA9PiB7XG4gICAgICAgIGlmIChhd2FpdCBleGlzdHMoZGVsRmlsZSkpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5yZWQoYERFTEVURTogJHtkZWxGaWxlfWApKTtcbiAgICAgICAgICBhd2FpdCB1bmxpbmsoZGVsRmlsZSk7XG4gICAgICAgICAgcmV0dXJuIGRlbEZpbGVzLmluY2x1ZGVzKFwiLnRzXCIpID8gMSA6IDA7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIDA7XG4gICAgICB9KVxuICAgICk7XG4gICAgcmV0dXJuIF8uc3VtKHJlcyk7XG4gIH1cblxuICAvKipcbiAgICog66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbzsnYQg7IOd7ISx7ZWp64uI64ukLlxuICAgKlxuICAgKiBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcmV0dXJucyDsg53shLHrkJwg66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbwg6rCc7IiYXG4gICAqL1xuICBhc3luYyBnZW5lcmF0ZVByZXBhcmVkQ29kZXMoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCB7IHByZXBhcmVkQ29kZXMgfSA9IGF3YWl0IHRoaXMuZ2V0U3RhdHVzKCk7XG4gICAgaWYgKHByZXBhcmVkQ29kZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihcIlxcbu2YhOyerCDrqqjrkZAg7Iux7YGs65CcIOyDge2DnOyeheuLiOuLpC5cIikpO1xuICAgICAgcmV0dXJuIDA7XG4gICAgfVxuXG4gICAgLy8g7Iuk7KCcIOy9lOuTnCDsg53shLFcbiAgICBjb25zdCBtaWdyYXRpb25zRGlyID0gYCR7U29uYW11LmFwaVJvb3RQYXRofS9zcmMvbWlncmF0aW9uc2A7XG5cbiAgICBmb3IgKGNvbnN0IFtpbmRleCwgcGNvZGVdIG9mIHByZXBhcmVkQ29kZXMuZW50cmllcygpKSB7XG4gICAgICBpZiAocGNvZGUuZm9ybWF0dGVkKSB7XG4gICAgICAgIGNvbnN0IGRhdGVUYWcgPSBEYXRlVGltZS5sb2NhbCgpXG4gICAgICAgICAgLnBsdXMoeyBzZWNvbmRzOiBpbmRleCB9KVxuICAgICAgICAgIC50b0Zvcm1hdChcInl5eXlNTWRkSEhtbXNzXCIpO1xuICAgICAgICBjb25zdCBmaWxlUGF0aCA9IGAke21pZ3JhdGlvbnNEaXJ9LyR7ZGF0ZVRhZ31fJHtwY29kZS50aXRsZX0udHNgO1xuICAgICAgICBhd2FpdCB3cml0ZUZpbGUoZmlsZVBhdGgsIHBjb2RlLmZvcm1hdHRlZCEpO1xuICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihgTUlHUlRBSU9OIENSRUFURUQgJHtmaWxlUGF0aH1gKSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHByZXBhcmVkQ29kZXMubGVuZ3RoO1xuICB9XG5cbiAgLyoqXG4gICAqIHBlbmRpbmcg66eI7J206re466CI7J207IWYIOuqqeuhneydhCDsgq3soJztlanri4jri6QuXG4gICAqXG4gICAqIENMSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqL1xuICBhc3luYyBjbGVhclBlbmRpbmdMaXN0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IFssIHBlbmRpbmdMaXN0XSA9IChhd2FpdCB0aGlzLnRhcmdldHMucGVuZGluZy5taWdyYXRlLmxpc3QoKSkgYXMgW1xuICAgICAgdW5rbm93bixcbiAgICAgIHtcbiAgICAgICAgZmlsZTogc3RyaW5nO1xuICAgICAgICBkaXJlY3Rvcnk6IHN0cmluZztcbiAgICAgIH1bXSxcbiAgICBdO1xuICAgIGNvbnN0IG1pZ3JhdGlvbnNEaXIgPSBgJHtTb25hbXUuYXBpUm9vdFBhdGh9L3NyYy9taWdyYXRpb25zYDtcbiAgICBjb25zdCBkZWxMaXN0ID0gcGVuZGluZ0xpc3QubWFwKChkZikgPT4ge1xuICAgICAgcmV0dXJuIHBhdGguam9pbihtaWdyYXRpb25zRGlyLCBkZi5maWxlKTtcbiAgICB9KTtcbiAgICBmb3IgKGxldCBwIG9mIGRlbExpc3QpIHtcbiAgICAgIGlmIChhd2FpdCBleGlzdHMocCkpIHtcbiAgICAgICAgYXdhaXQgdW5saW5rKHApO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvOydhCDtmZXsnbjtlanri4jri6QuXG4gICAqXG4gICAqIENMSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqL1xuICBhc3luYyBjaGVjaygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBjb2RlcyA9IGF3YWl0IHRoaXMuY29tcGFyZU1pZ3JhdGlvbnModGhpcy50YXJnZXRzLmNvbXBhcmUhKTtcbiAgICBpZiAoY29kZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihcIlxcbu2YhOyerCDrqqjrkZAg7Iux7YGs65CcIOyDge2DnOyeheuLiOuLpC5cIikpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIO2YhOyerCDsg53shLHrkJwg7L2U65OcIO2RnOq4sFxuICAgIGNvbnNvbGUudGFibGUoY29kZXMsIFtcInR5cGVcIiwgXCJ0aXRsZVwiXSk7XG4gICAgY29uc29sZS5sb2coY29kZXNbMF0pO1xuICB9XG5cbiAgLyoqXG4gICAqIOuniOydtOq3uOugiOydtOyFmOydhCDsiJjtlontlanri4jri6QuXG4gICAqXG4gICAqIHJ1bkFjdGlvbuydtCDsnbjsnpDroZwg65Ok7Ja07JioIO2DgOqyn+uTpOyXkCDrjIDtlbQg7KO87Ja07KeEIOuPmeyekShhcHBseS9yb2xsYmFjaynsnYQg7IiY7ZaJ7ZWc64uk66m0LFxuICAgKiDsnbQg7ZWo7IiY64qUIOyDneyEseyekOuhnCDrk6TslrTsmKggY29ubmVjdGlvbihrbmV4KeuTpOyXkCDrjIDtlbQg66eI7J206re466CI7J207IWY7J2EIOyImO2Wie2VqeuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICovXG4gIGFzeW5jIHJ1bigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyBwZW5kaW5nIOuniOydtOq3uOugiOydtOyFmCDtmZXsnbhcbiAgICBjb25zdCBbLCBwZW5kaW5nTGlzdF0gPSBhd2FpdCB0aGlzLnRhcmdldHMucGVuZGluZy5taWdyYXRlLmxpc3QoKTtcbiAgICBpZiAocGVuZGluZ0xpc3QubGVuZ3RoID4gMCkge1xuICAgICAgY29uc29sZS5sb2coXG4gICAgICAgIGNoYWxrLnJlZChcInBlbmRpbmcg65CcIOuniOydtOq3uOugiOydtOyFmOydtCDsobTsnqztlanri4jri6QuXCIpLFxuICAgICAgICBwZW5kaW5nTGlzdC5tYXAoKHBlbmRpbmc6IGFueSkgPT4gcGVuZGluZy5maWxlKVxuICAgICAgKTtcblxuICAgICAgLy8gcGVuZGluZ+ydtCDsnojripQg6rK97JqwIFNoYWRvdyBEQiDthYzsiqTtirgg7KeE7ZaJIOyXrOu2gCDsu6jtjoxcbiAgICAgIGNvbnN0IGFuc3dlciA9IGF3YWl0IHByb21wdHMoe1xuICAgICAgICB0eXBlOiBcImNvbmZpcm1cIixcbiAgICAgICAgbmFtZTogXCJ2YWx1ZVwiLFxuICAgICAgICBtZXNzYWdlOiBcIlNoYWRvdyBEQiDthYzsiqTtirjrpbwg7KeE7ZaJ7ZWY7Iuc6rKg7Iq164uI6rmMP1wiLFxuICAgICAgICBpbml0aWFsOiB0cnVlLFxuICAgICAgfSk7XG4gICAgICBpZiAoYW5zd2VyLnZhbHVlID09PSBmYWxzZSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnNvbGUudGltZShjaGFsay5ibHVlKFwiTWlncmF0b3IgLSBydW5TaGFkb3dUZXN0XCIpKTtcbiAgICAgIGF3YWl0IHRoaXMucnVuU2hhZG93VGVzdCgpO1xuICAgICAgY29uc29sZS50aW1lRW5kKGNoYWxrLmJsdWUoXCJNaWdyYXRvciAtIHJ1blNoYWRvd1Rlc3RcIikpO1xuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIHRoaXMudGFyZ2V0cy5hcHBseS5tYXAoYXN5bmMgKGFwcGx5RGIpID0+IHtcbiAgICAgICAgICBjb25zdCBsYWJlbCA9IGNoYWxrLmdyZWVuKFxuICAgICAgICAgICAgYEFQUExJRUQgJHtcbiAgICAgICAgICAgICAgYXBwbHlEYi5jbGllbnQuY29ubmVjdGlvblNldHRpbmdzLmhvc3RcbiAgICAgICAgICAgIH0gJHthcHBseURiLmNsaWVudC5kYXRhYmFzZSgpfWBcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnNvbGUudGltZShsYWJlbCk7XG4gICAgICAgICAgY29uc3QgWyxdID0gYXdhaXQgYXBwbHlEYi5taWdyYXRlLmxhdGVzdCgpO1xuICAgICAgICAgIGNvbnNvbGUudGltZUVuZChsYWJlbCk7XG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIEVudGl0eS1EQuqwhCDruYTqtZDtlZjsl6wg7L2U65OcIOyDneyEsSDrpqzthLRcbiAgICBjb25zdCBjb2RlcyA9IGF3YWl0IHRoaXMuY29tcGFyZU1pZ3JhdGlvbnModGhpcy50YXJnZXRzLmNvbXBhcmUhKTtcbiAgICBpZiAoY29kZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihcIlxcbu2YhOyerCDrqqjrkZAg7Iux7YGs65CcIOyDge2DnOyeheuLiOuLpC5cIikpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIO2YhOyerCDsg53shLHrkJwg7L2U65OcIO2RnOq4sFxuICAgIGNvbnNvbGUudGFibGUoY29kZXMsIFtcInR5cGVcIiwgXCJ0aXRsZVwiXSk7XG5cbiAgICAvKiBERUJVRzog65SU67KE6rmF7JqpIOy9lOuTnFxuICAgIGNvZGVzLm1hcCgoY29kZSkgPT4gY29uc29sZS5sb2coY29kZS5mb3JtYXR0ZWQpKTtcbiAgICBwcm9jZXNzLmV4aXQoKTtcbiAgICAgKi9cblxuICAgIC8vIOyLpOygnCDtjIzsnbwg7IOd7ISxIO2UhOuhrO2UhO2KuFxuICAgIGNvbnN0IGFuc3dlciA9IGF3YWl0IHByb21wdHMoe1xuICAgICAgdHlwZTogXCJjb25maXJtXCIsXG4gICAgICBuYW1lOiBcInZhbHVlXCIsXG4gICAgICBtZXNzYWdlOiBcIuuniOydtOq3uOugiOydtOyFmCDsvZTrk5zrpbwg7IOd7ISx7ZWY7Iuc6rKg7Iq164uI6rmMP1wiLFxuICAgICAgaW5pdGlhbDogZmFsc2UsXG4gICAgfSk7XG4gICAgaWYgKGFuc3dlci52YWx1ZSA9PT0gZmFsc2UpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyDsi6TsoJwg7L2U65OcIOyDneyEsVxuICAgIGNvbnN0IG1pZ3JhdGlvbnNEaXIgPSBgJHtTb25hbXUuYXBpUm9vdFBhdGh9L3NyYy9taWdyYXRpb25zYDtcblxuICAgIGZvciAoY29uc3QgW2luZGV4LCBjb2RlXSBvZiBjb2Rlcy5lbnRyaWVzKCkpIHtcbiAgICAgIGlmIChjb2RlLmZvcm1hdHRlZCkge1xuICAgICAgICBjb25zdCBkYXRlVGFnID0gRGF0ZVRpbWUubG9jYWwoKVxuICAgICAgICAgIC5wbHVzKHsgc2Vjb25kczogaW5kZXggfSlcbiAgICAgICAgICAudG9Gb3JtYXQoXCJ5eXl5TU1kZEhIbW1zc1wiKTtcbiAgICAgICAgY29uc3QgZmlsZVBhdGggPSBgJHttaWdyYXRpb25zRGlyfS8ke2RhdGVUYWd9XyR7Y29kZS50aXRsZX0udHNgO1xuICAgICAgICBhd2FpdCB3cml0ZUZpbGUoZmlsZVBhdGgsIGNvZGUuZm9ybWF0dGVkISk7XG4gICAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKGBNSUdSVEFJT04gQ1JFQVRFRCAke2ZpbGVQYXRofWApKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICog7YOA6rKf7Jy866GcIOyngOygleuQnCBEQuulvCDroaTrsLHtlanri4jri6QuXG4gICAqXG4gICAqIHJ1bkFjdGlvbuydtCDsnbjsnpDroZwg65Ok7Ja07JioIO2DgOqyn+uTpOyXkCDrjIDtlbQg7KO87Ja07KeEIOuPmeyekShhcHBseS9yb2xsYmFjaynsnYQg7IiY7ZaJ7ZWc64uk66m0LFxuICAgKiDsnbQg7ZWo7IiY64qUIOyDneyEseyekOuhnCDrk6TslrTsmKggY29ubmVjdGlvbihrbmV4KeuTpOyXkCDrjIDtlbQg66Gk67Cx7J2EIOyImO2Wie2VqeuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICovXG4gIGFzeW5jIHJvbGxiYWNrKCkge1xuICAgIGNvbnNvbGUudGltZShjaGFsay5yZWQoXCJyb2xsYmFjazpcIikpO1xuICAgIGNvbnN0IHJvbGxiYWNrQWxsUmVzdWx0ID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICB0aGlzLnRhcmdldHMuYXBwbHkubWFwKGFzeW5jIChkYikgPT4ge1xuICAgICAgICBhd2FpdCBkYi5taWdyYXRlLmZvcmNlRnJlZU1pZ3JhdGlvbnNMb2NrKCk7XG4gICAgICAgIHJldHVybiBkYi5taWdyYXRlLnJvbGxiYWNrKHVuZGVmaW5lZCwgZmFsc2UpO1xuICAgICAgfSlcbiAgICApO1xuICAgIGNvbnNvbGUuZGlyKHsgcm9sbGJhY2tBbGxSZXN1bHQgfSwgeyBkZXB0aDogbnVsbCB9KTtcbiAgICBjb25zb2xlLnRpbWVFbmQoY2hhbGsucmVkKFwicm9sbGJhY2s6XCIpKTtcbiAgfVxuICAvKipcbiAgICogU2hhZG93IERCIO2FjOyKpO2KuOulvCDsp4Ttlontlanri4jri6QuXG4gICAqXG4gICAqIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEByZXR1cm5zIFNoYWRvdyBEQiDthYzsiqTtirgg6rKw6rO8XG4gICAqL1xuICBhc3luYyBydW5TaGFkb3dUZXN0KCk6IFByb21pc2U8XG4gICAge1xuICAgICAgY29ubktleTogc3RyaW5nO1xuICAgICAgYmF0Y2hObzogbnVtYmVyO1xuICAgICAgYXBwbGllZDogc3RyaW5nW107XG4gICAgfVtdXG4gID4ge1xuICAgIC8vIFNoYWRvd0RCIOyDneyEsSDtm4Qg7YWM7Iqk7Yq4IOynhO2WiVxuICAgIGNvbnN0IHRkYiA9IGtuZXgoU29uYW11LmRiQ29uZmlnLnRlc3QpO1xuICAgIGNvbnN0IHRkYkNvbm4gPSBTb25hbXUuZGJDb25maWcudGVzdFxuICAgICAgLmNvbm5lY3Rpb24gYXMgS25leC5NeVNxbDJDb25uZWN0aW9uQ29uZmlnO1xuICAgIGNvbnN0IHNoYWRvd0RhdGFiYXNlID0gdGRiQ29ubi5kYXRhYmFzZSArIFwiX19taWdyYXRpb25fc2hhZG93XCI7XG4gICAgY29uc3QgdG1wU3FsUGF0aCA9IGAvdG1wLyR7c2hhZG93RGF0YWJhc2V9LnNxbGA7XG5cbiAgICAvLyDthYzsiqTtirhEQiDrjaTtlIQg7ZuEIERhdGFiYXNl66qFIOy5mO2ZmFxuICAgIGNvbnNvbGUubG9nKFxuICAgICAgY2hhbGsubWFnZW50YShgJHt0ZGJDb25uLmRhdGFiYXNlfeydmCDrjbDsnbTthLAgJHt0bXBTcWxQYXRofeuhnCDrjaTtlIRgKVxuICAgICk7XG4gICAgZXhlY1N5bmMoXG4gICAgICBgbXlzcWxkdW1wIC1oJHt0ZGJDb25uLmhvc3R9IC1QJHt0ZGJDb25uLnBvcnQgPz8gMzMwNn0gLXUke3RkYkNvbm4udXNlcn0gLXAnJHt0ZGJDb25uLnBhc3N3b3JkfScgJHt0ZGJDb25uLmRhdGFiYXNlfSAtLXNpbmdsZS10cmFuc2FjdGlvbiAtLW5vLWNyZWF0ZS1kYiAtLXRyaWdnZXJzID4gJHt0bXBTcWxQYXRofTtgXG4gICAgKTtcbiAgICBleGVjU3luYyhcbiAgICAgIGBzZWQgLWknJyAtZSAncy9cXGAke3RkYkNvbm4uZGF0YWJhc2V9XFxgL1xcYCR7c2hhZG93RGF0YWJhc2V9XFxgL2cnICR7dG1wU3FsUGF0aH07YFxuICAgICk7XG5cbiAgICAvLyDquLDsobQgU2hhZG93REIg66as7IWLXG4gICAgY29uc29sZS5sb2coY2hhbGsubWFnZW50YShgJHtzaGFkb3dEYXRhYmFzZX0g66as7IWLYCkpO1xuICAgIGF3YWl0IHRkYi5yYXcoYERST1AgREFUQUJBU0UgSUYgRVhJU1RTIFxcYCR7c2hhZG93RGF0YWJhc2V9XFxgO2ApO1xuICAgIGF3YWl0IHRkYi5yYXcoYENSRUFURSBEQVRBQkFTRSBcXGAke3NoYWRvd0RhdGFiYXNlfVxcYDtgKTtcblxuICAgIC8vIFNoYWRvd0RCIO2FjOydtOu4lCArIOuNsOydtO2EsCDsg53shLFcbiAgICBjb25zb2xlLmxvZyhjaGFsay5tYWdlbnRhKGAke3NoYWRvd0RhdGFiYXNlfSDrjbDsnbTthLDrsqDsnbTsiqQg7IOd7ISxYCkpO1xuICAgIGV4ZWNTeW5jKFxuICAgICAgYG15c3FsIC1oJHt0ZGJDb25uLmhvc3R9IC1QJHt0ZGJDb25uLnBvcnQgPz8gMzMwNn0gLXUke3RkYkNvbm4udXNlcn0gLXAnJHt0ZGJDb25uLnBhc3N3b3JkfScgJHtzaGFkb3dEYXRhYmFzZX0gPCAke3RtcFNxbFBhdGh9O2BcbiAgICApO1xuXG4gICAgLy8gc2hhZG93IGRiIO2FjOyKpO2KuCDsp4TtlolcbiAgICBjb25zdCBzZGIgPSBrbmV4KHtcbiAgICAgIC4uLlNvbmFtdS5kYkNvbmZpZy50ZXN0LFxuICAgICAgY29ubmVjdGlvbjoge1xuICAgICAgICAuLi50ZGJDb25uLFxuICAgICAgICBkYXRhYmFzZTogc2hhZG93RGF0YWJhc2UsXG4gICAgICAgIHBhc3N3b3JkOiB0ZGJDb25uLnBhc3N3b3JkLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIC8vIHNoYWRvdyBkYiDthYzsiqTtirgg7KeE7ZaJXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IFtiYXRjaE5vLCBhcHBsaWVkXSA9IGF3YWl0IHNkYi5taWdyYXRlLmxhdGVzdCgpO1xuICAgICAgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oXCJTaGFkb3cgREIg7YWM7Iqk7Yq47JeQIOyEseqzte2WiOyKteuLiOuLpCFcIiksIHtcbiAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgYXBwbGllZCxcbiAgICAgIH0pO1xuXG4gICAgICAvLyDsg53shLHtlZwgU2hhZG93IERCIOyCreygnFxuICAgICAgY29uc29sZS5sb2coY2hhbGsubWFnZW50YShgJHtzaGFkb3dEYXRhYmFzZX0g7IKt7KCcYCkpO1xuICAgICAgYXdhaXQgdGRiLnJhdyhgRFJPUCBEQVRBQkFTRSBJRiBFWElTVFMgXFxgJHtzaGFkb3dEYXRhYmFzZX1cXGA7YCk7XG5cbiAgICAgIHJldHVybiBbXG4gICAgICAgIHtcbiAgICAgICAgICBjb25uS2V5OiBcInNoYWRvd1wiLFxuICAgICAgICAgIGJhdGNoTm8sXG4gICAgICAgICAgYXBwbGllZCxcbiAgICAgICAgfSxcbiAgICAgIF07XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgY29uc29sZS5lcnJvcihlKTtcbiAgICAgIHRocm93IG5ldyBTZXJ2aWNlVW5hdmFpbGFibGVFeGNlcHRpb24oXCJTaGFkb3cgREIg7YWM7Iqk7Yq4IOynhO2WiSDspJEg7JeQ65+sXCIpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBhd2FpdCB0ZGIuZGVzdHJveSgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiDrqqjrk6AgRELrpbwg66Gk67Cx7ZWY6rOgIOyghOyytCDrp4jsnbTqt7jroIjsnbTshZgg7YyM7J287J2EIOyCreygnO2VqeuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQHJldHVybnNcbiAgICovXG4gIGFzeW5jIHJlc2V0QWxsKCkge1xuICAgIGNvbnN0IGFuc3dlciA9IGF3YWl0IHByb21wdHMoe1xuICAgICAgdHlwZTogXCJjb25maXJtXCIsXG4gICAgICBuYW1lOiBcInZhbHVlXCIsXG4gICAgICBtZXNzYWdlOiBcIuuqqOuToCBEQuulvCDroaTrsLHtlZjqs6Ag7KCE7LK0IOuniOydtOq3uOugiOydtOyFmCDtjIzsnbzsnYQg7IKt7KCc7ZWY7Iuc6rKg7Iq164uI6rmMP1wiLFxuICAgICAgaW5pdGlhbDogZmFsc2UsXG4gICAgfSk7XG4gICAgaWYgKGFuc3dlci52YWx1ZSA9PT0gZmFsc2UpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zb2xlLnRpbWUoY2hhbGsucmVkKFwicm9sbGJhY2stYWxsOlwiKSk7XG4gICAgY29uc3Qgcm9sbGJhY2tBbGxSZXN1bHQgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIHRoaXMudGFyZ2V0cy5hcHBseS5tYXAoYXN5bmMgKGRiKSA9PiB7XG4gICAgICAgIGF3YWl0IGRiLm1pZ3JhdGUuZm9yY2VGcmVlTWlncmF0aW9uc0xvY2soKTtcbiAgICAgICAgcmV0dXJuIGRiLm1pZ3JhdGUucm9sbGJhY2sodW5kZWZpbmVkLCB0cnVlKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgICBjb25zb2xlLmxvZyh7IHJvbGxiYWNrQWxsUmVzdWx0IH0pO1xuICAgIGNvbnNvbGUudGltZUVuZChjaGFsay5yZWQoXCJyb2xsYmFjay1hbGw6XCIpKTtcblxuICAgIGNvbnN0IG1pZ3JhdGlvbnNEaXIgPSBgJHtTb25hbXUuYXBpUm9vdFBhdGh9L3NyYy9taWdyYXRpb25zYDtcbiAgICBjb25zb2xlLnRpbWUoY2hhbGsucmVkKFwiZGVsZXRlIG1pZ3JhdGlvbiBmaWxlc1wiKSk7XG4gICAgZXhlY1N5bmMoYHJtIC1mICR7bWlncmF0aW9uc0Rpcn0vKmApO1xuICAgIGV4ZWNTeW5jKGBybSAtZiAke21pZ3JhdGlvbnNEaXIucmVwbGFjZShcIi9zcmMvXCIsIFwiL2Rpc3QvXCIpfS8qYCk7XG4gICAgY29uc29sZS50aW1lRW5kKGNoYWxrLnJlZChcImRlbGV0ZSBtaWdyYXRpb24gZmlsZXNcIikpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjb21wYXJlTWlncmF0aW9ucyhcbiAgICBjb21wYXJlREI6IEtuZXhcbiAgKTogUHJvbWlzZTxHZW5NaWdyYXRpb25Db2RlW10+IHtcbiAgICAvLyBFbnRpdHkg7Iic7ZqM7ZWY7JesIOyLse2BrFxuICAgIGNvbnN0IGVudGl0eUlkcyA9IEVudGl0eU1hbmFnZXIuZ2V0QWxsSWRzKCk7XG5cbiAgICAvLyDsobDsnbjthYzsnbTruJQg7Y+s7ZWo7ZWY7JesIEVudGl0eeyXkOyEnCBNaWdyYXRpb25TZXQg7LaU7LacXG4gICAgY29uc3QgZW50aXR5U2V0c1dpdGhKb2luVGFibGUgPSBlbnRpdHlJZHNcbiAgICAgIC5maWx0ZXIoKGVudGl0eUlkKSA9PiBFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCkucHJvcHMubGVuZ3RoID4gMClcbiAgICAgIC5tYXAoKGVudGl0eUlkKSA9PlxuICAgICAgICBnZXRNaWdyYXRpb25TZXRGcm9tRW50aXR5KEVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKSlcbiAgICAgICk7XG5cbiAgICAvLyDsobDsnbjthYzsnbTruJTrp4wg7LaU7LacXG4gICAgY29uc3Qgam9pblRhYmxlc1dpdGhEdXAgPSBlbnRpdHlTZXRzV2l0aEpvaW5UYWJsZVxuICAgICAgLm1hcCgoZW50aXR5U2V0KSA9PiBlbnRpdHlTZXQuam9pblRhYmxlcylcbiAgICAgIC5mbGF0KCk7XG4gICAgLy8g7KSR67O1IOygnOqxsCAo7KSR67O17J24IOqyveyasCBpbmRleGVz66W8IOuzke2VqSlcbiAgICBjb25zdCBqb2luVGFibGVzID0gT2JqZWN0LnZhbHVlcyhcbiAgICAgIF8uZ3JvdXBCeShqb2luVGFibGVzV2l0aER1cCwgKGp0KSA9PiBqdC50YWJsZSlcbiAgICApLm1hcCgodGFibGVzKSA9PiB7XG4gICAgICBpZiAodGFibGVzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICByZXR1cm4gdGFibGVzWzBdO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgLi4udGFibGVzWzBdLFxuICAgICAgICBpbmRleGVzOiBfLnVuaXFCeShcbiAgICAgICAgICB0YWJsZXMuZmxhdE1hcCgodCkgPT4gdC5pbmRleGVzKSxcbiAgICAgICAgICAoaW5kZXgpID0+IFtpbmRleC50eXBlLCAuLi5pbmRleC5jb2x1bW5zLnNvcnQoKV0uam9pbihcIi1cIilcbiAgICAgICAgKSxcbiAgICAgIH07XG4gICAgfSk7XG5cbiAgICAvLyDsobDsnbjthYzsnbTruJQg7Y+s7ZWo7ZWY7JesIE1pZ3JhdGlvblNldCDrsLDsl7RcbiAgICBjb25zdCBlbnRpdHlTZXRzOiBNaWdyYXRpb25TZXRbXSA9IFtcbiAgICAgIC4uLmVudGl0eVNldHNXaXRoSm9pblRhYmxlLFxuICAgICAgLi4uam9pblRhYmxlcyxcbiAgICBdO1xuXG4gICAgY29uc3QgY29kZXM6IEdlbk1pZ3JhdGlvbkNvZGVbXSA9IChcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBlbnRpdHlTZXRzLm1hcChhc3luYyAoZW50aXR5U2V0KSA9PiB7XG4gICAgICAgICAgY29uc3QgZGJTZXQgPSBhd2FpdCBnZXRNaWdyYXRpb25TZXRGcm9tREIoY29tcGFyZURCLCBlbnRpdHlTZXQudGFibGUpO1xuXG4gICAgICAgICAgaWYgKGRiU2V0ID09PSBudWxsKSB7XG4gICAgICAgICAgICAvLyDquLDsobQg7YWM7J2067iUIOyXhuydjCwg7IOI66GcIO2FjOydtOu4lCDsg53shLFcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBnZW5lcmF0ZUNyZWF0ZUNvZGUoZW50aXR5U2V0KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8g6riw7KG0IO2FjOydtOu4lCDsobTsnqztlZjripQg7LyA7J207IqkXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZ2VuZXJhdGVBbHRlckNvZGUoZW50aXR5U2V0LCBkYlNldCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgKVxuICAgICkuZmxhdCgpO1xuXG4gICAgLy8gbm9ybWFsIO2DgOyeheydtCDslZ7snLzroZwsIGZvcmVpZ27snbQg65Kk66GcXG4gICAgY29kZXMuc29ydCgoY29kZUEsIGNvZGVCKSA9PiB7XG4gICAgICBpZiAoY29kZUEudHlwZSA9PT0gXCJmb3JlaWduXCIgJiYgY29kZUIudHlwZSA9PSBcIm5vcm1hbFwiKSB7XG4gICAgICAgIHJldHVybiAxO1xuICAgICAgfSBlbHNlIGlmIChjb2RlQS50eXBlID09PSBcIm5vcm1hbFwiICYmIGNvZGVCLnR5cGUgPT09IFwiZm9yZWlnblwiKSB7XG4gICAgICAgIHJldHVybiAtMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGNvZGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIOuniOydtOq3uOugiOydtOyFmCDrjIDsg4Eg7Luk64Sl7IWY7J2EIOyiheujjO2VqeuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IOyiheujjCDqsrDqs7xcbiAgICovXG4gIGFzeW5jIGRlc3Ryb3koKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICB0aGlzLnRhcmdldHMuYXBwbHkubWFwKChkYikgPT4ge1xuICAgICAgICByZXR1cm4gZGIuZGVzdHJveSgpO1xuICAgICAgfSlcbiAgICApO1xuICB9XG59XG4iXSwibmFtZXMiOlsiXyIsImtuZXgiLCJjaGFsayIsIkRhdGVUaW1lIiwibWtkaXIiLCJyZWFkZGlyIiwidW5saW5rIiwid3JpdGVGaWxlIiwiZXhpc3RzIiwicHJvbXB0cyIsImV4ZWNTeW5jIiwicGF0aCIsIkVudGl0eU1hbmFnZXIiLCJTb25hbXUiLCJTZXJ2aWNlVW5hdmFpbGFibGVFeGNlcHRpb24iLCJnZW5lcmF0ZUNyZWF0ZUNvZGUiLCJnZW5lcmF0ZUFsdGVyQ29kZSIsImdldE1pZ3JhdGlvblNldEZyb21EQiIsImdldE1pZ3JhdGlvblNldEZyb21FbnRpdHkiLCJNaWdyYXRvciIsInRhcmdldHMiLCJvcHRpb25zIiwiZGJDb25maWciLCJtb2RlIiwiZGV2REIiLCJkZXZlbG9wbWVudF9tYXN0ZXIiLCJ0ZXN0REIiLCJ0ZXN0IiwiZml4dHVyZUxvY2FsREIiLCJmaXh0dXJlX2xvY2FsIiwiYXBwbHlEQnMiLCJjb25uZWN0aW9uIiwiaG9zdCIsImZpeHR1cmVfcmVtb3RlIiwiZGF0YWJhc2UiLCJmaXh0dXJlUmVtb3RlREIiLCJwdXNoIiwiY29tcGFyZSIsInBlbmRpbmciLCJzaGFkb3ciLCJhcHBseSIsInByb2R1Y3Rpb25EQiIsInByb2R1Y3Rpb25fbWFzdGVyIiwiRXJyb3IiLCJnZXRNaWdyYXRpb25Db2RlcyIsInNyY01pZ3JhdGlvbnNEaXIiLCJqb2luIiwiYXBpUm9vdFBhdGgiLCJyZWN1cnNpdmUiLCJjb2RlcyIsImZpbHRlciIsImYiLCJlbmRzV2l0aCIsIm1hcCIsIm5hbWUiLCJyZXBsYWNlIiwic29ydCIsImEiLCJiIiwiZ2V0U3RhdHVzIiwiY29ubktleXMiLCJPYmplY3QiLCJrZXlzIiwia2V5Iiwic3RhdHVzZXMiLCJQcm9taXNlIiwiYWxsIiwiY29ubktleSIsImtuZXhPcHRpb25zIiwidENvbm4iLCJzdGF0dXMiLCJtaWdyYXRlIiwiZXJyIiwiY29uc29sZSIsIndhcm4iLCJ5ZWxsb3ciLCJKU09OIiwic3RyaW5naWZ5IiwiZmRMaXN0IiwibGlzdCIsImZkIiwiZmlsZSIsImN1cnJlbnRWZXJzaW9uIiwiZGVzdHJveSIsImNvbm5TdHJpbmciLCJ1c2VyIiwicG9ydCIsInByZXBhcmVkQ29kZXMiLCJzdGF0dXMwY29ubiIsImZpbmQiLCJ1bmRlZmluZWQiLCJjb21wYXJlREJjb25uIiwiZ2VuQ29kZXMiLCJjb21wYXJlTWlncmF0aW9ucyIsImNvbm5zIiwicnVuQWN0aW9uIiwiYWN0aW9uIiwiY29uZmlncyIsInVuaXFCeSIsInRhcmdldCIsImMiLCJjb25maWciLCJyZXN1bHQiLCJiYXRjaE5vIiwiYXBwbGllZCIsImxhdGVzdCIsInJvbGxiYWNrIiwiZGVsQ29kZXMiLCJjb2RlTmFtZXMiLCJzb21lIiwiY29ubiIsImNvZGVOYW1lIiwiaW5jbHVkZXMiLCJkZWxGaWxlcyIsInJlcyIsImRlbEZpbGUiLCJsb2ciLCJyZWQiLCJzdW0iLCJnZW5lcmF0ZVByZXBhcmVkQ29kZXMiLCJsZW5ndGgiLCJncmVlbiIsIm1pZ3JhdGlvbnNEaXIiLCJpbmRleCIsInBjb2RlIiwiZW50cmllcyIsImZvcm1hdHRlZCIsImRhdGVUYWciLCJsb2NhbCIsInBsdXMiLCJzZWNvbmRzIiwidG9Gb3JtYXQiLCJmaWxlUGF0aCIsInRpdGxlIiwiY2xlYXJQZW5kaW5nTGlzdCIsInBlbmRpbmdMaXN0IiwiZGVsTGlzdCIsImRmIiwicCIsImNoZWNrIiwidGFibGUiLCJydW4iLCJhbnN3ZXIiLCJ0eXBlIiwibWVzc2FnZSIsImluaXRpYWwiLCJ2YWx1ZSIsInRpbWUiLCJibHVlIiwicnVuU2hhZG93VGVzdCIsInRpbWVFbmQiLCJhcHBseURiIiwibGFiZWwiLCJjbGllbnQiLCJjb25uZWN0aW9uU2V0dGluZ3MiLCJjb2RlIiwicm9sbGJhY2tBbGxSZXN1bHQiLCJkYiIsImZvcmNlRnJlZU1pZ3JhdGlvbnNMb2NrIiwiZGlyIiwiZGVwdGgiLCJ0ZGIiLCJ0ZGJDb25uIiwic2hhZG93RGF0YWJhc2UiLCJ0bXBTcWxQYXRoIiwibWFnZW50YSIsInBhc3N3b3JkIiwicmF3Iiwic2RiIiwiZSIsImVycm9yIiwicmVzZXRBbGwiLCJjb21wYXJlREIiLCJlbnRpdHlJZHMiLCJnZXRBbGxJZHMiLCJlbnRpdHlTZXRzV2l0aEpvaW5UYWJsZSIsImVudGl0eUlkIiwiZ2V0IiwicHJvcHMiLCJqb2luVGFibGVzV2l0aER1cCIsImVudGl0eVNldCIsImpvaW5UYWJsZXMiLCJmbGF0IiwidmFsdWVzIiwiZ3JvdXBCeSIsImp0IiwidGFibGVzIiwiaW5kZXhlcyIsImZsYXRNYXAiLCJ0IiwiY29sdW1ucyIsImVudGl0eVNldHMiLCJkYlNldCIsImNvZGVBIiwiY29kZUIiXSwibWFwcGluZ3MiOiJBQUFBLFlBQVlBLE9BQU8sWUFB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