sonamu 0.9.19 → 0.10.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 (282) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +36 -0
  2. package/dist/ai/agents/agent.js +5 -7
  3. package/dist/ai/agents/index.js +1 -2
  4. package/dist/ai/agents/types.js +1 -1
  5. package/dist/ai/index.js +1 -2
  6. package/dist/ai/providers/rtzr/api.js +2 -3
  7. package/dist/ai/providers/rtzr/error.js +14 -29
  8. package/dist/ai/providers/rtzr/index.js +1 -2
  9. package/dist/ai/providers/rtzr/model.js +13 -20
  10. package/dist/ai/providers/rtzr/options.js +2 -3
  11. package/dist/ai/providers/rtzr/provider.js +2 -3
  12. package/dist/ai/providers/rtzr/utils.js +12 -21
  13. package/dist/api/base-frame.js +4 -4
  14. package/dist/api/caster.js +21 -38
  15. package/dist/api/code-converters.js +41 -98
  16. package/dist/api/config.d.ts +1 -10
  17. package/dist/api/config.d.ts.map +1 -1
  18. package/dist/api/config.js +9 -8
  19. package/dist/api/context.js +2 -3
  20. package/dist/api/decorators.js +80 -116
  21. package/dist/api/index.js +2 -3
  22. package/dist/api/secret.js +6 -10
  23. package/dist/api/sonamu.d.ts.map +1 -1
  24. package/dist/api/sonamu.js +200 -387
  25. package/dist/api/validator.js +5 -8
  26. package/dist/api/websocket-helpers.js +21 -32
  27. package/dist/auth/audit-log/builders.js +2 -3
  28. package/dist/auth/audit-log/events.js +2 -2
  29. package/dist/auth/audit-log/plugin.js +30 -61
  30. package/dist/auth/audit-log-ingestor.js +19 -41
  31. package/dist/auth/auth-generator.js +16 -41
  32. package/dist/auth/better-auth-entities.js +3 -4
  33. package/dist/auth/index.js +2 -3
  34. package/dist/auth/knex-adapter.js +18 -45
  35. package/dist/auth/plugins/entity-definitions/admin.js +2 -2
  36. package/dist/auth/plugins/entity-definitions/anonymous.js +2 -2
  37. package/dist/auth/plugins/entity-definitions/api-key.js +2 -2
  38. package/dist/auth/plugins/entity-definitions/audit-log.js +2 -2
  39. package/dist/auth/plugins/entity-definitions/index.js +2 -3
  40. package/dist/auth/plugins/entity-definitions/jwt.js +2 -2
  41. package/dist/auth/plugins/entity-definitions/organization.js +2 -2
  42. package/dist/auth/plugins/entity-definitions/passkey.js +2 -2
  43. package/dist/auth/plugins/entity-definitions/phone-number.js +2 -2
  44. package/dist/auth/plugins/entity-definitions/sso.js +2 -2
  45. package/dist/auth/plugins/entity-definitions/two-factor.js +2 -2
  46. package/dist/auth/plugins/entity-definitions/types.js +1 -1
  47. package/dist/auth/plugins/entity-definitions/username.js +2 -2
  48. package/dist/auth/plugins/index.js +1 -2
  49. package/dist/auth/plugins/wrappers/admin.js +2 -3
  50. package/dist/auth/plugins/wrappers/anonymous.js +2 -3
  51. package/dist/auth/plugins/wrappers/api-key.js +2 -3
  52. package/dist/auth/plugins/wrappers/index.js +1 -2
  53. package/dist/auth/plugins/wrappers/jwt.js +2 -3
  54. package/dist/auth/plugins/wrappers/organization.js +2 -3
  55. package/dist/auth/plugins/wrappers/passkey.js +2 -3
  56. package/dist/auth/plugins/wrappers/phone-number.js +2 -3
  57. package/dist/auth/plugins/wrappers/sso.js +2 -3
  58. package/dist/auth/plugins/wrappers/two-factor.js +2 -3
  59. package/dist/auth/plugins/wrappers/username.js +2 -3
  60. package/dist/bin/build-config.js +2 -2
  61. package/dist/bin/cli.js +151 -258
  62. package/dist/bin/fixture.d.ts.map +1 -1
  63. package/dist/bin/fixture.js +55 -97
  64. package/dist/bin/hmr-hook-register.js +3 -3
  65. package/dist/bin/migrate-targets.d.ts +3 -0
  66. package/dist/bin/migrate-targets.d.ts.map +1 -0
  67. package/dist/bin/migrate-targets.js +11 -0
  68. package/dist/bin/test-command.js +25 -55
  69. package/dist/bin/ts-loader-register.js +5 -6
  70. package/dist/bin/ts-loader-registration.js +6 -13
  71. package/dist/cache/cache-manager.js +3 -4
  72. package/dist/cache/decorator.js +11 -21
  73. package/dist/cache/drivers.js +2 -3
  74. package/dist/cache/index.js +2 -3
  75. package/dist/cache/types.js +1 -1
  76. package/dist/cache-control/cache-control.js +21 -34
  77. package/dist/cache-control/types.js +1 -1
  78. package/dist/compress/compress.js +10 -10
  79. package/dist/compress/index.js +1 -2
  80. package/dist/compress/types.js +1 -1
  81. package/dist/cone/cone-generator.js +25 -63
  82. package/dist/database/_batch_update.js +26 -46
  83. package/dist/database/base-model.js +44 -97
  84. package/dist/database/base-model.types.js +1 -1
  85. package/dist/database/db.d.ts +8 -14
  86. package/dist/database/db.d.ts.map +1 -1
  87. package/dist/database/db.js +127 -72
  88. package/dist/database/knex.js +5 -8
  89. package/dist/database/puri-subset.types.js +1 -1
  90. package/dist/database/puri-wrapper.js +11 -15
  91. package/dist/database/puri.js +117 -234
  92. package/dist/database/puri.types.js +3 -4
  93. package/dist/database/transaction-context.js +4 -5
  94. package/dist/database/upsert-builder.js +109 -176
  95. package/dist/dict/en.d.ts +1 -0
  96. package/dist/dict/en.d.ts.map +1 -1
  97. package/dist/dict/en.js +4 -4
  98. package/dist/dict/index.js +2 -3
  99. package/dist/dict/ko.d.ts +1 -0
  100. package/dist/dict/ko.d.ts.map +1 -1
  101. package/dist/dict/ko.js +4 -4
  102. package/dist/dict/rc-keys.js +3 -4
  103. package/dist/dict/sd.js +8 -19
  104. package/dist/dict/sonamu-dictionary.js +141 -284
  105. package/dist/dict/types.js +1 -1
  106. package/dist/dict/utils.js +4 -5
  107. package/dist/entity/entity-manager.d.ts +2 -2
  108. package/dist/entity/entity-manager.js +34 -82
  109. package/dist/entity/entity-template-cone.js +33 -66
  110. package/dist/entity/entity.js +156 -310
  111. package/dist/env.d.ts +14 -0
  112. package/dist/env.d.ts.map +1 -0
  113. package/dist/env.js +75 -0
  114. package/dist/exceptions/error-handler.js +2 -3
  115. package/dist/exceptions/so-exceptions.js +7 -5
  116. package/dist/filter/index.js +1 -2
  117. package/dist/filter/types.js +3 -4
  118. package/dist/filter/utils.js +21 -54
  119. package/dist/index.js +8 -7
  120. package/dist/logger/category.js +6 -12
  121. package/dist/logger/configure.js +23 -34
  122. package/dist/migration/code-generation.js +146 -314
  123. package/dist/migration/index-where-predicate.js +52 -144
  124. package/dist/migration/migration-set.js +19 -33
  125. package/dist/migration/migrator.d.ts +2 -0
  126. package/dist/migration/migrator.d.ts.map +1 -1
  127. package/dist/migration/migrator.js +69 -53
  128. package/dist/migration/postgresql-schema-reader.js +126 -225
  129. package/dist/migration/slack-confirm.d.ts +1 -0
  130. package/dist/migration/slack-confirm.d.ts.map +1 -1
  131. package/dist/migration/slack-confirm.js +28 -38
  132. package/dist/migration/types.js +1 -1
  133. package/dist/naite/messaging-types.js +1 -1
  134. package/dist/naite/naite-reporter.js +15 -32
  135. package/dist/naite/naite.js +43 -76
  136. package/dist/ssr/index.js +6 -9
  137. package/dist/ssr/registry.js +10 -18
  138. package/dist/ssr/renderer.js +10 -21
  139. package/dist/ssr/types.js +1 -1
  140. package/dist/storage/base-file.js +5 -10
  141. package/dist/storage/buffered-file.js +3 -4
  142. package/dist/storage/drivers.js +2 -3
  143. package/dist/storage/index.js +2 -3
  144. package/dist/storage/s3-driver.js +5 -9
  145. package/dist/storage/storage-manager.js +5 -5
  146. package/dist/storage/types.js +1 -1
  147. package/dist/storage/uploaded-file.js +4 -6
  148. package/dist/stream/index.js +1 -2
  149. package/dist/stream/sse.js +8 -13
  150. package/dist/stream/ws-audience-resolver.js +5 -5
  151. package/dist/stream/ws-audience.js +3 -4
  152. package/dist/stream/ws-cluster-bus.js +3 -4
  153. package/dist/stream/ws-core.js +1 -1
  154. package/dist/stream/ws-delivery.js +11 -25
  155. package/dist/stream/ws-local-connection-store.js +9 -18
  156. package/dist/stream/ws-presence-store.js +43 -97
  157. package/dist/stream/ws-registry.js +17 -22
  158. package/dist/stream/ws-telemetry-memory.js +38 -45
  159. package/dist/stream/ws-telemetry-trace.js +4 -6
  160. package/dist/stream/ws-telemetry.js +82 -135
  161. package/dist/stream/ws.js +47 -91
  162. package/dist/syncer/api-parser.js +81 -147
  163. package/dist/syncer/checksum.js +9 -20
  164. package/dist/syncer/code-generator.js +29 -47
  165. package/dist/syncer/entity-operations.js +17 -27
  166. package/dist/syncer/event-batcher.js +8 -15
  167. package/dist/syncer/file-patterns.js +3 -4
  168. package/dist/syncer/file-tracking.js +6 -10
  169. package/dist/syncer/index.js +1 -2
  170. package/dist/syncer/module-loader.js +10 -26
  171. package/dist/syncer/syncer-actions.js +19 -37
  172. package/dist/syncer/syncer.js +46 -98
  173. package/dist/syncer/watcher.js +12 -26
  174. package/dist/tasks/decorator.js +7 -11
  175. package/dist/tasks/step-wrapper.js +7 -8
  176. package/dist/tasks/workflow-manager.js +18 -25
  177. package/dist/template/entity-converter.js +40 -64
  178. package/dist/template/helpers.js +32 -63
  179. package/dist/template/implementations/entity.template.js +7 -11
  180. package/dist/template/implementations/entry-server.template.js +2 -3
  181. package/dist/template/implementations/generated.template.js +25 -51
  182. package/dist/template/implementations/generated_http.template.js +31 -58
  183. package/dist/template/implementations/generated_sso.template.js +45 -85
  184. package/dist/template/implementations/init_types.template.js +4 -7
  185. package/dist/template/implementations/model.template.js +5 -10
  186. package/dist/template/implementations/model_test.template.js +2 -3
  187. package/dist/template/implementations/queries.template.js +4 -7
  188. package/dist/template/implementations/sd.template.js +17 -35
  189. package/dist/template/implementations/services.template.js +18 -30
  190. package/dist/template/implementations/view_form.template.js +72 -125
  191. package/dist/template/implementations/view_id_all_select.template.js +2 -3
  192. package/dist/template/implementations/view_list.template.js +86 -143
  193. package/dist/template/implementations/view_search_input.template.js +2 -3
  194. package/dist/template/index.js +5 -8
  195. package/dist/template/template-manager.js +13 -26
  196. package/dist/template/template-types.js +2 -3
  197. package/dist/template/template.js +7 -11
  198. package/dist/template/zod-converter.js +173 -348
  199. package/dist/testing/_relation-graph.js +18 -37
  200. package/dist/testing/bootstrap.js +5 -8
  201. package/dist/testing/data-explorer.js +34 -78
  202. package/dist/testing/dev-test-routes.js +54 -60
  203. package/dist/testing/dev-vitest-manager.js +33 -84
  204. package/dist/testing/faker-mappings.js +3 -4
  205. package/dist/testing/fixture-generator.d.ts +2 -1
  206. package/dist/testing/fixture-generator.d.ts.map +1 -1
  207. package/dist/testing/fixture-generator.js +159 -321
  208. package/dist/testing/fixture-loader.js +2 -2
  209. package/dist/testing/fixture-manager.d.ts.map +1 -1
  210. package/dist/testing/fixture-manager.js +124 -227
  211. package/dist/testing/global-setup.d.ts.map +1 -1
  212. package/dist/testing/global-setup.js +29 -17
  213. package/dist/testing/index.js +1 -2
  214. package/dist/testing/naite-vitest-reporter.js +2 -3
  215. package/dist/testing/parallel-db-manager.js +5 -3
  216. package/dist/testing/vitest-helpers.d.ts.map +1 -1
  217. package/dist/testing/vitest-helpers.js +15 -12
  218. package/dist/types/types.d.ts +14 -14
  219. package/dist/types/types.js +27 -50
  220. package/dist/ui/ai-api.js +6 -11
  221. package/dist/ui/ai-client.js +86 -134
  222. package/dist/ui/api.js +99 -195
  223. package/dist/ui/cdd-service.js +78 -130
  224. package/dist/ui/cdd-types.js +1 -1
  225. package/dist/ui-web/assets/{index-Df8q-fhb.js → index-DFStGyd0.js} +49 -49
  226. package/dist/ui-web/assets/index-Dx4ap5i4.css +1 -0
  227. package/dist/ui-web/index.html +2 -2
  228. package/dist/utils/async-utils.js +13 -25
  229. package/dist/utils/class-name.js +3 -4
  230. package/dist/utils/console-util.js +11 -26
  231. package/dist/utils/controller.d.ts.map +1 -1
  232. package/dist/utils/controller.js +14 -12
  233. package/dist/utils/esm-utils.js +5 -8
  234. package/dist/utils/formatter.js +10 -22
  235. package/dist/utils/fs-utils.js +14 -25
  236. package/dist/utils/lodash-able.js +3 -4
  237. package/dist/utils/model.js +7 -14
  238. package/dist/utils/object-utils.js +41 -73
  239. package/dist/utils/path-utils.js +5 -9
  240. package/dist/utils/process-utils.js +4 -7
  241. package/dist/utils/sql-parser.js +6 -13
  242. package/dist/utils/type-utils.js +16 -26
  243. package/dist/utils/utils.js +18 -40
  244. package/dist/utils/zod-error.js +9 -16
  245. package/dist/vector/chunking.js +24 -37
  246. package/dist/vector/config.js +2 -2
  247. package/dist/vector/embedding.js +8 -19
  248. package/dist/vector/index.js +1 -2
  249. package/dist/vector/types.js +1 -1
  250. package/package.json +7 -7
  251. package/src/__tests__/env.test.ts +127 -0
  252. package/src/api/__tests__/config.test.ts +10 -1
  253. package/src/api/config.ts +4 -12
  254. package/src/api/sonamu.ts +14 -4
  255. package/src/bin/__tests__/migrate-targets.test.ts +28 -0
  256. package/src/bin/__tests__/test-command.test.ts +82 -1
  257. package/src/bin/cli.ts +9 -18
  258. package/src/bin/fixture.ts +5 -4
  259. package/src/bin/migrate-targets.ts +7 -0
  260. package/src/bin/test-command.ts +2 -2
  261. package/src/database/__tests__/db.test.ts +175 -0
  262. package/src/database/db.ts +193 -71
  263. package/src/dict/en.ts +2 -0
  264. package/src/dict/ko.ts +2 -0
  265. package/src/env.ts +123 -0
  266. package/src/migration/__tests__/migrator.test.ts +149 -0
  267. package/src/migration/migrator.ts +74 -17
  268. package/src/migration/slack-confirm.ts +21 -0
  269. package/src/skills/sonamu/database.md +1 -1
  270. package/src/skills/sonamu/entity-basic.md +31 -0
  271. package/src/skills/sonamu/puri.md +22 -0
  272. package/src/skills/sonamu/testing-devrunner.md +1 -1
  273. package/src/skills/sonamu/upsert.md +53 -6
  274. package/src/stream/ws-telemetry-memory.ts +2 -2
  275. package/src/testing/fixture-generator.ts +2 -1
  276. package/src/testing/fixture-manager.ts +3 -4
  277. package/src/testing/global-setup.ts +42 -18
  278. package/src/testing/vitest-helpers.ts +14 -0
  279. package/src/utils/controller.ts +14 -7
  280. package/tsdown.api.config.ts +6 -0
  281. package/dist/_virtual/rolldown_runtime.js +0 -39
  282. package/dist/ui-web/assets/index-D4rYm-Xz.css +0 -1
