sonamu 0.9.4 → 0.9.6

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 (171) hide show
  1. package/dist/ai/providers/rtzr/utils.js +2 -2
  2. package/dist/api/config.d.ts +13 -2
  3. package/dist/api/config.d.ts.map +1 -1
  4. package/dist/api/config.js +1 -1
  5. package/dist/api/context.d.ts +17 -7
  6. package/dist/api/context.d.ts.map +1 -1
  7. package/dist/api/context.js +1 -1
  8. package/dist/api/decorators.d.ts +18 -0
  9. package/dist/api/decorators.d.ts.map +1 -1
  10. package/dist/api/decorators.js +54 -3
  11. package/dist/api/index.js +8 -3
  12. package/dist/api/sonamu.d.ts +24 -9
  13. package/dist/api/sonamu.d.ts.map +1 -1
  14. package/dist/api/sonamu.js +365 -79
  15. package/dist/api/websocket-helpers.d.ts +24 -0
  16. package/dist/api/websocket-helpers.d.ts.map +1 -0
  17. package/dist/api/websocket-helpers.js +77 -0
  18. package/dist/bin/cli.js +12 -4
  19. package/dist/database/upsert-builder.js +4 -4
  20. package/dist/dict/sonamu-dictionary.js +6 -6
  21. package/dist/entity/entity-manager.js +1 -1
  22. package/dist/entity/entity.js +3 -3
  23. package/dist/index.d.ts +6 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +16 -4
  26. package/dist/migration/code-generation.d.ts.map +1 -1
  27. package/dist/migration/code-generation.js +8 -9
  28. package/dist/stream/index.d.ts +6 -0
  29. package/dist/stream/index.d.ts.map +1 -1
  30. package/dist/stream/index.js +13 -2
  31. package/dist/stream/ws-audience-resolver.d.ts +15 -0
  32. package/dist/stream/ws-audience-resolver.d.ts.map +1 -0
  33. package/dist/stream/ws-audience-resolver.js +31 -0
  34. package/dist/stream/ws-audience.d.ts +28 -0
  35. package/dist/stream/ws-audience.d.ts.map +1 -0
  36. package/dist/stream/ws-audience.js +46 -0
  37. package/dist/stream/ws-cluster-bus.d.ts +23 -0
  38. package/dist/stream/ws-cluster-bus.d.ts.map +1 -0
  39. package/dist/stream/ws-cluster-bus.js +18 -0
  40. package/dist/stream/ws-core.d.ts +15 -0
  41. package/dist/stream/ws-core.d.ts.map +1 -0
  42. package/dist/stream/ws-core.js +1 -0
  43. package/dist/stream/ws-delivery.d.ts +24 -0
  44. package/dist/stream/ws-delivery.d.ts.map +1 -0
  45. package/dist/stream/ws-delivery.js +103 -0
  46. package/dist/stream/ws-local-connection-store.d.ts +10 -0
  47. package/dist/stream/ws-local-connection-store.d.ts.map +1 -0
  48. package/dist/stream/ws-local-connection-store.js +44 -0
  49. package/dist/stream/ws-presence-store.d.ts +61 -0
  50. package/dist/stream/ws-presence-store.d.ts.map +1 -0
  51. package/dist/stream/ws-presence-store.js +236 -0
  52. package/dist/stream/ws-registry.d.ts +42 -0
  53. package/dist/stream/ws-registry.d.ts.map +1 -0
  54. package/dist/stream/ws-registry.js +108 -0
  55. package/dist/stream/ws.d.ts +52 -0
  56. package/dist/stream/ws.d.ts.map +1 -0
  57. package/dist/stream/ws.js +397 -0
  58. package/dist/syncer/api-parser.d.ts.map +1 -1
  59. package/dist/syncer/api-parser.js +72 -2
  60. package/dist/syncer/checksum.d.ts.map +1 -1
  61. package/dist/syncer/checksum.js +13 -12
  62. package/dist/syncer/code-generator.d.ts.map +1 -1
  63. package/dist/syncer/code-generator.js +7 -4
  64. package/dist/syncer/event-batcher.d.ts +27 -0
  65. package/dist/syncer/event-batcher.d.ts.map +1 -0
  66. package/dist/syncer/event-batcher.js +69 -0
  67. package/dist/syncer/file-patterns.d.ts +48 -26
  68. package/dist/syncer/file-patterns.d.ts.map +1 -1
  69. package/dist/syncer/file-patterns.js +71 -23
  70. package/dist/syncer/file-tracking.d.ts +13 -0
  71. package/dist/syncer/file-tracking.d.ts.map +1 -0
  72. package/dist/syncer/file-tracking.js +33 -0
  73. package/dist/syncer/index.js +2 -2
  74. package/dist/syncer/module-loader.d.ts +2 -11
  75. package/dist/syncer/module-loader.d.ts.map +1 -1
  76. package/dist/syncer/module-loader.js +3 -3
  77. package/dist/syncer/syncer-actions.d.ts +39 -6
  78. package/dist/syncer/syncer-actions.d.ts.map +1 -1
  79. package/dist/syncer/syncer-actions.js +125 -10
  80. package/dist/syncer/syncer.d.ts +33 -19
  81. package/dist/syncer/syncer.d.ts.map +1 -1
  82. package/dist/syncer/syncer.js +168 -168
  83. package/dist/syncer/watcher.d.ts +8 -0
  84. package/dist/syncer/watcher.d.ts.map +1 -0
  85. package/dist/syncer/watcher.js +105 -0
  86. package/dist/tasks/workflow-manager.d.ts.map +1 -1
  87. package/dist/tasks/workflow-manager.js +2 -1
  88. package/dist/template/implementations/services.template.d.ts.map +1 -1
  89. package/dist/template/implementations/services.template.js +36 -1
  90. package/dist/testing/bootstrap.d.ts.map +1 -1
  91. package/dist/testing/bootstrap.js +8 -1
  92. package/dist/testing/data-explorer.d.ts.map +1 -1
  93. package/dist/testing/data-explorer.js +5 -3
  94. package/dist/testing/fixture-manager.js +1 -1
  95. package/dist/types/types.d.ts +2 -1
  96. package/dist/types/types.d.ts.map +1 -1
  97. package/dist/types/types.js +2 -2
  98. package/dist/ui/api.d.ts.map +1 -1
  99. package/dist/ui/api.js +4 -3
  100. package/dist/ui/cdd-service.js +1 -1
  101. package/dist/ui-web/assets/{index-C5KUjXm0.js → index-BmThfg-s.js} +39 -39
  102. package/dist/ui-web/assets/index-D4rYm-Xz.css +1 -0
  103. package/dist/ui-web/index.html +2 -2
  104. package/dist/utils/async-utils.d.ts +27 -3
  105. package/dist/utils/async-utils.d.ts.map +1 -1
  106. package/dist/utils/async-utils.js +56 -6
  107. package/dist/utils/formatter.d.ts +7 -1
  108. package/dist/utils/formatter.d.ts.map +1 -1
  109. package/dist/utils/formatter.js +95 -60
  110. package/dist/utils/fs-utils.d.ts +2 -0
  111. package/dist/utils/fs-utils.d.ts.map +1 -1
  112. package/dist/utils/fs-utils.js +10 -2
  113. package/dist/utils/process-utils.d.ts +6 -0
  114. package/dist/utils/process-utils.d.ts.map +1 -1
  115. package/dist/utils/process-utils.js +16 -3
  116. package/dist/utils/utils.d.ts +1 -0
  117. package/dist/utils/utils.d.ts.map +1 -1
  118. package/dist/utils/utils.js +2 -2
  119. package/package.json +7 -5
  120. package/src/ai/providers/rtzr/utils.ts +1 -1
  121. package/src/api/__tests__/sonamu.websocket.test.ts +64 -0
  122. package/src/api/__tests__/websocket-context.types.test.ts +58 -0
  123. package/src/api/config.ts +28 -2
  124. package/src/api/context.ts +21 -7
  125. package/src/api/decorators.ts +101 -1
  126. package/src/api/sonamu.ts +529 -127
  127. package/src/api/websocket-helpers.ts +122 -0
  128. package/src/bin/cli.ts +10 -2
  129. package/src/database/upsert-builder.ts +3 -3
  130. package/src/dict/sonamu-dictionary.ts +3 -3
  131. package/src/entity/entity.ts +1 -1
  132. package/src/index.ts +6 -0
  133. package/src/migration/code-generation.ts +6 -11
  134. package/src/shared/app.shared.ts.txt +312 -4
  135. package/src/shared/web.shared.ts.txt +340 -4
  136. package/src/stream/__tests__/ws-contracts.test.ts +381 -0
  137. package/src/stream/__tests__/ws.test.ts +449 -0
  138. package/src/stream/index.ts +6 -0
  139. package/src/stream/ws-audience-resolver.ts +35 -0
  140. package/src/stream/ws-audience.ts +62 -0
  141. package/src/stream/ws-cluster-bus.ts +32 -0
  142. package/src/stream/ws-core.ts +16 -0
  143. package/src/stream/ws-delivery.ts +138 -0
  144. package/src/stream/ws-local-connection-store.ts +44 -0
  145. package/src/stream/ws-presence-store.ts +326 -0
  146. package/src/stream/ws-registry.ts +138 -0
  147. package/src/stream/ws.ts +591 -0
  148. package/src/syncer/__tests__/api-parser.websocket-type-ref.test.ts +78 -0
  149. package/src/syncer/api-parser.ts +112 -1
  150. package/src/syncer/checksum.ts +23 -29
  151. package/src/syncer/code-generator.ts +4 -1
  152. package/src/syncer/event-batcher.ts +72 -0
  153. package/src/syncer/file-patterns.ts +98 -30
  154. package/src/syncer/file-tracking.ts +27 -0
  155. package/src/syncer/module-loader.ts +5 -12
  156. package/src/syncer/syncer-actions.ts +179 -17
  157. package/src/syncer/syncer.ts +250 -287
  158. package/src/syncer/watcher.ts +128 -0
  159. package/src/tasks/workflow-manager.ts +1 -0
  160. package/src/template/__tests__/services.template.websocket.test.ts +79 -0
  161. package/src/template/implementations/services.template.ts +69 -0
  162. package/src/testing/bootstrap.ts +8 -1
  163. package/src/testing/data-explorer.ts +3 -2
  164. package/src/types/types.ts +20 -2
  165. package/src/ui/api.ts +10 -1
  166. package/src/utils/async-utils.ts +71 -4
  167. package/src/utils/formatter.ts +114 -75
  168. package/src/utils/fs-utils.ts +9 -0
  169. package/src/utils/process-utils.ts +17 -0
  170. package/src/utils/utils.ts +1 -1
  171. package/dist/ui-web/assets/index-Dr8pRJC_.css +0 -1
@@ -1,30 +1,29 @@
1
1
  import { __esmMin } from "../_virtual/rolldown_runtime.js";
2
- import { AlreadyProcessedException, init_so_exceptions } from "../exceptions/so-exceptions.js";
2
+ import { centerText, init_console_util } from "../utils/console-util.js";
3
3
  import { init_controller, isTest } from "../utils/controller.js";
4
- import { copyFileWithReplaceCoreToShared, exists, init_fs_utils } from "../utils/fs-utils.js";
4
+ import { init_async_utils, mapAsync, reduceAsync } from "../utils/async-utils.js";
5
+ import { init_process_utils, runWithGracefulShutdown } from "../utils/process-utils.js";
6
+ import { exists, init_fs_utils } from "../utils/fs-utils.js";
5
7
  import { Sonamu, init_sonamu } from "../api/sonamu.js";
6
8
  import { TemplateKey, init_types } from "../types/types.js";
7
- import { init_async_utils, mapAsync, reduceAsync } from "../utils/async-utils.js";
8
9
  import { EntityManager, init_entity_manager } from "../entity/entity-manager.js";
9
10
  import { Naite, init_naite } from "../naite/naite.js";
10
11
  import { init_decorators, registeredApis } from "../api/decorators.js";
11
- import { centerText, init_console_util } from "../utils/console-util.js";
12
12
  import { TemplateManager, init_template_manager } from "../template/template-manager.js";
13
- import { checksumPatternGroup, getChecksumPatternGroupInAbsolutePath, init_file_patterns } from "./file-patterns.js";
13
+ import { getChecksumPatternGroup, getChecksumPatternGroupInAbsolutePath, init_file_patterns } from "./file-patterns.js";
14
14
  import { findChangedFilesUsingChecksums, init_checksum, renewChecksums } from "./checksum.js";
15
15
  import { generateTemplate, init_code_generator, renderTemplate } from "./code-generator.js";
16
16
  import { createEntity, delEntity, init_entity_operations } from "./entity-operations.js";
17
17
  import { init_module_loader, loadApis, loadModels, loadTypes, loadWorkflows } from "./module-loader.js";
18
- import { init_process_utils, runWithGracefulShutdown } from "../utils/process-utils.js";
19
- import { actionGenerateHttps, actionGenerateSchemas, actionGenerateServices, actionGenerateSsr, actionSyncConfig, actionSyncFilesToTargets, init_syncer_actions } from "./syncer-actions.js";
18
+ import { actionCopySharedToTargetsIfNotExists, actionGenerateHttps, actionGenerateInitialTypes, actionGenerateSchemas, actionGenerateServices, actionGenerateSsrEntryServerIfNotExists, actionGenerateSsrQueries, actionSyncConfig, actionSyncFilesToTargets, actionSyncSonamuDictionary, init_syncer_actions } from "./syncer-actions.js";
20
19
  import { group, unique } from "radashi";
21
20
  import assert from "assert";
22
- import { mkdir, readFile, writeFile } from "fs/promises";
21
+ import { unlink } from "fs/promises";
23
22
  import path from "path";
24
23
  import chalk from "chalk";
24
+ import { minimatch } from "minimatch";
25
25
  import { EventEmitter } from "events";
26
26
  import { hot } from "@sonamu-kit/hmr-hook";
27
- import { minimatch } from "minimatch";
28
27
 
29
28
  //#region src/syncer/syncer.ts
30
29
  var Syncer;
