@nlabs/lex 1.48.6 → 1.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/.storybook/main.ts +9 -2
  2. package/.vscode/settings.json +1 -6
  3. package/README.md +276 -4
  4. package/eslint.config.mjs +24 -0
  5. package/examples/lex.config.js +18 -8
  6. package/examples/serverless-example/README.md +109 -0
  7. package/examples/serverless-example/dist/handlers/echo.js +15 -0
  8. package/examples/serverless-example/dist/handlers/graphql.js +137 -0
  9. package/examples/serverless-example/dist/handlers/hello.js +15 -0
  10. package/examples/serverless-example/dist/handlers/test.js +17 -0
  11. package/examples/serverless-example/dist/handlers/websocket.js +14 -0
  12. package/examples/serverless-example/lex.config.mjs +74 -0
  13. package/jest.config.mjs +13 -12
  14. package/{dist → lib}/LexConfig.d.ts +14 -6
  15. package/lib/LexConfig.js +268 -0
  16. package/lib/commands/ai/ai.js +303 -0
  17. package/{dist → lib}/commands/build/build.d.ts +3 -0
  18. package/lib/commands/build/build.js +494 -0
  19. package/{dist → lib}/commands/clean/clean.js +1 -1
  20. package/lib/commands/compile/compile.js +241 -0
  21. package/lib/commands/copy/copy.js +38 -0
  22. package/{dist → lib}/commands/create/create.js +1 -1
  23. package/{dist → lib}/commands/dev/dev.d.ts +2 -0
  24. package/lib/commands/dev/dev.js +286 -0
  25. package/{dist → lib}/commands/init/init.js +1 -1
  26. package/{dist → lib}/commands/lint/lint.d.ts +4 -1
  27. package/lib/commands/lint/lint.js +993 -0
  28. package/{dist → lib}/commands/migrate/migrate.js +1 -1
  29. package/lib/commands/publish/publish.js +104 -0
  30. package/lib/commands/serverless/serverless.d.ts +17 -0
  31. package/lib/commands/serverless/serverless.js +662 -0
  32. package/lib/commands/storybook/storybook.js +249 -0
  33. package/lib/commands/test/test.js +428 -0
  34. package/lib/commands/update/update.js +128 -0
  35. package/lib/commands/versions/versions.js +41 -0
  36. package/{dist → lib}/create/changelog.js +1 -1
  37. package/{dist → lib}/index.d.ts +2 -0
  38. package/{dist → lib}/index.js +3 -1
  39. package/lib/lex.js +73 -0
  40. package/lib/storybook/index.d.ts +5 -0
  41. package/lib/types.js +1 -0
  42. package/lib/utils/aiService.d.ts +9 -0
  43. package/lib/utils/aiService.js +299 -0
  44. package/{dist → lib}/utils/app.d.ts +3 -0
  45. package/lib/utils/app.js +296 -0
  46. package/lib/utils/deepMerge.js +26 -0
  47. package/{dist → lib}/utils/file.d.ts +7 -3
  48. package/lib/utils/file.js +229 -0
  49. package/lib/utils/translations.d.ts +1 -0
  50. package/lib/utils/translations.js +74 -0
  51. package/package.json +62 -50
  52. package/postcss.config.js +5 -3
  53. package/tsconfig.build.json +2 -2
  54. package/webpack.config.js +229 -39
  55. package/dist/LexConfig.js +0 -286
  56. package/dist/commands/ai/ai.js +0 -303
  57. package/dist/commands/build/build.js +0 -404
  58. package/dist/commands/compile/compile.js +0 -234
  59. package/dist/commands/copy/copy.js +0 -38
  60. package/dist/commands/dev/dev.js +0 -74
  61. package/dist/commands/lint/lint.js +0 -811
  62. package/dist/commands/publish/publish.js +0 -104
  63. package/dist/commands/storybook/storybook.js +0 -249
  64. package/dist/commands/test/test.js +0 -429
  65. package/dist/commands/update/update.js +0 -132
  66. package/dist/commands/versions/versions.js +0 -41
  67. package/dist/lex.js +0 -70
  68. package/dist/utils/aiService.d.ts +0 -9
  69. package/dist/utils/aiService.js +0 -299
  70. package/dist/utils/app.js +0 -267
  71. package/dist/utils/deepMerge.js +0 -24
  72. package/dist/utils/file.js +0 -185
  73. package/emptyModule.js +0 -0
  74. package/eslint.config.js +0 -7
  75. /package/{dist → lib}/Button.stories.d.ts +0 -0
  76. /package/{dist → lib}/commands/ai/ai.d.ts +0 -0
  77. /package/{dist → lib}/commands/ai/index.d.ts +0 -0
  78. /package/{dist → lib}/commands/ai/index.js +0 -0
  79. /package/{dist → lib}/commands/clean/clean.d.ts +0 -0
  80. /package/{dist → lib}/commands/compile/compile.d.ts +0 -0
  81. /package/{dist → lib}/commands/config/config.d.ts +0 -0
  82. /package/{dist → lib}/commands/config/config.js +0 -0
  83. /package/{dist → lib}/commands/copy/copy.d.ts +0 -0
  84. /package/{dist → lib}/commands/create/create.d.ts +0 -0
  85. /package/{dist → lib}/commands/init/init.d.ts +0 -0
  86. /package/{dist → lib}/commands/link/link.d.ts +0 -0
  87. /package/{dist → lib}/commands/link/link.js +0 -0
  88. /package/{dist → lib}/commands/lint/autofix.d.ts +0 -0
  89. /package/{dist → lib}/commands/migrate/migrate.d.ts +0 -0
  90. /package/{dist → lib}/commands/publish/publish.d.ts +0 -0
  91. /package/{dist → lib}/commands/storybook/storybook.d.ts +0 -0
  92. /package/{dist → lib}/commands/test/test.d.ts +0 -0
  93. /package/{dist → lib}/commands/update/update.d.ts +0 -0
  94. /package/{dist → lib}/commands/upgrade/upgrade.d.ts +0 -0
  95. /package/{dist → lib}/commands/upgrade/upgrade.js +0 -0
  96. /package/{dist → lib}/commands/versions/versions.d.ts +0 -0
  97. /package/{dist → lib}/create/changelog.d.ts +0 -0
  98. /package/{dist → lib}/lex.d.ts +0 -0
  99. /package/{dist/types.js → lib/storybook/index.js} +0 -0
  100. /package/{dist → lib}/test-react/index.d.ts +0 -0
  101. /package/{dist → lib}/test-react/index.js +0 -0
  102. /package/{dist → lib}/types.d.ts +0 -0
  103. /package/{dist → lib}/utils/deepMerge.d.ts +0 -0
  104. /package/{dist → lib}/utils/log.d.ts +0 -0
  105. /package/{dist → lib}/utils/log.js +0 -0
  106. /package/{dist → lib}/utils/reactShim.d.ts +0 -0
  107. /package/{dist → lib}/utils/reactShim.js +0 -0