@@ -1,9 +1,10 @@
1
- import { __esmMin } from "../_virtual/rolldown_runtime.js";
1
+ import { __esmMin } from "../_virtual/_rolldown/runtime.js";
2
+ import { getSonamuEnvironment, init_env } from "../env.js";
2
3
  import { createKnexInstance, init_knex } from "../database/knex.js";
3
4
  import { DB, init_db } from "../database/db.js";
4
5
  import { SD, init_sd } from "../dict/sd.js";
5
6
  import { ServiceUnavailableException, init_so_exceptions } from "../exceptions/so-exceptions.js";
6
- import { init_controller, isTest } from "../utils/controller.js";
7
+ import { init_controller, isLocal, isTest } from "../utils/controller.js";
7
8
  import { exists, init_fs_utils } from "../utils/fs-utils.js";
8
9
  import { Sonamu, init_sonamu } from "../api/sonamu.js";
9
10
  import { EntityManager, init_entity_manager } from "../entity/entity-manager.js";
@@ -13,10 +14,9 @@ import { generateAlterCode, generateCreateCode, init_code_generation } from "./c
13
14
  import { getMigrationSetFromEntity, init_migration_set } from "./migration-set.js";
14
15
  import { group, sum, unique } from "radashi";
15
16
  import assert from "assert";
16
- import { mkdir, readdir, unlink, writeFile } from "fs/promises";
17
17
  import path from "path";
18
+ import { mkdir, readdir, unlink, writeFile } from "fs/promises";
18
19
  import chalk from "chalk";
19
-
20
20
  //#region src/migration/migrator.ts
21
21
  var Migrator;
