obsidian-dev-utils 87.0.2 → 87.0.4

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 (69) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/demo-vault-helper/main.js +232 -0
  3. package/dist/demo-vault-helper/manifest.json +9 -0
  4. package/dist/lib/cjs/__merged.cjs +13 -1
  5. package/dist/lib/cjs/__merged.d.cts +4 -2
  6. package/dist/lib/cjs/generated-during-build.cjs +1 -1
  7. package/dist/lib/cjs/obsidian/code-block-reg-exp.cjs +138 -0
  8. package/dist/lib/cjs/obsidian/code-block-reg-exp.d.cts +33 -0
  9. package/dist/lib/cjs/obsidian/command-handlers/open-demo-vault-command-handler.cjs +13 -6
  10. package/dist/lib/cjs/obsidian/command-handlers/open-demo-vault-command-handler.d.cts +13 -5
  11. package/dist/lib/cjs/obsidian/community-plugins.cjs +25 -1
  12. package/dist/lib/cjs/obsidian/community-plugins.d.cts +28 -0
  13. package/dist/lib/cjs/obsidian/demo-vault-helper.cjs +159 -0
  14. package/dist/lib/cjs/obsidian/demo-vault-helper.d.cts +40 -0
  15. package/dist/lib/cjs/obsidian/desktop-demo-vault-opener.cjs +17 -13
  16. package/dist/lib/cjs/obsidian/desktop-demo-vault-opener.d.cts +13 -5
  17. package/dist/lib/cjs/obsidian/index.cjs +7 -1
  18. package/dist/lib/cjs/obsidian/index.d.cts +2 -0
  19. package/dist/lib/cjs/obsidian/markdown-code-block-processor.cjs +12 -10
  20. package/dist/lib/cjs/obsidian/plugin/obsidian-plugin-repo-paths.cjs +2 -1
  21. package/dist/lib/cjs/obsidian/plugin/obsidian-plugin-repo-paths.d.cts +2 -0
  22. package/dist/lib/cjs/reg-exp.cjs +11 -1
  23. package/dist/lib/cjs/reg-exp.d.cts +34 -0
  24. package/dist/lib/cjs/script-utils/demo-vault-coverage.cjs +329 -0
  25. package/dist/lib/cjs/script-utils/demo-vault-coverage.d.cts +298 -0
  26. package/dist/lib/cjs/script-utils/demo-vault.cjs +36 -3
  27. package/dist/lib/cjs/script-utils/demo-vault.d.cts +5 -5
  28. package/dist/lib/cjs/script-utils/index.cjs +4 -1
  29. package/dist/lib/cjs/script-utils/index.d.cts +1 -0
  30. package/dist/lib/cjs/script-utils/linters/eslint-config.cjs +14 -1
  31. package/dist/lib/cjs/script-utils/linters/eslint-rules/require-method-template.cjs +4 -5
  32. package/dist/lib/cjs/script-utils/obsidian-dev-utils-repo-paths.cjs +2 -1
  33. package/dist/lib/cjs/script-utils/obsidian-dev-utils-repo-paths.d.cts +2 -0
  34. package/dist/lib/cjs/script-utils/version.cjs +2 -2
  35. package/dist/lib/esm/__merged.d.mts +4 -2
  36. package/dist/lib/esm/__merged.mjs +11 -1
  37. package/dist/lib/esm/generated-during-build.mjs +1 -1
  38. package/dist/lib/esm/obsidian/code-block-reg-exp.d.mts +33 -0
  39. package/dist/lib/esm/obsidian/code-block-reg-exp.mjs +30 -0
  40. package/dist/lib/esm/obsidian/command-handlers/open-demo-vault-command-handler.d.mts +13 -5
  41. package/dist/lib/esm/obsidian/command-handlers/open-demo-vault-command-handler.mjs +13 -6
  42. package/dist/lib/esm/obsidian/community-plugins.d.mts +28 -0
  43. package/dist/lib/esm/obsidian/community-plugins.mjs +24 -1
  44. package/dist/lib/esm/obsidian/demo-vault-helper.d.mts +40 -0
  45. package/dist/lib/esm/obsidian/demo-vault-helper.mjs +56 -0
  46. package/dist/lib/esm/obsidian/desktop-demo-vault-opener.d.mts +13 -5
  47. package/dist/lib/esm/obsidian/desktop-demo-vault-opener.mjs +17 -13
  48. package/dist/lib/esm/obsidian/index.d.mts +2 -0
  49. package/dist/lib/esm/obsidian/index.mjs +5 -1
  50. package/dist/lib/esm/obsidian/markdown-code-block-processor.mjs +15 -10
  51. package/dist/lib/esm/obsidian/plugin/obsidian-plugin-repo-paths.d.mts +2 -0
  52. package/dist/lib/esm/obsidian/plugin/obsidian-plugin-repo-paths.mjs +2 -1
  53. package/dist/lib/esm/reg-exp.d.mts +34 -0
  54. package/dist/lib/esm/reg-exp.mjs +11 -2
  55. package/dist/lib/esm/script-utils/demo-vault-coverage.d.mts +298 -0
  56. package/dist/lib/esm/script-utils/demo-vault-coverage.mjs +230 -0
  57. package/dist/lib/esm/script-utils/demo-vault.d.mts +5 -5
  58. package/dist/lib/esm/script-utils/demo-vault.mjs +31 -5
  59. package/dist/lib/esm/script-utils/index.d.mts +1 -0
  60. package/dist/lib/esm/script-utils/index.mjs +3 -1
  61. package/dist/lib/esm/script-utils/linters/eslint-config.mjs +14 -1
  62. package/dist/lib/esm/script-utils/linters/eslint-rules/require-method-template.mjs +4 -5
  63. package/dist/lib/esm/script-utils/obsidian-dev-utils-repo-paths.d.mts +2 -0
  64. package/dist/lib/esm/script-utils/obsidian-dev-utils-repo-paths.mjs +2 -1
  65. package/dist/lib/esm/script-utils/version.mjs +2 -2
  66. package/obsidian/code-block-reg-exp/package.json +6 -0
  67. package/obsidian/demo-vault-helper/package.json +6 -0
  68. package/package.json +6 -5
  69. package/script-utils/demo-vault-coverage/package.json +6 -0
