@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,25 +1,33 @@
1
- import { existsSync, readFileSync, writeFileSync } from "fs";
2
- import { resolve as pathResolve } from "path";
3
- import readline from "readline";
4
- import { LexConfig } from "../LexConfig.js";
5
- import { createSpinner } from "./app.js";
6
- import { log } from "./log.js";
7
- const callCursorAI = async (prompt, _options) => {
8
- try {
9
- log("Using Cursor IDE for AI fixes...", "info");
10
- log("AI fix requested via Cursor IDE", "info");
11
- const taskMatch = prompt.match(/^(Generate code according to the following request|Explain the following code|Generate comprehensive unit tests|Analyze the following code|Provide guidance on the following development question):/);
12
- const task = taskMatch ? taskMatch[1] : "";
13
- const isGenerateTask = task.startsWith("Generate code");
14
- const questionMatch = prompt.match(/(?:Generate code according to the following request|Explain the following code|Generate comprehensive unit tests|Analyze the following code|Provide guidance on the following development question):\s*([\s\S]+?)(?:===CONTEXT===|$)/);
15
- const question = questionMatch ? questionMatch[1].trim() : prompt;
16
- if (question.toLowerCase().includes("how many files") && prompt.includes("Project structure:")) {
17
- const projectStructure = prompt.split("Project structure:")[1] || "";
18
- const files = projectStructure.trim().split("\n");
19
- return `Based on the project structure provided, there are ${files.length} files in the project.`;
20
- }
21
- if (isGenerateTask) {
22
- return `
1
+ /**
2
+ * Copyright (c) 2022-Present, Nitrogen Labs, Inc.
3
+ * Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
4
+ */ import { existsSync, readFileSync, writeFileSync } from 'fs';
5
+ import { resolve as pathResolve } from 'path';
6
+ import readline from 'readline';
7
+ import { LexConfig } from '../LexConfig.js';
8
+ import { createSpinner } from './app.js';
9
+ import { log } from './log.js';
10
+ // Cursor IDE integration
11
+ export const callCursorAI = async (prompt, _options)=>{
12
+ try {
13
+ // When running within Cursor IDE, we can write the prompt to a temporary file
14
+ // that Cursor can use to provide AI assistance
15
+ log('Using Cursor IDE for AI fixes...', 'info');
16
+ // For now, just log the prompt and return a placeholder
17
+ // In a real implementation, Cursor would handle this automatically
18
+ log('AI fix requested via Cursor IDE', 'info');
19
+ const taskMatch = prompt.match(/^(Generate code according to the following request|Explain the following code|Generate comprehensive unit tests|Analyze the following code|Provide guidance on the following development question):/);
20
+ const task = taskMatch ? taskMatch[1] : '';
21
+ const isGenerateTask = task.startsWith('Generate code');
22
+ const questionMatch = prompt.match(/(?:Generate code according to the following request|Explain the following code|Generate comprehensive unit tests|Analyze the following code|Provide guidance on the following development question):\s*([\s\S]+?)(?:===CONTEXT===|$)/);
23
+ const question = questionMatch ? questionMatch[1].trim() : prompt;
24
+ if (question.toLowerCase().includes('how many files') && prompt.includes('Project structure:')) {
25
+ const projectStructure = prompt.split('Project structure:')[1] || '';
26
+ const files = projectStructure.trim().split('\n');
27
+ return `Based on the project structure provided, there are ${files.length} files in the project.`;
28
+ }
29
+ if (isGenerateTask) {
30
+ return `
23
31
  # Code Generation Request: "${question}"
24
32
 
25
33
  To generate code using Cursor's AI capabilities:
@@ -49,8 +57,8 @@ The current CLI integration doesn't have direct access to Cursor's code generati
49
57
  Install: \`npm install -g @cursor/cli\`
50
58
  Run: \`cursor ai "${question}"\`
51
59
  `;
52
- }
53
- return `
60
+ }
61
+ return `
54
62
  To use Cursor's AI capabilities for "${question}", you need to:
55
63
 
56
64
  1. Open your project in Cursor IDE (https://cursor.sh)
@@ -79,221 +87,226 @@ Then set your API key as an environment variable:
79
87
  export OPENAI_API_KEY=your_key_here
80
88
  \`\`\`
81
89
  `;
82
- } catch (error) {
83
- throw new Error(`Cursor AI error: ${error.message}`);
84
- }
85
- };
86
- const callOpenAIAI = async (prompt, options) => {
87
- try {
88
- const apiKey = options.apiKey || process.env.OPENAI_API_KEY;
89
- if (!apiKey) {
90
- throw new Error("OpenAI API key is required. Set it in your lex.config file or as OPENAI_API_KEY environment variable.");
91
- }
92
- const response = await fetch("https://api.openai.com/v1/chat/completions", {
93
- body: JSON.stringify({
94
- max_tokens: options.maxTokens || 4e3,
95
- messages: [
96
- { content: "You are a helpful assistant that fixes ESLint errors in code.", role: "system" },
97
- { content: prompt, role: "user" }
98
- ],
99
- model: options.model || "gpt-4o",
100
- temperature: options.temperature || 0.1
101
- }),
102
- headers: {
103
- Authorization: `Bearer ${apiKey}`,
104
- "Content-Type": "application/json"
105
- },
106
- method: "POST"
107
- });
108
- if (!response.ok) {
109
- const error = await response.json();
110
- throw new Error(`OpenAI API error: ${error.error?.message || response.statusText}`);
90
+ } catch (error) {
91
+ throw new Error(`Cursor AI error: ${error.message}`);
111
92
  }
112
- const data = await response.json();
113
- return data.choices[0].message.content;
114
- } catch (error) {
115
- throw new Error(`OpenAI AI error: ${error.message}`);
116
- }
117
93
  };
118
- const callAnthropicAI = async (prompt, options) => {
119
- try {
120
- const apiKey = options.apiKey || process.env.ANTHROPIC_API_KEY;
121
- if (!apiKey) {
122
- throw new Error("Anthropic API key is required. Set it in your lex.config file or as ANTHROPIC_API_KEY environment variable.");
94
+ export const callOpenAIAI = async (prompt, options)=>{
95
+ try {
96
+ const apiKey = options.apiKey || process.env.OPENAI_API_KEY;
97
+ if (!apiKey) {
98
+ throw new Error('OpenAI API key is required. Set it in your lex.config file or as OPENAI_API_KEY environment variable.');
99
+ }
100
+ const response = await fetch('https://api.openai.com/v1/chat/completions', {
101
+ body: JSON.stringify({
102
+ max_tokens: options.maxTokens || 4000,
103
+ messages: [
104
+ {
105
+ content: 'You are a helpful assistant that fixes ESLint errors in code.',
106
+ role: 'system'
107
+ },
108
+ {
109
+ content: prompt,
110
+ role: 'user'
111
+ }
112
+ ],
113
+ model: options.model || 'gpt-4o',
114
+ temperature: options.temperature || 0.1
115
+ }),
116
+ headers: {
117
+ Authorization: `Bearer ${apiKey}`,
118
+ 'Content-Type': 'application/json'
119
+ },
120
+ method: 'POST'
121
+ });
122
+ if (!response.ok) {
123
+ const error = await response.json();
124
+ throw new Error(`OpenAI API error: ${error.error?.message || response.statusText}`);
125
+ }
126
+ const data = await response.json();
127
+ return data.choices[0].message.content;
128
+ } catch (error) {
129
+ throw new Error(`OpenAI AI error: ${error.message}`);
123
130
  }
124
- const response = await fetch("https://api.anthropic.com/v1/messages", {
125
- body: JSON.stringify({
126
- max_tokens: options.maxTokens || 4e3,
127
- messages: [
128
- { content: prompt, role: "user" }
129
- ],
130
- model: options.model || "claude-3-sonnet-20240229",
131
- temperature: options.temperature || 0.1
132
- }),
133
- headers: {
134
- "Content-Type": "application/json",
135
- "anthropic-version": "2023-06-01",
136
- "x-api-key": apiKey
137
- },
138
- method: "POST"
139
- });
140
- if (!response.ok) {
141
- const error = await response.json();
142
- throw new Error(`Anthropic API error: ${error.error?.message || response.statusText}`);
131
+ };
132
+ export const callAnthropicAI = async (prompt, options)=>{
133
+ try {
134
+ const apiKey = options.apiKey || process.env.ANTHROPIC_API_KEY;
135
+ if (!apiKey) {
136
+ throw new Error('Anthropic API key is required. Set it in your lex.config file or as ANTHROPIC_API_KEY environment variable.');
137
+ }
138
+ const response = await fetch('https://api.anthropic.com/v1/messages', {
139
+ body: JSON.stringify({
140
+ max_tokens: options.maxTokens || 4000,
141
+ messages: [
142
+ {
143
+ content: prompt,
144
+ role: 'user'
145
+ }
146
+ ],
147
+ model: options.model || 'claude-3-sonnet-20240229',
148
+ temperature: options.temperature || 0.1
149
+ }),
150
+ headers: {
151
+ 'Content-Type': 'application/json',
152
+ 'anthropic-version': '2023-06-01',
153
+ 'x-api-key': apiKey
154
+ },
155
+ method: 'POST'
156
+ });
157
+ if (!response.ok) {
158
+ const error = await response.json();
159
+ throw new Error(`Anthropic API error: ${error.error?.message || response.statusText}`);
160
+ }
161
+ const data = await response.json();
162
+ return data.content[0].text;
163
+ } catch (error) {
164
+ throw new Error(`Anthropic AI error: ${error.message}`);
143
165
  }
144
- const data = await response.json();
145
- return data.content[0].text;
146
- } catch (error) {
147
- throw new Error(`Anthropic AI error: ${error.message}`);
148
- }
149
166
  };
150
- const callCopilotAI = async (prompt, _options) => {
151
- try {
152
- log("GitHub Copilot AI fixes not directly supported. Using manual fix mode.", "info");
153
- return prompt;
154
- } catch (error) {
155
- throw new Error(`GitHub Copilot AI error: ${error.message}`);
156
- }
167
+ export const callCopilotAI = async (prompt, _options)=>{
168
+ try {
169
+ log('GitHub Copilot AI fixes not directly supported. Using manual fix mode.', 'info');
170
+ return prompt;
171
+ } catch (error) {
172
+ throw new Error(`GitHub Copilot AI error: ${error.message}`);
173
+ }
157
174
  };
158
- const promptForAIProvider = async (_quiet = false) => {
159
- const rl = readline.createInterface({
160
- input: process.stdin,
161
- output: process.stdout
162
- });
163
- return new Promise((resolve) => {
164
- log("\nNo AI provider configured. Please choose an AI provider:", "info");
165
- log("1. Cursor IDE", "info");
166
- log("2. OpenAI", "info");
167
- log("3. Anthropic", "info");
168
- log("4. GitHub Copilot", "info");
169
- log("5. None (Skip AI features)", "info");
170
- rl.question("Enter your choice (1-5): ", (answer) => {
171
- rl.close();
172
- switch (answer) {
173
- case "1":
174
- resolve("cursor");
175
- break;
176
- case "2":
177
- resolve("openai");
178
- break;
179
- case "3":
180
- resolve("anthropic");
181
- break;
182
- case "4":
183
- resolve("copilot");
184
- break;
185
- default:
186
- resolve("none");
187
- }
175
+ export const promptForAIProvider = async (_quiet = false)=>{
176
+ const rl = readline.createInterface({
177
+ input: process.stdin,
178
+ output: process.stdout
188
179
  });
189
- });
190
- };
191
- const promptForAPIKey = async (provider, _quiet = false) => {
192
- const rl = readline.createInterface({
193
- input: process.stdin,
194
- output: process.stdout
195
- });
196
- return new Promise((resolve) => {
197
- rl.question(`Please enter your ${provider} API key: `, (answer) => {
198
- rl.close();
199
- resolve(answer);
180
+ return new Promise((resolve)=>{
181
+ log('\nNo AI provider configured. Please choose an AI provider:', 'info');
182
+ log('1. Cursor IDE', 'info');
183
+ log('2. OpenAI', 'info');
184
+ log('3. Anthropic', 'info');
185
+ log('4. GitHub Copilot', 'info');
186
+ log('5. None (Skip AI features)', 'info');
187
+ rl.question('Enter your choice (1-5): ', (answer)=>{
188
+ rl.close();
189
+ switch(answer){
190
+ case '1':
191
+ resolve('cursor');
192
+ break;
193
+ case '2':
194
+ resolve('openai');
195
+ break;
196
+ case '3':
197
+ resolve('anthropic');
198
+ break;
199
+ case '4':
200
+ resolve('copilot');
201
+ break;
202
+ default:
203
+ resolve('none');
204
+ }
205
+ });
200
206
  });
201
- });
202
207
  };
203
- const getAIService = (provider, _options) => {
204
- switch (provider) {
205
- case "cursor":
206
- return callCursorAI;
207
- case "openai":
208
- return callOpenAIAI;
209
- case "anthropic":
210
- return callAnthropicAI;
211
- case "copilot":
212
- return callCopilotAI;
213
- default:
214
- return async () => "No AI provider configured";
215
- }
208
+ export const promptForAPIKey = async (provider, _quiet = false)=>{
209
+ const rl = readline.createInterface({
210
+ input: process.stdin,
211
+ output: process.stdout
212
+ });
213
+ return new Promise((resolve)=>{
214
+ rl.question(`Please enter your ${provider} API key: `, (answer)=>{
215
+ rl.close();
216
+ resolve(answer);
217
+ });
218
+ });
216
219
  };
217
- const callAIService = async (prompt, quiet = false) => {
218
- const spinner = createSpinner(quiet);
219
- spinner.start("Calling AI service to fix code issues...");
220
- try {
221
- const aiConfig = LexConfig.config.ai || { provider: "none" };
222
- const isInCursorIDE = process.env.CURSOR_IDE === "true";
223
- if (isInCursorIDE && (aiConfig.provider === "none" || !aiConfig.provider)) {
224
- log("Detected Cursor IDE environment, using Cursor as AI provider", "info", quiet);
225
- aiConfig.provider = "cursor";
220
+ export const getAIService = (provider, _options)=>{
221
+ switch(provider){
222
+ case 'cursor':
223
+ return callCursorAI;
224
+ case 'openai':
225
+ return callOpenAIAI;
226
+ case 'anthropic':
227
+ return callAnthropicAI;
228
+ case 'copilot':
229
+ return callCopilotAI;
230
+ default:
231
+ return async ()=>'No AI provider configured';
226
232
  }
227
- if (aiConfig.provider === "none") {
228
- const provider = await promptForAIProvider(quiet);
229
- if (provider === "none") {
230
- spinner.fail("AI features skipped");
231
- return "";
232
- }
233
- aiConfig.provider = provider;
234
- if (provider !== "cursor" && provider !== "copilot" && !process.env[`${provider.toUpperCase()}_API_KEY`]) {
235
- aiConfig.apiKey = await promptForAPIKey(provider, quiet);
236
- }
237
- LexConfig.config.ai = aiConfig;
238
- const configFormats = ["js", "mjs", "cjs", "ts", "json"];
239
- const configBaseName = "lex.config";
240
- let configPath = "";
241
- for (const format of configFormats) {
242
- const potentialPath = pathResolve(process.cwd(), `./${configBaseName}.${format}`);
243
- if (existsSync(potentialPath)) {
244
- configPath = potentialPath;
245
- break;
233
+ };
234
+ export const callAIService = async (prompt, quiet = false)=>{
235
+ const spinner = createSpinner(quiet);
236
+ spinner.start('Calling AI service to fix code issues...');
237
+ try {
238
+ const aiConfig = LexConfig.config.ai || {
239
+ provider: 'none'
240
+ };
241
+ const isInCursorIDE = process.env.CURSOR_IDE === 'true';
242
+ if (isInCursorIDE && (aiConfig.provider === 'none' || !aiConfig.provider)) {
243
+ log('Detected Cursor IDE environment, using Cursor as AI provider', 'info', quiet);
244
+ aiConfig.provider = 'cursor';
246
245
  }
247
- }
248
- if (configPath) {
249
- try {
250
- const configContent = readFileSync(configPath, "utf8");
251
- const updatedConfig = configContent.replace(
252
- /ai:.*?[,}]/s,
253
- `ai: { provider: '${aiConfig.provider}' },`
254
- );
255
- writeFileSync(configPath, updatedConfig);
256
- } catch (_error) {
246
+ if (aiConfig.provider === 'none') {
247
+ const provider = await promptForAIProvider(quiet);
248
+ if (provider === 'none') {
249
+ spinner.fail('AI features skipped');
250
+ return '';
251
+ }
252
+ aiConfig.provider = provider;
253
+ if (provider !== 'cursor' && provider !== 'copilot' && !process.env[`${provider.toUpperCase()}_API_KEY`]) {
254
+ aiConfig.apiKey = await promptForAPIKey(provider, quiet);
255
+ }
256
+ LexConfig.config.ai = aiConfig;
257
+ // Search for config files in multiple formats like LexConfig.parseConfig does
258
+ const configFormats = [
259
+ 'js',
260
+ 'mjs',
261
+ 'cjs',
262
+ 'ts',
263
+ 'json'
264
+ ];
265
+ const configBaseName = 'lex.config';
266
+ let configPath = '';
267
+ for (const format of configFormats){
268
+ const potentialPath = pathResolve(process.cwd(), `./${configBaseName}.${format}`);
269
+ if (existsSync(potentialPath)) {
270
+ configPath = potentialPath;
271
+ break;
272
+ }
273
+ }
274
+ if (configPath) {
275
+ try {
276
+ const configContent = readFileSync(configPath, 'utf8');
277
+ const updatedConfig = configContent.replace(/ai:.*?[,}]/s, `ai: { provider: '${aiConfig.provider}' },`);
278
+ writeFileSync(configPath, updatedConfig);
279
+ } catch (_error) {}
280
+ }
257
281
  }
258
- }
259
- }
260
- let result = "";
261
- switch (aiConfig.provider) {
262
- case "cursor":
263
- result = await callCursorAI(prompt, aiConfig);
264
- log("Cursor IDE AI integration active", "info", quiet);
265
- break;
266
- case "openai":
267
- result = await callOpenAIAI(prompt, aiConfig);
268
- break;
269
- case "anthropic":
270
- result = await callAnthropicAI(prompt, aiConfig);
271
- break;
272
- case "copilot":
273
- result = await callCopilotAI(prompt, aiConfig);
274
- break;
275
- default:
276
- spinner.fail("No AI provider configured");
277
- return "";
278
- }
279
- spinner.succeed("AI code fixes generated successfully");
280
- return result;
281
- } catch (error) {
282
- spinner.fail(`AI service error: ${error.message}`);
283
- if (!quiet) {
284
- log(error, "error");
282
+ let result = '';
283
+ switch(aiConfig.provider){
284
+ case 'cursor':
285
+ result = await callCursorAI(prompt, aiConfig);
286
+ log('Cursor IDE AI integration active', 'info', quiet);
287
+ break;
288
+ case 'openai':
289
+ result = await callOpenAIAI(prompt, aiConfig);
290
+ break;
291
+ case 'anthropic':
292
+ result = await callAnthropicAI(prompt, aiConfig);
293
+ break;
294
+ case 'copilot':
295
+ result = await callCopilotAI(prompt, aiConfig);
296
+ break;
297
+ default:
298
+ spinner.fail('No AI provider configured');
299
+ return '';
300
+ }
301
+ spinner.succeed('AI code fixes generated successfully');
302
+ return result;
303
+ } catch (error) {
304
+ spinner.fail(`AI service error: ${error.message}`);
305
+ if (!quiet) {
306
+ log(error, 'error');
307
+ }
308
+ return '';
285
309
  }
286
- return "";
287
- }
288
310
  };
289
- export {
290
- callAIService,
291
- callAnthropicAI,
292
- callCopilotAI,
293
- callCursorAI,
294
- callOpenAIAI,
295
- getAIService,
296
- promptForAIProvider,
297
- promptForAPIKey
298
- };
299
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL3V0aWxzL2FpU2VydmljZS50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMjItUHJlc2VudCwgTml0cm9nZW4gTGFicywgSW5jLlxuICogQ29weXJpZ2h0cyBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSB0aGUgYWNjb21wYW55aW5nIExJQ0VOU0UgZmlsZSBmb3IgdGVybXMuXG4gKi9cbmltcG9ydCB7ZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jfSBmcm9tICdmcyc7XG5pbXBvcnQge3Jlc29sdmUgYXMgcGF0aFJlc29sdmV9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IHJlYWRsaW5lIGZyb20gJ3JlYWRsaW5lJztcblxuaW1wb3J0IHtBSUNvbmZpZywgTGV4Q29uZmlnfSBmcm9tICcuLi9MZXhDb25maWcuanMnO1xuaW1wb3J0IHtjcmVhdGVTcGlubmVyfSBmcm9tICcuL2FwcC5qcyc7XG5pbXBvcnQge2xvZ30gZnJvbSAnLi9sb2cuanMnO1xuXG4vLyBDdXJzb3IgSURFIGludGVncmF0aW9uXG5leHBvcnQgY29uc3QgY2FsbEN1cnNvckFJID0gYXN5bmMgKHByb21wdDogc3RyaW5nLCBfb3B0aW9uczogQUlDb25maWcpOiBQcm9taXNlPHN0cmluZz4gPT4ge1xuICB0cnkge1xuICAgIC8vIFdoZW4gcnVubmluZyB3aXRoaW4gQ3Vyc29yIElERSwgd2UgY2FuIHdyaXRlIHRoZSBwcm9tcHQgdG8gYSB0ZW1wb3JhcnkgZmlsZVxuICAgIC8vIHRoYXQgQ3Vyc29yIGNhbiB1c2UgdG8gcHJvdmlkZSBBSSBhc3Npc3RhbmNlXG4gICAgbG9nKCdVc2luZyBDdXJzb3IgSURFIGZvciBBSSBmaXhlcy4uLicsICdpbmZvJyk7XG5cbiAgICAvLyBGb3Igbm93LCBqdXN0IGxvZyB0aGUgcHJvbXB0IGFuZCByZXR1cm4gYSBwbGFjZWhvbGRlclxuICAgIC8vIEluIGEgcmVhbCBpbXBsZW1lbnRhdGlvbiwgQ3Vyc29yIHdvdWxkIGhhbmRsZSB0aGlzIGF1dG9tYXRpY2FsbHlcbiAgICBsb2coJ0FJIGZpeCByZXF1ZXN0ZWQgdmlhIEN1cnNvciBJREUnLCAnaW5mbycpO1xuXG4gICAgY29uc3QgdGFza01hdGNoID0gcHJvbXB0Lm1hdGNoKC9eKEdlbmVyYXRlIGNvZGUgYWNjb3JkaW5nIHRvIHRoZSBmb2xsb3dpbmcgcmVxdWVzdHxFeHBsYWluIHRoZSBmb2xsb3dpbmcgY29kZXxHZW5lcmF0ZSBjb21wcmVoZW5zaXZlIHVuaXQgdGVzdHN8QW5hbHl6ZSB0aGUgZm9sbG93aW5nIGNvZGV8UHJvdmlkZSBndWlkYW5jZSBvbiB0aGUgZm9sbG93aW5nIGRldmVsb3BtZW50IHF1ZXN0aW9uKTovKTtcbiAgICBjb25zdCB0YXNrID0gdGFza01hdGNoID8gdGFza01hdGNoWzFdIDogJyc7XG4gICAgY29uc3QgaXNHZW5lcmF0ZVRhc2sgPSB0YXNrLnN0YXJ0c1dpdGgoJ0dlbmVyYXRlIGNvZGUnKTtcblxuICAgIGNvbnN0IHF1ZXN0aW9uTWF0Y2ggPSBwcm9tcHQubWF0Y2goLyg/OkdlbmVyYXRlIGNvZGUgYWNjb3JkaW5nIHRvIHRoZSBmb2xsb3dpbmcgcmVxdWVzdHxFeHBsYWluIHRoZSBmb2xsb3dpbmcgY29kZXxHZW5lcmF0ZSBjb21wcmVoZW5zaXZlIHVuaXQgdGVzdHN8QW5hbHl6ZSB0aGUgZm9sbG93aW5nIGNvZGV8UHJvdmlkZSBndWlkYW5jZSBvbiB0aGUgZm9sbG93aW5nIGRldmVsb3BtZW50IHF1ZXN0aW9uKTpcXHMqKFtcXHNcXFNdKz8pKD86PT09Q09OVEVYVD09PXwkKS8pO1xuICAgIGNvbnN0IHF1ZXN0aW9uID0gcXVlc3Rpb25NYXRjaCA/IHF1ZXN0aW9uTWF0Y2hbMV0udHJpbSgpIDogcHJvbXB0O1xuXG4gICAgaWYocXVlc3Rpb24udG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnaG93IG1hbnkgZmlsZXMnKSAmJiBwcm9tcHQuaW5jbHVkZXMoJ1Byb2plY3Qgc3RydWN0dXJlOicpKSB7XG4gICAgICBjb25zdCBwcm9qZWN0U3RydWN0dXJlID0gcHJvbXB0LnNwbGl0KCdQcm9qZWN0IHN0cnVjdHVyZTonKVsxXSB8fCAnJztcbiAgICAgIGNvbnN0IGZpbGVzID0gcHJvamVjdFN0cnVjdHVyZS50cmltKCkuc3BsaXQoJ1xcbicpO1xuICAgICAgcmV0dXJuIGBCYXNlZCBvbiB0aGUgcHJvamVjdCBzdHJ1Y3R1cmUgcHJvdmlkZWQsIHRoZXJlIGFyZSAke2ZpbGVzLmxlbmd0aH0gZmlsZXMgaW4gdGhlIHByb2plY3QuYDtcbiAgICB9XG5cbiAgICBpZihpc0dlbmVyYXRlVGFzaykge1xuICAgICAgcmV0dXJuIGBcbiMgQ29kZSBHZW5lcmF0aW9uIFJlcXVlc3Q6IFwiJHtxdWVzdGlvbn1cIlxuXG5UbyBnZW5lcmF0ZSBjb2RlIHVzaW5nIEN1cnNvcidzIEFJIGNhcGFiaWxpdGllczpcblxuMS4gKipPcGVuIHlvdXIgcHJvamVjdCBpbiBDdXJzb3IgSURFKiogKGh0dHBzOi8vY3Vyc29yLnNoKVxuMi4gUHJlc3MgKipDbWQrTCoqIChvciBDdHJsK0wgb24gV2luZG93cy9MaW51eCkgdG8gb3BlbiB0aGUgQUkgY2hhdFxuMy4gVHlwZSB5b3VyIHJlcXVlc3Q6IFwiJHtxdWVzdGlvbn1cIlxuNC4gQ3Vyc29yIHdpbGwgZ2VuZXJhdGUgdGhlIGNvZGUgZGlyZWN0bHkgaW4geW91ciBlZGl0b3JcblxuVGhlIGN1cnJlbnQgQ0xJIGludGVncmF0aW9uIGRvZXNuJ3QgaGF2ZSBkaXJlY3QgYWNjZXNzIHRvIEN1cnNvcidzIGNvZGUgZ2VuZXJhdGlvbiBjYXBhYmlsaXRpZXMuXG5cbioqQWx0ZXJuYXRpdmUgb3B0aW9uczoqKlxuXG4xLiAqKlVzZSBPcGVuQUkgb3IgQW50aHJvcGljIGRpcmVjdGx5OioqXG4gICBDb25maWd1cmUgaW4geW91ciBsZXguY29uZmlnIGZpbGU6XG4gICBcXGBcXGBcXGBqc1xuICAgZXhwb3J0IGRlZmF1bHQge1xuICAgICBhaToge1xuICAgICAgIHByb3ZpZGVyOiAnb3BlbmFpJyxcbiAgICAgICBhcGlLZXk6IHByb2Nlc3MuZW52Lk9QRU5BSV9BUElfS0VZLFxuICAgICAgIG1vZGVsOiAnZ3B0LTRvJ1xuICAgICB9XG4gICB9XG4gICBcXGBcXGBcXGBcblxuMi4gKipVc2UgQ3Vyc29yJ3MgY29tbWFuZCBsaW5lIHRvb2w6KipcbiAgIEluc3RhbGw6IFxcYG5wbSBpbnN0YWxsIC1nIEBjdXJzb3IvY2xpXFxgXG4gICBSdW46IFxcYGN1cnNvciBhaSBcIiR7cXVlc3Rpb259XCJcXGBcbmA7XG4gICAgfVxuXG4gICAgcmV0dXJuIGBcblRvIHVzZSBDdXJzb3IncyBBSSBjYXBhYmlsaXRpZXMgZm9yIFwiJHtxdWVzdGlvbn1cIiwgeW91IG5lZWQgdG86XG5cbjEuIE9wZW4geW91ciBwcm9qZWN0IGluIEN1cnNvciBJREUgKGh0dHBzOi8vY3Vyc29yLnNoKVxuMi4gVXNlIEN1cnNvcidzIGJ1aWx0LWluIEFJIGZlYXR1cmVzIGJ5IHByZXNzaW5nIENtZCtLIG9yIENtZCtMXG4zLiBPciBydW4gdGhlICdjdXJzb3InIGNvbW1hbmQgZGlyZWN0bHkgZnJvbSB5b3VyIHRlcm1pbmFsXG5cblRoZSBjdXJyZW50IGludGVncmF0aW9uIGlzIGxpbWl0ZWQgYW5kIGRvZXNuJ3QgZGlyZWN0bHkgYWNjZXNzIEN1cnNvcidzIEFJIGNhcGFiaWxpdGllcy5cblxuRm9yIHRoZSBiZXN0IGV4cGVyaWVuY2Ugd2l0aCBBSSBjb2RlIGdlbmVyYXRpb246XG4tIFVzZSBDdXJzb3IgSURFIGRpcmVjdGx5XG4tIE9yIGNvbmZpZ3VyZSBPcGVuQUkgb3IgQW50aHJvcGljIGFzIHlvdXIgcHJvdmlkZXIgaW4geW91ciBsZXguY29uZmlnIGZpbGU6XG5cblxcYFxcYFxcYGpzXG4vLyBsZXguY29uZmlnLmpzIChvciBsZXguY29uZmlnLm1qcywgbGV4LmNvbmZpZy5janMsIGV0Yy4pXG5leHBvcnQgZGVmYXVsdCB7XG4gIGFpOiB7XG4gICAgcHJvdmlkZXI6ICdvcGVuYWknLCAvLyBvciAnYW50aHJvcGljJ1xuICAgIGFwaUtleTogcHJvY2Vzcy5lbnYuT1BFTkFJX0FQSV9LRVksIC8vIG9yIEFOVEhST1BJQ19BUElfS0VZXG4gICAgbW9kZWw6ICdncHQtNG8nIC8vIG9yICdjbGF1ZGUtMy1vcHVzJ1xuICB9XG59XG5cXGBcXGBcXGBcblxuVGhlbiBzZXQgeW91ciBBUEkga2V5IGFzIGFuIGVudmlyb25tZW50IHZhcmlhYmxlOlxuXFxgXFxgXFxgXG5leHBvcnQgT1BFTkFJX0FQSV9LRVk9eW91cl9rZXlfaGVyZVxuXFxgXFxgXFxgXG5gO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldyBFcnJvcihgQ3Vyc29yIEFJIGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XG4gIH1cbn07XG5cbmV4cG9ydCBjb25zdCBjYWxsT3BlbkFJQUkgPSBhc3luYyAocHJvbXB0OiBzdHJpbmcsIG9wdGlvbnM6IEFJQ29uZmlnKTogUHJvbWlzZTxzdHJpbmc+ID0+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBhcGlLZXkgPSBvcHRpb25zLmFwaUtleSB8fCBwcm9jZXNzLmVudi5PUEVOQUlfQVBJX0tFWTtcbiAgICBpZighYXBpS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ09wZW5BSSBBUEkga2V5IGlzIHJlcXVpcmVkLiBTZXQgaXQgaW4geW91ciBsZXguY29uZmlnIGZpbGUgb3IgYXMgT1BFTkFJX0FQSV9LRVkgZW52aXJvbm1lbnQgdmFyaWFibGUuJyk7XG4gICAgfVxuXG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCgnaHR0cHM6Ly9hcGkub3BlbmFpLmNvbS92MS9jaGF0L2NvbXBsZXRpb25zJywge1xuICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBtYXhfdG9rZW5zOiBvcHRpb25zLm1heFRva2VucyB8fCA0MDAwLFxuICAgICAgICBtZXNzYWdlczogW1xuICAgICAgICAgIHtjb250ZW50OiAnWW91IGFyZSBhIGhlbHBmdWwgYXNzaXN0YW50IHRoYXQgZml4ZXMgRVNMaW50IGVycm9ycyBpbiBjb2RlLicsIHJvbGU6ICdzeXN0ZW0nfSxcbiAgICAgICAgICB7Y29udGVudDogcHJvbXB0LCByb2xlOiAndXNlcid9XG4gICAgICAgIF0sXG4gICAgICAgIG1vZGVsOiBvcHRpb25zLm1vZGVsIHx8ICdncHQtNG8nLFxuICAgICAgICB0ZW1wZXJhdHVyZTogb3B0aW9ucy50ZW1wZXJhdHVyZSB8fCAwLjFcbiAgICAgIH0pLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICBBdXRob3JpemF0aW9uOiBgQmVhcmVyICR7YXBpS2V5fWAsXG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbidcbiAgICAgIH0sXG4gICAgICBtZXRob2Q6ICdQT1NUJ1xuICAgIH0pO1xuXG4gICAgaWYoIXJlc3BvbnNlLm9rKSB7XG4gICAgICBjb25zdCBlcnJvciA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgT3BlbkFJIEFQSSBlcnJvcjogJHtlcnJvci5lcnJvcj8ubWVzc2FnZSB8fCByZXNwb25zZS5zdGF0dXNUZXh0fWApO1xuICAgIH1cblxuICAgIGNvbnN0IGRhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7XG4gICAgcmV0dXJuIGRhdGEuY2hvaWNlc1swXS5tZXNzYWdlLmNvbnRlbnQ7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBPcGVuQUkgQUkgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IGNhbGxBbnRocm9waWNBSSA9IGFzeW5jIChwcm9tcHQ6IHN0cmluZywgb3B0aW9uczogQUlDb25maWcpOiBQcm9taXNlPHN0cmluZz4gPT4ge1xuICB0cnkge1xuICAgIGNvbnN0IGFwaUtleSA9IG9wdGlvbnMuYXBpS2V5IHx8IHByb2Nlc3MuZW52LkFOVEhST1BJQ19BUElfS0VZO1xuICAgIGlmKCFhcGlLZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQW50aHJvcGljIEFQSSBrZXkgaXMgcmVxdWlyZWQuIFNldCBpdCBpbiB5b3VyIGxleC5jb25maWcgZmlsZSBvciBhcyBBTlRIUk9QSUNfQVBJX0tFWSBlbnZpcm9ubWVudCB2YXJpYWJsZS4nKTtcbiAgICB9XG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKCdodHRwczovL2FwaS5hbnRocm9waWMuY29tL3YxL21lc3NhZ2VzJywge1xuICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBtYXhfdG9rZW5zOiBvcHRpb25zLm1heFRva2VucyB8fCA0MDAwLFxuICAgICAgICBtZXNzYWdlczogW1xuICAgICAgICAgIHtjb250ZW50OiBwcm9tcHQsIHJvbGU6ICd1c2VyJ31cbiAgICAgICAgXSxcbiAgICAgICAgbW9kZWw6IG9wdGlvbnMubW9kZWwgfHwgJ2NsYXVkZS0zLXNvbm5ldC0yMDI0MDIyOScsXG4gICAgICAgIHRlbXBlcmF0dXJlOiBvcHRpb25zLnRlbXBlcmF0dXJlIHx8IDAuMVxuICAgICAgfSksXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgICdhbnRocm9waWMtdmVyc2lvbic6ICcyMDIzLTA2LTAxJyxcbiAgICAgICAgJ3gtYXBpLWtleSc6IGFwaUtleVxuICAgICAgfSxcbiAgICAgIG1ldGhvZDogJ1BPU1QnXG4gICAgfSk7XG5cbiAgICBpZighcmVzcG9uc2Uub2spIHtcbiAgICAgIGNvbnN0IGVycm9yID0gYXdhaXQgcmVzcG9uc2UuanNvbigpO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBBbnRocm9waWMgQVBJIGVycm9yOiAke2Vycm9yLmVycm9yPy5tZXNzYWdlIHx8IHJlc3BvbnNlLnN0YXR1c1RleHR9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgZGF0YSA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKTtcbiAgICByZXR1cm4gZGF0YS5jb250ZW50WzBdLnRleHQ7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBBbnRocm9waWMgQUkgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IGNhbGxDb3BpbG90QUkgPSBhc3luYyAocHJvbXB0OiBzdHJpbmcsIF9vcHRpb25zOiBBSUNvbmZpZyk6IFByb21pc2U8c3RyaW5nPiA9PiB7XG4gIHRyeSB7XG4gICAgbG9nKCdHaXRIdWIgQ29waWxvdCBBSSBmaXhlcyBub3QgZGlyZWN0bHkgc3VwcG9ydGVkLiBVc2luZyBtYW51YWwgZml4IG1vZGUuJywgJ2luZm8nKTtcbiAgICByZXR1cm4gcHJvbXB0O1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldyBFcnJvcihgR2l0SHViIENvcGlsb3QgQUkgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IHByb21wdEZvckFJUHJvdmlkZXIgPSBhc3luYyAoX3F1aWV0ID0gZmFsc2UpOiBQcm9taXNlPCdjdXJzb3InIHwgJ2NvcGlsb3QnIHwgJ29wZW5haScgfCAnYW50aHJvcGljJyB8ICdub25lJz4gPT4ge1xuICBjb25zdCBybCA9IHJlYWRsaW5lLmNyZWF0ZUludGVyZmFjZSh7XG4gICAgaW5wdXQ6IHByb2Nlc3Muc3RkaW4sXG4gICAgb3V0cHV0OiBwcm9jZXNzLnN0ZG91dFxuICB9KTtcblxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICBsb2coJ1xcbk5vIEFJIHByb3ZpZGVyIGNvbmZpZ3VyZWQuIFBsZWFzZSBjaG9vc2UgYW4gQUkgcHJvdmlkZXI6JywgJ2luZm8nKTtcbiAgICBsb2coJzEuIEN1cnNvciBJREUnLCAnaW5mbycpO1xuICAgIGxvZygnMi4gT3BlbkFJJywgJ2luZm8nKTtcbiAgICBsb2coJzMuIEFudGhyb3BpYycsICdpbmZvJyk7XG4gICAgbG9nKCc0LiBHaXRIdWIgQ29waWxvdCcsICdpbmZvJyk7XG4gICAgbG9nKCc1LiBOb25lIChTa2lwIEFJIGZlYXR1cmVzKScsICdpbmZvJyk7XG5cbiAgICBybC5xdWVzdGlvbignRW50ZXIgeW91ciBjaG9pY2UgKDEtNSk6ICcsIChhbnN3ZXIpID0+IHtcbiAgICAgIHJsLmNsb3NlKCk7XG5cbiAgICAgIHN3aXRjaChhbnN3ZXIpIHtcbiAgICAgICAgY2FzZSAnMSc6XG4gICAgICAgICAgcmVzb2x2ZSgnY3Vyc29yJyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJzInOlxuICAgICAgICAgIHJlc29sdmUoJ29wZW5haScpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICczJzpcbiAgICAgICAgICByZXNvbHZlKCdhbnRocm9waWMnKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnNCc6XG4gICAgICAgICAgcmVzb2x2ZSgnY29waWxvdCcpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHJlc29sdmUoJ25vbmUnKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfSk7XG59O1xuXG5leHBvcnQgY29uc3QgcHJvbXB0Rm9yQVBJS2V5ID0gYXN5bmMgKHByb3ZpZGVyOiBzdHJpbmcsIF9xdWlldCA9IGZhbHNlKTogUHJvbWlzZTxzdHJpbmc+ID0+IHtcbiAgY29uc3QgcmwgPSByZWFkbGluZS5jcmVhdGVJbnRlcmZhY2Uoe1xuICAgIGlucHV0OiBwcm9jZXNzLnN0ZGluLFxuICAgIG91dHB1dDogcHJvY2Vzcy5zdGRvdXRcbiAgfSk7XG5cbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgcmwucXVlc3Rpb24oYFBsZWFzZSBlbnRlciB5b3VyICR7cHJvdmlkZXJ9IEFQSSBrZXk6IGAsIChhbnN3ZXIpID0+IHtcbiAgICAgIHJsLmNsb3NlKCk7XG4gICAgICByZXNvbHZlKGFuc3dlcik7XG4gICAgfSk7XG4gIH0pO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldEFJU2VydmljZSA9IChcbiAgcHJvdmlkZXI6IHN0cmluZyxcbiAgX29wdGlvbnM6IEFJQ29uZmlnXG4pOiAocHJvbXB0OiBzdHJpbmcsIG9wdGlvbnM6IEFJQ29uZmlnKSA9PiBQcm9taXNlPHN0cmluZz4gPT4ge1xuICBzd2l0Y2gocHJvdmlkZXIpIHtcbiAgICBjYXNlICdjdXJzb3InOlxuICAgICAgcmV0dXJuIGNhbGxDdXJzb3JBSTtcbiAgICBjYXNlICdvcGVuYWknOlxuICAgICAgcmV0dXJuIGNhbGxPcGVuQUlBSTtcbiAgICBjYXNlICdhbnRocm9waWMnOlxuICAgICAgcmV0dXJuIGNhbGxBbnRocm9waWNBSTtcbiAgICBjYXNlICdjb3BpbG90JzpcbiAgICAgIHJldHVybiBjYWxsQ29waWxvdEFJO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gYXN5bmMgKCkgPT4gJ05vIEFJIHByb3ZpZGVyIGNvbmZpZ3VyZWQnO1xuICB9XG59O1xuXG5leHBvcnQgY29uc3QgY2FsbEFJU2VydmljZSA9IGFzeW5jIChwcm9tcHQ6IHN0cmluZywgcXVpZXQgPSBmYWxzZSk6IFByb21pc2U8c3RyaW5nPiA9PiB7XG4gIGNvbnN0IHNwaW5uZXIgPSBjcmVhdGVTcGlubmVyKHF1aWV0KTtcbiAgc3Bpbm5lci5zdGFydCgnQ2FsbGluZyBBSSBzZXJ2aWNlIHRvIGZpeCBjb2RlIGlzc3Vlcy4uLicpO1xuXG4gIHRyeSB7XG4gICAgY29uc3QgYWlDb25maWcgPSBMZXhDb25maWcuY29uZmlnLmFpIHx8IHtwcm92aWRlcjogJ25vbmUnfTtcblxuICAgIGNvbnN0IGlzSW5DdXJzb3JJREUgPSBwcm9jZXNzLmVudi5DVVJTT1JfSURFID09PSAndHJ1ZSc7XG4gICAgaWYoaXNJbkN1cnNvcklERSAmJiAoYWlDb25maWcucHJvdmlkZXIgPT09ICdub25lJyB8fCAhYWlDb25maWcucHJvdmlkZXIpKSB7XG4gICAgICBsb2coJ0RldGVjdGVkIEN1cnNvciBJREUgZW52aXJvbm1lbnQsIHVzaW5nIEN1cnNvciBhcyBBSSBwcm92aWRlcicsICdpbmZvJywgcXVpZXQpO1xuICAgICAgYWlDb25maWcucHJvdmlkZXIgPSAnY3Vyc29yJztcbiAgICB9XG5cbiAgICBpZihhaUNvbmZpZy5wcm92aWRlciA9PT0gJ25vbmUnKSB7XG4gICAgICBjb25zdCBwcm92aWRlciA9IGF3YWl0IHByb21wdEZvckFJUHJvdmlkZXIocXVpZXQpO1xuXG4gICAgICBpZihwcm92aWRlciA9PT0gJ25vbmUnKSB7XG4gICAgICAgIHNwaW5uZXIuZmFpbCgnQUkgZmVhdHVyZXMgc2tpcHBlZCcpO1xuICAgICAgICByZXR1cm4gJyc7XG4gICAgICB9XG5cbiAgICAgIGFpQ29uZmlnLnByb3ZpZGVyID0gcHJvdmlkZXI7XG5cbiAgICAgIGlmKHByb3ZpZGVyICE9PSAnY3Vyc29yJyAmJiBwcm92aWRlciAhPT0gJ2NvcGlsb3QnICYmXG4gICAgICAgICFwcm9jZXNzLmVudltgJHtwcm92aWRlci50b1VwcGVyQ2FzZSgpfV9BUElfS0VZYF0pIHtcbiAgICAgICAgYWlDb25maWcuYXBpS2V5ID0gYXdhaXQgcHJvbXB0Rm9yQVBJS2V5KHByb3ZpZGVyLCBxdWlldCk7XG4gICAgICB9XG5cbiAgICAgIExleENvbmZpZy5jb25maWcuYWkgPSBhaUNvbmZpZztcblxuICAgICAgLy8gU2VhcmNoIGZvciBjb25maWcgZmlsZXMgaW4gbXVsdGlwbGUgZm9ybWF0cyBsaWtlIExleENvbmZpZy5wYXJzZUNvbmZpZyBkb2VzXG4gICAgICBjb25zdCBjb25maWdGb3JtYXRzID0gWydqcycsICdtanMnLCAnY2pzJywgJ3RzJywgJ2pzb24nXTtcbiAgICAgIGNvbnN0IGNvbmZpZ0Jhc2VOYW1lID0gJ2xleC5jb25maWcnO1xuICAgICAgbGV0IGNvbmZpZ1BhdGggPSAnJztcblxuICAgICAgZm9yKGNvbnN0IGZvcm1hdCBvZiBjb25maWdGb3JtYXRzKSB7XG4gICAgICAgIGNvbnN0IHBvdGVudGlhbFBhdGggPSBwYXRoUmVzb2x2ZShwcm9jZXNzLmN3ZCgpLCBgLi8ke2NvbmZpZ0Jhc2VOYW1lfS4ke2Zvcm1hdH1gKTtcbiAgICAgICAgaWYoZXhpc3RzU3luYyhwb3RlbnRpYWxQYXRoKSkge1xuICAgICAgICAgIGNvbmZpZ1BhdGggPSBwb3RlbnRpYWxQYXRoO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmKGNvbmZpZ1BhdGgpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCBjb25maWdDb250ZW50ID0gcmVhZEZpbGVTeW5jKGNvbmZpZ1BhdGgsICd1dGY4Jyk7XG4gICAgICAgICAgY29uc3QgdXBkYXRlZENvbmZpZyA9IGNvbmZpZ0NvbnRlbnQucmVwbGFjZShcbiAgICAgICAgICAgIC9haTouKj9bLH1dL3MsXG4gICAgICAgICAgICBgYWk6IHsgcHJvdmlkZXI6ICcke2FpQ29uZmlnLnByb3ZpZGVyfScgfSxgXG4gICAgICAgICAgKTtcbiAgICAgICAgICB3cml0ZUZpbGVTeW5jKGNvbmZpZ1BhdGgsIHVwZGF0ZWRDb25maWcpO1xuICAgICAgICB9IGNhdGNoIChfZXJyb3IpIHtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGxldCByZXN1bHQgPSAnJztcblxuICAgIHN3aXRjaChhaUNvbmZpZy5wcm92aWRlcikge1xuICAgICAgY2FzZSAnY3Vyc29yJzpcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgY2FsbEN1cnNvckFJKHByb21wdCwgYWlDb25maWcpO1xuICAgICAgICBsb2coJ0N1cnNvciBJREUgQUkgaW50ZWdyYXRpb24gYWN0aXZlJywgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnb3BlbmFpJzpcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgY2FsbE9wZW5BSUFJKHByb21wdCwgYWlDb25maWcpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2FudGhyb3BpYyc6XG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IGNhbGxBbnRocm9waWNBSShwcm9tcHQsIGFpQ29uZmlnKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdjb3BpbG90JzpcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgY2FsbENvcGlsb3RBSShwcm9tcHQsIGFpQ29uZmlnKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICBzcGlubmVyLmZhaWwoJ05vIEFJIHByb3ZpZGVyIGNvbmZpZ3VyZWQnKTtcbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIHNwaW5uZXIuc3VjY2VlZCgnQUkgY29kZSBmaXhlcyBnZW5lcmF0ZWQgc3VjY2Vzc2Z1bGx5Jyk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBzcGlubmVyLmZhaWwoYEFJIHNlcnZpY2UgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgICBpZighcXVpZXQpIHtcbiAgICAgIGxvZyhlcnJvciwgJ2Vycm9yJyk7XG4gICAgfVxuICAgIHJldHVybiAnJztcbiAgfVxufTsiXSwKICAibWFwcGluZ3MiOiAiQUFJQSxTQUFRLFlBQVksY0FBYyxxQkFBb0I7QUFDdEQsU0FBUSxXQUFXLG1CQUFrQjtBQUNyQyxPQUFPLGNBQWM7QUFFckIsU0FBa0IsaUJBQWdCO0FBQ2xDLFNBQVEscUJBQW9CO0FBQzVCLFNBQVEsV0FBVTtBQUdYLE1BQU0sZUFBZSxPQUFPLFFBQWdCLGFBQXdDO0FBQ3pGLE1BQUk7QUFHRixRQUFJLG9DQUFvQyxNQUFNO0FBSTlDLFFBQUksbUNBQW1DLE1BQU07QUFFN0MsVUFBTSxZQUFZLE9BQU8sTUFBTSxxTUFBcU07QUFDcE8sVUFBTSxPQUFPLFlBQVksVUFBVSxDQUFDLElBQUk7QUFDeEMsVUFBTSxpQkFBaUIsS0FBSyxXQUFXLGVBQWU7QUFFdEQsVUFBTSxnQkFBZ0IsT0FBTyxNQUFNLHNPQUFzTztBQUN6USxVQUFNLFdBQVcsZ0JBQWdCLGNBQWMsQ0FBQyxFQUFFLEtBQUssSUFB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
311
+
312
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9haVNlcnZpY2UudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMjItUHJlc2VudCwgTml0cm9nZW4gTGFicywgSW5jLlxuICogQ29weXJpZ2h0cyBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSB0aGUgYWNjb21wYW55aW5nIExJQ0VOU0UgZmlsZSBmb3IgdGVybXMuXG4gKi9cbmltcG9ydCB7ZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jfSBmcm9tICdmcyc7XG5pbXBvcnQge3Jlc29sdmUgYXMgcGF0aFJlc29sdmV9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IHJlYWRsaW5lIGZyb20gJ3JlYWRsaW5lJztcblxuaW1wb3J0IHtBSUNvbmZpZywgTGV4Q29uZmlnfSBmcm9tICcuLi9MZXhDb25maWcuanMnO1xuaW1wb3J0IHtjcmVhdGVTcGlubmVyfSBmcm9tICcuL2FwcC5qcyc7XG5pbXBvcnQge2xvZ30gZnJvbSAnLi9sb2cuanMnO1xuXG4vLyBDdXJzb3IgSURFIGludGVncmF0aW9uXG5leHBvcnQgY29uc3QgY2FsbEN1cnNvckFJID0gYXN5bmMgKHByb21wdDogc3RyaW5nLCBfb3B0aW9uczogQUlDb25maWcpOiBQcm9taXNlPHN0cmluZz4gPT4ge1xuICB0cnkge1xuICAgIC8vIFdoZW4gcnVubmluZyB3aXRoaW4gQ3Vyc29yIElERSwgd2UgY2FuIHdyaXRlIHRoZSBwcm9tcHQgdG8gYSB0ZW1wb3JhcnkgZmlsZVxuICAgIC8vIHRoYXQgQ3Vyc29yIGNhbiB1c2UgdG8gcHJvdmlkZSBBSSBhc3Npc3RhbmNlXG4gICAgbG9nKCdVc2luZyBDdXJzb3IgSURFIGZvciBBSSBmaXhlcy4uLicsICdpbmZvJyk7XG5cbiAgICAvLyBGb3Igbm93LCBqdXN0IGxvZyB0aGUgcHJvbXB0IGFuZCByZXR1cm4gYSBwbGFjZWhvbGRlclxuICAgIC8vIEluIGEgcmVhbCBpbXBsZW1lbnRhdGlvbiwgQ3Vyc29yIHdvdWxkIGhhbmRsZSB0aGlzIGF1dG9tYXRpY2FsbHlcbiAgICBsb2coJ0FJIGZpeCByZXF1ZXN0ZWQgdmlhIEN1cnNvciBJREUnLCAnaW5mbycpO1xuXG4gICAgY29uc3QgdGFza01hdGNoID0gcHJvbXB0Lm1hdGNoKC9eKEdlbmVyYXRlIGNvZGUgYWNjb3JkaW5nIHRvIHRoZSBmb2xsb3dpbmcgcmVxdWVzdHxFeHBsYWluIHRoZSBmb2xsb3dpbmcgY29kZXxHZW5lcmF0ZSBjb21wcmVoZW5zaXZlIHVuaXQgdGVzdHN8QW5hbHl6ZSB0aGUgZm9sbG93aW5nIGNvZGV8UHJvdmlkZSBndWlkYW5jZSBvbiB0aGUgZm9sbG93aW5nIGRldmVsb3BtZW50IHF1ZXN0aW9uKTovKTtcbiAgICBjb25zdCB0YXNrID0gdGFza01hdGNoID8gdGFza01hdGNoWzFdIDogJyc7XG4gICAgY29uc3QgaXNHZW5lcmF0ZVRhc2sgPSB0YXNrLnN0YXJ0c1dpdGgoJ0dlbmVyYXRlIGNvZGUnKTtcblxuICAgIGNvbnN0IHF1ZXN0aW9uTWF0Y2ggPSBwcm9tcHQubWF0Y2goLyg/OkdlbmVyYXRlIGNvZGUgYWNjb3JkaW5nIHRvIHRoZSBmb2xsb3dpbmcgcmVxdWVzdHxFeHBsYWluIHRoZSBmb2xsb3dpbmcgY29kZXxHZW5lcmF0ZSBjb21wcmVoZW5zaXZlIHVuaXQgdGVzdHN8QW5hbHl6ZSB0aGUgZm9sbG93aW5nIGNvZGV8UHJvdmlkZSBndWlkYW5jZSBvbiB0aGUgZm9sbG93aW5nIGRldmVsb3BtZW50IHF1ZXN0aW9uKTpcXHMqKFtcXHNcXFNdKz8pKD86PT09Q09OVEVYVD09PXwkKS8pO1xuICAgIGNvbnN0IHF1ZXN0aW9uID0gcXVlc3Rpb25NYXRjaCA/IHF1ZXN0aW9uTWF0Y2hbMV0udHJpbSgpIDogcHJvbXB0O1xuXG4gICAgaWYocXVlc3Rpb24udG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnaG93IG1hbnkgZmlsZXMnKSAmJiBwcm9tcHQuaW5jbHVkZXMoJ1Byb2plY3Qgc3RydWN0dXJlOicpKSB7XG4gICAgICBjb25zdCBwcm9qZWN0U3RydWN0dXJlID0gcHJvbXB0LnNwbGl0KCdQcm9qZWN0IHN0cnVjdHVyZTonKVsxXSB8fCAnJztcbiAgICAgIGNvbnN0IGZpbGVzID0gcHJvamVjdFN0cnVjdHVyZS50cmltKCkuc3BsaXQoJ1xcbicpO1xuICAgICAgcmV0dXJuIGBCYXNlZCBvbiB0aGUgcHJvamVjdCBzdHJ1Y3R1cmUgcHJvdmlkZWQsIHRoZXJlIGFyZSAke2ZpbGVzLmxlbmd0aH0gZmlsZXMgaW4gdGhlIHByb2plY3QuYDtcbiAgICB9XG5cbiAgICBpZihpc0dlbmVyYXRlVGFzaykge1xuICAgICAgcmV0dXJuIGBcbiMgQ29kZSBHZW5lcmF0aW9uIFJlcXVlc3Q6IFwiJHtxdWVzdGlvbn1cIlxuXG5UbyBnZW5lcmF0ZSBjb2RlIHVzaW5nIEN1cnNvcidzIEFJIGNhcGFiaWxpdGllczpcblxuMS4gKipPcGVuIHlvdXIgcHJvamVjdCBpbiBDdXJzb3IgSURFKiogKGh0dHBzOi8vY3Vyc29yLnNoKVxuMi4gUHJlc3MgKipDbWQrTCoqIChvciBDdHJsK0wgb24gV2luZG93cy9MaW51eCkgdG8gb3BlbiB0aGUgQUkgY2hhdFxuMy4gVHlwZSB5b3VyIHJlcXVlc3Q6IFwiJHtxdWVzdGlvbn1cIlxuNC4gQ3Vyc29yIHdpbGwgZ2VuZXJhdGUgdGhlIGNvZGUgZGlyZWN0bHkgaW4geW91ciBlZGl0b3JcblxuVGhlIGN1cnJlbnQgQ0xJIGludGVncmF0aW9uIGRvZXNuJ3QgaGF2ZSBkaXJlY3QgYWNjZXNzIHRvIEN1cnNvcidzIGNvZGUgZ2VuZXJhdGlvbiBjYXBhYmlsaXRpZXMuXG5cbioqQWx0ZXJuYXRpdmUgb3B0aW9uczoqKlxuXG4xLiAqKlVzZSBPcGVuQUkgb3IgQW50aHJvcGljIGRpcmVjdGx5OioqXG4gICBDb25maWd1cmUgaW4geW91ciBsZXguY29uZmlnIGZpbGU6XG4gICBcXGBcXGBcXGBqc1xuICAgZXhwb3J0IGRlZmF1bHQge1xuICAgICBhaToge1xuICAgICAgIHByb3ZpZGVyOiAnb3BlbmFpJyxcbiAgICAgICBhcGlLZXk6IHByb2Nlc3MuZW52Lk9QRU5BSV9BUElfS0VZLFxuICAgICAgIG1vZGVsOiAnZ3B0LTRvJ1xuICAgICB9XG4gICB9XG4gICBcXGBcXGBcXGBcblxuMi4gKipVc2UgQ3Vyc29yJ3MgY29tbWFuZCBsaW5lIHRvb2w6KipcbiAgIEluc3RhbGw6IFxcYG5wbSBpbnN0YWxsIC1nIEBjdXJzb3IvY2xpXFxgXG4gICBSdW46IFxcYGN1cnNvciBhaSBcIiR7cXVlc3Rpb259XCJcXGBcbmA7XG4gICAgfVxuXG4gICAgcmV0dXJuIGBcblRvIHVzZSBDdXJzb3IncyBBSSBjYXBhYmlsaXRpZXMgZm9yIFwiJHtxdWVzdGlvbn1cIiwgeW91IG5lZWQgdG86XG5cbjEuIE9wZW4geW91ciBwcm9qZWN0IGluIEN1cnNvciBJREUgKGh0dHBzOi8vY3Vyc29yLnNoKVxuMi4gVXNlIEN1cnNvcidzIGJ1aWx0LWluIEFJIGZlYXR1cmVzIGJ5IHByZXNzaW5nIENtZCtLIG9yIENtZCtMXG4zLiBPciBydW4gdGhlICdjdXJzb3InIGNvbW1hbmQgZGlyZWN0bHkgZnJvbSB5b3VyIHRlcm1pbmFsXG5cblRoZSBjdXJyZW50IGludGVncmF0aW9uIGlzIGxpbWl0ZWQgYW5kIGRvZXNuJ3QgZGlyZWN0bHkgYWNjZXNzIEN1cnNvcidzIEFJIGNhcGFiaWxpdGllcy5cblxuRm9yIHRoZSBiZXN0IGV4cGVyaWVuY2Ugd2l0aCBBSSBjb2RlIGdlbmVyYXRpb246XG4tIFVzZSBDdXJzb3IgSURFIGRpcmVjdGx5XG4tIE9yIGNvbmZpZ3VyZSBPcGVuQUkgb3IgQW50aHJvcGljIGFzIHlvdXIgcHJvdmlkZXIgaW4geW91ciBsZXguY29uZmlnIGZpbGU6XG5cblxcYFxcYFxcYGpzXG4vLyBsZXguY29uZmlnLmpzIChvciBsZXguY29uZmlnLm1qcywgbGV4LmNvbmZpZy5janMsIGV0Yy4pXG5leHBvcnQgZGVmYXVsdCB7XG4gIGFpOiB7XG4gICAgcHJvdmlkZXI6ICdvcGVuYWknLCAvLyBvciAnYW50aHJvcGljJ1xuICAgIGFwaUtleTogcHJvY2Vzcy5lbnYuT1BFTkFJX0FQSV9LRVksIC8vIG9yIEFOVEhST1BJQ19BUElfS0VZXG4gICAgbW9kZWw6ICdncHQtNG8nIC8vIG9yICdjbGF1ZGUtMy1vcHVzJ1xuICB9XG59XG5cXGBcXGBcXGBcblxuVGhlbiBzZXQgeW91ciBBUEkga2V5IGFzIGFuIGVudmlyb25tZW50IHZhcmlhYmxlOlxuXFxgXFxgXFxgXG5leHBvcnQgT1BFTkFJX0FQSV9LRVk9eW91cl9rZXlfaGVyZVxuXFxgXFxgXFxgXG5gO1xuICB9IGNhdGNoKGVycm9yKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBDdXJzb3IgQUkgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IGNhbGxPcGVuQUlBSSA9IGFzeW5jIChwcm9tcHQ6IHN0cmluZywgb3B0aW9uczogQUlDb25maWcpOiBQcm9taXNlPHN0cmluZz4gPT4ge1xuICB0cnkge1xuICAgIGNvbnN0IGFwaUtleSA9IG9wdGlvbnMuYXBpS2V5IHx8IHByb2Nlc3MuZW52Lk9QRU5BSV9BUElfS0VZO1xuICAgIGlmKCFhcGlLZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignT3BlbkFJIEFQSSBrZXkgaXMgcmVxdWlyZWQuIFNldCBpdCBpbiB5b3VyIGxleC5jb25maWcgZmlsZSBvciBhcyBPUEVOQUlfQVBJX0tFWSBlbnZpcm9ubWVudCB2YXJpYWJsZS4nKTtcbiAgICB9XG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKCdodHRwczovL2FwaS5vcGVuYWkuY29tL3YxL2NoYXQvY29tcGxldGlvbnMnLCB7XG4gICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIG1heF90b2tlbnM6IG9wdGlvbnMubWF4VG9rZW5zIHx8IDQwMDAsXG4gICAgICAgIG1lc3NhZ2VzOiBbXG4gICAgICAgICAge2NvbnRlbnQ6ICdZb3UgYXJlIGEgaGVscGZ1bCBhc3Npc3RhbnQgdGhhdCBmaXhlcyBFU0xpbnQgZXJyb3JzIGluIGNvZGUuJywgcm9sZTogJ3N5c3RlbSd9LFxuICAgICAgICAgIHtjb250ZW50OiBwcm9tcHQsIHJvbGU6ICd1c2VyJ31cbiAgICAgICAgXSxcbiAgICAgICAgbW9kZWw6IG9wdGlvbnMubW9kZWwgfHwgJ2dwdC00bycsXG4gICAgICAgIHRlbXBlcmF0dXJlOiBvcHRpb25zLnRlbXBlcmF0dXJlIHx8IDAuMVxuICAgICAgfSksXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgIEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHthcGlLZXl9YCxcbiAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJ1xuICAgICAgfSxcbiAgICAgIG1ldGhvZDogJ1BPU1QnXG4gICAgfSk7XG5cbiAgICBpZighcmVzcG9uc2Uub2spIHtcbiAgICAgIGNvbnN0IGVycm9yID0gYXdhaXQgcmVzcG9uc2UuanNvbigpO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBPcGVuQUkgQVBJIGVycm9yOiAke2Vycm9yLmVycm9yPy5tZXNzYWdlIHx8IHJlc3BvbnNlLnN0YXR1c1RleHR9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgZGF0YSA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKTtcbiAgICByZXR1cm4gZGF0YS5jaG9pY2VzWzBdLm1lc3NhZ2UuY29udGVudDtcbiAgfSBjYXRjaChlcnJvcikge1xuICAgIHRocm93IG5ldyBFcnJvcihgT3BlbkFJIEFJIGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XG4gIH1cbn07XG5cbmV4cG9ydCBjb25zdCBjYWxsQW50aHJvcGljQUkgPSBhc3luYyAocHJvbXB0OiBzdHJpbmcsIG9wdGlvbnM6IEFJQ29uZmlnKTogUHJvbWlzZTxzdHJpbmc+ID0+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBhcGlLZXkgPSBvcHRpb25zLmFwaUtleSB8fCBwcm9jZXNzLmVudi5BTlRIUk9QSUNfQVBJX0tFWTtcbiAgICBpZighYXBpS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0FudGhyb3BpYyBBUEkga2V5IGlzIHJlcXVpcmVkLiBTZXQgaXQgaW4geW91ciBsZXguY29uZmlnIGZpbGUgb3IgYXMgQU5USFJPUElDX0FQSV9LRVkgZW52aXJvbm1lbnQgdmFyaWFibGUuJyk7XG4gICAgfVxuXG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCgnaHR0cHM6Ly9hcGkuYW50aHJvcGljLmNvbS92MS9tZXNzYWdlcycsIHtcbiAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgbWF4X3Rva2Vuczogb3B0aW9ucy5tYXhUb2tlbnMgfHwgNDAwMCxcbiAgICAgICAgbWVzc2FnZXM6IFtcbiAgICAgICAgICB7Y29udGVudDogcHJvbXB0LCByb2xlOiAndXNlcid9XG4gICAgICAgIF0sXG4gICAgICAgIG1vZGVsOiBvcHRpb25zLm1vZGVsIHx8ICdjbGF1ZGUtMy1zb25uZXQtMjAyNDAyMjknLFxuICAgICAgICB0ZW1wZXJhdHVyZTogb3B0aW9ucy50ZW1wZXJhdHVyZSB8fCAwLjFcbiAgICAgIH0pLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAnYW50aHJvcGljLXZlcnNpb24nOiAnMjAyMy0wNi0wMScsXG4gICAgICAgICd4LWFwaS1rZXknOiBhcGlLZXlcbiAgICAgIH0sXG4gICAgICBtZXRob2Q6ICdQT1NUJ1xuICAgIH0pO1xuXG4gICAgaWYoIXJlc3BvbnNlLm9rKSB7XG4gICAgICBjb25zdCBlcnJvciA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQW50aHJvcGljIEFQSSBlcnJvcjogJHtlcnJvci5lcnJvcj8ubWVzc2FnZSB8fCByZXNwb25zZS5zdGF0dXNUZXh0fWApO1xuICAgIH1cblxuICAgIGNvbnN0IGRhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7XG4gICAgcmV0dXJuIGRhdGEuY29udGVudFswXS50ZXh0O1xuICB9IGNhdGNoKGVycm9yKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBBbnRocm9waWMgQUkgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IGNhbGxDb3BpbG90QUkgPSBhc3luYyAocHJvbXB0OiBzdHJpbmcsIF9vcHRpb25zOiBBSUNvbmZpZyk6IFByb21pc2U8c3RyaW5nPiA9PiB7XG4gIHRyeSB7XG4gICAgbG9nKCdHaXRIdWIgQ29waWxvdCBBSSBmaXhlcyBub3QgZGlyZWN0bHkgc3VwcG9ydGVkLiBVc2luZyBtYW51YWwgZml4IG1vZGUuJywgJ2luZm8nKTtcbiAgICByZXR1cm4gcHJvbXB0O1xuICB9IGNhdGNoKGVycm9yKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBHaXRIdWIgQ29waWxvdCBBSSBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xuICB9XG59O1xuXG5leHBvcnQgY29uc3QgcHJvbXB0Rm9yQUlQcm92aWRlciA9IGFzeW5jIChfcXVpZXQgPSBmYWxzZSk6IFByb21pc2U8J2N1cnNvcicgfCAnY29waWxvdCcgfCAnb3BlbmFpJyB8ICdhbnRocm9waWMnIHwgJ25vbmUnPiA9PiB7XG4gIGNvbnN0IHJsID0gcmVhZGxpbmUuY3JlYXRlSW50ZXJmYWNlKHtcbiAgICBpbnB1dDogcHJvY2Vzcy5zdGRpbixcbiAgICBvdXRwdXQ6IHByb2Nlc3Muc3Rkb3V0XG4gIH0pO1xuXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgIGxvZygnXFxuTm8gQUkgcHJvdmlkZXIgY29uZmlndXJlZC4gUGxlYXNlIGNob29zZSBhbiBBSSBwcm92aWRlcjonLCAnaW5mbycpO1xuICAgIGxvZygnMS4gQ3Vyc29yIElERScsICdpbmZvJyk7XG4gICAgbG9nKCcyLiBPcGVuQUknLCAnaW5mbycpO1xuICAgIGxvZygnMy4gQW50aHJvcGljJywgJ2luZm8nKTtcbiAgICBsb2coJzQuIEdpdEh1YiBDb3BpbG90JywgJ2luZm8nKTtcbiAgICBsb2coJzUuIE5vbmUgKFNraXAgQUkgZmVhdHVyZXMpJywgJ2luZm8nKTtcblxuICAgIHJsLnF1ZXN0aW9uKCdFbnRlciB5b3VyIGNob2ljZSAoMS01KTogJywgKGFuc3dlcikgPT4ge1xuICAgICAgcmwuY2xvc2UoKTtcblxuICAgICAgc3dpdGNoKGFuc3dlcikge1xuICAgICAgICBjYXNlICcxJzpcbiAgICAgICAgICByZXNvbHZlKCdjdXJzb3InKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnMic6XG4gICAgICAgICAgcmVzb2x2ZSgnb3BlbmFpJyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJzMnOlxuICAgICAgICAgIHJlc29sdmUoJ2FudGhyb3BpYycpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICc0JzpcbiAgICAgICAgICByZXNvbHZlKCdjb3BpbG90Jyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgcmVzb2x2ZSgnbm9uZScpO1xuICAgICAgfVxuICAgIH0pO1xuICB9KTtcbn07XG5cbmV4cG9ydCBjb25zdCBwcm9tcHRGb3JBUElLZXkgPSBhc3luYyAocHJvdmlkZXI6IHN0cmluZywgX3F1aWV0ID0gZmFsc2UpOiBQcm9taXNlPHN0cmluZz4gPT4ge1xuICBjb25zdCBybCA9IHJlYWRsaW5lLmNyZWF0ZUludGVyZmFjZSh7XG4gICAgaW5wdXQ6IHByb2Nlc3Muc3RkaW4sXG4gICAgb3V0cHV0OiBwcm9jZXNzLnN0ZG91dFxuICB9KTtcblxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICBybC5xdWVzdGlvbihgUGxlYXNlIGVudGVyIHlvdXIgJHtwcm92aWRlcn0gQVBJIGtleTogYCwgKGFuc3dlcikgPT4ge1xuICAgICAgcmwuY2xvc2UoKTtcbiAgICAgIHJlc29sdmUoYW5zd2VyKTtcbiAgICB9KTtcbiAgfSk7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0QUlTZXJ2aWNlID0gKFxuICBwcm92aWRlcjogc3RyaW5nLFxuICBfb3B0aW9uczogQUlDb25maWdcbik6IChwcm9tcHQ6IHN0cmluZywgb3B0aW9uczogQUlDb25maWcpID0+IFByb21pc2U8c3RyaW5nPiA9PiB7XG4gIHN3aXRjaChwcm92aWRlcikge1xuICAgIGNhc2UgJ2N1cnNvcic6XG4gICAgICByZXR1cm4gY2FsbEN1cnNvckFJO1xuICAgIGNhc2UgJ29wZW5haSc6XG4gICAgICByZXR1cm4gY2FsbE9wZW5BSUFJO1xuICAgIGNhc2UgJ2FudGhyb3BpYyc6XG4gICAgICByZXR1cm4gY2FsbEFudGhyb3BpY0FJO1xuICAgIGNhc2UgJ2NvcGlsb3QnOlxuICAgICAgcmV0dXJuIGNhbGxDb3BpbG90QUk7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBhc3luYyAoKSA9PiAnTm8gQUkgcHJvdmlkZXIgY29uZmlndXJlZCc7XG4gIH1cbn07XG5cbmV4cG9ydCBjb25zdCBjYWxsQUlTZXJ2aWNlID0gYXN5bmMgKHByb21wdDogc3RyaW5nLCBxdWlldCA9IGZhbHNlKTogUHJvbWlzZTxzdHJpbmc+ID0+IHtcbiAgY29uc3Qgc3Bpbm5lciA9IGNyZWF0ZVNwaW5uZXIocXVpZXQpO1xuICBzcGlubmVyLnN0YXJ0KCdDYWxsaW5nIEFJIHNlcnZpY2UgdG8gZml4IGNvZGUgaXNzdWVzLi4uJyk7XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBhaUNvbmZpZyA9IExleENvbmZpZy5jb25maWcuYWkgfHwge3Byb3ZpZGVyOiAnbm9uZSd9O1xuXG4gICAgY29uc3QgaXNJbkN1cnNvcklERSA9IHByb2Nlc3MuZW52LkNVUlNPUl9JREUgPT09ICd0cnVlJztcbiAgICBpZihpc0luQ3Vyc29ySURFICYmIChhaUNvbmZpZy5wcm92aWRlciA9PT0gJ25vbmUnIHx8ICFhaUNvbmZpZy5wcm92aWRlcikpIHtcbiAgICAgIGxvZygnRGV0ZWN0ZWQgQ3Vyc29yIElERSBlbnZpcm9ubWVudCwgdXNpbmcgQ3Vyc29yIGFzIEFJIHByb3ZpZGVyJywgJ2luZm8nLCBxdWlldCk7XG4gICAgICBhaUNvbmZpZy5wcm92aWRlciA9ICdjdXJzb3InO1xuICAgIH1cblxuICAgIGlmKGFpQ29uZmlnLnByb3ZpZGVyID09PSAnbm9uZScpIHtcbiAgICAgIGNvbnN0IHByb3ZpZGVyID0gYXdhaXQgcHJvbXB0Rm9yQUlQcm92aWRlcihxdWlldCk7XG5cbiAgICAgIGlmKHByb3ZpZGVyID09PSAnbm9uZScpIHtcbiAgICAgICAgc3Bpbm5lci5mYWlsKCdBSSBmZWF0dXJlcyBza2lwcGVkJyk7XG4gICAgICAgIHJldHVybiAnJztcbiAgICAgIH1cblxuICAgICAgYWlDb25maWcucHJvdmlkZXIgPSBwcm92aWRlcjtcblxuICAgICAgaWYocHJvdmlkZXIgIT09ICdjdXJzb3InICYmIHByb3ZpZGVyICE9PSAnY29waWxvdCcgJiZcbiAgICAgICAgIXByb2Nlc3MuZW52W2Ake3Byb3ZpZGVyLnRvVXBwZXJDYXNlKCl9X0FQSV9LRVlgXSkge1xuICAgICAgICBhaUNvbmZpZy5hcGlLZXkgPSBhd2FpdCBwcm9tcHRGb3JBUElLZXkocHJvdmlkZXIsIHF1aWV0KTtcbiAgICAgIH1cblxuICAgICAgTGV4Q29uZmlnLmNvbmZpZy5haSA9IGFpQ29uZmlnO1xuXG4gICAgICAvLyBTZWFyY2ggZm9yIGNvbmZpZyBmaWxlcyBpbiBtdWx0aXBsZSBmb3JtYXRzIGxpa2UgTGV4Q29uZmlnLnBhcnNlQ29uZmlnIGRvZXNcbiAgICAgIGNvbnN0IGNvbmZpZ0Zvcm1hdHMgPSBbJ2pzJywgJ21qcycsICdjanMnLCAndHMnLCAnanNvbiddO1xuICAgICAgY29uc3QgY29uZmlnQmFzZU5hbWUgPSAnbGV4LmNvbmZpZyc7XG4gICAgICBsZXQgY29uZmlnUGF0aCA9ICcnO1xuXG4gICAgICBmb3IoY29uc3QgZm9ybWF0IG9mIGNvbmZpZ0Zvcm1hdHMpIHtcbiAgICAgICAgY29uc3QgcG90ZW50aWFsUGF0aCA9IHBhdGhSZXNvbHZlKHByb2Nlc3MuY3dkKCksIGAuLyR7Y29uZmlnQmFzZU5hbWV9LiR7Zm9ybWF0fWApO1xuICAgICAgICBpZihleGlzdHNTeW5jKHBvdGVudGlhbFBhdGgpKSB7XG4gICAgICAgICAgY29uZmlnUGF0aCA9IHBvdGVudGlhbFBhdGg7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYoY29uZmlnUGF0aCkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IGNvbmZpZ0NvbnRlbnQgPSByZWFkRmlsZVN5bmMoY29uZmlnUGF0aCwgJ3V0ZjgnKTtcbiAgICAgICAgICBjb25zdCB1cGRhdGVkQ29uZmlnID0gY29uZmlnQ29udGVudC5yZXBsYWNlKFxuICAgICAgICAgICAgL2FpOi4qP1ssfV0vcyxcbiAgICAgICAgICAgIGBhaTogeyBwcm92aWRlcjogJyR7YWlDb25maWcucHJvdmlkZXJ9JyB9LGBcbiAgICAgICAgICApO1xuICAgICAgICAgIHdyaXRlRmlsZVN5bmMoY29uZmlnUGF0aCwgdXBkYXRlZENvbmZpZyk7XG4gICAgICAgIH0gY2F0Y2goX2Vycm9yKSB7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBsZXQgcmVzdWx0ID0gJyc7XG5cbiAgICBzd2l0Y2goYWlDb25maWcucHJvdmlkZXIpIHtcbiAgICAgIGNhc2UgJ2N1cnNvcic6XG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IGNhbGxDdXJzb3JBSShwcm9tcHQsIGFpQ29uZmlnKTtcbiAgICAgICAgbG9nKCdDdXJzb3IgSURFIEFJIGludGVncmF0aW9uIGFjdGl2ZScsICdpbmZvJywgcXVpZXQpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ29wZW5haSc6XG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IGNhbGxPcGVuQUlBSShwcm9tcHQsIGFpQ29uZmlnKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdhbnRocm9waWMnOlxuICAgICAgICByZXN1bHQgPSBhd2FpdCBjYWxsQW50aHJvcGljQUkocHJvbXB0LCBhaUNvbmZpZyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnY29waWxvdCc6XG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IGNhbGxDb3BpbG90QUkocHJvbXB0LCBhaUNvbmZpZyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgc3Bpbm5lci5mYWlsKCdObyBBSSBwcm92aWRlciBjb25maWd1cmVkJyk7XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG5cbiAgICBzcGlubmVyLnN1Y2NlZWQoJ0FJIGNvZGUgZml4ZXMgZ2VuZXJhdGVkIHN1Y2Nlc3NmdWxseScpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH0gY2F0Y2goZXJyb3IpIHtcbiAgICBzcGlubmVyLmZhaWwoYEFJIHNlcnZpY2UgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgICBpZighcXVpZXQpIHtcbiAgICAgIGxvZyhlcnJvciwgJ2Vycm9yJyk7XG4gICAgfVxuICAgIHJldHVybiAnJztcbiAgfVxufTsiXSwibmFtZXMiOlsiZXhpc3RzU3luYyIsInJlYWRGaWxlU3luYyIsIndyaXRlRmlsZVN5bmMiLCJyZXNvbHZlIiwicGF0aFJlc29sdmUiLCJyZWFkbGluZSIsIkxleENvbmZpZyIsImNyZWF0ZVNwaW5uZXIiLCJsb2ciLCJjYWxsQ3Vyc29yQUkiLCJwcm9tcHQiLCJfb3B0aW9ucyIsInRhc2tNYXRjaCIsIm1hdGNoIiwidGFzayIsImlzR2VuZXJhdGVUYXNrIiwic3RhcnRzV2l0aCIsInF1ZXN0aW9uTWF0Y2giLCJxdWVzdGlvbiIsInRyaW0iLCJ0b0xvd2VyQ2FzZSIsImluY2x1ZGVzIiwicHJvamVjdFN0cnVjdHVyZSIsInNwbGl0IiwiZmlsZXMiLCJsZW5ndGgiLCJlcnJvciIsIkVycm9yIiwibWVzc2FnZSIsImNhbGxPcGVuQUlBSSIsIm9wdGlvbnMiLCJhcGlLZXkiLCJwcm9jZXNzIiwiZW52IiwiT1BFTkFJX0FQSV9LRVkiLCJyZXNwb25zZSIsImZldGNoIiwiYm9keSIsIkpTT04iLCJzdHJpbmdpZnkiLCJtYXhfdG9rZW5zIiwibWF4VG9rZW5zIiwibWVzc2FnZXMiLCJjb250ZW50Iiwicm9sZSIsIm1vZGVsIiwidGVtcGVyYXR1cmUiLCJoZWFkZXJzIiwiQXV0aG9yaXphdGlvbiIsIm1ldGhvZCIsIm9rIiwianNvbiIsInN0YXR1c1RleHQiLCJkYXRhIiwiY2hvaWNlcyIsImNhbGxBbnRocm9waWNBSSIsIkFOVEhST1BJQ19BUElfS0VZIiwidGV4dCIsImNhbGxDb3BpbG90QUkiLCJwcm9tcHRGb3JBSVByb3ZpZGVyIiwiX3F1aWV0IiwicmwiLCJjcmVhdGVJbnRlcmZhY2UiLCJpbnB1dCIsInN0ZGluIiwib3V0cHV0Iiwic3Rkb3V0IiwiUHJvbWlzZSIsImFuc3dlciIsImNsb3NlIiwicHJvbXB0Rm9yQVBJS2V5IiwicHJvdmlkZXIiLCJnZXRBSVNlcnZpY2UiLCJjYWxsQUlTZXJ2aWNlIiwicXVpZXQiLCJzcGlubmVyIiwic3RhcnQiLCJhaUNvbmZpZyIsImNvbmZpZyIsImFpIiwiaXNJbkN1cnNvcklERSIsIkNVUlNPUl9JREUiLCJmYWlsIiwidG9VcHBlckNhc2UiLCJjb25maWdGb3JtYXRzIiwiY29uZmlnQmFzZU5hbWUiLCJjb25maWdQYXRoIiwiZm9ybWF0IiwicG90ZW50aWFsUGF0aCIsImN3ZCIsImNvbmZpZ0NvbnRlbnQiLCJ1cGRhdGVkQ29uZmlnIiwicmVwbGFjZSIsIl9lcnJvciIsInJlc3VsdCIsInN1Y2NlZWQiXSwibWFwcGluZ3MiOiJBQUFBOzs7Q0FHQyxHQUNELFNBQVFBLFVBQVUsRUFBRUMsWUFBWSxFQUFFQyxhQUFhLFFBQU8sS0FBSztBQUMzRCxTQUFRQyxXQUFXQyxXQUFXLFFBQU8sT0FBTztBQUM1QyxPQUFPQyxjQUFjLFdBQVc7QUFFaEMsU0FBa0JDLFNBQVMsUUFBTyxrQkFBa0I7QUFDcEQsU0FBUUMsYUFBYSxRQUFPLFdBQVc7QUFDdkMsU0FBUUMsR0FBRyxRQUFPLFdBQVc7QUFFN0IseUJBQXlCO0FBQ3pCLE9B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