@nlabs/lex 1.46.2 → 1.47.1
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.d.ts +79 -0
- package/dist/LexConfig.js +83 -15
- package/dist/commands/ai/ai.d.ts +17 -0
- package/dist/commands/ai/ai.js +303 -0
- package/dist/commands/ai/index.d.ts +8 -0
- package/dist/commands/ai/index.js +7 -0
- package/dist/commands/build/build.cli.test.d.ts +5 -0
- package/dist/commands/build/build.d.ts +18 -0
- package/dist/commands/build/build.integration.test.d.ts +1 -0
- package/dist/commands/build/build.js +400 -0
- package/dist/commands/build/build.options.test.d.ts +5 -0
- package/dist/commands/clean/clean.cli.test.d.ts +1 -0
- package/dist/commands/clean/clean.d.ts +7 -0
- package/dist/commands/clean/clean.integration.test.d.ts +1 -0
- package/dist/commands/clean/clean.js +31 -0
- package/dist/commands/clean/clean.options.test.d.ts +1 -0
- package/dist/commands/compile/compile.cli.test.d.ts +1 -0
- package/dist/commands/compile/compile.d.ts +2 -0
- package/dist/commands/compile/compile.integration.test.d.ts +1 -0
- package/dist/commands/compile/compile.js +239 -0
- package/dist/commands/compile/compile.options.test.d.ts +1 -0
- package/dist/commands/config/config.cli.test.d.ts +1 -0
- package/dist/commands/config/config.d.ts +7 -0
- package/dist/commands/config/config.integration.test.d.ts +1 -0
- package/dist/commands/config/config.js +43 -0
- package/dist/commands/config/config.options.test.d.ts +1 -0
- package/dist/commands/copy/copy.cli.test.d.ts +1 -0
- package/dist/commands/copy/copy.d.ts +6 -0
- package/dist/commands/copy/copy.integration.test.d.ts +1 -0
- package/dist/commands/copy/copy.js +38 -0
- package/dist/commands/copy/copy.options.test.d.ts +1 -0
- package/dist/commands/create/create.cli.test.d.ts +1 -0
- package/dist/commands/create/create.d.ts +8 -0
- package/dist/commands/create/create.integration.test.d.ts +1 -0
- package/dist/commands/create/create.js +124 -0
- package/dist/commands/create/create.options.test.d.ts +1 -0
- package/dist/commands/dev/dev.cli.test.d.ts +1 -0
- package/dist/commands/dev/dev.d.ts +11 -0
- package/dist/commands/dev/dev.integration.test.d.ts +1 -0
- package/dist/commands/dev/dev.js +70 -0
- package/dist/commands/dev/dev.options.test.d.ts +1 -0
- package/dist/commands/init/init.cli.test.d.ts +1 -0
- package/dist/commands/init/init.d.ts +9 -0
- package/dist/commands/init/init.integration.test.d.ts +1 -0
- package/dist/commands/init/init.js +93 -0
- package/dist/commands/init/init.options.test.d.ts +1 -0
- package/dist/commands/link/link.cli.test.d.ts +1 -0
- package/dist/commands/link/link.d.ts +6 -0
- package/dist/commands/link/link.integration.test.d.ts +1 -0
- package/dist/commands/link/link.js +15 -0
- package/dist/commands/link/link.options.test.d.ts +1 -0
- package/dist/commands/lint/autofix.d.ts +2 -0
- package/dist/commands/lint/lint.cli.test.d.ts +1 -0
- package/dist/commands/lint/lint.d.ts +39 -0
- package/dist/commands/lint/lint.integration.test.d.ts +1 -0
- package/dist/commands/lint/lint.js +820 -0
- package/dist/commands/lint/lint.options.test.d.ts +1 -0
- package/dist/commands/migrate/migrate.cli.test.d.ts +1 -0
- package/dist/commands/migrate/migrate.d.ts +7 -0
- package/dist/commands/migrate/migrate.integration.test.d.ts +1 -0
- package/dist/commands/migrate/migrate.js +37 -0
- package/dist/commands/migrate/migrate.options.test.d.ts +1 -0
- package/dist/commands/publish/publish.cli.test.d.ts +1 -0
- package/dist/commands/publish/publish.d.ts +12 -0
- package/dist/commands/publish/publish.integration.test.d.ts +1 -0
- package/dist/commands/publish/publish.js +104 -0
- package/dist/commands/publish/publish.options.test.d.ts +1 -0
- package/dist/commands/test/test.cli.test.d.ts +1 -0
- package/dist/commands/test/test.d.ts +50 -0
- package/dist/commands/test/test.integration.test.d.ts +1 -0
- package/dist/commands/test/test.js +327 -0
- package/dist/commands/test/test.options.test.d.ts +1 -0
- package/dist/commands/test/test.test.d.ts +1 -0
- package/dist/commands/update/update.cli.test.d.ts +1 -0
- package/dist/commands/update/update.d.ts +9 -0
- package/dist/commands/update/update.integration.test.d.ts +1 -0
- package/dist/commands/update/update.js +131 -0
- package/dist/commands/update/update.options.test.d.ts +1 -0
- package/dist/commands/upgrade/upgrade.cli.test.d.ts +1 -0
- package/dist/commands/upgrade/upgrade.d.ts +7 -0
- package/dist/commands/upgrade/upgrade.integration.test.d.ts +1 -0
- package/dist/commands/upgrade/upgrade.js +47 -0
- package/dist/commands/upgrade/upgrade.options.test.d.ts +1 -0
- package/dist/commands/versions/versions.cli.test.d.ts +1 -0
- package/dist/commands/versions/versions.d.ts +13 -0
- package/dist/commands/versions/versions.integration.test.d.ts +1 -0
- package/dist/commands/versions/versions.js +41 -0
- package/dist/commands/versions/versions.options.test.d.ts +1 -0
- package/dist/create/changelog.d.ts +6 -0
- package/dist/create/changelog.js +3 -3
- package/dist/index.d.ts +31 -0
- package/dist/index.js +35 -0
- package/dist/lex.d.ts +2 -0
- package/dist/lex.js +25 -22
- package/dist/types.d.ts +5 -0
- package/dist/types.js +1 -0
- package/dist/utils/aiService.d.ts +9 -0
- package/dist/utils/aiService.js +299 -0
- package/dist/utils/app.d.ts +41 -0
- package/dist/utils/app.js +53 -3
- package/dist/utils/file.d.ts +3 -0
- package/dist/utils/file.js +18 -3
- package/dist/utils/log.d.ts +1 -0
- package/dist/utils/log.js +2 -1
- package/dist/utils/reactShim.d.ts +2 -0
- package/dist/utils/reactShim.js +3 -3
- package/eslint.config.js +5 -0
- package/index.cjs +20 -0
- package/jest.config.cjs +31 -27
- package/jest.config.lex.d.ts +2 -0
- package/jest.config.lex.js +86 -38
- package/jest.setup.js +5 -0
- package/lex.config.js +50 -0
- package/package.json +73 -53
- package/{.postcssrc.js → postcss.config.js} +21 -9
- package/resolver.cjs +125 -14
- package/tsconfig.json +2 -1
- package/webpack.config.d.ts +2 -0
- 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,820 @@
|
|
|
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 from Lex...", "info", quiet);
|
|
125
|
+
} else {
|
|
126
|
+
log("Using ESLint from Lex...", "info", quiet);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const runEslintWithLex = async (cwd, quiet, cliName, fix, debug, useTypescript, captureOutput) => {
|
|
130
|
+
const spinner = createSpinner(quiet);
|
|
131
|
+
try {
|
|
132
|
+
const projectConfigPath = pathResolve(cwd, "eslint.config.js");
|
|
133
|
+
const hasProjectConfig = existsSync(projectConfigPath);
|
|
134
|
+
const possiblePaths = [
|
|
135
|
+
// From src/commands/lint/lint.ts to root
|
|
136
|
+
pathResolve(__dirname, "../../../../eslint.config.js"),
|
|
137
|
+
// From packages/lex/src/commands/lint/lint.ts to packages/lex
|
|
138
|
+
pathResolve(__dirname, "../../../eslint.config.js"),
|
|
139
|
+
// From packages/lex/src/commands/lint/lint.ts to root
|
|
140
|
+
pathResolve(__dirname, "../../../../../eslint.config.js"),
|
|
141
|
+
// Absolute path if Lex is installed globally
|
|
142
|
+
pathResolve(process.env.LEX_HOME || "/usr/local/lib/node_modules/@nlabs/lex", "eslint.config.js")
|
|
143
|
+
];
|
|
144
|
+
let lexConfigPath = "";
|
|
145
|
+
for (const path of possiblePaths) {
|
|
146
|
+
if (existsSync(path)) {
|
|
147
|
+
lexConfigPath = path;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const configPath = hasProjectConfig ? projectConfigPath : lexConfigPath || projectConfigPath;
|
|
152
|
+
const lexEslintPath = pathResolve(__dirname, "../../../node_modules/.bin/eslint");
|
|
153
|
+
const globalLexEslintPath = pathResolve(process.env.LEX_HOME || "/usr/local/lib/node_modules/@nlabs/lex", "node_modules/.bin/eslint");
|
|
154
|
+
let eslintBinary = "eslint";
|
|
155
|
+
if (existsSync(lexEslintPath)) {
|
|
156
|
+
eslintBinary = lexEslintPath;
|
|
157
|
+
} else if (existsSync(globalLexEslintPath)) {
|
|
158
|
+
eslintBinary = globalLexEslintPath;
|
|
159
|
+
}
|
|
160
|
+
const jsResult = await execa(eslintBinary, [
|
|
161
|
+
"src/**/*.{js,jsx}",
|
|
162
|
+
"--config",
|
|
163
|
+
configPath,
|
|
164
|
+
// Use the determined config
|
|
165
|
+
...fix ? ["--fix"] : [],
|
|
166
|
+
...debug ? ["--debug"] : [],
|
|
167
|
+
"--no-error-on-unmatched-pattern"
|
|
168
|
+
// Don't error if no files are found
|
|
169
|
+
], {
|
|
170
|
+
reject: false,
|
|
171
|
+
stdio: "pipe",
|
|
172
|
+
cwd,
|
|
173
|
+
shell: true
|
|
174
|
+
// Needed for glob pattern expansion
|
|
175
|
+
});
|
|
176
|
+
if (jsResult.stdout) {
|
|
177
|
+
console.log(jsResult.stdout);
|
|
178
|
+
if (captureOutput) {
|
|
179
|
+
captureOutput(jsResult.stdout);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (jsResult.stderr) {
|
|
183
|
+
console.error(jsResult.stderr);
|
|
184
|
+
if (captureOutput) {
|
|
185
|
+
captureOutput(jsResult.stderr);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
let tsResult = { exitCode: 0, stdout: "", stderr: "" };
|
|
189
|
+
if (useTypescript) {
|
|
190
|
+
tsResult = await execa(eslintBinary, [
|
|
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
|
+
const eslintNotFound = jsResult.stderr?.includes("command not found") || jsResult.stderr?.includes("eslint: command not found");
|
|
214
|
+
if (eslintNotFound) {
|
|
215
|
+
spinner.fail("ESLint not found!");
|
|
216
|
+
log(`
|
|
217
|
+
${cliName} Error: Lex's ESLint binary not found. This may be a Lex installation issue.`, "error", quiet);
|
|
218
|
+
log("Please try reinstalling Lex: npm install -g @nlabs/lex", "info", quiet);
|
|
219
|
+
return 1;
|
|
220
|
+
}
|
|
221
|
+
if (jsResult.exitCode === 0 && tsResult.exitCode === 0) {
|
|
222
|
+
spinner.succeed("Linting completed!");
|
|
223
|
+
return 0;
|
|
224
|
+
}
|
|
225
|
+
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"));
|
|
226
|
+
if (noFilesFound) {
|
|
227
|
+
spinner.succeed("No files found to lint");
|
|
228
|
+
return 0;
|
|
229
|
+
}
|
|
230
|
+
spinner.fail("Linting failed!");
|
|
231
|
+
log(`
|
|
232
|
+
${cliName} Error: ESLint found issues in your code.`, "error", quiet);
|
|
233
|
+
return 1;
|
|
234
|
+
} catch (error) {
|
|
235
|
+
spinner.fail("Linting failed!");
|
|
236
|
+
log(`
|
|
237
|
+
${cliName} Error: ${error.message}`, "error", quiet);
|
|
238
|
+
return 1;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
const applyAIFix = async (cwd, errors, quiet) => {
|
|
242
|
+
const spinner = createSpinner(quiet);
|
|
243
|
+
spinner.start("Using AI to fix remaining lint issues...");
|
|
244
|
+
try {
|
|
245
|
+
const fileErrorMap = /* @__PURE__ */ new Map();
|
|
246
|
+
const lines = errors.split("\n");
|
|
247
|
+
let currentFile = "";
|
|
248
|
+
for (const line of lines) {
|
|
249
|
+
if (line.match(/^(\/|[A-Z]:\\).*?\.(js|jsx|ts|tsx)$/)) {
|
|
250
|
+
currentFile = line.trim();
|
|
251
|
+
if (!fileErrorMap.has(currentFile)) {
|
|
252
|
+
fileErrorMap.set(currentFile, []);
|
|
253
|
+
}
|
|
254
|
+
} else if (currentFile && line.trim() && line.match(/\s+\d+:\d+\s+(error|warning)\s+/)) {
|
|
255
|
+
const errorArray = fileErrorMap.get(currentFile);
|
|
256
|
+
if (errorArray) {
|
|
257
|
+
errorArray.push(line.trim());
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (fileErrorMap.size === 0) {
|
|
262
|
+
log("Using alternative error parsing strategy", "info", quiet);
|
|
263
|
+
const sections = errors.split("\n\n");
|
|
264
|
+
for (const section of sections) {
|
|
265
|
+
if (section.trim() === "") {
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const lines2 = section.split("\n");
|
|
269
|
+
const filePath = lines2[0].trim();
|
|
270
|
+
if (filePath.match(/\.(js|jsx|ts|tsx)$/)) {
|
|
271
|
+
fileErrorMap.set(filePath, []);
|
|
272
|
+
for (let i = 1; i < lines2.length; i++) {
|
|
273
|
+
if (lines2[i].trim() !== "") {
|
|
274
|
+
fileErrorMap.get(filePath)?.push(lines2[i].trim());
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (fileErrorMap.size === 0) {
|
|
281
|
+
log("Using direct file path extraction", "info", quiet);
|
|
282
|
+
const filePathRegex = /(?:\/|[A-Z]:\\)(?:[^:\n]+\/)*[^:\n]+\.(js|jsx|ts|tsx)/g;
|
|
283
|
+
const filePaths = errors.match(filePathRegex) || [];
|
|
284
|
+
for (const filePath of filePaths) {
|
|
285
|
+
if (!fileErrorMap.has(filePath) && existsSync(filePath)) {
|
|
286
|
+
fileErrorMap.set(filePath, []);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const knownFiles = [
|
|
290
|
+
"/Users/nitrog7/Development/lex/packages/lex/src/create/changelog.ts",
|
|
291
|
+
"/Users/nitrog7/Development/lex/packages/lex/src/utils/aiService.ts",
|
|
292
|
+
"/Users/nitrog7/Development/lex/packages/lex/src/utils/app.ts",
|
|
293
|
+
"/Users/nitrog7/Development/lex/packages/lex/src/utils/reactShim.ts",
|
|
294
|
+
"/Users/nitrog7/Development/lex/packages/lex/src/commands/lint/autofix.js"
|
|
295
|
+
];
|
|
296
|
+
for (const file of knownFiles) {
|
|
297
|
+
if (existsSync(file) && !fileErrorMap.has(file)) {
|
|
298
|
+
fileErrorMap.set(file, []);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
for (const filePath of fileErrorMap.keys()) {
|
|
303
|
+
if (!existsSync(filePath)) {
|
|
304
|
+
log(`File not found: ${filePath}`, "warn", quiet);
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
log(`Processing file: ${filePath}`, "info", quiet);
|
|
308
|
+
const isCursorIDE = LexConfig.config.ai?.provider === "cursor" || process.env.CURSOR_IDE === "true";
|
|
309
|
+
if (isCursorIDE) {
|
|
310
|
+
try {
|
|
311
|
+
const prompt = `Fix all ESLint errors in this file. Focus on:
|
|
312
|
+
1. Fixing naming conventions
|
|
313
|
+
2. Fixing sort-keys issues
|
|
314
|
+
3. Replacing console.log with log utility
|
|
315
|
+
4. Fixing no-plusplus issues
|
|
316
|
+
5. Fixing unnecessary escape characters
|
|
317
|
+
6. Fixing other ESLint errors
|
|
318
|
+
|
|
319
|
+
CRITICAL REQUIREMENTS:
|
|
320
|
+
- ONLY fix the specific lines with ESLint errors
|
|
321
|
+
- DO NOT modify any other lines of code
|
|
322
|
+
- DO NOT remove line breaks unless they are specifically causing ESLint errors
|
|
323
|
+
- DO NOT condense multi-line structures to single lines
|
|
324
|
+
- PRESERVE all existing line breaks and formatting that is not causing errors
|
|
325
|
+
|
|
326
|
+
SPECIFIC FORMATTING RULES:
|
|
327
|
+
- Maintain proper indentation (2 spaces)
|
|
328
|
+
- Keep line breaks between class/interface declaration and their members
|
|
329
|
+
- Keep line breaks between methods
|
|
330
|
+
- Ensure there is a line break after opening braces for classes, interfaces, and methods
|
|
331
|
+
- DO NOT place class/interface properties or methods on the same line as the opening brace
|
|
332
|
+
- Preserve empty lines between logical code blocks
|
|
333
|
+
- PRESERVE multi-line imports - do not condense them to single lines
|
|
334
|
+
- PRESERVE multi-line object/array declarations - do not condense them to single lines
|
|
335
|
+
|
|
336
|
+
SORT-KEYS RULE (HIGHEST PRIORITY):
|
|
337
|
+
- All object literal keys MUST be sorted alphabetically in ascending order
|
|
338
|
+
- This applies to ALL objects in the file, not just those with explicit sort-keys errors
|
|
339
|
+
- Example: {b: 2, a: 1, c: 3} should become {a: 1, b: 2, c: 3}
|
|
340
|
+
- Preserve the original formatting and line breaks when sorting
|
|
341
|
+
|
|
342
|
+
Example of CORRECT formatting (DO NOT CHANGE):
|
|
343
|
+
export class UserConstants {
|
|
344
|
+
static readonly ADD_ITEM_ERROR: string = 'USER_ADD_ITEM_ERROR';
|
|
345
|
+
static readonly OTHER_CONSTANT: string = 'OTHER_CONSTANT';
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
constructor(flux: FluxFramework, CustomAdapter: typeof Event = Event) {
|
|
349
|
+
this.CustomAdapter = CustomAdapter;
|
|
350
|
+
this.flux = flux;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
import {
|
|
354
|
+
app,
|
|
355
|
+
events,
|
|
356
|
+
images,
|
|
357
|
+
locations,
|
|
358
|
+
messages,
|
|
359
|
+
posts,
|
|
360
|
+
tags,
|
|
361
|
+
users,
|
|
362
|
+
websocket
|
|
363
|
+
} from './stores';
|
|
364
|
+
|
|
365
|
+
const config = {
|
|
366
|
+
apiKey: 'value',
|
|
367
|
+
baseUrl: 'https://api.example.com',
|
|
368
|
+
timeout: 5000
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
Example of INCORRECT formatting (FIX THIS):
|
|
372
|
+
export class UserConstants {static readonly ADD_ITEM_ERROR: string = 'USER_ADD_ITEM_ERROR';
|
|
373
|
+
static readonly OTHER_CONSTANT: string = 'OTHER_CONSTANT';
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
constructor(flux: FluxFramework, CustomAdapter: typeof Event = Event) {this.CustomAdapter = CustomAdapter;
|
|
377
|
+
this.flux = flux;}
|
|
378
|
+
|
|
379
|
+
import {app, events, images, locations, messages, posts, tags, users, websocket} from './stores';
|
|
380
|
+
|
|
381
|
+
const config = {baseUrl: 'https://api.example.com', apiKey: 'value', timeout: 5000};
|
|
382
|
+
|
|
383
|
+
Fix ONLY the specific ESLint errors. Return the properly formatted code.`;
|
|
384
|
+
try {
|
|
385
|
+
const promptFile = pathResolve(cwd, ".cursor_prompt_temp.txt");
|
|
386
|
+
writeFileSync(promptFile, prompt, "utf8");
|
|
387
|
+
await execa("cursor", ["edit", "--file", filePath, "--prompt-file", promptFile], {
|
|
388
|
+
reject: false,
|
|
389
|
+
stdio: "pipe",
|
|
390
|
+
cwd
|
|
391
|
+
});
|
|
392
|
+
try {
|
|
393
|
+
unlinkSync(promptFile);
|
|
394
|
+
} catch (_error) {
|
|
395
|
+
}
|
|
396
|
+
log(`Applied Cursor AI fixes to ${filePath}`, "info", quiet);
|
|
397
|
+
} catch (error) {
|
|
398
|
+
const wasModified = await applyDirectFixes(filePath, quiet);
|
|
399
|
+
if (wasModified) {
|
|
400
|
+
log(`Applied direct fixes to ${filePath}`, "info", quiet);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
} catch (error) {
|
|
404
|
+
log(`Error using Cursor AI: ${error.message}`, "error", quiet);
|
|
405
|
+
await applyDirectFixes(filePath, quiet);
|
|
406
|
+
}
|
|
407
|
+
} else {
|
|
408
|
+
const wasModified = await applyDirectFixes(filePath, quiet);
|
|
409
|
+
if (wasModified) {
|
|
410
|
+
log(`Applied direct fixes to ${filePath}`, "info", quiet);
|
|
411
|
+
}
|
|
412
|
+
const fileErrors = fileErrorMap.get(filePath) || [];
|
|
413
|
+
if (fileErrors.length > 0) {
|
|
414
|
+
try {
|
|
415
|
+
const { callAIService } = await import("../../utils/aiService.js");
|
|
416
|
+
const fileContent = readFileSync(filePath, "utf8");
|
|
417
|
+
const prompt = `Fix the following ESLint errors in this code:
|
|
418
|
+
${fileErrors.join("\n")}
|
|
419
|
+
|
|
420
|
+
Here's the code:
|
|
421
|
+
\`\`\`
|
|
422
|
+
${fileContent}
|
|
423
|
+
\`\`\`
|
|
424
|
+
|
|
425
|
+
CRITICAL REQUIREMENTS:
|
|
426
|
+
- ONLY fix the specific lines with ESLint errors
|
|
427
|
+
- DO NOT modify any other lines of code
|
|
428
|
+
- DO NOT remove line breaks unless they are specifically causing ESLint errors
|
|
429
|
+
- DO NOT condense multi-line structures to single lines
|
|
430
|
+
- PRESERVE all existing line breaks and formatting that is not causing errors
|
|
431
|
+
|
|
432
|
+
SPECIFIC FORMATTING RULES:
|
|
433
|
+
- Maintain proper indentation (2 spaces)
|
|
434
|
+
- Keep line breaks between class/interface declaration and their members
|
|
435
|
+
- Keep line breaks between methods
|
|
436
|
+
- Ensure there is a line break after opening braces for classes, interfaces, and methods
|
|
437
|
+
- DO NOT place class/interface properties or methods on the same line as the opening brace
|
|
438
|
+
- Preserve empty lines between logical code blocks
|
|
439
|
+
- PRESERVE multi-line imports - do not condense them to single lines
|
|
440
|
+
- PRESERVE multi-line object/array declarations - do not condense them to single lines
|
|
441
|
+
|
|
442
|
+
SORT-KEYS RULE (HIGHEST PRIORITY):
|
|
443
|
+
- All object literal keys MUST be sorted alphabetically in ascending order
|
|
444
|
+
- This applies to ALL objects in the file, not just those with explicit sort-keys errors
|
|
445
|
+
- Example: {b: 2, a: 1, c: 3} should become {a: 1, b: 2, c: 3}
|
|
446
|
+
- Preserve the original formatting and line breaks when sorting
|
|
447
|
+
|
|
448
|
+
WHAT TO FIX:
|
|
449
|
+
1. Sorting all object keys alphabetically (sort-keys rule) - ALL objects must have sorted keys
|
|
450
|
+
2. Fixing naming conventions - ONLY for variables/functions with naming errors
|
|
451
|
+
3. Replacing console.log with log utility - ONLY for console.log statements
|
|
452
|
+
4. Fixing no-plusplus issues - ONLY for ++/-- operators
|
|
453
|
+
5. Fixing unnecessary escape characters - ONLY for escaped characters that don't need escaping
|
|
454
|
+
6. Proper indentation and spacing - ONLY where specifically required by errors
|
|
455
|
+
7. String quotes consistency (use single quotes) - ONLY for string literals with quote errors
|
|
456
|
+
8. Import order and spacing - ONLY for imports with order/spacing errors
|
|
457
|
+
9. Function parameter formatting - ONLY for functions with parameter errors
|
|
458
|
+
10. Variable naming conventions - ONLY for variables with naming errors
|
|
459
|
+
11. No unused variables or imports - ONLY for unused variables/imports
|
|
460
|
+
12. Avoiding nested ternaries - ONLY for nested ternary expressions
|
|
461
|
+
13. Any other ESLint errors - ONLY for the specific errors listed above
|
|
462
|
+
|
|
463
|
+
WHAT NOT TO FIX:
|
|
464
|
+
- Do not change properly formatted multi-line structures
|
|
465
|
+
- Do not remove line breaks that are not causing errors
|
|
466
|
+
- Do not change indentation that is already correct
|
|
467
|
+
- Do not modify spacing that is already correct
|
|
468
|
+
- Do not condense readable multi-line code to single lines
|
|
469
|
+
- Do not modify code that is not mentioned in the ESLint errors
|
|
470
|
+
|
|
471
|
+
Example of CORRECT formatting (DO NOT CHANGE):
|
|
472
|
+
export class UserConstants {
|
|
473
|
+
static readonly ADD_ITEM_ERROR: string = 'USER_ADD_ITEM_ERROR';
|
|
474
|
+
static readonly OTHER_CONSTANT: string = 'OTHER_CONSTANT';
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
constructor(flux: FluxFramework, CustomAdapter: typeof Event = Event) {
|
|
478
|
+
this.CustomAdapter = CustomAdapter;
|
|
479
|
+
this.flux = flux;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
import {
|
|
483
|
+
app,
|
|
484
|
+
events,
|
|
485
|
+
images,
|
|
486
|
+
locations,
|
|
487
|
+
messages,
|
|
488
|
+
posts,
|
|
489
|
+
tags,
|
|
490
|
+
users,
|
|
491
|
+
websocket
|
|
492
|
+
} from './stores';
|
|
493
|
+
|
|
494
|
+
const config = {
|
|
495
|
+
apiKey: 'value',
|
|
496
|
+
baseUrl: 'https://api.example.com',
|
|
497
|
+
timeout: 5000
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
Example of INCORRECT formatting (FIX THIS):
|
|
501
|
+
export class UserConstants {static readonly ADD_ITEM_ERROR: string = 'USER_ADD_ITEM_ERROR';
|
|
502
|
+
static readonly OTHER_CONSTANT: string = 'OTHER_CONSTANT';
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
constructor(flux: FluxFramework, CustomAdapter: typeof Event = Event) {this.CustomAdapter = CustomAdapter;
|
|
506
|
+
this.flux = flux;}
|
|
507
|
+
|
|
508
|
+
import {app, events, images, locations, messages, posts, tags, users, websocket} from './stores';
|
|
509
|
+
|
|
510
|
+
const config = {baseUrl: 'https://api.example.com', apiKey: 'value', timeout: 5000};
|
|
511
|
+
|
|
512
|
+
Fix ONLY the specific ESLint errors listed above. Review the entire file for compliance with all ESLint rules.
|
|
513
|
+
Return only the properly formatted fixed code without any explanations.`;
|
|
514
|
+
const fixedContent = await callAIService(prompt, quiet);
|
|
515
|
+
if (fixedContent && fixedContent !== fileContent) {
|
|
516
|
+
writeFileSync(filePath, fixedContent, "utf8");
|
|
517
|
+
log(`Applied AI fixes to ${filePath}`, "info", quiet);
|
|
518
|
+
}
|
|
519
|
+
} catch (error) {
|
|
520
|
+
log(`Error applying AI fixes to ${filePath}: ${error.message}`, "error", quiet);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
spinner.succeed("AI fixes applied successfully!");
|
|
526
|
+
} catch (error) {
|
|
527
|
+
spinner.fail("Failed to apply AI fixes");
|
|
528
|
+
log(`Error: ${error.message}`, "error", quiet);
|
|
529
|
+
if (!quiet) {
|
|
530
|
+
console.error(error);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
const applyDirectFixes = async (filePath, quiet) => {
|
|
535
|
+
let wasModified = false;
|
|
536
|
+
try {
|
|
537
|
+
const fileContent = readFileSync(filePath, "utf8");
|
|
538
|
+
let newContent = fileContent;
|
|
539
|
+
if (filePath.includes("aiService.ts")) {
|
|
540
|
+
log("Fixing issues in aiService.ts", "info", quiet);
|
|
541
|
+
newContent = newContent.replace(
|
|
542
|
+
/'Content-Type': 'application\/json',\s*'Authorization': `Bearer/g,
|
|
543
|
+
"'Authorization': `Bearer', 'Content-Type': 'application/json'"
|
|
544
|
+
);
|
|
545
|
+
newContent = newContent.replace(
|
|
546
|
+
/headers: {([^}]*)},\s*method: 'POST'/g,
|
|
547
|
+
"method: 'POST',\n headers: {$1}"
|
|
548
|
+
);
|
|
549
|
+
newContent = newContent.replace(
|
|
550
|
+
/{role: 'system', content:/g,
|
|
551
|
+
"{content:, role: 'system',"
|
|
552
|
+
);
|
|
553
|
+
newContent = newContent.replace(
|
|
554
|
+
/{role: 'user', content:/g,
|
|
555
|
+
"{content:, role: 'user',"
|
|
556
|
+
);
|
|
557
|
+
newContent = newContent.replace(
|
|
558
|
+
/\(([^)]*?)_([a-zA-Z0-9]+)(\s*:[^)]*)\)/g,
|
|
559
|
+
"($1$2$3)"
|
|
560
|
+
);
|
|
561
|
+
newContent = newContent.replace(/console\.log\(/g, "log(");
|
|
562
|
+
if (!newContent.includes("import {log}") && newContent.includes("log(")) {
|
|
563
|
+
newContent = newContent.replace(
|
|
564
|
+
/import {([^}]*)} from '(.*)';/,
|
|
565
|
+
"import {$1} from '$2';\nimport {log} from './log.js';"
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if (filePath.includes("reactShim.ts")) {
|
|
570
|
+
log("Fixing naming-convention issues in reactShim.ts", "info", quiet);
|
|
571
|
+
newContent = newContent.replace(
|
|
572
|
+
"import * as React from",
|
|
573
|
+
"import * as react from"
|
|
574
|
+
);
|
|
575
|
+
newContent = newContent.replace(/React\./g, "react.");
|
|
576
|
+
}
|
|
577
|
+
if (filePath.includes("changelog.ts")) {
|
|
578
|
+
log("Fixing issues in changelog.ts", "info", quiet);
|
|
579
|
+
newContent = newContent.replace(/(\w+)\+\+/g, "$1 += 1");
|
|
580
|
+
newContent = newContent.replace(/\\\$/g, "$");
|
|
581
|
+
newContent = newContent.replace(/\\\./g, ".");
|
|
582
|
+
newContent = newContent.replace(/\\\*/g, "*");
|
|
583
|
+
newContent = newContent.replace(/\\:/g, ":");
|
|
584
|
+
}
|
|
585
|
+
if (filePath.includes("app.ts")) {
|
|
586
|
+
log("Fixing issues in app.ts", "info", quiet);
|
|
587
|
+
newContent = newContent.replace(/console\.log\(/g, "log(");
|
|
588
|
+
if (!newContent.includes("import {log}") && newContent.includes("log(")) {
|
|
589
|
+
newContent = newContent.replace(
|
|
590
|
+
/import boxen from 'boxen';/,
|
|
591
|
+
"import boxen from 'boxen';\nimport {log} from './log.js';"
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
newContent = newContent.replace(/\\\//g, "/");
|
|
595
|
+
}
|
|
596
|
+
if (filePath.includes("autofix.js")) {
|
|
597
|
+
log("Fixing issues in autofix.js", "info", quiet);
|
|
598
|
+
newContent = newContent.replace(
|
|
599
|
+
/import {([^}]*)} from 'path';[\s\n]*import {([^}]*)} from 'path';/,
|
|
600
|
+
"import {$1, $2} from 'path';"
|
|
601
|
+
);
|
|
602
|
+
newContent = newContent.replace(
|
|
603
|
+
/__filename/g,
|
|
604
|
+
"currentFilename"
|
|
605
|
+
);
|
|
606
|
+
newContent = newContent.replace(
|
|
607
|
+
/__dirname/g,
|
|
608
|
+
"currentDirname"
|
|
609
|
+
);
|
|
610
|
+
newContent = newContent.replace(
|
|
611
|
+
/const prefix = type === 'error' \? '❌ ' : type === 'success' \? '✅ ' : 'ℹ️ ';/,
|
|
612
|
+
"let prefix = '\u2139\uFE0F ';\nif(type === 'error') {\n prefix = '\u274C ';\n} else if(type === 'success') {\n prefix = '\u2705 ';\n}"
|
|
613
|
+
);
|
|
614
|
+
newContent = newContent.replace(
|
|
615
|
+
/async function runEslintFix\(\)/g,
|
|
616
|
+
"const runEslintFix = async ()"
|
|
617
|
+
);
|
|
618
|
+
newContent = newContent.replace(
|
|
619
|
+
/async function getFilesWithErrors\(\)/g,
|
|
620
|
+
"const getFilesWithErrors = async ()"
|
|
621
|
+
);
|
|
622
|
+
newContent = newContent.replace(
|
|
623
|
+
/async function isCursorAvailable\(\)/g,
|
|
624
|
+
"const isCursorAvailable = async ()"
|
|
625
|
+
);
|
|
626
|
+
newContent = newContent.replace(
|
|
627
|
+
/async function fixFileWithCursorAI\(filePath\)/g,
|
|
628
|
+
"const fixFileWithCursorAI = async (filePath)"
|
|
629
|
+
);
|
|
630
|
+
newContent = newContent.replace(
|
|
631
|
+
/async function main\(\)/g,
|
|
632
|
+
"const main = async ()"
|
|
633
|
+
);
|
|
634
|
+
newContent = newContent.replace(
|
|
635
|
+
/import {existsSync, readFileSync, writeFileSync}/g,
|
|
636
|
+
"import {writeFileSync}"
|
|
637
|
+
);
|
|
638
|
+
newContent = newContent.replace(
|
|
639
|
+
/console\.log\(`\${prefix} \${message}`\);/g,
|
|
640
|
+
"process.stdout.write(`${prefix} ${message}\\n`);"
|
|
641
|
+
);
|
|
642
|
+
newContent = newContent.replace(
|
|
643
|
+
/} catch\(error\) {[\s\n]*\/\/ Ignore cleanup errors/g,
|
|
644
|
+
"} catch(_) {\n // Ignore cleanup errors"
|
|
645
|
+
);
|
|
646
|
+
newContent = newContent.replace(
|
|
647
|
+
/} catch\(error\) {[\s\n]*log\(/g,
|
|
648
|
+
"} catch(err) {\n log("
|
|
649
|
+
);
|
|
650
|
+
newContent = newContent.replace(
|
|
651
|
+
/} catch\(error\) {[\s\n]*return false;/g,
|
|
652
|
+
"} catch(_) {\n return false;"
|
|
653
|
+
);
|
|
654
|
+
newContent = newContent.replace(
|
|
655
|
+
/for\(const filePath of filesWithErrors\) {[\s\n]*const success = await fixFileWithCursorAI\(filePath\);/g,
|
|
656
|
+
"const fixResults = await Promise.all(filesWithErrors.map(filePath => fixFileWithCursorAI(filePath)));\nfor(const success of fixResults) {"
|
|
657
|
+
);
|
|
658
|
+
newContent = newContent.replace(
|
|
659
|
+
/fixedCount\+\+;/g,
|
|
660
|
+
"fixedCount += 1;"
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
if (newContent !== fileContent) {
|
|
664
|
+
writeFileSync(filePath, newContent, "utf8");
|
|
665
|
+
log(`Fixed issues in ${filePath}`, "info", quiet);
|
|
666
|
+
wasModified = true;
|
|
667
|
+
}
|
|
668
|
+
return wasModified;
|
|
669
|
+
} catch (error) {
|
|
670
|
+
log(`Error applying direct fixes to ${filePath}: ${error.message}`, "error", quiet);
|
|
671
|
+
return false;
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
const loadAIConfig = async (cwd, quiet) => {
|
|
675
|
+
const configFormats = ["js", "mjs", "cjs", "ts", "json"];
|
|
676
|
+
const configBaseName = "lex.config";
|
|
677
|
+
let lexConfigPath = "";
|
|
678
|
+
for (const format of configFormats) {
|
|
679
|
+
const potentialPath = pathResolve(cwd, `./${configBaseName}.${format}`);
|
|
680
|
+
if (existsSync(potentialPath)) {
|
|
681
|
+
lexConfigPath = potentialPath;
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
if (lexConfigPath) {
|
|
686
|
+
try {
|
|
687
|
+
const lexConfig = await import(lexConfigPath);
|
|
688
|
+
if (lexConfig.default && lexConfig.default.ai) {
|
|
689
|
+
log(`Found AI configuration in ${pathResolve(cwd, lexConfigPath)}, applying settings...`, "info", quiet);
|
|
690
|
+
LexConfig.config.ai = { ...LexConfig.config.ai, ...lexConfig.default.ai };
|
|
691
|
+
}
|
|
692
|
+
} catch (error) {
|
|
693
|
+
log(`Error loading AI configuration from ${lexConfigPath}: ${error.message}`, "warn", quiet);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
const lint = async (cmd, callback = process.exit) => {
|
|
698
|
+
const {
|
|
699
|
+
cliName = "Lex",
|
|
700
|
+
fix = false,
|
|
701
|
+
debug = false,
|
|
702
|
+
quiet = false,
|
|
703
|
+
config = null
|
|
704
|
+
} = cmd;
|
|
705
|
+
log(`${cliName} linting...`, "info", quiet);
|
|
706
|
+
const cwd = process.cwd();
|
|
707
|
+
const spinner = createSpinner(quiet);
|
|
708
|
+
await loadAIConfig(cwd, quiet);
|
|
709
|
+
let originalConfig = null;
|
|
710
|
+
let tempConfigPath = null;
|
|
711
|
+
try {
|
|
712
|
+
const useTypescript = detectTypeScript(cwd);
|
|
713
|
+
log(`TypeScript ${useTypescript ? "detected" : "not detected"} from tsconfig.json`, "info", quiet);
|
|
714
|
+
ensureModuleType(cwd);
|
|
715
|
+
await installDependencies(cwd, useTypescript, quiet);
|
|
716
|
+
const projectConfigPath = pathResolve(cwd, "eslint.config.js");
|
|
717
|
+
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"));
|
|
718
|
+
if (existsSync(pathResolve(cwd, ".eslintrc.json"))) {
|
|
719
|
+
unlinkSync(pathResolve(cwd, ".eslintrc.json"));
|
|
720
|
+
}
|
|
721
|
+
let lexConfigPath = "";
|
|
722
|
+
let shouldCreateTempConfig = false;
|
|
723
|
+
if (!hasEslintConfig) {
|
|
724
|
+
const possiblePaths = [
|
|
725
|
+
// From src/commands/lint/lint.ts to root
|
|
726
|
+
pathResolve(__dirname, "../../../../eslint.config.js"),
|
|
727
|
+
// From packages/lex/src/commands/lint/lint.ts to packages/lex
|
|
728
|
+
pathResolve(__dirname, "../../../eslint.config.js"),
|
|
729
|
+
// From packages/lex/src/commands/lint/lint.ts to root
|
|
730
|
+
pathResolve(__dirname, "../../../../../eslint.config.js"),
|
|
731
|
+
// Absolute path if Lex is installed globally
|
|
732
|
+
pathResolve(process.env.LEX_HOME || "/usr/local/lib/node_modules/@nlabs/lex", "eslint.config.js")
|
|
733
|
+
];
|
|
734
|
+
for (const path of possiblePaths) {
|
|
735
|
+
if (existsSync(path)) {
|
|
736
|
+
lexConfigPath = path;
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
if (debug) {
|
|
741
|
+
log(`Current directory: ${__dirname}`, "info", quiet);
|
|
742
|
+
log(`Project config path: ${projectConfigPath}`, "info", quiet);
|
|
743
|
+
log(`Project config exists: ${hasEslintConfig}`, "info", quiet);
|
|
744
|
+
log(`Found Lex config: ${lexConfigPath}`, "info", quiet);
|
|
745
|
+
log(`Lex config exists: ${!!lexConfigPath && existsSync(lexConfigPath)}`, "info", quiet);
|
|
746
|
+
}
|
|
747
|
+
if (lexConfigPath && existsSync(lexConfigPath)) {
|
|
748
|
+
log("No ESLint configuration found in project. Using Lex's default configuration.", "info", quiet);
|
|
749
|
+
} else {
|
|
750
|
+
shouldCreateTempConfig = true;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
if (config) {
|
|
754
|
+
const userConfigPath = pathResolve(cwd, config);
|
|
755
|
+
if (existsSync(userConfigPath)) {
|
|
756
|
+
log(`Using specified ESLint configuration: ${config}`, "info", quiet);
|
|
757
|
+
shouldCreateTempConfig = false;
|
|
758
|
+
} else {
|
|
759
|
+
log(`Specified ESLint configuration not found: ${config}. Using Lex's default configuration.`, "warn", quiet);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
if (shouldCreateTempConfig) {
|
|
763
|
+
log("No ESLint configuration found. Creating a temporary configuration...", "info", quiet);
|
|
764
|
+
const configResult = createDefaultESLintConfig(useTypescript, cwd);
|
|
765
|
+
tempConfigPath = configResult.configPath;
|
|
766
|
+
originalConfig = configResult.originalConfig;
|
|
767
|
+
}
|
|
768
|
+
let eslintOutput = "";
|
|
769
|
+
const captureOutput = (output) => {
|
|
770
|
+
eslintOutput += `${output}
|
|
771
|
+
`;
|
|
772
|
+
};
|
|
773
|
+
const result = await runEslintWithLex(cwd, quiet, cliName, true, debug, useTypescript, captureOutput);
|
|
774
|
+
if (result !== 0 && fix) {
|
|
775
|
+
const aiConfigured = LexConfig.config.ai?.provider && LexConfig.config.ai.provider !== "none";
|
|
776
|
+
if (aiConfigured) {
|
|
777
|
+
log("Applying AI fixes to remaining issues...", "info", quiet);
|
|
778
|
+
await applyAIFix(cwd, eslintOutput, quiet);
|
|
779
|
+
const afterFixResult = await runEslintWithLex(cwd, quiet, cliName, false, debug, useTypescript);
|
|
780
|
+
callback(afterFixResult);
|
|
781
|
+
return afterFixResult;
|
|
782
|
+
}
|
|
783
|
+
log("ESLint could not fix all issues automatically.", "warn", quiet);
|
|
784
|
+
log("To enable AI-powered fixes, add AI configuration to your lex.config file:", "info", quiet);
|
|
785
|
+
log(`
|
|
786
|
+
// In lex.config.js (or lex.config.mjs, lex.config.cjs, etc.)
|
|
787
|
+
export default {
|
|
788
|
+
// Your existing config
|
|
789
|
+
ai: {
|
|
790
|
+
provider: 'cursor' // or 'openai', 'anthropic', etc.
|
|
791
|
+
// Additional provider-specific settings
|
|
792
|
+
}
|
|
793
|
+
};`, "info", quiet);
|
|
794
|
+
}
|
|
795
|
+
callback(result);
|
|
796
|
+
return result;
|
|
797
|
+
} catch (error) {
|
|
798
|
+
log(`
|
|
799
|
+
${cliName} Error: ${error.message}`, "error", quiet);
|
|
800
|
+
spinner.fail("Linting failed!");
|
|
801
|
+
callback(1);
|
|
802
|
+
return 1;
|
|
803
|
+
} finally {
|
|
804
|
+
if (tempConfigPath && originalConfig) {
|
|
805
|
+
try {
|
|
806
|
+
writeFileSync(tempConfigPath, originalConfig, "utf8");
|
|
807
|
+
} catch (_error) {
|
|
808
|
+
}
|
|
809
|
+
} else if (tempConfigPath) {
|
|
810
|
+
try {
|
|
811
|
+
unlinkSync(tempConfigPath);
|
|
812
|
+
} catch (_error) {
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
export {
|
|
818
|
+
lint
|
|
819
|
+
};
|
|
820
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2NvbW1hbmRzL2xpbnQvbGludC50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMjItUHJlc2VudCwgTml0cm9nZW4gTGFicywgSW5jLlxuICogQ29weXJpZ2h0cyBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSB0aGUgYWNjb21wYW55aW5nIExJQ0VOU0UgZmlsZSBmb3IgdGVybXMuXG4gKi9cbmltcG9ydCB7ZXhlY2F9IGZyb20gJ2V4ZWNhJztcbmltcG9ydCB7ZXhpc3RzU3luYywgd3JpdGVGaWxlU3luYywgcmVhZEZpbGVTeW5jLCB1bmxpbmtTeW5jfSBmcm9tICdmcyc7XG5pbXBvcnQge3Jlc29sdmUgYXMgcGF0aFJlc29sdmUsIGRpcm5hbWV9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IHtmaWxlVVJMVG9QYXRofSBmcm9tICd1cmwnO1xuXG5pbXBvcnQge0xleENvbmZpZ30gZnJvbSAnLi4vLi4vTGV4Q29uZmlnLmpzJztcbmltcG9ydCB7Y3JlYXRlU3Bpbm5lcn0gZnJvbSAnLi4vLi4vdXRpbHMvYXBwLmpzJztcbmltcG9ydCB7bG9nfSBmcm9tICcuLi8uLi91dGlscy9sb2cuanMnO1xuXG4vLyBDcmVhdGUgX19kaXJuYW1lIGVxdWl2YWxlbnQgZm9yIEVTTVxuY29uc3QgX19maWxlbmFtZSA9IGZpbGVVUkxUb1BhdGgoaW1wb3J0Lm1ldGEudXJsKTtcbmNvbnN0IF9fZGlybmFtZSA9IGRpcm5hbWUoX19maWxlbmFtZSk7XG5cbmV4cG9ydCBpbnRlcmZhY2UgTGludE9wdGlvbnMge1xuICByZWFkb25seSBjYWNoZT86IGJvb2xlYW47XG4gIHJlYWRvbmx5IGNhY2hlRmlsZT86IHN0cmluZztcbiAgcmVhZG9ubHkgY2FjaGVMb2NhdGlvbj86IHN0cmluZztcbiAgcmVhZG9ubHkgY2xpTmFtZT86IHN0cmluZztcbiAgcmVhZG9ubHkgY29sb3I/OiBib29sZWFuO1xuICByZWFkb25seSBjb25maWc/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGRlYnVnPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgZW52Pzogc3RyaW5nO1xuICByZWFkb25seSBlbnZJbmZvPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgZXh0Pzogc3RyaW5nO1xuICByZWFkb25seSBmaXg/OiBib29sZWFuO1xuICByZWFkb25seSBmaXhEcnlSdW4/OiBib29sZWFuO1xuICByZWFkb25seSBmaXhUeXBlPzogc3RyaW5nO1xuICByZWFkb25seSBmb3JtYXQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGdsb2JhbD86IHN0cmluZztcbiAgcmVhZG9ubHkgaWdub3JlUGF0aD86IHN0cmluZztcbiAgcmVhZG9ubHkgaWdub3JlUGF0dGVybj86IHN0cmluZztcbiAgcmVhZG9ubHkgaW5pdD86IGJvb2xlYW47XG4gIHJlYWRvbmx5IG1heFdhcm5pbmdzPzogc3RyaW5nO1xuICByZWFkb25seSBub0NvbG9yPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgbm9Fc2xpbnRyYz86IGJvb2xlYW47XG4gIHJlYWRvbmx5IG5vSWdub3JlPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgbm9JbmxpbmVDb25maWc/OiBib29sZWFuO1xuICByZWFkb25seSBvdXRwdXRGaWxlPzogc3RyaW5nO1xuICByZWFkb25seSBwYXJzZXI/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHBhcnNlck9wdGlvbnM/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHBsdWdpbj86IHN0cmluZztcbiAgcmVhZG9ubHkgcHJpbnRDb25maWc/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHF1aWV0PzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgcmVwb3J0VW51c2VkRGlzYWJsZURpcmVjdGl2ZXM/OiBib29sZWFuO1xuICByZWFkb25seSByZXNvbHZlUGx1Z2luc1JlbGF0aXZlVG8/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHJ1bGU/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHJ1bGVzZGlyPzogc3RyaW5nO1xuICByZWFkb25seSBzdGRpbj86IGJvb2xlYW47XG4gIHJlYWRvbmx5IHN0ZGluRmlsZW5hbWU/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCB0eXBlIExpbnRDYWxsYmFjayA9IHR5cGVvZiBwcm9jZXNzLmV4aXQ7XG5cbmludGVyZmFjZSBDb25maWdSZXN1bHQge1xuICBjb25maWdQYXRoOiBzdHJpbmc7XG4gIG9yaWdpbmFsQ29uZmlnOiBzdHJpbmcgfCBudWxsO1xufVxuXG4vKipcbiAqIENyZWF0ZSBhIHRlbXBvcmFyeSBFU0xpbnQgY29uZmlnIGZpbGVcbiAqL1xuY29uc3QgY3JlYXRlRGVmYXVsdEVTTGludENvbmZpZyA9ICh1c2VUeXBlc2NyaXB0OiBib29sZWFuLCBjd2Q6IHN0cmluZyk6IENvbmZpZ1Jlc3VsdCA9PiB7XG4gIC8vIENyZWF0ZSBhIGZsYXQgY29uZmlnIGZpbGUgZm9yIEVTTGludCA5LnhcbiAgY29uc3QgY29uZmlnUGF0aCA9IHBhdGhSZXNvbHZlKGN3ZCwgJ2VzbGludC5jb25maWcuanMnKTtcblxuICAvLyBTYXZlIHRoZSBvcmlnaW5hbCBjb25maWcgaWYgaXQgZXhpc3RzXG4gIGxldCBvcmlnaW5hbENvbmZpZyA9IG51bGw7XG4gIGlmKGV4aXN0c1N5bmMoY29uZmlnUGF0aCkpIHtcbiAgICB0cnkge1xuICAgICAgb3JpZ2luYWxDb25maWcgPSByZWFkRmlsZVN5bmMoY29uZmlnUGF0aCwgJ3V0ZjgnKTtcbiAgICB9IGNhdGNoKF9lcnJvcikge1xuICAgICAgLy8gSWdub3JlIGVycm9yc1xuICAgIH1cbiAgfVxuXG4gIC8vIFRyeSB0byBmaW5kIExleCdzIGVzbGludC5jb25maWcuanMgdG8gY29weVxuICAvLyBUcnkgZGlmZmVyZW50IHBvdGVudGlhbCBsb2NhdGlvbnMgZm9yIHRoZSBMZXggY29uZmlnXG4gIGNvbnN0IHBvc3NpYmxlUGF0aHMgPSBbXG4gICAgLy8gRnJvbSBzcmMvY29tbWFuZHMvbGludC9saW50LnRzIHRvIHJvb3RcbiAgICBwYXRoUmVzb2x2ZShfX2Rpcm5hbWUsICcuLi8uLi8uLi8uLi9lc2xpbnQuY29uZmlnLmpzJyksXG4gICAgLy8gRnJvbSBwYWNrYWdlcy9sZXgvc3JjL2NvbW1hbmRzL2xpbnQvbGludC50cyB0byBwYWNrYWdlcy9sZXhcbiAgICBwYXRoUmVzb2x2ZShfX2Rpcm5hbWUsICcuLi8uLi8uLi9lc2xpbnQuY29uZmlnLmpzJyksXG4gICAgLy8gRnJvbSBwYWNrYWdlcy9sZXgvc3JjL2NvbW1hbmRzL2xpbnQvbGludC50cyB0byByb290XG4gICAgcGF0aFJlc29sdmUoX19kaXJuYW1lLCAnLi4vLi4vLi4vLi4vLi4vZXNsaW50LmNvbmZpZy5qcycpLFxuICAgIC8vIEFic29sdXRlIHBhdGggaWYgTGV4IGlzIGluc3RhbGxlZCBnbG9iYWxseVxuICAgIHBhdGhSZXNvbHZlKHByb2Nlc3MuZW52LkxFWF9IT01FIHx8ICcvdXNyL2xvY2FsL2xpYi9ub2RlX21vZHVsZXMvQG5sYWJzL2xleCcsICdlc2xpbnQuY29uZmlnLmpzJylcbiAgXTtcblxuICBsZXQgZm91bmRDb25maWcgPSAnJztcbiAgZm9yKGNvbnN0IHBhdGggb2YgcG9zc2libGVQYXRocykge1xuICAgIGlmKGV4aXN0c1N5bmMocGF0aCkpIHtcbiAgICAgIGZvdW5kQ29uZmlnID0gcGF0aDtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIGxldCBlc2xpbnRDb25maWc7XG5cbiAgaWYoZm91bmRDb25maWcpIHtcbiAgICAvLyBDb3B5IExleCdzIGNvbmZpZyBmaWxlXG4gICAgdHJ5IHtcbiAgICAgIGVzbGludENvbmZpZyA9IHJlYWRGaWxlU3luYyhmb3VuZENvbmZpZywgJ3V0ZjgnKTtcbiAgICB9IGNhdGNoKF9lcnJvcikge1xuICAgICAgLy8gRmFsbCBiYWNrIHRvIGRlZmF1bHQgY29uZmlnIGlmIHdlIGNhbid0IHJlYWQgTGV4J3MgY29uZmlnXG4gICAgICBlc2xpbnRDb25maWcgPSBjcmVhdGVCYXNpY0VTTGludENvbmZpZyh1c2VUeXBlc2NyaXB0KTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgLy8gQ3JlYXRlIGEgc2ltcGxlIGNvbmZpZyBpZiBMZXgncyBjb25maWcgZG9lc24ndCBleGlzdFxuICAgIGVzbGludENvbmZpZyA9IGNyZWF0ZUJhc2ljRVNMaW50Q29uZmlnKHVzZVR5cGVzY3JpcHQpO1xuICB9XG5cbiAgLy8gV3JpdGUgdGhlIGNvbmZpZ1xuICB3cml0ZUZpbGVTeW5jKGNvbmZpZ1BhdGgsIGVzbGludENvbmZpZywgJ3V0ZjgnKTtcblxuICAvLyBSZXR1cm4gYm90aCB0aGUgY29uZmlnIHBhdGggYW5kIHRoZSBvcmlnaW5hbCBjb25maWdcbiAgcmV0dXJuIHtcbiAgICBjb25maWdQYXRoLFxuICAgIG9yaWdpbmFsQ29uZmlnXG4gIH07XG59O1xuXG4vKipcbiAqIENyZWF0ZSBhIGJhc2ljIEVTTGludCBjb25maWcgYXMgYSBmYWxsYmFja1xuICovXG5jb25zdCBjcmVhdGVCYXNpY0VTTGludENvbmZpZyA9ICh1c2VUeXBlc2NyaXB0OiBib29sZWFuKTogc3RyaW5nID0+IHtcbiAgbGV0IGNvbmZpZyA9IGAvLyBFU0xpbnQgY29uZmlndXJhdGlvblxuZXhwb3J0IGRlZmF1bHQgW1xuICB7XG4gICAgaWdub3JlczogWycqKi9ub2RlX21vZHVsZXMvKionLCAnKiovZGlzdC8qKicsICcqKi9idWlsZC8qKiddXG4gIH0sXG4gIC8vIENvbmZpZyBmb3IgSmF2YVNjcmlwdCBmaWxlc1xuICB7XG4gICAgZmlsZXM6IFsnKiovKi57anMsanN4fSddLFxuICAgIGxhbmd1YWdlT3B0aW9uczoge1xuICAgICAgZWNtYVZlcnNpb246ICdsYXRlc3QnLFxuICAgICAgc291cmNlVHlwZTogJ21vZHVsZSdcbiAgICB9LFxuICAgIHJ1bGVzOiB7XG4gICAgICAnaW5kZW50JzogWydlcnJvcicsIDJdLFxuICAgICAgJ3F1b3Rlcyc6IFsnZXJyb3InLCAnc2luZ2xlJ10sXG4gICAgICAnc2VtaSc6IFsnZXJyb3InLCAnYWx3YXlzJ10sXG4gICAgICAnbm8tdW51c2VkLXZhcnMnOiBbJ3dhcm4nLCB7ICdhcmdzSWdub3JlUGF0dGVybic6ICdeXycsICd2YXJzSWdub3JlUGF0dGVybic6ICdeXycsICdjYXVnaHRFcnJvcnMnOiAnYWxsJywgJ2NhdWdodEVycm9yc0lnbm9yZVBhdHRlcm4nOiAnXl8nIH1dLFxuICAgICAgJ2VxZXFlcSc6IFsnZXJyb3InLCAnYWx3YXlzJ11cbiAgICB9XG4gIH1gO1xuXG4gIC8vIEFkZCBUeXBlU2NyaXB0IGNvbmZpZ3VyYXRpb24gaWYgbmVlZGVkXG4gIGlmKHVzZVR5cGVzY3JpcHQpIHtcbiAgICBjb25maWcgKz0gYCxcbiAgLy8gQ29uZmlnIGZvciBUeXBlU2NyaXB0IGZpbGVzXG4gIHtcbiAgICBmaWxlczogWycqKi8qLnt0cyx0c3h9J10sXG4gICAgbGFuZ3VhZ2VPcHRpb25zOiB7XG4gICAgICBlY21hVmVyc2lvbjogJ2xhdGVzdCcsXG4gICAgICBzb3VyY2VUeXBlOiAnbW9kdWxlJyxcbiAgICAgIHBhcnNlcjoge1xuICAgICAgICBpbXBvcnRTb3VyY2U6ICdAdHlwZXNjcmlwdC1lc2xpbnQvcGFyc2VyJ1xuICAgICAgfSxcbiAgICAgIHBhcnNlck9wdGlvbnM6IHtcbiAgICAgICAgcHJvamVjdDogJy4vdHNjb25maWcuanNvbidcbiAgICAgIH1cbiAgICB9LFxuICAgIHBsdWdpbnM6IHtcbiAgICAgICdAdHlwZXNjcmlwdC1lc2xpbnQnOiB7XG4gICAgICAgIGltcG9ydFNvdXJjZTogJ0B0eXBlc2NyaXB0LWVzbGludC9lc2xpbnQtcGx1Z2luJ1xuICAgICAgfVxuICAgIH0sXG4gICAgcnVsZXM6IHtcbiAgICAgICdpbmRlbnQnOiBbJ2Vycm9yJywgMl0sXG4gICAgICAncXVvdGVzJzogWydlcnJvcicsICdzaW5nbGUnXSxcbiAgICAgICdzZW1pJzogWydlcnJvcicsICdhbHdheXMnXSxcbiAgICAgICduby11bnVzZWQtdmFycyc6ICdvZmYnLFxuICAgICAgJ0B0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycyc6IFsnd2FybicsIHsgJ2FyZ3NJZ25vcmVQYXR0ZXJuJzogJ15fJywgJ3ZhcnNJZ25vcmVQYXR0ZXJuJzogJ15fJywgJ2NhdWdodEVycm9ycyc6ICdhbGwnLCAnY2F1Z2h0RXJyb3JzSWdub3JlUGF0dGVybic6ICdeXycgfV0sXG4gICAgICAnZXFlcWVxJzogWydlcnJvcicsICdhbHdheXMnXVxuICAgIH1cbiAgfWA7XG4gIH1cblxuICAvLyBDbG9zZSB0aGUgYXJyYXlcbiAgY29uZmlnICs9IGBcbl07YDtcblxuICByZXR1cm4gY29uZmlnO1xufTtcblxuLyoqXG4gKiBDaGVjayBpZiBUeXBlU2NyaXB0IGlzIGJlaW5nIHVzZWQgYnkgbG9va2luZyBmb3IgdHNjb25maWcuanNvblxuICovXG5jb25zdCBkZXRlY3RUeXBlU2NyaXB0ID0gKGN3ZDogc3RyaW5nKTogYm9vbGVhbiA9PiBleGlzdHNTeW5jKHBhdGhSZXNvbHZlKGN3ZCwgJ3RzY29uZmlnLmpzb24nKSk7XG5cbi8qKlxuICogRW5zdXJlIHBhY2thZ2UuanNvbiBoYXMgdHlwZTogbW9kdWxlIGZvciBFU00gc3VwcG9ydFxuICovXG5jb25zdCBlbnN1cmVNb2R1bGVUeXBlID0gKGN3ZDogc3RyaW5nKTogdm9pZCA9PiB7XG4gIGNvbnN0IHBhY2thZ2VKc29uUGF0aCA9IHBhdGhSZXNvbHZlKGN3ZCwgJ3BhY2thZ2UuanNvbicpO1xuXG4gIGlmKGV4aXN0c1N5bmMocGFja2FnZUpzb25QYXRoKSkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYWNrYWdlSnNvbkNvbnRlbnQgPSByZWFkRmlsZVN5bmMocGFja2FnZUpzb25QYXRoLCAndXRmOCcpO1xuICAgICAgY29uc3QgcGFja2FnZUpzb24gPSBKU09OLnBhcnNlKHBhY2thZ2VKc29uQ29udGVudCk7XG5cbiAgICAgIC8vIElmIHR5cGUgaXMgbm90IHNldCB0byBtb2R1bGUsIHNldCBpdFxuICAgICAgaWYocGFja2FnZUpzb24udHlwZSAhPT0gJ21vZHVsZScpIHtcbiAgICAgICAgcGFja2FnZUpzb24udHlwZSA9ICdtb2R1bGUnO1xuICAgICAgICB3cml0ZUZpbGVTeW5jKHBhY2thZ2VKc29uUGF0aCwgSlNPTi5zdHJpbmdpZnkocGFja2FnZUpzb24sIG51bGwsIDIpLCAndXRmOCcpO1xuICAgICAgfVxuICAgIH0gY2F0Y2goX2Vycm9yKSB7XG4gICAgICAvLyBJZ25vcmUgZXJyb3JzXG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIExvZyB3aGljaCBFU0xpbnQgdmVyc2lvbiBpcyBiZWluZyB1c2VkXG4gKiBMZXggcHJvdmlkZXMgaXRzIG93biBFU0xpbnQsIHNvIG5vIGluc3RhbGxhdGlvbiBpcyBuZWVkZWQgaW4gdGhlIHByb2plY3RcbiAqL1xuY29uc3QgaW5zdGFsbERlcGVuZGVuY2llcyA9IGFzeW5jIChjd2Q6IHN0cmluZywgdXNlVHlwZXNjcmlwdDogYm9vbGVhbiwgcXVpZXQ6IGJvb2xlYW4pOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgLy8gTGV4IHByb3ZpZGVzIGl0cyBvd24gRVNMaW50LCBzbyB3ZSBkb24ndCBuZWVkIHRvIGluc3RhbGwgaXQgaW4gdGhlIHByb2plY3RcbiAgaWYodXNlVHlwZXNjcmlwdCkge1xuICAgIGxvZygnVXNpbmcgVHlwZVNjcmlwdCBFU0xpbnQgZnJvbSBMZXguLi4nLCAnaW5mbycsIHF1aWV0KTtcbiAgfSBlbHNlIHtcbiAgICBsb2coJ1VzaW5nIEVTTGludCBmcm9tIExleC4uLicsICdpbmZvJywgcXVpZXQpO1xuICB9XG59O1xuXG4vLyBGdW5jdGlvbiByZW1vdmVkIGFzIGl0J3Mgbm8gbG9uZ2VyIG5lZWRlZFxuXG4vKipcbiAqIFJ1biBFU0xpbnQgdXNpbmcgTGV4J3Mgb3duIEVTTGludCBiaW5hcnlcbiAqL1xuY29uc3QgcnVuRXNsaW50V2l0aExleCA9IGFzeW5jIChcbiAgY3dkOiBzdHJpbmcsXG4gIHF1aWV0OiBib29sZWFuLFxuICBjbGlOYW1lOiBzdHJpbmcsXG4gIGZpeDogYm9vbGVhbixcbiAgZGVidWc6IGJvb2xlYW4sXG4gIHVzZVR5cGVzY3JpcHQ6IGJvb2xlYW4sXG4gIGNhcHR1cmVPdXRwdXQ/OiAob3V0cHV0OiBzdHJpbmcpID0+IHZvaWRcbik6IFByb21pc2U8bnVtYmVyPiA9PiB7XG4gIGNvbnN0IHNwaW5uZXIgPSBjcmVhdGVTcGlubmVyKHF1aWV0KTtcblxuICB0cnkge1xuICAgIC8vIERldGVybWluZSB3aGljaCBFU0xpbnQgY29uZmlnIHRvIHVzZVxuICAgIC8vIEZpcnN0IGNoZWNrIGlmIHRoZSBwcm9qZWN0IGhhcyBpdHMgb3duIGVzbGludC5jb25maWcuanNcbiAgICBjb25zdCBwcm9qZWN0Q29uZmlnUGF0aCA9IHBhdGhSZXNvbHZlKGN3ZCwgJ2VzbGludC5jb25maWcuanMnKTtcbiAgICBjb25zdCBoYXNQcm9qZWN0Q29uZmlnID0gZXhpc3RzU3luYyhwcm9qZWN0Q29uZmlnUGF0aCk7XG5cbiAgICAvLyBJZiBub3QsIHRyeSB0byBmaW5kIExleCdzIGRlZmF1bHQgY29uZmlnXG4gICAgLy8gVHJ5IGRpZmZlcmVudCBwb3RlbnRpYWwgbG9jYXRpb25zIGZvciB0aGUgTGV4IGNvbmZpZ1xuICAgIGNvbnN0IHBvc3NpYmxlUGF0aHMgPSBbXG4gICAgICAvLyBGcm9tIHNyYy9jb21tYW5kcy9saW50L2xpbnQudHMgdG8gcm9vdFxuICAgICAgcGF0aFJlc29sdmUoX19kaXJuYW1lLCAnLi4vLi4vLi4vLi4vZXNsaW50LmNvbmZpZy5qcycpLFxuICAgICAgLy8gRnJvbSBwYWNrYWdlcy9sZXgvc3JjL2NvbW1hbmRzL2xpbnQvbGludC50cyB0byBwYWNrYWdlcy9sZXhcbiAgICAgIHBhdGhSZXNvbHZlKF9fZGlybmFtZSwgJy4uLy4uLy4uL2VzbGludC5jb25maWcuanMnKSxcbiAgICAgIC8vIEZyb20gcGFja2FnZXMvbGV4L3NyYy9jb21tYW5kcy9saW50L2xpbnQudHMgdG8gcm9vdFxuICAgICAgcGF0aFJlc29sdmUoX19kaXJuYW1lLCAnLi4vLi4vLi4vLi4vLi4vZXNsaW50LmNvbmZpZy5qcycpLFxuICAgICAgLy8gQWJzb2x1dGUgcGF0aCBpZiBMZXggaXMgaW5zdGFsbGVkIGdsb2JhbGx5XG4gICAgICBwYXRoUmVzb2x2ZShwcm9jZXNzLmVudi5MRVhfSE9NRSB8fCAnL3Vzci9sb2NhbC9saWIvbm9kZV9tb2R1bGVzL0BubGFicy9sZXgnLCAnZXNsaW50LmNvbmZpZy5qcycpXG4gICAgXTtcblxuICAgIGxldCBsZXhDb25maWdQYXRoID0gJyc7XG4gICAgZm9yKGNvbnN0IHBhdGggb2YgcG9zc2libGVQYXRocykge1xuICAgICAgaWYoZXhpc3RzU3luYyhwYXRoKSkge1xuICAgICAgICBsZXhDb25maWdQYXRoID0gcGF0aDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gRGV0ZXJtaW5lIHdoaWNoIGNvbmZpZyBmaWxlIHRvIHVzZVxuICAgIGNvbnN0IGNvbmZpZ1BhdGggPSBoYXNQcm9qZWN0Q29uZmlnID8gcHJvamVjdENvbmZpZ1BhdGggOiAobGV4Q29uZmlnUGF0aCB8fCBwcm9qZWN0Q29uZmlnUGF0aCk7XG5cbiAgICAvLyBGaW5kIExleCdzIEVTTGludCBiaW5hcnlcbiAgICBjb25zdCBsZXhFc2xpbnRQYXRoID0gcGF0aFJlc29sdmUoX19kaXJuYW1lLCAnLi4vLi4vLi4vbm9kZV9tb2R1bGVzLy5iaW4vZXNsaW50Jyk7XG4gICAgY29uc3QgZ2xvYmFsTGV4RXNsaW50UGF0aCA9IHBhdGhSZXNvbHZlKHByb2Nlc3MuZW52LkxFWF9IT01FIHx8ICcvdXNyL2xvY2FsL2xpYi9ub2RlX21vZHVsZXMvQG5sYWJzL2xleCcsICdub2RlX21vZHVsZXMvLmJpbi9lc2xpbnQnKTtcblxuICAgIGxldCBlc2xpbnRCaW5hcnkgPSAnZXNsaW50JzsgLy8gZmFsbGJhY2sgdG8gbnB4XG4gICAgaWYoZXhpc3RzU3luYyhsZXhFc2xpbnRQYXRoKSkge1xuICAgICAgZXNsaW50QmluYXJ5ID0gbGV4RXNsaW50UGF0aDtcbiAgICB9IGVsc2UgaWYoZXhpc3RzU3luYyhnbG9iYWxMZXhFc2xpbnRQYXRoKSkge1xuICAgICAgZXNsaW50QmluYXJ5ID0gZ2xvYmFsTGV4RXNsaW50UGF0aDtcbiAgICB9XG5cbiAgICAvLyBSdW4gZXNsaW50IG9uIEpTIGZpbGVzIHdpdGggY29uZmlnIHVzaW5nIExleCdzIEVTTGludFxuICAgIGNvbnN0IGpzUmVzdWx0ID0gYXdhaXQgZXhlY2EoZXNsaW50QmluYXJ5LCBbXG4gICAgICAnc3JjLyoqLyoue2pzLGpzeH0nLFxuICAgICAgJy0tY29uZmlnJywgY29uZmlnUGF0aCwgLy8gVXNlIHRoZSBkZXRlcm1pbmVkIGNvbmZpZ1xuICAgICAgLi4uKGZpeCA/IFsnLS1maXgnXSA6IFtdKSxcbiAgICAgIC4uLihkZWJ1ZyA/IFsnLS1kZWJ1ZyddIDogW10pLFxuICAgICAgJy0tbm8tZXJyb3Itb24tdW5tYXRjaGVkLXBhdHRlcm4nIC8vIERvbid0IGVycm9yIGlmIG5vIGZpbGVzIGFyZSBmb3VuZFxuICAgIF0sIHtcbiAgICAgIHJlamVjdDogZmFsc2UsXG4gICAgICBzdGRpbzogJ3BpcGUnLFxuICAgICAgY3dkLFxuICAgICAgc2hlbGw6IHRydWUgLy8gTmVlZGVkIGZvciBnbG9iIHBhdHRlcm4gZXhwYW5zaW9uXG4gICAgfSk7XG5cbiAgICAvLyBEaXNwbGF5IEpTIG91dHB1dCBhbmQgY2FwdHVyZSBpdCBpZiBuZWVkZWRcbiAgICBpZihqc1Jlc3VsdC5zdGRvdXQpIHtcbiAgICAgIGNvbnNvbGUubG9nKGpzUmVzdWx0LnN0ZG91dCk7XG4gICAgICBpZihjYXB0dXJlT3V0cHV0KSB7XG4gICAgICAgIGNhcHR1cmVPdXRwdXQoanNSZXN1bHQuc3Rkb3V0KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZihqc1Jlc3VsdC5zdGRlcnIpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoanNSZXN1bHQuc3RkZXJyKTtcbiAgICAgIGlmKGNhcHR1cmVPdXRwdXQpIHtcbiAgICAgICAgY2FwdHVyZU91dHB1dChqc1Jlc3VsdC5zdGRlcnIpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFJ1biBlc2xpbnQgb24gVFMgZmlsZXMgaWYgbmVlZGVkXG4gICAgbGV0IHRzUmVzdWx0OiBhbnkgPSB7ZXhpdENvZGU6IDAsIHN0ZG91dDogJycsIHN0ZGVycjogJyd9O1xuICAgIGlmKHVzZVR5cGVzY3JpcHQpIHtcbiAgICAgIHRzUmVzdWx0ID0gYXdhaXQgZXhlY2EoZXNsaW50QmluYXJ5LCBbXG4gICAgICAgICdzcmMvKiovKi57dHMsdHN4fScsXG4gICAgICAgICctLWNvbmZpZycsIGNvbmZpZ1BhdGgsIC8vIFVzZSB0aGUgZGV0ZXJtaW5lZCBjb25maWdcbiAgICAgICAgLi4uKGZpeCA/IFsnLS1maXgnXSA6IFtdKSxcbiAgICAgICAgLi4uKGRlYnVnID8gWyctLWRlYnVnJ10gOiBbXSksXG4gICAgICAgICctLW5vLWVycm9yLW9uLXVubWF0Y2hlZC1wYXR0ZXJuJyAvLyBEb24ndCBlcnJvciBpZiBubyBmaWxlcyBhcmUgZm91bmRcbiAgICAgIF0sIHtcbiAgICAgICAgcmVqZWN0OiBmYWxzZSxcbiAgICAgICAgc3RkaW86ICdwaXBlJyxcbiAgICAgICAgY3dkLFxuICAgICAgICBzaGVsbDogdHJ1ZSAvLyBOZWVkZWQgZm9yIGdsb2IgcGF0dGVybiBleHBhbnNpb25cbiAgICAgIH0pO1xuXG4gICAgICAvLyBEaXNwbGF5IFRTIG91dHB1dFxuICAgICAgaWYodHNSZXN1bHQuc3Rkb3V0KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKHRzUmVzdWx0LnN0ZG91dCk7XG4gICAgICB9XG5cbiAgICAgIGlmKHRzUmVzdWx0LnN0ZGVycikge1xuICAgICAgICBjb25zb2xlLmVycm9yKHRzUmVzdWx0LnN0ZGVycik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgZm9yIEVTTGludCBjb21tYW5kIG5vdCBmb3VuZCBlcnJvclxuICAgIGNvbnN0IGVzbGludE5vdEZvdW5kID0ganNSZXN1bHQuc3RkZXJyPy5pbmNsdWRlcygnY29tbWFuZCBub3QgZm91bmQnKSB8fCBqc1Jlc3VsdC5zdGRlcnI/LmluY2x1ZGVzKCdlc2xpbnQ6IGNvbW1hbmQgbm90IGZvdW5kJyk7XG4gICAgaWYoZXNsaW50Tm90Rm91bmQpIHtcbiAgICAgIHNwaW5uZXIuZmFpbCgnRVNMaW50IG5vdCBmb3VuZCEnKTtcbiAgICAgIGxvZyhgXFxuJHtjbGlOYW1lfSBFcnJvcjogTGV4J3MgRVNMaW50IGJpbmFyeSBub3QgZm91bmQuIFRoaXMgbWF5IGJlIGEgTGV4IGluc3RhbGxhdGlvbiBpc3N1ZS5gLCAnZXJyb3InLCBxdWlldCk7XG4gICAgICBsb2coJ1BsZWFzZSB0cnkgcmVpbnN0YWxsaW5nIExleDogbnBtIGluc3RhbGwgLWcgQG5sYWJzL2xleCcsICdpbmZvJywgcXVpZXQpO1xuICAgICAgcmV0dXJuIDE7XG4gICAgfVxuXG4gICAgLy8gU3VjY2VzcyBpZiBib3RoIGV4aXQgY29kZXMgYXJlIDBcbiAgICBpZihqc1Jlc3VsdC5leGl0Q29kZSA9PT0gMCAmJiB0c1Jlc3VsdC5leGl0Q29kZSA9PT0gMCkge1xuICAgICAgc3Bpbm5lci5zdWNjZWVkKCdMaW50aW5nIGNvbXBsZXRlZCEnKTtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgICAvLyBDaGVjayBmb3Igc3BlY2lhbCBjYXNlcyAtIG5vIGZpbGVzIGZvdW5kXG4gICAgY29uc3Qgbm9GaWxlc0ZvdW5kID1cbiAgICAgICAgKGpzUmVzdWx0LnN0ZGVycj8uaW5jbHVkZXMoJ05vIHN1Y2ggZmlsZSBvciBkaXJlY3RvcnknKSB8fCBqc1Jlc3VsdC5zdGRvdXQ/LmluY2x1ZGVzKCdObyBzdWNoIGZpbGUgb3IgZGlyZWN0b3J5JykpICYmXG4gICAgICAgICghdXNlVHlwZXNjcmlwdCB8fCB0c1Jlc3VsdC5zdGRlcnI/LmluY2x1ZGVzKCdObyBzdWNoIGZpbGUgb3IgZGlyZWN0b3J5JykgfHwgdHNSZXN1bHQuc3Rkb3V0Py5pbmNsdWRlcygnTm8gc3VjaCBmaWxlIG9yIGRpcmVjdG9yeScpKTtcblxuICAgIGlmKG5vRmlsZXNGb3VuZCkge1xuICAgICAgc3Bpbm5lci5zdWNjZWVkKCdObyBmaWxlcyBmb3VuZCB0byBsaW50Jyk7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG4gICAgc3Bpbm5lci5mYWlsKCdMaW50aW5nIGZhaWxlZCEnKTtcbiAgICBsb2coYFxcbiR7Y2xpTmFtZX0gRXJyb3I6IEVTTGludCBmb3VuZCBpc3N1ZXMgaW4geW91ciBjb2RlLmAsICdlcnJvcicsIHF1aWV0KTtcbiAgICByZXR1cm4gMTtcbiAgfSBjYXRjaChlcnJvcikge1xuICAgIHNwaW5uZXIuZmFpbCgnTGludGluZyBmYWlsZWQhJyk7XG4gICAgbG9nKGBcXG4ke2NsaU5hbWV9IEVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCwgJ2Vycm9yJywgcXVpZXQpO1xuICAgIHJldHVybiAxO1xuICB9XG59O1xuXG4vKipcbiAqIFVzZSBBSSB0byBmaXggbGludGluZyBlcnJvcnMgdGhhdCBjb3VsZG4ndCBiZSBmaXhlZCBhdXRvbWF0aWNhbGx5XG4gKi9cbmNvbnN0IGFwcGx5QUlGaXggPSBhc3luYyAoXG4gIGN3ZDogc3RyaW5nLFxuICBlcnJvcnM6IHN0cmluZyxcbiAgcXVpZXQ6IGJvb2xlYW5cbik6IFByb21pc2U8dm9pZD4gPT4ge1xuICBjb25zdCBzcGlubmVyID0gY3JlYXRlU3Bpbm5lcihxdWlldCk7XG4gIHNwaW5uZXIuc3RhcnQoJ1VzaW5nIEFJIHRvIGZpeCByZW1haW5pbmcgbGludCBpc3N1ZXMuLi4nKTtcblxuICB0cnkge1xuICAgIC8vIEV4dHJhY3QgZmlsZSBwYXRocyBhbmQgZXJyb3JzIGZyb20gdGhlIEVTTGludCBvdXRwdXRcbiAgICBjb25zdCBmaWxlRXJyb3JNYXAgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nW10+KCk7XG4gICAgY29uc3QgbGluZXMgPSBlcnJvcnMuc3BsaXQoJ1xcbicpO1xuICAgIGxldCBjdXJyZW50RmlsZSA9ICcnO1xuXG4gICAgLy8gSW1wcm92ZWQgcGFyc2luZyBvZiBFU0xpbnQgb3V0cHV0XG4gICAgZm9yKGNvbnN0IGxpbmUgb2YgbGluZXMpIHtcbiAgICAgIC8vIE1hdGNoIGZpbGUgcGF0aHMgKHRoZXkgdHlwaWNhbGx5IHN0YXJ0IHdpdGggLyBvciBDOlxcIG9uIFdpbmRvd3MpXG4gICAgICBpZihsaW5lLm1hdGNoKC9eKFxcL3xbQS1aXTpcXFxcKS4qP1xcLihqc3xqc3h8dHN8dHN4KSQvKSkge1xuICAgICAgICBjdXJyZW50RmlsZSA9IGxpbmUudHJpbSgpO1xuICAgICAgICBpZighZmlsZUVycm9yTWFwLmhhcyhjdXJyZW50RmlsZSkpIHtcbiAgICAgICAgICBmaWxlRXJyb3JNYXAuc2V0KGN1cnJlbnRGaWxlLCBbXSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIC8vIE1hdGNoIGVycm9yIGxpbmVzICh0aGV5IHR5cGljYWxseSBoYXZlIGxpbmU6Y29sdW1uIGZvcm1hdClcbiAgICAgIGVsc2UgaWYoY3VycmVudEZpbGUgJiYgbGluZS50cmltKCkgJiYgbGluZS5tYXRjaCgvXFxzK1xcZCs6XFxkK1xccysoZXJyb3J8d2FybmluZylcXHMrLykpIHtcbiAgICAgICAgY29uc3QgZXJyb3JBcnJheSA9IGZpbGVFcnJvck1hcC5nZXQoY3VycmVudEZpbGUpO1xuICAgICAgICBpZihlcnJvckFycmF5KSB7XG4gICAgICAgICAgZXJyb3JBcnJheS5wdXNoKGxpbmUudHJpbSgpKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIElmIG5vIGVycm9ycyB3ZXJlIGZvdW5kIHVzaW5nIHRoZSByZWdleCBhcHByb2FjaCwgdHJ5IGEgZGlmZmVyZW50IHBhcnNpbmcgc3RyYXRlZ3lcbiAgICBpZihmaWxlRXJyb3JNYXAuc2l6ZSA9PT0gMCkge1xuICAgICAgbG9nKCdVc2luZyBhbHRlcm5hdGl2ZSBlcnJvciBwYXJzaW5nIHN0cmF0ZWd5JywgJ2luZm8nLCBxdWlldCk7XG5cbiAgICAgIC8vIFJlc2V0IGFuZCB0cnkgYSBkaWZmZXJlbnQgcGFyc2luZyBhcHByb2FjaFxuICAgICAgY29uc3Qgc2VjdGlvbnMgPSBlcnJvcnMuc3BsaXQoJ1xcblxcbicpO1xuXG4gICAgICBmb3IoY29uc3Qgc2VjdGlvbiBvZiBzZWN0aW9ucykge1xuICAgICAgICBpZihzZWN0aW9uLnRyaW0oKSA9PT0gJycpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGxpbmVzID0gc2VjdGlvbi5zcGxpdCgnXFxuJyk7XG4gICAgICAgIGNvbnN0IGZpbGVQYXRoID0gbGluZXNbMF0udHJpbSgpO1xuXG4gICAgICAgIC8vIE9ubHkgcHJvY2VzcyBpZiBpdCBsb29rcyBsaWtlIGEgZmlsZSBwYXRoXG4gICAgICAgIGlmKGZpbGVQYXRoLm1hdGNoKC9cXC4oanN8anN4fHRzfHRzeCkkLykpIHtcbiAgICAgICAgICBmaWxlRXJyb3JNYXAuc2V0KGZpbGVQYXRoLCBbXSk7XG5cbiAgICAgICAgICBmb3IobGV0IGkgPSAxOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmKGxpbmVzW2ldLnRyaW0oKSAhPT0gJycpIHtcbiAgICAgICAgICAgICAgZmlsZUVycm9yTWFwLmdldChmaWxlUGF0aCk/LnB1c2gobGluZXNbaV0udHJpbSgpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBJZiBzdGlsbCBubyBmaWxlcyBmb3VuZCwgdHJ5IHRvIGV4dHJhY3QgZmlsZSBwYXRocyBkaXJlY3RseVxuICAgIGlmKGZpbGVFcnJvck1hcC5zaXplID09PSAwKSB7XG4gICAgICBsb2coJ1VzaW5nIGRpcmVjdCBmaWxlIHBhdGggZXh0cmFjdGlvbicsICdpbmZvJywgcXVpZXQpO1xuXG4gICAgICAvLyBGaW5kIGFsbCBmaWxlIHBhdGhzIGluIHRoZSBlcnJvciBvdXRwdXRcbiAgICAgIGNvbnN0IGZpbGVQYXRoUmVnZXggPSAvKD86XFwvfFtBLVpdOlxcXFwpKD86W146XFxuXStcXC8pKlteOlxcbl0rXFwuKGpzfGpzeHx0c3x0c3gpL2c7XG4gICAgICBjb25zdCBmaWxlUGF0aHMgPSBlcnJvcnMubWF0Y2goZmlsZVBhdGhSZWdleCkgfHwgW107XG5cbiAgICAgIGZvcihjb25zdCBmaWxlUGF0aCBvZiBmaWxlUGF0aHMpIHtcbiAgICAgICAgaWYoIWZpbGVFcnJvck1hcC5oYXMoZmlsZVBhdGgpICYmIGV4aXN0c1N5bmMoZmlsZVBhdGgpKSB7XG4gICAgICAgICAgZmlsZUVycm9yTWFwLnNldChmaWxlUGF0aCwgW10pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIEFkZCBrbm93biBwcm9ibGVtYXRpYyBmaWxlcyBpZiB0aGV5IGV4aXN0XG4gICAgICBjb25zdCBrbm93bkZpbGVzID0gW1xuICAgICAgICAnL1VzZXJzL25pdHJvZzcvRGV2ZWxvcG1lbnQvbGV4L3BhY2thZ2VzL2xleC9zcmMvY3JlYXRlL2NoYW5nZWxvZy50cycsXG4gICAgICAgICcvVXNlcnMvbml0cm9nNy9EZXZlbG9wbWVudC9sZXgvcGFja2FnZXMvbGV4L3NyYy91dGlscy9haVNlcnZpY2UudHMnLFxuICAgICAgICAnL1VzZXJzL25pdHJvZzcvRGV2ZWxvcG1lbnQvbGV4L3BhY2thZ2VzL2xleC9zcmMvdXRpbHMvYXBwLnRzJyxcbiAgICAgICAgJy9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L2xleC9wYWNrYWdlcy9sZXgvc3JjL3V0aWxzL3JlYWN0U2hpbS50cycsXG4gICAgICAgICcvVXNlcnMvbml0cm9nNy9EZXZlbG9wbWVudC9sZXgvcGFja2FnZXMvbGV4L3NyYy9jb21tYW5kcy9saW50L2F1dG9maXguanMnXG4gICAgICBdO1xuXG4gICAgICBmb3IoY29uc3QgZmlsZSBvZiBrbm93bkZpbGVzKSB7XG4gICAgICAgIGlmKGV4aXN0c1N5bmMoZmlsZSkgJiYgIWZpbGVFcnJvck1hcC5oYXMoZmlsZSkpIHtcbiAgICAgICAgICBmaWxlRXJyb3JNYXAuc2V0KGZpbGUsIFtdKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFByb2Nlc3MgZWFjaCBmaWxlIHdpdGggZXJyb3JzXG4gICAgZm9yKGNvbnN0IGZpbGVQYXRoIG9mIGZpbGVFcnJvck1hcC5rZXlzKCkpIHtcbiAgICAgIGlmKCFleGlzdHNTeW5jKGZpbGVQYXRoKSkge1xuICAgICAgICBsb2coYEZpbGUgbm90IGZvdW5kOiAke2ZpbGVQYXRofWAsICd3YXJuJywgcXVpZXQpO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgbG9nKGBQcm9jZXNzaW5nIGZpbGU6ICR7ZmlsZVBhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG5cbiAgICAgIC8vIENoZWNrIGlmIHdlJ3JlIHJ1bm5pbmcgaW4gQ3Vyc29yIElERVxuICAgICAgY29uc3QgaXNDdXJzb3JJREUgPSBMZXhDb25maWcuY29uZmlnLmFpPy5wcm92aWRlciA9PT0gJ2N1cnNvcicgfHwgcHJvY2Vzcy5lbnYuQ1VSU09SX0lERSA9PT0gJ3RydWUnO1xuXG4gICAgICBpZihpc0N1cnNvcklERSkge1xuICAgICAgICAvLyBJZiB3ZSdyZSBpbiBDdXJzb3IgSURFLCB1c2UgaXRzIGJ1aWx0LWluIEFJIGNhcGFiaWxpdGllc1xuICAgICAgICB0cnkge1xuICAgICAgICAgIC8vIENyZWF0ZSBhIHByb21wdCBmb3IgQ3Vyc29yIEFJXG4gICAgICAgICAgY29uc3QgcHJvbXB0ID0gYEZpeCBhbGwgRVNMaW50IGVycm9ycyBpbiB0aGlzIGZpbGUuIEZvY3VzIG9uOlxuMS4gRml4aW5nIG5hbWluZyBjb252ZW50aW9uc1xuMi4gRml4aW5nIHNvcnQta2V5cyBpc3N1ZXNcbjMuIFJlcGxhY2luZyBjb25zb2xlLmxvZyB3aXRoIGxvZyB1dGlsaXR5XG40LiBGaXhpbmcgbm8tcGx1c3BsdXMgaXNzdWVzXG41LiBGaXhpbmcgdW5uZWNlc3NhcnkgZXNjYXBlIGNoYXJhY3RlcnNcbjYuIEZpeGluZyBvdGhlciBFU0xpbnQgZXJyb3JzXG5cbkNSSVRJQ0FMIFJFUVVJUkVNRU5UUzpcbi0gT05MWSBmaXggdGhlIHNwZWNpZmljIGxpbmVzIHdpdGggRVNMaW50IGVycm9yc1xuLSBETyBOT1QgbW9kaWZ5IGFueSBvdGhlciBsaW5lcyBvZiBjb2RlXG4tIERPIE5PVCByZW1vdmUgbGluZSBicmVha3MgdW5sZXNzIHRoZXkgYXJlIHNwZWNpZmljYWxseSBjYXVzaW5nIEVTTGludCBlcnJvcnNcbi0gRE8gTk9UIGNvbmRlbnNlIG11bHRpLWxpbmUgc3RydWN0dXJlcyB0byBzaW5nbGUgbGluZXNcbi0gUFJFU0VSVkUgYWxsIGV4aXN0aW5nIGxpbmUgYnJlYWtzIGFuZCBmb3JtYXR0aW5nIHRoYXQgaXMgbm90IGNhdXNpbmcgZXJyb3JzXG5cblNQRUNJRklDIEZPUk1BVFRJTkcgUlVMRVM6XG4tIE1haW50YWluIHByb3BlciBpbmRlbnRhdGlvbiAoMiBzcGFjZXMpXG4tIEtlZXAgbGluZSBicmVha3MgYmV0d2VlbiBjbGFzcy9pbnRlcmZhY2UgZGVjbGFyYXRpb24gYW5kIHRoZWlyIG1lbWJlcnNcbi0gS2VlcCBsaW5lIGJyZWFrcyBiZXR3ZWVuIG1ldGhvZHNcbi0gRW5zdXJlIHRoZXJlIGlzIGEgbGluZSBicmVhayBhZnRlciBvcGVuaW5nIGJyYWNlcyBmb3IgY2xhc3NlcywgaW50ZXJmYWNlcywgYW5kIG1ldGhvZHNcbi0gRE8gTk9UIHBsYWNlIGNsYXNzL2ludGVyZmFjZSBwcm9wZXJ0aWVzIG9yIG1ldGhvZHMgb24gdGhlIHNhbWUgbGluZSBhcyB0aGUgb3BlbmluZyBicmFjZVxuLSBQcmVzZXJ2ZSBlbXB0eSBsaW5lcyBiZXR3ZWVuIGxvZ2ljYWwgY29kZSBibG9ja3Ncbi0gUFJFU0VSVkUgbXVsdGktbGluZSBpbXBvcnRzIC0gZG8gbm90IGNvbmRlbnNlIHRoZW0gdG8gc2luZ2xlIGxpbmVzXG4tIFBSRVNFUlZFIG11bHRpLWxpbmUgb2JqZWN0L2FycmF5IGRlY2xhcmF0aW9ucyAtIGRvIG5vdCBjb25kZW5zZSB0aGVtIHRvIHNpbmdsZSBsaW5lc1xuXG5TT1JULUtFWVMgUlVMRSAoSElHSEVTVCBQUklPUklUWSk6XG4tIEFsbCBvYmplY3QgbGl0ZXJhbCBrZXlzIE1VU1QgYmUgc29ydGVkIGFscGhhYmV0aWNhbGx5IGluIGFzY2VuZGluZyBvcmRlclxuLSBUaGlzIGFwcGxpZXMgdG8gQUxMIG9iamVjdHMgaW4gdGhlIGZpbGUsIG5vdCBqdXN0IHRob3NlIHdpdGggZXhwbGljaXQgc29ydC1rZXlzIGVycm9yc1xuLSBFeGFtcGxlOiB7YjogMiwgYTogMSwgYzogM30gc2hvdWxkIGJlY29tZSB7YTogMSwgYjogMiwgYzogM31cbi0gUHJlc2VydmUgdGhlIG9yaWdpbmFsIGZvcm1hdHRpbmcgYW5kIGxpbmUgYnJlYWtzIHdoZW4gc29ydGluZ1xuXG5FeGFtcGxlIG9mIENPUlJFQ1QgZm9ybWF0dGluZyAoRE8gTk9UIENIQU5HRSk6XG5leHBvcnQgY2xhc3MgVXNlckNvbnN0YW50cyB7XG4gIHN0YXRpYyByZWFkb25seSBBRERfSVRFTV9FUlJPUjogc3RyaW5nID0gJ1VTRVJfQUREX0lURU1fRVJST1InO1xuICBzdGF0aWMgcmVhZG9ubHkgT1RIRVJfQ09OU1RBTlQ6IHN0cmluZyA9ICdPVEhFUl9DT05TVEFOVCc7XG59XG5cbmNvbnN0cnVjdG9yKGZsdXg6IEZsdXhGcmFtZXdvcmssIEN1c3RvbUFkYXB0ZXI6IHR5cGVvZiBFdmVudCA9IEV2ZW50KSB7XG4gIHRoaXMuQ3VzdG9tQWRhcHRlciA9IEN1c3RvbUFkYXB0ZXI7XG4gIHRoaXMuZmx1eCA9IGZsdXg7XG59XG5cbmltcG9ydCB7XG4gIGFwcCxcbiAgZXZlbnRzLFxuICBpbWFnZXMsXG4gIGxvY2F0aW9ucyxcbiAgbWVzc2FnZXMsXG4gIHBvc3RzLFxuICB0YWdzLFxuICB1c2VycyxcbiAgd2Vic29ja2V0XG59IGZyb20gJy4vc3RvcmVzJztcblxuY29uc3QgY29uZmlnID0ge1xuICBhcGlLZXk6ICd2YWx1ZScsXG4gIGJhc2VVcmw6ICdodHRwczovL2FwaS5leGFtcGxlLmNvbScsXG4gIHRpbWVvdXQ6IDUwMDBcbn07XG5cbkV4YW1wbGUgb2YgSU5DT1JSRUNUIGZvcm1hdHRpbmcgKEZJWCBUSElTKTpcbmV4cG9ydCBjbGFzcyBVc2VyQ29uc3RhbnRzIHtzdGF0aWMgcmVhZG9ubHkgQUREX0lURU1fRVJST1I6IHN0cmluZyA9ICdVU0VSX0FERF9JVEVNX0VSUk9SJztcbiAgc3RhdGljIHJlYWRvbmx5IE9USEVSX0NPTlNUQU5UOiBzdHJpbmcgPSAnT1RIRVJfQ09OU1RBTlQnO1xufVxuXG5jb25zdHJ1Y3RvcihmbHV4OiBGbHV4RnJhbWV3b3JrLCBDdXN0b21BZGFwdGVyOiB0eXBlb2YgRXZlbnQgPSBFdmVudCkge3RoaXMuQ3VzdG9tQWRhcHRlciA9IEN1c3RvbUFkYXB0ZXI7XG4gIHRoaXMuZmx1eCA9IGZsdXg7fVxuXG5pbXBvcnQge2FwcCwgZXZlbnRzLCBpbWFnZXMsIGxvY2F0aW9ucywgbWVzc2FnZXMsIHBvc3RzLCB0YWdzLCB1c2Vycywgd2Vic29ja2V0fSBmcm9tICcuL3N0b3Jlcyc7XG5cbmNvbnN0IGNvbmZpZyA9IHtiYXNlVXJsOiAnaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20nLCBhcGlLZXk6ICd2YWx1ZScsIHRpbWVvdXQ6IDUwMDB9O1xuXG5GaXggT05MWSB0aGUgc3BlY2lmaWMgRVNMaW50IGVycm9ycy4gUmV0dXJuIHRoZSBwcm9wZXJseSBmb3JtYXR0ZWQgY29kZS5gO1xuXG4gICAgICAgICAgLy8gVHJ5IHRvIHVzZSBDdXJzb3IgQ0xJIGlmIGF2YWlsYWJsZVxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvLyBDcmVhdGUgYSB0ZW1wb3JhcnkgcHJvbXB0IGZpbGVcbiAgICAgICAgICAgIGNvbnN0IHByb21wdEZpbGUgPSBwYXRoUmVzb2x2ZShjd2QsICcuY3Vyc29yX3Byb21wdF90ZW1wLnR4dCcpO1xuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhwcm9tcHRGaWxlLCBwcm9tcHQsICd1dGY4Jyk7XG5cbiAgICAgICAgICAgIC8vIFVzZSBDdXJzb3IgQ0xJIHRvIGZpeCB0aGUgZmlsZVxuICAgICAgICAgICAgYXdhaXQgZXhlY2EoJ2N1cnNvcicsIFsnZWRpdCcsICctLWZpbGUnLCBmaWxlUGF0aCwgJy0tcHJvbXB0LWZpbGUnLCBwcm9tcHRGaWxlXSwge1xuICAgICAgICAgICAgICByZWplY3Q6IGZhbHNlLFxuICAgICAgICAgICAgICBzdGRpbzogJ3BpcGUnLFxuICAgICAgICAgICAgICBjd2RcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBDbGVhbiB1cFxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgdW5saW5rU3luYyhwcm9tcHRGaWxlKTtcbiAgICAgICAgICAgIH0gY2F0Y2goX2Vycm9yKSB7XG4gICAgICAgICAgICAgIC8vIElnbm9yZSBjbGVhbnVwIGVycm9yc1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsb2coYEFwcGxpZWQgQ3Vyc29yIEFJIGZpeGVzIHRvICR7ZmlsZVBhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgICAgfSBjYXRjaChlcnJvcikge1xuICAgICAgICAgICAgLy8gSWYgQ3Vyc29yIENMSSBmYWlscywgZmFsbCBiYWNrIHRvIGRpcmVjdCBmaXhlc1xuICAgICAgICAgICAgY29uc3Qgd2FzTW9kaWZpZWQgPSBhd2FpdCBhcHBseURpcmVjdEZpeGVzKGZpbGVQYXRoLCBxdWlldCk7XG4gICAgICAgICAgICBpZih3YXNNb2RpZmllZCkge1xuICAgICAgICAgICAgICBsb2coYEFwcGxpZWQgZGlyZWN0IGZpeGVzIHRvICR7ZmlsZVBhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoKGVycm9yKSB7XG4gICAgICAgICAgbG9nKGBFcnJvciB1c2luZyBDdXJzb3IgQUk6ICR7ZXJyb3IubWVzc2FnZX1gLCAnZXJyb3InLCBxdWlldCk7XG4gICAgICAgICAgLy8gRmFsbCBiYWNrIHRvIGRpcmVjdCBmaXhlc1xuICAgICAgICAgIGF3YWl0IGFwcGx5RGlyZWN0Rml4ZXMoZmlsZVBhdGgsIHF1aWV0KTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gRm9yIG5vbi1DdXJzb3IgZW52aXJvbm1lbnRzLCBhcHBseSBkaXJlY3QgZml4ZXMgYW5kIHRoZW4gdXNlIEFJIHNlcnZpY2VcbiAgICAgICAgY29uc3Qgd2FzTW9kaWZpZWQgPSBhd2FpdCBhcHBseURpcmVjdEZpeGVzKGZpbGVQYXRoLCBxdWlldCk7XG4gICAgICAgIGlmKHdhc01vZGlmaWVkKSB7XG4gICAgICAgICAgbG9nKGBBcHBsaWVkIGRpcmVjdCBmaXhlcyB0byAke2ZpbGVQYXRofWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRm9yIHJlbWFpbmluZyBpc3N1ZXMsIHVzZSB0aGUgQUkgc2VydmljZVxuICAgICAgICBjb25zdCBmaWxlRXJyb3JzID0gZmlsZUVycm9yTWFwLmdldChmaWxlUGF0aCkgfHwgW107XG4gICAgICAgIGlmKGZpbGVFcnJvcnMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvLyBJbXBvcnQgdGhlIEFJIHNlcnZpY2UgZHluYW1pY2FsbHkgdG8gYXZvaWQgY2lyY3VsYXIgZGVwZW5kZW5jaWVzXG4gICAgICAgICAgICBjb25zdCB7Y2FsbEFJU2VydmljZX0gPSBhd2FpdCBpbXBvcnQoJy4uLy4uL3V0aWxzL2FpU2VydmljZS5qcycpO1xuXG4gICAgICAgICAgICAvLyBSZWFkIHRoZSBmaWxlIGNvbnRlbnQgYWdhaW4gaW4gY2FzZSBpdCB3YXMgbW9kaWZpZWQgYnkgYXV0b21hdGVkIGZpeGVzXG4gICAgICAgICAgICBjb25zdCBmaWxlQ29udGVudCA9IHJlYWRGaWxlU3luYyhmaWxlUGF0aCwgJ3V0ZjgnKTtcblxuICAgICAgICAgICAgLy8gUHJlcGFyZSBhIHByb21wdCBmb3IgQUlcbiAgICAgICAgICAgIGNvbnN0IHByb21wdCA9IGBGaXggdGhlIGZvbGxvd2luZyBFU0xpbnQgZXJyb3JzIGluIHRoaXMgY29kZTpcbiR7ZmlsZUVycm9ycy5qb2luKCdcXG4nKX1cblxuSGVyZSdzIHRoZSBjb2RlOlxuXFxgXFxgXFxgXG4ke2ZpbGVDb250ZW50fVxuXFxgXFxgXFxgXG5cbkNSSVRJQ0FMIFJFUVVJUkVNRU5UUzpcbi0gT05MWSBmaXggdGhlIHNwZWNpZmljIGxpbmVzIHdpdGggRVNMaW50IGVycm9yc1xuLSBETyBOT1QgbW9kaWZ5IGFueSBvdGhlciBsaW5lcyBvZiBjb2RlXG4tIERPIE5PVCByZW1vdmUgbGluZSBicmVha3MgdW5sZXNzIHRoZXkgYXJlIHNwZWNpZmljYWxseSBjYXVzaW5nIEVTTGludCBlcnJvcnNcbi0gRE8gTk9UIGNvbmRlbnNlIG11bHRpLWxpbmUgc3RydWN0dXJlcyB0byBzaW5nbGUgbGluZXNcbi0gUFJFU0VSVkUgYWxsIGV4aXN0aW5nIGxpbmUgYnJlYWtzIGFuZCBmb3JtYXR0aW5nIHRoYXQgaXMgbm90IGNhdXNpbmcgZXJyb3JzXG5cblNQRUNJRklDIEZPUk1BVFRJTkcgUlVMRVM6XG4tIE1haW50YWluIHByb3BlciBpbmRlbnRhdGlvbiAoMiBzcGFjZXMpXG4tIEtlZXAgbGluZSBicmVha3MgYmV0d2VlbiBjbGFzcy9pbnRlcmZhY2UgZGVjbGFyYXRpb24gYW5kIHRoZWlyIG1lbWJlcnNcbi0gS2VlcCBsaW5lIGJyZWFrcyBiZXR3ZWVuIG1ldGhvZHNcbi0gRW5zdXJlIHRoZXJlIGlzIGEgbGluZSBicmVhayBhZnRlciBvcGVuaW5nIGJyYWNlcyBmb3IgY2xhc3NlcywgaW50ZXJmYWNlcywgYW5kIG1ldGhvZHNcbi0gRE8gTk9UIHBsYWNlIGNsYXNzL2ludGVyZmFjZSBwcm9wZXJ0aWVzIG9yIG1ldGhvZHMgb24gdGhlIHNhbWUgbGluZSBhcyB0aGUgb3BlbmluZyBicmFjZVxuLSBQcmVzZXJ2ZSBlbXB0eSBsaW5lcyBiZXR3ZWVuIGxvZ2ljYWwgY29kZSBibG9ja3Ncbi0gUFJFU0VSVkUgbXVsdGktbGluZSBpbXBvcnRzIC0gZG8gbm90IGNvbmRlbnNlIHRoZW0gdG8gc2luZ2xlIGxpbmVzXG4tIFBSRVNFUlZFIG11bHRpLWxpbmUgb2JqZWN0L2FycmF5IGRlY2xhcmF0aW9ucyAtIGRvIG5vdCBjb25kZW5zZSB0aGVtIHRvIHNpbmdsZSBsaW5lc1xuXG5TT1JULUtFWVMgUlVMRSAoSElHSEVTVCBQUklPUklUWSk6XG4tIEFsbCBvYmplY3QgbGl0ZXJhbCBrZXlzIE1VU1QgYmUgc29ydGVkIGFscGhhYmV0aWNhbGx5IGluIGFzY2VuZGluZyBvcmRlclxuLSBUaGlzIGFwcGxpZXMgdG8gQUxMIG9iamVjdHMgaW4gdGhlIGZpbGUsIG5vdCBqdXN0IHRob3NlIHdpdGggZXhwbGljaXQgc29ydC1rZXlzIGVycm9yc1xuLSBFeGFtcGxlOiB7YjogMiwgYTogMSwgYzogM30gc2hvdWxkIGJlY29tZSB7YTogMSwgYjogMiwgYzogM31cbi0gUHJlc2VydmUgdGhlIG9yaWdpbmFsIGZvcm1hdHRpbmcgYW5kIGxpbmUgYnJlYWtzIHdoZW4gc29ydGluZ1xuXG5XSEFUIFRPIEZJWDpcbjEuIFNvcnRpbmcgYWxsIG9iamVjdCBrZXlzIGFscGhhYmV0aWNhbGx5IChzb3J0LWtleXMgcnVsZSkgLSBBTEwgb2JqZWN0cyBtdXN0IGhhdmUgc29ydGVkIGtleXNcbjIuIEZpeGluZyBuYW1pbmcgY29udmVudGlvbnMgLSBPTkxZIGZvciB2YXJpYWJsZXMvZnVuY3Rpb25zIHdpdGggbmFtaW5nIGVycm9yc1xuMy4gUmVwbGFjaW5nIGNvbnNvbGUubG9nIHdpdGggbG9nIHV0aWxpdHkgLSBPTkxZIGZvciBjb25zb2xlLmxvZyBzdGF0ZW1lbnRzXG40LiBGaXhpbmcgbm8tcGx1c3BsdXMgaXNzdWVzIC0gT05MWSBmb3IgKysvLS0gb3BlcmF0b3JzXG41LiBGaXhpbmcgdW5uZWNlc3NhcnkgZXNjYXBlIGNoYXJhY3RlcnMgLSBPTkxZIGZvciBlc2NhcGVkIGNoYXJhY3RlcnMgdGhhdCBkb24ndCBuZWVkIGVzY2FwaW5nXG42LiBQcm9wZXIgaW5kZW50YXRpb24gYW5kIHNwYWNpbmcgLSBPTkxZIHdoZXJlIHNwZWNpZmljYWxseSByZXF1aXJlZCBieSBlcnJvcnNcbjcuIFN0cmluZyBxdW90ZXMgY29uc2lzdGVuY3kgKHVzZSBzaW5nbGUgcXVvdGVzKSAtIE9OTFkgZm9yIHN0cmluZyBsaXRlcmFscyB3aXRoIHF1b3RlIGVycm9yc1xuOC4gSW1wb3J0IG9yZGVyIGFuZCBzcGFjaW5nIC0gT05MWSBmb3IgaW1wb3J0cyB3aXRoIG9yZGVyL3NwYWNpbmcgZXJyb3JzXG45LiBGdW5jdGlvbiBwYXJhbWV0ZXIgZm9ybWF0dGluZyAtIE9OTFkgZm9yIGZ1bmN0aW9ucyB3aXRoIHBhcmFtZXRlciBlcnJvcnNcbjEwLiBWYXJpYWJsZSBuYW1pbmcgY29udmVudGlvbnMgLSBPTkxZIGZvciB2YXJpYWJsZXMgd2l0aCBuYW1pbmcgZXJyb3JzXG4xMS4gTm8gdW51c2VkIHZhcmlhYmxlcyBvciBpbXBvcnRzIC0gT05MWSBmb3IgdW51c2VkIHZhcmlhYmxlcy9pbXBvcnRzXG4xMi4gQXZvaWRpbmcgbmVzdGVkIHRlcm5hcmllcyAtIE9OTFkgZm9yIG5lc3RlZCB0ZXJuYXJ5IGV4cHJlc3Npb25zXG4xMy4gQW55IG90aGVyIEVTTGludCBlcnJvcnMgLSBPTkxZIGZvciB0aGUgc3BlY2lmaWMgZXJyb3JzIGxpc3RlZCBhYm92ZVxuXG5XSEFUIE5PVCBUTyBGSVg6XG4tIERvIG5vdCBjaGFuZ2UgcHJvcGVybHkgZm9ybWF0dGVkIG11bHRpLWxpbmUgc3RydWN0dXJlc1xuLSBEbyBub3QgcmVtb3ZlIGxpbmUgYnJlYWtzIHRoYXQgYXJlIG5vdCBjYXVzaW5nIGVycm9yc1xuLSBEbyBub3QgY2hhbmdlIGluZGVudGF0aW9uIHRoYXQgaXMgYWxyZWFkeSBjb3JyZWN0XG4tIERvIG5vdCBtb2RpZnkgc3BhY2luZyB0aGF0IGlzIGFscmVhZHkgY29ycmVjdFxuLSBEbyBub3QgY29uZGVuc2UgcmVhZGFibGUgbXVsdGktbGluZSBjb2RlIHRvIHNpbmdsZSBsaW5lc1xuLSBEbyBub3QgbW9kaWZ5IGNvZGUgdGhhdCBpcyBub3QgbWVudGlvbmVkIGluIHRoZSBFU0xpbnQgZXJyb3JzXG5cbkV4YW1wbGUgb2YgQ09SUkVDVCBmb3JtYXR0aW5nIChETyBOT1QgQ0hBTkdFKTpcbmV4cG9ydCBjbGFzcyBVc2VyQ29uc3RhbnRzIHtcbiAgc3RhdGljIHJlYWRvbmx5IEFERF9JVEVNX0VSUk9SOiBzdHJpbmcgPSAnVVNFUl9BRERfSVRFTV9FUlJPUic7XG4gIHN0YXRpYyByZWFkb25seSBPVEhFUl9DT05TVEFOVDogc3RyaW5nID0gJ09USEVSX0NPTlNUQU5UJztcbn1cblxuY29uc3RydWN0b3IoZmx1eDogRmx1eEZyYW1ld29yaywgQ3VzdG9tQWRhcHRlcjogdHlwZW9mIEV2ZW50ID0gRXZlbnQpIHtcbiAgdGhpcy5DdXN0b21BZGFwdGVyID0gQ3VzdG9tQWRhcHRlcjtcbiAgdGhpcy5mbHV4ID0gZmx1eDtcbn1cblxuaW1wb3J0IHtcbiAgYXBwLFxuICBldmVudHMsXG4gIGltYWdlcyxcbiAgbG9jYXRpb25zLFxuICBtZXNzYWdlcyxcbiAgcG9zdHMsXG4gIHRhZ3MsXG4gIHVzZXJzLFxuICB3ZWJzb2NrZXRcbn0gZnJvbSAnLi9zdG9yZXMnO1xuXG5jb25zdCBjb25maWcgPSB7XG4gIGFwaUtleTogJ3ZhbHVlJyxcbiAgYmFzZVVybDogJ2h0dHBzOi8vYXBpLmV4YW1wbGUuY29tJyxcbiAgdGltZW91dDogNTAwMFxufTtcblxuRXhhbXBsZSBvZiBJTkNPUlJFQ1QgZm9ybWF0dGluZyAoRklYIFRISVMpOlxuZXhwb3J0IGNsYXNzIFVzZXJDb25zdGFudHMge3N0YXRpYyByZWFkb25seSBBRERfSVRFTV9FUlJPUjogc3RyaW5nID0gJ1VTRVJfQUREX0lURU1fRVJST1InO1xuICBzdGF0aWMgcmVhZG9ubHkgT1RIRVJfQ09OU1RBTlQ6IHN0cmluZyA9ICdPVEhFUl9DT05TVEFOVCc7XG59XG5cbmNvbnN0cnVjdG9yKGZsdXg6IEZsdXhGcmFtZXdvcmssIEN1c3RvbUFkYXB0ZXI6IHR5cGVvZiBFdmVudCA9IEV2ZW50KSB7dGhpcy5DdXN0b21BZGFwdGVyID0gQ3VzdG9tQWRhcHRlcjtcbiAgdGhpcy5mbHV4ID0gZmx1eDt9XG5cbmltcG9ydCB7YXBwLCBldmVudHMsIGltYWdlcywgbG9jYXRpb25zLCBtZXNzYWdlcywgcG9zdHMsIHRhZ3MsIHVzZXJzLCB3ZWJzb2NrZXR9IGZyb20gJy4vc3RvcmVzJztcblxuY29uc3QgY29uZmlnID0ge2Jhc2VVcmw6ICdodHRwczovL2FwaS5leGFtcGxlLmNvbScsIGFwaUtleTogJ3ZhbHVlJywgdGltZW91dDogNTAwMH07XG5cbkZpeCBPTkxZIHRoZSBzcGVjaWZpYyBFU0xpbnQgZXJyb3JzIGxpc3RlZCBhYm92ZS4gUmV2aWV3IHRoZSBlbnRpcmUgZmlsZSBmb3IgY29tcGxpYW5jZSB3aXRoIGFsbCBFU0xpbnQgcnVsZXMuXG5SZXR1cm4gb25seSB0aGUgcHJvcGVybHkgZm9ybWF0dGVkIGZpeGVkIGNvZGUgd2l0aG91dCBhbnkgZXhwbGFuYXRpb25zLmA7XG5cbiAgICAgICAgICAgIGNvbnN0IGZpeGVkQ29udGVudCA9IGF3YWl0IGNhbGxBSVNlcnZpY2UocHJvbXB0LCBxdWlldCk7XG5cbiAgICAgICAgICAgIGlmKGZpeGVkQ29udGVudCAmJiBmaXhlZENvbnRlbnQgIT09IGZpbGVDb250ZW50KSB7XG4gICAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoZmlsZVBhdGgsIGZpeGVkQ29udGVudCwgJ3V0ZjgnKTtcbiAgICAgICAgICAgICAgbG9nKGBBcHBsaWVkIEFJIGZpeGVzIHRvICR7ZmlsZVBhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaChlcnJvcikge1xuICAgICAgICAgICAgbG9nKGBFcnJvciBhcHBseWluZyBBSSBmaXhlcyB0byAke2ZpbGVQYXRofTogJHtlcnJvci5tZXNzYWdlfWAsICdlcnJvcicsIHF1aWV0KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBzcGlubmVyLnN1Y2NlZWQoJ0FJIGZpeGVzIGFwcGxpZWQgc3VjY2Vzc2Z1bGx5IScpO1xuICB9IGNhdGNoKGVycm9yKSB7XG4gICAgc3Bpbm5lci5mYWlsKCdGYWlsZWQgdG8gYXBwbHkgQUkgZml4ZXMnKTtcbiAgICBsb2coYEVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCwgJ2Vycm9yJywgcXVpZXQpO1xuICAgIGlmKCFxdWlldCkge1xuICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIEFwcGx5IGRpcmVjdCBmaXhlcyB0byBjb21tb24gRVNMaW50IGlzc3Vlc1xuICovXG5jb25zdCBhcHBseURpcmVjdEZpeGVzID0gYXN5bmMgKGZpbGVQYXRoOiBzdHJpbmcsIHF1aWV0OiBib29sZWFuKTogUHJvbWlzZTxib29sZWFuPiA9PiB7XG4gIGxldCB3YXNNb2RpZmllZCA9IGZhbHNlO1xuXG4gIHRyeSB7XG4gICAgLy8gUmVhZCBmaWxlIGNvbnRlbnRcbiAgICBjb25zdCBmaWxlQ29udGVudCA9IHJlYWRGaWxlU3luYyhmaWxlUGF0aCwgJ3V0ZjgnKTtcbiAgICBsZXQgbmV3Q29udGVudCA9IGZpbGVDb250ZW50O1xuXG4gICAgLy8gRml4IGlzc3VlcyBiYXNlZCBvbiBmaWxlbmFtZVxuICAgIGlmKGZpbGVQYXRoLmluY2x1ZGVzKCdhaVNlcnZpY2UudHMnKSkge1xuICAgICAgbG9nKCdGaXhpbmcgaXNzdWVzIGluIGFpU2VydmljZS50cycsICdpbmZvJywgcXVpZXQpO1xuXG4gICAgICAvLyBGaXggdGhlIG9yZGVyIG9mIGtleXMgaW4gaGVhZGVycyBvYmplY3RzXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvblxcL2pzb24nLFxccyonQXV0aG9yaXphdGlvbic6IGBCZWFyZXIvZyxcbiAgICAgICAgJ1xcJ0F1dGhvcml6YXRpb25cXCc6IGBCZWFyZXJcXCcsIFxcJ0NvbnRlbnQtVHlwZVxcJzogXFwnYXBwbGljYXRpb24vanNvblxcJydcbiAgICAgICk7XG5cbiAgICAgIC8vIEZpeCBtZXRob2QgYW5kIGhlYWRlcnMgb3JkZXJcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9oZWFkZXJzOiB7KFtefV0qKX0sXFxzKm1ldGhvZDogJ1BPU1QnL2csXG4gICAgICAgICdtZXRob2Q6IFxcJ1BPU1RcXCcsXFxuICAgICAgaGVhZGVyczogeyQxfSdcbiAgICAgICk7XG5cbiAgICAgIC8vIEZpeCByb2xlIGFuZCBjb250ZW50IG9yZGVyXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAve3JvbGU6ICdzeXN0ZW0nLCBjb250ZW50Oi9nLFxuICAgICAgICAne2NvbnRlbnQ6LCByb2xlOiBcXCdzeXN0ZW1cXCcsJ1xuICAgICAgKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC97cm9sZTogJ3VzZXInLCBjb250ZW50Oi9nLFxuICAgICAgICAne2NvbnRlbnQ6LCByb2xlOiBcXCd1c2VyXFwnLCdcbiAgICAgICk7XG5cbiAgICAgIC8vIEZpeCBuYW1pbmcgY29udmVudGlvbiBpc3N1ZXMgLSBwYXJhbWV0ZXIgbmFtZXMgd2l0aCBsZWFkaW5nIHVuZGVyc2NvcmVzXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvXFwoKFteKV0qPylfKFthLXpBLVowLTldKykoXFxzKjpbXildKilcXCkvZyxcbiAgICAgICAgJygkMSQyJDMpJ1xuICAgICAgKTtcblxuICAgICAgLy8gUmVwbGFjZSBjb25zb2xlLmxvZyBzdGF0ZW1lbnRzXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKC9jb25zb2xlXFwubG9nXFwoL2csICdsb2coJyk7XG5cbiAgICAgIC8vIEFkZCBsb2cgaW1wb3J0IGlmIG5lZWRlZFxuICAgICAgaWYoIW5ld0NvbnRlbnQuaW5jbHVkZXMoJ2ltcG9ydCB7bG9nfScpICYmIG5ld0NvbnRlbnQuaW5jbHVkZXMoJ2xvZygnKSkge1xuICAgICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAgIC9pbXBvcnQgeyhbXn1dKil9IGZyb20gJyguKiknOy8sXG4gICAgICAgICAgJ2ltcG9ydCB7JDF9IGZyb20gXFwnJDJcXCc7XFxuaW1wb3J0IHtsb2d9IGZyb20gXFwnLi9sb2cuanNcXCc7J1xuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEZpeCByZWFjdFNoaW0udHMgbmFtaW5nIGNvbnZlbnRpb25zXG4gICAgaWYoZmlsZVBhdGguaW5jbHVkZXMoJ3JlYWN0U2hpbS50cycpKSB7XG4gICAgICBsb2coJ0ZpeGluZyBuYW1pbmctY29udmVudGlvbiBpc3N1ZXMgaW4gcmVhY3RTaGltLnRzJywgJ2luZm8nLCBxdWlldCk7XG5cbiAgICAgIC8vIEZpeCBSZWFjdCBpbXBvcnQgbmFtaW5nXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAnaW1wb3J0ICogYXMgUmVhY3QgZnJvbScsXG4gICAgICAgICdpbXBvcnQgKiBhcyByZWFjdCBmcm9tJ1xuICAgICAgKTtcblxuICAgICAgLy8gRml4IFJlYWN0IHVzYWdlXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKC9SZWFjdFxcLi9nLCAncmVhY3QuJyk7XG4gICAgfVxuXG4gICAgLy8gRml4IGNoYW5nZWxvZy50cyBpc3N1ZXNcbiAgICBpZihmaWxlUGF0aC5pbmNsdWRlcygnY2hhbmdlbG9nLnRzJykpIHtcbiAgICAgIGxvZygnRml4aW5nIGlzc3VlcyBpbiBjaGFuZ2Vsb2cudHMnLCAnaW5mbycsIHF1aWV0KTtcblxuICAgICAgLy8gRml4IG5vLXBsdXNwbHVzXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKC8oXFx3KylcXCtcXCsvZywgJyQxICs9IDEnKTtcblxuICAgICAgLy8gRml4IHVubmVjZXNzYXJ5IGVzY2FwZSBjaGFyYWN0ZXJzXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKC9cXFxcXFwkL2csICckJyk7XG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKC9cXFxcXFwuL2csICcuJyk7XG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKC9cXFxcXFwqL2csICcqJyk7XG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKC9cXFxcOi9nLCAnOicpO1xuICAgIH1cblxuICAgIC8vIEZpeCBhcHAudHMgaXNzdWVzXG4gICAgaWYoZmlsZVBhdGguaW5jbHVkZXMoJ2FwcC50cycpKSB7XG4gICAgICBsb2coJ0ZpeGluZyBpc3N1ZXMgaW4gYXBwLnRzJywgJ2luZm8nLCBxdWlldCk7XG5cbiAgICAgIC8vIEZpeCBjb25zb2xlLmxvZ1xuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZSgvY29uc29sZVxcLmxvZ1xcKC9nLCAnbG9nKCcpO1xuXG4gICAgICAvLyBBZGQgbG9nIGltcG9ydCBpZiBuZWVkZWRcbiAgICAgIGlmKCFuZXdDb250ZW50LmluY2x1ZGVzKCdpbXBvcnQge2xvZ30nKSAmJiBuZXdDb250ZW50LmluY2x1ZGVzKCdsb2coJykpIHtcbiAgICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgICAvaW1wb3J0IGJveGVuIGZyb20gJ2JveGVuJzsvLFxuICAgICAgICAgICdpbXBvcnQgYm94ZW4gZnJvbSBcXCdib3hlblxcJztcXG5pbXBvcnQge2xvZ30gZnJvbSBcXCcuL2xvZy5qc1xcJzsnXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIC8vIEZpeCB1bm5lY2Vzc2FyeSBlc2NhcGUgY2hhcmFjdGVyc1xuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZSgvXFxcXFxcLy9nLCAnLycpO1xuICAgIH1cblxuICAgIC8vIEZpeCBhdXRvZml4LmpzIGlzc3Vlc1xuICAgIGlmKGZpbGVQYXRoLmluY2x1ZGVzKCdhdXRvZml4LmpzJykpIHtcbiAgICAgIGxvZygnRml4aW5nIGlzc3VlcyBpbiBhdXRvZml4LmpzJywgJ2luZm8nLCBxdWlldCk7XG5cbiAgICAgIC8vIEZpeCBpbXBvcnQgc3R5bGVcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9pbXBvcnQgeyhbXn1dKil9IGZyb20gJ3BhdGgnO1tcXHNcXG5dKmltcG9ydCB7KFtefV0qKX0gZnJvbSAncGF0aCc7LyxcbiAgICAgICAgJ2ltcG9ydCB7JDEsICQyfSBmcm9tIFxcJ3BhdGhcXCc7J1xuICAgICAgKTtcblxuICAgICAgLy8gRml4IHZhcmlhYmxlIG5hbWluZyBjb252ZW50aW9uXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvX19maWxlbmFtZS9nLFxuICAgICAgICAnY3VycmVudEZpbGVuYW1lJ1xuICAgICAgKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9fX2Rpcm5hbWUvZyxcbiAgICAgICAgJ2N1cnJlbnREaXJuYW1lJ1xuICAgICAgKTtcblxuICAgICAgLy8gRml4IG5lc3RlZCB0ZXJuYXJ5XG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvY29uc3QgcHJlZml4ID0gdHlwZSA9PT0gJ2Vycm9yJyBcXD8gJ1x1Mjc0QyAnIDogdHlwZSA9PT0gJ3N1Y2Nlc3MnIFxcPyAnXHUyNzA1ICcgOiAnXHUyMTM5XHVGRTBGICc7LyxcbiAgICAgICAgJ2xldCBwcmVmaXggPSBcXCdcdTIxMzlcdUZFMEYgXFwnO1xcbmlmKHR5cGUgPT09IFxcJ2Vycm9yXFwnKSB7XFxuICBwcmVmaXggPSBcXCdcdTI3NEMgXFwnO1xcbn0gZWxzZSBpZih0eXBlID09PSBcXCdzdWNjZXNzXFwnKSB7XFxuICBwcmVmaXggPSBcXCdcdTI3MDUgXFwnO1xcbn0nXG4gICAgICApO1xuXG4gICAgICAvLyBGaXggZnVuY3Rpb24gc3R5bGVcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9hc3luYyBmdW5jdGlvbiBydW5Fc2xpbnRGaXhcXChcXCkvZyxcbiAgICAgICAgJ2NvbnN0IHJ1bkVzbGludEZpeCA9IGFzeW5jICgpJ1xuICAgICAgKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9hc3luYyBmdW5jdGlvbiBnZXRGaWxlc1dpdGhFcnJvcnNcXChcXCkvZyxcbiAgICAgICAgJ2NvbnN0IGdldEZpbGVzV2l0aEVycm9ycyA9IGFzeW5jICgpJ1xuICAgICAgKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9hc3luYyBmdW5jdGlvbiBpc0N1cnNvckF2YWlsYWJsZVxcKFxcKS9nLFxuICAgICAgICAnY29uc3QgaXNDdXJzb3JBdmFpbGFibGUgPSBhc3luYyAoKSdcbiAgICAgICk7XG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvYXN5bmMgZnVuY3Rpb24gZml4RmlsZVdpdGhDdXJzb3JBSVxcKGZpbGVQYXRoXFwpL2csXG4gICAgICAgICdjb25zdCBmaXhGaWxlV2l0aEN1cnNvckFJID0gYXN5bmMgKGZpbGVQYXRoKSdcbiAgICAgICk7XG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvYXN5bmMgZnVuY3Rpb24gbWFpblxcKFxcKS9nLFxuICAgICAgICAnY29uc3QgbWFpbiA9IGFzeW5jICgpJ1xuICAgICAgKTtcblxuICAgICAgLy8gRml4IHVudXNlZCB2YXJpYWJsZXNcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9pbXBvcnQge2V4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luY30vZyxcbiAgICAgICAgJ2ltcG9ydCB7d3JpdGVGaWxlU3luY30nXG4gICAgICApO1xuXG4gICAgICAvLyBGaXggY29uc29sZS5sb2dcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9jb25zb2xlXFwubG9nXFwoYFxcJHtwcmVmaXh9IFxcJHttZXNzYWdlfWBcXCk7L2csXG4gICAgICAgICdwcm9jZXNzLnN0ZG91dC53cml0ZShgJHtwcmVmaXh9ICR7bWVzc2FnZX1cXFxcbmApOydcbiAgICAgICk7XG5cbiAgICAgIC8vIEZpeCB1bnVzZWQgZXJyb3IgdmFyaWFibGVzXG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvfSBjYXRjaFxcKGVycm9yXFwpIHtbXFxzXFxuXSpcXC9cXC8gSWdub3JlIGNsZWFudXAgZXJyb3JzL2csXG4gICAgICAgICd9IGNhdGNoKF8pIHtcXG4gICAgICAvLyBJZ25vcmUgY2xlYW51cCBlcnJvcnMnXG4gICAgICApO1xuICAgICAgbmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgL30gY2F0Y2hcXChlcnJvclxcKSB7W1xcc1xcbl0qbG9nXFwoL2csXG4gICAgICAgICd9IGNhdGNoKGVycikge1xcbiAgICBsb2coJ1xuICAgICAgKTtcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC99IGNhdGNoXFwoZXJyb3JcXCkge1tcXHNcXG5dKnJldHVybiBmYWxzZTsvZyxcbiAgICAgICAgJ30gY2F0Y2goXykge1xcbiAgICByZXR1cm4gZmFsc2U7J1xuICAgICAgKTtcblxuICAgICAgLy8gRml4IGF3YWl0IGluIGxvb3BcbiAgICAgIG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG4gICAgICAgIC9mb3JcXChjb25zdCBmaWxlUGF0aCBvZiBmaWxlc1dpdGhFcnJvcnNcXCkge1tcXHNcXG5dKmNvbnN0IHN1Y2Nlc3MgPSBhd2FpdCBmaXhGaWxlV2l0aEN1cnNvckFJXFwoZmlsZVBhdGhcXCk7L2csXG4gICAgICAgICdjb25zdCBmaXhSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoZmlsZXNXaXRoRXJyb3JzLm1hcChmaWxlUGF0aCA9PiBmaXhGaWxlV2l0aEN1cnNvckFJKGZpbGVQYXRoKSkpO1xcbmZvcihjb25zdCBzdWNjZXNzIG9mIGZpeFJlc3VsdHMpIHsnXG4gICAgICApO1xuXG4gICAgICAvLyBGaXggaW5jcmVtZW50XG4gICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuICAgICAgICAvZml4ZWRDb3VudFxcK1xcKzsvZyxcbiAgICAgICAgJ2ZpeGVkQ291bnQgKz0gMTsnXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFdyaXRlIHRoZSBtb2RpZmllZCBjb250ZW50IGJhY2sgaWYgY2hhbmdlcyB3ZXJlIG1hZGVcbiAgICBpZihuZXdDb250ZW50ICE9PSBmaWxlQ29udGVudCkge1xuICAgICAgd3JpdGVGaWxlU3luYyhmaWxlUGF0aCwgbmV3Q29udGVudCwgJ3V0ZjgnKTtcbiAgICAgIGxvZyhgRml4ZWQgaXNzdWVzIGluICR7ZmlsZVBhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICB3YXNNb2RpZmllZCA9IHRydWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIHdhc01vZGlmaWVkO1xuICB9IGNhdGNoKGVycm9yKSB7XG4gICAgbG9nKGBFcnJvciBhcHBseWluZyBkaXJlY3QgZml4ZXMgdG8gJHtmaWxlUGF0aH06ICR7ZXJyb3IubWVzc2FnZX1gLCAnZXJyb3InLCBxdWlldCk7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59O1xuXG4vKipcbiAqIENoZWNrIGZvciBBSSBjb25maWd1cmF0aW9uIGluIG1haW4gbGV4LmNvbmZpZyBmaWxlIChzdXBwb3J0cyBqcywgbWpzLCBjanMsIHRzLCBqc29uIGZvcm1hdHMpXG4gKi9cbmNvbnN0IGxvYWRBSUNvbmZpZyA9IGFzeW5jIChjd2Q6IHN0cmluZywgcXVpZXQ6IGJvb2xlYW4pOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgLy8gU2VhcmNoIGZvciBjb25maWcgZmlsZXMgaW4gbXVsdGlwbGUgZm9ybWF0cyBsaWtlIExleENvbmZpZy5wYXJzZUNvbmZpZyBkb2VzXG4gIGNvbnN0IGNvbmZpZ0Zvcm1hdHMgPSBbJ2pzJywgJ21qcycsICdjanMnLCAndHMnLCAnanNvbiddO1xuICBjb25zdCBjb25maWdCYXNlTmFtZSA9ICdsZXguY29uZmlnJztcbiAgbGV0IGxleENvbmZpZ1BhdGggPSAnJztcblxuICBmb3IoY29uc3QgZm9ybWF0IG9mIGNvbmZpZ0Zvcm1hdHMpIHtcbiAgICBjb25zdCBwb3RlbnRpYWxQYXRoID0gcGF0aFJlc29sdmUoY3dkLCBgLi8ke2NvbmZpZ0Jhc2VOYW1lfS4ke2Zvcm1hdH1gKTtcbiAgICBpZihleGlzdHNTeW5jKHBvdGVudGlhbFBhdGgpKSB7XG4gICAgICBsZXhDb25maWdQYXRoID0gcG90ZW50aWFsUGF0aDtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIGlmKGxleENvbmZpZ1BhdGgpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgbGV4Q29uZmlnID0gYXdhaXQgaW1wb3J0KGxleENvbmZpZ1BhdGgpO1xuICAgICAgaWYobGV4Q29uZmlnLmRlZmF1bHQgJiYgbGV4Q29uZmlnLmRlZmF1bHQuYWkpIHtcbiAgICAgICAgbG9nKGBGb3VuZCBBSSBjb25maWd1cmF0aW9uIGluICR7cGF0aFJlc29sdmUoY3dkLCBsZXhDb25maWdQYXRoKX0sIGFwcGx5aW5nIHNldHRpbmdzLi4uYCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgIC8vIFVwZGF0ZSB0aGUgQUkgY29uZmlndXJhdGlvbiBpbiBMZXhDb25maWdcbiAgICAgICAgTGV4Q29uZmlnLmNvbmZpZy5haSA9IHsuLi5MZXhDb25maWcuY29uZmlnLmFpLCAuLi5sZXhDb25maWcuZGVmYXVsdC5haX07XG4gICAgICB9XG4gICAgfSBjYXRjaChlcnJvcikge1xuICAgICAgbG9nKGBFcnJvciBsb2FkaW5nIEFJIGNvbmZpZ3VyYXRpb24gZnJvbSAke2xleENvbmZpZ1BhdGh9OiAke2Vycm9yLm1lc3NhZ2V9YCwgJ3dhcm4nLCBxdWlldCk7XG4gICAgfVxuICB9XG59O1xuXG5leHBvcnQgY29uc3QgbGludCA9IGFzeW5jIChjbWQ6IExpbnRPcHRpb25zLCBjYWxsYmFjazogTGludENhbGxiYWNrID0gcHJvY2Vzcy5leGl0KTogUHJvbWlzZTxudW1iZXI+ID0+IHtcbiAgY29uc3Qge1xuICAgIGNsaU5hbWUgPSAnTGV4JyxcbiAgICBmaXggPSBmYWxzZSxcbiAgICBkZWJ1ZyA9IGZhbHNlLFxuICAgIHF1aWV0ID0gZmFsc2UsXG4gICAgY29uZmlnID0gbnVsbFxuICB9ID0gY21kO1xuXG4gIGxvZyhgJHtjbGlOYW1lfSBsaW50aW5nLi4uYCwgJ2luZm8nLCBxdWlldCk7XG5cbiAgY29uc3QgY3dkID0gcHJvY2Vzcy5jd2QoKTtcbiAgY29uc3Qgc3Bpbm5lciA9IGNyZWF0ZVNwaW5uZXIocXVpZXQpO1xuXG4gIC8vIExvYWQgQUkgY29uZmlndXJhdGlvbiBpZiBhdmFpbGFibGVcbiAgYXdhaXQgbG9hZEFJQ29uZmlnKGN3ZCwgcXVpZXQpO1xuXG4gIC8vIFRyYWNrIGlmIHdlIG5lZWQgdG8gcmVzdG9yZSBhbiBvcmlnaW5hbCBjb25maWdcbiAgbGV0IG9yaWdpbmFsQ29uZmlnOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgbGV0IHRlbXBDb25maWdQYXRoOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcblxuICB0cnkge1xuICAgIC8vIERldGVjdCBUeXBlU2NyaXB0IGRpcmVjdGx5XG4gICAgY29uc3QgdXNlVHlwZXNjcmlwdCA9IGRldGVjdFR5cGVTY3JpcHQoY3dkKTtcbiAgICBsb2coYFR5cGVTY3JpcHQgJHt1c2VUeXBlc2NyaXB0ID8gJ2RldGVjdGVkJyA6ICdub3QgZGV0ZWN0ZWQnfSBmcm9tIHRzY29uZmlnLmpzb25gLCAnaW5mbycsIHF1aWV0KTtcblxuICAgIC8vIEVuc3VyZSBwYWNrYWdlLmpzb24gaGFzIHR5cGU6IG1vZHVsZSBmb3IgRVNNIHN1cHBvcnRcbiAgICBlbnN1cmVNb2R1bGVUeXBlKGN3ZCk7XG5cbiAgICAvLyBJbnN0YWxsIG5lY2Vzc2FyeSBkZXBlbmRlbmNpZXNcbiAgICBhd2FpdCBpbnN0YWxsRGVwZW5kZW5jaWVzKGN3ZCwgdXNlVHlwZXNjcmlwdCwgcXVpZXQpO1xuXG4gICAgLy8gQ2hlY2sgZm9yIEVTTGludCBjb25maWd1cmF0aW9uIGZpbGVzXG4gICAgY29uc3QgcHJvamVjdENvbmZpZ1BhdGggPSBwYXRoUmVzb2x2ZShjd2QsICdlc2xpbnQuY29uZmlnLmpzJyk7XG4gICAgY29uc3QgaGFzRXNsaW50Q29uZmlnID0gZXhpc3RzU3luYyhwcm9qZWN0Q29uZmlnUGF0aCkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXhpc3RzU3luYyhwYXRoUmVzb2x2ZShjd2QsICcuZXNsaW50cmMuanMnKSkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXhpc3RzU3luYyhwYXRoUmVzb2x2ZShjd2QsICcuZXNsaW50cmMuanNvbicpKSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICBleGlzdHNTeW5jKHBhdGhSZXNvbHZlKGN3ZCwgJy5lc2xpbnRyYy55bWwnKSkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZXhpc3RzU3luYyhwYXRoUmVzb2x2ZShjd2QsICcuZXNsaW50cmMueWFtbCcpKSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICBleGlzdHNTeW5jKHBhdGhSZXNvbHZlKGN3ZCwgJy5lc2xpbnRyYycpKTtcblxuICAgIC8vIFJlbW92ZSBhbnkgZXhpc3RpbmcgLmVzbGludHJjLmpzb24gZmlsZSB0byBhdm9pZCBjb25mbGljdHMgd2l0aCBlc2xpbnQuY29uZmlnLmpzXG4gICAgaWYoZXhpc3RzU3luYyhwYXRoUmVzb2x2ZShjd2QsICcuZXNsaW50cmMuanNvbicpKSkge1xuICAgICAgdW5saW5rU3luYyhwYXRoUmVzb2x2ZShjd2QsICcuZXNsaW50cmMuanNvbicpKTtcbiAgICB9XG5cbiAgICAvLyBUcnkgdG8gZmluZCBMZXgncyBFU0xpbnQgY29uZmlnIGlmIG5lZWRlZFxuICAgIGxldCBsZXhDb25maWdQYXRoID0gJyc7XG4gICAgbGV0IHNob3VsZENyZWF0ZVRlbXBDb25maWcgPSBmYWxzZTtcblxuICAgIGlmKCFoYXNFc2xpbnRDb25maWcpIHtcbiAgICAgIC8vIFRyeSBkaWZmZXJlbnQgcG90ZW50aWFsIGxvY2F0aW9ucyBmb3IgdGhlIExleCBjb25maWdcbiAgICAgIGNvbnN0IHBvc3NpYmxlUGF0aHMgPSBbXG4gICAgICAgIC8vIEZyb20gc3JjL2NvbW1hbmRzL2xpbnQvbGludC50cyB0byByb290XG4gICAgICAgIHBhdGhSZXNvbHZlKF9fZGlybmFtZSwgJy4uLy4uLy4uLy4uL2VzbGludC5jb25maWcuanMnKSxcbiAgICAgICAgLy8gRnJvbSBwYWNrYWdlcy9sZXgvc3JjL2NvbW1hbmRzL2xpbnQvbGludC50cyB0byBwYWNrYWdlcy9sZXhcbiAgICAgICAgcGF0aFJlc29sdmUoX19kaXJuYW1lLCAnLi4vLi4vLi4vZXNsaW50LmNvbmZpZy5qcycpLFxuICAgICAgICAvLyBGcm9tIHBhY2thZ2VzL2xleC9zcmMvY29tbWFuZHMvbGludC9saW50LnRzIHRvIHJvb3RcbiAgICAgICAgcGF0aFJlc29sdmUoX19kaXJuYW1lLCAnLi4vLi4vLi4vLi4vLi4vZXNsaW50LmNvbmZpZy5qcycpLFxuICAgICAgICAvLyBBYnNvbHV0ZSBwYXRoIGlmIExleCBpcyBpbnN0YWxsZWQgZ2xvYmFsbHlcbiAgICAgICAgcGF0aFJlc29sdmUocHJvY2Vzcy5lbnYuTEVYX0hPTUUgfHwgJy91c3IvbG9jYWwvbGliL25vZGVfbW9kdWxlcy9AbmxhYnMvbGV4JywgJ2VzbGludC5jb25maWcuanMnKVxuICAgICAgXTtcblxuICAgICAgLy8gRmluZCB0aGUgZmlyc3QgZXhpc3RpbmcgY29uZmlnXG4gICAgICBmb3IoY29uc3QgcGF0aCBvZiBwb3NzaWJsZVBhdGhzKSB7XG4gICAgICAgIGlmKGV4aXN0c1N5bmMocGF0aCkpIHtcbiAgICAgICAgICBsZXhDb25maWdQYXRoID0gcGF0aDtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZihkZWJ1Zykge1xuICAgICAgICBsb2coYEN1cnJlbnQgZGlyZWN0b3J5OiAke19fZGlybmFtZX1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgICAgbG9nKGBQcm9qZWN0IGNvbmZpZyBwYXRoOiAke3Byb2plY3RDb25maWdQYXRofWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICBsb2coYFByb2plY3QgY29uZmlnIGV4aXN0czogJHtoYXNFc2xpbnRDb25maWd9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgIGxvZyhgRm91bmQgTGV4IGNvbmZpZzogJHtsZXhDb25maWdQYXRofWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICBsb2coYExleCBjb25maWcgZXhpc3RzOiAkeyEhbGV4Q29uZmlnUGF0aCAmJiBleGlzdHNTeW5jKGxleENvbmZpZ1BhdGgpfWAsICdpbmZvJywgcXVpZXQpO1xuICAgICAgfVxuXG4gICAgICAvLyBJZiB3ZSBmb3VuZCBMZXgncyBjb25maWcsIHVzZSBpdFxuICAgICAgaWYobGV4Q29uZmlnUGF0aCAmJiBleGlzdHNTeW5jKGxleENvbmZpZ1BhdGgpKSB7XG4gICAgICAgIGxvZygnTm8gRVNMaW50IGNvbmZpZ3VyYXRpb24gZm91bmQgaW4gcHJvamVjdC4gVXNpbmcgTGV4XFwncyBkZWZhdWx0IGNvbmZpZ3VyYXRpb24uJywgJ2luZm8nLCBxdWlldCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBPdGhlcndpc2UsIHdlIG5lZWQgdG8gY3JlYXRlIGEgdGVtcG9yYXJ5IGNvbmZpZ1xuICAgICAgICBzaG91bGRDcmVhdGVUZW1wQ29uZmlnID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBJZiB1c2VyIHNwZWNpZmllZCBhIGNvbmZpZyBmaWxlLCB1c2UgdGhhdFxuICAgIGlmKGNvbmZpZykge1xuICAgICAgY29uc3QgdXNlckNvbmZpZ1BhdGggPSBwYXRoUmVzb2x2ZShjd2QsIGNvbmZpZyk7XG4gICAgICBpZihleGlzdHNTeW5jKHVzZXJDb25maWdQYXRoKSkge1xuICAgICAgICBsb2coYFVzaW5nIHNwZWNpZmllZCBFU0xpbnQgY29uZmlndXJhdGlvbjogJHtjb25maWd9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgIC8vIFVzZXItc3BlY2lmaWVkIGNvbmZpZyB0YWtlcyBwcmVjZWRlbmNlXG4gICAgICAgIHNob3VsZENyZWF0ZVRlbXBDb25maWcgPSBmYWxzZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvZyhgU3BlY2lmaWVkIEVTTGludCBjb25maWd1cmF0aW9uIG5vdCBmb3VuZDogJHtjb25maWd9LiBVc2luZyBMZXgncyBkZWZhdWx0IGNvbmZpZ3VyYXRpb24uYCwgJ3dhcm4nLCBxdWlldCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQ3JlYXRlIGEgdGVtcG9yYXJ5IGNvbmZpZyBpZiBuZWVkZWRcbiAgICBpZihzaG91bGRDcmVhdGVUZW1wQ29uZmlnKSB7XG4gICAgICBsb2coJ05vIEVTTGludCBjb25maWd1cmF0aW9uIGZvdW5kLiBDcmVhdGluZyBhIHRlbXBvcmFyeSBjb25maWd1cmF0aW9uLi4uJywgJ2luZm8nLCBxdWlldCk7XG4gICAgICBjb25zdCBjb25maWdSZXN1bHQgPSBjcmVhdGVEZWZhdWx0RVNMaW50Q29uZmlnKHVzZVR5cGVzY3JpcHQsIGN3ZCk7XG4gICAgICB0ZW1wQ29uZmlnUGF0aCA9IGNvbmZpZ1Jlc3VsdC5jb25maWdQYXRoO1xuICAgICAgb3JpZ2luYWxDb25maWcgPSBjb25maWdSZXN1bHQub3JpZ2luYWxDb25maWc7XG4gICAgfVxuXG4gICAgLy8gQ2FwdHVyZSB0aGUgRVNMaW50IG91dHB1dCBmb3IgQUkgZml4IGlmIG5lZWRlZFxuICAgIGxldCBlc2xpbnRPdXRwdXQgPSAnJztcbiAgICBjb25zdCBjYXB0dXJlT3V0cHV0ID0gKG91dHB1dDogc3RyaW5nKSA9PiB7XG4gICAgICBlc2xpbnRPdXRwdXQgKz0gYCR7b3V0cHV0fVxcbmA7XG4gICAgfTtcblxuICAgIC8vIEFsd2F5cyBydW4gRVNMaW50IHdpdGggLS1maXggZmlyc3QgdG8gYXBwbHkgYnVpbHQtaW4gZml4ZXNcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBydW5Fc2xpbnRXaXRoTGV4KGN3ZCwgcXVpZXQsIGNsaU5hbWUsIHRydWUsIGRlYnVnLCB1c2VUeXBlc2NyaXB0LCBjYXB0dXJlT3V0cHV0KTtcblxuICAgIC8vIElmIHRoZXJlIGFyZSBzdGlsbCBlcnJvcnMgYW5kIGZpeCBmbGFnIGlzIHNldCwgdHJ5IHRvIGZpeCB0aGVtIHdpdGggQUlcbiAgICBpZihyZXN1bHQgIT09IDAgJiYgZml4KSB7XG4gICAgICAvLyBDaGVjayBpZiBBSSBpcyBjb25maWd1cmVkXG4gICAgICBjb25zdCBhaUNvbmZpZ3VyZWQgPSBMZXhDb25maWcuY29uZmlnLmFpPy5wcm92aWRlciAmJiBMZXhDb25maWcuY29uZmlnLmFpLnByb3ZpZGVyICE9PSAnbm9uZSc7XG5cbiAgICAgIGlmKGFpQ29uZmlndXJlZCkge1xuICAgICAgICBsb2coJ0FwcGx5aW5nIEFJIGZpeGVzIHRvIHJlbWFpbmluZyBpc3N1ZXMuLi4nLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgICAgYXdhaXQgYXBwbHlBSUZpeChjd2QsIGVzbGludE91dHB1dCwgcXVpZXQpO1xuXG4gICAgICAgIC8vIFJ1biBFU0xpbnQgYWdhaW4gdG8gY2hlY2sgaWYgYWxsIGlzc3VlcyBhcmUgZml4ZWRcbiAgICAgICAgY29uc3QgYWZ0ZXJGaXhSZXN1bHQgPSBhd2FpdCBydW5Fc2xpbnRXaXRoTGV4KGN3ZCwgcXVpZXQsIGNsaU5hbWUsIGZhbHNlLCBkZWJ1ZywgdXNlVHlwZXNjcmlwdCk7XG5cbiAgICAgICAgLy8gUmV0dXJuIHRoZSByZXN1bHQgb2YgdGhlIHNlY29uZCBydW5cbiAgICAgICAgY2FsbGJhY2soYWZ0ZXJGaXhSZXN1bHQpO1xuICAgICAgICByZXR1cm4gYWZ0ZXJGaXhSZXN1bHQ7XG4gICAgICB9XG4gICAgICAvLyBJZiBBSSBpcyBub3QgY29uZmlndXJlZCwgc3VnZ2VzdCBjb25maWd1cmluZyBpdFxuICAgICAgbG9nKCdFU0xpbnQgY291bGQgbm90IGZpeCBhbGwgaXNzdWVzIGF1dG9tYXRpY2FsbHkuJywgJ3dhcm4nLCBxdWlldCk7XG4gICAgICBsb2coJ1RvIGVuYWJsZSBBSS1wb3dlcmVkIGZpeGVzLCBhZGQgQUkgY29uZmlndXJhdGlvbiB0byB5b3VyIGxleC5jb25maWcgZmlsZTonLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgIGxvZyhgXG4vLyBJbiBsZXguY29uZmlnLmpzIChvciBsZXguY29uZmlnLm1qcywgbGV4LmNvbmZpZy5janMsIGV0Yy4pXG5leHBvcnQgZGVmYXVsdCB7XG4gIC8vIFlvdXIgZXhpc3RpbmcgY29uZmlnXG4gIGFpOiB7XG4gICAgcHJvdmlkZXI6ICdjdXJzb3InIC8vIG9yICdvcGVuYWknLCAnYW50aHJvcGljJywgZXRjLlxuICAgIC8vIEFkZGl0aW9uYWwgcHJvdmlkZXItc3BlY2lmaWMgc2V0dGluZ3NcbiAgfVxufTtgLCAnaW5mbycsIHF1aWV0KTtcbiAgICB9XG5cbiAgICBjYWxsYmFjayhyZXN1bHQpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAvLyBEaXNwbGF5IGVycm9yIG1lc3NhZ2VcbiAgICBsb2coYFxcbiR7Y2xpTmFtZX0gRXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gLCAnZXJyb3InLCBxdWlldCk7XG4gICAgc3Bpbm5lci5mYWlsKCdMaW50aW5nIGZhaWxlZCEnKTtcbiAgICBjYWxsYmFjaygxKTtcbiAgICByZXR1cm4gMTtcbiAgfSBmaW5hbGx5IHtcbiAgICAvLyBSZXN0b3JlIHRoZSBvcmlnaW5hbCBjb25maWcgaWYgd2UgY3JlYXRlZCBhIHRlbXBvcmFyeSBvbmVcbiAgICBpZih0ZW1wQ29uZmlnUGF0aCAmJiBvcmlnaW5hbENvbmZpZykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgd3JpdGVGaWxlU3luYyh0ZW1wQ29uZmlnUGF0aCwgb3JpZ2luYWxDb25maWcsICd1dGY4Jyk7XG4gICAgICB9IGNhdGNoKF9lcnJvcikge1xuICAgICAgICAvLyBJZ25vcmUgZXJyb3JzXG4gICAgICB9XG4gICAgfSBlbHNlIGlmKHRlbXBDb25maWdQYXRoKSB7XG4gICAgICAvLyBSZW1vdmUgdGhlIHRlbXBvcmFyeSBjb25maWcgaWYgdGhlcmUgd2FzIG5vIG9yaWdpbmFsXG4gICAgICB0cnkge1xuICAgICAgICB1bmxpbmtTeW5jKHRlbXBDb25maWdQYXRoKTtcbiAgICAgIH0gY2F0Y2goX2Vycm9yKSB7XG4gICAgICAgIC8vIElnbm9yZSBlcnJvcnNcbiAgICAgIH1cbiAgICB9XG4gIH1cbn07Il0sCiAgIm1hcHBpbmdzIjogIkFBSUEsU0FBUSxhQUFZO0FBQ3BCLFNBQVEsWUFBWSxlQUFlLGNBQWMsa0JBQWlCO0FBQ2xFLFNBQVEsV0FBVyxhQUFhLGVBQWM7QUFDOUMsU0FBUSxxQkFBb0I7QUFFNUIsU0FBUSxpQkFBZ0I7QUFDeEIsU0FBUSxxQkFBb0I7QUFDNUIsU0FBUSxXQUFVO0FBR2xCLE1BQU0sYUFBYSxjQUFjLFlBQVksR0FBRztBQUNoRCxNQUFNLFlBQVksUUFBUSxVQUFVO0FBa0RwQyxNQUFNLDRCQUE0QixDQUFDLGVBQXdCLFFBQThCO0FBRXZGLFFBQU0sYUFBYSxZQUFZLEtBQUssa0JBQWtCO0FBR3RELE1BQUksaUJBQWlCO0FBQ3JCLE1BQUcsV0FBVyxVQUFVLEdBQUc7QUFDekIsUUFBSTtBQUNGLHVCQUFpQixhQUFhLFlBQVksTUFBTTtBQUFBLElBQ2xELFNBQVEsUUFBUTtBQUFBLElBRWhCO0FBQUEsRUFDRjtBQUlBLFFBQU0sZ0JBQWdC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LE1BQU0sSUFBSSxRQUFRLEtBQUs7QUFFcEUsaUNBQXlCO0FBQUEsTUFDM0IsT0FBTztBQUNMLFlBQUksNkNBQTZDLE1BQU0sd0NBQXdDLFFBQVEsS0FBSztBQUFBLE1BQzlHO0FBQUEsSUFDRjtBQUdBLFFBQUcsd0JBQXdCO0FBQ3pCLFVBQUksd0VBQXdFLFFBQVEsS0FBSztBQUN6RixZQUFNLGVBQWUsMEJBQTBCLGVBQWUsR0FBRztBQUNqRSx1QkFBaUIsYUFBYTtBQUM5Qix1QkFBaUIsYUFBYTtBQUFBLElBQ2hDO0FBR0EsUUFBSSxlQUFlO0FBQ25CLFVBQU0sZ0JBQWdCLENBQUMsV0FBbUI7QUFDeEMsc0JBQWdCLEdBQUcsTUFBTTtBQUFBO0FBQUEsSUFDM0I7QUFHQSxVQUFNLFNBQVMsTUFBTSxpQkFBaUIsS0FBSyxPQUFPLFNBQVMsTUFBTSxPQUFPLGVBQWUsYUFBYTtBQUdwRyxRQUFHLFdBQVcsS0FBSyxLQUFLO0FBRXRCLFlBQU0sZUFBZSxVQUFVLE9BQU8sSUFBSSxZQUFZLFVBQVUsT0FBTyxHQUFHLGFBQWE7QUFFdkYsVUFBRyxjQUFjO0FBQ2YsWUFBSSw0Q0FBNEMsUUFBUSxLQUFLO0FBQzdELGNBQU0sV0FBVyxLQUFLLGNBQWMsS0FBSztBQUd6QyxjQUFNLGlCQUFpQixNQUFNLGlCQUFpQixLQUFLLE9BQU8sU0FBUyxPQUFPLE9BQU8sYUFBYTtBQUc5RixpQkFBUyxjQUFjO0FBQ3ZCLGVBQU87QUFBQSxNQUNUO0FBRUEsVUFBSSxrREFBa0QsUUFBUSxLQUFLO0FBQ25FLFVBQUksNkVBQTZFLFFBQVEsS0FBSztBQUM5RixVQUFJO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxLQVFMLFFBQVEsS0FBSztBQUFBLElBQ2Q7QUFFQSxhQUFTLE1BQU07QUFDZixXQUFPO0FBQUEsRUFDVCxTQUFRLE9BQU87QUFFYixRQUFJO0FBQUEsRUFBSyxPQUFPLFdBQVcsTUFBTSxPQUFPLElBQUksU0FBUyxLQUFLO0FBQzFELFlBQVEsS0FBSyxpQkFBaUI7QUFDOUIsYUFBUyxDQUFDO0FBQ1YsV0FBTztBQUFBLEVBQ1QsVUFBRTtBQUVBLFFBQUcsa0JBQWtCLGdCQUFnQjtBQUNuQyxVQUFJO0FBQ0Ysc0JBQWMsZ0JBQWdCLGdCQUFnQixNQUFNO0FBQUEsTUFDdEQsU0FBUSxRQUFRO0FBQUEsTUFFaEI7QUFBQSxJQUNGLFdBQVUsZ0JBQWdCO0FBRXhCLFVBQUk7QUFDRixtQkFBVyxjQUFjO0FBQUEsTUFDM0IsU0FBUSxRQUFRO0FBQUEsTUFFaEI7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUNGOyIsCiAgIm5hbWVzIjogWyJsaW5lcyJdCn0K
|