@nlabs/lex 1.49.4 → 1.50.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 (55) hide show
  1. package/.swcrc +35 -0
  2. package/README.md +43 -59
  3. package/__mocks__/chalk.js +19 -17
  4. package/config.json +32 -8
  5. package/examples/lex.config.js +110 -10
  6. package/index.cjs +1 -5
  7. package/lex.config.js +34 -7
  8. package/lib/Button.stories.js +99 -0
  9. package/lib/LexConfig.d.ts +60 -22
  10. package/lib/LexConfig.js +285 -244
  11. package/lib/commands/ai/ai.js +287 -288
  12. package/lib/commands/ai/index.js +8 -7
  13. package/lib/commands/build/build.d.ts +2 -2
  14. package/lib/commands/build/build.js +349 -458
  15. package/lib/commands/clean/clean.js +45 -33
  16. package/lib/commands/compile/compile.js +214 -227
  17. package/lib/commands/config/config.js +46 -42
  18. package/lib/commands/copy/copy.js +36 -35
  19. package/lib/commands/create/create.js +200 -121
  20. package/lib/commands/dev/dev.d.ts +2 -0
  21. package/lib/commands/dev/dev.js +259 -263
  22. package/lib/commands/init/init.js +108 -88
  23. package/lib/commands/link/link.js +18 -14
  24. package/lib/commands/lint/lint.js +735 -742
  25. package/lib/commands/migrate/migrate.js +49 -36
  26. package/lib/commands/publish/publish.js +116 -96
  27. package/lib/commands/serverless/serverless.js +611 -585
  28. package/lib/commands/storybook/storybook.js +242 -238
  29. package/lib/commands/test/test.d.ts +1 -1
  30. package/lib/commands/test/test.js +382 -394
  31. package/lib/commands/update/update.js +141 -120
  32. package/lib/commands/upgrade/upgrade.js +51 -44
  33. package/lib/commands/versions/versions.d.ts +1 -1
  34. package/lib/commands/versions/versions.js +36 -38
  35. package/lib/create/changelog.js +136 -125
  36. package/lib/index.js +40 -38
  37. package/lib/lex.js +95 -68
  38. package/lib/storybook/index.js +6 -1
  39. package/lib/test-react/index.js +7 -84
  40. package/lib/types.d.ts +1 -1
  41. package/lib/types.js +7 -1
  42. package/lib/utils/aiService.js +240 -227
  43. package/lib/utils/app.js +274 -273
  44. package/lib/utils/deepMerge.js +37 -23
  45. package/lib/utils/file.js +218 -215
  46. package/lib/utils/log.js +29 -27
  47. package/lib/utils/reactShim.js +7 -85
  48. package/lib/utils/translations.js +91 -65
  49. package/package.json +63 -64
  50. package/templates/typescript/DataLayer.js.txt +218 -0
  51. package/templates/typescript/DataLayer.test.js.txt +268 -0
  52. package/templates/typescript/DataLayer.test.ts.txt +269 -0
  53. package/templates/typescript/DataLayer.ts.txt +227 -0
  54. package/webpack.config.js +53 -26
  55. package/lib/commands/lint/autofix.d.ts +0 -2