22
22
  var init_migrator = __esmMin((() => {
@@ -25,6 +25,7 @@ var init_migrator = __esmMin((() => {
25
25
  init_knex();
26
26
  init_sd();
27
27
  init_entity_manager();
28
+ init_env();
28
29
  init_so_exceptions();
29
30
  init_naite();
30
31
  init_controller();
@@ -33,6 +34,17 @@ var init_migrator = __esmMin((() => {
33
34
  init_migration_set();
34
35
  init_postgresql_schema_reader();
35
36
  Migrator = class {
37
+ isMissingMigrationTableError(error) {
38
+ if (typeof error !== "object" || error === null) return false;
39
+ const maybePostgresError = error;
40
+ return maybePostgresError.code === "42P01" && typeof maybePostgresError.message === "string" && maybePostgresError.message.includes("knex_migrations");
41
+ }
42
+ getMigrationTargetKeys() {
43
+ const connKeys = Object.keys(Sonamu.dbConfig).filter((key) => !key.endsWith("_readonly"));
44
+ if (isLocal()) return connKeys;
45
+ const environment = getSonamuEnvironment();
46
+ return connKeys.filter((key) => key === environment);
47
+ }
36
48
  async runMigrationsSequentially(conns, action) {
37
49
  const results = [];
38
50
  for (const { connKey, knex } of conns) {
@@ -47,9 +59,7 @@ var init_migrator = __esmMin((() => {
47
59
  }
48
60
  async getMigrationCodes() {
49
61
  const srcMigrationsDir = path.join(Sonamu.apiRootPath, "src", "migrations");
50
- if (!await exists(srcMigrationsDir)) {
51
- await mkdir(srcMigrationsDir, { recursive: true });
52
- }
62
+ if (!await exists(srcMigrationsDir)) await mkdir(srcMigrationsDir, { recursive: true });
53
63
  const codes = (await readdir(srcMigrationsDir)).filter((f) => f.endsWith(".ts")).map((f) => ({
54
64
  name: f.replace(".ts", ""),
55
65
  path: path.join(srcMigrationsDir, f)
@@ -69,7 +79,7 @@ var init_migrator = __esmMin((() => {
69
79
  async getStatus() {
70
80
  const codes = await this.getMigrationCodes();
71
81
  Naite.t("migrator:getStatus:codes", codes);
72
- const connKeys = Object.keys(Sonamu.dbConfig).filter((key) => !key.endsWith("_slave"));
82
+ const connKeys = this.getMigrationTargetKeys();
73
83
  let migrationStatusError;
74
84
  const statuses = await Promise.all(connKeys.map(async (connKey) => {
75
85
  const knexOptions = Sonamu.dbConfig[connKey];
@@ -79,6 +89,7 @@ var init_migrator = __esmMin((() => {
79
89
  try {
80
90
  return await tConn.migrate.status();
81
91
  } catch (err) {
92
+ if (this.isMissingMigrationTableError(err)) return codes.length;
82
93
  console.warn(chalk.yellow(`${connKey}의 마이그레이션 상태를 가져오는 데에 실패하였습니다. 데이터베이스가 올바르게 구성되지 않은 것 같습니다. 확인하시고 다시 시도해주세요.\n시도한 연결 설정:\n${JSON.stringify(knexOptions.connection, null, 2)}\n발생한 에러:\n${err}\n`));
83
94
  migrationStatusError = err instanceof Error ? err.message : String(err);
84
95
  return "error";
@@ -89,6 +100,7 @@ var init_migrator = __esmMin((() => {
89
100
  const [, fdList] = await tConn.migrate.list();
90
101
  return fdList.map((fd) => fd.file.replace(".ts", ""));
91
102
  } catch (err) {
103
+ if (this.isMissingMigrationTableError(err)) return codes.map((code) => code.name);
92
104
  migrationStatusError = err instanceof Error ? err.message : String(err);
93
105
  return [];
94
106
  }
@@ -97,6 +109,7 @@ var init_migrator = __esmMin((() => {
97
109
  try {
98
110
  return await tConn.migrate.currentVersion();
99
111
  } catch (_err) {
112
+ if (this.isMissingMigrationTableError(_err)) return "none";
100
113
  migrationStatusError = _err instanceof Error ? _err.message : String(_err);
101
114
  return "error";
102
115
  }
@@ -104,7 +117,7 @@ var init_migrator = __esmMin((() => {
104
117
  Naite.t("migrator:getStatus:status", status);
105
118
  const connection = knexOptions.connection;
106
119
  return {
107
- name: connKey.replace("_master", ""),
120
+ name: connKey,
108
121
  connKey,
109
122
  connString: `pg://${connection.user ?? ""}@${connection.host}:${connection.port}/${connection.database}`,
110
123
  currentVersion,
@@ -118,7 +131,7 @@ var init_migrator = __esmMin((() => {
118
131
  Naite.t("migrator:getStatus:conns", statuses);
119
132
  const preparedCodes = await (async () => {
120
133
  const status0conn = statuses.find((status) => status.status === 0);
121
- if (status0conn === undefined) {
134
+ if (status0conn === void 0) {
122
135
  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.`));
123
136
  return [];
124
137
  }
@@ -150,10 +163,13 @@ var init_migrator = __esmMin((() => {
150
163
  async runAction(action, targets) {
151
164
  Naite.t("migrator:runAction:action", action);
152
165
  Naite.t("migrator:runAction:targets", targets);
166
+ const allowedTargets = new Set(this.getMigrationTargetKeys());
167
+ const disallowedTargets = targets.filter((target) => !allowedTargets.has(target));
168
+ if (disallowedTargets.length > 0) throw new Error(`Migration targets are not allowed in NODE_ENV=${getSonamuEnvironment()}: ${disallowedTargets.join(", ")}`);
153
169
  const configs = unique(targets.map((target) => ({
154
170
  connKey: target,
155
171
  options: Sonamu.dbConfig[target]
156
- })).filter((c) => c.options !== undefined), ({ options }) => `${options.connection.host}:${options.connection.port ?? 5432}/${options.connection.database}`);
172
+ })).filter((c) => c.options !== void 0), ({ options }) => `${options.connection.host}:${options.connection.port ?? 5432}/${options.connection.database}`);
157
173
  const conns = await Promise.all(configs.map(async (config) => ({
158
174
  connKey: config.connKey,
159
175
  knex: createKnexInstance(config.options)
@@ -198,9 +214,7 @@ var init_migrator = __esmMin((() => {
198
214
  async delCodes(codeNames) {
199
215
  const { conns } = await this.getStatus();
200
216
  const { canDelete, appliedCodes } = this.validateDeletable(conns, codeNames);
201
- if (!canDelete) {
202
- throw new Error(`You cannot delete a migration file if there is already applied. Applied codes: ${appliedCodes.join(", ")}`);
203
- }
217
+ if (!canDelete) throw new Error(`You cannot delete a migration file if there is already applied. Applied codes: ${appliedCodes.join(", ")}`);
204
218
  return sum(await Promise.all(codeNames.map(async (codeName) => {
205
219
  const filePath = `${Sonamu.apiRootPath}/src/migrations/${codeName}.ts`;
206
220
  if (await exists(filePath)) {
@@ -210,7 +224,7 @@ var init_migrator = __esmMin((() => {
210
224
  return 0;
211
225
  })));
212
226
  }
213
- genDateTag(index, baseDate = new Date()) {
227
+ genDateTag(index, baseDate = /* @__PURE__ */ new Date()) {
214
228
  const date = new Date(baseDate.getTime() + index * 1e3);
215
229
  const pad = (num, size = 2) => num.toString().padStart(size, "0");
216
230
  return date.getFullYear().toString() + pad(date.getMonth() + 1) + pad(date.getDate()) + pad(date.getHours()) + pad(date.getMinutes()) + pad(date.getSeconds());
@@ -230,49 +244,41 @@ var init_migrator = __esmMin((() => {
230
244
  return 0;
231
245
  }
232
246
  const migrationsDir = `${Sonamu.apiRootPath}/src/migrations`;
233
- for (const [index, pcode] of preparedCodes.entries()) {
234
- if (pcode.formatted) {
235
- const dateTag = this.genDateTag(index);
236
- const filePath = `${migrationsDir}/${dateTag}_${pcode.title}.ts`;
237
- await writeFile(filePath, pcode.formatted);
238
- !isTest() && console.log(chalk.green(`MIGRATION CREATED ${filePath}`));
239
- }
247
+ for (const [index, pcode] of preparedCodes.entries()) if (pcode.formatted) {
248
+ const filePath = `${migrationsDir}/${this.genDateTag(index)}_${pcode.title}.ts`;
249
+ await writeFile(filePath, pcode.formatted);
250
+ !isTest() && console.log(chalk.green(`MIGRATION CREATED ${filePath}`));
240
251
  }
241
252
  return preparedCodes.length;
242
253
  }
243
254
  async compareMigrations(compareDB) {
244
- const entityIds = EntityManager.getAllIds();
245
- const entitySetsWithJoinTable = entityIds.filter((entityId) => EntityManager.get(entityId).props.length > 0).map((entityId) => getMigrationSetFromEntity(EntityManager.get(entityId)));
255
+ const entitySetsWithJoinTable = EntityManager.getAllIds().filter((entityId) => EntityManager.get(entityId).props.length > 0).map((entityId) => getMigrationSetFromEntity(EntityManager.get(entityId)));
246
256
  const joinTablesWithDup = entitySetsWithJoinTable.flatMap((entitySet) => entitySet.joinTables);
247
257
  const joinTables = Object.values(group(joinTablesWithDup, (jt) => jt.table)).map((tables) => {
248
- assert(tables !== undefined, "tables is undefined");
249
- if (tables.length === 1) {
250
- return tables[0];
251
- }
258
+ assert(tables !== void 0, "tables is undefined");
259
+ if (tables.length === 1) return tables[0];
252
260
  return {
253
261
  ...tables[0],
254
262
  indexes: unique(tables.flatMap((t) => t.indexes), (index) => [index.type, ...index.columns].join("-"))
255
263
  };
256
264
  });
257
265
  const entitySets = [...entitySetsWithJoinTable, ...joinTables];
258
- const codes = (await Promise.all(entitySets.map(async (entitySet) => {
259
- const dbSet = await PostgreSQLSchemaReader.getMigrationSetFromDB(compareDB, entitySet.table);
260
- Naite.t(`migrator:compareMigrations:entitySet:${entitySet.table}`, entitySet);
261
- Naite.t(`migrator:compareMigrations:dbSet:${entitySet.table}`, dbSet);
262
- if (dbSet === null) {
263
- return await generateCreateCode(entitySet);
264
- } else {
265
- return await generateAlterCode(entitySet, dbSet, compareDB);
266
- }
267
- }))).flat();
266
+ const codes = [];
267
+ const batchSize = 4;
268
+ for (let i = 0; i < entitySets.length; i += batchSize) {
269
+ const batchCodes = await Promise.all(entitySets.slice(i, i + batchSize).map(async (entitySet) => {
270
+ const dbSet = await PostgreSQLSchemaReader.getMigrationSetFromDB(compareDB, entitySet.table);
271
+ Naite.t(`migrator:compareMigrations:entitySet:${entitySet.table}`, entitySet);
272
+ Naite.t(`migrator:compareMigrations:dbSet:${entitySet.table}`, dbSet);
273
+ if (dbSet === null) return await generateCreateCode(entitySet);
274
+ else return await generateAlterCode(entitySet, dbSet, compareDB);
275
+ }));
276
+ codes.push(...batchCodes.flat());
277
+ }
268
278
  codes.sort((codeA, codeB) => {
269
- if (codeA.type === "foreign" && codeB.type === "normal") {
270
- return 1;
271
- } else if (codeA.type === "normal" && codeB.type === "foreign") {
272
- return -1;
273
- } else {
274
- return 0;
275
- }
279
+ if (codeA.type === "foreign" && codeB.type === "normal") return 1;
280
+ else if (codeA.type === "normal" && codeB.type === "foreign") return -1;
281
+ else return 0;
276
282
  });
277
283
  return codes;
278
284
  }
@@ -284,15 +290,25 @@ var init_migrator = __esmMin((() => {
284
290
  * @returns Shadow DB 테스트 결과
285
291
  */
286
292
  async runShadowTest() {
287
- const tdbConn = Sonamu.dbConfig.test.connection;
288
- const shadowDatabase = `${tdbConn.database}__migration_shadow`;
293
+ const baseTestConn = Sonamu.dbConfig.test.connection;
294
+ const workerId = process.env.SONAMU_WORKER_DB === "true" ? process.env.VITEST_POOL_ID : null;
295
+ const templateDatabase = workerId !== null ? `${baseTestConn.database}_${workerId ?? "1"}` : baseTestConn.database;
296
+ const tdbConn = {
297
+ ...baseTestConn,
298
+ database: templateDatabase
299
+ };
300
+ const shadowDatabase = `${templateDatabase}__migration_shadow`;
289
301
  if (isTest()) {
290
302
  await DB.clearTestTransaction();
291
- if (process.env.SONAMU_WORKER_DB !== "true") {
292
- await DB.destroy();
293
- }
303
+ await DB.destroy();
294
304
  }
295
- const tdb = createKnexInstance(Sonamu.dbConfig.test);
305
+ const tdb = createKnexInstance({
306
+ ...Sonamu.dbConfig.test,
307
+ connection: {
308
+ ...baseTestConn,
309
+ database: "postgres"
310
+ }
311
+ });
296
312
  try {
297
313
  !isTest() && console.log(chalk.magenta(`${shadowDatabase} 삭제`));
298
314
  await tdb.raw(`DROP DATABASE IF EXISTS ${shadowDatabase}`);
@@ -341,8 +357,8 @@ var init_migrator = __esmMin((() => {
341
357
  }
342
358
  };
343
359
  }));
344
-
345
360
  //#endregion
346
361
  init_migrator();
347
362
  export { Migrator, init_migrator };
348
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlncmF0b3IuanMiLCJuYW1lcyI6WyJyZXN1bHRzOiBNaWdyYXRpb25SZXN1bHQiLCJtaWdyYXRpb25TdGF0dXNFcnJvcjogc3RyaW5nIHwgdW5kZWZpbmVkIiwic3RhdHVzOiBudW1iZXIgfCBcImVycm9yXCIiLCJwZW5kaW5nOiBzdHJpbmdbXSIsImN1cnJlbnRWZXJzaW9uOiBzdHJpbmcgfCBcImVycm9yXCIiLCJwcmVwYXJlZENvZGVzOiBHZW5NaWdyYXRpb25Db2RlW10iLCJlbnRpdHlTZXRzOiBNaWdyYXRpb25TZXRbXSIsImNvZGVzOiBHZW5NaWdyYXRpb25Db2RlW10iXSwic291cmNlcyI6WyIuLi8uLi9zcmMvbWlncmF0aW9uL21pZ3JhdG9yLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuaW1wb3J0IHsgbWtkaXIsIHJlYWRkaXIsIHVubGluaywgd3JpdGVGaWxlIH0gZnJvbSBcImZzL3Byb21pc2VzXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuXG5pbXBvcnQgY2hhbGsgZnJvbSBcImNoYWxrXCI7XG5pbXBvcnQgeyB0eXBlIEtuZXggfSBmcm9tIFwia25leFwiO1xuaW1wb3J0IHsgZ3JvdXAsIHN1bSwgdW5pcXVlIH0gZnJvbSBcInJhZGFzaGlcIjtcblxuaW1wb3J0IHsgU29uYW11IH0gZnJvbSBcIi4uL2FwaS9zb25hbXVcIjtcbmltcG9ydCB7IERCIH0gZnJvbSBcIi4uL2RhdGFiYXNlL2RiXCI7XG5pbXBvcnQgeyB0eXBlIFNvbmFtdURCQ29uZmlnIH0gZnJvbSBcIi4uL2RhdGFiYXNlL2RiXCI7XG5pbXBvcnQgeyBjcmVhdGVLbmV4SW5zdGFuY2UgfSBmcm9tIFwiLi4vZGF0YWJhc2Uva25leFwiO1xuaW1wb3J0IHsgU0QgfSBmcm9tIFwiLi4vZGljdC9zZFwiO1xuaW1wb3J0IHsgRW50aXR5TWFuYWdlciB9IGZyb20gXCIuLi9lbnRpdHkvZW50aXR5LW1hbmFnZXJcIjtcbmltcG9ydCB7IFNlcnZpY2VVbmF2YWlsYWJsZUV4Y2VwdGlvbiB9IGZyb20gXCIuLi9leGNlcHRpb25zL3NvLWV4Y2VwdGlvbnNcIjtcbmltcG9ydCB7IE5haXRlIH0gZnJvbSBcIi4uL25haXRlL25haXRlXCI7XG5pbXBvcnQgeyB0eXBlIEdlbk1pZ3JhdGlvbkNvZGUsIHR5cGUgTWlncmF0aW9uU2V0IH0gZnJvbSBcIi4uL3R5cGVzL3R5cGVzXCI7XG5pbXBvcnQgeyBpc1Rlc3QgfSBmcm9tIFwiLi4vdXRpbHMvY29udHJvbGxlclwiO1xuaW1wb3J0IHsgZXhpc3RzIH0gZnJvbSBcIi4uL3V0aWxzL2ZzLXV0aWxzXCI7XG5pbXBvcnQgeyBnZW5lcmF0ZUFsdGVyQ29kZSwgZ2VuZXJhdGVDcmVhdGVDb2RlIH0gZnJvbSBcIi4vY29kZS1nZW5lcmF0aW9uXCI7XG5pbXBvcnQgeyBnZXRNaWdyYXRpb25TZXRGcm9tRW50aXR5IH0gZnJvbSBcIi4vbWlncmF0aW9uLXNldFwiO1xuaW1wb3J0IHsgUG9zdGdyZVNRTFNjaGVtYVJlYWRlciB9IGZyb20gXCIuL3Bvc3RncmVzcWwtc2NoZW1hLXJlYWRlclwiO1xuaW1wb3J0IHsgdHlwZSBDb25uU3RyaW5nLCB0eXBlIE1pZ3JhdGlvbkNvZGUsIHR5cGUgTWlncmF0aW9uU3RhdHVzIH0gZnJvbSBcIi4vdHlwZXNcIjtcblxuZXhwb3J0IHR5cGUgTWlncmF0aW9uUmVzdWx0ID0ge1xuICBjb25uS2V5OiBzdHJpbmc7XG4gIGJhdGNoTm86IG51bWJlcjtcbiAgYXBwbGllZDogc3RyaW5nW107XG59W107XG5cbmV4cG9ydCBjbGFzcyBNaWdyYXRvciB7XG4gIHByaXZhdGUgYXN5bmMgcnVuTWlncmF0aW9uc1NlcXVlbnRpYWxseShcbiAgICBjb25uczogeyBjb25uS2V5OiBrZXlvZiBTb25hbXVEQkNvbmZpZzsga25leDogS25leCB9W10sXG4gICAgYWN0aW9uOiBcImFwcGx5XCIgfCBcInJvbGxiYWNrXCIsXG4gICk6IFByb21pc2U8TWlncmF0aW9uUmVzdWx0PiB7XG4gICAgY29uc3QgcmVzdWx0czogTWlncmF0aW9uUmVzdWx0ID0gW107XG5cbiAgICBmb3IgKGNvbnN0IHsgY29ubktleSwga25leCB9IG9mIGNvbm5zKSB7XG4gICAgICBjb25zdCBbYmF0Y2hObywgYXBwbGllZF0gPVxuICAgICAgICBhY3Rpb24gPT09IFwiYXBwbHlcIiA/IGF3YWl0IGtuZXgubWlncmF0ZS5sYXRlc3QoKSA6IGF3YWl0IGtuZXgubWlncmF0ZS5yb2xsYmFjaygpO1xuXG4gICAgICByZXN1bHRzLnB1c2goe1xuICAgICAgICBjb25uS2V5LFxuICAgICAgICBiYXRjaE5vLFxuICAgICAgICBhcHBsaWVkLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdHM7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGdldE1pZ3JhdGlvbkNvZGVzKCk6IFByb21pc2U8TWlncmF0aW9uQ29kZVtdPiB7XG4gICAgY29uc3Qgc3JjTWlncmF0aW9uc0RpciA9IHBhdGguam9pbihTb25hbXUuYXBpUm9vdFBhdGgsIFwic3JjXCIsIFwibWlncmF0aW9uc1wiKTsgLy8g7J206rG0IO2ZmOqyveyXkCDqtIDqs4Tsl4bsnbQg7ZWt7IOBIHNyY+yXkOyEnCDssL7slYTslbwg7ZW07JqULlxuXG4gICAgaWYgKCEoYXdhaXQgZXhpc3RzKHNyY01pZ3JhdGlvbnNEaXIpKSkge1xuICAgICAgYXdhaXQgbWtkaXIoc3JjTWlncmF0aW9uc0Rpciwge1xuICAgICAgICByZWN1cnNpdmU6IHRydWUsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBjb25zdCBjb2RlcyA9IChhd2FpdCByZWFkZGlyKHNyY01pZ3JhdGlvbnNEaXIpKVxuICAgICAgLmZpbHRlcigoZikgPT4gZi5lbmRzV2l0aChcIi50c1wiKSlcbiAgICAgIC5tYXAoKGYpID0+ICh7XG4gICAgICAgIG5hbWU6IGYucmVwbGFjZShcIi50c1wiLCBcIlwiKSxcbiAgICAgICAgcGF0aDogcGF0aC5qb2luKHNyY01pZ3JhdGlvbnNEaXIsIGYpLFxuICAgICAgfSkpXG4gICAgICAudG9Tb3J0ZWQoKGEsIGIpID0+IChhLm5hbWUgPCBiLm5hbWUgPyAxIDogLTEpKTsgLy8g7J2066aEIOuCtOumvOywqOyInCDsoJXroKwo7LWc7Iug7IicKVxuXG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOmdldE1pZ3JhdGlvbkNvZGVzOnJlc3VsdHNcIiwgY29kZXMpO1xuICAgIHJldHVybiBjb2RlcztcbiAgfVxuXG4gIC8qKlxuICAgKiDtg4Dqsp/rs4Qg66eI7J206re466CI7J207IWYIOyDge2DnOyZgCDsvZTrk5wg7IOd7ISxL+ykgOu5hCDsg4Htg5zrpbwg6rWs7ZW07Ji164uI64ukLlxuICAgKiDsi6TsoJzroZwgRELsl5Ag7KCR6re864+EIO2VmOqzoCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvOuPhCDtmZXsnbjtlZjqs6AsXG4gICAqIO2VhOyalO2VmOuLpOuptCDsoIHsmqntlaAg7IiYIOyeiOuKlCDsvZTrk5zrpbwg7IOd7ISx6rmM7KeAIO2VtOyYteuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JmAIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEByZXR1cm5zXG4gICAqL1xuICBhc3luYyBnZXRTdGF0dXMoKTogUHJvbWlzZTxNaWdyYXRpb25TdGF0dXM+IHtcbiAgICBjb25zdCBjb2RlcyA9IGF3YWl0IHRoaXMuZ2V0TWlncmF0aW9uQ29kZXMoKTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOmNvZGVzXCIsIGNvZGVzKTtcblxuICAgIGNvbnN0IGNvbm5LZXlzID0gT2JqZWN0LmtleXMoU29uYW11LmRiQ29uZmlnKS5maWx0ZXIoXG4gICAgICAoa2V5KSA9PiAha2V5LmVuZHNXaXRoKFwiX3NsYXZlXCIpLFxuICAgICkgYXMgKGtleW9mIHR5cGVvZiBTb25hbXUuZGJDb25maWcpW107XG5cbiAgICBsZXQgbWlncmF0aW9uU3RhdHVzRXJyb3I6IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICAgIGNvbnN0IHN0YXR1c2VzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBjb25uS2V5cy5tYXAoYXN5bmMgKGNvbm5LZXkpID0+IHtcbiAgICAgICAgY29uc3Qga25leE9wdGlvbnMgPSBTb25hbXUuZGJDb25maWdbY29ubktleV07XG4gICAgICAgIGNvbnN0IHRDb25uID0gY3JlYXRlS25leEluc3RhbmNlKGtuZXhPcHRpb25zKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHN0YXR1czogbnVtYmVyIHwgXCJlcnJvclwiID0gYXdhaXQgKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIHJldHVybiBhd2FpdCB0Q29ubi5taWdyYXRlLnN0YXR1cygpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgICAgICBjaGFsay55ZWxsb3coXG4gICAgICAgICAgICAgICAgICBgJHtjb25uS2V5feydmCDrp4jsnbTqt7jroIjsnbTshZgg7IOB7YOc66W8IOqwgOyguOyYpOuKlCDrjbDsl5Ag7Iuk7Yyo7ZWY7JiA7Iq164uI64ukLiDrjbDsnbTthLDrsqDsnbTsiqTqsIAg7Jis67CU66W06rKMIOq1rOyEseuQmOyngCDslYrsnYAg6rKDIOqwmeyKteuLiOuLpC4g7ZmV7J247ZWY7Iuc6rOgIOuLpOyLnCDsi5zrj4TtlbTso7zshLjsmpQuXFxu7Iuc64+E7ZWcIOyXsOqysCDshKTsoJU6XFxuJHtKU09OLnN0cmluZ2lmeShrbmV4T3B0aW9ucy5jb25uZWN0aW9uLCBudWxsLCAyKX1cXG7rsJzsg53tlZwg7JeQ65+sOlxcbiR7ZXJyfVxcbmAsXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgbWlncmF0aW9uU3RhdHVzRXJyb3IgPSBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVycik7XG4gICAgICAgICAgICAgIHJldHVybiBcImVycm9yXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSkoKTtcbiAgICAgICAgICBjb25zdCBwZW5kaW5nOiBzdHJpbmdbXSA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBjb25zdCBbLCBmZExpc3RdID0gYXdhaXQgdENvbm4ubWlncmF0ZS5saXN0KCk7XG4gICAgICAgICAgICAgIHJldHVybiBmZExpc3QubWFwKChmZDogeyBmaWxlOiBzdHJpbmcgfSkgPT4gZmQuZmlsZS5yZXBsYWNlKFwiLnRzXCIsIFwiXCIpKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICBtaWdyYXRpb25TdGF0dXNFcnJvciA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcbiAgICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pKCk7XG4gICAgICAgICAgY29uc3QgY3VycmVudFZlcnNpb246IHN0cmluZyB8IFwiZXJyb3JcIiA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICByZXR1cm4gYXdhaXQgdENvbm4ubWlncmF0ZS5jdXJyZW50VmVyc2lvbigpO1xuICAgICAgICAgICAgfSBjYXRjaCAoX2Vycikge1xuICAgICAgICAgICAgICBtaWdyYXRpb25TdGF0dXNFcnJvciA9IF9lcnIgaW5zdGFuY2VvZiBFcnJvciA/IF9lcnIubWVzc2FnZSA6IFN0cmluZyhfZXJyKTtcbiAgICAgICAgICAgICAgcmV0dXJuIFwiZXJyb3JcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KSgpO1xuICAgICAgICAgIE5haXRlLnQoXCJtaWdyYXRvcjpnZXRTdGF0dXM6c3RhdHVzXCIsIHN0YXR1cyk7XG5cbiAgICAgICAgICBjb25zdCBjb25uZWN0aW9uID0ga25leE9wdGlvbnMuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZztcblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBuYW1lOiBjb25uS2V5LnJlcGxhY2UoXCJfbWFzdGVyXCIsIFwiXCIpLFxuICAgICAgICAgICAgY29ubktleSxcbiAgICAgICAgICAgIGNvbm5TdHJpbmc6IGBwZzovLyR7Y29ubmVjdGlvbi51c2VyID8/IFwiXCJ9QCR7Y29ubmVjdGlvbi5ob3N0fToke1xuICAgICAgICAgICAgICBjb25uZWN0aW9uLnBvcnRcbiAgICAgICAgICAgIH0vJHtjb25uZWN0aW9uLmRhdGFiYXNlfWAgYXMgQ29ublN0cmluZyxcbiAgICAgICAgICAgIGN1cnJlbnRWZXJzaW9uLFxuICAgICAgICAgICAgc3RhdHVzOiBzdGF0dXMsXG4gICAgICAgICAgICBwZW5kaW5nLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgYXdhaXQgdENvbm4uZGVzdHJveSgpO1xuICAgICAgICB9XG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOmdldFN0YXR1czpjb25uc1wiLCBzdGF0dXNlcyk7XG5cbiAgICBjb25zdCBwcmVwYXJlZENvZGVzOiBHZW5NaWdyYXRpb25Db2RlW10gPSBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3Qgc3RhdHVzMGNvbm4gPSBzdGF0dXNlcy5maW5kKChzdGF0dXMpID0+IHN0YXR1cy5zdGF0dXMgPT09IDApO1xuICAgICAgaWYgKHN0YXR1czBjb25uID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgIGNoYWxrLnllbGxvdyhcbiAgICAgICAgICAgIGBXaGlsZSB0cnlpbmcgdG8gcHJlcGFyZSBtaWdyYXRpb24gY29kZXMsIHdlIGZvdW5kIHRoYXQgdGhlcmUgaXMgbm8gZGF0YWJhc2UgdG8gY29tcGFyZSBtaWdyYXRpb25zLiBXZSBuZWVkIGF0IGxlYXN0IG9uZSBkYXRhYmFzZSB3aGVyZSBldmVyeSBtaWdyYXRpb24gaXMgYXBwbGllZChzdGF0dXMgPT09IDApLiBZb3UgbWlnaHQgd2FudCB0byBhcHBseSB5b3VyIGV4aXN0aW5nIG1pZ3JhdGlvbnMgdG8gb25lIG9mIHRoZSBkYXRhYmFzZXMuYCxcbiAgICAgICAgICApLFxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gW107XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNvbXBhcmVEQmNvbm4gPSBjcmVhdGVLbmV4SW5zdGFuY2UoU29uYW11LmRiQ29uZmlnW3N0YXR1czBjb25uLmNvbm5LZXldKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmNvbXBhcmVNaWdyYXRpb25zKGNvbXBhcmVEQmNvbm4pO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYXdhaXQgY29tcGFyZURCY29ubi5kZXN0cm95KCk7XG4gICAgICB9XG4gICAgfSkoKTtcblxuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpnZXRTdGF0dXM6cHJlcGFyZWRDb2Rlc1wiLCBwcmVwYXJlZENvZGVzKTtcblxuICAgIHJldHVybiB7XG4gICAgICBjb25uczogc3RhdHVzZXMsXG4gICAgICBjb2RlcyxcbiAgICAgIHByZXBhcmVkQ29kZXMsXG4gICAgICBlcnJvcjogbWlncmF0aW9uU3RhdHVzRXJyb3IsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiDrp4jsnbTqt7jroIjsnbTshZjsnYQg7KCB7Jqp7ZWY6rGw64KYIOuhpOuwse2VqeuLiOuLpC5cbiAgICogU29uYW11IFVJ7JeQ7IScIOuniOydtOq3uOugiOydtOyFmCDsnpHsl4XsnYQg7IiY7ZaJ7ZWgIOuVjCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIENMSeyZgCBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcGFyYW0gYWN0aW9uIOyekeyXhSDsnKDtmJUgKGFwcGx5L3JvbGxiYWNrKVxuICAgKiBAcGFyYW0gdGFyZ2V0cyDsnpHsl4Ug64yA7IOBIERCIOyEpOyglSDtgqQgKGtleW9mIFNvbmFtdURCQ29uZmlnKVxuICAgKiBAcmV0dXJucyDsnpHsl4Ug6rKw6rO8XG4gICAqL1xuICBhc3luYyBydW5BY3Rpb24oXG4gICAgYWN0aW9uOiBcImFwcGx5XCIgfCBcInJvbGxiYWNrXCIsXG4gICAgdGFyZ2V0czogKGtleW9mIFNvbmFtdURCQ29uZmlnKVtdLFxuICApOiBQcm9taXNlPE1pZ3JhdGlvblJlc3VsdD4ge1xuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpydW5BY3Rpb246YWN0aW9uXCIsIGFjdGlvbik7XG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOnJ1bkFjdGlvbjp0YXJnZXRzXCIsIHRhcmdldHMpO1xuXG4gICAgLy8gZ2V0IHVuaXEga25leCBjb25maWdzXG4gICAgY29uc3QgY29uZmlncyA9IHVuaXF1ZShcbiAgICAgIHRhcmdldHNcbiAgICAgICAgLm1hcCgodGFyZ2V0KSA9PiAoe1xuICAgICAgICAgIGNvbm5LZXk6IHRhcmdldCxcbiAgICAgICAgICBvcHRpb25zOiBTb25hbXUuZGJDb25maWdbdGFyZ2V0XSxcbiAgICAgICAgfSkpXG4gICAgICAgIC5maWx0ZXIoKGMpID0+IGMub3B0aW9ucyAhPT0gdW5kZWZpbmVkKSxcbiAgICAgICh7IG9wdGlvbnMgfSkgPT5cbiAgICAgICAgYCR7KG9wdGlvbnMuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZykuaG9zdH06JHtcbiAgICAgICAgICAob3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnKS5wb3J0ID8/IDU0MzJcbiAgICAgICAgfS8keyhvcHRpb25zLmNvbm5lY3Rpb24gYXMgS25leC5QZ0Nvbm5lY3Rpb25Db25maWcpLmRhdGFiYXNlfWAsXG4gICAgKTtcblxuICAgIC8vIGdldCBjb25uZWN0aW9uc1xuICAgIGNvbnN0IGNvbm5zID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBjb25maWdzLm1hcChhc3luYyAoY29uZmlnKSA9PiAoe1xuICAgICAgICBjb25uS2V5OiBjb25maWcuY29ubktleSxcbiAgICAgICAga25leDogY3JlYXRlS25leEluc3RhbmNlKGNvbmZpZy5vcHRpb25zKSxcbiAgICAgIH0pKSxcbiAgICApO1xuXG4gICAgdHJ5IHtcbiAgICAgIC8vIGFjdGlvblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgKGFzeW5jICgpID0+IHtcbiAgICAgICAgc3dpdGNoIChhY3Rpb24pIHtcbiAgICAgICAgICBjYXNlIFwiYXBwbHlcIjpcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJ1bk1pZ3JhdGlvbnNTZXF1ZW50aWFsbHkoY29ubnMsIFwiYXBwbHlcIik7XG4gICAgICAgICAgY2FzZSBcInJvbGxiYWNrXCI6XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5ydW5NaWdyYXRpb25zU2VxdWVudGlhbGx5KGNvbm5zLCBcInJvbGxiYWNrXCIpO1xuICAgICAgICB9XG4gICAgICB9KSgpO1xuXG4gICAgICBOYWl0ZS50KFwibWlncmF0b3I6cnVuQWN0aW9uOnJlc3VsdFwiLCByZXN1bHQpO1xuXG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH0gZmluYWxseSB7XG4gICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgY29ubnMubWFwKCh7IGtuZXggfSkgPT4ge1xuICAgICAgICAgIHJldHVybiBrbmV4LmRlc3Ryb3koKTtcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiDsgq3soJwg6rCA64ql7ZWcIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J287J2EIOqygOymne2VqeuLiOuLpC5cbiAgICpcbiAgICogQHBhcmFtIGNvbm5zIOuniOydtOq3uOugiOydtOyFmCDsg4Htg5wg67Cw7Je0XG4gICAqIEBwYXJhbSBjb2RlTmFtZXMg7IKt7KCc7ZWgIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J28IOydtOumhCDrsLDsl7RcbiAgICogQHJldHVybnMg7IKt7KCcIOqwgOuKpSDsl6zrtoAg67CPIOyggeyaqeuQnCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDsnbTrpoRcbiAgICovXG4gIHZhbGlkYXRlRGVsZXRhYmxlKGNvbm5zOiBNaWdyYXRpb25TdGF0dXNbXCJjb25uc1wiXSwgY29kZU5hbWVzOiBzdHJpbmdbXSkge1xuICAgIGNvbnN0IGFwcGxpZWRDb2RlcyA9IGNvZGVOYW1lcy5maWx0ZXIoKGNvZGVOYW1lKSA9PlxuICAgICAgY29ubnMuc29tZSgoY29ubikgPT4gIWNvbm4ucGVuZGluZy5pbmNsdWRlcyhjb2RlTmFtZSkpLFxuICAgICk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgY2FuRGVsZXRlOiBhcHBsaWVkQ29kZXMubGVuZ3RoID09PSAwLFxuICAgICAgYXBwbGllZENvZGVzLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICog66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbzsnYQg7IKt7KCc7ZWp64uI64ukLlxuICAgKlxuICAgKiBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcGFyYW0gY29kZU5hbWVzIOyCreygnO2VoCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDsnbTrpoQg67Cw7Je0XG4gICAqIEByZXR1cm5zIOyCreygnOuQnCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDqsJzsiJhcbiAgICovXG4gIGFzeW5jIGRlbENvZGVzKGNvZGVOYW1lczogc3RyaW5nW10pOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgY29ubnMgfSA9IGF3YWl0IHRoaXMuZ2V0U3RhdHVzKCk7XG4gICAgY29uc3QgeyBjYW5EZWxldGUsIGFwcGxpZWRDb2RlcyB9ID0gdGhpcy52YWxpZGF0ZURlbGV0YWJsZShjb25ucywgY29kZU5hbWVzKTtcbiAgICBpZiAoIWNhbkRlbGV0ZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgWW91IGNhbm5vdCBkZWxldGUgYSBtaWdyYXRpb24gZmlsZSBpZiB0aGVyZSBpcyBhbHJlYWR5IGFwcGxpZWQuIEFwcGxpZWQgY29kZXM6ICR7YXBwbGllZENvZGVzLmpvaW4oXCIsIFwiKX1gLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc3VtKFxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIGNvZGVOYW1lcy5tYXAoYXN5bmMgKGNvZGVOYW1lKSA9PiB7XG4gICAgICAgICAgY29uc3QgZmlsZVBhdGggPSBgJHtTb25hbXUuYXBpUm9vdFBhdGh9L3NyYy9taWdyYXRpb25zLyR7Y29kZU5hbWV9LnRzYDtcbiAgICAgICAgICBpZiAoYXdhaXQgZXhpc3RzKGZpbGVQYXRoKSkge1xuICAgICAgICAgICAgYXdhaXQgdW5saW5rKGZpbGVQYXRoKTtcbiAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgfSksXG4gICAgICApLFxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGdlbkRhdGVUYWcoaW5kZXg6IG51bWJlciwgYmFzZURhdGU6IERhdGUgPSBuZXcgRGF0ZSgpKTogc3RyaW5nIHtcbiAgICBjb25zdCBkYXRlID0gbmV3IERhdGUoYmFzZURhdGUuZ2V0VGltZSgpICsgaW5kZXggKiAxMDAwKTtcbiAgICBjb25zdCBwYWQgPSAobnVtOiBudW1iZXIsIHNpemU6IG51bWJlciA9IDIpID0+IG51bS50b1N0cmluZygpLnBhZFN0YXJ0KHNpemUsIFwiMFwiKTtcbiAgICByZXR1cm4gKFxuICAgICAgZGF0ZS5nZXRGdWxsWWVhcigpLnRvU3RyaW5nKCkgK1xuICAgICAgcGFkKGRhdGUuZ2V0TW9udGgoKSArIDEpICtcbiAgICAgIHBhZChkYXRlLmdldERhdGUoKSkgK1xuICAgICAgcGFkKGRhdGUuZ2V0SG91cnMoKSkgK1xuICAgICAgcGFkKGRhdGUuZ2V0TWludXRlcygpKSArXG4gICAgICBwYWQoZGF0ZS5nZXRTZWNvbmRzKCkpXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvOydhCDsg53shLHtlanri4jri6QuXG4gICAqXG4gICAqIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEByZXR1cm5zIOyDneyEseuQnCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDqsJzsiJhcbiAgICovXG4gIGFzeW5jIGdlbmVyYXRlUHJlcGFyZWRDb2RlcygpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgcHJlcGFyZWRDb2RlcyB9ID0gYXdhaXQgdGhpcy5nZXRTdGF0dXMoKTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2VuZXJhdGVQcmVwYXJlZENvZGVzOnByZXBhcmVkQ29kZXNcIiwgcHJlcGFyZWRDb2Rlcyk7XG4gICAgaWYgKHByZXBhcmVkQ29kZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihcIlxcbu2YhOyerCDrqqjrkZAg7Iux7YGs65CcIOyDge2DnOyeheuLiOuLpC5cIikpO1xuICAgICAgcmV0dXJuIDA7XG4gICAgfVxuXG4gICAgLy8g7Iuk7KCcIOy9lOuTnCDsg53shLFcbiAgICBjb25zdCBtaWdyYXRpb25zRGlyID0gYCR7U29uYW11LmFwaVJvb3RQYXRofS9zcmMvbWlncmF0aW9uc2A7XG5cbiAgICBmb3IgKGNvbnN0IFtpbmRleCwgcGNvZGVdIG9mIHByZXBhcmVkQ29kZXMuZW50cmllcygpKSB7XG4gICAgICBpZiAocGNvZGUuZm9ybWF0dGVkKSB7XG4gICAgICAgIGNvbnN0IGRhdGVUYWcgPSB0aGlzLmdlbkRhdGVUYWcoaW5kZXgpO1xuICAgICAgICBjb25zdCBmaWxlUGF0aCA9IGAke21pZ3JhdGlvbnNEaXJ9LyR7ZGF0ZVRhZ31fJHtwY29kZS50aXRsZX0udHNgO1xuICAgICAgICBhd2FpdCB3cml0ZUZpbGUoZmlsZVBhdGgsIHBjb2RlLmZvcm1hdHRlZCk7XG4gICAgICAgICFpc1Rlc3QoKSAmJiBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihgTUlHUkFUSU9OIENSRUFURUQgJHtmaWxlUGF0aH1gKSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHByZXBhcmVkQ29kZXMubGVuZ3RoO1xuICB9XG5cbiAgYXN5bmMgY29tcGFyZU1pZ3JhdGlvbnMoY29tcGFyZURCOiBLbmV4KTogUHJvbWlzZTxHZW5NaWdyYXRpb25Db2RlW10+IHtcbiAgICAvLyBFbnRpdHkg7Iic7ZqM7ZWY7JesIOyLse2BrFxuICAgIGNvbnN0IGVudGl0eUlkcyA9IEVudGl0eU1hbmFnZXIuZ2V0QWxsSWRzKCk7XG5cbiAgICAvLyDsobDsnbjthYzsnbTruJQg7Y+s7ZWo7ZWY7JesIEVudGl0eeyXkOyEnCBNaWdyYXRpb25TZXQg7LaU7LacXG4gICAgY29uc3QgZW50aXR5U2V0c1dpdGhKb2luVGFibGUgPSBlbnRpdHlJZHNcbiAgICAgIC5maWx0ZXIoKGVudGl0eUlkKSA9PiBFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCkucHJvcHMubGVuZ3RoID4gMClcbiAgICAgIC5tYXAoKGVudGl0eUlkKSA9PiBnZXRNaWdyYXRpb25TZXRGcm9tRW50aXR5KEVudGl0eU1hbmFnZXIuZ2V0KGVudGl0eUlkKSkpO1xuXG4gICAgLy8g7KGw7J247YWM7J2067iU66eMIOy2lOy2nFxuICAgIGNvbnN0IGpvaW5UYWJsZXNXaXRoRHVwID0gZW50aXR5U2V0c1dpdGhKb2luVGFibGUuZmxhdE1hcCgoZW50aXR5U2V0KSA9PiBlbnRpdHlTZXQuam9pblRhYmxlcyk7XG4gICAgLy8g7KSR67O1IOygnOqxsCAo7KSR67O17J24IOqyveyasCBpbmRleGVz66W8IOuzke2VqSlcbiAgICBjb25zdCBqb2luVGFibGVzID0gT2JqZWN0LnZhbHVlcyhncm91cChqb2luVGFibGVzV2l0aER1cCwgKGp0KSA9PiBqdC50YWJsZSkpLm1hcCgodGFibGVzKSA9PiB7XG4gICAgICBhc3NlcnQodGFibGVzICE9PSB1bmRlZmluZWQsIFwidGFibGVzIGlzIHVuZGVmaW5lZFwiKTtcbiAgICAgIGlmICh0YWJsZXMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIHJldHVybiB0YWJsZXNbMF07XG4gICAgICB9XG4gICAgICByZXR1cm4ge1xuICAgICAgICAuLi50YWJsZXNbMF0sXG4gICAgICAgIGluZGV4ZXM6IHVuaXF1ZShcbiAgICAgICAgICB0YWJsZXMuZmxhdE1hcCgodCkgPT4gdC5pbmRleGVzKSxcbiAgICAgICAgICAoaW5kZXgpID0+IFtpbmRleC50eXBlLCAuLi5pbmRleC5jb2x1bW5zXS5qb2luKFwiLVwiKSxcbiAgICAgICAgKSxcbiAgICAgIH07XG4gICAgfSk7XG5cbiAgICAvLyDsobDsnbjthYzsnbTruJQg7Y+s7ZWo7ZWY7JesIE1pZ3JhdGlvblNldCDrsLDsl7RcbiAgICBjb25zdCBlbnRpdHlTZXRzOiBNaWdyYXRpb25TZXRbXSA9IFsuLi5lbnRpdHlTZXRzV2l0aEpvaW5UYWJsZSwgLi4uam9pblRhYmxlc107XG5cbiAgICBjb25zdCBjb2RlczogR2VuTWlncmF0aW9uQ29kZVtdID0gKFxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIGVudGl0eVNldHMubWFwKGFzeW5jIChlbnRpdHlTZXQpID0+IHtcbiAgICAgICAgICBjb25zdCBkYlNldCA9IGF3YWl0IFBvc3RncmVTUUxTY2hlbWFSZWFkZXIuZ2V0TWlncmF0aW9uU2V0RnJvbURCKFxuICAgICAgICAgICAgY29tcGFyZURCLFxuICAgICAgICAgICAgZW50aXR5U2V0LnRhYmxlLFxuICAgICAgICAgICk7XG4gICAgICAgICAgTmFpdGUudChgbWlncmF0b3I6Y29tcGFyZU1pZ3JhdGlvbnM6ZW50aXR5U2V0OiR7ZW50aXR5U2V0LnRhYmxlfWAsIGVudGl0eVNldCk7XG4gICAgICAgICAgTmFpdGUudChgbWlncmF0b3I6Y29tcGFyZU1pZ3JhdGlvbnM6ZGJTZXQ6JHtlbnRpdHlTZXQudGFibGV9YCwgZGJTZXQpO1xuXG4gICAgICAgICAgaWYgKGRiU2V0ID09PSBudWxsKSB7XG4gICAgICAgICAgICAvLyDquLDsobQg7YWM7J2067iUIOyXhuydjCwg7IOI66GcIO2FjOydtOu4lCDsg53shLFcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBnZW5lcmF0ZUNyZWF0ZUNvZGUoZW50aXR5U2V0KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8g6riw7KG0IO2FjOydtOu4lCDsobTsnqztlZjripQg7LyA7J207IqkXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZ2VuZXJhdGVBbHRlckNvZGUoZW50aXR5U2V0LCBkYlNldCwgY29tcGFyZURCKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pLFxuICAgICAgKVxuICAgICkuZmxhdCgpO1xuXG4gICAgLy8gbm9ybWFsIO2DgOyeheydtCDslZ7snLzroZwsIGZvcmVpZ27snbQg65Kk66GcXG4gICAgY29kZXMuc29ydCgoY29kZUEsIGNvZGVCKSA9PiB7XG4gICAgICBpZiAoY29kZUEudHlwZSA9PT0gXCJmb3JlaWduXCIgJiYgY29kZUIudHlwZSA9PT0gXCJub3JtYWxcIikge1xuICAgICAgICByZXR1cm4gMTtcbiAgICAgIH0gZWxzZSBpZiAoY29kZUEudHlwZSA9PT0gXCJub3JtYWxcIiAmJiBjb2RlQi50eXBlID09PSBcImZvcmVpZ25cIikge1xuICAgICAgICByZXR1cm4gLTE7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gMDtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHJldHVybiBjb2RlcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTaGFkb3cgREIg7YWM7Iqk7Yq466W8IOynhO2Wie2VqeuLiOuLpC5cbiAgICpcbiAgICogU29uYW11IFVJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQHJldHVybnMgU2hhZG93IERCIO2FjOyKpO2KuCDqsrDqs7xcbiAgICovXG4gIGFzeW5jIHJ1blNoYWRvd1Rlc3QoKTogUHJvbWlzZTxNaWdyYXRpb25SZXN1bHQ+IHtcbiAgICBjb25zdCB0ZGJDb25uID0gU29uYW11LmRiQ29uZmlnLnRlc3QuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZztcbiAgICBjb25zdCBzaGFkb3dEYXRhYmFzZSA9IGAke3RkYkNvbm4uZGF0YWJhc2V9X19taWdyYXRpb25fc2hhZG93YDtcblxuICAgIC8vIO2FjOyKpO2KuCDsg4Htmansl5DshJzripQg7Yq4656c7J6t7IWY7J2EIOy0iOq4sO2ZlO2VmOqzoCwg7IOIIOuNsOydtO2EsOuyoOydtOyKpCDsu6TrhKXshZjsnYQg6rCA7KC47JmA7JW8IO2VqFxuICAgIGlmIChpc1Rlc3QoKSkge1xuICAgICAgYXdhaXQgREIuY2xlYXJUZXN0VHJhbnNhY3Rpb24oKTtcbiAgICAgIC8vIOuzkeugrCDthYzsiqTtirgg66qo65Oc7JeQ7ISc64qUIHdvcmtlciBEQiDsl7DqsrAg7Jyg7KeAXG4gICAgICBpZiAocHJvY2Vzcy5lbnYuU09OQU1VX1dPUktFUl9EQiAhPT0gXCJ0cnVlXCIpIHtcbiAgICAgICAgYXdhaXQgREIuZGVzdHJveSgpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIOq4sOyhtCBTaGFkb3cgREIg7IKt7KCcIO2bhCBTaGFkb3cgREIg7IOd7ISxXG4gICAgY29uc3QgdGRiID0gY3JlYXRlS25leEluc3RhbmNlKFNvbmFtdS5kYkNvbmZpZy50ZXN0KTtcbiAgICB0cnkge1xuICAgICAgIWlzVGVzdCgpICYmIGNvbnNvbGUubG9nKGNoYWxrLm1hZ2VudGEoYCR7c2hhZG93RGF0YWJhc2V9IOyCreygnGApKTtcbiAgICAgIGF3YWl0IHRkYi5yYXcoYERST1AgREFUQUJBU0UgSUYgRVhJU1RTICR7c2hhZG93RGF0YWJhc2V9YCk7XG4gICAgICBhd2FpdCB0ZGIucmF3KGBcbiAgICAgICAgU0VMRUNUIHBnX3Rlcm1pbmF0ZV9iYWNrZW5kKHBnX3N0YXRfYWN0aXZpdHkucGlkKVxuICAgICAgICBGUk9NIHBnX3N0YXRfYWN0aXZpdHlcbiAgICAgICAgV0hFUkUgZGF0bmFtZSA9ICcke3RkYkNvbm4uZGF0YWJhc2V9J1xuICAgICAgICAgIEFORCBwaWQgPD4gcGdfYmFja2VuZF9waWQoKTtcbiAgICAgIGApO1xuICAgICAgYXdhaXQgdGRiLnJhdyhgQ1JFQVRFIERBVEFCQVNFICR7c2hhZG93RGF0YWJhc2V9IFRFTVBMQVRFICR7dGRiQ29ubi5kYXRhYmFzZX1gKTtcblxuICAgICAgLy8gU2hhZG93IERC7JeQIOyXsOqysFxuICAgICAgY29uc3Qgc2RiID0gY3JlYXRlS25leEluc3RhbmNlKHtcbiAgICAgICAgLi4uU29uYW11LmRiQ29uZmlnLnRlc3QsXG4gICAgICAgIGNvbm5lY3Rpb246IHtcbiAgICAgICAgICAuLi50ZGJDb25uLFxuICAgICAgICAgIGRhdGFiYXNlOiBzaGFkb3dEYXRhYmFzZSxcbiAgICAgICAgICBwYXNzd29yZDogdGRiQ29ubi5wYXNzd29yZCxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBzaGFkb3cgREIg7YWM7Iqk7Yq4IOynhO2WiVxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgW2JhdGNoTm8sIGFwcGxpZWRdID0gYXdhaXQgc2RiLm1pZ3JhdGUubGF0ZXN0KCk7XG4gICAgICAgICFpc1Rlc3QoKSAmJlxuICAgICAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmdyZWVuKFwiU2hhZG93IERCIO2FjOyKpO2KuOyXkCDshLHqs7XtlojsirXri4jri6QhXCIpLCB7XG4gICAgICAgICAgICBiYXRjaE5vLFxuICAgICAgICAgICAgYXBwbGllZCxcbiAgICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIGNvbm5LZXk6IFwic2hhZG93XCIsXG4gICAgICAgICAgICBiYXRjaE5vLFxuICAgICAgICAgICAgYXBwbGllZCxcbiAgICAgICAgICB9LFxuICAgICAgICBdO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjb25zb2xlLmVycm9yKGUpO1xuICAgICAgICB0aHJvdyBuZXcgU2VydmljZVVuYXZhaWxhYmxlRXhjZXB0aW9uKFNEKFwic29uYW11LmVycm9yLnNoYWRvd0RiVGVzdEZhaWxlZFwiKSk7XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBhd2FpdCBzZGIuZGVzdHJveSgpO1xuICAgICAgfVxuICAgIH0gZmluYWxseSB7XG4gICAgICAvLyBTaGFkb3cgREIg7IKt7KCcXG4gICAgICAhaXNUZXN0KCkgJiYgY29uc29sZS5sb2coY2hhbGsubWFnZW50YShgJHtzaGFkb3dEYXRhYmFzZX0g7IKt7KCcYCkpO1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgdGRiLnJhdyhgRFJPUCBEQVRBQkFTRSBJRiBFWElTVFMgJHtzaGFkb3dEYXRhYmFzZX1gKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIlNoYWRvdyBEQiDsoJXrpqwg7Iuk7YyoOlwiLCBlKTsgLy8g7J206rKMIOyXhuycvOuptCDsobDsmqntnogg64iE7IiYXG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBhd2FpdCB0ZGIuZGVzdHJveSgpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O2NBUXVDO1VBQ0g7WUFFa0I7VUFDdEI7c0JBQ3lCO3FCQUNpQjthQUNuQztrQkFFTTtnQkFDRjt1QkFDK0I7cUJBQ2Q7Z0NBQ1E7Q0FTdkQsV0FBYixNQUFzQjtFQUNwQixNQUFjLDBCQUNaLE9BQ0EsUUFDMEI7R0FDMUIsTUFBTUEsVUFBMkIsRUFBRTtBQUVuQyxRQUFLLE1BQU0sRUFBRSxTQUFTLFVBQVUsT0FBTztJQUNyQyxNQUFNLENBQUMsU0FBUyxXQUNkLFdBQVcsVUFBVSxNQUFNLEtBQUssUUFBUSxRQUFRLEdBQUcsTUFBTSxLQUFLLFFBQVEsVUFBVTtBQUVsRixZQUFRLEtB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
363
+
364
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlncmF0b3IuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL21pZ3JhdGlvbi9taWdyYXRvci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCB7IG1rZGlyLCByZWFkZGlyLCB1bmxpbmssIHdyaXRlRmlsZSB9IGZyb20gXCJmcy9wcm9taXNlc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcblxuaW1wb3J0IGNoYWxrIGZyb20gXCJjaGFsa1wiO1xuaW1wb3J0IHsgdHlwZSBLbmV4IH0gZnJvbSBcImtuZXhcIjtcbmltcG9ydCB7IGdyb3VwLCBzdW0sIHVuaXF1ZSB9IGZyb20gXCJyYWRhc2hpXCI7XG5cbmltcG9ydCB7IFNvbmFtdSB9IGZyb20gXCIuLi9hcGkvc29uYW11XCI7XG5pbXBvcnQgeyBEQiB9IGZyb20gXCIuLi9kYXRhYmFzZS9kYlwiO1xuaW1wb3J0IHsgdHlwZSBTb25hbXVEQkNvbmZpZyB9IGZyb20gXCIuLi9kYXRhYmFzZS9kYlwiO1xuaW1wb3J0IHsgY3JlYXRlS25leEluc3RhbmNlIH0gZnJvbSBcIi4uL2RhdGFiYXNlL2tuZXhcIjtcbmltcG9ydCB7IFNEIH0gZnJvbSBcIi4uL2RpY3Qvc2RcIjtcbmltcG9ydCB7IEVudGl0eU1hbmFnZXIgfSBmcm9tIFwiLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyBnZXRTb25hbXVFbnZpcm9ubWVudCB9IGZyb20gXCIuLi9lbnZcIjtcbmltcG9ydCB7IFNlcnZpY2VVbmF2YWlsYWJsZUV4Y2VwdGlvbiB9IGZyb20gXCIuLi9leGNlcHRpb25zL3NvLWV4Y2VwdGlvbnNcIjtcbmltcG9ydCB7IE5haXRlIH0gZnJvbSBcIi4uL25haXRlL25haXRlXCI7XG5pbXBvcnQgeyB0eXBlIEdlbk1pZ3JhdGlvbkNvZGUsIHR5cGUgTWlncmF0aW9uU2V0IH0gZnJvbSBcIi4uL3R5cGVzL3R5cGVzXCI7XG5pbXBvcnQgeyBpc0xvY2FsLCBpc1Rlc3QgfSBmcm9tIFwiLi4vdXRpbHMvY29udHJvbGxlclwiO1xuaW1wb3J0IHsgZXhpc3RzIH0gZnJvbSBcIi4uL3V0aWxzL2ZzLXV0aWxzXCI7XG5pbXBvcnQgeyBnZW5lcmF0ZUFsdGVyQ29kZSwgZ2VuZXJhdGVDcmVhdGVDb2RlIH0gZnJvbSBcIi4vY29kZS1nZW5lcmF0aW9uXCI7XG5pbXBvcnQgeyBnZXRNaWdyYXRpb25TZXRGcm9tRW50aXR5IH0gZnJvbSBcIi4vbWlncmF0aW9uLXNldFwiO1xuaW1wb3J0IHsgUG9zdGdyZVNRTFNjaGVtYVJlYWRlciB9IGZyb20gXCIuL3Bvc3RncmVzcWwtc2NoZW1hLXJlYWRlclwiO1xuaW1wb3J0IHsgdHlwZSBDb25uU3RyaW5nLCB0eXBlIE1pZ3JhdGlvbkNvZGUsIHR5cGUgTWlncmF0aW9uU3RhdHVzIH0gZnJvbSBcIi4vdHlwZXNcIjtcblxuZXhwb3J0IHR5cGUgTWlncmF0aW9uUmVzdWx0ID0ge1xuICBjb25uS2V5OiBzdHJpbmc7XG4gIGJhdGNoTm86IG51bWJlcjtcbiAgYXBwbGllZDogc3RyaW5nW107XG59W107XG5cbmV4cG9ydCBjbGFzcyBNaWdyYXRvciB7XG4gIHByaXZhdGUgaXNNaXNzaW5nTWlncmF0aW9uVGFibGVFcnJvcihlcnJvcjogdW5rbm93bik6IGJvb2xlYW4ge1xuICAgIGlmICh0eXBlb2YgZXJyb3IgIT09IFwib2JqZWN0XCIgfHwgZXJyb3IgPT09IG51bGwpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCBtYXliZVBvc3RncmVzRXJyb3IgPSBlcnJvciBhcyB7IGNvZGU/OiB1bmtub3duOyBtZXNzYWdlPzogdW5rbm93biB9O1xuICAgIHJldHVybiAoXG4gICAgICBtYXliZVBvc3RncmVzRXJyb3IuY29kZSA9PT0gXCI0MlAwMVwiICYmXG4gICAgICB0eXBlb2YgbWF5YmVQb3N0Z3Jlc0Vycm9yLm1lc3NhZ2UgPT09IFwic3RyaW5nXCIgJiZcbiAgICAgIG1heWJlUG9zdGdyZXNFcnJvci5tZXNzYWdlLmluY2x1ZGVzKFwia25leF9taWdyYXRpb25zXCIpXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0TWlncmF0aW9uVGFyZ2V0S2V5cygpOiAoa2V5b2YgU29uYW11REJDb25maWcpW10ge1xuICAgIGNvbnN0IGNvbm5LZXlzID0gT2JqZWN0LmtleXMoU29uYW11LmRiQ29uZmlnKS5maWx0ZXIoXG4gICAgICAoa2V5KSA9PiAha2V5LmVuZHNXaXRoKFwiX3JlYWRvbmx5XCIpLFxuICAgICkgYXMgKGtleW9mIFNvbmFtdURCQ29uZmlnKVtdO1xuXG4gICAgaWYgKGlzTG9jYWwoKSkge1xuICAgICAgcmV0dXJuIGNvbm5LZXlzO1xuICAgIH1cblxuICAgIGNvbnN0IGVudmlyb25tZW50ID0gZ2V0U29uYW11RW52aXJvbm1lbnQoKTtcbiAgICByZXR1cm4gY29ubktleXMuZmlsdGVyKChrZXkpID0+IGtleSA9PT0gZW52aXJvbm1lbnQpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBydW5NaWdyYXRpb25zU2VxdWVudGlhbGx5KFxuICAgIGNvbm5zOiB7IGNvbm5LZXk6IGtleW9mIFNvbmFtdURCQ29uZmlnOyBrbmV4OiBLbmV4IH1bXSxcbiAgICBhY3Rpb246IFwiYXBwbHlcIiB8IFwicm9sbGJhY2tcIixcbiAgKTogUHJvbWlzZTxNaWdyYXRpb25SZXN1bHQ+IHtcbiAgICBjb25zdCByZXN1bHRzOiBNaWdyYXRpb25SZXN1bHQgPSBbXTtcblxuICAgIGZvciAoY29uc3QgeyBjb25uS2V5LCBrbmV4IH0gb2YgY29ubnMpIHtcbiAgICAgIGNvbnN0IFtiYXRjaE5vLCBhcHBsaWVkXSA9XG4gICAgICAgIGFjdGlvbiA9PT0gXCJhcHBseVwiID8gYXdhaXQga25leC5taWdyYXRlLmxhdGVzdCgpIDogYXdhaXQga25leC5taWdyYXRlLnJvbGxiYWNrKCk7XG5cbiAgICAgIHJlc3VsdHMucHVzaCh7XG4gICAgICAgIGNvbm5LZXksXG4gICAgICAgIGJhdGNoTm8sXG4gICAgICAgIGFwcGxpZWQsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZ2V0TWlncmF0aW9uQ29kZXMoKTogUHJvbWlzZTxNaWdyYXRpb25Db2RlW10+IHtcbiAgICBjb25zdCBzcmNNaWdyYXRpb25zRGlyID0gcGF0aC5qb2luKFNvbmFtdS5hcGlSb290UGF0aCwgXCJzcmNcIiwgXCJtaWdyYXRpb25zXCIpOyAvLyDsnbTqsbQg7ZmY6rK97JeQIOq0gOqzhOyXhuydtCDtla3sg4Egc3Jj7JeQ7IScIOywvuyVhOyVvCDtlbTsmpQuXG5cbiAgICBpZiAoIShhd2FpdCBleGlzdHMoc3JjTWlncmF0aW9uc0RpcikpKSB7XG4gICAgICBhd2FpdCBta2RpcihzcmNNaWdyYXRpb25zRGlyLCB7XG4gICAgICAgIHJlY3Vyc2l2ZTogdHJ1ZSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IGNvZGVzID0gKGF3YWl0IHJlYWRkaXIoc3JjTWlncmF0aW9uc0RpcikpXG4gICAgICAuZmlsdGVyKChmKSA9PiBmLmVuZHNXaXRoKFwiLnRzXCIpKVxuICAgICAgLm1hcCgoZikgPT4gKHtcbiAgICAgICAgbmFtZTogZi5yZXBsYWNlKFwiLnRzXCIsIFwiXCIpLFxuICAgICAgICBwYXRoOiBwYXRoLmpvaW4oc3JjTWlncmF0aW9uc0RpciwgZiksXG4gICAgICB9KSlcbiAgICAgIC50b1NvcnRlZCgoYSwgYikgPT4gKGEubmFtZSA8IGIubmFtZSA/IDEgOiAtMSkpOyAvLyDsnbTrpoQg64K066a87LCo7IicIOygleugrCjstZzsi6DsiJwpXG5cbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0TWlncmF0aW9uQ29kZXM6cmVzdWx0c1wiLCBjb2Rlcyk7XG4gICAgcmV0dXJuIGNvZGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIO2DgOqyn+uzhCDrp4jsnbTqt7jroIjsnbTshZgg7IOB7YOc7JmAIOy9lOuTnCDsg53shLEv7KSA67mEIOyDge2DnOulvCDqtaztlbTsmLXri4jri6QuXG4gICAqIOyLpOygnOuhnCBEQuyXkCDsoJHqt7zrj4Qg7ZWY6rOgIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J2864+EIO2ZleyduO2VmOqzoCxcbiAgICog7ZWE7JqU7ZWY64uk66m0IOyggeyaqe2VoCDsiJgg7J6I64qUIOy9lOuTnOulvCDsg53shLHquYzsp4Ag7ZW07Ji164uI64ukLlxuICAgKlxuICAgKiBDTEnsmYAgU29uYW11IFVJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQHJldHVybnNcbiAgICovXG4gIGFzeW5jIGdldFN0YXR1cygpOiBQcm9taXNlPE1pZ3JhdGlvblN0YXR1cz4ge1xuICAgIGNvbnN0IGNvZGVzID0gYXdhaXQgdGhpcy5nZXRNaWdyYXRpb25Db2RlcygpO1xuICAgIE5haXRlLnQoXCJtaWdyYXRvcjpnZXRTdGF0dXM6Y29kZXNcIiwgY29kZXMpO1xuXG4gICAgY29uc3QgY29ubktleXMgPSB0aGlzLmdldE1pZ3JhdGlvblRhcmdldEtleXMoKTtcblxuICAgIGxldCBtaWdyYXRpb25TdGF0dXNFcnJvcjogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gICAgY29uc3Qgc3RhdHVzZXMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIGNvbm5LZXlzLm1hcChhc3luYyAoY29ubktleSkgPT4ge1xuICAgICAgICBjb25zdCBrbmV4T3B0aW9ucyA9IFNvbmFtdS5kYkNvbmZpZ1tjb25uS2V5XTtcbiAgICAgICAgY29uc3QgdENvbm4gPSBjcmVhdGVLbmV4SW5zdGFuY2Uoa25leE9wdGlvbnMpO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3Qgc3RhdHVzOiBudW1iZXIgfCBcImVycm9yXCIgPSBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRDb25uLm1pZ3JhdGUuc3RhdHVzKCk7XG4gICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgaWYgKHRoaXMuaXNNaXNzaW5nTWlncmF0aW9uVGFibGVFcnJvcihlcnIpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGNvZGVzLmxlbmd0aDtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgICAgICBjaGFsay55ZWxsb3coXG4gICAgICAgICAgICAgICAgICBgJHtjb25uS2V5feydmCDrp4jsnbTqt7jroIjsnbTshZgg7IOB7YOc66W8IOqwgOyguOyYpOuKlCDrjbDsl5Ag7Iuk7Yyo7ZWY7JiA7Iq164uI64ukLiDrjbDsnbTthLDrsqDsnbTsiqTqsIAg7Jis67CU66W06rKMIOq1rOyEseuQmOyngCDslYrsnYAg6rKDIOqwmeyKteuLiOuLpC4g7ZmV7J247ZWY7Iuc6rOgIOuLpOyLnCDsi5zrj4TtlbTso7zshLjsmpQuXFxu7Iuc64+E7ZWcIOyXsOqysCDshKTsoJU6XFxuJHtKU09OLnN0cmluZ2lmeShrbmV4T3B0aW9ucy5jb25uZWN0aW9uLCBudWxsLCAyKX1cXG7rsJzsg53tlZwg7JeQ65+sOlxcbiR7ZXJyfVxcbmAsXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgbWlncmF0aW9uU3RhdHVzRXJyb3IgPSBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVycik7XG4gICAgICAgICAgICAgIHJldHVybiBcImVycm9yXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSkoKTtcbiAgICAgICAgICBjb25zdCBwZW5kaW5nOiBzdHJpbmdbXSA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBjb25zdCBbLCBmZExpc3RdID0gYXdhaXQgdENvbm4ubWlncmF0ZS5saXN0KCk7XG4gICAgICAgICAgICAgIHJldHVybiBmZExpc3QubWFwKChmZDogeyBmaWxlOiBzdHJpbmcgfSkgPT4gZmQuZmlsZS5yZXBsYWNlKFwiLnRzXCIsIFwiXCIpKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICBpZiAodGhpcy5pc01pc3NpbmdNaWdyYXRpb25UYWJsZUVycm9yKGVycikpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gY29kZXMubWFwKChjb2RlKSA9PiBjb2RlLm5hbWUpO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgbWlncmF0aW9uU3RhdHVzRXJyb3IgPSBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVycik7XG4gICAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KSgpO1xuICAgICAgICAgIGNvbnN0IGN1cnJlbnRWZXJzaW9uOiBzdHJpbmcgfCBcImVycm9yXCIgPSBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRDb25uLm1pZ3JhdGUuY3VycmVudFZlcnNpb24oKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKF9lcnIpIHtcbiAgICAgICAgICAgICAgaWYgKHRoaXMuaXNNaXNzaW5nTWlncmF0aW9uVGFibGVFcnJvcihfZXJyKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBcIm5vbmVcIjtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIG1pZ3JhdGlvblN0YXR1c0Vycm9yID0gX2VyciBpbnN0YW5jZW9mIEVycm9yID8gX2Vyci5tZXNzYWdlIDogU3RyaW5nKF9lcnIpO1xuICAgICAgICAgICAgICByZXR1cm4gXCJlcnJvclwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pKCk7XG4gICAgICAgICAgTmFpdGUudChcIm1pZ3JhdG9yOmdldFN0YXR1czpzdGF0dXNcIiwgc3RhdHVzKTtcblxuICAgICAgICAgIGNvbnN0IGNvbm5lY3Rpb24gPSBrbmV4T3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIG5hbWU6IGNvbm5LZXksXG4gICAgICAgICAgICBjb25uS2V5LFxuICAgICAgICAgICAgY29ublN0cmluZzogYHBnOi8vJHtjb25uZWN0aW9uLnVzZXIgPz8gXCJcIn1AJHtjb25uZWN0aW9uLmhvc3R9OiR7XG4gICAgICAgICAgICAgIGNvbm5lY3Rpb24ucG9ydFxuICAgICAgICAgICAgfS8ke2Nvbm5lY3Rpb24uZGF0YWJhc2V9YCBhcyBDb25uU3RyaW5nLFxuICAgICAgICAgICAgY3VycmVudFZlcnNpb24sXG4gICAgICAgICAgICBzdGF0dXM6IHN0YXR1cyxcbiAgICAgICAgICAgIHBlbmRpbmcsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICBhd2FpdCB0Q29ubi5kZXN0cm95KCk7XG4gICAgICAgIH1cbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICBOYWl0ZS50KFwibWlncmF0b3I6Z2V0U3RhdHVzOmNvbm5zXCIsIHN0YXR1c2VzKTtcblxuICAgIGNvbnN0IHByZXBhcmVkQ29kZXM6IEdlbk1pZ3JhdGlvbkNvZGVbXSA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBzdGF0dXMwY29ubiA9IHN0YXR1c2VzLmZpbmQoKHN0YXR1cykgPT4gc3RhdHVzLnN0YXR1cyA9PT0gMCk7XG4gICAgICBpZiAoc3RhdHVzMGNvbm4gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgY2hhbGsueWVsbG93KFxuICAgICAgICAgICAgYFdoaWxlIHRyeWluZyB0byBwcmVwYXJlIG1pZ3JhdGlvbiBjb2Rlcywgd2UgZm91bmQgdGhhdCB0aGVyZSBpcyBubyBkYXRhYmFzZSB0byBjb21wYXJlIG1pZ3JhdGlvbnMuIFdlIG5lZWQgYXQgbGVhc3Qgb25lIGRhdGFiYXNlIHdoZXJlIGV2ZXJ5IG1pZ3JhdGlvbiBpcyBhcHBsaWVkKHN0YXR1cyA9PT0gMCkuIFlvdSBtaWdodCB3YW50IHRvIGFwcGx5IHlvdXIgZXhpc3RpbmcgbWlncmF0aW9ucyB0byBvbmUgb2YgdGhlIGRhdGFiYXNlcy5gLFxuICAgICAgICAgICksXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgY29tcGFyZURCY29ubiA9IGNyZWF0ZUtuZXhJbnN0YW5jZShTb25hbXUuZGJDb25maWdbc3RhdHVzMGNvbm4uY29ubktleV0pO1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuY29tcGFyZU1pZ3JhdGlvbnMoY29tcGFyZURCY29ubik7XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBhd2FpdCBjb21wYXJlREJjb25uLmRlc3Ryb3koKTtcbiAgICAgIH1cbiAgICB9KSgpO1xuXG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOmdldFN0YXR1czpwcmVwYXJlZENvZGVzXCIsIHByZXBhcmVkQ29kZXMpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGNvbm5zOiBzdGF0dXNlcyxcbiAgICAgIGNvZGVzLFxuICAgICAgcHJlcGFyZWRDb2RlcyxcbiAgICAgIGVycm9yOiBtaWdyYXRpb25TdGF0dXNFcnJvcixcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIOuniOydtOq3uOugiOydtOyFmOydhCDsoIHsmqntlZjqsbDrgpgg66Gk67Cx7ZWp64uI64ukLlxuICAgKiBTb25hbXUgVUnsl5DshJwg66eI7J206re466CI7J207IWYIOyekeyXheydhCDsiJjtlontlaAg65WMIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQ0xJ7JmAIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEBwYXJhbSBhY3Rpb24g7J6R7JeFIOycoO2YlSAoYXBwbHkvcm9sbGJhY2spXG4gICAqIEBwYXJhbSB0YXJnZXRzIOyekeyXhSDrjIDsg4EgREIg7ISk7KCVIO2CpCAoa2V5b2YgU29uYW11REJDb25maWcpXG4gICAqIEByZXR1cm5zIOyekeyXhSDqsrDqs7xcbiAgICovXG4gIGFzeW5jIHJ1bkFjdGlvbihcbiAgICBhY3Rpb246IFwiYXBwbHlcIiB8IFwicm9sbGJhY2tcIixcbiAgICB0YXJnZXRzOiAoa2V5b2YgU29uYW11REJDb25maWcpW10sXG4gICk6IFByb21pc2U8TWlncmF0aW9uUmVzdWx0PiB7XG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOnJ1bkFjdGlvbjphY3Rpb25cIiwgYWN0aW9uKTtcbiAgICBOYWl0ZS50KFwibWlncmF0b3I6cnVuQWN0aW9uOnRhcmdldHNcIiwgdGFyZ2V0cyk7XG5cbiAgICBjb25zdCBhbGxvd2VkVGFyZ2V0cyA9IG5ldyBTZXQodGhpcy5nZXRNaWdyYXRpb25UYXJnZXRLZXlzKCkpO1xuICAgIGNvbnN0IGRpc2FsbG93ZWRUYXJnZXRzID0gdGFyZ2V0cy5maWx0ZXIoKHRhcmdldCkgPT4gIWFsbG93ZWRUYXJnZXRzLmhhcyh0YXJnZXQpKTtcbiAgICBpZiAoZGlzYWxsb3dlZFRhcmdldHMubGVuZ3RoID4gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgTWlncmF0aW9uIHRhcmdldHMgYXJlIG5vdCBhbGxvd2VkIGluIE5PREVfRU5WPSR7Z2V0U29uYW11RW52aXJvbm1lbnQoKX06ICR7ZGlzYWxsb3dlZFRhcmdldHMuam9pbihcIiwgXCIpfWAsXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIGdldCB1bmlxIGtuZXggY29uZmlnc1xuICAgIGNvbnN0IGNvbmZpZ3MgPSB1bmlxdWUoXG4gICAgICB0YXJnZXRzXG4gICAgICAgIC5tYXAoKHRhcmdldCkgPT4gKHtcbiAgICAgICAgICBjb25uS2V5OiB0YXJnZXQsXG4gICAgICAgICAgb3B0aW9uczogU29uYW11LmRiQ29uZmlnW3RhcmdldF0sXG4gICAgICAgIH0pKVxuICAgICAgICAuZmlsdGVyKChjKSA9PiBjLm9wdGlvbnMgIT09IHVuZGVmaW5lZCksXG4gICAgICAoeyBvcHRpb25zIH0pID0+XG4gICAgICAgIGAkeyhvcHRpb25zLmNvbm5lY3Rpb24gYXMgS25leC5QZ0Nvbm5lY3Rpb25Db25maWcpLmhvc3R9OiR7XG4gICAgICAgICAgKG9wdGlvbnMuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZykucG9ydCA/PyA1NDMyXG4gICAgICAgIH0vJHsob3B0aW9ucy5jb25uZWN0aW9uIGFzIEtuZXguUGdDb25uZWN0aW9uQ29uZmlnKS5kYXRhYmFzZX1gLFxuICAgICk7XG5cbiAgICAvLyBnZXQgY29ubmVjdGlvbnNcbiAgICBjb25zdCBjb25ucyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgY29uZmlncy5tYXAoYXN5bmMgKGNvbmZpZykgPT4gKHtcbiAgICAgICAgY29ubktleTogY29uZmlnLmNvbm5LZXksXG4gICAgICAgIGtuZXg6IGNyZWF0ZUtuZXhJbnN0YW5jZShjb25maWcub3B0aW9ucyksXG4gICAgICB9KSksXG4gICAgKTtcblxuICAgIHRyeSB7XG4gICAgICAvLyBhY3Rpb25cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICAgIHN3aXRjaCAoYWN0aW9uKSB7XG4gICAgICAgICAgY2FzZSBcImFwcGx5XCI6XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5ydW5NaWdyYXRpb25zU2VxdWVudGlhbGx5KGNvbm5zLCBcImFwcGx5XCIpO1xuICAgICAgICAgIGNhc2UgXCJyb2xsYmFja1wiOlxuICAgICAgICAgICAgcmV0dXJuIHRoaXMucnVuTWlncmF0aW9uc1NlcXVlbnRpYWxseShjb25ucywgXCJyb2xsYmFja1wiKTtcbiAgICAgICAgfVxuICAgICAgfSkoKTtcblxuICAgICAgTmFpdGUudChcIm1pZ3JhdG9yOnJ1bkFjdGlvbjpyZXN1bHRcIiwgcmVzdWx0KTtcblxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIGNvbm5zLm1hcCgoeyBrbmV4IH0pID0+IHtcbiAgICAgICAgICByZXR1cm4ga25leC5kZXN0cm95KCk7XG4gICAgICAgIH0pLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICog7IKt7KCcIOqwgOuKpe2VnCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvOydhCDqsoDspp3tlanri4jri6QuXG4gICAqXG4gICAqIEBwYXJhbSBjb25ucyDrp4jsnbTqt7jroIjsnbTshZgg7IOB7YOcIOuwsOyXtFxuICAgKiBAcGFyYW0gY29kZU5hbWVzIOyCreygnO2VoCDrp4jsnbTqt7jroIjsnbTshZgg7L2U65OcIO2MjOydvCDsnbTrpoQg67Cw7Je0XG4gICAqIEByZXR1cm5zIOyCreygnCDqsIDriqUg7Jes67aAIOuwjyDsoIHsmqnrkJwg66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbwg7J2066aEXG4gICAqL1xuICB2YWxpZGF0ZURlbGV0YWJsZShjb25uczogTWlncmF0aW9uU3RhdHVzW1wiY29ubnNcIl0sIGNvZGVOYW1lczogc3RyaW5nW10pIHtcbiAgICBjb25zdCBhcHBsaWVkQ29kZXMgPSBjb2RlTmFtZXMuZmlsdGVyKChjb2RlTmFtZSkgPT5cbiAgICAgIGNvbm5zLnNvbWUoKGNvbm4pID0+ICFjb25uLnBlbmRpbmcuaW5jbHVkZXMoY29kZU5hbWUpKSxcbiAgICApO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGNhbkRlbGV0ZTogYXBwbGllZENvZGVzLmxlbmd0aCA9PT0gMCxcbiAgICAgIGFwcGxpZWRDb2RlcyxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIOuniOydtOq3uOugiOydtOyFmCDsvZTrk5wg7YyM7J287J2EIOyCreygnO2VqeuLiOuLpC5cbiAgICpcbiAgICogU29uYW11IFVJ7JeQ7IScIOyCrOyaqeuQqeuLiOuLpC5cbiAgICpcbiAgICogQHBhcmFtIGNvZGVOYW1lcyDsgq3soJztlaAg66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbwg7J2066aEIOuwsOyXtFxuICAgKiBAcmV0dXJucyDsgq3soJzrkJwg66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbwg6rCc7IiYXG4gICAqL1xuICBhc3luYyBkZWxDb2Rlcyhjb2RlTmFtZXM6IHN0cmluZ1tdKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCB7IGNvbm5zIH0gPSBhd2FpdCB0aGlzLmdldFN0YXR1cygpO1xuICAgIGNvbnN0IHsgY2FuRGVsZXRlLCBhcHBsaWVkQ29kZXMgfSA9IHRoaXMudmFsaWRhdGVEZWxldGFibGUoY29ubnMsIGNvZGVOYW1lcyk7XG4gICAgaWYgKCFjYW5EZWxldGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYFlvdSBjYW5ub3QgZGVsZXRlIGEgbWlncmF0aW9uIGZpbGUgaWYgdGhlcmUgaXMgYWxyZWFkeSBhcHBsaWVkLiBBcHBsaWVkIGNvZGVzOiAke2FwcGxpZWRDb2Rlcy5qb2luKFwiLCBcIil9YCxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHN1bShcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBjb2RlTmFtZXMubWFwKGFzeW5jIChjb2RlTmFtZSkgPT4ge1xuICAgICAgICAgIGNvbnN0IGZpbGVQYXRoID0gYCR7U29uYW11LmFwaVJvb3RQYXRofS9zcmMvbWlncmF0aW9ucy8ke2NvZGVOYW1lfS50c2A7XG4gICAgICAgICAgaWYgKGF3YWl0IGV4aXN0cyhmaWxlUGF0aCkpIHtcbiAgICAgICAgICAgIGF3YWl0IHVubGluayhmaWxlUGF0aCk7XG4gICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgIH0pLFxuICAgICAgKSxcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBnZW5EYXRlVGFnKGluZGV4OiBudW1iZXIsIGJhc2VEYXRlOiBEYXRlID0gbmV3IERhdGUoKSk6IHN0cmluZyB7XG4gICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKGJhc2VEYXRlLmdldFRpbWUoKSArIGluZGV4ICogMTAwMCk7XG4gICAgY29uc3QgcGFkID0gKG51bTogbnVtYmVyLCBzaXplOiBudW1iZXIgPSAyKSA9PiBudW0udG9TdHJpbmcoKS5wYWRTdGFydChzaXplLCBcIjBcIik7XG4gICAgcmV0dXJuIChcbiAgICAgIGRhdGUuZ2V0RnVsbFllYXIoKS50b1N0cmluZygpICtcbiAgICAgIHBhZChkYXRlLmdldE1vbnRoKCkgKyAxKSArXG4gICAgICBwYWQoZGF0ZS5nZXREYXRlKCkpICtcbiAgICAgIHBhZChkYXRlLmdldEhvdXJzKCkpICtcbiAgICAgIHBhZChkYXRlLmdldE1pbnV0ZXMoKSkgK1xuICAgICAgcGFkKGRhdGUuZ2V0U2Vjb25kcygpKVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICog66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbzsnYQg7IOd7ISx7ZWp64uI64ukLlxuICAgKlxuICAgKiBTb25hbXUgVUnsl5DshJwg7IKs7Jqp65Cp64uI64ukLlxuICAgKlxuICAgKiBAcmV0dXJucyDsg53shLHrkJwg66eI7J206re466CI7J207IWYIOy9lOuTnCDtjIzsnbwg6rCc7IiYXG4gICAqL1xuICBhc3luYyBnZW5lcmF0ZVByZXBhcmVkQ29kZXMoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCB7IHByZXBhcmVkQ29kZXMgfSA9IGF3YWl0IHRoaXMuZ2V0U3RhdHVzKCk7XG4gICAgTmFpdGUudChcIm1pZ3JhdG9yOmdlbmVyYXRlUHJlcGFyZWRDb2RlczpwcmVwYXJlZENvZGVzXCIsIHByZXBhcmVkQ29kZXMpO1xuICAgIGlmIChwcmVwYXJlZENvZGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oXCJcXG7tmITsnqwg66qo65GQIOyLse2BrOuQnCDsg4Htg5zsnoXri4jri6QuXCIpKTtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cblxuICAgIC8vIOyLpOygnCDsvZTrk5wg7IOd7ISxXG4gICAgY29uc3QgbWlncmF0aW9uc0RpciA9IGAke1NvbmFtdS5hcGlSb290UGF0aH0vc3JjL21pZ3JhdGlvbnNgO1xuXG4gICAgZm9yIChjb25zdCBbaW5kZXgsIHBjb2RlXSBvZiBwcmVwYXJlZENvZGVzLmVudHJpZXMoKSkge1xuICAgICAgaWYgKHBjb2RlLmZvcm1hdHRlZCkge1xuICAgICAgICBjb25zdCBkYXRlVGFnID0gdGhpcy5nZW5EYXRlVGFnKGluZGV4KTtcbiAgICAgICAgY29uc3QgZmlsZVBhdGggPSBgJHttaWdyYXRpb25zRGlyfS8ke2RhdGVUYWd9XyR7cGNvZGUudGl0bGV9LnRzYDtcbiAgICAgICAgYXdhaXQgd3JpdGVGaWxlKGZpbGVQYXRoLCBwY29kZS5mb3JtYXR0ZWQpO1xuICAgICAgICAhaXNUZXN0KCkgJiYgY29uc29sZS5sb2coY2hhbGsuZ3JlZW4oYE1JR1JBVElPTiBDUkVBVEVEICR7ZmlsZVBhdGh9YCkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBwcmVwYXJlZENvZGVzLmxlbmd0aDtcbiAgfVxuXG4gIGFzeW5jIGNvbXBhcmVNaWdyYXRpb25zKGNvbXBhcmVEQjogS25leCk6IFByb21pc2U8R2VuTWlncmF0aW9uQ29kZVtdPiB7XG4gICAgLy8gRW50aXR5IOyInO2ajO2VmOyXrCDsi7HtgaxcbiAgICBjb25zdCBlbnRpdHlJZHMgPSBFbnRpdHlNYW5hZ2VyLmdldEFsbElkcygpO1xuXG4gICAgLy8g7KGw7J247YWM7J2067iUIO2PrO2VqO2VmOyXrCBFbnRpdHnsl5DshJwgTWlncmF0aW9uU2V0IOy2lOy2nFxuICAgIGNvbnN0IGVudGl0eVNldHNXaXRoSm9pblRhYmxlID0gZW50aXR5SWRzXG4gICAgICAuZmlsdGVyKChlbnRpdHlJZCkgPT4gRW50aXR5TWFuYWdlci5nZXQoZW50aXR5SWQpLnByb3BzLmxlbmd0aCA+IDApXG4gICAgICAubWFwKChlbnRpdHlJZCkgPT4gZ2V0TWlncmF0aW9uU2V0RnJvbUVudGl0eShFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCkpKTtcblxuICAgIC8vIOyhsOyduO2FjOydtOu4lOunjCDstpTstpxcbiAgICBjb25zdCBqb2luVGFibGVzV2l0aER1cCA9IGVudGl0eVNldHNXaXRoSm9pblRhYmxlLmZsYXRNYXAoKGVudGl0eVNldCkgPT4gZW50aXR5U2V0LmpvaW5UYWJsZXMpO1xuICAgIC8vIOykkeuztSDsoJzqsbAgKOykkeuzteyduCDqsr3smrAgaW5kZXhlc+ulvCDrs5HtlakpXG4gICAgY29uc3Qgam9pblRhYmxlcyA9IE9iamVjdC52YWx1ZXMoZ3JvdXAoam9pblRhYmxlc1dpdGhEdXAsIChqdCkgPT4ganQudGFibGUpKS5tYXAoKHRhYmxlcykgPT4ge1xuICAgICAgYXNzZXJ0KHRhYmxlcyAhPT0gdW5kZWZpbmVkLCBcInRhYmxlcyBpcyB1bmRlZmluZWRcIik7XG4gICAgICBpZiAodGFibGVzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICByZXR1cm4gdGFibGVzWzBdO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgLi4udGFibGVzWzBdLFxuICAgICAgICBpbmRleGVzOiB1bmlxdWUoXG4gICAgICAgICAgdGFibGVzLmZsYXRNYXAoKHQpID0+IHQuaW5kZXhlcyksXG4gICAgICAgICAgKGluZGV4KSA9PiBbaW5kZXgudHlwZSwgLi4uaW5kZXguY29sdW1uc10uam9pbihcIi1cIiksXG4gICAgICAgICksXG4gICAgICB9O1xuICAgIH0pO1xuXG4gICAgLy8g7KGw7J247YWM7J2067iUIO2PrO2VqO2VmOyXrCBNaWdyYXRpb25TZXQg67Cw7Je0XG4gICAgY29uc3QgZW50aXR5U2V0czogTWlncmF0aW9uU2V0W10gPSBbLi4uZW50aXR5U2V0c1dpdGhKb2luVGFibGUsIC4uLmpvaW5UYWJsZXNdO1xuXG4gICAgY29uc3QgY29kZXM6IEdlbk1pZ3JhdGlvbkNvZGVbXSA9IFtdO1xuICAgIGNvbnN0IGJhdGNoU2l6ZSA9IDQ7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGVudGl0eVNldHMubGVuZ3RoOyBpICs9IGJhdGNoU2l6ZSkge1xuICAgICAgY29uc3QgYmF0Y2hDb2RlcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBlbnRpdHlTZXRzLnNsaWNlKGksIGkgKyBiYXRjaFNpemUpLm1hcChhc3luYyAoZW50aXR5U2V0KSA9PiB7XG4gICAgICAgICAgY29uc3QgZGJTZXQgPSBhd2FpdCBQb3N0Z3JlU1FMU2NoZW1hUmVhZGVyLmdldE1pZ3JhdGlvblNldEZyb21EQihcbiAgICAgICAgICAgIGNvbXBhcmVEQixcbiAgICAgICAgICAgIGVudGl0eVNldC50YWJsZSxcbiAgICAgICAgICApO1xuICAgICAgICAgIE5haXRlLnQoYG1pZ3JhdG9yOmNvbXBhcmVNaWdyYXRpb25zOmVudGl0eVNldDoke2VudGl0eVNldC50YWJsZX1gLCBlbnRpdHlTZXQpO1xuICAgICAgICAgIE5haXRlLnQoYG1pZ3JhdG9yOmNvbXBhcmVNaWdyYXRpb25zOmRiU2V0OiR7ZW50aXR5U2V0LnRhYmxlfWAsIGRiU2V0KTtcblxuICAgICAgICAgIGlmIChkYlNldCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgLy8g6riw7KG0IO2FjOydtOu4lCDsl4bsnYwsIOyDiOuhnCDthYzsnbTruJQg7IOd7ISxXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZ2VuZXJhdGVDcmVhdGVDb2RlKGVudGl0eVNldCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIOq4sOyhtCDthYzsnbTruJQg7KG07J6s7ZWY64qUIOy8gOydtOyKpFxuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IGdlbmVyYXRlQWx0ZXJDb2RlKGVudGl0eVNldCwgZGJTZXQsIGNvbXBhcmVEQik7XG4gICAgICAgICAgfVxuICAgICAgICB9KSxcbiAgICAgICk7XG5cbiAgICAgIGNvZGVzLnB1c2goLi4uYmF0Y2hDb2Rlcy5mbGF0KCkpO1xuICAgIH1cblxuICAgIC8vIG5vcm1hbCDtg4DsnoXsnbQg7JWe7Jy866GcLCBmb3JlaWdu7J20IOuSpOuhnFxuICAgIGNvZGVzLnNvcnQoKGNvZGVBLCBjb2RlQikgPT4ge1xuICAgICAgaWYgKGNvZGVBLnR5cGUgPT09IFwiZm9yZWlnblwiICYmIGNvZGVCLnR5cGUgPT09IFwibm9ybWFsXCIpIHtcbiAgICAgICAgcmV0dXJuIDE7XG4gICAgICB9IGVsc2UgaWYgKGNvZGVBLnR5cGUgPT09IFwibm9ybWFsXCIgJiYgY29kZUIudHlwZSA9PT0gXCJmb3JlaWduXCIpIHtcbiAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIDA7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICByZXR1cm4gY29kZXM7XG4gIH1cblxuICAvKipcbiAgICogU2hhZG93IERCIO2FjOyKpO2KuOulvCDsp4Ttlontlanri4jri6QuXG4gICAqXG4gICAqIFNvbmFtdSBVSeyXkOyEnCDsgqzsmqnrkKnri4jri6QuXG4gICAqXG4gICAqIEByZXR1cm5zIFNoYWRvdyBEQiDthYzsiqTtirgg6rKw6rO8XG4gICAqL1xuICBhc3luYyBydW5TaGFkb3dUZXN0KCk6IFByb21pc2U8TWlncmF0aW9uUmVzdWx0PiB7XG4gICAgY29uc3QgYmFzZVRlc3RDb25uID0gU29uYW11LmRiQ29uZmlnLnRlc3QuY29ubmVjdGlvbiBhcyBLbmV4LlBnQ29ubmVjdGlvbkNvbmZpZztcbiAgICBjb25zdCB3b3JrZXJJZCA9IHByb2Nlc3MuZW52LlNPTkFNVV9XT1JLRVJfREIgPT09IFwidHJ1ZVwiID8gcHJvY2Vzcy5lbnYuVklURVNUX1BPT0xfSUQgOiBudWxsO1xuICAgIGNvbnN0IHRlbXBsYXRlRGF0YWJhc2UgPVxuICAgICAgd29ya2VySWQgIT09IG51bGwgPyBgJHtiYXNlVGVzdENvbm4uZGF0YWJhc2V9XyR7d29ya2VySWQgPz8gXCIxXCJ9YCA6IGJhc2VUZXN0Q29ubi5kYXRhYmFzZTtcbiAgICBjb25zdCB0ZGJDb25uID0geyAuLi5iYXNlVGVzdENvbm4sIGRhdGFiYXNlOiB0ZW1wbGF0ZURhdGFiYXNlIH07XG4gICAgY29uc3Qgc2hhZG93RGF0YWJhc2UgPSBgJHt0ZW1wbGF0ZURhdGFiYXNlfV9fbWlncmF0aW9uX3NoYWRvd2A7XG5cbiAgICAvLyDthYzsiqTtirgg7IOB7Zmp7JeQ7ISc64qUIO2KuOuenOyereyFmOydhCDstIjquLDtmZTtlZjqs6AsIOyDiCDrjbDsnbTthLDrsqDsnbTsiqQg7Luk64Sl7IWY7J2EIOqwgOyguOyZgOyVvCDtlahcbiAgICBpZiAoaXNUZXN0KCkpIHtcbiAgICAgIGF3YWl0IERCLmNsZWFyVGVzdFRyYW5zYWN0aW9uKCk7XG4gICAgICBhd2FpdCBEQi5kZXN0cm95KCk7XG4gICAgfVxuXG4gICAgLy8g6riw7KG0IFNoYWRvdyBEQiDsgq3soJwg7ZuEIFNoYWRvdyBEQiDsg53shLFcbiAgICBjb25zdCB0ZGIgPSBjcmVhdGVLbmV4SW5zdGFuY2Uoe1xuICAgICAgLi4uU29uYW11LmRiQ29uZmlnLnRlc3QsXG4gICAgICBjb25uZWN0aW9uOiB7XG4gICAgICAgIC4uLmJhc2VUZXN0Q29ubixcbiAgICAgICAgZGF0YWJhc2U6IFwicG9zdGdyZXNcIixcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgdHJ5IHtcbiAgICAgICFpc1Rlc3QoKSAmJiBjb25zb2xlLmxvZyhjaGFsay5tYWdlbnRhKGAke3NoYWRvd0RhdGFiYXNlfSDsgq3soJxgKSk7XG4gICAgICBhd2FpdCB0ZGIucmF3KGBEUk9QIERBVEFCQVNFIElGIEVYSVNUUyAke3NoYWRvd0RhdGFiYXNlfWApO1xuICAgICAgYXdhaXQgdGRiLnJhdyhgXG4gICAgICAgIFNFTEVDVCBwZ190ZXJtaW5hdGVfYmFja2VuZChwZ19zdGF0X2FjdGl2aXR5LnBpZClcbiAgICAgICAgRlJPTSBwZ19zdGF0X2FjdGl2aXR5XG4gICAgICAgIFdIRVJFIGRhdG5hbWUgPSAnJHt0ZGJDb25uLmRhdGFiYXNlfSdcbiAgICAgICAgICBBTkQgcGlkIDw+IHBnX2JhY2tlbmRfcGlkKCk7XG4gICAgICBgKTtcbiAgICAgIGF3YWl0IHRkYi5yYXcoYENSRUFURSBEQVRBQkFTRSAke3NoYWRvd0RhdGFiYXNlfSBURU1QTEFURSAke3RkYkNvbm4uZGF0YWJhc2V9YCk7XG5cbiAgICAgIC8vIFNoYWRvdyBEQuyXkCDsl7DqsrBcbiAgICAgIGNvbnN0IHNkYiA9IGNyZWF0ZUtuZXhJbnN0YW5jZSh7XG4gICAgICAgIC4uLlNvbmFtdS5kYkNvbmZpZy50ZXN0LFxuICAgICAgICBjb25uZWN0aW9uOiB7XG4gICAgICAgICAgLi4udGRiQ29ubixcbiAgICAgICAgICBkYXRhYmFzZTogc2hhZG93RGF0YWJhc2UsXG4gICAgICAgICAgcGFzc3dvcmQ6IHRkYkNvbm4ucGFzc3dvcmQsXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgLy8gc2hhZG93IERCIO2FjOyKpO2KuCDsp4TtlolcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IFtiYXRjaE5vLCBhcHBsaWVkXSA9IGF3YWl0IHNkYi5taWdyYXRlLmxhdGVzdCgpO1xuICAgICAgICAhaXNUZXN0KCkgJiZcbiAgICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmVlbihcIlNoYWRvdyBEQiDthYzsiqTtirjsl5Ag7ISx6rO17ZaI7Iq164uI64ukIVwiKSwge1xuICAgICAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgICAgIGFwcGxpZWQsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBjb25uS2V5OiBcInNoYWRvd1wiLFxuICAgICAgICAgICAgYmF0Y2hObyxcbiAgICAgICAgICAgIGFwcGxpZWQsXG4gICAgICAgICAgfSxcbiAgICAgICAgXTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihlKTtcbiAgICAgICAgdGhyb3cgbmV3IFNlcnZpY2VVbmF2YWlsYWJsZUV4Y2VwdGlvbihTRChcInNvbmFtdS5lcnJvci5zaGFkb3dEYlRlc3RGYWlsZWRcIikpO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYXdhaXQgc2RiLmRlc3Ryb3koKTtcbiAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgLy8gU2hhZG93IERCIOyCreygnFxuICAgICAgIWlzVGVzdCgpICYmIGNvbnNvbGUubG9nKGNoYWxrLm1hZ2VudGEoYCR7c2hhZG93RGF0YWJhc2V9IOyCreygnGApKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRkYi5yYXcoYERST1AgREFUQUJBU0UgSUYgRVhJU1RTICR7c2hhZG93RGF0YWJhc2V9YCk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJTaGFkb3cgREIg7KCV66asIOyLpO2MqDpcIiwgZSk7IC8vIOydtOqyjCDsl4bsnLzrqbQg7KGw7Jqp7Z6IIOuIhOyImFxuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgYXdhaXQgdGRiLmRlc3Ryb3koKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzthQVFzQztTQUNIO1dBRWtCO1NBQ3RCO3FCQUN5QjtVQUNYO29CQUM0QjtZQUNuQztpQkFFZTtlQUNYO3NCQUMrQjtvQkFDZDsrQkFDUTtDQVN0RCxXQUFiLE1BQXNCO0VBQ3BCLDZCQUFxQyxPQUF5QjtHQUM1RCxJQUFJLE9BQU8sVUFBVSxZQUFZLFVBQVUsTUFDekMsT0FBTztHQUdULE1BQU0scUJBQXFCO0dBQzNCLE9BQ0UsbUJBQW1CLFNBQVMsV0FDNUIsT0FBTyxtQkFBbUIsWUFBWSxZQUN0QyxtQkFBbUIsUUFBUSxTQUFTLGlCQUFpQjtFQUV6RDtFQUVBLHlCQUEyRDtHQUN6RCxNQUFNLFdBQVcsT0FBTyxLQUFLLE9BQU8sUUFBUSxDQUFDLENBQUMsUUFDM0MsUUFBUSxDQUFDLElBQUksU0FBUyxXQUFXLENBQ3BDO0dBRUEsSUFBSSxRQUFRLEdBQ1YsT0FBTztHQUdULE1BQU0sY0FB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