@brainfish-ai/devdoc 0.1.45 → 0.1.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -2
- package/dist/cli/commands/create.js +25 -8
- package/dist/cli/commands/sdk.d.ts +30 -0
- package/dist/cli/commands/sdk.js +365 -0
- package/dist/cli/index.js +28 -1
- package/dist/sdk/index.d.ts +126 -0
- package/dist/sdk/index.js +871 -0
- package/package.json +7 -3
- package/renderer/app/api/collections/route.js +38 -9
- package/renderer/components/docs-viewer/agent/agent-chat.js +146 -109
- package/renderer/components/docs-viewer/index.js +21 -3
|
@@ -0,0 +1,871 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SDK Generation Module
|
|
4
|
+
*
|
|
5
|
+
* This module provides functionality for generating client SDKs from OpenAPI specifications.
|
|
6
|
+
* It supports multiple languages using both native generators and OpenAPI Generator.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
42
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
43
|
+
};
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.SUPPORTED_LANGUAGES = void 0;
|
|
46
|
+
exports.loadSDKConfig = loadSDKConfig;
|
|
47
|
+
exports.initSDKConfig = initSDKConfig;
|
|
48
|
+
exports.getEnabledGenerators = getEnabledGenerators;
|
|
49
|
+
exports.getGeneratorInfo = getGeneratorInfo;
|
|
50
|
+
exports.isNativeGenerator = isNativeGenerator;
|
|
51
|
+
exports.resolveSpecPath = resolveSpecPath;
|
|
52
|
+
exports.validateSpec = validateSpec;
|
|
53
|
+
exports.generateSDKs = generateSDKs;
|
|
54
|
+
const path_1 = __importDefault(require("path"));
|
|
55
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
56
|
+
const child_process_1 = require("child_process");
|
|
57
|
+
const util_1 = require("util");
|
|
58
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
59
|
+
// ============================================================================
|
|
60
|
+
// Constants
|
|
61
|
+
// ============================================================================
|
|
62
|
+
/**
|
|
63
|
+
* All supported languages
|
|
64
|
+
*/
|
|
65
|
+
exports.SUPPORTED_LANGUAGES = [
|
|
66
|
+
'typescript',
|
|
67
|
+
'python',
|
|
68
|
+
'go',
|
|
69
|
+
'java',
|
|
70
|
+
'csharp',
|
|
71
|
+
'ruby',
|
|
72
|
+
'php',
|
|
73
|
+
'swift',
|
|
74
|
+
'kotlin',
|
|
75
|
+
'rust',
|
|
76
|
+
];
|
|
77
|
+
/**
|
|
78
|
+
* Generator information for each language
|
|
79
|
+
*/
|
|
80
|
+
const GENERATORS = [
|
|
81
|
+
{ language: 'typescript', displayName: 'TypeScript', native: true, requiresJava: false },
|
|
82
|
+
{ language: 'python', displayName: 'Python', native: true, requiresJava: false },
|
|
83
|
+
{ language: 'go', displayName: 'Go', native: true, requiresJava: false },
|
|
84
|
+
{ language: 'java', displayName: 'Java', native: false, requiresJava: true, generatorName: 'java' },
|
|
85
|
+
{ language: 'csharp', displayName: 'C#', native: false, requiresJava: true, generatorName: 'csharp' },
|
|
86
|
+
{ language: 'ruby', displayName: 'Ruby', native: false, requiresJava: true, generatorName: 'ruby' },
|
|
87
|
+
{ language: 'php', displayName: 'PHP', native: false, requiresJava: true, generatorName: 'php' },
|
|
88
|
+
{ language: 'swift', displayName: 'Swift', native: false, requiresJava: true, generatorName: 'swift5' },
|
|
89
|
+
{ language: 'kotlin', displayName: 'Kotlin', native: false, requiresJava: true, generatorName: 'kotlin' },
|
|
90
|
+
{ language: 'rust', displayName: 'Rust', native: false, requiresJava: true, generatorName: 'rust' },
|
|
91
|
+
];
|
|
92
|
+
const CONFIG_FILENAME = 'sdk.json';
|
|
93
|
+
// ============================================================================
|
|
94
|
+
// Configuration Functions
|
|
95
|
+
// ============================================================================
|
|
96
|
+
/**
|
|
97
|
+
* Load SDK configuration from project directory
|
|
98
|
+
*/
|
|
99
|
+
async function loadSDKConfig(projectRoot) {
|
|
100
|
+
const configPath = path_1.default.join(projectRoot, CONFIG_FILENAME);
|
|
101
|
+
if (!(await fs_extra_1.default.pathExists(configPath))) {
|
|
102
|
+
return { config: null, error: `${CONFIG_FILENAME} not found` };
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
const config = await fs_extra_1.default.readJson(configPath);
|
|
106
|
+
return { config };
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
return {
|
|
110
|
+
config: null,
|
|
111
|
+
error: `Failed to parse ${CONFIG_FILENAME}: ${error instanceof Error ? error.message : String(error)}`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Initialize SDK configuration
|
|
117
|
+
*/
|
|
118
|
+
async function initSDKConfig(projectRoot, options) {
|
|
119
|
+
const configPath = path_1.default.join(projectRoot, CONFIG_FILENAME);
|
|
120
|
+
// Check if config already exists
|
|
121
|
+
if ((await fs_extra_1.default.pathExists(configPath)) && !options.force) {
|
|
122
|
+
throw new Error(`${CONFIG_FILENAME} already exists. Use --force to overwrite.`);
|
|
123
|
+
}
|
|
124
|
+
// Create language configurations
|
|
125
|
+
const languages = {};
|
|
126
|
+
for (const lang of options.languages) {
|
|
127
|
+
languages[lang] = {
|
|
128
|
+
enabled: true,
|
|
129
|
+
packageName: getDefaultPackageName(options.packageName, lang),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const config = {
|
|
133
|
+
openapi: options.openapi,
|
|
134
|
+
packageName: options.packageName,
|
|
135
|
+
output: './sdks',
|
|
136
|
+
languages,
|
|
137
|
+
};
|
|
138
|
+
await fs_extra_1.default.writeJson(configPath, config, { spaces: 2 });
|
|
139
|
+
return { configPath, config };
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get enabled generators from config
|
|
143
|
+
*/
|
|
144
|
+
function getEnabledGenerators(config) {
|
|
145
|
+
return Object.entries(config.languages)
|
|
146
|
+
.filter(([, langConfig]) => langConfig?.enabled)
|
|
147
|
+
.map(([lang]) => lang);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get generator information for all languages
|
|
151
|
+
*/
|
|
152
|
+
function getGeneratorInfo() {
|
|
153
|
+
return [...GENERATORS];
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Check if a generator is native (doesn't require Java)
|
|
157
|
+
*/
|
|
158
|
+
function isNativeGenerator(language) {
|
|
159
|
+
const generator = GENERATORS.find((g) => g.language === language);
|
|
160
|
+
return generator?.native ?? false;
|
|
161
|
+
}
|
|
162
|
+
// ============================================================================
|
|
163
|
+
// Path Utilities
|
|
164
|
+
// ============================================================================
|
|
165
|
+
/**
|
|
166
|
+
* Resolve OpenAPI spec path relative to project root
|
|
167
|
+
*/
|
|
168
|
+
function resolveSpecPath(projectRoot, specPath) {
|
|
169
|
+
if (path_1.default.isAbsolute(specPath)) {
|
|
170
|
+
return specPath;
|
|
171
|
+
}
|
|
172
|
+
return path_1.default.resolve(projectRoot, specPath);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Get default package name for a language
|
|
176
|
+
*/
|
|
177
|
+
function getDefaultPackageName(baseName, language) {
|
|
178
|
+
const sanitized = baseName.toLowerCase().replace(/[^a-z0-9]/g, '-');
|
|
179
|
+
switch (language) {
|
|
180
|
+
case 'typescript':
|
|
181
|
+
return `@${sanitized}/sdk`;
|
|
182
|
+
case 'python':
|
|
183
|
+
return sanitized.replace(/-/g, '_');
|
|
184
|
+
case 'go':
|
|
185
|
+
return sanitized;
|
|
186
|
+
case 'java':
|
|
187
|
+
return `com.${sanitized.replace(/-/g, '.')}`;
|
|
188
|
+
case 'csharp':
|
|
189
|
+
return sanitized.split('-').map(capitalize).join('.');
|
|
190
|
+
case 'ruby':
|
|
191
|
+
return sanitized.replace(/-/g, '_');
|
|
192
|
+
case 'php':
|
|
193
|
+
return sanitized.split('-').map(capitalize).join('\\');
|
|
194
|
+
case 'swift':
|
|
195
|
+
return sanitized.split('-').map(capitalize).join('');
|
|
196
|
+
case 'kotlin':
|
|
197
|
+
return `com.${sanitized.replace(/-/g, '.')}`;
|
|
198
|
+
case 'rust':
|
|
199
|
+
return sanitized.replace(/-/g, '_');
|
|
200
|
+
default:
|
|
201
|
+
return sanitized;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function capitalize(str) {
|
|
205
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
206
|
+
}
|
|
207
|
+
// ============================================================================
|
|
208
|
+
// Validation
|
|
209
|
+
// ============================================================================
|
|
210
|
+
/**
|
|
211
|
+
* Validate an OpenAPI specification
|
|
212
|
+
*/
|
|
213
|
+
async function validateSpec(specPath) {
|
|
214
|
+
const errors = [];
|
|
215
|
+
const warnings = [];
|
|
216
|
+
// Check file exists
|
|
217
|
+
if (!(await fs_extra_1.default.pathExists(specPath))) {
|
|
218
|
+
return {
|
|
219
|
+
valid: false,
|
|
220
|
+
errors: [`OpenAPI specification not found: ${specPath}`],
|
|
221
|
+
warnings: [],
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
// Read and parse the spec
|
|
226
|
+
const content = await fs_extra_1.default.readFile(specPath, 'utf-8');
|
|
227
|
+
let spec;
|
|
228
|
+
if (specPath.endsWith('.yaml') || specPath.endsWith('.yml')) {
|
|
229
|
+
const yaml = await Promise.resolve().then(() => __importStar(require('js-yaml')));
|
|
230
|
+
spec = yaml.load(content);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
spec = JSON.parse(content);
|
|
234
|
+
}
|
|
235
|
+
// Basic validation
|
|
236
|
+
if (!spec.openapi && !spec.swagger) {
|
|
237
|
+
errors.push('Missing "openapi" or "swagger" version field');
|
|
238
|
+
}
|
|
239
|
+
if (!spec.info) {
|
|
240
|
+
errors.push('Missing "info" section');
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
const info = spec.info;
|
|
244
|
+
if (!info.title) {
|
|
245
|
+
warnings.push('Missing "info.title"');
|
|
246
|
+
}
|
|
247
|
+
if (!info.version) {
|
|
248
|
+
warnings.push('Missing "info.version"');
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (!spec.paths || Object.keys(spec.paths).length === 0) {
|
|
252
|
+
warnings.push('No paths defined in specification');
|
|
253
|
+
}
|
|
254
|
+
// Check for common issues
|
|
255
|
+
const openapiVersion = spec.openapi;
|
|
256
|
+
if (openapiVersion && !openapiVersion.startsWith('3.')) {
|
|
257
|
+
warnings.push(`OpenAPI ${openapiVersion} detected. Version 3.x is recommended.`);
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
valid: errors.length === 0,
|
|
261
|
+
errors,
|
|
262
|
+
warnings,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
return {
|
|
267
|
+
valid: false,
|
|
268
|
+
errors: [`Failed to parse specification: ${error instanceof Error ? error.message : String(error)}`],
|
|
269
|
+
warnings: [],
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// ============================================================================
|
|
274
|
+
// SDK Generation
|
|
275
|
+
// ============================================================================
|
|
276
|
+
/**
|
|
277
|
+
* Generate SDKs for configured languages
|
|
278
|
+
*/
|
|
279
|
+
async function generateSDKs(projectRoot, options = {}) {
|
|
280
|
+
const startTime = Date.now();
|
|
281
|
+
const results = [];
|
|
282
|
+
// Load config
|
|
283
|
+
const { config, error } = await loadSDKConfig(projectRoot);
|
|
284
|
+
if (!config) {
|
|
285
|
+
throw new Error(error || 'SDK configuration not found');
|
|
286
|
+
}
|
|
287
|
+
// Determine which languages to generate
|
|
288
|
+
let languagesToGenerate = getEnabledGenerators(config);
|
|
289
|
+
if (options.language) {
|
|
290
|
+
if (!languagesToGenerate.includes(options.language)) {
|
|
291
|
+
throw new Error(`Language "${options.language}" is not enabled in sdk.json`);
|
|
292
|
+
}
|
|
293
|
+
languagesToGenerate = [options.language];
|
|
294
|
+
}
|
|
295
|
+
// Resolve spec path
|
|
296
|
+
const specPath = resolveSpecPath(projectRoot, config.openapi);
|
|
297
|
+
// Validate spec exists
|
|
298
|
+
if (!(await fs_extra_1.default.pathExists(specPath))) {
|
|
299
|
+
throw new Error(`OpenAPI specification not found: ${config.openapi}`);
|
|
300
|
+
}
|
|
301
|
+
// Base output directory
|
|
302
|
+
const baseOutputDir = options.outputDir
|
|
303
|
+
? path_1.default.resolve(projectRoot, options.outputDir)
|
|
304
|
+
: path_1.default.resolve(projectRoot, config.output);
|
|
305
|
+
// Generate SDKs for each language
|
|
306
|
+
for (const language of languagesToGenerate) {
|
|
307
|
+
const langStart = Date.now();
|
|
308
|
+
const langConfig = config.languages[language];
|
|
309
|
+
const outputPath = langConfig?.output
|
|
310
|
+
? path_1.default.resolve(projectRoot, langConfig.output)
|
|
311
|
+
: path_1.default.join(baseOutputDir, language);
|
|
312
|
+
try {
|
|
313
|
+
if (options.preview) {
|
|
314
|
+
// Preview mode - just report what would be generated
|
|
315
|
+
results.push({
|
|
316
|
+
language,
|
|
317
|
+
success: true,
|
|
318
|
+
outputPath,
|
|
319
|
+
duration: Date.now() - langStart,
|
|
320
|
+
});
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
// Ensure output directory exists
|
|
324
|
+
await fs_extra_1.default.ensureDir(outputPath);
|
|
325
|
+
// Generate SDK based on generator type
|
|
326
|
+
const generator = GENERATORS.find((g) => g.language === language);
|
|
327
|
+
if (generator?.native) {
|
|
328
|
+
await generateNativeSDK(language, specPath, outputPath, config, langConfig);
|
|
329
|
+
}
|
|
330
|
+
else if (generator?.generatorName) {
|
|
331
|
+
await generateOpenAPIGeneratorSDK(generator.generatorName, specPath, outputPath, config, langConfig);
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
throw new Error(`No generator found for ${language}`);
|
|
335
|
+
}
|
|
336
|
+
results.push({
|
|
337
|
+
language,
|
|
338
|
+
success: true,
|
|
339
|
+
outputPath,
|
|
340
|
+
duration: Date.now() - langStart,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
catch (err) {
|
|
344
|
+
results.push({
|
|
345
|
+
language,
|
|
346
|
+
success: false,
|
|
347
|
+
outputPath,
|
|
348
|
+
error: err instanceof Error ? err.message : String(err),
|
|
349
|
+
duration: Date.now() - langStart,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return {
|
|
354
|
+
results,
|
|
355
|
+
successCount: results.filter((r) => r.success).length,
|
|
356
|
+
failureCount: results.filter((r) => !r.success).length,
|
|
357
|
+
totalDuration: Date.now() - startTime,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Generate SDK using native generator (TypeScript, Python, Go)
|
|
362
|
+
*/
|
|
363
|
+
async function generateNativeSDK(language, specPath, outputPath, config, langConfig) {
|
|
364
|
+
const packageName = langConfig?.packageName || getDefaultPackageName(config.packageName, language);
|
|
365
|
+
switch (language) {
|
|
366
|
+
case 'typescript':
|
|
367
|
+
await generateTypeScriptSDK(specPath, outputPath, packageName);
|
|
368
|
+
break;
|
|
369
|
+
case 'python':
|
|
370
|
+
await generatePythonSDK(specPath, outputPath, packageName);
|
|
371
|
+
break;
|
|
372
|
+
case 'go':
|
|
373
|
+
await generateGoSDK(specPath, outputPath, packageName);
|
|
374
|
+
break;
|
|
375
|
+
default:
|
|
376
|
+
throw new Error(`Native generator not implemented for ${language}`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Generate SDK using OpenAPI Generator (Java-based)
|
|
381
|
+
*/
|
|
382
|
+
async function generateOpenAPIGeneratorSDK(generatorName, specPath, outputPath, config, langConfig) {
|
|
383
|
+
// Check if Java is available
|
|
384
|
+
try {
|
|
385
|
+
await execAsync('java -version');
|
|
386
|
+
}
|
|
387
|
+
catch {
|
|
388
|
+
throw new Error('Java is required for this generator. Please install Java 11 or later.');
|
|
389
|
+
}
|
|
390
|
+
// Check if openapi-generator is available
|
|
391
|
+
let generatorCmd = 'openapi-generator';
|
|
392
|
+
try {
|
|
393
|
+
await execAsync('openapi-generator version');
|
|
394
|
+
}
|
|
395
|
+
catch {
|
|
396
|
+
// Try npx fallback
|
|
397
|
+
generatorCmd = 'npx @openapitools/openapi-generator-cli';
|
|
398
|
+
}
|
|
399
|
+
const additionalProps = langConfig?.additionalOptions
|
|
400
|
+
? Object.entries(langConfig.additionalOptions)
|
|
401
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
402
|
+
.join(',')
|
|
403
|
+
: '';
|
|
404
|
+
const cmd = [
|
|
405
|
+
generatorCmd,
|
|
406
|
+
'generate',
|
|
407
|
+
'-i',
|
|
408
|
+
specPath,
|
|
409
|
+
'-g',
|
|
410
|
+
generatorName,
|
|
411
|
+
'-o',
|
|
412
|
+
outputPath,
|
|
413
|
+
additionalProps ? `--additional-properties=${additionalProps}` : '',
|
|
414
|
+
]
|
|
415
|
+
.filter(Boolean)
|
|
416
|
+
.join(' ');
|
|
417
|
+
await execAsync(cmd);
|
|
418
|
+
}
|
|
419
|
+
// ============================================================================
|
|
420
|
+
// Native Generator Implementations
|
|
421
|
+
// ============================================================================
|
|
422
|
+
/**
|
|
423
|
+
* Generate TypeScript SDK
|
|
424
|
+
*/
|
|
425
|
+
async function generateTypeScriptSDK(specPath, outputPath, packageName) {
|
|
426
|
+
// Read the OpenAPI spec
|
|
427
|
+
const content = await fs_extra_1.default.readFile(specPath, 'utf-8');
|
|
428
|
+
let spec;
|
|
429
|
+
if (specPath.endsWith('.yaml') || specPath.endsWith('.yml')) {
|
|
430
|
+
const yaml = await Promise.resolve().then(() => __importStar(require('js-yaml')));
|
|
431
|
+
spec = yaml.load(content);
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
spec = JSON.parse(content);
|
|
435
|
+
}
|
|
436
|
+
const info = (spec.info || {});
|
|
437
|
+
const paths = (spec.paths || {});
|
|
438
|
+
// Generate package.json
|
|
439
|
+
const packageJson = {
|
|
440
|
+
name: packageName,
|
|
441
|
+
version: info.version || '1.0.0',
|
|
442
|
+
description: info.description || 'Generated SDK',
|
|
443
|
+
main: 'dist/index.js',
|
|
444
|
+
types: 'dist/index.d.ts',
|
|
445
|
+
scripts: {
|
|
446
|
+
build: 'tsc',
|
|
447
|
+
prepublishOnly: 'npm run build',
|
|
448
|
+
},
|
|
449
|
+
devDependencies: {
|
|
450
|
+
typescript: '^5.0.0',
|
|
451
|
+
'@types/node': '^20.0.0',
|
|
452
|
+
},
|
|
453
|
+
};
|
|
454
|
+
await fs_extra_1.default.writeJson(path_1.default.join(outputPath, 'package.json'), packageJson, { spaces: 2 });
|
|
455
|
+
// Generate tsconfig.json
|
|
456
|
+
const tsConfig = {
|
|
457
|
+
compilerOptions: {
|
|
458
|
+
target: 'ES2020',
|
|
459
|
+
module: 'commonjs',
|
|
460
|
+
declaration: true,
|
|
461
|
+
outDir: './dist',
|
|
462
|
+
strict: true,
|
|
463
|
+
esModuleInterop: true,
|
|
464
|
+
skipLibCheck: true,
|
|
465
|
+
forceConsistentCasingInFileNames: true,
|
|
466
|
+
},
|
|
467
|
+
include: ['src/**/*'],
|
|
468
|
+
exclude: ['node_modules', 'dist'],
|
|
469
|
+
};
|
|
470
|
+
await fs_extra_1.default.writeJson(path_1.default.join(outputPath, 'tsconfig.json'), tsConfig, { spaces: 2 });
|
|
471
|
+
// Generate source files
|
|
472
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(outputPath, 'src'));
|
|
473
|
+
// Generate types
|
|
474
|
+
const typesContent = generateTypeScriptTypes(spec);
|
|
475
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputPath, 'src', 'types.ts'), typesContent);
|
|
476
|
+
// Generate client
|
|
477
|
+
const clientContent = generateTypeScriptClient(spec, paths);
|
|
478
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputPath, 'src', 'client.ts'), clientContent);
|
|
479
|
+
// Generate index
|
|
480
|
+
const indexContent = `export * from './types';\nexport * from './client';\n`;
|
|
481
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputPath, 'src', 'index.ts'), indexContent);
|
|
482
|
+
// Generate README
|
|
483
|
+
const readmeContent = `# ${packageName}
|
|
484
|
+
|
|
485
|
+
Generated TypeScript SDK for ${info.title || 'API'}.
|
|
486
|
+
|
|
487
|
+
## Installation
|
|
488
|
+
|
|
489
|
+
\`\`\`bash
|
|
490
|
+
npm install ${packageName}
|
|
491
|
+
\`\`\`
|
|
492
|
+
|
|
493
|
+
## Usage
|
|
494
|
+
|
|
495
|
+
\`\`\`typescript
|
|
496
|
+
import { ApiClient } from '${packageName}';
|
|
497
|
+
|
|
498
|
+
const client = new ApiClient({
|
|
499
|
+
baseUrl: 'https://api.example.com',
|
|
500
|
+
// apiKey: 'your-api-key',
|
|
501
|
+
});
|
|
502
|
+
\`\`\`
|
|
503
|
+
`;
|
|
504
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputPath, 'README.md'), readmeContent);
|
|
505
|
+
}
|
|
506
|
+
function generateTypeScriptTypes(spec) {
|
|
507
|
+
let content = '/**\n * Generated types from OpenAPI specification\n */\n\n';
|
|
508
|
+
const schemas = (spec.components?.schemas || {});
|
|
509
|
+
// If no schemas, export a placeholder to make this a valid module
|
|
510
|
+
if (Object.keys(schemas).length === 0) {
|
|
511
|
+
content += '// No schemas defined in the OpenAPI specification\n';
|
|
512
|
+
content += 'export type ApiResponse<T> = T;\n';
|
|
513
|
+
content += 'export type ApiError = { message: string; code?: number };\n';
|
|
514
|
+
return content;
|
|
515
|
+
}
|
|
516
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
517
|
+
content += `export interface ${name} {\n`;
|
|
518
|
+
const properties = schema.properties;
|
|
519
|
+
const required = (schema.required || []);
|
|
520
|
+
if (properties) {
|
|
521
|
+
for (const [propName, propSchema] of Object.entries(properties)) {
|
|
522
|
+
const isRequired = required.includes(propName);
|
|
523
|
+
const tsType = openApiTypeToTs(propSchema);
|
|
524
|
+
content += ` ${propName}${isRequired ? '' : '?'}: ${tsType};\n`;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
content += '}\n\n';
|
|
528
|
+
}
|
|
529
|
+
return content;
|
|
530
|
+
}
|
|
531
|
+
function openApiTypeToTs(schema) {
|
|
532
|
+
const type = schema.type;
|
|
533
|
+
const format = schema.format;
|
|
534
|
+
const ref = schema.$ref;
|
|
535
|
+
if (ref) {
|
|
536
|
+
return ref.split('/').pop() || 'unknown';
|
|
537
|
+
}
|
|
538
|
+
switch (type) {
|
|
539
|
+
case 'string':
|
|
540
|
+
return 'string';
|
|
541
|
+
case 'integer':
|
|
542
|
+
case 'number':
|
|
543
|
+
return 'number';
|
|
544
|
+
case 'boolean':
|
|
545
|
+
return 'boolean';
|
|
546
|
+
case 'array':
|
|
547
|
+
const items = schema.items;
|
|
548
|
+
return `${openApiTypeToTs(items || {})}[]`;
|
|
549
|
+
case 'object':
|
|
550
|
+
return 'Record<string, unknown>';
|
|
551
|
+
default:
|
|
552
|
+
return 'unknown';
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
function generateTypeScriptClient(spec, paths) {
|
|
556
|
+
const info = (spec.info || {});
|
|
557
|
+
const servers = (spec.servers || []);
|
|
558
|
+
const defaultBaseUrl = servers[0]?.url || 'https://api.example.com';
|
|
559
|
+
let content = `/**
|
|
560
|
+
* ${info.title || 'API'} Client
|
|
561
|
+
* ${info.description || ''}
|
|
562
|
+
*/
|
|
563
|
+
|
|
564
|
+
export interface ClientConfig {
|
|
565
|
+
baseUrl?: string;
|
|
566
|
+
apiKey?: string;
|
|
567
|
+
headers?: Record<string, string>;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
export class ApiClient {
|
|
571
|
+
private baseUrl: string;
|
|
572
|
+
private headers: Record<string, string>;
|
|
573
|
+
|
|
574
|
+
constructor(config: ClientConfig = {}) {
|
|
575
|
+
this.baseUrl = config.baseUrl || '${defaultBaseUrl}';
|
|
576
|
+
this.headers = {
|
|
577
|
+
'Content-Type': 'application/json',
|
|
578
|
+
...config.headers,
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
if (config.apiKey) {
|
|
582
|
+
this.headers['Authorization'] = \`Bearer \${config.apiKey}\`;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
private async request<T>(
|
|
587
|
+
method: string,
|
|
588
|
+
path: string,
|
|
589
|
+
options: { body?: unknown; query?: Record<string, string> } = {}
|
|
590
|
+
): Promise<T> {
|
|
591
|
+
let url = \`\${this.baseUrl}\${path}\`;
|
|
592
|
+
|
|
593
|
+
if (options.query) {
|
|
594
|
+
const params = new URLSearchParams(options.query);
|
|
595
|
+
url += \`?\${params.toString()}\`;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
const response = await fetch(url, {
|
|
599
|
+
method,
|
|
600
|
+
headers: this.headers,
|
|
601
|
+
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
if (!response.ok) {
|
|
605
|
+
throw new Error(\`HTTP \${response.status}: \${response.statusText}\`);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
return response.json();
|
|
609
|
+
}
|
|
610
|
+
`;
|
|
611
|
+
// Generate methods for each path
|
|
612
|
+
for (const [pathUrl, pathItem] of Object.entries(paths)) {
|
|
613
|
+
const methods = ['get', 'post', 'put', 'patch', 'delete'];
|
|
614
|
+
for (const method of methods) {
|
|
615
|
+
const operation = pathItem[method];
|
|
616
|
+
if (!operation)
|
|
617
|
+
continue;
|
|
618
|
+
const operationId = operation.operationId || `${method}${pathUrl.replace(/[^a-zA-Z0-9]/g, '_')}`;
|
|
619
|
+
const summary = operation.summary || '';
|
|
620
|
+
content += `
|
|
621
|
+
/**
|
|
622
|
+
* ${summary}
|
|
623
|
+
*/
|
|
624
|
+
async ${operationId}(): Promise<unknown> {
|
|
625
|
+
return this.request('${method.toUpperCase()}', '${pathUrl}');
|
|
626
|
+
}
|
|
627
|
+
`;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
content += '}\n';
|
|
631
|
+
return content;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Generate Python SDK
|
|
635
|
+
*/
|
|
636
|
+
async function generatePythonSDK(specPath, outputPath, packageName) {
|
|
637
|
+
// Read the OpenAPI spec
|
|
638
|
+
const content = await fs_extra_1.default.readFile(specPath, 'utf-8');
|
|
639
|
+
let spec;
|
|
640
|
+
if (specPath.endsWith('.yaml') || specPath.endsWith('.yml')) {
|
|
641
|
+
const yaml = await Promise.resolve().then(() => __importStar(require('js-yaml')));
|
|
642
|
+
spec = yaml.load(content);
|
|
643
|
+
}
|
|
644
|
+
else {
|
|
645
|
+
spec = JSON.parse(content);
|
|
646
|
+
}
|
|
647
|
+
const info = (spec.info || {});
|
|
648
|
+
const servers = (spec.servers || []);
|
|
649
|
+
const defaultBaseUrl = servers[0]?.url || 'https://api.example.com';
|
|
650
|
+
// Create package directory
|
|
651
|
+
const pkgDir = path_1.default.join(outputPath, packageName);
|
|
652
|
+
await fs_extra_1.default.ensureDir(pkgDir);
|
|
653
|
+
// Generate setup.py
|
|
654
|
+
const setupPy = `from setuptools import setup, find_packages
|
|
655
|
+
|
|
656
|
+
setup(
|
|
657
|
+
name="${packageName}",
|
|
658
|
+
version="${info.version || '1.0.0'}",
|
|
659
|
+
description="${info.description || 'Generated SDK'}",
|
|
660
|
+
packages=find_packages(),
|
|
661
|
+
python_requires=">=3.8",
|
|
662
|
+
install_requires=[
|
|
663
|
+
"httpx>=0.24.0",
|
|
664
|
+
],
|
|
665
|
+
)
|
|
666
|
+
`;
|
|
667
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputPath, 'setup.py'), setupPy);
|
|
668
|
+
// Generate __init__.py
|
|
669
|
+
const initPy = `"""${info.title || 'API'} SDK"""
|
|
670
|
+
|
|
671
|
+
from .client import ApiClient
|
|
672
|
+
|
|
673
|
+
__all__ = ["ApiClient"]
|
|
674
|
+
__version__ = "${info.version || '1.0.0'}"
|
|
675
|
+
`;
|
|
676
|
+
await fs_extra_1.default.writeFile(path_1.default.join(pkgDir, '__init__.py'), initPy);
|
|
677
|
+
// Generate client.py
|
|
678
|
+
const clientPy = `"""API Client"""
|
|
679
|
+
|
|
680
|
+
import httpx
|
|
681
|
+
from typing import Optional, Dict, Any
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
class ApiClient:
|
|
685
|
+
"""${info.title || 'API'} Client"""
|
|
686
|
+
|
|
687
|
+
def __init__(
|
|
688
|
+
self,
|
|
689
|
+
base_url: str = "${defaultBaseUrl}",
|
|
690
|
+
api_key: Optional[str] = None,
|
|
691
|
+
headers: Optional[Dict[str, str]] = None,
|
|
692
|
+
):
|
|
693
|
+
self.base_url = base_url.rstrip("/")
|
|
694
|
+
self.headers = headers or {}
|
|
695
|
+
self.headers["Content-Type"] = "application/json"
|
|
696
|
+
|
|
697
|
+
if api_key:
|
|
698
|
+
self.headers["Authorization"] = f"Bearer {api_key}"
|
|
699
|
+
|
|
700
|
+
self._client = httpx.Client(headers=self.headers)
|
|
701
|
+
|
|
702
|
+
def _request(
|
|
703
|
+
self,
|
|
704
|
+
method: str,
|
|
705
|
+
path: str,
|
|
706
|
+
params: Optional[Dict[str, Any]] = None,
|
|
707
|
+
json: Optional[Dict[str, Any]] = None,
|
|
708
|
+
) -> Any:
|
|
709
|
+
url = f"{self.base_url}{path}"
|
|
710
|
+
response = self._client.request(method, url, params=params, json=json)
|
|
711
|
+
response.raise_for_status()
|
|
712
|
+
return response.json()
|
|
713
|
+
|
|
714
|
+
def close(self):
|
|
715
|
+
self._client.close()
|
|
716
|
+
|
|
717
|
+
def __enter__(self):
|
|
718
|
+
return self
|
|
719
|
+
|
|
720
|
+
def __exit__(self, *args):
|
|
721
|
+
self.close()
|
|
722
|
+
`;
|
|
723
|
+
await fs_extra_1.default.writeFile(path_1.default.join(pkgDir, 'client.py'), clientPy);
|
|
724
|
+
// Generate README
|
|
725
|
+
const readme = `# ${packageName}
|
|
726
|
+
|
|
727
|
+
Generated Python SDK for ${info.title || 'API'}.
|
|
728
|
+
|
|
729
|
+
## Installation
|
|
730
|
+
|
|
731
|
+
\`\`\`bash
|
|
732
|
+
pip install -e .
|
|
733
|
+
\`\`\`
|
|
734
|
+
|
|
735
|
+
## Usage
|
|
736
|
+
|
|
737
|
+
\`\`\`python
|
|
738
|
+
from ${packageName} import ApiClient
|
|
739
|
+
|
|
740
|
+
client = ApiClient(
|
|
741
|
+
base_url="${defaultBaseUrl}",
|
|
742
|
+
api_key="your-api-key",
|
|
743
|
+
)
|
|
744
|
+
\`\`\`
|
|
745
|
+
`;
|
|
746
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputPath, 'README.md'), readme);
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Generate Go SDK
|
|
750
|
+
*/
|
|
751
|
+
async function generateGoSDK(specPath, outputPath, packageName) {
|
|
752
|
+
// Read the OpenAPI spec
|
|
753
|
+
const content = await fs_extra_1.default.readFile(specPath, 'utf-8');
|
|
754
|
+
let spec;
|
|
755
|
+
if (specPath.endsWith('.yaml') || specPath.endsWith('.yml')) {
|
|
756
|
+
const yaml = await Promise.resolve().then(() => __importStar(require('js-yaml')));
|
|
757
|
+
spec = yaml.load(content);
|
|
758
|
+
}
|
|
759
|
+
else {
|
|
760
|
+
spec = JSON.parse(content);
|
|
761
|
+
}
|
|
762
|
+
const info = (spec.info || {});
|
|
763
|
+
const servers = (spec.servers || []);
|
|
764
|
+
const defaultBaseUrl = servers[0]?.url || 'https://api.example.com';
|
|
765
|
+
// Generate go.mod
|
|
766
|
+
const goMod = `module ${packageName}
|
|
767
|
+
|
|
768
|
+
go 1.21
|
|
769
|
+
`;
|
|
770
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputPath, 'go.mod'), goMod);
|
|
771
|
+
// Generate client.go
|
|
772
|
+
const clientGo = `// Package ${packageName.split('/').pop()} provides a client for ${info.title || 'the API'}.
|
|
773
|
+
package ${packageName.split('/').pop() || 'sdk'}
|
|
774
|
+
|
|
775
|
+
import (
|
|
776
|
+
\t"bytes"
|
|
777
|
+
\t"encoding/json"
|
|
778
|
+
\t"fmt"
|
|
779
|
+
\t"io"
|
|
780
|
+
\t"net/http"
|
|
781
|
+
)
|
|
782
|
+
|
|
783
|
+
// Client represents an API client.
|
|
784
|
+
type Client struct {
|
|
785
|
+
\tBaseURL string
|
|
786
|
+
\tAPIKey string
|
|
787
|
+
\tHTTPClient *http.Client
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// NewClient creates a new API client.
|
|
791
|
+
func NewClient(baseURL, apiKey string) *Client {
|
|
792
|
+
\tif baseURL == "" {
|
|
793
|
+
\t\tbaseURL = "${defaultBaseUrl}"
|
|
794
|
+
\t}
|
|
795
|
+
\treturn &Client{
|
|
796
|
+
\t\tBaseURL: baseURL,
|
|
797
|
+
\t\tAPIKey: apiKey,
|
|
798
|
+
\t\tHTTPClient: &http.Client{},
|
|
799
|
+
\t}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
func (c *Client) doRequest(method, path string, body interface{}) ([]byte, error) {
|
|
803
|
+
\turl := c.BaseURL + path
|
|
804
|
+
|
|
805
|
+
\tvar reqBody io.Reader
|
|
806
|
+
\tif body != nil {
|
|
807
|
+
\t\tjsonBody, err := json.Marshal(body)
|
|
808
|
+
\t\tif err != nil {
|
|
809
|
+
\t\t\treturn nil, fmt.Errorf("failed to marshal request body: %w", err)
|
|
810
|
+
\t\t}
|
|
811
|
+
\t\treqBody = bytes.NewBuffer(jsonBody)
|
|
812
|
+
\t}
|
|
813
|
+
|
|
814
|
+
\treq, err := http.NewRequest(method, url, reqBody)
|
|
815
|
+
\tif err != nil {
|
|
816
|
+
\t\treturn nil, fmt.Errorf("failed to create request: %w", err)
|
|
817
|
+
\t}
|
|
818
|
+
|
|
819
|
+
\treq.Header.Set("Content-Type", "application/json")
|
|
820
|
+
\tif c.APIKey != "" {
|
|
821
|
+
\t\treq.Header.Set("Authorization", "Bearer "+c.APIKey)
|
|
822
|
+
\t}
|
|
823
|
+
|
|
824
|
+
\tresp, err := c.HTTPClient.Do(req)
|
|
825
|
+
\tif err != nil {
|
|
826
|
+
\t\treturn nil, fmt.Errorf("request failed: %w", err)
|
|
827
|
+
\t}
|
|
828
|
+
\tdefer resp.Body.Close()
|
|
829
|
+
|
|
830
|
+
\trespBody, err := io.ReadAll(resp.Body)
|
|
831
|
+
\tif err != nil {
|
|
832
|
+
\t\treturn nil, fmt.Errorf("failed to read response: %w", err)
|
|
833
|
+
\t}
|
|
834
|
+
|
|
835
|
+
\tif resp.StatusCode >= 400 {
|
|
836
|
+
\t\treturn nil, fmt.Errorf("API error %d: %s", resp.StatusCode, string(respBody))
|
|
837
|
+
\t}
|
|
838
|
+
|
|
839
|
+
\treturn respBody, nil
|
|
840
|
+
}
|
|
841
|
+
`;
|
|
842
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputPath, 'client.go'), clientGo);
|
|
843
|
+
// Generate README
|
|
844
|
+
const readme = `# ${packageName}
|
|
845
|
+
|
|
846
|
+
Generated Go SDK for ${info.title || 'API'}.
|
|
847
|
+
|
|
848
|
+
## Installation
|
|
849
|
+
|
|
850
|
+
\`\`\`bash
|
|
851
|
+
go get ${packageName}
|
|
852
|
+
\`\`\`
|
|
853
|
+
|
|
854
|
+
## Usage
|
|
855
|
+
|
|
856
|
+
\`\`\`go
|
|
857
|
+
package main
|
|
858
|
+
|
|
859
|
+
import (
|
|
860
|
+
\t"${packageName}"
|
|
861
|
+
)
|
|
862
|
+
|
|
863
|
+
func main() {
|
|
864
|
+
\tclient := ${packageName.split('/').pop()}.NewClient("${defaultBaseUrl}", "your-api-key")
|
|
865
|
+
\t// Use client...
|
|
866
|
+
}
|
|
867
|
+
\`\`\`
|
|
868
|
+
`;
|
|
869
|
+
await fs_extra_1.default.writeFile(path_1.default.join(outputPath, 'README.md'), readme);
|
|
870
|
+
}
|
|
871
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2RrL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7R0FLRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBMkpILHNDQWtCQztBQUtELHNDQThCQztBQUtELG9EQUlDO0FBS0QsNENBRUM7QUFLRCw4Q0FHQztBQVNELDBDQUtDO0FBNkNELG9DQWdFQztBQVNELG9DQTZGQztBQXZjRCxnREFBd0I7QUFDeEIsd0RBQTBCO0FBQzFCLGlEQUE0QztBQUM1QywrQkFBaUM7QUFFakMsTUFBTSxTQUFTLEdBQUcsSUFBQSxnQkFBUyxFQUFDLG9CQUFJLENBQUMsQ0FBQztBQXVHbEMsK0VBQStFO0FBQy9FLFlBQVk7QUFDWiwrRUFBK0U7QUFFL0U7O0dBRUc7QUFDVSxRQUFBLG1CQUFtQixHQUFrQjtJQUNoRCxZQUFZO0lBQ1osUUFBUTtJQUNSLElBQUk7SUFDSixNQUFNO0lBQ04sUUFBUTtJQUNSLE1BQU07SUFDTixLQUFLO0lBQ0wsT0FBTztJQUNQLFFBQVE7SUFDUixNQUFNO0NBQ1AsQ0FBQztBQUVGOztHQUVHO0FBQ0gsTUFBTSxVQUFVLEdBQW9CO0lBQ2xDLEVBQUUsUUFBUSxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRTtJQUN4RixFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUU7SUFDaEYsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFO0lBQ3hFLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsTUFBTSxFQUFFLE1B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VUFBVSxFQUFFLFdBQVcsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0FBQ2pFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNESyBHZW5lcmF0aW9uIE1vZHVsZVxuICpcbiAqIFRoaXMgbW9kdWxlIHByb3ZpZGVzIGZ1bmN0aW9uYWxpdHkgZm9yIGdlbmVyYXRpbmcgY2xpZW50IFNES3MgZnJvbSBPcGVuQVBJIHNwZWNpZmljYXRpb25zLlxuICogSXQgc3VwcG9ydHMgbXVsdGlwbGUgbGFuZ3VhZ2VzIHVzaW5nIGJvdGggbmF0aXZlIGdlbmVyYXRvcnMgYW5kIE9wZW5BUEkgR2VuZXJhdG9yLlxuICovXG5cbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IGZzIGZyb20gJ2ZzLWV4dHJhJztcbmltcG9ydCB7IGV4ZWMsIHNwYXduIH0gZnJvbSAnY2hpbGRfcHJvY2Vzcyc7XG5pbXBvcnQgeyBwcm9taXNpZnkgfSBmcm9tICd1dGlsJztcblxuY29uc3QgZXhlY0FzeW5jID0gcHJvbWlzaWZ5KGV4ZWMpO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBUeXBlc1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIFN1cHBvcnRlZCBTREsgbGFuZ3VhZ2VzXG4gKi9cbmV4cG9ydCB0eXBlIFNES0xhbmd1YWdlID1cbiAgfCAndHlwZXNjcmlwdCdcbiAgfCAncHl0aG9uJ1xuICB8ICdnbydcbiAgfCAnamF2YSdcbiAgfCAnY3NoYXJwJ1xuICB8ICdydWJ5J1xuICB8ICdwaHAnXG4gIHwgJ3N3aWZ0J1xuICB8ICdrb3RsaW4nXG4gIHwgJ3J1c3QnO1xuXG4vKipcbiAqIFNESyBjb25maWd1cmF0aW9uIGZpbGUgKHNkay5qc29uKVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNES0NvbmZpZyB7XG4gIG9wZW5hcGk6IHN0cmluZztcbiAgcGFja2FnZU5hbWU6IHN0cmluZztcbiAgb3V0cHV0OiBzdHJpbmc7XG4gIGxhbmd1YWdlczoge1xuICAgIFtrZXkgaW4gU0RLTGFuZ3VhZ2VdPzogTGFuZ3VhZ2VDb25maWc7XG4gIH07XG59XG5cbi8qKlxuICogTGFuZ3VhZ2Utc3BlY2lmaWMgY29uZmlndXJhdGlvblxuICovXG5leHBvcnQgaW50ZXJmYWNlIExhbmd1YWdlQ29uZmlnIHtcbiAgZW5hYmxlZDogYm9vbGVhbjtcbiAgcGFja2FnZU5hbWU/OiBzdHJpbmc7XG4gIG91dHB1dD86IHN0cmluZztcbiAgYWRkaXRpb25hbE9wdGlvbnM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xufVxuXG4vKipcbiAqIEdlbmVyYXRvciBpbmZvcm1hdGlvblxuICovXG5leHBvcnQgaW50ZXJmYWNlIEdlbmVyYXRvckluZm8ge1xuICBsYW5ndWFnZTogU0RLTGFuZ3VhZ2U7XG4gIGRpc3BsYXlOYW1lOiBzdHJpbmc7XG4gIG5hdGl2ZTogYm9vbGVhbjtcbiAgcmVxdWlyZXNKYXZhOiBib29sZWFuO1xuICBnZW5lcmF0b3JOYW1lPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFNESyBnZW5lcmF0aW9uIHJlc3VsdCBmb3IgYSBzaW5nbGUgbGFuZ3VhZ2VcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTREtHZW5lcmF0aW9uUmVzdWx0IHtcbiAgbGFuZ3VhZ2U6IFNES0xhbmd1YWdlO1xuICBzdWNjZXNzOiBib29sZWFuO1xuICBvdXRwdXRQYXRoOiBzdHJpbmc7XG4gIGVycm9yPzogc3RyaW5nO1xuICBkdXJhdGlvbjogbnVtYmVyO1xufVxuXG4vKipcbiAqIE92ZXJhbGwgU0RLIGdlbmVyYXRpb24gcmVzdWx0XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgR2VuZXJhdGVTREtzUmVzdWx0IHtcbiAgcmVzdWx0czogU0RLR2VuZXJhdGlvblJlc3VsdFtdO1xuICBzdWNjZXNzQ291bnQ6IG51bWJlcjtcbiAgZmFpbHVyZUNvdW50OiBudW1iZXI7XG4gIHRvdGFsRHVyYXRpb246IG51bWJlcjtcbn1cblxuLyoqXG4gKiBWYWxpZGF0aW9uIHJlc3VsdFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFZhbGlkYXRpb25SZXN1bHQge1xuICB2YWxpZDogYm9vbGVhbjtcbiAgZXJyb3JzOiBzdHJpbmdbXTtcbiAgd2FybmluZ3M6IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIFNESyBnZW5lcmF0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgR2VuZXJhdGVPcHRpb25zIHtcbiAgbGFuZ3VhZ2U/OiBTREtMYW5ndWFnZTtcbiAgcHJldmlldz86IGJvb2xlYW47XG4gIG91dHB1dERpcj86IHN0cmluZztcbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciBTREsgY29uZmlnIGluaXRpYWxpemF0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSW5pdENvbmZpZ09wdGlvbnMge1xuICBvcGVuYXBpOiBzdHJpbmc7XG4gIHBhY2thZ2VOYW1lOiBzdHJpbmc7XG4gIGxhbmd1YWdlczogU0RLTGFuZ3VhZ2VbXTtcbiAgZm9yY2U/OiBib29sZWFuO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBDb25zdGFudHNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBBbGwgc3VwcG9ydGVkIGxhbmd1YWdlc1xuICovXG5leHBvcnQgY29uc3QgU1VQUE9SVEVEX0xBTkdVQUdFUzogU0RLTGFuZ3VhZ2VbXSA9IFtcbiAgJ3R5cGVzY3JpcHQnLFxuICAncHl0aG9uJyxcbiAgJ2dvJyxcbiAgJ2phdmEnLFxuICAnY3NoYXJwJyxcbiAgJ3J1YnknLFxuICAncGhwJyxcbiAgJ3N3aWZ0JyxcbiAgJ2tvdGxpbicsXG4gICdydXN0Jyxcbl07XG5cbi8qKlxuICogR2VuZXJhdG9yIGluZm9ybWF0aW9uIGZvciBlYWNoIGxhbmd1YWdlXG4gKi9cbmNvbnN0IEdFTkVSQVRPUlM6IEdlbmVyYXRvckluZm9bXSA9IFtcbiAgeyBsYW5ndWFnZTogJ3R5cGVzY3JpcHQnLCBkaXNwbGF5TmFtZTogJ1R5cGVTY3JpcHQnLCBuYXRpdmU6IHRydWUsIHJlcXVpcmVzSmF2YTogZmFsc2UgfSxcbiAgeyBsYW5ndWFnZTogJ3B5dGhvbicsIGRpc3BsYXlOYW1lOiAnUHl0aG9uJywgbmF0aXZlOiB0cnVlLCByZXF1aXJlc0phdmE6IGZhbHNlIH0sXG4gIHsgbGFuZ3VhZ2U6ICdnbycsIGRpc3BsYXlOYW1lOiAnR28nLCBuYXRpdmU6IHRydWUsIHJlcXVpcmVzSmF2YTogZmFsc2UgfSxcbiAgeyBsYW5ndWFnZTogJ2phdmEnLCBkaXNwbGF5TmFtZTogJ0phdmEnLCBuYXRpdmU6IGZhbHNlLCByZXF1aXJlc0phdmE6IHRydWUsIGdlbmVyYXRvck5hbWU6ICdqYXZhJyB9LFxuICB7IGxhbmd1YWdlOiAnY3NoYXJwJywgZGlzcGxheU5hbWU6ICdDIycsIG5hdGl2ZTogZmFsc2UsIHJlcXVpcmVzSmF2YTogdHJ1ZSwgZ2VuZXJhdG9yTmFtZTogJ2NzaGFycCcgfSxcbiAgeyBsYW5ndWFnZTogJ3J1YnknLCBkaXNwbGF5TmFtZTogJ1J1YnknLCBuYXRpdmU6IGZhbHNlLCByZXF1aXJlc0phdmE6IHRydWUsIGdlbmVyYXRvck5hbWU6ICdydWJ5JyB9LFxuICB7IGxhbmd1YWdlOiAncGhwJywgZGlzcGxheU5hbWU6ICdQSFAnLCBuYXRpdmU6IGZhbHNlLCByZXF1aXJlc0phdmE6IHRydWUsIGdlbmVyYXRvck5hbWU6ICdwaHAnIH0sXG4gIHsgbGFuZ3VhZ2U6ICdzd2lmdCcsIGRpc3BsYXlOYW1lOiAnU3dpZnQnLCBuYXRpdmU6IGZhbHNlLCByZXF1aXJlc0phdmE6IHRydWUsIGdlbmVyYXRvck5hbWU6ICdzd2lmdDUnIH0sXG4gIHsgbGFuZ3VhZ2U6ICdrb3RsaW4nLCBkaXNwbGF5TmFtZTogJ0tvdGxpbicsIG5hdGl2ZTogZmFsc2UsIHJlcXVpcmVzSmF2YTogdHJ1ZSwgZ2VuZXJhdG9yTmFtZTogJ2tvdGxpbicgfSxcbiAgeyBsYW5ndWFnZTogJ3J1c3QnLCBkaXNwbGF5TmFtZTogJ1J1c3QnLCBuYXRpdmU6IGZhbHNlLCByZXF1aXJlc0phdmE6IHRydWUsIGdlbmVyYXRvck5hbWU6ICdydXN0JyB9LFxuXTtcblxuY29uc3QgQ09ORklHX0ZJTEVOQU1FID0gJ3Nkay5qc29uJztcblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gQ29uZmlndXJhdGlvbiBGdW5jdGlvbnNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBMb2FkIFNESyBjb25maWd1cmF0aW9uIGZyb20gcHJvamVjdCBkaXJlY3RvcnlcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxvYWRTREtDb25maWcoXG4gIHByb2plY3RSb290OiBzdHJpbmdcbik6IFByb21pc2U8eyBjb25maWc6IFNES0NvbmZpZyB8IG51bGw7IGVycm9yPzogc3RyaW5nIH0+IHtcbiAgY29uc3QgY29uZmlnUGF0aCA9IHBhdGguam9pbihwcm9qZWN0Um9vdCwgQ09ORklHX0ZJTEVOQU1FKTtcblxuICBpZiAoIShhd2FpdCBmcy5wYXRoRXhpc3RzKGNvbmZpZ1BhdGgpKSkge1xuICAgIHJldHVybiB7IGNvbmZpZzogbnVsbCwgZXJyb3I6IGAke0NPTkZJR19GSUxFTkFNRX0gbm90IGZvdW5kYCB9O1xuICB9XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBjb25maWcgPSBhd2FpdCBmcy5yZWFkSnNvbihjb25maWdQYXRoKTtcbiAgICByZXR1cm4geyBjb25maWcgfTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4ge1xuICAgICAgY29uZmlnOiBudWxsLFxuICAgICAgZXJyb3I6IGBGYWlsZWQgdG8gcGFyc2UgJHtDT05GSUdfRklMRU5BTUV9OiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gLFxuICAgIH07XG4gIH1cbn1cblxuLyoqXG4gKiBJbml0aWFsaXplIFNESyBjb25maWd1cmF0aW9uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbml0U0RLQ29uZmlnKFxuICBwcm9qZWN0Um9vdDogc3RyaW5nLFxuICBvcHRpb25zOiBJbml0Q29uZmlnT3B0aW9uc1xuKTogUHJvbWlzZTx7IGNvbmZpZ1BhdGg6IHN0cmluZzsgY29uZmlnOiBTREtDb25maWcgfT4ge1xuICBjb25zdCBjb25maWdQYXRoID0gcGF0aC5qb2luKHByb2plY3RSb290LCBDT05GSUdfRklMRU5BTUUpO1xuXG4gIC8vIENoZWNrIGlmIGNvbmZpZyBhbHJlYWR5IGV4aXN0c1xuICBpZiAoKGF3YWl0IGZzLnBhdGhFeGlzdHMoY29uZmlnUGF0aCkpICYmICFvcHRpb25zLmZvcmNlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGAke0NPTkZJR19GSUxFTkFNRX0gYWxyZWFkeSBleGlzdHMuIFVzZSAtLWZvcmNlIHRvIG92ZXJ3cml0ZS5gKTtcbiAgfVxuXG4gIC8vIENyZWF0ZSBsYW5ndWFnZSBjb25maWd1cmF0aW9uc1xuICBjb25zdCBsYW5ndWFnZXM6IFNES0NvbmZpZ1snbGFuZ3VhZ2VzJ10gPSB7fTtcbiAgZm9yIChjb25zdCBsYW5nIG9mIG9wdGlvbnMubGFuZ3VhZ2VzKSB7XG4gICAgbGFuZ3VhZ2VzW2xhbmddID0ge1xuICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgIHBhY2thZ2VOYW1lOiBnZXREZWZhdWx0UGFja2FnZU5hbWUob3B0aW9ucy5wYWNrYWdlTmFtZSwgbGFuZyksXG4gICAgfTtcbiAgfVxuXG4gIGNvbnN0IGNvbmZpZzogU0RLQ29uZmlnID0ge1xuICAgIG9wZW5hcGk6IG9wdGlvbnMub3BlbmFwaSxcbiAgICBwYWNrYWdlTmFtZTogb3B0aW9ucy5wYWNrYWdlTmFtZSxcbiAgICBvdXRwdXQ6ICcuL3Nka3MnLFxuICAgIGxhbmd1YWdlcyxcbiAgfTtcblxuICBhd2FpdCBmcy53cml0ZUpzb24oY29uZmlnUGF0aCwgY29uZmlnLCB7IHNwYWNlczogMiB9KTtcblxuICByZXR1cm4geyBjb25maWdQYXRoLCBjb25maWcgfTtcbn1cblxuLyoqXG4gKiBHZXQgZW5hYmxlZCBnZW5lcmF0b3JzIGZyb20gY29uZmlnXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRFbmFibGVkR2VuZXJhdG9ycyhjb25maWc6IFNES0NvbmZpZyk6IFNES0xhbmd1YWdlW10ge1xuICByZXR1cm4gT2JqZWN0LmVudHJpZXMoY29uZmlnLmxhbmd1YWdlcylcbiAgICAuZmlsdGVyKChbLCBsYW5nQ29uZmlnXSkgPT4gbGFuZ0NvbmZpZz8uZW5hYmxlZClcbiAgICAubWFwKChbbGFuZ10pID0+IGxhbmcgYXMgU0RLTGFuZ3VhZ2UpO1xufVxuXG4vKipcbiAqIEdldCBnZW5lcmF0b3IgaW5mb3JtYXRpb24gZm9yIGFsbCBsYW5ndWFnZXNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEdlbmVyYXRvckluZm8oKTogR2VuZXJhdG9ySW5mb1tdIHtcbiAgcmV0dXJuIFsuLi5HRU5FUkFUT1JTXTtcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBhIGdlbmVyYXRvciBpcyBuYXRpdmUgKGRvZXNuJ3QgcmVxdWlyZSBKYXZhKVxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNOYXRpdmVHZW5lcmF0b3IobGFuZ3VhZ2U6IFNES0xhbmd1YWdlKTogYm9vbGVhbiB7XG4gIGNvbnN0IGdlbmVyYXRvciA9IEdFTkVSQVRPUlMuZmluZCgoZykgPT4gZy5sYW5ndWFnZSA9PT0gbGFuZ3VhZ2UpO1xuICByZXR1cm4gZ2VuZXJhdG9yPy5uYXRpdmUgPz8gZmFsc2U7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIFBhdGggVXRpbGl0aWVzXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogUmVzb2x2ZSBPcGVuQVBJIHNwZWMgcGF0aCByZWxhdGl2ZSB0byBwcm9qZWN0IHJvb3RcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVTcGVjUGF0aChwcm9qZWN0Um9vdDogc3RyaW5nLCBzcGVjUGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgaWYgKHBhdGguaXNBYnNvbHV0ZShzcGVjUGF0aCkpIHtcbiAgICByZXR1cm4gc3BlY1BhdGg7XG4gIH1cbiAgcmV0dXJuIHBhdGgucmVzb2x2ZShwcm9qZWN0Um9vdCwgc3BlY1BhdGgpO1xufVxuXG4vKipcbiAqIEdldCBkZWZhdWx0IHBhY2thZ2UgbmFtZSBmb3IgYSBsYW5ndWFnZVxuICovXG5mdW5jdGlvbiBnZXREZWZhdWx0UGFja2FnZU5hbWUoYmFzZU5hbWU6IHN0cmluZywgbGFuZ3VhZ2U6IFNES0xhbmd1YWdlKTogc3RyaW5nIHtcbiAgY29uc3Qgc2FuaXRpemVkID0gYmFzZU5hbWUudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9bXmEtejAtOV0vZywgJy0nKTtcblxuICBzd2l0Y2ggKGxhbmd1YWdlKSB7XG4gICAgY2FzZSAndHlwZXNjcmlwdCc6XG4gICAgICByZXR1cm4gYEAke3Nhbml0aXplZH0vc2RrYDtcbiAgICBjYXNlICdweXRob24nOlxuICAgICAgcmV0dXJuIHNhbml0aXplZC5yZXBsYWNlKC8tL2csICdfJyk7XG4gICAgY2FzZSAnZ28nOlxuICAgICAgcmV0dXJuIHNhbml0aXplZDtcbiAgICBjYXNlICdqYXZhJzpcbiAgICAgIHJldHVybiBgY29tLiR7c2FuaXRpemVkLnJlcGxhY2UoLy0vZywgJy4nKX1gO1xuICAgIGNhc2UgJ2NzaGFycCc6XG4gICAgICByZXR1cm4gc2FuaXRpemVkLnNwbGl0KCctJykubWFwKGNhcGl0YWxpemUpLmpvaW4oJy4nKTtcbiAgICBjYXNlICdydWJ5JzpcbiAgICAgIHJldHVybiBzYW5pdGl6ZWQucmVwbGFjZSgvLS9nLCAnXycpO1xuICAgIGNhc2UgJ3BocCc6XG4gICAgICByZXR1cm4gc2FuaXRpemVkLnNwbGl0KCctJykubWFwKGNhcGl0YWxpemUpLmpvaW4oJ1xcXFwnKTtcbiAgICBjYXNlICdzd2lmdCc6XG4gICAgICByZXR1cm4gc2FuaXRpemVkLnNwbGl0KCctJykubWFwKGNhcGl0YWxpemUpLmpvaW4oJycpO1xuICAgIGNhc2UgJ2tvdGxpbic6XG4gICAgICByZXR1cm4gYGNvbS4ke3Nhbml0aXplZC5yZXBsYWNlKC8tL2csICcuJyl9YDtcbiAgICBjYXNlICdydXN0JzpcbiAgICAgIHJldHVybiBzYW5pdGl6ZWQucmVwbGFjZSgvLS9nLCAnXycpO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gc2FuaXRpemVkO1xuICB9XG59XG5cbmZ1bmN0aW9uIGNhcGl0YWxpemUoc3RyOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gc3RyLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgc3RyLnNsaWNlKDEpO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBWYWxpZGF0aW9uXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogVmFsaWRhdGUgYW4gT3BlbkFQSSBzcGVjaWZpY2F0aW9uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB2YWxpZGF0ZVNwZWMoc3BlY1BhdGg6IHN0cmluZyk6IFByb21pc2U8VmFsaWRhdGlvblJlc3VsdD4ge1xuICBjb25zdCBlcnJvcnM6IHN0cmluZ1tdID0gW107XG4gIGNvbnN0IHdhcm5pbmdzOiBzdHJpbmdbXSA9IFtdO1xuXG4gIC8vIENoZWNrIGZpbGUgZXhpc3RzXG4gIGlmICghKGF3YWl0IGZzLnBhdGhFeGlzdHMoc3BlY1BhdGgpKSkge1xuICAgIHJldHVybiB7XG4gICAgICB2YWxpZDogZmFsc2UsXG4gICAgICBlcnJvcnM6IFtgT3BlbkFQSSBzcGVjaWZpY2F0aW9uIG5vdCBmb3VuZDogJHtzcGVjUGF0aH1gXSxcbiAgICAgIHdhcm5pbmdzOiBbXSxcbiAgICB9O1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBSZWFkIGFuZCBwYXJzZSB0aGUgc3BlY1xuICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZShzcGVjUGF0aCwgJ3V0Zi04Jyk7XG4gICAgbGV0IHNwZWM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuXG4gICAgaWYgKHNwZWNQYXRoLmVuZHNXaXRoKCcueWFtbCcpIHx8IHNwZWNQYXRoLmVuZHNXaXRoKCcueW1sJykpIHtcbiAgICAgIGNvbnN0IHlhbWwgPSBhd2FpdCBpbXBvcnQoJ2pzLXlhbWwnKTtcbiAgICAgIHNwZWMgPSB5YW1sLmxvYWQoY29udGVudCkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgfSBlbHNlIHtcbiAgICAgIHNwZWMgPSBKU09OLnBhcnNlKGNvbnRlbnQpO1xuICAgIH1cblxuICAgIC8vIEJhc2ljIHZhbGlkYXRpb25cbiAgICBpZiAoIXNwZWMub3BlbmFwaSAmJiAhc3BlYy5zd2FnZ2VyKSB7XG4gICAgICBlcnJvcnMucHVzaCgnTWlzc2luZyBcIm9wZW5hcGlcIiBvciBcInN3YWdnZXJcIiB2ZXJzaW9uIGZpZWxkJyk7XG4gICAgfVxuXG4gICAgaWYgKCFzcGVjLmluZm8pIHtcbiAgICAgIGVycm9ycy5wdXNoKCdNaXNzaW5nIFwiaW5mb1wiIHNlY3Rpb24nKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgaW5mbyA9IHNwZWMuaW5mbyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICAgIGlmICghaW5mby50aXRsZSkge1xuICAgICAgICB3YXJuaW5ncy5wdXNoKCdNaXNzaW5nIFwiaW5mby50aXRsZVwiJyk7XG4gICAgICB9XG4gICAgICBpZiAoIWluZm8udmVyc2lvbikge1xuICAgICAgICB3YXJuaW5ncy5wdXNoKCdNaXNzaW5nIFwiaW5mby52ZXJzaW9uXCInKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoIXNwZWMucGF0aHMgfHwgT2JqZWN0LmtleXMoc3BlYy5wYXRocyBhcyBvYmplY3QpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgd2FybmluZ3MucHVzaCgnTm8gcGF0aHMgZGVmaW5lZCBpbiBzcGVjaWZpY2F0aW9uJyk7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgZm9yIGNvbW1vbiBpc3N1ZXNcbiAgICBjb25zdCBvcGVuYXBpVmVyc2lvbiA9IHNwZWMub3BlbmFwaSBhcyBzdHJpbmc7XG4gICAgaWYgKG9wZW5hcGlWZXJzaW9uICYmICFvcGVuYXBpVmVyc2lvbi5zdGFydHNXaXRoKCczLicpKSB7XG4gICAgICB3YXJuaW5ncy5wdXNoKGBPcGVuQVBJICR7b3BlbmFwaVZlcnNpb259IGRldGVjdGVkLiBWZXJzaW9uIDMueCBpcyByZWNvbW1lbmRlZC5gKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgdmFsaWQ6IGVycm9ycy5sZW5ndGggPT09IDAsXG4gICAgICBlcnJvcnMsXG4gICAgICB3YXJuaW5ncyxcbiAgICB9O1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHJldHVybiB7XG4gICAgICB2YWxpZDogZmFsc2UsXG4gICAgICBlcnJvcnM6IFtgRmFpbGVkIHRvIHBhcnNlIHNwZWNpZmljYXRpb246ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWBdLFxuICAgICAgd2FybmluZ3M6IFtdLFxuICAgIH07XG4gIH1cbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gU0RLIEdlbmVyYXRpb25cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBHZW5lcmF0ZSBTREtzIGZvciBjb25maWd1cmVkIGxhbmd1YWdlc1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2VuZXJhdGVTREtzKFxuICBwcm9qZWN0Um9vdDogc3RyaW5nLFxuICBvcHRpb25zOiBHZW5lcmF0ZU9wdGlvbnMgPSB7fVxuKTogUHJvbWlzZTxHZW5lcmF0ZVNES3NSZXN1bHQ+IHtcbiAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgY29uc3QgcmVzdWx0czogU0RLR2VuZXJhdGlvblJlc3VsdFtdID0gW107XG5cbiAgLy8gTG9hZCBjb25maWdcbiAgY29uc3QgeyBjb25maWcsIGVycm9yIH0gPSBhd2FpdCBsb2FkU0RLQ29uZmlnKHByb2plY3RSb290KTtcbiAgaWYgKCFjb25maWcpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoZXJyb3IgfHwgJ1NESyBjb25maWd1cmF0aW9uIG5vdCBmb3VuZCcpO1xuICB9XG5cbiAgLy8gRGV0ZXJtaW5lIHdoaWNoIGxhbmd1YWdlcyB0byBnZW5lcmF0ZVxuICBsZXQgbGFuZ3VhZ2VzVG9HZW5lcmF0ZSA9IGdldEVuYWJsZWRHZW5lcmF0b3JzKGNvbmZpZyk7XG5cbiAgaWYgKG9wdGlvbnMubGFuZ3VhZ2UpIHtcbiAgICBpZiAoIWxhbmd1YWdlc1RvR2VuZXJhdGUuaW5jbHVkZXMob3B0aW9ucy5sYW5ndWFnZSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgTGFuZ3VhZ2UgXCIke29wdGlvbnMubGFuZ3VhZ2V9XCIgaXMgbm90IGVuYWJsZWQgaW4gc2RrLmpzb25gKTtcbiAgICB9XG4gICAgbGFuZ3VhZ2VzVG9HZW5lcmF0ZSA9IFtvcHRpb25zLmxhbmd1YWdlXTtcbiAgfVxuXG4gIC8vIFJlc29sdmUgc3BlYyBwYXRoXG4gIGNvbnN0IHNwZWNQYXRoID0gcmVzb2x2ZVNwZWNQYXRoKHByb2plY3RSb290LCBjb25maWcub3BlbmFwaSk7XG5cbiAgLy8gVmFsaWRhdGUgc3BlYyBleGlzdHNcbiAgaWYgKCEoYXdhaXQgZnMucGF0aEV4aXN0cyhzcGVjUGF0aCkpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBPcGVuQVBJIHNwZWNpZmljYXRpb24gbm90IGZvdW5kOiAke2NvbmZpZy5vcGVuYXBpfWApO1xuICB9XG5cbiAgLy8gQmFzZSBvdXRwdXQgZGlyZWN0b3J5XG4gIGNvbnN0IGJhc2VPdXRwdXREaXIgPSBvcHRpb25zLm91dHB1dERpclxuICAgID8gcGF0aC5yZXNvbHZlKHByb2plY3RSb290LCBvcHRpb25zLm91dHB1dERpcilcbiAgICA6IHBhdGgucmVzb2x2ZShwcm9qZWN0Um9vdCwgY29uZmlnLm91dHB1dCk7XG5cbiAgLy8gR2VuZXJhdGUgU0RLcyBmb3IgZWFjaCBsYW5ndWFnZVxuICBmb3IgKGNvbnN0IGxhbmd1YWdlIG9mIGxhbmd1YWdlc1RvR2VuZXJhdGUpIHtcbiAgICBjb25zdCBsYW5nU3RhcnQgPSBEYXRlLm5vdygpO1xuICAgIGNvbnN0IGxhbmdDb25maWcgPSBjb25maWcubGFuZ3VhZ2VzW2xhbmd1YWdlXTtcbiAgICBjb25zdCBvdXRwdXRQYXRoID0gbGFuZ0NvbmZpZz8ub3V0cHV0XG4gICAgICA/IHBhdGgucmVzb2x2ZShwcm9qZWN0Um9vdCwgbGFuZ0NvbmZpZy5vdXRwdXQpXG4gICAgICA6IHBhdGguam9pbihiYXNlT3V0cHV0RGlyLCBsYW5ndWFnZSk7XG5cbiAgICB0cnkge1xuICAgICAgaWYgKG9wdGlvbnMucHJldmlldykge1xuICAgICAgICAvLyBQcmV2aWV3IG1vZGUgLSBqdXN0IHJlcG9ydCB3aGF0IHdvdWxkIGJlIGdlbmVyYXRlZFxuICAgICAgICByZXN1bHRzLnB1c2goe1xuICAgICAgICAgIGxhbmd1YWdlLFxuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgb3V0cHV0UGF0aCxcbiAgICAgICAgICBkdXJhdGlvbjogRGF0ZS5ub3coKSAtIGxhbmdTdGFydCxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICAvLyBFbnN1cmUgb3V0cHV0IGRpcmVjdG9yeSBleGlzdHNcbiAgICAgIGF3YWl0IGZzLmVuc3VyZURpcihvdXRwdXRQYXRoKTtcblxuICAgICAgLy8gR2VuZXJhdGUgU0RLIGJhc2VkIG9uIGdlbmVyYXRvciB0eXBlXG4gICAgICBjb25zdCBnZW5lcmF0b3IgPSBHRU5FUkFUT1JTLmZpbmQoKGcpID0+IGcubGFuZ3VhZ2UgPT09IGxhbmd1YWdlKTtcblxuICAgICAgaWYgKGdlbmVyYXRvcj8ubmF0aXZlKSB7XG4gICAgICAgIGF3YWl0IGdlbmVyYXRlTmF0aXZlU0RLKGxhbmd1YWdlLCBzcGVjUGF0aCwgb3V0cHV0UGF0aCwgY29uZmlnLCBsYW5nQ29uZmlnKTtcbiAgICAgIH0gZWxzZSBpZiAoZ2VuZXJhdG9yPy5nZW5lcmF0b3JOYW1lKSB7XG4gICAgICAgIGF3YWl0IGdlbmVyYXRlT3BlbkFQSUdlbmVyYXRvclNESyhnZW5lcmF0b3IuZ2VuZXJhdG9yTmFtZSwgc3BlY1BhdGgsIG91dHB1dFBhdGgsIGNvbmZpZywgbGFuZ0NvbmZpZyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGdlbmVyYXRvciBmb3VuZCBmb3IgJHtsYW5ndWFnZX1gKTtcbiAgICAgIH1cblxuICAgICAgcmVzdWx0cy5wdXNoKHtcbiAgICAgICAgbGFuZ3VhZ2UsXG4gICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgIG91dHB1dFBhdGgsXG4gICAgICAgIGR1cmF0aW9uOiBEYXRlLm5vdygpIC0gbGFuZ1N0YXJ0LFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICByZXN1bHRzLnB1c2goe1xuICAgICAgICBsYW5ndWFnZSxcbiAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgIG91dHB1dFBhdGgsXG4gICAgICAgIGVycm9yOiBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVyciksXG4gICAgICAgIGR1cmF0aW9uOiBEYXRlLm5vdygpIC0gbGFuZ1N0YXJ0LFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICByZXN1bHRzLFxuICAgIHN1Y2Nlc3NDb3VudDogcmVzdWx0cy5maWx0ZXIoKHIpID0+IHIuc3VjY2VzcykubGVuZ3RoLFxuICAgIGZhaWx1cmVDb3VudDogcmVzdWx0cy5maWx0ZXIoKHIpID0+ICFyLnN1Y2Nlc3MpLmxlbmd0aCxcbiAgICB0b3RhbER1cmF0aW9uOiBEYXRlLm5vdygpIC0gc3RhcnRUaW1lLFxuICB9O1xufVxuXG4vKipcbiAqIEdlbmVyYXRlIFNESyB1c2luZyBuYXRpdmUgZ2VuZXJhdG9yIChUeXBlU2NyaXB0LCBQeXRob24sIEdvKVxuICovXG5hc3luYyBmdW5jdGlvbiBnZW5lcmF0ZU5hdGl2ZVNESyhcbiAgbGFuZ3VhZ2U6IFNES0xhbmd1YWdlLFxuICBzcGVjUGF0aDogc3RyaW5nLFxuICBvdXRwdXRQYXRoOiBzdHJpbmcsXG4gIGNvbmZpZzogU0RLQ29uZmlnLFxuICBsYW5nQ29uZmlnPzogTGFuZ3VhZ2VDb25maWdcbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBwYWNrYWdlTmFtZSA9IGxhbmdDb25maWc/LnBhY2thZ2VOYW1lIHx8IGdldERlZmF1bHRQYWNrYWdlTmFtZShjb25maWcucGFja2FnZU5hbWUsIGxhbmd1YWdlKTtcblxuICBzd2l0Y2ggKGxhbmd1YWdlKSB7XG4gICAgY2FzZSAndHlwZXNjcmlwdCc6XG4gICAgICBhd2FpdCBnZW5lcmF0ZVR5cGVTY3JpcHRTREsoc3BlY1BhdGgsIG91dHB1dFBhdGgsIHBhY2thZ2VOYW1lKTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgJ3B5dGhvbic6XG4gICAgICBhd2FpdCBnZW5lcmF0ZVB5dGhvblNESyhzcGVjUGF0aCwgb3V0cHV0UGF0aCwgcGFja2FnZU5hbWUpO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSAnZ28nOlxuICAgICAgYXdhaXQgZ2VuZXJhdGVHb1NESyhzcGVjUGF0aCwgb3V0cHV0UGF0aCwgcGFja2FnZU5hbWUpO1xuICAgICAgYnJlYWs7XG4gICAgZGVmYXVsdDpcbiAgICAgIHRocm93IG5ldyBFcnJvcihgTmF0aXZlIGdlbmVyYXRvciBub3QgaW1wbGVtZW50ZWQgZm9yICR7bGFuZ3VhZ2V9YCk7XG4gIH1cbn1cblxuLyoqXG4gKiBHZW5lcmF0ZSBTREsgdXNpbmcgT3BlbkFQSSBHZW5lcmF0b3IgKEphdmEtYmFzZWQpXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGdlbmVyYXRlT3BlbkFQSUdlbmVyYXRvclNESyhcbiAgZ2VuZXJhdG9yTmFtZTogc3RyaW5nLFxuICBzcGVjUGF0aDogc3RyaW5nLFxuICBvdXRwdXRQYXRoOiBzdHJpbmcsXG4gIGNvbmZpZzogU0RLQ29uZmlnLFxuICBsYW5nQ29uZmlnPzogTGFuZ3VhZ2VDb25maWdcbik6IFByb21pc2U8dm9pZD4ge1xuICAvLyBDaGVjayBpZiBKYXZhIGlzIGF2YWlsYWJsZVxuICB0cnkge1xuICAgIGF3YWl0IGV4ZWNBc3luYygnamF2YSAtdmVyc2lvbicpO1xuICB9IGNhdGNoIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0phdmEgaXMgcmVxdWlyZWQgZm9yIHRoaXMgZ2VuZXJhdG9yLiBQbGVhc2UgaW5zdGFsbCBKYXZhIDExIG9yIGxhdGVyLicpO1xuICB9XG5cbiAgLy8gQ2hlY2sgaWYgb3BlbmFwaS1nZW5lcmF0b3IgaXMgYXZhaWxhYmxlXG4gIGxldCBnZW5lcmF0b3JDbWQgPSAnb3BlbmFwaS1nZW5lcmF0b3InO1xuICB0cnkge1xuICAgIGF3YWl0IGV4ZWNBc3luYygnb3BlbmFwaS1nZW5lcmF0b3IgdmVyc2lvbicpO1xuICB9IGNhdGNoIHtcbiAgICAvLyBUcnkgbnB4IGZhbGxiYWNrXG4gICAgZ2VuZXJhdG9yQ21kID0gJ25weCBAb3BlbmFwaXRvb2xzL29wZW5hcGktZ2VuZXJhdG9yLWNsaSc7XG4gIH1cblxuICBjb25zdCBhZGRpdGlvbmFsUHJvcHMgPSBsYW5nQ29uZmlnPy5hZGRpdGlvbmFsT3B0aW9uc1xuICAgID8gT2JqZWN0LmVudHJpZXMobGFuZ0NvbmZpZy5hZGRpdGlvbmFsT3B0aW9ucylcbiAgICAgICAgLm1hcCgoW2ssIHZdKSA9PiBgJHtrfT0ke3Z9YClcbiAgICAgICAgLmpvaW4oJywnKVxuICAgIDogJyc7XG5cbiAgY29uc3QgY21kID0gW1xuICAgIGdlbmVyYXRvckNtZCxcbiAgICAnZ2VuZXJhdGUnLFxuICAgICctaScsXG4gICAgc3BlY1BhdGgsXG4gICAgJy1nJyxcbiAgICBnZW5lcmF0b3JOYW1lLFxuICAgICctbycsXG4gICAgb3V0cHV0UGF0aCxcbiAgICBhZGRpdGlvbmFsUHJvcHMgPyBgLS1hZGRpdGlvbmFsLXByb3BlcnRpZXM9JHthZGRpdGlvbmFsUHJvcHN9YCA6ICcnLFxuICBdXG4gICAgLmZpbHRlcihCb29sZWFuKVxuICAgIC5qb2luKCcgJyk7XG5cbiAgYXdhaXQgZXhlY0FzeW5jKGNtZCk7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIE5hdGl2ZSBHZW5lcmF0b3IgSW1wbGVtZW50YXRpb25zXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogR2VuZXJhdGUgVHlwZVNjcmlwdCBTREtcbiAqL1xuYXN5bmMgZnVuY3Rpb24gZ2VuZXJhdGVUeXBlU2NyaXB0U0RLKFxuICBzcGVjUGF0aDogc3RyaW5nLFxuICBvdXRwdXRQYXRoOiBzdHJpbmcsXG4gIHBhY2thZ2VOYW1lOiBzdHJpbmdcbik6IFByb21pc2U8dm9pZD4ge1xuICAvLyBSZWFkIHRoZSBPcGVuQVBJIHNwZWNcbiAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKHNwZWNQYXRoLCAndXRmLTgnKTtcbiAgbGV0IHNwZWM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuXG4gIGlmIChzcGVjUGF0aC5lbmRzV2l0aCgnLnlhbWwnKSB8fCBzcGVjUGF0aC5lbmRzV2l0aCgnLnltbCcpKSB7XG4gICAgY29uc3QgeWFtbCA9IGF3YWl0IGltcG9ydCgnanMteWFtbCcpO1xuICAgIHNwZWMgPSB5YW1sLmxvYWQoY29udGVudCkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIH0gZWxzZSB7XG4gICAgc3BlYyA9IEpTT04ucGFyc2UoY29udGVudCk7XG4gIH1cblxuICBjb25zdCBpbmZvID0gKHNwZWMuaW5mbyB8fCB7fSkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIGNvbnN0IHBhdGhzID0gKHNwZWMucGF0aHMgfHwge30pIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuXG4gIC8vIEdlbmVyYXRlIHBhY2thZ2UuanNvblxuICBjb25zdCBwYWNrYWdlSnNvbiA9IHtcbiAgICBuYW1lOiBwYWNrYWdlTmFtZSxcbiAgICB2ZXJzaW9uOiAoaW5mby52ZXJzaW9uIGFzIHN0cmluZykgfHwgJzEuMC4wJyxcbiAgICBkZXNjcmlwdGlvbjogKGluZm8uZGVzY3JpcHRpb24gYXMgc3RyaW5nKSB8fCAnR2VuZXJhdGVkIFNESycsXG4gICAgbWFpbjogJ2Rpc3QvaW5kZXguanMnLFxuICAgIHR5cGVzOiAnZGlzdC9pbmRleC5kLnRzJyxcbiAgICBzY3JpcHRzOiB7XG4gICAgICBidWlsZDogJ3RzYycsXG4gICAgICBwcmVwdWJsaXNoT25seTogJ25wbSBydW4gYnVpbGQnLFxuICAgIH0sXG4gICAgZGV2RGVwZW5kZW5jaWVzOiB7XG4gICAgICB0eXBlc2NyaXB0OiAnXjUuMC4wJyxcbiAgICAgICdAdHlwZXMvbm9kZSc6ICdeMjAuMC4wJyxcbiAgICB9LFxuICB9O1xuXG4gIGF3YWl0IGZzLndyaXRlSnNvbihwYXRoLmpvaW4ob3V0cHV0UGF0aCwgJ3BhY2thZ2UuanNvbicpLCBwYWNrYWdlSnNvbiwgeyBzcGFjZXM6IDIgfSk7XG5cbiAgLy8gR2VuZXJhdGUgdHNjb25maWcuanNvblxuICBjb25zdCB0c0NvbmZpZyA9IHtcbiAgICBjb21waWxlck9wdGlvbnM6IHtcbiAgICAgIHRhcmdldDogJ0VTMjAyMCcsXG4gICAgICBtb2R1bGU6ICdjb21tb25qcycsXG4gICAgICBkZWNsYXJhdGlvbjogdHJ1ZSxcbiAgICAgIG91dERpcjogJy4vZGlzdCcsXG4gICAgICBzdHJpY3Q6IHRydWUsXG4gICAgICBlc01vZHVsZUludGVyb3A6IHRydWUsXG4gICAgICBza2lwTGliQ2hlY2s6IHRydWUsXG4gICAgICBmb3JjZUNvbnNpc3RlbnRDYXNpbmdJbkZpbGVOYW1lczogdHJ1ZSxcbiAgICB9LFxuICAgIGluY2x1ZGU6IFsnc3JjLyoqLyonXSxcbiAgICBleGNsdWRlOiBbJ25vZGVfbW9kdWxlcycsICdkaXN0J10sXG4gIH07XG5cbiAgYXdhaXQgZnMud3JpdGVKc29uKHBhdGguam9pbihvdXRwdXRQYXRoLCAndHNjb25maWcuanNvbicpLCB0c0NvbmZpZywgeyBzcGFjZXM6IDIgfSk7XG5cbiAgLy8gR2VuZXJhdGUgc291cmNlIGZpbGVzXG4gIGF3YWl0IGZzLmVuc3VyZURpcihwYXRoLmpvaW4ob3V0cHV0UGF0aCwgJ3NyYycpKTtcblxuICAvLyBHZW5lcmF0ZSB0eXBlc1xuICBjb25zdCB0eXBlc0NvbnRlbnQgPSBnZW5lcmF0ZVR5cGVTY3JpcHRUeXBlcyhzcGVjKTtcbiAgYXdhaXQgZnMud3JpdGVGaWxlKHBhdGguam9pbihvdXRwdXRQYXRoLCAnc3JjJywgJ3R5cGVzLnRzJyksIHR5cGVzQ29udGVudCk7XG5cbiAgLy8gR2VuZXJhdGUgY2xpZW50XG4gIGNvbnN0IGNsaWVudENvbnRlbnQgPSBnZW5lcmF0ZVR5cGVTY3JpcHRDbGllbnQoc3BlYywgcGF0aHMpO1xuICBhd2FpdCBmcy53cml0ZUZpbGUocGF0aC5qb2luKG91dHB1dFBhdGgsICdzcmMnLCAnY2xpZW50LnRzJyksIGNsaWVudENvbnRlbnQpO1xuXG4gIC8vIEdlbmVyYXRlIGluZGV4XG4gIGNvbnN0IGluZGV4Q29udGVudCA9IGBleHBvcnQgKiBmcm9tICcuL3R5cGVzJztcXG5leHBvcnQgKiBmcm9tICcuL2NsaWVudCc7XFxuYDtcbiAgYXdhaXQgZnMud3JpdGVGaWxlKHBhdGguam9pbihvdXRwdXRQYXRoLCAnc3JjJywgJ2luZGV4LnRzJyksIGluZGV4Q29udGVudCk7XG5cbiAgLy8gR2VuZXJhdGUgUkVBRE1FXG4gIGNvbnN0IHJlYWRtZUNvbnRlbnQgPSBgIyAke3BhY2thZ2VOYW1lfVxuXG5HZW5lcmF0ZWQgVHlwZVNjcmlwdCBTREsgZm9yICR7KGluZm8udGl0bGUgYXMgc3RyaW5nKSB8fCAnQVBJJ30uXG5cbiMjIEluc3RhbGxhdGlvblxuXG5cXGBcXGBcXGBiYXNoXG5ucG0gaW5zdGFsbCAke3BhY2thZ2VOYW1lfVxuXFxgXFxgXFxgXG5cbiMjIFVzYWdlXG5cblxcYFxcYFxcYHR5cGVzY3JpcHRcbmltcG9ydCB7IEFwaUNsaWVudCB9IGZyb20gJyR7cGFja2FnZU5hbWV9JztcblxuY29uc3QgY2xpZW50ID0gbmV3IEFwaUNsaWVudCh7XG4gIGJhc2VVcmw6ICdodHRwczovL2FwaS5leGFtcGxlLmNvbScsXG4gIC8vIGFwaUtleTogJ3lvdXItYXBpLWtleScsXG59KTtcblxcYFxcYFxcYFxuYDtcblxuICBhd2FpdCBmcy53cml0ZUZpbGUocGF0aC5qb2luKG91dHB1dFBhdGgsICdSRUFETUUubWQnKSwgcmVhZG1lQ29udGVudCk7XG59XG5cbmZ1bmN0aW9uIGdlbmVyYXRlVHlwZVNjcmlwdFR5cGVzKHNwZWM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogc3RyaW5nIHtcbiAgbGV0IGNvbnRlbnQgPSAnLyoqXFxuICogR2VuZXJhdGVkIHR5cGVzIGZyb20gT3BlbkFQSSBzcGVjaWZpY2F0aW9uXFxuICovXFxuXFxuJztcblxuICBjb25zdCBzY2hlbWFzID0gKChzcGVjLmNvbXBvbmVudHMgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pPy5zY2hlbWFzIHx8IHt9KSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcblxuICAvLyBJZiBubyBzY2hlbWFzLCBleHBvcnQgYSBwbGFjZWhvbGRlciB0byBtYWtlIHRoaXMgYSB2YWxpZCBtb2R1bGVcbiAgaWYgKE9iamVjdC5rZXlzKHNjaGVtYXMpLmxlbmd0aCA9PT0gMCkge1xuICAgIGNvbnRlbnQgKz0gJy8vIE5vIHNjaGVtYXMgZGVmaW5lZCBpbiB0aGUgT3BlbkFQSSBzcGVjaWZpY2F0aW9uXFxuJztcbiAgICBjb250ZW50ICs9ICdleHBvcnQgdHlwZSBBcGlSZXNwb25zZTxUPiA9IFQ7XFxuJztcbiAgICBjb250ZW50ICs9ICdleHBvcnQgdHlwZSBBcGlFcnJvciA9IHsgbWVzc2FnZTogc3RyaW5nOyBjb2RlPzogbnVtYmVyIH07XFxuJztcbiAgICByZXR1cm4gY29udGVudDtcbiAgfVxuXG4gIGZvciAoY29uc3QgW25hbWUsIHNjaGVtYV0gb2YgT2JqZWN0LmVudHJpZXMoc2NoZW1hcykpIHtcbiAgICBjb250ZW50ICs9IGBleHBvcnQgaW50ZXJmYWNlICR7bmFtZX0ge1xcbmA7XG4gICAgY29uc3QgcHJvcGVydGllcyA9IChzY2hlbWEgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pLnByb3BlcnRpZXMgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWQ7XG4gICAgY29uc3QgcmVxdWlyZWQgPSAoKHNjaGVtYSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikucmVxdWlyZWQgfHwgW10pIGFzIHN0cmluZ1tdO1xuXG4gICAgaWYgKHByb3BlcnRpZXMpIHtcbiAgICAgIGZvciAoY29uc3QgW3Byb3BOYW1lLCBwcm9wU2NoZW1hXSBvZiBPYmplY3QuZW50cmllcyhwcm9wZXJ0aWVzKSkge1xuICAgICAgICBjb25zdCBpc1JlcXVpcmVkID0gcmVxdWlyZWQuaW5jbHVkZXMocHJvcE5hbWUpO1xuICAgICAgICBjb25zdCB0c1R5cGUgPSBvcGVuQXBpVHlwZVRvVHMocHJvcFNjaGVtYSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik7XG4gICAgICAgIGNvbnRlbnQgKz0gYCAgJHtwcm9wTmFtZX0ke2lzUmVxdWlyZWQgPyAnJyA6ICc/J306ICR7dHNUeXBlfTtcXG5gO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnRlbnQgKz0gJ31cXG5cXG4nO1xuICB9XG5cbiAgcmV0dXJuIGNvbnRlbnQ7XG59XG5cbmZ1bmN0aW9uIG9wZW5BcGlUeXBlVG9UcyhzY2hlbWE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogc3RyaW5nIHtcbiAgY29uc3QgdHlwZSA9IHNjaGVtYS50eXBlIGFzIHN0cmluZztcbiAgY29uc3QgZm9ybWF0ID0gc2NoZW1hLmZvcm1hdCBhcyBzdHJpbmc7XG4gIGNvbnN0IHJlZiA9IHNjaGVtYS4kcmVmIGFzIHN0cmluZztcblxuICBpZiAocmVmKSB7XG4gICAgcmV0dXJuIHJlZi5zcGxpdCgnLycpLnBvcCgpIHx8ICd1bmtub3duJztcbiAgfVxuXG4gIHN3aXRjaCAodHlwZSkge1xuICAgIGNhc2UgJ3N0cmluZyc6XG4gICAgICByZXR1cm4gJ3N0cmluZyc7XG4gICAgY2FzZSAnaW50ZWdlcic6XG4gICAgY2FzZSAnbnVtYmVyJzpcbiAgICAgIHJldHVybiAnbnVtYmVyJztcbiAgICBjYXNlICdib29sZWFuJzpcbiAgICAgIHJldHVybiAnYm9vbGVhbic7XG4gICAgY2FzZSAnYXJyYXknOlxuICAgICAgY29uc3QgaXRlbXMgPSBzY2hlbWEuaXRlbXMgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgICByZXR1cm4gYCR7b3BlbkFwaVR5cGVUb1RzKGl0ZW1zIHx8IHt9KX1bXWA7XG4gICAgY2FzZSAnb2JqZWN0JzpcbiAgICAgIHJldHVybiAnUmVjb3JkPHN0cmluZywgdW5rbm93bj4nO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gJ3Vua25vd24nO1xuICB9XG59XG5cbmZ1bmN0aW9uIGdlbmVyYXRlVHlwZVNjcmlwdENsaWVudChzcGVjOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiwgcGF0aHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogc3RyaW5nIHtcbiAgY29uc3QgaW5mbyA9IChzcGVjLmluZm8gfHwge30pIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBjb25zdCBzZXJ2ZXJzID0gKHNwZWMuc2VydmVycyB8fCBbXSkgYXMgeyB1cmw6IHN0cmluZyB9W107XG4gIGNvbnN0IGRlZmF1bHRCYXNlVXJsID0gc2VydmVyc1swXT8udXJsIHx8ICdodHRwczovL2FwaS5leGFtcGxlLmNvbSc7XG5cbiAgbGV0IGNvbnRlbnQgPSBgLyoqXG4gKiAkeyhpbmZvLnRpdGxlIGFzIHN0cmluZykgfHwgJ0FQSSd9IENsaWVudFxuICogJHsoaW5mby5kZXNjcmlwdGlvbiBhcyBzdHJpbmcpIHx8ICcnfVxuICovXG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2xpZW50Q29uZmlnIHtcbiAgYmFzZVVybD86IHN0cmluZztcbiAgYXBpS2V5Pzogc3RyaW5nO1xuICBoZWFkZXJzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbn1cblxuZXhwb3J0IGNsYXNzIEFwaUNsaWVudCB7XG4gIHByaXZhdGUgYmFzZVVybDogc3RyaW5nO1xuICBwcml2YXRlIGhlYWRlcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG5cbiAgY29uc3RydWN0b3IoY29uZmlnOiBDbGllbnRDb25maWcgPSB7fSkge1xuICAgIHRoaXMuYmFzZVVybCA9IGNvbmZpZy5iYXNlVXJsIHx8ICcke2RlZmF1bHRCYXNlVXJsfSc7XG4gICAgdGhpcy5oZWFkZXJzID0ge1xuICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgIC4uLmNvbmZpZy5oZWFkZXJzLFxuICAgIH07XG5cbiAgICBpZiAoY29uZmlnLmFwaUtleSkge1xuICAgICAgdGhpcy5oZWFkZXJzWydBdXRob3JpemF0aW9uJ10gPSBcXGBCZWFyZXIgXFwke2NvbmZpZy5hcGlLZXl9XFxgO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcmVxdWVzdDxUPihcbiAgICBtZXRob2Q6IHN0cmluZyxcbiAgICBwYXRoOiBzdHJpbmcsXG4gICAgb3B0aW9uczogeyBib2R5PzogdW5rbm93bjsgcXVlcnk/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IH0gPSB7fVxuICApOiBQcm9taXNlPFQ+IHtcbiAgICBsZXQgdXJsID0gXFxgXFwke3RoaXMuYmFzZVVybH1cXCR7cGF0aH1cXGA7XG5cbiAgICBpZiAob3B0aW9ucy5xdWVyeSkge1xuICAgICAgY29uc3QgcGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyhvcHRpb25zLnF1ZXJ5KTtcbiAgICAgIHVybCArPSBcXGA/XFwke3BhcmFtcy50b1N0cmluZygpfVxcYDtcbiAgICB9XG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKHVybCwge1xuICAgICAgbWV0aG9kLFxuICAgICAgaGVhZGVyczogdGhpcy5oZWFkZXJzLFxuICAgICAgYm9keTogb3B0aW9ucy5ib2R5ID8gSlNPTi5zdHJpbmdpZnkob3B0aW9ucy5ib2R5KSA6IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcXGBIVFRQIFxcJHtyZXNwb25zZS5zdGF0dXN9OiBcXCR7cmVzcG9uc2Uuc3RhdHVzVGV4dH1cXGApO1xuICAgIH1cblxuICAgIHJldHVybiByZXNwb25zZS5qc29uKCk7XG4gIH1cbmA7XG5cbiAgLy8gR2VuZXJhdGUgbWV0aG9kcyBmb3IgZWFjaCBwYXRoXG4gIGZvciAoY29uc3QgW3BhdGhVcmwsIHBhdGhJdGVtXSBvZiBPYmplY3QuZW50cmllcyhwYXRocykpIHtcbiAgICBjb25zdCBtZXRob2RzID0gWydnZXQnLCAncG9zdCcsICdwdXQnLCAncGF0Y2gnLCAnZGVsZXRlJ10gYXMgY29uc3Q7XG5cbiAgICBmb3IgKGNvbnN0IG1ldGhvZCBvZiBtZXRob2RzKSB7XG4gICAgICBjb25zdCBvcGVyYXRpb24gPSAocGF0aEl0ZW0gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW21ldGhvZF0gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWQ7XG4gICAgICBpZiAoIW9wZXJhdGlvbikgY29udGludWU7XG5cbiAgICAgIGNvbnN0IG9wZXJhdGlvbklkID0gKG9wZXJhdGlvbi5vcGVyYXRpb25JZCBhcyBzdHJpbmcpIHx8IGAke21ldGhvZH0ke3BhdGhVcmwucmVwbGFjZSgvW15hLXpBLVowLTldL2csICdfJyl9YDtcbiAgICAgIGNvbnN0IHN1bW1hcnkgPSAob3BlcmF0aW9uLnN1bW1hcnkgYXMgc3RyaW5nKSB8fCAnJztcblxuICAgICAgY29udGVudCArPSBgXG4gIC8qKlxuICAgKiAke3N1bW1hcnl9XG4gICAqL1xuICBhc3luYyAke29wZXJhdGlvbklkfSgpOiBQcm9taXNlPHVua25vd24+IHtcbiAgICByZXR1cm4gdGhpcy5yZXF1ZXN0KCcke21ldGhvZC50b1VwcGVyQ2FzZSgpfScsICcke3BhdGhVcmx9Jyk7XG4gIH1cbmA7XG4gICAgfVxuICB9XG5cbiAgY29udGVudCArPSAnfVxcbic7XG5cbiAgcmV0dXJuIGNvbnRlbnQ7XG59XG5cbi8qKlxuICogR2VuZXJhdGUgUHl0aG9uIFNES1xuICovXG5hc3luYyBmdW5jdGlvbiBnZW5lcmF0ZVB5dGhvblNESyhcbiAgc3BlY1BhdGg6IHN0cmluZyxcbiAgb3V0cHV0UGF0aDogc3RyaW5nLFxuICBwYWNrYWdlTmFtZTogc3RyaW5nXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgLy8gUmVhZCB0aGUgT3BlbkFQSSBzcGVjXG4gIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZShzcGVjUGF0aCwgJ3V0Zi04Jyk7XG4gIGxldCBzcGVjOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcblxuICBpZiAoc3BlY1BhdGguZW5kc1dpdGgoJy55YW1sJykgfHwgc3BlY1BhdGguZW5kc1dpdGgoJy55bWwnKSkge1xuICAgIGNvbnN0IHlhbWwgPSBhd2FpdCBpbXBvcnQoJ2pzLXlhbWwnKTtcbiAgICBzcGVjID0geWFtbC5sb2FkKGNvbnRlbnQpIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICB9IGVsc2Uge1xuICAgIHNwZWMgPSBKU09OLnBhcnNlKGNvbnRlbnQpO1xuICB9XG5cbiAgY29uc3QgaW5mbyA9IChzcGVjLmluZm8gfHwge30pIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBjb25zdCBzZXJ2ZXJzID0gKHNwZWMuc2VydmVycyB8fCBbXSkgYXMgeyB1cmw6IHN0cmluZyB9W107XG4gIGNvbnN0IGRlZmF1bHRCYXNlVXJsID0gc2VydmVyc1swXT8udXJsIHx8ICdodHRwczovL2FwaS5leGFtcGxlLmNvbSc7XG5cbiAgLy8gQ3JlYXRlIHBhY2thZ2UgZGlyZWN0b3J5XG4gIGNvbnN0IHBrZ0RpciA9IHBhdGguam9pbihvdXRwdXRQYXRoLCBwYWNrYWdlTmFtZSk7XG4gIGF3YWl0IGZzLmVuc3VyZURpcihwa2dEaXIpO1xuXG4gIC8vIEdlbmVyYXRlIHNldHVwLnB5XG4gIGNvbnN0IHNldHVwUHkgPSBgZnJvbSBzZXR1cHRvb2xzIGltcG9ydCBzZXR1cCwgZmluZF9wYWNrYWdlc1xuXG5zZXR1cChcbiAgICBuYW1lPVwiJHtwYWNrYWdlTmFtZX1cIixcbiAgICB2ZXJzaW9uPVwiJHsoaW5mby52ZXJzaW9uIGFzIHN0cmluZykgfHwgJzEuMC4wJ31cIixcbiAgICBkZXNjcmlwdGlvbj1cIiR7KGluZm8uZGVzY3JpcHRpb24gYXMgc3RyaW5nKSB8fCAnR2VuZXJhdGVkIFNESyd9XCIsXG4gICAgcGFja2FnZXM9ZmluZF9wYWNrYWdlcygpLFxuICAgIHB5dGhvbl9yZXF1aXJlcz1cIj49My44XCIsXG4gICAgaW5zdGFsbF9yZXF1aXJlcz1bXG4gICAgICAgIFwiaHR0cHg+PTAuMjQuMFwiLFxuICAgIF0sXG4pXG5gO1xuXG4gIGF3YWl0IGZzLndyaXRlRmlsZShwYXRoLmpvaW4ob3V0cHV0UGF0aCwgJ3NldHVwLnB5JyksIHNldHVwUHkpO1xuXG4gIC8vIEdlbmVyYXRlIF9faW5pdF9fLnB5XG4gIGNvbnN0IGluaXRQeSA9IGBcIlwiXCIkeyhpbmZvLnRpdGxlIGFzIHN0cmluZykgfHwgJ0FQSSd9IFNES1wiXCJcIlxuXG5mcm9tIC5jbGllbnQgaW1wb3J0IEFwaUNsaWVudFxuXG5fX2FsbF9fID0gW1wiQXBpQ2xpZW50XCJdXG5fX3ZlcnNpb25fXyA9IFwiJHsoaW5mby52ZXJzaW9uIGFzIHN0cmluZykgfHwgJzEuMC4wJ31cIlxuYDtcblxuICBhd2FpdCBmcy53cml0ZUZpbGUocGF0aC5qb2luKHBrZ0RpciwgJ19faW5pdF9fLnB5JyksIGluaXRQeSk7XG5cbiAgLy8gR2VuZXJhdGUgY2xpZW50LnB5XG4gIGNvbnN0IGNsaWVudFB5ID0gYFwiXCJcIkFQSSBDbGllbnRcIlwiXCJcblxuaW1wb3J0IGh0dHB4XG5mcm9tIHR5cGluZyBpbXBvcnQgT3B0aW9uYWwsIERpY3QsIEFueVxuXG5cbmNsYXNzIEFwaUNsaWVudDpcbiAgICBcIlwiXCIkeyhpbmZvLnRpdGxlIGFzIHN0cmluZykgfHwgJ0FQSSd9IENsaWVudFwiXCJcIlxuXG4gICAgZGVmIF9faW5pdF9fKFxuICAgICAgICBzZWxmLFxuICAgICAgICBiYXNlX3VybDogc3RyID0gXCIke2RlZmF1bHRCYXNlVXJsfVwiLFxuICAgICAgICBhcGlfa2V5OiBPcHRpb25hbFtzdHJdID0gTm9uZSxcbiAgICAgICAgaGVhZGVyczogT3B0aW9uYWxbRGljdFtzdHIsIHN0cl1dID0gTm9uZSxcbiAgICApOlxuICAgICAgICBzZWxmLmJhc2VfdXJsID0gYmFzZV91cmwucnN0cmlwKFwiL1wiKVxuICAgICAgICBzZWxmLmhlYWRlcnMgPSBoZWFkZXJzIG9yIHt9XG4gICAgICAgIHNlbGYuaGVhZGVyc1tcIkNvbnRlbnQtVHlwZVwiXSA9IFwiYXBwbGljYXRpb24vanNvblwiXG5cbiAgICAgICAgaWYgYXBpX2tleTpcbiAgICAgICAgICAgIHNlbGYuaGVhZGVyc1tcIkF1dGhvcml6YXRpb25cIl0gPSBmXCJCZWFyZXIge2FwaV9rZXl9XCJcblxuICAgICAgICBzZWxmLl9jbGllbnQgPSBodHRweC5DbGllbnQoaGVhZGVycz1zZWxmLmhlYWRlcnMpXG5cbiAgICBkZWYgX3JlcXVlc3QoXG4gICAgICAgIHNlbGYsXG4gICAgICAgIG1ldGhvZDogc3RyLFxuICAgICAgICBwYXRoOiBzdHIsXG4gICAgICAgIHBhcmFtczogT3B0aW9uYWxbRGljdFtzdHIsIEFueV1dID0gTm9uZSxcbiAgICAgICAganNvbjogT3B0aW9uYWxbRGljdFtzdHIsIEFueV1dID0gTm9uZSxcbiAgICApIC0+IEFueTpcbiAgICAgICAgdXJsID0gZlwie3NlbGYuYmFzZV91cmx9e3BhdGh9XCJcbiAgICAgICAgcmVzcG9uc2UgPSBzZWxmLl9jbGllbnQucmVxdWVzdChtZXRob2QsIHVybCwgcGFyYW1zPXBhcmFtcywganNvbj1qc29uKVxuICAgICAgICByZXNwb25zZS5yYWlzZV9mb3Jfc3RhdHVzKClcbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlLmpzb24oKVxuXG4gICAgZGVmIGNsb3NlKHNlbGYpOlxuICAgICAgICBzZWxmLl9jbGllbnQuY2xvc2UoKVxuXG4gICAgZGVmIF9fZW50ZXJfXyhzZWxmKTpcbiAgICAgICAgcmV0dXJuIHNlbGZcblxuICAgIGRlZiBfX2V4aXRfXyhzZWxmLCAqYXJncyk6XG4gICAgICAgIHNlbGYuY2xvc2UoKVxuYDtcblxuICBhd2FpdCBmcy53cml0ZUZpbGUocGF0aC5qb2luKHBrZ0RpciwgJ2NsaWVudC5weScpLCBjbGllbnRQeSk7XG5cbiAgLy8gR2VuZXJhdGUgUkVBRE1FXG4gIGNvbnN0IHJlYWRtZSA9IGAjICR7cGFja2FnZU5hbWV9XG5cbkdlbmVyYXRlZCBQeXRob24gU0RLIGZvciAkeyhpbmZvLnRpdGxlIGFzIHN0cmluZykgfHwgJ0FQSSd9LlxuXG4jIyBJbnN0YWxsYXRpb25cblxuXFxgXFxgXFxgYmFzaFxucGlwIGluc3RhbGwgLWUgLlxuXFxgXFxgXFxgXG5cbiMjIFVzYWdlXG5cblxcYFxcYFxcYHB5dGhvblxuZnJvbSAke3BhY2thZ2VOYW1lfSBpbXBvcnQgQXBpQ2xpZW50XG5cbmNsaWVudCA9IEFwaUNsaWVudChcbiAgICBiYXNlX3VybD1cIiR7ZGVmYXVsdEJhc2VVcmx9XCIsXG4gICAgYXBpX2tleT1cInlvdXItYXBpLWtleVwiLFxuKVxuXFxgXFxgXFxgXG5gO1xuXG4gIGF3YWl0IGZzLndyaXRlRmlsZShwYXRoLmpvaW4ob3V0cHV0UGF0aCwgJ1JFQURNRS5tZCcpLCByZWFkbWUpO1xufVxuXG4vKipcbiAqIEdlbmVyYXRlIEdvIFNES1xuICovXG5hc3luYyBmdW5jdGlvbiBnZW5lcmF0ZUdvU0RLKFxuICBzcGVjUGF0aDogc3RyaW5nLFxuICBvdXRwdXRQYXRoOiBzdHJpbmcsXG4gIHBhY2thZ2VOYW1lOiBzdHJpbmdcbik6IFByb21pc2U8dm9pZD4ge1xuICAvLyBSZWFkIHRoZSBPcGVuQVBJIHNwZWNcbiAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKHNwZWNQYXRoLCAndXRmLTgnKTtcbiAgbGV0IHNwZWM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuXG4gIGlmIChzcGVjUGF0aC5lbmRzV2l0aCgnLnlhbWwnKSB8fCBzcGVjUGF0aC5lbmRzV2l0aCgnLnltbCcpKSB7XG4gICAgY29uc3QgeWFtbCA9IGF3YWl0IGltcG9ydCgnanMteWFtbCcpO1xuICAgIHNwZWMgPSB5YW1sLmxvYWQoY29udGVudCkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIH0gZWxzZSB7XG4gICAgc3BlYyA9IEpTT04ucGFyc2UoY29udGVudCk7XG4gIH1cblxuICBjb25zdCBpbmZvID0gKHNwZWMuaW5mbyB8fCB7fSkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIGNvbnN0IHNlcnZlcnMgPSAoc3BlYy5zZXJ2ZXJzIHx8IFtdKSBhcyB7IHVybDogc3RyaW5nIH1bXTtcbiAgY29uc3QgZGVmYXVsdEJhc2VVcmwgPSBzZXJ2ZXJzWzBdPy51cmwgfHwgJ2h0dHBzOi8vYXBpLmV4YW1wbGUuY29tJztcblxuICAvLyBHZW5lcmF0ZSBnby5tb2RcbiAgY29uc3QgZ29Nb2QgPSBgbW9kdWxlICR7cGFja2FnZU5hbWV9XG5cbmdvIDEuMjFcbmA7XG5cbiAgYXdhaXQgZnMud3JpdGVGaWxlKHBhdGguam9pbihvdXRwdXRQYXRoLCAnZ28ubW9kJyksIGdvTW9kKTtcblxuICAvLyBHZW5lcmF0ZSBjbGllbnQuZ29cbiAgY29uc3QgY2xpZW50R28gPSBgLy8gUGFja2FnZSAke3BhY2thZ2VOYW1lLnNwbGl0KCcvJykucG9wKCl9IHByb3ZpZGVzIGEgY2xpZW50IGZvciAkeyhpbmZvLnRpdGxlIGFzIHN0cmluZykgfHwgJ3RoZSBBUEknfS5cbnBhY2thZ2UgJHtwYWNrYWdlTmFtZS5zcGxpdCgnLycpLnBvcCgpIHx8ICdzZGsnfVxuXG5pbXBvcnQgKFxuXFx0XCJieXRlc1wiXG5cXHRcImVuY29kaW5nL2pzb25cIlxuXFx0XCJmbXRcIlxuXFx0XCJpb1wiXG5cXHRcIm5ldC9odHRwXCJcbilcblxuLy8gQ2xpZW50IHJlcHJlc2VudHMgYW4gQVBJIGNsaWVudC5cbnR5cGUgQ2xpZW50IHN0cnVjdCB7XG5cXHRCYXNlVVJMICAgIHN0cmluZ1xuXFx0QVBJS2V5ICAgICBzdHJpbmdcblxcdEhUVFBDbGllbnQgKmh0dHAuQ2xpZW50XG59XG5cbi8vIE5ld0NsaWVudCBjcmVhdGVzIGEgbmV3IEFQSSBjbGllbnQuXG5mdW5jIE5ld0NsaWVudChiYXNlVVJMLCBhcGlLZXkgc3RyaW5nKSAqQ2xpZW50IHtcblxcdGlmIGJhc2VVUkwgPT0gXCJcIiB7XG5cXHRcXHRiYXNlVVJMID0gXCIke2RlZmF1bHRCYXNlVXJsfVwiXG5cXHR9XG5cXHRyZXR1cm4gJkNsaWVudHtcblxcdFxcdEJhc2VVUkw6ICAgIGJhc2VVUkwsXG5cXHRcXHRBUElLZXk6ICAgICBhcGlLZXksXG5cXHRcXHRIVFRQQ2xpZW50OiAmaHR0cC5DbGllbnR7fSxcblxcdH1cbn1cblxuZnVuYyAoYyAqQ2xpZW50KSBkb1JlcXVlc3QobWV0aG9kLCBwYXRoIHN0cmluZywgYm9keSBpbnRlcmZhY2V7fSkgKFtdYnl0ZSwgZXJyb3IpIHtcblxcdHVybCA6PSBjLkJhc2VVUkwgKyBwYXRoXG5cblxcdHZhciByZXFCb2R5IGlvLlJlYWRlclxuXFx0aWYgYm9keSAhPSBuaWwge1xuXFx0XFx0anNvbkJvZHksIGVyciA6PSBqc29uLk1hcnNoYWwoYm9keSlcblxcdFxcdGlmIGVyciAhPSBuaWwge1xuXFx0XFx0XFx0cmV0dXJuIG5pbCwgZm10LkVycm9yZihcImZhaWxlZCB0byBtYXJzaGFsIHJlcXVlc3QgYm9keTogJXdcIiwgZXJyKVxuXFx0XFx0fVxuXFx0XFx0cmVxQm9keSA9IGJ5dGVzLk5ld0J1ZmZlcihqc29uQm9keSlcblxcdH1cblxuXFx0cmVxLCBlcnIgOj0gaHR0cC5OZXdSZXF1ZXN0KG1ldGhvZCwgdXJsLCByZXFCb2R5KVxuXFx0aWYgZXJyICE9IG5pbCB7XG5cXHRcXHRyZXR1cm4gbmlsLCBmbXQuRXJyb3JmKFwiZmFpbGVkIHRvIGNyZWF0ZSByZXF1ZXN0OiAld1wiLCBlcnIpXG5cXHR9XG5cblxcdHJlcS5IZWFkZXIuU2V0KFwiQ29udGVudC1UeXBlXCIsIFwiYXBwbGljYXRpb24vanNvblwiKVxuXFx0aWYgYy5BUElLZXkgIT0gXCJcIiB7XG5cXHRcXHRyZXEuSGVhZGVyLlNldChcIkF1dGhvcml6YXRpb25cIiwgXCJCZWFyZXIgXCIrYy5BUElLZXkpXG5cXHR9XG5cblxcdHJlc3AsIGVyciA6PSBjLkhUVFBDbGllbnQuRG8ocmVxKVxuXFx0aWYgZXJyICE9IG5pbCB7XG5cXHRcXHRyZXR1cm4gbmlsLCBmbXQuRXJyb3JmKFwicmVxdWVzdCBmYWlsZWQ6ICV3XCIsIGVycilcblxcdH1cblxcdGRlZmVyIHJlc3AuQm9keS5DbG9zZSgpXG5cblxcdHJlc3BCb2R5LCBlcnIgOj0gaW8uUmVhZEFsbChyZXNwLkJvZHkpXG5cXHRpZiBlcnIgIT0gbmlsIHtcblxcdFxcdHJldHVybiBuaWwsIGZtdC5FcnJvcmYoXCJmYWlsZWQgdG8gcmVhZCByZXNwb25zZTogJXdcIiwgZXJyKVxuXFx0fVxuXG5cXHRpZiByZXNwLlN0YXR1c0NvZGUgPj0gNDAwIHtcblxcdFxcdHJldHVybiBuaWwsIGZtdC5FcnJvcmYoXCJBUEkgZXJyb3IgJWQ6ICVzXCIsIHJlc3AuU3RhdHVzQ29kZSwgc3RyaW5nKHJlc3BCb2R5KSlcblxcdH1cblxuXFx0cmV0dXJuIHJlc3BCb2R5LCBuaWxcbn1cbmA7XG5cbiAgYXdhaXQgZnMud3JpdGVGaWxlKHBhdGguam9pbihvdXRwdXRQYXRoLCAnY2xpZW50LmdvJyksIGNsaWVudEdvKTtcblxuICAvLyBHZW5lcmF0ZSBSRUFETUVcbiAgY29uc3QgcmVhZG1lID0gYCMgJHtwYWNrYWdlTmFtZX1cblxuR2VuZXJhdGVkIEdvIFNESyBmb3IgJHsoaW5mby50aXRsZSBhcyBzdHJpbmcpIHx8ICdBUEknfS5cblxuIyMgSW5zdGFsbGF0aW9uXG5cblxcYFxcYFxcYGJhc2hcbmdvIGdldCAke3BhY2thZ2VOYW1lfVxuXFxgXFxgXFxgXG5cbiMjIFVzYWdlXG5cblxcYFxcYFxcYGdvXG5wYWNrYWdlIG1haW5cblxuaW1wb3J0IChcblxcdFwiJHtwYWNrYWdlTmFtZX1cIlxuKVxuXG5mdW5jIG1haW4oKSB7XG5cXHRjbGllbnQgOj0gJHtwYWNrYWdlTmFtZS5zcGxpdCgnLycpLnBvcCgpfS5OZXdDbGllbnQoXCIke2RlZmF1bHRCYXNlVXJsfVwiLCBcInlvdXItYXBpLWtleVwiKVxuXFx0Ly8gVXNlIGNsaWVudC4uLlxufVxuXFxgXFxgXFxgXG5gO1xuXG4gIGF3YWl0IGZzLndyaXRlRmlsZShwYXRoLmpvaW4ob3V0cHV0UGF0aCwgJ1JFQURNRS5tZCcpLCByZWFkbWUpO1xufVxuIl19
|