@@ -1,303 +0,0 @@
1
- import chalk from "chalk";
2
- import { Command } from "commander";
3
- import { readFileSync } from "fs";
4
- import { sync as globSync } from "glob";
5
- import { LexConfig } from "../../LexConfig.js";
6
- import { callAIService } from "../../utils/aiService.js";
7
- import { log } from "../../utils/log.js";
8
- if (process.env.CURSOR_EXTENSION === "true" || process.env.CURSOR_TERMINAL === "true" || process.env.CURSOR_APP === "true" || process.env.PATH?.includes("cursor") || process.env.CURSOR_SESSION_ID) {
9
- process.env.CURSOR_IDE = "true";
10
- }
11
- const getFileContext = (filePath) => {
12
- try {
13
- const content = readFileSync(filePath, "utf-8");
14
- return `File: ${filePath}
15
-
16
- ${content}`;
17
- } catch (_error) {
18
- return `Error reading file: ${filePath}`;
19
- }
20
- };
21
- const getProjectContext = async (options) => {
22
- const { file, task, context } = options;
23
- if (context === false) {
24
- return "";
25
- }
26
- let projectContext = "";
27
- if (file) {
28
- projectContext += getFileContext(file);
29
- }
30
- switch (task) {
31
- case "generate":
32
- const files = globSync("src/**/*.{ts,tsx,js,jsx}", {
33
- cwd: process.cwd(),
34
- ignore: ["**/node_modules/**", "**/dist/**", "**/*.test.*", "**/*.spec.*"],
35
- maxDepth: 3
36
- });
37
- projectContext += `
38
-
39
- Project structure:
40
- ${files.join("\n")}`;
41
- break;
42
- case "test":
43
- if (file) {
44
- const testConfig = getFileContext("jest.config.js");
45
- projectContext += `
46
-
47
- Test configuration:
48
- ${testConfig}`;
49
- }
50
- break;
51
- case "optimize":
52
- const webpackConfig = getFileContext("webpack.config.js");
53
- projectContext += `
54
-
55
- Webpack configuration:
56
- ${webpackConfig}`;
57
- break;
58
- default:
59
- break;
60
- }
61
- return projectContext;
62
- };
63
- const constructPrompt = (options, projectContext) => {
64
- const { task = "help", prompt = "" } = options;
65
- const taskInstructions = {
66
- generate: "Generate code according to the following request. Make sure it follows best practices and is well documented:",
67
- explain: "Explain the following code in detail, including any patterns, potential issues, and improvement suggestions:",
68
- test: "Generate comprehensive unit tests for the following code:",
69
- optimize: "Analyze the following code/configuration and suggest optimization improvements:",
70
- help: "Provide guidance on the following development question:",
71
- ask: "Provide guidance on the following development question:",
72
- analyze: "Analyze the following code:"
73
- };
74
- const taskInstruction = taskInstructions[task] || taskInstructions.help;
75
- let fullPrompt = `${taskInstruction}
76
-
77
- ${prompt}`;
78
- if (projectContext) {
79
- fullPrompt += `
80
-
81
- ===CONTEXT===
82
- ${projectContext}`;
83
- }
84
- return fullPrompt;
85
- };
86
- const displayResponse = (response, options) => {
87
- const { task = "help", quiet = false } = options;
88
- let content = "";
89
- if (typeof response === "string") {
90
- content = response;
91
- } else if (response.choices?.[0]?.message?.content) {
92
- content = response.choices[0].message.content;
93
- } else if (response.content) {
94
- content = response.content;
95
- } else {
96
- content = "No response received from AI model";
97
- }
98
- const cleanedContent = cleanResponse(content, options);
99
- switch (task) {
100
- case "generate":
101
- log("\nGenerated Code:\n", "success", quiet);
102
- log(cleanedContent, "default", quiet);
103
- break;
104
- case "explain":
105
- log("\nCode Explanation:\n", "success", quiet);
106
- log(cleanedContent, "default", quiet);
107
- break;
108
- case "test":
109
- log("\nGenerated Tests:\n", "success", quiet);
110
- log(cleanedContent, "default", quiet);
111
- break;
112
- case "optimize":
113
- log("\nOptimization Suggestions:\n", "success", quiet);
114
- log(cleanedContent, "default", quiet);
115
- break;
116
- default:
117
- log("\nAI Response:\n", "success", quiet);
118
- log(cleanedContent, "default", quiet);
119
- break;
120
- }
121
- };
122
- const cleanResponse = (content, options) => {
123
- const { prompt = "", task = "help" } = options;
124
- if (!content) {
125
- return content;
126
- }
127
- let cleanedContent = content;
128
- const taskInstructions = {
129
- generate: "Generate code according to the following request. Make sure it follows best practices and is well documented:",
130
- explain: "Explain the following code in detail, including any patterns, potential issues, and improvement suggestions:",
131
- test: "Generate comprehensive unit tests for the following code:",
132
- optimize: "Analyze the following code/configuration and suggest optimization improvements:",
133
- help: "Provide guidance on the following development question:",
134
- ask: "Provide guidance on the following development question:",
135
- analyze: "Analyze the following code:"
136
- };
137
- const instruction = taskInstructions[task] || "";
138
- if (instruction && cleanedContent.includes(instruction)) {
139
- cleanedContent = cleanedContent.replace(instruction, "").trim();
140
- }
141
- if (prompt && cleanedContent.includes(prompt)) {
142
- cleanedContent = cleanedContent.replace(prompt, "").trim();
143
- }
144
- if (cleanedContent.includes("===CONTEXT===")) {
145
- cleanedContent = cleanedContent.split("===CONTEXT===")[0].trim();
146
- }
147
- if (!cleanedContent) {
148
- return content;
149
- }
150
- return cleanedContent;
151
- };
152
- const getProviderAuth = (provider) => {
153
- if (process.cwd().includes("reaktor")) {
154
- return "cursor-auth";
155
- }
156
- if (process.env.AI_API_KEY) {
157
- return process.env.AI_API_KEY;
158
- }
159
- if (provider === "none" && process.env.CURSOR_IDE === "true") {
160
- return "cursor-auth";
161
- }
162
- switch (provider) {
163
- case "openai":
164
- return process.env.OPENAI_API_KEY;
165
- case "anthropic":
166
- return process.env.ANTHROPIC_API_KEY;
167
- case "cursor":
168
- return "cursor-auth";
169
- case "copilot":
170
- return process.env.GITHUB_TOKEN;
171
- case "none":
172
- return void 0;
173
- default:
174
- return void 0;
175
- }
176
- };
177
- const detectCursorIDE = () => {
178
- if (process.env.CURSOR_IDE === "true") {
179
- return true;
180
- }
181
- const possibleCursorSignals = [
182
- process.env.CURSOR_EXTENSION === "true",
183
- process.env.CURSOR_TERMINAL === "true",
184
- process.env.CURSOR_APP === "true",
185
- process.env.PATH?.includes("cursor"),
186
- !!process.env.CURSOR_SESSION_ID
187
- ];
188
- const isCursorIDE = possibleCursorSignals.some((signal) => signal);
189
- if (isCursorIDE) {
190
- process.env.CURSOR_IDE = "true";
191
- }
192
- return isCursorIDE;
193
- };
194
- const aiFunction = async (options) => {
195
- try {
196
- const config = LexConfig.config || {};
197
- const aiConfig = config.ai || {};
198
- const provider = options.provider || aiConfig.provider || "none";
199
- if (provider === "none" && !process.env.CURSOR_EXTENSION) {
200
- log(`${chalk.red("Error:")} No AI provider configured.`, "error");
201
- return { error: "No AI provider configured" };
202
- }
203
- const task = options.task || "ask";
204
- const validTasks = ["explain", "generate", "test", "analyze", "ask"];
205
- if (!validTasks.includes(task)) {
206
- log(`${chalk.red("Error:")} Invalid task "${task}". Valid tasks are: ${validTasks.join(", ")}`, "error");
207
- return { error: `Invalid task "${task}"` };
208
- }
209
- const { prompt } = options;
210
- if (!prompt) {
211
- log(`${chalk.red("Error:")} No prompt provided. Use --prompt "Your prompt here"`, "error");
212
- return { error: "No prompt provided" };
213
- }
214
- let context = "";
215
- if (options.file) {
216
- try {
217
- const fs = await import("fs/promises");
218
- const glob = await import("glob");
219
- const files = await glob.glob(options.file);
220
- if (files.length === 0) {
221
- log(`${chalk.yellow("Warning:")} No files found matching "${options.file}"`, "warning");
222
- } else {
223
- for (const file of files) {
224
- const content = await fs.readFile(file, "utf8");
225
- context += `
226
- ===FILE: ${file}===
227
- ${content}
228
- `;
229
- }
230
- }
231
- } catch (error) {
232
- log(`${chalk.yellow("Warning:")} Error reading file: ${error.message}`, "warning");
233
- }
234
- }
235
- if (options.dir) {
236
- try {
237
- const { execaSync } = await import("execa");
238
- const result = execaSync("find", [options.dir, "-type", "f", "|", "sort"]);
239
- context += `
240
- ===Project structure:===
241
- ${result.stdout}
242
- `;
243
- } catch (error) {
244
- log(`${chalk.yellow("Warning:")} Error reading directory: ${error.message}`, "warning");
245
- }
246
- }
247
- let formattedPrompt = "";
248
- switch (task) {
249
- case "explain":
250
- formattedPrompt = `Explain the following code:
251
- ${prompt}`;
252
- break;
253
- case "generate":
254
- formattedPrompt = `Generate code according to the following request:
255
- ${prompt}`;
256
- break;
257
- case "test":
258
- formattedPrompt = `Generate comprehensive unit tests:
259
- ${prompt}`;
260
- break;
261
- case "analyze":
262
- formattedPrompt = `Analyze the following code:
263
- ${prompt}`;
264
- break;
265
- case "ask":
266
- formattedPrompt = `Provide guidance on the following development question:
267
- ${prompt}`;
268
- break;
269
- }
270
- if (context) {
271
- formattedPrompt += `
272
- ===CONTEXT===
273
- ${context}`;
274
- }
275
- if ((provider === "cursor" || process.env.CURSOR_EXTENSION) && task === "generate") {
276
- log("Using Cursor IDE for code generation...", "info");
277
- log("Note: For full code generation capabilities, please use Cursor IDE directly with Cmd+L or Cmd+K.", "info");
278
- log("The CLI integration has limited capabilities for code generation.", "warning");
279
- } else if (provider === "cursor" || process.env.CURSOR_EXTENSION) {
280
- log("Using Cursor IDE for AI assistance...", "info");
281
- log("Note: This is a limited integration. For full AI capabilities, use Cursor IDE directly.", "info");
282
- } else {
283
- log(`Using ${provider} for AI assistance...`, "info");
284
- }
285
- const response = await callAIService(formattedPrompt, options.quiet || false);
286
- log(`
287
- ${response}`, "success");
288
- return { response };
289
- } catch (error) {
290
- log(`${chalk.red("Error:")} ${error.message}`, "error");
291
- return { error: error.message };
292
- }
293
- };
294
- const ai = new Command("ai").description("Use AI to help with development tasks").option("--provider <provider>", "AI provider to use (openai, anthropic, cursor)").option("--task <task>", "Task to perform (explain, generate, test, analyze, ask)").option("--prompt <prompt>", "Prompt to send to AI").option("--file <file>", "File to analyze").option("--dir <dir>", "Directory to analyze").action(async (options) => {
295
- await aiFunction(options);
296
- });
297
- var ai_default = ai;
298
- export {
299
- ai,
300
- aiFunction,
301
- ai_default as default
302
- };
303
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2NvbW1hbmRzL2FpL2FpLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIENvcHlyaWdodCAoYykgMjAxOC1QcmVzZW50LCBOaXRyb2dlbiBMYWJzLCBJbmMuXG4gKiBDb3B5cmlnaHRzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIHRoZSBhY2NvbXBhbnlpbmcgTElDRU5TRSBmaWxlIGZvciB0ZXJtcy5cbiAqL1xuaW1wb3J0IGNoYWxrIGZyb20gJ2NoYWxrJztcbmltcG9ydCB7Q29tbWFuZH0gZnJvbSAnY29tbWFuZGVyJztcbmltcG9ydCB7cmVhZEZpbGVTeW5jfSBmcm9tICdmcyc7XG5pbXBvcnQge3N5bmMgYXMgZ2xvYlN5bmN9IGZyb20gJ2dsb2InO1xuXG5pbXBvcnQge0xleENvbmZpZ30gZnJvbSAnLi4vLi4vTGV4Q29uZmlnLmpzJztcbmltcG9ydCB7Y2FsbEFJU2VydmljZX0gZnJvbSAnLi4vLi4vdXRpbHMvYWlTZXJ2aWNlLmpzJztcbmltcG9ydCB7bG9nfSBmcm9tICcuLi8uLi91dGlscy9sb2cuanMnO1xuXG5pZihwcm9jZXNzLmVudi5DVVJTT1JfRVhURU5TSU9OID09PSAndHJ1ZScgfHxcbiAgcHJvY2Vzcy5lbnYuQ1VSU09SX1RFUk1JTkFMID09PSAndHJ1ZScgfHxcbiAgcHJvY2Vzcy5lbnYuQ1VSU09SX0FQUCA9PT0gJ3RydWUnIHx8XG4gIHByb2Nlc3MuZW52LlBBVEg/LmluY2x1ZGVzKCdjdXJzb3InKSB8fFxuICBwcm9jZXNzLmVudi5DVVJTT1JfU0VTU0lPTl9JRCkge1xuICBwcm9jZXNzLmVudi5DVVJTT1JfSURFID0gJ3RydWUnO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEFJT3B0aW9ucyB7XG4gIHJlYWRvbmx5IGNsaU5hbWU/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGNvbnRleHQ/OiBib29sZWFuO1xuICByZWFkb25seSBmaWxlPzogc3RyaW5nO1xuICByZWFkb25seSBsZXhDb25maWc/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IG1vZGVsPzogc3RyaW5nO1xuICByZWFkb25seSBwcm9tcHQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHF1aWV0PzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgdGFzaz86ICdnZW5lcmF0ZScgfCAnZXhwbGFpbicgfCAndGVzdCcgfCAnb3B0aW1pemUnIHwgJ2hlbHAnIHwgJ2FzaycgfCAnYW5hbHl6ZSc7XG4gIHJlYWRvbmx5IGRlYnVnPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgcHJvdmlkZXI/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGRpcj86IHN0cmluZztcbn1cblxuY29uc3QgZ2V0RmlsZUNvbnRleHQgPSAoZmlsZVBhdGg6IHN0cmluZyk6IHN0cmluZyA9PiB7XG4gIHRyeSB7XG4gICAgY29uc3QgY29udGVudCA9IHJlYWRGaWxlU3luYyhmaWxlUGF0aCwgJ3V0Zi04Jyk7XG4gICAgcmV0dXJuIGBGaWxlOiAke2ZpbGVQYXRofVxcblxcbiR7Y29udGVudH1gO1xuICB9IGNhdGNoKF9lcnJvcikge1xuICAgIHJldHVybiBgRXJyb3IgcmVhZGluZyBmaWxlOiAke2ZpbGVQYXRofWA7XG4gIH1cbn07XG5cbmNvbnN0IGdldFByb2plY3RDb250ZXh0ID0gYXN5bmMgKG9wdGlvbnM6IEFJT3B0aW9ucyk6IFByb21pc2U8c3RyaW5nPiA9PiB7XG4gIGNvbnN0IHtmaWxlLCB0YXNrLCBjb250ZXh0fSA9IG9wdGlvbnM7XG5cbiAgaWYoY29udGV4dCA9PT0gZmFsc2UpIHtcbiAgICByZXR1cm4gJyc7XG4gIH1cblxuICBsZXQgcHJvamVjdENvbnRleHQgPSAnJztcblxuICBpZihmaWxlKSB7XG4gICAgcHJvamVjdENvbnRleHQgKz0gZ2V0RmlsZUNvbnRleHQoZmlsZSk7XG4gIH1cblxuICBzd2l0Y2godGFzaykge1xuICAgIGNhc2UgJ2dlbmVyYXRlJzpcbiAgICAgIGNvbnN0IGZpbGVzID0gZ2xvYlN5bmMoJ3NyYy8qKi8qLnt0cyx0c3gsanMsanN4fScsIHtcbiAgICAgICAgY3dkOiBwcm9jZXNzLmN3ZCgpLFxuICAgICAgICBpZ25vcmU6IFsnKiovbm9kZV9tb2R1bGVzLyoqJywgJyoqL2Rpc3QvKionLCAnKiovKi50ZXN0LionLCAnKiovKi5zcGVjLionXSxcbiAgICAgICAgbWF4RGVwdGg6IDNcbiAgICAgIH0pO1xuICAgICAgcHJvamVjdENvbnRleHQgKz0gYFxcblxcblByb2plY3Qgc3RydWN0dXJlOlxcbiR7ZmlsZXMuam9pbignXFxuJyl9YDtcbiAgICAgIGJyZWFrO1xuXG4gICAgY2FzZSAndGVzdCc6XG4gICAgICBpZihmaWxlKSB7XG4gICAgICAgIGNvbnN0IHRlc3RDb25maWcgPSBnZXRGaWxlQ29udGV4dCgnamVzdC5jb25maWcuanMnKTtcbiAgICAgICAgcHJvamVjdENvbnRleHQgKz0gYFxcblxcblRlc3QgY29uZmlndXJhdGlvbjpcXG4ke3Rlc3RDb25maWd9YDtcbiAgICAgIH1cbiAgICAgIGJyZWFrO1xuXG4gICAgY2FzZSAnb3B0aW1pemUnOlxuICAgICAgY29uc3Qgd2VicGFja0NvbmZpZyA9IGdldEZpbGVDb250ZXh0KCd3ZWJwYWNrLmNvbmZpZy5qcycpO1xuICAgICAgcHJvamVjdENvbnRleHQgKz0gYFxcblxcbldlYnBhY2sgY29uZmlndXJhdGlvbjpcXG4ke3dlYnBhY2tDb25maWd9YDtcbiAgICAgIGJyZWFrO1xuXG4gICAgZGVmYXVsdDpcbiAgICAgIGJyZWFrO1xuICB9XG5cbiAgcmV0dXJuIHByb2plY3RDb250ZXh0O1xufTtcblxuY29uc3QgY29uc3RydWN0UHJvbXB0ID0gKG9wdGlvbnM6IEFJT3B0aW9ucywgcHJvamVjdENvbnRleHQ6IHN0cmluZyk6IHN0cmluZyA9PiB7XG4gIGNvbnN0IHt0YXNrID0gJ2hlbHAnLCBwcm9tcHQgPSAnJ30gPSBvcHRpb25zO1xuXG4gIGNvbnN0IHRhc2tJbnN0cnVjdGlvbnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgZ2VuZXJhdGU6ICdHZW5lcmF0ZSBjb2RlIGFjY29yZGluZyB0byB0aGUgZm9sbG93aW5nIHJlcXVlc3QuIE1ha2Ugc3VyZSBpdCBmb2xsb3dzIGJlc3QgcHJhY3RpY2VzIGFuZCBpcyB3ZWxsIGRvY3VtZW50ZWQ6JyxcbiAgICBleHBsYWluOiAnRXhwbGFpbiB0aGUgZm9sbG93aW5nIGNvZGUgaW4gZGV0YWlsLCBpbmNsdWRpbmcgYW55IHBhdHRlcm5zLCBwb3RlbnRpYWwgaXNzdWVzLCBhbmQgaW1wcm92ZW1lbnQgc3VnZ2VzdGlvbnM6JyxcbiAgICB0ZXN0OiAnR2VuZXJhdGUgY29tcHJlaGVuc2l2ZSB1bml0IHRlc3RzIGZvciB0aGUgZm9sbG93aW5nIGNvZGU6JyxcbiAgICBvcHRpbWl6ZTogJ0FuYWx5emUgdGhlIGZvbGxvd2luZyBjb2RlL2NvbmZpZ3VyYXRpb24gYW5kIHN1Z2dlc3Qgb3B0aW1pemF0aW9uIGltcHJvdmVtZW50czonLFxuICAgIGhlbHA6ICdQcm92aWRlIGd1aWRhbmNlIG9uIHRoZSBmb2xsb3dpbmcgZGV2ZWxvcG1lbnQgcXVlc3Rpb246JyxcbiAgICBhc2s6ICdQcm92aWRlIGd1aWRhbmNlIG9uIHRoZSBmb2xsb3dpbmcgZGV2ZWxvcG1lbnQgcXVlc3Rpb246JyxcbiAgICBhbmFseXplOiAnQW5hbHl6ZSB0aGUgZm9sbG93aW5nIGNvZGU6J1xuICB9O1xuXG4gIGNvbnN0IHRhc2tJbnN0cnVjdGlvbiA9IHRhc2tJbnN0cnVjdGlvbnNbdGFza10gfHwgdGFza0luc3RydWN0aW9ucy5oZWxwO1xuXG4gIGxldCBmdWxsUHJvbXB0ID0gYCR7dGFza0luc3RydWN0aW9ufVxcblxcbiR7cHJvbXB0fWA7XG5cbiAgaWYocHJvamVjdENvbnRleHQpIHtcbiAgICBmdWxsUHJvbXB0ICs9IGBcXG5cXG49PT1DT05URVhUPT09XFxuJHtwcm9qZWN0Q29udGV4dH1gO1xuICB9XG5cbiAgcmV0dXJuIGZ1bGxQcm9tcHQ7XG59O1xuXG5jb25zdCBkaXNwbGF5UmVzcG9uc2UgPSAocmVzcG9uc2U6IGFueSwgb3B0aW9uczogQUlPcHRpb25zKTogdm9pZCA9PiB7XG4gIGNvbnN0IHt0YXNrID0gJ2hlbHAnLCBxdWlldCA9IGZhbHNlfSA9IG9wdGlvbnM7XG5cbiAgbGV0IGNvbnRlbnQgPSAnJztcblxuICBpZih0eXBlb2YgcmVzcG9uc2UgPT09ICdzdHJpbmcnKSB7XG4gICAgY29udGVudCA9IHJlc3BvbnNlO1xuICB9IGVsc2UgaWYocmVzcG9uc2UuY2hvaWNlcz8uWzBdPy5tZXNzYWdlPy5jb250ZW50KSB7XG4gICAgY29udGVudCA9IHJlc3BvbnNlLmNob2ljZXNbMF0ubWVzc2FnZS5jb250ZW50O1xuICB9IGVsc2UgaWYocmVzcG9uc2UuY29udGVudCkge1xuICAgIGNvbnRlbnQgPSByZXNwb25zZS5jb250ZW50O1xuICB9IGVsc2Uge1xuICAgIGNvbnRlbnQgPSAnTm8gcmVzcG9uc2UgcmVjZWl2ZWQgZnJvbSBBSSBtb2RlbCc7XG4gIH1cblxuICBjb25zdCBjbGVhbmVkQ29udGVudCA9IGNsZWFuUmVzcG9uc2UoY29udGVudCwgb3B0aW9ucyk7XG5cbiAgc3dpdGNoKHRhc2spIHtcbiAgICBjYXNlICdnZW5lcmF0ZSc6XG4gICAgICBsb2coJ1xcbkdlbmVyYXRlZCBDb2RlOlxcbicsICdzdWNjZXNzJywgcXVpZXQpO1xuICAgICAgbG9nKGNsZWFuZWRDb250ZW50LCAnZGVmYXVsdCcsIHF1aWV0KTtcbiAgICAgIGJyZWFrO1xuXG4gICAgY2FzZSAnZXhwbGFpbic6XG4gICAgICBsb2coJ1xcbkNvZGUgRXhwbGFuYXRpb246XFxuJywgJ3N1Y2Nlc3MnLCBxdWlldCk7XG4gICAgICBsb2coY2xlYW5lZENvbnRlbnQsICdkZWZhdWx0JywgcXVpZXQpO1xuICAgICAgYnJlYWs7XG5cbiAgICBjYXNlICd0ZXN0JzpcbiAgICAgIGxvZygnXFxuR2VuZXJhdGVkIFRlc3RzOlxcbicsICdzdWNjZXNzJywgcXVpZXQpO1xuICAgICAgbG9nKGNsZWFuZWRDb250ZW50LCAnZGVmYXVsdCcsIHF1aWV0KTtcbiAgICAgIGJyZWFrO1xuXG4gICAgY2FzZSAnb3B0aW1pemUnOlxuICAgICAgbG9nKCdcXG5PcHRpbWl6YXRpb24gU3VnZ2VzdGlvbnM6XFxuJywgJ3N1Y2Nlc3MnLCBxdWlldCk7XG4gICAgICBsb2coY2xlYW5lZENvbnRlbnQsICdkZWZhdWx0JywgcXVpZXQpO1xuICAgICAgYnJlYWs7XG5cbiAgICBkZWZhdWx0OlxuICAgICAgbG9nKCdcXG5BSSBSZXNwb25zZTpcXG4nLCAnc3VjY2VzcycsIHF1aWV0KTtcbiAgICAgIGxvZyhjbGVhbmVkQ29udGVudCwgJ2RlZmF1bHQnLCBxdWlldCk7XG4gICAgICBicmVhaztcbiAgfVxufTtcblxuY29uc3QgY2xlYW5SZXNwb25zZSA9IChjb250ZW50OiBzdHJpbmcsIG9wdGlvbnM6IEFJT3B0aW9ucyk6IHN0cmluZyA9PiB7XG4gIGNvbnN0IHtwcm9tcHQgPSAnJywgdGFzayA9ICdoZWxwJ30gPSBvcHRpb25zO1xuXG4gIGlmKCFjb250ZW50KSB7XG4gICAgcmV0dXJuIGNvbnRlbnQ7XG4gIH1cblxuICBsZXQgY2xlYW5lZENvbnRlbnQgPSBjb250ZW50O1xuXG4gIGNvbnN0IHRhc2tJbnN0cnVjdGlvbnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgZ2VuZXJhdGU6ICdHZW5lcmF0ZSBjb2RlIGFjY29yZGluZyB0byB0aGUgZm9sbG93aW5nIHJlcXVlc3QuIE1ha2Ugc3VyZSBpdCBmb2xsb3dzIGJlc3QgcHJhY3RpY2VzIGFuZCBpcyB3ZWxsIGRvY3VtZW50ZWQ6JyxcbiAgICBleHBsYWluOiAnRXhwbGFpbiB0aGUgZm9sbG93aW5nIGNvZGUgaW4gZGV0YWlsLCBpbmNsdWRpbmcgYW55IHBhdHRlcm5zLCBwb3RlbnRpYWwgaXNzdWVzLCBhbmQgaW1wcm92ZW1lbnQgc3VnZ2VzdGlvbnM6JyxcbiAgICB0ZXN0OiAnR2VuZXJhdGUgY29tcHJlaGVuc2l2ZSB1bml0IHRlc3RzIGZvciB0aGUgZm9sbG93aW5nIGNvZGU6JyxcbiAgICBvcHRpbWl6ZTogJ0FuYWx5emUgdGhlIGZvbGxvd2luZyBjb2RlL2NvbmZpZ3VyYXRpb24gYW5kIHN1Z2dlc3Qgb3B0aW1pemF0aW9uIGltcHJvdmVtZW50czonLFxuICAgIGhlbHA6ICdQcm92aWRlIGd1aWRhbmNlIG9uIHRoZSBmb2xsb3dpbmcgZGV2ZWxvcG1lbnQgcXVlc3Rpb246JyxcbiAgICBhc2s6ICdQcm92aWRlIGd1aWRhbmNlIG9uIHRoZSBmb2xsb3dpbmcgZGV2ZWxvcG1lbnQgcXVlc3Rpb246JyxcbiAgICBhbmFseXplOiAnQW5hbHl6ZSB0aGUgZm9sbG93aW5nIGNvZGU6J1xuICB9O1xuXG4gIGNvbnN0IGluc3RydWN0aW9uID0gdGFza0luc3RydWN0aW9uc1t0YXNrXSB8fCAnJztcblxuICBpZihpbnN0cnVjdGlvbiAmJiBjbGVhbmVkQ29udGVudC5pbmNsdWRlcyhpbnN0cnVjdGlvbikpIHtcbiAgICBjbGVhbmVkQ29udGVudCA9IGNsZWFuZWRDb250ZW50LnJlcGxhY2UoaW5zdHJ1Y3Rpb24sICcnKS50cmltKCk7XG4gIH1cblxuICBpZihwcm9tcHQgJiYgY2xlYW5lZENvbnRlbnQuaW5jbHVkZXMocHJvbXB0KSkge1xuICAgIGNsZWFuZWRDb250ZW50ID0gY2xlYW5lZENvbnRlbnQucmVwbGFjZShwcm9tcHQsICcnKS50cmltKCk7XG4gIH1cblxuICBpZihjbGVhbmVkQ29udGVudC5pbmNsdWRlcygnPT09Q09OVEVYVD09PScpKSB7XG4gICAgY2xlYW5lZENvbnRlbnQgPSBjbGVhbmVkQ29udGVudC5zcGxpdCgnPT09Q09OVEVYVD09PScpWzBdLnRyaW0oKTtcbiAgfVxuXG4gIGlmKCFjbGVhbmVkQ29udGVudCkge1xuICAgIHJldHVybiBjb250ZW50O1xuICB9XG5cbiAgcmV0dXJuIGNsZWFuZWRDb250ZW50O1xufTtcblxuY29uc3QgZ2V0UHJvdmlkZXJBdXRoID0gKHByb3ZpZGVyOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQgPT4ge1xuICBpZihwcm9jZXNzLmN3ZCgpLmluY2x1ZGVzKCdyZWFrdG9yJykpIHtcbiAgICByZXR1cm4gJ2N1cnNvci1hdXRoJztcbiAgfVxuXG4gIGlmKHByb2Nlc3MuZW52LkFJX0FQSV9LRVkpIHtcbiAgICByZXR1cm4gcHJvY2Vzcy5lbnYuQUlfQVBJX0tFWTtcbiAgfVxuXG4gIGlmKHByb3ZpZGVyID09PSAnbm9uZScgJiYgcHJvY2Vzcy5lbnYuQ1VSU09SX0lERSA9PT0gJ3RydWUnKSB7XG4gICAgcmV0dXJuICdjdXJzb3ItYXV0aCc7XG4gIH1cblxuICBzd2l0Y2gocHJvdmlkZXIpIHtcbiAgICBjYXNlICdvcGVuYWknOlxuICAgICAgcmV0dXJuIHByb2Nlc3MuZW52Lk9QRU5BSV9BUElfS0VZO1xuICAgIGNhc2UgJ2FudGhyb3BpYyc6XG4gICAgICByZXR1cm4gcHJvY2Vzcy5lbnYuQU5USFJPUElDX0FQSV9LRVk7XG4gICAgY2FzZSAnY3Vyc29yJzpcbiAgICAgIHJldHVybiAnY3Vyc29yLWF1dGgnO1xuICAgIGNhc2UgJ2NvcGlsb3QnOlxuICAgICAgcmV0dXJuIHByb2Nlc3MuZW52LkdJVEhVQl9UT0tFTjtcbiAgICBjYXNlICdub25lJzpcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn07XG5cbmNvbnN0IGRldGVjdEN1cnNvcklERSA9ICgpOiBib29sZWFuID0+IHtcbiAgaWYocHJvY2Vzcy5lbnYuQ1VSU09SX0lERSA9PT0gJ3RydWUnKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBjb25zdCBwb3NzaWJsZUN1cnNvclNpZ25hbHMgPSBbXG4gICAgcHJvY2Vzcy5lbnYuQ1VSU09SX0VYVEVOU0lPTiA9PT0gJ3RydWUnLFxuICAgIHByb2Nlc3MuZW52LkNVUlNPUl9URVJNSU5BTCA9PT0gJ3RydWUnLFxuICAgIHByb2Nlc3MuZW52LkNVUlNPUl9BUFAgPT09ICd0cnVlJyxcbiAgICBwcm9jZXNzLmVudi5QQVRIPy5pbmNsdWRlcygnY3Vyc29yJyksXG4gICAgISFwcm9jZXNzLmVudi5DVVJTT1JfU0VTU0lPTl9JRFxuICBdO1xuXG4gIGNvbnN0IGlzQ3Vyc29ySURFID0gcG9zc2libGVDdXJzb3JTaWduYWxzLnNvbWUoKHNpZ25hbCkgPT4gc2lnbmFsKTtcblxuICBpZihpc0N1cnNvcklERSkge1xuICAgIHByb2Nlc3MuZW52LkNVUlNPUl9JREUgPSAndHJ1ZSc7XG4gIH1cblxuICByZXR1cm4gaXNDdXJzb3JJREU7XG59O1xuXG5leHBvcnQgY29uc3QgYWlGdW5jdGlvbiA9IGFzeW5jIChvcHRpb25zOiBBSU9wdGlvbnMpOiBQcm9taXNlPGFueT4gPT4ge1xuICB0cnkge1xuICAgIGNvbnN0IGNvbmZpZyA9IExleENvbmZpZy5jb25maWcgfHwge307XG4gICAgY29uc3QgYWlDb25maWcgPSBjb25maWcuYWkgfHwge307XG4gICAgY29uc3QgcHJvdmlkZXIgPSBvcHRpb25zLnByb3ZpZGVyIHx8IGFpQ29uZmlnLnByb3ZpZGVyIHx8ICdub25lJztcblxuICAgIGlmKHByb3ZpZGVyID09PSAnbm9uZScgJiYgIXByb2Nlc3MuZW52LkNVUlNPUl9FWFRFTlNJT04pIHtcbiAgICAgIGxvZyhgJHtjaGFsay5yZWQoJ0Vycm9yOicpfSBObyBBSSBwcm92aWRlciBjb25maWd1cmVkLmAsICdlcnJvcicpO1xuICAgICAgcmV0dXJuIHtlcnJvcjogJ05vIEFJIHByb3ZpZGVyIGNvbmZpZ3VyZWQnfTtcbiAgICB9XG5cbiAgICBjb25zdCB0YXNrID0gb3B0aW9ucy50YXNrIHx8ICdhc2snO1xuICAgIGNvbnN0IHZhbGlkVGFza3MgPSBbJ2V4cGxhaW4nLCAnZ2VuZXJhdGUnLCAndGVzdCcsICdhbmFseXplJywgJ2FzayddO1xuXG4gICAgaWYoIXZhbGlkVGFza3MuaW5jbHVkZXModGFzaykpIHtcbiAgICAgIGxvZyhgJHtjaGFsay5yZWQoJ0Vycm9yOicpfSBJbnZhbGlkIHRhc2sgXCIke3Rhc2t9XCIuIFZhbGlkIHRhc2tzIGFyZTogJHt2YWxpZFRhc2tzLmpvaW4oJywgJyl9YCwgJ2Vycm9yJyk7XG4gICAgICByZXR1cm4ge2Vycm9yOiBgSW52YWxpZCB0YXNrIFwiJHt0YXNrfVwiYH07XG4gICAgfVxuXG4gICAgY29uc3Qge3Byb21wdH0gPSBvcHRpb25zO1xuXG4gICAgaWYoIXByb21wdCkge1xuICAgICAgbG9nKGAke2NoYWxrLnJlZCgnRXJyb3I6Jyl9IE5vIHByb21wdCBwcm92aWRlZC4gVXNlIC0tcHJvbXB0IFwiWW91ciBwcm9tcHQgaGVyZVwiYCwgJ2Vycm9yJyk7XG4gICAgICByZXR1cm4ge2Vycm9yOiAnTm8gcHJvbXB0IHByb3ZpZGVkJ307XG4gICAgfVxuXG4gICAgbGV0IGNvbnRleHQgPSAnJztcblxuICAgIGlmKG9wdGlvbnMuZmlsZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgZnMgPSBhd2FpdCBpbXBvcnQoJ2ZzL3Byb21pc2VzJyk7XG4gICAgICAgIGNvbnN0IGdsb2IgPSBhd2FpdCBpbXBvcnQoJ2dsb2InKTtcbiAgICAgICAgY29uc3QgZmlsZXMgPSBhd2FpdCBnbG9iLmdsb2Iob3B0aW9ucy5maWxlKTtcblxuICAgICAgICBpZihmaWxlcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICBsb2coYCR7Y2hhbGsueWVsbG93KCdXYXJuaW5nOicpfSBObyBmaWxlcyBmb3VuZCBtYXRjaGluZyBcIiR7b3B0aW9ucy5maWxlfVwiYCwgJ3dhcm5pbmcnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBmb3IoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuICAgICAgICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKGZpbGUsICd1dGY4Jyk7XG4gICAgICAgICAgICBjb250ZXh0ICs9IGBcXG49PT1GSUxFOiAke2ZpbGV9PT09XFxuJHtjb250ZW50fVxcbmA7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGNhdGNoKGVycm9yKSB7XG4gICAgICAgIGxvZyhgJHtjaGFsay55ZWxsb3coJ1dhcm5pbmc6Jyl9IEVycm9yIHJlYWRpbmcgZmlsZTogJHtlcnJvci5tZXNzYWdlfWAsICd3YXJuaW5nJyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYob3B0aW9ucy5kaXIpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHtleGVjYVN5bmN9ID0gYXdhaXQgaW1wb3J0KCdleGVjYScpO1xuICAgICAgICBjb25zdCByZXN1bHQgPSBleGVjYVN5bmMoJ2ZpbmQnLCBbb3B0aW9ucy5kaXIsICctdHlwZScsICdmJywgJ3wnLCAnc29ydCddKTtcbiAgICAgICAgY29udGV4dCArPSBgXFxuPT09UHJvamVjdCBzdHJ1Y3R1cmU6PT09XFxuJHtyZXN1bHQuc3Rkb3V0fVxcbmA7XG4gICAgICB9IGNhdGNoKGVycm9yKSB7XG4gICAgICAgIGxvZyhgJHtjaGFsay55ZWxsb3coJ1dhcm5pbmc6Jyl9IEVycm9yIHJlYWRpbmcgZGlyZWN0b3J5OiAke2Vycm9yLm1lc3NhZ2V9YCwgJ3dhcm5pbmcnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBsZXQgZm9ybWF0dGVkUHJvbXB0ID0gJyc7XG5cbiAgICBzd2l0Y2godGFzaykge1xuICAgICAgY2FzZSAnZXhwbGFpbic6XG4gICAgICAgIGZvcm1hdHRlZFByb21wdCA9IGBFeHBsYWluIHRoZSBmb2xsb3dpbmcgY29kZTpcXG4ke3Byb21wdH1gO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2dlbmVyYXRlJzpcbiAgICAgICAgZm9ybWF0dGVkUHJvbXB0ID0gYEdlbmVyYXRlIGNvZGUgYWNjb3JkaW5nIHRvIHRoZSBmb2xsb3dpbmcgcmVxdWVzdDpcXG4ke3Byb21wdH1gO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ3Rlc3QnOlxuICAgICAgICBmb3JtYXR0ZWRQcm9tcHQgPSBgR2VuZXJhdGUgY29tcHJlaGVuc2l2ZSB1bml0IHRlc3RzOlxcbiR7cHJvbXB0fWA7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnYW5hbHl6ZSc6XG4gICAgICAgIGZvcm1hdHRlZFByb21wdCA9IGBBbmFseXplIHRoZSBmb2xsb3dpbmcgY29kZTpcXG4ke3Byb21wdH1gO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2Fzayc6XG4gICAgICAgIGZvcm1hdHRlZFByb21wdCA9IGBQcm92aWRlIGd1aWRhbmNlIG9uIHRoZSBmb2xsb3dpbmcgZGV2ZWxvcG1lbnQgcXVlc3Rpb246XFxuJHtwcm9tcHR9YDtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgaWYoY29udGV4dCkge1xuICAgICAgZm9ybWF0dGVkUHJvbXB0ICs9IGBcXG49PT1DT05URVhUPT09XFxuJHtjb250ZXh0fWA7XG4gICAgfVxuXG4gICAgaWYoKHByb3ZpZGVyID09PSAnY3Vyc29yJyB8fCBwcm9jZXNzLmVudi5DVVJTT1JfRVhURU5TSU9OKSAmJiB0YXNrID09PSAnZ2VuZXJhdGUnKSB7XG4gICAgICBsb2coJ1VzaW5nIEN1cnNvciBJREUgZm9yIGNvZGUgZ2VuZXJhdGlvbi4uLicsICdpbmZvJyk7XG4gICAgICBsb2coJ05vdGU6IEZvciBmdWxsIGNvZGUgZ2VuZXJhdGlvbiBjYXBhYmlsaXRpZXMsIHBsZWFzZSB1c2UgQ3Vyc29yIElERSBkaXJlY3RseSB3aXRoIENtZCtMIG9yIENtZCtLLicsICdpbmZvJyk7XG4gICAgICBsb2coJ1RoZSBDTEkgaW50ZWdyYXRpb24gaGFzIGxpbWl0ZWQgY2FwYWJpbGl0aWVzIGZvciBjb2RlIGdlbmVyYXRpb24uJywgJ3dhcm5pbmcnKTtcbiAgICB9IGVsc2UgaWYocHJvdmlkZXIgPT09ICdjdXJzb3InIHx8IHByb2Nlc3MuZW52LkNVUlNPUl9FWFRFTlNJT04pIHtcbiAgICAgIGxvZygnVXNpbmcgQ3Vyc29yIElERSBmb3IgQUkgYXNzaXN0YW5jZS4uLicsICdpbmZvJyk7XG4gICAgICBsb2coJ05vdGU6IFRoaXMgaXMgYSBsaW1pdGVkIGludGVncmF0aW9uLiBGb3IgZnVsbCBBSSBjYXBhYmlsaXRpZXMsIHVzZSBDdXJzb3IgSURFIGRpcmVjdGx5LicsICdpbmZvJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZyhgVXNpbmcgJHtwcm92aWRlcn0gZm9yIEFJIGFzc2lzdGFuY2UuLi5gLCAnaW5mbycpO1xuICAgIH1cblxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2FsbEFJU2VydmljZShmb3JtYXR0ZWRQcm9tcHQsIG9wdGlvbnMucXVpZXQgfHwgZmFsc2UpO1xuXG4gICAgbG9nKGBcXG4ke3Jlc3BvbnNlfWAsICdzdWNjZXNzJyk7XG5cbiAgICByZXR1cm4ge3Jlc3BvbnNlfTtcbiAgfSBjYXRjaChlcnJvcikge1xuICAgIGxvZyhgJHtjaGFsay5yZWQoJ0Vycm9yOicpfSAke2Vycm9yLm1lc3NhZ2V9YCwgJ2Vycm9yJyk7XG4gICAgcmV0dXJuIHtlcnJvcjogZXJyb3IubWVzc2FnZX07XG4gIH1cbn07XG5cbmV4cG9ydCBjb25zdCBhaSA9IG5ldyBDb21tYW5kKCdhaScpXG4gIC5kZXNjcmlwdGlvbignVXNlIEFJIHRvIGhlbHAgd2l0aCBkZXZlbG9wbWVudCB0YXNrcycpXG4gIC5vcHRpb24oJy0tcHJvdmlkZXIgPHByb3ZpZGVyPicsICdBSSBwcm92aWRlciB0byB1c2UgKG9wZW5haSwgYW50aHJvcGljLCBjdXJzb3IpJylcbiAgLm9wdGlvbignLS10YXNrIDx0YXNrPicsICdUYXNrIHRvIHBlcmZvcm0gKGV4cGxhaW4sIGdlbmVyYXRlLCB0ZXN0LCBhbmFseXplLCBhc2spJylcbiAgLm9wdGlvbignLS1wcm9tcHQgPHByb21wdD4nLCAnUHJvbXB0IHRvIHNlbmQgdG8gQUknKVxuICAub3B0aW9uKCctLWZpbGUgPGZpbGU+JywgJ0ZpbGUgdG8gYW5hbHl6ZScpXG4gIC5vcHRpb24oJy0tZGlyIDxkaXI+JywgJ0RpcmVjdG9yeSB0byBhbmFseXplJylcbiAgLmFjdGlvbihhc3luYyAob3B0aW9uczogQUlPcHRpb25zKSA9PiB7XG4gICAgYXdhaXQgYWlGdW5jdGlvbihvcHRpb25zKTtcbiAgfSk7XG5cbmV4cG9ydCBkZWZhdWx0IGFpOyJd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