@@ -1,303 +1,302 @@
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";
1
+ /**
2
+ * Copyright (c) 2018-Present, Nitrogen Labs, Inc.
3
+ * Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
4
+ */ import chalk from 'chalk';
5
+ import { Command } from 'commander';
6
+ import { readFileSync } from 'fs';
7
+ import { sync as globSync } from 'glob';
8
+ import { LexConfig } from '../../LexConfig.js';
9
+ import { callAIService } from '../../utils/aiService.js';
10
+ import { log } from '../../utils/log.js';
11
+ 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) {
12
+ process.env.CURSOR_IDE = 'true';
10
13
  }
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/**", "**/lib/**", "**/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
- }
14
+ const getFileContext = (filePath)=>{
15
+ try {
16
+ const content = readFileSync(filePath, 'utf-8');
17
+ return `File: ${filePath}\n\n${content}`;
18
+ } catch (_error) {
19
+ return `Error reading file: ${filePath}`;
20
+ }
121
21
  };
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;
22
+ const getProjectContext = async (options)=>{
23
+ const { file, task, context } = options;
24
+ if (context === false) {
25
+ return '';
26
+ }
27
+ let projectContext = '';
28
+ if (file) {
29
+ projectContext += getFileContext(file);
30
+ }
31
+ switch(task){
32
+ case 'generate':
33
+ const files = globSync('src/**/*.{ts,tsx,js,jsx}', {
34
+ cwd: process.cwd(),
35
+ ignore: [
36
+ '**/node_modules/**',
37
+ '**/lib/**',
38
+ '**/dist/**',
39
+ '**/*.test.*',
40
+ '**/*.spec.*'
41
+ ],
42
+ maxDepth: 3
43
+ });
44
+ projectContext += `\n\nProject structure:\n${files.join('\n')}`;
45
+ break;
46
+ case 'test':
47
+ if (file) {
48
+ const testConfig = getFileContext('jest.config.js');
49
+ projectContext += `\n\nTest configuration:\n${testConfig}`;
50
+ }
51
+ break;
52
+ case 'optimize':
53
+ const webpackConfig = getFileContext('webpack.config.js');
54
+ projectContext += `\n\nWebpack configuration:\n${webpackConfig}`;
55
+ break;
56
+ default:
57
+ break;
58
+ }
59
+ return projectContext;
151
60
  };
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
- }
61
+ const constructPrompt = (options, projectContext)=>{
62
+ const { task = 'help', prompt = '' } = options;
63
+ const taskInstructions = {
64
+ analyze: 'Analyze the following code:',
65
+ ask: 'Provide guidance on the following development question:',
66
+ explain: 'Explain the following code in detail, including any patterns, potential issues, and improvement suggestions:',
67
+ generate: 'Generate code according to the following request. Make sure it follows best practices and is well documented:',
68
+ help: 'Provide guidance on the following development question:',
69
+ optimize: 'Analyze the following code/configuration and suggest optimization improvements:',
70
+ test: 'Generate comprehensive unit tests for the following code:'
71
+ };
72
+ const taskInstruction = taskInstructions[task] || taskInstructions.help;
73
+ let fullPrompt = `${taskInstruction}\n\n${prompt}`;
74
+ if (projectContext) {
75
+ fullPrompt += `\n\n===CONTEXT===\n${projectContext}`;
76
+ }
77
+ return fullPrompt;
176
78
  };
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;
79
+ const displayResponse = (response, options)=>{
80
+ const { task = 'help', quiet = false } = options;
81
+ let content = '';
82
+ if (typeof response === 'string') {
83
+ content = response;
84
+ } else if (response.choices?.[0]?.message?.content) {
85
+ const { content: messageContent } = response.choices[0].message;
86
+ content = messageContent;
87
+ } else if (response.content) {
88
+ const { content: responseContent } = response;
89
+ content = responseContent;
90
+ } else {
91
+ content = 'No response received from AI model';
92
+ }
93
+ const cleanedContent = cleanResponse(content, options);
94
+ switch(task){
95
+ case 'generate':
96
+ log('\nGenerated Code:\n', 'success', quiet);
97
+ log(cleanedContent, 'default', quiet);
98
+ break;
99
+ case 'explain':
100
+ log('\nCode Explanation:\n', 'success', quiet);
101
+ log(cleanedContent, 'default', quiet);
102
+ break;
103
+ case 'test':
104
+ log('\nGenerated Tests:\n', 'success', quiet);
105
+ log(cleanedContent, 'default', quiet);
106
+ break;
107
+ case 'optimize':
108
+ log('\nOptimization Suggestions:\n', 'success', quiet);
109
+ log(cleanedContent, 'default', quiet);
110
+ break;
111
+ default:
112
+ log('\nAI Response:\n', 'success', quiet);
113
+ log(cleanedContent, 'default', quiet);
114
+ break;
115
+ }
193
116
  };
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" };
117
+ const cleanResponse = (content, options)=>{
118
+ const { prompt = '', task = 'help' } = options;
119
+ if (!content) {
120
+ return content;
202
121
  }
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}"` };
122
+ let cleanedContent = content;
123
+ const taskInstructions = {
124
+ analyze: 'Analyze the following code:',
125
+ ask: 'Provide guidance on the following development question:',
126
+ explain: 'Explain the following code in detail, including any patterns, potential issues, and improvement suggestions:',
127
+ generate: 'Generate code according to the following request. Make sure it follows best practices and is well documented:',
128
+ help: 'Provide guidance on the following development question:',
129
+ optimize: 'Analyze the following code/configuration and suggest optimization improvements:',
130
+ test: 'Generate comprehensive unit tests for the following code:'
131
+ };
132
+ const instruction = taskInstructions[task] || '';
133
+ if (instruction && cleanedContent.includes(instruction)) {
134
+ cleanedContent = cleanedContent.replace(instruction, '').trim();
208
135
  }
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" };
136
+ if (prompt && cleanedContent.includes(prompt)) {
137
+ cleanedContent = cleanedContent.replace(prompt, '').trim();
213
138
  }
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
- }
139
+ if (cleanedContent.includes('===CONTEXT===')) {
140
+ cleanedContent = cleanedContent.split('===CONTEXT===')[0].trim();
234
141
  }
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
- }
142
+ if (!cleanedContent) {
143
+ return content;
246
144
  }
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;
145
+ return cleanedContent;
146
+ };
147
+ const getProviderAuth = (provider)=>{
148
+ if (process.cwd().includes('reaktor')) {
149
+ return 'cursor-auth';
269
150
  }
270
- if (context) {
271
- formattedPrompt += `
272
- ===CONTEXT===
273
- ${context}`;
151
+ if (process.env.AI_API_KEY) {
152
+ return process.env.AI_API_KEY;
274
153
  }
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");
154
+ if (provider === 'none' && process.env.CURSOR_IDE === 'true') {
155
+ return 'cursor-auth';
156
+ }
157
+ switch(provider){
158
+ case 'openai':
159
+ return process.env.OPENAI_API_KEY;
160
+ case 'anthropic':
161
+ return process.env.ANTHROPIC_API_KEY;
162
+ case 'cursor':
163
+ return 'cursor-auth';
164
+ case 'copilot':
165
+ return process.env.GITHUB_TOKEN;
166
+ case 'none':
167
+ return undefined;
168
+ default:
169
+ return undefined;
284
170
  }
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
171
  };
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
172
+ const detectCursorIDE = ()=>{
173
+ if (process.env.CURSOR_IDE === 'true') {
174
+ return true;
175
+ }
176
+ const possibleCursorSignals = [
177
+ process.env.CURSOR_EXTENSION === 'true',
178
+ process.env.CURSOR_TERMINAL === 'true',
179
+ process.env.CURSOR_APP === 'true',
180
+ process.env.PATH?.includes('cursor'),
181
+ !!process.env.CURSOR_SESSION_ID
182
+ ];
183
+ const isCursorIDE = possibleCursorSignals.some((signal)=>signal);
184
+ if (isCursorIDE) {
185
+ process.env.CURSOR_IDE = 'true';
186
+ }
187
+ return isCursorIDE;
302
188
  };
303
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2NvbW1hbmRzL2FpL2FpLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIENvcHlyaWdodCAoYykgMjAxOC1QcmVzZW50LCBOaXRyb2dlbiBMYWJzLCBJbmMuXG4gKiBDb3B5cmlnaHRzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIHRoZSBhY2NvbXBhbnlpbmcgTElDRU5TRSBmaWxlIGZvciB0ZXJtcy5cbiAqL1xuaW1wb3J0IGNoYWxrIGZyb20gJ2NoYWxrJztcbmltcG9ydCB7Q29tbWFuZH0gZnJvbSAnY29tbWFuZGVyJztcbmltcG9ydCB7cmVhZEZpbGVTeW5jfSBmcm9tICdmcyc7XG5pbXBvcnQge3N5bmMgYXMgZ2xvYlN5bmN9IGZyb20gJ2dsb2InO1xuXG5pbXBvcnQge0xleENvbmZpZ30gZnJvbSAnLi4vLi4vTGV4Q29uZmlnLmpzJztcbmltcG9ydCB7Y2FsbEFJU2VydmljZX0gZnJvbSAnLi4vLi4vdXRpbHMvYWlTZXJ2aWNlLmpzJztcbmltcG9ydCB7bG9nfSBmcm9tICcuLi8uLi91dGlscy9sb2cuanMnO1xuXG5pZihwcm9jZXNzLmVudi5DVVJTT1JfRVhURU5TSU9OID09PSAndHJ1ZScgfHxcbiAgcHJvY2Vzcy5lbnYuQ1VSU09SX1RFUk1JTkFMID09PSAndHJ1ZScgfHxcbiAgcHJvY2Vzcy5lbnYuQ1VSU09SX0FQUCA9PT0gJ3RydWUnIHx8XG4gIHByb2Nlc3MuZW52LlBBVEg/LmluY2x1ZGVzKCdjdXJzb3InKSB8fFxuICBwcm9jZXNzLmVudi5DVVJTT1JfU0VTU0lPTl9JRCkge1xuICBwcm9jZXNzLmVudi5DVVJTT1JfSURFID0gJ3RydWUnO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEFJT3B0aW9ucyB7XG4gIHJlYWRvbmx5IGNsaU5hbWU/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGNvbnRleHQ/OiBib29sZWFuO1xuICByZWFkb25seSBmaWxlPzogc3RyaW5nO1xuICByZWFkb25seSBsZXhDb25maWc/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IG1vZGVsPzogc3RyaW5nO1xuICByZWFkb25seSBwcm9tcHQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHF1aWV0PzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgdGFzaz86ICdnZW5lcmF0ZScgfCAnZXhwbGFpbicgfCAndGVzdCcgfCAnb3B0aW1pemUnIHwgJ2hlbHAnIHwgJ2FzaycgfCAnYW5hbHl6ZSc7XG4gIHJlYWRvbmx5IGRlYnVnPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgcHJvdmlkZXI/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGRpcj86IHN0cmluZztcbn1cblxuY29uc3QgZ2V0RmlsZUNvbnRleHQgPSAoZmlsZVBhdGg6IHN0cmluZyk6IHN0cmluZyA9PiB7XG4gIHRyeSB7XG4gICAgY29uc3QgY29udGVudCA9IHJlYWRGaWxlU3luYyhmaWxlUGF0aCwgJ3V0Zi04Jyk7XG4gICAgcmV0dXJuIGBGaWxlOiAke2ZpbGVQYXRofVxcblxcbiR7Y29udGVudH1gO1xuICB9IGNhdGNoIChfZXJyb3IpIHtcbiAgICByZXR1cm4gYEVycm9yIHJlYWRpbmcgZmlsZTogJHtmaWxlUGF0aH1gO1xuICB9XG59O1xuXG5jb25zdCBnZXRQcm9qZWN0Q29udGV4dCA9IGFzeW5jIChvcHRpb25zOiBBSU9wdGlvbnMpOiBQcm9taXNlPHN0cmluZz4gPT4ge1xuICBjb25zdCB7ZmlsZSwgdGFzaywgY29udGV4dH0gPSBvcHRpb25zO1xuXG4gIGlmKGNvbnRleHQgPT09IGZhbHNlKSB7XG4gICAgcmV0dXJuICcnO1xuICB9XG5cbiAgbGV0IHByb2plY3RDb250ZXh0ID0gJyc7XG5cbiAgaWYoZmlsZSkge1xuICAgIHByb2plY3RDb250ZXh0ICs9IGdldEZpbGVDb250ZXh0KGZpbGUpO1xuICB9XG5cbiAgc3dpdGNoKHRhc2spIHtcbiAgICBjYXNlICdnZW5lcmF0ZSc6XG4gICAgICBjb25zdCBmaWxlcyA9IGdsb2JTeW5jKCdzcmMvKiovKi57dHMsdHN4LGpzLGpzeH0nLCB7XG4gICAgICAgIGN3ZDogcHJvY2Vzcy5jd2QoKSxcbiAgICAgICAgaWdub3JlOiBbJyoqL25vZGVfbW9kdWxlcy8qKicsICcqKi9saWIvKionLCAnKiovZGlzdC8qKicsICcqKi8qLnRlc3QuKicsICcqKi8qLnNwZWMuKiddLFxuICAgICAgICBtYXhEZXB0aDogM1xuICAgICAgfSk7XG4gICAgICBwcm9qZWN0Q29udGV4dCArPSBgXFxuXFxuUHJvamVjdCBzdHJ1Y3R1cmU6XFxuJHtmaWxlcy5qb2luKCdcXG4nKX1gO1xuICAgICAgYnJlYWs7XG5cbiAgICBjYXNlICd0ZXN0JzpcbiAgICAgIGlmKGZpbGUpIHtcbiAgICAgICAgY29uc3QgdGVzdENvbmZpZyA9IGdldEZpbGVDb250ZXh0KCdqZXN0LmNvbmZpZy5qcycpO1xuICAgICAgICBwcm9qZWN0Q29udGV4dCArPSBgXFxuXFxuVGVzdCBjb25maWd1cmF0aW9uOlxcbiR7dGVzdENvbmZpZ31gO1xuICAgICAgfVxuICAgICAgYnJlYWs7XG5cbiAgICBjYXNlICdvcHRpbWl6ZSc6XG4gICAgICBjb25zdCB3ZWJwYWNrQ29uZmlnID0gZ2V0RmlsZUNvbnRleHQoJ3dlYnBhY2suY29uZmlnLmpzJyk7XG4gICAgICBwcm9qZWN0Q29udGV4dCArPSBgXFxuXFxuV2VicGFjayBjb25maWd1cmF0aW9uOlxcbiR7d2VicGFja0NvbmZpZ31gO1xuICAgICAgYnJlYWs7XG5cbiAgICBkZWZhdWx0OlxuICAgICAgYnJlYWs7XG4gIH1cblxuICByZXR1cm4gcHJvamVjdENvbnRleHQ7XG59O1xuXG5jb25zdCBjb25zdHJ1Y3RQcm9tcHQgPSAob3B0aW9uczogQUlPcHRpb25zLCBwcm9qZWN0Q29udGV4dDogc3RyaW5nKTogc3RyaW5nID0+IHtcbiAgY29uc3Qge3Rhc2sgPSAnaGVscCcsIHByb21wdCA9ICcnfSA9IG9wdGlvbnM7XG5cbiAgY29uc3QgdGFza0luc3RydWN0aW9uczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICBnZW5lcmF0ZTogJ0dlbmVyYXRlIGNvZGUgYWNjb3JkaW5nIHRvIHRoZSBmb2xsb3dpbmcgcmVxdWVzdC4gTWFrZSBzdXJlIGl0IGZvbGxvd3MgYmVzdCBwcmFjdGljZXMgYW5kIGlzIHdlbGwgZG9jdW1lbnRlZDonLFxuICAgIGV4cGxhaW46ICdFeHBsYWluIHRoZSBmb2xsb3dpbmcgY29kZSBpbiBkZXRhaWwsIGluY2x1ZGluZyBhbnkgcGF0dGVybnMsIHBvdGVudGlhbCBpc3N1ZXMsIGFuZCBpbXByb3ZlbWVudCBzdWdnZXN0aW9uczonLFxuICAgIHRlc3Q6ICdHZW5lcmF0ZSBjb21wcmVoZW5zaXZlIHVuaXQgdGVzdHMgZm9yIHRoZSBmb2xsb3dpbmcgY29kZTonLFxuICAgIG9wdGltaXplOiAnQW5hbHl6ZSB0aGUgZm9sbG93aW5nIGNvZGUvY29uZmlndXJhdGlvbiBhbmQgc3VnZ2VzdCBvcHRpbWl6YXRpb24gaW1wcm92ZW1lbnRzOicsXG4gICAgaGVscDogJ1Byb3ZpZGUgZ3VpZGFuY2Ugb24gdGhlIGZvbGxvd2luZyBkZXZlbG9wbWVudCBxdWVzdGlvbjonLFxuICAgIGFzazogJ1Byb3ZpZGUgZ3VpZGFuY2Ugb24gdGhlIGZvbGxvd2luZyBkZXZlbG9wbWVudCBxdWVzdGlvbjonLFxuICAgIGFuYWx5emU6ICdBbmFseXplIHRoZSBmb2xsb3dpbmcgY29kZTonXG4gIH07XG5cbiAgY29uc3QgdGFza0luc3RydWN0aW9uID0gdGFza0luc3RydWN0aW9uc1t0YXNrXSB8fCB0YXNrSW5zdHJ1Y3Rpb25zLmhlbHA7XG5cbiAgbGV0IGZ1bGxQcm9tcHQgPSBgJHt0YXNrSW5zdHJ1Y3Rpb259XFxuXFxuJHtwcm9tcHR9YDtcblxuICBpZihwcm9qZWN0Q29udGV4dCkge1xuICAgIGZ1bGxQcm9tcHQgKz0gYFxcblxcbj09PUNPTlRFWFQ9PT1cXG4ke3Byb2plY3RDb250ZXh0fWA7XG4gIH1cblxuICByZXR1cm4gZnVsbFByb21wdDtcbn07XG5cbmNvbnN0IGRpc3BsYXlSZXNwb25zZSA9IChyZXNwb25zZTogYW55LCBvcHRpb25zOiBBSU9wdGlvbnMpOiB2b2lkID0+IHtcbiAgY29uc3Qge3Rhc2sgPSAnaGVscCcsIHF1aWV0ID0gZmFsc2V9ID0gb3B0aW9ucztcblxuICBsZXQgY29udGVudCA9ICcnO1xuXG4gIGlmKHR5cGVvZiByZXNwb25zZSA9PT0gJ3N0cmluZycpIHtcbiAgICBjb250ZW50ID0gcmVzcG9uc2U7XG4gIH0gZWxzZSBpZihyZXNwb25zZS5jaG9pY2VzPy5bMF0/Lm1lc3NhZ2U/LmNvbnRlbnQpIHtcbiAgICBjb250ZW50ID0gcmVzcG9uc2UuY2hvaWNlc1swXS5tZXNzYWdlLmNvbnRlbnQ7XG4gIH0gZWxzZSBpZihyZXNwb25zZS5jb250ZW50KSB7XG4gICAgY29udGVudCA9IHJlc3BvbnNlLmNvbnRlbnQ7XG4gIH0gZWxzZSB7XG4gICAgY29udGVudCA9ICdObyByZXNwb25zZSByZWNlaXZlZCBmcm9tIEFJIG1vZGVsJztcbiAgfVxuXG4gIGNvbnN0IGNsZWFuZWRDb250ZW50ID0gY2xlYW5SZXNwb25zZShjb250ZW50LCBvcHRpb25zKTtcblxuICBzd2l0Y2godGFzaykge1xuICAgIGNhc2UgJ2dlbmVyYXRlJzpcbiAgICAgIGxvZygnXFxuR2VuZXJhdGVkIENvZGU6XFxuJywgJ3N1Y2Nlc3MnLCBxdWlldCk7XG4gICAgICBsb2coY2xlYW5lZENvbnRlbnQsICdkZWZhdWx0JywgcXVpZXQpO1xuICAgICAgYnJlYWs7XG5cbiAgICBjYXNlICdleHBsYWluJzpcbiAgICAgIGxvZygnXFxuQ29kZSBFeHBsYW5hdGlvbjpcXG4nLCAnc3VjY2VzcycsIHF1aWV0KTtcbiAgICAgIGxvZyhjbGVhbmVkQ29udGVudCwgJ2RlZmF1bHQnLCBxdWlldCk7XG4gICAgICBicmVhaztcblxuICAgIGNhc2UgJ3Rlc3QnOlxuICAgICAgbG9nKCdcXG5HZW5lcmF0ZWQgVGVzdHM6XFxuJywgJ3N1Y2Nlc3MnLCBxdWlldCk7XG4gICAgICBsb2coY2xlYW5lZENvbnRlbnQsICdkZWZhdWx0JywgcXVpZXQpO1xuICAgICAgYnJlYWs7XG5cbiAgICBjYXNlICdvcHRpbWl6ZSc6XG4gICAgICBsb2coJ1xcbk9wdGltaXphdGlvbiBTdWdnZXN0aW9uczpcXG4nLCAnc3VjY2VzcycsIHF1aWV0KTtcbiAgICAgIGxvZyhjbGVhbmVkQ29udGVudCwgJ2RlZmF1bHQnLCBxdWlldCk7XG4gICAgICBicmVhaztcblxuICAgIGRlZmF1bHQ6XG4gICAgICBsb2coJ1xcbkFJIFJlc3BvbnNlOlxcbicsICdzdWNjZXNzJywgcXVpZXQpO1xuICAgICAgbG9nKGNsZWFuZWRDb250ZW50LCAnZGVmYXVsdCcsIHF1aWV0KTtcbiAgICAgIGJyZWFrO1xuICB9XG59O1xuXG5jb25zdCBjbGVhblJlc3BvbnNlID0gKGNvbnRlbnQ6IHN0cmluZywgb3B0aW9uczogQUlPcHRpb25zKTogc3RyaW5nID0+IHtcbiAgY29uc3Qge3Byb21wdCA9ICcnLCB0YXNrID0gJ2hlbHAnfSA9IG9wdGlvbnM7XG5cbiAgaWYoIWNvbnRlbnQpIHtcbiAgICByZXR1cm4gY29udGVudDtcbiAgfVxuXG4gIGxldCBjbGVhbmVkQ29udGVudCA9IGNvbnRlbnQ7XG5cbiAgY29uc3QgdGFza0luc3RydWN0aW9uczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICBnZW5lcmF0ZTogJ0dlbmVyYXRlIGNvZGUgYWNjb3JkaW5nIHRvIHRoZSBmb2xsb3dpbmcgcmVxdWVzdC4gTWFrZSBzdXJlIGl0IGZvbGxvd3MgYmVzdCBwcmFjdGljZXMgYW5kIGlzIHdlbGwgZG9jdW1lbnRlZDonLFxuICAgIGV4cGxhaW46ICdFeHBsYWluIHRoZSBmb2xsb3dpbmcgY29kZSBpbiBkZXRhaWwsIGluY2x1ZGluZyBhbnkgcGF0dGVybnMsIHBvdGVudGlhbCBpc3N1ZXMsIGFuZCBpbXByb3ZlbWVudCBzdWdnZXN0aW9uczonLFxuICAgIHRlc3Q6ICdHZW5lcmF0ZSBjb21wcmVoZW5zaXZlIHVuaXQgdGVzdHMgZm9yIHRoZSBmb2xsb3dpbmcgY29kZTonLFxuICAgIG9wdGltaXplOiAnQW5hbHl6ZSB0aGUgZm9sbG93aW5nIGNvZGUvY29uZmlndXJhdGlvbiBhbmQgc3VnZ2VzdCBvcHRpbWl6YXRpb24gaW1wcm92ZW1lbnRzOicsXG4gICAgaGVscDogJ1Byb3ZpZGUgZ3VpZGFuY2Ugb24gdGhlIGZvbGxvd2luZyBkZXZlbG9wbWVudCBxdWVzdGlvbjonLFxuICAgIGFzazogJ1Byb3ZpZGUgZ3VpZGFuY2Ugb24gdGhlIGZvbGxvd2luZyBkZXZlbG9wbWVudCBxdWVzdGlvbjonLFxuICAgIGFuYWx5emU6ICdBbmFseXplIHRoZSBmb2xsb3dpbmcgY29kZTonXG4gIH07XG5cbiAgY29uc3QgaW5zdHJ1Y3Rpb24gPSB0YXNrSW5zdHJ1Y3Rpb25zW3Rhc2tdIHx8ICcnO1xuXG4gIGlmKGluc3RydWN0aW9uICYmIGNsZWFuZWRDb250ZW50LmluY2x1ZGVzKGluc3RydWN0aW9uKSkge1xuICAgIGNsZWFuZWRDb250ZW50ID0gY2xlYW5lZENvbnRlbnQucmVwbGFjZShpbnN0cnVjdGlvbiwgJycpLnRyaW0oKTtcbiAgfVxuXG4gIGlmKHByb21wdCAmJiBjbGVhbmVkQ29udGVudC5pbmNsdWRlcyhwcm9tcHQpKSB7XG4gICAgY2xlYW5lZENvbnRlbnQgPSBjbGVhbmVkQ29udGVudC5yZXBsYWNlKHByb21wdCwgJycpLnRyaW0oKTtcbiAgfVxuXG4gIGlmKGNsZWFuZWRDb250ZW50LmluY2x1ZGVzKCc9PT1DT05URVhUPT09JykpIHtcbiAgICBjbGVhbmVkQ29udGVudCA9IGNsZWFuZWRDb250ZW50LnNwbGl0KCc9PT1DT05URVhUPT09JylbMF0udHJpbSgpO1xuICB9XG5cbiAgaWYoIWNsZWFuZWRDb250ZW50KSB7XG4gICAgcmV0dXJuIGNvbnRlbnQ7XG4gIH1cblxuICByZXR1cm4gY2xlYW5lZENvbnRlbnQ7XG59O1xuXG5jb25zdCBnZXRQcm92aWRlckF1dGggPSAocHJvdmlkZXI6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCA9PiB7XG4gIGlmKHByb2Nlc3MuY3dkKCkuaW5jbHVkZXMoJ3JlYWt0b3InKSkge1xuICAgIHJldHVybiAnY3Vyc29yLWF1dGgnO1xuICB9XG5cbiAgaWYocHJvY2Vzcy5lbnYuQUlfQVBJX0tFWSkge1xuICAgIHJldHVybiBwcm9jZXNzLmVudi5BSV9BUElfS0VZO1xuICB9XG5cbiAgaWYocHJvdmlkZXIgPT09ICdub25lJyAmJiBwcm9jZXNzLmVudi5DVVJTT1JfSURFID09PSAndHJ1ZScpIHtcbiAgICByZXR1cm4gJ2N1cnNvci1hdXRoJztcbiAgfVxuXG4gIHN3aXRjaChwcm92aWRlcikge1xuICAgIGNhc2UgJ29wZW5haSc6XG4gICAgICByZXR1cm4gcHJvY2Vzcy5lbnYuT1BFTkFJX0FQSV9LRVk7XG4gICAgY2FzZSAnYW50aHJvcGljJzpcbiAgICAgIHJldHVybiBwcm9jZXNzLmVudi5BTlRIUk9QSUNfQVBJX0tFWTtcbiAgICBjYXNlICdjdXJzb3InOlxuICAgICAgcmV0dXJuICdjdXJzb3ItYXV0aCc7XG4gICAgY2FzZSAnY29waWxvdCc6XG4gICAgICByZXR1cm4gcHJvY2Vzcy5lbnYuR0lUSFVCX1RPS0VOO1xuICAgIGNhc2UgJ25vbmUnOlxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufTtcblxuY29uc3QgZGV0ZWN0Q3Vyc29ySURFID0gKCk6IGJvb2xlYW4gPT4ge1xuICBpZihwcm9jZXNzLmVudi5DVVJTT1JfSURFID09PSAndHJ1ZScpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGNvbnN0IHBvc3NpYmxlQ3Vyc29yU2lnbmFscyA9IFtcbiAgICBwcm9jZXNzLmVudi5DVVJTT1JfRVhURU5TSU9OID09PSAndHJ1ZScsXG4gICAgcHJvY2Vzcy5lbnYuQ1VSU09SX1RFUk1JTkFMID09PSAndHJ1ZScsXG4gICAgcHJvY2Vzcy5lbnYuQ1VSU09SX0FQUCA9PT0gJ3RydWUnLFxuICAgIHByb2Nlc3MuZW52LlBBVEg/LmluY2x1ZGVzKCdjdXJzb3InKSxcbiAgICAhIXByb2Nlc3MuZW52LkNVUlNPUl9TRVNTSU9OX0lEXG4gIF07XG5cbiAgY29uc3QgaXNDdXJzb3JJREUgPSBwb3NzaWJsZUN1cnNvclNpZ25hbHMuc29tZSgoc2lnbmFsKSA9PiBzaWduYWwpO1xuXG4gIGlmKGlzQ3Vyc29ySURFKSB7XG4gICAgcHJvY2Vzcy5lbnYuQ1VSU09SX0lERSA9ICd0cnVlJztcbiAgfVxuXG4gIHJldHVybiBpc0N1cnNvcklERTtcbn07XG5cbmV4cG9ydCBjb25zdCBhaUZ1bmN0aW9uID0gYXN5bmMgKG9wdGlvbnM6IEFJT3B0aW9ucyk6IFByb21pc2U8YW55PiA9PiB7XG4gIHRyeSB7XG4gICAgY29uc3QgY29uZmlnID0gTGV4Q29uZmlnLmNvbmZpZyB8fCB7fTtcbiAgICBjb25zdCBhaUNvbmZpZyA9IGNvbmZpZy5haSB8fCB7fTtcbiAgICBjb25zdCBwcm92aWRlciA9IG9wdGlvbnMucHJvdmlkZXIgfHwgYWlDb25maWcucHJvdmlkZXIgfHwgJ25vbmUnO1xuXG4gICAgaWYocHJvdmlkZXIgPT09ICdub25lJyAmJiAhcHJvY2Vzcy5lbnYuQ1VSU09SX0VYVEVOU0lPTikge1xuICAgICAgbG9nKGAke2NoYWxrLnJlZCgnRXJyb3I6Jyl9IE5vIEFJIHByb3ZpZGVyIGNvbmZpZ3VyZWQuYCwgJ2Vycm9yJyk7XG4gICAgICByZXR1cm4ge2Vycm9yOiAnTm8gQUkgcHJvdmlkZXIgY29uZmlndXJlZCd9O1xuICAgIH1cblxuICAgIGNvbnN0IHRhc2sgPSBvcHRpb25zLnRhc2sgfHwgJ2Fzayc7XG4gICAgY29uc3QgdmFsaWRUYXNrcyA9IFsnZXhwbGFpbicsICdnZW5lcmF0ZScsICd0ZXN0JywgJ2FuYWx5emUnLCAnYXNrJ107XG5cbiAgICBpZighdmFsaWRUYXNrcy5pbmNsdWRlcyh0YXNrKSkge1xuICAgICAgbG9nKGAke2NoYWxrLnJlZCgnRXJyb3I6Jyl9IEludmFsaWQgdGFzayBcIiR7dGFza31cIi4gVmFsaWQgdGFza3MgYXJlOiAke3ZhbGlkVGFza3Muam9pbignLCAnKX1gLCAnZXJyb3InKTtcbiAgICAgIHJldHVybiB7ZXJyb3I6IGBJbnZhbGlkIHRhc2sgXCIke3Rhc2t9XCJgfTtcbiAgICB9XG5cbiAgICBjb25zdCB7cHJvbXB0fSA9IG9wdGlvbnM7XG5cbiAgICBpZighcHJvbXB0KSB7XG4gICAgICBsb2coYCR7Y2hhbGsucmVkKCdFcnJvcjonKX0gTm8gcHJvbXB0IHByb3ZpZGVkLiBVc2UgLS1wcm9tcHQgXCJZb3VyIHByb21wdCBoZXJlXCJgLCAnZXJyb3InKTtcbiAgICAgIHJldHVybiB7ZXJyb3I6ICdObyBwcm9tcHQgcHJvdmlkZWQnfTtcbiAgICB9XG5cbiAgICBsZXQgY29udGV4dCA9ICcnO1xuXG4gICAgaWYob3B0aW9ucy5maWxlKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBmcyA9IGF3YWl0IGltcG9ydCgnZnMvcHJvbWlzZXMnKTtcbiAgICAgICAgY29uc3QgZ2xvYiA9IGF3YWl0IGltcG9ydCgnZ2xvYicpO1xuICAgICAgICBjb25zdCBmaWxlcyA9IGF3YWl0IGdsb2IuZ2xvYihvcHRpb25zLmZpbGUpO1xuXG4gICAgICAgIGlmKGZpbGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIGxvZyhgJHtjaGFsay55ZWxsb3coJ1dhcm5pbmc6Jyl9IE5vIGZpbGVzIGZvdW5kIG1hdGNoaW5nIFwiJHtvcHRpb25zLmZpbGV9XCJgLCAnd2FybmluZycpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGZvcihjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICAgICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUoZmlsZSwgJ3V0ZjgnKTtcbiAgICAgICAgICAgIGNvbnRleHQgKz0gYFxcbj09PUZJTEU6ICR7ZmlsZX09PT1cXG4ke2NvbnRlbnR9XFxuYDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxvZyhgJHtjaGFsay55ZWxsb3coJ1dhcm5pbmc6Jyl9IEVycm9yIHJlYWRpbmcgZmlsZTogJHtlcnJvci5tZXNzYWdlfWAsICd3YXJuaW5nJyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYob3B0aW9ucy5kaXIpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHtleGVjYVN5bmN9ID0gYXdhaXQgaW1wb3J0KCdleGVjYScpO1xuICAgICAgICBjb25zdCByZXN1bHQgPSBleGVjYVN5bmMoJ2ZpbmQnLCBbb3B0aW9ucy5kaXIsICctdHlwZScsICdmJywgJ3wnLCAnc29ydCddKTtcbiAgICAgICAgY29udGV4dCArPSBgXFxuPT09UHJvamVjdCBzdHJ1Y3R1cmU6PT09XFxuJHtyZXN1bHQuc3Rkb3V0fVxcbmA7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2coYCR7Y2hhbGsueWVsbG93KCdXYXJuaW5nOicpfSBFcnJvciByZWFkaW5nIGRpcmVjdG9yeTogJHtlcnJvci5tZXNzYWdlfWAsICd3YXJuaW5nJyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgbGV0IGZvcm1hdHRlZFByb21wdCA9ICcnO1xuXG4gICAgc3dpdGNoKHRhc2spIHtcbiAgICAgIGNhc2UgJ2V4cGxhaW4nOlxuICAgICAgICBmb3JtYXR0ZWRQcm9tcHQgPSBgRXhwbGFpbiB0aGUgZm9sbG93aW5nIGNvZGU6XFxuJHtwcm9tcHR9YDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdnZW5lcmF0ZSc6XG4gICAgICAgIGZvcm1hdHRlZFByb21wdCA9IGBHZW5lcmF0ZSBjb2RlIGFjY29yZGluZyB0byB0aGUgZm9sbG93aW5nIHJlcXVlc3Q6XFxuJHtwcm9tcHR9YDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICd0ZXN0JzpcbiAgICAgICAgZm9ybWF0dGVkUHJvbXB0ID0gYEdlbmVyYXRlIGNvbXByZWhlbnNpdmUgdW5pdCB0ZXN0czpcXG4ke3Byb21wdH1gO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2FuYWx5emUnOlxuICAgICAgICBmb3JtYXR0ZWRQcm9tcHQgPSBgQW5hbHl6ZSB0aGUgZm9sbG93aW5nIGNvZGU6XFxuJHtwcm9tcHR9YDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdhc2snOlxuICAgICAgICBmb3JtYXR0ZWRQcm9tcHQgPSBgUHJvdmlkZSBndWlkYW5jZSBvbiB0aGUgZm9sbG93aW5nIGRldmVsb3BtZW50IHF1ZXN0aW9uOlxcbiR7cHJvbXB0fWA7XG4gICAgICAgIGJyZWFrO1xuICAgIH1cblxuICAgIGlmKGNvbnRleHQpIHtcbiAgICAgIGZvcm1hdHRlZFByb21wdCArPSBgXFxuPT09Q09OVEVYVD09PVxcbiR7Y29udGV4dH1gO1xuICAgIH1cblxuICAgIGlmKChwcm92aWRlciA9PT0gJ2N1cnNvcicgfHwgcHJvY2Vzcy5lbnYuQ1VSU09SX0VYVEVOU0lPTikgJiYgdGFzayA9PT0gJ2dlbmVyYXRlJykge1xuICAgICAgbG9nKCdVc2luZyBDdXJzb3IgSURFIGZvciBjb2RlIGdlbmVyYXRpb24uLi4nLCAnaW5mbycpO1xuICAgICAgbG9nKCdOb3RlOiBGb3IgZnVsbCBjb2RlIGdlbmVyYXRpb24gY2FwYWJpbGl0aWVzLCBwbGVhc2UgdXNlIEN1cnNvciBJREUgZGlyZWN0bHkgd2l0aCBDbWQrTCBvciBDbWQrSy4nLCAnaW5mbycpO1xuICAgICAgbG9nKCdUaGUgQ0xJIGludGVncmF0aW9uIGhhcyBsaW1pdGVkIGNhcGFiaWxpdGllcyBmb3IgY29kZSBnZW5lcmF0aW9uLicsICd3YXJuaW5nJyk7XG4gICAgfSBlbHNlIGlmKHByb3ZpZGVyID09PSAnY3Vyc29yJyB8fCBwcm9jZXNzLmVudi5DVVJTT1JfRVhURU5TSU9OKSB7XG4gICAgICBsb2coJ1VzaW5nIEN1cnNvciBJREUgZm9yIEFJIGFzc2lzdGFuY2UuLi4nLCAnaW5mbycpO1xuICAgICAgbG9nKCdOb3RlOiBUaGlzIGlzIGEgbGltaXRlZCBpbnRlZ3JhdGlvbi4gRm9yIGZ1bGwgQUkgY2FwYWJpbGl0aWVzLCB1c2UgQ3Vyc29yIElERSBkaXJlY3RseS4nLCAnaW5mbycpO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2coYFVzaW5nICR7cHJvdmlkZXJ9IGZvciBBSSBhc3Npc3RhbmNlLi4uYCwgJ2luZm8nKTtcbiAgICB9XG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNhbGxBSVNlcnZpY2UoZm9ybWF0dGVkUHJvbXB0LCBvcHRpb25zLnF1aWV0IHx8IGZhbHNlKTtcblxuICAgIGxvZyhgXFxuJHtyZXNwb25zZX1gLCAnc3VjY2VzcycpO1xuXG4gICAgcmV0dXJuIHtyZXNwb25zZX07XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgbG9nKGAke2NoYWxrLnJlZCgnRXJyb3I6Jyl9ICR7ZXJyb3IubWVzc2FnZX1gLCAnZXJyb3InKTtcbiAgICByZXR1cm4ge2Vycm9yOiBlcnJvci5tZXNzYWdlfTtcbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IGFpID0gbmV3IENvbW1hbmQoJ2FpJylcbiAgLmRlc2NyaXB0aW9uKCdVc2UgQUkgdG8gaGVscCB3aXRoIGRldmVsb3BtZW50IHRhc2tzJylcbiAgLm9wdGlvbignLS1wcm92aWRlciA8cHJvdmlkZXI+JywgJ0FJIHByb3ZpZGVyIHRvIHVzZSAob3BlbmFpLCBhbnRocm9waWMsIGN1cnNvciknKVxuICAub3B0aW9uKCctLXRhc2sgPHRhc2s+JywgJ1Rhc2sgdG8gcGVyZm9ybSAoZXhwbGFpbiwgZ2VuZXJhdGUsIHRlc3QsIGFuYWx5emUsIGFzayknKVxuICAub3B0aW9uKCctLXByb21wdCA8cHJvbXB0PicsICdQcm9tcHQgdG8gc2VuZCB0byBBSScpXG4gIC5vcHRpb24oJy0tZmlsZSA8ZmlsZT4nLCAnRmlsZSB0byBhbmFseXplJylcbiAgLm9wdGlvbignLS1kaXIgPGRpcj4nLCAnRGlyZWN0b3J5IHRvIGFuYWx5emUnKVxuICAuYWN0aW9uKGFzeW5jIChvcHRpb25zOiBBSU9wdGlvbnMpID0+IHtcbiAgICBhd2FpdCBhaUZ1bmN0aW9uKG9wdGlvbnMpO1xuICB9KTtcblxuZXhw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
189
+ export const aiFunction = async (options)=>{
190
+ try {
191
+ const config = LexConfig.config || {};
192
+ const aiConfig = config.ai || {};
193
+ const provider = options.provider || aiConfig.provider || 'none';
194
+ if (provider === 'none' && !process.env.CURSOR_EXTENSION) {
195
+ log(`${chalk.red('Error:')} No AI provider configured.`, 'error');
196
+ return {
197
+ error: 'No AI provider configured'
198
+ };
199
+ }
200
+ const task = options.task || 'ask';
201
+ const validTasks = [
202
+ 'explain',
203
+ 'generate',
204
+ 'test',
205
+ 'analyze',
206
+ 'ask'
207
+ ];
208
+ if (!validTasks.includes(task)) {
209
+ log(`${chalk.red('Error:')} Invalid task "${task}". Valid tasks are: ${validTasks.join(', ')}`, 'error');
210
+ return {
211
+ error: `Invalid task "${task}"`
212
+ };
213
+ }
214
+ const { prompt } = options;
215
+ if (!prompt) {
216
+ log(`${chalk.red('Error:')} No prompt provided. Use --prompt "Your prompt here"`, 'error');
217
+ return {
218
+ error: 'No prompt provided'
219
+ };
220
+ }
221
+ let context = '';
222
+ if (options.file) {
223
+ try {
224
+ const fs = await import('fs/promises');
225
+ const glob = await import('glob');
226
+ const files = await glob.glob(options.file);
227
+ if (files.length === 0) {
228
+ log(`${chalk.yellow('Warning:')} No files found matching "${options.file}"`, 'warning');
229
+ } else {
230
+ for (const file of files){
231
+ const content = await fs.readFile(file, 'utf8');
232
+ context += `\n===FILE: ${file}===\n${content}\n`;
233
+ }
234
+ }
235
+ } catch (error) {
236
+ log(`${chalk.yellow('Warning:')} Error reading file: ${error.message}`, 'warning');
237
+ }
238
+ }
239
+ if (options.dir) {
240
+ try {
241
+ const { execaSync } = await import('execa');
242
+ const result = execaSync('find', [
243
+ options.dir,
244
+ '-type',
245
+ 'f',
246
+ '|',
247
+ 'sort'
248
+ ]);
249
+ context += `\n===Project structure:===\n${result.stdout}\n`;
250
+ } catch (error) {
251
+ log(`${chalk.yellow('Warning:')} Error reading directory: ${error.message}`, 'warning');
252
+ }
253
+ }
254
+ let formattedPrompt = '';
255
+ switch(task){
256
+ case 'explain':
257
+ formattedPrompt = `Explain the following code:\n${prompt}`;
258
+ break;
259
+ case 'generate':
260
+ formattedPrompt = `Generate code according to the following request:\n${prompt}`;
261
+ break;
262
+ case 'test':
263
+ formattedPrompt = `Generate comprehensive unit tests:\n${prompt}`;
264
+ break;
265
+ case 'analyze':
266
+ formattedPrompt = `Analyze the following code:\n${prompt}`;
267
+ break;
268
+ case 'ask':
269
+ formattedPrompt = `Provide guidance on the following development question:\n${prompt}`;
270
+ break;
271
+ }
272
+ if (context) {
273
+ formattedPrompt += `\n===CONTEXT===\n${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(`\n${response}`, 'success');
287
+ return {
288
+ response
289
+ };
290
+ } catch (error) {
291
+ log(`${chalk.red('Error:')} ${error.message}`, 'error');
292
+ return {
293
+ error: error.message
294
+ };
295
+ }
296
+ };
297
+ export 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)=>{
298
+ await aiFunction(options);
299
+ });
300
+ export default ai;
301
+
302
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb21tYW5kcy9haS9haS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvcHlyaWdodCAoYykgMjAxOC1QcmVzZW50LCBOaXRyb2dlbiBMYWJzLCBJbmMuXG4gKiBDb3B5cmlnaHRzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIHRoZSBhY2NvbXBhbnlpbmcgTElDRU5TRSBmaWxlIGZvciB0ZXJtcy5cbiAqL1xuaW1wb3J0IGNoYWxrIGZyb20gJ2NoYWxrJztcbmltcG9ydCB7Q29tbWFuZH0gZnJvbSAnY29tbWFuZGVyJztcbmltcG9ydCB7cmVhZEZpbGVTeW5jfSBmcm9tICdmcyc7XG5pbXBvcnQge3N5bmMgYXMgZ2xvYlN5bmN9IGZyb20gJ2dsb2InO1xuXG5pbXBvcnQge0xleENvbmZpZ30gZnJvbSAnLi4vLi4vTGV4Q29uZmlnLmpzJztcbmltcG9ydCB7Y2FsbEFJU2VydmljZX0gZnJvbSAnLi4vLi4vdXRpbHMvYWlTZXJ2aWNlLmpzJztcbmltcG9ydCB7bG9nfSBmcm9tICcuLi8uLi91dGlscy9sb2cuanMnO1xuXG5pZihwcm9jZXNzLmVudi5DVVJTT1JfRVhURU5TSU9OID09PSAndHJ1ZScgfHxcbiAgcHJvY2Vzcy5lbnYuQ1VSU09SX1RFUk1JTkFMID09PSAndHJ1ZScgfHxcbiAgcHJvY2Vzcy5lbnYuQ1VSU09SX0FQUCA9PT0gJ3RydWUnIHx8XG4gIHByb2Nlc3MuZW52LlBBVEg/LmluY2x1ZGVzKCdjdXJzb3InKSB8fFxuICBwcm9jZXNzLmVudi5DVVJTT1JfU0VTU0lPTl9JRCkge1xuICBwcm9jZXNzLmVudi5DVVJTT1JfSURFID0gJ3RydWUnO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEFJT3B0aW9ucyB7XG4gIHJlYWRvbmx5IGNsaU5hbWU/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGNvbnRleHQ/OiBib29sZWFuO1xuICByZWFkb25seSBmaWxlPzogc3RyaW5nO1xuICByZWFkb25seSBsZXhDb25maWc/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IG1vZGVsPzogc3RyaW5nO1xuICByZWFkb25seSBwcm9tcHQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHF1aWV0PzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgdGFzaz86ICdnZW5lcmF0ZScgfCAnZXhwbGFpbicgfCAndGVzdCcgfCAnb3B0aW1pemUnIHwgJ2hlbHAnIHwgJ2FzaycgfCAnYW5hbHl6ZSc7XG4gIHJlYWRvbmx5IGRlYnVnPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgcHJvdmlkZXI/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGRpcj86IHN0cmluZztcbn1cblxuY29uc3QgZ2V0RmlsZUNvbnRleHQgPSAoZmlsZVBhdGg6IHN0cmluZyk6IHN0cmluZyA9PiB7XG4gIHRyeSB7XG4gICAgY29uc3QgY29udGVudCA9IHJlYWRGaWxlU3luYyhmaWxlUGF0aCwgJ3V0Zi04Jyk7XG4gICAgcmV0dXJuIGBGaWxlOiAke2ZpbGVQYXRofVxcblxcbiR7Y29udGVudH1gO1xuICB9IGNhdGNoKF9lcnJvcikge1xuICAgIHJldHVybiBgRXJyb3IgcmVhZGluZyBmaWxlOiAke2ZpbGVQYXRofWA7XG4gIH1cbn07XG5cbmNvbnN0IGdldFByb2plY3RDb250ZXh0ID0gYXN5bmMgKG9wdGlvbnM6IEFJT3B0aW9ucyk6IFByb21pc2U8c3RyaW5nPiA9PiB7XG4gIGNvbnN0IHtmaWxlLCB0YXNrLCBjb250ZXh0fSA9IG9wdGlvbnM7XG5cbiAgaWYoY29udGV4dCA9PT0gZmFsc2UpIHtcbiAgICByZXR1cm4gJyc7XG4gIH1cblxuICBsZXQgcHJvamVjdENvbnRleHQgPSAnJztcblxuICBpZihmaWxlKSB7XG4gICAgcHJvamVjdENvbnRleHQgKz0gZ2V0RmlsZUNvbnRleHQoZmlsZSk7XG4gIH1cblxuICBzd2l0Y2godGFzaykge1xuICAgIGNhc2UgJ2dlbmVyYXRlJzpcbiAgICAgIGNvbnN0IGZpbGVzID0gZ2xvYlN5bmMoJ3NyYy8qKi8qLnt0cyx0c3gsanMsanN4fScsIHtcbiAgICAgICAgY3dkOiBwcm9jZXNzLmN3ZCgpLFxuICAgICAgICBpZ25vcmU6IFsnKiovbm9kZV9tb2R1bGVzLyoqJywgJyoqL2xpYi8qKicsICcqKi9kaXN0LyoqJywgJyoqLyoudGVzdC4qJywgJyoqLyouc3BlYy4qJ10sXG4gICAgICAgIG1heERlcHRoOiAzXG4gICAgICB9KTtcbiAgICAgIHByb2plY3RDb250ZXh0ICs9IGBcXG5cXG5Qcm9qZWN0IHN0cnVjdHVyZTpcXG4ke2ZpbGVzLmpvaW4oJ1xcbicpfWA7XG4gICAgICBicmVhaztcblxuICAgIGNhc2UgJ3Rlc3QnOlxuICAgICAgaWYoZmlsZSkge1xuICAgICAgICBjb25zdCB0ZXN0Q29uZmlnID0gZ2V0RmlsZUNvbnRleHQoJ2plc3QuY29uZmlnLmpzJyk7XG4gICAgICAgIHByb2plY3RDb250ZXh0ICs9IGBcXG5cXG5UZXN0IGNvbmZpZ3VyYXRpb246XFxuJHt0ZXN0Q29uZmlnfWA7XG4gICAgICB9XG4gICAgICBicmVhaztcblxuICAgIGNhc2UgJ29wdGltaXplJzpcbiAgICAgIGNvbnN0IHdlYnBhY2tDb25maWcgPSBnZXRGaWxlQ29udGV4dCgnd2VicGFjay5jb25maWcuanMnKTtcbiAgICAgIHByb2plY3RDb250ZXh0ICs9IGBcXG5cXG5XZWJwYWNrIGNvbmZpZ3VyYXRpb246XFxuJHt3ZWJwYWNrQ29uZmlnfWA7XG4gICAgICBicmVhaztcblxuICAgIGRlZmF1bHQ6XG4gICAgICBicmVhaztcbiAgfVxuXG4gIHJldHVybiBwcm9qZWN0Q29udGV4dDtcbn07XG5cbmNvbnN0IGNvbnN0cnVjdFByb21wdCA9IChvcHRpb25zOiBBSU9wdGlvbnMsIHByb2plY3RDb250ZXh0OiBzdHJpbmcpOiBzdHJpbmcgPT4ge1xuICBjb25zdCB7dGFzayA9ICdoZWxwJywgcHJvbXB0ID0gJyd9ID0gb3B0aW9ucztcblxuICBjb25zdCB0YXNrSW5zdHJ1Y3Rpb25zOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgIGFuYWx5emU6ICdBbmFseXplIHRoZSBmb2xsb3dpbmcgY29kZTonLFxuICAgIGFzazogJ1Byb3ZpZGUgZ3VpZGFuY2Ugb24gdGhlIGZvbGxvd2luZyBkZXZlbG9wbWVudCBxdWVzdGlvbjonLFxuICAgIGV4cGxhaW46ICdFeHBsYWluIHRoZSBmb2xsb3dpbmcgY29kZSBpbiBkZXRhaWwsIGluY2x1ZGluZyBhbnkgcGF0dGVybnMsIHBvdGVudGlhbCBpc3N1ZXMsIGFuZCBpbXByb3ZlbWVudCBzdWdnZXN0aW9uczonLFxuICAgIGdlbmVyYXRlOiAnR2VuZXJhdGUgY29kZSBhY2NvcmRpbmcgdG8gdGhlIGZvbGxvd2luZyByZXF1ZXN0LiBNYWtlIHN1cmUgaXQgZm9sbG93cyBiZXN0IHByYWN0aWNlcyBhbmQgaXMgd2VsbCBkb2N1bWVudGVkOicsXG4gICAgaGVscDogJ1Byb3ZpZGUgZ3VpZGFuY2Ugb24gdGhlIGZvbGxvd2luZyBkZXZlbG9wbWVudCBxdWVzdGlvbjonLFxuICAgIG9wdGltaXplOiAnQW5hbHl6ZSB0aGUgZm9sbG93aW5nIGNvZGUvY29uZmlndXJhdGlvbiBhbmQgc3VnZ2VzdCBvcHRpbWl6YXRpb24gaW1wcm92ZW1lbnRzOicsXG4gICAgdGVzdDogJ0dlbmVyYXRlIGNvbXByZWhlbnNpdmUgdW5pdCB0ZXN0cyBmb3IgdGhlIGZvbGxvd2luZyBjb2RlOidcbiAgfTtcblxuICBjb25zdCB0YXNrSW5zdHJ1Y3Rpb24gPSB0YXNrSW5zdHJ1Y3Rpb25zW3Rhc2tdIHx8IHRhc2tJbnN0cnVjdGlvbnMuaGVscDtcblxuICBsZXQgZnVsbFByb21wdCA9IGAke3Rhc2tJbnN0cnVjdGlvbn1cXG5cXG4ke3Byb21wdH1gO1xuXG4gIGlmKHByb2plY3RDb250ZXh0KSB7XG4gICAgZnVsbFByb21wdCArPSBgXFxuXFxuPT09Q09OVEVYVD09PVxcbiR7cHJvamVjdENvbnRleHR9YDtcbiAgfVxuXG4gIHJldHVybiBmdWxsUHJvbXB0O1xufTtcblxuY29uc3QgZGlzcGxheVJlc3BvbnNlID0gKHJlc3BvbnNlOiBhbnksIG9wdGlvbnM6IEFJT3B0aW9ucyk6IHZvaWQgPT4ge1xuICBjb25zdCB7dGFzayA9ICdoZWxwJywgcXVpZXQgPSBmYWxzZX0gPSBvcHRpb25zO1xuXG4gIGxldCBjb250ZW50ID0gJyc7XG5cbiAgaWYodHlwZW9mIHJlc3BvbnNlID09PSAnc3RyaW5nJykge1xuICAgIGNvbnRlbnQgPSByZXNwb25zZTtcbiAgfSBlbHNlIGlmKHJlc3BvbnNlLmNob2ljZXM/LlswXT8ubWVzc2FnZT8uY29udGVudCkge1xuICAgIGNvbnN0IHtjb250ZW50OiBtZXNzYWdlQ29udGVudH0gPSByZXNwb25zZS5jaG9pY2VzWzBdLm1lc3NhZ2U7XG4gICAgY29udGVudCA9IG1lc3NhZ2VDb250ZW50O1xuICB9IGVsc2UgaWYocmVzcG9uc2UuY29udGVudCkge1xuICAgIGNvbnN0IHtjb250ZW50OiByZXNwb25zZUNvbnRlbnR9ID0gcmVzcG9uc2U7XG4gICAgY29udGVudCA9IHJlc3BvbnNlQ29udGVudDtcbiAgfSBlbHNlIHtcbiAgICBjb250ZW50ID0gJ05vIHJlc3BvbnNlIHJlY2VpdmVkIGZyb20gQUkgbW9kZWwnO1xuICB9XG5cbiAgY29uc3QgY2xlYW5lZENvbnRlbnQgPSBjbGVhblJlc3BvbnNlKGNvbnRlbnQsIG9wdGlvbnMpO1xuXG4gIHN3aXRjaCh0YXNrKSB7XG4gICAgY2FzZSAnZ2VuZXJhdGUnOlxuICAgICAgbG9nKCdcXG5HZW5lcmF0ZWQgQ29kZTpcXG4nLCAnc3VjY2VzcycsIHF1aWV0KTtcbiAgICAgIGxvZyhjbGVhbmVkQ29udGVudCwgJ2RlZmF1bHQnLCBxdWlldCk7XG4gICAgICBicmVhaztcblxuICAgIGNhc2UgJ2V4cGxhaW4nOlxuICAgICAgbG9nKCdcXG5Db2RlIEV4cGxhbmF0aW9uOlxcbicsICdzdWNjZXNzJywgcXVpZXQpO1xuICAgICAgbG9nKGNsZWFuZWRDb250ZW50LCAnZGVmYXVsdCcsIHF1aWV0KTtcbiAgICAgIGJyZWFrO1xuXG4gICAgY2FzZSAndGVzdCc6XG4gICAgICBsb2coJ1xcbkdlbmVyYXRlZCBUZXN0czpcXG4nLCAnc3VjY2VzcycsIHF1aWV0KTtcbiAgICAgIGxvZyhjbGVhbmVkQ29udGVudCwgJ2RlZmF1bHQnLCBxdWlldCk7XG4gICAgICBicmVhaztcblxuICAgIGNhc2UgJ29wdGltaXplJzpcbiAgICAgIGxvZygnXFxuT3B0aW1pemF0aW9uIFN1Z2dlc3Rpb25zOlxcbicsICdzdWNjZXNzJywgcXVpZXQpO1xuICAgICAgbG9nKGNsZWFuZWRDb250ZW50LCAnZGVmYXVsdCcsIHF1aWV0KTtcbiAgICAgIGJyZWFrO1xuXG4gICAgZGVmYXVsdDpcbiAgICAgIGxvZygnXFxuQUkgUmVzcG9uc2U6XFxuJywgJ3N1Y2Nlc3MnLCBxdWlldCk7XG4gICAgICBsb2coY2xlYW5lZENvbnRlbnQsICdkZWZhdWx0JywgcXVpZXQpO1xuICAgICAgYnJlYWs7XG4gIH1cbn07XG5cbmNvbnN0IGNsZWFuUmVzcG9uc2UgPSAoY29udGVudDogc3RyaW5nLCBvcHRpb25zOiBBSU9wdGlvbnMpOiBzdHJpbmcgPT4ge1xuICBjb25zdCB7cHJvbXB0ID0gJycsIHRhc2sgPSAnaGVscCd9ID0gb3B0aW9ucztcblxuICBpZighY29udGVudCkge1xuICAgIHJldHVybiBjb250ZW50O1xuICB9XG5cbiAgbGV0IGNsZWFuZWRDb250ZW50ID0gY29udGVudDtcblxuICBjb25zdCB0YXNrSW5zdHJ1Y3Rpb25zOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgIGFuYWx5emU6ICdBbmFseXplIHRoZSBmb2xsb3dpbmcgY29kZTonLFxuICAgIGFzazogJ1Byb3ZpZGUgZ3VpZGFuY2Ugb24gdGhlIGZvbGxvd2luZyBkZXZlbG9wbWVudCBxdWVzdGlvbjonLFxuICAgIGV4cGxhaW46ICdFeHBsYWluIHRoZSBmb2xsb3dpbmcgY29kZSBpbiBkZXRhaWwsIGluY2x1ZGluZyBhbnkgcGF0dGVybnMsIHBvdGVudGlhbCBpc3N1ZXMsIGFuZCBpbXByb3ZlbWVudCBzdWdnZXN0aW9uczonLFxuICAgIGdlbmVyYXRlOiAnR2VuZXJhdGUgY29kZSBhY2NvcmRpbmcgdG8gdGhlIGZvbGxvd2luZyByZXF1ZXN0LiBNYWtlIHN1cmUgaXQgZm9sbG93cyBiZXN0IHByYWN0aWNlcyBhbmQgaXMgd2VsbCBkb2N1bWVudGVkOicsXG4gICAgaGVscDogJ1Byb3ZpZGUgZ3VpZGFuY2Ugb24gdGhlIGZvbGxvd2luZyBkZXZlbG9wbWVudCBxdWVzdGlvbjonLFxuICAgIG9wdGltaXplOiAnQW5hbHl6ZSB0aGUgZm9sbG93aW5nIGNvZGUvY29uZmlndXJhdGlvbiBhbmQgc3VnZ2VzdCBvcHRpbWl6YXRpb24gaW1wcm92ZW1lbnRzOicsXG4gICAgdGVzdDogJ0dlbmVyYXRlIGNvbXByZWhlbnNpdmUgdW5pdCB0ZXN0cyBmb3IgdGhlIGZvbGxvd2luZyBjb2RlOidcbiAgfTtcblxuICBjb25zdCBpbnN0cnVjdGlvbiA9IHRhc2tJbnN0cnVjdGlvbnNbdGFza10gfHwgJyc7XG5cbiAgaWYoaW5zdHJ1Y3Rpb24gJiYgY2xlYW5lZENvbnRlbnQuaW5jbHVkZXMoaW5zdHJ1Y3Rpb24pKSB7XG4gICAgY2xlYW5lZENvbnRlbnQgPSBjbGVhbmVkQ29udGVudC5yZXBsYWNlKGluc3RydWN0aW9uLCAnJykudHJpbSgpO1xuICB9XG5cbiAgaWYocHJvbXB0ICYmIGNsZWFuZWRDb250ZW50LmluY2x1ZGVzKHByb21wdCkpIHtcbiAgICBjbGVhbmVkQ29udGVudCA9IGNsZWFuZWRDb250ZW50LnJlcGxhY2UocHJvbXB0LCAnJykudHJpbSgpO1xuICB9XG5cbiAgaWYoY2xlYW5lZENvbnRlbnQuaW5jbHVkZXMoJz09PUNPTlRFWFQ9PT0nKSkge1xuICAgIGNsZWFuZWRDb250ZW50ID0gY2xlYW5lZENvbnRlbnQuc3BsaXQoJz09PUNPTlRFWFQ9PT0nKVswXS50cmltKCk7XG4gIH1cblxuICBpZighY2xlYW5lZENvbnRlbnQpIHtcbiAgICByZXR1cm4gY29udGVudDtcbiAgfVxuXG4gIHJldHVybiBjbGVhbmVkQ29udGVudDtcbn07XG5cbmNvbnN0IGdldFByb3ZpZGVyQXV0aCA9IChwcm92aWRlcjogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkID0+IHtcbiAgaWYocHJvY2Vzcy5jd2QoKS5pbmNsdWRlcygncmVha3RvcicpKSB7XG4gICAgcmV0dXJuICdjdXJzb3ItYXV0aCc7XG4gIH1cblxuICBpZihwcm9jZXNzLmVudi5BSV9BUElfS0VZKSB7XG4gICAgcmV0dXJuIHByb2Nlc3MuZW52LkFJX0FQSV9LRVk7XG4gIH1cblxuICBpZihwcm92aWRlciA9PT0gJ25vbmUnICYmIHByb2Nlc3MuZW52LkNVUlNPUl9JREUgPT09ICd0cnVlJykge1xuICAgIHJldHVybiAnY3Vyc29yLWF1dGgnO1xuICB9XG5cbiAgc3dpdGNoKHByb3ZpZGVyKSB7XG4gICAgY2FzZSAnb3BlbmFpJzpcbiAgICAgIHJldHVybiBwcm9jZXNzLmVudi5PUEVOQUlfQVBJX0tFWTtcbiAgICBjYXNlICdhbnRocm9waWMnOlxuICAgICAgcmV0dXJuIHByb2Nlc3MuZW52LkFOVEhST1BJQ19BUElfS0VZO1xuICAgIGNhc2UgJ2N1cnNvcic6XG4gICAgICByZXR1cm4gJ2N1cnNvci1hdXRoJztcbiAgICBjYXNlICdjb3BpbG90JzpcbiAgICAgIHJldHVybiBwcm9jZXNzLmVudi5HSVRIVUJfVE9LRU47XG4gICAgY2FzZSAnbm9uZSc6XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59O1xuXG5jb25zdCBkZXRlY3RDdXJzb3JJREUgPSAoKTogYm9vbGVhbiA9PiB7XG4gIGlmKHByb2Nlc3MuZW52LkNVUlNPUl9JREUgPT09ICd0cnVlJykge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgY29uc3QgcG9zc2libGVDdXJzb3JTaWduYWxzID0gW1xuICAgIHByb2Nlc3MuZW52LkNVUlNPUl9FWFRFTlNJT04gPT09ICd0cnVlJyxcbiAgICBwcm9jZXNzLmVudi5DVVJTT1JfVEVSTUlOQUwgPT09ICd0cnVlJyxcbiAgICBwcm9jZXNzLmVudi5DVVJTT1JfQVBQID09PSAndHJ1ZScsXG4gICAgcHJvY2Vzcy5lbnYuUEFUSD8uaW5jbHVkZXMoJ2N1cnNvcicpLFxuICAgICEhcHJvY2Vzcy5lbnYuQ1VSU09SX1NFU1NJT05fSURcbiAgXTtcblxuICBjb25zdCBpc0N1cnNvcklERSA9IHBvc3NpYmxlQ3Vyc29yU2lnbmFscy5zb21lKChzaWduYWwpID0+IHNpZ25hbCk7XG5cbiAgaWYoaXNDdXJzb3JJREUpIHtcbiAgICBwcm9jZXNzLmVudi5DVVJTT1JfSURFID0gJ3RydWUnO1xuICB9XG5cbiAgcmV0dXJuIGlzQ3Vyc29ySURFO1xufTtcblxuZXhwb3J0IGNvbnN0IGFpRnVuY3Rpb24gPSBhc3luYyAob3B0aW9uczogQUlPcHRpb25zKTogUHJvbWlzZTxhbnk+ID0+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBjb25maWcgPSBMZXhDb25maWcuY29uZmlnIHx8IHt9O1xuICAgIGNvbnN0IGFpQ29uZmlnID0gY29uZmlnLmFpIHx8IHt9O1xuICAgIGNvbnN0IHByb3ZpZGVyID0gb3B0aW9ucy5wcm92aWRlciB8fCBhaUNvbmZpZy5wcm92aWRlciB8fCAnbm9uZSc7XG5cbiAgICBpZihwcm92aWRlciA9PT0gJ25vbmUnICYmICFwcm9jZXNzLmVudi5DVVJTT1JfRVhURU5TSU9OKSB7XG4gICAgICBsb2coYCR7Y2hhbGsucmVkKCdFcnJvcjonKX0gTm8gQUkgcHJvdmlkZXIgY29uZmlndXJlZC5gLCAnZXJyb3InKTtcbiAgICAgIHJldHVybiB7ZXJyb3I6ICdObyBBSSBwcm92aWRlciBjb25maWd1cmVkJ307XG4gICAgfVxuXG4gICAgY29uc3QgdGFzayA9IG9wdGlvbnMudGFzayB8fCAnYXNrJztcbiAgICBjb25zdCB2YWxpZFRhc2tzID0gWydleHBsYWluJywgJ2dlbmVyYXRlJywgJ3Rlc3QnLCAnYW5hbHl6ZScsICdhc2snXTtcblxuICAgIGlmKCF2YWxpZFRhc2tzLmluY2x1ZGVzKHRhc2spKSB7XG4gICAgICBsb2coYCR7Y2hhbGsucmVkKCdFcnJvcjonKX0gSW52YWxpZCB0YXNrIFwiJHt0YXNrfVwiLiBWYWxpZCB0YXNrcyBhcmU6ICR7dmFsaWRUYXNrcy5qb2luKCcsICcpfWAsICdlcnJvcicpO1xuICAgICAgcmV0dXJuIHtlcnJvcjogYEludmFsaWQgdGFzayBcIiR7dGFza31cImB9O1xuICAgIH1cblxuICAgIGNvbnN0IHtwcm9tcHR9ID0gb3B0aW9ucztcblxuICAgIGlmKCFwcm9tcHQpIHtcbiAgICAgIGxvZyhgJHtjaGFsay5yZWQoJ0Vycm9yOicpfSBObyBwcm9tcHQgcHJvdmlkZWQuIFVzZSAtLXByb21wdCBcIllvdXIgcHJvbXB0IGhlcmVcImAsICdlcnJvcicpO1xuICAgICAgcmV0dXJuIHtlcnJvcjogJ05vIHByb21wdCBwcm92aWRlZCd9O1xuICAgIH1cblxuICAgIGxldCBjb250ZXh0ID0gJyc7XG5cbiAgICBpZihvcHRpb25zLmZpbGUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGZzID0gYXdhaXQgaW1wb3J0KCdmcy9wcm9taXNlcycpO1xuICAgICAgICBjb25zdCBnbG9iID0gYXdhaXQgaW1wb3J0KCdnbG9iJyk7XG4gICAgICAgIGNvbnN0IGZpbGVzID0gYXdhaXQgZ2xvYi5nbG9iKG9wdGlvbnMuZmlsZSk7XG5cbiAgICAgICAgaWYoZmlsZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgbG9nKGAke2NoYWxrLnllbGxvdygnV2FybmluZzonKX0gTm8gZmlsZXMgZm91bmQgbWF0Y2hpbmcgXCIke29wdGlvbnMuZmlsZX1cImAsICd3YXJuaW5nJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZm9yKGNvbnN0IGZpbGUgb2YgZmlsZXMpIHtcbiAgICAgICAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZShmaWxlLCAndXRmOCcpO1xuICAgICAgICAgICAgY29udGV4dCArPSBgXFxuPT09RklMRTogJHtmaWxlfT09PVxcbiR7Y29udGVudH1cXG5gO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBjYXRjaChlcnJvcikge1xuICAgICAgICBsb2coYCR7Y2hhbGsueWVsbG93KCdXYXJuaW5nOicpfSBFcnJvciByZWFkaW5nIGZpbGU6ICR7ZXJyb3IubWVzc2FnZX1gLCAnd2FybmluZycpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmKG9wdGlvbnMuZGlyKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCB7ZXhlY2FTeW5jfSA9IGF3YWl0IGltcG9ydCgnZXhlY2EnKTtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gZXhlY2FTeW5jKCdmaW5kJywgW29wdGlvbnMuZGlyLCAnLXR5cGUnLCAnZicsICd8JywgJ3NvcnQnXSk7XG4gICAgICAgIGNvbnRleHQgKz0gYFxcbj09PVByb2plY3Qgc3RydWN0dXJlOj09PVxcbiR7cmVzdWx0LnN0ZG91dH1cXG5gO1xuICAgICAgfSBjYXRjaChlcnJvcikge1xuICAgICAgICBsb2coYCR7Y2hhbGsueWVsbG93KCdXYXJuaW5nOicpfSBFcnJvciByZWFkaW5nIGRpcmVjdG9yeTogJHtlcnJvci5tZXNzYWdlfWAsICd3YXJuaW5nJyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgbGV0IGZvcm1hdHRlZFByb21wdCA9ICcnO1xuXG4gICAgc3dpdGNoKHRhc2spIHtcbiAgICAgIGNhc2UgJ2V4cGxhaW4nOlxuICAgICAgICBmb3JtYXR0ZWRQcm9tcHQgPSBgRXhwbGFpbiB0aGUgZm9sbG93aW5nIGNvZGU6XFxuJHtwcm9tcHR9YDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdnZW5lcmF0ZSc6XG4gICAgICAgIGZvcm1hdHRlZFByb21wdCA9IGBHZW5lcmF0ZSBjb2RlIGFjY29yZGluZyB0byB0aGUgZm9sbG93aW5nIHJlcXVlc3Q6XFxuJHtwcm9tcHR9YDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICd0ZXN0JzpcbiAgICAgICAgZm9ybWF0dGVkUHJvbXB0ID0gYEdlbmVyYXRlIGNvbXByZWhlbnNpdmUgdW5pdCB0ZXN0czpcXG4ke3Byb21wdH1gO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2FuYWx5emUnOlxuICAgICAgICBmb3JtYXR0ZWRQcm9tcHQgPSBgQW5hbHl6ZSB0aGUgZm9sbG93aW5nIGNvZGU6XFxuJHtwcm9tcHR9YDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdhc2snOlxuICAgICAgICBmb3JtYXR0ZWRQcm9tcHQgPSBgUHJvdmlkZSBndWlkYW5jZSBvbiB0aGUgZm9sbG93aW5nIGRldmVsb3BtZW50IHF1ZXN0aW9uOlxcbiR7cHJvbXB0fWA7XG4gICAgICAgIGJyZWFrO1xuICAgIH1cblxuICAgIGlmKGNvbnRleHQpIHtcbiAgICAgIGZvcm1hdHRlZFByb21wdCArPSBgXFxuPT09Q09OVEVYVD09PVxcbiR7Y29udGV4dH1gO1xuICAgIH1cblxuICAgIGlmKChwcm92aWRlciA9PT0gJ2N1cnNvcicgfHwgcHJvY2Vzcy5lbnYuQ1VSU09SX0VYVEVOU0lPTikgJiYgdGFzayA9PT0gJ2dlbmVyYXRlJykge1xuICAgICAgbG9nKCdVc2luZyBDdXJzb3IgSURFIGZvciBjb2RlIGdlbmVyYXRpb24uLi4nLCAnaW5mbycpO1xuICAgICAgbG9nKCdOb3RlOiBGb3IgZnVsbCBjb2RlIGdlbmVyYXRpb24gY2FwYWJpbGl0aWVzLCBwbGVhc2UgdXNlIEN1cnNvciBJREUgZGlyZWN0bHkgd2l0aCBDbWQrTCBvciBDbWQrSy4nLCAnaW5mbycpO1xuICAgICAgbG9nKCdUaGUgQ0xJIGludGVncmF0aW9uIGhhcyBsaW1pdGVkIGNhcGFiaWxpdGllcyBmb3IgY29kZSBnZW5lcmF0aW9uLicsICd3YXJuaW5nJyk7XG4gICAgfSBlbHNlIGlmKHByb3ZpZGVyID09PSAnY3Vyc29yJyB8fCBwcm9jZXNzLmVudi5DVVJTT1JfRVhURU5TSU9OKSB7XG4gICAgICBsb2coJ1VzaW5nIEN1cnNvciBJREUgZm9yIEFJIGFzc2lzdGFuY2UuLi4nLCAnaW5mbycpO1xuICAgICAgbG9nKCdOb3RlOiBUaGlzIGlzIGEgbGltaXRlZCBpbnRlZ3JhdGlvbi4gRm9yIGZ1bGwgQUkgY2FwYWJpbGl0aWVzLCB1c2UgQ3Vyc29yIElERSBkaXJlY3RseS4nLCAnaW5mbycpO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2coYFVzaW5nICR7cHJvdmlkZXJ9IGZvciBBSSBhc3Npc3RhbmNlLi4uYCwgJ2luZm8nKTtcbiAgICB9XG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNhbGxBSVNlcnZpY2UoZm9ybWF0dGVkUHJvbXB0LCBvcHRpb25zLnF1aWV0IHx8IGZhbHNlKTtcblxuICAgIGxvZyhgXFxuJHtyZXNwb25zZX1gLCAnc3VjY2VzcycpO1xuXG4gICAgcmV0dXJuIHtyZXNwb25zZX07XG4gIH0gY2F0Y2goZXJyb3IpIHtcbiAgICBsb2coYCR7Y2hhbGsucmVkKCdFcnJvcjonKX0gJHtlcnJvci5tZXNzYWdlfWAsICdlcnJvcicpO1xuICAgIHJldHVybiB7ZXJyb3I6IGVycm9yLm1lc3NhZ2V9O1xuICB9XG59O1xuXG5leHBvcnQgY29uc3QgYWkgPSBuZXcgQ29tbWFuZCgnYWknKVxuICAuZGVzY3JpcHRpb24oJ1VzZSBBSSB0byBoZWxwIHdpdGggZGV2ZWxvcG1lbnQgdGFza3MnKVxuICAub3B0aW9uKCctLXByb3ZpZGVyIDxwcm92aWRlcj4nLCAnQUkgcHJvdmlkZXIgdG8gdXNlIChvcGVuYWksIGFudGhyb3BpYywgY3Vyc29yKScpXG4gIC5vcHRpb24oJy0tdGFzayA8dGFzaz4nLCAnVGFzayB0byBwZXJmb3JtIChleHBsYWluLCBnZW5lcmF0ZSwgdGVzdCwgYW5hbHl6ZSwgYXNrKScpXG4gIC5vcHRpb24oJy0tcHJvbXB0IDxwcm9tcHQ+JywgJ1Byb21wdCB0byBzZW5kIHRvIEFJJylcbiAgLm9wdGlvbignLS1maWxlIDxmaWxlPicsICdGaWxlIHRvIGFuYWx5emUnKVxuICAub3B0aW9uKCctLWRpciA8ZGlyPicsICdEaXJlY3RvcnkgdG8gYW5hbHl6ZScpXG4gIC5hY3Rpb24oYXN5bmMgKG9wdGlvbnM6IEFJT3B0aW9ucykgPT4ge1xuICAgIGF3YWl0IGFpRnVuY3Rpb24ob3B0aW9ucyk7XG4gIH0pO1xuXG5leHBvcnQgZGVmYXVsdCBhaTsiXSwibmFtZXMiOlsiY2hhbGsiLCJDb21tYW5kIiwicmVhZEZpbGVTeW5jIiwic3luYyIsImdsb2JTeW5jIiwiTGV4Q29uZmlnIiwiY2FsbEFJU2VydmljZSIsImxvZyIsInByb2Nlc3MiLCJlbnYiLCJDVVJTT1JfRVhURU5TSU9OIiwiQ1VSU09SX1RFUk1JTkFMIiwiQ1VSU09SX0FQUCIsIlBBVEgiLCJpbmNsdWRlcyIsIkNVUlNPUl9TRVNTSU9OX0lEIiwiQ1VSU09SX0lERSIsImdldEZpbGVDb250ZXh0IiwiZmlsZVBhdGgiLCJjb250ZW50IiwiX2Vycm9yIiwiZ2V0UHJvamVjdENvbnRleHQiLCJvcHRpb25zIiwiZmlsZSIsInRhc2siLCJjb250ZXh0IiwicHJvamVjdENvbnRleHQiLCJmaWxlcyIsImN3ZCIsImlnbm9yZSIsIm1heERlcHRoIiwiam9pbiIsInRlc3RDb25maWciLCJ3ZWJwYWNrQ29uZmlnIiwiY29uc3RydWN0UHJvbXB0IiwicHJvbXB0IiwidGFza0luc3RydWN0aW9ucyIsImFuYWx5emUiLCJhc2siLCJleHBsYWluIiwiZ2VuZXJhdGUiLCJoZWxwIiwib3B0aW1pemUiLCJ0ZXN0IiwidGFza0luc3RydWN0aW9uIiwiZnVsbFByb21wdCIsImRpc3BsYXlSZXNwb25zZSIsInJlc3BvbnNlIiwicXVpZXQiLCJjaG9pY2VzIiwibWVzc2FnZSIsIm1lc3NhZ2VDb250ZW50IiwicmVzcG9uc2VDb250ZW50IiwiY2xlYW5lZENvbnRlbnQiLCJjbGVhblJlc3BvbnNlIiwiaW5zdHJ1Y3Rpb24iLCJyZXBsYWNlIiwidHJpbSIsInNwbGl0IiwiZ2V0UHJvdmlkZXJBdXRoIiwicHJvdmlkZXIiLCJBSV9BUElfS0VZIiwiT1BFTkFJX0FQSV9LRVkiLCJBTlRIUk9QSUNfQVBJX0tFWSIsIkdJVEhVQl9UT0tFTiIsInVuZGVmaW5lZCIsImRldGVjdEN1cnNvcklERSIsInBvc3NpYmxlQ3Vyc29yU2lnbmFscyIsImlzQ3Vyc29ySURFIiwic29tZSIsInNpZ25hbCIsImFpRnVuY3Rpb24iLCJjb25maWciLCJhaUNvbmZpZyIsImFpIiwicmVkIiwiZXJyb3IiLCJ2YWxpZFRhc2tzIiwiZnMiLCJnbG9iIiwibGVuZ3RoIiwieWVsbG93IiwicmVhZEZpbGUiLCJkaXIiLCJleGVjYVN5bmMiLCJyZXN1bHQiLCJzdGRvdXQiLCJmb3JtYXR0ZWRQcm9tcHQiLCJkZXNjcmlwdGlvbiIsIm9wdGlvbiIsImFjdGlvbiJdLCJtYXBwaW5ncyI6IkFBQUE7OztDQUdDLEdBQ0QsT0FBT0EsV0FBVyxRQUFRO0FBQzFCLFNBQVFDLE9BQU8sUUFBTyxZQUFZO0FBQ2xDLFNBQVFDLFlBQVksUUFBTyxLQUFLO0FBQ2hDLFNBQVFDLFFBQVFDLFFBQVEsUUFBTyxPQUFPO0FBRXRDLFNBQVFDLFNBQVMsUUFBTyxxQkFBcUI7QUFDN0MsU0FBUUMsYUFBYSxRQUFPLDJCQUEyQjtBQUN2RCxTQUFRQyxHQUFHLFFBQU8scUJBQXFCO0FBRXZDLElBQUdDLFFBQVFDLEdBQUcsQ0FBQ0MsZ0JBQWdCLEtBQUssVUFDbENGLFFBQVFDLEdBQUcsQ0FBQ0UsZUFBZSxLQUFLLFVBQ2hDSCxRQUFRQyxHQUFHLENBQUNHLFVBQVUsS0FBSyxVQUMzQkosUUFBUUMsR0FBRyxDQUFDSSxJQUFJLEVBQUVDLFNBQVMsYUFDM0JOLFFBQVFDLEdBQUcsQ0FBQ00saUJBQWlCLEVBQUU7SUFDL0JQLFFBQVFDLEdBQUcsQ0FBQ08sVUFBVSxHQUFHO0FBQzNCO0FBZ0JBLE1BQU1DLGlCQUFpQixDQUFDQztJQUN0QixJQUFJO1FBQ0YsTUFBTUMsVUFBVWpCLGFBQWFnQixVQUFVO1FBQ3ZDLE9BQU8sQ0FBQyxNQUFNLEVBQUVBLFNBQVMsSUFBSSxFQUFFQyxTQUFTO0lBQzFDLEVBQUUsT0FBTUMsUUFBUTtRQUNkLE9BQU8sQ0FBQyxvQkFBb0IsRUFBRUYsVUFBVTtJQUMxQztBQUNGO0FBRUEs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