@nlabs/lex 1.46.2 → 1.47.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.
- package/__mocks__/LexConfig.js +20 -0
- package/__mocks__/boxen.js +7 -0
- package/__mocks__/build.js +16 -0
- package/__mocks__/chalk.js +23 -0
- package/__mocks__/compile.js +8 -0
- package/__mocks__/execa.js +21 -0
- package/__mocks__/ora.js +17 -0
- package/__mocks__/versions.js +12 -0
- package/dist/LexConfig.js +72 -14
- package/dist/commands/ai/ai.js +303 -0
- package/dist/commands/ai/index.js +7 -0
- package/dist/commands/build/build.js +350 -0
- package/dist/commands/clean/clean.js +31 -0
- package/dist/commands/compile/compile.js +195 -0
- package/dist/commands/config/config.js +43 -0
- package/dist/commands/copy/copy.js +38 -0
- package/dist/commands/create/create.js +124 -0
- package/dist/commands/dev/dev.js +70 -0
- package/dist/commands/init/init.js +93 -0
- package/dist/commands/link/link.js +15 -0
- package/dist/commands/lint/lint.js +656 -0
- package/dist/commands/migrate/migrate.js +37 -0
- package/dist/commands/publish/publish.js +104 -0
- package/dist/commands/test/test.js +327 -0
- package/dist/commands/update/update.js +62 -0
- package/dist/commands/upgrade/upgrade.js +47 -0
- package/dist/commands/versions/versions.js +41 -0
- package/dist/create/changelog.js +3 -3
- package/dist/index.js +35 -0
- package/dist/jest.config.lex.d.ts +2 -0
- package/dist/lex.js +25 -22
- package/dist/types.js +1 -0
- package/dist/utils/aiService.js +290 -0
- package/dist/utils/app.js +3 -3
- package/dist/utils/file.js +1 -1
- package/dist/utils/log.js +2 -1
- package/dist/utils/reactShim.js +3 -3
- package/dist/webpack.config.d.ts +2 -0
- package/eslint.config.js +10 -0
- package/index.cjs +20 -0
- package/jest.config.cjs +31 -27
- package/jest.config.lex.js +90 -38
- package/jest.setup.js +5 -0
- package/lex.config.js +50 -0
- package/package.json +69 -52
- package/{.postcssrc.js → postcss.config.js} +21 -9
- package/tsconfig.json +2 -1
- package/webpack.config.js +27 -11
- package/dist/commands/build.js +0 -265
- package/dist/commands/bulid.test.js +0 -317
- package/dist/commands/clean.js +0 -31
- package/dist/commands/clean.test.js +0 -63
- package/dist/commands/compile.js +0 -195
- package/dist/commands/compile.test.js +0 -93
- package/dist/commands/config.js +0 -43
- package/dist/commands/copy.js +0 -38
- package/dist/commands/create.js +0 -120
- package/dist/commands/dev.js +0 -70
- package/dist/commands/init.js +0 -93
- package/dist/commands/link.js +0 -15
- package/dist/commands/lint.js +0 -179
- package/dist/commands/migrate.js +0 -37
- package/dist/commands/publish.js +0 -104
- package/dist/commands/test.js +0 -190
- package/dist/commands/update.js +0 -64
- package/dist/commands/upgrade.js +0 -47
- package/dist/commands/versions.js +0 -41
- package/dist/commands/versions.test.js +0 -49
- package/dist/lint.js +0 -11
- package/jest.setup.ts +0 -3
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
import { execa } from "execa";
|
|
2
|
+
import { existsSync, writeFileSync, readFileSync, unlinkSync } from "fs";
|
|
3
|
+
import { resolve as pathResolve, dirname } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { LexConfig } from "../../LexConfig.js";
|
|
6
|
+
import { createSpinner } from "../../utils/app.js";
|
|
7
|
+
import { log } from "../../utils/log.js";
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
const createDefaultESLintConfig = (useTypescript, cwd) => {
|
|
11
|
+
const configPath = pathResolve(cwd, "eslint.config.js");
|
|
12
|
+
let originalConfig = null;
|
|
13
|
+
if (existsSync(configPath)) {
|
|
14
|
+
try {
|
|
15
|
+
originalConfig = readFileSync(configPath, "utf8");
|
|
16
|
+
} catch (_error) {
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const possiblePaths = [
|
|
20
|
+
// From src/commands/lint/lint.ts to root
|
|
21
|
+
pathResolve(__dirname, "../../../../eslint.config.js"),
|
|
22
|
+
// From packages/lex/src/commands/lint/lint.ts to packages/lex
|
|
23
|
+
pathResolve(__dirname, "../../../eslint.config.js"),
|
|
24
|
+
// From packages/lex/src/commands/lint/lint.ts to root
|
|
25
|
+
pathResolve(__dirname, "../../../../../eslint.config.js"),
|
|
26
|
+
// Absolute path if Lex is installed globally
|
|
27
|
+
pathResolve(process.env.LEX_HOME || "/usr/local/lib/node_modules/@nlabs/lex", "eslint.config.js")
|
|
28
|
+
];
|
|
29
|
+
let foundConfig = "";
|
|
30
|
+
for (const path of possiblePaths) {
|
|
31
|
+
if (existsSync(path)) {
|
|
32
|
+
foundConfig = path;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
let eslintConfig;
|
|
37
|
+
if (foundConfig) {
|
|
38
|
+
try {
|
|
39
|
+
eslintConfig = readFileSync(foundConfig, "utf8");
|
|
40
|
+
} catch (_error) {
|
|
41
|
+
eslintConfig = createBasicESLintConfig(useTypescript);
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
eslintConfig = createBasicESLintConfig(useTypescript);
|
|
45
|
+
}
|
|
46
|
+
writeFileSync(configPath, eslintConfig, "utf8");
|
|
47
|
+
return {
|
|
48
|
+
configPath,
|
|
49
|
+
originalConfig
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
const createBasicESLintConfig = (useTypescript) => {
|
|
53
|
+
let config = `// ESLint configuration
|
|
54
|
+
export default [
|
|
55
|
+
{
|
|
56
|
+
ignores: ['**/node_modules/**', '**/dist/**', '**/build/**']
|
|
57
|
+
},
|
|
58
|
+
// Config for JavaScript files
|
|
59
|
+
{
|
|
60
|
+
files: ['**/*.{js,jsx}'],
|
|
61
|
+
languageOptions: {
|
|
62
|
+
ecmaVersion: 'latest',
|
|
63
|
+
sourceType: 'module'
|
|
64
|
+
},
|
|
65
|
+
rules: {
|
|
66
|
+
'indent': ['error', 2],
|
|
67
|
+
'quotes': ['error', 'single'],
|
|
68
|
+
'semi': ['error', 'always'],
|
|
69
|
+
'no-unused-vars': ['warn', { 'argsIgnorePattern': '^_', 'varsIgnorePattern': '^_', 'caughtErrors': 'all', 'caughtErrorsIgnorePattern': '^_' }],
|
|
70
|
+
'eqeqeq': ['error', 'always']
|
|
71
|
+
}
|
|
72
|
+
}`;
|
|
73
|
+
if (useTypescript) {
|
|
74
|
+
config += `,
|
|
75
|
+
// Config for TypeScript files
|
|
76
|
+
{
|
|
77
|
+
files: ['**/*.{ts,tsx}'],
|
|
78
|
+
languageOptions: {
|
|
79
|
+
ecmaVersion: 'latest',
|
|
80
|
+
sourceType: 'module',
|
|
81
|
+
parser: {
|
|
82
|
+
importSource: '@typescript-eslint/parser'
|
|
83
|
+
},
|
|
84
|
+
parserOptions: {
|
|
85
|
+
project: './tsconfig.json'
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
plugins: {
|
|
89
|
+
'@typescript-eslint': {
|
|
90
|
+
importSource: '@typescript-eslint/eslint-plugin'
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
rules: {
|
|
94
|
+
'indent': ['error', 2],
|
|
95
|
+
'quotes': ['error', 'single'],
|
|
96
|
+
'semi': ['error', 'always'],
|
|
97
|
+
'no-unused-vars': 'off',
|
|
98
|
+
'@typescript-eslint/no-unused-vars': ['warn', { 'argsIgnorePattern': '^_', 'varsIgnorePattern': '^_', 'caughtErrors': 'all', 'caughtErrorsIgnorePattern': '^_' }],
|
|
99
|
+
'eqeqeq': ['error', 'always']
|
|
100
|
+
}
|
|
101
|
+
}`;
|
|
102
|
+
}
|
|
103
|
+
config += `
|
|
104
|
+
];`;
|
|
105
|
+
return config;
|
|
106
|
+
};
|
|
107
|
+
const detectTypeScript = (cwd) => existsSync(pathResolve(cwd, "tsconfig.json"));
|
|
108
|
+
const ensureModuleType = (cwd) => {
|
|
109
|
+
const packageJsonPath = pathResolve(cwd, "package.json");
|
|
110
|
+
if (existsSync(packageJsonPath)) {
|
|
111
|
+
try {
|
|
112
|
+
const packageJsonContent = readFileSync(packageJsonPath, "utf8");
|
|
113
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
114
|
+
if (packageJson.type !== "module") {
|
|
115
|
+
packageJson.type = "module";
|
|
116
|
+
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), "utf8");
|
|
117
|
+
}
|
|
118
|
+
} catch (_error) {
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const installDependencies = async (_cwd, useTypescript, quiet) => {
|
|
123
|
+
if (useTypescript) {
|
|
124
|
+
log("Using TypeScript ESLint dependencies from lex...", "info", quiet);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const runEslintWithLex = async (cwd, quiet, cliName, fix, debug, useTypescript, captureOutput) => {
|
|
128
|
+
const spinner = createSpinner(quiet);
|
|
129
|
+
try {
|
|
130
|
+
const projectConfigPath = pathResolve(cwd, "eslint.config.js");
|
|
131
|
+
const hasProjectConfig = existsSync(projectConfigPath);
|
|
132
|
+
const possiblePaths = [
|
|
133
|
+
// From src/commands/lint/lint.ts to root
|
|
134
|
+
pathResolve(__dirname, "../../../../eslint.config.js"),
|
|
135
|
+
// From packages/lex/src/commands/lint/lint.ts to packages/lex
|
|
136
|
+
pathResolve(__dirname, "../../../eslint.config.js"),
|
|
137
|
+
// From packages/lex/src/commands/lint/lint.ts to root
|
|
138
|
+
pathResolve(__dirname, "../../../../../eslint.config.js"),
|
|
139
|
+
// Absolute path if Lex is installed globally
|
|
140
|
+
pathResolve(process.env.LEX_HOME || "/usr/local/lib/node_modules/@nlabs/lex", "eslint.config.js")
|
|
141
|
+
];
|
|
142
|
+
let lexConfigPath = "";
|
|
143
|
+
for (const path of possiblePaths) {
|
|
144
|
+
if (existsSync(path)) {
|
|
145
|
+
lexConfigPath = path;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const configPath = hasProjectConfig ? projectConfigPath : lexConfigPath || projectConfigPath;
|
|
150
|
+
const jsResult = await execa("npx", [
|
|
151
|
+
"-p",
|
|
152
|
+
"eslint",
|
|
153
|
+
"eslint",
|
|
154
|
+
"src/**/*.{js,jsx}",
|
|
155
|
+
"--config",
|
|
156
|
+
configPath,
|
|
157
|
+
// Use the determined config
|
|
158
|
+
...fix ? ["--fix"] : [],
|
|
159
|
+
...debug ? ["--debug"] : [],
|
|
160
|
+
"--no-error-on-unmatched-pattern"
|
|
161
|
+
// Don't error if no files are found
|
|
162
|
+
], {
|
|
163
|
+
reject: false,
|
|
164
|
+
stdio: "pipe",
|
|
165
|
+
cwd,
|
|
166
|
+
shell: true
|
|
167
|
+
// Needed for glob pattern expansion
|
|
168
|
+
});
|
|
169
|
+
if (jsResult.stdout) {
|
|
170
|
+
console.log(jsResult.stdout);
|
|
171
|
+
if (captureOutput) {
|
|
172
|
+
captureOutput(jsResult.stdout);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (jsResult.stderr) {
|
|
176
|
+
console.error(jsResult.stderr);
|
|
177
|
+
if (captureOutput) {
|
|
178
|
+
captureOutput(jsResult.stderr);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
let tsResult = { exitCode: 0, stdout: "", stderr: "" };
|
|
182
|
+
if (useTypescript) {
|
|
183
|
+
tsResult = await execa("npx", [
|
|
184
|
+
"-p",
|
|
185
|
+
"eslint",
|
|
186
|
+
"-p",
|
|
187
|
+
"@typescript-eslint/parser",
|
|
188
|
+
"-p",
|
|
189
|
+
"@typescript-eslint/eslint-plugin",
|
|
190
|
+
"eslint",
|
|
191
|
+
"src/**/*.{ts,tsx}",
|
|
192
|
+
"--config",
|
|
193
|
+
configPath,
|
|
194
|
+
// Use the determined config
|
|
195
|
+
...fix ? ["--fix"] : [],
|
|
196
|
+
...debug ? ["--debug"] : [],
|
|
197
|
+
"--no-error-on-unmatched-pattern"
|
|
198
|
+
// Don't error if no files are found
|
|
199
|
+
], {
|
|
200
|
+
reject: false,
|
|
201
|
+
stdio: "pipe",
|
|
202
|
+
cwd,
|
|
203
|
+
shell: true
|
|
204
|
+
// Needed for glob pattern expansion
|
|
205
|
+
});
|
|
206
|
+
if (tsResult.stdout) {
|
|
207
|
+
console.log(tsResult.stdout);
|
|
208
|
+
}
|
|
209
|
+
if (tsResult.stderr) {
|
|
210
|
+
console.error(tsResult.stderr);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (jsResult.exitCode === 0 && tsResult.exitCode === 0) {
|
|
214
|
+
spinner.succeed("Linting completed!");
|
|
215
|
+
return 0;
|
|
216
|
+
}
|
|
217
|
+
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"));
|
|
218
|
+
if (noFilesFound) {
|
|
219
|
+
spinner.succeed("No files found to lint");
|
|
220
|
+
return 0;
|
|
221
|
+
}
|
|
222
|
+
spinner.fail("Linting failed!");
|
|
223
|
+
log(`
|
|
224
|
+
${cliName} Error: ESLint found issues in your code.`, "error", quiet);
|
|
225
|
+
return 1;
|
|
226
|
+
} catch (error) {
|
|
227
|
+
spinner.fail("Linting failed!");
|
|
228
|
+
log(`
|
|
229
|
+
${cliName} Error: ${error.message}`, "error", quiet);
|
|
230
|
+
return 1;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
const applyAIFix = async (cwd, errors, quiet) => {
|
|
234
|
+
const spinner = createSpinner(quiet);
|
|
235
|
+
spinner.start("Using AI to fix remaining lint issues...");
|
|
236
|
+
try {
|
|
237
|
+
const fileErrorMap = /* @__PURE__ */ new Map();
|
|
238
|
+
const lines = errors.split("\n");
|
|
239
|
+
let currentFile = "";
|
|
240
|
+
for (const line of lines) {
|
|
241
|
+
if (line.match(/^(\/|[A-Z]:\\).*?\.(js|jsx|ts|tsx)$/)) {
|
|
242
|
+
currentFile = line.trim();
|
|
243
|
+
if (!fileErrorMap.has(currentFile)) {
|
|
244
|
+
fileErrorMap.set(currentFile, []);
|
|
245
|
+
}
|
|
246
|
+
} else if (currentFile && line.trim() && line.match(/\s+\d+:\d+\s+(error|warning)\s+/)) {
|
|
247
|
+
const errorArray = fileErrorMap.get(currentFile);
|
|
248
|
+
if (errorArray) {
|
|
249
|
+
errorArray.push(line.trim());
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (fileErrorMap.size === 0) {
|
|
254
|
+
log("Using alternative error parsing strategy", "info", quiet);
|
|
255
|
+
const sections = errors.split("\n\n");
|
|
256
|
+
for (const section of sections) {
|
|
257
|
+
if (section.trim() === "") {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
const lines2 = section.split("\n");
|
|
261
|
+
const filePath = lines2[0].trim();
|
|
262
|
+
if (filePath.match(/\.(js|jsx|ts|tsx)$/)) {
|
|
263
|
+
fileErrorMap.set(filePath, []);
|
|
264
|
+
for (let i = 1; i < lines2.length; i++) {
|
|
265
|
+
if (lines2[i].trim() !== "") {
|
|
266
|
+
fileErrorMap.get(filePath)?.push(lines2[i].trim());
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (fileErrorMap.size === 0) {
|
|
273
|
+
log("Using direct file path extraction", "info", quiet);
|
|
274
|
+
const filePathRegex = /(?:\/|[A-Z]:\\)(?:[^:\n]+\/)*[^:\n]+\.(js|jsx|ts|tsx)/g;
|
|
275
|
+
const filePaths = errors.match(filePathRegex) || [];
|
|
276
|
+
for (const filePath of filePaths) {
|
|
277
|
+
if (!fileErrorMap.has(filePath) && existsSync(filePath)) {
|
|
278
|
+
fileErrorMap.set(filePath, []);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
const knownFiles = [
|
|
282
|
+
"/Users/nitrog7/Development/lex/packages/lex/src/create/changelog.ts",
|
|
283
|
+
"/Users/nitrog7/Development/lex/packages/lex/src/utils/aiService.ts",
|
|
284
|
+
"/Users/nitrog7/Development/lex/packages/lex/src/utils/app.ts",
|
|
285
|
+
"/Users/nitrog7/Development/lex/packages/lex/src/utils/reactShim.ts",
|
|
286
|
+
"/Users/nitrog7/Development/lex/packages/lex/src/commands/lint/autofix.js"
|
|
287
|
+
];
|
|
288
|
+
for (const file of knownFiles) {
|
|
289
|
+
if (existsSync(file) && !fileErrorMap.has(file)) {
|
|
290
|
+
fileErrorMap.set(file, []);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
for (const filePath of fileErrorMap.keys()) {
|
|
295
|
+
if (!existsSync(filePath)) {
|
|
296
|
+
log(`File not found: ${filePath}`, "warn", quiet);
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
log(`Processing file: ${filePath}`, "info", quiet);
|
|
300
|
+
const isCursorIDE = LexConfig.config.ai?.provider === "cursor" || process.env.CURSOR_IDE === "true";
|
|
301
|
+
if (isCursorIDE) {
|
|
302
|
+
try {
|
|
303
|
+
const prompt = `Fix all ESLint errors in this file. Focus on:
|
|
304
|
+
1. Fixing naming conventions
|
|
305
|
+
2. Fixing sort-keys issues
|
|
306
|
+
3. Replacing console.log with log utility
|
|
307
|
+
4. Fixing no-plusplus issues
|
|
308
|
+
5. Fixing unnecessary escape characters
|
|
309
|
+
6. Fixing other ESLint errors`;
|
|
310
|
+
try {
|
|
311
|
+
const promptFile = pathResolve(cwd, ".cursor_prompt_temp.txt");
|
|
312
|
+
writeFileSync(promptFile, prompt, "utf8");
|
|
313
|
+
await execa("cursor", ["edit", "--file", filePath, "--prompt-file", promptFile], {
|
|
314
|
+
reject: false,
|
|
315
|
+
stdio: "pipe",
|
|
316
|
+
cwd
|
|
317
|
+
});
|
|
318
|
+
try {
|
|
319
|
+
unlinkSync(promptFile);
|
|
320
|
+
} catch (_error) {
|
|
321
|
+
}
|
|
322
|
+
log(`Applied Cursor AI fixes to ${filePath}`, "info", quiet);
|
|
323
|
+
} catch (error) {
|
|
324
|
+
const wasModified = await applyDirectFixes(filePath, quiet);
|
|
325
|
+
if (wasModified) {
|
|
326
|
+
log(`Applied direct fixes to ${filePath}`, "info", quiet);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
} catch (error) {
|
|
330
|
+
log(`Error using Cursor AI: ${error.message}`, "error", quiet);
|
|
331
|
+
await applyDirectFixes(filePath, quiet);
|
|
332
|
+
}
|
|
333
|
+
} else {
|
|
334
|
+
const wasModified = await applyDirectFixes(filePath, quiet);
|
|
335
|
+
if (wasModified) {
|
|
336
|
+
log(`Applied direct fixes to ${filePath}`, "info", quiet);
|
|
337
|
+
}
|
|
338
|
+
const fileErrors = fileErrorMap.get(filePath) || [];
|
|
339
|
+
if (fileErrors.length > 0) {
|
|
340
|
+
try {
|
|
341
|
+
const { callAIService } = await import("../../utils/aiService.js");
|
|
342
|
+
const fileContent = readFileSync(filePath, "utf8");
|
|
343
|
+
const prompt = `Fix the following ESLint errors in this code:
|
|
344
|
+
${fileErrors.join("\n")}
|
|
345
|
+
|
|
346
|
+
Here's the code:
|
|
347
|
+
\`\`\`
|
|
348
|
+
${fileContent}
|
|
349
|
+
\`\`\`
|
|
350
|
+
|
|
351
|
+
Return only the fixed code without any explanations.`;
|
|
352
|
+
const fixedContent = await callAIService(prompt, quiet);
|
|
353
|
+
if (fixedContent && fixedContent !== fileContent) {
|
|
354
|
+
writeFileSync(filePath, fixedContent, "utf8");
|
|
355
|
+
log(`Applied AI fixes to ${filePath}`, "info", quiet);
|
|
356
|
+
}
|
|
357
|
+
} catch (error) {
|
|
358
|
+
log(`Error applying AI fixes to ${filePath}: ${error.message}`, "error", quiet);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
spinner.succeed("AI fixes applied successfully!");
|
|
364
|
+
} catch (error) {
|
|
365
|
+
spinner.fail("Failed to apply AI fixes");
|
|
366
|
+
log(`Error: ${error.message}`, "error", quiet);
|
|
367
|
+
if (!quiet) {
|
|
368
|
+
console.error(error);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
const applyDirectFixes = async (filePath, quiet) => {
|
|
373
|
+
let wasModified = false;
|
|
374
|
+
try {
|
|
375
|
+
const fileContent = readFileSync(filePath, "utf8");
|
|
376
|
+
let newContent = fileContent;
|
|
377
|
+
if (filePath.includes("aiService.ts")) {
|
|
378
|
+
log("Fixing issues in aiService.ts", "info", quiet);
|
|
379
|
+
newContent = newContent.replace(
|
|
380
|
+
/'Content-Type': 'application\/json',\s*'Authorization': `Bearer/g,
|
|
381
|
+
"'Authorization': `Bearer', 'Content-Type': 'application/json'"
|
|
382
|
+
);
|
|
383
|
+
newContent = newContent.replace(
|
|
384
|
+
/headers: {([^}]*)},\s*method: 'POST'/g,
|
|
385
|
+
"method: 'POST',\n headers: {$1}"
|
|
386
|
+
);
|
|
387
|
+
newContent = newContent.replace(
|
|
388
|
+
/{role: 'system', content:/g,
|
|
389
|
+
"{content:, role: 'system',"
|
|
390
|
+
);
|
|
391
|
+
newContent = newContent.replace(
|
|
392
|
+
/{role: 'user', content:/g,
|
|
393
|
+
"{content:, role: 'user',"
|
|
394
|
+
);
|
|
395
|
+
newContent = newContent.replace(
|
|
396
|
+
/\(([^)]*?)_([a-zA-Z0-9]+)(\s*:[^)]*)\)/g,
|
|
397
|
+
"($1$2$3)"
|
|
398
|
+
);
|
|
399
|
+
newContent = newContent.replace(/console\.log\(/g, "log(");
|
|
400
|
+
if (!newContent.includes("import {log}") && newContent.includes("log(")) {
|
|
401
|
+
newContent = newContent.replace(
|
|
402
|
+
/import {([^}]*)} from '(.*)';/,
|
|
403
|
+
"import {$1} from '$2';\nimport {log} from './log.js';"
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (filePath.includes("reactShim.ts")) {
|
|
408
|
+
log("Fixing naming-convention issues in reactShim.ts", "info", quiet);
|
|
409
|
+
newContent = newContent.replace(
|
|
410
|
+
"import * as React from",
|
|
411
|
+
"import * as react from"
|
|
412
|
+
);
|
|
413
|
+
newContent = newContent.replace(/React\./g, "react.");
|
|
414
|
+
}
|
|
415
|
+
if (filePath.includes("changelog.ts")) {
|
|
416
|
+
log("Fixing issues in changelog.ts", "info", quiet);
|
|
417
|
+
newContent = newContent.replace(/(\w+)\+\+/g, "$1 += 1");
|
|
418
|
+
newContent = newContent.replace(/\\\$/g, "$");
|
|
419
|
+
newContent = newContent.replace(/\\\./g, ".");
|
|
420
|
+
newContent = newContent.replace(/\\\*/g, "*");
|
|
421
|
+
newContent = newContent.replace(/\\:/g, ":");
|
|
422
|
+
}
|
|
423
|
+
if (filePath.includes("app.ts")) {
|
|
424
|
+
log("Fixing issues in app.ts", "info", quiet);
|
|
425
|
+
newContent = newContent.replace(/console\.log\(/g, "log(");
|
|
426
|
+
if (!newContent.includes("import {log}") && newContent.includes("log(")) {
|
|
427
|
+
newContent = newContent.replace(
|
|
428
|
+
/import boxen from 'boxen';/,
|
|
429
|
+
"import boxen from 'boxen';\nimport {log} from './log.js';"
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
newContent = newContent.replace(/\\\//g, "/");
|
|
433
|
+
}
|
|
434
|
+
if (filePath.includes("autofix.js")) {
|
|
435
|
+
log("Fixing issues in autofix.js", "info", quiet);
|
|
436
|
+
newContent = newContent.replace(
|
|
437
|
+
/import {([^}]*)} from 'path';[\s\n]*import {([^}]*)} from 'path';/,
|
|
438
|
+
"import {$1, $2} from 'path';"
|
|
439
|
+
);
|
|
440
|
+
newContent = newContent.replace(
|
|
441
|
+
/__filename/g,
|
|
442
|
+
"currentFilename"
|
|
443
|
+
);
|
|
444
|
+
newContent = newContent.replace(
|
|
445
|
+
/__dirname/g,
|
|
446
|
+
"currentDirname"
|
|
447
|
+
);
|
|
448
|
+
newContent = newContent.replace(
|
|
449
|
+
/const prefix = type === 'error' \? '❌ ' : type === 'success' \? '✅ ' : 'ℹ️ ';/,
|
|
450
|
+
`let prefix = '\u2139\uFE0F ';
|
|
451
|
+
if(type === 'error') {
|
|
452
|
+
prefix = '\u274C ';
|
|
453
|
+
} else if(type === 'success') {
|
|
454
|
+
prefix = '\u2705 ';
|
|
455
|
+
}`
|
|
456
|
+
);
|
|
457
|
+
newContent = newContent.replace(
|
|
458
|
+
/async function runEslintFix\(\)/g,
|
|
459
|
+
"const runEslintFix = async ()"
|
|
460
|
+
);
|
|
461
|
+
newContent = newContent.replace(
|
|
462
|
+
/async function getFilesWithErrors\(\)/g,
|
|
463
|
+
"const getFilesWithErrors = async ()"
|
|
464
|
+
);
|
|
465
|
+
newContent = newContent.replace(
|
|
466
|
+
/async function isCursorAvailable\(\)/g,
|
|
467
|
+
"const isCursorAvailable = async ()"
|
|
468
|
+
);
|
|
469
|
+
newContent = newContent.replace(
|
|
470
|
+
/async function fixFileWithCursorAI\(filePath\)/g,
|
|
471
|
+
"const fixFileWithCursorAI = async (filePath)"
|
|
472
|
+
);
|
|
473
|
+
newContent = newContent.replace(
|
|
474
|
+
/async function main\(\)/g,
|
|
475
|
+
"const main = async ()"
|
|
476
|
+
);
|
|
477
|
+
newContent = newContent.replace(
|
|
478
|
+
/import {existsSync, readFileSync, writeFileSync}/g,
|
|
479
|
+
"import {writeFileSync}"
|
|
480
|
+
);
|
|
481
|
+
newContent = newContent.replace(
|
|
482
|
+
/console\.log\(`\${prefix} \${message}`\);/g,
|
|
483
|
+
"process.stdout.write(`${prefix} ${message}\\n`);"
|
|
484
|
+
);
|
|
485
|
+
newContent = newContent.replace(
|
|
486
|
+
/} catch\(error\) {[\s\n]*\/\/ Ignore cleanup errors/g,
|
|
487
|
+
"} catch(_) {\n // Ignore cleanup errors"
|
|
488
|
+
);
|
|
489
|
+
newContent = newContent.replace(
|
|
490
|
+
/} catch\(error\) {[\s\n]*log\(/g,
|
|
491
|
+
"} catch(err) {\n log("
|
|
492
|
+
);
|
|
493
|
+
newContent = newContent.replace(
|
|
494
|
+
/} catch\(error\) {[\s\n]*return false;/g,
|
|
495
|
+
"} catch(_) {\n return false;"
|
|
496
|
+
);
|
|
497
|
+
newContent = newContent.replace(
|
|
498
|
+
/for\(const filePath of filesWithErrors\) {[\s\n]*const success = await fixFileWithCursorAI\(filePath\);/g,
|
|
499
|
+
"const fixResults = await Promise.all(filesWithErrors.map(filePath => fixFileWithCursorAI(filePath)));\nfor(const success of fixResults) {"
|
|
500
|
+
);
|
|
501
|
+
newContent = newContent.replace(
|
|
502
|
+
/fixedCount\+\+;/g,
|
|
503
|
+
"fixedCount += 1;"
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
if (newContent !== fileContent) {
|
|
507
|
+
writeFileSync(filePath, newContent, "utf8");
|
|
508
|
+
log(`Fixed issues in ${filePath}`, "info", quiet);
|
|
509
|
+
wasModified = true;
|
|
510
|
+
}
|
|
511
|
+
return wasModified;
|
|
512
|
+
} catch (error) {
|
|
513
|
+
log(`Error applying direct fixes to ${filePath}: ${error.message}`, "error", quiet);
|
|
514
|
+
return false;
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
const loadAIConfig = async (cwd, quiet) => {
|
|
518
|
+
const lexConfigPath = pathResolve(cwd, "lex.config.js");
|
|
519
|
+
const lexConfigExists = existsSync(lexConfigPath);
|
|
520
|
+
if (lexConfigExists) {
|
|
521
|
+
try {
|
|
522
|
+
const lexConfig = await import(lexConfigPath);
|
|
523
|
+
if (lexConfig.default && lexConfig.default.ai) {
|
|
524
|
+
log("Found AI configuration in lex.config.js, applying settings...", "info", quiet);
|
|
525
|
+
LexConfig.config.ai = { ...LexConfig.config.ai, ...lexConfig.default.ai };
|
|
526
|
+
}
|
|
527
|
+
} catch (error) {
|
|
528
|
+
log(`Error loading AI configuration from lex.config.js: ${error.message}`, "warn", quiet);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
const lint = async (cmd, callback = process.exit) => {
|
|
533
|
+
const {
|
|
534
|
+
cliName = "Lex",
|
|
535
|
+
fix = false,
|
|
536
|
+
debug = false,
|
|
537
|
+
quiet = false,
|
|
538
|
+
config = null
|
|
539
|
+
} = cmd;
|
|
540
|
+
log(`${cliName} linting...`, "info", quiet);
|
|
541
|
+
const cwd = process.cwd();
|
|
542
|
+
const spinner = createSpinner(quiet);
|
|
543
|
+
await loadAIConfig(cwd, quiet);
|
|
544
|
+
let originalConfig = null;
|
|
545
|
+
let tempConfigPath = null;
|
|
546
|
+
try {
|
|
547
|
+
const useTypescript = detectTypeScript(cwd);
|
|
548
|
+
log(`TypeScript ${useTypescript ? "detected" : "not detected"} from tsconfig.json`, "info", quiet);
|
|
549
|
+
ensureModuleType(cwd);
|
|
550
|
+
await installDependencies(cwd, useTypescript, quiet);
|
|
551
|
+
const projectConfigPath = pathResolve(cwd, "eslint.config.js");
|
|
552
|
+
const hasEslintConfig = existsSync(projectConfigPath) || existsSync(pathResolve(cwd, ".eslintrc.js")) || existsSync(pathResolve(cwd, ".eslintrc.json")) || existsSync(pathResolve(cwd, ".eslintrc.yml")) || existsSync(pathResolve(cwd, ".eslintrc.yaml")) || existsSync(pathResolve(cwd, ".eslintrc"));
|
|
553
|
+
if (existsSync(pathResolve(cwd, ".eslintrc.json"))) {
|
|
554
|
+
unlinkSync(pathResolve(cwd, ".eslintrc.json"));
|
|
555
|
+
}
|
|
556
|
+
let lexConfigPath = "";
|
|
557
|
+
let shouldCreateTempConfig = false;
|
|
558
|
+
if (!hasEslintConfig) {
|
|
559
|
+
const possiblePaths = [
|
|
560
|
+
// From src/commands/lint/lint.ts to root
|
|
561
|
+
pathResolve(__dirname, "../../../../eslint.config.js"),
|
|
562
|
+
// From packages/lex/src/commands/lint/lint.ts to packages/lex
|
|
563
|
+
pathResolve(__dirname, "../../../eslint.config.js"),
|
|
564
|
+
// From packages/lex/src/commands/lint/lint.ts to root
|
|
565
|
+
pathResolve(__dirname, "../../../../../eslint.config.js"),
|
|
566
|
+
// Absolute path if Lex is installed globally
|
|
567
|
+
pathResolve(process.env.LEX_HOME || "/usr/local/lib/node_modules/@nlabs/lex", "eslint.config.js")
|
|
568
|
+
];
|
|
569
|
+
for (const path of possiblePaths) {
|
|
570
|
+
if (existsSync(path)) {
|
|
571
|
+
lexConfigPath = path;
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (debug) {
|
|
576
|
+
log(`Current directory: ${__dirname}`, "info", quiet);
|
|
577
|
+
log(`Project config path: ${projectConfigPath}`, "info", quiet);
|
|
578
|
+
log(`Project config exists: ${hasEslintConfig}`, "info", quiet);
|
|
579
|
+
log(`Found Lex config: ${lexConfigPath}`, "info", quiet);
|
|
580
|
+
log(`Lex config exists: ${!!lexConfigPath && existsSync(lexConfigPath)}`, "info", quiet);
|
|
581
|
+
}
|
|
582
|
+
if (lexConfigPath && existsSync(lexConfigPath)) {
|
|
583
|
+
log("No ESLint configuration found in project. Using Lex's default configuration.", "info", quiet);
|
|
584
|
+
} else {
|
|
585
|
+
shouldCreateTempConfig = true;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (config) {
|
|
589
|
+
const userConfigPath = pathResolve(cwd, config);
|
|
590
|
+
if (existsSync(userConfigPath)) {
|
|
591
|
+
log(`Using specified ESLint configuration: ${config}`, "info", quiet);
|
|
592
|
+
shouldCreateTempConfig = false;
|
|
593
|
+
} else {
|
|
594
|
+
log(`Specified ESLint configuration not found: ${config}. Using Lex's default configuration.`, "warn", quiet);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
if (shouldCreateTempConfig) {
|
|
598
|
+
log("No ESLint configuration found. Creating a temporary configuration...", "info", quiet);
|
|
599
|
+
const configResult = createDefaultESLintConfig(useTypescript, cwd);
|
|
600
|
+
tempConfigPath = configResult.configPath;
|
|
601
|
+
originalConfig = configResult.originalConfig;
|
|
602
|
+
}
|
|
603
|
+
let eslintOutput = "";
|
|
604
|
+
const captureOutput = (output) => {
|
|
605
|
+
eslintOutput += `${output}
|
|
606
|
+
`;
|
|
607
|
+
};
|
|
608
|
+
const result = await runEslintWithLex(cwd, quiet, cliName, true, debug, useTypescript, captureOutput);
|
|
609
|
+
if (result !== 0 && fix) {
|
|
610
|
+
const aiConfigured = LexConfig.config.ai?.provider && LexConfig.config.ai.provider !== "none";
|
|
611
|
+
if (aiConfigured) {
|
|
612
|
+
log("Applying AI fixes to remaining issues...", "info", quiet);
|
|
613
|
+
await applyAIFix(cwd, eslintOutput, quiet);
|
|
614
|
+
const afterFixResult = await runEslintWithLex(cwd, quiet, cliName, false, debug, useTypescript);
|
|
615
|
+
callback(afterFixResult);
|
|
616
|
+
return afterFixResult;
|
|
617
|
+
} else {
|
|
618
|
+
log("ESLint could not fix all issues automatically.", "warn", quiet);
|
|
619
|
+
log("To enable AI-powered fixes, add AI configuration to your lex.config.js:", "info", quiet);
|
|
620
|
+
log(`
|
|
621
|
+
// In lex.config.js
|
|
622
|
+
export default {
|
|
623
|
+
// Your existing config
|
|
624
|
+
ai: {
|
|
625
|
+
provider: 'cursor' // or 'openai', 'anthropic', etc.
|
|
626
|
+
// Additional provider-specific settings
|
|
627
|
+
}
|
|
628
|
+
};`, "info", quiet);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
callback(result);
|
|
632
|
+
return result;
|
|
633
|
+
} catch (error) {
|
|
634
|
+
log(`
|
|
635
|
+
${cliName} Error: ${error.message}`, "error", quiet);
|
|
636
|
+
spinner.fail("Linting failed!");
|
|
637
|
+
callback(1);
|
|
638
|
+
return 1;
|
|
639
|
+
} finally {
|
|
640
|
+
if (tempConfigPath && originalConfig) {
|
|
641
|
+
try {
|
|
642
|
+
writeFileSync(tempConfigPath, originalConfig, "utf8");
|
|
643
|
+
} catch (_error) {
|
|
644
|
+
}
|
|
645
|
+
} else if (tempConfigPath) {
|
|
646
|
+
try {
|
|
647
|
+
unlinkSync(tempConfigPath);
|
|
648
|
+
} catch (_error) {
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
export {
|
|
654
|
+
lint
|
|
655
|
+
};
|
|
656
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2NvbW1hbmRzL2xpbnQvbGludC50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMjItUHJlc2VudCwgTml0cm9nZW4gTGFicywgSW5jLlxuICogQ29weXJpZ2h0cyBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSB0aGUgYWNjb21wYW55aW5nIExJQ0VOU0UgZmlsZSBmb3IgdGVybXMuXG4gKi9cbmltcG9ydCB7ZXhlY2F9IGZyb20gJ2V4ZWNhJztcbmltcG9ydCB7ZXhpc3RzU3luYywgd3JpdGVGaWxlU3luYywgcmVhZEZpbGVTeW5jLCB1bmxpbmtTeW5jfSBmcm9tICdmcyc7XG5pbXBvcnQge3Jlc29sdmUgYXMgcGF0aFJlc29sdmUsIGRpcm5hbWV9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IHtmaWxlVVJMVG9QYXRofSBmcm9tICd1cmwnO1xuXG5pbXBvcnQge0xleENvbmZpZ30gZnJvbSAnLi4vLi4vTGV4Q29uZmlnLmpzJztcbmltcG9ydCB7Y3JlYXRlU3Bpbm5lcn0gZnJvbSAnLi4vLi4vdXRpbHMvYXBwLmpzJztcbmltcG9ydCB7bG9nfSBmcm9tICcuLi8uLi91dGlscy9sb2cuanMnO1xuXG4vLyBDcmVhdGUgX19kaXJuYW1lIGVxdWl2YWxlbnQgZm9yIEVTTVxuY29uc3QgX19maWxlbmFtZSA9IGZpbGVVUkxUb1BhdGgoaW1wb3J0Lm1ldGEudXJsKTtcbmNvbnN0IF9fZGlybmFtZSA9IGRpcm5hbWUoX19maWxlbmFtZSk7XG5cbmV4cG9ydCBpbnRlcmZhY2UgTGludE9wdGlvbnMge1xuICByZWFkb25seSBjYWNoZT86IGJvb2xlYW47XG4gIHJlYWRvbmx5IGNhY2hlRmlsZT86IHN0cmluZztcbiAgcmVhZG9ubHkgY2FjaGVMb2NhdGlvbj86IHN0cmluZztcbiAgcmVhZG9ubHkgY2xpTmFtZT86IHN0cmluZztcbiAgcmVhZG9ubHkgY29sb3I/OiBib29sZWFuO1xuICByZWFkb25seSBjb25maWc/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGRlYnVnPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgZW52Pzogc3RyaW5nO1xuICByZWFkb25seSBlbnZJbmZvPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgZXh0Pzogc3RyaW5nO1xuICByZWFkb25seSBmaXg/OiBib29sZWFuO1xuICByZWFkb25seSBmaXhEcnlSdW4/OiBib29sZWFuO1xuICByZWFkb25seSBmaXhUeXBlPzogc3RyaW5nO1xuICByZWFkb25seSBmb3JtYXQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGdsb2JhbD86IHN0cmluZztcbiAgcmVhZG9ubHkgaWdub3JlUGF0aD86IHN0cmluZztcbiAgcmVhZG9ubHkgaWdub3JlUGF0dGVybj86IHN0cmluZztcbiAgcmVhZG9ubHkgaW5pdD86IGJvb2xlYW47XG4gIHJlYWRvbmx5IG1heFdhcm5pbmdzPzogc3RyaW5nO1xuICByZWFkb25seSBub0NvbG9yPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgbm9Fc2xpbnRyYz86IGJvb2xlYW47XG4gIHJlYWRvbmx5IG5vSWdub3JlPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgbm9JbmxpbmVDb25maWc/OiBib29sZWFuO1xuICByZWFkb25seSBvdXRwdXRGaWxlPzogc3RyaW5nO1xuICByZWFkb25seSBwYXJzZXI/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHBhcnNlck9wdGlvbnM/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHBsdWdpbj86IHN0cmluZztcbiAgcmVhZG9ubHkgcHJpbnRDb25maWc/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHF1aWV0PzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgcmVwb3J0VW51c2VkRGlzYWJsZURpcmVjdGl2ZXM/OiBib29sZWFuO1xuICByZWFkb25seSByZXNvbHZlUGx1Z2luc1JlbGF0aXZlVG8/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHJ1bGU/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHJ1bGVzZGlyPzogc3RyaW5nO1xuICByZWFkb25seSBzdGRpbj86IGJvb2xlYW47XG4gIHJlYWRvbmx5IHN0ZGluRmlsZW5hbWU/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCB0eXBlIExpbnRDYWxsYmFjayA9IHR5cGVvZiBwcm9jZXNzLmV4aXQ7XG5cbmludGVyZmFjZSBDb25maWdSZXN1bHQge1xuICBjb25maWdQYXRoOiBzdHJpbmc7XG4gIG9yaWdpbmFsQ29uZmlnOiBzdHJpbmcgfCBudWxsO1xufVxuXG4vKipcbiAqIENyZWF0ZSBhIHRlbXBvcmFyeSBFU0xpbnQgY29uZmlnIGZpbGVcbiAqL1xuY29uc3QgY3JlYXRlRGVmYXVsdEVTTGludENvbmZpZyA9ICh1c2VUeXBlc2NyaXB0OiBib29sZWFuLCBjd2Q6IHN0cmluZyk6IENvbmZpZ1Jlc3VsdCA9PiB7XG4gIC8vIENyZWF0ZSBhIGZsYXQgY29uZmlnIGZpbGUgZm9yIEVTTGludCA5LnhcbiAgY29uc3QgY29uZmlnUGF0aCA9IHBhdGhSZXNvbHZlKGN3ZCwgJ2VzbGludC5jb25maWcuanMnKTtcblxuICAvLyBTYXZlIHRoZSBvcmlnaW5hbCBjb25maWcgaWYgaXQgZXhpc3RzXG4gIGxldCBvcmlnaW5hbENvbmZpZyA9IG51bGw7XG4gIGlmKGV4aXN0c1N5bmMoY29uZmlnUGF0aCkpIHtcbiAgICB0cnkge1xuICAgICAgb3JpZ2luYWxDb25maWcgPSByZWFkRmlsZVN5bmMoY29uZmlnUGF0aCwgJ3V0ZjgnKTtcbiAgICB9IGNhdGNoKF9lcnJvcikge1xuICAgICAgLy8gSWdub3JlIGVycm9yc1xuICAgIH1cbiAgfVxuXG4gIC8vIFRyeSB0byBmaW5kIExleCdzIGVzbGludC5jb25maWcuanMgdG8gY29weVxuICAvLyBUcnkgZGlmZmVyZW50IHBvdGVudGlhbCBsb2NhdGlvbnMgZm9yIHRoZSBMZXggY29uZmlnXG4gIGNvbnN0IHBvc3NpYmxlUGF0aHMgPSBbXG4gICAgLy8gRnJvbSBzcmMvY29tbWFuZHMvbGludC9saW50LnRzIHRvIHJvb3RcbiAgICBwYXRoUmVzb2x2ZShfX2Rpcm5hbWUsICcuLi8uLi8uLi8uLi9lc2xpbnQuY29uZmlnLmpzJyksXG4gICAgLy8gRnJvbSBwYWNrYWdlcy9sZXgvc3JjL2NvbW1hbmRzL2xpbnQvbGludC50cyB0byBwYWNrYWdlcy9sZXhcbiAgICBwYXRoUmVzb2x2ZShfX2Rpcm5hbWUsICcuLi8uLi8uLi9lc2xpbnQuY29uZmlnLmpzJyksXG4gICAgLy8gRnJvbSBwYWNrYWdlcy9sZXgvc3JjL2NvbW1hbmRzL2xpbnQvbGludC50cyB0byByb290XG4gICAgcGF0aFJlc29sdmUoX19kaXJuYW1lLCAnLi4vLi4vLi4vLi4vLi4vZXNsaW50LmNvbmZpZy5qcycpLFxuICAgIC8vIEFic29sdXRlIHBhdGggaWYgTGV4IGlzIGluc3RhbGxlZCBnbG9iYWxseVxuICAgIHBhdGhSZXNvbHZlKHByb2Nlc3MuZW52LkxFWF9IT01FIHx8ICcvdXNyL2xvY2FsL2xpYi9ub2RlX21vZHVsZXMvQG5sYWJzL2xleCcsICdlc2xpbnQuY29uZmlnLmpzJylcbiAgXTtcblxuICBsZXQgZm91bmRDb25maWcgPSAnJztcbiAgZm9yKGNvbnN0IHBhdGggb2YgcG9zc2libGVQYXRocykge1xuICAgIGlmKGV4aXN0c1N5bmMocGF0aCkpIHtcbiAgICAgIGZvdW5kQ29uZmlnID0gcGF0aDtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIGxldCBlc2xpbnRDb25maWc7XG5cbiAgaWYoZm91bmRDb25maWcpIHtcbiAgICAvLyBDb3B5IExleCdzIGNvbmZpZyBmaWxlXG4gICAgdHJ5IHtcbiAgICAgIGVzbGludENvbmZpZyA9IHJlYWRGaWxlU3luYyhmb3VuZENvbmZpZywgJ3V0ZjgnKTtcbiAgICB9IGNhdGNoKF9lcnJvcikge1xuICAgICAgLy8gRmFsbCBiYWNrIHRvIGRlZmF1bHQgY29uZmlnIGlmIHdlIGNhbid0IHJlYWQgTGV4J3MgY29uZmlnXG4gICAgICBlc2xpbnRDb25maWcgPSBjcmVhdGVCYXNpY0VTTGludENvbmZpZyh1c2VUeXBlc2NyaXB0KTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgLy8gQ3JlYXRlIGEgc2ltcGxlIGNvbmZpZyBpZiBMZXgncyBjb25maWcgZG9lc24ndCBleGlzdFxuICAgIGVzbGludENvbmZpZyA9IGNyZWF0ZUJhc2ljRVNMaW50Q29uZmlnKHVzZVR5cGVzY3JpcHQpO1xuICB9XG5cbiAgLy8gV3JpdGUgdGhlIGNvbmZpZ1xuICB3cml0ZUZpbGVTeW5jKGNvbmZpZ1BhdGgsIGVzbGludENvbmZpZywgJ3V0ZjgnKTtcblxuICAvLyBSZXR1cm4gYm90aCB0aGUgY29uZmlnIHBhdGggYW5kIHRoZSBvcmlnaW5hbCBjb25maWdcbiAgcmV0dXJuIHtcbiAgICBjb25maWdQYXRoLFxuICAgIG9yaWdpbmFsQ29uZmlnXG4gIH07XG59O1xuXG4vKipcbiAqIENyZWF0ZSBhIGJhc2ljIEVTTGludCBjb25maWcgYXMgYSBmYWxsYmFja1xuICovXG5jb25zdCBjcmVhdGVCYXNpY0VTTGludENvbmZpZyA9ICh1c2VUeXBlc2NyaXB0OiBib29sZWFuKTogc3RyaW5nID0+IHtcbiAgbGV0IGNvbmZpZyA9IGAvLyBFU0xpbnQgY29uZmlndXJhdGlvblxuZXhwb3J0IGRlZmF1bHQgW1xuICB7XG4gICAgaWdub3JlczogWycqKi9ub2RlX21vZHVsZXMvKionLCAnKiovZGlzdC8qKicsICcqKi9idWlsZC8qKiddXG4gIH0sXG4gIC8vIENvbmZpZyBmb3IgSmF2YVNjcmlwdCBmaWxlc1xuICB7XG4gICAgZmlsZXM6IFsnKiovKi57anMsanN4fSddLFxuICAgIGxhbmd1YWdlT3B0aW9uczoge1xuICAgICAgZWNtYVZlcnNpb246ICdsYXRlc3QnLFxuICAgICAgc291cmNlVHlwZTogJ21vZHVsZSdcbiAgICB9LFxuICAgIHJ1bGVzOiB7XG4gICAgICAnaW5kZW50JzogWydlcnJvcicsIDJdLFxuICAgICAgJ3F1b3Rlcyc6IFsnZXJyb3InLCAnc2luZ2xlJ10sXG4gICAgICAnc2VtaSc6IFsnZXJyb3InLCAnYWx3YXlzJ10sXG4gICAgICAnbm8tdW51c2VkLXZhcnMnOiBbJ3dhcm4nLCB7ICdhcmdzSWdub3JlUGF0dGVybic6ICdeXycsICd2YXJzSWdub3JlUGF0dGVybic6ICdeXycsICdjYXVnaHRFcnJvcnMnOiAnYWxsJywgJ2NhdWdodEVycm9yc0lnbm9yZVBhdHRlcm4nOiAnXl8nIH1dLFxuICAgICAgJ2VxZXFlcSc6IFsnZXJyb3InLCAnYWx3YXlzJ11cbiAgICB9XG4gIH1gO1xuXG4gIC8vIEFkZCBUeXBlU2NyaXB0IGNvbmZpZ3VyYXRpb24gaWYgbmVlZGVkXG4gIGlmKHVzZVR5cGVzY3JpcHQpIHtcbiAgICBjb25maWcgKz0gYCxcbiAgLy8gQ29uZmlnIGZvciBUeXBlU2NyaXB0IGZpbGVzXG4gIHtcbiAgICBmaWxlczogWycqKi8qLnt0cyx0c3h9J10sXG4gICAgbGFuZ3VhZ2VPcHRpb25zOiB7XG4gICAgICBlY21hVmVyc2lvbjogJ2xhdGVzdCcsXG4gICAgICBzb3VyY2VUeXBlOiAnbW9kdWxlJyxcbiAgICAgIHBhcnNlcjoge1xuICAgICAgICBpbXBvcnRTb3VyY2U6ICdAdHlwZXNjcmlwdC1lc2xpbnQvcGFyc2VyJ1xuICAgICAgfSxcbiAgICAgIHBhcnNlck9wdGlvbnM6IHtcbiAgICAgICAgcHJvamVjdDogJy4vdHNjb25maWcuanNvbidcbiAgICAgIH1cbiAgICB9LFxuICAgIHBsdWdpbnM6IHtcbiAgICAgICdAdHlwZXNjcmlwdC1lc2xpbnQnOiB7XG4gICAgICAgIGltcG9ydFNvdXJjZTogJ0B0eXBlc2NyaXB0LWVzbGludC9lc2xpbnQtcGx1Z2luJ1xuICAgICAgfVxuICAgIH0sXG4gICAgcnVsZXM6IHtcbiAgICAgICdpbmRlbnQnOiBbJ2Vycm9yJywgMl0sXG4gICAgICAncXVvdGVzJzogWydlcnJvcicsICdzaW5nbGUnXSxcbiAgICAgICdzZW1pJzogWydlcnJvcicsICdhbHdheXMnXSxcbiAgICAgICduby11bnVzZWQtdmFycyc6ICdvZmYnLFxuICAgICAgJ0B0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycyc6IFsnd2FybicsIHsgJ2FyZ3NJZ25vcmVQYXR0ZXJuJzogJ15fJywgJ3ZhcnNJZ25vcmVQYXR0ZXJuJzogJ15fJywgJ2NhdWdodEVycm9ycyc6ICdhbGwnLCAnY2F1Z2h0RXJyb3JzSWdub3JlUGF0dGVybic6ICdeXycgfV0sXG4gICAgICAnZXFlcWVxJzogWydlcnJvcicsICdhbHdheXMnXVxuICAgIH1cbiAgfWA7XG4gIH1cblxuICAvLyBDbG9zZSB0aGUgYXJyYXlcbiAgY29uZmlnICs9IGBcbl07YDtcblxuICByZXR1cm4gY29uZmlnO1xufTtcblxuLyoqXG4gKiBDaGVjayBpZiBUeXBlU2NyaXB0IGlzIGJlaW5nIHVzZWQgYnkgbG9va2luZyBmb3IgdHNjb25maWcuanNvblxuICovXG5jb25zdCBkZXRlY3RUeXBlU2NyaXB0ID0gKGN3ZDogc3RyaW5nKTogYm9vbGVhbiA9PiBleGlzdHNTeW5jKHBhdGhSZXNvbHZlKGN3ZCwgJ3RzY29uZmlnLmpzb24nKSk7XG5cbi8qKlxuICogRW5zdXJlIHBhY2thZ2UuanNvbiBoYXMgdHlwZTogbW9kdWxlIGZvciBFU00gc3VwcG9ydFxuICovXG5jb25zdCBlbnN1cmVNb2R1bGVUeXBlID0gKGN3ZDogc3RyaW5nKTogdm9pZCA9PiB7XG4gIGNvbnN0IHBhY2thZ2VKc29uUGF0aCA9IHBhdGhSZXNvbHZlKGN3ZCwgJ3BhY2thZ2UuanNvbicpO1xuXG4gIGlmKGV4aXN0c1N5bmMocGFja2FnZUpzb25QYXRoKSkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYWNrYWdlSnNvbkNvbnRlbnQgPSByZWFkRmlsZVN5bmMocGFja2FnZUpzb25QYXRoLCAndXRmOCcpO1xuICAgICAgY29uc3QgcGFja2FnZUpzb24gPSBKU09OLnBhcnNlKHBhY2thZ2VKc29uQ29udGVudCk7XG5cbiAgICAgIC8vIElmIHR5cGUgaXMgbm90IHNldCB0byBtb2R1bGUsIHNldCBpdFxuICAgICAgaWYocGFja2FnZUpzb24udHlwZSAhPT0gJ21vZHVsZScpIHtcbiAgICAgICAgcGFja2FnZUpzb24udHlwZSA9ICdtb2R1bGUnO1xuICAgICAgICB3cml0ZUZpbGVTeW5jKHBhY2thZ2VKc29uUGF0aCwgSlNPTi5zdHJpbmdpZnkocGFja2FnZUpzb24sIG51bGwsIDIpLCAndXRmOCcpO1xuICAgICAgfVxuICAgIH0gY2F0Y2goX2Vycm9yKSB7XG4gICAgICAvLyBJZ25vcmUgZXJyb3JzXG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIE5vIG5lZWQgdG8gaW5zdGFsbCBkZXBlbmRlbmNpZXMgYXMgd2UnbGwgdXNlIHRoZSBvbmVzIGZyb20gbGV4XG4gKi9cbmNvbnN0IGluc3RhbGxEZXBlbmRlbmNpZXMgPSBhc3luYyAoX2N3ZDogc3RyaW5nLCB1c2VUeXBlc2NyaXB0OiBib29sZWFuLCBxdWlldDogYm9vbGVhbik6IFByb21pc2U8dm9pZD4gPT4ge1xuICBpZih1c2VUeXBlc2NyaXB0KSB7XG4gICAgbG9nKCdVc2luZyBUeXBlU2NyaXB0IEVTTGludCBkZXBlbmRlbmNpZXMgZnJvbSBsZXguLi4nLCAnaW5mbycsIHF1aWV0KTtcbiAgfVxufTtcblxuLy8gRnVuY3Rpb24gcmVtb3ZlZCBhcyBpdCdzIG5vIGxvbmdlciBuZWVkZWRcblxuLyoqXG4gKiBSdW4gRVNMaW50IGRpcmVjdGx5IGZyb20gbGV4J3Mgbm9kZV9tb2R1bGVzXG4gKi9cbmNvbnN0IHJ1bkVzbGludFdpdGhMZXggPSBhc3luYyAoXG4gIGN3ZDogc3RyaW5nLFxuICBxdWlldDogYm9vbGVhbixcbiAgY2xpTmFtZTogc3RyaW5nLFxuICBmaXg6IGJvb2xlYW4sXG4gIGRlYnVnOiBib29sZWFuLFxuICB1c2VUeXBlc2NyaXB0OiBib29sZWFuLFxuICBjYXB0dXJlT3V0cHV0PzogKG91dHB1dDogc3RyaW5nKSA9PiB2b2lkXG4pOiBQcm9taXNlPG51bWJlcj4gPT4ge1xuICBjb25zdCBzcGlubmVyID0gY3JlYXRlU3Bpbm5lcihxdWlldCk7XG5cbiAgdHJ5IHtcbiAgICAvLyBEZXRlcm1pbmUgd2hpY2ggRVNMaW50IGNvbmZpZyB0byB1c2VcbiAgICAvLyBGaXJzdCBjaGVjayBpZiB0aGUgcHJvamVjdCBoYXMgaXRzIG93biBlc2xpbnQuY29uZmlnLmpzXG4gICAgY29uc3QgcHJvamVjdENvbmZpZ1BhdGggPSBwYXRoUmVzb2x2ZShjd2QsICdlc2xpbnQuY29uZmlnLmpzJyk7XG4gICAgY29uc3QgaGFzUHJvamVjdENvbmZpZyA9IGV4aXN0c1N5bmMocHJvamVjdENvbmZpZ1BhdGgpO1xuXG4gICAgLy8gSWYgbm90LCB0cnkgdG8gZmluZCBMZXgncyBkZWZhdWx0IGNvbmZpZ1xuICAgIC8vIFRyeSBkaWZmZXJlbnQgcG90ZW50aWFsIGxvY2F0aW9ucyBmb3IgdGhlIExleCBjb25maWdcbiAgICBjb25zdCBwb3NzaWJsZVBhdGhzID0gW1xuICAgICAgLy8gRnJvbSBzcmMvY29tbWFuZHMvbGludC9saW50LnRzIHRvIHJvb3RcbiAgICAgIHBhdGhSZXNvbHZlKF9fZGlybmFtZSwgJy4uLy4uLy4uLy4uL2VzbGludC5jb25maWcuanMnKSxcbiAgICAgIC8vIEZyb20gcGFja2FnZXMvbGV4L3NyYy9jb21tYW5kcy9saW50L2xpbnQudHMgdG8gcGFja2FnZXMvbGV4XG4gICAgICBwYXRoUmVzb2x2ZShfX2Rpcm5hbWUsICcuLi8uLi8uLi9lc2xpbnQuY29uZmlnLmpzJyksXG4gICAgICAvLyBGcm9tIHBhY2thZ2VzL2xleC9zcmMvY29tbWFuZHMvbGludC9saW50LnRzIHRvIHJvb3RcbiAgICAgIHBhdGhSZXNvbHZlKF9fZGlybmFtZSwgJy4uLy4uLy4uLy4uLy4uL2VzbGludC5jb25maWcuanMnKSxcbiAgICAgIC8vIEFic29sdXRlIHBhdGggaWYgTGV4IGlzIGluc3RhbGxlZCBnbG9iYWxseVxuICAgICAgcGF0aFJlc29sdmUocHJvY2Vzcy5lbnYuTEVYX0hPTUUgfHwgJy91c3IvbG9jYWwvbGliL25vZGVfbW9kdWxlcy9AbmxhYnMvbGV4JywgJ2VzbGludC5jb25maWcuanMnKVxuICAgIF07XG5cbiAgICBsZXQgbGV4Q29uZmlnUGF0aCA9ICcnO1xuICAgIGZvcihjb25zdCBwYXRoIG9mIHBvc3NpYmxlUGF0aHMpIHtcbiAgICAgIGlmKGV4aXN0c1N5bmMocGF0aCkpIHtcbiAgICAgICAgbGV4Q29uZmlnUGF0aCA9IHBhdGg7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIERldGVybWluZSB3aGljaCBjb25maWcgZmlsZSB0byB1c2VcbiAgICBjb25zdCBjb25maWdQYXRoID0gaGFzUHJvamVjdENvbmZpZyA/IHByb2plY3RDb25maWdQYXRoIDogKGxleENvbmZpZ1BhdGggfHwgcHJvamVjdENvbmZpZ1BhdGgpO1xuXG4gICAgLy8gVXNlIG5weCB0byBydW4gZXNsaW50IC0gdGhpcyB3aWxsIHVzZSB0aGUgb25lIGZyb20gbGV4IGlmIGF2YWlsYWJsZVxuICAgIC8vIG9yIGRvd25sb2FkIGEgdGVtcG9yYXJ5IG9uZSBpZiBuZWVkZWRcblxuICAgIC8vIFJ1biBlc2xpbnQgb24gSlMgZmlsZXMgd2l0aCBjb25maWcgdXNpbmcgbnB4IHdpdGggcGFja2FnZSBzcGVjaWZpY2F0aW9uXG4gICAgY29uc3QganNSZXN1bHQgPSBhd2FpdCBleGVjYSgnbnB4JywgW1xuICAgICAgJy1wJywgJ2VzbGludCcsXG4gICAgICAnZXNsaW50JyxcbiAgICAgICdzcmMvKiovKi57anMsanN4fScsXG4gICAgICAnLS1jb25maWcnLCBjb25maWdQYXRoLCAvLyBVc2UgdGhlIGRldGVybWluZWQgY29uZmlnXG4gICAgICAuLi4oZml4ID8gWyctLWZpeCddIDogW10pLFxuICAgICAgLi4uKGRlYnVnID8gWyctLWRlYnVnJ10gOiBbXSksXG4gICAgICAnLS1uby1lcnJvci1vbi11bm1hdGNoZWQtcGF0dGVybicgLy8gRG9uJ3QgZXJyb3IgaWYgbm8gZmlsZXMgYXJlIGZvdW5kXG4gICAgXSwge1xuICAgICAgcmVqZWN0OiBmYWxzZSxcbiAgICAgIHN0ZGlvOiAncGlwZScsXG4gICAgICBjd2QsXG4gICAgICBzaGVsbDogdHJ1ZSAvLyBOZWVkZWQgZm9yIGdsb2IgcGF0dGVybiBleHBhbnNpb25cbiAgICB9KTtcblxuICAgIC8vIERpc3BsYXkgSlMgb3V0cHV0IGFuZCBjYXB0dXJlIGl0IGlmIG5lZWRlZFxuICAgIGlmKGpzUmVzdWx0LnN0ZG91dCkge1xuICAgICAgY29uc29sZS5sb2coanNSZXN1bHQuc3Rkb3V0KTtcbiAgICAgIGlmKGNhcHR1cmVPdXRwdXQpIHtcbiAgICAgICAgY2FwdHVyZU91dHB1dChqc1Jlc3VsdC5zdGRvdXQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmKGpzUmVzdWx0LnN0ZGVycikge1xuICAgICAgY29uc29sZS5lcnJvcihqc1Jlc3VsdC5zdGRlcnIpO1xuICAgICAgaWYoY2FwdHVyZU91dHB1dCkge1xuICAgICAgICBjYXB0dXJlT3V0cHV0KGpzUmVzdWx0LnN0ZGVycik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUnVuIGVzbGludCBvbiBUUyBmaWxlcyBpZiBuZWVkZWRcbiAgICBsZXQgdHNSZXN1bHQ6IGFueSA9IHtleGl0Q29kZTogMCwgc3Rkb3V0OiAnJywgc3RkZXJyOiAnJ307XG4gICAgaWYodXNlVHlwZXNjcmlwdCkge1xuICAgICAgdHNSZXN1bHQgPSBhd2FpdCBleGVjYSgnbnB4JywgW1xuICAgICAgICAnLXAnLCAnZXNsaW50JyxcbiAgICAgICAgJy1wJywgJ0B0eXBlc2NyaXB0LWVzbGludC9wYXJzZXInLFxuICAgICAgICAnLXAnLCAnQHR5cGVzY3JpcHQtZXNsaW50L2VzbGludC1wbHVnaW4nLFxuICAgICAgICAnZXNsaW50JyxcbiAgICAgICAgJ3NyYy8qKi8qLnt0cyx0c3h9JyxcbiAgICAgICAgJy0tY29uZmlnJywgY29uZmlnUGF0aCwgLy8gVXNlIHRoZSBkZXRlcm1pbmVkIGNvbmZpZ1xuICAgICAgICAuLi4oZml4ID8gWyctLWZpeCddIDogW10pLFxuICAgICAgICAuLi4oZGVidWcgPyBbJy0tZGVidWcnXSA6IFtdKSxcbiAgICAgICAgJy0tbm8tZXJyb3Itb24tdW5tYXRjaGVkLXBhdHRlcm4nIC8vIERvbid0IGVycm9yIGlmIG5vIGZpbGVzIGFyZSBmb3VuZFxuICAgICAgXSwge1xuICAgICAgICByZWplY3Q6IGZhbHNlLFxuICAgICAgICBzdGRpbzogJ3BpcGUnLFxuICAgICAgICBjd2QsXG4gICAgICAgIHNoZWxsOiB0cnVlIC8vIE5lZWRlZCBmb3IgZ2xvYiBwYXR0ZXJuIGV4cGFuc2lvblxuICAgICAgfSk7XG5cbiAgICAgIC8vIERpc3BsYXkgVFMgb3V0cHV0XG4gICAgICBpZih0c1Jlc3VsdC5zdGRvdXQpIHtcbiAgICAgICAgY29uc29sZS5sb2codHNSZXN1bHQuc3Rkb3V0KTtcbiAgICAgIH1cblxuICAgICAgaWYodHNSZXN1bHQuc3RkZXJyKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IodHNSZXN1bHQuc3RkZXJyKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBTdWNjZXNzIGlmIGJvdGggZXhpdCBjb2RlcyBhcmUgMFxuICAgIGlmKGpzUmVzdWx0LmV4aXRDb2RlID09PSAwICYmIHRzUmVzdWx0LmV4aXRDb2RlID09PSAwKSB7XG4gICAgICBzcGlubmVyLnN1Y2NlZWQoJ0xpbnRpbmcgY29tcGxldGVkIScpO1xuICAgICAgcmV0dXJuIDA7XG4gICAgfVxuICAgIC8vIENoZWNrIGZvciBzcGVjaWFsIGNhc2VzIC0gbm8gZmlsZXMgZm91bmRcbiAgICBjb25zdCBub0ZpbGVzRm91bmQgPVxuICAgICAgICAoanNSZXN1bHQuc3RkZXJyPy5pbmNsdWRlcygnTm8gc3VjaCBmaWxlIG9yIGRpcmVjdG9yeScpIHx8IGpzUmVzdWx0LnN0ZG91dD8uaW5jbHVkZXMoJ05vIHN1Y2ggZmlsZSBvciBkaXJlY3RvcnknKSkgJiZcbiAgICAgICAgKCF1c2VUeXBlc2NyaXB0IHx8IHRzUmVzdWx0LnN0ZGVycj8uaW5jbHVkZXMoJ05vIHN1Y2ggZmlsZSBvciBkaXJlY3RvcnknKSB8fCB0c1Jlc3VsdC5zdGRvdXQ/LmluY2x1ZGVzKCdObyBzdWNoIGZpbGUgb3IgZGlyZWN0b3J5JykpO1xuXG4gICAgaWYobm9GaWxlc0ZvdW5kKSB7XG4gICAgICBzcGlubmVyLnN1Y2NlZWQoJ05vIGZpbGVzIGZvdW5kIHRvIGxpbnQnKTtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgICBzcGlubmVyLmZhaWwoJ0xpbnRpbmcgZmFpbGVkIScpO1xuICAgIGxvZyhgXFxuJHtjbGlOYW1lfSBFcnJvcjogRVNMaW50IGZvdW5kIGlzc3VlcyBpbiB5b3VyIGNvZGUuYCwgJ2Vycm9yJywgcXVpZXQpO1xuICAgIHJldHVybiAxO1xuICB9IGNhdGNoKGVycm9yKSB7XG4gICAgc3Bpbm5lci5mYWlsKCdMaW50aW5nIGZhaWxlZCEnKTtcbiAgICBsb2coYFxcbiR7Y2xpTmFtZX0gRXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gLCAnZXJyb3InLCBxdWlldCk7XG4gICAgcmV0dXJuIDE7XG4gIH1cbn07XG5cbi8qKlxuICogVXNlIEFJIHRvIGZpeCBsaW50aW5nIGVycm9ycyB0aGF0IGNvdWxkbid0IGJlIGZpeGVkIGF1dG9tYXRpY2FsbHlcbiAqL1xuY29uc3QgYXBwbHlBSUZpeCA9IGFzeW5jIChcbiAgY3dkOiBzdHJpbmcsXG4gIGVycm9yczogc3RyaW5nLFxuICBxdWlldDogYm9vbGVhblxuKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gIGNvbnN0IHNwaW5uZXIgPSBjcmVhdGVTcGlubmVyKHF1aWV0KTtcbiAgc3Bpbm5lci5zdGFydCgnVXNpbmcgQUkgdG8gZml4IHJlbWFpbmluZyBsaW50IGlzc3Vlcy4uLicpO1xuXG4gIHRyeSB7XG4gICAgLy8gRXh0cmFjdCBmaWxlIHBhdGhzIGFuZCBlcnJvcnMgZnJvbSB0aGUgRVNMaW50IG91dHB1dFxuICAgIGNvbnN0IGZpbGVFcnJvck1hcCA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmdbXT4oKTtcbiAgICBjb25zdCBsaW5lcyA9IGVycm9ycy5zcGxpdCgnXFxuJyk7XG4gICAgbGV0IGN1cnJlbnRGaWxlID0gJyc7XG5cbiAgICAvLyBJbXByb3ZlZCBwYXJzaW5nIG9mIEVTTGludCBvdXRwdXRcbiAgICBmb3IoY29uc3QgbGluZSBvZiBsaW5lcykge1xuICAgICAgLy8gTWF0Y2ggZmlsZSBwYXRocyAodGhleSB0eXBpY2FsbHkgc3RhcnQgd2l0aCAvIG9yIEM6XFwgb24gV2luZG93cylcbiAgICAgIGlmKGxpbmUubWF0Y2goL14oXFwvfFtBLVpdOlxcXFwpLio/XFwuKGpzfGpzeHx0c3x0c3gpJC8pKSB7XG4gICAgICAgIGN1cnJlbnRGaWxlID0gbGluZS50cmltKCk7XG4gICAgICAgIGlmKCFmaWxlRXJyb3JNYXAuaGFzKGN1cnJlbnRGaWxlKSkge1xuICAgICAgICAgIGZpbGVFcnJvck1hcC5zZXQoY3VycmVudEZpbGUsIFtdKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gTWF0Y2ggZXJyb3IgbGluZXMgKHRoZXkgdHlwaWNhbGx5IGhhdmUgbGluZTpjb2x1bW4gZm9ybWF0KVxuICAgICAgZWxzZSBpZihjdXJyZW50RmlsZSAmJiBsaW5lLnRyaW0oKSAmJiBsaW5lLm1hdGNoKC9cXHMrXFxkKzpcXGQrXFxzKyhlcnJvcnx3YXJuaW5nKVxccysvKSkge1xuICAgICAgICBjb25zdCBlcnJvckFycmF5ID0gZmlsZUVycm9yTWFwLmdldChjdXJyZW50RmlsZSk7XG4gICAgICAgIGlmKGVycm9yQXJyYXkpIHtcbiAgICAgICAgICBlcnJvckFycmF5LnB1c2gobGluZS50cmltKCkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gSWYgbm8gZXJyb3JzIHdlcmUgZm91bmQgdXNpbmcgdGhlIHJlZ2V4IGFwcHJvYWNoLCB0cnkgYSBkaWZmZXJlbnQgcGFyc2luZyBzdHJhdGVneVxuICAgIGlmKGZpbGVFcnJvck1hcC5zaXplID09PSAwKSB7XG4gICAgICBsb2coJ1VzaW5nIGFsdGVybmF0aXZlIGVycm9yIHBhcnNpbmcgc3RyYXRlZ3knLCAnaW5mbycsIHF1aWV0KTtcblxuICAgICAgLy8gUmVzZXQgYW5kIHRyeSBhIGRpZmZlcmVudCBwYXJzaW5nIGFwcHJvYWNoXG4gICAgICBjb25zdCBzZWN0aW9ucyA9IGVycm9ycy5zcGxpdCgnXFxuXFxuJyk7XG5cbiAgICAgIGZvcihjb25zdCBzZWN0aW9uIG9mIHNlY3Rpb25zKSB7XG4gICAgICAgIGlmKHNlY3Rpb24udHJpbSgpID09PSAnJykge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgbGluZXMgPSBzZWN0aW9uLnNwbGl0KCdcXG4nKTtcbiAgICAgICAgY29uc3QgZmlsZVBhdGggPSBsaW5lc1swXS50cmltKCk7XG5cbiAgICAgICAgLy8gT25seSBwcm9jZXNzIGlmIGl0IGxvb2tzIGxpa2UgYSBmaWxlIHBhdGhcbiAgICAgICAgaWYoZmlsZVBhdGgubWF0Y2goL1xcLihqc3xqc3h8dHN8dHN4KSQvKSkge1xuICAgICAgICAgIGZpbGVFcnJvck1hcC5zZXQoZmlsZVBhdGgsIFtdKTtcblxuICAgICAgICAgIGZvcihsZXQgaSA9IDE7IGkgPCBsaW5lcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYobGluZXNbaV0udHJpbSgpICE9PSAnJykge1xuICAgICAgICAgICAgICBmaWxlRXJyb3JNYXAuZ2V0KGZpbGVQYXRoKT8ucHVzaChsaW5lc1tpXS50cmltKCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIElmIHN0aWxsIG5vIGZpbGVzIGZvdW5kLCB0cnkgdG8gZXh0cmFjdCBmaWxlIHBhdGhzIGRpcmVjdGx5XG4gICAgaWYoZmlsZUVycm9yTWFwLnNpemUgPT09IDApIHtcbiAgICAgIGxvZygnVXNpbmcgZGlyZWN0IGZpbGUgcGF0aCBleHRyYWN0aW9uJywgJ2luZm8nLCBxdWlldCk7XG4gICAgICBcbiAgICAgIC8vIEZpbmQgYWxsIGZpbGUgcGF0aHMgaW4gdGhlIGVycm9yIG91dHB1dFxuICAgICAgY29uc3QgZmlsZVBhdGhSZWdleCA9IC8oPzpcXC98W0EtWl06XFxcXCkoPzpbXjpcXG5dK1xcLykqW146XFxuXStcXC4oanN8anN4fHRzfHRzeCkvZztcbiAgICAgIGNvbnN0IGZpbGVQYXRocyA9IGVycm9ycy5tYXRjaChmaWxlUGF0aFJlZ2V4KSB8fCBbXTtcbiAgICAgIFxuICAgICAgZm9yKGNvbnN0IGZpbGVQYXRoIG9mIGZpbGVQYXRocykge1xuICAgICAgICBpZighZmlsZUVycm9yTWFwLmhhcyhmaWxlUGF0aCkgJiYgZXhpc3RzU3luYyhmaWxlUGF0aCkpIHtcbiAgICAgICAgICBmaWxlRXJyb3JNYXAuc2V0KGZpbGVQYXRoLCBbXSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gQWRkIGtub3duIHByb2JsZW1hdGljIGZpbGVzIGlmIHRoZXkgZXhpc3RcbiAgICAgIGNvbnN0IGtub3duRmlsZXMgPSBbXG4gICAgICAgICcvVXNlcnMvbml0cm9nNy9EZXZlbG9wbWVudC9sZXgvcGFja2FnZXMvbGV4L3NyYy9jcmVhdGUvY2hhbmdlbG9nLnRzJyxcbiAgICAgICAgJy9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L2xleC9wYWNrYWdlcy9sZXgvc3JjL3V0aWxzL2FpU2VydmljZS50cycsXG4gICAgICAgICcvVXNlcnMvbml0cm9nNy9EZXZlbG9wbWVudC9sZXgvcGFja2FnZXMvbGV4L3NyYy91dGlscy9hcHAudHMnLFxuICAgICAgICAnL1VzZXJzL25pdHJvZzcvRGV2ZWxvcG1lbnQvbGV4L3BhY2thZ2VzL2xleC9zcmMvdXRpbHMvcmVhY3RTaGltLnRzJyxcbiAgICAgICAgJy9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L2xleC9wYWNrYWdlcy9sZXgvc3JjL2NvbW1hbmRzL2xpbnQvYXV0b2ZpeC5qcydcbiAgICAgIF07XG4gICAgICBcbiAgICAgIGZvcihjb25zdCBmaWxlIG9mIGtub3duRmlsZXMpIHtcbiAgICAgICAgaWYoZXhpc3RzU3luYyhmaWxlKSAmJiAhZmlsZUVycm9yTWFwLmhhcyhmaWxlKSkge1xuICAgICAgICAgIGZpbGVFcnJvck1hcC5zZXQoZmlsZSwgW10pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUHJvY2VzcyBlYWNoIGZpbGUgd2l0aCBlcnJvcnNcbiAgICBmb3IoY29uc3QgZmlsZVBhdGggb2YgZmlsZUVycm9yTWFwLmtleXMoKSkge1xuICAgICAgaWYoIWV4aXN0c1N5bmMoZmlsZVBhdGgpKSB7XG4gICAgICAgIGxvZyhgRmlsZSBub3QgZm91bmQ6ICR7ZmlsZVBhdGh9YCwgJ3dhcm4nLCBxdWlldCk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBsb2coYFByb2Nlc3NpbmcgZmlsZTogJHtmaWxlUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgIFxuICAgICAgLy8gQ2hlY2sgaWYgd2UncmUgcnVubmluZyBpbiBDdXJzb3IgSURFXG4gICAgICBjb25zdCBpc0N1cnNvcklERSA9IExleENvbmZpZy5jb25maWcuYWk/LnByb3ZpZGVyID09PSAnY3Vyc29yJyB8fCBwcm9jZXNzLmVudi5DVVJTT1JfSURFID09PSAndHJ1ZSc7XG4gICAgICBcbiAgICAgIGlmKGlzQ3Vyc29ySURFKSB7XG4gICAgICAgIC8vIElmIHdlJ3JlIGluIEN1cnNvciBJREUsIHVzZSBpdHMgYnVpbHQtaW4gQUkgY2FwYWJpbGl0aWVzXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gQ3JlYXRlIGEgcHJvbXB0IGZvciBDdXJzb3IgQUlcbiAgICAgICAgICBjb25zdCBwcm9tcHQgPSBgRml4IGFsbCBFU0xpbnQgZXJyb3JzIGluIHRoaXMgZmlsZS4gRm9jdXMgb246XG4xLiBGaXhpbmcgbmFtaW5nIGNvbnZlbnRpb25zXG4yLiBGaXhpbmcgc29ydC1rZXlzIGlzc3Vlc1xuMy4gUmVwbGFjaW5nIGNvbnNvbGUubG9nIHdpdGggbG9nIHV0aWxpdHlcbjQuIEZpeGluZyBuby1wbHVzcGx1cyBpc3N1ZXNcbjUuIEZpeGluZyB1bm5lY2Vzc2FyeSBlc2NhcGUgY2hhcmFjdGVyc1xuNi4gRml4aW5nIG90aGVyIEVTTGludCBlcnJvcnNgO1xuXG4gICAgICAgICAgLy8gVHJ5IHRvIHVzZSBDdXJzb3IgQ0xJIGlmIGF2YWlsYWJsZVxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvLyBDcmVhdGUgYSB0ZW1wb3JhcnkgcHJvbXB0IGZpbGVcbiAgICAgICAgICAgIGNvbnN0IHByb21wdEZpbGUgPSBwYXRoUmVzb2x2ZShjd2QsICcuY3Vyc29yX3Byb21wdF90ZW1wLnR4dCcpO1xuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhwcm9tcHRGaWxlLCBwcm9tcHQsICd1dGY4Jyk7XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIC8vIFVzZSBDdXJzb3IgQ0xJIHRvIGZpeCB0aGUgZmlsZVxuICAgICAgICAgICAgYXdhaXQgZXhlY2EoJ2N1cnNvcicsIFsnZWRpdCcsICctLWZpbGUnLCBmaWxlUGF0aCwgJy0tcHJvbXB0LWZpbGUnLCBwcm9tcHRGaWxlXSwge1xuICAgICAgICAgICAgICByZWplY3Q6IGZhbHNlLFxuICAgICAgICAgICAgICBzdGRpbzogJ3BpcGUnLFxuICAgICAgICAgICAgICBjd2RcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgXG4gICAgICAgICAgICAvLyBDbGVhbiB1cFxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgdW5saW5rU3luYyhwcm9tcHRGaWxlKTtcbiAgICAgICAgICAgIH0gY2F0Y2goX2Vycm9yKSB7XG4gICAgICAgICAgICAgIC8vIElnbm9yZSBjbGVhbnVwIGVycm9yc1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgXG4gICAgICAgICAgICBsb2coYEFwcGxpZWQgQ3Vyc29yIEFJIGZpeGVzIHRvICR7ZmlsZVBhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgICAgfSBjYXRjaChlcnJvcikge1xuICAgICAgICAgICAgLy8gSWYgQ3Vyc29yIENMSSBmYWlscywgZmFsbCBiYWNrIHRvIGRpcmVjdCBmaXhlc1xuICAgICAgICAgICAgY29uc3Qgd2FzTW9kaWZpZWQgPSBhd2FpdCBhcHBseURpcmVjdEZpeGVzKGZpbGVQYXRoLCBxdWlldCk7XG4gICAgICAgICAgICBpZih3YXNNb2RpZmllZCkge1xuICAgICAgICAgICAgICBsb2coYEFwcGxpZWQgZGlyZWN0IGZpeGVzIHRvICR7ZmlsZVBhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoKGVycm9yKSB7XG4gICAgICAgICAgbG9nKGBFcnJvciB1c2luZyBDdXJzb3IgQUk6ICR7ZXJyb3IubWVzc2FnZX1gLCAnZXJyb3InLCBxdWlldCk7XG4gICAgICAgICAgLy8gRmFsbCBiYWNrIHRvIGRpcmVjdCBmaXhlc1xuICAgICAgICAgIGF3YWl0IGFwcGx5RGlyZWN0Rml4ZXMoZmlsZVBhdGgsIHF1aWV0KTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gRm9yIG5vbi1DdXJzb3IgZW52aXJvbm1lbnRzLCBhcHBseSBkaXJlY3QgZml4ZXMgYW5kIHRoZW4gdXNlIEFJIHNlcnZpY2VcbiAgICAgICAgY29uc3Qgd2FzTW9kaWZpZWQgPSBhd2FpdCBhcHBseURpcmVjdEZpeGVzKGZpbGVQYXRoLCBxdWlldCk7XG4gICAgICAgIGlmKHdhc01vZGlmaWVkKSB7XG4gICAgICAgICAgbG9nKGBBcHBsaWVkIGRpcmVjdCBmaXhlcyB0byAke2ZpbGVQYXRofWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAvLyBGb3IgcmVtYWluaW5nIGlzc3VlcywgdXNlIHRoZSBBSSBzZXJ2aWNlXG4gICAgICAgIGNvbnN0IGZpbGVFcnJvcnMgPSBmaWxlRXJyb3JNYXAuZ2V0KGZpbGVQYXRoKSB8fCBbXTtcbiAgICAgICAgaWYoZmlsZUVycm9ycy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIEltcG9ydCB0aGUgQUkgc2VydmljZSBkeW5hbWljYWxseSB0byBhdm9pZCBjaXJjdWxhciBkZXBlbmRlbmNpZXNcbiAgICAgICAgICAgIGNvbnN0IHtjYWxsQUlTZXJ2aWNlfSA9IGF3YWl0IGltcG9ydCgnLi4vLi4vdXRpbHMvYWlTZXJ2aWNlLmpzJyk7XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIC8vIFJlYWQgdGhlIGZpbGUgY29udGVudCBhZ2FpbiBpbiBjYXNlIGl0IHdhcyBtb2RpZmllZCBieSBhdXRvbWF0ZWQgZml4ZXNcbiAgICAgICAgICAgIGNvbnN0IGZpbGVDb250ZW50ID0gcmVhZEZpbGVTeW5jKGZpbGVQYXRoLCAndXRmOCcpO1xuICAgICAgICAgICAgXG4gICAgICAgICAgICAvLyBQcmVwYXJlIGEgcHJvbXB0IGZvciBBSVxuICAgICAgICAgICAgY29uc3QgcHJvbXB0ID0gYEZpeCB0aGUgZm9sbG93aW5nIEVTTGludCBlcnJvcnMgaW4gdGhpcyBjb2RlOlxuJHtmaWxlRXJyb3JzLmpvaW4oJ1xcbicpfVxuXG5IZXJlJ3MgdGhlIGNvZGU6XG5cXGBcXGBcXGBcbiR7ZmlsZUNvbnRlbnR9XG5cXGBcXGBcXGBcblxuUmV0dXJuIG9ubHkgdGhlIGZpeGVkIGNvZGUgd2l0aG91dCBhbnkgZXhwbGFuYXRpb25zLmA7XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIC8vIENhbGwgdGhlIEFJIHNlcnZpY2UgdG8gZ2V0IGZpeGVkIGNvZGVcbiAgICAgICAgICAgIGNvbnN0IGZpeGVkQ29udGVudCA9IGF3YWl0IGNhbGxBSVNlcnZpY2UocHJvbXB0LCBxdWlldCk7XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIGlmKGZpeGVkQ29udGVudCAmJiBmaXhlZENvbnRlbnQgIT09IGZpbGVDb250ZW50KSB7XG4gICAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoZmlsZVBhdGgsIGZpeGVkQ29udGVudCwgJ3V0ZjgnKTtcbiAgICAgICAgICAgICAgbG9nKGBBcHBsaWVkIEFJIGZpeGVzIHRvICR7ZmlsZVBhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaChlcnJvcikge1xuICAgICAgICAgICAgbG9nKGBFcnJvciBhcHBseWluZyBBSSBmaXhlcyB0byAke2ZpbGVQYXRofTogJHtlcnJvci5tZXNzYWdlfWAsICdlcnJvcicsIHF1aWV0KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBzcGlubmVyLnN1Y2NlZWQoJ0FJIGZpeGVzIGFwcGxpZWQgc3VjY2Vzc2Z1bGx5IScpO1xuICB9IGNhdGNoKGVycm9yKSB7XG4gICAgc3Bpbm5lci5mYWlsKCdGYWlsZWQgdG8gYXBwbHkgQUkgZml4ZXMnKTtcbiAgICBsb2coYEVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCwgJ2Vycm9yJywgcXVpZXQpO1xuICAgIGlmKCFxdWlldCkge1xuICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIEFwcGx5IGRpcmVjdCBmaXhlcyB0byBjb21tb24gRVNMaW50IGlzc3Vlc1xuICovXG5jb25zdCBhcHBseURpcmVjdEZpeGVzID0gYXN5bmMgKGZpbGVQYXRoOiBzdHJpbmcsIHF1aWV0OiBib29sZWFuKTogUHJvbWlzZTxib29sZWFuPiA9PiB7XG4gIGxldCB3YXNNb2RpZmllZCA9IGZhbHNlO1xuICBcbiAgdHJ5IHtcbiAgICAvLyBSZWFkIGZpbGUgY29udGVudFxuICAgIGNvbnN0IGZpbGVDb250ZW50ID0gcmVhZEZpbGVTeW5jKGZpbGVQYXRoLCAndXRmOCcpO1xuICAgIGxldCBuZXdDb250ZW50ID0gZmlsZUNvbnRlbnQ7XG4gICAgXG4gICAgLy8gRml4IGlzc3VlcyBiYXNlZCBvbiBmaWxlbmFtZVxuICAgIGlmKGZpbGVQYXRoLmluY2x1ZGVzKCdhaVNlcnZpY2UudHMnKSkge1xuICAgICAgbG9nKCdGaXhpbmcgaXNzdWVzIGluIGFpU2VydmljZS50cycsICdpbmZvJywgcXVpZXQpO1xuICAgICAgXG4gICAgICAvLyBGaXggdGhlIG9yZGVyIG9mIGtleXMgaW4gaGVhZGVycyBvYmplY3RzXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvblxcL2pzb24nLFxccyonQXV0aG9yaXphdGlvbic6IGBCZWFyZXIvZyxcbiAgICAgICAgJ1xcJ0F1dGhvcml6YXRpb25cXCc6IGBCZWFyZXJcXCcsIFxcJ0NvbnRlbnQtVHlwZVxcJzogXFwnYXBwbGljYXRpb24vanNvblxcJydcbiAgICAgICk7XG4gICAgICBcbiAgICAgIC8vIEZpeCBtZXRob2QgYW5kIGhlYWRlcnMgb3JkZXJcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9oZWFkZXJzOiB7KFtefV0qKX0sXFxzKm1ldGhvZDogJ1BPU1QnL2csXG4gICAgICAgICdtZXRob2Q6IFxcJ1BPU1RcXCcsXFxuICAgICAgaGVhZGVyczogeyQxfSdcbiAgICAgICk7XG4gICAgICBcbiAgICAgIC8vIEZpeCByb2xlIGFuZCBjb250ZW50IG9yZGVyXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAve3JvbGU6ICdzeXN0ZW0nLCBjb250ZW50Oi9nLFxuICAgICAgICAne2NvbnRlbnQ6LCByb2xlOiBcXCdzeXN0ZW1cXCcsJ1xuICAgICAgKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC97cm9sZTogJ3VzZXInLCBjb250ZW50Oi9nLFxuICAgICAgICAne2NvbnRlbnQ6LCByb2xlOiBcXCd1c2VyXFwnLCdcbiAgICAgICk7XG4gICAgICBcbiAgICAgIC8vIEZpeCBuYW1pbmcgY29udmVudGlvbiBpc3N1ZXMgLSBwYXJhbWV0ZXIgbmFtZXMgd2l0aCBsZWFkaW5nIHVuZGVyc2NvcmVzXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvXFwoKFteKV0qPylfKFthLXpBLVowLTldKykoXFxzKjpbXildKilcXCkvZyxcbiAgICAgICAgJygkMSQyJDMpJ1xuICAgICAgKTtcbiAgICAgIFxuICAgICAgLy8gUmVwbGFjZSBjb25zb2xlLmxvZyBzdGF0ZW1lbnRzXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKC9jb25zb2xlXFwubG9nXFwoL2csICdsb2coJyk7XG4gICAgICBcbiAgICAgIC8vIEFkZCBsb2cgaW1wb3J0IGlmIG5lZWRlZFxuICAgICAgaWYoIW5ld0NvbnRlbnQuaW5jbHVkZXMoJ2ltcG9ydCB7bG9nfScpICYmIG5ld0NvbnRlbnQuaW5jbHVkZXMoJ2xvZygnKSkge1xuICAgICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAgIC9pbXBvcnQgeyhbXn1dKil9IGZyb20gJyguKiknOy8sXG4gICAgICAgICAgJ2ltcG9ydCB7JDF9IGZyb20gXFwnJDJcXCc7XFxuaW1wb3J0IHtsb2d9IGZyb20gXFwnLi9sb2cuanNcXCc7J1xuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICAvLyBGaXggcmVhY3RTaGltLnRzIG5hbWluZyBjb252ZW50aW9uc1xuICAgIGlmKGZpbGVQYXRoLmluY2x1ZGVzKCdyZWFjdFNoaW0udHMnKSkge1xuICAgICAgbG9nKCdGaXhpbmcgbmFtaW5nLWNvbnZlbnRpb24gaXNzdWVzIGluIHJlYWN0U2hpbS50cycsICdpbmZvJywgcXVpZXQpO1xuICAgICAgXG4gICAgICAvLyBGaXggUmVhY3QgaW1wb3J0IG5hbWluZ1xuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgJ2ltcG9ydCAqIGFzIFJlYWN0IGZyb20nLFxuICAgICAgICAnaW1wb3J0ICogYXMgcmVhY3QgZnJvbSdcbiAgICAgICk7XG4gICAgICBcbiAgICAgIC8vIEZpeCBSZWFjdCB1c2FnZVxuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZSgvUmVhY3RcXC4vZywgJ3JlYWN0LicpO1xuICAgIH1cbiAgICBcbiAgICAvLyBGaXggY2hhbmdlbG9nLnRzIGlzc3Vlc1xuICAgIGlmKGZpbGVQYXRoLmluY2x1ZGVzKCdjaGFuZ2Vsb2cudHMnKSkge1xuICAgICAgbG9nKCdGaXhpbmcgaXNzdWVzIGluIGNoYW5nZWxvZy50cycsICdpbmZvJywgcXVpZXQpO1xuICAgICAgXG4gICAgICAvLyBGaXggbm8tcGx1c3BsdXNcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoLyhcXHcrKVxcK1xcKy9nLCAnJDEgKz0gMScpO1xuICAgICAgXG4gICAgICAvLyBGaXggdW5uZWNlc3NhcnkgZXNjYXBlIGNoYXJhY3RlcnNcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoL1xcXFxcXCQvZywgJyQnKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoL1xcXFxcXC4vZywgJy4nKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoL1xcXFxcXCovZywgJyonKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoL1xcXFw6L2csICc6Jyk7XG4gICAgfVxuICAgIFxuICAgIC8vIEZpeCBhcHAudHMgaXNzdWVzXG4gICAgaWYoZmlsZVBhdGguaW5jbHVkZXMoJ2FwcC50cycpKSB7XG4gICAgICBsb2coJ0ZpeGluZyBpc3N1ZXMgaW4gYXBwLnRzJywgJ2luZm8nLCBxdWlldCk7XG4gICAgICBcbiAgICAgIC8vIEZpeCBjb25zb2xlLmxvZ1xuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZSgvY29uc29sZVxcLmxvZ1xcKC9nLCAnbG9nKCcpO1xuICAgICAgXG4gICAgICAvLyBBZGQgbG9nIGltcG9ydCBpZiBuZWVkZWRcbiAgICAgIGlmKCFuZXdDb250ZW50LmluY2x1ZGVzKCdpbXBvcnQge2xvZ30nKSAmJiBuZXdDb250ZW50LmluY2x1ZGVzKCdsb2coJykpIHtcbiAgICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgICAvaW1wb3J0IGJveGVuIGZyb20gJ2JveGVuJzsvLFxuICAgICAgICAgICdpbXBvcnQgYm94ZW4gZnJvbSBcXCdib3hlblxcJztcXG5pbXBvcnQge2xvZ30gZnJvbSBcXCcuL2xvZy5qc1xcJzsnXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIEZpeCB1bm5lY2Vzc2FyeSBlc2NhcGUgY2hhcmFjdGVyc1xuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZSgvXFxcXFxcLy9nLCAnLycpO1xuICAgIH1cbiAgICBcbiAgICAvLyBGaXggYXV0b2ZpeC5qcyBpc3N1ZXNcbiAgICBpZihmaWxlUGF0aC5pbmNsdWRlcygnYXV0b2ZpeC5qcycpKSB7XG4gICAgICBsb2coJ0ZpeGluZyBpc3N1ZXMgaW4gYXV0b2ZpeC5qcycsICdpbmZvJywgcXVpZXQpO1xuICAgICAgXG4gICAgICAvLyBGaXggaW1wb3J0IHN0eWxlXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvaW1wb3J0IHsoW159XSopfSBmcm9tICdwYXRoJztbXFxzXFxuXSppbXBvcnQgeyhbXn1dKil9IGZyb20gJ3BhdGgnOy8sXG4gICAgICAgICdpbXBvcnQgeyQxLCAkMn0gZnJvbSBcXCdwYXRoXFwnOydcbiAgICAgICk7XG4gICAgICBcbiAgICAgIC8vIEZpeCB2YXJpYWJsZSBuYW1pbmcgY29udmVudGlvblxuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgL19fZmlsZW5hbWUvZyxcbiAgICAgICAgJ2N1cnJlbnRGaWxlbmFtZSdcbiAgICAgICk7XG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvX19kaXJuYW1lL2csXG4gICAgICAgICdjdXJyZW50RGlybmFtZSdcbiAgICAgICk7XG4gICAgICBcbiAgICAgIC8vIEZpeCBuZXN0ZWQgdGVybmFyeVxuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgL2NvbnN0IHByZWZpeCA9IHR5cGUgPT09ICdlcnJvcicgXFw/ICdcdTI3NEMgJyA6IHR5cGUgPT09ICdzdWNjZXNzJyBcXD8gJ1x1MjcwNSAnIDogJ1x1MjEzOVx1RkUwRiAnOy8sXG4gICAgICAgIGBsZXQgcHJlZml4ID0gJ1x1MjEzOVx1RkUwRiAnO1xcbmlmKHR5cGUgPT09ICdlcnJvcicpIHtcXG4gIHByZWZpeCA9ICdcdTI3NEMgJztcXG59IGVsc2UgaWYodHlwZSA9PT0gJ3N1Y2Nlc3MnKSB7XFxuICBwcmVmaXggPSAnXHUyNzA1ICc7XFxufWBcbiAgICAgICk7XG4gICAgICBcbiAgICAgIC8vIEZpeCBmdW5jdGlvbiBzdHlsZVxuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgL2FzeW5jIGZ1bmN0aW9uIHJ1bkVzbGludEZpeFxcKFxcKS9nLFxuICAgICAgICAnY29uc3QgcnVuRXNsaW50Rml4ID0gYXN5bmMgKCknXG4gICAgICApO1xuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgL2FzeW5jIGZ1bmN0aW9uIGdldEZpbGVzV2l0aEVycm9yc1xcKFxcKS9nLFxuICAgICAgICAnY29uc3QgZ2V0RmlsZXNXaXRoRXJyb3JzID0gYXN5bmMgKCknXG4gICAgICApO1xuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgL2FzeW5jIGZ1bmN0aW9uIGlzQ3Vyc29yQXZhaWxhYmxlXFwoXFwpL2csXG4gICAgICAgICdjb25zdCBpc0N1cnNvckF2YWlsYWJsZSA9IGFzeW5jICgpJ1xuICAgICAgKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9hc3luYyBmdW5jdGlvbiBmaXhGaWxlV2l0aEN1cnNvckFJXFwoZmlsZVBhdGhcXCkvZyxcbiAgICAgICAgJ2NvbnN0IGZpeEZpbGVXaXRoQ3Vyc29yQUkgPSBhc3luYyAoZmlsZVBhdGgpJ1xuICAgICAgKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9hc3luYyBmdW5jdGlvbiBtYWluXFwoXFwpL2csXG4gICAgICAgICdjb25zdCBtYWluID0gYXN5bmMgKCknXG4gICAgICApO1xuICAgICAgXG4gICAgICAvLyBGaXggdW51c2VkIHZhcmlhYmxlc1xuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgL2ltcG9ydCB7ZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jfS9nLFxuICAgICAgICAnaW1wb3J0IHt3cml0ZUZpbGVTeW5jfSdcbiAgICAgICk7XG4gICAgICBcbiAgICAgIC8vIEZpeCBjb25zb2xlLmxvZ1xuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgL2NvbnNvbGVcXC5sb2dcXChgXFwke3ByZWZpeH0gXFwke21lc3NhZ2V9YFxcKTsvZyxcbiAgICAgICAgJ3Byb2Nlc3Muc3Rkb3V0LndyaXRlKGAke3ByZWZpeH0gJHttZXNzYWdlfVxcXFxuYCk7J1xuICAgICAgKTtcbiAgICAgIFxuICAgICAgLy8gRml4IHVudXNlZCBlcnJvciB2YXJpYWJsZXNcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC99IGNhdGNoXFwoZXJyb3JcXCkge1tcXHNcXG5dKlxcL1xcLyBJZ25vcmUgY2xlYW51cCBlcnJvcnMvZyxcbiAgICAgICAgJ30gY2F0Y2goXykge1xcbiAgICAgIC8vIElnbm9yZSBjbGVhbnVwIGVycm9ycydcbiAgICAgICk7XG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvfSBjYXRjaFxcKGVycm9yXFwpIHtbXFxzXFxuXSpsb2dcXCgvZyxcbiAgICAgICAgJ30gY2F0Y2goZXJyKSB7XFxuICAgIGxvZygnXG4gICAgICApO1xuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgL30gY2F0Y2hcXChlcnJvclxcKSB7W1xcc1xcbl0qcmV0dXJuIGZhbHNlOy9nLFxuICAgICAgICAnfSBjYXRjaChfKSB7XFxuICAgIHJldHVybiBmYWxzZTsnXG4gICAgICApO1xuICAgICAgXG4gICAgICAvLyBGaXggYXdhaXQgaW4gbG9vcFxuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgL2ZvclxcKGNvbnN0IGZpbGVQYXRoIG9mIGZpbGVzV2l0aEVycm9yc1xcKSB7W1xcc1xcbl0qY29uc3Qgc3VjY2VzcyA9IGF3YWl0IGZpeEZpbGVXaXRoQ3Vyc29yQUlcXChmaWxlUGF0aFxcKTsvZyxcbiAgICAgICAgJ2NvbnN0IGZpeFJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbChmaWxlc1dpdGhFcnJvcnMubWFwKGZpbGVQYXRoID0+IGZpeEZpbGVXaXRoQ3Vyc29yQUkoZmlsZVBhdGgpKSk7XFxuZm9yKGNvbnN0IHN1Y2Nlc3Mgb2YgZml4UmVzdWx0cykgeydcbiAgICAgICk7XG4gICAgICBcbiAgICAgIC8vIEZpeCBpbmNyZW1lbnRcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9maXhlZENvdW50XFwrXFwrOy9nLFxuICAgICAgICAnZml4ZWRDb3VudCArPSAxOydcbiAgICAgICk7XG4gICAgfVxuICAgIFxuICAgIC8vIFdyaXRlIHRoZSBtb2RpZmllZCBjb250ZW50IGJhY2sgaWYgY2hhbmdlcyB3ZXJlIG1hZGVcbiAgICBpZihuZXdDb250ZW50ICE9PSBmaWxlQ29udGVudCkge1xuICAgICAgd3JpdGVGaWxlU3luYyhmaWxlUGF0aCwgbmV3Q29udGVudCwgJ3V0ZjgnKTtcbiAgICAgIGxvZyhgRml4ZWQgaXNzdWVzIGluICR7ZmlsZVBhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICB3YXNNb2RpZmllZCA9IHRydWU7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiB3YXNNb2RpZmllZDtcbiAgfSBjYXRjaChlcnJvcikge1xuICAgIGxvZyhgRXJyb3IgYXBwbHlpbmcgZGlyZWN0IGZpeGVzIHRvICR7ZmlsZVBhdGh9OiAke2Vycm9yLm1lc3NhZ2V9YCwgJ2Vycm9yJywgcXVpZXQpO1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufTtcblxuLyoqXG4gKiBDaGVjayBmb3IgQUkgY29uZmlndXJhdGlvbiBpbiBtYWluIGxleC5jb25maWcuanMgZmlsZVxuICovXG5jb25zdCBsb2FkQUlDb25maWcgPSBhc3luYyAoY3dkOiBzdHJpbmcsIHF1aWV0OiBib29sZWFuKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gIGNvbnN0IGxleENvbmZpZ1BhdGggPSBwYXRoUmVzb2x2ZShjd2QsICdsZXguY29uZmlnLmpzJyk7XG4gIGNvbnN0IGxleENvbmZpZ0V4aXN0cyA9IGV4aXN0c1N5bmMobGV4Q29uZmlnUGF0aCk7XG5cbiAgaWYobGV4Q29uZmlnRXhpc3RzKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGxleENvbmZpZyA9IGF3YWl0IGltcG9ydChsZXhDb25maWdQYXRoKTtcbiAgICAgIGlmKGxleENvbmZpZy5kZWZhdWx0ICYmIGxleENvbmZpZy5kZWZhdWx0LmFpKSB7XG4gICAgICAgIGxvZygnRm91bmQgQUkgY29uZmlndXJhdGlvbiBpbiBsZXguY29uZmlnLmpzLCBhcHBseWluZyBzZXR0aW5ncy4uLicsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICAvLyBVcGRhdGUgdGhlIEFJIGNvbmZpZ3VyYXRpb24gaW4gTGV4Q29uZmlnXG4gICAgICAgIExleENvbmZpZy5jb25maWcuYWkgPSB7Li4uTGV4Q29uZmlnLmNvbmZpZy5haSwgLi4ubGV4Q29uZmlnLmRlZmF1bHQuYWl9O1xuICAgICAgfVxuICAgIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAgIGxvZyhgRXJyb3IgbG9hZGluZyBBSSBjb25maWd1cmF0aW9uIGZyb20gbGV4LmNvbmZpZy5qczogJHtlcnJvci5tZXNzYWdlfWAsICd3YXJuJywgcXVpZXQpO1xuICAgIH1cbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IGxpbnQgPSBhc3luYyAoY21kOiBMaW50T3B0aW9ucywgY2FsbGJhY2s6IExpbnRDYWxsYmFjayA9IHByb2Nlc3MuZXhpdCk6IFByb21pc2U8bnVtYmVyPiA9PiB7XG4gIGNvbnN0IHtcbiAgICBjbGlOYW1lID0gJ0xleCcsXG4gICAgZml4ID0gZmFsc2UsXG4gICAgZGVidWcgPSBmYWxzZSxcbiAgICBxdWlldCA9IGZhbHNlLFxuICAgIGNvbmZpZyA9IG51bGxcbiAgfSA9IGNtZDtcblxuICBsb2coYCR7Y2xpTmFtZX0gbGludGluZy4uLmAsICdpbmZvJywgcXVpZXQpO1xuXG4gIGNvbnN0IGN3ZCA9IHByb2Nlc3MuY3dkKCk7XG4gIGNvbnN0IHNwaW5uZXIgPSBjcmVhdGVTcGlubmVyKHF1aWV0KTtcblxuICAvLyBMb2FkIEFJIGNvbmZpZ3VyYXRpb24gaWYgYXZhaWxhYmxlXG4gIGF3YWl0IGxvYWRBSUNvbmZpZyhjd2QsIHF1aWV0KTtcblxuICAvLyBUcmFjayBpZiB3ZSBuZWVkIHRvIHJlc3RvcmUgYW4gb3JpZ2luYWwgY29uZmlnXG4gIGxldCBvcmlnaW5hbENvbmZpZzogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIGxldCB0ZW1wQ29uZmlnUGF0aDogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG5cbiAgdHJ5IHtcbiAgICAvLyBEZXRlY3QgVHlwZVNjcmlwdCBkaXJlY3RseVxuICAgIGNvbnN0IHVzZVR5cGVzY3JpcHQgPSBkZXRlY3RUeXBlU2NyaXB0KGN3ZCk7XG4gICAgbG9nKGBUeXBlU2NyaXB0ICR7dXNlVHlwZXNjcmlwdCA/ICdkZXRlY3RlZCcgOiAnbm90IGRldGVjdGVkJ30gZnJvbSB0c2NvbmZpZy5qc29uYCwgJ2luZm8nLCBxdWlldCk7XG5cbiAgICAvLyBFbnN1cmUgcGFja2FnZS5qc29uIGhhcyB0eXBlOiBtb2R1bGUgZm9yIEVTTSBzdXBwb3J0XG4gICAgZW5zdXJlTW9kdWxlVHlwZShjd2QpO1xuXG4gICAgLy8gSW5zdGFsbCBuZWNlc3NhcnkgZGVwZW5kZW5jaWVzXG4gICAgYXdhaXQgaW5zdGFsbERlcGVuZGVuY2llcyhjd2QsIHVzZVR5cGVzY3JpcHQsIHF1aWV0KTtcblxuICAgIC8vIENoZWNrIGZvciBFU0xpbnQgY29uZmlndXJhdGlvbiBmaWxlc1xuICAgIGNvbnN0IHByb2plY3RDb25maWdQYXRoID0gcGF0aFJlc29sdmUoY3dkLCAnZXNsaW50LmNvbmZpZy5qcycpO1xuICAgIGNvbnN0IGhhc0VzbGludENvbmZpZyA9IGV4aXN0c1N5bmMocHJvamVjdENvbmZpZ1BhdGgpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGV4aXN0c1N5bmMocGF0aFJlc29sdmUoY3dkLCAnLmVzbGludHJjLmpzJykpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGV4aXN0c1N5bmMocGF0aFJlc29sdmUoY3dkLCAnLmVzbGludHJjLmpzb24nKSkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXhpc3RzU3luYyhwYXRoUmVzb2x2ZShjd2QsICcuZXNsaW50cmMueW1sJykpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGV4aXN0c1N5bmMocGF0aFJlc29sdmUoY3dkLCAnLmVzbGludHJjLnlhbWwnKSkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXhpc3RzU3luYyhwYXRoUmVzb2x2ZShjd2QsICcuZXNsaW50cmMnKSk7XG5cbiAgICAvLyBSZW1vdmUgYW55IGV4aXN0aW5nIC5lc2xpbnRyYy5qc29uIGZpbGUgdG8gYXZvaWQgY29uZmxpY3RzIHdpdGggZXNsaW50LmNvbmZpZy5qc1xuICAgIGlmKGV4aXN0c1N5bmMocGF0aFJlc29sdmUoY3dkLCAnLmVzbGludHJjLmpzb24nKSkpIHtcbiAgICAgIHVubGlua1N5bmMocGF0aFJlc29sdmUoY3dkLCAnLmVzbGludHJjLmpzb24nKSk7XG4gICAgfVxuXG4gICAgLy8gVHJ5IHRvIGZpbmQgTGV4J3MgRVNMaW50IGNvbmZpZyBpZiBuZWVkZWRcbiAgICBsZXQgbGV4Q29uZmlnUGF0aCA9ICcnO1xuICAgIGxldCBzaG91bGRDcmVhdGVUZW1wQ29uZmlnID0gZmFsc2U7XG5cbiAgICBpZighaGFzRXNsaW50Q29uZmlnKSB7XG4gICAgICAvLyBUcnkgZGlmZmVyZW50IHBvdGVudGlhbCBsb2NhdGlvbnMgZm9yIHRoZSBMZXggY29uZmlnXG4gICAgICBjb25zdCBwb3NzaWJsZVBhdGhzID0gW1xuICAgICAgICAvLyBGcm9tIHNyYy9jb21tYW5kcy9saW50L2xpbnQudHMgdG8gcm9vdFxuICAgICAgICBwYXRoUmVzb2x2ZShfX2Rpcm5hbWUsICcuLi8uLi8uLi8uLi9lc2xpbnQuY29uZmlnLmpzJyksXG4gICAgICAgIC8vIEZyb20gcGFja2FnZXMvbGV4L3NyYy9jb21tYW5kcy9saW50L2xpbnQudHMgdG8gcGFja2FnZXMvbGV4XG4gICAgICAgIHBhdGhSZXNvbHZlKF9fZGlybmFtZSwgJy4uLy4uLy4uL2VzbGludC5jb25maWcuanMnKSxcbiAgICAgICAgLy8gRnJvbSBwYWNrYWdlcy9sZXgvc3JjL2NvbW1hbmRzL2xpbnQvbGludC50cyB0byByb290XG4gICAgICAgIHBhdGhSZXNvbHZlKF9fZGlybmFtZSwgJy4uLy4uLy4uLy4uLy4uL2VzbGludC5jb25maWcuanMnKSxcbiAgICAgICAgLy8gQWJzb2x1dGUgcGF0aCBpZiBMZXggaXMgaW5zdGFsbGVkIGdsb2JhbGx5XG4gICAgICAgIHBhdGhSZXNvbHZlKHByb2Nlc3MuZW52LkxFWF9IT01FIHx8ICcvdXNyL2xvY2FsL2xpYi9ub2RlX21vZHVsZXMvQG5sYWJzL2xleCcsICdlc2xpbnQuY29uZmlnLmpzJylcbiAgICAgIF07XG5cbiAgICAgIC8vIEZpbmQgdGhlIGZpcnN0IGV4aXN0aW5nIGNvbmZpZ1xuICAgICAgZm9yKGNvbnN0IHBhdGggb2YgcG9zc2libGVQYXRocykge1xuICAgICAgICBpZihleGlzdHNTeW5jKHBhdGgpKSB7XG4gICAgICAgICAgbGV4Q29uZmlnUGF0aCA9IHBhdGg7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYoZGVidWcpIHtcbiAgICAgICAgbG9nKGBDdXJyZW50IGRpcmVjdG9yeTogJHtfX2Rpcm5hbWV9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgIGxvZyhgUHJvamVjdCBjb25maWcgcGF0aDogJHtwcm9qZWN0Q29uZmlnUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgICAgbG9nKGBQcm9qZWN0IGNvbmZpZyBleGlzdHM6ICR7aGFzRXNsaW50Q29uZmlnfWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICBsb2coYEZvdW5kIExleCBjb25maWc6ICR7bGV4Q29uZmlnUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgICAgbG9nKGBMZXggY29uZmlnIGV4aXN0czogJHshIWxleENvbmZpZ1BhdGggJiYgZXhpc3RzU3luYyhsZXhDb25maWdQYXRoKX1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgIH1cblxuICAgICAgLy8gSWYgd2UgZm91bmQgTGV4J3MgY29uZmlnLCB1c2UgaXRcbiAgICAgIGlmKGxleENvbmZpZ1BhdGggJiYgZXhpc3RzU3luYyhsZXhDb25maWdQYXRoKSkge1xuICAgICAgICBsb2coJ05vIEVTTGludCBjb25maWd1cmF0aW9uIGZvdW5kIGluIHByb2plY3QuIFVzaW5nIExleFxcJ3MgZGVmYXVsdCBjb25maWd1cmF0aW9uLicsICdpbmZvJywgcXVpZXQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gT3RoZXJ3aXNlLCB3ZSBuZWVkIHRvIGNyZWF0ZSBhIHRlbXBvcmFyeSBjb25maWdcbiAgICAgICAgc2hvdWxkQ3JlYXRlVGVtcENvbmZpZyA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gSWYgdXNlciBzcGVjaWZpZWQgYSBjb25maWcgZmlsZSwgdXNlIHRoYXRcbiAgICBpZihjb25maWcpIHtcbiAgICAgIGNvbnN0IHVzZXJDb25maWdQYXRoID0gcGF0aFJlc29sdmUoY3dkLCBjb25maWcpO1xuICAgICAgaWYoZXhpc3RzU3luYyh1c2VyQ29uZmlnUGF0aCkpIHtcbiAgICAgICAgbG9nKGBVc2luZyBzcGVjaWZpZWQgRVNMaW50IGNvbmZpZ3VyYXRpb246ICR7Y29uZmlnfWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICAvLyBVc2VyLXNwZWNpZmllZCBjb25maWcgdGFrZXMgcHJlY2VkZW5jZVxuICAgICAgICBzaG91bGRDcmVhdGVUZW1wQ29uZmlnID0gZmFsc2U7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsb2coYFNwZWNpZmllZCBFU0xpbnQgY29uZmlndXJhdGlvbiBub3QgZm91bmQ6ICR7Y29uZmlnfS4gVXNpbmcgTGV4J3MgZGVmYXVsdCBjb25maWd1cmF0aW9uLmAsICd3YXJuJywgcXVpZXQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENyZWF0ZSBhIHRlbXBvcmFyeSBjb25maWcgaWYgbmVlZGVkXG4gICAgaWYoc2hvdWxkQ3JlYXRlVGVtcENvbmZpZykge1xuICAgICAgbG9nKCdObyBFU0xpbnQgY29uZmlndXJhdGlvbiBmb3VuZC4gQ3JlYXRpbmcgYSB0ZW1wb3JhcnkgY29uZmlndXJhdGlvbi4uLicsICdpbmZvJywgcXVpZXQpO1xuICAgICAgY29uc3QgY29uZmlnUmVzdWx0ID0gY3JlYXRlRGVmYXVsdEVTTGludENvbmZpZyh1c2VUeXBlc2NyaXB0LCBjd2QpO1xuICAgICAgdGVtcENvbmZpZ1BhdGggPSBjb25maWdSZXN1bHQuY29uZmlnUGF0aDtcbiAgICAgIG9yaWdpbmFsQ29uZmlnID0gY29uZmlnUmVzdWx0Lm9yaWdpbmFsQ29uZmlnO1xuICAgIH1cblxuICAgIC8vIENhcHR1cmUgdGhlIEVTTGludCBvdXRwdXQgZm9yIEFJIGZpeCBpZiBuZWVkZWRcbiAgICBsZXQgZXNsaW50T3V0cHV0ID0gJyc7XG4gICAgY29uc3QgY2FwdHVyZU91dHB1dCA9IChvdXRwdXQ6IHN0cmluZykgPT4ge1xuICAgICAgZXNsaW50T3V0cHV0ICs9IGAke291dHB1dH1cXG5gO1xuICAgIH07XG5cbiAgICAvLyBBbHdheXMgcnVuIEVTTGludCB3aXRoIC0tZml4IGZpcnN0IHRvIGFwcGx5IGJ1aWx0LWluIGZpeGVzXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcnVuRXNsaW50V2l0aExleChjd2QsIHF1aWV0LCBjbGlOYW1lLCB0cnVlLCBkZWJ1ZywgdXNlVHlwZXNjcmlwdCwgY2FwdHVyZU91dHB1dCk7XG5cbiAgICAvLyBJZiB0aGVyZSBhcmUgc3RpbGwgZXJyb3JzIGFuZCBmaXggZmxhZyBpcyBzZXQsIHRyeSB0byBmaXggdGhlbSB3aXRoIEFJXG4gICAgaWYocmVzdWx0ICE9PSAwICYmIGZpeCkge1xuICAgICAgLy8gQ2hlY2sgaWYgQUkgaXMgY29uZmlndXJlZFxuICAgICAgY29uc3QgYWlDb25maWd1cmVkID0gTGV4Q29uZmlnLmNvbmZpZy5haT8ucHJvdmlkZXIgJiYgTGV4Q29uZmlnLmNvbmZpZy5haS5wcm92aWRlciAhPT0gJ25vbmUnO1xuXG4gICAgICBpZihhaUNvbmZpZ3VyZWQpIHtcbiAgICAgICAgbG9nKCdBcHBseWluZyBBSSBmaXhlcyB0byByZW1haW5pbmcgaXNzdWVzLi4uJywgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgIGF3YWl0IGFwcGx5QUlGaXgoY3dkLCBlc2xpbnRPdXRwdXQsIHF1aWV0KTtcblxuICAgICAgICAvLyBSdW4gRVNMaW50IGFnYWluIHRvIGNoZWNrIGlmIGFsbCBpc3N1ZXMgYXJlIGZpeGVkXG4gICAgICAgIGNvbnN0IGFmdGVyRml4UmVzdWx0ID0gYXdhaXQgcnVuRXNsaW50V2l0aExleChjd2QsIHF1aWV0LCBjbGlOYW1lLCBmYWxzZSwgZGVidWcsIHVzZVR5cGVzY3JpcHQpO1xuXG4gICAgICAgIC8vIFJldHVybiB0aGUgcmVzdWx0IG9mIHRoZSBzZWNvbmQgcnVuXG4gICAgICAgIGNhbGxiYWNrKGFmdGVyRml4UmVzdWx0KTtcbiAgICAgICAgcmV0dXJuIGFmdGVyRml4UmVzdWx0O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gSWYgQUkgaXMgbm90IGNvbmZpZ3VyZWQsIHN1Z2dlc3QgY29uZmlndXJpbmcgaXRcbiAgICAgICAgbG9nKCdFU0xpbnQgY291bGQgbm90IGZpeCBhbGwgaXNzdWVzIGF1dG9tYXRpY2FsbHkuJywgJ3dhcm4nLCBxdWlldCk7XG4gICAgICAgIGxvZygnVG8gZW5hYmxlIEFJLXBvd2VyZWQgZml4ZXMsIGFkZCBBSSBjb25maWd1cmF0aW9uIHRvIHlvdXIgbGV4LmNvbmZpZy5qczonLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgICAgbG9nKGBcbi8vIEluIGxleC5jb25maWcuanNcbmV4cG9ydCBkZWZhdWx0IHtcbiAgLy8gWW91ciBleGlzdGluZyBjb25maWdcbiAgYWk6IHtcbiAgICBwcm92aWRlcjogJ2N1cnNvcicgLy8gb3IgJ29wZW5haScsICdhbnRocm9waWMnLCBldGMuXG4gICAgLy8gQWRkaXRpb25hbCBwcm92aWRlci1zcGVjaWZpYyBzZXR0aW5nc1xuICB9XG59O2AsICdpbmZvJywgcXVpZXQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNhbGxiYWNrKHJlc3VsdCk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfSBjYXRjaChlcnJvcikge1xuICAgIC8vIERpc3BsYXkgZXJyb3IgbWVzc2FnZVxuICAgIGxvZyhgXFxuJHtjbGlOYW1lfSBFcnJvcjogJHtlcnJvci5tZXNzYWdlfWAsICdlcnJvcicsIHF1aWV0KTtcbiAgICBzcGlubmVyLmZhaWwoJ0xpbnRpbmcgZmFpbGVkIScpO1xuICAgIGNhbGxiYWNrKDEpO1xuICAgIHJldHVybiAxO1xuICB9IGZpbmFsbHkge1xuICAgIC8vIFJlc3RvcmUgdGhlIG9yaWdpbmFsIGNvbmZpZyBpZiB3ZSBjcmVhdGVkIGEgdGVtcG9yYXJ5IG9uZVxuICAgIGlmKHRlbXBDb25maWdQYXRoICYmIG9yaWdpbmFsQ29uZmlnKSB7XG4gICAgICB0cnkge1xuICAgICAgICB3cml0ZUZpbGVTeW5jKHRlbXBDb25maWdQYXRoLCBvcmlnaW5hbENvbmZpZywgJ3V0ZjgnKTtcbiAgICAgIH0gY2F0Y2goX2Vycm9yKSB7XG4gICAgICAgIC8vIElnbm9yZSBlcnJvcnNcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYodGVtcENvbmZpZ1BhdGgpIHtcbiAgICAgIC8vIFJlbW92ZSB0aGUgdGVtcG9yYXJ5IGNvbmZpZyBpZiB0aGVyZSB3YXMgbm8gb3JpZ2luYWxcbiAgICAgIHRyeSB7XG4gICAgICAgIHVubGlua1N5bmModGVtcENvbmZpZ1BhdGgpO1xuICAgICAgfSBjYXRjaChfZXJyb3IpIHtcbiAgICAgICAgLy8gSWdub3JlIGVycm9yc1xuICAgICAgfVxuICAgIH1cbiAgfVxufTsiXSwKICAibWFwcGluZ3MiOiAiQUFJQSxTQUFRLGFBQVk7QUFDcEIsU0FBUSxZQUFZLGVBQWUsY0FBYyxrQkFBaUI7QUFDbEUsU0FBUSxXQUFXLGFBQWEsZUFBYztBQUM5QyxTQUFRLHFCQUFvQjtBQUU1QixTQUFRLGlCQUFnQjtBQUN4QixTQUFRLHFCQUFvQjtBQUM1QixTQUFRLFdBQVU7QUFHbEIsTUFBTSxhQUFhLGNBQWMsWUFBWSxHQUFHO0FBQ2hELE1BQU0sWUFBWSxRQUFRLFVBQVU7QUFrRHBDLE1BQU0sNEJBQTRCLENBQUMsZUFBd0IsUUFBOEI7QUFFdkYsUUFBTSxhQUFhLFlBQVksS0FBSyxrQkFBa0I7QUFHdEQsTUFBSSxpQkFBaUI7QUFDckIsTUFBRyxXQUFXLFVBQVUsR0FBRztBQUN6QixRQUFJO0FBQ0YsdUJBQWlCLGFBQWEsWUFBWSxNQUFNO0FBQUEsSUFDbEQsU0FBUSxRQUFRO0FBQUEsSUFFaEI7QUFBQSxFQUNGO0FBSUEsUUFBTSxnQkFBZ0I7QUFBQTtBQUFBLElBRXBCLFlBQVks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
|