@nlabs/lex 1.48.7 → 1.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/.storybook/main.ts +9 -2
  2. package/.vscode/settings.json +1 -6
  3. package/README.md +249 -0
  4. package/eslint.config.mjs +24 -0
  5. package/examples/lex.config.js +18 -8
  6. package/examples/serverless-example/README.md +109 -0
  7. package/examples/serverless-example/dist/handlers/echo.js +15 -0
  8. package/examples/serverless-example/dist/handlers/graphql.js +137 -0
  9. package/examples/serverless-example/dist/handlers/hello.js +15 -0
  10. package/examples/serverless-example/dist/handlers/test.js +17 -0
  11. package/examples/serverless-example/dist/handlers/websocket.js +14 -0
  12. package/examples/serverless-example/lex.config.mjs +74 -0
  13. package/jest.config.mjs +13 -12
  14. package/{dist → lib}/LexConfig.d.ts +7 -6
  15. package/lib/LexConfig.js +268 -0
  16. package/lib/commands/ai/ai.js +303 -0
  17. package/{dist → lib}/commands/build/build.d.ts +3 -0
  18. package/lib/commands/build/build.js +494 -0
  19. package/{dist → lib}/commands/clean/clean.js +1 -1
  20. package/lib/commands/compile/compile.js +241 -0
  21. package/lib/commands/copy/copy.js +38 -0
  22. package/{dist → lib}/commands/create/create.js +1 -1
  23. package/{dist → lib}/commands/dev/dev.d.ts +2 -0
  24. package/lib/commands/dev/dev.js +286 -0
  25. package/{dist → lib}/commands/init/init.js +1 -1
  26. package/lib/commands/lint/lint.js +993 -0
  27. package/{dist → lib}/commands/migrate/migrate.js +1 -1
  28. package/lib/commands/publish/publish.js +104 -0
  29. package/lib/commands/serverless/serverless.d.ts +17 -0
  30. package/lib/commands/serverless/serverless.js +662 -0
  31. package/lib/commands/storybook/storybook.js +249 -0
  32. package/lib/commands/test/test.js +428 -0
  33. package/lib/commands/update/update.js +128 -0
  34. package/{dist → lib}/create/changelog.js +1 -1
  35. package/{dist → lib}/index.d.ts +1 -0
  36. package/{dist → lib}/index.js +2 -1
  37. package/lib/lex.js +73 -0
  38. package/lib/utils/aiService.d.ts +9 -0
  39. package/lib/utils/aiService.js +299 -0
  40. package/{dist → lib}/utils/app.d.ts +3 -0
  41. package/lib/utils/app.js +296 -0
  42. package/{dist → lib}/utils/file.d.ts +7 -3
  43. package/lib/utils/file.js +229 -0
  44. package/lib/utils/translations.d.ts +1 -0
  45. package/lib/utils/translations.js +74 -0
  46. package/package.json +59 -53
  47. package/postcss.config.js +5 -3
  48. package/tsconfig.build.json +2 -2
  49. package/webpack.config.js +229 -39
  50. package/dist/LexConfig.js +0 -287
  51. package/dist/commands/ai/ai.js +0 -303
  52. package/dist/commands/build/build.js +0 -404
  53. package/dist/commands/compile/compile.js +0 -234
  54. package/dist/commands/copy/copy.js +0 -38
  55. package/dist/commands/dev/dev.js +0 -74
  56. package/dist/commands/lint/lint.js +0 -993
  57. package/dist/commands/publish/publish.js +0 -104
  58. package/dist/commands/storybook/storybook.js +0 -249
  59. package/dist/commands/test/test.js +0 -429
  60. package/dist/commands/update/update.js +0 -132
  61. package/dist/lex.js +0 -70
  62. package/dist/utils/aiService.d.ts +0 -9
  63. package/dist/utils/aiService.js +0 -299
  64. package/dist/utils/app.js +0 -267
  65. package/dist/utils/file.js +0 -185
  66. package/emptyModule.js +0 -0
  67. package/eslint.config.js +0 -3
  68. /package/{dist → lib}/Button.stories.d.ts +0 -0
  69. /package/{dist → lib}/commands/ai/ai.d.ts +0 -0
  70. /package/{dist → lib}/commands/ai/index.d.ts +0 -0
  71. /package/{dist → lib}/commands/ai/index.js +0 -0
  72. /package/{dist → lib}/commands/clean/clean.d.ts +0 -0
  73. /package/{dist → lib}/commands/compile/compile.d.ts +0 -0
  74. /package/{dist → lib}/commands/config/config.d.ts +0 -0
  75. /package/{dist → lib}/commands/config/config.js +0 -0
  76. /package/{dist → lib}/commands/copy/copy.d.ts +0 -0
  77. /package/{dist → lib}/commands/create/create.d.ts +0 -0
  78. /package/{dist → lib}/commands/init/init.d.ts +0 -0
  79. /package/{dist → lib}/commands/link/link.d.ts +0 -0
  80. /package/{dist → lib}/commands/link/link.js +0 -0
  81. /package/{dist → lib}/commands/lint/autofix.d.ts +0 -0
  82. /package/{dist → lib}/commands/lint/lint.d.ts +0 -0
  83. /package/{dist → lib}/commands/migrate/migrate.d.ts +0 -0
  84. /package/{dist → lib}/commands/publish/publish.d.ts +0 -0
  85. /package/{dist → lib}/commands/storybook/storybook.d.ts +0 -0
  86. /package/{dist → lib}/commands/test/test.d.ts +0 -0
  87. /package/{dist → lib}/commands/update/update.d.ts +0 -0
  88. /package/{dist → lib}/commands/upgrade/upgrade.d.ts +0 -0
  89. /package/{dist → lib}/commands/upgrade/upgrade.js +0 -0
  90. /package/{dist → lib}/commands/versions/versions.d.ts +0 -0
  91. /package/{dist → lib}/commands/versions/versions.js +0 -0
  92. /package/{dist → lib}/create/changelog.d.ts +0 -0
  93. /package/{dist → lib}/lex.d.ts +0 -0
  94. /package/{dist → lib}/storybook/index.d.ts +0 -0
  95. /package/{dist → lib}/storybook/index.js +0 -0
  96. /package/{dist → lib}/test-react/index.d.ts +0 -0
  97. /package/{dist → lib}/test-react/index.js +0 -0
  98. /package/{dist → lib}/types.d.ts +0 -0
  99. /package/{dist → lib}/types.js +0 -0
  100. /package/{dist → lib}/utils/deepMerge.d.ts +0 -0
  101. /package/{dist → lib}/utils/deepMerge.js +0 -0
  102. /package/{dist → lib}/utils/log.d.ts +0 -0
  103. /package/{dist → lib}/utils/log.js +0 -0
  104. /package/{dist → lib}/utils/reactShim.d.ts +0 -0
  105. /package/{dist → lib}/utils/reactShim.js +0 -0
