@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.
- package/CHANGELOG.md +22 -0
- package/README.md.backup +0 -8
- package/dist/auth/GitHubAuthManager.js +2 -2
- package/dist/config/ConfigManager.d.ts +158 -25
- package/dist/config/ConfigManager.d.ts.map +1 -1
- package/dist/config/ConfigManager.js +627 -88
- package/dist/generated/version.d.ts +2 -2
- package/dist/generated/version.js +3 -3
- package/dist/handlers/ConfigHandler.d.ts +32 -0
- package/dist/handlers/ConfigHandler.d.ts.map +1 -0
- package/dist/handlers/ConfigHandler.js +202 -0
- package/dist/handlers/SyncHandlerV2.d.ts +42 -0
- package/dist/handlers/SyncHandlerV2.d.ts.map +1 -0
- package/dist/handlers/SyncHandlerV2.js +231 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -3
- package/dist/portfolio/GitHubPortfolioIndexer.d.ts +0 -1
- package/dist/portfolio/GitHubPortfolioIndexer.d.ts.map +1 -1
- package/dist/portfolio/GitHubPortfolioIndexer.js +36 -16
- package/dist/portfolio/PortfolioRepoManager.d.ts +2 -1
- package/dist/portfolio/PortfolioRepoManager.d.ts.map +1 -1
- package/dist/portfolio/PortfolioRepoManager.js +2 -1
- package/dist/portfolio/PortfolioSyncManager.d.ts +127 -0
- package/dist/portfolio/PortfolioSyncManager.d.ts.map +1 -0
- package/dist/portfolio/PortfolioSyncManager.js +818 -0
- package/dist/security/audit/config/suppressions.d.ts.map +1 -1
- package/dist/security/audit/config/suppressions.js +54 -2
- package/dist/security/secureYamlParser.d.ts +46 -2
- package/dist/security/secureYamlParser.d.ts.map +1 -1
- package/dist/security/secureYamlParser.js +47 -3
- package/dist/server/ServerSetup.d.ts.map +1 -1
- package/dist/server/ServerSetup.js +16 -10
- package/dist/server/tools/ConfigToolsV2.d.ts +10 -0
- package/dist/server/tools/ConfigToolsV2.d.ts.map +1 -0
- package/dist/server/tools/ConfigToolsV2.js +110 -0
- package/dist/server/types.d.ts +2 -0
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js +1 -1
- 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
|