@@ -32,7 +31,6 @@ var init_syncer = __esmMin((() => {
32
31
  init_decorators();
33
32
  init_sonamu();
34
33
  init_entity_manager();
35
- init_so_exceptions();
36
34
  init_naite();
37
35
  init_template_manager();
38
36
  init_types();
@@ -55,23 +53,15 @@ var init_syncer = __esmMin((() => {
55
53
  eventEmitter = new EventEmitter();
56
54
  /**
57
55
  * 체크섬이 변경된 부분에 대해 싱크를 진행합니다.
58
- * sonamu.shared.ts는 파일이 없을 때만 1회 생성하고, 이후에는 덮어쓰지 않습니다.
56
+ * dev 서버가 처음 떴을 때, sonamu sync 실행됩니다. 이후에는 syncFromWatcher 경로를 타요.
59
57
  * @returns
60
58
  */
61
59
  async sync() {
62
- const { targets } = Sonamu.config.sync;
63
- await this.copySharedToTargets(targets);
60
+ await actionCopySharedToTargetsIfNotExists();
61
+ await actionGenerateSsrEntryServerIfNotExists();
64
62
  const changedFiles = await findChangedFilesUsingChecksums();
65
63
  if (changedFiles.length === 0) {
66
64
  console.log(chalk.black.bgGreen(centerText("All files are synced!")));
67
- try {
68
- await generateTemplate("queries", {}, { overwrite: false });
69
- await generateTemplate("entry_server", {}, { overwrite: false });
70
- } catch (e) {
71
- if (!(e instanceof AlreadyProcessedException)) {
72
- console.error("Failed to generate SSR templates:", e);
73
- }
74
- }
75
65
  return;
76
66
  }
77
67
  await runWithGracefulShutdown(async () => {
@@ -83,56 +73,95 @@ var init_syncer = __esmMin((() => {
83
73
  });
84
74
  }
85
75
  /**
86
- * Watcher가 감지한 파일 변경 사항에 대해 싱크를 진행합니다.
87
- * 주어진 변경 파일들 중 체크섬 관리 대상인 것들만 가져다가 싱크를 진행합니다.
88
- * 체크섬 파일 업데이트는 여기에서 하지 않습니다. 호출자가 합니다.
89
- * @param diffFilePath - 변경 파일들. 프로젝트 루트부터 "src/" 또는 "dist/"로 시작하는 상대 경로입니다. 예시: "src/application/user/user.model.ts"
76
+ * 강제 풀-싱크: lock을 무시하고 처음부터 다시 싱크합니다.
77
+ *
78
+ * **사용처**: git post-merge hook, CI, dev 서버의 `f` 핫키.
79
+ * **실패 안전성**: 도중에 프로세스가 죽어 lock 없는 상태로 남아도 무해 다음 sync에서
80
+ * lock 없으면 자연스럽게 풀-싱크가 트리거되어 새 lock이 작성됨.
90
81
  */
91
- async syncFromWatcher(event, diffFilePath) {
92
- if (event !== "change" && event !== "add" && event !== "unlink") {
93
- return;
82
+ async forceSync() {
83
+ const lockPath = path.join(Sonamu.apiRootPath, "sonamu.lock");
84
+ if (await exists(lockPath)) {
85
+ await unlink(lockPath);
94
86
  }
95
- if (diffFilePath.includes("/src/ssr/")) {
96
- console.log(chalk.bold.yellow("SSR config changed - reloading..."));
97
- if (!isTest()) {
98
- await hot.invalidateFile(diffFilePath, event);
87
+ await this.sync();
88
+ }
89
+ /**
90
+ * Watcher가 batch로 모은 변경 파일들에 대해 한 번의 HMR/sync 사이클을 돕니다.
91
+ *
92
+ * HMR은 api/src 안에서 일어나는 모든 파일들에 대해서 수행합니다.
93
+ * checksumPatternGroup 매칭 여부와 무관하게 api/src 전체 대상입니다.
94
+ * 가령 api/src/utils/subset-loaders.ts 같은 파일도 변경되면 HMR은 해줍니다.
95
+ *
96
+ * Sync는 checksumPatternGroup으로 매칭되는 파일들에 대해서만 수행합니다.
97
+ * 여기에는 web/src나 app/src 같은 다른 target의 파일이 포함될 수 있습니다.
98
+ * 이런 non-api 경로의 파일들은 HMR과는 아무 상관이 없으므로, invalidate을 하지 않습니다.
99
+ *
100
+ * @param fileEvents - path → event 맵. event는 "change" | "add".
101
+ */
102
+ async hmrAndSync(fileEvents) {
103
+ const hmrActionRequiredEvents = this.extractHmrActionRequiredFileEvents(fileEvents);
104
+ const syncTriggeringPaths = await this.extractSyncTriggeringFileEventPaths(fileEvents);
105
+ await this.invalidateDependentsAffectedByFileEvents(hmrActionRequiredEvents);
106
+ if (syncTriggeringPaths.length > 0) {
107
+ await this.doSyncActions(syncTriggeringPaths);
108
+ }
109
+ await this.autoloadTypes();
110
+ await this.autoloadModels();
111
+ await this.autoloadApis();
112
+ await this.autoloadWorkflows();
113
+ await this.autoloadSsrRoutes();
114
+ this.eventEmitter.emit("onHMRCompleted");
115
+ }
116
+ extractHmrActionRequiredFileEvents(fileEvents) {
117
+ const apiSrc = path.join(Sonamu.apiRootPath, "src");
118
+ const result = new Map();
119
+ for (const [filePath, event] of fileEvents) {
120
+ if (!filePath.startsWith(apiSrc)) {
121
+ continue;
99
122
  }
100
- await this.autoloadSSRRoutes();
101
- this.eventEmitter.emit("onHMRCompleted");
102
- return;
123
+ result.set(filePath, event);
124
+ }
125
+ return result;
126
+ }
127
+ async extractSyncTriggeringFileEventPaths(fileEvents) {
128
+ const checkPatternGroup = getChecksumPatternGroupInAbsolutePath();
129
+ const syncTriggeringPaths = [];
130
+ for (const [diffFilePath] of fileEvents) {
131
+ const isInCheckPatternGroup = Object.values(checkPatternGroup).some((pattern) => minimatch(diffFilePath, pattern));
132
+ if (!isInCheckPatternGroup) {
133
+ continue;
134
+ }
135
+ syncTriggeringPaths.push(diffFilePath);
103
136
  }
104
- if (!isTest()) {
105
- const invalidatedPaths = await hot.invalidateFile(diffFilePath, event);
106
- if (invalidatedPaths.length > 0) {
107
- console.log(chalk.bold(`🔄 Invalidated:`));
108
- for (const invalidatedPath of invalidatedPaths) {
109
- try {
110
- const removedApis = this.removeInvalidatedRegisteredApis(invalidatedPath);
111
- if (removedApis.length > 0) {
112
- console.log(chalk.blue(`- ${path.relative(Sonamu.apiRootPath, invalidatedPath)}`), chalk.gray(`(with ${removedApis.length} APIs)`));
113
- } else {
114
- console.log(chalk.blue(`- ${path.relative(Sonamu.apiRootPath, invalidatedPath)}`));
137
+ return syncTriggeringPaths;
138
+ }
139
+ async invalidateDependentsAffectedByFileEvents(fileEvents) {
140
+ for (const [diffFilePath, event] of fileEvents) {
141
+ if (!isTest()) {
142
+ const invalidatedPaths = await hot.invalidateFile(diffFilePath, event);
143
+ if (invalidatedPaths.length > 0) {
144
+ console.log(chalk.bold(`🔄 Invalidated:`));
145
+ for (const invalidatedPath of invalidatedPaths) {
146
+ try {
147
+ const removedApis = this.removeInvalidatedRegisteredApis(invalidatedPath);
148
+ if (removedApis.length > 0) {
149
+ console.log(chalk.blue(`- ${path.relative(Sonamu.apiRootPath, invalidatedPath)}`), chalk.gray(`(with ${removedApis.length} APIs)`));
150
+ } else {
151
+ console.log(chalk.blue(`- ${path.relative(Sonamu.apiRootPath, invalidatedPath)}`));
152
+ }
153
+ } catch (e) {
154
+ console.error(e);
155
+ console.error(chalk.red(`Failed to remove invalidated registered APIs for ${invalidatedPath}`));
115
156
  }
116
- } catch (e) {
117
- console.error(e);
118
- console.error(chalk.red(`Failed to remove invalidated registered APIs for ${invalidatedPath}`));
119
157
  }
120
158
  }
121
159
  }
160
+ if (!isTest() && Sonamu.config.test?.devRunner?.enabled && Sonamu.devVitestManager) {
161
+ Sonamu.devVitestManager.invalidateFiles([diffFilePath]);
162
+ console.log(chalk.dim(`Test invalidated: ${path.relative(Sonamu.apiRootPath, diffFilePath)}`));
163
+ }
122
164
  }
123
- if (!isTest() && Sonamu.config.test?.devRunner?.enabled && Sonamu.devVitestManager) {
124
- Sonamu.devVitestManager.invalidateFiles([diffFilePath]);
125
- console.log(chalk.dim(`Test invalidated: ${path.relative(Sonamu.apiRootPath, diffFilePath)}`));
126
- }
127
- const isInCheckPatternGroup = Object.values(getChecksumPatternGroupInAbsolutePath()).some((pattern) => minimatch(diffFilePath, pattern));
128
- if (isInCheckPatternGroup) {
129
- await this.doSyncActions([diffFilePath]);
130
- }
131
- await this.autoloadTypes();
132
- await this.autoloadModels();
133
- await this.autoloadApis();
134
- await this.autoloadWorkflows();
135
- this.eventEmitter.emit("onHMRCompleted");
136
165
  }
137
166
  removeInvalidatedRegisteredApis(invalidatedPath) {
138
167
  if (!invalidatedPath.endsWith(".model.ts")) {
@@ -148,35 +177,6 @@ var init_syncer = __esmMin((() => {
148
177
  }
149
178
  return toRemove;
150
179
  }
151
- async copySharedToTargets(targets) {
152
- const dictUtilsPath = path.join(import.meta.dirname.replace("/dist/", "/src/"), "../dict/utils.ts");
153
- const dictUtilsCode = await exists(dictUtilsPath) ? await readFile(dictUtilsPath, "utf-8") : "";
154
- const convertMap = {
155
- baseUrl: Sonamu.config.server.baseUrl ?? `http://${Sonamu.config.server.listen?.host ?? "localhost"}:${Sonamu.config.server.listen?.port ?? 3e3}`,
156
- dictUtils: dictUtilsCode
157
- };
158
- for (const target of targets) {
159
- const srcPath = path.join(import.meta.dirname.replace("/dist/", "/src/"), `../shared/${target}.shared.ts.txt`);
160
- if (!await exists(srcPath)) {
161
- continue;
162
- }
163
- if (!await exists(path.join(Sonamu.appRootPath, target))) {
164
- throw new Error(`Tried to copy sonamu.shared.ts to target '${target}' but the target directory does not exist. Please check your project directory structure.`);
165
- }
166
- const fullText = await readFile(srcPath, "utf-8");
167
- const convertedText = Object.entries(convertMap).reduce((acc, [key, value]) => acc.replace(`$[[${key}]]`, value), fullText);
168
- const destPath = path.join(Sonamu.appRootPath, target, "src/services/sonamu.shared.ts");
169
- if (!await exists(path.dirname(destPath))) {
170
- await mkdir(path.dirname(destPath), { recursive: true });
171
- console.warn(`Created directory '${path.dirname(destPath)}' because it did not exist.`);
172
- }
173
- if (await exists(destPath)) {
174
- continue;
175
- }
176
- await writeFile(destPath, convertedText);
177
- !isTest() && console.log(chalk.bold("Copied: ") + chalk.blue(path.relative(Sonamu.appRootPath, destPath)));
178
- }
179
- }
180
180
  async autoloadTypes() {
181
181
  this.types = await loadTypes();
182
182
  }
@@ -190,7 +190,7 @@ var init_syncer = __esmMin((() => {
190
190
  this.workflows = await loadWorkflows();
191
191
  await Sonamu.workflows.synchronize(this.workflows);
192
192
  }
193
- async autoloadSSRRoutes() {
193
+ async autoloadSsrRoutes() {
194
194
  const ssrConfigPath = path.join(Sonamu.apiRootPath, "src/ssr");
195
195
  const { clearSSRRoutes } = await import("../ssr/index.js");
196
196
  clearSSRRoutes();
@@ -212,51 +212,78 @@ var init_syncer = __esmMin((() => {
212
212
  /**
213
213
  * 실제 싱크를 수행하는 본체입니다.
214
214
  * 변경된 파일들을 타입별로 분류하고 각 타입에 맞는 액션을 실행합니다.
215
+ *
215
216
  * @param diffFilePaths - 변경된 파일들의 절대 경로 목록
216
217
  * @returns diffTypes - 변경된 파일의 타입 목록 (entity, types, model 등)
217
218
  */
218
219
  async doSyncActions(diffFilePaths) {
219
220
  const diffGroups = this.calculateDiffGroups(diffFilePaths);
220
221
  const diffTypes = Object.keys(diffGroups);
221
- if (diffTypes.includes("entity") || diffTypes.includes("types")) {
222
- await this.handleTruthSourceChanges(diffGroups, diffTypes);
222
+ const { changeMatches, nothingMatches, unhandledPaths } = this.changeMatcher(diffTypes, diffGroups);
223
+ if (changeMatches("entity", "types")) {
224
+ await this.handleTruthSourceChanges(diffGroups);
223
225
  }
224
- if (diffTypes.includes("types") || diffTypes.includes("functions") || diffTypes.includes("generated")) {
225
- await this.handleSyncableFileChanges(diffGroups);
226
- }
227
- if (diffTypes.includes("model") || diffTypes.includes("frame")) {
226
+ if (changeMatches("model", "frame")) {
228
227
  await this.handleImplementationChanges(diffGroups);
229
228
  }
230
- if (diffTypes.includes("config")) {
231
- await actionSyncConfig();
229
+ if (changeMatches("types", "functions")) {
230
+ await this.handleAuxiliarySymbolChanges(diffGroups);
231
+ }
232
+ if (changeMatches("config")) {
233
+ await this.handleConfigChanges(diffGroups);
232
234
  }
233
- if (diffTypes.includes("workflow")) {
234
- await this.autoloadWorkflows();
235
+ if (changeMatches("i18n", "entity", "config")) {
236
+ await this.handleSonamuDictionaryRelatedChanges(diffGroups);
235
237
  }
236
- if (diffTypes.includes("i18n") || diffTypes.includes("entity") || diffTypes.includes("config")) {
237
- await this.syncSD();
238
+ if (nothingMatches()) {
239
+ await this.handleDrifts(unhandledPaths());
238
240
  }
239
241
  return { diffTypes };
240
242
  }
241
243
  calculateDiffGroups(diffFiles) {
242
- const fileTypes = Object.keys(checksumPatternGroup);
244
+ const patternGroup = getChecksumPatternGroup();
245
+ const fileTypes = Object.keys(patternGroup);
243
246
  return group(diffFiles, (filePath) => {
244
- const srcIndex = filePath.indexOf("/src/");
245
- if (srcIndex === -1) return "unknown";
246
- const relativePath = filePath.slice(srcIndex + 1);
247
+ const relativePath = path.relative(Sonamu.appRootPath, filePath);
248
+ if (relativePath.startsWith("..")) return "unknown";
247
249
  for (const fileType of fileTypes) {
248
- if (minimatch(relativePath, checksumPatternGroup[fileType])) {
250
+ if (minimatch(relativePath, patternGroup[fileType])) {
249
251
  return fileType;
250
252
  }
251
253
  }
252
254
  return "unknown";
253
255
  });
254
256
  }
255
- async handleTruthSourceChanges(diffGroups, diffTypes) {
256
- Naite.t("handleTruthSourceChanges", {
257
- diffGroups,
258
- diffTypes
259
- });
257
+ changeMatcher(diffTypes, diffGroups) {
258
+ const handled = new Set();
259
+ /**
260
+ * 변경 사항이 인자로 받은 FileType들 중 하나 이상을 포함하는지 확인합니다.
261
+ * 가령 ["entity"]가 변경된 호출에서 changeMatches("entity")는 trye를 반환하며,
262
+ * ["types", "i18n"]이 변경된 호출에서 changeMatches("types", "functions")도 true를 반환하지만,
263
+ * ["functions"]가 변경된 호출에서 changeMatches("frame")은 false를 반환합니다.
264
+ * @param types
265
+ */
266
+ const changeMatches = (...types) => {
267
+ const matching = types.filter((t) => diffTypes.includes(t));
268
+ matching.forEach((t) => handled.add(t));
269
+ return matching.length > 0;
270
+ };
271
+ /**
272
+ * changeMatches로 매칭된 것이 하나도 없는지 여부를 가져옵니다.
273
+ */
274
+ const nothingMatches = () => handled.size === 0;
275
+ /**
276
+ * 어떤 changeMatches 호출에도 걸리지 않은 FileType들의 실제 파일 경로를 모아서 반환합니다.
277
+ */
278
+ const unhandledPaths = () => diffTypes.filter((t) => !handled.has(t)).flatMap((t) => diffGroups[t] ?? []);
279
+ return {
280
+ changeMatches,
281
+ nothingMatches,
282
+ unhandledPaths
283
+ };
284
+ }
285
+ async handleTruthSourceChanges(diffGroups) {
286
+ Naite.t("handleTruthSourceChanges", { diffGroups });
260
287
  await EntityManager.reload();
261
288
  const entityPath = diffGroups.entity?.at(0);
262
289
  if (entityPath !== undefined) {
@@ -264,22 +291,12 @@ var init_syncer = __esmMin((() => {
264
291
  const entity = EntityManager.get(entityId);
265
292
  const typeFilePath = path.join(Sonamu.apiRootPath, `src/application/${entity.names.fs}/${entity.names.fs}.types.ts`);
266
293
  if (entity.parentId === undefined && !await exists(typeFilePath)) {
267
- await generateTemplate("init_types", { entityId });
294
+ const types = await actionGenerateInitialTypes(entityId);
295
+ await actionSyncFilesToTargets(types);
268
296
  }
269
297
  }
270
- await actionGenerateSchemas();
271
- diffGroups.generated = unique([...diffGroups.generated ?? [], path.join(Sonamu.apiRootPath, "src/application/sonamu.generated.ts")]);
272
- diffTypes.push("generated");
273
- }
274
- async handleSyncableFileChanges(diffGroups) {
275
- const tsPaths = unique([
276
- ...diffGroups.types ?? [],
277
- ...diffGroups.functions ?? [],
278
- ...diffGroups.generated ?? []
279
- ]);
280
- Naite.t("handleSyncableFileChanges", { diffGroups });
281
- await actionSyncFilesToTargets(tsPaths);
282
- return [];
298
+ const generated = await actionGenerateSchemas();
299
+ await actionSyncFilesToTargets(generated);
283
300
  }
284
301
  async handleImplementationChanges(diffGroups) {
285
302
  Naite.t("handleImplementationChanges", { diffGroups });
@@ -297,7 +314,28 @@ var init_syncer = __esmMin((() => {
297
314
  });
298
315
  await actionGenerateServices(params);
299
316
  await actionGenerateHttps();
300
- await actionGenerateSsr();
317
+ const queries = await actionGenerateSsrQueries();
318
+ await actionSyncFilesToTargets(queries);
319
+ }
320
+ async handleAuxiliarySymbolChanges(diffGroups) {
321
+ Naite.t("handleAuxiliarySymbolChanges", { diffGroups });
322
+ const tsPaths = unique([...diffGroups.types ?? [], ...diffGroups.functions ?? []]);
323
+ await actionSyncFilesToTargets(tsPaths);
324
+ }
325
+ async handleConfigChanges(_) {
326
+ await actionSyncConfig();
327
+ }
328
+ async handleSonamuDictionaryRelatedChanges(_) {
329
+ await actionSyncSonamuDictionary();
330
+ }
331
+ async handleDrifts(drifts) {
332
+ if (drifts.length > 0) {
333
+ console.warn(chalk.yellow("⚠️ Sonamu가 자동 생성한 파일에 대한 변경이 감지되었습니다. 파일이 Sonamu watcher 외부에서 변경된 것으로 추정됩니다."));
334
+ for (const p of drifts) {
335
+ console.warn(chalk.yellow(` - ${path.relative(Sonamu.appRootPath, p)}`));
336
+ }
337
+ console.warn(chalk.dim(" → `pnpm sonamu sync --force`를 권장합니다."));
338
+ }
301
339
  }
302
340
  /**
303
341
  * 주어진 엔티티와 템플릿 키에 대해, 생성된 코드가 존재하는지 확인합니다.
@@ -377,48 +415,10 @@ var init_syncer = __esmMin((() => {
377
415
  async renewChecksums() {
378
416
  return await renewChecksums();
379
417
  }
380
- /**
381
- * SD(Sonamu Dictionary) 템플릿을 생성합니다.
382
- */
383
- async syncSD() {
384
- const { targets } = Sonamu.config.sync;
385
- const i18nConfig = Sonamu.config.i18n;
386
- const targetList = ["api", ...targets];
387
- const apiI18nDir = path.join(Sonamu.appRootPath, Sonamu.config.api.dir, "src/i18n");
388
- for (const target of targetList) {
389
- try {
390
- if (target !== "api") {
391
- await this.syncLocaleFiles(target, apiI18nDir, i18nConfig.supportedLocales);
392
- }
393
- await generateTemplate("sd", { target }, { overwrite: true });
394
- } catch (e) {
395
- console.error(`Failed to generate SD template for ${target}:`, e);
396
- }
397
- }
398
- }
399
- /**
400
- * api의 locale 파일을 web/app으로 복사합니다.
401
- */
402
- async syncLocaleFiles(target, apiI18nDir, locales) {
403
- const targetI18nDir = path.join(Sonamu.appRootPath, target, "src/i18n");
404
- await mkdir(targetI18nDir, { recursive: true });
405
- for (const locale of locales) {
406
- const sourceFile = path.join(apiI18nDir, `${locale}.ts`);
407
- const targetFile = path.join(targetI18nDir, `${locale}.ts`);
408
- const syncHeader = [
409
- "/**",
410
- " * @generated",
411
- " * API에서 동기화된 파일입니다. 직접 수정하지 마세요.",
412
- " */"
413
- ].join("\n");
414
- await copyFileWithReplaceCoreToShared(sourceFile, targetFile, syncHeader);
415
- !isTest() && console.log(chalk.bold("Copied: ") + chalk.cyan(`${target}/src/i18n/${locale}.ts`));
416
- }
417
- }
418
418
  };
419
419
  }));
420
420
 
421
421
  //#endregion
422
422
  init_syncer();
423
423
  export { Syncer, init_syncer };
424
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luY2VyLmpzIiwibmFtZXMiOlsiU3luY2VyQWN0aW9ucy5hY3Rpb25TeW5jQ29uZmlnIiwiU3luY2VyQWN0aW9ucy5hY3Rpb25HZW5lcmF0ZVNjaGVtYXMiLCJTeW5jZXJBY3Rpb25zLmFjdGlvblN5bmNGaWxlc1RvVGFyZ2V0cyIsInBhcmFtczoge1xuICAgICAgbmFtZXNSZWNvcmQ6IEVudGl0eU5hbWVzUmVjb3JkO1xuICAgIH1bXSIsIlN5bmNlckFjdGlvbnMuYWN0aW9uR2VuZXJhdGVTZXJ2aWNlcyIsIlN5bmNlckFjdGlvbnMuYWN0aW9uR2VuZXJhdGVIdHRwcyIsIlN5bmNlckFjdGlvbnMuYWN0aW9uR2VuZXJhdGVTc3IiLCJrZXlzOiBUZW1wbGF0ZUtleVtdIiwicCIsInRhcmdldCJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zeW5jZXIvc3luY2VyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSBcImV2ZW50c1wiO1xuaW1wb3J0IHsgbWtkaXIsIHJlYWRGaWxlLCB3cml0ZUZpbGUgfSBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5cbmltcG9ydCB7IGhvdCB9IGZyb20gXCJAc29uYW11LWtpdC9obXItaG9va1wiO1xuaW1wb3J0IGNoYWxrIGZyb20gXCJjaGFsa1wiO1xuaW1wb3J0IHsgbWluaW1hdGNoIH0gZnJvbSBcIm1pbmltYXRjaFwiO1xuaW1wb3J0IHsgZ3JvdXAsIHVuaXF1ZSB9IGZyb20gXCJyYWRhc2hpXCI7XG5pbXBvcnQgeyB0eXBlIHogfSBmcm9tIFwiem9kXCI7XG5cbmltcG9ydCB7IHJlZ2lzdGVyZWRBcGlzIH0gZnJvbSBcIi4uL2FwaS9kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBTb25hbXUgfSBmcm9tIFwiLi4vYXBpL3NvbmFtdVwiO1xuaW1wb3J0IHsgRW50aXR5TWFuYWdlciB9IGZyb20gXCIuLi9lbnRpdHkvZW50aXR5LW1hbmFnZXJcIjtcbmltcG9ydCB7IHR5cGUgRW50aXR5TmFtZXNSZWNvcmQgfSBmcm9tIFwiLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyBBbHJlYWR5UHJvY2Vzc2VkRXhjZXB0aW9uIH0gZnJvbSBcIi4uL2V4Y2VwdGlvbnMvc28tZXhjZXB0aW9uc1wiO1xuaW1wb3J0IHsgTmFpdGUgfSBmcm9tIFwiLi4vbmFpdGUvbmFpdGVcIjtcbmltcG9ydCB7IHR5cGUgV29ya2Zsb3dNZXRhZGF0YSB9IGZyb20gXCIuLi90YXNrcy9kZWNvcmF0b3JcIjtcbmltcG9ydCB7IFRlbXBsYXRlTWFuYWdlciB9IGZyb20gXCIuLi90ZW1wbGF0ZS90ZW1wbGF0ZS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyB0eXBlIEdlbmVyYXRlT3B0aW9ucywgdHlwZSBQYXRoQW5kQ29kZSB9IGZyb20gXCIuLi90eXBlcy90eXBlc1wiO1xuaW1wb3J0IHsgVGVtcGxhdGVLZXkgfSBmcm9tIFwiLi4vdHlwZXMvdHlwZXNcIjtcbmltcG9ydCB7IHR5cGUgVGVtcGxhdGVPcHRpb25zIH0gZnJvbSBcIi4uL3R5cGVzL3R5cGVzXCI7XG5pbXBvcnQgeyBtYXBBc3luYywgcmVkdWNlQXN5bmMgfSBmcm9tIFwiLi4vdXRpbHMvYXN5bmMtdXRpbHNcIjtcbmltcG9ydCB7IGNlbnRlclRleHQgfSBmcm9tIFwiLi4vdXRpbHMvY29uc29sZS11dGlsXCI7XG5pbXBvcnQgeyBpc1Rlc3QgfSBmcm9tIFwiLi4vdXRpbHMvY29udHJvbGxlclwiO1xuaW1wb3J0IHsgY29weUZpbGVXaXRoUmVwbGFjZUNvcmVUb1NoYXJlZCwgZXhpc3RzIH0gZnJvbSBcIi4uL3V0aWxzL2ZzLXV0aWxzXCI7XG5pbXBvcnQgeyB0eXBlIEFic29sdXRlUGF0aCB9IGZyb20gXCIuLi91dGlscy9wYXRoLXV0aWxzXCI7XG5pbXBvcnQgeyBydW5XaXRoR3JhY2VmdWxTaHV0ZG93biB9IGZyb20gXCIuLi91dGlscy9wcm9jZXNzLXV0aWxzXCI7XG5pbXBvcnQgeyBmaW5kQ2hhbmdlZEZpbGVzVXNpbmdDaGVja3N1bXMsIHJlbmV3Q2hlY2tzdW1zIH0gZnJvbSBcIi4vY2hlY2tzdW1cIjtcbmltcG9ydCB7IGdlbmVyYXRlVGVtcGxhdGUsIHJlbmRlclRlbXBsYXRlIH0gZnJvbSBcIi4vY29kZS1nZW5lcmF0b3JcIjtcbmltcG9ydCB7IGNyZWF0ZUVudGl0eSwgZGVsRW50aXR5IH0gZnJvbSBcIi4vZW50aXR5LW9wZXJhdGlvbnNcIjtcbmltcG9ydCB7IGNoZWNrc3VtUGF0dGVybkdyb3VwLCBnZXRDaGVja3N1bVBhdHRlcm5Hcm91cEluQWJzb2x1dGVQYXRoIH0gZnJvbSBcIi4vZmlsZS1wYXR0ZXJuc1wiO1xuaW1wb3J0IHsgdHlwZSBGaWxlVHlwZSB9IGZyb20gXCIuL2ZpbGUtcGF0dGVybnNcIjtcbmltcG9ydCB7IGxvYWRBcGlzLCBsb2FkTW9kZWxzLCBsb2FkVHlwZXMsIGxvYWRXb3JrZmxvd3MgfSBmcm9tIFwiLi9tb2R1bGUtbG9hZGVyXCI7XG5pbXBvcnQgeyB0eXBlIExvYWRlZEFwaXMsIHR5cGUgTG9hZGVkTW9kZWxzLCB0eXBlIExvYWRlZFR5cGVzIH0gZnJvbSBcIi4vbW9kdWxlLWxvYWRlclwiO1xuaW1wb3J0ICogYXMgU3luY2VyQWN0aW9ucyBmcm9tIFwiLi9zeW5jZXItYWN0aW9uc1wiO1xuXG50eXBlIERpZmZHcm91cHMgPSB7XG4gIFtrZXkgaW4gRmlsZVR5cGVdOiBBYnNvbHV0ZVBhdGhbXTtcbn07XG5cbmV4cG9ydCBjbGFzcyBTeW5jZXIge1xuICBhcGlzOiBMb2FkZWRBcGlzID0gW107XG4gIHR5cGVzOiBMb2FkZWRUeXBlcyA9IHt9O1xuICBtb2RlbHM6IExvYWRlZE1vZGVscyA9IHt9O1xuICB3b3JrZmxvd3M6IE1hcDxzdHJpbmcsIFdvcmtmbG93TWV0YWRhdGFbXT4gPSBuZXcgTWFwKCk7XG4gIGV2ZW50RW1pdHRlcjogRXZlbnRFbWl0dGVyID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gIC8qKlxuICAgKiDssrTtgazshKzsnbQg67OA6rK965CcIOu2gOu2hOyXkCDrjIDtlbQg7Iux7YGs66W8IOynhO2Wie2VqeuLiOuLpC5cbiAgICogc29uYW11LnNoYXJlZC50c+uKlCDtjIzsnbzsnbQg7JeG7J2EIOuVjOunjCAx7ZqMIOyDneyEse2VmOqzoCwg7J207ZuE7JeQ64qUIOuNruyWtOyTsOyngCDslYrsirXri4jri6QuXG4gICAqIEByZXR1cm5zXG4gICAqL1xuICBhc3luYyBzeW5jKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgdGFyZ2V0cyB9ID0gU29uYW11LmNvbmZpZy5zeW5jO1xuXG4gICAgLy8gc29uYW11LnNoYXJlZC50c+uKlCDtjIzsnbzsnbQg7JeG7J2EIOuVjOunjCAx7ZqMIOyDneyEse2VqeuLiOuLpC5cbiAgICBhd2FpdCB0aGlzLmNvcHlTaGFyZWRUb1RhcmdldHModGFyZ2V0cyk7XG5cbiAgICAvLyDqt7gg64uk7J2M67aA7YSw64qUIOuzgOqyveuQnCDtjIzsnbzsnYQg7LC+7JWE7IScIOuPmeq4sO2ZlCDsnpHsl4XsnYQg7Iuk7ZaJ7ZWp64uI64ukLlxuICAgIGNvbnN0IGNoYW5nZWRGaWxlcyA9IGF3YWl0IGZpbmRDaGFuZ2VkRmlsZXNVc2luZ0NoZWNrc3VtcygpO1xuICAgIGlmIChjaGFuZ2VkRmlsZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZyhjaGFsay5ibGFjay5iZ0dyZWVuKGNlbnRlclRleHQoXCJBbGwgZmlsZXMgYXJlIHN5bmNlZCFcIikpKTtcblxuICAgICAgLy8g67OA6rK97IKs7ZWt7J20IOyXhuyWtOuPhCBTU1Ig7YWc7ZSM66a/7J2AIOyDneyEsSAo7LSI6riwIOyEpOyglSDsi5wsIOydtOuvuCDsobTsnqztlZjrqbQg7Iqk7YK1KVxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZ2VuZXJhdGVUZW1wbGF0ZShcInF1ZXJpZXNcIiwge30sIHsgb3ZlcndyaXRlOiBmYWxzZSB9KTtcbiAgICAgICAgYXdhaXQgZ2VuZXJhdGVUZW1wbGF0ZShcImVudHJ5X3NlcnZlclwiLCB7fSwgeyBvdmVyd3JpdGU6IGZhbHNlIH0pO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAvLyDtjIzsnbzsnbQg7J2066+4IOyhtOyerO2VmOuptCDrrLTsi5xcbiAgICAgICAgaWYgKCEoZSBpbnN0YW5jZW9mIEFscmVhZHlQcm9jZXNzZWRFeGNlcHRpb24pKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcIkZhaWxlZCB0byBnZW5lcmF0ZSBTU1IgdGVtcGxhdGVzOlwiLCBlKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8g66eM7JW9IOyLse2BrCDspJHsl5Ag7ZSE66Gc7IS47Iqk6rCAIOyjveycvOuptCDqvKzsl6zrsoTrpqzquLAg65WM66y47JeQLFxuICAgIC8vIOyLnOq3uOuEkOyXkOuPhCDsnqDsi5wg67KE7Yu4IOyImCDsnojripQg7ZmY6rK9IOyGjeyXkOyEnCDsi7Htgazrpbwg7Iuk7ZaJ7ZWp64uI64ukLlxuICAgIGF3YWl0IHJ1bldpdGhHcmFjZWZ1bFNodXRkb3duKFxuICAgICAgYXN5bmMgKCkgPT4ge1xuICAgICAgICAvLyDslpjqsIAg7Iux7YGsIOyekeyXhSDsiJjtlontlZjripQg67O47LK07J6F64uI64ukLlxuICAgICAgICBhd2FpdCB0aGlzLmRvU3luY0FjdGlvbnMoY2hhbmdlZEZpbGVzKTtcblxuICAgICAgICAvLyDsi7Htgawg7JWh7IWY7J20IOuBneuCmOuptCDtla3sg4Eg7LK07YGs7ISs7J2EIOuLpOyLnCDqsLHsi6Dtlanri4jri6QuXG4gICAgICAgIGF3YWl0IHJlbmV3Q2hlY2tzdW1zKCk7XG4gICAgICB9LFxuICAgICAgeyB3aGVuVGhpc0hhcHBlbnM6IFwiU0lHVVNSMlwiLCB3YWl0Rm9yVXBUbzogMjAwMDAgfSxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFdhdGNoZXLqsIAg6rCQ7KeA7ZWcIO2MjOydvCDrs4Dqsr0g7IKs7ZWt7JeQIOuMgO2VtCDsi7Htgazrpbwg7KeE7ZaJ7ZWp64uI64ukLlxuICAgKiDso7zslrTsp4Qg67OA6rK9IO2MjOydvOuTpCDspJEg7LK07YGs7ISsIOq0gOumrCDrjIDsg4Hsnbgg6rKD65Ok66eMIOqwgOyguOuLpOqwgCDsi7Htgazrpbwg7KeE7ZaJ7ZWp64uI64ukLlxuICAgKiDssrTtgazshKwg7YyM7J28IOyXheuNsOydtO2KuOuKlCDsl6zquLDsl5DshJwg7ZWY7KeAIOyViuyKteuLiOuLpC4g7Zi47Lac7J6Q6rCAIO2VqeuLiOuLpC5cbiAgICogQHBhcmFtIGRpZmZGaWxlUGF0aCAtIOuzgOqyvSDtjIzsnbzrk6QuIO2UhOuhnOygne2KuCDro6jtirjrtoDthLAgXCJzcmMvXCIg65iQ64qUIFwiZGlzdC9cIuuhnCDsi5zsnpHtlZjripQg7IOB64yAIOqyveuhnOyeheuLiOuLpC4g7JiI7IucOiBcInNyYy9hcHBsaWNhdGlvbi91c2VyL3VzZXIubW9kZWwudHNcIlxuICAgKi9cbiAgYXN5bmMgc3luY0Zyb21XYXRjaGVyKGV2ZW50OiBzdHJpbmcsIGRpZmZGaWxlUGF0aDogQWJzb2x1dGVQYXRoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKGV2ZW50ICE9PSBcImNoYW5nZVwiICYmIGV2ZW50ICE9PSBcImFkZFwiICYmIGV2ZW50ICE9PSBcInVubGlua1wiKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gU1NSIOyEpOyglSDtjIzsnbwg67OA6rK9IOqwkOyngFxuICAgIGlmIChkaWZmRmlsZVBhdGguaW5jbHVkZXMoXCIvc3JjL3Nzci9cIikpIHtcbiAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmJvbGQueWVsbG93KFwiU1NSIGNvbmZpZyBjaGFuZ2VkIC0gcmVsb2FkaW5nLi4uXCIpKTtcbiAgICAgIC8vIFNTUiDtjIzsnbzrj4QgaW52YWxpZGF0ZSDtm4QgcmVsb2FkXG4gICAgICBpZiAoIWlzVGVzdCgpKSB7XG4gICAgICAgIGF3YWl0IGhvdC5pbnZhbGlkYXRlRmlsZShkaWZmRmlsZVBhdGgsIGV2ZW50KTtcbiAgICAgIH1cbiAgICAgIGF3YWl0IHRoaXMuYXV0b2xvYWRTU1JSb3V0ZXMoKTtcbiAgICAgIHRoaXMuZXZlbnRFbWl0dGVyLmVtaXQoXCJvbkhNUkNvbXBsZXRlZFwiKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyDsnbzri6gg67OA6rK965CcIO2MjOydvOqzvCBkZXBlbmRlbnQg7YyM7J2865Ok7J2EIGludmFsaWRhdGUg7ZWp64uI64ukLlxuICAgIC8vIO2VnCDrsogg7J207IOBIGltcG9ydOuQnCDsuZzqtazrk6Tsl5Ag64yA7ZW07ISc66eMIOyLpOygnCDsnpHsl4XsnbQg7J287Ja064Kp64uI64ukLlxuICAgIC8vIOq3uOufrOuLiCDslYjsi6ztlZjqs6AgaW52YWxpZGF0ZSDtlbTrj4Qg65Cp64uI64ukLlxuICAgIC8vIO2FjOyKpO2KuCDtmZjqsr3sl5DshJzripQgaG90LmludmFsaWRhdGVGaWxl7IucIOy0iOq4sCDsl5Drn6zqsIAg67Cc7IOd7ZWY6riwIOuVjOusuOyXkCBpbnZhbGlkYXRlIO2VmOyngCDslYrsirXri4jri6QuXG4gICAgaWYgKCFpc1Rlc3QoKSkge1xuICAgICAgY29uc3QgaW52YWxpZGF0ZWRQYXRocyA9IChhd2FpdCBob3QuaW52YWxpZGF0ZUZpbGUoZGlmZkZpbGVQYXRoLCBldmVudCkpIGFzIEFic29sdXRlUGF0aFtdO1xuXG4gICAgICBpZiAoaW52YWxpZGF0ZWRQYXRocy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmJvbGQoYPCflIQgSW52YWxpZGF0ZWQ6YCkpO1xuXG4gICAgICAgIGZvciAoY29uc3QgaW52YWxpZGF0ZWRQYXRoIG9mIGludmFsaWRhdGVkUGF0aHMpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8g66eM7JW9IG1vZGVsLnRzIO2MjOydvOydtCDrs4Dqsr0oaW52YWxpZGF0ZSnrkJjsl4jri6Q/IOq3uOufrOuptCByZWdpc3RlcmVkQXBpcyDspJHsl5DshJwg7J20IOuqqOuNuOyXkCDtlbTri7ntlZjripQgYXBp65Ok7J2AIOyngOybjOykmOyalC5cbiAgICAgICAgICAgIC8vIHJlZ2lzdGVyZWRBcGlz64qUIO2GteycvOuhnCDri6Qg64Kg66Ck67KE66a0IOyImCDsl4bsirXri4jri6QuIHJlZ2lzdGVyZWRBcGlz7JeQIOyYrOudvOyYpOuKlCDsuZzqtazrk6TsnYAg7LSI6riwIOuhnOuTnOyLnCDrmJDripQgSE1S7Iuc7JeQ66eMIOuTseuhneuQmOq4sCDrlYzrrLjsnoXri4jri6QuXG4gICAgICAgICAgICAvLyDrlLDrnbzshJwgbW9kZWwudHMg7YyM7J287J2YIOuzgOqyveycvOuhnCDri6TsnYzrsogg7IOI66Gc7Jq0IGV2YWzsnbQg7JiI7IOB65CY64qUIOydtCDsi5zsoJDsl5DshJzrp4wsIOydtCDrqqjrjbjsl5DshJwg64KY7JioIHJlZ2lzdGVyZWRBcGlz65Ok7J2EIOyngOybjOykhCDsiJgg7J6I7Iq164uI64ukLlxuICAgICAgICAgICAgY29uc3QgcmVtb3ZlZEFwaXMgPSB0aGlzLnJlbW92ZUludmFsaWRhdGVkUmVnaXN0ZXJlZEFwaXMoaW52YWxpZGF0ZWRQYXRoKTtcbiAgICAgICAgICAgIGlmIChyZW1vdmVkQXBpcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgICAgIGNoYWxrLmJsdWUoYC0gJHtwYXRoLnJlbGF0aXZlKFNvbmFtdS5hcGlSb290UGF0aCwgaW52YWxpZGF0ZWRQYXRoKX1gKSxcbiAgICAgICAgICAgICAgICBjaGFsay5ncmF5KGAod2l0aCAke3JlbW92ZWRBcGlzLmxlbmd0aH0gQVBJcylgKSxcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmJsdWUoYC0gJHtwYXRoLnJlbGF0aXZlKFNvbmFtdS5hcGlSb290UGF0aCwgaW52YWxpZGF0ZWRQYXRoKX1gKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlKTtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgICAgICAgIGNoYWxrLnJlZChgRmFpbGVkIHRvIHJlbW92ZSBpbnZhbGlkYXRlZCByZWdpc3RlcmVkIEFQSXMgZm9yICR7aW52YWxpZGF0ZWRQYXRofWApLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBkZXZSdW5uZXIg7Zmc7ISx7ZmUIOyLnCwg67OA6rK965CcIOyGjOyKpCDtjIzsnbzsnYQgVml0ZXN0IOuqqOuTiCDqt7jrnpjtlITsl5DshJzrj4Qg66y07Zqo7ZmU7ZWp64uI64ukLlxuICAgIC8vIFZpdGXsnZggbW9kdWxlR3JhcGguaW52YWxpZGF0ZU1vZHVsZSgp7J20IGltcG9ydGVyIOuwqe2WpeycvOuhnCDsnqzqt4DsoIEgY2FzY2FkZe2VmOuvgOuhnCxcbiAgICAvLyDshozsiqQg7YyM7J28IO2VmOuCmOunjCDrrLTtmqjtmZTtlZjrqbQg7J2066W8IGltcG9ydO2VmOuKlCDthYzsiqTtirgg7YyM7J2864+EIOyekOuPmeycvOuhnCDrrLTtmqjtmZTrkKnri4jri6QuXG4gICAgaWYgKCFpc1Rlc3QoKSAmJiBTb25hbXUuY29uZmlnLnRlc3Q/LmRldlJ1bm5lcj8uZW5hYmxlZCAmJiBTb25hbXUuZGV2Vml0ZXN0TWFuYWdlcikge1xuICAgICAgU29uYW11LmRldlZpdGVzdE1hbmFnZXIuaW52YWxpZGF0ZUZpbGVzKFtkaWZmRmlsZVBhdGhdKTtcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICBjaGFsay5kaW0oYFRlc3QgaW52YWxpZGF0ZWQ6ICR7cGF0aC5yZWxhdGl2ZShTb25hbXUuYXBpUm9vdFBhdGgsIGRpZmZGaWxlUGF0aCl9YCksXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGlzSW5DaGVja1BhdHRlcm5Hcm91cCA9IE9iamVjdC52YWx1ZXMoZ2V0Q2hlY2tzdW1QYXR0ZXJuR3JvdXBJbkFic29sdXRlUGF0aCgpKS5zb21lKFxuICAgICAgKHBhdHRlcm4pID0+IG1pbmltYXRjaChkaWZmRmlsZVBhdGgsIHBhdHRlcm4pLFxuICAgICk7XG5cbiAgICAvLyDtlaAg7J28KHN5bmMp7J20IOyeiOycvOuptCDtlanri4jri6QuXG4gICAgaWYgKGlzSW5DaGVja1BhdHRlcm5Hcm91cCkge1xuICAgICAgYXdhaXQgdGhpcy5kb1N5bmNBY3Rpb25zKFtkaWZmRmlsZVBhdGhdKTtcbiAgICB9XG5cbiAgICAvLyDsi7Htgawg7J6R7JeF7J20IOuBneuCmOuptCDrqqjrk6Ag66qo65OI7J2EIOuhnOuTnO2VqeuLiOuLpC5cbiAgICAvLyBobXItaG9va+yXkCDsnZjtlbQgaW52YWxpZGF0ZeuQnCDrtoDrtoTrk6TsnbQg7JWE64uI652866m0IOy6kOyLnCDqt7jrjIDroZwg7Jyg7KeA7ZWp64uI64ukLlxuICAgIGF3YWl0IHRoaXMuYXV0b2xvYWRUeXBlcygpO1xuICAgIGF3YWl0IHRoaXMuYXV0b2xvYWRNb2RlbHMoKTtcbiAgICBhd2FpdCB0aGlzLmF1dG9sb2FkQXBpcygpO1xuICAgIGF3YWl0IHRoaXMuYXV0b2xvYWRXb3JrZmxvd3MoKTtcblxuICAgIHRoaXMuZXZlbnRFbWl0dGVyLmVtaXQoXCJvbkhNUkNvbXBsZXRlZFwiKTtcbiAgfVxuXG4gIHJlbW92ZUludmFsaWRhdGVkUmVnaXN0ZXJlZEFwaXMoXG4gICAgaW52YWxpZGF0ZWRQYXRoOiBBYnNvbHV0ZVBhdGgsXG4gICk6ICh0eXBlb2YgcmVnaXN0ZXJlZEFwaXMpW251bWJlcl1bXSB7XG4gICAgaWYgKCFpbnZhbGlkYXRlZFBhdGguZW5kc1dpdGgoXCIubW9kZWwudHNcIiAvKuyGjOyKpCDsvZTrk5zrpbwg64uk66Oo64qUIOyDge2ZqeydtOuLiCAudHMg6rK966Gc66GcIOu0heuLiOuLpC4qLykpIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICBjb25zdCBlbnRpdHlJZCA9IEVudGl0eU1hbmFnZXIuZ2V0RW50aXR5SWRGcm9tUGF0aChpbnZhbGlkYXRlZFBhdGgpO1xuICAgIGNvbnN0IHRvUmVtb3ZlID0gcmVnaXN0ZXJlZEFwaXMuZmlsdGVyKChhcGkpID0+IGFwaS5tb2RlbE5hbWUgPT09IGAke2VudGl0eUlkfU1vZGVsYCk7XG4gICAgZm9yIChjb25zdCBhcGkgb2YgdG9SZW1vdmUpIHtcbiAgICAgIGNvbnN0IGlkeCA9IHJlZ2lzdGVyZWRBcGlzLmluZGV4T2YoYXBpKTtcbiAgICAgIGlmIChpZHggIT09IC0xKSB7XG4gICAgICAgIHJlZ2lzdGVyZWRBcGlzLnNwbGljZShpZHgsIDEpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0b1JlbW92ZTtcbiAgfVxuXG4gIGFzeW5jIGNvcHlTaGFyZWRUb1RhcmdldHModGFyZ2V0czogc3RyaW5nW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyBwbHVyYWwudHMg64K07Jqp7J2EIOydveyWtOyEnCBzaGFyZWQg7YyM7J287JeQIOyCveyehe2VqeuLiOuLpC5cbiAgICBjb25zdCBkaWN0VXRpbHNQYXRoID0gcGF0aC5qb2luKFxuICAgICAgaW1wb3J0Lm1ldGEuZGlybmFtZS5yZXBsYWNlKFwiL2Rpc3QvXCIsIFwiL3NyYy9cIiksXG4gICAgICBcIi4uL2RpY3QvdXRpbHMudHNcIixcbiAgICApO1xuICAgIGNvbnN0IGRpY3RVdGlsc0NvZGUgPSAoYXdhaXQgZXhpc3RzKGRpY3RVdGlsc1BhdGgpKVxuICAgICAgPyBhd2FpdCByZWFkRmlsZShkaWN0VXRpbHNQYXRoLCBcInV0Zi04XCIpXG4gICAgICA6IFwiXCI7XG5cbiAgICAvLyDtirnsoJUg67OA7IiYIOy5mO2ZmOydhCDsnITtlbTshJwg7IKs7Jqp7ZWp64uI64ukLlxuICAgIGNvbnN0IGNvbnZlcnRNYXAgPSB7XG4gICAgICBiYXNlVXJsOlxuICAgICAgICBTb25hbXUuY29uZmlnLnNlcnZlci5iYXNlVXJsID8/XG4gICAgICAgIGBodHRwOi8vJHtTb25hbXUuY29uZmlnLnNlcnZlci5saXN0ZW4/Lmhvc3QgPz8gXCJsb2NhbGhvc3RcIn06JHtTb25hbXUuY29uZmlnLnNlcnZlci5saXN0ZW4/LnBvcnQgPz8gMzAwMH1gLFxuICAgICAgZGljdFV0aWxzOiBkaWN0VXRpbHNDb2RlLFxuICAgIH07XG5cbiAgICBmb3IgKGNvbnN0IHRhcmdldCBvZiB0YXJnZXRzKSB7XG4gICAgICAvLyDsp4DquIgg6rCA7KC46rCA66Ck64qUIOydtCDtjIzsnbzsnYAgU29uYW11IOy9lOuTnOuyoOydtOyKpOydmCDsnbzrtoDsnoXri4jri6QuXG4gICAgICAvLyDqt7jrn7DrjbAgZGlzdCDsho0g67mM65Oc65CcIOyGjOyKpCDsvZTrk5wg7YyM7J287J20IO2VhOyalO2VnCDqsoPsnbQg7JWE64uI6rOgLCBzcmPsl5Drp4wg7J6I64qUIO2FjeyKpO2KuCDtjIzsnbzsnbQg7ZWE7JqU7ZWp64uI64ukLlxuICAgICAgLy8g65Sw65287IScIC9zcmMv7JeQ7IScIOywvuyKteuLiOuLpC5cbiAgICAgIGNvbnN0IHNyY1BhdGggPSBwYXRoLmpvaW4oXG4gICAgICAgIGltcG9ydC5tZXRhLmRpcm5hbWUucmVwbGFjZShcIi9kaXN0L1wiLCBcIi9zcmMvXCIpLFxuICAgICAgICBgLi4vc2hhcmVkLyR7dGFyZ2V0fS5zaGFyZWQudHMudHh0YCxcbiAgICAgICk7XG4gICAgICBpZiAoIShhd2FpdCBleGlzdHMoc3JjUGF0aCkpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKCEoYXdhaXQgZXhpc3RzKHBhdGguam9pbihTb25hbXUuYXBwUm9vdFBhdGgsIHRhcmdldCkpKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYFRyaWVkIHRvIGNvcHkgc29uYW11LnNoYXJlZC50cyB0byB0YXJnZXQgJyR7dGFyZ2V0fScgYnV0IHRoZSB0YXJnZXQgZGlyZWN0b3J5IGRvZXMgbm90IGV4aXN0LiBQbGVhc2UgY2hlY2sgeW91ciBwcm9qZWN0IGRpcmVjdG9yeSBzdHJ1Y3R1cmUuYCxcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZnVsbFRleHQgPSBhd2FpdCByZWFkRmlsZShzcmNQYXRoLCBcInV0Zi04XCIpO1xuICAgICAgY29uc3QgY29udmVydGVkVGV4dCA9IE9iamVjdC5lbnRyaWVzKGNvbnZlcnRNYXApLnJlZHVjZShcbiAgICAgICAgKGFjYywgW2tleSwgdmFsdWVdKSA9PiBhY2MucmVwbGFjZShgJFtbJHtrZXl9XV1gLCB2YWx1ZSksXG4gICAgICAgIGZ1bGxUZXh0LFxuICAgICAgKTtcblxuICAgICAgLy8g7J206rG0IO2UhOuhnOygne2KuOyXkCAudHMg7IaM7IqkIOy9lOuTnCDtjIzsnbzsnYQg7IOd7ISx7ZWY64qUIOqyg+ydtOuvgOuhnCBzcmPsnZggLnRzIOqyveuhnOuhnCDqsJHri4jri6QuXG4gICAgICBjb25zdCBkZXN0UGF0aCA9IHBhdGguam9pbihTb25hbXUuYXBwUm9vdFBhdGgsIHRhcmdldCwgXCJzcmMvc2VydmljZXMvc29uYW11LnNoYXJlZC50c1wiKTtcblxuICAgICAgLy8g7KCV66eQIO2YueyLnOuCmOyngOunjCB0YXJnZXQg65SU66CJ7Yag66as64qUIOyeiOyWtOuPhCBzcmMvc2VydmljZXMg65SU66CJ7Yag66as64qUIOyXhuydhCDsiJgg7J6I7Jy866+A66GcIOuvuOumrCDsg53shLHtlbTspI3ri4jri6QuXG4gICAgICBpZiAoIShhd2FpdCBleGlzdHMocGF0aC5kaXJuYW1lKGRlc3RQYXRoKSkpKSB7XG4gICAgICAgIGF3YWl0IG1rZGlyKHBhdGguZGlybmFtZShkZXN0UGF0aCksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgICAgICBjb25zb2xlLndhcm4oYENyZWF0ZWQgZGlyZWN0b3J5ICcke3BhdGguZGlybmFtZShkZXN0UGF0aCl9JyBiZWNhdXNlIGl0IGRpZCBub3QgZXhpc3QuYCk7XG4gICAgICB9XG5cbiAgICAgIC8vIO2MjOydvOydtCDsnbTrr7gg7KG07J6s7ZWY66m0IOqxtOuEiOucgeuLiOuLpC5cbiAgICAgIC8vIHNvbmFtdS5zaGFyZWQudHPripQg7ZSE66Gc7KCd7Yq47JeQ7IScIOyekOycoOuhreqyjCDsu6TsiqTthLDrp4jsnbTsp5XtlaAg7IiYIOyeiOyWtOyVvCDtlZjrr4DroZwsXG4gICAgICAvLyDstZzstIggMe2ajOunjCDsg53shLHtlZjqs6Ag7J207ZuE7JeQ64qUIOuNruyWtOyTsOyngCDslYrsirXri4jri6QuXG4gICAgICAvLyDthZztlIzrpr8g64K07JqpKCRbW2RpY3RVdGlsc11dIOuTsSnsnbQg67OA6rK965CY7JeI7J2EIOuVjCDrsJjsmIHsnbQg7ZWE7JqU7ZWY66m0LFxuICAgICAgLy8g7ZW064u5IO2MjOydvOydhCDsgq3soJztlZwg65KkIGBwbnBtIHNvbmFtdSBzeW5jYOuhnCDsnqzsg53shLHtlZjrqbQg65Cp64uI64ukLlxuICAgICAgaWYgKGF3YWl0IGV4aXN0cyhkZXN0UGF0aCkpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGF3YWl0IHdyaXRlRmlsZShkZXN0UGF0aCwgY29udmVydGVkVGV4dCk7XG4gICAgICAhaXNUZXN0KCkgJiZcbiAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgY2hhbGsuYm9sZChcIkNvcGllZDogXCIpICsgY2hhbGsuYmx1ZShwYXRoLnJlbGF0aXZlKFNvbmFtdS5hcHBSb290UGF0aCwgZGVzdFBhdGgpKSxcbiAgICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBhdXRvbG9hZFR5cGVzKCkge1xuICAgIHRoaXMudHlwZXMgPSBhd2FpdCBsb2FkVHlwZXMoKTtcbiAgfVxuXG4gIGFzeW5jIGF1dG9sb2FkTW9kZWxzKCkge1xuICAgIHRoaXMubW9kZWxzID0gYXdhaXQgbG9hZE1vZGVscygpO1xuICB9XG5cbiAgYXN5bmMgYXV0b2xvYWRBcGlzKCkge1xuICAgIHRoaXMuYXBpcyA9IGF3YWl0IGxvYWRBcGlzKCk7XG4gIH1cblxuICBhc3luYyBhdXRvbG9hZFdvcmtmbG93cygpIHtcbiAgICB0aGlzLndvcmtmbG93cyA9IGF3YWl0IGxvYWRXb3JrZmxvd3MoKTtcbiAgICBhd2FpdCBTb25hbXUud29ya2Zsb3dzLnN5bmNocm9uaXplKHRoaXMud29ya2Zsb3dzKTtcbiAgfVxuXG4gIGFzeW5jIGF1dG9sb2FkU1NSUm91dGVzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHNzckNvbmZpZ1BhdGggPSBwYXRoLmpvaW4oU29uYW11LmFwaVJvb3RQYXRoLCBcInNyYy9zc3JcIik7XG5cbiAgICAvLyDquLDsobQgcm91dGVzIOy0iOq4sO2ZlFxuICAgIGNvbnN0IHsgY2xlYXJTU1JSb3V0ZXMgfSA9IGF3YWl0IGltcG9ydChcIi4uL3NzclwiKTtcbiAgICBjbGVhclNTUlJvdXRlcygpO1xuXG4gICAgLy8gc3NyIO2PtOuNlCDsl4bsnLzrqbQg7Iqk7YK1XG4gICAgaWYgKCEoYXdhaXQgZXhpc3RzKHNzckNvbmZpZ1BhdGgpKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHNzciDtj7TrjZQg7JWI7J2YIOuqqOuToCAudHMg7YyM7J28IOuhnOuTnFxuICAgIGNvbnN0IHsgZ2xvYkFzeW5jIH0gPSBhd2FpdCBpbXBvcnQoXCIuLi91dGlscy9hc3luYy11dGlsc1wiKTtcbiAgICBjb25zdCB7IGltcG9ydE1lbWJlcnMgfSA9IGF3YWl0IGltcG9ydChcIi4uL3V0aWxzL2VzbS11dGlsc1wiKTtcbiAgICBjb25zdCB7IHJ1bnRpbWVQYXRoIH0gPSBhd2FpdCBpbXBvcnQoXCIuLi91dGlscy9wYXRoLXV0aWxzXCIpO1xuXG4gICAgLy8gcnVudGltZVBhdGjrpbwg7IKs7Jqp7ZWY7JesIOqwnOuwnC/tlITroZzrjZXshZgg7ZmY6rK97JeQIOunnuuKlCDtmZXsnqXsnpAg7LKY66asXG4gICAgY29uc3QgZmlsZXMgPSBhd2FpdCBnbG9iQXN5bmMocGF0aC5qb2luKHNzckNvbmZpZ1BhdGgsIHJ1bnRpbWVQYXRoKFwiKiovKi50c1wiKSkpO1xuXG4gICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICB0cnkge1xuICAgICAgICAvLyBpbXBvcnRNZW1iZXJz66W8IOyCrOyaqe2VmOuptCDtjIzsnbzsnZggc2lkZSBlZmZlY3QocmVnaXN0ZXJTU1Ig7Zi47LacKeqwgCDsi6TtlonrkKhcbiAgICAgICAgYXdhaXQgaW1wb3J0TWVtYmVycyhmaWxlKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihgRmFpbGVkIHRvIGxvYWQgU1NSIHJvdXRlOiAke2ZpbGV9YCwgZSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIOyLpOygnCDsi7Htgazrpbwg7IiY7ZaJ7ZWY64qUIOuzuOyytOyeheuLiOuLpC5cbiAgICog67OA6rK965CcIO2MjOydvOuTpOydhCDtg4DsnoXrs4TroZwg67aE66WY7ZWY6rOgIOqwgSDtg4DsnoXsl5Ag66ee64qUIOyVoeyFmOydhCDsi6Ttlontlanri4jri6QuXG4gICAqIEBwYXJhbSBkaWZmRmlsZVBhdGhzIC0g67OA6rK965CcIO2MjOydvOuTpOydmCDsoIjrjIAg6rK966GcIOuqqeuhnVxuICAgKiBAcmV0dXJucyBkaWZmVHlwZXMgLSDrs4Dqsr3rkJwg7YyM7J287J2YIO2DgOyehSDrqqnroZ0gKGVudGl0eSwgdHlwZXMsIG1vZGVsIOuTsSlcbiAgICovXG4gIGFzeW5jIGRvU3luY0FjdGlvbnMoZGlmZkZpbGVQYXRoczogQWJzb2x1dGVQYXRoW10pOiBQcm9taXNlPHsgZGlmZlR5cGVzOiBzdHJpbmdbXSB9PiB7XG4gICAgY29uc3QgZGlmZkdyb3VwcyA9IHRoaXMuY2FsY3VsYXRlRGlmZkdyb3VwcyhkaWZmRmlsZVBhdGhzKTtcbiAgICBjb25zdCBkaWZmVHlwZXMgPSBPYmplY3Qua2V5cyhkaWZmR3JvdXBzKSBhcyBGaWxlVHlwZVtdO1xuXG4gICAgLy8gU2luZ2xlIHNvdXJjZSBvZiB0cnV0aOqwgCDrs4Dqsr3rkJwg6rK97JqwXG4gICAgaWYgKGRpZmZUeXBlcy5pbmNsdWRlcyhcImVudGl0eVwiKSB8fCBkaWZmVHlwZXMuaW5jbHVkZXMoXCJ0eXBlc1wiKSkge1xuICAgICAgYXdhaXQgdGhpcy5oYW5kbGVUcnV0aFNvdXJjZUNoYW5nZXMoZGlmZkdyb3VwcywgZGlmZlR5cGVzKTtcbiAgICB9XG5cbiAgICAvLyDtg4Dqsp/snLzroZwg67O17IKs66eMIO2VmOuptCDrkJjripQg7YyM7J287J20IOuzgOqyveuQnCDqsr3smrBcbiAgICBpZiAoXG4gICAgICBkaWZmVHlwZXMuaW5jbHVkZXMoXCJ0eXBlc1wiKSB8fFxuICAgICAgZGlmZlR5cGVzLmluY2x1ZGVzKFwiZnVuY3Rpb25zXCIpIHx8XG4gICAgICBkaWZmVHlwZXMuaW5jbHVkZXMoXCJnZW5lcmF0ZWRcIilcbiAgICApIHtcbiAgICAgIGF3YWl0IHRoaXMuaGFuZGxlU3luY2FibGVGaWxlQ2hhbmdlcyhkaWZmR3JvdXBzKTtcbiAgICB9XG5cbiAgICAvLyDrqqjrjbgv7ZSE66CI7J6EIOq1rO2YhOyytOqwgCDrs4Dqsr3rkJwg6rK97JqwXG4gICAgaWYgKGRpZmZUeXBlcy5pbmNsdWRlcyhcIm1vZGVsXCIpIHx8IGRpZmZUeXBlcy5pbmNsdWRlcyhcImZyYW1lXCIpKSB7XG4gICAgICBhd2FpdCB0aGlzLmhhbmRsZUltcGxlbWVudGF0aW9uQ2hhbmdlcyhkaWZmR3JvdXBzKTtcbiAgICB9XG5cbiAgICAvLyDshKTsoJUg7YyM7J287J20IOuzgOqyveuQnCDqsr3smrBcbiAgICBpZiAoZGlmZlR5cGVzLmluY2x1ZGVzKFwiY29uZmlnXCIpKSB7XG4gICAgICBhd2FpdCBTeW5jZXJBY3Rpb25zLmFjdGlvblN5bmNDb25maWcoKTtcbiAgICB9XG5cbiAgICAvLyDsm4ztgaztlIzroZzsmrAg7YyM7J287J20IOuzgOqyveuQnCDqsr3smrBcbiAgICBpZiAoZGlmZlR5cGVzLmluY2x1ZGVzKFwid29ya2Zsb3dcIikpIHtcbiAgICAgIGF3YWl0IHRoaXMuYXV0b2xvYWRXb3JrZmxvd3MoKTtcbiAgICB9XG5cbiAgICAvLyBpMThuIOq0gOugqCDtjIzsnbzsnbQg67OA6rK965CcIOqyveyasFxuICAgIC8vIC0gaTE4bi8qLnRzOiBsb2NhbGUg67KI7JetIO2MjOydvFxuICAgIC8vIC0gZW50aXR5Lmpzb246IGVudGl0eSBsYWJlbHNcbiAgICAvLyAtIHNvbmFtdS5jb25maWcudHM6IGkxOG4g7ISk7KCVIChkZWZhdWx0TG9jYWxlLCBzdXBwb3J0ZWRMb2NhbGVzKVxuICAgIGlmIChcbiAgICAgIGRpZmZUeXBlcy5pbmNsdWRlcyhcImkxOG5cIikgfHxcbiAgICAgIGRpZmZUeXBlcy5pbmNsdWRlcyhcImVudGl0eVwiKSB8fFxuICAgICAgZGlmZlR5cGVzLmluY2x1ZGVzKFwiY29uZmlnXCIpXG4gICAgKSB7XG4gICAgICBhd2FpdCB0aGlzLnN5bmNTRCgpO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBkaWZmVHlwZXMsXG4gICAgfTtcbiAgfVxuXG4gIGNhbGN1bGF0ZURpZmZHcm91cHMoZGlmZkZpbGVzOiBBYnNvbHV0ZVBhdGhbXSk6IERpZmZHcm91cHMge1xuICAgIGNvbnN0IGZpbGVUeXBlcyA9IE9iamVjdC5rZXlzKGNoZWNrc3VtUGF0dGVybkdyb3VwKSBhcyBGaWxlVHlwZVtdO1xuXG4gICAgcmV0dXJuIGdyb3VwKGRpZmZGaWxlcywgKGZpbGVQYXRoKSA9PiB7XG4gICAgICAvLyDsoIjrjIAg6rK966Gc7JeQ7IScIHNyYy/roZwg7Iuc7J6R7ZWY64qUIOyDgeuMgCDqsr3roZwg67aA67aE7J2EIOy2lOy2nO2VqeuLiOuLpC5cbiAgICAgIGNvbnN0IHNyY0luZGV4ID0gZmlsZVBhdGguaW5kZXhPZihcIi9zcmMvXCIpO1xuICAgICAgaWYgKHNyY0luZGV4ID09PSAtMSkgcmV0dXJuIFwidW5rbm93blwiO1xuICAgICAgY29uc3QgcmVsYXRpdmVQYXRoID0gZmlsZVBhdGguc2xpY2Uoc3JjSW5kZXggKyAxKTsgLy8gXCJzcmMvLi4uXCIg7ZiV7YOcXG5cbiAgICAgIGZvciAoY29uc3QgZmlsZVR5cGUgb2YgZmlsZVR5cGVzKSB7XG4gICAgICAgIGlmIChtaW5pbWF0Y2gocmVsYXRpdmVQYXRoLCBjaGVja3N1bVBhdHRlcm5Hcm91cFtmaWxlVHlwZV0pKSB7XG4gICAgICAgICAgcmV0dXJuIGZpbGVUeXBlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gXCJ1bmtub3duXCI7XG4gICAgfSkgYXMgdW5rbm93biBhcyBEaWZmR3JvdXBzO1xuICB9XG5cbiAgYXN5bmMgaGFuZGxlVHJ1dGhTb3VyY2VDaGFuZ2VzKGRpZmZHcm91cHM6IERpZmZHcm91cHMsIGRpZmZUeXBlczogc3RyaW5nW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBOYWl0ZS50KFwiaGFuZGxlVHJ1dGhTb3VyY2VDaGFuZ2VzXCIsIHsgZGlmZkdyb3VwcywgZGlmZlR5cGVzIH0pO1xuXG4gICAgYXdhaXQgRW50aXR5TWFuYWdlci5yZWxvYWQoKTtcblxuICAgIC8vIHR5cGVzIOyDneyEsShlbnRpdHkg7IOI66GcIOy2lOqwgOuQnCDqsr3smrApXG4gICAgLy8gcGFyZW50SWTqsIAg7JeG6rOgLCB0eXBlc+qwgCDsl4bripQg6rK97Jqw7JeQ66eMIOyDneyEsVxuICAgIGNvbnN0IGVudGl0eVBhdGggPSBkaWZmR3JvdXBzLmVudGl0eT8uYXQoMCk7XG4gICAgaWYgKGVudGl0eVBhdGggIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgZW50aXR5SWQgPSBFbnRpdHlNYW5hZ2VyLmdldEVudGl0eUlkRnJvbVBhdGgoZW50aXR5UGF0aCk7XG4gICAgICBjb25zdCBlbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCk7XG4gICAgICAvLyDtlITroZzsoJ3tirjsl5Ag7IOd7ISx65CY7Ja07JW8IO2VmOuKlCAudHMg7YyM7J287J2YIOqyveuhnOyeheuLiOuLpC5cbiAgICAgIGNvbnN0IHR5cGVGaWxlUGF0aCA9IHBhdGguam9pbihcbiAgICAgICAgU29uYW11LmFwaVJvb3RQYXRoLFxuICAgICAgICBgc3JjL2FwcGxpY2F0aW9uLyR7ZW50aXR5Lm5hbWVzLmZzfS8ke2VudGl0eS5uYW1lcy5mc30udHlwZXMudHNgLFxuICAgICAgKTtcbiAgICAgIGlmIChlbnRpdHkucGFyZW50SWQgPT09IHVuZGVmaW5lZCAmJiAhKGF3YWl0IGV4aXN0cyh0eXBlRmlsZVBhdGgpKSkge1xuICAgICAgICBhd2FpdCBnZW5lcmF0ZVRlbXBsYXRlKFwiaW5pdF90eXBlc1wiLCB7IGVudGl0eUlkIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIGF3YWl0IFN5bmNlckFjdGlvbnMuYWN0aW9uR2VuZXJhdGVTY2hlbWFzKCk7XG5cbiAgICBkaWZmR3JvdXBzLmdlbmVyYXRlZCA9IHVuaXF1ZShbXG4gICAgICAuLi4oZGlmZkdyb3Vwcy5nZW5lcmF0ZWQgPz8gW10pLFxuICAgICAgcGF0aC5qb2luKFNvbmFtdS5hcGlSb290UGF0aCwgXCJzcmMvYXBwbGljYXRpb24vc29uYW11LmdlbmVyYXRlZC50c1wiKSBhcyBBYnNvbHV0ZVBhdGgsXG4gICAgXSk7XG4gICAgZGlmZlR5cGVzLnB1c2goXCJnZW5lcmF0ZWRcIik7XG4gIH1cblxuICBhc3luYyBoYW5kbGVTeW5jYWJsZUZpbGVDaGFuZ2VzKGRpZmZHcm91cHM6IERpZmZHcm91cHMpOiBQcm9taXNlPEZpbGVUeXBlW10+IHtcbiAgICBjb25zdCB0c1BhdGhzID0gdW5pcXVlKFtcbiAgICAgIC4uLihkaWZmR3JvdXBzLnR5cGVzID8/IFtdKSxcbiAgICAgIC4uLihkaWZmR3JvdXBzLmZ1bmN0aW9ucyA/PyBbXSksXG4gICAgICAuLi4oZGlmZkdyb3Vwcy5nZW5lcmF0ZWQgPz8gW10pLFxuICAgIF0pO1xuICAgIE5haXRlLnQoXCJoYW5kbGVTeW5jYWJsZUZpbGVDaGFuZ2VzXCIsIHsgZGlmZkdyb3VwcyB9KTtcblxuICAgIC8vIGNvbnNvbGUubG9nKFxuICAgIC8vICAgY2hhbGsuZ3JheShcbiAgICAvLyAgICAgYFtQcm9jZXNzaW5nXSBIYW5kbGluZyB0eXBlcy9mdW5jdGlvbnMvZ2VuZXJhdGVkIGNoYW5nZXM6ICR7dHNQYXRocy5tYXAoKHApID0+IHBhdGgucmVsYXRpdmUoU29uYW11LmFwaVJvb3RQYXRoLCBwKSkuam9pbihcIiwgXCIpfWBcbiAgICAvLyAgIClcbiAgICAvLyApO1xuXG4gICAgYXdhaXQgU3luY2VyQWN0aW9ucy5hY3Rpb25TeW5jRmlsZXNUb1RhcmdldHModHNQYXRocyk7XG5cbiAgICByZXR1cm4gW107XG4gIH1cblxuICBhc3luYyBoYW5kbGVJbXBsZW1lbnRhdGlvbkNoYW5nZXMoZGlmZkdyb3VwczogRGlmZkdyb3Vwcyk6IFByb21pc2U8dm9pZD4ge1xuICAgIE5haXRlLnQoXCJoYW5kbGVJbXBsZW1lbnRhdGlvbkNoYW5nZXNcIiwgeyBkaWZmR3JvdXBzIH0pO1xuICAgIGNvbnN0IG1lcmdlZEdyb3VwID0gWy4uLihkaWZmR3JvdXBzLm1vZGVsID8/IFtdKSwgLi4uKGRpZmZHcm91cHMuZnJhbWUgPz8gW10pXTtcblxuICAgIC8vIGNvbnNvbGUubG9nKFxuICAgIC8vICAgY2hhbGsuZ3JheShcbiAgICAvLyAgICAgYFtQcm9jZXNzaW5nXSBIYW5kbGluZyBtb2RlbC9mcmFtZSBjaGFuZ2VzOiAke21lcmdlZEdyb3VwLm1hcCgocCkgPT4gcGF0aC5yZWxhdGl2ZShTb25hbXUuYXBpUm9vdFBhdGgsIHApKS5qb2luKFwiLCBcIil9YFxuICAgIC8vICAgKVxuICAgIC8vICk7XG5cbiAgICAvLyBnZW5lcmF0ZWRfaHR0cC50ZW1wbGF0ZS50c+yXkOyEnCBzeW5jZXIudHlwZXPrpbwg7JSB64uI64ukLlxuICAgIC8vIHNlcnZpY2UudGVtcGxhdGUudHPsl5DshJwgc3luY2VyLmFwaXPrpbwg7JSB64uI64ukLlxuICAgIGF3YWl0IHRoaXMuYXV0b2xvYWRNb2RlbHMoKTtcbiAgICBhd2FpdCB0aGlzLmF1dG9sb2FkVHlwZXMoKTtcbiAgICBhd2FpdCB0aGlzLmF1dG9sb2FkQXBpcygpO1xuXG4gICAgY29uc3QgcGFyYW1zOiB7XG4gICAgICBuYW1lc1JlY29yZDogRW50aXR5TmFtZXNSZWNvcmQ7XG4gICAgfVtdID0gbWVyZ2VkR3JvdXAubWFwKChtb2RlbFBhdGgpID0+IHtcbiAgICAgIGlmIChtb2RlbFBhdGguZW5kc1dpdGgoXCIubW9kZWwudHNcIikgfHwgbW9kZWxQYXRoLmVuZHNXaXRoKFwiLmZyYW1lLnRzXCIpKSB7XG4gICAgICAgIGNvbnN0IGVudGl0eUlkID0gRW50aXR5TWFuYWdlci5nZXRFbnRpdHlJZEZyb21QYXRoKG1vZGVsUGF0aCk7XG4gICAgICAgIGFzc2VydChlbnRpdHlJZCk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgbmFtZXNSZWNvcmQ6IEVudGl0eU1hbmFnZXIuZ2V0TmFtZXNGcm9tSWQoZW50aXR5SWQpLFxuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwibm90IHJlYWNoYWJsZVwiKTtcbiAgICB9KTtcblxuICAgIGF3YWl0IFN5bmNlckFjdGlvbnMuYWN0aW9uR2VuZXJhdGVTZXJ2aWNlcyhwYXJhbXMpO1xuICAgIGF3YWl0IFN5bmNlckFjdGlvbnMuYWN0aW9uR2VuZXJhdGVIdHRwcygpO1xuICAgIGF3YWl0IFN5bmNlckFjdGlvbnMuYWN0aW9uR2VuZXJhdGVTc3IoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDso7zslrTsp4Qg7JeU7Yuw7Yuw7JmAIO2FnO2UjOumvyDtgqTsl5Ag64yA7ZW0LCDsg53shLHrkJwg7L2U65Oc6rCAIOyhtOyerO2VmOuKlOyngCDtmZXsnbjtlanri4jri6QuXG4gICAqIEBwYXJhbSBlbnRpdHlJZCDsl5Tti7Dti7AgSURcbiAgICogQHBhcmFtIHRlbXBsYXRlS2V5IO2FnO2UjOumvyDtgqRcbiAgICogQHBhcmFtIGVudW1JZCDsl7TqsbDtmJUgSURcbiAgICogQHJldHVybnMg7IOd7ISx65CcIOy9lOuTnOqwgCDsobTsnqztlZjripTsp4Ag7Jes67aAXG4gICAqL1xuICBhc3luYyBjaGVja0V4aXN0c0dlbkNvZGUoXG4gICAgZW50aXR5SWQ6IHN0cmluZyxcbiAgICB0ZW1wbGF0ZUtleTogVGVtcGxhdGVLZXksXG4gICAgZW51bUlkPzogc3RyaW5nLFxuICApOiBQcm9taXNlPHsgc3ViUGF0aDogc3RyaW5nOyBmdWxsUGF0aDogc3RyaW5nOyBpc0V4aXN0czogYm9vbGVhbiB9PiB7XG4gICAgY29uc3QgeyB0YXJnZXQsIHBhdGg6IGdlblBhdGggfSA9IFRlbXBsYXRlTWFuYWdlci5nZXQodGVtcGxhdGVLZXkpLmdldFRhcmdldEFuZFBhdGgoXG4gICAgICBFbnRpdHlNYW5hZ2VyLmdldE5hbWVzRnJvbUlkKGVudGl0eUlkKSxcbiAgICAgIGVudW1JZCxcbiAgICApO1xuXG4gICAgY29uc3Qgc3ViUGF0aCA9IHBhdGguam9pbih0YXJnZXQsIGdlblBhdGgpO1xuICAgIGNvbnN0IGZ1bGxQYXRoID0gcGF0aC5qb2luKFNvbmFtdS5hcHBSb290UGF0aCwgc3ViUGF0aCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHN1YlBhdGgsXG4gICAgICBmdWxsUGF0aCxcbiAgICAgIGlzRXhpc3RzOiBhd2FpdCBleGlzdHMoZnVsbFBhdGgpLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICog7KO87Ja07KeEIOyXlO2LsO2LsOyZgCDsl7TqsbDtmJXsl5Ag64yA7ZW0LCDsg53shLHrkJwg7L2U65Oc6rCAIOyhtOyerO2VmOuKlOyngCDtmZXsnbjtlanri4jri6QuXG4gICAqIEBwYXJhbSBlbnRpdHlJZCDsl5Tti7Dti7AgSURcbiAgICogQHBhcmFtIGVudW1zIOyXtOqxsO2YlSDroIjsnbTruJRcbiAgICogQHJldHVybnMg7IOd7ISx65CcIOy9lOuTnOqwgCDsobTsnqztlZjripTsp4Ag7Jes67aAXG4gICAqL1xuICBhc3luYyBjaGVja0V4aXN0cyhcbiAgICBlbnRpdHlJZDogc3RyaW5nLFxuICAgIGVudW1zOiB7XG4gICAgICBbbmFtZTogc3RyaW5nXTogei5ab2RFbnVtO1xuICAgIH0sXG4gICk6IFByb21pc2U8UmVjb3JkPGAke1RlbXBsYXRlS2V5fSR7c3RyaW5nfWAsIGJvb2xlYW4+PiB7XG4gICAgY29uc3Qga2V5czogVGVtcGxhdGVLZXlbXSA9IFRlbXBsYXRlS2V5Lm9wdGlvbnM7XG4gICAgY29uc3QgbmFtZXMgPSBFbnRpdHlNYW5hZ2VyLmdldE5hbWVzRnJvbUlkKGVudGl0eUlkKTtcbiAgICBjb25zdCBlbnVtc0tleXMgPSBPYmplY3Qua2V5cyhlbnVtcykuZmlsdGVyKChuYW1lKSA9PiBuYW1lICE9PSBuYW1lcy5jb25zdGFudCk7XG5cbiAgICByZXR1cm4gYXdhaXQgcmVkdWNlQXN5bmMoXG4gICAgICBrZXlzLFxuICAgICAgYXN5bmMgKHJlc3VsdCwga2V5KSA9PiB7XG4gICAgICAgIGNvbnN0IHRwbCA9IFRlbXBsYXRlTWFuYWdlci5nZXQoa2V5KTtcbiAgICAgICAgaWYgKGtleS5zdGFydHNXaXRoKFwidmlld19lbnVtc1wiKSkge1xuICAgICAgICAgIGF3YWl0IG1hcEFzeW5jKGVudW1zS2V5cywgYXN5bmMgKGNvbXBvbmVudElkKSA9PiB7XG4gICAgICAgICAgICBjb25zdCB7IHRhcmdldCwgcGF0aDogcCB9ID0gdHBsLmdldFRhcmdldEFuZFBhdGgobmFtZXMsIGNvbXBvbmVudElkKTtcbiAgICAgICAgICAgIHJlc3VsdFtgJHtrZXl9X18ke2NvbXBvbmVudElkfWBdID0gYXdhaXQgZXhpc3RzKFxuICAgICAgICAgICAgICBwYXRoLmpvaW4oU29uYW11LmFwcFJvb3RQYXRoLCB0YXJnZXQsIHApLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgeyB0YXJnZXQsIHBhdGg6IHAgfSA9IHRwbC5nZXRUYXJnZXRBbmRQYXRoKG5hbWVzKTtcbiAgICAgICAgY29uc3QgeyB0YXJnZXRzIH0gPSBTb25hbXUuY29uZmlnLnN5bmM7XG4gICAgICAgIGlmICh0YXJnZXQuaW5jbHVkZXMoXCI6dGFyZ2V0XCIpKSB7XG4gICAgICAgICAgYXdhaXQgbWFwQXN5bmModGFyZ2V0cywgYXN5bmMgKHQpID0+IHtcbiAgICAgICAgICAgIHJlc3VsdFtgJHtrZXl9X18ke3R9YF0gPSBhd2FpdCBleGlzdHMoXG4gICAgICAgICAgICAgIHBhdGguam9pbihTb25hbXUuYXBwUm9vdFBhdGgsIHRhcmdldC5yZXBsYWNlKFwiOnRhcmdldFwiLCB0KSwgcCksXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJlc3VsdFtrZXldID0gYXdhaXQgZXhpc3RzKHBhdGguam9pbihTb25hbXUuYXBwUm9vdFBhdGgsIHRhcmdldCwgcCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH0sXG4gICAgICB7fSBhcyBSZWNvcmQ8YCR7VGVtcGxhdGVLZXl9JHtzdHJpbmd9YCwgYm9vbGVhbj4sXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDtlZjsnITtmLjtmZjsmqkg7ZSE66Gd7IucIOuplOyGjOuTnOyeheuLiOuLpC5cbiAgICovXG4gIGFzeW5jIGNyZWF0ZUVudGl0eShmb3JtOiBUZW1wbGF0ZU9wdGlvbnNbXCJlbnRpdHlcIl0pIHtcbiAgICByZXR1cm4gYXdhaXQgY3JlYXRlRW50aXR5KGZvcm0pO1xuICB9XG5cbiAgLyoqXG4gICAqIO2VmOychO2YuO2ZmOyaqSDtlITroZ3si5wg66mU7IaM65Oc7J6F64uI64ukLlxuICAgKi9cbiAgYXN5bmMgZGVsRW50aXR5KGVudGl0eUlkOiBzdHJpbmcpOiBQcm9taXNlPHsgZGVsUGF0aHM6IHN0cmluZ1tdIH0+IHtcbiAgICByZXR1cm4gYXdhaXQgZGVsRW50aXR5KGVudGl0eUlkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDtlZjsnITtmLjtmZjsmqkg7ZSE66Gd7IucIOuplOyGjOuTnOyeheuLiOuLpC5cbiAgICovXG4gIGFzeW5jIGdlbmVyYXRlVGVtcGxhdGU8VCBleHRlbmRzIFRlbXBsYXRlS2V5PihcbiAgICBrZXk6IFQsXG4gICAgdGVtcGxhdGVPcHRpb25zOiBUZW1wbGF0ZU9wdGlvbnNbVF0sXG4gICAgX2dlbmVyYXRlT3B0aW9ucz86IEdlbmVyYXRlT3B0aW9ucyxcbiAgKTogUHJvbWlzZTxBYnNvbHV0ZVBhdGhbXT4ge1xuICAgIHJldHVybiBhd2FpdCBnZW5lcmF0ZVRlbXBsYXRlKGtleSwgdGVtcGxhdGVPcHRpb25zLCBfZ2VuZXJhdGVPcHRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDtlZjsnITtmLjtmZjsmqkg7ZSE66Gd7IucIOuplOyGjOuTnOyeheuLiOuLpC5cbiAgICovXG4gIGFzeW5jIHJlbmRlclRlbXBsYXRlPFQgZXh0ZW5kcyBrZXlvZiBUZW1wbGF0ZU9wdGlvbnM+KFxuICAgIGtleTogVCxcbiAgICB0ZW1wbGF0ZU9wdGlvbnM6IFRlbXBsYXRlT3B0aW9uc1tUXSxcbiAgKTogUHJvbWlzZTxQYXRoQW5kQ29kZVtdPiB7XG4gICAgcmV0dXJuIGF3YWl0IHJlbmRlclRlbXBsYXRlKGtleSwgdGVtcGxhdGVPcHRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDtlZjsnITtmLjtmZjsmqkg7ZSE66Gd7IucIOuplOyGjOuTnOyeheuLiOuLpC5cbiAgICovXG4gIGFzeW5jIHJlbmV3Q2hlY2tzdW1zKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiBhd2FpdCByZW5ld0NoZWNrc3VtcygpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNEKFNvbmFtdSBEaWN0aW9uYXJ5KSDthZztlIzrpr/snYQg7IOd7ISx7ZWp64uI64ukLlxuICAgKi9cbiAgYXN5bmMgc3luY1NEKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgdGFyZ2V0cyB9ID0gU29uYW11LmNvbmZpZy5zeW5jO1xuICAgIGNvbnN0IGkxOG5Db25maWcgPSBTb25hbXUuY29uZmlnLmkxOG47XG5cbiAgICBjb25zdCB0YXJnZXRMaXN0ID0gW1wiYXBpXCIsIC4uLnRhcmdldHNdIGFzIChcImFwaVwiIHwgXCJ3ZWJcIiB8IFwiYXBwXCIpW107XG5cbiAgICBjb25zdCBhcGlJMThuRGlyID0gcGF0aC5qb2luKFNvbmFtdS5hcHBSb290UGF0aCwgU29uYW11LmNvbmZpZy5hcGkuZGlyLCBcInNyYy9pMThuXCIpO1xuXG4gICAgZm9yIChjb25zdCB0YXJnZXQgb2YgdGFyZ2V0TGlzdCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gd2ViL2FwcOydmCDqsr3smrAgbG9jYWxlIO2MjOydvOuTpOydhCBhcGnsl5DshJwg67O17IKsXG4gICAgICAgIGlmICh0YXJnZXQgIT09IFwiYXBpXCIpIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLnN5bmNMb2NhbGVGaWxlcyh0YXJnZXQsIGFwaUkxOG5EaXIsIGkxOG5Db25maWcuc3VwcG9ydGVkTG9jYWxlcyk7XG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCBnZW5lcmF0ZVRlbXBsYXRlKFwic2RcIiwgeyB0YXJnZXQgfSwgeyBvdmVyd3JpdGU6IHRydWUgfSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYEZhaWxlZCB0byBnZW5lcmF0ZSBTRCB0ZW1wbGF0ZSBmb3IgJHt0YXJnZXR9OmAsIGUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBhcGnsnZggbG9jYWxlIO2MjOydvOydhCB3ZWIvYXBw7Jy866GcIOuzteyCrO2VqeuLiOuLpC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgc3luY0xvY2FsZUZpbGVzKFxuICAgIHRhcmdldDogc3RyaW5nLFxuICAgIGFwaUkxOG5EaXI6IHN0cmluZyxcbiAgICBsb2NhbGVzOiBzdHJpbmdbXSxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgdGFyZ2V0STE4bkRpciA9IHBhdGguam9pbihTb25hbXUuYXBwUm9vdFBhdGgsIHRhcmdldCwgXCJzcmMvaTE4blwiKTtcblxuICAgIC8vIOuUlOugie2GoOumrOqwgCDsl4bsnLzrqbQg7IOd7ISxXG4gICAgYXdhaXQgbWtkaXIodGFyZ2V0STE4bkRpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cbiAgICBmb3IgKGNvbnN0IGxvY2FsZSBvZiBsb2NhbGVzKSB7XG4gICAgICBjb25zdCBzb3VyY2VGaWxlID0gcGF0aC5qb2luKGFwaUkxOG5EaXIsIGAke2xvY2FsZX0udHNgKTtcbiAgICAgIGNvbnN0IHRhcmdldEZpbGUgPSBwYXRoLmpvaW4odGFyZ2V0STE4bkRpciwgYCR7bG9jYWxlfS50c2ApO1xuXG4gICAgICBjb25zdCBzeW5jSGVhZGVyID0gW1xuICAgICAgICBcIi8qKlwiLFxuICAgICAgICBcIiAqIEBnZW5lcmF0ZWRcIixcbiAgICAgICAgXCIgKiBBUEnsl5DshJwg64+Z6riw7ZmU65CcIO2MjOydvOyeheuLiOuLpC4g7KeB7KCRIOyImOygle2VmOyngCDrp4jshLjsmpQuXCIsXG4gICAgICAgIFwiICovXCIsXG4gICAgICBdLmpvaW4oXCJcXG5cIik7XG4gICAgICBhd2FpdCBjb3B5RmlsZVdpdGhSZXBsYWNlQ29yZVRvU2hhcmVkKHNvdXJjZUZpbGUsIHRhcmdldEZpbGUsIHN5bmNIZWFkZXIpO1xuICAgICAgIWlzVGVzdCgpICYmXG4gICAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmJvbGQoXCJDb3BpZWQ6IFwiKSArIGNoYWxrLmN5YW4oYCR7dGFyZ2V0fS9zcmMvaTE4bi8ke2xvY2FsZX0udHNgKSk7XG4gICAgfVxuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7a0JBV21EO2NBQ1o7c0JBQ2tCO3FCQUVlO2FBQ2pDO3dCQUV3QjthQUVsQjttQkFFZ0I7b0JBQ1Y7a0JBQ047Z0JBQytCO3FCQUVYO2dCQUNXO3NCQUNSO3lCQUNOO3FCQUNnQztxQkFFYjtzQkFFL0I7Q0FNckMsU0FBYixNQUFvQjtFQUNsQixPQUFtQixFQUFFO0VBQ3JCLFFBQXFCLEVBQUU7RUFDdkIsU0FBdUIsRUFBRTtFQUN6QixZQUE2QyxJQUFJLEtBQUs7RUFD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
424
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luY2VyLmpzIiwibmFtZXMiOlsiU3luY2VyQWN0aW9ucy5hY3Rpb25Db3B5U2hhcmVkVG9UYXJnZXRzSWZOb3RFeGlzdHMiLCJTeW5jZXJBY3Rpb25zLmFjdGlvbkdlbmVyYXRlU3NyRW50cnlTZXJ2ZXJJZk5vdEV4aXN0cyIsInN5bmNUcmlnZ2VyaW5nUGF0aHM6IEFic29sdXRlUGF0aFtdIiwiU3luY2VyQWN0aW9ucy5hY3Rpb25HZW5lcmF0ZUluaXRpYWxUeXBlcyIsIlN5bmNlckFjdGlvbnMuYWN0aW9uU3luY0ZpbGVzVG9UYXJnZXRzIiwiU3luY2VyQWN0aW9ucy5hY3Rpb25HZW5lcmF0ZVNjaGVtYXMiLCJwYXJhbXM6IHtcbiAgICAgIG5hbWVzUmVjb3JkOiBFbnRpdHlOYW1lc1JlY29yZDtcbiAgICB9W10iLCJTeW5jZXJBY3Rpb25zLmFjdGlvbkdlbmVyYXRlU2VydmljZXMiLCJTeW5jZXJBY3Rpb25zLmFjdGlvbkdlbmVyYXRlSHR0cHMiLCJTeW5jZXJBY3Rpb25zLmFjdGlvbkdlbmVyYXRlU3NyUXVlcmllcyIsIlN5bmNlckFjdGlvbnMuYWN0aW9uU3luY0NvbmZpZyIsIlN5bmNlckFjdGlvbnMuYWN0aW9uU3luY1NvbmFtdURpY3Rpb25hcnkiLCJrZXlzOiBUZW1wbGF0ZUtleVtdIiwicCIsInRhcmdldCJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zeW5jZXIvc3luY2VyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSBcImV2ZW50c1wiO1xuaW1wb3J0IHsgdW5saW5rIH0gZnJvbSBcImZzL3Byb21pc2VzXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuXG5pbXBvcnQgeyBob3QgfSBmcm9tIFwiQHNvbmFtdS1raXQvaG1yLWhvb2tcIjtcbmltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIjtcbmltcG9ydCB7IG1pbmltYXRjaCB9IGZyb20gXCJtaW5pbWF0Y2hcIjtcbmltcG9ydCB7IGdyb3VwLCB1bmlxdWUgfSBmcm9tIFwicmFkYXNoaVwiO1xuaW1wb3J0IHsgdHlwZSB6IH0gZnJvbSBcInpvZFwiO1xuXG5pbXBvcnQgeyByZWdpc3RlcmVkQXBpcyB9IGZyb20gXCIuLi9hcGkvZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgU29uYW11IH0gZnJvbSBcIi4uL2FwaS9zb25hbXVcIjtcbmltcG9ydCB7IEVudGl0eU1hbmFnZXIgfSBmcm9tIFwiLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyB0eXBlIEVudGl0eU5hbWVzUmVjb3JkIH0gZnJvbSBcIi4uL2VudGl0eS9lbnRpdHktbWFuYWdlclwiO1xuaW1wb3J0IHsgTmFpdGUgfSBmcm9tIFwiLi4vbmFpdGUvbmFpdGVcIjtcbmltcG9ydCB7IHR5cGUgV29ya2Zsb3dNZXRhZGF0YSB9IGZyb20gXCIuLi90YXNrcy9kZWNvcmF0b3JcIjtcbmltcG9ydCB7IFRlbXBsYXRlTWFuYWdlciB9IGZyb20gXCIuLi90ZW1wbGF0ZS90ZW1wbGF0ZS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyB0eXBlIEdlbmVyYXRlT3B0aW9ucywgdHlwZSBQYXRoQW5kQ29kZSB9IGZyb20gXCIuLi90eXBlcy90eXBlc1wiO1xuaW1wb3J0IHsgVGVtcGxhdGVLZXkgfSBmcm9tIFwiLi4vdHlwZXMvdHlwZXNcIjtcbmltcG9ydCB7IHR5cGUgVGVtcGxhdGVPcHRpb25zIH0gZnJvbSBcIi4uL3R5cGVzL3R5cGVzXCI7XG5pbXBvcnQgeyBtYXBBc3luYywgcmVkdWNlQXN5bmMgfSBmcm9tIFwiLi4vdXRpbHMvYXN5bmMtdXRpbHNcIjtcbmltcG9ydCB7IGNlbnRlclRleHQgfSBmcm9tIFwiLi4vdXRpbHMvY29uc29sZS11dGlsXCI7XG5pbXBvcnQgeyBpc1Rlc3QgfSBmcm9tIFwiLi4vdXRpbHMvY29udHJvbGxlclwiO1xuaW1wb3J0IHsgZXhpc3RzIH0gZnJvbSBcIi4uL3V0aWxzL2ZzLXV0aWxzXCI7XG5pbXBvcnQgeyB0eXBlIEFic29sdXRlUGF0aCB9IGZyb20gXCIuLi91dGlscy9wYXRoLXV0aWxzXCI7XG5pbXBvcnQgeyBydW5XaXRoR3JhY2VmdWxTaHV0ZG93biB9IGZyb20gXCIuLi91dGlscy9wcm9jZXNzLXV0aWxzXCI7XG5pbXBvcnQgeyBmaW5kQ2hhbmdlZEZpbGVzVXNpbmdDaGVja3N1bXMsIHJlbmV3Q2hlY2tzdW1zIH0gZnJvbSBcIi4vY2hlY2tzdW1cIjtcbmltcG9ydCB7IGdlbmVyYXRlVGVtcGxhdGUsIHJlbmRlclRlbXBsYXRlIH0gZnJvbSBcIi4vY29kZS1nZW5lcmF0b3JcIjtcbmltcG9ydCB7IGNyZWF0ZUVudGl0eSwgZGVsRW50aXR5IH0gZnJvbSBcIi4vZW50aXR5LW9wZXJhdGlvbnNcIjtcbmltcG9ydCB7IGdldENoZWNrc3VtUGF0dGVybkdyb3VwLCBnZXRDaGVja3N1bVBhdHRlcm5Hcm91cEluQWJzb2x1dGVQYXRoIH0gZnJvbSBcIi4vZmlsZS1wYXR0ZXJuc1wiO1xuaW1wb3J0IHsgdHlwZSBGaWxlVHlwZSB9IGZyb20gXCIuL2ZpbGUtcGF0dGVybnNcIjtcbmltcG9ydCB7IGxvYWRBcGlzLCBsb2FkTW9kZWxzLCBsb2FkVHlwZXMsIGxvYWRXb3JrZmxvd3MgfSBmcm9tIFwiLi9tb2R1bGUtbG9hZGVyXCI7XG5pbXBvcnQgeyB0eXBlIExvYWRlZEFwaXMsIHR5cGUgTG9hZGVkTW9kZWxzLCB0eXBlIExvYWRlZFR5cGVzIH0gZnJvbSBcIi4vbW9kdWxlLWxvYWRlclwiO1xuaW1wb3J0ICogYXMgU3luY2VyQWN0aW9ucyBmcm9tIFwiLi9zeW5jZXItYWN0aW9uc1wiO1xuXG50eXBlIERpZmZHcm91cHMgPSB7XG4gIFtrZXkgaW4gRmlsZVR5cGVdOiBBYnNvbHV0ZVBhdGhbXTtcbn07XG5cbmV4cG9ydCBjbGFzcyBTeW5jZXIge1xuICBhcGlzOiBMb2FkZWRBcGlzID0gW107XG4gIHR5cGVzOiBMb2FkZWRUeXBlcyA9IHt9O1xuICBtb2RlbHM6IExvYWRlZE1vZGVscyA9IHt9O1xuICB3b3JrZmxvd3M6IE1hcDxzdHJpbmcsIFdvcmtmbG93TWV0YWRhdGFbXT4gPSBuZXcgTWFwKCk7XG4gIGV2ZW50RW1pdHRlcjogRXZlbnRFbWl0dGVyID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gIC8qKlxuICAgKiDssrTtgazshKzsnbQg67OA6rK965CcIOu2gOu2hOyXkCDrjIDtlbQg7Iux7YGs66W8IOynhO2Wie2VqeuLiOuLpC5cbiAgICogZGV2IOyEnOuyhOqwgCDsspjsnYwg65a07J2EIOuVjCwgc29uYW11IHN5bmMg7ZWgIOuVjCDsi6TtlonrkKnri4jri6QuIOydtO2bhOyXkOuKlCBzeW5jRnJvbVdhdGNoZXIg6rK966Gc66W8IO2DgOyalC5cbiAgICogQHJldHVybnNcbiAgICovXG4gIGFzeW5jIHN5bmMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8g7LSI6riwIOu2gO2KuOyKpO2KuOueqSEg7JaY64Sk65Ok7J2AIGlkZW1wb3RlbnTtlZjqs6Ag6rCA67ON6riwIOuVjOusuOyXkCDrrLTsp4DshLEg7Iuk7ZaJ7ZW064+EIOuQqeuLiOuLpC5cbiAgICAvLyDslpjrhKTrk6TsnYAgc29uYW11LmxvY2vsl5Ag65Ok7Ja06rCA7KeA64+EIOyViuqzoCDrlLDrnbzshJwgSE1SIOqyveuhnOulvCDtg4Dsp4Drj4Qg7JWK64qUIOy5nOq1rOuTpOyeheuLiOuLpC5cbiAgICAvLyDqt7jrnpjshJwg7JWE66y0IOuVjOuCmCDqt7jrg6Ug64+M66Ck7KO866m0IOuQmOuKlOuNsCwgc3luY0Zyb21XYXRjaGVy7JeQ7IScIOunpOuyiCDtlZjripQg6rKD7J2AIOuCreu5hOydtOuLiCDsl6zquLDshJwg7ZWcIOuyiOunjCDtlanri4jri6QuXG4gICAgYXdhaXQgU3luY2VyQWN0aW9ucy5hY3Rpb25Db3B5U2hhcmVkVG9UYXJnZXRzSWZOb3RFeGlzdHMoKTtcbiAgICBhd2FpdCBTeW5jZXJBY3Rpb25zLmFjdGlvbkdlbmVyYXRlU3NyRW50cnlTZXJ2ZXJJZk5vdEV4aXN0cygpO1xuXG4gICAgLy8g67CU64CQIOqyg+ydtCDsl4bsnLzrqbQg6re464OlIOuEmOyWtOqwgOyalC5cbiAgICBjb25zdCBjaGFuZ2VkRmlsZXMgPSBhd2FpdCBmaW5kQ2hhbmdlZEZpbGVzVXNpbmdDaGVja3N1bXMoKTtcbiAgICBpZiAoY2hhbmdlZEZpbGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgY29uc29sZS5sb2coY2hhbGsuYmxhY2suYmdHcmVlbihjZW50ZXJUZXh0KFwiQWxsIGZpbGVzIGFyZSBzeW5jZWQhXCIpKSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8g7Jes6riw7IScIOyLpOygnCDsi7Htgawg64+Z7J6R7J2EIOyImO2Wie2VqeuLiOuLpC5cbiAgICAvLyDri6Trp4wg7Iux7YGsIOykkeyXkCDtlITroZzshLjsiqTqsIAg7KO97Jy866m0IOq8rOyXrOuyhOumrOq4sCDrlYzrrLjsl5AsXG4gICAgLy8g7Iuc6re464SQ7JeQ64+EIOyeoOyLnCDrsoTti7gg7IiYIOyeiOuKlCDtmZjqsr0g7IaN7JeQ7IScIOyLse2BrOulvCDsi6Ttlontlanri4jri6QuXG4gICAgYXdhaXQgcnVuV2l0aEdyYWNlZnVsU2h1dGRvd24oXG4gICAgICBhc3luYyAoKSA9PiB7XG4gICAgICAgIC8vIOyWmOqwgCDsi7Htgawg7J6R7JeFIOyImO2Wie2VmOuKlCDrs7jssrTsnoXri4jri6QuXG4gICAgICAgIGF3YWl0IHRoaXMuZG9TeW5jQWN0aW9ucyhjaGFuZ2VkRmlsZXMpO1xuXG4gICAgICAgIC8vIOyLse2BrCDslaHshZjsnbQg64Gd64KY66m0IO2VreyDgSDssrTtgazshKzsnYQg64uk7IucIOqwseyLoO2VqeuLiOuLpC5cbiAgICAgICAgYXdhaXQgcmVuZXdDaGVja3N1bXMoKTtcbiAgICAgIH0sXG4gICAgICB7IHdoZW5UaGlzSGFwcGVuczogXCJTSUdVU1IyXCIsIHdhaXRGb3JVcFRvOiAyMDAwMCB9LFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICog6rCV7KCcIO2SgC3si7Htgaw6IGxvY2vsnYQg66y07Iuc7ZWY6rOgIOyymOydjOu2gO2EsCDri6Tsi5wg7Iux7YGs7ZWp64uI64ukLlxuICAgKlxuICAgKiAqKuyCrOyaqeyymCoqOiBnaXQgcG9zdC1tZXJnZSBob29rLCBDSSwgZGV2IOyEnOuyhOydmCBgZmAg7ZWr7YKkLlxuICAgKiAqKuyLpO2MqCDslYjsoITshLEqKjog64+E7KSR7JeQIO2UhOuhnOyEuOyKpOqwgCDso73slrQgbG9jayDsl4bripQg7IOB7YOc66GcIOuCqOyVhOuPhCDrrLTtlbQg4oCUIOuLpOydjCBzeW5j7JeQ7IScXG4gICAqIGxvY2sg7JeG7Jy866m0IOyekOyXsOyKpOufveqyjCDtkoAt7Iux7YGs6rCAIO2KuOumrOqxsOuQmOyWtCDsg4ggbG9ja+ydtCDsnpHshLHrkKguXG4gICAqL1xuICBhc3luYyBmb3JjZVN5bmMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbG9ja1BhdGggPSBwYXRoLmpvaW4oU29uYW11LmFwaVJvb3RQYXRoLCBcInNvbmFtdS5sb2NrXCIpO1xuICAgIGlmIChhd2FpdCBleGlzdHMobG9ja1BhdGgpKSB7XG4gICAgICBhd2FpdCB1bmxpbmsobG9ja1BhdGgpO1xuICAgIH1cbiAgICBhd2FpdCB0aGlzLnN5bmMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXYXRjaGVy6rCAIGJhdGNo66GcIOuqqOydgCDrs4Dqsr0g7YyM7J2865Ok7JeQIOuMgO2VtCDtlZwg67KI7J2YIEhNUi9zeW5jIOyCrOydtO2BtOydhCDrj5Xri4jri6QuXG4gICAqXG4gICAqIEhNUuydgCBhcGkvc3JjIOyViOyXkOyEnCDsnbzslrTrgpjripQg66qo65OgIO2MjOydvOuTpOyXkCDrjIDtlbTshJwg7IiY7ZaJ7ZWp64uI64ukLlxuICAgKiBjaGVja3N1bVBhdHRlcm5Hcm91cCDrp6Tsua0g7Jes67aA7JmAIOustOq0gO2VmOqyjCBhcGkvc3JjIOyghOyytCDrjIDsg4HsnoXri4jri6QuXG4gICAqIOqwgOuguSBhcGkvc3JjL3V0aWxzL3N1YnNldC1sb2FkZXJzLnRzIOqwmeydgCDtjIzsnbzrj4Qg67OA6rK965CY66m0IEhNUuydgCDtlbTspI3ri4jri6QuXG4gICAqXG4gICAqIFN5bmPripQgY2hlY2tzdW1QYXR0ZXJuR3JvdXDsnLzroZwg66ek7Lmt65CY64qUIO2MjOydvOuTpOyXkCDrjIDtlbTshJzrp4wg7IiY7ZaJ7ZWp64uI64ukLlxuICAgKiDsl6zquLDsl5DripQgd2ViL3NyY+uCmCBhcHAvc3JjIOqwmeydgCDri6TrpbggdGFyZ2V07J2YIO2MjOydvOydtCDtj6ztlajrkKAg7IiYIOyeiOyKteuLiOuLpC5cbiAgICog7J2065+wIG5vbi1hcGkg6rK966Gc7J2YIO2MjOydvOuTpOydgCBITVLqs7zripQg7JWE66y0IOyDgeq0gOydtCDsl4bsnLzrr4DroZwsIGludmFsaWRhdGXsnYQg7ZWY7KeAIOyViuyKteuLiOuLpC5cbiAgICpcbiAgICogQHBhcmFtIGZpbGVFdmVudHMgLSBwYXRoIOKGkiBldmVudCDrp7UuIGV2ZW5064qUIFwiY2hhbmdlXCIgfCBcImFkZFwiLlxuICAgKi9cbiAgYXN5bmMgaG1yQW5kU3luYyhmaWxlRXZlbnRzOiBNYXA8QWJzb2x1dGVQYXRoLCBcImNoYW5nZVwiIHwgXCJhZGRcIj4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBobXJBY3Rpb25SZXF1aXJlZEV2ZW50cyA9IHRoaXMuZXh0cmFjdEhtckFjdGlvblJlcXVpcmVkRmlsZUV2ZW50cyhmaWxlRXZlbnRzKTtcbiAgICBjb25zdCBzeW5jVHJpZ2dlcmluZ1BhdGhzID0gYXdhaXQgdGhpcy5leHRyYWN0U3luY1RyaWdnZXJpbmdGaWxlRXZlbnRQYXRocyhmaWxlRXZlbnRzKTtcblxuICAgIC8vIEhNUiDsmIHsl606IO2MjOydvCDsnbTrsqTtirgg7KSRIGFwaeydmCDrqqjrk4gg6re4656Y7ZSE7JeQIOyeiOuKlCDtjIzsnbzrk6Tsl5Ag64yA7ZWcIOuzgOuPmeydgCBobXJBY3Rpb25SZXF1aXJlZEV2ZW50c+uhnCDsnqHtnpnri4jri6QuXG4gICAgLy8g7J20IOy5nOq1rOuTpOydgCBpbnZhbGlkYXRlIOyymOumrO2VtOykjeuLiOuLpC5cbiAgICAvLyDsnbQg7Zi47Lac7J2AIOyVhOuemCBzeW5j67O064ukIOustOyhsOqxtCDrqLzsoIAg7J287Ja064KY7JW8IO2VqeuLiOuLpCFcbiAgICAvLyDsmZzrg5DtlZjrqbQgc3luY+yXkOyEnOuKlCDrs4Dqsr3rkJwgbW9kZWwg7L2U65Oc66W8IOyDiOuhnCBpbXBvcnTtlbTshJwg7LKY66as7ZW07JW8IO2VmOuKlCDqsr3smrDrj4Qg7J6I6riwIOuVjOusuOyeheuLiOuLpC5cbiAgICBhd2FpdCB0aGlzLmludmFsaWRhdGVEZXBlbmRlbnRzQWZmZWN0ZWRCeUZpbGVFdmVudHMoaG1yQWN0aW9uUmVxdWlyZWRFdmVudHMpO1xuXG4gICAgLy8gU3luYyDsmIHsl606IGNoZWNrc3VtUGF0dGVybkdyb3Vw7JeQIOuqheyLnOuQnCDtjIzsnbzrk6Tsl5Ag64yA7ZWcIOuzgOuPmeydgCBzeW5jVHJpZ2dlcmluZ1BhdGhz66GcIOyeoe2emeuLiOuLpC5cbiAgICAvLyDsnbQg7Lmc6rWs65Ok7J2AIOyggeygiO2VnCBzeW5jIOyekeyXheycvOuhnCDrjIDsnZHtlanri4jri6QuXG4gICAgaWYgKHN5bmNUcmlnZ2VyaW5nUGF0aHMubGVuZ3RoID4gMCkge1xuICAgICAgYXdhaXQgdGhpcy5kb1N5bmNBY3Rpb25zKHN5bmNUcmlnZ2VyaW5nUGF0aHMpO1xuICAgIH1cblxuICAgIC8vIOyLse2BrCDsnpHsl4XsnbQg64Gd64Ks7Jy866m0IOustOyngOyEsSDroZzrk5zrpbwg7IiY7ZaJ7ZWp64uI64ukLlxuICAgIC8vIOyLse2BrOulvCDslYgg7ZWcIOqyveyasOyXkOuPhCDroZzrk5zripQg7ZW07JW8IO2VtOyalC4g7JyE7JeQ7IScIOq0gOugqOyeiOuKlCDsuZzqtazrk6TsnYAg64ukIGludmFsaWRhdGUg65CY7JeI6rGw65Og7JqUIVxuICAgIC8vXG4gICAgLy8g67OA6rK965CcIO2MjOydvOuTpOyXkCDrjIDtlbTshJwg7IOI66Gt6rKMIOuLueqyqOyYpOuKlChsb2FkKSDtlonsnITripQgZG9TeW5jQWN0aW9uc+yXkOyEnCDtlZjsp4Ag7JWK7Iq164uI64ukLlxuICAgIC8vIGRvU3luY0FjdGlvbnPsl5DshJzripQg7YyM7J287J2EIOydveqzoCDrp4zrk5zripQg7Iux7YGsIO2WieychOunjCDtlanri4jri6QuXG4gICAgLy8g6rGw6riw7IScIOuUsSDrs4Dqsr3rkJwg67aA67aE7JeQIOyYge2Wpeuwm+uKlCBhdXRvbG9hZOunjCDshKDrs4TtlbTshJwg7IiY7ZaJ7ZWY66Ck66m0IOuEiOustCDsp4DsoIDrtoTtlZjqs6Ag67O17J6h7ZW07KeR64uI64ukLlxuICAgIC8vXG4gICAgLy8g7Y287Y+s66i87IqkIOyYge2WpeydgCDrrLTsi5ztlbTrj4Qg7KKL7Iq164uI64ukLlxuICAgIC8vIOyWtOywqO2UvCBobXItaG9va+yXkCDsnZjtlbQgaW52YWxpZGF0ZeuQnCDrtoDrtoTrk6TsnbQg7JWE64uI652866m0IOy6kOyLnCDqt7jrjIDroZwg7Jyg7KeA7ZWp64uI64ukLlxuICAgIGF3YWl0IHRoaXMuYXV0b2xvYWRUeXBlcygpO1xuICAgIGF3YWl0IHRoaXMuYXV0b2xvYWRNb2RlbHMoKTtcbiAgICBhd2FpdCB0aGlzLmF1dG9sb2FkQXBpcygpO1xuICAgIGF3YWl0IHRoaXMuYXV0b2xvYWRXb3JrZmxvd3MoKTtcbiAgICBhd2FpdCB0aGlzLmF1dG9sb2FkU3NyUm91dGVzKCk7XG5cbiAgICB0aGlzLmV2ZW50RW1pdHRlci5lbWl0KFwib25ITVJDb21wbGV0ZWRcIik7XG4gIH1cblxuICBwcml2YXRlIGV4dHJhY3RIbXJBY3Rpb25SZXF1aXJlZEZpbGVFdmVudHMoXG4gICAgZmlsZUV2ZW50czogTWFwPEFic29sdXRlUGF0aCwgXCJjaGFuZ2VcIiB8IFwiYWRkXCI+LFxuICApOiBNYXA8QWJzb2x1dGVQYXRoLCBcImNoYW5nZVwiIHwgXCJhZGRcIj4ge1xuICAgIGNvbnN0IGFwaVNyYyA9IHBhdGguam9pbihTb25hbXUuYXBpUm9vdFBhdGgsIFwic3JjXCIpO1xuICAgIGNvbnN0IHJlc3VsdCA9IG5ldyBNYXA8QWJzb2x1dGVQYXRoLCBcImNoYW5nZVwiIHwgXCJhZGRcIj4oKTtcbiAgICBmb3IgKGNvbnN0IFtmaWxlUGF0aCwgZXZlbnRdIG9mIGZpbGVFdmVudHMpIHtcbiAgICAgIGlmICghZmlsZVBhdGguc3RhcnRzV2l0aChhcGlTcmMpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgcmVzdWx0LnNldChmaWxlUGF0aCwgZXZlbnQpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBleHRyYWN0U3luY1RyaWdnZXJpbmdGaWxlRXZlbnRQYXRocyhcbiAgICBmaWxlRXZlbnRzOiBNYXA8QWJzb2x1dGVQYXRoLCBcImNoYW5nZVwiIHwgXCJhZGRcIj4sXG4gICk6IFByb21pc2U8QWJzb2x1dGVQYXRoW10+IHtcbiAgICBjb25zdCBjaGVja1BhdHRlcm5Hcm91cCA9IGdldENoZWNrc3VtUGF0dGVybkdyb3VwSW5BYnNvbHV0ZVBhdGgoKTtcbiAgICBjb25zdCBzeW5jVHJpZ2dlcmluZ1BhdGhzOiBBYnNvbHV0ZVBhdGhbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgW2RpZmZGaWxlUGF0aF0gb2YgZmlsZUV2ZW50cykge1xuICAgICAgY29uc3QgaXNJbkNoZWNrUGF0dGVybkdyb3VwID0gT2JqZWN0LnZhbHVlcyhjaGVja1BhdHRlcm5Hcm91cCkuc29tZSgocGF0dGVybikgPT5cbiAgICAgICAgbWluaW1hdGNoKGRpZmZGaWxlUGF0aCwgcGF0dGVybiksXG4gICAgICApO1xuICAgICAgaWYgKCFpc0luQ2hlY2tQYXR0ZXJuR3JvdXApIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBzeW5jVHJpZ2dlcmluZ1BhdGhzLnB1c2goZGlmZkZpbGVQYXRoKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc3luY1RyaWdnZXJpbmdQYXRocztcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgaW52YWxpZGF0ZURlcGVuZGVudHNBZmZlY3RlZEJ5RmlsZUV2ZW50cyhcbiAgICBmaWxlRXZlbnRzOiBNYXA8QWJzb2x1dGVQYXRoLCBcImNoYW5nZVwiIHwgXCJhZGRcIj4sXG4gICkge1xuICAgIGZvciAoY29uc3QgW2RpZmZGaWxlUGF0aCwgZXZlbnRdIG9mIGZpbGVFdmVudHMpIHtcbiAgICAgIC8vIOuzgOqyveuQnCDtjIzsnbzqs7wgZGVwZW5kZW50IO2MjOydvOuTpOydhCBpbnZhbGlkYXRlIO2VqeuLiOuLpC5cbiAgICAgIC8vIO2VnCDrsogg7J207IOBIGltcG9ydOuQnCDsuZzqtazrk6Tsl5Ag64yA7ZW07ISc66eMIOyLpOygnCDsnpHsl4XsnbQg7J287Ja064Kp64uI64ukLlxuICAgICAgLy8g6re465+s64uIIOyViOyLrO2VmOqzoCBpbnZhbGlkYXRlIO2VtOuPhCDrkKnri4jri6QuXG4gICAgICAvLyDthYzsiqTtirgg7ZmY6rK97JeQ7ISc64qUIGhvdC5pbnZhbGlkYXRlRmlsZeyLnCDstIjquLAg7JeQ65+s6rCAIOuwnOyDne2VmOq4sCDrlYzrrLjsl5AgaW52YWxpZGF0ZSDtlZjsp4Ag7JWK7Iq164uI64ukLlxuICAgICAgaWYgKCFpc1Rlc3QoKSkge1xuICAgICAgICBjb25zdCBpbnZhbGlkYXRlZFBhdGhzID0gKGF3YWl0IGhvdC5pbnZhbGlkYXRlRmlsZShkaWZmRmlsZVBhdGgsIGV2ZW50KSkgYXMgQWJzb2x1dGVQYXRoW107XG5cbiAgICAgICAgaWYgKGludmFsaWRhdGVkUGF0aHMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmJvbGQoYPCflIQgSW52YWxpZGF0ZWQ6YCkpO1xuXG4gICAgICAgICAgZm9yIChjb25zdCBpbnZhbGlkYXRlZFBhdGggb2YgaW52YWxpZGF0ZWRQYXRocykge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgLy8g66eM7JW9IG1vZGVsLnRzIO2MjOydvOydtCDrs4Dqsr0oaW52YWxpZGF0ZSnrkJjsl4jri6Q/IOq3uOufrOuptCByZWdpc3RlcmVkQXBpcyDspJHsl5DshJwg7J20IOuqqOuNuOyXkCDtlbTri7ntlZjripQgYXBp65Ok7J2AIOyngOybjOykmOyalC5cbiAgICAgICAgICAgICAgLy8gcmVnaXN0ZXJlZEFwaXPripQg7Ya17Jy866GcIOuLpCDrgqDroKTrsoTrprQg7IiYIOyXhuyKteuLiOuLpC4gcmVnaXN0ZXJlZEFwaXPsl5Ag7Jis65287Jik64qUIOy5nOq1rOuTpOydgCDstIjquLAg66Gc65Oc7IucIOuYkOuKlCBITVLsi5zsl5Drp4wg65Ox66Gd65CY6riwIOuVjOusuOyeheuLiOuLpC5cbiAgICAgICAgICAgICAgLy8g65Sw65287IScIG1vZGVsLnRzIO2MjOydvOydmCDrs4Dqsr3snLzroZwg64uk7J2M67KIIOyDiOuhnOyatCBldmFs7J20IOyYiOyDgeuQmOuKlCDsnbQg7Iuc7KCQ7JeQ7ISc66eMLCDsnbQg66qo64247JeQ7IScIOuCmOyYqCByZWdpc3RlcmVkQXBpc+uTpOydhCDsp4Dsm4zspIQg7IiYIOyeiOyKteuLiOuLpC5cbiAgICAgICAgICAgICAgY29uc3QgcmVtb3ZlZEFwaXMgPSB0aGlzLnJlbW92ZUludmFsaWRhdGVkUmVnaXN0ZXJlZEFwaXMoaW52YWxpZGF0ZWRQYXRoKTtcbiAgICAgICAgICAgICAgaWYgKHJlbW92ZWRBcGlzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgICAgIGNoYWxrLmJsdWUoYC0gJHtwYXRoLnJlbGF0aXZlKFNvbmFtdS5hcGlSb290UGF0aCwgaW52YWxpZGF0ZWRQYXRoKX1gKSxcbiAgICAgICAgICAgICAgICAgIGNoYWxrLmdyYXkoYCh3aXRoICR7cmVtb3ZlZEFwaXMubGVuZ3RofSBBUElzKWApLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coY2hhbGsuYmx1ZShgLSAke3BhdGgucmVsYXRpdmUoU29uYW11LmFwaVJvb3RQYXRoLCBpbnZhbGlkYXRlZFBhdGgpfWApKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGUpO1xuICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgICAgICAgIGNoYWxrLnJlZChgRmFpbGVkIHRvIHJlbW92ZSBpbnZhbGlkYXRlZCByZWdpc3RlcmVkIEFQSXMgZm9yICR7aW52YWxpZGF0ZWRQYXRofWApLFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBkZXZSdW5uZXIg7Zmc7ISx7ZmUIOyLnCwg67OA6rK965CcIOyGjOyKpCDtjIzsnbzsnYQgVml0ZXN0IOuqqOuTiCDqt7jrnpjtlITsl5DshJzrj4Qg66y07Zqo7ZmU7ZWp64uI64ukLlxuICAgICAgLy8gVml0ZeydmCBtb2R1bGVHcmFwaC5pbnZhbGlkYXRlTW9kdWxlKCnsnbQgaW1wb3J0ZXIg67Cp7Zal7Jy866GcIOyerOq3gOyggSBjYXNjYWRl7ZWY66+A66GcLFxuICAgICAgLy8g7IaM7IqkIO2MjOydvCDtlZjrgpjrp4wg66y07Zqo7ZmU7ZWY66m0IOydtOulvCBpbXBvcnTtlZjripQg7YWM7Iqk7Yq4IO2MjOydvOuPhCDsnpDrj5nsnLzroZwg66y07Zqo7ZmU65Cp64uI64ukLlxuICAgICAgaWYgKCFpc1Rlc3QoKSAmJiBTb25hbXUuY29uZmlnLnRlc3Q/LmRldlJ1bm5lcj8uZW5hYmxlZCAmJiBTb25hbXUuZGV2Vml0ZXN0TWFuYWdlcikge1xuICAgICAgICBTb25hbXUuZGV2Vml0ZXN0TWFuYWdlci5pbnZhbGlkYXRlRmlsZXMoW2RpZmZGaWxlUGF0aF0pO1xuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICBjaGFsay5kaW0oYFRlc3QgaW52YWxpZGF0ZWQ6ICR7cGF0aC5yZWxhdGl2ZShTb25hbXUuYXBpUm9vdFBhdGgsIGRpZmZGaWxlUGF0aCl9YCksXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmVtb3ZlSW52YWxpZGF0ZWRSZWdpc3RlcmVkQXBpcyhcbiAgICBpbnZhbGlkYXRlZFBhdGg6IEFic29sdXRlUGF0aCxcbiAgKTogKHR5cGVvZiByZWdpc3RlcmVkQXBpcylbbnVtYmVyXVtdIHtcbiAgICBpZiAoIWludmFsaWRhdGVkUGF0aC5lbmRzV2l0aChcIi5tb2RlbC50c1wiIC8q7IaM7IqkIOy9lOuTnOulvCDri6Tro6jripQg7IOB7Zmp7J2064uIIC50cyDqsr3roZzroZwg67SF64uI64ukLiovKSkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIGNvbnN0IGVudGl0eUlkID0gRW50aXR5TWFuYWdlci5nZXRFbnRpdHlJZEZyb21QYXRoKGludmFsaWRhdGVkUGF0aCk7XG4gICAgY29uc3QgdG9SZW1vdmUgPSByZWdpc3RlcmVkQXBpcy5maWx0ZXIoKGFwaSkgPT4gYXBpLm1vZGVsTmFtZSA9PT0gYCR7ZW50aXR5SWR9TW9kZWxgKTtcbiAgICBmb3IgKGNvbnN0IGFwaSBvZiB0b1JlbW92ZSkge1xuICAgICAgY29uc3QgaWR4ID0gcmVnaXN0ZXJlZEFwaXMuaW5kZXhPZihhcGkpO1xuICAgICAgaWYgKGlkeCAhPT0gLTEpIHtcbiAgICAgICAgcmVnaXN0ZXJlZEFwaXMuc3BsaWNlKGlkeCwgMSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRvUmVtb3ZlO1xuICB9XG5cbiAgYXN5bmMgYXV0b2xvYWRUeXBlcygpIHtcbiAgICB0aGlzLnR5cGVzID0gYXdhaXQgbG9hZFR5cGVzKCk7XG4gIH1cblxuICBhc3luYyBhdXRvbG9hZE1vZGVscygpIHtcbiAgICB0aGlzLm1vZGVscyA9IGF3YWl0IGxvYWRNb2RlbHMoKTtcbiAgfVxuXG4gIGFzeW5jIGF1dG9sb2FkQXBpcygpIHtcbiAgICB0aGlzLmFwaXMgPSBhd2FpdCBsb2FkQXBpcygpO1xuICB9XG5cbiAgYXN5bmMgYXV0b2xvYWRXb3JrZmxvd3MoKSB7XG4gICAgdGhpcy53b3JrZmxvd3MgPSBhd2FpdCBsb2FkV29ya2Zsb3dzKCk7XG4gICAgYXdhaXQgU29uYW11LndvcmtmbG93cy5zeW5jaHJvbml6ZSh0aGlzLndvcmtmbG93cyk7XG4gIH1cblxuICBhc3luYyBhdXRvbG9hZFNzclJvdXRlcygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBzc3JDb25maWdQYXRoID0gcGF0aC5qb2luKFNvbmFtdS5hcGlSb290UGF0aCwgXCJzcmMvc3NyXCIpO1xuXG4gICAgLy8g6riw7KG0IHJvdXRlcyDstIjquLDtmZRcbiAgICBjb25zdCB7IGNsZWFyU1NSUm91dGVzIH0gPSBhd2FpdCBpbXBvcnQoXCIuLi9zc3JcIik7XG4gICAgY2xlYXJTU1JSb3V0ZXMoKTtcblxuICAgIC8vIHNzciDtj7TrjZQg7JeG7Jy866m0IOyKpO2CtVxuICAgIGlmICghKGF3YWl0IGV4aXN0cyhzc3JDb25maWdQYXRoKSkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBzc3Ig7Y+0642UIOyViOydmCDrqqjrk6AgLnRzIO2MjOydvCDroZzrk5xcbiAgICBjb25zdCB7IGdsb2JBc3luYyB9ID0gYXdhaXQgaW1wb3J0KFwiLi4vdXRpbHMvYXN5bmMtdXRpbHNcIik7XG4gICAgY29uc3QgeyBpbXBvcnRNZW1iZXJzIH0gPSBhd2FpdCBpbXBvcnQoXCIuLi91dGlscy9lc20tdXRpbHNcIik7XG4gICAgY29uc3QgeyBydW50aW1lUGF0aCB9ID0gYXdhaXQgaW1wb3J0KFwiLi4vdXRpbHMvcGF0aC11dGlsc1wiKTtcblxuICAgIC8vIHJ1bnRpbWVQYXRo66W8IOyCrOyaqe2VmOyXrCDqsJzrsJwv7ZSE66Gc642V7IWYIO2ZmOqyveyXkCDrp57ripQg7ZmV7J6l7J6QIOyymOumrFxuICAgIGNvbnN0IGZpbGVzID0gYXdhaXQgZ2xvYkFzeW5jKHBhdGguam9pbihzc3JDb25maWdQYXRoLCBydW50aW1lUGF0aChcIioqLyoudHNcIikpKTtcblxuICAgIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gaW1wb3J0TWVtYmVyc+ulvCDsgqzsmqntlZjrqbQg7YyM7J287J2YIHNpZGUgZWZmZWN0KHJlZ2lzdGVyU1NSIO2YuOy2nCnqsIAg7Iuk7ZaJ65CoXG4gICAgICAgIGF3YWl0IGltcG9ydE1lbWJlcnMoZmlsZSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYEZhaWxlZCB0byBsb2FkIFNTUiByb3V0ZTogJHtmaWxlfWAsIGUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiDsi6TsoJwg7Iux7YGs66W8IOyImO2Wie2VmOuKlCDrs7jssrTsnoXri4jri6QuXG4gICAqIOuzgOqyveuQnCDtjIzsnbzrk6TsnYQg7YOA7J6F67OE66GcIOu2hOulmO2VmOqzoCDqsIEg7YOA7J6F7JeQIOunnuuKlCDslaHshZjsnYQg7Iuk7ZaJ7ZWp64uI64ukLlxuICAgKlxuICAgKiBAcGFyYW0gZGlmZkZpbGVQYXRocyAtIOuzgOqyveuQnCDtjIzsnbzrk6TsnZgg7KCI64yAIOqyveuhnCDrqqnroZ1cbiAgICogQHJldHVybnMgZGlmZlR5cGVzIC0g67OA6rK965CcIO2MjOydvOydmCDtg4DsnoUg66qp66GdIChlbnRpdHksIHR5cGVzLCBtb2RlbCDrk7EpXG4gICAqL1xuICBhc3luYyBkb1N5bmNBY3Rpb25zKGRpZmZGaWxlUGF0aHM6IEFic29sdXRlUGF0aFtdKTogUHJvbWlzZTx7IGRpZmZUeXBlczogRmlsZVR5cGVbXSB9PiB7XG4gICAgY29uc3QgZGlmZkdyb3VwcyA9IHRoaXMuY2FsY3VsYXRlRGlmZkdyb3VwcyhkaWZmRmlsZVBhdGhzKTtcbiAgICBjb25zdCBkaWZmVHlwZXMgPSBPYmplY3Qua2V5cyhkaWZmR3JvdXBzKSBhcyBGaWxlVHlwZVtdO1xuXG4gICAgLy8g7Jes6riw64qUIOuzhOuhnCDspJHsmpTtlZwg7YyM7Yq464qUIOyVhOuLmeuLiOuLpC5cbiAgICAvLyDslYTrnpjsnZggaWYg7KCE6rCc66W8IOq5lOuBlO2VmOqyjCDtlZjroKTqs6Ag66eM65OgIERTTCDqsJnsnYAg6rGw65287IScLCDrrLTsi5ztlZjshZTrj4Qg65Cp64uI64ukLlxuICAgIGNvbnN0IHsgY2hhbmdlTWF0Y2hlcywgbm90aGluZ01hdGNoZXMsIHVuaGFuZGxlZFBhdGhzIH0gPSB0aGlzLmNoYW5nZU1hdGNoZXIoXG4gICAgICBkaWZmVHlwZXMsXG4gICAgICBkaWZmR3JvdXBzLFxuICAgICk7XG5cbiAgICBpZiAoY2hhbmdlTWF0Y2hlcyhcImVudGl0eVwiLCBcInR5cGVzXCIpKSB7XG4gICAgICBhd2FpdCB0aGlzLmhhbmRsZVRydXRoU291cmNlQ2hhbmdlcyhkaWZmR3JvdXBzKTtcbiAgICB9XG5cbiAgICBpZiAoY2hhbmdlTWF0Y2hlcyhcIm1vZGVsXCIsIFwiZnJhbWVcIikpIHtcbiAgICAgIGF3YWl0IHRoaXMuaGFuZGxlSW1wbGVtZW50YXRpb25DaGFuZ2VzKGRpZmZHcm91cHMpO1xuICAgIH1cblxuICAgIGlmIChjaGFuZ2VNYXRjaGVzKFwidHlwZXNcIiwgXCJmdW5jdGlvbnNcIikpIHtcbiAgICAgIGF3YWl0IHRoaXMuaGFuZGxlQXV4aWxpYXJ5U3ltYm9sQ2hhbmdlcyhkaWZmR3JvdXBzKTtcbiAgICB9XG5cbiAgICBpZiAoY2hhbmdlTWF0Y2hlcyhcImNvbmZpZ1wiKSkge1xuICAgICAgYXdhaXQgdGhpcy5oYW5kbGVDb25maWdDaGFuZ2VzKGRpZmZHcm91cHMpO1xuICAgIH1cblxuICAgIGlmIChjaGFuZ2VNYXRjaGVzKFwiaTE4blwiLCBcImVudGl0eVwiIC8q66CI7J2067iUKi8sIFwiY29uZmlnXCIgLypkZWZhdWx0TG9jYWxl65OxKi8pKSB7XG4gICAgICBhd2FpdCB0aGlzLmhhbmRsZVNvbmFtdURpY3Rpb25hcnlSZWxhdGVkQ2hhbmdlcyhkaWZmR3JvdXBzKTtcbiAgICB9XG5cbiAgICBpZiAobm90aGluZ01hdGNoZXMoKSkge1xuICAgICAgLy8g7YyM7J28IOuzgOqyveydgCDqsJDsp4DrkJjsl4jsnLzrgpgg7KCAIOychCDslrTripAgY2hhbmdlTWF0Y2hlc+yXkOuPhCDqsbjrpqzsp4Ag7JWK7J2AIO2MjOydvOuTpOydtCBkcmlmdHPsnoXri4jri6QuXG4gICAgICAvLyBzeW5jZXLripQg7IaM7Iqk7J2YIOuzgOqyveyXkOuKlCDrsJjsnZHtlZjsp4Drp4wg7IKw7Lac66y87J2YIOuzgOqyvShkcmlmdCnsl5DripQg7KeB7KCR7KCB7Jy866GcIOuwmOydke2VmOyngCDslYrsirXri4jri6QuXG4gICAgICAvLyDrjIDsi6Ag7J20IGRyaWZ07JeQIOuMgO2VtCDqsr3qs6Ag7KCV64+E66eMIOy2nOugpe2VtOykjeuLiOuLpC5cbiAgICAgIGF3YWl0IHRoaXMuaGFuZGxlRHJpZnRzKHVuaGFuZGxlZFBhdGhzKCkpO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBkaWZmVHlwZXMsXG4gICAgfTtcbiAgfVxuXG4gIGNhbGN1bGF0ZURpZmZHcm91cHMoZGlmZkZpbGVzOiBBYnNvbHV0ZVBhdGhbXSk6IERpZmZHcm91cHMge1xuICAgIGNvbnN0IHBhdHRlcm5Hcm91cCA9IGdldENoZWNrc3VtUGF0dGVybkdyb3VwKCk7XG4gICAgY29uc3QgZmlsZVR5cGVzID0gT2JqZWN0LmtleXMocGF0dGVybkdyb3VwKSBhcyBGaWxlVHlwZVtdO1xuXG4gICAgcmV0dXJuIGdyb3VwKGRpZmZGaWxlcywgKGZpbGVQYXRoKSA9PiB7XG4gICAgICAvLyDsoIjrjIAg6rK966GcIOKGkiBhcHBSb290IOq4sOykgCDsg4HrjIAg6rK966GcICjsmIg6IFwiYXBpL3NyYy8uLi5cIiwgXCJ3ZWIvc3JjLy4uLlwiKVxuICAgICAgY29uc3QgcmVsYXRpdmVQYXRoID0gcGF0aC5yZWxhdGl2ZShTb25hbXUuYXBwUm9vdFBhdGgsIGZpbGVQYXRoKTtcbiAgICAgIGlmIChyZWxhdGl2ZVBhdGguc3RhcnRzV2l0aChcIi4uXCIpKSByZXR1cm4gXCJ1bmtub3duXCI7XG5cbiAgICAgIGZvciAoY29uc3QgZmlsZVR5cGUgb2YgZmlsZVR5cGVzKSB7XG4gICAgICAgIGlmIChtaW5pbWF0Y2gocmVsYXRpdmVQYXRoLCBwYXR0ZXJuR3JvdXBbZmlsZVR5cGVdKSkge1xuICAgICAgICAgIHJldHVybiBmaWxlVHlwZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIFwidW5rbm93blwiO1xuICAgIH0pIGFzIHVua25vd24gYXMgRGlmZkdyb3VwcztcbiAgfVxuXG4gIHByaXZhdGUgY2hhbmdlTWF0Y2hlcihkaWZmVHlwZXM6IEZpbGVUeXBlW10sIGRpZmZHcm91cHM6IERpZmZHcm91cHMpIHtcbiAgICBjb25zdCBoYW5kbGVkID0gbmV3IFNldDxGaWxlVHlwZT4oKTtcblxuICAgIC8qKlxuICAgICAqIOuzgOqyvSDsgqztla3snbQg7J247J6Q66GcIOuwm+ydgCBGaWxlVHlwZeuTpCDspJEg7ZWY64KYIOydtOyDgeydhCDtj6ztlajtlZjripTsp4Ag7ZmV7J247ZWp64uI64ukLlxuICAgICAqIOqwgOuguSBbXCJlbnRpdHlcIl3qsIAg67OA6rK965CcIO2YuOy2nOyXkOyEnCBjaGFuZ2VNYXRjaGVzKFwiZW50aXR5XCIp64qUIHRyeWXrpbwg67CY7ZmY7ZWY66mwLFxuICAgICAqIFtcInR5cGVzXCIsIFwiaTE4blwiXeydtCDrs4Dqsr3rkJwg7Zi47Lac7JeQ7IScIGNoYW5nZU1hdGNoZXMoXCJ0eXBlc1wiLCBcImZ1bmN0aW9uc1wiKeuPhCB0cnVl66W8IOuwmO2ZmO2VmOyngOunjCxcbiAgICAgKiBbXCJmdW5jdGlvbnNcIl3qsIAg67OA6rK965CcIO2YuOy2nOyXkOyEnCBjaGFuZ2VNYXRjaGVzKFwiZnJhbWVcIinsnYAgZmFsc2Xrpbwg67CY7ZmY7ZWp64uI64ukLlxuICAgICAqIEBwYXJhbSB0eXBlc1xuICAgICAqL1xuICAgIGNvbnN0IGNoYW5nZU1hdGNoZXMgPSAoLi4udHlwZXM6IEZpbGVUeXBlW10pID0+IHtcbiAgICAgIGNvbnN0IG1hdGNoaW5nID0gdHlwZXMuZmlsdGVyKCh0KSA9PiBkaWZmVHlwZXMuaW5jbHVkZXModCkpO1xuICAgICAgbWF0Y2hpbmcuZm9yRWFjaCgodCkgPT4gaGFuZGxlZC5hZGQodCkpO1xuICAgICAgcmV0dXJuIG1hdGNoaW5nLmxlbmd0aCA+IDA7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIGNoYW5nZU1hdGNoZXProZwg66ek7Lmt65CcIOqyg+ydtCDtlZjrgpjrj4Qg7JeG64qU7KeAIOyXrOu2gOulvCDqsIDsoLjsmLXri4jri6QuXG4gICAgICovXG4gICAgY29uc3Qgbm90aGluZ01hdGNoZXMgPSAoKSA9PiBoYW5kbGVkLnNpemUgPT09IDA7XG5cbiAgICAvKipcbiAgICAgKiDslrTrlqQgY2hhbmdlTWF0Y2hlcyDtmLjstpzsl5Drj4Qg6rG466as7KeAIOyViuydgCBGaWxlVHlwZeuTpOydmCDsi6TsoJwg7YyM7J28IOqyveuhnOulvCDrqqjslYTshJwg67CY7ZmY7ZWp64uI64ukLlxuICAgICAqL1xuICAgIGNvbnN0IHVuaGFuZGxlZFBhdGhzID0gKCk6IEFic29sdXRlUGF0aFtdID0+XG4gICAgICBkaWZmVHlwZXMuZmlsdGVyKCh0KSA9PiAhaGFuZGxlZC5oYXModCkpLmZsYXRNYXAoKHQpID0+IGRpZmZHcm91cHNbdF0gPz8gW10pO1xuXG4gICAgcmV0dXJuIHsgY2hhbmdlTWF0Y2hlcywgbm90aGluZ01hdGNoZXMsIHVuaGFuZGxlZFBhdGhzIH07XG4gIH1cblxuICBhc3luYyBoYW5kbGVUcnV0aFNvdXJjZUNoYW5nZXMoZGlmZkdyb3VwczogRGlmZkdyb3Vwcyk6IFByb21pc2U8dm9pZD4ge1xuICAgIE5haXRlLnQoXCJoYW5kbGVUcnV0aFNvdXJjZUNoYW5nZXNcIiwgeyBkaWZmR3JvdXBzIH0pO1xuXG4gICAgYXdhaXQgRW50aXR5TWFuYWdlci5yZWxvYWQoKTtcblxuICAgIC8vIHR5cGVzIOyDneyEsShlbnRpdHkg7IOI66GcIOy2lOqwgOuQnCDqsr3smrApXG4gICAgLy8gcGFyZW50SWTqsIAg7JeG6rOgLCB0eXBlc+qwgCDsl4bripQg6rK97Jqw7JeQ66eMIOyDneyEsVxuICAgIGNvbnN0IGVudGl0eVBhdGggPSBkaWZmR3JvdXBzLmVudGl0eT8uYXQoMCk7XG4gICAgaWYgKGVudGl0eVBhdGggIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgZW50aXR5SWQgPSBFbnRpdHlNYW5hZ2VyLmdldEVudGl0eUlkRnJvbVBhdGgoZW50aXR5UGF0aCk7XG4gICAgICBjb25zdCBlbnRpdHkgPSBFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCk7XG5cbiAgICAgIC8vIO2UhOuhnOygne2KuOyXkCDsg53shLHrkJjslrTslbwg7ZWY64qUIC50cyDtjIzsnbzsnZgg6rK966Gc7J6F64uI64ukLlxuICAgICAgY29uc3QgdHlwZUZpbGVQYXRoID0gcGF0aC5qb2luKFxuICAgICAgICBTb25hbXUuYXBpUm9vdFBhdGgsXG4gICAgICAgIGBzcmMvYXBwbGljYXRpb24vJHtlbnRpdHkubmFtZXMuZnN9LyR7ZW50aXR5Lm5hbWVzLmZzfS50eXBlcy50c2AsXG4gICAgICApIGFzIEFic29sdXRlUGF0aDtcblxuICAgICAgaWYgKGVudGl0eS5wYXJlbnRJZCA9PT0gdW5kZWZpbmVkICYmICEoYXdhaXQgZXhpc3RzKHR5cGVGaWxlUGF0aCkpKSB7XG4gICAgICAgIC8vICoudHlwZXMudHPqsIAg66eM65Ok7Ja07KeR64uI64ukLlxuICAgICAgICBjb25zdCB0eXBlcyA9IGF3YWl0IFN5bmNlckFjdGlvbnMuYWN0aW9uR2VuZXJhdGVJbml0aWFsVHlwZXMoZW50aXR5SWQpO1xuXG4gICAgICAgIC8vIOq3uOqxuCDtg4Dqsp/sl5Ag6rCW64uk65Gs7JqULlxuICAgICAgICBhd2FpdCBTeW5jZXJBY3Rpb25zLmFjdGlvblN5bmNGaWxlc1RvVGFyZ2V0cyh0eXBlcyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gc29uYW11LmdlbmVyYXRlZC50c+qwgCDrp4zrk6TslrTsp5Hri4jri6QuXG4gICAgY29uc3QgZ2VuZXJhdGVkID0gYXdhaXQgU3luY2VyQWN0aW9ucy5hY3Rpb25HZW5lcmF0ZVNjaGVtYXMoKTtcblxuICAgIC8vIOq3uOqxuCB0YXJnZXTrk6Tsl5Drj4Qg67O064K07JqULlxuICAgIGF3YWl0IFN5bmNlckFjdGlvbnMuYWN0aW9uU3luY0ZpbGVzVG9UYXJnZXRzKGdlbmVyYXRlZCk7XG4gIH1cblxuICBhc3luYyBoYW5kbGVJbXBsZW1lbnRhdGlvbkNoYW5nZXMoZGlmZkdyb3VwczogRGlmZkdyb3Vwcyk6IFByb21pc2U8dm9pZD4ge1xuICAgIE5haXRlLnQoXCJoYW5kbGVJbXBsZW1lbnRhdGlvbkNoYW5nZXNcIiwgeyBkaWZmR3JvdXBzIH0pO1xuICAgIGNvbnN0IG1lcmdlZEdyb3VwID0gWy4uLihkaWZmR3JvdXBzLm1vZGVsID8/IFtdKSwgLi4uKGRpZmZHcm91cHMuZnJhbWUgPz8gW10pXTtcblxuICAgIC8vIGdlbmVyYXRlZF9odHRwLnRlbXBsYXRlLnRz7JeQ7IScIHN5bmNlci50eXBlc+ulvCDslIHri4jri6QuXG4gICAgLy8gc2VydmljZS50ZW1wbGF0ZS50c+yXkOyEnCBzeW5jZXIuYXBpc+ulvCDslIHri4jri6QuXG4gICAgYXdhaXQgdGhpcy5hdXRvbG9hZE1vZGVscygpO1xuICAgIGF3YWl0IHRoaXMuYXV0b2xvYWRUeXBlcygpO1xuICAgIGF3YWl0IHRoaXMuYXV0b2xvYWRBcGlzKCk7XG5cbiAgICBjb25zdCBwYXJhbXM6IHtcbiAgICAgIG5hbWVzUmVjb3JkOiBFbnRpdHlOYW1lc1JlY29yZDtcbiAgICB9W10gPSBtZXJnZWRHcm91cC5tYXAoKG1vZGVsUGF0aCkgPT4ge1xuICAgICAgaWYgKG1vZGVsUGF0aC5lbmRzV2l0aChcIi5tb2RlbC50c1wiKSB8fCBtb2RlbFBhdGguZW5kc1dpdGgoXCIuZnJhbWUudHNcIikpIHtcbiAgICAgICAgY29uc3QgZW50aXR5SWQgPSBFbnRpdHlNYW5hZ2VyLmdldEVudGl0eUlkRnJvbVBhdGgobW9kZWxQYXRoKTtcbiAgICAgICAgYXNzZXJ0KGVudGl0eUlkKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBuYW1lc1JlY29yZDogRW50aXR5TWFuYWdlci5nZXROYW1lc0Zyb21JZChlbnRpdHlJZCksXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJub3QgcmVhY2hhYmxlXCIpO1xuICAgIH0pO1xuXG4gICAgLy8gc2VydmljZXMuZ2VuZXJhdGVkLnRz66W8IHRhcmdldOuTpOyXkCwgc29uYW11LmdlbmVyYXRlZC5odHRw66W8IGFwaeyXkCDrp4zrk6TslrTspJjsmpQuXG4gICAgYXdhaXQgU3luY2VyQWN0aW9ucy5hY3Rpb25HZW5lcmF0ZVNlcnZpY2VzKHBhcmFtcyk7XG4gICAgYXdhaXQgU3luY2VyQWN0aW9ucy5hY3Rpb25HZW5lcmF0ZUh0dHBzKCk7XG5cbiAgICAvLyBxdWVyaWVzLmdlbmVyYXRlZC50c+qwgCDrp4zrk6TslrTsp5Hri4jri6QuXG4gICAgY29uc3QgcXVlcmllcyA9IGF3YWl0IFN5bmNlckFjdGlvbnMuYWN0aW9uR2VuZXJhdGVTc3JRdWVyaWVzKCk7XG5cbiAgICAvLyDqt7jqsbggdGFyZ2V065Ok7JeQ64+EIOuztOuCtOyalC5cbiAgICBhd2FpdCBTeW5jZXJBY3Rpb25zLmFjdGlvblN5bmNGaWxlc1RvVGFyZ2V0cyhxdWVyaWVzKTtcbiAgfVxuXG4gIGFzeW5jIGhhbmRsZUF1eGlsaWFyeVN5bWJvbENoYW5nZXMoZGlmZkdyb3VwczogRGlmZkdyb3Vwcyk6IFByb21pc2U8dm9pZD4ge1xuICAgIE5haXRlLnQoXCJoYW5kbGVBdXhpbGlhcnlTeW1ib2xDaGFuZ2VzXCIsIHsgZGlmZkdyb3VwcyB9KTtcbiAgICBjb25zdCB0c1BhdGhzID0gdW5pcXVlKFsuLi4oZGlmZkdyb3Vwcy50eXBlcyA/PyBbXSksIC4uLihkaWZmR3JvdXBzLmZ1bmN0aW9ucyA/PyBbXSldKTtcbiAgICBhd2FpdCBTeW5jZXJBY3Rpb25zLmFjdGlvblN5bmNGaWxlc1RvVGFyZ2V0cyh0c1BhdGhzKTtcbiAgfVxuXG4gIGFzeW5jIGhhbmRsZUNvbmZpZ0NoYW5nZXMoXzogRGlmZkdyb3Vwcyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IFN5bmNlckFjdGlvbnMuYWN0aW9uU3luY0NvbmZpZygpO1xuICB9XG5cbiAgYXN5bmMgaGFuZGxlU29uYW11RGljdGlvbmFyeVJlbGF0ZWRDaGFuZ2VzKF86IERpZmZHcm91cHMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCBTeW5jZXJBY3Rpb25zLmFjdGlvblN5bmNTb25hbXVEaWN0aW9uYXJ5KCk7XG4gIH1cblxuICBhc3luYyBoYW5kbGVEcmlmdHMoZHJpZnRzOiBBYnNvbHV0ZVBhdGhbXSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmIChkcmlmdHMubGVuZ3RoID4gMCkge1xuICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICBjaGFsay55ZWxsb3coXG4gICAgICAgICAgXCLimqDvuI8gU29uYW116rCAIOyekOuPmSDsg53shLHtlZwg7YyM7J287JeQIOuMgO2VnCDrs4Dqsr3snbQg6rCQ7KeA65CY7JeI7Iq164uI64ukLiDtjIzsnbzsnbQgU29uYW11IHdhdGNoZXIg7Jm467aA7JeQ7IScIOuzgOqyveuQnCDqsoPsnLzroZwg7LaU7KCV65Cp64uI64ukLlwiLFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICAgIGZvciAoY29uc3QgcCBvZiBkcmlmdHMpIHtcbiAgICAgICAgY29uc29sZS53YXJuKGNoYWxrLnllbGxvdyhgICAtICR7cGF0aC5yZWxhdGl2ZShTb25hbXUuYXBwUm9vdFBhdGgsIHApfWApKTtcbiAgICAgIH1cbiAgICAgIGNvbnNvbGUud2FybihjaGFsay5kaW0oXCIgIOKGkiBgcG5wbSBzb25hbXUgc3luYyAtLWZvcmNlYOulvCDqtozsnqXtlanri4jri6QuXCIpKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICog7KO87Ja07KeEIOyXlO2LsO2LsOyZgCDthZztlIzrpr8g7YKk7JeQIOuMgO2VtCwg7IOd7ISx65CcIOy9lOuTnOqwgCDsobTsnqztlZjripTsp4Ag7ZmV7J247ZWp64uI64ukLlxuICAgKiBAcGFyYW0gZW50aXR5SWQg7JeU7Yuw7YuwIElEXG4gICAqIEBwYXJhbSB0ZW1wbGF0ZUtleSDthZztlIzrpr8g7YKkXG4gICAqIEBwYXJhbSBlbnVtSWQg7Je06rGw7ZiVIElEXG4gICAqIEByZXR1cm5zIOyDneyEseuQnCDsvZTrk5zqsIAg7KG07J6s7ZWY64qU7KeAIOyXrOu2gFxuICAgKi9cbiAgYXN5bmMgY2hlY2tFeGlzdHNHZW5Db2RlKFxuICAgIGVudGl0eUlkOiBzdHJpbmcsXG4gICAgdGVtcGxhdGVLZXk6IFRlbXBsYXRlS2V5LFxuICAgIGVudW1JZD86IHN0cmluZyxcbiAgKTogUHJvbWlzZTx7IHN1YlBhdGg6IHN0cmluZzsgZnVsbFBhdGg6IHN0cmluZzsgaXNFeGlzdHM6IGJvb2xlYW4gfT4ge1xuICAgIGNvbnN0IHsgdGFyZ2V0LCBwYXRoOiBnZW5QYXRoIH0gPSBUZW1wbGF0ZU1hbmFnZXIuZ2V0KHRlbXBsYXRlS2V5KS5nZXRUYXJnZXRBbmRQYXRoKFxuICAgICAgRW50aXR5TWFuYWdlci5nZXROYW1lc0Zyb21JZChlbnRpdHlJZCksXG4gICAgICBlbnVtSWQsXG4gICAgKTtcblxuICAgIGNvbnN0IHN1YlBhdGggPSBwYXRoLmpvaW4odGFyZ2V0LCBnZW5QYXRoKTtcbiAgICBjb25zdCBmdWxsUGF0aCA9IHBhdGguam9pbihTb25hbXUuYXBwUm9vdFBhdGgsIHN1YlBhdGgpO1xuICAgIHJldHVybiB7XG4gICAgICBzdWJQYXRoLFxuICAgICAgZnVsbFBhdGgsXG4gICAgICBpc0V4aXN0czogYXdhaXQgZXhpc3RzKGZ1bGxQYXRoKSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIOyjvOyWtOynhCDsl5Tti7Dti7DsmYAg7Je06rGw7ZiV7JeQIOuMgO2VtCwg7IOd7ISx65CcIOy9lOuTnOqwgCDsobTsnqztlZjripTsp4Ag7ZmV7J247ZWp64uI64ukLlxuICAgKiBAcGFyYW0gZW50aXR5SWQg7JeU7Yuw7YuwIElEXG4gICAqIEBwYXJhbSBlbnVtcyDsl7TqsbDtmJUg66CI7J2067iUXG4gICAqIEByZXR1cm5zIOyDneyEseuQnCDsvZTrk5zqsIAg7KG07J6s7ZWY64qU7KeAIOyXrOu2gFxuICAgKi9cbiAgYXN5bmMgY2hlY2tFeGlzdHMoXG4gICAgZW50aXR5SWQ6IHN0cmluZyxcbiAgICBlbnVtczoge1xuICAgICAgW25hbWU6IHN0cmluZ106IHouWm9kRW51bTtcbiAgICB9LFxuICApOiBQcm9taXNlPFJlY29yZDxgJHtUZW1wbGF0ZUtleX0ke3N0cmluZ31gLCBib29sZWFuPj4ge1xuICAgIGNvbnN0IGtleXM6IFRlbXBsYXRlS2V5W10gPSBUZW1wbGF0ZUtleS5vcHRpb25zO1xuICAgIGNvbnN0IG5hbWVzID0gRW50aXR5TWFuYWdlci5nZXROYW1lc0Zyb21JZChlbnRpdHlJZCk7XG4gICAgY29uc3QgZW51bXNLZXlzID0gT2JqZWN0LmtleXMoZW51bXMpLmZpbHRlcigobmFtZSkgPT4gbmFtZSAhPT0gbmFtZXMuY29uc3RhbnQpO1xuXG4gICAgcmV0dXJuIGF3YWl0IHJlZHVjZUFzeW5jKFxuICAgICAga2V5cyxcbiAgICAgIGFzeW5jIChyZXN1bHQsIGtleSkgPT4ge1xuICAgICAgICBjb25zdCB0cGwgPSBUZW1wbGF0ZU1hbmFnZXIuZ2V0KGtleSk7XG4gICAgICAgIGlmIChrZXkuc3RhcnRzV2l0aChcInZpZXdfZW51bXNcIikpIHtcbiAgICAgICAgICBhd2FpdCBtYXBBc3luYyhlbnVtc0tleXMsIGFzeW5jIChjb21wb25lbnRJZCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgeyB0YXJnZXQsIHBhdGg6IHAgfSA9IHRwbC5nZXRUYXJnZXRBbmRQYXRoKG5hbWVzLCBjb21wb25lbnRJZCk7XG4gICAgICAgICAgICByZXN1bHRbYCR7a2V5fV9fJHtjb21wb25lbnRJZH1gXSA9IGF3YWl0IGV4aXN0cyhcbiAgICAgICAgICAgICAgcGF0aC5qb2luKFNvbmFtdS5hcHBSb290UGF0aCwgdGFyZ2V0LCBwKSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHsgdGFyZ2V0LCBwYXRoOiBwIH0gPSB0cGwuZ2V0VGFyZ2V0QW5kUGF0aChuYW1lcyk7XG4gICAgICAgIGNvbnN0IHsgdGFyZ2V0cyB9ID0gU29uYW11LmNvbmZpZy5zeW5jO1xuICAgICAgICBpZiAodGFyZ2V0LmluY2x1ZGVzKFwiOnRhcmdldFwiKSkge1xuICAgICAgICAgIGF3YWl0IG1hcEFzeW5jKHRhcmdldHMsIGFzeW5jICh0KSA9PiB7XG4gICAgICAgICAgICByZXN1bHRbYCR7a2V5fV9fJHt0fWBdID0gYXdhaXQgZXhpc3RzKFxuICAgICAgICAgICAgICBwYXRoLmpvaW4oU29uYW11LmFwcFJvb3RQYXRoLCB0YXJnZXQucmVwbGFjZShcIjp0YXJnZXRcIiwgdCksIHApLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXN1bHRba2V5XSA9IGF3YWl0IGV4aXN0cyhwYXRoLmpvaW4oU29uYW11LmFwcFJvb3RQYXRoLCB0YXJnZXQsIHApKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICB9LFxuICAgICAge30gYXMgUmVjb3JkPGAke1RlbXBsYXRlS2V5fSR7c3RyaW5nfWAsIGJvb2xlYW4+LFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICog7ZWY7JyE7Zi47ZmY7JqpIO2UhOuhneyLnCDrqZTshozrk5zsnoXri4jri6QuXG4gICAqL1xuICBhc3luYyBjcmVhdGVFbnRpdHkoZm9ybTogVGVtcGxhdGVPcHRpb25zW1wiZW50aXR5XCJdKSB7XG4gICAgcmV0dXJuIGF3YWl0IGNyZWF0ZUVudGl0eShmb3JtKTtcbiAgfVxuXG4gIC8qKlxuICAgKiDtlZjsnITtmLjtmZjsmqkg7ZSE66Gd7IucIOuplOyGjOuTnOyeheuLiOuLpC5cbiAgICovXG4gIGFzeW5jIGRlbEVudGl0eShlbnRpdHlJZDogc3RyaW5nKTogUHJvbWlzZTx7IGRlbFBhdGhzOiBzdHJpbmdbXSB9PiB7XG4gICAgcmV0dXJuIGF3YWl0IGRlbEVudGl0eShlbnRpdHlJZCk7XG4gIH1cblxuICAvKipcbiAgICog7ZWY7JyE7Zi47ZmY7JqpIO2UhOuhneyLnCDrqZTshozrk5zsnoXri4jri6QuXG4gICAqL1xuICBhc3luYyBnZW5lcmF0ZVRlbXBsYXRlPFQgZXh0ZW5kcyBUZW1wbGF0ZUtleT4oXG4gICAga2V5OiBULFxuICAgIHRlbXBsYXRlT3B0aW9uczogVGVtcGxhdGVPcHRpb25zW1RdLFxuICAgIF9nZW5lcmF0ZU9wdGlvbnM/OiBHZW5lcmF0ZU9wdGlvbnMsXG4gICk6IFByb21pc2U8QWJzb2x1dGVQYXRoW10+IHtcbiAgICByZXR1cm4gYXdhaXQgZ2VuZXJhdGVUZW1wbGF0ZShrZXksIHRlbXBsYXRlT3B0aW9ucywgX2dlbmVyYXRlT3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICog7ZWY7JyE7Zi47ZmY7JqpIO2UhOuhneyLnCDrqZTshozrk5zsnoXri4jri6QuXG4gICAqL1xuICBhc3luYyByZW5kZXJUZW1wbGF0ZTxUIGV4dGVuZHMga2V5b2YgVGVtcGxhdGVPcHRpb25zPihcbiAgICBrZXk6IFQsXG4gICAgdGVtcGxhdGVPcHRpb25zOiBUZW1wbGF0ZU9wdGlvbnNbVF0sXG4gICk6IFByb21pc2U8UGF0aEFuZENvZGVbXT4ge1xuICAgIHJldHVybiBhd2FpdCByZW5kZXJUZW1wbGF0ZShrZXksIHRlbXBsYXRlT3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICog7ZWY7JyE7Zi47ZmY7JqpIO2UhOuhneyLnCDrqZTshozrk5zsnoXri4jri6QuXG4gICAqL1xuICBhc3luYyByZW5ld0NoZWNrc3VtcygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gYXdhaXQgcmVuZXdDaGVja3N1bXMoKTtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7a0JBV21EO2NBQ1o7c0JBQ2tCO2FBRWxCO3dCQUV3QjthQUVsQjttQkFFZ0I7b0JBQ1Y7a0JBQ047Z0JBQ0Y7cUJBRXNCO2dCQUNXO3NCQUNSO3lCQUNOO3FCQUNtQztxQkFFaEI7c0JBRS9CO0NBTXJDLFNBQWIsTUFBb0I7RUFDbEIsT0FBbUIsRUFBRTtFQUNyQixRQUFxQixFQUFFO0VBQ3ZCLFNBQXVCLEVBQUU7RUFDekIsWUFBNkMsSUFBSSxLQUFLO0VBQ3RELGVBQTZCLElBQUksY0FBYzs7Ozs7O0VBTy9DLE1BQU0sT0FBc0I7QUFJMUIsU0FBTUEsc0NBQW9EO0FBQzFELFNBQU1DLHlDQUF1RDtHQUc3RCxNQUFNLGVBQWUsTUFBTSxnQ0FBZ0M7QUFDM0QsT0FBSSxhQUFhLFdBQVcsR0FBRztBQUM3QixZQUFRLElBQUksTUFBTSxNQUFNLFFBQVEsV0FBVyx3QkFBd0IsQ0FBQyxDQUFDO0FBQ3JFOztBQU1GLFNBQU0sd0JBQ0osWUFBWTtBQUVWLFVBQU0sS0FBSyxjQUFjLGFBQWE7QUFHdEMsVUFBTSxnQkFBZ0I7TUFFeEI7SUFBRSxpQkFBaUI7SUFBVyxhQUFhO0lBQU8sQ0FDbkQ7Ozs7Ozs7OztFQVVILE1BQU0sWUFBMkI7R0FDL0IsTUFBTSxXQUFXLEtBQUssS0FBSyxPQUFPLGFBQWEsY0FBYztBQUM3RCxPQUFJLE1BQU0sT0FBTyxTQUFTLEVBQUU7QUFDMUIsVUFBTSxPQUFPLFNBQVM7O0FBRXhCLFNBQU0sS0FBSyxNQUFNOzs7Ozs7Ozs7Ozs7Ozs7RUFnQm5CLE1BQU0sV0FBVyxZQUFnRTtHQUMvRSxNQUFNLDBCQUEwQixLQUFLLG1DQUFtQyxXQUFXO0dBQ25GLE1BQU0sc0JBQXNCLE1BQU0sS0FBSyxvQ0FBb0MsV0FBVztBQU10RixTQUFNLEtBQUsseUNBQXlDLHdCQUF3QjtBQUk1RSxPQUFJLG9CQUFvQixTQUFTLEdBQUc7QUFDbEMsVUFBTSxLQUFLLGNBQWMsb0JBQW9COztBQVkvQyxTQUFNLEtBQUssZUFBZTtBQUMxQixTQUFNLEtBQUssZ0JBQWdCO0FBQzNCLFNBQU0sS0FBSyxjQUFjO0FBQ3pCLFNBQU0sS0FBSyxtQkFBbUI7QUFDOUIsU0FBTSxLQUFLLG1CQUFtQjtBQUU5QixRQUFLLGFBQWEsS0FBSyxpQkFBaUI7O0VBRzFDLEFBQVEsbUNBQ04sWUFDcUM7R0FDckMsTUFBTSxTQUFTLEtBQUssS0FBSyxPQUFPLGFBQWEsTUFBTTtHQUNuRCxNQUFNLFNBQVMsSUFBSSxLQUFxQztBQUN4RCxRQUFLLE1BQU0sQ0FBQyxVQUFVLFVBQVUsWUFBWTtBQUMxQyxRQUFJLENBQUMsU0FBUyxXQUFXLE9BQU8sRUFBRTtBQUNoQzs7QUFFRixXQUFPLElBQUksVUFBVSxNQUFNOztBQUU3QixVQUFPOztFQUdULE1BQWMsb0NBQ1osWUFDeUI7R0FDekIsTUFBTSxvQkFBb0IsdUNBQXVDO0dBQ2pFLE1BQU1DLHNCQUFzQyxFQUFFO0FBQzlDLFFBQUssTUFBTSxDQUFDLGlCQUFpQixZQUFZO0lBQ3ZDLE1BQU0sd0JBQXdCLE9BQU8sT0FBTyxrQkFBa0IsQ0FBQyxNQUFNLFlBQ25FLFVBQVUsY0FBYyxRQUFRLENBQ2pDO0FBQ0QsUUFBSSxDQUFDLHVCQUF1QjtBQUMxQjs7QUFFRix3QkFBb0IsS0FBSyxhQUFhOztBQUd4QyxVQUFPOztFQUdULE1BQWMseUNBQ1osWUFDQTtBQUNBLFFBQUssTUFBTSxDQUFDLGNBQWMsVUFBVSxZQUFZO0FBSzlDLFFBQUksQ0FBQyxRQUFRLEVBQUU7S0FDYixNQUFNLG1CQUFvQixNQUFNLElBQUksZUFBZSxjQUFjLE1BQU07QUFFdkUsU0FBSSxpQkFBaUIsU0FBUyxHQUFHO0FBQy9CLGNBQVEsSUFBSSxNQUFNLEtBQUssa0JBQWtCLENBQUM7QUFFMUMsV0FBSyxNQUFNLG1CQUFtQixrQkFBa0I7QUFDOUMsV0FBSTtRQUlGLE1BQU0sY0FBYyxLQUFLLGdDQUFnQyxnQkFBZ0I7QUFDekUsWUFBSSxZQUFZLFNBQVMsR0FBRztBQUMxQixpQkFBUSxJQUNOLE1BQU0sS0FBSyxLQUFLLEtBQUssU0FBUyxPQUFPLGFBQWEsZ0JBQWdCLEdBQUcsRUFDckUsTUFBTSxLQUFLLFNBQVMsWUFBWSxPQUFPLFFBQVEsQ0FDaEQ7ZUFDSTtBQUNMLGlCQUFRLElBQUksTUFBTSxLQUFLLEtBQUssS0FBSyxTQUFTLE9BQU8sYUFBYSxnQkFBZ0IsR0FBRyxDQUFDOztnQkFFN0UsR0FBRztBQUNWLGdCQUFRLE1BQU0sRUFBRTtBQUNoQixnQkFBUSxNQUNOLE1BQU0sSUFBSSxvREFBb0Qsa0JBQWtCLENBQ2pGOzs7OztBQVNULFFBQUksQ0FBQyxRQUFRLElBQUksT0FBTyxPQUFPLE1BQU0sV0FBVyxXQUFXLE9BQU8sa0JBQWtCO0FBQ2xGLFlBQU8saUJBQWlCLGdCQUFnQixDQUFDLGFBQWEsQ0FBQztBQUN2RCxhQUFRLElBQ04sTUFBTSxJQUFJLHFCQUFxQixLQUFLLFNBQVMsT0FBTyxhQUFhLGFBQWEsR0FBRyxDQUNsRjs7OztFQUtQLGdDQUNFLGlCQUNtQztBQUNuQyxPQUFJLENBQUMsZ0JBQWdCLFNBQVMsWUFBNkMsRUFBRTtBQUMzRSxXQUFPLEVBQUU7O0dBR1gsTUFBTSxXQUFXLGNBQWMsb0JBQW9CLGdCQUFnQjtHQUNuRSxNQUFNLFdBQVcsZUFBZSxRQUFRLFFBQVEsSUFBSSxjQUFjLEdBQUcsU0FBUyxPQUFPO0FBQ3JGLFFBQUssTUFBTSxPQUFPLFVBQVU7SUFDMUIsTUFBTSxNQUFNLGVBQWUsUUFBUSxJQUFJO0FBQ3ZDLFFBQUksUUFBUSxDQUFDLEdBQUc7QUFDZCxvQkFBZSxPQUFPLEtBQUssRUFBRTs7O0FBSWpDLFVBQU87O0VBR1QsTUFBTSxnQkFBZ0I7QUFDcEIsUUFBSyxRQUFRLE1BQU0sV0FBVzs7RUFHaEMsTUFBTSxpQkFBaUI7QUFDckIsUUFBSyxTQUFTLE1BQU0sWUFBWTs7RUFHbEMsTUFBTSxlQUFlO0FBQ25CLFFBQUssT0FBTyxNQUFNLFVBQVU7O0VBRzlCLE1BQU0sb0JBQW9CO0FBQ3hCLFFBQUssWUFBWSxNQUFNLGVBQWU7QUFDdEMsU0FBTSxPQUFPLFVBQVUsWUFBWSxLQUFLLFVBQVU7O0VBR3BELE1BQU0sb0JBQW1DO0dBQ3ZDLE1BQU0sZ0JBQWdCLEtBQUssS0FBSyxPQUFPLGFBQWEsVUFBVTtHQUc5RCxNQUFNLEVBQUUsbUJBQW1CLE1BQU0sT0FBTztBQUN4QyxtQkFBZ0I7QUFHaEIsT0FBSSxDQUFFLE1BQU0sT0FBTyxjQUFjLEVBQUc7QUFDbEM7O0dBSUYsTUFBTSxFQUFFLGNBQWMsTUFBTSxPQUFPO0dBQ25DLE1BQU0sRUFBRSxrQkFBa0IsTUFBTSxPQUFPO0dBQ3ZDLE1BQU0sRUFBRSxnQkFBZ0IsTUFBTSxPQUFPO0dBR3JDLE1BQU0sUUFBUSxNQUFNLFVBQVUsS0FBSyxLQUFLLGVBQWUsWUFBWSxVQUFVLENBQUMsQ0FBQztBQUUvRSxRQUFLLE1BQU0sUUFBUSxPQUFPO0FBQ3hCLFFBQUk7QUFFRixXQUFNLGNBQWMsS0FBSzthQUNsQixHQUFHO0FBQ1YsYUFBUSxNQUFNLDZCQUE2QixRQUFRLEVBQUU7Ozs7Ozs7Ozs7O0VBWTNELE1BQU0sY0FBYyxlQUFtRTtHQUNyRixNQUFNLGFBQWEsS0FBSyxvQkFBb0IsY0FBYztHQUMxRCxNQUFNLFlBQVksT0FBTyxLQUFLLFdBQVc7R0FJekMsTUFBTSxFQUFFLGVBQWUsZ0JBQWdCLG1CQUFtQixLQUFLLGNBQzdELFdBQ0EsV0FDRDtBQUVELE9BQUksY0FBYyxVQUFVLFFBQVEsRUFBRTtBQUNwQyxVQUFNLEtBQUsseUJBQXlCLFdBQVc7O0FBR2pELE9BQUksY0FBYyxTQUFTLFFBQVEsRUFBRTtBQUNuQyxVQUFNLEtBQUssNEJBQTRCLFdBQVc7O0FBR3BELE9BQUksY0FBYyxTQUFTLFlBQVksRUFBRTtBQUN2QyxVQUFNLEtBQUssNkJBQTZCLFdBQVc7O0FBR3JELE9BQUksY0FBYyxTQUFTLEVBQUU7QUFDM0IsVUFBTSxLQUFLLG9CQUFvQixXQUFXOztBQUc1QyxPQUFJLGNBQWMsUUFBUSxVQUFrQixTQUE0QixFQUFFO0FBQ3hFLFVBQU0sS0FBSyxxQ0FBcUMsV0FBVzs7QUFHN0QsT0FBSSxnQkFBZ0IsRUFBRTtBQUlwQixVQUFNLEtBQUssYUFBYSxnQkFBZ0IsQ0FBQzs7QUFHM0MsVUFBTyxFQUNMLFdBQ0Q7O0VBR0gsb0JBQW9CLFdBQXVDO0dBQ3pELE1BQU0sZUFBZSx5QkFBeUI7R0FDOUMsTUFBTSxZQUFZLE9BQU8sS0FBSyxhQUFhO0FBRTNDLFVBQU8sTUFBTSxZQUFZLGFBQWE7SUFFcEMsTUFBTSxlQUFlLEtBQUssU0FBUyxPQUFPLGFBQWEsU0FBUztBQUNoRSxRQUFJLGFBQWEsV0FBVyxLQUFLLENBQUUsUUFBTztBQUUxQyxTQUFLLE1BQU0sWUFBWSxXQUFXO0FBQ2hDLFNBQUksVUFBVSxjQUFjLGFBQWEsVUFBVSxFQUFFO0FBQ25ELGFBQU87OztBQUdYLFdBQU87S0FDUDs7RUFHSixBQUFRLGNBQWMsV0FBdUIsWUFBd0I7R0FDbkUsTUFBTSxVQUFVLElBQUksS0FBZTs7Ozs7Ozs7R0FTbkMsTUFBTSxpQkFBaUIsR0FBRyxVQUFzQjtJQUM5QyxNQUFNLFdBQVcsTUFBTSxRQUFRLE1BQU0sVUFBVSxTQUFTLEVBQUUsQ0FBQztBQUMzRCxhQUFTLFNBQVMsTUFBTSxRQUFRLElBQUksRUFBRSxDQUFDO0FBQ3ZDLFdBQU8sU0FBUyxTQUFTOzs7OztHQU0zQixNQUFNLHVCQUF1QixRQUFRLFNBQVM7Ozs7R0FLOUMsTUFBTSx1QkFDSixVQUFVLFFBQVEsTUFBTSxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQUMsQ0FBQyxTQUFTLE1BQU0sV0FBVyxNQUFNLEVBQUUsQ0FBQztBQUU5RSxVQUFPO0lBQUU7SUFBZTtJQUFnQjtJQUFnQjs7RUFHMUQsTUFBTSx5QkFBeUIsWUFBdUM7QUFDcEUsU0FBTSxFQUFFLDRCQUE0QixFQUFFLFlBQVksQ0FBQztBQUVuRCxTQUFNLGNBQWMsUUFBUTtHQUk1QixNQUFNLGFBQWEsV0FBVyxRQUFRLEdBQUcsRUFBRTtBQUMzQyxPQUFJLGVBQWUsV0FBVztJQUM1QixNQUFNLFdBQVcsY0FBYyxvQkFBb0IsV0FBVztJQUM5RCxNQUFNLFNBQVMsY0FBYyxJQUFJLFNBQVM7SUFHMUMsTUFBTSxlQUFlLEtBQUssS0FDeEIsT0FBTyxhQUNQLG1CQUFtQixPQUFPLE1BQU0sR0FBRyxHQUFHLE9BQU8sTUFBTSxHQUFHLFdBQ3ZEO0FBRUQsUUFBSSxPQUFPLGFBQWEsYUFBYSxDQUFFLE1BQU0sT0FBTyxhQUFhLEVBQUc7S0FFbEUsTUFBTSxRQUFRLE1BQU1DLDJCQUF5QyxTQUFTO0FBR3RFLFdBQU1DLHlCQUF1QyxNQUFNOzs7R0FLdkQsTUFBTSxZQUFZLE1BQU1DLHVCQUFxQztBQUc3RCxTQUFNRCx5QkFBdUMsVUFBVTs7RUFHekQsTUFBTSw0QkFBNEIsWUFBdUM7QUFDdkUsU0FBTSxFQUFFLCtCQUErQixFQUFFLFlBQVksQ0FBQztHQUN0RCxNQUFNLGNBQWMsQ0FBQyxHQUFJLFdBQVcsU0FBUyxFQUFFLEVBQUcsR0FBSSxXQUFXLFNBQVMsRUFBRSxDQUFFO0FBSTlFLFNBQU0sS0FBSyxnQkFBZ0I7QUFDM0IsU0FBTSxLQUFLLGVBQWU7QUFDMUIsU0FBTSxLQUFLLGNBQWM7R0FFekIsTUFBTUUsU0FFQSxZQUFZLEtBQUssY0FBYztBQUNuQyxRQUFJLFVBQVUsU0FBUyxZQUFZLElBQUksVUFBVSxTQUFTLFlBQVksRUFBRTtLQUN0RSxNQUFNLFdBQVcsY0FBYyxvQkFBb0IsVUFBVTtBQUM3RCxZQUFPLFNBQVM7QUFDaEIsWUFBTyxFQUNMLGFBQWEsY0FBYyxlQUFlLFNBQVMsRUFDcEQ7O0FBRUgsVUFBTSxJQUFJLE1BQU0sZ0JBQWdCO0tBQ2hDO0FBR0YsU0FBTUMsdUJBQXFDLE9BQU87QUFDbEQsU0FBTUMscUJBQW1DO0dBR3pDLE1BQU0sVUFBVSxNQUFNQywwQkFBd0M7QUFHOUQsU0FBTUwseUJBQXVDLFFBQVE7O0VBR3ZELE1BQU0sNkJBQTZCLFlBQXVDO0FBQ3hFLFNBQU0sRUFBRSxnQ0FBZ0MsRUFBRSxZQUFZLENBQUM7R0FDdkQsTUFBTSxVQUFVLE9BQU8sQ0FBQyxHQUFJLFdBQVcsU0FBUyxFQUFFLEVBQUcsR0FBSSxXQUFXLGFBQWEsRUFBRSxDQUFFLENBQUM7QUFDdEYsU0FBTUEseUJBQXVDLFFBQVE7O0VBR3ZELE1BQU0sb0JBQW9CLEdBQThCO0FBQ3RELFNBQU1NLGtCQUFnQzs7RUFHeEMsTUFBTSxxQ0FBcUMsR0FBOEI7QUFDdkUsU0FBTUMsNEJBQTBDOztFQUdsRCxNQUFNLGFBQWEsUUFBdUM7QUFDeEQsT0FBSSxPQUFPLFNBQVMsR0FBRztBQUNyQixZQUFRLEtBQ04sTUFBTSxPQUNKLCtFQUNELENBQ0Y7QUFDRCxTQUFLLE1BQU0sS0FBSyxRQUFRO0FBQ3RCLGFBQVEsS0FBSyxNQUFNLE9BQU8sT0FBTyxLQUFLLFNBQVMsT0FBTyxhQUFhLEVBQUUsR0FBRyxDQUFDOztBQUUzRSxZQUFRLEtBQUssTUFBTSxJQUFJLHlDQUF5QyxDQUFDOzs7Ozs7Ozs7O0VBV3JFLE1BQU0sbUJBQ0osVUFDQSxhQUNBLFFBQ21FO0dBQ25FLE1BQU0sRUFBRSxRQUFRLE1BQU0sWUFBWSxnQkFBZ0IsSUFBSSxZQUFZLENBQUMsaUJBQ2pFLGNBQWMsZUFBZSxTQUFTLEVBQ3RDLE9BQ0Q7R0FFRCxNQUFNLFVBQVUsS0FBSyxLQUFLLFFBQVEsUUFBUTtHQUMxQyxNQUFNLFdBQVcsS0FBSyxLQUFLLE9BQU8sYUFBYSxRQUFRO0FBQ3ZELFVBQU87SUFDTDtJQUNBO0lBQ0EsVUFBVSxNQUFNLE9BQU8sU0FBUztJQUNqQzs7Ozs7Ozs7RUFTSCxNQUFNLFlBQ0osVUFDQSxPQUdxRDtHQUNyRCxNQUFNQyxPQUFzQixZQUFZO0dBQ3hDLE1BQU0sUUFBUSxjQUFjLGVBQWUsU0FBUztHQUNwRCxNQUFNLFlBQVksT0FBTyxLQUFLLE1BQU0sQ0FBQyxRQUFRLFNBQVMsU0FBUyxNQUFNLFNBQVM7QUFFOUUsVUFBTyxNQUFNLFlBQ1gsTUFDQSxPQUFPLFFBQVEsUUFBUTtJQUNyQixNQUFNLE1BQU0sZ0JBQWdCLElBQUksSUFBSTtBQUNwQyxRQUFJLElBQUksV0FBVyxhQUFhLEVBQUU7QUFDaEMsV0FBTSxTQUFTLFdBQVcsT0FBTyxnQkFBZ0I7TUFDL0MsTUFBTSxFQUFFLGtCQUFRLE1BQU1DLFFBQU0sSUFBSSxpQkFBaUIsT0FBTyxZQUFZO0FBQ3BFLGFBQU8sR0FBRyxJQUFJLElBQUksaUJBQWlCLE1BQU0sT0FDdkMsS0FBSyxLQUFLLE9BQU8sYUFBYUMsVUFBUUQsSUFBRSxDQUN6QztPQUNEO0FBQ0YsWUFBTzs7SUFHVCxNQUFNLEVBQUUsUUFBUSxNQUFNLE1BQU0sSUFBSSxpQkFBaUIsTUFBTTtJQUN2RCxNQUFNLEVBQUUsWUFBWSxPQUFPLE9BQU87QUFDbEMsUUFBSSxPQUFPLFNBQVMsVUFBVSxFQUFFO0FBQzlCLFdBQU0sU0FBUyxTQUFTLE9BQU8sTUFBTTtBQUNuQyxhQUFPLEdBQUcsSUFBSSxJQUFJLE9BQU8sTUFBTSxPQUM3QixLQUFLLEtBQUssT0FBTyxhQUFhLE9BQU8sUUFBUSxXQUFXLEVBQUUsRUFBRSxFQUFFLENBQy9EO09BQ0Q7V0FDRztBQUNMLFlBQU8sT0FBTyxNQUFNLE9BQU8sS0FBSyxLQUFLLE9BQU8sYUFBYSxRQUFRLEVBQUUsQ0FBQzs7QUFHdEUsV0FBTztNQUVULEVBQUUsQ0FDSDs7Ozs7RUFNSCxNQUFNLGFBQWEsTUFBaUM7QUFDbEQsVUFBTyxNQUFNLGFBQWEsS0FBSzs7Ozs7RUFNakMsTUFBTSxVQUFVLFVBQW1EO0FBQ2pFLFVBQU8sTUFBTSxVQUFVLFNBQVM7Ozs7O0VBTWxDLE1BQU0saUJBQ0osS0FDQSxpQkFDQSxrQkFDeUI7QUFDekIsVUFBTyxNQUFNLGlCQUFpQixLQUFLLGlCQUFpQixpQkFBaUI7Ozs7O0VBTXZFLE1BQU0sZUFDSixLQUNBLGlCQUN3QjtBQUN4QixVQUFPLE1BQU0sZUFBZSxLQUFLLGdCQUFnQjs7Ozs7RUFNbkQsTUFBTSxpQkFBZ0M7QUFDcEMsVUFBTyxNQUFNLGdCQUFnQiJ9