@@ -1,993 +0,0 @@
1
- import { execa } from "execa";
2
- import { existsSync, readFileSync, unlinkSync, writeFileSync } from "fs";
3
- import { dirname, resolve as pathResolve, extname } from "path";
4
- import { LexConfig } from "../../LexConfig.js";
5
- import { createSpinner } from "../../utils/app.js";
6
- import { resolveBinaryPath } from "../../utils/file.js";
7
- import { log } from "../../utils/log.js";
8
- let currentFilename;
9
- let currentDirname;
10
- try {
11
- currentFilename = eval('require("url").fileURLToPath(import.meta.url)');
12
- currentDirname = dirname(currentFilename);
13
- } catch {
14
- currentFilename = process.cwd();
15
- currentDirname = process.cwd();
16
- }
17
- const createDefaultESLintConfig = (useTypescript, cwd) => {
18
- const configPath = pathResolve(cwd, ".lex-temp-default-eslint.cjs");
19
- const originalConfig = null;
20
- const possiblePaths = [
21
- pathResolve(currentDirname, "eslint.config.ts"),
22
- pathResolve(currentDirname, "eslint.config.js"),
23
- pathResolve(process.env.LEX_HOME || "./node_modules/@nlabs/lex", "eslint.config.ts"),
24
- pathResolve(process.env.LEX_HOME || "./node_modules/@nlabs/lex", "eslint.config.js")
25
- ];
26
- let foundConfig = "";
27
- for (const path of possiblePaths) {
28
- if (existsSync(path)) {
29
- foundConfig = path;
30
- break;
31
- }
32
- }
33
- const configContent = `// Temporary ESLint config generated by Lex
34
- const lexConfig = require('@nlabs/lex/eslint.config.js');
35
-
36
- module.exports = lexConfig;`;
37
- writeFileSync(configPath, configContent, "utf8");
38
- return {
39
- configPath,
40
- originalConfig
41
- };
42
- };
43
- const createBasicESLintConfig = (useTypescript) => {
44
- const config = `// ESLint configuration
45
- import lexConfig from '@nlabs/lex/eslint.config.js';
46
-
47
- return lexConfig;`;
48
- return config;
49
- };
50
- const detectTypeScript = (cwd) => existsSync(pathResolve(cwd, "tsconfig.json"));
51
- const ensureModuleType = (cwd) => {
52
- const packageJsonPath = pathResolve(cwd, "package.json");
53
- if (existsSync(packageJsonPath)) {
54
- try {
55
- const packageJsonContent = readFileSync(packageJsonPath, "utf8");
56
- const packageJson = JSON.parse(packageJsonContent);
57
- if (packageJson.type !== "module") {
58
- log('Warning: package.json should have "type": "module" for ESM support. Please add this manually.', "warn", false);
59
- }
60
- } catch (_error) {
61
- }
62
- }
63
- };
64
- const installDependencies = async (cwd, useTypescript, quiet) => {
65
- if (useTypescript) {
66
- log("Using TypeScript ESLint from Lex...", "info", quiet);
67
- } else {
68
- log("Using ESLint from Lex...", "info", quiet);
69
- }
70
- };
71
- const runEslintWithLex = async (cwd, quiet, cliName, fix, debug, useTypescript, captureOutput) => {
72
- const spinner = createSpinner(quiet);
73
- try {
74
- const projectConfigPath = pathResolve(cwd, "eslint.config.js");
75
- const projectConfigPathTs = pathResolve(cwd, "eslint.config.ts");
76
- const hasProjectConfig = existsSync(projectConfigPath) || existsSync(projectConfigPathTs);
77
- const hasLexConfigEslint = LexConfig.config.eslint && Object.keys(LexConfig.config.eslint).length > 0;
78
- const possiblePaths = [
79
- pathResolve(currentDirname, "../../../../eslint.config.js"),
80
- pathResolve(currentDirname, "../../../../eslint.config.ts"),
81
- pathResolve(process.env.LEX_HOME || "/usr/local/lib/node_modules/@nlabs/lex", "eslint.config.js"),
82
- pathResolve(process.env.LEX_HOME || "/usr/local/lib/node_modules/@nlabs/lex", "eslint.config.ts")
83
- ];
84
- let lexConfigPath = "";
85
- for (const path of possiblePaths) {
86
- if (existsSync(path)) {
87
- lexConfigPath = path;
88
- break;
89
- }
90
- }
91
- let configPath = "";
92
- let tempConfigPath = "";
93
- if (hasProjectConfig) {
94
- configPath = existsSync(projectConfigPathTs) ? projectConfigPathTs : projectConfigPath;
95
- if (debug) {
96
- log(`Using project ESLint config file: ${configPath}`, "info", quiet);
97
- }
98
- } else if (hasLexConfigEslint) {
99
- tempConfigPath = pathResolve(cwd, ".lex-temp-eslint.cjs");
100
- const configContent = `// Temporary ESLint config generated by Lex
101
- const lexConfig = require('@nlabs/lex/eslint.config.js');
102
- const userConfig = ${JSON.stringify(LexConfig.config.eslint, null, 2)};
103
-
104
- // Merge Lex's config with user config
105
- module.exports = {
106
- ...lexConfig
107
- };`;
108
- writeFileSync(tempConfigPath, configContent, "utf8");
109
- configPath = tempConfigPath;
110
- if (debug) {
111
- log(`Using ESLint config from lex.config.* file via temp file: ${tempConfigPath}`, "info", quiet);
112
- }
113
- } else if (lexConfigPath && existsSync(lexConfigPath)) {
114
- configPath = lexConfigPath;
115
- if (debug) {
116
- log(`Using Lex ESLint config file: ${configPath}`, "info", quiet);
117
- }
118
- } else {
119
- tempConfigPath = pathResolve(cwd, ".lex-temp-default-eslint.cjs");
120
- const configContent = `// Temporary default ESLint config generated by Lex
121
- const lexConfig = require('@nlabs/lex/eslint.config.js');
122
-
123
- module.exports = lexConfig;`;
124
- writeFileSync(tempConfigPath, configContent, "utf8");
125
- configPath = tempConfigPath;
126
- if (debug) {
127
- log(`Created temporary default ESLint config at: ${tempConfigPath}`, "info", quiet);
128
- } else {
129
- log("No ESLint configuration found. Using Lex default configuration.", "info", quiet);
130
- }
131
- }
132
- const eslintBinary = resolveBinaryPath("eslint", "eslint");
133
- if (!eslintBinary) {
134
- log(`
135
- ${cliName} Error: ESLint binary not found in Lex's node_modules`, "error", quiet);
136
- log("Please reinstall Lex or check your installation.", "info", quiet);
137
- return 1;
138
- }
139
- const baseEslintArgs = [
140
- ...fix ? ["--fix"] : [],
141
- ...debug ? ["--debug"] : [],
142
- "--no-error-on-unmatched-pattern",
143
- "--no-warn-ignored"
144
- ];
145
- const configArgs = configPath ? ["--config", configPath] : [];
146
- const jsResult = await execa(eslintBinary, [
147
- "src/**/*.{js,jsx}",
148
- ...configArgs,
149
- ...baseEslintArgs
150
- ], {
151
- reject: false,
152
- stdio: "pipe",
153
- cwd,
154
- shell: true
155
- });
156
- if (jsResult.stdout) {
157
- console.log(jsResult.stdout);
158
- if (captureOutput) {
159
- captureOutput(jsResult.stdout);
160
- }
161
- }
162
- if (jsResult.stderr) {
163
- console.error(jsResult.stderr);
164
- if (captureOutput) {
165
- captureOutput(jsResult.stderr);
166
- }
167
- }
168
- let tsResult = { exitCode: 0, stdout: "", stderr: "" };
169
- if (useTypescript) {
170
- tsResult = await execa(eslintBinary, [
171
- "src/**/*.{ts,tsx}",
172
- ...configArgs,
173
- ...baseEslintArgs
174
- ], {
175
- reject: false,
176
- stdio: "pipe",
177
- cwd,
178
- shell: true
179
- });
180
- if (tsResult.stdout) {
181
- console.log(tsResult.stdout);
182
- }
183
- if (tsResult.stderr) {
184
- console.error(tsResult.stderr);
185
- }
186
- }
187
- if (tempConfigPath && existsSync(tempConfigPath)) {
188
- try {
189
- unlinkSync(tempConfigPath);
190
- if (debug) {
191
- log(`Removed temporary ESLint config at ${tempConfigPath}`, "info", quiet);
192
- }
193
- } catch (error) {
194
- if (debug) {
195
- log(`Failed to remove temporary ESLint config: ${error.message}`, "warn", quiet);
196
- }
197
- }
198
- }
199
- const eslintNotFound = jsResult.stderr?.includes("command not found") || jsResult.stderr?.includes("eslint: command not found");
200
- if (eslintNotFound) {
201
- spinner.fail("ESLint not found!");
202
- log(`
203
- ${cliName} Error: Lex's ESLint binary not found. Please reinstall Lex or check your installation.`, "error", quiet);
204
- return 1;
205
- }
206
- if (jsResult.exitCode === 0 && tsResult.exitCode === 0) {
207
- spinner.succeed("Linting completed!");
208
- return 0;
209
- }
210
- const noFilesFound = (jsResult.stderr?.includes("No such file or directory") || jsResult.stdout?.includes("No such file or directory")) && (!useTypescript || tsResult.stderr?.includes("No such file or directory") || tsResult.stdout?.includes("No such file or directory"));
211
- if (noFilesFound) {
212
- spinner.succeed("No files found to lint");
213
- return 0;
214
- }
215
- spinner.fail("Linting failed!");
216
- log(`
217
- ${cliName} Error: ESLint found issues in your code.`, "error", quiet);
218
- return 1;
219
- } catch (error) {
220
- spinner.fail("Linting failed!");
221
- log(`
222
- ${cliName} Error: ${error.message}`, "error", quiet);
223
- return 1;
224
- }
225
- };
226
- const applyAIFix = async (cwd, errors, quiet) => {
227
- const spinner = createSpinner(quiet);
228
- spinner.start("Using AI to fix remaining lint issues...");
229
- try {
230
- const fileErrorMap = /* @__PURE__ */ new Map();
231
- const lines = errors.split("\n");
232
- let currentFile = "";
233
- for (const line of lines) {
234
- if (line.match(/^(\/|[A-Z]:\\).*?\.(js|jsx|ts|tsx)$/)) {
235
- currentFile = line.trim();
236
- if (!fileErrorMap.has(currentFile)) {
237
- fileErrorMap.set(currentFile, []);
238
- }
239
- } else if (currentFile && line.trim() && line.match(/\s+\d+:\d+\s+(error|warning)\s+/)) {
240
- const errorArray = fileErrorMap.get(currentFile);
241
- if (errorArray) {
242
- errorArray.push(line.trim());
243
- }
244
- }
245
- }
246
- if (fileErrorMap.size === 0) {
247
- log("Using alternative error parsing strategy", "info", quiet);
248
- const sections = errors.split("\n\n");
249
- for (const section of sections) {
250
- if (section.trim() === "") {
251
- continue;
252
- }
253
- const lines2 = section.split("\n");
254
- const filePath = lines2[0].trim();
255
- if (filePath.match(/\.(js|jsx|ts|tsx)$/)) {
256
- fileErrorMap.set(filePath, []);
257
- for (let i = 1; i < lines2.length; i++) {
258
- if (lines2[i].trim() !== "") {
259
- fileErrorMap.get(filePath)?.push(lines2[i].trim());
260
- }
261
- }
262
- }
263
- }
264
- }
265
- if (fileErrorMap.size === 0) {
266
- log("Using direct file path extraction", "info", quiet);
267
- const filePathRegex = /(?:\/|[A-Z]:\\)(?:[^:\n]+\/)*[^:\n]+\.(js|jsx|ts|tsx)/g;
268
- const filePaths = errors.match(filePathRegex) || [];
269
- for (const filePath of filePaths) {
270
- if (!fileErrorMap.has(filePath) && existsSync(filePath)) {
271
- fileErrorMap.set(filePath, []);
272
- }
273
- }
274
- const knownFiles = [
275
- pathResolve(cwd, "src/create/changelog.ts"),
276
- pathResolve(cwd, "src/utils/aiService.ts"),
277
- pathResolve(cwd, "src/utils/app.ts"),
278
- pathResolve(cwd, "src/utils/reactShim.ts"),
279
- pathResolve(cwd, "src/commands/lint/autofix.js")
280
- ];
281
- for (const file of knownFiles) {
282
- if (existsSync(file) && !fileErrorMap.has(file)) {
283
- fileErrorMap.set(file, []);
284
- }
285
- }
286
- }
287
- for (const filePath of fileErrorMap.keys()) {
288
- if (!existsSync(filePath)) {
289
- log(`File not found: ${filePath}`, "warn", quiet);
290
- continue;
291
- }
292
- log(`Processing file: ${filePath}`, "info", quiet);
293
- const isCursorIDE = LexConfig.config.ai?.provider === "cursor" || process.env.CURSOR_IDE === "true";
294
- if (isCursorIDE) {
295
- try {
296
- const prompt = `Fix all ESLint errors in this file. Focus on:
297
- 1. Fixing naming conventions
298
- 2. Fixing sort-keys issues
299
- 3. Replacing console.log with log utility
300
- 4. Fixing no-plusplus issues
301
- 5. Fixing unnecessary escape characters
302
- 6. Fixing other ESLint errors
303
-
304
- CRITICAL REQUIREMENTS:
305
- - ONLY fix the specific lines with ESLint errors
306
- - DO NOT modify any other lines of code
307
- - DO NOT remove line breaks unless they are specifically causing ESLint errors
308
- - DO NOT condense multi-line structures to single lines
309
- - PRESERVE all existing line breaks and formatting that is not causing errors
310
-
311
- SPECIFIC FORMATTING RULES:
312
- - Maintain proper indentation (2 spaces)
313
- - Keep line breaks between class/interface declaration and their members
314
- - Keep line breaks between methods
315
- - Ensure there is a line break after opening braces for classes, interfaces, and methods
316
- - DO NOT place class/interface properties or methods on the same line as the opening brace
317
- - Preserve empty lines between logical code blocks
318
- - PRESERVE multi-line imports - do not condense them to single lines
319
- - PRESERVE multi-line object/array declarations - do not condense them to single lines
320
-
321
- SORT-KEYS RULE (HIGHEST PRIORITY):
322
- - All object literal keys MUST be sorted alphabetically in ascending order
323
- - This applies to ALL objects in the file, not just those with explicit sort-keys errors
324
- - Example: {b: 2, a: 1, c: 3} should become {a: 1, b: 2, c: 3}
325
- - Preserve the original formatting and line breaks when sorting
326
-
327
- Example of CORRECT formatting (DO NOT CHANGE):
328
- export class UserConstants {
329
- static readonly ADD_ITEM_ERROR: string = 'USER_ADD_ITEM_ERROR';
330
- static readonly OTHER_CONSTANT: string = 'OTHER_CONSTANT';
331
- }
332
-
333
- constructor(flux: FluxFramework, CustomAdapter: typeof Event = Event) {
334
- this.CustomAdapter = CustomAdapter;
335
- this.flux = flux;
336
- }
337
-
338
- import {
339
- app,
340
- events,
341
- images,
342
- locations,
343
- messages,
344
- posts,
345
- tags,
346
- users,
347
- websocket
348
- } from './stores';
349
-
350
- const config = {
351
- apiKey: 'value',
352
- baseUrl: 'https://api.example.com',
353
- timeout: 5000
354
- };
355
-
356
- Example of INCORRECT formatting (FIX THIS):
357
- export class UserConstants {static readonly ADD_ITEM_ERROR: string = 'USER_ADD_ITEM_ERROR';
358
- static readonly OTHER_CONSTANT: string = 'OTHER_CONSTANT';
359
- }
360
-
361
- constructor(flux: FluxFramework, CustomAdapter: typeof Event = Event) {this.CustomAdapter = CustomAdapter;
362
- this.flux = flux;}
363
-
364
- import {app, events, images, locations, messages, posts, tags, users, websocket} from './stores';
365
-
366
- const config = {baseUrl: 'https://api.example.com', apiKey: 'value', timeout: 5000};
367
-
368
- Fix ONLY the specific ESLint errors. Return the properly formatted code.`;
369
- try {
370
- const promptFile = pathResolve(cwd, ".cursor_prompt_temp.txt");
371
- writeFileSync(promptFile, prompt, "utf8");
372
- await execa("cursor", ["edit", "--file", filePath, "--prompt-file", promptFile], {
373
- reject: false,
374
- stdio: "pipe",
375
- cwd
376
- });
377
- try {
378
- unlinkSync(promptFile);
379
- } catch (_error) {
380
- }
381
- log(`Applied Cursor AI fixes to ${filePath}`, "info", quiet);
382
- } catch (error) {
383
- const wasModified = await applyDirectFixes(filePath, quiet);
384
- if (wasModified) {
385
- log(`Applied direct fixes to ${filePath}`, "info", quiet);
386
- }
387
- }
388
- } catch (error) {
389
- log(`Error using Cursor AI: ${error.message}`, "error", quiet);
390
- await applyDirectFixes(filePath, quiet);
391
- }
392
- } else {
393
- const wasModified = await applyDirectFixes(filePath, quiet);
394
- if (wasModified) {
395
- log(`Applied direct fixes to ${filePath}`, "info", quiet);
396
- }
397
- const fileErrors = fileErrorMap.get(filePath) || [];
398
- if (fileErrors.length > 0) {
399
- try {
400
- const { callAIService } = await import("../../utils/aiService.js");
401
- const fileContent = readFileSync(filePath, "utf8");
402
- const prompt = `Fix the following ESLint errors in this code:
403
- ${fileErrors.join("\n")}
404
-
405
- Here's the code:
406
- \`\`\`
407
- ${fileContent}
408
- \`\`\`
409
-
410
- CRITICAL REQUIREMENTS:
411
- - ONLY fix the specific lines with ESLint errors
412
- - DO NOT modify any other lines of code
413
- - DO NOT remove line breaks unless they are specifically causing ESLint errors
414
- - DO NOT condense multi-line structures to single lines
415
- - PRESERVE all existing line breaks and formatting that is not causing errors
416
-
417
- SPECIFIC FORMATTING RULES:
418
- - Maintain proper indentation (2 spaces)
419
- - Keep line breaks between class/interface declaration and their members
420
- - Keep line breaks between methods
421
- - Ensure there is a line break after opening braces for classes, interfaces, and methods
422
- - DO NOT place class/interface properties or methods on the same line as the opening brace
423
- - Preserve empty lines between logical code blocks
424
- - PRESERVE multi-line imports - do not condense them to single lines
425
- - PRESERVE multi-line object/array declarations - do not condense them to single lines
426
-
427
- SORT-KEYS RULE (HIGHEST PRIORITY):
428
- - All object literal keys MUST be sorted alphabetically in ascending order
429
- - This applies to ALL objects in the file, not just those with explicit sort-keys errors
430
- - Example: {b: 2, a: 1, c: 3} should become {a: 1, b: 2, c: 3}
431
- - Preserve the original formatting and line breaks when sorting
432
-
433
- WHAT TO FIX:
434
- 1. Sorting all object keys alphabetically (sort-keys rule) - ALL objects must have sorted keys
435
- 2. Fixing naming conventions - ONLY for variables/functions with naming errors
436
- 3. Replacing console.log with log utility - ONLY for console.log statements
437
- 4. Fixing no-plusplus issues - ONLY for ++/-- operators
438
- 5. Fixing unnecessary escape characters - ONLY for escaped characters that don't need escaping
439
- 6. Proper indentation and spacing - ONLY where specifically required by errors
440
- 7. String quotes consistency (use single quotes) - ONLY for string literals with quote errors
441
- 8. Import order and spacing - ONLY for imports with order/spacing errors
442
- 9. Function parameter formatting - ONLY for functions with parameter errors
443
- 10. Variable naming conventions - ONLY for variables with naming errors
444
- 11. No unused variables or imports - ONLY for unused variables/imports
445
- 12. Avoiding nested ternaries - ONLY for nested ternary expressions
446
- 13. Any other ESLint errors - ONLY for the specific errors listed above
447
-
448
- WHAT NOT TO FIX:
449
- - Do not change properly formatted multi-line structures
450
- - Do not remove line breaks that are not causing errors
451
- - Do not change indentation that is already correct
452
- - Do not modify spacing that is already correct
453
- - Do not condense readable multi-line code to single lines
454
- - Do not modify code that is not mentioned in the ESLint errors
455
-
456
- Example of CORRECT formatting (DO NOT CHANGE):
457
- export class UserConstants {
458
- static readonly ADD_ITEM_ERROR: string = 'USER_ADD_ITEM_ERROR';
459
- static readonly OTHER_CONSTANT: string = 'OTHER_CONSTANT';
460
- }
461
-
462
- constructor(flux: FluxFramework, CustomAdapter: typeof Event = Event) {
463
- this.CustomAdapter = CustomAdapter;
464
- this.flux = flux;
465
- }
466
-
467
- import {
468
- app,
469
- events,
470
- images,
471
- locations,
472
- messages,
473
- posts,
474
- tags,
475
- users,
476
- websocket
477
- } from './stores';
478
-
479
- const config = {
480
- apiKey: 'value',
481
- baseUrl: 'https://api.example.com',
482
- timeout: 5000
483
- };
484
-
485
- Example of INCORRECT formatting (FIX THIS):
486
- export class UserConstants {static readonly ADD_ITEM_ERROR: string = 'USER_ADD_ITEM_ERROR';
487
- static readonly OTHER_CONSTANT: string = 'OTHER_CONSTANT';
488
- }
489
-
490
- constructor(flux: FluxFramework, CustomAdapter: typeof Event = Event) {this.CustomAdapter = CustomAdapter;
491
- this.flux = flux;}
492
-
493
- import {app, events, images, locations, messages, posts, tags, users, websocket} from './stores';
494
-
495
- const config = {baseUrl: 'https://api.example.com', apiKey: 'value', timeout: 5000};
496
-
497
- Fix ONLY the specific ESLint errors listed above. Review the entire file for compliance with all ESLint rules.
498
- Return only the properly formatted fixed code without any explanations.`;
499
- const fixedContent = await callAIService(prompt, quiet);
500
- if (fixedContent && fixedContent !== fileContent) {
501
- writeFileSync(filePath, fixedContent, "utf8");
502
- log(`Applied AI fixes to ${filePath}`, "info", quiet);
503
- }
504
- } catch (error) {
505
- log(`Error applying AI fixes to ${filePath}: ${error.message}`, "error", quiet);
506
- }
507
- }
508
- }
509
- }
510
- spinner.succeed("AI fixes applied successfully!");
511
- } catch (error) {
512
- spinner.fail("Failed to apply AI fixes");
513
- log(`Error: ${error.message}`, "error", quiet);
514
- if (!quiet) {
515
- console.error(error);
516
- }
517
- }
518
- };
519
- const applyDirectFixes = async (filePath, quiet) => {
520
- let wasModified = false;
521
- try {
522
- const fileContent = readFileSync(filePath, "utf8");
523
- let newContent = fileContent;
524
- if (filePath.includes("aiService.ts")) {
525
- log("Fixing issues in aiService.ts", "info", quiet);
526
- newContent = newContent.replace(
527
- /'Content-Type': 'application\/json',\s*'Authorization': `Bearer/g,
528
- "'Authorization': `Bearer', 'Content-Type': 'application/json'"
529
- );
530
- newContent = newContent.replace(
531
- /headers: {([^}]*)},\s*method: 'POST'/g,
532
- "method: 'POST',\n headers: {$1}"
533
- );
534
- newContent = newContent.replace(
535
- /{role: 'system', content:/g,
536
- "{content:, role: 'system',"
537
- );
538
- newContent = newContent.replace(
539
- /{role: 'user', content:/g,
540
- "{content:, role: 'user',"
541
- );
542
- newContent = newContent.replace(
543
- /\(([^)]*?)_([a-zA-Z0-9]+)(\s*:[^)]*)\)/g,
544
- "($1$2$3)"
545
- );
546
- newContent = newContent.replace(/console\.log\(/g, "log(");
547
- if (!newContent.includes("import {log}") && newContent.includes("log(")) {
548
- newContent = newContent.replace(
549
- /import {([^}]*)} from '(.*)';/,
550
- "import {$1} from '$2';\nimport {log} from './log.js';"
551
- );
552
- }
553
- }
554
- if (filePath.includes("reactShim.ts")) {
555
- log("Fixing naming-convention issues in reactShim.ts", "info", quiet);
556
- newContent = newContent.replace(
557
- "import * as React from",
558
- "import * as react from"
559
- );
560
- newContent = newContent.replace(/React\./g, "react.");
561
- }
562
- if (filePath.includes("changelog.ts")) {
563
- log("Fixing issues in changelog.ts", "info", quiet);
564
- newContent = newContent.replace(/(\w+)\+\+/g, "$1 += 1");
565
- newContent = newContent.replace(/\\\$/g, "$");
566
- newContent = newContent.replace(/\\\./g, ".");
567
- newContent = newContent.replace(/\\\*/g, "*");
568
- newContent = newContent.replace(/\\:/g, ":");
569
- }
570
- if (filePath.includes("app.ts")) {
571
- log("Fixing issues in app.ts", "info", quiet);
572
- newContent = newContent.replace(/console\.log\(/g, "log(");
573
- if (!newContent.includes("import {log}") && newContent.includes("log(")) {
574
- newContent = newContent.replace(
575
- /import boxen from 'boxen';/,
576
- "import boxen from 'boxen';\nimport {log} from './log.js';"
577
- );
578
- }
579
- newContent = newContent.replace(/\\\//g, "/");
580
- }
581
- if (filePath.includes("autofix.js")) {
582
- log("Fixing issues in autofix.js", "info", quiet);
583
- newContent = newContent.replace(
584
- /import {([^}]*)} from 'path';[\s\n]*import {([^}]*)} from 'path';/,
585
- "import {$1, $2} from 'path';"
586
- );
587
- newContent = newContent.replace(
588
- /__filename/g,
589
- "currentFilename"
590
- );
591
- newContent = newContent.replace(
592
- /__dirname/g,
593
- "currentDirname"
594
- );
595
- newContent = newContent.replace(
596
- /const prefix = type === 'error' \? '❌ ' : type === 'success' \? '✅ ' : 'ℹ️ ';/,
597
- "let prefix = '\u2139\uFE0F ';\nif(type === 'error') {\n prefix = '\u274C ';\n} else if(type === 'success') {\n prefix = '\u2705 ';\n}"
598
- );
599
- newContent = newContent.replace(
600
- /async function runEslintFix\(\)/g,
601
- "const runEslintFix = async ()"
602
- );
603
- newContent = newContent.replace(
604
- /async function getFilesWithErrors\(\)/g,
605
- "const getFilesWithErrors = async ()"
606
- );
607
- newContent = newContent.replace(
608
- /async function isCursorAvailable\(\)/g,
609
- "const isCursorAvailable = async ()"
610
- );
611
- newContent = newContent.replace(
612
- /async function fixFileWithCursorAI\(filePath\)/g,
613
- "const fixFileWithCursorAI = async (filePath)"
614
- );
615
- newContent = newContent.replace(
616
- /async function main\(\)/g,
617
- "const main = async ()"
618
- );
619
- newContent = newContent.replace(
620
- /import {existsSync, readFileSync, writeFileSync}/g,
621
- "import {writeFileSync}"
622
- );
623
- newContent = newContent.replace(
624
- /console\.log\(`\${prefix} \${message}`\);/g,
625
- "process.stdout.write(`${prefix} ${message}\\n`);"
626
- );
627
- newContent = newContent.replace(
628
- /} catch\(error\) {[\s\n]*\/\/ Ignore cleanup errors/g,
629
- "} catch(_) {\n // Ignore cleanup errors"
630
- );
631
- newContent = newContent.replace(
632
- /} catch\(error\) {[\s\n]*log\(/g,
633
- "} catch(err) {\n log("
634
- );
635
- newContent = newContent.replace(
636
- /} catch\(error\) {[\s\n]*return false;/g,
637
- "} catch(_) {\n return false;"
638
- );
639
- newContent = newContent.replace(
640
- /for\(const filePath of filesWithErrors\) {[\s\n]*const success = await fixFileWithCursorAI\(filePath\);/g,
641
- "const fixResults = await Promise.all(filesWithErrors.map(filePath => fixFileWithCursorAI(filePath)));\nfor(const success of fixResults) {"
642
- );
643
- newContent = newContent.replace(
644
- /fixedCount\+\+;/g,
645
- "fixedCount += 1;"
646
- );
647
- }
648
- if (newContent !== fileContent) {
649
- writeFileSync(filePath, newContent, "utf8");
650
- log(`Fixed issues in ${filePath}`, "info", quiet);
651
- wasModified = true;
652
- }
653
- return wasModified;
654
- } catch (error) {
655
- log(`Error applying direct fixes to ${filePath}: ${error.message}`, "error", quiet);
656
- return false;
657
- }
658
- };
659
- const loadAIConfig = async (cwd, quiet, debug = false) => {
660
- const configFormats = ["js", "mjs", "cjs", "ts", "json"];
661
- const configBaseName = "lex.config";
662
- let lexConfigPath = "";
663
- for (const format of configFormats) {
664
- const potentialPath = pathResolve(cwd, `./${configBaseName}.${format}`);
665
- if (existsSync(potentialPath)) {
666
- lexConfigPath = potentialPath;
667
- break;
668
- }
669
- }
670
- if (lexConfigPath) {
671
- try {
672
- const format = extname(lexConfigPath).slice(1);
673
- let importPath = lexConfigPath;
674
- if (format === "mjs") {
675
- try {
676
- const url = new URL(`file://${lexConfigPath}`);
677
- importPath = url.href;
678
- if (debug) {
679
- log(`Using URL format for MJS import: ${importPath}`, "info", quiet);
680
- }
681
- } catch (urlError) {
682
- log(`Error creating URL for MJS import: ${urlError.message}`, "warn", debug || !quiet);
683
- importPath = `file://${lexConfigPath}`;
684
- }
685
- }
686
- if (debug) {
687
- log(`Trying to import config from ${importPath} (format: ${format})`, "info", quiet);
688
- }
689
- let lexConfig;
690
- try {
691
- lexConfig = await import(importPath);
692
- } catch (importError) {
693
- if (importError.message.includes("not defined in ES module scope")) {
694
- log(`ES Module syntax error in ${lexConfigPath}. Make sure you're using 'export' instead of 'module.exports'.`, "error", quiet);
695
- if (debug) {
696
- console.error(importError);
697
- }
698
- return;
699
- }
700
- throw importError;
701
- }
702
- let configData = null;
703
- if (lexConfig.default) {
704
- configData = lexConfig.default;
705
- if (debug) {
706
- log(`Found default export in ${lexConfigPath}`, "info", quiet);
707
- }
708
- } else {
709
- configData = lexConfig;
710
- if (debug) {
711
- log(`Using direct export in ${lexConfigPath}`, "info", quiet);
712
- }
713
- }
714
- if (configData && configData.ai) {
715
- log(`Found AI configuration in ${pathResolve(cwd, lexConfigPath)}, applying settings...`, "info", quiet);
716
- LexConfig.config.ai = { ...LexConfig.config.ai, ...configData.ai };
717
- }
718
- } catch (error) {
719
- log(`Error loading AI configuration from ${lexConfigPath}: ${error.message}`, "warn", quiet);
720
- if (debug) {
721
- console.error(error);
722
- }
723
- }
724
- }
725
- };
726
- const loadESLintConfig = async (cwd, quiet, debug) => {
727
- if (LexConfig.config.eslint && Object.keys(LexConfig.config.eslint).length > 0) {
728
- log("Found ESLint configuration in lex.config.* file", "info", debug || !quiet);
729
- return true;
730
- }
731
- const configFormats = ["js", "mjs", "cjs", "ts", "json"];
732
- const configBaseName = "lex.config";
733
- for (const format of configFormats) {
734
- const potentialPath = pathResolve(cwd, `./${configBaseName}.${format}`);
735
- if (existsSync(potentialPath)) {
736
- try {
737
- const fileFormat = extname(potentialPath).slice(1);
738
- let importPath = potentialPath;
739
- if (fileFormat === "mjs") {
740
- try {
741
- const url = new URL(`file://${potentialPath}`);
742
- importPath = url.href;
743
- if (debug) {
744
- log(`Using URL format for MJS import: ${importPath}`, "info", quiet);
745
- }
746
- } catch (urlError) {
747
- log(`Error creating URL for MJS import: ${urlError.message}`, "warn", debug || !quiet);
748
- importPath = `file://${potentialPath}`;
749
- }
750
- }
751
- if (debug) {
752
- log(`Trying to import config from ${importPath} (format: ${fileFormat})`, "info", quiet);
753
- }
754
- let lexConfig;
755
- try {
756
- lexConfig = await import(importPath);
757
- } catch (importError) {
758
- if (importError.message.includes("not defined in ES module scope")) {
759
- log(`ES Module syntax error in ${potentialPath}. Make sure you're using 'export' instead of 'module.exports'.`, "error", quiet);
760
- if (debug) {
761
- console.error(importError);
762
- }
763
- continue;
764
- }
765
- throw importError;
766
- }
767
- let configData = null;
768
- if (lexConfig.default) {
769
- configData = lexConfig.default;
770
- if (debug) {
771
- log(`Found default export in ${potentialPath}`, "info", quiet);
772
- }
773
- } else {
774
- configData = lexConfig;
775
- if (debug) {
776
- log(`Using direct export in ${potentialPath}`, "info", quiet);
777
- }
778
- }
779
- if (configData && configData.eslint && Object.keys(configData.eslint).length > 0) {
780
- log(`Found ESLint configuration in ${pathResolve(cwd, potentialPath)}, applying settings...`, "info", debug || !quiet);
781
- LexConfig.config.eslint = { ...LexConfig.config.eslint, ...configData.eslint };
782
- return true;
783
- }
784
- } catch (error) {
785
- log(`Error loading ESLint configuration from ${potentialPath}: ${error.message}`, "warn", quiet);
786
- if (debug) {
787
- console.error(error);
788
- }
789
- }
790
- }
791
- }
792
- return false;
793
- };
794
- const removeFileComments = (filePath, quiet) => {
795
- try {
796
- const fileContent = readFileSync(filePath, "utf8");
797
- if (fileContent.length > 1e6) {
798
- log(`Skipping comment removal for large file: ${filePath}`, "info", quiet);
799
- return false;
800
- }
801
- const ext = extname(filePath);
802
- let isTypeScript = false;
803
- let isJavaScript = false;
804
- if ([".ts", ".tsx"].includes(ext)) {
805
- isTypeScript = true;
806
- } else if ([".js", ".jsx"].includes(ext)) {
807
- isJavaScript = true;
808
- } else {
809
- return false;
810
- }
811
- let newContent = fileContent.replace(
812
- /\/\*[\s\S]*?\*\//g,
813
- (match) => {
814
- if (match.includes("Copyright") || match.includes("LICENSE") || match.includes("License") || match.includes("license")) {
815
- return match;
816
- }
817
- return "";
818
- }
819
- );
820
- newContent = newContent.replace(
821
- /\/\/.*$/gm,
822
- (match) => {
823
- if (match.includes("TODO") || match.includes("FIXME")) {
824
- return match;
825
- }
826
- return "";
827
- }
828
- );
829
- newContent = newContent.replace(/\n\s*\n\s*\n/g, "\n\n");
830
- if (newContent !== fileContent) {
831
- writeFileSync(filePath, newContent, "utf8");
832
- log(`Removed comments from ${filePath}`, "info", quiet);
833
- return true;
834
- }
835
- return false;
836
- } catch (error) {
837
- log(`Error removing comments from ${filePath}: ${error.message}`, "error", quiet);
838
- return false;
839
- }
840
- };
841
- const lint = async (cmd, callback = process.exit) => {
842
- const {
843
- cliName = "Lex",
844
- fix = false,
845
- debug = false,
846
- quiet = false,
847
- config = null,
848
- removeComments = false,
849
- // Handle kebab-case CLI flag conversion
850
- "remove-comments": removeCommentsFlag = false
851
- } = cmd;
852
- const shouldRemoveComments = removeComments || removeCommentsFlag;
853
- log(`${cliName} linting...`, "info", quiet);
854
- const cwd = process.cwd();
855
- const spinner = createSpinner(quiet);
856
- await loadAIConfig(cwd, quiet, debug);
857
- let tempConfigPath = null;
858
- try {
859
- const useTypescript = detectTypeScript(cwd);
860
- log(`TypeScript ${useTypescript ? "detected" : "not detected"} from tsconfig.json`, "info", quiet);
861
- if (useTypescript) {
862
- LexConfig.checkLintTypescriptConfig();
863
- }
864
- ensureModuleType(cwd);
865
- await installDependencies(cwd, useTypescript, quiet);
866
- const projectConfigPath = pathResolve(cwd, "eslint.config.js");
867
- const projectConfigPathTs = pathResolve(cwd, "eslint.config.ts");
868
- const hasEslintConfig = existsSync(projectConfigPath) || existsSync(projectConfigPathTs) || existsSync(pathResolve(cwd, ".eslintrc.js")) || existsSync(pathResolve(cwd, ".eslintrc.json")) || existsSync(pathResolve(cwd, ".eslintrc.yml")) || existsSync(pathResolve(cwd, ".eslintrc.yaml")) || existsSync(pathResolve(cwd, ".eslintrc"));
869
- const hasLexEslintConfig = await loadESLintConfig(cwd, quiet, debug);
870
- if (hasLexEslintConfig) {
871
- log("Using ESLint configuration from lex.config.* file", "info", quiet);
872
- }
873
- if (existsSync(pathResolve(cwd, ".eslintrc.json"))) {
874
- unlinkSync(pathResolve(cwd, ".eslintrc.json"));
875
- }
876
- let lexConfigPath = "";
877
- let shouldCreateTempConfig = false;
878
- if (!hasEslintConfig && !hasLexEslintConfig) {
879
- const possiblePaths = [
880
- pathResolve(currentDirname, "../../../../eslint.config.ts"),
881
- pathResolve(currentDirname, "../../../../eslint.config.js"),
882
- pathResolve(process.env.LEX_HOME || "./node_modules/@nlabs/lex", "eslint.config.ts"),
883
- pathResolve(process.env.LEX_HOME || "./node_modules/@nlabs/lex", "eslint.config.js")
884
- ];
885
- for (const path of possiblePaths) {
886
- if (existsSync(path)) {
887
- lexConfigPath = path;
888
- break;
889
- }
890
- }
891
- if (debug) {
892
- log(`Current directory: ${currentDirname}`, "info", quiet);
893
- log(`Project config path: ${projectConfigPath}`, "info", quiet);
894
- log(`Project config exists: ${hasEslintConfig}`, "info", quiet);
895
- log(`Found Lex config: ${lexConfigPath}`, "info", quiet);
896
- log(`Lex config exists: ${!!lexConfigPath && existsSync(lexConfigPath)}`, "info", quiet);
897
- }
898
- if (lexConfigPath && existsSync(lexConfigPath)) {
899
- log("No ESLint configuration found in project. Using Lex's default configuration.", "info", quiet);
900
- } else {
901
- shouldCreateTempConfig = true;
902
- }
903
- }
904
- if (config) {
905
- const userConfigPath = pathResolve(cwd, config);
906
- if (existsSync(userConfigPath)) {
907
- log(`Using specified ESLint configuration: ${config}`, "info", quiet);
908
- shouldCreateTempConfig = false;
909
- } else {
910
- log(`Specified ESLint configuration not found: ${config}. Using Lex's default configuration.`, "warn", quiet);
911
- }
912
- }
913
- if (shouldCreateTempConfig) {
914
- log("No ESLint configuration found. Creating a temporary configuration...", "info", quiet);
915
- const configResult = createDefaultESLintConfig(useTypescript, cwd);
916
- tempConfigPath = configResult.configPath;
917
- }
918
- let eslintOutput = "";
919
- const captureOutput = (output) => {
920
- eslintOutput += `${output}
921
- `;
922
- };
923
- const result = await runEslintWithLex(cwd, quiet, cliName, true, debug, useTypescript, captureOutput);
924
- if (shouldRemoveComments) {
925
- spinner.start("Removing comments from files...");
926
- const glob = await import("glob");
927
- const files = glob.sync("{src,lib}/**/*.{js,jsx,ts,tsx}", {
928
- cwd,
929
- ignore: ["**/node_modules/**", "**/dist/**", "**/build/**"]
930
- });
931
- let processedCount = 0;
932
- for (const file of files) {
933
- const filePath = pathResolve(cwd, file);
934
- if (removeFileComments(filePath, quiet)) {
935
- processedCount++;
936
- }
937
- }
938
- spinner.succeed(`Removed comments from ${processedCount} files`);
939
- }
940
- if (result !== 0 && fix) {
941
- const aiConfigured = LexConfig.config.ai?.provider && LexConfig.config.ai.provider !== "none";
942
- if (aiConfigured) {
943
- log("Applying AI fixes to remaining issues...", "info", quiet);
944
- await applyAIFix(cwd, eslintOutput, quiet);
945
- const afterFixResult = await runEslintWithLex(cwd, quiet, cliName, false, debug, useTypescript);
946
- callback(afterFixResult);
947
- return afterFixResult;
948
- }
949
- log("ESLint could not fix all issues automatically.", "warn", quiet);
950
- log("To enable AI-powered fixes, add AI configuration to your lex.config file:", "info", quiet);
951
- log(`
952
- // In lex.config.js (or lex.config.mjs, lex.config.cjs, etc.)
953
- export default {
954
- // Your existing config
955
- ai: {
956
- provider: 'cursor' // or 'openai', 'anthropic', etc.
957
- // Additional provider-specific settings
958
- }
959
- };`, "info", quiet);
960
- }
961
- callback(result);
962
- return result;
963
- } catch (error) {
964
- log(`
965
- ${cliName} Error: ${error.message}`, "error", quiet);
966
- if (spinner) {
967
- spinner.fail("Linting failed!");
968
- }
969
- callback(1);
970
- return 1;
971
- } finally {
972
- const tempFilePaths = [
973
- tempConfigPath,
974
- pathResolve(cwd, ".lex-temp-eslint.cjs"),
975
- pathResolve(cwd, ".lex-temp-default-eslint.cjs")
976
- ];
977
- for (const filePath of tempFilePaths) {
978
- if (filePath && existsSync(filePath)) {
979
- try {
980
- unlinkSync(filePath);
981
- if (debug) {
982
- log(`Cleaned up temporary ESLint config at ${filePath}`, "info", quiet);
983
- }
984
- } catch (_error) {
985
- }
986
- }
987
- }
988
- }
989
- };
990
- export {
991
- lint
992
- };
993
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2NvbW1hbmRzL2xpbnQvbGludC50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMjItUHJlc2VudCwgTml0cm9nZW4gTGFicywgSW5jLlxuICogQ29weXJpZ2h0cyBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSB0aGUgYWNjb21wYW55aW5nIExJQ0VOU0UgZmlsZSBmb3IgdGVybXMuXG4gKi9cbmltcG9ydCB7ZXhlY2F9IGZyb20gJ2V4ZWNhJztcbmltcG9ydCB7ZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCB1bmxpbmtTeW5jLCB3cml0ZUZpbGVTeW5jfSBmcm9tICdmcyc7XG5pbXBvcnQge2Rpcm5hbWUsIHJlc29sdmUgYXMgcGF0aFJlc29sdmUsIGV4dG5hbWV9IGZyb20gJ3BhdGgnO1xuXG5pbXBvcnQge0xleENvbmZpZ30gZnJvbSAnLi4vLi4vTGV4Q29uZmlnLmpzJztcbmltcG9ydCB7Y3JlYXRlU3Bpbm5lcn0gZnJvbSAnLi4vLi4vdXRpbHMvYXBwLmpzJztcbmltcG9ydCB7cmVzb2x2ZUJpbmFyeVBhdGh9IGZyb20gJy4uLy4uL3V0aWxzL2ZpbGUuanMnO1xuaW1wb3J0IHtsb2d9IGZyb20gJy4uLy4uL3V0aWxzL2xvZy5qcyc7XG5cbmxldCBjdXJyZW50RmlsZW5hbWU6IHN0cmluZztcbmxldCBjdXJyZW50RGlybmFtZTogc3RyaW5nO1xuXG50cnkge1xuICBjdXJyZW50RmlsZW5hbWUgPSBldmFsKCdyZXF1aXJlKFwidXJsXCIpLmZpbGVVUkxUb1BhdGgoaW1wb3J0Lm1ldGEudXJsKScpO1xuICBjdXJyZW50RGlybmFtZSA9IGRpcm5hbWUoY3VycmVudEZpbGVuYW1lKTtcbn0gY2F0Y2gge1xuICBjdXJyZW50RmlsZW5hbWUgPSBwcm9jZXNzLmN3ZCgpO1xuICBjdXJyZW50RGlybmFtZSA9IHByb2Nlc3MuY3dkKCk7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTGludE9wdGlvbnMge1xuICByZWFkb25seSBjYWNoZT86IGJvb2xlYW47XG4gIHJlYWRvbmx5IGNhY2hlRmlsZT86IHN0cmluZztcbiAgcmVhZG9ubHkgY2FjaGVMb2NhdGlvbj86IHN0cmluZztcbiAgcmVhZG9ubHkgY2xpTmFtZT86IHN0cmluZztcbiAgcmVhZG9ubHkgY29sb3I/OiBib29sZWFuO1xuICByZWFkb25seSBjb25maWc/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGRlYnVnPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgZW52Pzogc3RyaW5nO1xuICByZWFkb25seSBlbnZJbmZvPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgZXh0Pzogc3RyaW5nO1xuICByZWFkb25seSBmaXg/OiBib29sZWFuO1xuICByZWFkb25seSBmaXhEcnlSdW4/OiBib29sZWFuO1xuICByZWFkb25seSBmaXhUeXBlPzogc3RyaW5nO1xuICByZWFkb25seSBmb3JtYXQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGdsb2JhbD86IHN0cmluZztcbiAgcmVhZG9ubHkgaWdub3JlUGF0aD86IHN0cmluZztcbiAgcmVhZG9ubHkgaWdub3JlUGF0dGVybj86IHN0cmluZztcbiAgcmVhZG9ubHkgaW5pdD86IGJvb2xlYW47XG4gIHJlYWRvbmx5IG1heFdhcm5pbmdzPzogc3RyaW5nO1xuICByZWFkb25seSBub0NvbG9yPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgbm9Fc2xpbnRyYz86IGJvb2xlYW47XG4gIHJlYWRvbmx5IG5vSWdub3JlPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgbm9JbmxpbmVDb25maWc/OiBib29sZWFuO1xuICByZWFkb25seSBvdXRwdXRGaWxlPzogc3RyaW5nO1xuICByZWFkb25seSBwYXJzZXI/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHBhcnNlck9wdGlvbnM/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHBsdWdpbj86IHN0cmluZztcbiAgcmVhZG9ubHkgcHJpbnRDb25maWc/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHF1aWV0PzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgcmVtb3ZlQ29tbWVudHM/OiBib29sZWFuO1xuICByZWFkb25seSByZXBvcnRVbnVzZWREaXNhYmxlRGlyZWN0aXZlcz86IGJvb2xlYW47XG4gIHJlYWRvbmx5IHJlc29sdmVQbHVnaW5zUmVsYXRpdmVUbz86IHN0cmluZztcbiAgcmVhZG9ubHkgcnVsZT86IHN0cmluZztcbiAgcmVhZG9ubHkgcnVsZXNkaXI/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHN0ZGluPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgc3RkaW5GaWxlbmFtZT86IHN0cmluZztcbn1cblxuZXhwb3J0IHR5cGUgTGludENhbGxiYWNrID0gdHlwZW9mIHByb2Nlc3MuZXhpdDtcblxuaW50ZXJmYWNlIENvbmZpZ1Jlc3VsdCB7XG4gIGNvbmZpZ1BhdGg6IHN0cmluZztcbiAgb3JpZ2luYWxDb25maWc6IHN0cmluZyB8IG51bGw7XG59XG5cbmNvbnN0IGNyZWF0ZURlZmF1bHRFU0xpbnRDb25maWcgPSAodXNlVHlwZXNjcmlwdDogYm9vbGVhbiwgY3dkOiBzdHJpbmcpOiBDb25maWdSZXN1bHQgPT4ge1xuICAvLyBVc2UgYSB0ZW1wb3JhcnkgZmlsZSBwYXRoIGluc3RlYWQgb2YgY3JlYXRpbmcgaW4gdGhlIHByb2plY3QgZGlyZWN0b3J5XG4gIGNvbnN0IGNvbmZpZ1BhdGggPSBwYXRoUmVzb2x2ZShjd2QsICcubGV4LXRlbXAtZGVmYXVsdC1lc2xpbnQuY2pzJyk7XG4gIGNvbnN0IG9yaWdpbmFsQ29uZmlnID0gbnVsbDtcblxuICAvLyBUcnkgdG8gbG9jYXRlIExleCdzIEVTTGludCBjb25maWdcbiAgY29uc3QgcG9zc2libGVQYXRocyA9IFtcbiAgICBwYXRoUmVzb2x2ZShjdXJyZW50RGlybmFtZSwgJ2VzbGludC5jb25maWcudHMnKSxcbiAgICBwYXRoUmVzb2x2ZShjdXJyZW50RGlybmFtZSwgJ2VzbGludC5jb25maWcuanMnKSxcbiAgICBwYXRoUmVzb2x2ZShwcm9jZXNzLmVudi5MRVhfSE9NRSB8fCAnLi9ub2RlX21vZHVsZXMvQG5sYWJzL2xleCcsICdlc2xpbnQuY29uZmlnLnRzJyksXG4gICAgcGF0aFJlc29sdmUocHJvY2Vzcy5lbnYuTEVYX0hPTUUgfHwgJy4vbm9kZV9tb2R1bGVzL0BubGFicy9sZXgnLCAnZXNsaW50LmNvbmZpZy5qcycpXG4gIF07XG5cbiAgbGV0IGZvdW5kQ29uZmlnID0gJyc7XG5cbiAgZm9yKGNvbnN0IHBhdGggb2YgcG9zc2libGVQYXRocykge1xuICAgIGlmKGV4aXN0c1N5bmMocGF0aCkpIHtcbiAgICAgIGZvdW5kQ29uZmlnID0gcGF0aDtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIC8vIENyZWF0ZSBhIHRlbXBvcmFyeSBDb21tb25KUyBtb2R1bGUgdGhhdCByZXF1aXJlcyBMZXgncyBFU0xpbnQgY29uZmlnXG4gIGNvbnN0IGNvbmZpZ0NvbnRlbnQgPSBgLy8gVGVtcG9yYXJ5IEVTTGludCBjb25maWcgZ2VuZXJhdGVkIGJ5IExleFxuY29uc3QgbGV4Q29uZmlnID0gcmVxdWlyZSgnQG5sYWJzL2xleC9lc2xpbnQuY29uZmlnLmpzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gbGV4Q29uZmlnO2A7XG5cbiAgd3JpdGVGaWxlU3luYyhjb25maWdQYXRoLCBjb25maWdDb250ZW50LCAndXRmOCcpO1xuXG4gIHJldHVybiB7XG4gICAgY29uZmlnUGF0aCxcbiAgICBvcmlnaW5hbENvbmZpZ1xuICB9O1xufTtcblxuY29uc3QgY3JlYXRlQmFzaWNFU0xpbnRDb25maWcgPSAodXNlVHlwZXNjcmlwdDogYm9vbGVhbik6IHN0cmluZyA9PiB7XG4gIC8vIENyZWF0ZSBhIHNpbXBsaWZpZWQgY29uZmlnIHRoYXQgZXh0ZW5kcyBMZXgncyBFU0xpbnQgY29uZmlnXG4gIGNvbnN0IGNvbmZpZyA9IGAvLyBFU0xpbnQgY29uZmlndXJhdGlvblxuaW1wb3J0IGxleENvbmZpZyBmcm9tICdAbmxhYnMvbGV4L2VzbGludC5jb25maWcuanMnO1xuXG5yZXR1cm4gbGV4Q29uZmlnO2A7XG4gIHJldHVybiBjb25maWc7XG59O1xuXG4vKipcbiAqIENoZWNrIGlmIFR5cGVTY3JpcHQgaXMgYmVpbmcgdXNlZCBieSBsb29raW5nIGZvciB0c2NvbmZpZy5qc29uXG4gKi9cbmNvbnN0IGRldGVjdFR5cGVTY3JpcHQgPSAoY3dkOiBzdHJpbmcpOiBib29sZWFuID0+IGV4aXN0c1N5bmMocGF0aFJlc29sdmUoY3dkLCAndHNjb25maWcuanNvbicpKTtcblxuLyoqXG4gKiBFbnN1cmUgcGFja2FnZS5qc29uIGhhcyB0eXBlOiBtb2R1bGUgZm9yIEVTTSBzdXBwb3J0XG4gKi9cbmNvbnN0IGVuc3VyZU1vZHVsZVR5cGUgPSAoY3dkOiBzdHJpbmcpOiB2b2lkID0+IHtcbiAgY29uc3QgcGFja2FnZUpzb25QYXRoID0gcGF0aFJlc29sdmUoY3dkLCAncGFja2FnZS5qc29uJyk7XG5cbiAgaWYoZXhpc3RzU3luYyhwYWNrYWdlSnNvblBhdGgpKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHBhY2thZ2VKc29uQ29udGVudCA9IHJlYWRGaWxlU3luYyhwYWNrYWdlSnNvblBhdGgsICd1dGY4Jyk7XG4gICAgICBjb25zdCBwYWNrYWdlSnNvbiA9IEpTT04ucGFyc2UocGFja2FnZUpzb25Db250ZW50KTtcblxuICAgICAgLy8gSWYgdHlwZSBpcyBub3Qgc2V0IHRvIG1vZHVsZSwgd2FybiBpbnN0ZWFkIG9mIGF1dG8tbW9kaWZ5aW5nXG4gICAgICBpZihwYWNrYWdlSnNvbi50eXBlICE9PSAnbW9kdWxlJykge1xuICAgICAgICBsb2coJ1dhcm5pbmc6IHBhY2thZ2UuanNvbiBzaG91bGQgaGF2ZSBcInR5cGVcIjogXCJtb2R1bGVcIiBmb3IgRVNNIHN1cHBvcnQuIFBsZWFzZSBhZGQgdGhpcyBtYW51YWxseS4nLCAnd2FybicsIGZhbHNlKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoKF9lcnJvcikge1xuICAgICAgLy8gSWdub3JlIGVycm9yc1xuICAgIH1cbiAgfVxufTtcblxuY29uc3QgaW5zdGFsbERlcGVuZGVuY2llcyA9IGFzeW5jIChjd2Q6IHN0cmluZywgdXNlVHlwZXNjcmlwdDogYm9vbGVhbiwgcXVpZXQ6IGJvb2xlYW4pOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgaWYodXNlVHlwZXNjcmlwdCkge1xuICAgIGxvZygnVXNpbmcgVHlwZVNjcmlwdCBFU0xpbnQgZnJvbSBMZXguLi4nLCAnaW5mbycsIHF1aWV0KTtcbiAgfSBlbHNlIHtcbiAgICBsb2coJ1VzaW5nIEVTTGludCBmcm9tIExleC4uLicsICdpbmZvJywgcXVpZXQpO1xuICB9XG59O1xuXG5jb25zdCBydW5Fc2xpbnRXaXRoTGV4ID0gYXN5bmMgKFxuICBjd2Q6IHN0cmluZyxcbiAgcXVpZXQ6IGJvb2xlYW4sXG4gIGNsaU5hbWU6IHN0cmluZyxcbiAgZml4OiBib29sZWFuLFxuICBkZWJ1ZzogYm9vbGVhbixcbiAgdXNlVHlwZXNjcmlwdDogYm9vbGVhbixcbiAgY2FwdHVyZU91dHB1dD86IChvdXRwdXQ6IHN0cmluZykgPT4gdm9pZFxuKTogUHJvbWlzZTxudW1iZXI+ID0+IHtcbiAgY29uc3Qgc3Bpbm5lciA9IGNyZWF0ZVNwaW5uZXIocXVpZXQpO1xuXG4gIHRyeSB7XG4gICAgY29uc3QgcHJvamVjdENvbmZpZ1BhdGggPSBwYXRoUmVzb2x2ZShjd2QsICdlc2xpbnQuY29uZmlnLmpzJyk7XG4gICAgY29uc3QgcHJvamVjdENvbmZpZ1BhdGhUcyA9IHBhdGhSZXNvbHZlKGN3ZCwgJ2VzbGludC5jb25maWcudHMnKTtcbiAgICBjb25zdCBoYXNQcm9qZWN0Q29uZmlnID0gZXhpc3RzU3luYyhwcm9qZWN0Q29uZmlnUGF0aCkgfHwgZXhpc3RzU3luYyhwcm9qZWN0Q29uZmlnUGF0aFRzKTtcbiAgICBjb25zdCBoYXNMZXhDb25maWdFc2xpbnQgPSBMZXhDb25maWcuY29uZmlnLmVzbGludCAmJiBPYmplY3Qua2V5cyhMZXhDb25maWcuY29uZmlnLmVzbGludCkubGVuZ3RoID4gMDtcblxuICAgIGNvbnN0IHBvc3NpYmxlUGF0aHMgPSBbXG4gICAgICBwYXRoUmVzb2x2ZShjdXJyZW50RGlybmFtZSwgJy4uLy4uLy4uLy4uL2VzbGludC5jb25maWcuanMnKSxcbiAgICAgIHBhdGhSZXNvbHZlKGN1cnJlbnREaXJuYW1lLCAnLi4vLi4vLi4vLi4vZXNsaW50LmNvbmZpZy50cycpLFxuICAgICAgcGF0aFJlc29sdmUocHJvY2Vzcy5lbnYuTEVYX0hPTUUgfHwgJy91c3IvbG9jYWwvbGliL25vZGVfbW9kdWxlcy9AbmxhYnMvbGV4JywgJ2VzbGludC5jb25maWcuanMnKSxcbiAgICAgIHBhdGhSZXNvbHZlKHByb2Nlc3MuZW52LkxFWF9IT01FIHx8ICcvdXNyL2xvY2FsL2xpYi9ub2RlX21vZHVsZXMvQG5sYWJzL2xleCcsICdlc2xpbnQuY29uZmlnLnRzJylcbiAgICBdO1xuXG4gICAgbGV0IGxleENvbmZpZ1BhdGggPSAnJztcbiAgICBmb3IoY29uc3QgcGF0aCBvZiBwb3NzaWJsZVBhdGhzKSB7XG4gICAgICBpZihleGlzdHNTeW5jKHBhdGgpKSB7XG4gICAgICAgIGxleENvbmZpZ1BhdGggPSBwYXRoO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBsZXQgY29uZmlnUGF0aCA9ICcnO1xuICAgIGxldCB0ZW1wQ29uZmlnUGF0aCA9ICcnO1xuXG4gICAgLy8gUHJpb3JpdHk6XG4gICAgLy8gMS4gUHJvamVjdCBlc2xpbnQuY29uZmlnIGZpbGVzXG4gICAgLy8gMi4gRVNMaW50IGNvbmZpZyBpbiBsZXguY29uZmlnLiogZmlsZVxuICAgIC8vIDMuIExleCdzIGRlZmF1bHQgZXNsaW50LmNvbmZpZy5qc1xuICAgIC8vIDQuIENyZWF0ZSBhIHRlbXBvcmFyeSBjb25maWcgZmlsZVxuICAgIGlmKGhhc1Byb2plY3RDb25maWcpIHtcbiAgICAgIGNvbmZpZ1BhdGggPSBleGlzdHNTeW5jKHByb2plY3RDb25maWdQYXRoVHMpID8gcHJvamVjdENvbmZpZ1BhdGhUcyA6IHByb2plY3RDb25maWdQYXRoO1xuICAgICAgaWYoZGVidWcpIHtcbiAgICAgICAgbG9nKGBVc2luZyBwcm9qZWN0IEVTTGludCBjb25maWcgZmlsZTogJHtjb25maWdQYXRofWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZihoYXNMZXhDb25maWdFc2xpbnQpIHtcbiAgICAgIC8vIFdoZW4gdXNpbmcgbGV4LmNvbmZpZy5lc2xpbnQsIGNyZWF0ZSBhIHRlbXBvcmFyeSBKUyBjb25maWcgZmlsZSAobm90IEpTT04pXG4gICAgICAvLyB0byBhdm9pZCBFU00gSlNPTiBpbXBvcnQgaXNzdWVzXG4gICAgICB0ZW1wQ29uZmlnUGF0aCA9IHBhdGhSZXNvbHZlKGN3ZCwgJy5sZXgtdGVtcC1lc2xpbnQuY2pzJyk7XG5cbiAgICAgIC8vIENyZWF0ZSBhIENvbW1vbkpTIG1vZHVsZSB0aGF0IGV4dGVuZHMgTGV4J3MgZXNsaW50IGNvbmZpZ1xuICAgICAgY29uc3QgY29uZmlnQ29udGVudCA9IGAvLyBUZW1wb3JhcnkgRVNMaW50IGNvbmZpZyBnZW5lcmF0ZWQgYnkgTGV4XG5jb25zdCBsZXhDb25maWcgPSByZXF1aXJlKCdAbmxhYnMvbGV4L2VzbGludC5jb25maWcuanMnKTtcbmNvbnN0IHVzZXJDb25maWcgPSAke0pTT04uc3RyaW5naWZ5KExleENvbmZpZy5jb25maWcuZXNsaW50LCBudWxsLCAyKX07XG5cbi8vIE1lcmdlIExleCdzIGNvbmZpZyB3aXRoIHVzZXIgY29uZmlnXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgLi4ubGV4Q29uZmlnXG59O2A7XG5cbiAgICAgIHdyaXRlRmlsZVN5bmModGVtcENvbmZpZ1BhdGgsIGNvbmZpZ0NvbnRlbnQsICd1dGY4Jyk7XG4gICAgICBjb25maWdQYXRoID0gdGVtcENvbmZpZ1BhdGg7XG5cbiAgICAgIGlmKGRlYnVnKSB7XG4gICAgICAgIGxvZyhgVXNpbmcgRVNMaW50IGNvbmZpZyBmcm9tIGxleC5jb25maWcuKiBmaWxlIHZpYSB0ZW1wIGZpbGU6ICR7dGVtcENvbmZpZ1BhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmKGxleENvbmZpZ1BhdGggJiYgZXhpc3RzU3luYyhsZXhDb25maWdQYXRoKSkge1xuICAgICAgY29uZmlnUGF0aCA9IGxleENvbmZpZ1BhdGg7XG4gICAgICBpZihkZWJ1Zykge1xuICAgICAgICBsb2coYFVzaW5nIExleCBFU0xpbnQgY29uZmlnIGZpbGU6ICR7Y29uZmlnUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gQ3JlYXRlIGEgdGVtcG9yYXJ5IGRlZmF1bHQgY29uZmlnIGZpbGUgaWYgbm8gb3RoZXIgY29uZmlnIGlzIGZvdW5kXG4gICAgICB0ZW1wQ29uZmlnUGF0aCA9IHBhdGhSZXNvbHZlKGN3ZCwgJy5sZXgtdGVtcC1kZWZhdWx0LWVzbGludC5janMnKTtcblxuICAgICAgLy8gQ3JlYXRlIGEgYmFzaWMgRVNMaW50IGNvbmZpZ1xuICAgICAgY29uc3QgY29uZmlnQ29udGVudCA9IGAvLyBUZW1wb3JhcnkgZGVmYXVsdCBFU0xpbnQgY29uZmlnIGdlbmVyYXRlZCBieSBMZXhcbmNvbnN0IGxleENvbmZpZyA9IHJlcXVpcmUoJ0BubGFicy9sZXgvZXNsaW50LmNvbmZpZy5qcycpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGxleENvbmZpZztgO1xuXG4gICAgICB3cml0ZUZpbGVTeW5jKHRlbXBDb25maWdQYXRoLCBjb25maWdDb250ZW50LCAndXRmOCcpO1xuICAgICAgY29uZmlnUGF0aCA9IHRlbXBDb25maWdQYXRoO1xuXG4gICAgICBpZihkZWJ1Zykge1xuICAgICAgICBsb2coYENyZWF0ZWQgdGVtcG9yYXJ5IGRlZmF1bHQgRVNMaW50IGNvbmZpZyBhdDogJHt0ZW1wQ29uZmlnUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvZygnTm8gRVNMaW50IGNvbmZpZ3VyYXRpb24gZm91bmQuIFVzaW5nIExleCBkZWZhdWx0IGNvbmZpZ3VyYXRpb24uJywgJ2luZm8nLCBxdWlldCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgZXNsaW50QmluYXJ5ID0gcmVzb2x2ZUJpbmFyeVBhdGgoJ2VzbGludCcsICdlc2xpbnQnKTtcblxuICAgIGlmKCFlc2xpbnRCaW5hcnkpIHtcbiAgICAgIGxvZyhgXFxuJHtjbGlOYW1lfSBFcnJvcjogRVNMaW50IGJpbmFyeSBub3QgZm91bmQgaW4gTGV4J3Mgbm9kZV9tb2R1bGVzYCwgJ2Vycm9yJywgcXVpZXQpO1xuICAgICAgbG9nKCdQbGVhc2UgcmVpbnN0YWxsIExleCBvciBjaGVjayB5b3VyIGluc3RhbGxhdGlvbi4nLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgIHJldHVybiAxO1xuICAgIH1cblxuICAgIC8vIEJhc2UgRVNMaW50IGFyZ3VtZW50c1xuICAgIGNvbnN0IGJhc2VFc2xpbnRBcmdzID0gW1xuICAgICAgLi4uKGZpeCA/IFsnLS1maXgnXSA6IFtdKSxcbiAgICAgIC4uLihkZWJ1ZyA/IFsnLS1kZWJ1ZyddIDogW10pLFxuICAgICAgJy0tbm8tZXJyb3Itb24tdW5tYXRjaGVkLXBhdHRlcm4nLFxuICAgICAgJy0tbm8td2Fybi1pZ25vcmVkJ1xuICAgIF07XG5cbiAgICAvLyBBZGQgY29uZmlnIHBhdGhcbiAgICBjb25zdCBjb25maWdBcmdzID0gY29uZmlnUGF0aCA/IFsnLS1jb25maWcnLCBjb25maWdQYXRoXSA6IFtdO1xuXG4gICAgY29uc3QganNSZXN1bHQgPSBhd2FpdCBleGVjYShlc2xpbnRCaW5hcnksIFtcbiAgICAgICdzcmMvKiovKi57anMsanN4fScsXG4gICAgICAuLi5jb25maWdBcmdzLFxuICAgICAgLi4uYmFzZUVzbGludEFyZ3NcbiAgICBdLCB7XG4gICAgICByZWplY3Q6IGZhbHNlLFxuICAgICAgc3RkaW86ICdwaXBlJyxcbiAgICAgIGN3ZCxcbiAgICAgIHNoZWxsOiB0cnVlXG4gICAgfSk7XG5cbiAgICBpZihqc1Jlc3VsdC5zdGRvdXQpIHtcbiAgICAgIGNvbnNvbGUubG9nKGpzUmVzdWx0LnN0ZG91dCk7XG4gICAgICBpZihjYXB0dXJlT3V0cHV0KSB7XG4gICAgICAgIGNhcHR1cmVPdXRwdXQoanNSZXN1bHQuc3Rkb3V0KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZihqc1Jlc3VsdC5zdGRlcnIpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoanNSZXN1bHQuc3RkZXJyKTtcbiAgICAgIGlmKGNhcHR1cmVPdXRwdXQpIHtcbiAgICAgICAgY2FwdHVyZU91dHB1dChqc1Jlc3VsdC5zdGRlcnIpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGxldCB0c1Jlc3VsdDogYW55ID0ge2V4aXRDb2RlOiAwLCBzdGRvdXQ6ICcnLCBzdGRlcnI6ICcnfTtcbiAgICBpZih1c2VUeXBlc2NyaXB0KSB7XG4gICAgICB0c1Jlc3VsdCA9IGF3YWl0IGV4ZWNhKGVzbGludEJpbmFyeSwgW1xuICAgICAgICAnc3JjLyoqLyoue3RzLHRzeH0nLFxuICAgICAgICAuLi5jb25maWdBcmdzLFxuICAgICAgICAuLi5iYXNlRXNsaW50QXJnc1xuICAgICAgXSwge1xuICAgICAgICByZWplY3Q6IGZhbHNlLFxuICAgICAgICBzdGRpbzogJ3BpcGUnLFxuICAgICAgICBjd2QsXG4gICAgICAgIHNoZWxsOiB0cnVlXG4gICAgICB9KTtcblxuICAgICAgaWYodHNSZXN1bHQuc3Rkb3V0KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKHRzUmVzdWx0LnN0ZG91dCk7XG4gICAgICB9XG5cbiAgICAgIGlmKHRzUmVzdWx0LnN0ZGVycikge1xuICAgICAgICBjb25zb2xlLmVycm9yKHRzUmVzdWx0LnN0ZGVycik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQ2xlYW4gdXAgdGVtcCBmaWxlIGlmIGNyZWF0ZWRcbiAgICBpZih0ZW1wQ29uZmlnUGF0aCAmJiBleGlzdHNTeW5jKHRlbXBDb25maWdQYXRoKSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgdW5saW5rU3luYyh0ZW1wQ29uZmlnUGF0aCk7XG4gICAgICAgIGlmKGRlYnVnKSB7XG4gICAgICAgICAgbG9nKGBSZW1vdmVkIHRlbXBvcmFyeSBFU0xpbnQgY29uZmlnIGF0ICR7dGVtcENvbmZpZ1BhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAgICAgLy8gSWdub3JlIGVycm9ycyB3aGVuIGNsZWFuaW5nIHVwXG4gICAgICAgIGlmKGRlYnVnKSB7XG4gICAgICAgICAgbG9nKGBGYWlsZWQgdG8gcmVtb3ZlIHRlbXBvcmFyeSBFU0xpbnQgY29uZmlnOiAke2Vycm9yLm1lc3NhZ2V9YCwgJ3dhcm4nLCBxdWlldCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBlc2xpbnROb3RGb3VuZCA9IGpzUmVzdWx0LnN0ZGVycj8uaW5jbHVkZXMoJ2NvbW1hbmQgbm90IGZvdW5kJykgfHwganNSZXN1bHQuc3RkZXJyPy5pbmNsdWRlcygnZXNsaW50OiBjb21tYW5kIG5vdCBmb3VuZCcpO1xuICAgIGlmKGVzbGludE5vdEZvdW5kKSB7XG4gICAgICBzcGlubmVyLmZhaWwoJ0VTTGludCBub3QgZm91bmQhJyk7XG4gICAgICBsb2coYFxcbiR7Y2xpTmFtZX0gRXJyb3I6IExleCdzIEVTTGludCBiaW5hcnkgbm90IGZvdW5kLiBQbGVhc2UgcmVpbnN0YWxsIExleCBvciBjaGVjayB5b3VyIGluc3RhbGxhdGlvbi5gLCAnZXJyb3InLCBxdWlldCk7XG4gICAgICByZXR1cm4gMTtcbiAgICB9XG5cbiAgICBpZihqc1Jlc3VsdC5leGl0Q29kZSA9PT0gMCAmJiB0c1Jlc3VsdC5leGl0Q29kZSA9PT0gMCkge1xuICAgICAgc3Bpbm5lci5zdWNjZWVkKCdMaW50aW5nIGNvbXBsZXRlZCEnKTtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cblxuICAgIGNvbnN0IG5vRmlsZXNGb3VuZCA9XG4gICAgICAoanNSZXN1bHQuc3RkZXJyPy5pbmNsdWRlcygnTm8gc3VjaCBmaWxlIG9yIGRpcmVjdG9yeScpIHx8IGpzUmVzdWx0LnN0ZG91dD8uaW5jbHVkZXMoJ05vIHN1Y2ggZmlsZSBvciBkaXJlY3RvcnknKSkgJiZcbiAgICAgICghdXNlVHlwZXNjcmlwdCB8fCB0c1Jlc3VsdC5zdGRlcnI/LmluY2x1ZGVzKCdObyBzdWNoIGZpbGUgb3IgZGlyZWN0b3J5JykgfHwgdHNSZXN1bHQuc3Rkb3V0Py5pbmNsdWRlcygnTm8gc3VjaCBmaWxlIG9yIGRpcmVjdG9yeScpKTtcblxuICAgIGlmKG5vRmlsZXNGb3VuZCkge1xuICAgICAgc3Bpbm5lci5zdWNjZWVkKCdObyBmaWxlcyBmb3VuZCB0byBsaW50Jyk7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG4gICAgc3Bpbm5lci5mYWlsKCdMaW50aW5nIGZhaWxlZCEnKTtcbiAgICBsb2coYFxcbiR7Y2xpTmFtZX0gRXJyb3I6IEVTTGludCBmb3VuZCBpc3N1ZXMgaW4geW91ciBjb2RlLmAsICdlcnJvcicsIHF1aWV0KTtcbiAgICByZXR1cm4gMTtcbiAgfSBjYXRjaChlcnJvcikge1xuICAgIHNwaW5uZXIuZmFpbCgnTGludGluZyBmYWlsZWQhJyk7XG4gICAgbG9nKGBcXG4ke2NsaU5hbWV9IEVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCwgJ2Vycm9yJywgcXVpZXQpO1xuICAgIHJldHVybiAxO1xuICB9XG59O1xuXG5jb25zdCBhcHBseUFJRml4ID0gYXN5bmMgKFxuICBjd2Q6IHN0cmluZyxcbiAgZXJyb3JzOiBzdHJpbmcsXG4gIHF1aWV0OiBib29sZWFuXG4pOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgY29uc3Qgc3Bpbm5lciA9IGNyZWF0ZVNwaW5uZXIocXVpZXQpO1xuICBzcGlubmVyLnN0YXJ0KCdVc2luZyBBSSB0byBmaXggcmVtYWluaW5nIGxpbnQgaXNzdWVzLi4uJyk7XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBmaWxlRXJyb3JNYXAgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nW10+KCk7XG4gICAgY29uc3QgbGluZXMgPSBlcnJvcnMuc3BsaXQoJ1xcbicpO1xuICAgIGxldCBjdXJyZW50RmlsZSA9ICcnO1xuXG4gICAgZm9yKGNvbnN0IGxpbmUgb2YgbGluZXMpIHtcbiAgICAgIGlmKGxpbmUubWF0Y2goL14oXFwvfFtBLVpdOlxcXFwpLio/XFwuKGpzfGpzeHx0c3x0c3gpJC8pKSB7XG4gICAgICAgIGN1cnJlbnRGaWxlID0gbGluZS50cmltKCk7XG4gICAgICAgIGlmKCFmaWxlRXJyb3JNYXAuaGFzKGN1cnJlbnRGaWxlKSkge1xuICAgICAgICAgIGZpbGVFcnJvck1hcC5zZXQoY3VycmVudEZpbGUsIFtdKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmKGN1cnJlbnRGaWxlICYmIGxpbmUudHJpbSgpICYmIGxpbmUubWF0Y2goL1xccytcXGQrOlxcZCtcXHMrKGVycm9yfHdhcm5pbmcpXFxzKy8pKSB7XG4gICAgICAgIGNvbnN0IGVycm9yQXJyYXkgPSBmaWxlRXJyb3JNYXAuZ2V0KGN1cnJlbnRGaWxlKTtcbiAgICAgICAgaWYoZXJyb3JBcnJheSkge1xuICAgICAgICAgIGVycm9yQXJyYXkucHVzaChsaW5lLnRyaW0oKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZihmaWxlRXJyb3JNYXAuc2l6ZSA9PT0gMCkge1xuICAgICAgbG9nKCdVc2luZyBhbHRlcm5hdGl2ZSBlcnJvciBwYXJzaW5nIHN0cmF0ZWd5JywgJ2luZm8nLCBxdWlldCk7XG5cbiAgICAgIGNvbnN0IHNlY3Rpb25zID0gZXJyb3JzLnNwbGl0KCdcXG5cXG4nKTtcblxuICAgICAgZm9yKGNvbnN0IHNlY3Rpb24gb2Ygc2VjdGlvbnMpIHtcbiAgICAgICAgaWYoc2VjdGlvbi50cmltKCkgPT09ICcnKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBsaW5lcyA9IHNlY3Rpb24uc3BsaXQoJ1xcbicpO1xuICAgICAgICBjb25zdCBmaWxlUGF0aCA9IGxpbmVzWzBdLnRyaW0oKTtcblxuICAgICAgICBpZihmaWxlUGF0aC5tYXRjaCgvXFwuKGpzfGpzeHx0c3x0c3gpJC8pKSB7XG4gICAgICAgICAgZmlsZUVycm9yTWFwLnNldChmaWxlUGF0aCwgW10pO1xuXG4gICAgICAgICAgZm9yKGxldCBpID0gMTsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBpZihsaW5lc1tpXS50cmltKCkgIT09ICcnKSB7XG4gICAgICAgICAgICAgIGZpbGVFcnJvck1hcC5nZXQoZmlsZVBhdGgpPy5wdXNoKGxpbmVzW2ldLnRyaW0oKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYoZmlsZUVycm9yTWFwLnNpemUgPT09IDApIHtcbiAgICAgIGxvZygnVXNpbmcgZGlyZWN0IGZpbGUgcGF0aCBleHRyYWN0aW9uJywgJ2luZm8nLCBxdWlldCk7XG5cbiAgICAgIGNvbnN0IGZpbGVQYXRoUmVnZXggPSAvKD86XFwvfFtBLVpdOlxcXFwpKD86W146XFxuXStcXC8pKlteOlxcbl0rXFwuKGpzfGpzeHx0c3x0c3gpL2c7XG4gICAgICBjb25zdCBmaWxlUGF0aHMgPSBlcnJvcnMubWF0Y2goZmlsZVBhdGhSZWdleCkgfHwgW107XG5cbiAgICAgIGZvcihjb25zdCBmaWxlUGF0aCBvZiBmaWxlUGF0aHMpIHtcbiAgICAgICAgaWYoIWZpbGVFcnJvck1hcC5oYXMoZmlsZVBhdGgpICYmIGV4aXN0c1N5bmMoZmlsZVBhdGgpKSB7XG4gICAgICAgICAgZmlsZUVycm9yTWFwLnNldChmaWxlUGF0aCwgW10pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGtub3duRmlsZXMgPSBbXG4gICAgICAgIHBhdGhSZXNvbHZlKGN3ZCwgJ3NyYy9jcmVhdGUvY2hhbmdlbG9nLnRzJyksXG4gICAgICAgIHBhdGhSZXNvbHZlKGN3ZCwgJ3NyYy91dGlscy9haVNlcnZpY2UudHMnKSxcbiAgICAgICAgcGF0aFJlc29sdmUoY3dkLCAnc3JjL3V0aWxzL2FwcC50cycpLFxuICAgICAgICBwYXRoUmVzb2x2ZShjd2QsICdzcmMvdXRpbHMvcmVhY3RTaGltLnRzJyksXG4gICAgICAgIHBhdGhSZXNvbHZlKGN3ZCwgJ3NyYy9jb21tYW5kcy9saW50L2F1dG9maXguanMnKVxuICAgICAgXTtcblxuICAgICAgZm9yKGNvbnN0IGZpbGUgb2Yga25vd25GaWxlcykge1xuICAgICAgICBpZihleGlzdHNTeW5jKGZpbGUpICYmICFmaWxlRXJyb3JNYXAuaGFzKGZpbGUpKSB7XG4gICAgICAgICAgZmlsZUVycm9yTWFwLnNldChmaWxlLCBbXSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IoY29uc3QgZmlsZVBhdGggb2YgZmlsZUVycm9yTWFwLmtleXMoKSkge1xuICAgICAgaWYoIWV4aXN0c1N5bmMoZmlsZVBhdGgpKSB7XG4gICAgICAgIGxvZyhgRmlsZSBub3QgZm91bmQ6ICR7ZmlsZVBhdGh9YCwgJ3dhcm4nLCBxdWlldCk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBsb2coYFByb2Nlc3NpbmcgZmlsZTogJHtmaWxlUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcblxuICAgICAgY29uc3QgaXNDdXJzb3JJREUgPSBMZXhDb25maWcuY29uZmlnLmFpPy5wcm92aWRlciA9PT0gJ2N1cnNvcicgfHwgcHJvY2Vzcy5lbnYuQ1VSU09SX0lERSA9PT0gJ3RydWUnO1xuXG4gICAgICBpZihpc0N1cnNvcklERSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHByb21wdCA9IGBGaXggYWxsIEVTTGludCBlcnJvcnMgaW4gdGhpcyBmaWxlLiBGb2N1cyBvbjpcbjEuIEZpeGluZyBuYW1pbmcgY29udmVudGlvbnNcbjIuIEZpeGluZyBzb3J0LWtleXMgaXNzdWVzXG4zLiBSZXBsYWNpbmcgY29uc29sZS5sb2cgd2l0aCBsb2cgdXRpbGl0eVxuNC4gRml4aW5nIG5vLXBsdXNwbHVzIGlzc3Vlc1xuNS4gRml4aW5nIHVubmVjZXNzYXJ5IGVzY2FwZSBjaGFyYWN0ZXJzXG42LiBGaXhpbmcgb3RoZXIgRVNMaW50IGVycm9yc1xuXG5DUklUSUNBTCBSRVFVSVJFTUVOVFM6XG4tIE9OTFkgZml4IHRoZSBzcGVjaWZpYyBsaW5lcyB3aXRoIEVTTGludCBlcnJvcnNcbi0gRE8gTk9UIG1vZGlmeSBhbnkgb3RoZXIgbGluZXMgb2YgY29kZVxuLSBETyBOT1QgcmVtb3ZlIGxpbmUgYnJlYWtzIHVubGVzcyB0aGV5IGFyZSBzcGVjaWZpY2FsbHkgY2F1c2luZyBFU0xpbnQgZXJyb3JzXG4tIERPIE5PVCBjb25kZW5zZSBtdWx0aS1saW5lIHN0cnVjdHVyZXMgdG8gc2luZ2xlIGxpbmVzXG4tIFBSRVNFUlZFIGFsbCBleGlzdGluZyBsaW5lIGJyZWFrcyBhbmQgZm9ybWF0dGluZyB0aGF0IGlzIG5vdCBjYXVzaW5nIGVycm9yc1xuXG5TUEVDSUZJQyBGT1JNQVRUSU5HIFJVTEVTOlxuLSBNYWludGFpbiBwcm9wZXIgaW5kZW50YXRpb24gKDIgc3BhY2VzKVxuLSBLZWVwIGxpbmUgYnJlYWtzIGJldHdlZW4gY2xhc3MvaW50ZXJmYWNlIGRlY2xhcmF0aW9uIGFuZCB0aGVpciBtZW1iZXJzXG4tIEtlZXAgbGluZSBicmVha3MgYmV0d2VlbiBtZXRob2RzXG4tIEVuc3VyZSB0aGVyZSBpcyBhIGxpbmUgYnJlYWsgYWZ0ZXIgb3BlbmluZyBicmFjZXMgZm9yIGNsYXNzZXMsIGludGVyZmFjZXMsIGFuZCBtZXRob2RzXG4tIERPIE5PVCBwbGFjZSBjbGFzcy9pbnRlcmZhY2UgcHJvcGVydGllcyBvciBtZXRob2RzIG9uIHRoZSBzYW1lIGxpbmUgYXMgdGhlIG9wZW5pbmcgYnJhY2Vcbi0gUHJlc2VydmUgZW1wdHkgbGluZXMgYmV0d2VlbiBsb2dpY2FsIGNvZGUgYmxvY2tzXG4tIFBSRVNFUlZFIG11bHRpLWxpbmUgaW1wb3J0cyAtIGRvIG5vdCBjb25kZW5zZSB0aGVtIHRvIHNpbmdsZSBsaW5lc1xuLSBQUkVTRVJWRSBtdWx0aS1saW5lIG9iamVjdC9hcnJheSBkZWNsYXJhdGlvbnMgLSBkbyBub3QgY29uZGVuc2UgdGhlbSB0byBzaW5nbGUgbGluZXNcblxuU09SVC1LRVlTIFJVTEUgKEhJR0hFU1QgUFJJT1JJVFkpOlxuLSBBbGwgb2JqZWN0IGxpdGVyYWwga2V5cyBNVVNUIGJlIHNvcnRlZCBhbHBoYWJldGljYWxseSBpbiBhc2NlbmRpbmcgb3JkZXJcbi0gVGhpcyBhcHBsaWVzIHRvIEFMTCBvYmplY3RzIGluIHRoZSBmaWxlLCBub3QganVzdCB0aG9zZSB3aXRoIGV4cGxpY2l0IHNvcnQta2V5cyBlcnJvcnNcbi0gRXhhbXBsZToge2I6IDIsIGE6IDEsIGM6IDN9IHNob3VsZCBiZWNvbWUge2E6IDEsIGI6IDIsIGM6IDN9XG4tIFByZXNlcnZlIHRoZSBvcmlnaW5hbCBmb3JtYXR0aW5nIGFuZCBsaW5lIGJyZWFrcyB3aGVuIHNvcnRpbmdcblxuRXhhbXBsZSBvZiBDT1JSRUNUIGZvcm1hdHRpbmcgKERPIE5PVCBDSEFOR0UpOlxuZXhwb3J0IGNsYXNzIFVzZXJDb25zdGFudHMge1xuICBzdGF0aWMgcmVhZG9ubHkgQUREX0lURU1fRVJST1I6IHN0cmluZyA9ICdVU0VSX0FERF9JVEVNX0VSUk9SJztcbiAgc3RhdGljIHJlYWRvbmx5IE9USEVSX0NPTlNUQU5UOiBzdHJpbmcgPSAnT1RIRVJfQ09OU1RBTlQnO1xufVxuXG5jb25zdHJ1Y3RvcihmbHV4OiBGbHV4RnJhbWV3b3JrLCBDdXN0b21BZGFwdGVyOiB0eXBlb2YgRXZlbnQgPSBFdmVudCkge1xuICB0aGlzLkN1c3RvbUFkYXB0ZXIgPSBDdXN0b21BZGFwdGVyO1xuICB0aGlzLmZsdXggPSBmbHV4O1xufVxuXG5pbXBvcnQge1xuICBhcHAsXG4gIGV2ZW50cyxcbiAgaW1hZ2VzLFxuICBsb2NhdGlvbnMsXG4gIG1lc3NhZ2VzLFxuICBwb3N0cyxcbiAgdGFncyxcbiAgdXNlcnMsXG4gIHdlYnNvY2tldFxufSBmcm9tICcuL3N0b3Jlcyc7XG5cbmNvbnN0IGNvbmZpZyA9IHtcbiAgYXBpS2V5OiAndmFsdWUnLFxuICBiYXNlVXJsOiAnaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20nLFxuICB0aW1lb3V0OiA1MDAwXG59O1xuXG5FeGFtcGxlIG9mIElOQ09SUkVDVCBmb3JtYXR0aW5nIChGSVggVEhJUyk6XG5leHBvcnQgY2xhc3MgVXNlckNvbnN0YW50cyB7c3RhdGljIHJlYWRvbmx5IEFERF9JVEVNX0VSUk9SOiBzdHJpbmcgPSAnVVNFUl9BRERfSVRFTV9FUlJPUic7XG4gIHN0YXRpYyByZWFkb25seSBPVEhFUl9DT05TVEFOVDogc3RyaW5nID0gJ09USEVSX0NPTlNUQU5UJztcbn1cblxuY29uc3RydWN0b3IoZmx1eDogRmx1eEZyYW1ld29yaywgQ3VzdG9tQWRhcHRlcjogdHlwZW9mIEV2ZW50ID0gRXZlbnQpIHt0aGlzLkN1c3RvbUFkYXB0ZXIgPSBDdXN0b21BZGFwdGVyO1xuICB0aGlzLmZsdXggPSBmbHV4O31cblxuaW1wb3J0IHthcHAsIGV2ZW50cywgaW1hZ2VzLCBsb2NhdGlvbnMsIG1lc3NhZ2VzLCBwb3N0cywgdGFncywgdXNlcnMsIHdlYnNvY2tldH0gZnJvbSAnLi9zdG9yZXMnO1xuXG5jb25zdCBjb25maWcgPSB7YmFzZVVybDogJ2h0dHBzOi8vYXBpLmV4YW1wbGUuY29tJywgYXBpS2V5OiAndmFsdWUnLCB0aW1lb3V0OiA1MDAwfTtcblxuRml4IE9OTFkgdGhlIHNwZWNpZmljIEVTTGludCBlcnJvcnMuIFJldHVybiB0aGUgcHJvcGVybHkgZm9ybWF0dGVkIGNvZGUuYDtcblxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBwcm9tcHRGaWxlID0gcGF0aFJlc29sdmUoY3dkLCAnLmN1cnNvcl9wcm9tcHRfdGVtcC50eHQnKTtcbiAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMocHJvbXB0RmlsZSwgcHJvbXB0LCAndXRmOCcpO1xuXG4gICAgICAgICAgICAvLyBVc2UgQ3Vyc29yIENMSSB0byBmaXggdGhlIGZpbGVcbiAgICAgICAgICAgIGF3YWl0IGV4ZWNhKCdjdXJzb3InLCBbJ2VkaXQnLCAnLS1maWxlJywgZmlsZVBhdGgsICctLXByb21wdC1maWxlJywgcHJvbXB0RmlsZV0sIHtcbiAgICAgICAgICAgICAgcmVqZWN0OiBmYWxzZSxcbiAgICAgICAgICAgICAgc3RkaW86ICdwaXBlJyxcbiAgICAgICAgICAgICAgY3dkXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgdW5saW5rU3luYyhwcm9tcHRGaWxlKTtcbiAgICAgICAgICAgIH0gY2F0Y2goX2Vycm9yKSB7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxvZyhgQXBwbGllZCBDdXJzb3IgQUkgZml4ZXMgdG8gJHtmaWxlUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgICAgICB9IGNhdGNoKGVycm9yKSB7XG4gICAgICAgICAgICBjb25zdCB3YXNNb2RpZmllZCA9IGF3YWl0IGFwcGx5RGlyZWN0Rml4ZXMoZmlsZVBhdGgsIHF1aWV0KTtcbiAgICAgICAgICAgIGlmKHdhc01vZGlmaWVkKSB7XG4gICAgICAgICAgICAgIGxvZyhgQXBwbGllZCBkaXJlY3QgZml4ZXMgdG8gJHtmaWxlUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAgICAgICBsb2coYEVycm9yIHVzaW5nIEN1cnNvciBBSTogJHtlcnJvci5tZXNzYWdlfWAsICdlcnJvcicsIHF1aWV0KTtcbiAgICAgICAgICBhd2FpdCBhcHBseURpcmVjdEZpeGVzKGZpbGVQYXRoLCBxdWlldCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHdhc01vZGlmaWVkID0gYXdhaXQgYXBwbHlEaXJlY3RGaXhlcyhmaWxlUGF0aCwgcXVpZXQpO1xuICAgICAgICBpZih3YXNNb2RpZmllZCkge1xuICAgICAgICAgIGxvZyhgQXBwbGllZCBkaXJlY3QgZml4ZXMgdG8gJHtmaWxlUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGZpbGVFcnJvcnMgPSBmaWxlRXJyb3JNYXAuZ2V0KGZpbGVQYXRoKSB8fCBbXTtcbiAgICAgICAgaWYoZmlsZUVycm9ycy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHtjYWxsQUlTZXJ2aWNlfSA9IGF3YWl0IGltcG9ydCgnLi4vLi4vdXRpbHMvYWlTZXJ2aWNlLmpzJyk7XG5cbiAgICAgICAgICAgIGNvbnN0IGZpbGVDb250ZW50ID0gcmVhZEZpbGVTeW5jKGZpbGVQYXRoLCAndXRmOCcpO1xuXG4gICAgICAgICAgICBjb25zdCBwcm9tcHQgPSBgRml4IHRoZSBmb2xsb3dpbmcgRVNMaW50IGVycm9ycyBpbiB0aGlzIGNvZGU6XG4ke2ZpbGVFcnJvcnMuam9pbignXFxuJyl9XG5cbkhlcmUncyB0aGUgY29kZTpcblxcYFxcYFxcYFxuJHtmaWxlQ29udGVudH1cblxcYFxcYFxcYFxuXG5DUklUSUNBTCBSRVFVSVJFTUVOVFM6XG4tIE9OTFkgZml4IHRoZSBzcGVjaWZpYyBsaW5lcyB3aXRoIEVTTGludCBlcnJvcnNcbi0gRE8gTk9UIG1vZGlmeSBhbnkgb3RoZXIgbGluZXMgb2YgY29kZVxuLSBETyBOT1QgcmVtb3ZlIGxpbmUgYnJlYWtzIHVubGVzcyB0aGV5IGFyZSBzcGVjaWZpY2FsbHkgY2F1c2luZyBFU0xpbnQgZXJyb3JzXG4tIERPIE5PVCBjb25kZW5zZSBtdWx0aS1saW5lIHN0cnVjdHVyZXMgdG8gc2luZ2xlIGxpbmVzXG4tIFBSRVNFUlZFIGFsbCBleGlzdGluZyBsaW5lIGJyZWFrcyBhbmQgZm9ybWF0dGluZyB0aGF0IGlzIG5vdCBjYXVzaW5nIGVycm9yc1xuXG5TUEVDSUZJQyBGT1JNQVRUSU5HIFJVTEVTOlxuLSBNYWludGFpbiBwcm9wZXIgaW5kZW50YXRpb24gKDIgc3BhY2VzKVxuLSBLZWVwIGxpbmUgYnJlYWtzIGJldHdlZW4gY2xhc3MvaW50ZXJmYWNlIGRlY2xhcmF0aW9uIGFuZCB0aGVpciBtZW1iZXJzXG4tIEtlZXAgbGluZSBicmVha3MgYmV0d2VlbiBtZXRob2RzXG4tIEVuc3VyZSB0aGVyZSBpcyBhIGxpbmUgYnJlYWsgYWZ0ZXIgb3BlbmluZyBicmFjZXMgZm9yIGNsYXNzZXMsIGludGVyZmFjZXMsIGFuZCBtZXRob2RzXG4tIERPIE5PVCBwbGFjZSBjbGFzcy9pbnRlcmZhY2UgcHJvcGVydGllcyBvciBtZXRob2RzIG9uIHRoZSBzYW1lIGxpbmUgYXMgdGhlIG9wZW5pbmcgYnJhY2Vcbi0gUHJlc2VydmUgZW1wdHkgbGluZXMgYmV0d2VlbiBsb2dpY2FsIGNvZGUgYmxvY2tzXG4tIFBSRVNFUlZFIG11bHRpLWxpbmUgaW1wb3J0cyAtIGRvIG5vdCBjb25kZW5zZSB0aGVtIHRvIHNpbmdsZSBsaW5lc1xuLSBQUkVTRVJWRSBtdWx0aS1saW5lIG9iamVjdC9hcnJheSBkZWNsYXJhdGlvbnMgLSBkbyBub3QgY29uZGVuc2UgdGhlbSB0byBzaW5nbGUgbGluZXNcblxuU09SVC1LRVlTIFJVTEUgKEhJR0hFU1QgUFJJT1JJVFkpOlxuLSBBbGwgb2JqZWN0IGxpdGVyYWwga2V5cyBNVVNUIGJlIHNvcnRlZCBhbHBoYWJldGljYWxseSBpbiBhc2NlbmRpbmcgb3JkZXJcbi0gVGhpcyBhcHBsaWVzIHRvIEFMTCBvYmplY3RzIGluIHRoZSBmaWxlLCBub3QganVzdCB0aG9zZSB3aXRoIGV4cGxpY2l0IHNvcnQta2V5cyBlcnJvcnNcbi0gRXhhbXBsZToge2I6IDIsIGE6IDEsIGM6IDN9IHNob3VsZCBiZWNvbWUge2E6IDEsIGI6IDIsIGM6IDN9XG4tIFByZXNlcnZlIHRoZSBvcmlnaW5hbCBmb3JtYXR0aW5nIGFuZCBsaW5lIGJyZWFrcyB3aGVuIHNvcnRpbmdcblxuV0hBVCBUTyBGSVg6XG4xLiBTb3J0aW5nIGFsbCBvYmplY3Qga2V5cyBhbHBoYWJldGljYWxseSAoc29ydC1rZXlzIHJ1bGUpIC0gQUxMIG9iamVjdHMgbXVzdCBoYXZlIHNvcnRlZCBrZXlzXG4yLiBGaXhpbmcgbmFtaW5nIGNvbnZlbnRpb25zIC0gT05MWSBmb3IgdmFyaWFibGVzL2Z1bmN0aW9ucyB3aXRoIG5hbWluZyBlcnJvcnNcbjMuIFJlcGxhY2luZyBjb25zb2xlLmxvZyB3aXRoIGxvZyB1dGlsaXR5IC0gT05MWSBmb3IgY29uc29sZS5sb2cgc3RhdGVtZW50c1xuNC4gRml4aW5nIG5vLXBsdXNwbHVzIGlzc3VlcyAtIE9OTFkgZm9yICsrLy0tIG9wZXJhdG9yc1xuNS4gRml4aW5nIHVubmVjZXNzYXJ5IGVzY2FwZSBjaGFyYWN0ZXJzIC0gT05MWSBmb3IgZXNjYXBlZCBjaGFyYWN0ZXJzIHRoYXQgZG9uJ3QgbmVlZCBlc2NhcGluZ1xuNi4gUHJvcGVyIGluZGVudGF0aW9uIGFuZCBzcGFjaW5nIC0gT05MWSB3aGVyZSBzcGVjaWZpY2FsbHkgcmVxdWlyZWQgYnkgZXJyb3JzXG43LiBTdHJpbmcgcXVvdGVzIGNvbnNpc3RlbmN5ICh1c2Ugc2luZ2xlIHF1b3RlcykgLSBPTkxZIGZvciBzdHJpbmcgbGl0ZXJhbHMgd2l0aCBxdW90ZSBlcnJvcnNcbjguIEltcG9ydCBvcmRlciBhbmQgc3BhY2luZyAtIE9OTFkgZm9yIGltcG9ydHMgd2l0aCBvcmRlci9zcGFjaW5nIGVycm9yc1xuOS4gRnVuY3Rpb24gcGFyYW1ldGVyIGZvcm1hdHRpbmcgLSBPTkxZIGZvciBmdW5jdGlvbnMgd2l0aCBwYXJhbWV0ZXIgZXJyb3JzXG4xMC4gVmFyaWFibGUgbmFtaW5nIGNvbnZlbnRpb25zIC0gT05MWSBmb3IgdmFyaWFibGVzIHdpdGggbmFtaW5nIGVycm9yc1xuMTEuIE5vIHVudXNlZCB2YXJpYWJsZXMgb3IgaW1wb3J0cyAtIE9OTFkgZm9yIHVudXNlZCB2YXJpYWJsZXMvaW1wb3J0c1xuMTIuIEF2b2lkaW5nIG5lc3RlZCB0ZXJuYXJpZXMgLSBPTkxZIGZvciBuZXN0ZWQgdGVybmFyeSBleHByZXNzaW9uc1xuMTMuIEFueSBvdGhlciBFU0xpbnQgZXJyb3JzIC0gT05MWSBmb3IgdGhlIHNwZWNpZmljIGVycm9ycyBsaXN0ZWQgYWJvdmVcblxuV0hBVCBOT1QgVE8gRklYOlxuLSBEbyBub3QgY2hhbmdlIHByb3Blcmx5IGZvcm1hdHRlZCBtdWx0aS1saW5lIHN0cnVjdHVyZXNcbi0gRG8gbm90IHJlbW92ZSBsaW5lIGJyZWFrcyB0aGF0IGFyZSBub3QgY2F1c2luZyBlcnJvcnNcbi0gRG8gbm90IGNoYW5nZSBpbmRlbnRhdGlvbiB0aGF0IGlzIGFscmVhZHkgY29ycmVjdFxuLSBEbyBub3QgbW9kaWZ5IHNwYWNpbmcgdGhhdCBpcyBhbHJlYWR5IGNvcnJlY3Rcbi0gRG8gbm90IGNvbmRlbnNlIHJlYWRhYmxlIG11bHRpLWxpbmUgY29kZSB0byBzaW5nbGUgbGluZXNcbi0gRG8gbm90IG1vZGlmeSBjb2RlIHRoYXQgaXMgbm90IG1lbnRpb25lZCBpbiB0aGUgRVNMaW50IGVycm9yc1xuXG5FeGFtcGxlIG9mIENPUlJFQ1QgZm9ybWF0dGluZyAoRE8gTk9UIENIQU5HRSk6XG5leHBvcnQgY2xhc3MgVXNlckNvbnN0YW50cyB7XG4gIHN0YXRpYyByZWFkb25seSBBRERfSVRFTV9FUlJPUjogc3RyaW5nID0gJ1VTRVJfQUREX0lURU1fRVJST1InO1xuICBzdGF0aWMgcmVhZG9ubHkgT1RIRVJfQ09OU1RBTlQ6IHN0cmluZyA9ICdPVEhFUl9DT05TVEFOVCc7XG59XG5cbmNvbnN0cnVjdG9yKGZsdXg6IEZsdXhGcmFtZXdvcmssIEN1c3RvbUFkYXB0ZXI6IHR5cGVvZiBFdmVudCA9IEV2ZW50KSB7XG4gIHRoaXMuQ3VzdG9tQWRhcHRlciA9IEN1c3RvbUFkYXB0ZXI7XG4gIHRoaXMuZmx1eCA9IGZsdXg7XG59XG5cbmltcG9ydCB7XG4gIGFwcCxcbiAgZXZlbnRzLFxuICBpbWFnZXMsXG4gIGxvY2F0aW9ucyxcbiAgbWVzc2FnZXMsXG4gIHBvc3RzLFxuICB0YWdzLFxuICB1c2VycyxcbiAgd2Vic29ja2V0XG59IGZyb20gJy4vc3RvcmVzJztcblxuY29uc3QgY29uZmlnID0ge1xuICBhcGlLZXk6ICd2YWx1ZScsXG4gIGJhc2VVcmw6ICdodHRwczovL2FwaS5leGFtcGxlLmNvbScsXG4gIHRpbWVvdXQ6IDUwMDBcbn07XG5cbkV4YW1wbGUgb2YgSU5DT1JSRUNUIGZvcm1hdHRpbmcgKEZJWCBUSElTKTpcbmV4cG9ydCBjbGFzcyBVc2VyQ29uc3RhbnRzIHtzdGF0aWMgcmVhZG9ubHkgQUREX0lURU1fRVJST1I6IHN0cmluZyA9ICdVU0VSX0FERF9JVEVNX0VSUk9SJztcbiAgc3RhdGljIHJlYWRvbmx5IE9USEVSX0NPTlNUQU5UOiBzdHJpbmcgPSAnT1RIRVJfQ09OU1RBTlQnO1xufVxuXG5jb25zdHJ1Y3RvcihmbHV4OiBGbHV4RnJhbWV3b3JrLCBDdXN0b21BZGFwdGVyOiB0eXBlb2YgRXZlbnQgPSBFdmVudCkge3RoaXMuQ3VzdG9tQWRhcHRlciA9IEN1c3RvbUFkYXB0ZXI7XG4gIHRoaXMuZmx1eCA9IGZsdXg7fVxuXG5pbXBvcnQge2FwcCwgZXZlbnRzLCBpbWFnZXMsIGxvY2F0aW9ucywgbWVzc2FnZXMsIHBvc3RzLCB0YWdzLCB1c2Vycywgd2Vic29ja2V0fSBmcm9tICcuL3N0b3Jlcyc7XG5cbmNvbnN0IGNvbmZpZyA9IHtiYXNlVXJsOiAnaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20nLCBhcGlLZXk6ICd2YWx1ZScsIHRpbWVvdXQ6IDUwMDB9O1xuXG5GaXggT05MWSB0aGUgc3BlY2lmaWMgRVNMaW50IGVycm9ycyBsaXN0ZWQgYWJvdmUuIFJldmlldyB0aGUgZW50aXJlIGZpbGUgZm9yIGNvbXBsaWFuY2Ugd2l0aCBhbGwgRVNMaW50IHJ1bGVzLlxuUmV0dXJuIG9ubHkgdGhlIHByb3Blcmx5IGZvcm1hdHRlZCBmaXhlZCBjb2RlIHdpdGhvdXQgYW55IGV4cGxhbmF0aW9ucy5gO1xuXG4gICAgICAgICAgICBjb25zdCBmaXhlZENvbnRlbnQgPSBhd2FpdCBjYWxsQUlTZXJ2aWNlKHByb21wdCwgcXVpZXQpO1xuXG4gICAgICAgICAgICBpZihmaXhlZENvbnRlbnQgJiYgZml4ZWRDb250ZW50ICE9PSBmaWxlQ29udGVudCkge1xuICAgICAgICAgICAgICB3cml0ZUZpbGVTeW5jKGZpbGVQYXRoLCBmaXhlZENvbnRlbnQsICd1dGY4Jyk7XG4gICAgICAgICAgICAgIGxvZyhgQXBwbGllZCBBSSBmaXhlcyB0byAke2ZpbGVQYXRofWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAgICAgICAgIGxvZyhgRXJyb3IgYXBwbHlpbmcgQUkgZml4ZXMgdG8gJHtmaWxlUGF0aH06ICR7ZXJyb3IubWVzc2FnZX1gLCAnZXJyb3InLCBxdWlldCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgc3Bpbm5lci5zdWNjZWVkKCdBSSBmaXhlcyBhcHBsaWVkIHN1Y2Nlc3NmdWxseSEnKTtcbiAgfSBjYXRjaChlcnJvcikge1xuICAgIHNwaW5uZXIuZmFpbCgnRmFpbGVkIHRvIGFwcGx5IEFJIGZpeGVzJyk7XG4gICAgbG9nKGBFcnJvcjogJHtlcnJvci5tZXNzYWdlfWAsICdlcnJvcicsIHF1aWV0KTtcbiAgICBpZighcXVpZXQpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgIH1cbiAgfVxufTtcblxuY29uc3QgYXBwbHlEaXJlY3RGaXhlcyA9IGFzeW5jIChmaWxlUGF0aDogc3RyaW5nLCBxdWlldDogYm9vbGVhbik6IFByb21pc2U8Ym9vbGVhbj4gPT4ge1xuICBsZXQgd2FzTW9kaWZpZWQgPSBmYWxzZTtcblxuICB0cnkge1xuICAgIGNvbnN0IGZpbGVDb250ZW50ID0gcmVhZEZpbGVTeW5jKGZpbGVQYXRoLCAndXRmOCcpO1xuICAgIGxldCBuZXdDb250ZW50ID0gZmlsZUNvbnRlbnQ7XG5cbiAgICBpZihmaWxlUGF0aC5pbmNsdWRlcygnYWlTZXJ2aWNlLnRzJykpIHtcbiAgICAgIGxvZygnRml4aW5nIGlzc3VlcyBpbiBhaVNlcnZpY2UudHMnLCAnaW5mbycsIHF1aWV0KTtcblxuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgLydDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb25cXC9qc29uJyxcXHMqJ0F1dGhvcml6YXRpb24nOiBgQmVhcmVyL2csXG4gICAgICAgICdcXCdBdXRob3JpemF0aW9uXFwnOiBgQmVhcmVyXFwnLCBcXCdDb250ZW50LVR5cGVcXCc6IFxcJ2FwcGxpY2F0aW9uL2pzb25cXCcnXG4gICAgICApO1xuXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvaGVhZGVyczogeyhbXn1dKil9LFxccyptZXRob2Q6ICdQT1NUJy9nLFxuICAgICAgICAnbWV0aG9kOiBcXCdQT1NUXFwnLFxcbiAgICAgIGhlYWRlcnM6IHskMX0nXG4gICAgICApO1xuXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAve3JvbGU6ICdzeXN0ZW0nLCBjb250ZW50Oi9nLFxuICAgICAgICAne2NvbnRlbnQ6LCByb2xlOiBcXCdzeXN0ZW1cXCcsJ1xuICAgICAgKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC97cm9sZTogJ3VzZXInLCBjb250ZW50Oi9nLFxuICAgICAgICAne2NvbnRlbnQ6LCByb2xlOiBcXCd1c2VyXFwnLCdcbiAgICAgICk7XG5cbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9cXCgoW14pXSo/KV8oW2EtekEtWjAtOV0rKShcXHMqOlteKV0qKVxcKS9nLFxuICAgICAgICAnKCQxJDIkMyknXG4gICAgICApO1xuXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKC9jb25zb2xlXFwubG9nXFwoL2csICdsb2coJyk7XG5cbiAgICAgIGlmKCFuZXdDb250ZW50LmluY2x1ZGVzKCdpbXBvcnQge2xvZ30nKSAmJiBuZXdDb250ZW50LmluY2x1ZGVzKCdsb2coJykpIHtcbiAgICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgICAvaW1wb3J0IHsoW159XSopfSBmcm9tICcoLiopJzsvLFxuICAgICAgICAgICdpbXBvcnQgeyQxfSBmcm9tIFxcJyQyXFwnO1xcbmltcG9ydCB7bG9nfSBmcm9tIFxcJy4vbG9nLmpzXFwnOydcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZihmaWxlUGF0aC5pbmNsdWRlcygncmVhY3RTaGltLnRzJykpIHtcbiAgICAgIGxvZygnRml4aW5nIG5hbWluZy1jb252ZW50aW9uIGlzc3VlcyBpbiByZWFjdFNoaW0udHMnLCAnaW5mbycsIHF1aWV0KTtcblxuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgJ2ltcG9ydCAqIGFzIFJlYWN0IGZyb20nLFxuICAgICAgICAnaW1wb3J0ICogYXMgcmVhY3QgZnJvbSdcbiAgICAgICk7XG5cbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoL1JlYWN0XFwuL2csICdyZWFjdC4nKTtcbiAgICB9XG5cbiAgICBpZihmaWxlUGF0aC5pbmNsdWRlcygnY2hhbmdlbG9nLnRzJykpIHtcbiAgICAgIGxvZygnRml4aW5nIGlzc3VlcyBpbiBjaGFuZ2Vsb2cudHMnLCAnaW5mbycsIHF1aWV0KTtcblxuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZSgvKFxcdyspXFwrXFwrL2csICckMSArPSAxJyk7XG5cbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoL1xcXFxcXCQvZywgJyQnKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoL1xcXFxcXC4vZywgJy4nKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoL1xcXFxcXCovZywgJyonKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoL1xcXFw6L2csICc6Jyk7XG4gICAgfVxuXG4gICAgaWYoZmlsZVBhdGguaW5jbHVkZXMoJ2FwcC50cycpKSB7XG4gICAgICBsb2coJ0ZpeGluZyBpc3N1ZXMgaW4gYXBwLnRzJywgJ2luZm8nLCBxdWlldCk7XG5cbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoL2NvbnNvbGVcXC5sb2dcXCgvZywgJ2xvZygnKTtcblxuICAgICAgaWYoIW5ld0NvbnRlbnQuaW5jbHVkZXMoJ2ltcG9ydCB7bG9nfScpICYmIG5ld0NvbnRlbnQuaW5jbHVkZXMoJ2xvZygnKSkge1xuICAgICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAgIC9pbXBvcnQgYm94ZW4gZnJvbSAnYm94ZW4nOy8sXG4gICAgICAgICAgJ2ltcG9ydCBib3hlbiBmcm9tIFxcJ2JveGVuXFwnO1xcbmltcG9ydCB7bG9nfSBmcm9tIFxcJy4vbG9nLmpzXFwnOydcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZSgvXFxcXFxcLy9nLCAnLycpO1xuICAgIH1cblxuICAgIGlmKGZpbGVQYXRoLmluY2x1ZGVzKCdhdXRvZml4LmpzJykpIHtcbiAgICAgIGxvZygnRml4aW5nIGlzc3VlcyBpbiBhdXRvZml4LmpzJywgJ2luZm8nLCBxdWlldCk7XG5cbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9pbXBvcnQgeyhbXn1dKil9IGZyb20gJ3BhdGgnO1tcXHNcXG5dKmltcG9ydCB7KFtefV0qKX0gZnJvbSAncGF0aCc7LyxcbiAgICAgICAgJ2ltcG9ydCB7JDEsICQyfSBmcm9tIFxcJ3BhdGhcXCc7J1xuICAgICAgKTtcblxuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgL19fZmlsZW5hbWUvZyxcbiAgICAgICAgJ2N1cnJlbnRGaWxlbmFtZSdcbiAgICAgICk7XG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvX19kaXJuYW1lL2csXG4gICAgICAgICdjdXJyZW50RGlybmFtZSdcbiAgICAgICk7XG5cbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9jb25zdCBwcmVmaXggPSB0eXBlID09PSAnZXJyb3InIFxcPyAnXHUyNzRDICcgOiB0eXBlID09PSAnc3VjY2VzcycgXFw/ICdcdTI3MDUgJyA6ICdcdTIxMzlcdUZFMEYgJzsvLFxuICAgICAgICAnbGV0IHByZWZpeCA9IFxcJ1x1MjEzOVx1RkUwRiBcXCc7XFxuaWYodHlwZSA9PT0gXFwnZXJyb3JcXCcpIHtcXG4gIHByZWZpeCA9IFxcJ1x1Mjc0QyBcXCc7XFxufSBlbHNlIGlmKHR5cGUgPT09IFxcJ3N1Y2Nlc3NcXCcpIHtcXG4gIHByZWZpeCA9IFxcJ1x1MjcwNSBcXCc7XFxufSdcbiAgICAgICk7XG5cbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9hc3luYyBmdW5jdGlvbiBydW5Fc2xpbnRGaXhcXChcXCkvZyxcbiAgICAgICAgJ2NvbnN0IHJ1bkVzbGludEZpeCA9IGFzeW5jICgpJ1xuICAgICAgKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9hc3luYyBmdW5jdGlvbiBnZXRGaWxlc1dpdGhFcnJvcnNcXChcXCkvZyxcbiAgICAgICAgJ2NvbnN0IGdldEZpbGVzV2l0aEVycm9ycyA9IGFzeW5jICgpJ1xuICAgICAgKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9hc3luYyBmdW5jdGlvbiBpc0N1cnNvckF2YWlsYWJsZVxcKFxcKS9nLFxuICAgICAgICAnY29uc3QgaXNDdXJzb3JBdmFpbGFibGUgPSBhc3luYyAoKSdcbiAgICAgICk7XG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvYXN5bmMgZnVuY3Rpb24gZml4RmlsZVdpdGhDdXJzb3JBSVxcKGZpbGVQYXRoXFwpL2csXG4gICAgICAgICdjb25zdCBmaXhGaWxlV2l0aEN1cnNvckFJID0gYXN5bmMgKGZpbGVQYXRoKSdcbiAgICAgICk7XG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvYXN5bmMgZnVuY3Rpb24gbWFpblxcKFxcKS9nLFxuICAgICAgICAnY29uc3QgbWFpbiA9IGFzeW5jICgpJ1xuICAgICAgKTtcblxuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgL2ltcG9ydCB7ZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jfS9nLFxuICAgICAgICAnaW1wb3J0IHt3cml0ZUZpbGVTeW5jfSdcbiAgICAgICk7XG5cbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9jb25zb2xlXFwubG9nXFwoYFxcJHtwcmVmaXh9IFxcJHttZXNzYWdlfWBcXCk7L2csXG4gICAgICAgICdwcm9jZXNzLnN0ZG91dC53cml0ZShgJHtwcmVmaXh9ICR7bWVzc2FnZX1cXFxcbmApOydcbiAgICAgICk7XG5cbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC99IGNhdGNoXFwoZXJyb3JcXCkge1tcXHNcXG5dKlxcL1xcLyBJZ25vcmUgY2xlYW51cCBlcnJvcnMvZyxcbiAgICAgICAgJ30gY2F0Y2goXykge1xcbiAgICAgIC8vIElnbm9yZSBjbGVhbnVwIGVycm9ycydcbiAgICAgICk7XG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvfSBjYXRjaFxcKGVycm9yXFwpIHtbXFxzXFxuXSpsb2dcXCgvZyxcbiAgICAgICAgJ30gY2F0Y2goZXJyKSB7XFxuICAgIGxvZygnXG4gICAgICApO1xuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgL30gY2F0Y2hcXChlcnJvclxcKSB7W1xcc1xcbl0qcmV0dXJuIGZhbHNlOy9nLFxuICAgICAgICAnfSBjYXRjaChfKSB7XFxuICAgIHJldHVybiBmYWxzZTsnXG4gICAgICApO1xuXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvZm9yXFwoY29uc3QgZmlsZVBhdGggb2YgZmlsZXNXaXRoRXJyb3JzXFwpIHtbXFxzXFxuXSpjb25zdCBzdWNjZXNzID0gYXdhaXQgZml4RmlsZVdpdGhDdXJzb3JBSVxcKGZpbGVQYXRoXFwpOy9nLFxuICAgICAgICAnY29uc3QgZml4UmVzdWx0cyA9IGF3YWl0IFByb21pc2UuYWxsKGZpbGVzV2l0aEVycm9ycy5tYXAoZmlsZVBhdGggPT4gZml4RmlsZVdpdGhDdXJzb3JBSShmaWxlUGF0aCkpKTtcXG5mb3IoY29uc3Qgc3VjY2VzcyBvZiBmaXhSZXN1bHRzKSB7J1xuICAgICAgKTtcblxuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgL2ZpeGVkQ291bnRcXCtcXCs7L2csXG4gICAgICAgICdmaXhlZENvdW50ICs9IDE7J1xuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZihuZXdDb250ZW50ICE9PSBmaWxlQ29udGVudCkge1xuICAgICAgd3JpdGVGaWxlU3luYyhmaWxlUGF0aCwgbmV3Q29udGVudCwgJ3V0ZjgnKTtcbiAgICAgIGxvZyhgRml4ZWQgaXNzdWVzIGluICR7ZmlsZVBhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICB3YXNNb2RpZmllZCA9IHRydWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIHdhc01vZGlmaWVkO1xuICB9IGNhdGNoKGVycm9yKSB7XG4gICAgbG9nKGBFcnJvciBhcHBseWluZyBkaXJlY3QgZml4ZXMgdG8gJHtmaWxlUGF0aH06ICR7ZXJyb3IubWVzc2FnZX1gLCAnZXJyb3InLCBxdWlldCk7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59O1xuXG5jb25zdCBsb2FkQUlDb25maWcgPSBhc3luYyAoY3dkOiBzdHJpbmcsIHF1aWV0OiBib29sZWFuLCBkZWJ1ZzogYm9vbGVhbiA9IGZhbHNlKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gIGNvbnN0IGNvbmZpZ0Zvcm1hdHMgPSBbJ2pzJywgJ21qcycsICdjanMnLCAndHMnLCAnanNvbiddO1xuICBjb25zdCBjb25maWdCYXNlTmFtZSA9ICdsZXguY29uZmlnJztcbiAgbGV0IGxleENvbmZpZ1BhdGggPSAnJztcblxuICBmb3IoY29uc3QgZm9ybWF0IG9mIGNvbmZpZ0Zvcm1hdHMpIHtcbiAgICBjb25zdCBwb3RlbnRpYWxQYXRoID0gcGF0aFJlc29sdmUoY3dkLCBgLi8ke2NvbmZpZ0Jhc2VOYW1lfS4ke2Zvcm1hdH1gKTtcbiAgICBpZihleGlzdHNTeW5jKHBvdGVudGlhbFBhdGgpKSB7XG4gICAgICBsZXhDb25maWdQYXRoID0gcG90ZW50aWFsUGF0aDtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIGlmKGxleENvbmZpZ1BhdGgpIHtcbiAgICB0cnkge1xuICAgICAgLy8gRm9yIE1KUyBmaWxlcywgd2UgbmVlZCB0byB1c2UgZHluYW1pYyBpbXBvcnQgd2l0aCBVUkwgZm9yIGNvbXBhdGliaWxpdHlcbiAgICAgIGNvbnN0IGZvcm1hdCA9IGV4dG5hbWUobGV4Q29uZmlnUGF0aCkuc2xpY2UoMSk7XG4gICAgICBsZXQgaW1wb3J0UGF0aCA9IGxleENvbmZpZ1BhdGg7XG5cbiAgICAgIC8vIFVzZSBVUkwgcHJvdG9jb2wgZm9yIEVTTSBpbXBvcnRzXG4gICAgICBpZihmb3JtYXQgPT09ICdtanMnKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgdXJsID0gbmV3IFVSTChgZmlsZTovLyR7bGV4Q29uZmlnUGF0aH1gKTtcbiAgICAgICAgICBpbXBvcnRQYXRoID0gdXJsLmhyZWY7XG4gICAgICAgICAgaWYoZGVidWcpIHtcbiAgICAgICAgICAgIGxvZyhgVXNpbmcgVVJMIGZvcm1hdCBmb3IgTUpTIGltcG9ydDogJHtpbXBvcnRQYXRofWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCh1cmxFcnJvcikge1xuICAgICAgICAgIGxvZyhgRXJyb3IgY3JlYXRpbmcgVVJMIGZvciBNSlMgaW1wb3J0OiAke3VybEVycm9yLm1lc3NhZ2V9YCwgJ3dhcm4nLCBkZWJ1ZyB8fCAhcXVpZXQpO1xuICAgICAgICAgIGltcG9ydFBhdGggPSBgZmlsZTovLyR7bGV4Q29uZmlnUGF0aH1gO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmKGRlYnVnKSB7XG4gICAgICAgIGxvZyhgVHJ5aW5nIHRvIGltcG9ydCBjb25maWcgZnJvbSAke2ltcG9ydFBhdGh9IChmb3JtYXQ6ICR7Zm9ybWF0fSlgLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgIH1cblxuICAgICAgbGV0IGxleENvbmZpZztcbiAgICAgIHRyeSB7XG4gICAgICAgIGxleENvbmZpZyA9IGF3YWl0IGltcG9ydChpbXBvcnRQYXRoKTtcbiAgICAgIH0gY2F0Y2goaW1wb3J0RXJyb3IpIHtcbiAgICAgICAgaWYoaW1wb3J0RXJyb3IubWVzc2FnZS5pbmNsdWRlcygnbm90IGRlZmluZWQgaW4gRVMgbW9kdWxlIHNjb3BlJykpIHtcbiAgICAgICAgICBsb2coYEVTIE1vZHVsZSBzeW50YXggZXJyb3IgaW4gJHtsZXhDb25maWdQYXRofS4gTWFrZSBzdXJlIHlvdSdyZSB1c2luZyAnZXhwb3J0JyBpbnN0ZWFkIG9mICdtb2R1bGUuZXhwb3J0cycuYCwgJ2Vycm9yJywgcXVpZXQpO1xuICAgICAgICAgIGlmKGRlYnVnKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGltcG9ydEVycm9yKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IGltcG9ydEVycm9yO1xuICAgICAgfVxuXG4gICAgICAvLyBIYW5kbGUgYm90aCBFU00gKGRlZmF1bHQgZXhwb3J0KSBhbmQgQ29tbW9uSlMgKG1vZHVsZS5leHBvcnRzKVxuICAgICAgbGV0IGNvbmZpZ0RhdGEgPSBudWxsO1xuICAgICAgaWYobGV4Q29uZmlnLmRlZmF1bHQpIHtcbiAgICAgICAgY29uZmlnRGF0YSA9IGxleENvbmZpZy5kZWZhdWx0O1xuICAgICAgICBpZihkZWJ1Zykge1xuICAgICAgICAgIGxvZyhgRm91bmQgZGVmYXVsdCBleHBvcnQgaW4gJHtsZXhDb25maWdQYXRofWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBGb3IgQ29tbW9uSlMgb3Igb3RoZXIgbW9kdWxlIHN5c3RlbXNcbiAgICAgICAgY29uZmlnRGF0YSA9IGxleENvbmZpZztcbiAgICAgICAgaWYoZGVidWcpIHtcbiAgICAgICAgICBsb2coYFVzaW5nIGRpcmVjdCBleHBvcnQgaW4gJHtsZXhDb25maWdQYXRofWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmKGNvbmZpZ0RhdGEgJiYgY29uZmlnRGF0YS5haSkge1xuICAgICAgICBsb2coYEZvdW5kIEFJIGNvbmZpZ3VyYXRpb24gaW4gJHtwYXRoUmVzb2x2ZShjd2QsIGxleENvbmZpZ1BhdGgpfSwgYXBwbHlpbmcgc2V0dGluZ3MuLi5gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgICAgTGV4Q29uZmlnLmNvbmZpZy5haSA9IHsuLi5MZXhDb25maWcuY29uZmlnLmFpLCAuLi5jb25maWdEYXRhLmFpfTtcbiAgICAgIH1cbiAgICB9IGNhdGNoKGVycm9yKSB7XG4gICAgICBsb2coYEVycm9yIGxvYWRpbmcgQUkgY29uZmlndXJhdGlvbiBmcm9tICR7bGV4Q29uZmlnUGF0aH06ICR7ZXJyb3IubWVzc2FnZX1gLCAnd2FybicsIHF1aWV0KTtcbiAgICAgIGlmKGRlYnVnKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufTtcblxuLyoqXG4gKiBMb2FkIEVTTGludCBjb25maWd1cmF0aW9uIGZyb20gbGV4LmNvbmZpZy4qIGZpbGVzXG4gKi9cbmNvbnN0IGxvYWRFU0xpbnRDb25maWcgPSBhc3luYyAoY3dkOiBzdHJpbmcsIHF1aWV0OiBib29sZWFuLCBkZWJ1ZzogYm9vbGVhbik6IFByb21pc2U8Ym9vbGVhbj4gPT4ge1xuICAvLyBDaGVjayBpZiBMZXhDb25maWcgYWxyZWFkeSBoYXMgRVNMaW50IGNvbmZpZ3VyYXRpb24gbG9hZGVkXG4gIGlmKExleENvbmZpZy5jb25maWcuZXNsaW50ICYmIE9iamVjdC5rZXlzKExleENvbmZpZy5jb25maWcuZXNsaW50KS5sZW5ndGggPiAwKSB7XG4gICAgbG9nKCdGb3VuZCBFU0xpbnQgY29uZmlndXJhdGlvbiBpbiBsZXguY29uZmlnLiogZmlsZScsICdpbmZvJywgZGVidWcgfHwgIXF1aWV0KTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8vIFRyeSB0byBsb2FkIGZyb20gbGV4LmNvbmZpZy4qIGZpbGVzIGlmIG5vdCBhbHJlYWR5IGxvYWRlZFxuICBjb25zdCBjb25maWdGb3JtYXRzID0gWydqcycsICdtanMnLCAnY2pzJywgJ3RzJywgJ2pzb24nXTtcbiAgY29uc3QgY29uZmlnQmFzZU5hbWUgPSAnbGV4LmNvbmZpZyc7XG5cbiAgZm9yKGNvbnN0IGZvcm1hdCBvZiBjb25maWdGb3JtYXRzKSB7XG4gICAgY29uc3QgcG90ZW50aWFsUGF0aCA9IHBhdGhSZXNvbHZlKGN3ZCwgYC4vJHtjb25maWdCYXNlTmFtZX0uJHtmb3JtYXR9YCk7XG4gICAgaWYoZXhpc3RzU3luYyhwb3RlbnRpYWxQYXRoKSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gRm9yIE1KUyBmaWxlcywgd2UgbmVlZCB0byB1c2UgZHluYW1pYyBpbXBvcnQgd2l0aCBVUkwgZm9yIGNvbXBhdGliaWxpdHlcbiAgICAgICAgY29uc3QgZmlsZUZvcm1hdCA9IGV4dG5hbWUocG90ZW50aWFsUGF0aCkuc2xpY2UoMSk7XG4gICAgICAgIGxldCBpbXBvcnRQYXRoID0gcG90ZW50aWFsUGF0aDtcblxuICAgICAgICAvLyBVc2UgVVJMIHByb3RvY29sIGZvciBFU00gaW1wb3J0c1xuICAgICAgICBpZihmaWxlRm9ybWF0ID09PSAnbWpzJykge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCB1cmwgPSBuZXcgVVJMKGBmaWxlOi8vJHtwb3RlbnRpYWxQYXRofWApO1xuICAgICAgICAgICAgaW1wb3J0UGF0aCA9IHVybC5ocmVmO1xuICAgICAgICAgICAgaWYoZGVidWcpIHtcbiAgICAgICAgICAgICAgbG9nKGBVc2luZyBVUkwgZm9ybWF0IGZvciBNSlMgaW1wb3J0OiAke2ltcG9ydFBhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaCh1cmxFcnJvcikge1xuICAgICAgICAgICAgbG9nKGBFcnJvciBjcmVhdGluZyBVUkwgZm9yIE1KUyBpbXBvcnQ6ICR7dXJsRXJyb3IubWVzc2FnZX1gLCAnd2FybicsIGRlYnVnIHx8ICFxdWlldCk7XG4gICAgICAgICAgICBpbXBvcnRQYXRoID0gYGZpbGU6Ly8ke3BvdGVudGlhbFBhdGh9YDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZihkZWJ1Zykge1xuICAgICAgICAgIGxvZyhgVHJ5aW5nIHRvIGltcG9ydCBjb25maWcgZnJvbSAke2ltcG9ydFBhdGh9IChmb3JtYXQ6ICR7ZmlsZUZvcm1hdH0pYCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgbGV4Q29uZmlnO1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGxleENvbmZpZyA9IGF3YWl0IGltcG9ydChpbXBvcnRQYXRoKTtcbiAgICAgICAgfSBjYXRjaChpbXBvcnRFcnJvcikge1xuICAgICAgICAgIGlmKGltcG9ydEVycm9yLm1lc3NhZ2UuaW5jbHVkZXMoJ25vdCBkZWZpbmVkIGluIEVTIG1vZHVsZSBzY29wZScpKSB7XG4gICAgICAgICAgICBsb2coYEVTIE1vZHVsZSBzeW50YXggZXJyb3IgaW4gJHtwb3RlbnRpYWxQYXRofS4gTWFrZSBzdXJlIHlvdSdyZSB1c2luZyAnZXhwb3J0JyBpbnN0ZWFkIG9mICdtb2R1bGUuZXhwb3J0cycuYCwgJ2Vycm9yJywgcXVpZXQpO1xuICAgICAgICAgICAgaWYoZGVidWcpIHtcbiAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihpbXBvcnRFcnJvcik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhyb3cgaW1wb3J0RXJyb3I7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBIYW5kbGUgYm90aCBFU00gKGRlZmF1bHQgZXhwb3J0KSBhbmQgQ29tbW9uSlMgKG1vZHVsZS5leHBvcnRzKVxuICAgICAgICBsZXQgY29uZmlnRGF0YSA9IG51bGw7XG4gICAgICAgIGlmKGxleENvbmZpZy5kZWZhdWx0KSB7XG4gICAgICAgICAgY29uZmlnRGF0YSA9IGxleENvbmZpZy5kZWZhdWx0O1xuICAgICAgICAgIGlmKGRlYnVnKSB7XG4gICAgICAgICAgICBsb2coYEZvdW5kIGRlZmF1bHQgZXhwb3J0IGluICR7cG90ZW50aWFsUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gRm9yIENvbW1vbkpTIG9yIG90aGVyIG1vZHVsZSBzeXN0ZW1zXG4gICAgICAgICAgY29uZmlnRGF0YSA9IGxleENvbmZpZztcbiAgICAgICAgICBpZihkZWJ1Zykge1xuICAgICAgICAgICAgbG9nKGBVc2luZyBkaXJlY3QgZXhwb3J0IGluICR7cG90ZW50aWFsUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZihjb25maWdEYXRhICYmIGNvbmZpZ0RhdGEuZXNsaW50ICYmIE9iamVjdC5rZXlzKGNvbmZpZ0RhdGEuZXNsaW50KS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgbG9nKGBGb3VuZCBFU0xpbnQgY29uZmlndXJhdGlvbiBpbiAke3BhdGhSZXNvbHZlKGN3ZCwgcG90ZW50aWFsUGF0aCl9LCBhcHBseWluZyBzZXR0aW5ncy4uLmAsICdpbmZvJywgZGVidWcgfHwgIXF1aWV0KTtcbiAgICAgICAgICBMZXhDb25maWcuY29uZmlnLmVzbGludCA9IHsuLi5MZXhDb25maWcuY29uZmlnLmVzbGludCwgLi4uY29uZmlnRGF0YS5lc2xpbnR9O1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoKGVycm9yKSB7XG4gICAgICAgIGxvZyhgRXJyb3IgbG9hZGluZyBFU0xpbnQgY29uZmlndXJhdGlvbiBmcm9tICR7cG90ZW50aWFsUGF0aH06ICR7ZXJyb3IubWVzc2FnZX1gLCAnd2FybicsIHF1aWV0KTtcbiAgICAgICAgaWYoZGVidWcpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBmYWxzZTtcbn07XG5cbi8qKlxuICogUmVtb3ZlcyBjb21tZW50cyBmcm9tIGEgZmlsZSBleGNlcHQgZm9yIFRPRE9zIGFuZCBjb3B5cmlnaHQgbm90aWNlc1xuICovXG5jb25zdCByZW1vdmVGaWxlQ29tbWVudHMgPSAoZmlsZVBhdGg6IHN0cmluZywgcXVpZXQ6IGJvb2xlYW4pOiBib29sZWFuID0+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBmaWxlQ29udGVudCA9IHJlYWRGaWxlU3luYyhmaWxlUGF0aCwgJ3V0ZjgnKTtcblxuICAgIC8vIFNraXAgZmlsZXMgdGhhdCBhcmUgdG9vIGxhcmdlIHRvIGF2b2lkIHBlcmZvcm1hbmNlIGlzc3Vlc1xuICAgIGlmKGZpbGVDb250ZW50Lmxlbmd0aCA+IDEwMDAwMDApIHsgLy8gMU1CIGxpbWl0XG4gICAgICBsb2coYFNraXBwaW5nIGNvbW1lbnQgcmVtb3ZhbCBmb3IgbGFyZ2UgZmlsZTogJHtmaWxlUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBEZXRlcm1pbmUgZmlsZSB0eXBlIGZyb20gZXh0ZW5zaW9uXG4gICAgY29uc3QgZXh0ID0gZXh0bmFtZShmaWxlUGF0aCk7XG4gICAgbGV0IGlzVHlwZVNjcmlwdCA9IGZhbHNlO1xuICAgIGxldCBpc0phdmFTY3JpcHQgPSBmYWxzZTtcblxuICAgIGlmKFsnLnRzJywgJy50c3gnXS5pbmNsdWRlcyhleHQpKSB7XG4gICAgICBpc1R5cGVTY3JpcHQgPSB0cnVlO1xuICAgIH0gZWxzZSBpZihbJy5qcycsICcuanN4J10uaW5jbHVkZXMoZXh0KSkge1xuICAgICAgaXNKYXZhU2NyaXB0ID0gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gU2tpcCB1bnN1cHBvcnRlZCBmaWxlIHR5cGVzXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gVXNlIHJlZ2V4IHRvIG1hdGNoIGRpZmZlcmVudCB0eXBlcyBvZiBjb21tZW50c1xuICAgIC8vIFByZXNlcnZlczpcbiAgICAvLyAxLiBDb3B5cmlnaHQgbm90aWNlcyAoLyogQ29weXJpZ2h0IC4uLiAqLylcbiAgICAvLyAyLiBUT0RPIGNvbW1lbnRzICgvLyBUT0RPOiAuLi4pXG4gICAgLy8gMy4gTGljZW5zZSBoZWFkZXJzICgvKiAuLi4gTGljZW5zZSAuLi4gKi8pXG5cbiAgICAvLyBIYW5kbGUgbXVsdGktbGluZSBjb21tZW50cyBmaXJzdCAtIHByZXNlcnZlIGNvcHlyaWdodC9saWNlbnNlIG5vdGljZXNcbiAgICBsZXQgbmV3Q29udGVudCA9IGZpbGVDb250ZW50LnJlcGxhY2UoXG4gICAgICAvXFwvXFwqW1xcc1xcU10qP1xcKlxcLy9nLFxuICAgICAgKG1hdGNoKSA9PiB7XG4gICAgICAgIGlmKG1hdGNoLmluY2x1ZGVzKCdDb3B5cmlnaHQnKSB8fFxuICAgICAgICAgIG1hdGNoLmluY2x1ZGVzKCdMSUNFTlNFJykgfHxcbiAgICAgICAgICBtYXRjaC5pbmNsdWRlcygnTGljZW5zZScpIHx8XG4gICAgICAgICAgbWF0Y2guaW5jbHVkZXMoJ2xpY2Vuc2UnKSkge1xuICAgICAgICAgIHJldHVybiBtYXRjaDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gJyc7XG4gICAgICB9XG4gICAgKTtcblxuICAgIC8vIEhhbmRsZSBzaW5nbGUtbGluZSBjb21tZW50cyAtIHByZXNlcnZlIFRPRE9zXG4gICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgIC9cXC9cXC8uKiQvZ20sXG4gICAgICAobWF0Y2gpID0+IHtcbiAgICAgICAgaWYobWF0Y2guaW5jbHVkZXMoJ1RPRE8nKSB8fCBtYXRjaC5pbmNsdWRlcygnRklYTUUnKSkge1xuICAgICAgICAgIHJldHVybiBtYXRjaDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gJyc7XG4gICAgICB9XG4gICAgKTtcblxuICAgIC8vIENsZWFuIHVwIGFueSBtdWx0aXBsZSBibGFuayBsaW5lcyBjcmVhdGVkIGJ5IGNvbW1lbnQgcmVtb3ZhbFxuICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoL1xcblxccypcXG5cXHMqXFxuL2csICdcXG5cXG4nKTtcblxuICAgIC8vIElmIHRoZSBmaWxlIHdhcyBtb2RpZmllZCwgc2F2ZSBpdFxuICAgIGlmKG5ld0NvbnRlbnQgIT09IGZpbGVDb250ZW50KSB7XG4gICAgICB3cml0ZUZpbGVTeW5jKGZpbGVQYXRoLCBuZXdDb250ZW50LCAndXRmOCcpO1xuICAgICAgbG9nKGBSZW1vdmVkIGNvbW1lbnRzIGZyb20gJHtmaWxlUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTtcbiAgfSBjYXRjaChlcnJvcikge1xuICAgIGxvZyhgRXJyb3IgcmVtb3ZpbmcgY29tbWVudHMgZnJvbSAke2ZpbGVQYXRofTogJHtlcnJvci5tZXNzYWdlfWAsICdlcnJvcicsIHF1aWV0KTtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn07XG5cbmV4cG9ydCBjb25zdCBsaW50ID0gYXN5bmMgKGNtZDogTGludE9wdGlvbnMgJiB7J3JlbW92ZS1jb21tZW50cyc/OiBib29sZWFufSwgY2FsbGJhY2s6IExpbnRDYWxsYmFjayA9IHByb2Nlc3MuZXhpdCk6IFByb21pc2U8bnVtYmVyPiA9PiB7XG4gIGNvbnN0IHtcbiAgICBjbGlOYW1lID0gJ0xleCcsXG4gICAgZml4ID0gZmFsc2UsXG4gICAgZGVidWcgPSBmYWxzZSxcbiAgICBxdWlldCA9IGZhbHNlLFxuICAgIGNvbmZpZyA9IG51bGwsXG4gICAgcmVtb3ZlQ29tbWVudHMgPSBmYWxzZSxcbiAgICAvLyBIYW5kbGUga2ViYWItY2FzZSBDTEkgZmxhZyBjb252ZXJzaW9uXG4gICAgJ3JlbW92ZS1jb21tZW50cyc6IHJlbW92ZUNvbW1lbnRzRmxhZyA9IGZhbHNlXG4gIH0gPSBjbWQ7XG5cbiAgLy8gVXNlIGVpdGhlciB0aGUgY2FtZWxDYXNlIG9yIGtlYmFiLWNhc2UgdmVyc2lvbiBvZiB0aGUgZmxhZ1xuICBjb25zdCBzaG91bGRSZW1vdmVDb21tZW50cyA9IHJlbW92ZUNvbW1lbnRzIHx8IHJlbW92ZUNvbW1lbnRzRmxhZztcblxuICBsb2coYCR7Y2xpTmFtZX0gbGludGluZy4uLmAsICdpbmZvJywgcXVpZXQpO1xuXG4gIGNvbnN0IGN3ZCA9IHByb2Nlc3MuY3dkKCk7XG4gIGNvbnN0IHNwaW5uZXIgPSBjcmVhdGVTcGlubmVyKHF1aWV0KTtcblxuICBhd2FpdCBsb2FkQUlDb25maWcoY3dkLCBxdWlldCwgZGVidWcpO1xuXG4gIGxldCB0ZW1wQ29uZmlnUGF0aDogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG5cbiAgdHJ5IHtcbiAgICBjb25zdCB1c2VUeXBlc2NyaXB0ID0gZGV0ZWN0VHlwZVNjcmlwdChjd2QpO1xuICAgIGxvZyhgVHlwZVNjcmlwdCAke3VzZVR5cGVzY3JpcHQgPyAnZGV0ZWN0ZWQnIDogJ25vdCBkZXRlY3RlZCd9IGZyb20gdHNjb25maWcuanNvbmAsICdpbmZvJywgcXVpZXQpO1xuXG4gICAgaWYodXNlVHlwZXNjcmlwdCkge1xuICAgICAgTGV4Q29uZmlnLmNoZWNrTGludFR5cGVzY3JpcHRDb25maWcoKTtcbiAgICB9XG5cbiAgICBlbnN1cmVNb2R1bGVUeXBlKGN3ZCk7XG5cbiAgICBhd2FpdCBpbnN0YWxsRGVwZW5kZW5jaWVzKGN3ZCwgdXNlVHlwZXNjcmlwdCwgcXVpZXQpO1xuXG4gICAgY29uc3QgcHJvamVjdENvbmZpZ1BhdGggPSBwYXRoUmVzb2x2ZShjd2QsICdlc2xpbnQuY29uZmlnLmpzJyk7XG4gICAgY29uc3QgcHJvamVjdENvbmZpZ1BhdGhUcyA9IHBhdGhSZXNvbHZlKGN3ZCwgJ2VzbGludC5jb25maWcudHMnKTtcbiAgICBjb25zdCBoYXNFc2xpbnRDb25maWcgPSBleGlzdHNTeW5jKHByb2plY3RDb25maWdQYXRoKSB8fFxuICAgICAgZXhpc3RzU3luYyhwcm9qZWN0Q29uZmlnUGF0aFRzKSB8fFxuICAgICAgZXhpc3RzU3luYyhwYXRoUmVzb2x2ZShjd2QsICcuZXNsaW50cmMuanMnKSkgfHxcbiAgICAgIGV4aXN0c1N5bmMocGF0aFJlc29sdmUoY3dkLCAnLmVzbGludHJjLmpzb24nKSkgfHxcbiAgICAgIGV4aXN0c1N5bmMocGF0aFJlc29sdmUoY3dkLCAnLmVzbGludHJjLnltbCcpKSB8fFxuICAgICAgZXhpc3RzU3luYyhwYXRoUmVzb2x2ZShjd2QsICcuZXNsaW50cmMueWFtbCcpKSB8fFxuICAgICAgZXhpc3RzU3luYyhwYXRoUmVzb2x2ZShjd2QsICcuZXNsaW50cmMnKSk7XG5cbiAgICAvLyBDaGVjayBmb3IgRVNMaW50IGNvbmZpZyBpbiBsZXguY29uZmlnLipcbiAgICBjb25zdCBoYXNMZXhFc2xpbnRDb25maWcgPSBhd2FpdCBsb2FkRVNMaW50Q29uZmlnKGN3ZCwgcXVpZXQsIGRlYnVnKTtcblxuICAgIGlmKGhhc0xleEVzbGludENvbmZpZykge1xuICAgICAgbG9nKCdVc2luZyBFU0xpbnQgY29uZmlndXJhdGlvbiBmcm9tIGxleC5jb25maWcuKiBmaWxlJywgJ2luZm8nLCBxdWlldCk7XG4gICAgfVxuXG4gICAgaWYoZXhpc3RzU3luYyhwYXRoUmVzb2x2ZShjd2QsICcuZXNsaW50cmMuanNvbicpKSkge1xuICAgICAgdW5saW5rU3luYyhwYXRoUmVzb2x2ZShjd2QsICcuZXNsaW50cmMuanNvbicpKTtcbiAgICB9XG5cbiAgICBsZXQgbGV4Q29uZmlnUGF0aCA9ICcnO1xuICAgIGxldCBzaG91bGRDcmVhdGVUZW1wQ29uZmlnID0gZmFsc2U7XG5cbiAgICBpZighaGFzRXNsaW50Q29uZmlnICYmICFoYXNMZXhFc2xpbnRDb25maWcpIHtcbiAgICAgIGNvbnN0IHBvc3NpYmxlUGF0aHMgPSBbXG4gICAgICAgIHBhdGhSZXNvbHZlKGN1cnJlbnREaXJuYW1lLCAnLi4vLi4vLi4vLi4vZXNsaW50LmNvbmZpZy50cycpLFxuICAgICAgICBwYXRoUmVzb2x2ZShjdXJyZW50RGlybmFtZSwgJy4uLy4uLy4uLy4uL2VzbGludC5jb25maWcuanMnKSxcbiAgICAgICAgcGF0aFJlc29sdmUocHJvY2Vzcy5lbnYuTEVYX0hPTUUgfHwgJy4vbm9kZV9tb2R1bGVzL0BubGFicy9sZXgnLCAnZXNsaW50LmNvbmZpZy50cycpLFxuICAgICAgICBwYXRoUmVzb2x2ZShwcm9jZXNzLmVudi5MRVhfSE9NRSB8fCAnLi9ub2RlX21vZHVsZXMvQG5sYWJzL2xleCcsICdlc2xpbnQuY29uZmlnLmpzJylcbiAgICAgIF07XG5cbiAgICAgIGZvcihjb25zdCBwYXRoIG9mIHBvc3NpYmxlUGF0aHMpIHtcbiAgICAgICAgaWYoZXhpc3RzU3luYyhwYXRoKSkge1xuICAgICAgICAgIGxleENvbmZpZ1BhdGggPSBwYXRoO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmKGRlYnVnKSB7XG4gICAgICAgIGxvZyhgQ3VycmVudCBkaXJlY3Rvcnk6ICR7Y3VycmVudERpcm5hbWV9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgIGxvZyhgUHJvamVjdCBjb25maWcgcGF0aDogJHtwcm9qZWN0Q29uZmlnUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgICAgbG9nKGBQcm9qZWN0IGNvbmZpZyBleGlzdHM6ICR7aGFzRXNsaW50Q29uZmlnfWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICBsb2coYEZvdW5kIExleCBjb25maWc6ICR7bGV4Q29uZmlnUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgICAgbG9nKGBMZXggY29uZmlnIGV4aXN0czogJHshIWxleENvbmZpZ1BhdGggJiYgZXhpc3RzU3luYyhsZXhDb25maWdQYXRoKX1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgIH1cblxuICAgICAgaWYobGV4Q29uZmlnUGF0aCAmJiBleGlzdHNTeW5jKGxleENvbmZpZ1BhdGgpKSB7XG4gICAgICAgIGxvZygnTm8gRVNMaW50IGNvbmZpZ3VyYXRpb24gZm91bmQgaW4gcHJvamVjdC4gVXNpbmcgTGV4XFwncyBkZWZhdWx0IGNvbmZpZ3VyYXRpb24uJywgJ2luZm8nLCBxdWlldCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzaG91bGRDcmVhdGVUZW1wQ29uZmlnID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZihjb25maWcpIHtcbiAgICAgIGNvbnN0IHVzZXJDb25maWdQYXRoID0gcGF0aFJlc29sdmUoY3dkLCBjb25maWcpO1xuICAgICAgaWYoZXhpc3RzU3luYyh1c2VyQ29uZmlnUGF0aCkpIHtcbiAgICAgICAgbG9nKGBVc2luZyBzcGVjaWZpZWQgRVNMaW50IGNvbmZpZ3VyYXRpb246ICR7Y29uZmlnfWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICBzaG91bGRDcmVhdGVUZW1wQ29uZmlnID0gZmFsc2U7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsb2coYFNwZWNpZmllZCBFU0xpbnQgY29uZmlndXJhdGlvbiBub3QgZm91bmQ6ICR7Y29uZmlnfS4gVXNpbmcgTGV4J3MgZGVmYXVsdCBjb25maWd1cmF0aW9uLmAsICd3YXJuJywgcXVpZXQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmKHNob3VsZENyZWF0ZVRlbXBDb25maWcpIHtcbiAgICAgIGxvZygnTm8gRVNMaW50IGNvbmZpZ3VyYXRpb24gZm91bmQuIENyZWF0aW5nIGEgdGVtcG9yYXJ5IGNvbmZpZ3VyYXRpb24uLi4nLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgIGNvbnN0IGNvbmZpZ1Jlc3VsdCA9IGNyZWF0ZURlZmF1bHRFU0xpbnRDb25maWcodXNlVHlwZXNjcmlwdCwgY3dkKTtcbiAgICAgIHRlbXBDb25maWdQYXRoID0gY29uZmlnUmVzdWx0LmNvbmZpZ1BhdGg7XG4gICAgfVxuXG4gICAgbGV0IGVzbGludE91dHB1dCA9ICcnO1xuICAgIGNvbnN0IGNhcHR1cmVPdXRwdXQgPSAob3V0cHV0OiBzdHJpbmcpID0+IHtcbiAgICAgIGVzbGludE91dHB1dCArPSBgJHtvdXRwdXR9XFxuYDtcbiAgICB9O1xuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcnVuRXNsaW50V2l0aExleChjd2QsIHF1aWV0LCBjbGlOYW1lLCB0cnVlLCBkZWJ1ZywgdXNlVHlwZXNjcmlwdCwgY2FwdHVyZU91dHB1dCk7XG5cbiAgICAvLyBSZW1vdmUgY29tbWVudHMgaWYgZW5hYmxlZFxuICAgIGlmKHNob3VsZFJlbW92ZUNvbW1lbnRzKSB7XG4gICAgICBzcGlubmVyLnN0YXJ0KCdSZW1vdmluZyBjb21tZW50cyBmcm9tIGZpbGVzLi4uJyk7XG5cbiAgICAgIC8vIEdldCBhbGwgLmpzLCAuanN4LCAudHMsIC50c3ggZmlsZXMgaW4gdGhlIHByb2plY3RcbiAgICAgIGNvbnN0IGdsb2IgPSBhd2FpdCBpbXBvcnQoJ2dsb2InKTtcbiAgICAgIGNvbnN0IGZpbGVzID0gZ2xvYi5zeW5jKCd7c3JjLGxpYn0vKiovKi57anMsanN4LHRzLHRzeH0nLCB7XG4gICAgICAgIGN3ZCxcbiAgICAgICAgaWdub3JlOiBbJyoqL25vZGVfbW9kdWxlcy8qKicsICcqKi9kaXN0LyoqJywgJyoqL2J1aWxkLyoqJ11cbiAgICAgIH0pO1xuXG4gICAgICBsZXQgcHJvY2Vzc2VkQ291bnQgPSAwO1xuICAgICAgZm9yKGNvbnN0IGZpbGUgb2YgZmlsZXMpIHtcbiAgICAgICAgY29uc3QgZmlsZVBhdGggPSBwYXRoUmVzb2x2ZShjd2QsIGZpbGUpO1xuICAgICAgICBpZihyZW1vdmVGaWxlQ29tbWVudHMoZmlsZVBhdGgsIHF1aWV0KSkge1xuICAgICAgICAgIHByb2Nlc3NlZENvdW50Kys7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgc3Bpbm5lci5zdWNjZWVkKGBSZW1vdmVkIGNvbW1lbnRzIGZyb20gJHtwcm9jZXNzZWRDb3VudH0gZmlsZXNgKTtcbiAgICB9XG5cbiAgICBpZihyZXN1bHQgIT09IDAgJiYgZml4KSB7XG4gICAgICBjb25zdCBhaUNvbmZpZ3VyZWQgPSBMZXhDb25maWcuY29uZmlnLmFpPy5wcm92aWRlciAmJiBMZXhDb25maWcuY29uZmlnLmFpLnByb3ZpZGVyICE9PSAnbm9uZSc7XG5cbiAgICAgIGlmKGFpQ29uZmlndXJlZCkge1xuICAgICAgICBsb2coJ0FwcGx5aW5nIEFJIGZpeGVzIHRvIHJlbWFpbmluZyBpc3N1ZXMuLi4nLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgICAgYXdhaXQgYXBwbHlBSUZpeChjd2QsIGVzbGludE91dHB1dCwgcXVpZXQpO1xuXG4gICAgICAgIGNvbnN0IGFmdGVyRml4UmVzdWx0ID0gYXdhaXQgcnVuRXNsaW50V2l0aExleChjd2QsIHF1aWV0LCBjbGlOYW1lLCBmYWxzZSwgZGVidWcsIHVzZVR5cGVzY3JpcHQpO1xuXG4gICAgICAgIGNhbGxiYWNrKGFmdGVyRml4UmVzdWx0KTtcbiAgICAgICAgcmV0dXJuIGFmdGVyRml4UmVzdWx0O1xuICAgICAgfVxuICAgICAgbG9nKCdFU0xpbnQgY291bGQgbm90IGZpeCBhbGwgaXNzdWVzIGF1dG9tYXRpY2FsbHkuJywgJ3dhcm4nLCBxdWlldCk7XG4gICAgICBsb2coJ1RvIGVuYWJsZSBBSS1wb3dlcmVkIGZpeGVzLCBhZGQgQUkgY29uZmlndXJhdGlvbiB0byB5b3VyIGxleC5jb25maWcgZmlsZTonLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgIGxvZyhgXG4vLyBJbiBsZXguY29uZmlnLmpzIChvciBsZXguY29uZmlnLm1qcywgbGV4LmNvbmZpZy5janMsIGV0Yy4pXG5leHBvcnQgZGVmYXVsdCB7XG4gIC8vIFlvdXIgZXhpc3RpbmcgY29uZmlnXG4gIGFpOiB7XG4gICAgcHJvdmlkZXI6ICdjdXJzb3InIC8vIG9yICdvcGVuYWknLCAnYW50aHJvcGljJywgZXRjLlxuICAgIC8vIEFkZGl0aW9uYWwgcHJvdmlkZXItc3BlY2lmaWMgc2V0dGluZ3NcbiAgfVxufTtgLCAnaW5mbycsIHF1aWV0KTtcbiAgICB9XG5cbiAgICBjYWxsYmFjayhyZXN1bHQpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH0gY2F0Y2goZXJyb3IpIHtcbiAgICBsb2coYFxcbiR7Y2xpTmFtZX0gRXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gLCAnZXJyb3InLCBxdWlldCk7XG4gICAgaWYoc3Bpbm5lcikge1xuICAgICAgc3Bpbm5lci5mYWlsKCdMaW50aW5nIGZhaWxlZCEnKTtcbiAgICB9XG4gICAgY2FsbGJhY2soMSk7XG4gICAgcmV0dXJuIDE7XG4gIH0gZmluYWxseSB7XG4gICAgLy8gQ2xlYW4gdXAgdGVtcG9yYXJ5IGNvbmZpZyBmaWxlc1xuICAgIGNvbnN0IHRlbXBGaWxlUGF0aHMgPSBbXG4gICAgICB0ZW1wQ29uZmlnUGF0aCxcbiAgICAgIHBhdGhSZXNvbHZlKGN3ZCwgJy5sZXgtdGVtcC1lc2xpbnQuY2pzJyksXG4gICAgICBwYXRoUmVzb2x2ZShjd2QsICcubGV4LXRlbXAtZGVmYXVsdC1lc2xpbnQuY2pzJylcbiAgICBdO1xuXG4gICAgZm9yKGNvbnN0IGZpbGVQYXRoIG9mIHRlbXBGaWxlUGF0aHMpIHtcbiAgICAgIGlmKGZpbGVQYXRoICYmIGV4aXN0c1N5bmMoZmlsZVBhdGgpKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgdW5saW5rU3luYyhmaWxlUGF0aCk7XG4gICAgICAgICAgaWYoZGVidWcpIHtcbiAgICAgICAgICAgIGxvZyhgQ2xlYW5lZCB1cCB0ZW1wb3JhcnkgRVNMaW50IGNvbmZpZyBhdCAke2ZpbGVQYXRofWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaChfZXJyb3IpIHtcbiAgICAgICAgICAvLyBJZ25vcmUgZXJyb3JzXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbn07Il0sCiAgIm1hcHBpbmdzIjogIkFBSUEsU0FBUSxhQUFZO0FBQ3BCLFNBQVEsWUFBWSxjQUFjLFlBQVkscUJBQW9CO0FBQ2xFLFNBQVEsU0FBUyxXQUFXLGFBQWEsZUFBYztBQUV2RCxTQUFRLGlCQUFnQjtBQUN4QixTQUFRLHFCQUFvQjtBQUM1QixTQUFRLHlCQUF3QjtBQUNoQyxTQUFRLFdBQVU7QUFFbEIsSUFBSTtBQUNKLElBQUk7QUFFSixJQUFJO0FBQ0Ysb0JBQWtCLEtBQUssK0NBQStDO0FBQ3RFLG1CQUFpQixRQUFRLGVBQWU7QUFDMUMsUUFBUTtBQUNOLG9CQUFrQixRQUFRLElBQUk7QUFDOUIsbUJBQWlCLFFBQVEsSUFBSTtBQUMvQjtBQWdEQSxNQUFNLDRCQUE0QixDQUFDLGVBQXdCLFFBQThCO0FBRXZGLFFBQU0sYUFBYSxZQUFZLEtBQUssOEJBQThCO0FBQ2xFLFFBQU0saUJBQWlCO0FB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