@dollhousemcp/mcp-server 1.7.2 → 1.7.3

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 (40) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md.backup +0 -8
  3. package/dist/auth/GitHubAuthManager.js +2 -2
  4. package/dist/config/ConfigManager.d.ts +158 -25
  5. package/dist/config/ConfigManager.d.ts.map +1 -1
  6. package/dist/config/ConfigManager.js +627 -88
  7. package/dist/generated/version.d.ts +2 -2
  8. package/dist/generated/version.js +3 -3
  9. package/dist/handlers/ConfigHandler.d.ts +32 -0
  10. package/dist/handlers/ConfigHandler.d.ts.map +1 -0
  11. package/dist/handlers/ConfigHandler.js +202 -0
  12. package/dist/handlers/SyncHandlerV2.d.ts +42 -0
  13. package/dist/handlers/SyncHandlerV2.d.ts.map +1 -0
  14. package/dist/handlers/SyncHandlerV2.js +231 -0
  15. package/dist/index.d.ts +18 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +19 -3
  18. package/dist/portfolio/GitHubPortfolioIndexer.d.ts +0 -1
  19. package/dist/portfolio/GitHubPortfolioIndexer.d.ts.map +1 -1
  20. package/dist/portfolio/GitHubPortfolioIndexer.js +36 -16
  21. package/dist/portfolio/PortfolioRepoManager.d.ts +2 -1
  22. package/dist/portfolio/PortfolioRepoManager.d.ts.map +1 -1
  23. package/dist/portfolio/PortfolioRepoManager.js +2 -1
  24. package/dist/portfolio/PortfolioSyncManager.d.ts +127 -0
  25. package/dist/portfolio/PortfolioSyncManager.d.ts.map +1 -0
  26. package/dist/portfolio/PortfolioSyncManager.js +818 -0
  27. package/dist/security/audit/config/suppressions.d.ts.map +1 -1
  28. package/dist/security/audit/config/suppressions.js +54 -2
  29. package/dist/security/secureYamlParser.d.ts +46 -2
  30. package/dist/security/secureYamlParser.d.ts.map +1 -1
  31. package/dist/security/secureYamlParser.js +47 -3
  32. package/dist/server/ServerSetup.d.ts.map +1 -1
  33. package/dist/server/ServerSetup.js +16 -10
  34. package/dist/server/tools/ConfigToolsV2.d.ts +10 -0
  35. package/dist/server/tools/ConfigToolsV2.d.ts.map +1 -0
  36. package/dist/server/tools/ConfigToolsV2.js +110 -0
  37. package/dist/server/types.d.ts +2 -0
  38. package/dist/server/types.d.ts.map +1 -1
  39. package/dist/server/types.js +1 -1
  40. package/package.json +1 -1