@@ -0,0 +1,329 @@
1
+ /*
2
+ THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
3
+ if you want to view the source, please visit the github repository of this plugin
4
+ */
5
+
6
+ (function initCjs() {
7
+ // eslint-disable-next-line obsidianmd/no-global-this -- Actively use globalThis.
8
+ const globalThisRecord = globalThis;
9
+ globalThisRecord['__name'] ??= name;
10
+ const originalRequire = require;
11
+ if (originalRequire && !originalRequire.__isPatched) {
12
+ // eslint-disable-next-line no-global-assign, no-implicit-globals -- We need to patch the `require()` function.
13
+ require = Object.assign(
14
+ (id) => requirePatched(id),
15
+ originalRequire,
16
+ {
17
+ __isPatched: true
18
+ }
19
+ );
20
+ }
21
+
22
+ const newFuncs = {
23
+ __extractDefault() {
24
+ return extractDefault;
25
+ },
26
+ process() {
27
+ const browserProcess = {
28
+ browser: true,
29
+ cwd() {
30
+ return '/';
31
+ },
32
+ env: {},
33
+ platform: 'android'
34
+ };
35
+ return browserProcess;
36
+ }
37
+ };
38
+
39
+ for (const key of Object.keys(newFuncs)) {
40
+ globalThisRecord[key] ??= newFuncs[key]?.();
41
+ }
42
+
43
+ function name(obj) {
44
+ return obj;
45
+ }
46
+
47
+ function extractDefault(module) {
48
+ return module && module.__esModule && 'default' in module ? module.default : module;
49
+ }
50
+
51
+ const OBSIDIAN_BUILT_IN_MODULE_NAMES = [
52
+ 'obsidian',
53
+ '@codemirror/autocomplete',
54
+ '@codemirror/collab',
55
+ '@codemirror/commands',
56
+ '@codemirror/language',
57
+ '@codemirror/lint',
58
+ '@codemirror/search',
59
+ '@codemirror/state',
60
+ '@codemirror/text',
61
+ '@codemirror/view',
62
+ '@lezer/common',
63
+ '@lezer/lr',
64
+ '@lezer/highlight'];
65
+
66
+
67
+ const DEPRECATED_OBSIDIAN_BUILT_IN_MODULE_NAMES = [
68
+ '@codemirror/closebrackets',
69
+ '@codemirror/comment',
70
+ '@codemirror/fold',
71
+ '@codemirror/gutter',
72
+ '@codemirror/highlight',
73
+ '@codemirror/history',
74
+ '@codemirror/matchbrackets',
75
+ '@codemirror/panel',
76
+ '@codemirror/rangeset',
77
+ '@codemirror/rectangular-selection',
78
+ '@codemirror/stream-parser',
79
+ '@codemirror/tooltip'];
80
+
81
+
82
+ function requirePatched(id) {
83
+ if (OBSIDIAN_BUILT_IN_MODULE_NAMES.includes(id) || DEPRECATED_OBSIDIAN_BUILT_IN_MODULE_NAMES.includes(id)) {
84
+ return originalRequire?.(id);
85
+ }
86
+
87
+ // eslint-disable-next-line @typescript-eslint/no-deprecated, obsidianmd/no-global-this -- Need access to app. Actively use globalThis.
88
+ if (globalThis.app.isMobile) {
89
+ if (id === 'process' || id === 'node:process') {
90
+ // eslint-disable-next-line no-console -- Valid usage.
91
+ console.debug(`The most likely you can safely ignore this error. Module not found: ${id}. Fake process object is returned instead.`);
92
+ // eslint-disable-next-line obsidianmd/no-global-this -- Actively use globalThis.
93
+ return globalThis.process;
94
+ }
95
+ } else {
96
+ const module = originalRequire?.(id);
97
+ if (module) {
98
+ return extractDefault(module);
99
+ }
100
+ }
101
+
102
+ // eslint-disable-next-line no-console -- Valid usage.
103
+ console.debug(`The most likely you can safely ignore this error. Module not found: ${id}. Empty object is returned instead.`);
104
+ return {};
105
+ }
106
+ })();
107
+
108
+ "use strict";
109
+ var __defProp = Object.defineProperty;
110
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
111
+ var __getOwnPropNames = Object.getOwnPropertyNames;
112
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
113
+ var __export = (target, all) => {
114
+ for (var name in all)
115
+ __defProp(target, name, { get: all[name], enumerable: true });
116
+ };
117
+ var __copyProps = (to, from, except, desc) => {
118
+ if (from && typeof from === "object" || typeof from === "function") {
119
+ for (let key of __getOwnPropNames(from))
120
+ if (!__hasOwnProp.call(to, key) && key !== except)
121
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
122
+ }
123
+ return to;
124
+ };
125
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
126
+ var demo_vault_coverage_exports = {};
127
+ __export(demo_vault_coverage_exports, {
128
+ DemoVaultCoverageChecker: () => DemoVaultCoverageChecker,
129
+ registerDemoVaultCoverageSuite: () => registerDemoVaultCoverageSuite
130
+ });
131
+ module.exports = __toCommonJS(demo_vault_coverage_exports);
132
+ var import_node_fs = require('node:fs');
133
+ var import_vitest = require('vitest');
134
+ var import_obsidian_plugin_repo_paths = require('../obsidian/plugin/obsidian-plugin-repo-paths.cjs');
135
+ var import_path = require('../path.cjs');
136
+ var import_reg_exp = require('../reg-exp.cjs');
137
+ class DemoVaultCoverageChecker {
138
+ cachedCorpus = null;
139
+ demoVaultFolder;
140
+ rootFolder;
141
+ /**
142
+ * Creates a checker rooted at a plugin repo.
143
+ *
144
+ * @param params - The parameters for the constructor.
145
+ */
146
+ constructor(params) {
147
+ this.rootFolder = params.rootFolder;
148
+ this.demoVaultFolder = (0, import_path.join)(this.rootFolder, import_obsidian_plugin_repo_paths.ObsidianPluginRepoPaths.DemoVault);
149
+ }
150
+ /**
151
+ * Collects the demo notes as paths relative to the demo vault folder (for a non-trivial-surface guard).
152
+ *
153
+ * @returns The relative paths of every `*.md` note in the demo vault.
154
+ */
155
+ collectDemoNoteRelativePaths() {
156
+ return this.collectMarkdownFiles(this.demoVaultFolder).map((file) => (0, import_path.relative)(this.demoVaultFolder, file));
157
+ }
158
+ /**
159
+ * Finds members that the demo notes reference on a receiver but that no longer exist on it (rename drift).
160
+ *
161
+ * @param params - The parameters for the lookup.
162
+ * @returns The distinct stale member names referenced in the demo corpus.
163
+ */
164
+ findStaleReferences(params) {
165
+ const validMembers = new Set(params.validMembers);
166
+ const referenced = [...this.readCorpus().matchAll(new RegExp(`${params.receiver}\\.(?<member>\\w+)`, "g"))].map((match) => (0, import_reg_exp.getMandatoryNamedGroup)(match, "member"));
167
+ return [...new Set(referenced)].filter((member) => !validMembers.has(member));
168
+ }
169
+ /**
170
+ * Finds members that are not demonstrated anywhere in the demo corpus.
171
+ *
172
+ * @param params - The parameters for the lookup.
173
+ * @returns The member names with no demonstration.
174
+ */
175
+ findUndemonstratedMembers(params) {
176
+ const corpus = this.readCorpus();
177
+ return params.members.filter((member) => {
178
+ const needle = params.receiver === void 0 ? member : `${params.receiver}.${member}`;
179
+ return !corpus.includes(needle);
180
+ });
181
+ }
182
+ /**
183
+ * Finds feature docs that no demo note links to.
184
+ *
185
+ * @param params - The parameters for the lookup.
186
+ * @returns The feature-doc basenames (without `.md`) not linked from any demo note.
187
+ */
188
+ findUnlinkedFeatureDocs(params) {
189
+ const nonFeatureDocs = new Set(params.nonFeatureDocs);
190
+ const featureDocs = (0, import_node_fs.readdirSync)((0, import_path.join)(this.rootFolder, params.docsFolder)).filter((file) => file.endsWith(".md")).map((file) => file.replace(/\.md$/, "")).filter((name) => !nonFeatureDocs.has(name));
191
+ const linkedDocs = new Set(
192
+ [...this.readCorpus().matchAll(/docs\/(?<doc>[\w-]+)\.md/g)].map((match) => (0, import_reg_exp.getMandatoryNamedGroup)(match, "doc"))
193
+ );
194
+ return featureDocs.filter((doc) => !linkedDocs.has(doc));
195
+ }
196
+ /**
197
+ * Parses the names of the `export function`s (including `async` and generator declarations) in a source file.
198
+ *
199
+ * @param params - The parameters for the lookup.
200
+ * @returns The exported function names in source order.
201
+ */
202
+ getExportedFunctionNames(params) {
203
+ const source = (0, import_node_fs.readFileSync)((0, import_path.join)(this.rootFolder, params.sourcePath), "utf-8");
204
+ return [...source.matchAll(/^export (?:async )?function\*? (?<name>\w+)/gm)].map((match) => (0, import_reg_exp.getMandatoryNamedGroup)(match, "name"));
205
+ }
206
+ /**
207
+ * Parses the members of an `export interface`, `export class`, or `export enum` declared in a source file.
208
+ *
209
+ * @param params - The parameters for the lookup.
210
+ * @returns The parsed {@link InterfaceMembers}.
211
+ * @throws When the interface, class, or enum cannot be found in the source file.
212
+ */
213
+ getInterfaceMembers(params) {
214
+ const source = (0, import_node_fs.readFileSync)((0, import_path.join)(this.rootFolder, params.sourcePath), "utf-8");
215
+ const match = new RegExp(`export (?<keyword>interface|class|enum) ${params.interfaceName}\\b[^{]*\\{(?<body>[\\s\\S]*?)\\n\\}`).exec(source);
216
+ if (!match) {
217
+ throw new Error(`Could not find interface ${params.interfaceName}`);
218
+ }
219
+ return parseMembers((0, import_reg_exp.getMandatoryNamedGroup)(match, "keyword"), (0, import_reg_exp.getMandatoryNamedGroup)(match, "body"));
220
+ }
221
+ /**
222
+ * Reads and caches the demo corpus — every `*.md` note in the demo vault joined into one string.
223
+ *
224
+ * @returns The concatenated demo-note contents.
225
+ */
226
+ readCorpus() {
227
+ this.cachedCorpus ??= this.collectMarkdownFiles(this.demoVaultFolder).map((file) => (0, import_node_fs.readFileSync)(file, "utf-8")).join("\n");
228
+ return this.cachedCorpus;
229
+ }
230
+ collectMarkdownFiles(folder) {
231
+ const result = [];
232
+ for (const entry of (0, import_node_fs.readdirSync)(folder, { withFileTypes: true })) {
233
+ if (entry.isDirectory()) {
234
+ if (entry.name === import_obsidian_plugin_repo_paths.ObsidianPluginRepoPaths.NodeModules) {
235
+ continue;
236
+ }
237
+ result.push(...this.collectMarkdownFiles((0, import_path.join)(folder, entry.name)));
238
+ } else if (entry.name.endsWith(".md")) {
239
+ result.push((0, import_path.join)(folder, entry.name));
240
+ }
241
+ }
242
+ return result;
243
+ }
244
+ }
245
+ function registerDemoVaultCoverageSuite(params) {
246
+ const checker = new DemoVaultCoverageChecker({ rootFolder: params.rootFolder });
247
+ (0, import_vitest.describe)("demo-vault coverage", () => {
248
+ for (const spec of params.interfaces) {
249
+ (0, import_vitest.it)(`demonstrates every ${spec.interfaceName} ${spec.kind}`, () => {
250
+ const members = checker.getInterfaceMembers(spec);
251
+ const demonstrated = members[spec.kind];
252
+ (0, import_vitest.expect)(demonstrated.length).toBeGreaterThan(0);
253
+ (0, import_vitest.expect)(checker.findUndemonstratedMembers({ members: demonstrated, receiver: spec.receiver })).toEqual([]);
254
+ });
255
+ (0, import_vitest.it)(`references no ${spec.interfaceName} member that no longer exists`, () => {
256
+ const members = checker.getInterfaceMembers(spec);
257
+ (0, import_vitest.expect)(checker.findStaleReferences({ receiver: spec.receiver, validMembers: members.all })).toEqual([]);
258
+ });
259
+ }
260
+ for (const spec of params.configInterfaces) {
261
+ (0, import_vitest.it)(`demonstrates every ${spec.interfaceName} option`, () => {
262
+ const members = checker.getInterfaceMembers(spec);
263
+ (0, import_vitest.expect)(members.properties.length).toBeGreaterThan(0);
264
+ (0, import_vitest.expect)(checker.findUndemonstratedMembers({ members: members.properties })).toEqual([]);
265
+ });
266
+ }
267
+ for (const spec of params.functionModules ?? []) {
268
+ (0, import_vitest.it)(`demonstrates every exported function in ${spec.sourcePath}`, () => {
269
+ const functionNames = checker.getExportedFunctionNames(spec);
270
+ (0, import_vitest.expect)(functionNames.length).toBeGreaterThan(0);
271
+ (0, import_vitest.expect)(checker.findUndemonstratedMembers({ members: functionNames })).toEqual([]);
272
+ });
273
+ }
274
+ const docs = params.docs;
275
+ if (docs) {
276
+ (0, import_vitest.it)("links a demo note for every feature doc", () => {
277
+ (0, import_vitest.expect)(checker.findUnlinkedFeatureDocs({ docsFolder: docs.folder, nonFeatureDocs: docs.nonFeatureDocs })).toEqual([]);
278
+ });
279
+ }
280
+ (0, import_vitest.it)("keeps the reflected surface non-trivial", () => {
281
+ const guard = params.nonTrivialGuard;
282
+ const members = checker.getInterfaceMembers(guard);
283
+ (0, import_vitest.expect)(members.all).toContain(guard.expectMember);
284
+ (0, import_vitest.expect)(checker.collectDemoNoteRelativePaths()).toContain(guard.expectDemoNote);
285
+ });
286
+ });
287
+ }
288
+ const CLASS_MEMBER_MODIFIERS = "(?:(?:public|private|protected|readonly|static|abstract|override)\\s+)*";
289
+ function buildMembers(methods, properties) {
290
+ return {
291
+ all: [...methods, ...properties],
292
+ methods,
293
+ properties
294
+ };
295
+ }
296
+ function extractClassMethodNames(classBody) {
297
+ return [...classBody.matchAll(new RegExp(`^ {2}(?<modifiers>${CLASS_MEMBER_MODIFIERS})(?<name>\\w+)(?:<[^>]*>)?\\(`, "gm"))].filter((match) => !isNonPublicMember((0, import_reg_exp.getMandatoryNamedGroup)(match, "modifiers"))).map((match) => (0, import_reg_exp.getMandatoryNamedGroup)(match, "name"));
298
+ }
299
+ function extractClassPropertyNames(classBody) {
300
+ return [...classBody.matchAll(new RegExp(`^ {2}(?<modifiers>${CLASS_MEMBER_MODIFIERS})(?<name>\\w+)\\s*\\??\\s*[:=]`, "gm"))].filter((match) => !isNonPublicMember((0, import_reg_exp.getMandatoryNamedGroup)(match, "modifiers"))).map((match) => (0, import_reg_exp.getMandatoryNamedGroup)(match, "name"));
301
+ }
302
+ function extractEnumMemberNames(enumBody) {
303
+ return [...enumBody.matchAll(/^ {2}(?<name>\w+)/gm)].map((match) => (0, import_reg_exp.getMandatoryNamedGroup)(match, "name"));
304
+ }
305
+ function extractMethodNames(interfaceBody) {
306
+ return [...interfaceBody.matchAll(/^ {2}(?<name>\w+)(?:<[^>]*>)?\(/gm)].map((match) => (0, import_reg_exp.getMandatoryNamedGroup)(match, "name"));
307
+ }
308
+ function extractPropertyNames(interfaceBody) {
309
+ return [...interfaceBody.matchAll(/^ {2}(?<name>\w+)\??:/gm)].map((match) => (0, import_reg_exp.getMandatoryNamedGroup)(match, "name"));
310
+ }
311
+ function isNonPublicMember(modifiers) {
312
+ return /\b(?:private|protected)\b/.test(modifiers);
313
+ }
314
+ function parseMembers(keyword, body) {
315
+ switch (keyword) {
316
+ case "class":
317
+ return buildMembers(extractClassMethodNames(body), extractClassPropertyNames(body));
318
+ case "enum":
319
+ return buildMembers([], extractEnumMemberNames(body));
320
+ default:
321
+ return buildMembers(extractMethodNames(body), extractPropertyNames(body));
322
+ }
323
+ }
324
+ // Annotate the CommonJS export names for ESM import in node:
325
+ 0 && (module.exports = {
326
+ DemoVaultCoverageChecker,
327
+ registerDemoVaultCoverageSuite
328
+ });
329
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vc3JjL3NjcmlwdC11dGlscy9kZW1vLXZhdWx0LWNvdmVyYWdlLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogU3RhdGljIGNvdmVyYWdlL2ZyZXNobmVzcyBjaGVja3MgdGhhdCBrZWVwIGEgcGx1Z2luJ3MgaW4tcmVwbyBgZGVtby12YXVsdC9gIGluIHN5bmMgd2l0aCBpdHMgcHVibGljIHN1cmZhY2UuXG4gKlxuICogQSBwbHVnaW4gY2FuIHNoaXAgYSBjdXJhdGVkIGRlbW8gdmF1bHQgYXQgYGRlbW8tdmF1bHQvYCBpbiBpdHMgcmVwbyByb290LiBUaGVzZSBoZWxwZXJzIHJlZmxlY3QgdGhlIHJlYWxcbiAqIHB1YmxpYyBBUEkvY29uZmlnL2RvY3Mgc3RyYWlnaHQgZnJvbSBzb3VyY2UgYW5kIGFzc2VydCBcdTIwMTQgV0lUSE9VVCBsYXVuY2hpbmcgT2JzaWRpYW4gXHUyMDE0IHRoYXQgZXZlcnkgZmVhdHVyZSBpc1xuICogZGVtb25zdHJhdGVkIGluIHRoZSBub3RlcyBhbmQgdGhhdCB0aGUgbm90ZXMgcmVmZXJlbmNlIG5vIEFQSSBtZW1iZXIgdGhhdCBubyBsb25nZXIgZXhpc3RzIChyZW5hbWUgZHJpZnQpLlxuICogVGhlIHJ1bnRpbWUgYmVoYXZpb3Igb2YgdGhlIHBsdWdpbiBpcyBjb3ZlcmVkIGJ5IGl0cyBvdGhlciBpbnRlZ3JhdGlvbiB0ZXN0cywgbm90IGJ5IHRoZSBkZW1vIHZhdWx0OyB0aGVcbiAqIHZhdWx0IGlzIGEgbGVhcm5pbmcgcmVzb3VyY2UsIGFuZCB0aGVzZSBjaGVja3Mgb25seSBndWFyZCB0aGF0IGl0IHN0YXlzIHRydXRoZnVsLlxuICpcbiAqIFR3byBsYXllcnMgYXJlIGV4cG9zZWQ6XG4gKiAtIHtAbGluayBEZW1vVmF1bHRDb3ZlcmFnZUNoZWNrZXJ9IFx1MjAxNCBhIGZyYW1ld29yay1hZ25vc3RpYyBjb3JlIHRoYXQgcmVhZHMgdGhlIGNvcnB1cywgcGFyc2VzIGludGVyZmFjZSAvXG4gKiAgIGNsYXNzIC8gZW51bSBtZW1iZXJzIGFuZCBleHBvcnRlZCBmdW5jdGlvbnMsIGFuZCByZXR1cm5zIGRpYWdub3N0aWMgYXJyYXlzICh3aGF0IGlzIHVuZGVtb25zdHJhdGVkIC8gc3RhbGVcbiAqICAgLyB1bmxpbmtlZCkuXG4gKiAtIHtAbGluayByZWdpc3RlckRlbW9WYXVsdENvdmVyYWdlU3VpdGV9IFx1MjAxNCBhIHRoaW4gd3JhcHBlciB0aGF0IHJlZ2lzdGVycyBhIGB2aXRlc3RgIHN1aXRlIG92ZXIgdGhlIGNvcmUsIHNvXG4gKiAgIGEgcGx1Z2luJ3MgYGRlbW8tdmF1bHQubm8tYXBwLmludGVncmF0aW9uLnRlc3QudHNgIGlzIGEgc2luZ2xlIGRlY2xhcmF0aXZlIGNhbGwuXG4gKi9cblxuaW1wb3J0IHtcbiAgcmVhZGRpclN5bmMsXG4gIHJlYWRGaWxlU3luY1xufSBmcm9tICdub2RlOmZzJztcbmltcG9ydCB7XG4gIGRlc2NyaWJlLFxuICBleHBlY3QsXG4gIGl0XG59IGZyb20gJ3ZpdGVzdCc7XG5cbmltcG9ydCB7IE9ic2lkaWFuUGx1Z2luUmVwb1BhdGhzIH0gZnJvbSAnLi4vb2JzaWRpYW4vcGx1Z2luL29ic2lkaWFuLXBsdWdpbi1yZXBvLXBhdGhzLnRzJztcbmltcG9ydCB7XG4gIGpvaW4sXG4gIHJlbGF0aXZlXG59IGZyb20gJy4uL3BhdGgudHMnO1xuaW1wb3J0IHsgZ2V0TWFuZGF0b3J5TmFtZWRHcm91cCB9IGZyb20gJy4uL3JlZy1leHAudHMnO1xuXG4vKipcbiAqIFJlZmxlY3RzIGEgY29uZmlnIGludGVyZmFjZSB3aG9zZSBvcHRpb25zIGFyZSBkZW1vbnN0cmF0ZWQgYnkgdGhlaXIgYmFyZSBuYW1lLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIERlbW9WYXVsdENvbmZpZ0ludGVyZmFjZUNvdmVyYWdlU3BlYyB7XG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgYGV4cG9ydCBpbnRlcmZhY2VgLCBgZXhwb3J0IGNsYXNzYCwgb3IgYGV4cG9ydCBlbnVtYCB3aG9zZSBwcm9wZXJ0aWVzIGFyZSB0aGUgY29uZmlnXG4gICAqIG9wdGlvbnMuXG4gICAqL1xuICByZWFkb25seSBpbnRlcmZhY2VOYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBzb3VyY2UgZmlsZSBwYXRoIChyZWxhdGl2ZSB0byB0aGUgcmVwbyByb290KSB0aGF0IGRlY2xhcmVzIHRoZSBpbnRlcmZhY2UsIGNsYXNzLCBvciBlbnVtLlxuICAgKi9cbiAgcmVhZG9ubHkgc291cmNlUGF0aDogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciB0aGUge0BsaW5rIERlbW9WYXVsdENvdmVyYWdlQ2hlY2tlcn0gY29uc3RydWN0b3IuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRGVtb1ZhdWx0Q292ZXJhZ2VDaGVja2VyQ29uc3RydWN0b3JQYXJhbXMge1xuICAvKipcbiAgICogVGhlIGFic29sdXRlIHBhdGggb2YgdGhlIHBsdWdpbiByZXBvIHJvb3QgXHUyMDE0IHRoZSBmb2xkZXIgY29udGFpbmluZyBgZGVtby12YXVsdC9gIGFuZCB0aGUgc291cmNlIGJlaW5nXG4gICAqIHJlZmxlY3RlZC4gQ2FsbGVycyB0eXBpY2FsbHkgcGFzcyBgZ2V0Um9vdEZvbGRlcigpID8/IHByb2Nlc3MuY3dkKClgLlxuICAgKi9cbiAgcmVhZG9ubHkgcm9vdEZvbGRlcjogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciB7QGxpbmsgRGVtb1ZhdWx0Q292ZXJhZ2VDaGVja2VyLmZpbmRTdGFsZVJlZmVyZW5jZXN9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIERlbW9WYXVsdENvdmVyYWdlQ2hlY2tlckZpbmRTdGFsZVJlZmVyZW5jZXNQYXJhbXMge1xuICAvKipcbiAgICogVGhlIHJlY2VpdmVyIHdob3NlIGBgIGAke3JlY2VpdmVyfS48bWVtYmVyPmAgYGAgcmVmZXJlbmNlcyBhcmUgc2Nhbm5lZCBmb3IgaW4gdGhlIGRlbW8gY29ycHVzLlxuICAgKi9cbiAgcmVhZG9ubHkgcmVjZWl2ZXI6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG1lbWJlcnMgdGhhdCBjdXJyZW50bHkgZXhpc3Qgb24gdGhlIHJlY2VpdmVyOyBhbnkgcmVmZXJlbmNlZCBtZW1iZXIgbm90IGluIHRoaXMgc2V0IGlzIHN0YWxlLlxuICAgKi9cbiAgcmVhZG9ubHkgdmFsaWRNZW1iZXJzOiBzdHJpbmdbXTtcbn1cblxuLyoqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3Ige0BsaW5rIERlbW9WYXVsdENvdmVyYWdlQ2hlY2tlci5maW5kVW5kZW1vbnN0cmF0ZWRNZW1iZXJzfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZW1vVmF1bHRDb3ZlcmFnZUNoZWNrZXJGaW5kVW5kZW1vbnN0cmF0ZWRNZW1iZXJzUGFyYW1zIHtcbiAgLyoqXG4gICAqIFRoZSBtZW1iZXIgbmFtZXMgdGhhdCBtdXN0IGVhY2ggYXBwZWFyIGluIHRoZSBkZW1vIGNvcnB1cy5cbiAgICovXG4gIHJlYWRvbmx5IG1lbWJlcnM6IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBXaGVuIHNldCwgYSBtZW1iZXIgaXMgZGVtb25zdHJhdGVkIG9ubHkgaWYgYGAgYCR7cmVjZWl2ZXJ9LiR7bWVtYmVyfWAgYGAgYXBwZWFycyAoZS5nLiBhIGNvbnRleHQgb2JqZWN0J3NcbiAgICogbWV0aG9kcyk7IHdoZW4gYWJzZW50LCB0aGUgYmFyZSBtZW1iZXIgbmFtZSBpcyBsb29rZWQgdXAgKGUuZy4gYSBjb25maWcgb3B0aW9uKS5cbiAgICovXG4gIHJlYWRvbmx5IHJlY2VpdmVyPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciB7QGxpbmsgRGVtb1ZhdWx0Q292ZXJhZ2VDaGVja2VyLmZpbmRVbmxpbmtlZEZlYXR1cmVEb2NzfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZW1vVmF1bHRDb3ZlcmFnZUNoZWNrZXJGaW5kVW5saW5rZWRGZWF0dXJlRG9jc1BhcmFtcyB7XG4gIC8qKlxuICAgKiBUaGUgZG9jcyBmb2xkZXIgKHJlbGF0aXZlIHRvIHRoZSByZXBvIHJvb3QpIHdob3NlIHRvcC1sZXZlbCBgKi5tZGAgZmlsZXMgYXJlIHRoZSBmZWF0dXJlIGRvY3MuXG4gICAqL1xuICByZWFkb25seSBkb2NzRm9sZGVyOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBkb2MgYmFzZW5hbWVzICh3aXRob3V0IGAubWRgKSB0aGF0IGFyZSBOT1QgcGVyLWZlYXR1cmUgcGFnZXMgYW5kIHNvIG5lZWQgbm8gbGlua2luZyBkZW1vIG5vdGUuXG4gICAqL1xuICByZWFkb25seSBub25GZWF0dXJlRG9jczogc3RyaW5nW107XG59XG5cbi8qKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIHtAbGluayBEZW1vVmF1bHRDb3ZlcmFnZUNoZWNrZXIuZ2V0RXhwb3J0ZWRGdW5jdGlvbk5hbWVzfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZW1vVmF1bHRDb3ZlcmFnZUNoZWNrZXJHZXRFeHBvcnRlZEZ1bmN0aW9uTmFtZXNQYXJhbXMge1xuICAvKipcbiAgICogVGhlIHNvdXJjZSBmaWxlIHBhdGggKHJlbGF0aXZlIHRvIHRoZSByZXBvIHJvb3QpIHdob3NlIGBleHBvcnQgZnVuY3Rpb25gcyBhcmUgcGFyc2VkLlxuICAgKi9cbiAgcmVhZG9ubHkgc291cmNlUGF0aDogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciB7QGxpbmsgRGVtb1ZhdWx0Q292ZXJhZ2VDaGVja2VyLmdldEludGVyZmFjZU1lbWJlcnN9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIERlbW9WYXVsdENvdmVyYWdlQ2hlY2tlckdldEludGVyZmFjZU1lbWJlcnNQYXJhbXMge1xuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIGBleHBvcnQgaW50ZXJmYWNlYCwgYGV4cG9ydCBjbGFzc2AsIG9yIGBleHBvcnQgZW51bWAgdG8gcGFyc2UuXG4gICAqL1xuICByZWFkb25seSBpbnRlcmZhY2VOYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBzb3VyY2UgZmlsZSBwYXRoIChyZWxhdGl2ZSB0byB0aGUgcmVwbyByb290KSB0aGF0IGRlY2xhcmVzIHRoZSBpbnRlcmZhY2UsIGNsYXNzLCBvciBlbnVtLlxuICAgKi9cbiAgcmVhZG9ubHkgc291cmNlUGF0aDogc3RyaW5nO1xufVxuXG4vKipcbiAqIENvbmZpZ3VyZXMgdGhlIGZlYXR1cmUtZG9jIGxpbmtpbmcgY2hlY2suXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRGVtb1ZhdWx0RG9jc0NvdmVyYWdlU3BlYyB7XG4gIC8qKlxuICAgKiBUaGUgZG9jcyBmb2xkZXIgKHJlbGF0aXZlIHRvIHRoZSByZXBvIHJvb3QpIHdob3NlIHRvcC1sZXZlbCBgKi5tZGAgZmlsZXMgYXJlIHRoZSBmZWF0dXJlIGRvY3MuXG4gICAqL1xuICByZWFkb25seSBmb2xkZXI6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGRvYyBiYXNlbmFtZXMgKHdpdGhvdXQgYC5tZGApIHRoYXQgYXJlIE5PVCBwZXItZmVhdHVyZSBwYWdlcyBhbmQgc28gbmVlZCBubyBsaW5raW5nIGRlbW8gbm90ZS5cbiAgICovXG4gIHJlYWRvbmx5IG5vbkZlYXR1cmVEb2NzOiBzdHJpbmdbXTtcbn1cblxuLyoqXG4gKiBSZWZsZWN0cyBhIG1vZHVsZSdzIGV4cG9ydGVkIGZ1bmN0aW9ucywgZWFjaCBkZW1vbnN0cmF0ZWQgYnkgaXRzIGJhcmUgbmFtZSBpbiB0aGUgZGVtbyBjb3JwdXMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRGVtb1ZhdWx0RnVuY3Rpb25zQ292ZXJhZ2VTcGVjIHtcbiAgLyoqXG4gICAqIFRoZSBzb3VyY2UgZmlsZSBwYXRoIChyZWxhdGl2ZSB0byB0aGUgcmVwbyByb290KSB3aG9zZSBgZXhwb3J0IGZ1bmN0aW9uYHMgbXVzdCBlYWNoIGJlIGRlbW9uc3RyYXRlZC5cbiAgICovXG4gIHJlYWRvbmx5IHNvdXJjZVBhdGg6IHN0cmluZztcbn1cblxuLyoqXG4gKiBSZWZsZWN0cyBhIHNpbmdsZSBpbnRlcmZhY2UncyBtZW1iZXJzIGFuZCBkZW1vbnN0cmF0ZXMgdGhlbSB2aWEgYGAgYCR7cmVjZWl2ZXJ9LjxtZW1iZXI+YCBgYCByZWZlcmVuY2VzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIERlbW9WYXVsdEludGVyZmFjZUNvdmVyYWdlU3BlYyB7XG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgYGV4cG9ydCBpbnRlcmZhY2VgLCBgZXhwb3J0IGNsYXNzYCwgb3IgYGV4cG9ydCBlbnVtYCB0byByZWZsZWN0LlxuICAgKi9cbiAgcmVhZG9ubHkgaW50ZXJmYWNlTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBkZW1vbnN0cmF0ZWQgbWVtYmVycyBhcmUgdGhlIHJlZmxlY3RlZCB0eXBlJ3MgbWV0aG9kcyBvciBpdHMgcHJvcGVydGllcyAoZW51bSBtZW1iZXJzIGNvdW50IGFzXG4gICAqIHByb3BlcnRpZXMpLlxuICAgKi9cbiAgcmVhZG9ubHkga2luZDogRGVtb1ZhdWx0SW50ZXJmYWNlTWVtYmVyS2luZDtcblxuICAvKipcbiAgICogVGhlIGlkZW50aWZpZXIgdGhlIG5vdGVzIGNhbGwgdGhlIG1lbWJlcnMgb24gKGUuZy4gYGNvZGVCdXR0b25Db250ZXh0YCkuXG4gICAqL1xuICByZWFkb25seSByZWNlaXZlcjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgc291cmNlIGZpbGUgcGF0aCAocmVsYXRpdmUgdG8gdGhlIHJlcG8gcm9vdCkgdGhhdCBkZWNsYXJlcyB0aGUgaW50ZXJmYWNlLCBjbGFzcywgb3IgZW51bS5cbiAgICovXG4gIHJlYWRvbmx5IHNvdXJjZVBhdGg6IHN0cmluZztcbn1cblxuLyoqXG4gKiBXaGV0aGVyIGFuIGludGVyZmFjZSdzIGRlbW9uc3RyYXRlZCBtZW1iZXJzIGFyZSBpdHMgbWV0aG9kcyBvciBpdHMgcHJvcGVydGllcy5cbiAqL1xuZXhwb3J0IHR5cGUgRGVtb1ZhdWx0SW50ZXJmYWNlTWVtYmVyS2luZCA9ICdtZXRob2RzJyB8ICdwcm9wZXJ0aWVzJztcblxuLyoqXG4gKiBDb25maWd1cmVzIHRoZSBndWFyZCB0aGF0IHRoZSByZWZsZWN0ZWQgc3VyZmFjZSBpcyBub24tdHJpdmlhbCAocHJvdGVjdHMgYWdhaW5zdCBhIHBhcnNpbmcgcmVncmVzc2lvblxuICogc2lsZW50bHkgZW1wdHlpbmcgZXZlcnkgb3RoZXIgY2hlY2spLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIERlbW9WYXVsdE5vblRyaXZpYWxHdWFyZFNwZWMge1xuICAvKipcbiAgICogQSBkZW1vIG5vdGUgKHBhdGggcmVsYXRpdmUgdG8gdGhlIGRlbW8gdmF1bHQpIHRoYXQgbXVzdCBiZSBwcmVzZW50LlxuICAgKi9cbiAgcmVhZG9ubHkgZXhwZWN0RGVtb05vdGU6IHN0cmluZztcblxuICAvKipcbiAgICogQSBtZW1iZXIgdGhhdCBtdXN0IGJlIHJlZmxlY3RlZCBmcm9tIHtAbGluayBEZW1vVmF1bHROb25Ucml2aWFsR3VhcmRTcGVjLmludGVyZmFjZU5hbWV9LlxuICAgKi9cbiAgcmVhZG9ubHkgZXhwZWN0TWVtYmVyOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBgZXhwb3J0IGludGVyZmFjZWAsIGBleHBvcnQgY2xhc3NgLCBvciBgZXhwb3J0IGVudW1gIHdob3NlIG1lbWJlcnMgYXJlIHJlLXBhcnNlZCBmb3IgdGhlXG4gICAqIGd1YXJkLlxuICAgKi9cbiAgcmVhZG9ubHkgaW50ZXJmYWNlTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgc291cmNlIGZpbGUgcGF0aCAocmVsYXRpdmUgdG8gdGhlIHJlcG8gcm9vdCkgdGhhdCBkZWNsYXJlcyB0aGUgaW50ZXJmYWNlLCBjbGFzcywgb3IgZW51bS5cbiAgICovXG4gIHJlYWRvbmx5IHNvdXJjZVBhdGg6IHN0cmluZztcbn1cblxuLyoqXG4gKiBUaGUgcGFyc2VkIG1lbWJlcnMgb2YgYSBzb3VyY2UgaW50ZXJmYWNlLCBjbGFzcywgb3IgZW51bS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJbnRlcmZhY2VNZW1iZXJzIHtcbiAgLyoqXG4gICAqIEV2ZXJ5IG1lbWJlciBcdTIwMTQge0BsaW5rIEludGVyZmFjZU1lbWJlcnMubWV0aG9kc30gZm9sbG93ZWQgYnkge0BsaW5rIEludGVyZmFjZU1lbWJlcnMucHJvcGVydGllc30uXG4gICAqL1xuICByZWFkb25seSBhbGw6IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBUaGUgbWV0aG9kIG1lbWJlcnMgKGRlY2xhcmVkIGFzIGBuYW1lKC4uLilgKS5cbiAgICovXG4gIHJlYWRvbmx5IG1ldGhvZHM6IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBUaGUgcHJvcGVydHkgbWVtYmVycyAoZGVjbGFyZWQgYXMgYG5hbWU/OiAuLi5gKS5cbiAgICovXG4gIHJlYWRvbmx5IHByb3BlcnRpZXM6IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciB7QGxpbmsgcmVnaXN0ZXJEZW1vVmF1bHRDb3ZlcmFnZVN1aXRlfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZWdpc3RlckRlbW9WYXVsdENvdmVyYWdlU3VpdGVQYXJhbXMge1xuICAvKipcbiAgICogVGhlIGNvbmZpZyBpbnRlcmZhY2VzIHdob3NlIG9wdGlvbnMgbXVzdCBlYWNoIGJlIGRlbW9uc3RyYXRlZCBieSB0aGVpciBiYXJlIG5hbWUuXG4gICAqL1xuICByZWFkb25seSBjb25maWdJbnRlcmZhY2VzOiBEZW1vVmF1bHRDb25maWdJbnRlcmZhY2VDb3ZlcmFnZVNwZWNbXTtcblxuICAvKipcbiAgICogVGhlIGZlYXR1cmUtZG9jIGxpbmtpbmcgY2hlY2ssIG9yIGB1bmRlZmluZWRgIHdoZW4gdGhlIHBsdWdpbiBzaGlwcyBubyBgZG9jcy9gIGZvbGRlci5cbiAgICovXG4gIHJlYWRvbmx5IGRvY3M/OiBEZW1vVmF1bHREb2NzQ292ZXJhZ2VTcGVjO1xuXG4gIC8qKlxuICAgKiBUaGUgbW9kdWxlcyB3aG9zZSBgZXhwb3J0IGZ1bmN0aW9uYHMgbXVzdCBlYWNoIGJlIGRlbW9uc3RyYXRlZCBieSB0aGVpciBiYXJlIG5hbWUsIG9yIGB1bmRlZmluZWRgIHdoZW4gdGhlXG4gICAqIHBsdWdpbiBleHBvc2VzIG5vIHN1Y2ggbW9kdWxlIHRvIGNoZWNrLlxuICAgKi9cbiAgcmVhZG9ubHkgZnVuY3Rpb25Nb2R1bGVzPzogRGVtb1ZhdWx0RnVuY3Rpb25zQ292ZXJhZ2VTcGVjW107XG5cbiAgLyoqXG4gICAqIFRoZSBpbnRlcmZhY2VzIHdob3NlIG1lbWJlcnMgbXVzdCBlYWNoIGJlIGRlbW9uc3RyYXRlZCAoYW5kIHJlZmVyZW5jZWQgd2l0aG91dCBkcmlmdCkuXG4gICAqL1xuICByZWFkb25seSBpbnRlcmZhY2VzOiBEZW1vVmF1bHRJbnRlcmZhY2VDb3ZlcmFnZVNwZWNbXTtcblxuICAvKipcbiAgICogVGhlIGd1YXJkIHRoYXQga2VlcHMgdGhlIHJlZmxlY3RlZCBzdXJmYWNlIG5vbi10cml2aWFsLlxuICAgKi9cbiAgcmVhZG9ubHkgbm9uVHJpdmlhbEd1YXJkOiBEZW1vVmF1bHROb25Ucml2aWFsR3VhcmRTcGVjO1xuXG4gIC8qKlxuICAgKiBUaGUgYWJzb2x1dGUgcGF0aCBvZiB0aGUgcGx1Z2luIHJlcG8gcm9vdC4gQ2FsbGVycyB0eXBpY2FsbHkgcGFzcyBgZ2V0Um9vdEZvbGRlcigpID8/IHByb2Nlc3MuY3dkKClgLlxuICAgKi9cbiAgcmVhZG9ubHkgcm9vdEZvbGRlcjogc3RyaW5nO1xufVxuXG4vKipcbiAqIFJlZmxlY3RzIGEgcGx1Z2luJ3MgcHVibGljIHN1cmZhY2UgZnJvbSBzb3VyY2UgYW5kIGNoZWNrcyBpdHMgaW4tcmVwbyBgZGVtby12YXVsdC9gIHN0YXlzIGluIHN5bmMgd2l0aCBpdC5cbiAqXG4gKiBFdmVyeSBtZXRob2QgaXMgYSBwdXJlIHF1ZXJ5IG92ZXIgZmlsZXMgdW5kZXIgdGhlIHJlcG8gcm9vdCAodGhlIGRlbW8gY29ycHVzIGlzIHJlYWQgb25jZSBhbmQgY2FjaGVkKSwgc29cbiAqIHRoZSBjaGVja2VyIGlzIHRyaXZpYWxseSB1bml0LXRlc3RhYmxlIGFnYWluc3QgYSBmaXh0dXJlIHJlcG8gYW5kIGNhcnJpZXMgbm8gdGVzdC1mcmFtZXdvcmsgZGVwZW5kZW5jeS5cbiAqL1xuZXhwb3J0IGNsYXNzIERlbW9WYXVsdENvdmVyYWdlQ2hlY2tlciB7XG4gIHByaXZhdGUgY2FjaGVkQ29ycHVzOiBudWxsIHwgc3RyaW5nID0gbnVsbDtcbiAgcHJpdmF0ZSByZWFkb25seSBkZW1vVmF1bHRGb2xkZXI6IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSByb290Rm9sZGVyOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBjaGVja2VyIHJvb3RlZCBhdCBhIHBsdWdpbiByZXBvLlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1zIC0gVGhlIHBhcmFtZXRlcnMgZm9yIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICovXG4gIHB1YmxpYyBjb25zdHJ1Y3RvcihwYXJhbXM6IERlbW9WYXVsdENvdmVyYWdlQ2hlY2tlckNvbnN0cnVjdG9yUGFyYW1zKSB7XG4gICAgdGhpcy5yb290Rm9sZGVyID0gcGFyYW1zLnJvb3RGb2xkZXI7XG4gICAgdGhpcy5kZW1vVmF1bHRGb2xkZXIgPSBqb2luKHRoaXMucm9vdEZvbGRlciwgT2JzaWRpYW5QbHVnaW5SZXBvUGF0aHMuRGVtb1ZhdWx0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb2xsZWN0cyB0aGUgZGVtbyBub3RlcyBhcyBwYXRocyByZWxhdGl2ZSB0byB0aGUgZGVtbyB2YXVsdCBmb2xkZXIgKGZvciBhIG5vbi10cml2aWFsLXN1cmZhY2UgZ3VhcmQpLlxuICAgKlxuICAgKiBAcmV0dXJucyBUaGUgcmVsYXRpdmUgcGF0aHMgb2YgZXZlcnkgYCoubWRgIG5vdGUgaW4gdGhlIGRlbW8gdmF1bHQuXG4gICAqL1xuICBwdWJsaWMgY29sbGVjdERlbW9Ob3RlUmVsYXRpdmVQYXRocygpOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIHRoaXMuY29sbGVjdE1hcmtkb3duRmlsZXModGhpcy5kZW1vVmF1bHRGb2xkZXIpLm1hcCgoZmlsZSkgPT4gcmVsYXRpdmUodGhpcy5kZW1vVmF1bHRGb2xkZXIsIGZpbGUpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5kcyBtZW1iZXJzIHRoYXQgdGhlIGRlbW8gbm90ZXMgcmVmZXJlbmNlIG9uIGEgcmVjZWl2ZXIgYnV0IHRoYXQgbm8gbG9uZ2VyIGV4aXN0IG9uIGl0IChyZW5hbWUgZHJpZnQpLlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1zIC0gVGhlIHBhcmFtZXRlcnMgZm9yIHRoZSBsb29rdXAuXG4gICAqIEByZXR1cm5zIFRoZSBkaXN0aW5jdCBzdGFsZSBtZW1iZXIgbmFtZXMgcmVmZXJlbmNlZCBpbiB0aGUgZGVtbyBjb3JwdXMuXG4gICAqL1xuICBwdWJsaWMgZmluZFN0YWxlUmVmZXJlbmNlcyhwYXJhbXM6IERlbW9WYXVsdENvdmVyYWdlQ2hlY2tlckZpbmRTdGFsZVJlZmVyZW5jZXNQYXJhbXMpOiBzdHJpbmdbXSB7XG4gICAgY29uc3QgdmFsaWRNZW1iZXJzID0gbmV3IFNldChwYXJhbXMudmFsaWRNZW1iZXJzKTtcbiAgICBjb25zdCByZWZlcmVuY2VkID0gWy4uLnRoaXMucmVhZENvcnB1cygpLm1hdGNoQWxsKG5ldyBSZWdFeHAoYCR7cGFyYW1zLnJlY2VpdmVyfVxcXFwuKD88bWVtYmVyPlxcXFx3KylgLCAnZycpKV1cbiAgICAgIC5tYXAoKG1hdGNoKSA9PiBnZXRNYW5kYXRvcnlOYW1lZEdyb3VwKG1hdGNoLCAnbWVtYmVyJykpO1xuICAgIHJldHVybiBbLi4ubmV3IFNldChyZWZlcmVuY2VkKV0uZmlsdGVyKChtZW1iZXIpID0+ICF2YWxpZE1lbWJlcnMuaGFzKG1lbWJlcikpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmRzIG1lbWJlcnMgdGhhdCBhcmUgbm90IGRlbW9uc3RyYXRlZCBhbnl3aGVyZSBpbiB0aGUgZGVtbyBjb3JwdXMuXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgcGFyYW1ldGVycyBmb3IgdGhlIGxvb2t1cC5cbiAgICogQHJldHVybnMgVGhlIG1lbWJlciBuYW1lcyB3aXRoIG5vIGRlbW9uc3RyYXRpb24uXG4gICAqL1xuICBwdWJsaWMgZmluZFVuZGVtb25zdHJhdGVkTWVtYmVycyhwYXJhbXM6IERlbW9WYXVsdENvdmVyYWdlQ2hlY2tlckZpbmRVbmRlbW9uc3RyYXRlZE1lbWJlcnNQYXJhbXMpOiBzdHJpbmdbXSB7XG4gICAgY29uc3QgY29ycHVzID0gdGhpcy5yZWFkQ29ycHVzKCk7XG4gICAgcmV0dXJuIHBhcmFtcy5tZW1iZXJzLmZpbHRlcigobWVtYmVyKSA9PiB7XG4gICAgICBjb25zdCBuZWVkbGUgPSBwYXJhbXMucmVjZWl2ZXIgPT09IHVuZGVmaW5lZCA/IG1lbWJlciA6IGAke3BhcmFtcy5yZWNlaXZlcn0uJHttZW1iZXJ9YDtcbiAgICAgIHJldHVybiAhY29ycHVzLmluY2x1ZGVzKG5lZWRsZSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogRmluZHMgZmVhdHVyZSBkb2NzIHRoYXQgbm8gZGVtbyBub3RlIGxpbmtzIHRvLlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1zIC0gVGhlIHBhcmFtZXRlcnMgZm9yIHRoZSBsb29rdXAuXG4gICAqIEByZXR1cm5zIFRoZSBmZWF0dXJlLWRvYyBiYXNlbmFtZXMgKHdpdGhvdXQgYC5tZGApIG5vdCBsaW5rZWQgZnJvbSBhbnkgZGVtbyBub3RlLlxuICAgKi9cbiAgcHVibGljIGZpbmRVbmxpbmtlZEZlYXR1cmVEb2NzKHBhcmFtczogRGVtb1ZhdWx0Q292ZXJhZ2VDaGVja2VyRmluZFVubGlua2VkRmVhdHVyZURvY3NQYXJhbXMpOiBzdHJpbmdbXSB7XG4gICAgY29uc3Qgbm9uRmVhdHVyZURvY3MgPSBuZXcgU2V0KHBhcmFtcy5ub25GZWF0dXJlRG9jcyk7XG4gICAgY29uc3QgZmVhdHVyZURvY3MgPSByZWFkZGlyU3luYyhqb2luKHRoaXMucm9vdEZvbGRlciwgcGFyYW1zLmRvY3NGb2xkZXIpKVxuICAgICAgLmZpbHRlcigoZmlsZSkgPT4gZmlsZS5lbmRzV2l0aCgnLm1kJykpXG4gICAgICAubWFwKChmaWxlKSA9PiBmaWxlLnJlcGxhY2UoL1xcLm1kJC8sICcnKSlcbiAgICAgIC5maWx0ZXIoKG5hbWUpID0+ICFub25GZWF0dXJlRG9jcy5oYXMobmFtZSkpO1xuICAgIGNvbnN0IGxpbmtlZERvY3MgPSBuZXcgU2V0KFxuICAgICAgWy4uLnRoaXMucmVhZENvcnB1cygpLm1hdGNoQWxsKC9kb2NzXFwvKD88ZG9jPltcXHctXSspXFwubWQvZyldLm1hcCgobWF0Y2gpID0+IGdldE1hbmRhdG9yeU5hbWVkR3JvdXAobWF0Y2gsICdkb2MnKSlcbiAgICApO1xuICAgIHJldHVybiBmZWF0dXJlRG9jcy5maWx0ZXIoKGRvYykgPT4gIWxpbmtlZERvY3MuaGFzKGRvYykpO1xuICB9XG5cbiAgLyoqXG4gICAqIFBhcnNlcyB0aGUgbmFtZXMgb2YgdGhlIGBleHBvcnQgZnVuY3Rpb25gcyAoaW5jbHVkaW5nIGBhc3luY2AgYW5kIGdlbmVyYXRvciBkZWNsYXJhdGlvbnMpIGluIGEgc291cmNlIGZpbGUuXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgcGFyYW1ldGVycyBmb3IgdGhlIGxvb2t1cC5cbiAgICogQHJldHVybnMgVGhlIGV4cG9ydGVkIGZ1bmN0aW9uIG5hbWVzIGluIHNvdXJjZSBvcmRlci5cbiAgICovXG4gIHB1YmxpYyBnZXRFeHBvcnRlZEZ1bmN0aW9uTmFtZXMocGFyYW1zOiBEZW1vVmF1bHRDb3ZlcmFnZUNoZWNrZXJHZXRFeHBvcnRlZEZ1bmN0aW9uTmFtZXNQYXJhbXMpOiBzdHJpbmdbXSB7XG4gICAgY29uc3Qgc291cmNlID0gcmVhZEZpbGVTeW5jKGpvaW4odGhpcy5yb290Rm9sZGVyLCBwYXJhbXMuc291cmNlUGF0aCksICd1dGYtOCcpO1xuICAgIHJldHVybiBbLi4uc291cmNlLm1hdGNoQWxsKC9eZXhwb3J0ICg/OmFzeW5jICk/ZnVuY3Rpb25cXCo/ICg/PG5hbWU+XFx3KykvZ20pXVxuICAgICAgLm1hcCgobWF0Y2gpID0+IGdldE1hbmRhdG9yeU5hbWVkR3JvdXAobWF0Y2gsICduYW1lJykpO1xuICB9XG5cbiAgLyoqXG4gICAqIFBhcnNlcyB0aGUgbWVtYmVycyBvZiBhbiBgZXhwb3J0IGludGVyZmFjZWAsIGBleHBvcnQgY2xhc3NgLCBvciBgZXhwb3J0IGVudW1gIGRlY2xhcmVkIGluIGEgc291cmNlIGZpbGUuXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgcGFyYW1ldGVycyBmb3IgdGhlIGxvb2t1cC5cbiAgICogQHJldHVybnMgVGhlIHBhcnNlZCB7QGxpbmsgSW50ZXJmYWNlTWVtYmVyc30uXG4gICAqIEB0aHJvd3MgV2hlbiB0aGUgaW50ZXJmYWNlLCBjbGFzcywgb3IgZW51bSBjYW5ub3QgYmUgZm91bmQgaW4gdGhlIHNvdXJjZSBmaWxlLlxuICAgKi9cbiAgcHVibGljIGdldEludGVyZmFjZU1lbWJlcnMocGFyYW1zOiBEZW1vVmF1bHRDb3ZlcmFnZUNoZWNrZXJHZXRJbnRlcmZhY2VNZW1iZXJzUGFyYW1zKTogSW50ZXJmYWNlTWVtYmVycyB7XG4gICAgY29uc3Qgc291cmNlID0gcmVhZEZpbGVTeW5jKGpvaW4odGhpcy5yb290Rm9sZGVyLCBwYXJhbXMuc291cmNlUGF0aCksICd1dGYtOCcpO1xuICAgIGNvbnN0IG1hdGNoID0gbmV3IFJlZ0V4cChgZXhwb3J0ICg/PGtleXdvcmQ+aW50ZXJmYWNlfGNsYXNzfGVudW0pICR7cGFyYW1zLmludGVyZmFjZU5hbWV9XFxcXGJbXntdKlxcXFx7KD88Ym9keT5bXFxcXHNcXFxcU10qPylcXFxcblxcXFx9YCkuZXhlYyhzb3VyY2UpO1xuICAgIGlmICghbWF0Y2gpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ291bGQgbm90IGZpbmQgaW50ZXJmYWNlICR7cGFyYW1zLmludGVyZmFjZU5hbWV9YCk7XG4gICAgfVxuICAgIHJldHVybiBwYXJzZU1lbWJlcnMoZ2V0TWFuZGF0b3J5TmFtZWRHcm91cChtYXRjaCwgJ2tleXdvcmQnKSwgZ2V0TWFuZGF0b3J5TmFtZWRHcm91cChtYXRjaCwgJ2JvZHknKSk7XG4gIH1cblxuICAvKipcbiAgICogUmVhZHMgYW5kIGNhY2hlcyB0aGUgZGVtbyBjb3JwdXMgXHUyMDE0IGV2ZXJ5IGAqLm1kYCBub3RlIGluIHRoZSBkZW1vIHZhdWx0IGpvaW5lZCBpbnRvIG9uZSBzdHJpbmcuXG4gICAqXG4gICAqIEByZXR1cm5zIFRoZSBjb25jYXRlbmF0ZWQgZGVtby1ub3RlIGNvbnRlbnRzLlxuICAgKi9cbiAgcHVibGljIHJlYWRDb3JwdXMoKTogc3RyaW5nIHtcbiAgICB0aGlzLmNhY2hlZENvcnB1cyA/Pz0gdGhpcy5jb2xsZWN0TWFya2Rvd25GaWxlcyh0aGlzLmRlbW9WYXVsdEZvbGRlcilcbiAgICAgIC5tYXAoKGZpbGUpID0+IHJlYWRGaWxlU3luYyhmaWxlLCAndXRmLTgnKSlcbiAgICAgIC5qb2luKCdcXG4nKTtcbiAgICByZXR1cm4gdGhpcy5jYWNoZWRDb3JwdXM7XG4gIH1cblxuICBwcml2YXRlIGNvbGxlY3RNYXJrZG93bkZpbGVzKGZvbGRlcjogc3RyaW5nKTogc3RyaW5nW10ge1xuICAgIGNvbnN0IHJlc3VsdDogc3RyaW5nW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIHJlYWRkaXJTeW5jKGZvbGRlciwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pKSB7XG4gICAgICBpZiAoZW50cnkuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgICBpZiAoZW50cnkubmFtZSA9PT0gT2JzaWRpYW5QbHVnaW5SZXBvUGF0aHMuTm9kZU1vZHVsZXMgYXMgc3RyaW5nKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgcmVzdWx0LnB1c2goLi4udGhpcy5jb2xsZWN0TWFya2Rvd25GaWxlcyhqb2luKGZvbGRlciwgZW50cnkubmFtZSkpKTtcbiAgICAgIH0gZWxzZSBpZiAoZW50cnkubmFtZS5lbmRzV2l0aCgnLm1kJykpIHtcbiAgICAgICAgcmVzdWx0LnB1c2goam9pbihmb2xkZXIsIGVudHJ5Lm5hbWUpKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxufVxuXG4vKipcbiAqIFJlZ2lzdGVycyBhIGB2aXRlc3RgIHN1aXRlIHRoYXQga2VlcHMgYSBwbHVnaW4ncyBpbi1yZXBvIGBkZW1vLXZhdWx0L2AgaW4gc3luYyB3aXRoIGl0cyBwdWJsaWMgc3VyZmFjZS5cbiAqXG4gKiBDYWxsIGl0IG9uY2UgZnJvbSBhIHBsdWdpbidzIGBkZW1vLXZhdWx0Lm5vLWFwcC5pbnRlZ3JhdGlvbi50ZXN0LnRzYDsgaXQgcmVnaXN0ZXJzIG9uZSB0ZXN0IHBlciBjaGVjayxcbiAqIGRlbGVnYXRpbmcgdG8ge0BsaW5rIERlbW9WYXVsdENvdmVyYWdlQ2hlY2tlcn0uXG4gKlxuICogQHBhcmFtIHBhcmFtcyAtIFRoZSBkZWNsYXJhdGl2ZSBjb3ZlcmFnZSBzcGVjaWZpY2F0aW9uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVnaXN0ZXJEZW1vVmF1bHRDb3ZlcmFnZVN1aXRlKHBhcmFtczogUmVnaXN0ZXJEZW1vVmF1bHRDb3ZlcmFnZVN1aXRlUGFyYW1zKTogdm9pZCB7XG4gIGNvbnN0IGNoZWNrZXIgPSBuZXcgRGVtb1ZhdWx0Q292ZXJhZ2VDaGVja2VyKHsgcm9vdEZvbGRlcjogcGFyYW1zLnJvb3RGb2xkZXIgfSk7XG5cbiAgZGVzY3JpYmUoJ2RlbW8tdmF1bHQgY292ZXJhZ2UnLCAoKSA9PiB7XG4gICAgZm9yIChjb25zdCBzcGVjIG9mIHBhcmFtcy5pbnRlcmZhY2VzKSB7XG4gICAgICBpdChgZGVtb25zdHJhdGVzIGV2ZXJ5ICR7c3BlYy5pbnRlcmZhY2VOYW1lfSAke3NwZWMua2luZH1gLCAoKSA9PiB7XG4gICAgICAgIGNvbnN0IG1lbWJlcnMgPSBjaGVja2VyLmdldEludGVyZmFjZU1lbWJlcnMoc3BlYyk7XG4gICAgICAgIGNvbnN0IGRlbW9uc3RyYXRlZCA9IG1lbWJlcnNbc3BlYy5raW5kXTtcbiAgICAgICAgZXhwZWN0KGRlbW9uc3RyYXRlZC5sZW5ndGgpLnRvQmVHcmVhdGVyVGhhbigwKTtcbiAgICAgICAgZXhwZWN0KGNoZWNrZXIuZmluZFVuZGVtb25zdHJhdGVkTWVtYmVycyh7IG1lbWJlcnM6IGRlbW9uc3RyYXRlZCwgcmVjZWl2ZXI6IHNwZWMucmVjZWl2ZXIgfSkpLnRvRXF1YWwoW10pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KGByZWZlcmVuY2VzIG5vICR7c3BlYy5pbnRlcmZhY2VOYW1lfSBtZW1iZXIgdGhhdCBubyBsb25nZXIgZXhpc3RzYCwgKCkgPT4ge1xuICAgICAgICBjb25zdCBtZW1iZXJzID0gY2hlY2tlci5nZXRJbnRlcmZhY2VNZW1iZXJzKHNwZWMpO1xuICAgICAgICBleHBlY3QoY2hlY2tlci5maW5kU3RhbGVSZWZlcmVuY2VzKHsgcmVjZWl2ZXI6IHNwZWMucmVjZWl2ZXIsIHZhbGlkTWVtYmVyczogbWVtYmVycy5hbGwgfSkpLnRvRXF1YWwoW10pO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBzcGVjIG9mIHBhcmFtcy5jb25maWdJbnRlcmZhY2VzKSB7XG4gICAgICBpdChgZGVtb25zdHJhdGVzIGV2ZXJ5ICR7c3BlYy5pbnRlcmZhY2VOYW1lfSBvcHRpb25gLCAoKSA9PiB7XG4gICAgICAgIGNvbnN0IG1lbWJlcnMgPSBjaGVja2VyLmdldEludGVyZmFjZU1lbWJlcnMoc3BlYyk7XG4gICAgICAgIGV4cGVjdChtZW1iZXJzLnByb3BlcnRpZXMubGVuZ3RoKS50b0JlR3JlYXRlclRoYW4oMCk7XG4gICAgICAgIGV4cGVjdChjaGVja2VyLmZpbmRVbmRlbW9uc3RyYXRlZE1lbWJlcnMoeyBtZW1iZXJzOiBtZW1iZXJzLnByb3BlcnRpZXMgfSkpLnRvRXF1YWwoW10pO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBzcGVjIG9mIHBhcmFtcy5mdW5jdGlvbk1vZHVsZXMgPz8gW10pIHtcbiAgICAgIGl0KGBkZW1vbnN0cmF0ZXMgZXZlcnkgZXhwb3J0ZWQgZnVuY3Rpb24gaW4gJHtzcGVjLnNvdXJjZVBhdGh9YCwgKCkgPT4ge1xuICAgICAgICBjb25zdCBmdW5jdGlvbk5hbWVzID0gY2hlY2tlci5nZXRFeHBvcnRlZEZ1bmN0aW9uTmFtZXMoc3BlYyk7XG4gICAgICAgIGV4cGVjdChmdW5jdGlvbk5hbWVzLmxlbmd0aCkudG9CZUdyZWF0ZXJUaGFuKDApO1xuICAgICAgICBleHBlY3QoY2hlY2tlci5maW5kVW5kZW1vbnN0cmF0ZWRNZW1iZXJzKHsgbWVtYmVyczogZnVuY3Rpb25OYW1lcyB9KSkudG9FcXVhbChbXSk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBjb25zdCBkb2NzID0gcGFyYW1zLmRvY3M7XG4gICAgaWYgKGRvY3MpIHtcbiAgICAgIGl0KCdsaW5rcyBhIGRlbW8gbm90ZSBmb3IgZXZlcnkgZmVhdHVyZSBkb2MnLCAoKSA9PiB7XG4gICAgICAgIGV4cGVjdChjaGVja2VyLmZpbmRVbmxpbmtlZEZlYXR1cmVEb2NzKHsgZG9jc0ZvbGRlcjogZG9jcy5mb2xkZXIsIG5vbkZlYXR1cmVEb2NzOiBkb2NzLm5vbkZlYXR1cmVEb2NzIH0pKVxuICAgICAgICAgIC50b0VxdWFsKFtdKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGl0KCdrZWVwcyB0aGUgcmVmbGVjdGVkIHN1cmZhY2Ugbm9uLXRyaXZpYWwnLCAoKSA9PiB7XG4gICAgICBjb25zdCBndWFyZCA9IHBhcmFtcy5ub25Ucml2aWFsR3VhcmQ7XG4gICAgICBjb25zdCBtZW1iZXJzID0gY2hlY2tlci5nZXRJbnRlcmZhY2VNZW1iZXJzKGd1YXJkKTtcbiAgICAgIGV4cGVjdChtZW1iZXJzLmFsbCkudG9Db250YWluKGd1YXJkLmV4cGVjdE1lbWJlcik7XG4gICAgICBleHBlY3QoY2hlY2tlci5jb2xsZWN0RGVtb05vdGVSZWxhdGl2ZVBhdGhzKCkpLnRvQ29udGFpbihndWFyZC5leHBlY3REZW1vTm90ZSk7XG4gICAgfSk7XG4gIH0pO1xufVxuXG5jb25zdCBDTEFTU19NRU1CRVJfTU9ESUZJRVJTID0gJyg/Oig/OnB1YmxpY3xwcml2YXRlfHByb3RlY3RlZHxyZWFkb25seXxzdGF0aWN8YWJzdHJhY3R8b3ZlcnJpZGUpXFxcXHMrKSonO1xuXG5mdW5jdGlvbiBidWlsZE1lbWJlcnMobWV0aG9kczogc3RyaW5nW10sIHByb3BlcnRpZXM6IHN0cmluZ1tdKTogSW50ZXJmYWNlTWVtYmVycyB7XG4gIHJldHVybiB7XG4gICAgYWxsOiBbLi4ubWV0aG9kcywgLi4ucHJvcGVydGllc10sXG4gICAgbWV0aG9kcyxcbiAgICBwcm9wZXJ0aWVzXG4gIH07XG59XG5cbmZ1bmN0aW9uIGV4dHJhY3RDbGFzc01ldGhvZE5hbWVzKGNsYXNzQm9keTogc3RyaW5nKTogc3RyaW5nW10ge1xuICByZXR1cm4gWy4uLmNsYXNzQm9keS5tYXRjaEFsbChuZXcgUmVnRXhwKGBeIHsyfSg/PG1vZGlmaWVycz4ke0NMQVNTX01FTUJFUl9NT0RJRklFUlN9KSg/PG5hbWU+XFxcXHcrKSg/OjxbXj5dKj4pP1xcXFwoYCwgJ2dtJykpXVxuICAgIC5maWx0ZXIoKG1hdGNoKSA9PiAhaXNOb25QdWJsaWNNZW1iZXIoZ2V0TWFuZGF0b3J5TmFtZWRHcm91cChtYXRjaCwgJ21vZGlmaWVycycpKSlcbiAgICAubWFwKChtYXRjaCkgPT4gZ2V0TWFuZGF0b3J5TmFtZWRHcm91cChtYXRjaCwgJ25hbWUnKSk7XG59XG5cbmZ1bmN0aW9uIGV4dHJhY3RDbGFzc1Byb3BlcnR5TmFtZXMoY2xhc3NCb2R5OiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gIHJldHVybiBbLi4uY2xhc3NCb2R5Lm1hdGNoQWxsKG5ldyBSZWdFeHAoYF4gezJ9KD88bW9kaWZpZXJzPiR7Q0xBU1NfTUVNQkVSX01PRElGSUVSU30pKD88bmFtZT5cXFxcdyspXFxcXHMqXFxcXD8/XFxcXHMqWzo9XWAsICdnbScpKV1cbiAgICAuZmlsdGVyKChtYXRjaCkgPT4gIWlzTm9uUHVibGljTWVtYmVyKGdldE1hbmRhdG9yeU5hbWVkR3JvdXAobWF0Y2gsICdtb2RpZmllcnMnKSkpXG4gICAgLm1hcCgobWF0Y2gpID0+IGdldE1hbmRhdG9yeU5hbWVkR3JvdXAobWF0Y2gsICduYW1lJykpO1xufVxuXG5mdW5jdGlvbiBleHRyYWN0RW51bU1lbWJlck5hbWVzKGVudW1Cb2R5OiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gIHJldHVybiBbLi4uZW51bUJvZHkubWF0Y2hBbGwoL14gezJ9KD88bmFtZT5cXHcrKS9nbSldLm1hcCgobWF0Y2gpID0+IGdldE1hbmRhdG9yeU5hbWVkR3JvdXAobWF0Y2gsICduYW1lJykpO1xufVxuXG5mdW5jdGlvbiBleHRyYWN0TWV0aG9kTmFtZXMoaW50ZXJmYWNlQm9keTogc3RyaW5nKTogc3RyaW5nW10ge1xuICByZXR1cm4gWy4uLmludGVyZmFjZUJvZHkubWF0Y2hBbGwoL14gezJ9KD88bmFtZT5cXHcrKSg/OjxbXj5dKj4pP1xcKC9nbSldLm1hcCgobWF0Y2gpID0+IGdldE1hbmRhdG9yeU5hbWVkR3JvdXAobWF0Y2gsICduYW1lJykpO1xufVxuXG5mdW5jdGlvbiBleHRyYWN0UHJvcGVydHlOYW1lcyhpbnRlcmZhY2VCb2R5OiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gIHJldHVybiBbLi4uaW50ZXJmYWNlQm9keS5tYXRjaEFsbCgvXiB7Mn0oPzxuYW1lPlxcdyspXFw/PzovZ20pXS5tYXAoKG1hdGNoKSA9PiBnZXRNYW5kYXRvcnlOYW1lZEdyb3VwKG1hdGNoLCAnbmFtZScpKTtcbn1cblxuZnVuY3Rpb24gaXNOb25QdWJsaWNNZW1iZXIobW9kaWZpZXJzOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIC9cXGIoPzpwcml2YXRlfHByb3RlY3RlZClcXGIvLnRlc3QobW9kaWZpZXJzKTtcbn1cblxuZnVuY3Rpb24gcGFyc2VNZW1iZXJzKGtleXdvcmQ6IHN0cmluZywgYm9keTogc3RyaW5nKTogSW50ZXJmYWNlTWVtYmVycyB7XG4gIHN3aXRjaCAoa2V5d29yZCkge1xuICAgIGNhc2UgJ2NsYXNzJzpcbiAgICAgIHJldHVybiBidWlsZE1lbWJlcnMoZXh0cmFjdENsYXNzTWV0aG9kTmFtZXMoYm9keSksIGV4dHJhY3RDbGFzc1Byb3BlcnR5TmFtZXMoYm9keSkpO1xuICAgIGNhc2UgJ2VudW0nOlxuICAgICAgcmV0dXJuIGJ1aWxkTWVtYmVycyhbXSwgZXh0cmFjdEVudW1NZW1iZXJOYW1lcyhib2R5KSk7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBidWlsZE1lbWJlcnMoZXh0cmFjdE1ldGhvZE5hbWVzKGJvZHkpLCBleHRyYWN0UHJvcGVydHlOYW1lcyhib2R5KSk7XG4gIH1cbn1cbiJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBbUJBLHFCQUdPO0FBQ1Asb0JBSU87QUFFUCx3Q0FBd0M7QUFDeEMsa0JBR087QUFDUCxxQkFBdUM7QUFxUGhDLE1BQU0seUJBQXlCO0FBQUEsRUFDNUIsZUFBOEI7QUFBQSxFQUNyQjtBQUFBLEVBQ0E7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFPVixZQUFZLFFBQW1EO0FBQ3BFLFNBQUssYUFBYSxPQUFPO0FBQ3pCLFNBQUssc0JBQWtCLGtCQUFLLEtBQUssWUFBWSwwREFBd0IsU0FBUztBQUFBLEVBQ2hGO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEVBT08sK0JBQXlDO0FBQzlDLFdBQU8sS0FBSyxxQkFBcUIsS0FBSyxlQUFlLEVBQUUsSUFBSSxDQUFDLGFBQVMsc0JBQVMsS0FBSyxpQkFBaUIsSUFBSSxDQUFDO0FBQUEsRUFDM0c7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxFQVFPLG9CQUFv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QUFBQSxFQUNGO0FBQ0Y7QUFFQSxTQUFTLHdCQUF3QixXQUE2QjtBQUM1RCxTQUFPLENBQUMsR0FBRyxVQUFVLFNBQVMsSUFBSSxPQUFPLHFCQUFxQixzQkFBc0IsaUNBQWlDLElBQUksQ0FBQyxDQUFDLEVBQ3hILE9BQU8sQ0FBQyxVQUFVLENBQUMsc0JBQWtCLHVDQUF1QixPQUFPLFdBQVcsQ0FBQyxDQUFDLEVBQ2hGLElBQUksQ0FBQyxjQUFVLHVDQUF1QixPQUFPLE1BQU0sQ0FBQztBQUN6RDtBQUVBLFNBQVMsMEJBQTBCLFdBQTZCO0FBQzlELFNBQU8sQ0FBQyxHQUFHLFVBQVUsU0FBUyxJQUFJLE9BQU8scUJBQXFCLHNCQUFzQixrQ0FBa0MsSUFBSSxDQUFDLENBQUMsRUFDekgsT0FBTyxDQUFDLFVBQVUsQ0FBQyxzQkFBa0IsdUNBQXVCLE9BQU8sV0FBVyxDQUFDLENBQUMsRUFDaEYsSUFBSSxDQUFDLGNBQVUsdUNBQXVCLE9BQU8sTUFBTSxDQUFDO0FBQ3pEO0FBRUEsU0FBUyx1QkFBdUIsVUFBNEI7QUFDMUQsU0FBTyxDQUFDLEdBQUcsU0FBUyxTQUFTLHFCQUFxQixDQUFDLEVBQUUsSUFBSSxDQUFDLGNBQVUsdUNBQXVCLE9BQU8sTUFBTSxDQUFDO0FBQzNHO0FBRUEsU0FBUyxtQkFBbUIsZUFBaUM7QUFDM0QsU0FBTyxDQUFDLEdBQUcsY0FBYyxTQUFTLG1DQUFtQyxDQUFDLEVBQUUsSUFBSSxDQUFDLGNBQVUsdUNBQXVCLE9BQU8sTUFBTSxDQUFDO0FBQzlIO0FBRUEsU0FBUyxxQkFBcUIsZUFBaUM7QUFDN0QsU0FBTyxDQUFDLEdBQUcsY0FBYyxTQUFTLHlCQUF5QixDQUFDLEVBQUUsSUFBSSxDQUFDLGNBQVUsdUNBQXVCLE9BQU8sTUFBTSxDQUFDO0FBQ3BIO0FBRUEsU0FBUyxrQkFBa0IsV0FBNEI7QUFDckQsU0FBTyw0QkFBNEIsS0FBSyxTQUFTO0FBQ25EO0FBRUEsU0FBUyxhQUFhLFNBQWlCLE1BQWdDO0FBQ3JFLFVBQVEsU0FBUztBQUFBLElBQ2YsS0FBSztBQUNILGFBQU8sYUFBYSx3QkFBd0IsSUFBSSxHQUFHLDBCQUEwQixJQUFJLENBQUM7QUFBQSxJQUNwRixLQUFLO0FBQ0gsYUFBTyxhQUFhLENBQUMsR0FBRyx1QkFBdUIsSUFBSSxDQUFDO0FBQUEsSUFDdEQ7QUFDRSxhQUFPLGFBQWEsbUJBQW1CLElBQUksR0FBRyxxQkFBcUIsSUFBSSxDQUFDO0FBQUEsRUFDNUU7QUFDRjsiLAogICJuYW1lcyI6IFtdCn0K