@@ -0,0 +1,818 @@
1
+ /**
2
+ * PortfolioSyncManager - Handles synchronization between local and GitHub portfolios
3
+ *
4
+ * Features:
5
+ * - Download elements from GitHub portfolio
6
+ * - Upload elements with consent
7
+ * - Version comparison and diff viewing
8
+ * - Privacy-first with explicit permissions
9
+ * - Conflict resolution strategies
10
+ * - Bulk operations with configuration checks
11
+ */
12
+ import * as fs from 'fs/promises';
13
+ import * as path from 'path';
14
+ import { createHash } from 'crypto';
15
+ import { logger } from '../utils/logger.js';
16
+ import { ConfigManager } from '../config/ConfigManager.js';
17
+ import { PortfolioManager } from './PortfolioManager.js';
18
+ import { PortfolioRepoManager } from './PortfolioRepoManager.js';
19
+ import { GitHubPortfolioIndexer } from './GitHubPortfolioIndexer.js';
20
+ import { TokenManager } from '../security/tokenManager.js';
21
+ import { ContentValidator } from '../security/contentValidator.js';
22
+ import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
23
+ import { SecureYamlParser } from '../security/secureYamlParser.js';
24
+ import { ElementType } from './types.js';
25
+ import { ElementStatus } from '../types/elements/IElement.js';
26
+ export class PortfolioSyncManager {
27
+ configManager;
28
+ portfolioManager;
29
+ repoManager;
30
+ indexer;
31
+ constructor() {
32
+ this.configManager = ConfigManager.getInstance();
33
+ this.portfolioManager = PortfolioManager.getInstance();
34
+ this.repoManager = new PortfolioRepoManager();
35
+ this.indexer = GitHubPortfolioIndexer.getInstance();
36
+ }
37
+ /**
38
+ * Main handler for sync operations
39
+ */
40
+ async handleSyncOperation(params) {
41
+ try {
42
+ // Check if sync is enabled in config
43
+ const config = this.configManager.getConfig();
44
+ if (!config.sync.enabled && params.operation !== 'list-remote') {
45
+ return {
46
+ success: false,
47
+ message: 'Sync is disabled. Enable it with: dollhouse_config --action update --setting sync.enabled --value true'
48
+ };
49
+ }
50
+ // Check bulk permissions
51
+ if (params.bulk) {
52
+ const bulkAllowed = this.isBulkOperationAllowed(params.operation, config);
53
+ if (!bulkAllowed.allowed) {
54
+ return {
55
+ success: false,
56
+ message: bulkAllowed.message
57
+ };
58
+ }
59
+ }
60
+ // Handle operations
61
+ switch (params.operation) {
62
+ case 'list-remote':
63
+ return await this.listRemoteElements(params.element_type);
64
+ case 'download':
65
+ if (params.bulk) {
66
+ return await this.bulkDownload(params.element_type, params.confirm);
67
+ }
68
+ else if (params.element_name) {
69
+ return await this.downloadElement(params.element_name, params.element_type, params.version, params.force);
70
+ }
71
+ else {
72
+ return {
73
+ success: false,
74
+ message: 'Element name required for individual download'
75
+ };
76
+ }
77
+ case 'upload':
78
+ if (params.bulk) {
79
+ return await this.bulkUpload(params.element_type, params.confirm);
80
+ }
81
+ else if (params.element_name) {
82
+ return await this.uploadElement(params.element_name, params.element_type, params.confirm);
83
+ }
84
+ else {
85
+ return {
86
+ success: false,
87
+ message: 'Element name required for individual upload'
88
+ };
89
+ }
90
+ case 'compare':
91
+ if (params.element_name && params.element_type) {
92
+ return await this.compareVersions(params.element_name, params.element_type, params.show_diff);
93
+ }
94
+ else {
95
+ return {
96
+ success: false,
97
+ message: 'Element name and type required for comparison'
98
+ };
99
+ }
100
+ default:
101
+ return {
102
+ success: false,
103
+ message: `Unknown operation: ${params.operation}`
104
+ };
105
+ }
106
+ }
107
+ catch (error) {
108
+ logger.error('Sync operation failed', {
109
+ operation: params.operation,
110
+ error: error instanceof Error ? error.message : String(error)
111
+ });
112
+ return {
113
+ success: false,
114
+ message: `Sync operation failed: ${error instanceof Error ? error.message : String(error)}`
115
+ };
116
+ }
117
+ }
118
+ /**
119
+ * Check if bulk operation is allowed
120
+ */
121
+ isBulkOperationAllowed(operation, config) {
122
+ if (operation === 'download' && !config.sync.bulk.download_enabled) {
123
+ return {
124
+ allowed: false,
125
+ message: 'Bulk download is disabled. Enable with: dollhouse_config --action update --setting sync.bulk.download_enabled --value true'
126
+ };
127
+ }
128
+ if (operation === 'upload' && !config.sync.bulk.upload_enabled) {
129
+ return {
130
+ allowed: false,
131
+ message: 'Bulk upload is disabled. Enable with: dollhouse_config --action update --setting sync.bulk.upload_enabled --value true'
132
+ };
133
+ }
134
+ return { allowed: true, message: '' };
135
+ }
136
+ /**
137
+ * List elements available in GitHub portfolio
138
+ */
139
+ async listRemoteElements(filterType) {
140
+ try {
141
+ // Get GitHub token
142
+ const token = await TokenManager.getGitHubTokenAsync();
143
+ if (!token) {
144
+ return {
145
+ success: false,
146
+ message: 'GitHub authentication required. Use setup_github_auth first.'
147
+ };
148
+ }
149
+ this.repoManager.setToken(token);
150
+ // Get index of GitHub portfolio
151
+ const index = await this.indexer.getIndex();
152
+ if (!index || index.totalElements === 0) {
153
+ return {
154
+ success: true,
155
+ message: 'No elements found in GitHub portfolio',
156
+ elements: []
157
+ };
158
+ }
159
+ // Format elements for display
160
+ const elements = [];
161
+ for (const [type, entries] of index.elements) {
162
+ // Skip if filtering by type and this isn't the requested type
163
+ if (filterType && type !== filterType) {
164
+ continue;
165
+ }
166
+ for (const entry of entries) {
167
+ elements.push({
168
+ name: entry.name,
169
+ type: type,
170
+ remoteVersion: entry.version,
171
+ status: 'unchanged',
172
+ action: 'download'
173
+ });
174
+ }
175
+ }
176
+ return {
177
+ success: true,
178
+ message: `Found ${elements.length} elements in GitHub portfolio`,
179
+ elements
180
+ };
181
+ }
182
+ catch (error) {
183
+ return {
184
+ success: false,
185
+ message: `Failed to list remote elements: ${error instanceof Error ? error.message : String(error)}`
186
+ };
187
+ }
188
+ }
189
+ /**
190
+ * Download a specific element from GitHub
191
+ */
192
+ async downloadElement(elementName, elementType, version, force) {
193
+ try {
194
+ const config = this.configManager.getConfig();
195
+ // Validate element name
196
+ const validation = UnicodeValidator.normalize(elementName);
197
+ if (!validation.isValid) {
198
+ return {
199
+ success: false,
200
+ message: `Invalid element name: ${validation.detectedIssues?.[0] || 'unknown error'}`
201
+ };
202
+ }
203
+ // Get token and set it
204
+ const token = await TokenManager.getGitHubTokenAsync();
205
+ if (!token) {
206
+ return {
207
+ success: false,
208
+ message: 'GitHub authentication required'
209
+ };
210
+ }
211
+ this.repoManager.setToken(token);
212
+ // Get GitHub index
213
+ const index = await this.indexer.getIndex();
214
+ // Find the element - first try exact match, then fuzzy match
215
+ const entries = index.elements.get(elementType) || [];
216
+ let entry = entries.find(e => e.name === elementName);
217
+ // If exact match not found, try fuzzy matching
218
+ if (!entry) {
219
+ // Try case-insensitive exact match first
220
+ entry = entries.find(e => e.name.toLowerCase() === elementName.toLowerCase());
221
+ // If still not found, try fuzzy matching
222
+ if (!entry) {
223
+ const fuzzyMatch = this.findFuzzyMatch(elementName, entries);
224
+ if (fuzzyMatch) {
225
+ logger.info(`Fuzzy match found: '${elementName}' matched to '${fuzzyMatch.name}'`);
226
+ entry = fuzzyMatch;
227
+ }
228
+ }
229
+ }
230
+ if (!entry) {
231
+ // Generate helpful suggestions
232
+ const suggestions = this.getSuggestions(elementName, entries);
233
+ const suggestionText = suggestions.length > 0
234
+ ? `\n\nDid you mean one of these?\n${suggestions.map(s => ` • ${s.name}`).join('\n')}`
235
+ : '';
236
+ return {
237
+ success: false,
238
+ message: `Element '${elementName}' (${elementType}) not found in GitHub portfolio${suggestionText}`
239
+ };
240
+ }
241
+ // Check for local conflicts
242
+ const localPath = this.portfolioManager.getElementPath(elementType, `${elementName}.md`);
243
+ let hasLocalVersion = false;
244
+ let localContent = null;
245
+ try {
246
+ localContent = await fs.readFile(localPath, 'utf-8');
247
+ hasLocalVersion = true;
248
+ }
249
+ catch {
250
+ // No local version exists
251
+ }
252
+ // Download the element
253
+ const response = await fetch(entry.downloadUrl, {
254
+ headers: {
255
+ 'Authorization': `Bearer ${token}`,
256
+ 'Accept': 'application/vnd.github.v3.raw'
257
+ }
258
+ });
259
+ if (!response.ok) {
260
+ throw new Error(`Failed to download: ${response.statusText}`);
261
+ }
262
+ const remoteContent = await response.text();
263
+ // Validate content security
264
+ const validationResult = ContentValidator.validateAndSanitize(remoteContent);
265
+ if (!validationResult.isValid && validationResult.severity === 'critical') {
266
+ return {
267
+ success: false,
268
+ message: `Security issue detected in remote content: ${validationResult.detectedPatterns?.join(', ')}`
269
+ };
270
+ }
271
+ // Check if content is different
272
+ if (hasLocalVersion && localContent) {
273
+ const localHash = createHash('sha256').update(localContent).digest('hex');
274
+ const remoteHash = createHash('sha256').update(remoteContent).digest('hex');
275
+ if (localHash === remoteHash) {
276
+ return {
277
+ success: true,
278
+ message: `Element '${elementName}' is already up to date`
279
+ };
280
+ }
281
+ // Show confirmation for overwrite unless force flag is set
282
+ if (config.sync.individual.require_confirmation && !force) {
283
+ const diff = await this.generateDiff(localContent, remoteContent);
284
+ return {
285
+ success: false,
286
+ message: `Local version exists. Please confirm download will overwrite:\n\n${diff}\n\nTo proceed, use --force flag`,
287
+ data: { requiresConfirmation: true }
288
+ };
289
+ }
290
+ }
291
+ // Save the element
292
+ await fs.mkdir(path.dirname(localPath), { recursive: true });
293
+ await fs.writeFile(localPath, remoteContent, 'utf-8');
294
+ logger.info('Element downloaded from GitHub', {
295
+ element: elementName,
296
+ type: elementType,
297
+ version: entry.version
298
+ });
299
+ return {
300
+ success: true,
301
+ message: `Successfully downloaded '${elementName}' (${elementType}) from GitHub portfolio`
302
+ };
303
+ }
304
+ catch (error) {
305
+ return {
306
+ success: false,
307
+ message: `Failed to download element: ${error instanceof Error ? error.message : String(error)}`
308
+ };
309
+ }
310
+ }
311
+ /**
312
+ * Upload a specific element to GitHub
313
+ */
314
+ async uploadElement(elementName, elementType, confirm) {
315
+ try {
316
+ const config = this.configManager.getConfig();
317
+ // Check for local element
318
+ const localPath = this.portfolioManager.getElementPath(elementType, `${elementName}.md`);
319
+ let content;
320
+ try {
321
+ content = await fs.readFile(localPath, 'utf-8');
322
+ }
323
+ catch {
324
+ return {
325
+ success: false,
326
+ message: `Element '${elementName}' (${elementType}) not found locally`
327
+ };
328
+ }
329
+ // Check privacy metadata
330
+ const parsed = SecureYamlParser.parse(content, {
331
+ maxYamlSize: 64 * 1024,
332
+ validateContent: false,
333
+ validateFields: false
334
+ });
335
+ if (parsed.data?.privacy?.local_only === true) {
336
+ return {
337
+ success: false,
338
+ message: `Element '${elementName}' is marked as local-only and cannot be uploaded`
339
+ };
340
+ }
341
+ // Validate content security
342
+ const validationResult = ContentValidator.validateAndSanitize(content);
343
+ if (!validationResult.isValid && validationResult.severity === 'critical') {
344
+ return {
345
+ success: false,
346
+ message: `Security issue detected: ${validationResult.detectedPatterns?.join(', ')}`
347
+ };
348
+ }
349
+ // Scan for sensitive content if configured
350
+ if (config.sync.privacy.scan_for_secrets) {
351
+ logger.debug('Scanning for secrets before upload');
352
+ // Implement actual secret scanning
353
+ const secretPatterns = [
354
+ /api[_-]?key\s*[:=]\s*['"][^'"]+['"]/gi,
355
+ /secret\s*[:=]\s*['"][^'"]+['"]/gi,
356
+ /password\s*[:=]\s*['"][^'"]+['"]/gi,
357
+ /token\s*[:=]\s*['"][^'"]+['"]/gi,
358
+ /private[_-]?key\s*[:=]\s*['"][^'"]+['"]/gi
359
+ ];
360
+ for (const pattern of secretPatterns) {
361
+ if (pattern.test(content)) {
362
+ return {
363
+ success: false,
364
+ message: `Potential secret detected in content. Please review and remove sensitive information before uploading.`
365
+ };
366
+ }
367
+ }
368
+ }
369
+ // Get confirmation if required (unless already confirmed)
370
+ if (config.sync.individual.require_confirmation && !confirm) {
371
+ return {
372
+ success: false,
373
+ message: `Please confirm upload of '${elementName}' (${elementType}) to GitHub.\n\nContent preview:\n${content.substring(0, 500)}...\n\nTo proceed, use --confirm flag`,
374
+ data: { requiresConfirmation: true }
375
+ };
376
+ }
377
+ // Get token and validate
378
+ const token = await TokenManager.getGitHubTokenAsync();
379
+ if (!token) {
380
+ return {
381
+ success: false,
382
+ message: 'GitHub authentication required'
383
+ };
384
+ }
385
+ // Create an IElement object for the PortfolioRepoManager
386
+ const element = {
387
+ id: `${elementType}_${elementName}_${Date.now()}`,
388
+ type: elementType,
389
+ version: parsed.data?.version || '1.0.0',
390
+ metadata: {
391
+ name: elementName,
392
+ description: parsed.data?.description || '',
393
+ author: parsed.data?.author || 'unknown',
394
+ created: parsed.data?.created || new Date().toISOString(),
395
+ modified: new Date().toISOString(),
396
+ tags: parsed.data?.tags || [],
397
+ custom: parsed.data
398
+ },
399
+ validate: () => ({ valid: true, errors: [], warnings: [] }),
400
+ serialize: () => content,
401
+ deserialize: () => { },
402
+ getStatus: () => ElementStatus.ACTIVE
403
+ };
404
+ // Use PortfolioRepoManager to upload
405
+ this.repoManager.setToken(token);
406
+ try {
407
+ const url = await this.repoManager.saveElement(element, true); // consent is true since we've already checked
408
+ logger.info('Element uploaded to GitHub', {
409
+ element: elementName,
410
+ type: elementType,
411
+ url
412
+ });
413
+ return {
414
+ success: true,
415
+ message: `Successfully uploaded '${elementName}' (${elementType}) to GitHub portfolio`,
416
+ data: { url }
417
+ };
418
+ }
419
+ catch (uploadError) {
420
+ // Handle specific errors
421
+ if (uploadError instanceof Error && uploadError.message.includes('repository does not exist')) {
422
+ return {
423
+ success: false,
424
+ message: `GitHub portfolio repository not found. Please initialize it first using init_portfolio tool.`
425
+ };
426
+ }
427
+ throw uploadError;
428
+ }
429
+ }
430
+ catch (error) {
431
+ return {
432
+ success: false,
433
+ message: `Failed to upload element: ${error instanceof Error ? error.message : String(error)}`
434
+ };
435
+ }
436
+ }
437
+ /**
438
+ * Compare local and remote versions
439
+ */
440
+ async compareVersions(elementName, elementType, showDiff) {
441
+ try {
442
+ // Get local version
443
+ const localPath = this.portfolioManager.getElementPath(elementType, `${elementName}.md`);
444
+ let localContent = null;
445
+ let localVersion = null;
446
+ try {
447
+ localContent = await fs.readFile(localPath, 'utf-8');
448
+ const parsed = SecureYamlParser.parse(localContent, {
449
+ maxYamlSize: 64 * 1024,
450
+ validateContent: false,
451
+ validateFields: false
452
+ });
453
+ localVersion = {
454
+ version: parsed.data?.version || '1.0.0',
455
+ timestamp: new Date(parsed.data?.updated || parsed.data?.created || Date.now()),
456
+ author: parsed.data?.author || 'unknown',
457
+ hash: createHash('sha256').update(localContent).digest('hex'),
458
+ size: Buffer.byteLength(localContent),
459
+ source: 'local'
460
+ };
461
+ }
462
+ catch {
463
+ // No local version
464
+ }
465
+ // Get remote version
466
+ const token = await TokenManager.getGitHubTokenAsync();
467
+ if (!token) {
468
+ return {
469
+ success: false,
470
+ message: 'GitHub authentication required'
471
+ };
472
+ }
473
+ const index = await this.indexer.getIndex();
474
+ const entries = index.elements.get(elementType) || [];
475
+ const entry = entries.find(e => e.name === elementName);
476
+ let remoteVersion = null;
477
+ let remoteContent = null;
478
+ if (entry) {
479
+ const response = await fetch(entry.downloadUrl, {
480
+ headers: {
481
+ 'Authorization': `Bearer ${token}`,
482
+ 'Accept': 'application/vnd.github.v3.raw'
483
+ }
484
+ });
485
+ if (response.ok) {
486
+ remoteContent = await response.text();
487
+ remoteVersion = {
488
+ version: entry.version || '1.0.0',
489
+ timestamp: entry.lastModified,
490
+ author: entry.author || 'unknown',
491
+ hash: createHash('sha256').update(remoteContent).digest('hex'),
492
+ size: entry.size,
493
+ source: 'remote'
494
+ };
495
+ }
496
+ }
497
+ // Build comparison result
498
+ const result = {
499
+ element: elementName,
500
+ type: elementType,
501
+ local: localVersion,
502
+ remote: remoteVersion
503
+ };
504
+ if (localVersion && remoteVersion) {
505
+ result.status = localVersion.hash === remoteVersion.hash ? 'identical' : 'different';
506
+ if (showDiff && localContent && remoteContent && result.status === 'different') {
507
+ result.diff = await this.generateDiff(localContent, remoteContent);
508
+ }
509
+ }
510
+ else if (localVersion && !remoteVersion) {
511
+ result.status = 'local-only';
512
+ }
513
+ else if (!localVersion && remoteVersion) {
514
+ result.status = 'remote-only';
515
+ }
516
+ else {
517
+ result.status = 'not-found';
518
+ }
519
+ return {
520
+ success: true,
521
+ message: `Version comparison for '${elementName}' (${elementType})`,
522
+ data: result
523
+ };
524
+ }
525
+ catch (error) {
526
+ return {
527
+ success: false,
528
+ message: `Failed to compare versions: ${error instanceof Error ? error.message : String(error)}`
529
+ };
530
+ }
531
+ }
532
+ /**
533
+ * Bulk download elements
534
+ */
535
+ async bulkDownload(elementType, confirm) {
536
+ const config = this.configManager.getConfig();
537
+ if (!config.sync.bulk.download_enabled) {
538
+ return {
539
+ success: false,
540
+ message: 'Bulk download is not enabled in configuration'
541
+ };
542
+ }
543
+ // Get list of remote elements
544
+ const remoteResult = await this.listRemoteElements();
545
+ if (!remoteResult.success || !remoteResult.elements) {
546
+ return remoteResult;
547
+ }
548
+ // Filter by type if specified
549
+ let elementsToDownload = remoteResult.elements;
550
+ if (elementType) {
551
+ elementsToDownload = elementsToDownload.filter(e => e.type === elementType);
552
+ }
553
+ if (elementsToDownload.length === 0) {
554
+ return {
555
+ success: true,
556
+ message: 'No elements to download',
557
+ elements: []
558
+ };
559
+ }
560
+ // Show preview if required (unless already confirmed)
561
+ if (config.sync.bulk.require_preview && !confirm) {
562
+ return {
563
+ success: false,
564
+ message: `Bulk download preview:\n\n${elementsToDownload.length} elements will be downloaded:\n${elementsToDownload.map(e => `- ${e.name} (${e.type})`).join('\n')}\n\nTo proceed, use --confirm flag`,
565
+ data: { requiresConfirmation: true },
566
+ elements: elementsToDownload
567
+ };
568
+ }
569
+ // Perform actual bulk download
570
+ const results = {
571
+ downloaded: [],
572
+ skipped: [],
573
+ failed: []
574
+ };
575
+ for (const element of elementsToDownload) {
576
+ try {
577
+ const result = await this.downloadElement(element.name, element.type, undefined, true); // force=true to skip individual confirmations
578
+ if (result.success) {
579
+ results.downloaded.push(element.name);
580
+ }
581
+ else if (result.message?.includes('already up to date')) {
582
+ results.skipped.push(element.name);
583
+ }
584
+ else {
585
+ results.failed.push({ name: element.name, error: result.message || 'Unknown error' });
586
+ }
587
+ }
588
+ catch (error) {
589
+ results.failed.push({
590
+ name: element.name,
591
+ error: error instanceof Error ? error.message : String(error)
592
+ });
593
+ }
594
+ }
595
+ // Build summary message
596
+ let message = `Bulk download complete:\n`;
597
+ message += `- Downloaded: ${results.downloaded.length} elements\n`;
598
+ message += `- Skipped (up to date): ${results.skipped.length} elements\n`;
599
+ message += `- Failed: ${results.failed.length} elements`;
600
+ if (results.failed.length > 0) {
601
+ message += `\n\nFailed downloads:\n${results.failed.map(f => `- ${f.name}: ${f.error}`).join('\n')}`;
602
+ }
603
+ return {
604
+ success: results.failed.length === 0,
605
+ message,
606
+ data: results
607
+ };
608
+ }
609
+ /**
610
+ * Bulk upload elements
611
+ */
612
+ async bulkUpload(elementType, confirm) {
613
+ const config = this.configManager.getConfig();
614
+ if (!config.sync.bulk.upload_enabled) {
615
+ return {
616
+ success: false,
617
+ message: 'Bulk upload is not enabled in configuration'
618
+ };
619
+ }
620
+ // Get list of local elements
621
+ const types = elementType ? [elementType] : [
622
+ ElementType.PERSONA,
623
+ ElementType.SKILL,
624
+ ElementType.TEMPLATE,
625
+ ElementType.AGENT,
626
+ ElementType.MEMORY,
627
+ ElementType.ENSEMBLE
628
+ ];
629
+ const localElements = [];
630
+ for (const type of types) {
631
+ const dir = this.portfolioManager.getElementDir(type);
632
+ try {
633
+ const files = await fs.readdir(dir);
634
+ for (const file of files) {
635
+ if (file.endsWith('.md')) {
636
+ localElements.push({
637
+ name: file.replace('.md', ''),
638
+ type,
639
+ path: path.join(dir, file)
640
+ });
641
+ }
642
+ }
643
+ }
644
+ catch (error) {
645
+ // Directory may not exist yet
646
+ logger.debug(`Directory for ${type} does not exist yet`);
647
+ }
648
+ }
649
+ if (localElements.length === 0) {
650
+ return {
651
+ success: true,
652
+ message: 'No local elements to upload',
653
+ elements: []
654
+ };
655
+ }
656
+ // Show preview if required (unless already confirmed)
657
+ if (config.sync.bulk.require_preview && !confirm) {
658
+ // Convert to SyncElementInfo format for preview
659
+ const previewElements = localElements.map(e => ({
660
+ name: e.name,
661
+ type: e.type,
662
+ status: 'local-only',
663
+ action: 'upload'
664
+ }));
665
+ return {
666
+ success: false,
667
+ message: `Bulk upload preview:\n\n${localElements.length} elements will be uploaded:\n${localElements.map(e => `- ${e.name} (${e.type})`).join('\n')}\n\nTo proceed, use --confirm flag`,
668
+ data: { requiresConfirmation: true },
669
+ elements: previewElements
670
+ };
671
+ }
672
+ // Perform actual bulk upload
673
+ const results = {
674
+ uploaded: [],
675
+ skipped: [],
676
+ failed: []
677
+ };
678
+ for (const element of localElements) {
679
+ try {
680
+ const result = await this.uploadElement(element.name, element.type, true); // confirm=true to skip individual confirmations
681
+ if (result.success) {
682
+ results.uploaded.push(element.name);
683
+ }
684
+ else if (result.message?.includes('local-only')) {
685
+ results.skipped.push(element.name);
686
+ }
687
+ else {
688
+ results.failed.push({ name: element.name, error: result.message || 'Unknown error' });
689
+ }
690
+ }
691
+ catch (error) {
692
+ results.failed.push({
693
+ name: element.name,
694
+ error: error instanceof Error ? error.message : String(error)
695
+ });
696
+ }
697
+ }
698
+ // Build summary message
699
+ let message = `Bulk upload complete:\n`;
700
+ message += `- Uploaded: ${results.uploaded.length} elements\n`;
701
+ message += `- Skipped (local-only): ${results.skipped.length} elements\n`;
702
+ message += `- Failed: ${results.failed.length} elements`;
703
+ if (results.failed.length > 0) {
704
+ message += `\n\nFailed uploads:\n${results.failed.map(f => `- ${f.name}: ${f.error}`).join('\n')}`;
705
+ }
706
+ return {
707
+ success: results.failed.length === 0,
708
+ message,
709
+ data: results
710
+ };
711
+ }
712
+ /**
713
+ * Generate diff between two content versions
714
+ */
715
+ async generateDiff(local, remote) {
716
+ // Simple line-based diff for now
717
+ const localLines = local.split('\n');
718
+ const remoteLines = remote.split('\n');
719
+ let diff = '';
720
+ const maxLines = Math.max(localLines.length, remoteLines.length);
721
+ for (let i = 0; i < maxLines && i < 10; i++) { // Show first 10 lines of diff
722
+ const localLine = localLines[i] || '';
723
+ const remoteLine = remoteLines[i] || '';
724
+ if (localLine !== remoteLine) {
725
+ if (localLine && !remoteLine) {
726
+ diff += `- ${localLine}\n`;
727
+ }
728
+ else if (!localLine && remoteLine) {
729
+ diff += `+ ${remoteLine}\n`;
730
+ }
731
+ else {
732
+ diff += `- ${localLine}\n`;
733
+ diff += `+ ${remoteLine}\n`;
734
+ }
735
+ }
736
+ }
737
+ if (maxLines > 10) {
738
+ diff += `\n... ${maxLines - 10} more lines ...`;
739
+ }
740
+ return diff || 'No differences found';
741
+ }
742
+ /**
743
+ * Find a fuzzy match for an element name
744
+ */
745
+ findFuzzyMatch(searchName, entries) {
746
+ const search = searchName.toLowerCase().replace(/[-_]/g, '');
747
+ let bestMatch = null;
748
+ let bestScore = 0;
749
+ for (const entry of entries) {
750
+ // Normalize the entry name for comparison
751
+ const normalized = entry.name.toLowerCase().replace(/[-_]/g, '');
752
+ // Calculate similarity score
753
+ const score = this.calculateSimilarity(search, normalized);
754
+ if (score > bestScore && score > 0.5) { // Minimum threshold of 0.5
755
+ bestScore = score;
756
+ bestMatch = entry;
757
+ }
758
+ }
759
+ return bestMatch;
760
+ }
761
+ /**
762
+ * Get suggestions for similar element names
763
+ */
764
+ getSuggestions(searchName, entries) {
765
+ const search = searchName.toLowerCase().replace(/[-_]/g, '');
766
+ const scored = [];
767
+ for (const entry of entries) {
768
+ const normalized = entry.name.toLowerCase().replace(/[-_]/g, '');
769
+ const score = this.calculateSimilarity(search, normalized);
770
+ if (score > 0.3) { // Lower threshold for suggestions
771
+ scored.push({ entry, score });
772
+ }
773
+ }
774
+ // Sort by score and return top 5
775
+ return scored
776
+ .sort((a, b) => b.score - a.score)
777
+ .slice(0, 5)
778
+ .map(s => ({ name: s.entry.name }));
779
+ }
780
+ /**
781
+ * Calculate similarity between two strings
782
+ * Returns a score between 0 and 1
783
+ */
784
+ calculateSimilarity(a, b) {
785
+ // Exact match
786
+ if (a === b)
787
+ return 1.0;
788
+ // One contains the other
789
+ if (a.includes(b) || b.includes(a))
790
+ return 0.8;
791
+ // Calculate word overlap
792
+ const wordsA = a.split(/[^a-z0-9]+/);
793
+ const wordsB = b.split(/[^a-z0-9]+/);
794
+ let matches = 0;
795
+ for (const wordA of wordsA) {
796
+ if (wordA && wordsB.some(wordB => wordB === wordA)) {
797
+ matches++;
798
+ }
799
+ }
800
+ if (matches > 0) {
801
+ const overlap = (matches * 2) / (wordsA.length + wordsB.length);
802
+ return Math.max(0.6, overlap); // At least 0.6 for any word match
803
+ }
804
+ // Check for partial matches
805
+ for (const wordA of wordsA) {
806
+ for (const wordB of wordsB) {
807
+ if (wordA.length > 3 && wordB.length > 3) {
808
+ if (wordA.includes(wordB) || wordB.includes(wordA)) {
809
+ return 0.5;
810
+ }
811
+ }
812
+ }
813
+ }
814
+ // No significant similarity
815
+ return 0;
816
+ }
817
+ }
818
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUG9ydGZvbGlvU3luY01hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcG9ydGZvbGlvL1BvcnRmb2xpb1N5bmNNYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7O0dBVUc7QUFFSCxPQUFPLEtBQUssRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNsQyxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUM3QixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QyxPQUFPLEVBQUUsYUFBYSxFQUFtQixNQUFNLDRCQUE0QixDQUFDO0FBQzVFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxzQkFBc0IsRUFBb0IsTUFBTSw2QkFBNkIsQ0FBQztBQUN2RixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbkUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDOUUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbkUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUN6QyxPQUFPLEVBQVksYUFBYSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFrRXhFLE1BQU0sT0FBTyxvQkFBb0I7SUFDdkIsYUFBYSxDQUFnQjtJQUM3QixnQkFBZ0IsQ0FBbUI7SUFDbkMsV0FBVyxDQUF1QjtJQUNsQyxPQUFPLENBQXlCO0lBRXhDO1FBQ0UsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUMsV0FBVyxF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RSxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsa0NBQWtDO1FBQ25FLENBQUM7UUFFRCw0QkFBNEI7UUFDNUIsS0FBSyxNQUFNLEtBQUssSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUMzQixLQUFLLE1BQU0sS0FBSyxJQUFJLE1BQU0sRUFBRSxDQUFDO2dCQUMzQixJQUFJLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQ3pDLElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7d0JBQ25ELE9BQU8sR0FBRyxDQUFDO29CQUNiLENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBRUQsNEJBQTRCO1FBQzVCLE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBQb3J0Zm9saW9TeW5jTWFuYWdlciAtIEhhbmRsZXMgc3luY2hyb25pemF0aW9uIGJldHdlZW4gbG9jYWwgYW5kIEdpdEh1YiBwb3J0Zm9saW9zXG4gKiBcbiAqIEZlYXR1cmVzOlxuICogLSBEb3dubG9hZCBlbGVtZW50cyBmcm9tIEdpdEh1YiBwb3J0Zm9saW9cbiAqIC0gVXBsb2FkIGVsZW1lbnRzIHdpdGggY29uc2VudFxuICogLSBWZXJzaW9uIGNvbXBhcmlzb24gYW5kIGRpZmYgdmlld2luZ1xuICogLSBQcml2YWN5LWZpcnN0IHdpdGggZXhwbGljaXQgcGVybWlzc2lvbnNcbiAqIC0gQ29uZmxpY3QgcmVzb2x1dGlvbiBzdHJhdGVnaWVzXG4gKiAtIEJ1bGsgb3BlcmF0aW9ucyB3aXRoIGNvbmZpZ3VyYXRpb24gY2hlY2tzXG4gKi9cblxuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMvcHJvbWlzZXMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IGNyZWF0ZUhhc2ggfSBmcm9tICdjcnlwdG8nO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IENvbmZpZ01hbmFnZXIsIERvbGxob3VzZUNvbmZpZyB9IGZyb20gJy4uL2NvbmZpZy9Db25maWdNYW5hZ2VyLmpzJztcbmltcG9ydCB7IFBvcnRmb2xpb01hbmFnZXIgfSBmcm9tICcuL1BvcnRmb2xpb01hbmFnZXIuanMnO1xuaW1wb3J0IHsgUG9ydGZvbGlvUmVwb01hbmFnZXIgfSBmcm9tICcuL1BvcnRmb2xpb1JlcG9NYW5hZ2VyLmpzJztcbmltcG9ydCB7IEdpdEh1YlBvcnRmb2xpb0luZGV4ZXIsIEdpdEh1YkluZGV4RW50cnkgfSBmcm9tICcuL0dpdEh1YlBvcnRmb2xpb0luZGV4ZXIuanMnO1xuaW1wb3J0IHsgVG9rZW5NYW5hZ2VyIH0gZnJvbSAnLi4vc2VjdXJpdHkvdG9rZW5NYW5hZ2VyLmpzJztcbmltcG9ydCB7IENvbnRlbnRWYWxpZGF0b3IgfSBmcm9tICcuLi9zZWN1cml0eS9jb250ZW50VmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IFVuaWNvZGVWYWxpZGF0b3IgfSBmcm9tICcuLi9zZWN1cml0eS92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuaW1wb3J0IHsgU2VjdXJlWWFtbFBhcnNlciB9IGZyb20gJy4uL3NlY3VyaXR5L3NlY3VyZVlhbWxQYXJzZXIuanMnO1xuaW1wb3J0IHsgRWxlbWVudFR5cGUgfSBmcm9tICcuL3R5cGVzLmpzJztcbmltcG9ydCB7IElFbGVtZW50LCBFbGVtZW50U3RhdHVzIH0gZnJvbSAnLi4vdHlwZXMvZWxlbWVudHMvSUVsZW1lbnQuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFN5bmNPcGVyYXRpb24ge1xuICBvcGVyYXRpb246ICdkb3dubG9hZCcgfCAndXBsb2FkJyB8ICdjb21wYXJlJyB8ICdsaXN0LXJlbW90ZSc7XG4gIGVsZW1lbnRfbmFtZT86IHN0cmluZztcbiAgZWxlbWVudF90eXBlPzogRWxlbWVudFR5cGU7XG4gIGJ1bGs/OiBib29sZWFuO1xuICB2ZXJzaW9uPzogc3RyaW5nO1xuICBzaG93X2RpZmY/OiBib29sZWFuO1xuICBmb3JjZT86IGJvb2xlYW47XG4gIGNvbmZpcm0/OiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFN5bmNSZXN1bHQge1xuICBzdWNjZXNzOiBib29sZWFuO1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIGRhdGE/OiBhbnk7XG4gIGVsZW1lbnRzPzogU3luY0VsZW1lbnRJbmZvW107XG4gIGNvbmZsaWN0cz86IENvbmZsaWN0SW5mb1tdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFN5bmNFbGVtZW50SW5mbyB7XG4gIG5hbWU6IHN0cmluZztcbiAgdHlwZTogRWxlbWVudFR5cGU7XG4gIGxvY2FsVmVyc2lvbj86IHN0cmluZztcbiAgcmVtb3RlVmVyc2lvbj86IHN0cmluZztcbiAgc3RhdHVzOiAnbmV3JyB8ICd1cGRhdGVkJyB8ICdjb25mbGljdCcgfCAndW5jaGFuZ2VkJyB8ICdsb2NhbC1vbmx5JztcbiAgYWN0aW9uPzogJ2Rvd25sb2FkJyB8ICd1cGxvYWQnIHwgJ3NraXAnO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENvbmZsaWN0SW5mbyB7XG4gIGVsZW1lbnQ6IHN0cmluZztcbiAgdHlwZTogRWxlbWVudFR5cGU7XG4gIGxvY2FsVmVyc2lvbjogc3RyaW5nO1xuICByZW1vdGVWZXJzaW9uOiBzdHJpbmc7XG4gIGxvY2FsTW9kaWZpZWQ6IERhdGU7XG4gIHJlbW90ZU1vZGlmaWVkOiBEYXRlO1xuICByZXNvbHV0aW9uPzogJ2xvY2FsJyB8ICdyZW1vdGUnIHwgJ21hbnVhbCc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVmVyc2lvbkluZm8ge1xuICB2ZXJzaW9uOiBzdHJpbmc7XG4gIHRpbWVzdGFtcDogRGF0ZTtcbiAgYXV0aG9yOiBzdHJpbmc7XG4gIGhhc2g6IHN0cmluZztcbiAgc2l6ZTogbnVtYmVyO1xuICBzb3VyY2U6ICdsb2NhbCcgfCAncmVtb3RlJztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFbGVtZW50RGlmZiB7XG4gIGVsZW1lbnQ6IHN0cmluZztcbiAgdHlwZTogRWxlbWVudFR5cGU7XG4gIGNoYW5nZXM6IHtcbiAgICBtZXRhZGF0YT86IHtcbiAgICAgIGZpZWxkOiBzdHJpbmc7XG4gICAgICBvbGRWYWx1ZTogYW55O1xuICAgICAgbmV3VmFsdWU6IGFueTtcbiAgICB9W107XG4gICAgY29udGVudD86IHtcbiAgICAgIGFkZGl0aW9uczogbnVtYmVyO1xuICAgICAgZGVsZXRpb25zOiBudW1iZXI7XG4gICAgICBkaWZmOiBzdHJpbmc7XG4gICAgfTtcbiAgfTtcbn1cblxuZXhwb3J0IGNsYXNzIFBvcnRmb2xpb1N5bmNNYW5hZ2VyIHtcbiAgcHJpdmF0ZSBjb25maWdNYW5hZ2VyOiBDb25maWdNYW5hZ2VyO1xuICBwcml2YXRlIHBvcnRmb2xpb01hbmFnZXI6IFBvcnRmb2xpb01hbmFnZXI7XG4gIHByaXZhdGUgcmVwb01hbmFnZXI6IFBvcnRmb2xpb1JlcG9NYW5hZ2VyO1xuICBwcml2YXRlIGluZGV4ZXI6IEdpdEh1YlBvcnRmb2xpb0luZGV4ZXI7XG4gIFxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLmNvbmZpZ01hbmFnZXIgPSBDb25maWdNYW5hZ2VyLmdldEluc3RhbmNlKCk7XG4gICAgdGhpcy5wb3J0Zm9saW9NYW5hZ2VyID0gUG9ydGZvbGlvTWFuYWdlci5nZXRJbnN0YW5jZSgpO1xuICAgIHRoaXMucmVwb01hbmFnZXIgPSBuZXcgUG9ydGZvbGlvUmVwb01hbmFnZXIoKTtcbiAgICB0aGlzLmluZGV4ZXIgPSBHaXRIdWJQb3J0Zm9saW9JbmRleGVyLmdldEluc3RhbmNlKCk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBNYWluIGhhbmRsZXIgZm9yIHN5bmMgb3BlcmF0aW9uc1xuICAgKi9cbiAgcHVibGljIGFzeW5jIGhhbmRsZVN5bmNPcGVyYXRpb24ocGFyYW1zOiBTeW5jT3BlcmF0aW9uKTogUHJvbWlzZTxTeW5jUmVzdWx0PiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIENoZWNrIGlmIHN5bmMgaXMgZW5hYmxlZCBpbiBjb25maWdcbiAgICAgIGNvbnN0IGNvbmZpZyA9IHRoaXMuY29uZmlnTWFuYWdlci5nZXRDb25maWcoKTtcbiAgICAgIGlmICghY29uZmlnLnN5bmMuZW5hYmxlZCAmJiBwYXJhbXMub3BlcmF0aW9uICE9PSAnbGlzdC1yZW1vdGUnKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgbWVzc2FnZTogJ1N5bmMgaXMgZGlzYWJsZWQuIEVuYWJsZSBpdCB3aXRoOiBkb2xsaG91c2VfY29uZmlnIC0tYWN0aW9uIHVwZGF0ZSAtLXNldHRpbmcgc3luYy5lbmFibGVkIC0tdmFsdWUgdHJ1ZSdcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gQ2hlY2sgYnVsayBwZXJtaXNzaW9uc1xuICAgICAgaWYgKHBhcmFtcy5idWxrKSB7XG4gICAgICAgIGNvbnN0IGJ1bGtBbGxvd2VkID0gdGhpcy5pc0J1bGtPcGVyYXRpb25BbGxvd2VkKHBhcmFtcy5vcGVyYXRpb24sIGNvbmZpZyk7XG4gICAgICAgIGlmICghYnVsa0FsbG93ZWQuYWxsb3dlZCkge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgIG1lc3NhZ2U6IGJ1bGtBbGxvd2VkLm1lc3NhZ2VcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIEhhbmRsZSBvcGVyYXRpb25zXG4gICAgICBzd2l0Y2ggKHBhcmFtcy5vcGVyYXRpb24pIHtcbiAgICAgICAgY2FzZSAnbGlzdC1yZW1vdGUnOlxuICAgICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmxpc3RSZW1vdGVFbGVtZW50cyhwYXJhbXMuZWxlbWVudF90eXBlKTtcbiAgICAgICAgICBcbiAgICAgICAgY2FzZSAnZG93bmxvYWQnOlxuICAgICAgICAgIGlmIChwYXJhbXMuYnVsaykge1xuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuYnVsa0Rvd25sb2FkKHBhcmFtcy5lbGVtZW50X3R5cGUsIHBhcmFtcy5jb25maXJtKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKHBhcmFtcy5lbGVtZW50X25hbWUpIHtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmRvd25sb2FkRWxlbWVudChcbiAgICAgICAgICAgICAgcGFyYW1zLmVsZW1lbnRfbmFtZSxcbiAgICAgICAgICAgICAgcGFyYW1zLmVsZW1lbnRfdHlwZSEsXG4gICAgICAgICAgICAgIHBhcmFtcy52ZXJzaW9uLFxuICAgICAgICAgICAgICBwYXJhbXMuZm9yY2VcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBtZXNzYWdlOiAnRWxlbWVudCBuYW1lIHJlcXVpcmVkIGZvciBpbmRpdmlkdWFsIGRvd25sb2FkJ1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgICAgXG4gICAgICAgIGNhc2UgJ3VwbG9hZCc6XG4gICAgICAgICAgaWYgKHBhcmFtcy5idWxrKSB7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5idWxrVXBsb2FkKHBhcmFtcy5lbGVtZW50X3R5cGUsIHBhcmFtcy5jb25maXJtKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKHBhcmFtcy5lbGVtZW50X25hbWUpIHtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnVwbG9hZEVsZW1lbnQoXG4gICAgICAgICAgICAgIHBhcmFtcy5lbGVtZW50X25hbWUsXG4gICAgICAgICAgICAgIHBhcmFtcy5lbGVtZW50X3R5cGUhLFxuICAgICAgICAgICAgICBwYXJhbXMuY29uZmlybVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6ICdFbGVtZW50IG5hbWUgcmVxdWlyZWQgZm9yIGluZGl2aWR1YWwgdXBsb2FkJ1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgICAgXG4gICAgICAgIGNhc2UgJ2NvbXBhcmUnOlxuICAgICAgICAgIGlmIChwYXJhbXMuZWxlbWVudF9uYW1lICYmIHBhcmFtcy5lbGVtZW50X3R5cGUpIHtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmNvbXBhcmVWZXJzaW9ucyhcbiAgICAgICAgICAgICAgcGFyYW1zLmVsZW1lbnRfbmFtZSxcbiAgICAgICAgICAgICAgcGFyYW1zLmVsZW1lbnRfdHlwZSxcbiAgICAgICAgICAgICAgcGFyYW1zLnNob3dfZGlmZlxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6ICdFbGVtZW50IG5hbWUgYW5kIHR5cGUgcmVxdWlyZWQgZm9yIGNvbXBhcmlzb24nXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cbiAgICAgICAgICBcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBtZXNzYWdlOiBgVW5rbm93biBvcGVyYXRpb246ICR7cGFyYW1zLm9wZXJhdGlvbn1gXG4gICAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdTeW5jIG9wZXJhdGlvbiBmYWlsZWQnLCB7XG4gICAgICAgIG9wZXJhdGlvbjogcGFyYW1zLm9wZXJhdGlvbixcbiAgICAgICAgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKVxuICAgICAgfSk7XG4gICAgICBcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBtZXNzYWdlOiBgU3luYyBvcGVyYXRpb24gZmFpbGVkOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gXG4gICAgICB9O1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIENoZWNrIGlmIGJ1bGsgb3BlcmF0aW9uIGlzIGFsbG93ZWRcbiAgICovXG4gIHByaXZhdGUgaXNCdWxrT3BlcmF0aW9uQWxsb3dlZChvcGVyYXRpb246IHN0cmluZywgY29uZmlnOiBEb2xsaG91c2VDb25maWcpOiB7IGFsbG93ZWQ6IGJvb2xlYW47IG1lc3NhZ2U6IHN0cmluZyB9IHtcbiAgICBpZiAob3BlcmF0aW9uID09PSAnZG93bmxvYWQnICYmICFjb25maWcuc3luYy5idWxrLmRvd25sb2FkX2VuYWJsZWQpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGFsbG93ZWQ6IGZhbHNlLFxuICAgICAgICBtZXNzYWdlOiAnQnVsayBkb3dubG9hZCBpcyBkaXNhYmxlZC4gRW5hYmxlIHdpdGg6IGRvbGxob3VzZV9jb25maWcgLS1hY3Rpb24gdXBkYXRlIC0tc2V0dGluZyBzeW5jLmJ1bGsuZG93bmxvYWRfZW5hYmxlZCAtLXZhbHVlIHRydWUnXG4gICAgICB9O1xuICAgIH1cbiAgICBcbiAgICBpZiAob3BlcmF0aW9uID09PSAndXBsb2FkJyAmJiAhY29uZmlnLnN5bmMuYnVsay51cGxvYWRfZW5hYmxlZCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYWxsb3dlZDogZmFsc2UsXG4gICAgICAgIG1lc3NhZ2U6ICdCdWxrIHVwbG9hZCBpcyBkaXNhYmxlZC4gRW5hYmxlIHdpdGg6IGRvbGxob3VzZV9jb25maWcgLS1hY3Rpb24gdXBkYXRlIC0tc2V0dGluZyBzeW5jLmJ1bGsudXBsb2FkX2VuYWJsZWQgLS12YWx1ZSB0cnVlJ1xuICAgICAgfTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHsgYWxsb3dlZDogdHJ1ZSwgbWVzc2FnZTogJycgfTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIExpc3QgZWxlbWVudHMgYXZhaWxhYmxlIGluIEdpdEh1YiBwb3J0Zm9saW9cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgbGlzdFJlbW90ZUVsZW1lbnRzKGZpbHRlclR5cGU/OiBFbGVtZW50VHlwZSk6IFByb21pc2U8U3luY1Jlc3VsdD4ge1xuICAgIHRyeSB7XG4gICAgICAvLyBHZXQgR2l0SHViIHRva2VuXG4gICAgICBjb25zdCB0b2tlbiA9IGF3YWl0IFRva2VuTWFuYWdlci5nZXRHaXRIdWJUb2tlbkFzeW5jKCk7XG4gICAgICBpZiAoIXRva2VuKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgbWVzc2FnZTogJ0dpdEh1YiBhdXRoZW50aWNhdGlvbiByZXF1aXJlZC4gVXNlIHNldHVwX2dpdGh1Yl9hdXRoIGZpcnN0LidcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgdGhpcy5yZXBvTWFuYWdlci5zZXRUb2tlbih0b2tlbik7XG4gICAgICBcbiAgICAgIC8vIEdldCBpbmRleCBvZiBHaXRIdWIgcG9ydGZvbGlvXG4gICAgICBjb25zdCBpbmRleCA9IGF3YWl0IHRoaXMuaW5kZXhlci5nZXRJbmRleCgpO1xuICAgICAgXG4gICAgICBpZiAoIWluZGV4IHx8IGluZGV4LnRvdGFsRWxlbWVudHMgPT09IDApIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgIG1lc3NhZ2U6ICdObyBlbGVtZW50cyBmb3VuZCBpbiBHaXRIdWIgcG9ydGZvbGlvJyxcbiAgICAgICAgICBlbGVtZW50czogW11cbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gRm9ybWF0IGVsZW1lbnRzIGZvciBkaXNwbGF5XG4gICAgICBjb25zdCBlbGVtZW50czogU3luY0VsZW1lbnRJbmZvW10gPSBbXTtcbiAgICAgIFxuICAgICAgZm9yIChjb25zdCBbdHlwZSwgZW50cmllc10gb2YgaW5kZXguZWxlbWVudHMpIHtcbiAgICAgICAgLy8gU2tpcCBpZiBmaWx0ZXJpbmcgYnkgdHlwZSBhbmQgdGhpcyBpc24ndCB0aGUgcmVxdWVzdGVkIHR5cGVcbiAgICAgICAgaWYgKGZpbHRlclR5cGUgJiYgdHlwZSAhPT0gZmlsdGVyVHlwZSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgICBlbGVtZW50cy5wdXNoKHtcbiAgICAgICAgICAgIG5hbWU6IGVudHJ5Lm5hbWUsXG4gICAgICAgICAgICB0eXBlOiB0eXBlLFxuICAgICAgICAgICAgcmVtb3RlVmVyc2lvbjogZW50cnkudmVyc2lvbixcbiAgICAgICAgICAgIHN0YXR1czogJ3VuY2hhbmdlZCcsXG4gICAgICAgICAgICBhY3Rpb246ICdkb3dubG9hZCdcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICBtZXNzYWdlOiBgRm91bmQgJHtlbGVtZW50cy5sZW5ndGh9IGVsZW1lbnRzIGluIEdpdEh1YiBwb3J0Zm9saW9gLFxuICAgICAgICBlbGVtZW50c1xuICAgICAgfTtcbiAgICAgIFxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgbWVzc2FnZTogYEZhaWxlZCB0byBsaXN0IHJlbW90ZSBlbGVtZW50czogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YFxuICAgICAgfTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBEb3dubG9hZCBhIHNwZWNpZmljIGVsZW1lbnQgZnJvbSBHaXRIdWJcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZG93bmxvYWRFbGVtZW50KFxuICAgIGVsZW1lbnROYW1lOiBzdHJpbmcsXG4gICAgZWxlbWVudFR5cGU6IEVsZW1lbnRUeXBlLFxuICAgIHZlcnNpb24/OiBzdHJpbmcsXG4gICAgZm9yY2U/OiBib29sZWFuXG4gICk6IFByb21pc2U8U3luY1Jlc3VsdD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjb25maWcgPSB0aGlzLmNvbmZpZ01hbmFnZXIuZ2V0Q29uZmlnKCk7XG4gICAgICBcbiAgICAgIC8vIFZhbGlkYXRlIGVsZW1lbnQgbmFtZVxuICAgICAgY29uc3QgdmFsaWRhdGlvbiA9IFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKGVsZW1lbnROYW1lKTtcbiAgICAgIGlmICghdmFsaWRhdGlvbi5pc1ZhbGlkKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgbWVzc2FnZTogYEludmFsaWQgZWxlbWVudCBuYW1lOiAke3ZhbGlkYXRpb24uZGV0ZWN0ZWRJc3N1ZXM/LlswXSB8fCAndW5rbm93biBlcnJvcid9YFxuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBHZXQgdG9rZW4gYW5kIHNldCBpdFxuICAgICAgY29uc3QgdG9rZW4gPSBhd2FpdCBUb2tlbk1hbmFnZXIuZ2V0R2l0SHViVG9rZW5Bc3luYygpO1xuICAgICAgaWYgKCF0b2tlbikge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgIG1lc3NhZ2U6ICdHaXRIdWIgYXV0aGVudGljYXRpb24gcmVxdWlyZWQnXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIHRoaXMucmVwb01hbmFnZXIuc2V0VG9rZW4odG9rZW4pO1xuICAgICAgXG4gICAgICAvLyBHZXQgR2l0SHViIGluZGV4XG4gICAgICBjb25zdCBpbmRleCA9IGF3YWl0IHRoaXMuaW5kZXhlci5nZXRJbmRleCgpO1xuICAgICAgXG4gICAgICAvLyBGaW5kIHRoZSBlbGVtZW50IC0gZmlyc3QgdHJ5IGV4YWN0IG1hdGNoLCB0aGVuIGZ1enp5IG1hdGNoXG4gICAgICBjb25zdCBlbnRyaWVzID0gaW5kZXguZWxlbWVudHMuZ2V0KGVsZW1lbnRUeXBlKSB8fCBbXTtcbiAgICAgIGxldCBlbnRyeSA9IGVudHJpZXMuZmluZChlID0+IGUubmFtZSA9PT0gZWxlbWVudE5hbWUpO1xuICAgICAgXG4gICAgICAvLyBJZiBleGFjdCBtYXRjaCBub3QgZm91bmQsIHRyeSBmdXp6eSBtYXRjaGluZ1xuICAgICAgaWYgKCFlbnRyeSkge1xuICAgICAgICAvLyBUcnkgY2FzZS1pbnNlbnNpdGl2ZSBleGFjdCBtYXRjaCBmaXJzdFxuICAgICAgICBlbnRyeSA9IGVudHJpZXMuZmluZChlID0+IGUubmFtZS50b0xvd2VyQ2FzZSgpID09PSBlbGVtZW50TmFtZS50b0xvd2VyQ2FzZSgpKTtcbiAgICAgICAgXG4gICAgICAgIC8vIElmIHN0aWxsIG5vdCBmb3VuZCwgdHJ5IGZ1enp5IG1hdGNoaW5nXG4gICAgICAgIGlmICghZW50cnkpIHtcbiAgICAgICAgICBjb25zdCBmdXp6eU1hdGNoID0gdGhpcy5maW5kRnV6enlNYXRjaChlbGVtZW50TmFtZSwgZW50cmllcyk7XG4gICAgICAgICAgaWYgKGZ1enp5TWF0Y2gpIHtcbiAgICAgICAgICAgIGxvZ2dlci5pbmZvKGBGdXp6eSBtYXRjaCBmb3VuZDogJyR7ZWxlbWVudE5hbWV9JyBtYXRjaGVkIHRvICcke2Z1enp5TWF0Y2gubmFtZX0nYCk7XG4gICAgICAgICAgICBlbnRyeSA9IGZ1enp5TWF0Y2g7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIGlmICghZW50cnkpIHtcbiAgICAgICAgLy8gR2VuZXJhdGUgaGVscGZ1bCBzdWdnZXN0aW9uc1xuICAgICAgICBjb25zdCBzdWdnZXN0aW9ucyA9IHRoaXMuZ2V0U3VnZ2VzdGlvbnMoZWxlbWVudE5hbWUsIGVudHJpZXMpO1xuICAgICAgICBjb25zdCBzdWdnZXN0aW9uVGV4dCA9IHN1Z2dlc3Rpb25zLmxlbmd0aCA+IDAgXG4gICAgICAgICAgPyBgXFxuXFxuRGlkIHlvdSBtZWFuIG9uZSBvZiB0aGVzZT9cXG4ke3N1Z2dlc3Rpb25zLm1hcChzID0+IGAgIOKAoiAke3MubmFtZX1gKS5qb2luKCdcXG4nKX1gXG4gICAgICAgICAgOiAnJztcbiAgICAgICAgXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgbWVzc2FnZTogYEVsZW1lbnQgJyR7ZWxlbWVudE5hbWV9JyAoJHtlbGVtZW50VHlwZX0pIG5vdCBmb3VuZCBpbiBHaXRIdWIgcG9ydGZvbGlvJHtzdWdnZXN0aW9uVGV4dH1gXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIENoZWNrIGZvciBsb2NhbCBjb25mbGljdHNcbiAgICAgIGNvbnN0IGxvY2FsUGF0aCA9IHRoaXMucG9ydGZvbGlvTWFuYWdlci5nZXRFbGVtZW50UGF0aChlbGVtZW50VHlwZSwgYCR7ZWxlbWVudE5hbWV9Lm1kYCk7XG4gICAgICBsZXQgaGFzTG9jYWxWZXJzaW9uID0gZmFsc2U7XG4gICAgICBsZXQgbG9jYWxDb250ZW50OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgICAgIFxuICAgICAgdHJ5IHtcbiAgICAgICAgbG9jYWxDb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUobG9jYWxQYXRoLCAndXRmLTgnKTtcbiAgICAgICAgaGFzTG9jYWxWZXJzaW9uID0gdHJ1ZTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBObyBsb2NhbCB2ZXJzaW9uIGV4aXN0c1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBEb3dubG9hZCB0aGUgZWxlbWVudFxuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChlbnRyeS5kb3dubG9hZFVybCwge1xuICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiBgQmVhcmVyICR7dG9rZW59YCxcbiAgICAgICAgICAnQWNjZXB0JzogJ2FwcGxpY2F0aW9uL3ZuZC5naXRodWIudjMucmF3J1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIFxuICAgICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBkb3dubG9hZDogJHtyZXNwb25zZS5zdGF0dXNUZXh0fWApO1xuICAgICAgfVxuICAgICAgXG4gICAgICBjb25zdCByZW1vdGVDb250ZW50ID0gYXdhaXQgcmVzcG9uc2UudGV4dCgpO1xuICAgICAgXG4gICAgICAvLyBWYWxpZGF0ZSBjb250ZW50IHNlY3VyaXR5XG4gICAgICBjb25zdCB2YWxpZGF0aW9uUmVzdWx0ID0gQ29udGVudFZhbGlkYXRvci52YWxpZGF0ZUFuZFNhbml0aXplKHJlbW90ZUNvbnRlbnQpO1xuICAgICAgaWYgKCF2YWxpZGF0aW9uUmVzdWx0LmlzVmFsaWQgJiYgdmFsaWRhdGlvblJlc3VsdC5zZXZlcml0eSA9PT0gJ2NyaXRpY2FsJykge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgIG1lc3NhZ2U6IGBTZWN1cml0eSBpc3N1ZSBkZXRlY3RlZCBpbiByZW1vdGUgY29udGVudDogJHt2YWxpZGF0aW9uUmVzdWx0LmRldGVjdGVkUGF0dGVybnM/LmpvaW4oJywgJyl9YFxuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBDaGVjayBpZiBjb250ZW50IGlzIGRpZmZlcmVudFxuICAgICAgaWYgKGhhc0xvY2FsVmVyc2lvbiAmJiBsb2NhbENvbnRlbnQpIHtcbiAgICAgICAgY29uc3QgbG9jYWxIYXNoID0gY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKGxvY2FsQ29udGVudCkuZGlnZXN0KCdoZXgnKTtcbiAgICAgICAgY29uc3QgcmVtb3RlSGFzaCA9IGNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShyZW1vdGVDb250ZW50KS5kaWdlc3QoJ2hleCcpO1xuICAgICAgICBcbiAgICAgICAgaWYgKGxvY2FsSGFzaCA9PT0gcmVtb3RlSGFzaCkge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgbWVzc2FnZTogYEVsZW1lbnQgJyR7ZWxlbWVudE5hbWV9JyBpcyBhbHJlYWR5IHVwIHRvIGRhdGVgXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgLy8gU2hvdyBjb25maXJtYXRpb24gZm9yIG92ZXJ3cml0ZSB1bmxlc3MgZm9yY2UgZmxhZyBpcyBzZXRcbiAgICAgICAgaWYgKGNvbmZpZy5zeW5jLmluZGl2aWR1YWwucmVxdWlyZV9jb25maXJtYXRpb24gJiYgIWZvcmNlKSB7XG4gICAgICAgICAgY29uc3QgZGlmZiA9IGF3YWl0IHRoaXMuZ2VuZXJhdGVEaWZmKGxvY2FsQ29udGVudCwgcmVtb3RlQ29udGVudCk7XG4gICAgICAgICAgXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgbWVzc2FnZTogYExvY2FsIHZlcnNpb24gZXhpc3RzLiBQbGVhc2UgY29uZmlybSBkb3dubG9hZCB3aWxsIG92ZXJ3cml0ZTpcXG5cXG4ke2RpZmZ9XFxuXFxuVG8gcHJvY2VlZCwgdXNlIC0tZm9yY2UgZmxhZ2AsXG4gICAgICAgICAgICBkYXRhOiB7IHJlcXVpcmVzQ29uZmlybWF0aW9uOiB0cnVlIH1cbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIFNhdmUgdGhlIGVsZW1lbnRcbiAgICAgIGF3YWl0IGZzLm1rZGlyKHBhdGguZGlybmFtZShsb2NhbFBhdGgpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgIGF3YWl0IGZzLndyaXRlRmlsZShsb2NhbFBhdGgsIHJlbW90ZUNvbnRlbnQsICd1dGYtOCcpO1xuICAgICAgXG4gICAgICBsb2dnZXIuaW5mbygnRWxlbWVudCBkb3dubG9hZGVkIGZyb20gR2l0SHViJywge1xuICAgICAgICBlbGVtZW50OiBlbGVtZW50TmFtZSxcbiAgICAgICAgdHlwZTogZWxlbWVudFR5cGUsXG4gICAgICAgIHZlcnNpb246IGVudHJ5LnZlcnNpb25cbiAgICAgIH0pO1xuICAgICAgXG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IGRvd25sb2FkZWQgJyR7ZWxlbWVudE5hbWV9JyAoJHtlbGVtZW50VHlwZX0pIGZyb20gR2l0SHViIHBvcnRmb2xpb2BcbiAgICAgIH07XG4gICAgICBcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgIG1lc3NhZ2U6IGBGYWlsZWQgdG8gZG93bmxvYWQgZWxlbWVudDogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YFxuICAgICAgfTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBVcGxvYWQgYSBzcGVjaWZpYyBlbGVtZW50IHRvIEdpdEh1YlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB1cGxvYWRFbGVtZW50KFxuICAgIGVsZW1lbnROYW1lOiBzdHJpbmcsXG4gICAgZWxlbWVudFR5cGU6IEVsZW1lbnRUeXBlLFxuICAgIGNvbmZpcm0/OiBib29sZWFuXG4gICk6IFByb21pc2U8U3luY1Jlc3VsdD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjb25maWcgPSB0aGlzLmNvbmZpZ01hbmFnZXIuZ2V0Q29uZmlnKCk7XG4gICAgICBcbiAgICAgIC8vIENoZWNrIGZvciBsb2NhbCBlbGVtZW50XG4gICAgICBjb25zdCBsb2NhbFBhdGggPSB0aGlzLnBvcnRmb2xpb01hbmFnZXIuZ2V0RWxlbWVudFBhdGgoZWxlbWVudFR5cGUsIGAke2VsZW1lbnROYW1lfS5tZGApO1xuICAgICAgXG4gICAgICBsZXQgY29udGVudDogc3RyaW5nO1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKGxvY2FsUGF0aCwgJ3V0Zi04Jyk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICBtZXNzYWdlOiBgRWxlbWVudCAnJHtlbGVtZW50TmFtZX0nICgke2VsZW1lbnRUeXBlfSkgbm90IGZvdW5kIGxvY2FsbHlgXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIENoZWNrIHByaXZhY3kgbWV0YWRhdGFcbiAgICAgIGNvbnN0IHBhcnNlZCA9IFNlY3VyZVlhbWxQYXJzZXIucGFyc2UoY29udGVudCwge1xuICAgICAgICBtYXhZYW1sU2l6ZTogNjQgKiAxMDI0LFxuICAgICAgICB2YWxpZGF0ZUNvbnRlbnQ6IGZhbHNlLFxuICAgICAgICB2YWxpZGF0ZUZpZWxkczogZmFsc2VcbiAgICAgIH0pO1xuICAgICAgXG4gICAgICBpZiAocGFyc2VkLmRhdGE/LnByaXZhY3k/LmxvY2FsX29ubHkgPT09IHRydWUpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICBtZXNzYWdlOiBgRWxlbWVudCAnJHtlbGVtZW50TmFtZX0nIGlzIG1hcmtlZCBhcyBsb2NhbC1vbmx5IGFuZCBjYW5ub3QgYmUgdXBsb2FkZWRgXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIFZhbGlkYXRlIGNvbnRlbnQgc2VjdXJpdHlcbiAgICAgIGNvbnN0IHZhbGlkYXRpb25SZXN1bHQgPSBDb250ZW50VmFsaWRhdG9yLnZhbGlkYXRlQW5kU2FuaXRpemUoY29udGVudCk7XG4gICAgICBpZiAoIXZhbGlkYXRpb25SZXN1bHQuaXNWYWxpZCAmJiB2YWxpZGF0aW9uUmVzdWx0LnNldmVyaXR5ID09PSAnY3JpdGljYWwnKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgbWVzc2FnZTogYFNlY3VyaXR5IGlzc3VlIGRldGVjdGVkOiAke3ZhbGlkYXRpb25SZXN1bHQuZGV0ZWN0ZWRQYXR0ZXJucz8uam9pbignLCAnKX1gXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIFNjYW4gZm9yIHNlbnNpdGl2ZSBjb250ZW50IGlmIGNvbmZpZ3VyZWRcbiAgICAgIGlmIChjb25maWcuc3luYy5wcml2YWN5LnNjYW5fZm9yX3NlY3JldHMpIHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKCdTY2FubmluZyBmb3Igc2VjcmV0cyBiZWZvcmUgdXBsb2FkJyk7XG4gICAgICAgIC8vIEltcGxlbWVudCBhY3R1YWwgc2VjcmV0IHNjYW5uaW5nXG4gICAgICAgIGNvbnN0IHNlY3JldFBhdHRlcm5zID0gW1xuICAgICAgICAgIC9hcGlbXy1dP2tleVxccypbOj1dXFxzKlsnXCJdW14nXCJdK1snXCJdL2dpLFxuICAgICAgICAgIC9zZWNyZXRcXHMqWzo9XVxccypbJ1wiXVteJ1wiXStbJ1wiXS9naSxcbiAgICAgICAgICAvcGFzc3dvcmRcXHMqWzo9XVxccypbJ1wiXVteJ1wiXStbJ1wiXS9naSxcbiAgICAgICAgICAvdG9rZW5cXHMqWzo9XVxccypbJ1wiXVteJ1wiXStbJ1wiXS9naSxcbiAgICAgICAgICAvcHJpdmF0ZVtfLV0/a2V5XFxzKls6PV1cXHMqWydcIl1bXidcIl0rWydcIl0vZ2lcbiAgICAgICAgXTtcbiAgICAgICAgXG4gICAgICAgIGZvciAoY29uc3QgcGF0dGVybiBvZiBzZWNyZXRQYXR0ZXJucykge1xuICAgICAgICAgIGlmIChwYXR0ZXJuLnRlc3QoY29udGVudCkpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBgUG90ZW50aWFsIHNlY3JldCBkZXRlY3RlZCBpbiBjb250ZW50LiBQbGVhc2UgcmV2aWV3IGFuZCByZW1vdmUgc2Vuc2l0aXZlIGluZm9ybWF0aW9uIGJlZm9yZSB1cGxvYWRpbmcuYFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gR2V0IGNvbmZpcm1hdGlvbiBpZiByZXF1aXJlZCAodW5sZXNzIGFscmVhZHkgY29uZmlybWVkKVxuICAgICAgaWYgKGNvbmZpZy5zeW5jLmluZGl2aWR1YWwucmVxdWlyZV9jb25maXJtYXRpb24gJiYgIWNvbmZpcm0pIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICBtZXNzYWdlOiBgUGxlYXNlIGNvbmZpcm0gdXBsb2FkIG9mICcke2VsZW1lbnROYW1lfScgKCR7ZWxlbWVudFR5cGV9KSB0byBHaXRIdWIuXFxuXFxuQ29udGVudCBwcmV2aWV3OlxcbiR7Y29udGVudC5zdWJzdHJpbmcoMCwgNTAwKX0uLi5cXG5cXG5UbyBwcm9jZWVkLCB1c2UgLS1jb25maXJtIGZsYWdgLFxuICAgICAgICAgIGRhdGE6IHsgcmVxdWlyZXNDb25maXJtYXRpb246IHRydWUgfVxuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBHZXQgdG9rZW4gYW5kIHZhbGlkYXRlXG4gICAgICBjb25zdCB0b2tlbiA9IGF3YWl0IFRva2VuTWFuYWdlci5nZXRHaXRIdWJUb2tlbkFzeW5jKCk7XG4gICAgICBpZiAoIXRva2VuKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgbWVzc2FnZTogJ0dpdEh1YiBhdXRoZW50aWNhdGlvbiByZXF1aXJlZCdcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gQ3JlYXRlIGFuIElFbGVtZW50IG9iamVjdCBmb3IgdGhlIFBvcnRmb2xpb1JlcG9NYW5hZ2VyXG4gICAgICBjb25zdCBlbGVtZW50OiBJRWxlbWVudCA9IHtcbiAgICAgICAgaWQ6IGAke2VsZW1lbnRUeXBlfV8ke2VsZW1lbnROYW1lfV8ke0RhdGUubm93KCl9YCxcbiAgICAgICAgdHlwZTogZWxlbWVudFR5cGUsXG4gICAgICAgIHZlcnNpb246IHBhcnNlZC5kYXRhPy52ZXJzaW9uIHx8ICcxLjAuMCcsXG4gICAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgICAgbmFtZTogZWxlbWVudE5hbWUsXG4gICAgICAgICAgZGVzY3JpcHRpb246IHBhcnNlZC5kYXRhPy5kZXNjcmlwdGlvbiB8fCAnJyxcbiAgICAgICAgICBhdXRob3I6IHBhcnNlZC5kYXRhPy5hdXRob3IgfHwgJ3Vua25vd24nLFxuICAgICAgICAgIGNyZWF0ZWQ6IHBhcnNlZC5kYXRhPy5jcmVhdGVkIHx8IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgICAgICBtb2RpZmllZDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICAgIHRhZ3M6IHBhcnNlZC5kYXRhPy50YWdzIHx8IFtdLFxuICAgICAgICAgIGN1c3RvbTogcGFyc2VkLmRhdGFcbiAgICAgICAgfSxcbiAgICAgICAgdmFsaWRhdGU6ICgpID0+ICh7IHZhbGlkOiB0cnVlLCBlcnJvcnM6IFtdLCB3YXJuaW5nczogW10gfSksXG4gICAgICAgIHNlcmlhbGl6ZTogKCkgPT4gY29udGVudCxcbiAgICAgICAgZGVzZXJpYWxpemU6ICgpID0+IHt9LFxuICAgICAgICBnZXRTdGF0dXM6ICgpID0+IEVsZW1lbnRTdGF0dXMuQUNUSVZFXG4gICAgICB9O1xuICAgICAgXG4gICAgICAvLyBVc2UgUG9ydGZvbGlvUmVwb01hbmFnZXIgdG8gdXBsb2FkXG4gICAgICB0aGlzLnJlcG9NYW5hZ2VyLnNldFRva2VuKHRva2VuKTtcbiAgICAgIFxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgdXJsID0gYXdhaXQgdGhpcy5yZXBvTWFuYWdlci5zYXZlRWxlbWVudChlbGVtZW50LCB0cnVlKTsgLy8gY29uc2VudCBpcyB0cnVlIHNpbmNlIHdlJ3ZlIGFscmVhZHkgY2hlY2tlZFxuICAgICAgICBcbiAgICAgICAgbG9nZ2VyLmluZm8oJ0VsZW1lbnQgdXBsb2FkZWQgdG8gR2l0SHViJywge1xuICAgICAgICAgIGVsZW1lbnQ6IGVsZW1lbnROYW1lLFxuICAgICAgICAgIHR5cGU6IGVsZW1lbnRUeXBlLFxuICAgICAgICAgIHVybFxuICAgICAgICB9KTtcbiAgICAgICAgXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IHVwbG9hZGVkICcke2VsZW1lbnROYW1lfScgKCR7ZWxlbWVudFR5cGV9KSB0byBHaXRIdWIgcG9ydGZvbGlvYCxcbiAgICAgICAgICBkYXRhOiB7IHVybCB9XG4gICAgICAgIH07XG4gICAgICB9IGNhdGNoICh1cGxvYWRFcnJvcikge1xuICAgICAgICAvLyBIYW5kbGUgc3BlY2lmaWMgZXJyb3JzXG4gICAgICAgIGlmICh1cGxvYWRFcnJvciBpbnN0YW5jZW9mIEVycm9yICYmIHVwbG9hZEVycm9yLm1lc3NhZ2UuaW5jbHVkZXMoJ3JlcG9zaXRvcnkgZG9lcyBub3QgZXhpc3QnKSkge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgIG1lc3NhZ2U6IGBHaXRIdWIgcG9ydGZvbGlvIHJlcG9zaXRvcnkgbm90IGZvdW5kLiBQbGVhc2UgaW5pdGlhbGl6ZSBpdCBmaXJzdCB1c2luZyBpbml0X3BvcnRmb2xpbyB0b29sLmBcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHRocm93IHVwbG9hZEVycm9yO1xuICAgICAgfVxuICAgICAgXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBtZXNzYWdlOiBgRmFpbGVkIHRvIHVwbG9hZCBlbGVtZW50OiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gXG4gICAgICB9O1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIENvbXBhcmUgbG9jYWwgYW5kIHJlbW90ZSB2ZXJzaW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjb21wYXJlVmVyc2lvbnMoXG4gICAgZWxlbWVudE5hbWU6IHN0cmluZyxcbiAgICBlbGVtZW50VHlwZTogRWxlbWVudFR5cGUsXG4gICAgc2hvd0RpZmY/OiBib29sZWFuXG4gICk6IFByb21pc2U8U3luY1Jlc3VsdD4ge1xuICAgIHRyeSB7XG4gICAgICAvLyBHZXQgbG9jYWwgdmVyc2lvblxuICAgICAgY29uc3QgbG9jYWxQYXRoID0gdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmdldEVsZW1lbnRQYXRoKGVsZW1lbnRUeXBlLCBgJHtlbGVtZW50TmFtZX0ubWRgKTtcbiAgICAgIGxldCBsb2NhbENvbnRlbnQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAgICAgbGV0IGxvY2FsVmVyc2lvbjogVmVyc2lvbkluZm8gfCBudWxsID0gbnVsbDtcbiAgICAgIFxuICAgICAgdHJ5IHtcbiAgICAgICAgbG9jYWxDb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUobG9jYWxQYXRoLCAndXRmLTgnKTtcbiAgICAgICAgY29uc3QgcGFyc2VkID0gU2VjdXJlWWFtbFBhcnNlci5wYXJzZShsb2NhbENvbnRlbnQsIHtcbiAgICAgICAgICBtYXhZYW1sU2l6ZTogNjQgKiAxMDI0LFxuICAgICAgICAgIHZhbGlkYXRlQ29udGVudDogZmFsc2UsXG4gICAgICAgICAgdmFsaWRhdGVGaWVsZHM6IGZhbHNlXG4gICAgICAgIH0pO1xuICAgICAgICBcbiAgICAgICAgbG9jYWxWZXJzaW9uID0ge1xuICAgICAgICAgIHZlcnNpb246IHBhcnNlZC5kYXRhPy52ZXJzaW9uIHx8ICcxLjAuMCcsXG4gICAgICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZShwYXJzZWQuZGF0YT8udXBkYXRlZCB8fCBwYXJzZWQuZGF0YT8uY3JlYXRlZCB8fCBEYXRlLm5vdygpKSxcbiAgICAgICAgICBhdXRob3I6IHBhcnNlZC5kYXRhPy5hdXRob3IgfHwgJ3Vua25vd24nLFxuICAgICAgICAgIGhhc2g6IGNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShsb2NhbENvbnRlbnQpLmRpZ2VzdCgnaGV4JyksXG4gICAgICAgICAgc2l6ZTogQnVmZmVyLmJ5dGVMZW5ndGgobG9jYWxDb250ZW50KSxcbiAgICAgICAgICBzb3VyY2U6ICdsb2NhbCdcbiAgICAgICAgfTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBObyBsb2NhbCB2ZXJzaW9uXG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIEdldCByZW1vdGUgdmVyc2lvblxuICAgICAgY29uc3QgdG9rZW4gPSBhd2FpdCBUb2tlbk1hbmFnZXIuZ2V0R2l0SHViVG9rZW5Bc3luYygpO1xuICAgICAgaWYgKCF0b2tlbikge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgIG1lc3NhZ2U6ICdHaXRIdWIgYXV0aGVudGljYXRpb24gcmVxdWlyZWQnXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIGNvbnN0IGluZGV4ID0gYXdhaXQgdGhpcy5pbmRleGVyLmdldEluZGV4KCk7XG4gICAgICBjb25zdCBlbnRyaWVzID0gaW5kZXguZWxlbWVudHMuZ2V0KGVsZW1lbnRUeXBlKSB8fCBbXTtcbiAgICAgIGNvbnN0IGVudHJ5ID0gZW50cmllcy5maW5kKGUgPT4gZS5uYW1lID09PSBlbGVtZW50TmFtZSk7XG4gICAgICBcbiAgICAgIGxldCByZW1vdGVWZXJzaW9uOiBWZXJzaW9uSW5mbyB8IG51bGwgPSBudWxsO1xuICAgICAgbGV0IHJlbW90ZUNvbnRlbnQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAgICAgXG4gICAgICBpZiAoZW50cnkpIHtcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChlbnRyeS5kb3dubG9hZFVybCwge1xuICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3Rva2VufWAsXG4gICAgICAgICAgICAnQWNjZXB0JzogJ2FwcGxpY2F0aW9uL3ZuZC5naXRodWIudjMucmF3J1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIFxuICAgICAgICBpZiAocmVzcG9uc2Uub2spIHtcbiAgICAgICAgICByZW1vdGVDb250ZW50ID0gYXdhaXQgcmVzcG9uc2UudGV4dCgpO1xuICAgICAgICAgIHJlbW90ZVZlcnNpb24gPSB7XG4gICAgICAgICAgICB2ZXJzaW9uOiBlbnRyeS52ZXJzaW9uIHx8ICcxLjAuMCcsXG4gICAgICAgICAgICB0aW1lc3RhbXA6IGVudHJ5Lmxhc3RNb2RpZmllZCxcbiAgICAgICAgICAgIGF1dGhvcjogZW50cnkuYXV0aG9yIHx8ICd1bmtub3duJyxcbiAgICAgICAgICAgIGhhc2g6IGNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShyZW1vdGVDb250ZW50KS5kaWdlc3QoJ2hleCcpLFxuICAgICAgICAgICAgc2l6ZTogZW50cnkuc2l6ZSxcbiAgICAgICAgICAgIHNvdXJjZTogJ3JlbW90ZSdcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIEJ1aWxkIGNvbXBhcmlzb24gcmVzdWx0XG4gICAgICBjb25zdCByZXN1bHQ6IGFueSA9IHtcbiAgICAgICAgZWxlbWVudDogZWxlbWVudE5hbWUsXG4gICAgICAgIHR5cGU6IGVsZW1lbnRUeXBlLFxuICAgICAgICBsb2NhbDogbG9jYWxWZXJzaW9uLFxuICAgICAgICByZW1vdGU6IHJlbW90ZVZlcnNpb25cbiAgICAgIH07XG4gICAgICBcbiAgICAgIGlmIChsb2NhbFZlcnNpb24gJiYgcmVtb3RlVmVyc2lvbikge1xuICAgICAgICByZXN1bHQuc3RhdHVzID0gbG9jYWxWZXJzaW9uLmhhc2ggPT09IHJlbW90ZVZlcnNpb24uaGFzaCA/ICdpZGVudGljYWwnIDogJ2RpZmZlcmVudCc7XG4gICAgICAgIFxuICAgICAgICBpZiAoc2hvd0RpZmYgJiYgbG9jYWxDb250ZW50ICYmIHJlbW90ZUNvbnRlbnQgJiYgcmVzdWx0LnN0YXR1cyA9PT0gJ2RpZmZlcmVudCcpIHtcbiAgICAgICAgICByZXN1bHQuZGlmZiA9IGF3YWl0IHRoaXMuZ2VuZXJhdGVEaWZmKGxvY2FsQ29udGVudCwgcmVtb3RlQ29udGVudCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAobG9jYWxWZXJzaW9uICYmICFyZW1vdGVWZXJzaW9uKSB7XG4gICAgICAgIHJlc3VsdC5zdGF0dXMgPSAnbG9jYWwtb25seSc7XG4gICAgICB9IGVsc2UgaWYgKCFsb2NhbFZlcnNpb24gJiYgcmVtb3RlVmVyc2lvbikge1xuICAgICAgICByZXN1bHQuc3RhdHVzID0gJ3JlbW90ZS1vbmx5JztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJlc3VsdC5zdGF0dXMgPSAnbm90LWZvdW5kJztcbiAgICAgIH1cbiAgICAgIFxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgbWVzc2FnZTogYFZlcnNpb24gY29tcGFyaXNvbiBmb3IgJyR7ZWxlbWVudE5hbWV9JyAoJHtlbGVtZW50VHlwZX0pYCxcbiAgICAgICAgZGF0YTogcmVzdWx0XG4gICAgICB9O1xuICAgICAgXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBtZXNzYWdlOiBgRmFpbGVkIHRvIGNvbXBhcmUgdmVyc2lvbnM6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWBcbiAgICAgIH07XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogQnVsayBkb3dubG9hZCBlbGVtZW50c1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBidWxrRG93bmxvYWQoZWxlbWVudFR5cGU/OiBFbGVtZW50VHlwZSwgY29uZmlybT86IGJvb2xlYW4pOiBQcm9taXNlPFN5bmNSZXN1bHQ+IHtcbiAgICBjb25zdCBjb25maWcgPSB0aGlzLmNvbmZpZ01hbmFnZXIuZ2V0Q29uZmlnKCk7XG4gICAgXG4gICAgaWYgKCFjb25maWcuc3luYy5idWxrLmRvd25sb2FkX2VuYWJsZWQpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBtZXNzYWdlOiAnQnVsayBkb3dubG9hZCBpcyBub3QgZW5hYmxlZCBpbiBjb25maWd1cmF0aW9uJ1xuICAgICAgfTtcbiAgICB9XG4gICAgXG4gICAgLy8gR2V0IGxpc3Qgb2YgcmVtb3RlIGVsZW1lbnRzXG4gICAgY29uc3QgcmVtb3RlUmVzdWx0ID0gYXdhaXQgdGhpcy5saXN0UmVtb3RlRWxlbWVudHMoKTtcbiAgICBpZiAoIXJlbW90ZVJlc3VsdC5zdWNjZXNzIHx8ICFyZW1vdGVSZXN1bHQuZWxlbWVudHMpIHtcbiAgICAgIHJldHVybiByZW1vdGVSZXN1bHQ7XG4gICAgfVxuICAgIFxuICAgIC8vIEZpbHRlciBieSB0eXBlIGlmIHNwZWNpZmllZFxuICAgIGxldCBlbGVtZW50c1RvRG93bmxvYWQgPSByZW1vdGVSZXN1bHQuZWxlbWVudHM7XG4gICAgaWYgKGVsZW1lbnRUeXBlKSB7XG4gICAgICBlbGVtZW50c1RvRG93bmxvYWQgPSBlbGVtZW50c1RvRG93bmxvYWQuZmlsdGVyKGUgPT4gZS50eXBlID09PSBlbGVtZW50VHlwZSk7XG4gICAgfVxuICAgIFxuICAgIGlmIChlbGVtZW50c1RvRG93bmxvYWQubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICBtZXNzYWdlOiAnTm8gZWxlbWVudHMgdG8gZG93bmxvYWQnLFxuICAgICAgICBlbGVtZW50czogW11cbiAgICAgIH07XG4gICAgfVxuICAgIFxuICAgIC8vIFNob3cgcHJldmlldyBpZiByZXF1aXJlZCAodW5sZXNzIGFscmVhZHkgY29uZmlybWVkKVxuICAgIGlmIChjb25maWcuc3luYy5idWxrLnJlcXVpcmVfcHJldmlldyAmJiAhY29uZmlybSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgIG1lc3NhZ2U6IGBCdWxrIGRvd25sb2FkIHByZXZpZXc6XFxuXFxuJHtlbGVtZW50c1RvRG93bmxvYWQubGVuZ3RofSBlbGVtZW50cyB3aWxsIGJlIGRvd25sb2FkZWQ6XFxuJHtlbGVtZW50c1RvRG93bmxvYWQubWFwKGUgPT4gYC0gJHtlLm5hbWV9ICgke2UudHlwZX0pYCkuam9pbignXFxuJyl9XFxuXFxuVG8gcHJvY2VlZCwgdXNlIC0tY29uZmlybSBmbGFnYCxcbiAgICAgICAgZGF0YTogeyByZXF1aXJlc0NvbmZpcm1hdGlvbjogdHJ1ZSB9LFxuICAgICAgICBlbGVtZW50czogZWxlbWVudHNUb0Rvd25sb2FkXG4gICAgICB9O1xuICAgIH1cbiAgICBcbiAgICAvLyBQZXJmb3JtIGFjdHVhbCBidWxrIGRvd25sb2FkXG4gICAgY29uc3QgcmVzdWx0cyA9IHtcbiAgICAgIGRvd25sb2FkZWQ6IFtdIGFzIHN0cmluZ1tdLFxuICAgICAgc2tpcHBlZDogW10gYXMgc3RyaW5nW10sXG4gICAgICBmYWlsZWQ6IFtdIGFzIHsgbmFtZTogc3RyaW5nOyBlcnJvcjogc3RyaW5nIH1bXVxuICAgIH07XG4gICAgXG4gICAgZm9yIChjb25zdCBlbGVtZW50IG9mIGVsZW1lbnRzVG9Eb3dubG9hZCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5kb3dubG9hZEVsZW1lbnQoZWxlbWVudC5uYW1lLCBlbGVtZW50LnR5cGUsIHVuZGVmaW5lZCwgdHJ1ZSk7IC8vIGZvcmNlPXRydWUgdG8gc2tpcCBpbmRpdmlkdWFsIGNvbmZpcm1hdGlvbnNcbiAgICAgICAgaWYgKHJlc3VsdC5zdWNjZXNzKSB7XG4gICAgICAgICAgcmVzdWx0cy5kb3dubG9hZGVkLnB1c2goZWxlbWVudC5uYW1lKTtcbiAgICAgICAgfSBlbHNlIGlmIChyZXN1bHQubWVzc2FnZT8uaW5jbHVkZXMoJ2FscmVhZHkgdXAgdG8gZGF0ZScpKSB7XG4gICAgICAgICAgcmVzdWx0cy5za2lwcGVkLnB1c2goZWxlbWVudC5uYW1lKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXN1bHRzLmZhaWxlZC5wdXNoKHsgbmFtZTogZWxlbWVudC5uYW1lLCBlcnJvcjogcmVzdWx0Lm1lc3NhZ2UgfHwgJ1Vua25vd24gZXJyb3InIH0pO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICByZXN1bHRzLmZhaWxlZC5wdXNoKHsgXG4gICAgICAgICAgbmFtZTogZWxlbWVudC5uYW1lLCBcbiAgICAgICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpIFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gQnVpbGQgc3VtbWFyeSBtZXNzYWdlXG4gICAgbGV0IG1lc3NhZ2UgPSBgQnVsayBkb3dubG9hZCBjb21wbGV0ZTpcXG5gO1xuICAgIG1lc3NhZ2UgKz0gYC0gRG93bmxvYWRlZDogJHtyZXN1bHRzLmRvd25sb2FkZWQubGVuZ3RofSBlbGVtZW50c1xcbmA7XG4gICAgbWVzc2FnZSArPSBgLSBTa2lwcGVkICh1cCB0byBkYXRlKTogJHtyZXN1bHRzLnNraXBwZWQubGVuZ3RofSBlbGVtZW50c1xcbmA7XG4gICAgbWVzc2FnZSArPSBgLSBGYWlsZWQ6ICR7cmVzdWx0cy5mYWlsZWQubGVuZ3RofSBlbGVtZW50c2A7XG4gICAgXG4gICAgaWYgKHJlc3VsdHMuZmFpbGVkLmxlbmd0aCA+IDApIHtcbiAgICAgIG1lc3NhZ2UgKz0gYFxcblxcbkZhaWxlZCBkb3dubG9hZHM6XFxuJHtyZXN1bHRzLmZhaWxlZC5tYXAoZiA9PiBgLSAke2YubmFtZX06ICR7Zi5lcnJvcn1gKS5qb2luKCdcXG4nKX1gO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4ge1xuICAgICAgc3VjY2VzczogcmVzdWx0cy5mYWlsZWQubGVuZ3RoID09PSAwLFxuICAgICAgbWVzc2FnZSxcbiAgICAgIGRhdGE6IHJlc3VsdHNcbiAgICB9O1xuICB9XG4gIFxuICAvKipcbiAgICogQnVsayB1cGxvYWQgZWxlbWVudHNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgYnVsa1VwbG9hZChlbGVtZW50VHlwZT86IEVsZW1lbnRUeXBlLCBjb25maXJtPzogYm9vbGVhbik6IFByb21pc2U8U3luY1Jlc3VsdD4ge1xuICAgIGNvbnN0IGNvbmZpZyA9IHRoaXMuY29uZmlnTWFuYWdlci5nZXRDb25maWcoKTtcbiAgICBcbiAgICBpZiAoIWNvbmZpZy5zeW5jLmJ1bGsudXBsb2FkX2VuYWJsZWQpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBtZXNzYWdlOiAnQnVsayB1cGxvYWQgaXMgbm90IGVuYWJsZWQgaW4gY29uZmlndXJhdGlvbidcbiAgICAgIH07XG4gICAgfVxuICAgIFxuICAgIC8vIEdldCBsaXN0IG9mIGxvY2FsIGVsZW1lbnRzXG4gICAgY29uc3QgdHlwZXMgPSBlbGVtZW50VHlwZSA/IFtlbGVtZW50VHlwZV0gOiBbXG4gICAgICBFbGVtZW50VHlwZS5QRVJTT05BLFxuICAgICAgRWxlbWVudFR5cGUuU0tJTEwsXG4gICAgICBFbGVtZW50VHlwZS5URU1QTEFURSxcbiAgICAgIEVsZW1lbnRUeXBlLkFHRU5ULFxuICAgICAgRWxlbWVudFR5cGUuTUVNT1JZLFxuICAgICAgRWxlbWVudFR5cGUuRU5TRU1CTEVcbiAgICBdO1xuICAgIFxuICAgIGNvbnN0IGxvY2FsRWxlbWVudHM6IHsgbmFtZTogc3RyaW5nOyB0eXBlOiBFbGVtZW50VHlwZTsgcGF0aDogc3RyaW5nIH1bXSA9IFtdO1xuICAgIFxuICAgIGZvciAoY29uc3QgdHlwZSBvZiB0eXBlcykge1xuICAgICAgY29uc3QgZGlyID0gdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmdldEVsZW1lbnREaXIodHlwZSk7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBmaWxlcyA9IGF3YWl0IGZzLnJlYWRkaXIoZGlyKTtcbiAgICAgICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICAgICAgaWYgKGZpbGUuZW5kc1dpdGgoJy5tZCcpKSB7XG4gICAgICAgICAgICBsb2NhbEVsZW1lbnRzLnB1c2goe1xuICAgICAgICAgICAgICBuYW1lOiBmaWxlLnJlcGxhY2UoJy5tZCcsICcnKSxcbiAgICAgICAgICAgICAgdHlwZSxcbiAgICAgICAgICAgICAgcGF0aDogcGF0aC5qb2luKGRpciwgZmlsZSlcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgLy8gRGlyZWN0b3J5IG1heSBub3QgZXhpc3QgeWV0XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhgRGlyZWN0b3J5IGZvciAke3R5cGV9IGRvZXMgbm90IGV4aXN0IHlldGApO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICBpZiAobG9jYWxFbGVtZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgIG1lc3NhZ2U6ICdObyBsb2NhbCBlbGVtZW50cyB0byB1cGxvYWQnLFxuICAgICAgICBlbGVtZW50czogW11cbiAgICAgIH07XG4gICAgfVxuICAgIFxuICAgIC8vIFNob3cgcHJldmlldyBpZiByZXF1aXJlZCAodW5sZXNzIGFscmVhZHkgY29uZmlybWVkKVxuICAgIGlmIChjb25maWcuc3luYy5idWxrLnJlcXVpcmVfcHJldmlldyAmJiAhY29uZmlybSkge1xuICAgICAgLy8gQ29udmVydCB0byBTeW5jRWxlbWVudEluZm8gZm9ybWF0IGZvciBwcmV2aWV3XG4gICAgICBjb25zdCBwcmV2aWV3RWxlbWVudHM6IFN5bmNFbGVtZW50SW5mb1tdID0gbG9jYWxFbGVtZW50cy5tYXAoZSA9PiAoe1xuICAgICAgICBuYW1lOiBlLm5hbWUsXG4gICAgICAgIHR5cGU6IGUudHlwZSxcbiAgICAgICAgc3RhdHVzOiAnbG9jYWwtb25seScgYXMgY29uc3QsXG4gICAgICAgIGFjdGlvbjogJ3VwbG9hZCcgYXMgY29uc3RcbiAgICAgIH0pKTtcbiAgICAgIFxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgIG1lc3NhZ2U6IGBCdWxrIHVwbG9hZCBwcmV2aWV3OlxcblxcbiR7bG9jYWxFbGVtZW50cy5sZW5ndGh9IGVsZW1lbnRzIHdpbGwgYmUgdXBsb2FkZWQ6XFxuJHtsb2NhbEVsZW1lbnRzLm1hcChlID0+IGAtICR7ZS5uYW1lfSAoJHtlLnR5cGV9KWApLmpvaW4oJ1xcbicpfVxcblxcblRvIHByb2NlZWQsIHVzZSAtLWNvbmZpcm0gZmxhZ2AsXG4gICAgICAgIGRhdGE6IHsgcmVxdWlyZXNDb25maXJtYXRpb246IHRydWUgfSxcbiAgICAgICAgZWxlbWVudHM6IHByZXZpZXdFbGVtZW50c1xuICAgICAgfTtcbiAgICB9XG4gICAgXG4gICAgLy8gUGVyZm9ybSBhY3R1YWwgYnVsayB1cGxvYWRcbiAgICBjb25zdCByZXN1bHRzID0ge1xuICAgICAgdXBsb2FkZWQ6IFtdIGFzIHN0cmluZ1tdLFxuICAgICAgc2tpcHBlZDogW10gYXMgc3RyaW5nW10sXG4gICAgICBmYWlsZWQ6IFtdIGFzIHsgbmFtZTogc3RyaW5nOyBlcnJvcjogc3RyaW5nIH1bXVxuICAgIH07XG4gICAgXG4gICAgZm9yIChjb25zdCBlbGVtZW50IG9mIGxvY2FsRWxlbWVudHMpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMudXBsb2FkRWxlbWVudChlbGVtZW50Lm5hbWUsIGVsZW1lbnQudHlwZSwgdHJ1ZSk7IC8vIGNvbmZpcm09dHJ1ZSB0byBza2lwIGluZGl2aWR1YWwgY29uZmlybWF0aW9uc1xuICAgICAgICBpZiAocmVzdWx0LnN1Y2Nlc3MpIHtcbiAgICAgICAgICByZXN1bHRzLnVwbG9hZGVkLnB1c2goZWxlbWVudC5uYW1lKTtcbiAgICAgICAgfSBlbHNlIGlmIChyZXN1bHQubWVzc2FnZT8uaW5jbHVkZXMoJ2xvY2FsLW9ubHknKSkge1xuICAgICAgICAgIHJlc3VsdHMuc2tpcHBlZC5wdXNoKGVsZW1lbnQubmFtZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmVzdWx0cy5mYWlsZWQucHVzaCh7IG5hbWU6IGVsZW1lbnQubmFtZSwgZXJyb3I6IHJlc3VsdC5tZXNzYWdlIHx8ICdVbmtub3duIGVycm9yJyB9KTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgcmVzdWx0cy5mYWlsZWQucHVzaCh7IFxuICAgICAgICAgIG5hbWU6IGVsZW1lbnQubmFtZSwgXG4gICAgICAgICAgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKSBcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIEJ1aWxkIHN1bW1hcnkgbWVzc2FnZVxuICAgIGxldCBtZXNzYWdlID0gYEJ1bGsgdXBsb2FkIGNvbXBsZXRlOlxcbmA7XG4gICAgbWVzc2FnZSArPSBgLSBVcGxvYWRlZDogJHtyZXN1bHRzLnVwbG9hZGVkLmxlbmd0aH0gZWxlbWVudHNcXG5gO1xuICAgIG1lc3NhZ2UgKz0gYC0gU2tpcHBlZCAobG9jYWwtb25seSk6ICR7cmVzdWx0cy5za2lwcGVkLmxlbmd0aH0gZWxlbWVudHNcXG5gO1xuICAgIG1lc3NhZ2UgKz0gYC0gRmFpbGVkOiAke3Jlc3VsdHMuZmFpbGVkLmxlbmd0aH0gZWxlbWVudHNgO1xuICAgIFxuICAgIGlmIChyZXN1bHRzLmZhaWxlZC5sZW5ndGggPiAwKSB7XG4gICAgICBtZXNzYWdlICs9IGBcXG5cXG5GYWlsZWQgdXBsb2FkczpcXG4ke3Jlc3VsdHMuZmFpbGVkLm1hcChmID0+IGAtICR7Zi5uYW1lfTogJHtmLmVycm9yfWApLmpvaW4oJ1xcbicpfWA7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiB7XG4gICAgICBzdWNjZXNzOiByZXN1bHRzLmZhaWxlZC5sZW5ndGggPT09IDAsXG4gICAgICBtZXNzYWdlLFxuICAgICAgZGF0YTogcmVzdWx0c1xuICAgIH07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBkaWZmIGJldHdlZW4gdHdvIGNvbnRlbnQgdmVyc2lvbnNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2VuZXJhdGVEaWZmKGxvY2FsOiBzdHJpbmcsIHJlbW90ZTogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAvLyBTaW1wbGUgbGluZS1iYXNlZCBkaWZmIGZvciBub3dcbiAgICBjb25zdCBsb2NhbExpbmVzID0gbG9jYWwuc3BsaXQoJ1xcbicpO1xuICAgIGNvbnN0IHJlbW90ZUxpbmVzID0gcmVtb3RlLnNwbGl0KCdcXG4nKTtcbiAgICBcbiAgICBsZXQgZGlmZiA9ICcnO1xuICAgIGNvbnN0IG1heExpbmVzID0gTWF0aC5tYXgobG9jYWxMaW5lcy5sZW5ndGgsIHJlbW90ZUxpbmVzLmxlbmd0aCk7XG4gICAgXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBtYXhMaW5lcyAmJiBpIDwgMTA7IGkrKykgeyAvLyBTaG93IGZpcnN0IDEwIGxpbmVzIG9mIGRpZmZcbiAgICAgIGNvbnN0IGxvY2FsTGluZSA9IGxvY2FsTGluZXNbaV0gfHwgJyc7XG4gICAgICBjb25zdCByZW1vdGVMaW5lID0gcmVtb3RlTGluZXNbaV0gfHwgJyc7XG4gICAgICBcbiAgICAgIGlmIChsb2NhbExpbmUgIT09IHJlbW90ZUxpbmUpIHtcbiAgICAgICAgaWYgKGxvY2FsTGluZSAmJiAhcmVtb3RlTGluZSkge1xuICAgICAgICAgIGRpZmYgKz0gYC0gJHtsb2NhbExpbmV9XFxuYDtcbiAgICAgICAgfSBlbHNlIGlmICghbG9jYWxMaW5lICYmIHJlbW90ZUxpbmUpIHtcbiAgICAgICAgICBkaWZmICs9IGArICR7cmVtb3RlTGluZX1cXG5gO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGRpZmYgKz0gYC0gJHtsb2NhbExpbmV9XFxuYDtcbiAgICAgICAgICBkaWZmICs9IGArICR7cmVtb3RlTGluZX1cXG5gO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIGlmIChtYXhMaW5lcyA+IDEwKSB7XG4gICAgICBkaWZmICs9IGBcXG4uLi4gJHttYXhMaW5lcyAtIDEwfSBtb3JlIGxpbmVzIC4uLmA7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBkaWZmIHx8ICdObyBkaWZmZXJlbmNlcyBmb3VuZCc7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBGaW5kIGEgZnV6enkgbWF0Y2ggZm9yIGFuIGVsZW1lbnQgbmFtZVxuICAgKi9cbiAgcHJpdmF0ZSBmaW5kRnV6enlNYXRjaChzZWFyY2hOYW1lOiBzdHJpbmcsIGVudHJpZXM6IEdpdEh1YkluZGV4RW50cnlbXSk6IEdpdEh1YkluZGV4RW50cnkgfCBudWxsIHtcbiAgICBjb25zdCBzZWFyY2ggPSBzZWFyY2hOYW1lLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvWy1fXS9nLCAnJyk7XG4gICAgbGV0IGJlc3RNYXRjaDogdHlwZW9mIGVudHJpZXNbMF0gfCBudWxsID0gbnVsbDtcbiAgICBsZXQgYmVzdFNjb3JlID0gMDtcbiAgICBcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgIC8vIE5vcm1hbGl6ZSB0aGUgZW50cnkgbmFtZSBmb3IgY29tcGFyaXNvblxuICAgICAgY29uc3Qgbm9ybWFsaXplZCA9IGVudHJ5Lm5hbWUudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9bLV9dL2csICcnKTtcbiAgICAgIFxuICAgICAgLy8gQ2FsY3VsYXRlIHNpbWlsYXJpdHkgc2NvcmVcbiAgICAgIGNvbnN0IHNjb3JlID0gdGhpcy5jYWxjdWxhdGVTaW1pbGFyaXR5KHNlYXJjaCwgbm9ybWFsaXplZCk7XG4gICAgICBpZiAoc2NvcmUgPiBiZXN0U2NvcmUgJiYgc2NvcmUgPiAwLjUpIHsgLy8gTWluaW11bSB0aHJlc2hvbGQgb2YgMC41XG4gICAgICAgIGJlc3RTY29yZSA9IHNjb3JlO1xuICAgICAgICBiZXN0TWF0Y2ggPSBlbnRyeTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGJlc3RNYXRjaDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBzdWdnZXN0aW9ucyBmb3Igc2ltaWxhciBlbGVtZW50IG5hbWVzXG4gICAqL1xuICBwcml2YXRlIGdldFN1Z2dlc3Rpb25zKHNlYXJjaE5hbWU6IHN0cmluZywgZW50cmllczogR2l0SHViSW5kZXhFbnRyeVtdKTogQXJyYXk8e25hbWU6IHN0cmluZ30+IHtcbiAgICBjb25zdCBzZWFyY2ggPSBzZWFyY2hOYW1lLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvWy1fXS9nLCAnJyk7XG4gICAgY29uc3Qgc2NvcmVkOiBBcnJheTx7ZW50cnk6IHR5cGVvZiBlbnRyaWVzWzBdOyBzY29yZTogbnVtYmVyfT4gPSBbXTtcbiAgICBcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBlbnRyeS5uYW1lLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvWy1fXS9nLCAnJyk7XG4gICAgICBjb25zdCBzY29yZSA9IHRoaXMuY2FsY3VsYXRlU2ltaWxhcml0eShzZWFyY2gsIG5vcm1hbGl6ZWQpO1xuICAgICAgaWYgKHNjb3JlID4gMC4zKSB7IC8vIExvd2VyIHRocmVzaG9sZCBmb3Igc3VnZ2VzdGlvbnNcbiAgICAgICAgc2NvcmVkLnB1c2goeyBlbnRyeSwgc2NvcmUgfSk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIFNvcnQgYnkgc2NvcmUgYW5kIHJldHVybiB0b3AgNVxuICAgIHJldHVybiBzY29yZWRcbiAgICAgIC5zb3J0KChhLCBiKSA9PiBiLnNjb3JlIC0gYS5zY29yZSlcbiAgICAgIC5zbGljZSgwLCA1KVxuICAgICAgLm1hcChzID0+ICh7IG5hbWU6IHMuZW50cnkubmFtZSB9KSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDYWxjdWxhdGUgc2ltaWxhcml0eSBiZXR3ZWVuIHR3byBzdHJpbmdzXG4gICAqIFJldHVybnMgYSBzY29yZSBiZXR3ZWVuIDAgYW5kIDFcbiAgICovXG4gIHByaXZhdGUgY2FsY3VsYXRlU2ltaWxhcml0eShhOiBzdHJpbmcsIGI6IHN0cmluZyk6IG51bWJlciB7XG4gICAgLy8gRXhhY3QgbWF0Y2hcbiAgICBpZiAoYSA9PT0gYikgcmV0dXJuIDEuMDtcbiAgICBcbiAgICAvLyBPbmUgY29udGFpbnMgdGhlIG90aGVyXG4gICAgaWYgKGEuaW5jbHVkZXMoYikgfHwgYi5pbmNsdWRlcyhhKSkgcmV0dXJuIDAuODtcbiAgICBcbiAgICAvLyBDYWxjdWxhdGUgd29yZCBvdmVybGFwXG4gICAgY29uc3Qgd29yZHNBID0gYS5zcGxpdCgvW15hLXowLTldKy8pO1xuICAgIGNvbnN0IHdvcmRzQiA9IGIuc3BsaXQoL1teYS16MC05XSsvKTtcbiAgICBcbiAgICBsZXQgbWF0Y2hlcyA9IDA7XG4gICAgZm9yIChjb25zdCB3b3JkQSBvZiB3b3Jkc0EpIHtcbiAgICAgIGlmICh3b3JkQSAmJiB3b3Jkc0Iuc29tZSh3b3JkQiA9PiB3b3JkQiA9PT0gd29yZEEpKSB7XG4gICAgICAgIG1hdGNoZXMrKztcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgaWYgKG1hdGNoZXMgPiAwKSB7XG4gICAgICBjb25zdCBvdmVybGFwID0gKG1hdGNoZXMgKiAyKSAvICh3b3Jkc0EubGVuZ3RoICsgd29yZHNCLmxlbmd0aCk7XG4gICAgICByZXR1cm4gTWF0aC5tYXgoMC42LCBvdmVybGFwKTsgLy8gQXQgbGVhc3QgMC42IGZvciBhbnkgd29yZCBtYXRjaFxuICAgIH1cbiAgICBcbiAgICAvLyBDaGVjayBmb3IgcGFydGlhbCBtYXRjaGVzXG4gICAgZm9yIChjb25zdCB3b3JkQSBvZiB3b3Jkc0EpIHtcbiAgICAgIGZvciAoY29uc3Qgd29yZEIgb2Ygd29yZHNCKSB7XG4gICAgICAgIGlmICh3b3JkQS5sZW5ndGggPiAzICYmIHdvcmRCLmxlbmd0aCA+IDMpIHtcbiAgICAgICAgICBpZiAod29yZEEuaW5jbHVkZXMod29yZEIpIHx8IHdvcmRCLmluY2x1ZGVzKHdvcmRBKSkge1xuICAgICAgICAgICAgcmV0dXJuIDAuNTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gTm8gc2lnbmlmaWNhbnQgc2ltaWxhcml0eVxuICAgIHJldHVybiAwO1xuICB9XG59Il19