@dollhousemcp/mcp-server 1.6.10 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.github.md +1036 -0
  3. package/README.md +165 -1668
  4. package/README.md.backup +298 -0
  5. package/README.npm.md +298 -0
  6. package/dist/cache/CollectionIndexCache.d.ts.map +1 -1
  7. package/dist/cache/CollectionIndexCache.js +2 -2
  8. package/dist/collection/CollectionBrowser.d.ts.map +1 -1
  9. package/dist/collection/CollectionBrowser.js +6 -3
  10. package/dist/collection/CollectionIndexManager.d.ts.map +1 -1
  11. package/dist/collection/CollectionIndexManager.js +4 -2
  12. package/dist/collection/GitHubClient.d.ts.map +1 -1
  13. package/dist/collection/GitHubClient.js +5 -1
  14. package/dist/generated/version.d.ts +2 -2
  15. package/dist/generated/version.d.ts.map +1 -1
  16. package/dist/generated/version.js +3 -3
  17. package/dist/index.d.ts +0 -19
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +87 -98
  20. package/dist/persona/export-import/index.d.ts +1 -3
  21. package/dist/persona/export-import/index.d.ts.map +1 -1
  22. package/dist/persona/export-import/index.js +2 -3
  23. package/dist/portfolio/PortfolioRepoManager.d.ts +1 -1
  24. package/dist/portfolio/PortfolioRepoManager.d.ts.map +1 -1
  25. package/dist/portfolio/PortfolioRepoManager.js +118 -33
  26. package/dist/security/contentValidator.js +8 -8
  27. package/dist/server/tools/PersonaTools.d.ts.map +1 -1
  28. package/dist/server/tools/PersonaTools.js +36 -76
  29. package/dist/server/types.d.ts +0 -2
  30. package/dist/server/types.d.ts.map +1 -1
  31. package/dist/server/types.js +1 -1
  32. package/dist/tools/portfolio/PortfolioElementAdapter.d.ts.map +1 -1
  33. package/dist/tools/portfolio/PortfolioElementAdapter.js +3 -1
  34. package/package.json +9 -3
  35. package/dist/persona/export-import/PersonaSharer.d.ts +0 -81
  36. package/dist/persona/export-import/PersonaSharer.d.ts.map +0 -1
  37. package/dist/persona/export-import/PersonaSharer.js +0 -678
@@ -1,678 +0,0 @@
1
- /**
2
- * Persona sharing functionality via URLs
3
- *
4
- * SECURITY FIX IMPLEMENTED (Defense-in-Depth Validation):
5
- * 1. CRITICAL: Added validate-before-return pattern in all import methods
6
- * 2. HIGH: Content security validation using ContentValidator before data return
7
- * 3. MEDIUM: Size validation to prevent memory exhaustion attacks
8
- * 4. MEDIUM: Structure validation to prevent malformed data processing
9
- * 5. DEFENSE-IN-DEPTH: Multiple validation layers before PersonaImporter processing
10
- *
11
- * This provides defense-in-depth security by validating content at the earliest
12
- * possible point before any data is returned to calling code or file operations.
13
- */
14
- import { PersonaExporter } from './PersonaExporter.js';
15
- import { TokenManager } from '../../security/tokenManager.js';
16
- import { SecurityError } from '../../security/errors.js';
17
- import { logger } from '../../utils/logger.js';
18
- import { SecurityMonitor } from '../../security/securityMonitor.js';
19
- import { ErrorHandler, ErrorCategory } from '../../utils/ErrorHandler.js';
20
- import { ValidationErrorCodes, NetworkErrorCodes } from '../../utils/errorCodes.js';
21
- import { RateLimiter } from '../../utils/RateLimiter.js';
22
- import { ContentValidator } from '../../security/contentValidator.js';
23
- import { validateContentSize } from '../../security/InputValidator.js';
24
- export class PersonaSharer {
25
- githubClient;
26
- currentUser;
27
- exporter;
28
- githubRateLimiter;
29
- constructor(githubClient, currentUser) {
30
- this.githubClient = githubClient;
31
- this.currentUser = currentUser;
32
- this.exporter = new PersonaExporter(currentUser);
33
- // GitHub API rate limit: 60 requests per hour for unauthenticated
34
- // 5000 per hour for authenticated - use TokenManager to check
35
- const hasValidToken = TokenManager.getGitHubToken() !== null;
36
- this.githubRateLimiter = new RateLimiter({
37
- maxRequests: hasValidToken ? 100 : 30, // Conservative limits
38
- windowMs: 60 * 60 * 1000, // 1 hour
39
- minDelayMs: 1000 // Minimum 1 second between requests
40
- });
41
- }
42
- /**
43
- * Share a persona via GitHub Gist
44
- */
45
- async sharePersona(persona, expiryDays = 7) {
46
- try {
47
- // Validate gist permissions if token is available
48
- const token = TokenManager.getGitHubToken();
49
- let hasValidToken = false;
50
- if (token) {
51
- try {
52
- const validation = await TokenManager.ensureTokenPermissions('gist');
53
- if (!validation.isValid) {
54
- const safeMessage = TokenManager.createSafeErrorMessage(validation.error || 'Unknown validation error', token);
55
- logger.warn('GitHub token lacks gist permissions, falling back to base64 URL', { error: safeMessage });
56
- // Continue to fallback instead of failing
57
- }
58
- else {
59
- hasValidToken = true;
60
- }
61
- }
62
- catch (error) {
63
- // Handle rate limiting or other security errors gracefully
64
- if (error instanceof SecurityError && error.code === 'RATE_LIMIT_EXCEEDED') {
65
- logger.warn('Token validation rate limited, falling back to base64 URL', {
66
- error: 'Rate limit exceeded for token validation'
67
- });
68
- }
69
- else if (error instanceof Error) {
70
- const safeMessage = TokenManager.createSafeErrorMessage(error.message, token);
71
- logger.warn('Token validation failed, falling back to base64 URL', { error: safeMessage });
72
- }
73
- // Continue to fallback instead of failing
74
- }
75
- }
76
- // Export persona to structured format
77
- const exportData = this.exporter.exportPersona(persona);
78
- // Add sharing metadata
79
- const shareData = {
80
- ...exportData,
81
- sharedAt: new Date().toISOString(),
82
- sharedBy: this.currentUser || 'anonymous',
83
- expiresAt: new Date(Date.now() + expiryDays * 24 * 60 * 60 * 1000).toISOString(),
84
- shareVersion: '1.0.0'
85
- };
86
- // Create GitHub Gist if token has proper permissions
87
- if (hasValidToken) {
88
- const gistResult = await this.createGist(persona.metadata.name, shareData);
89
- if (gistResult.success) {
90
- return {
91
- success: true,
92
- url: gistResult.url,
93
- gistId: gistResult.gistId,
94
- expiresAt: shareData.expiresAt,
95
- message: this.formatShareSuccess(gistResult.url, shareData.expiresAt)
96
- };
97
- }
98
- }
99
- // Fallback to base64 URL if Gist fails or no token
100
- return this.createBase64Url(shareData);
101
- }
102
- catch (error) {
103
- const errorMessage = error instanceof Error ? error.message : String(error);
104
- const safeMessage = TokenManager.createSafeErrorMessage(errorMessage);
105
- logger.error('Share error', { error: safeMessage });
106
- return {
107
- success: false,
108
- message: `Failed to share persona: ${safeMessage}`
109
- };
110
- }
111
- }
112
- /**
113
- * Import a persona from a share URL
114
- * SECURITY FIX: Validate ALL content before returning any data
115
- */
116
- async importFromUrl(url) {
117
- try {
118
- // Validate URL first
119
- if (!this.validateShareUrl(url)) {
120
- return {
121
- success: false,
122
- message: 'Invalid or unsafe URL provided'
123
- };
124
- }
125
- // Check if it's a GitHub Gist URL
126
- const gistId = this.extractGistId(url);
127
- if (gistId) {
128
- return await this.importFromGist(gistId);
129
- }
130
- // Check if it's a base64 URL
131
- if (url.includes('#dollhouse-persona=')) {
132
- return await this.importFromBase64Url(url);
133
- }
134
- // Validate URL for security
135
- if (!this.validateShareUrl(url)) {
136
- throw ErrorHandler.createError('Invalid or potentially malicious URL', ErrorCategory.VALIDATION_ERROR, ValidationErrorCodes.INVALID_URL);
137
- }
138
- // Try direct fetch with timeout
139
- const controller = new AbortController();
140
- const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout
141
- try {
142
- const response = await fetch(url, {
143
- signal: controller.signal,
144
- headers: {
145
- 'User-Agent': 'DollhouseMCP/1.0',
146
- 'Accept': 'application/json'
147
- }
148
- });
149
- clearTimeout(timeoutId);
150
- if (!response.ok) {
151
- throw ErrorHandler.createError(`Request failed with status ${response.status}`, ErrorCategory.NETWORK_ERROR, NetworkErrorCodes.REQUEST_FAILED);
152
- }
153
- // ENHANCED SECURITY FIX: Comprehensive Content-Type validation
154
- const contentType = response.headers.get('content-type');
155
- const contentTypeValidation = this.validateContentType(contentType, 'application/json');
156
- if (!contentTypeValidation.isValid) {
157
- throw ErrorHandler.createError(`Invalid response type: ${contentTypeValidation.error}`, ErrorCategory.NETWORK_ERROR, NetworkErrorCodes.INVALID_RESPONSE);
158
- }
159
- // Check response size to prevent memory exhaustion
160
- const contentLength = response.headers.get('content-length');
161
- const maxSize = 5 * 1024 * 1024; // 5MB max
162
- if (contentLength && parseInt(contentLength) > maxSize) {
163
- throw ErrorHandler.createError('Response too large', ErrorCategory.VALIDATION_ERROR, NetworkErrorCodes.RESPONSE_TOO_LARGE);
164
- }
165
- const data = await response.json();
166
- // SECURITY FIX: Validate content before returning
167
- const dataValidation = await this.validatePersonaData(data);
168
- if (!dataValidation.isValid) {
169
- throw new SecurityError(`Content validation failed: ${dataValidation.error}`);
170
- }
171
- return {
172
- success: true,
173
- data,
174
- message: 'Successfully retrieved persona data'
175
- };
176
- }
177
- finally {
178
- clearTimeout(timeoutId);
179
- }
180
- }
181
- catch (error) {
182
- logger.error('Import from URL error', error);
183
- return {
184
- success: false,
185
- message: `Failed to import from URL: ${error instanceof Error ? error.message : String(error)}`
186
- };
187
- }
188
- }
189
- /**
190
- * Create a GitHub Gist
191
- */
192
- async createGist(personaName, data) {
193
- try {
194
- // Use TokenManager for secure token handling
195
- const token = TokenManager.getGitHubToken();
196
- if (!token) {
197
- logger.info('No valid GitHub token available for Gist creation');
198
- return { success: false };
199
- }
200
- // Check rate limit
201
- const rateLimitStatus = this.githubRateLimiter.checkLimit();
202
- if (!rateLimitStatus.allowed) {
203
- logger.warn(`GitHub API rate limit exceeded. Retry after ${rateLimitStatus.retryAfterMs}ms`);
204
- return { success: false };
205
- }
206
- const controller = new AbortController();
207
- const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 second timeout
208
- try {
209
- const response = await fetch('https://api.github.com/gists', {
210
- method: 'POST',
211
- signal: controller.signal,
212
- headers: {
213
- 'Authorization': `Bearer ${token}`,
214
- 'Accept': 'application/vnd.github.v3+json',
215
- 'Content-Type': 'application/json',
216
- 'User-Agent': 'DollhouseMCP/1.0'
217
- },
218
- body: JSON.stringify({
219
- description: `DollhouseMCP Persona: ${personaName}`,
220
- public: false, // Private gist for security
221
- files: {
222
- 'persona.json': {
223
- content: JSON.stringify(data, null, 2)
224
- }
225
- }
226
- })
227
- });
228
- clearTimeout(timeoutId);
229
- if (!response.ok) {
230
- throw ErrorHandler.createError(`GitHub API error: ${response.status}`, ErrorCategory.NETWORK_ERROR, NetworkErrorCodes.API_ERROR);
231
- }
232
- // ENHANCED SECURITY FIX: Comprehensive Content-Type validation for GitHub API
233
- const contentType = response.headers.get('content-type');
234
- const gistContentTypeValidation = this.validateContentType(contentType, 'application/json');
235
- if (!gistContentTypeValidation.isValid) {
236
- throw ErrorHandler.createError(`Invalid GitHub API response type: ${gistContentTypeValidation.error}`, ErrorCategory.NETWORK_ERROR, NetworkErrorCodes.INVALID_RESPONSE);
237
- }
238
- const gist = await response.json();
239
- // Consume the rate limit token after successful request
240
- this.githubRateLimiter.consumeToken();
241
- return {
242
- success: true,
243
- url: gist.html_url,
244
- gistId: gist.id
245
- };
246
- }
247
- finally {
248
- clearTimeout(timeoutId);
249
- }
250
- }
251
- catch (error) {
252
- const errorMessage = error instanceof Error ? error.message : String(error);
253
- const safeMessage = TokenManager.createSafeErrorMessage(errorMessage);
254
- logger.error('Gist creation error', { error: safeMessage });
255
- return { success: false };
256
- }
257
- }
258
- /**
259
- * Create a base64 URL (fallback)
260
- */
261
- createBase64Url(data) {
262
- const base64 = this.exporter.toBase64(data);
263
- const url = `https://dollhousemcp.com/import#dollhouse-persona=${base64}`;
264
- return {
265
- success: true,
266
- url,
267
- expiresAt: data.expiresAt,
268
- message: this.formatShareSuccess(url, data.expiresAt)
269
- };
270
- }
271
- /**
272
- * Import from GitHub Gist
273
- */
274
- async importFromGist(gistId) {
275
- try {
276
- // Check rate limit
277
- const rateLimitStatus = this.githubRateLimiter.checkLimit();
278
- if (!rateLimitStatus.allowed) {
279
- throw ErrorHandler.createError(`GitHub API rate limit exceeded. Please try again in ${Math.ceil(rateLimitStatus.retryAfterMs / 1000)} seconds`, ErrorCategory.NETWORK_ERROR, NetworkErrorCodes.RATE_LIMIT_EXCEEDED);
280
- }
281
- const gistUrl = `https://api.github.com/gists/${gistId}`;
282
- // Validate URL (should always pass for GitHub API)
283
- if (!this.validateShareUrl(gistUrl)) {
284
- throw ErrorHandler.createError('Invalid GitHub API URL', ErrorCategory.VALIDATION_ERROR, ValidationErrorCodes.INVALID_URL);
285
- }
286
- const controller = new AbortController();
287
- const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 second timeout for API
288
- try {
289
- const response = await fetch(gistUrl, {
290
- signal: controller.signal,
291
- headers: {
292
- 'Accept': 'application/vnd.github.v3+json',
293
- 'User-Agent': 'DollhouseMCP/1.0'
294
- }
295
- });
296
- clearTimeout(timeoutId);
297
- if (!response.ok) {
298
- throw ErrorHandler.createError(`Failed to fetch gist: ${response.status}`, ErrorCategory.NETWORK_ERROR, NetworkErrorCodes.FETCH_FAILED);
299
- }
300
- // ENHANCED SECURITY FIX: Comprehensive Content-Type validation for GitHub API
301
- const contentType = response.headers.get('content-type');
302
- const gistContentTypeValidation = this.validateContentType(contentType, 'application/json');
303
- if (!gistContentTypeValidation.isValid) {
304
- throw ErrorHandler.createError(`Invalid GitHub API response type: ${gistContentTypeValidation.error}`, ErrorCategory.NETWORK_ERROR, NetworkErrorCodes.INVALID_RESPONSE);
305
- }
306
- const gist = await response.json();
307
- const personaFile = gist.files['persona.json'];
308
- if (!personaFile) {
309
- throw ErrorHandler.createError('No persona data found in gist', ErrorCategory.VALIDATION_ERROR, ValidationErrorCodes.INVALID_INPUT);
310
- }
311
- const data = JSON.parse(personaFile.content);
312
- // Check expiry
313
- if (data.expiresAt && new Date(data.expiresAt) < new Date()) {
314
- return {
315
- success: false,
316
- message: 'This share link has expired'
317
- };
318
- }
319
- // SECURITY FIX: Validate content before returning
320
- const gistDataValidation = await this.validatePersonaData(data);
321
- if (!gistDataValidation.isValid) {
322
- throw new SecurityError(`Content validation failed: ${gistDataValidation.error}`);
323
- }
324
- // Consume the rate limit token after successful request
325
- this.githubRateLimiter.consumeToken();
326
- return {
327
- success: true,
328
- data,
329
- message: 'Successfully retrieved persona from GitHub'
330
- };
331
- }
332
- finally {
333
- clearTimeout(timeoutId);
334
- }
335
- }
336
- catch (error) {
337
- logger.error('Gist import error', error);
338
- return {
339
- success: false,
340
- message: `Failed to import from gist: ${error instanceof Error ? error.message : String(error)}`
341
- };
342
- }
343
- }
344
- /**
345
- * Validate URL for security (prevent SSRF attacks)
346
- */
347
- validateShareUrl(url) {
348
- try {
349
- // 1. URL length check to prevent DoS
350
- if (url.length > 2048) {
351
- logger.warn('URL exceeds maximum length', { urlLength: url.length });
352
- return false;
353
- }
354
- const parsed = new URL(url);
355
- // 2. Protocol check - only allow http/https
356
- if (!['https:', 'http:'].includes(parsed.protocol)) {
357
- logger.warn('Invalid protocol in URL', { protocol: parsed.protocol });
358
- return false;
359
- }
360
- // 3. Port restrictions - block non-standard ports that could be internal services
361
- const port = parsed.port || (parsed.protocol === 'https:' ? '443' : '80');
362
- const allowedPorts = ['80', '443', '8080', '8443'];
363
- if (!allowedPorts.includes(port)) {
364
- logger.warn('Blocked non-standard port', { port });
365
- return false;
366
- }
367
- // 4. Hostname validation
368
- const hostname = parsed.hostname.toLowerCase();
369
- // Block various localhost representations
370
- const blockedHostnames = [
371
- 'localhost',
372
- 'localhost.localdomain',
373
- '0.0.0.0',
374
- '0',
375
- '0x0',
376
- '0x00000000',
377
- '[::1]',
378
- '[::ffff:127.0.0.1]',
379
- '[0000:0000:0000:0000:0000:0000:0000:0001]'
380
- ];
381
- if (blockedHostnames.includes(hostname)) {
382
- logger.warn('Blocked localhost hostname', { hostname });
383
- return false;
384
- }
385
- // Block private IP ranges with comprehensive patterns
386
- const privateIpPatterns = [
387
- /^127\./, // Loopback
388
- /^10\./, // Private class A
389
- /^192\.168\./, // Private class C
390
- /^172\.(1[6-9]|2[0-9]|3[0-1])\./, // Private class B
391
- /^169\.254\./, // Link-local
392
- /^fc00:/i, // IPv6 private
393
- /^fe80:/i, // IPv6 link-local
394
- /^::1$/, // IPv6 loopback
395
- /^::ffff:0?:?0?:?0?:?0?$/i, // IPv6 mapped IPv4
396
- /^100\.6[4-9]\./, // Carrier-grade NAT
397
- /^100\.[7-9][0-9]\./, // Carrier-grade NAT
398
- /^100\.1[0-2][0-9]\./, // Carrier-grade NAT
399
- /^0\./, // Reserved
400
- /^255\.255\.255\.255$/ // Broadcast
401
- ];
402
- if (privateIpPatterns.some(pattern => pattern.test(hostname))) {
403
- logger.warn('Blocked private IP range', { hostname });
404
- return false;
405
- }
406
- // Block cloud metadata endpoints
407
- const metadataEndpoints = [
408
- '169.254.169.254', // AWS/GCP/Azure
409
- 'metadata.google.internal',
410
- 'metadata.azure.com',
411
- '100.100.100.200' // Alibaba Cloud
412
- ];
413
- if (metadataEndpoints.includes(hostname)) {
414
- logger.warn('Blocked cloud metadata endpoint', { hostname });
415
- return false;
416
- }
417
- // Block numeric IP representations that could bypass checks
418
- if (/^\d+$/.test(hostname)) {
419
- // Convert decimal to IP and check
420
- const num = parseInt(hostname, 10);
421
- if (num <= 0xFFFFFFFF) {
422
- const ip = `${(num >>> 24) & 0xFF}.${(num >>> 16) & 0xFF}.${(num >>> 8) & 0xFF}.${num & 0xFF}`;
423
- logger.warn('Blocked numeric IP representation', { hostname, resolvedIp: ip });
424
- return false;
425
- }
426
- }
427
- // Block hex IP representations
428
- if (/^0x[0-9a-f]+$/i.test(hostname)) {
429
- logger.warn('Blocked hex IP representation', { hostname });
430
- return false;
431
- }
432
- // Validate domain format (basic check)
433
- // Allow GitHub domains and common share platforms
434
- const trustedDomains = [
435
- 'github.com',
436
- 'gist.github.com',
437
- 'api.github.com',
438
- 'raw.githubusercontent.com',
439
- 'dollhousemcp.com'
440
- ];
441
- // Check if it's a trusted domain
442
- const isTrustedDomain = trustedDomains.some(domain => hostname === domain || hostname.endsWith(`.${domain}`));
443
- if (!isTrustedDomain) {
444
- // For non-trusted domains, apply stricter validation
445
- // Must be a valid domain format, not just an IP
446
- const domainPattern = /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i;
447
- const ipv4Pattern = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
448
- const ipv6Pattern = /^\[?([0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}\]?$/i;
449
- if (ipv4Pattern.test(hostname) || ipv6Pattern.test(hostname)) {
450
- logger.warn('Direct IP access not allowed for untrusted sources', { hostname });
451
- return false;
452
- }
453
- if (!domainPattern.test(hostname)) {
454
- logger.warn('Invalid domain format', { hostname });
455
- return false;
456
- }
457
- }
458
- logger.debug('URL validation passed', {
459
- hostname,
460
- protocol: parsed.protocol,
461
- isTrusted: isTrustedDomain
462
- });
463
- return true;
464
- }
465
- catch (error) {
466
- logger.warn('URL validation error', { error: error instanceof Error ? error.message : 'Unknown error' });
467
- return false;
468
- }
469
- }
470
- /**
471
- * Import from base64 URL
472
- */
473
- async importFromBase64Url(url) {
474
- try {
475
- // Limit base64 length to prevent ReDoS attacks (10KB max for base64 encoded data)
476
- const match = url.match(/#dollhouse-persona=([A-Za-z0-9+/=]{1,10000})$/);
477
- if (!match) {
478
- throw ErrorHandler.createError('Invalid share URL format', ErrorCategory.VALIDATION_ERROR, ValidationErrorCodes.INVALID_FORMAT);
479
- }
480
- const base64 = match[1];
481
- const json = Buffer.from(base64, 'base64').toString('utf-8');
482
- const data = JSON.parse(json);
483
- // Check expiry
484
- if (data.expiresAt && new Date(data.expiresAt) < new Date()) {
485
- return {
486
- success: false,
487
- message: 'This share link has expired'
488
- };
489
- }
490
- // SECURITY FIX: Validate content before returning
491
- const base64DataValidation = await this.validatePersonaData(data);
492
- if (!base64DataValidation.isValid) {
493
- throw new SecurityError(`Content validation failed: ${base64DataValidation.error}`);
494
- }
495
- return {
496
- success: true,
497
- data,
498
- message: 'Successfully decoded persona data'
499
- };
500
- }
501
- catch (error) {
502
- return {
503
- success: false,
504
- message: `Failed to decode share URL: ${error instanceof Error ? error.message : String(error)}`
505
- };
506
- }
507
- }
508
- /**
509
- * Extract Gist ID from GitHub URL
510
- */
511
- extractGistId(url) {
512
- const match = url.match(/gist\.github\.com\/[^\/]+\/([a-f0-9]+)/);
513
- return match ? match[1] : null;
514
- }
515
- /**
516
- * Format share success message
517
- */
518
- formatShareSuccess(url, expiresAt) {
519
- const expiryDate = new Date(expiresAt);
520
- const daysUntilExpiry = Math.ceil((expiryDate.getTime() - Date.now()) / (24 * 60 * 60 * 1000));
521
- return `✅ Successfully created share link!
522
-
523
- 🔗 Share URL:
524
- ${url}
525
-
526
- ⏱️ Expires: ${expiryDate.toLocaleDateString()} (${daysUntilExpiry} days)
527
-
528
- 📋 To share this persona:
529
- 1. Copy the URL above
530
- 2. Share it with others
531
- 3. They can import using: import_from_url "${url}"
532
-
533
- 🔒 Privacy: This link is private and will expire automatically.`;
534
- }
535
- /**
536
- * SECURITY FIX: Validate persona data before any processing
537
- * This provides defense-in-depth validation before content reaches file operations
538
- */
539
- async validatePersonaData(data) {
540
- try {
541
- // Basic structure validation
542
- if (!data || typeof data !== 'object') {
543
- return { isValid: false, error: 'Invalid data structure' };
544
- }
545
- // Validate required fields for persona data
546
- if (data.metadata && (!data.metadata.name || !data.metadata.description)) {
547
- return { isValid: false, error: 'Missing required persona metadata' };
548
- }
549
- // Validate content if present
550
- if (data.content) {
551
- // Size validation
552
- try {
553
- validateContentSize(data.content, 100 * 1024); // 100KB limit
554
- }
555
- catch (error) {
556
- return { isValid: false, error: `Content size validation failed: ${error instanceof Error ? error.message : 'Unknown error'}` };
557
- }
558
- // Content security validation
559
- const contentValidation = ContentValidator.validateAndSanitize(data.content);
560
- if (!contentValidation.isValid && contentValidation.severity === 'critical') {
561
- return {
562
- isValid: false,
563
- error: `Critical security threat detected: ${contentValidation.detectedPatterns?.join(', ')}`
564
- };
565
- }
566
- }
567
- // Validate bundle structure if it's a bundle
568
- if (data.personas && Array.isArray(data.personas)) {
569
- for (const persona of data.personas) {
570
- const personaValidation = await this.validatePersonaData(persona);
571
- if (!personaValidation.isValid) {
572
- return { isValid: false, error: `Bundle validation failed: ${personaValidation.error}` };
573
- }
574
- }
575
- }
576
- return { isValid: true };
577
- }
578
- catch (error) {
579
- return {
580
- isValid: false,
581
- error: `Validation error: ${error instanceof Error ? error.message : 'Unknown error'}`
582
- };
583
- }
584
- }
585
- /**
586
- * ENHANCED SECURITY FIX: Comprehensive Content-Type validation
587
- * Strengthens MIME type validation with comprehensive security checks
588
- */
589
- validateContentType(contentType, expectedType) {
590
- // Check if Content-Type header exists
591
- if (!contentType) {
592
- return {
593
- isValid: false,
594
- error: 'Missing Content-Type header'
595
- };
596
- }
597
- // Normalize and sanitize the content type
598
- const normalizedContentType = contentType.toLowerCase().trim();
599
- const normalizedExpectedType = expectedType.toLowerCase().trim();
600
- // Validate Content-Type format (basic MIME type structure)
601
- const mimeTypePattern = /^[a-z0-9][a-z0-9!#$&\-\^_]*\/[a-z0-9][a-z0-9!#$&\-\^_]*(?:\s*;.*)?$/;
602
- if (!mimeTypePattern.test(normalizedContentType)) {
603
- return {
604
- isValid: false,
605
- error: `Malformed Content-Type header: ${contentType}`
606
- };
607
- }
608
- // Extract main MIME type (before any parameters like charset)
609
- const mainType = normalizedContentType.split(';')[0].trim();
610
- // Security check: Block dangerous MIME types that could bypass validation
611
- const dangerousMimeTypes = [
612
- 'text/html', // Could contain XSS
613
- 'text/javascript', // Could contain malicious scripts
614
- 'application/javascript', // Could contain malicious scripts
615
- 'text/xml', // Could contain XXE attacks
616
- 'application/xml', // Could contain XXE attacks
617
- 'image/svg+xml', // Could contain XSS in SVG
618
- 'multipart/form-data', // Unexpected for API responses
619
- 'application/x-www-form-urlencoded' // Unexpected for API responses
620
- ];
621
- if (dangerousMimeTypes.includes(mainType)) {
622
- SecurityMonitor.logSecurityEvent({
623
- type: 'CONTENT_INJECTION_ATTEMPT',
624
- severity: 'HIGH',
625
- source: 'persona_sharer',
626
- details: `Dangerous Content-Type detected: ${contentType}`,
627
- metadata: { contentType, expectedType }
628
- });
629
- return {
630
- isValid: false,
631
- error: `Dangerous Content-Type not allowed: ${mainType}`
632
- };
633
- }
634
- // Check if the main type matches expected type
635
- if (!mainType.includes(normalizedExpectedType)) {
636
- return {
637
- isValid: false,
638
- error: `Content-Type mismatch: expected ${expectedType}, got ${mainType}`
639
- };
640
- }
641
- // Additional validation for JSON responses
642
- if (normalizedExpectedType === 'application/json') {
643
- // Accept various JSON-compatible MIME types
644
- const acceptableJsonTypes = [
645
- 'application/json',
646
- 'application/vnd.api+json',
647
- 'application/vnd.github.v3+json',
648
- 'text/json' // Some APIs use this (though not standard)
649
- ];
650
- const isAcceptableJson = acceptableJsonTypes.some(type => mainType === type);
651
- if (!isAcceptableJson) {
652
- return {
653
- isValid: false,
654
- error: `Unsupported JSON Content-Type: ${mainType}`
655
- };
656
- }
657
- // Validate charset parameter if present
658
- const charsetMatch = normalizedContentType.match(/charset=([^;\s]+)/);
659
- if (charsetMatch) {
660
- const charset = charsetMatch[1].toLowerCase();
661
- const supportedCharsets = ['utf-8', 'utf8', 'ascii', 'iso-8859-1'];
662
- if (!supportedCharsets.includes(charset)) {
663
- return {
664
- isValid: false,
665
- error: `Unsupported charset: ${charset}`
666
- };
667
- }
668
- }
669
- }
670
- // Log successful validation for monitoring
671
- logger.debug('Content-Type validation passed', {
672
- contentType: mainType,
673
- expectedType: normalizedExpectedType
674
- });
675
- return { isValid: true };
676
- }
677
- }
678
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVyc29uYVNoYXJlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wZXJzb25hL2V4cG9ydC1pbXBvcnQvUGVyc29uYVNoYXJlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7O0dBWUc7QUFHSCxPQUFPLEVBQUUsZUFBZSxFQUFtQixNQUFNLHNCQUFzQixDQUFDO0FBRXhFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUM5RCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDekQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQy9DLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUNwRSxPQUFPLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQzFFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3BGLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUN0RSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQVV2RSxNQUFNLE9BQU8sYUFBYTtJQUtkO0lBQ0E7SUFMRixRQUFRLENBQWtCO0lBQzFCLGlCQUFpQixDQUFjO0lBRXZDLFlBQ1UsWUFBMEIsRUFDMUIsV0FBMEI7UUFEMUIsaUJBQVksR0FBWixZQUFZLENBQWM7UUFDMUIsZ0JBQVcsR0FBWCxXQUFXLENBQWU7UUFFbEMsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLGVBQWUsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUVqRCxrRUFBa0U7UUFDbEUsOERBQThEO1FBQzlELE1BQU0sYUFBYSxHQUFHLFlBQVksQ0FBQyxjQUFjLEVBQUUsS0FBSyxJ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Q3RFLElBQUksWUFBWSxFQUFFLENBQUM7Z0JBQ2pCLE1BQU0sT0FBTyxHQUFHLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDOUMsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLFlBQVksQ0FBQyxDQUFDO2dCQUNuRSxJQUFJLENBQUMsaUJBQWlCLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7b0JBQ3pDLE9BQU87d0JBQ0wsT0FBTyxFQUFFLEtBQUs7d0JBQ2QsS0FBSyxFQUFFLHdCQUF3QixPQUFPLEVBQUU7cUJBQ3pDLENBQUM7Z0JBQ0osQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBRUQsMkNBQTJDO1FBQzNDLE1BQU0sQ0FBQyxLQUFLLENBQUMsZ0NBQWdDLEVBQUU7WUFDN0MsV0FBVyxFQUFFLFFBQVE7WUFDckIsWUFBWSxFQUFFLHNCQUFzQjtTQUNyQyxDQUFDLENBQUM7UUFFSCxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxDQUFDO0lBQzNCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUGVyc29uYSBzaGFyaW5nIGZ1bmN0aW9uYWxpdHkgdmlhIFVSTHNcbiAqIFxuICogU0VDVVJJVFkgRklYIElNUExFTUVOVEVEIChEZWZlbnNlLWluLURlcHRoIFZhbGlkYXRpb24pOlxuICogMS4gQ1JJVElDQUw6IEFkZGVkIHZhbGlkYXRlLWJlZm9yZS1yZXR1cm4gcGF0dGVybiBpbiBhbGwgaW1wb3J0IG1ldGhvZHNcbiAqIDIuIEhJR0g6IENvbnRlbnQgc2VjdXJpdHkgdmFsaWRhdGlvbiB1c2luZyBDb250ZW50VmFsaWRhdG9yIGJlZm9yZSBkYXRhIHJldHVyblxuICogMy4gTUVESVVNOiBTaXplIHZhbGlkYXRpb24gdG8gcHJldmVudCBtZW1vcnkgZXhoYXVzdGlvbiBhdHRhY2tzXG4gKiA0LiBNRURJVU06IFN0cnVjdHVyZSB2YWxpZGF0aW9uIHRvIHByZXZlbnQgbWFsZm9ybWVkIGRhdGEgcHJvY2Vzc2luZ1xuICogNS4gREVGRU5TRS1JTi1ERVBUSDogTXVsdGlwbGUgdmFsaWRhdGlvbiBsYXllcnMgYmVmb3JlIFBlcnNvbmFJbXBvcnRlciBwcm9jZXNzaW5nXG4gKiBcbiAqIFRoaXMgcHJvdmlkZXMgZGVmZW5zZS1pbi1kZXB0aCBzZWN1cml0eSBieSB2YWxpZGF0aW5nIGNvbnRlbnQgYXQgdGhlIGVhcmxpZXN0XG4gKiBwb3NzaWJsZSBwb2ludCBiZWZvcmUgYW55IGRhdGEgaXMgcmV0dXJuZWQgdG8gY2FsbGluZyBjb2RlIG9yIGZpbGUgb3BlcmF0aW9ucy5cbiAqL1xuXG5pbXBvcnQgeyBQZXJzb25hIH0gZnJvbSAnLi4vLi4vdHlwZXMvcGVyc29uYS5qcyc7XG5pbXBvcnQgeyBQZXJzb25hRXhwb3J0ZXIsIEV4cG9ydGVkUGVyc29uYSB9IGZyb20gJy4vUGVyc29uYUV4cG9ydGVyLmpzJztcbmltcG9ydCB7IEdpdEh1YkNsaWVudCB9IGZyb20gJy4uLy4uL2NvbGxlY3Rpb24vR2l0SHViQ2xpZW50LmpzJztcbmltcG9ydCB7IFRva2VuTWFuYWdlciB9IGZyb20gJy4uLy4uL3NlY3VyaXR5L3Rva2VuTWFuYWdlci5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eUVycm9yIH0gZnJvbSAnLi4vLi4vc2VjdXJpdHkvZXJyb3JzLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uLy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi8uLi9zZWN1cml0eS9zZWN1cml0eU1vbml0b3IuanMnO1xuaW1wb3J0IHsgRXJyb3JIYW5kbGVyLCBFcnJvckNhdGVnb3J5IH0gZnJvbSAnLi4vLi4vdXRpbHMvRXJyb3JIYW5kbGVyLmpzJztcbmltcG9ydCB7IFZhbGlkYXRpb25FcnJvckNvZGVzLCBOZXR3b3JrRXJyb3JDb2RlcyB9IGZyb20gJy4uLy4uL3V0aWxzL2Vycm9yQ29kZXMuanMnO1xuaW1wb3J0IHsgUmF0ZUxpbWl0ZXIgfSBmcm9tICcuLi8uLi91dGlscy9SYXRlTGltaXRlci5qcyc7XG5pbXBvcnQgeyBDb250ZW50VmFsaWRhdG9yIH0gZnJvbSAnLi4vLi4vc2VjdXJpdHkvY29udGVudFZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyB2YWxpZGF0ZUNvbnRlbnRTaXplIH0gZnJvbSAnLi4vLi4vc2VjdXJpdHkvSW5wdXRWYWxpZGF0b3IuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFNoYXJlUmVzdWx0IHtcbiAgc3VjY2VzczogYm9vbGVhbjtcbiAgdXJsPzogc3RyaW5nO1xuICBnaXN0SWQ/OiBzdHJpbmc7XG4gIGV4cGlyZXNBdD86IHN0cmluZztcbiAgbWVzc2FnZTogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgUGVyc29uYVNoYXJlciB7XG4gIHByaXZhdGUgZXhwb3J0ZXI6IFBlcnNvbmFFeHBvcnRlcjtcbiAgcHJpdmF0ZSBnaXRodWJSYXRlTGltaXRlcjogUmF0ZUxpbWl0ZXI7XG4gIFxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGdpdGh1YkNsaWVudDogR2l0SHViQ2xpZW50LFxuICAgIHByaXZhdGUgY3VycmVudFVzZXI6IHN0cmluZyB8IG51bGxcbiAgKSB7XG4gICAgdGhpcy5leHBvcnRlciA9IG5ldyBQZXJzb25hRXhwb3J0ZXIoY3VycmVudFVzZXIpO1xuICAgIFxuICAgIC8vIEdpdEh1YiBBUEkgcmF0ZSBsaW1pdDogNjAgcmVxdWVzdHMgcGVyIGhvdXIgZm9yIHVuYXV0aGVudGljYXRlZFxuICAgIC8vIDUwMDAgcGVyIGhvdXIgZm9yIGF1dGhlbnRpY2F0ZWQgLSB1c2UgVG9rZW5NYW5hZ2VyIHRvIGNoZWNrXG4gICAgY29uc3QgaGFzVmFsaWRUb2tlbiA9IFRva2VuTWFuYWdlci5nZXRHaXRIdWJUb2tlbigpICE9PSBudWxsO1xuICAgIHRoaXMuZ2l0aHViUmF0ZUxpbWl0ZXIgPSBuZXcgUmF0ZUxpbWl0ZXIoe1xuICAgICAgbWF4UmVxdWVzdHM6IGhhc1ZhbGlkVG9rZW4gPyAxMDAgOiAzMCwgLy8gQ29uc2VydmF0aXZlIGxpbWl0c1xuICAgICAgd2luZG93TXM6IDYwICogNjAgKiAxMDAwLCAvLyAxIGhvdXJcbiAgICAgIG1pbkRlbGF5TXM6IDEwMDAgLy8gTWluaW11bSAxIHNlY29uZCBiZXR3ZWVuIHJlcXVlc3RzXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogU2hhcmUgYSBwZXJzb25hIHZpYSBHaXRIdWIgR2lzdFxuICAgKi9cbiAgYXN5bmMgc2hhcmVQZXJzb25hKHBlcnNvbmE6IFBlcnNvbmEsIGV4cGlyeURheXM6IG51bWJlciA9IDcpOiBQcm9taXNlPFNoYXJlUmVzdWx0PiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFZhbGlkYXRlIGdpc3QgcGVybWlzc2lvbnMgaWYgdG9rZW4gaXMgYXZhaWxhYmxlXG4gICAgICBjb25zdCB0b2tlbiA9IFRva2VuTWFuYWdlci5nZXRHaXRIdWJUb2tlbigpO1xuICAgICAgbGV0IGhhc1ZhbGlkVG9rZW4gPSBmYWxzZTtcbiAgICAgIFxuICAgICAgaWYgKHRva2VuKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgdmFsaWRhdGlvbiA9IGF3YWl0IFRva2VuTWFuYWdlci5lbnN1cmVUb2tlblBlcm1pc3Npb25zKCdnaXN0Jyk7XG4gICAgICAgICAgaWYgKCF2YWxpZGF0aW9uLmlzVmFsaWQpIHtcbiAgICAgICAgICAgIGNvbnN0IHNhZmVNZXNzYWdlID0gVG9rZW5NYW5hZ2VyLmNyZWF0ZVNhZmVFcnJvck1lc3NhZ2UodmFsaWRhdGlvbi5lcnJvciB8fCAnVW5rbm93biB2YWxpZGF0aW9uIGVycm9yJywgdG9rZW4pO1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oJ0dpdEh1YiB0b2tlbiBsYWNrcyBnaXN0IHBlcm1pc3Npb25zLCBmYWxsaW5nIGJhY2sgdG8gYmFzZTY0IFVSTCcsIHsgZXJyb3I6IHNhZmVNZXNzYWdlIH0pO1xuICAgICAgICAgICAgLy8gQ29udGludWUgdG8gZmFsbGJhY2sgaW5zdGVhZCBvZiBmYWlsaW5nXG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGhhc1ZhbGlkVG9rZW4gPSB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAvLyBIYW5kbGUgcmF0ZSBsaW1pdGluZyBvciBvdGhlciBzZWN1cml0eSBlcnJvcnMgZ3JhY2VmdWxseVxuICAgICAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIFNlY3VyaXR5RXJyb3IgJiYgZXJyb3IuY29kZSA9PT0gJ1JBVEVfTElNSVRfRVhDRUVERUQnKSB7XG4gICAgICAgICAgICBsb2dnZXIud2FybignVG9rZW4gdmFsaWRhdGlvbiByYXRlIGxpbWl0ZWQsIGZhbGxpbmcgYmFjayB0byBiYXNlNjQgVVJMJywgeyBcbiAgICAgICAgICAgICAgZXJyb3I6ICdSYXRlIGxpbWl0IGV4Y2VlZGVkIGZvciB0b2tlbiB2YWxpZGF0aW9uJyBcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICAgICAgY29uc3Qgc2FmZU1lc3NhZ2UgPSBUb2tlbk1hbmFnZXIuY3JlYXRlU2FmZUVycm9yTWVzc2FnZShlcnJvci5tZXNzYWdlLCB0b2tlbik7XG4gICAgICAgICAgICBsb2dnZXIud2FybignVG9rZW4gdmFsaWRhdGlvbiBmYWlsZWQsIGZhbGxpbmcgYmFjayB0byBiYXNlNjQgVVJMJywgeyBlcnJvcjogc2FmZU1lc3NhZ2UgfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIENvbnRpbnVlIHRvIGZhbGxiYWNrIGluc3RlYWQgb2YgZmFpbGluZ1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIEV4cG9ydCBwZXJzb25hIHRvIHN0cnVjdHVyZWQgZm9ybWF0XG4gICAgICBjb25zdCBleHBvcnREYXRhID0gdGhpcy5leHBvcnRlci5leHBvcnRQZXJzb25hKHBlcnNvbmEpO1xuICAgICAgXG4gICAgICAvLyBBZGQgc2hhcmluZyBtZXRhZGF0YVxuICAgICAgY29uc3Qgc2hhcmVEYXRhID0ge1xuICAgICAgICAuLi5leHBvcnREYXRhLFxuICAgICAgICBzaGFyZWRBdDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICBzaGFyZWRCeTogdGhpcy5jdXJyZW50VXNlciB8fCAnYW5vbnltb3VzJyxcbiAgICAgICAgZXhwaXJlc0F0OiBuZXcgRGF0ZShEYXRlLm5vdygpICsgZXhwaXJ5RGF5cyAqIDI0ICogNjAgKiA2MCAqIDEwMDApLnRvSVNPU3RyaW5nKCksXG4gICAgICAgIHNoYXJlVmVyc2lvbjogJzEuMC4wJ1xuICAgICAgfTtcblxuICAgICAgLy8gQ3JlYXRlIEdpdEh1YiBHaXN0IGlmIHRva2VuIGhhcyBwcm9wZXIgcGVybWlzc2lvbnNcbiAgICAgIGlmIChoYXNWYWxpZFRva2VuKSB7XG4gICAgICAgIGNvbnN0IGdpc3RSZXN1bHQgPSBhd2FpdCB0aGlzLmNyZWF0ZUdpc3QocGVyc29uYS5tZXRhZGF0YS5uYW1lLCBzaGFyZURhdGEpO1xuICAgICAgICBcbiAgICAgICAgaWYgKGdpc3RSZXN1bHQuc3VjY2Vzcykge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgdXJsOiBnaXN0UmVzdWx0LnVybCEsXG4gICAgICAgICAgICBnaXN0SWQ6IGdpc3RSZXN1bHQuZ2lzdElkLFxuICAgICAgICAgICAgZXhwaXJlc0F0OiBzaGFyZURhdGEuZXhwaXJlc0F0LFxuICAgICAgICAgICAgbWVzc2FnZTogdGhpcy5mb3JtYXRTaGFyZVN1Y2Nlc3MoZ2lzdFJlc3VsdC51cmwhLCBzaGFyZURhdGEuZXhwaXJlc0F0KVxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gRmFsbGJhY2sgdG8gYmFzZTY0IFVSTCBpZiBHaXN0IGZhaWxzIG9yIG5vIHRva2VuXG4gICAgICByZXR1cm4gdGhpcy5jcmVhdGVCYXNlNjRVcmwoc2hhcmVEYXRhKTtcblxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcik7XG4gICAgICBjb25zdCBzYWZlTWVzc2FnZSA9IFRva2VuTWFuYWdlci5jcmVhdGVTYWZlRXJyb3JNZXNzYWdlKGVycm9yTWVzc2FnZSk7XG4gICAgICBsb2dnZXIuZXJyb3IoJ1NoYXJlIGVycm9yJywgeyBlcnJvcjogc2FmZU1lc3NhZ2UgfSk7XG4gICAgICBcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBtZXNzYWdlOiBgRmFpbGVkIHRvIHNoYXJlIHBlcnNvbmE6ICR7c2FmZU1lc3NhZ2V9YFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSW1wb3J0IGEgcGVyc29uYSBmcm9tIGEgc2hhcmUgVVJMXG4gICAqIFNFQ1VSSVRZIEZJWDogVmFsaWRhdGUgQUxMIGNvbnRlbnQgYmVmb3JlIHJldHVybmluZyBhbnkgZGF0YVxuICAgKi9cbiAgYXN5bmMgaW1wb3J0RnJvbVVybCh1cmw6IHN0cmluZyk6IFByb21pc2U8eyBzdWNjZXNzOiBib29sZWFuOyBkYXRhPzogYW55OyBtZXNzYWdlOiBzdHJpbmcgfT4ge1xuICAgIHRyeSB7XG4gICAgICAvLyBWYWxpZGF0ZSBVUkwgZmlyc3RcbiAgICAgIGlmICghdGhpcy52YWxpZGF0ZVNoYXJlVXJsKHVybCkpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICBtZXNzYWdlOiAnSW52YWxpZCBvciB1bnNhZmUgVVJMIHByb3ZpZGVkJ1xuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgLy8gQ2hlY2sgaWYgaXQncyBhIEdpdEh1YiBHaXN0IFVSTFxuICAgICAgY29uc3QgZ2lzdElkID0gdGhpcy5leHRyYWN0R2lzdElkKHVybCk7XG4gICAgICBpZiAoZ2lzdElkKSB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmltcG9ydEZyb21HaXN0KGdpc3RJZCk7XG4gICAgICB9XG5cbiAgICAgIC8vIENoZWNrIGlmIGl0J3MgYSBiYXNlNjQgVVJMXG4gICAgICBpZiAodXJsLmluY2x1ZGVzKCcjZG9sbGhvdXNlLXBlcnNvbmE9JykpIHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuaW1wb3J0RnJvbUJhc2U2NFVybCh1cmwpO1xuICAgICAgfVxuXG4gICAgICAvLyBWYWxpZGF0ZSBVUkwgZm9yIHNlY3VyaXR5XG4gICAgICBpZiAoIXRoaXMudmFsaWRhdGVTaGFyZVVybCh1cmwpKSB7XG4gICAgICAgIHRocm93IEVycm9ySGFuZGxlci5jcmVhdGVFcnJvcignSW52YWxpZCBvciBwb3RlbnRpYWxseSBtYWxpY2lvdXMgVVJMJywgRXJyb3JDYXRlZ29yeS5WQUxJREFUSU9OX0VSUk9SLCBWYWxpZGF0aW9uRXJyb3JDb2Rlcy5JTlZBTElEX1VSTCk7XG4gICAgICB9XG5cbiAgICAgIC8vIFRyeSBkaXJlY3QgZmV0Y2ggd2l0aCB0aW1lb3V0XG4gICAgICBjb25zdCBjb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICAgICAgY29uc3QgdGltZW91dElkID0gc2V0VGltZW91dCgoKSA9PiBjb250cm9sbGVyLmFib3J0KCksIDUwMDApOyAvLyA1IHNlY29uZCB0aW1lb3V0XG4gICAgICBcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgICAgICAgc2lnbmFsOiBjb250cm9sbGVyLnNpZ25hbCxcbiAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAnVXNlci1BZ2VudCc6ICdEb2xsaG91c2VNQ1AvMS4wJyxcbiAgICAgICAgICAgICdBY2NlcHQnOiAnYXBwbGljYXRpb24vanNvbidcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXRJZCk7XG4gICAgICAgIFxuICAgICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgICAgdGhyb3cgRXJyb3JIYW5kbGVyLmNyZWF0ZUVycm9yKGBSZXF1ZXN0IGZhaWxlZCB3aXRoIHN0YXR1cyAke3Jlc3BvbnNlLnN0YXR1c31gLCBFcnJvckNhdGVnb3J5Lk5FVFdPUktfRVJST1IsIE5ldHdvcmtFcnJvckNvZGVzLlJFUVVFU1RfRkFJTEVEKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEVOSEFOQ0VEIFNFQ1VSSVRZIEZJWDogQ29tcHJlaGVuc2l2ZSBDb250ZW50LVR5cGUgdmFsaWRhdGlvblxuICAgICAgICBjb25zdCBjb250ZW50VHlwZSA9IHJlc3BvbnNlLmhlYWRlcnMuZ2V0KCdjb250ZW50LXR5cGUnKTtcbiAgICAgICAgY29uc3QgY29udGVudFR5cGVWYWxpZGF0aW9uID0gdGhpcy52YWxpZGF0ZUNvbnRlbnRUeXBlKGNvbnRlbnRUeXBlLCAnYXBwbGljYXRpb24vanNvbicpO1xuICAgICAgICBpZiAoIWNvbnRlbnRUeXBlVmFsaWRhdGlvbi5pc1ZhbGlkKSB7XG4gICAgICAgICAgdGhyb3cgRXJyb3JIYW5kbGVyLmNyZWF0ZUVycm9yKFxuICAgICAgICAgICAgYEludmFsaWQgcmVzcG9uc2UgdHlwZTogJHtjb250ZW50VHlwZVZhbGlkYXRpb24uZXJyb3J9YCwgXG4gICAgICAgICAgICBFcnJvckNhdGVnb3J5Lk5FVFdPUktfRVJST1IsIFxuICAgICAgICAgICAgTmV0d29ya0Vycm9yQ29kZXMuSU5WQUxJRF9SRVNQT05TRVxuICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDaGVjayByZXNwb25zZSBzaXplIHRvIHByZXZlbnQgbWVtb3J5IGV4aGF1c3Rpb25cbiAgICAgICAgY29uc3QgY29udGVudExlbmd0aCA9IHJlc3BvbnNlLmhlYWRlcnMuZ2V0KCdjb250ZW50LWxlbmd0aCcpO1xuICAgICAgICBjb25zdCBtYXhTaXplID0gNSAqIDEwMjQgKiAxMDI0OyAvLyA1TUIgbWF4XG4gICAgICAgIGlmIChjb250ZW50TGVuZ3RoICYmIHBhcnNlSW50KGNvbnRlbnRMZW5ndGgpID4gbWF4U2l6ZSkge1xuICAgICAgICAgIHRocm93IEVycm9ySGFuZGxlci5jcmVhdGVFcnJvcignUmVzcG9uc2UgdG9vIGxhcmdlJywgRXJyb3JDYXRlZ29yeS5WQUxJREFUSU9OX0VSUk9SLCBOZXR3b3JrRXJyb3JDb2Rlcy5SRVNQT05TRV9UT09fTEFSR0UpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKTtcbiAgICAgICAgXG4gICAgICAgIC8vIFNFQ1VSSVRZIEZJWDogVmFsaWRhdGUgY29udGVudCBiZWZvcmUgcmV0dXJuaW5nXG4gICAgICAgIGNvbnN0IGRhdGFWYWxpZGF0aW9uID0gYXdhaXQgdGhpcy52YWxpZGF0ZVBlcnNvbmFEYXRhKGRhdGEpO1xuICAgICAgICBpZiAoIWRhdGFWYWxpZGF0aW9uLmlzVmFsaWQpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFcnJvcihgQ29udGVudCB2YWxpZGF0aW9uIGZhaWxlZDogJHtkYXRhVmFsaWRhdGlvbi5lcnJvcn1gKTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgIGRhdGEsXG4gICAgICAgICAgbWVzc2FnZTogJ1N1Y2Nlc3NmdWxseSByZXRyaWV2ZWQgcGVyc29uYSBkYXRhJ1xuICAgICAgICB9O1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXRJZCk7XG4gICAgICB9XG5cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdJbXBvcnQgZnJvbSBVUkwgZXJyb3InLCBlcnJvcik7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgbWVzc2FnZTogYEZhaWxlZCB0byBpbXBvcnQgZnJvbSBVUkw6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWBcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIEdpdEh1YiBHaXN0XG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGNyZWF0ZUdpc3QocGVyc29uYU5hbWU6IHN0cmluZywgZGF0YTogYW55KTogUHJvbWlzZTx7IHN1Y2Nlc3M6IGJvb2xlYW47IHVybD86IHN0cmluZzsgZ2lzdElkPzogc3RyaW5nIH0+IHtcbiAgICB0cnkge1xuICAgICAgLy8gVXNlIFRva2VuTWFuYWdlciBmb3Igc2VjdXJlIHRva2VuIGhhbmRsaW5nXG4gICAgICBjb25zdCB0b2tlbiA9IFRva2VuTWFuYWdlci5nZXRHaXRIdWJUb2tlbigpO1xuICAgICAgaWYgKCF0b2tlbikge1xuICAgICAgICBsb2dnZXIuaW5mbygnTm8gdmFsaWQgR2l0SHViIHRva2VuIGF2YWlsYWJsZSBmb3IgR2lzdCBjcmVhdGlvbicpO1xuICAgICAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSB9O1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBDaGVjayByYXRlIGxpbWl0XG4gICAgICBjb25zdCByYXRlTGltaXRTdGF0dXMgPSB0aGlzLmdpdGh1YlJhdGVMaW1pdGVyLmNoZWNrTGltaXQoKTtcbiAgICAgIGlmICghcmF0ZUxpbWl0U3RhdHVzLmFsbG93ZWQpIHtcbiAgICAgICAgbG9nZ2VyLndhcm4oYEdpdEh1YiBBUEkgcmF0ZSBsaW1pdCBleGNlZWRlZC4gUmV0cnkgYWZ0ZXIgJHtyYXRlTGltaXRTdGF0dXMucmV0cnlBZnRlck1zfW1zYCk7XG4gICAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IGZhbHNlIH07XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gICAgICBjb25zdCB0aW1lb3V0SWQgPSBzZXRUaW1lb3V0KCgpID0+IGNvbnRyb2xsZXIuYWJvcnQoKSwgMTAwMDApOyAvLyAxMCBzZWNvbmQgdGltZW91dFxuICAgICAgXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKCdodHRwczovL2FwaS5naXRodWIuY29tL2dpc3RzJywge1xuICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgIHNpZ25hbDogY29udHJvbGxlci5zaWduYWwsXG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAnQXV0aG9yaXphdGlvbic6IGBCZWFyZXIgJHt0b2tlbn1gLFxuICAgICAgICAgICdBY2NlcHQnOiAnYXBwbGljYXRpb24vdm5kLmdpdGh1Yi52Mytqc29uJyxcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICdVc2VyLUFnZW50JzogJ0RvbGxob3VzZU1DUC8xLjAnXG4gICAgICAgIH0sXG4gICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICBkZXNjcmlwdGlvbjogYERvbGxob3VzZU1DUCBQZXJzb25hOiAke3BlcnNvbmFOYW1lfWAsXG4gICAgICAgICAgcHVibGljOiBmYWxzZSwgLy8gUHJpdmF0ZSBnaXN0IGZvciBzZWN1cml0eVxuICAgICAgICAgIGZpbGVzOiB7XG4gICAgICAgICAgICAncGVyc29uYS5qc29uJzoge1xuICAgICAgICAgICAgICBjb250ZW50OiBKU09OLnN0cmluZ2lmeShkYXRhLCBudWxsLCAyKVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgICAgfSk7XG4gICAgICAgIFxuICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dElkKTtcblxuICAgICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgICAgdGhyb3cgRXJyb3JIYW5kbGVyLmNyZWF0ZUVycm9yKGBHaXRIdWIgQVBJIGVycm9yOiAke3Jlc3BvbnNlLnN0YXR1c31gLCBFcnJvckNhdGVnb3J5Lk5FVFdPUktfRVJST1IsIE5ldHdvcmtFcnJvckNvZGVzLkFQSV9FUlJPUik7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFTkhBTkNFRCBTRUNVUklUWSBGSVg6IENvbXByZWhlbnNpdmUgQ29udGVudC1UeXBlIHZhbGlkYXRpb24gZm9yIEdpdEh1YiBBUElcbiAgICAgICAgY29uc3QgY29udGVudFR5cGUgPSByZXNwb25zZS5oZWFkZXJzLmdldCgnY29udGVudC10eXBlJyk7XG4gICAgICAgIGNvbnN0IGdpc3RDb250ZW50VHlwZVZhbGlkYXRpb24gPSB0aGlzLnZhbGlkYXRlQ29udGVudFR5cGUoY29udGVudFR5cGUsICdhcHBsaWNhdGlvbi9qc29uJyk7XG4gICAgICAgIGlmICghZ2lzdENvbnRlbnRUeXBlVmFsaWRhdGlvbi5pc1ZhbGlkKSB7XG4gICAgICAgICAgdGhyb3cgRXJyb3JIYW5kbGVyLmNyZWF0ZUVycm9yKFxuICAgICAgICAgICAgYEludmFsaWQgR2l0SHViIEFQSSByZXNwb25zZSB0eXBlOiAke2dpc3RDb250ZW50VHlwZVZhbGlkYXRpb24uZXJyb3J9YCwgXG4gICAgICAgICAgICBFcnJvckNhdGVnb3J5Lk5FVFdPUktfRVJST1IsIFxuICAgICAgICAgICAgTmV0d29ya0Vycm9yQ29kZXMuSU5WQUxJRF9SRVNQT05TRVxuICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBnaXN0ID0gYXdhaXQgcmVzcG9uc2UuanNvbigpO1xuICAgICAgICBcbiAgICAgICAgLy8gQ29uc3VtZSB0aGUgcmF0ZSBsaW1pdCB0b2tlbiBhZnRlciBzdWNjZXNzZnVsIHJlcXVlc3RcbiAgICAgICAgdGhpcy5naXRodWJSYXRlTGltaXRlci5jb25zdW1lVG9rZW4oKTtcbiAgICAgICAgXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICB1cmw6IGdpc3QuaHRtbF91cmwsXG4gICAgICAgICAgZ2lzdElkOiBnaXN0LmlkXG4gICAgICAgIH07XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dElkKTtcbiAgICAgIH1cblxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcik7XG4gICAgICBjb25zdCBzYWZlTWVzc2FnZSA9IFRva2VuTWFuYWdlci5jcmVhdGVTYWZlRXJyb3JNZXNzYWdlKGVycm9yTWVzc2FnZSk7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0dpc3QgY3JlYXRpb24gZXJyb3InLCB7IGVycm9yOiBzYWZlTWVzc2FnZSB9KTtcbiAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IGZhbHNlIH07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIGJhc2U2NCBVUkwgKGZhbGxiYWNrKVxuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVCYXNlNjRVcmwoZGF0YTogYW55KTogU2hhcmVSZXN1bHQge1xuICAgIGNvbnN0IGJhc2U2NCA9IHRoaXMuZXhwb3J0ZXIudG9CYXNlNjQoZGF0YSk7XG4gICAgY29uc3QgdXJsID0gYGh0dHBzOi8vZG9sbGhvdXNlbWNwLmNvbS9pbXBvcnQjZG9sbGhvdXNlLXBlcnNvbmE9JHtiYXNlNjR9YDtcbiAgICBcbiAgICByZXR1cm4ge1xuICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgIHVybCxcbiAgICAgIGV4cGlyZXNBdDogZGF0YS5leHBpcmVzQXQsXG4gICAgICBtZXNzYWdlOiB0aGlzLmZvcm1hdFNoYXJlU3VjY2Vzcyh1cmwsIGRhdGEuZXhwaXJlc0F0KVxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogSW1wb3J0IGZyb20gR2l0SHViIEdpc3RcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgaW1wb3J0RnJvbUdpc3QoZ2lzdElkOiBzdHJpbmcpOiBQcm9taXNlPHsgc3VjY2VzczogYm9vbGVhbjsgZGF0YT86IGFueTsgbWVzc2FnZTogc3RyaW5nIH0+IHtcbiAgICB0cnkge1xuICAgICAgLy8gQ2hlY2sgcmF0ZSBsaW1pdFxuICAgICAgY29uc3QgcmF0ZUxpbWl0U3RhdHVzID0gdGhpcy5naXRodWJSYXRlTGltaXRlci5jaGVja0xpbWl0KCk7XG4gICAgICBpZiAoIXJhdGVMaW1pdFN0YXR1cy5hbGxvd2VkKSB7XG4gICAgICAgIHRocm93IEVycm9ySGFuZGxlci5jcmVhdGVFcnJvcihgR2l0SHViIEFQSSByYXRlIGxpbWl0IGV4Y2VlZGVkLiBQbGVhc2UgdHJ5IGFnYWluIGluICR7TWF0aC5jZWlsKHJhdGVMaW1pdFN0YXR1cy5yZXRyeUFmdGVyTXMhIC8gMTAwMCl9IHNlY29uZHNgLCBFcnJvckNhdGVnb3J5Lk5FVFdPUktfRVJST1IsIE5ldHdvcmtFcnJvckNvZGVzLlJBVEVfTElNSVRfRVhDRUVERUQpO1xuICAgICAgfVxuICAgICAgXG4gICAgICBjb25zdCBnaXN0VXJsID0gYGh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vZ2lzdHMvJHtnaXN0SWR9YDtcbiAgICAgIFxuICAgICAgLy8gVmFsaWRhdGUgVVJMIChzaG91bGQgYWx3YXlzIHBhc3MgZm9yIEdpdEh1YiBBUEkpXG4gICAgICBpZiAoIXRoaXMudmFsaWRhdGVTaGFyZVVybChnaXN0VXJsKSkge1xuICAgICAgICB0aHJvdyBFcnJvckhhbmRsZXIuY3JlYXRlRXJyb3IoJ0ludmFsaWQgR2l0SHViIEFQSSBVUkwnLCBFcnJvckNhdGVnb3J5LlZBTElEQVRJT05fRVJST1IsIFZhbGlkYXRpb25FcnJvckNvZGVzLklOVkFMSURfVVJMKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgY29uc3QgY29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcbiAgICAgIGNvbnN0IHRpbWVvdXRJZCA9IHNldFRpbWVvdXQoKCkgPT4gY29udHJvbGxlci5hYm9ydCgpLCAxMDAwMCk7IC8vIDEwIHNlY29uZCB0aW1lb3V0IGZvciBBUElcbiAgICAgIFxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChnaXN0VXJsLCB7XG4gICAgICAgICAgc2lnbmFsOiBjb250cm9sbGVyLnNpZ25hbCxcbiAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAnQWNjZXB0JzogJ2FwcGxpY2F0aW9uL3ZuZC5naXRodWIudjMranNvbicsXG4gICAgICAgICAgICAnVXNlci1BZ2VudCc6ICdEb2xsaG91c2VNQ1AvMS4wJ1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIFxuICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dElkKTtcblxuICAgICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgICAgdGhyb3cgRXJyb3JIYW5kbGVyLmNyZWF0ZUVycm9yKGBGYWlsZWQgdG8gZmV0Y2ggZ2lzdDogJHtyZXNwb25zZS5zdGF0dXN9YCwgRXJyb3JDYXRlZ29yeS5ORVRXT1JLX0VSUk9SLCBOZXR3b3JrRXJyb3JDb2Rlcy5GRVRDSF9GQUlMRUQpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRU5IQU5DRUQgU0VDVVJJVFkgRklYOiBDb21wcmVoZW5zaXZlIENvbnRlbnQtVHlwZSB2YWxpZGF0aW9uIGZvciBHaXRIdWIgQVBJXG4gICAgICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gcmVzcG9uc2UuaGVhZGVycy5nZXQoJ2NvbnRlbnQtdHlwZScpO1xuICAgICAgICBjb25zdCBnaXN0Q29udGVudFR5cGVWYWxpZGF0aW9uID0gdGhpcy52YWxpZGF0ZUNvbnRlbnRUeXBlKGNvbnRlbnRUeXBlLCAnYXBwbGljYXRpb24vanNvbicpO1xuICAgICAgICBpZiAoIWdpc3RDb250ZW50VHlwZVZhbGlkYXRpb24uaXNWYWxpZCkge1xuICAgICAgICAgIHRocm93IEVycm9ySGFuZGxlci5jcmVhdGVFcnJvcihcbiAgICAgICAgICAgIGBJbnZhbGlkIEdpdEh1YiBBUEkgcmVzcG9uc2UgdHlwZTogJHtnaXN0Q29udGVudFR5cGVWYWxpZGF0aW9uLmVycm9yfWAsIFxuICAgICAgICAgICAgRXJyb3JDYXRlZ29yeS5ORVRXT1JLX0VSUk9SLCBcbiAgICAgICAgICAgIE5ldHdvcmtFcnJvckNvZGVzLklOVkFMSURfUkVTUE9OU0VcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZ2lzdCA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKTtcbiAgICAgICAgY29uc3QgcGVyc29uYUZpbGUgPSBnaXN0LmZpbGVzWydwZXJzb25hLmpzb24nXTtcbiAgICAgICAgXG4gICAgICAgIGlmICghcGVyc29uYUZpbGUpIHtcbiAgICAgICAgICB0aHJvdyBFcnJvckhhbmRsZXIuY3JlYXRlRXJyb3IoJ05vIHBlcnNvbmEgZGF0YSBmb3VuZCBpbiBnaXN0JywgRXJyb3JDYXRlZ29yeS5WQUxJREFUSU9OX0VSUk9SLCBWYWxpZGF0aW9uRXJyb3JDb2Rlcy5JTlZBTElEX0lOUFVUKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGRhdGEgPSBKU09OLnBhcnNlKHBlcnNvbmFGaWxlLmNvbnRlbnQpO1xuICAgICAgICBcbiAgICAgICAgLy8gQ2hlY2sgZXhwaXJ5XG4gICAgICAgIGlmIChkYXRhLmV4cGlyZXNBdCAmJiBuZXcgRGF0ZShkYXRhLmV4cGlyZXNBdCkgPCBuZXcgRGF0ZSgpKSB7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgbWVzc2FnZTogJ1RoaXMgc2hhcmUgbGluayBoYXMgZXhwaXJlZCdcbiAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU0VDVVJJVFkgRklYOiBWYWxpZGF0ZSBjb250ZW50IGJlZm9yZSByZXR1cm5pbmdcbiAgICAgICAgY29uc3QgZ2lzdERhdGFWYWxpZGF0aW9uID0gYXdhaXQgdGhpcy52YWxpZGF0ZVBlcnNvbmFEYXRhKGRhdGEpO1xuICAgICAgICBpZiAoIWdpc3REYXRhVmFsaWRhdGlvbi5pc1ZhbGlkKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IFNlY3VyaXR5RXJyb3IoYENvbnRlbnQgdmFsaWRhdGlvbiBmYWlsZWQ6ICR7Z2lzdERhdGFWYWxpZGF0aW9uLmVycm9yfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ29uc3VtZSB0aGUgcmF0ZSBsaW1pdCB0b2tlbiBhZnRlciBzdWNjZXNzZnVsIHJlcXVlc3RcbiAgICAgICAgdGhpcy5naXRodWJSYXRlTGltaXRlci5jb25zdW1lVG9rZW4oKTtcbiAgICAgICAgXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICBkYXRhLFxuICAgICAgICAgIG1lc3NhZ2U6ICdTdWNjZXNzZnVsbHkgcmV0cmlldmVkIHBlcnNvbmEgZnJvbSBHaXRIdWInXG4gICAgICAgIH07XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dElkKTtcbiAgICAgIH1cblxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0dpc3QgaW1wb3J0IGVycm9yJywgZXJyb3IpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgIG1lc3NhZ2U6IGBGYWlsZWQgdG8gaW1wb3J0IGZyb20gZ2lzdDogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgVVJMIGZvciBzZWN1cml0eSAocHJldmVudCBTU1JGIGF0dGFja3MpXG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlU2hhcmVVcmwodXJsOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICB0cnkge1xuICAgICAgLy8gMS4gVVJMIGxlbmd0aCBjaGVjayB0byBwcmV2ZW50IERvU1xuICAgICAgaWYgKHVybC5sZW5ndGggPiAyMDQ4KSB7XG4gICAgICAgIGxvZ2dlci53YXJuKCdVUkwgZXhjZWVkcyBtYXhpbXVtIGxlbmd0aCcsIHsgdXJsTGVuZ3RoOiB1cmwubGVuZ3RoIH0pO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHBhcnNlZCA9IG5ldyBVUkwodXJsKTtcbiAgICAgIFxuICAgICAgLy8gMi4gUHJvdG9jb2wgY2hlY2sgLSBvbmx5IGFsbG93IGh0dHAvaHR0cHNcbiAgICAgIGlmICghWydodHRwczonLCAnaHR0cDonXS5pbmNsdWRlcyhwYXJzZWQucHJvdG9jb2wpKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKCdJbnZhbGlkIHByb3RvY29sIGluIFVSTCcsIHsgcHJvdG9jb2w6IHBhcnNlZC5wcm90b2NvbCB9KTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyAzLiBQb3J0IHJlc3RyaWN0aW9ucyAtIGJsb2NrIG5vbi1zdGFuZGFyZCBwb3J0cyB0aGF0IGNvdWxkIGJlIGludGVybmFsIHNlcnZpY2VzXG4gICAgICBjb25zdCBwb3J0ID0gcGFyc2VkLnBvcnQgfHwgKHBhcnNlZC5wcm90b2NvbCA9PT0gJ2h0dHBzOicgPyAnNDQzJyA6ICc4MCcpO1xuICAgICAgY29uc3QgYWxsb3dlZFBvcnRzID0gWyc4MCcsICc0NDMnLCAnODA4MCcsICc4NDQzJ107XG4gICAgICBpZiAoIWFsbG93ZWRQb3J0cy5pbmNsdWRlcyhwb3J0KSkge1xuICAgICAgICBsb2dnZXIud2FybignQmxvY2tlZCBub24tc3RhbmRhcmQgcG9ydCcsIHsgcG9ydCB9KTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyA0LiBIb3N0bmFtZSB2YWxpZGF0aW9uXG4gICAgICBjb25zdCBob3N0bmFtZSA9IHBhcnNlZC5ob3N0bmFtZS50b0xvd2VyQ2FzZSgpO1xuICAgICAgXG4gICAgICAvLyBCbG9jayB2YXJpb3VzIGxvY2FsaG9zdCByZXByZXNlbnRhdGlvbnNcbiAgICAgIGNvbnN0IGJsb2NrZWRIb3N0bmFtZXMgPSBbXG4gICAgICAgICdsb2NhbGhvc3QnLCBcbiAgICAgICAgJ2xvY2FsaG9zdC5sb2NhbGRvbWFpbicsXG4gICAgICAgICcwLjAuMC4wJyxcbiAgICAgICAgJzAnLFxuICAgICAgICAnMHgwJyxcbiAgICAgICAgJzB4MDAwMDAwMDAnLFxuICAgICAgICAnWzo6MV0nLFxuICAgICAgICAnWzo6ZmZmZjoxMjcuMC4wLjFdJyxcbiAgICAgICAgJ1swMDAwOjAwMDA6MDAwMDowMDAwOjAwMDA6MDAwMDowMDAwOjAwMDFdJ1xuICAgICAgXTtcbiAgICAgIFxuICAgICAgaWYgKGJsb2NrZWRIb3N0bmFtZXMuaW5jbHVkZXMoaG9zdG5hbWUpKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKCdCbG9ja2VkIGxvY2FsaG9zdCBob3N0bmFtZScsIHsgaG9zdG5hbWUgfSk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gQmxvY2sgcHJpdmF0ZSBJUCByYW5nZXMgd2l0aCBjb21wcmVoZW5zaXZlIHBhdHRlcm5zXG4gICAgICBjb25zdCBwcml2YXRlSXBQYXR0ZXJucyA9IFtcbiAgICAgICAgL14xMjdcXC4vLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExvb3BiYWNrXG4gICAgICAgIC9eMTBcXC4vLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBQcml2YXRlIGNsYXNzIEFcbiAgICAgICAgL14xOTJcXC4xNjhcXC4vLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBQcml2YXRlIGNsYXNzIENcbiAgICAgICAgL14xNzJcXC4oMVs2LTldfDJbMC05XXwzWzAtMV0pXFwuLywgICAgICAgICAgLy8gUHJpdmF0ZSBjbGFzcyBCXG4gICAgICAgIC9eMTY5XFwuMjU0XFwuLywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTGluay1sb2NhbFxuICAgICAgICAvXmZjMDA6L2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJUHY2IHByaXZhdGVcbiAgICAgICAgL15mZTgwOi9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSVB2NiBsaW5rLWxvY2FsXG4gICAgICAgIC9eOjoxJC8sICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElQdjYgbG9vcGJhY2tcbiAgICAgICAgL146OmZmZmY6MD86PzA/Oj8wPzo/MD8kL2ksICAgICAgICAgICAgICAgIC8vIElQdjYgbWFwcGVkIElQdjRcbiAgICAgICAgL14xMDBcXC42WzQtOV1cXC4vLCAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIENhcnJpZXItZ3JhZGUgTkFUXG4gICAgICAgIC9eMTAwXFwuWzctOV1bMC05XVxcLi8sICAgICAgICAgICAgICAgICAgICAgICAvLyBDYXJyaWVyLWdyYWRlIE5BVFxuICAgICAgICAvXjEwMFxcLjFbMC0yXVswLTldXFwuLywgICAgICAgICAgICAgICAgICAgICAgLy8gQ2Fycmllci1ncmFkZSBOQVRcbiAgICAgICAgL14wXFwuLywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJlc2VydmVkXG4gICAgICAgIC9eMjU1XFwuMjU1XFwuMjU1XFwuMjU1JC8gICAgICAgICAgICAgICAgICAgICAgLy8gQnJvYWRjYXN0XG4gICAgICBdO1xuICAgICAgXG4gICAgICBpZiAocHJpdmF0ZUlwUGF0dGVybnMuc29tZShwYXR0ZXJuID0+IHBhdHRlcm4udGVzdChob3N0bmFtZSkpKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKCdCbG9ja2VkIHByaXZhdGUgSVAgcmFuZ2UnLCB7IGhvc3RuYW1lIH0pO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIEJsb2NrIGNsb3VkIG1ldGFkYXRhIGVuZHBvaW50c1xuICAgICAgY29uc3QgbWV0YWRhdGFFbmRwb2ludHMgPSBbXG4gICAgICAgICcxNjkuMjU0LjE2OS4yNTQnLCAgICAgLy8gQVdTL0dDUC9BenVyZVxuICAgICAgICAnbWV0YWRhdGEuZ29vZ2xlLmludGVybmFsJyxcbiAgICAgICAgJ21ldGFkYXRhLmF6dXJlLmNvbScsXG4gICAgICAgICcxMDAuMTAwLjEwMC4yMDAnICAgICAgLy8gQWxpYmFiYSBDbG91ZFxuICAgICAgXTtcbiAgICAgIFxuICAgICAgaWYgKG1ldGFkYXRhRW5kcG9pbnRzLmluY2x1ZGVzKGhvc3RuYW1lKSkge1xuICAgICAgICBsb2dnZXIud2FybignQmxvY2tlZCBjbG91ZCBtZXRhZGF0YSBlbmRwb2ludCcsIHsgaG9zdG5hbWUgfSk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gQmxvY2sgbnVtZXJpYyBJUCByZXByZXNlbnRhdGlvbnMgdGhhdCBjb3VsZCBieXBhc3MgY2hlY2tzXG4gICAgICBpZiAoL15cXGQrJC8udGVzdChob3N0bmFtZSkpIHtcbiAgICAgICAgLy8gQ29udmVydCBkZWNpbWFsIHRvIElQIGFuZCBjaGVja1xuICAgICAgICBjb25zdCBudW0gPSBwYXJzZUludChob3N0bmFtZSwgMTApO1xuICAgICAgICBpZiAobnVtIDw9IDB4RkZGRkZGRkYpIHtcbiAgICAgICAgICBjb25zdCBpcCA9IGAkeyhudW0gPj4+IDI0KSAmIDB4RkZ9LiR7KG51bSA+Pj4gMTYpICYgMHhGRn0uJHsobnVtID4+PiA4KSAmIDB4RkZ9LiR7bnVtICYgMHhGRn1gO1xuICAgICAgICAgIGxvZ2dlci53YXJuKCdCbG9ja2VkIG51bWVyaWMgSVAgcmVwcmVzZW50YXRpb24nLCB7IGhvc3RuYW1lLCByZXNvbHZlZElwOiBpcCB9KTtcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gQmxvY2sgaGV4IElQIHJlcHJlc2VudGF0aW9uc1xuICAgICAgaWYgKC9eMHhbMC05YS1mXSskL2kudGVzdChob3N0bmFtZSkpIHtcbiAgICAgICAgbG9nZ2VyLndhcm4oJ0Jsb2NrZWQgaGV4IElQIHJlcHJlc2VudGF0aW9uJywgeyBob3N0bmFtZSB9KTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBWYWxpZGF0ZSBkb21haW4gZm9ybWF0IChiYXNpYyBjaGVjaylcbiAgICAgIC8vIEFsbG93IEdpdEh1YiBkb21haW5zIGFuZCBjb21tb24gc2hhcmUgcGxhdGZvcm1zXG4gICAgICBjb25zdCB0cnVzdGVkRG9tYWlucyA9IFtcbiAgICAgICAgJ2dpdGh1Yi5jb20nLFxuICAgICAgICAnZ2lzdC5naXRodWIuY29tJywgXG4gICAgICAgICdhcGkuZ2l0aHViLmNvbScsXG4gICAgICAgICdyYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tJyxcbiAgICAgICAgJ2RvbGxob3VzZW1jcC5jb20nXG4gICAgICBdO1xuICAgICAgXG4gICAgICAvLyBDaGVjayBpZiBpdCdzIGEgdHJ1c3RlZCBkb21haW5cbiAgICAgIGNvbnN0IGlzVHJ1c3RlZERvbWFpbiA9IHRydXN0ZWREb21haW5zLnNvbWUoZG9tYWluID0+IFxuICAgICAgICBob3N0bmFtZSA9PT0gZG9tYWluIHx8IGhvc3RuYW1lLmVuZHNXaXRoKGAuJHtkb21haW59YClcbiAgICAgICk7XG4gICAgICBcbiAgICAgIGlmICghaXNUcnVzdGVkRG9tYWluKSB7XG4gICAgICAgIC8vIEZvciBub24tdHJ1c3RlZCBkb21haW5zLCBhcHBseSBzdHJpY3RlciB2YWxpZGF0aW9uXG4gICAgICAgIC8vIE11c3QgYmUgYSB2YWxpZCBkb21haW4gZm9ybWF0LCBub3QganVzdCBhbiBJUFxuICAgICAgICBjb25zdCBkb21haW5QYXR0ZXJuID0gL14oW2EtejAtOV0rKC1bYS16MC05XSspKlxcLikrW2Etel17Mix9JC9pO1xuICAgICAgICBjb25zdCBpcHY0UGF0dGVybiA9IC9eXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM30kLztcbiAgICAgICAgY29uc3QgaXB2NlBhdHRlcm4gPSAvXlxcWz8oWzAtOWEtZl17MCw0fTopezIsN31bMC05YS1mXXswLDR9XFxdPyQvaTtcbiAgICAgICAgXG4gICAgICAgIGlmIChpcHY0UGF0dGVybi50ZXN0KGhvc3RuYW1lKSB8fCBpcHY2UGF0dGVybi50ZXN0KGhvc3RuYW1lKSkge1xuICAgICAgICAgIGxvZ2dlci53YXJuKCdEaXJlY3QgSVAgYWNjZXNzIG5vdCBhbGxvd2VkIGZvciB1bnRydXN0ZWQgc291cmNlcycsIHsgaG9zdG5hbWUgfSk7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICBpZiAoIWRvbWFpblBhdHRlcm4udGVzdChob3N0bmFtZSkpIHtcbiAgICAgICAgICBsb2dnZXIud2FybignSW52YWxpZCBkb21haW4gZm9ybWF0JywgeyBob3N0bmFtZSB9KTtcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIFxuICAgICAgbG9nZ2VyLmRlYnVnKCdVUkwgdmFsaWRhdGlvbiBwYXNzZWQnLCB7IFxuICAgICAgICBob3N0bmFtZSwgXG4gICAgICAgIHByb3RvY29sOiBwYXJzZWQucHJvdG9jb2wsXG4gICAgICAgIGlzVHJ1c3RlZDogaXNUcnVzdGVkRG9tYWluIFxuICAgICAgfSk7XG4gICAgICBcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIud2FybignVVJMIHZhbGlkYXRpb24gZXJyb3InLCB7IGVycm9yOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6ICdVbmtub3duIGVycm9yJyB9KTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSW1wb3J0IGZyb20gYmFzZTY0IFVSTFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBpbXBvcnRGcm9tQmFzZTY0VXJsKHVybDogc3RyaW5nKTogUHJvbWlzZTx7IHN1Y2Nlc3M6IGJvb2xlYW47IGRhdGE/OiBhbnk7IG1lc3NhZ2U6IHN0cmluZyB9PiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIExpbWl0IGJhc2U2NCBsZW5ndGggdG8gcHJldmVudCBSZURvUyBhdHRhY2tzICgxMEtCIG1heCBmb3IgYmFzZTY0IGVuY29kZWQgZGF0YSlcbiAgICAgIGNvbnN0IG1hdGNoID0gdXJsLm1hdGNoKC8jZG9sbGhvdXNlLXBlcnNvbmE9KFtBLVphLXowLTkrLz1dezEsMTAwMDB9KSQvKTtcbiAgICAgIGlmICghbWF0Y2gpIHtcbiAgICAgICAgdGhyb3cgRXJyb3JIYW5kbGVyLmNyZWF0ZUVycm9yKCdJbnZhbGlkIHNoYXJlIFVSTCBmb3JtYXQnLCBFcnJvckNhdGVnb3J5LlZBTElEQVRJT05fRVJST1IsIFZhbGlkYXRpb25FcnJvckNvZGVzLklOVkFMSURfRk9STUFUKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgYmFzZTY0ID0gbWF0Y2hbMV07XG4gICAgICBjb25zdCBqc29uID0gQnVmZmVyLmZyb20oYmFzZTY0LCAnYmFzZTY0JykudG9TdHJpbmcoJ3V0Zi04Jyk7XG4gICAgICBjb25zdCBkYXRhID0gSlNPTi5wYXJzZShqc29uKTtcblxuICAgICAgLy8gQ2hlY2sgZXhwaXJ5XG4gICAgICBpZiAoZGF0YS5leHBpcmVzQXQgJiYgbmV3IERhdGUoZGF0YS5leHBpcmVzQXQpIDwgbmV3IERhdGUoKSkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgIG1lc3NhZ2U6ICdUaGlzIHNoYXJlIGxpbmsgaGFzIGV4cGlyZWQnXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIC8vIFNFQ1VSSVRZIEZJWDogVmFsaWRhdGUgY29udGVudCBiZWZvcmUgcmV0dXJuaW5nXG4gICAgICBjb25zdCBiYXNlNjREYXRhVmFsaWRhdGlvbiA9IGF3YWl0IHRoaXMudmFsaWRhdGVQZXJzb25hRGF0YShkYXRhKTtcbiAgICAgIGlmICghYmFzZTY0RGF0YVZhbGlkYXRpb24uaXNWYWxpZCkge1xuICAgICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFcnJvcihgQ29udGVudCB2YWxpZGF0aW9uIGZhaWxlZDogJHtiYXNlNjREYXRhVmFsaWRhdGlvbi5lcnJvcn1gKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgZGF0YSxcbiAgICAgICAgbWVzc2FnZTogJ1N1Y2Nlc3NmdWxseSBkZWNvZGVkIHBlcnNvbmEgZGF0YSdcbiAgICAgIH07XG5cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgIG1lc3NhZ2U6IGBGYWlsZWQgdG8gZGVjb2RlIHNoYXJlIFVSTDogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRXh0cmFjdCBHaXN0IElEIGZyb20gR2l0SHViIFVSTFxuICAgKi9cbiAgcHJpdmF0ZSBleHRyYWN0R2lzdElkKHVybDogc3RyaW5nKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgY29uc3QgbWF0Y2ggPSB1cmwubWF0Y2goL2dpc3RcXC5naXRodWJcXC5jb21cXC9bXlxcL10rXFwvKFthLWYwLTldKykvKTtcbiAgICByZXR1cm4gbWF0Y2ggPyBtYXRjaFsxXSA6IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogRm9ybWF0IHNoYXJlIHN1Y2Nlc3MgbWVzc2FnZVxuICAgKi9cbiAgcHJpdmF0ZSBmb3JtYXRTaGFyZVN1Y2Nlc3ModXJsOiBzdHJpbmcsIGV4cGlyZXNBdDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBleHBpcnlEYXRlID0gbmV3IERhdGUoZXhwaXJlc0F0KTtcbiAgICBjb25zdCBkYXlzVW50aWxFeHBpcnkgPSBNYXRoLmNlaWwoKGV4cGlyeURhdGUuZ2V0VGltZSgpIC0gRGF0ZS5ub3coKSkgLyAoMjQgKiA2MCAqIDYwICogMTAwMCkpO1xuXG4gICAgcmV0dXJuIGDinIUgU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgc2hhcmUgbGluayFcblxu8J+UlyBTaGFyZSBVUkw6XG4ke3VybH1cblxu4o+x77iPIEV4cGlyZXM6ICR7ZXhwaXJ5RGF0ZS50b0xvY2FsZURhdGVTdHJpbmcoKX0gKCR7ZGF5c1VudGlsRXhwaXJ5fSBkYXlzKVxuXG7wn5OLIFRvIHNoYXJlIHRoaXMgcGVyc29uYTpcbjEuIENvcHkgdGhlIFVSTCBhYm92ZVxuMi4gU2hhcmUgaXQgd2l0aCBvdGhlcnNcbjMuIFRoZXkgY2FuIGltcG9ydCB1c2luZzogaW1wb3J0X2Zyb21fdXJsIFwiJHt1cmx9XCJcblxu8J+UkiBQcml2YWN5OiBUaGlzIGxpbmsgaXMgcHJpdmF0ZSBhbmQgd2lsbCBleHBpcmUgYXV0b21hdGljYWxseS5gO1xuICB9XG5cbiAgLyoqXG4gICAqIFNFQ1VSSVRZIEZJWDogVmFsaWRhdGUgcGVyc29uYSBkYXRhIGJlZm9yZSBhbnkgcHJvY2Vzc2luZ1xuICAgKiBUaGlzIHByb3ZpZGVzIGRlZmVuc2UtaW4tZGVwdGggdmFsaWRhdGlvbiBiZWZvcmUgY29udGVudCByZWFjaGVzIGZpbGUgb3BlcmF0aW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB2YWxpZGF0ZVBlcnNvbmFEYXRhKGRhdGE6IGFueSk6IFByb21pc2U8eyBpc1ZhbGlkOiBib29sZWFuOyBlcnJvcj86IHN0cmluZyB9PiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIEJhc2ljIHN0cnVjdHVyZSB2YWxpZGF0aW9uXG4gICAgICBpZiAoIWRhdGEgfHwgdHlwZW9mIGRhdGEgIT09ICdvYmplY3QnKSB7XG4gICAgICAgIHJldHVybiB7IGlzVmFsaWQ6IGZhbHNlLCBlcnJvcjogJ0ludmFsaWQgZGF0YSBzdHJ1Y3R1cmUnIH07XG4gICAgICB9XG5cbiAgICAgIC8vIFZhbGlkYXRlIHJlcXVpcmVkIGZpZWxkcyBmb3IgcGVyc29uYSBkYXRhXG4gICAgICBpZiAoZGF0YS5tZXRhZGF0YSAmJiAoIWRhdGEubWV0YWRhdGEubmFtZSB8fCAhZGF0YS5tZXRhZGF0YS5kZXNjcmlwdGlvbikpIHtcbiAgICAgICAgcmV0dXJuIHsgaXNWYWxpZDogZmFsc2UsIGVycm9yOiAnTWlzc2luZyByZXF1aXJlZCBwZXJzb25hIG1ldGFkYXRhJyB9O1xuICAgICAgfVxuXG4gICAgICAvLyBWYWxpZGF0ZSBjb250ZW50IGlmIHByZXNlbnRcbiAgICAgIGlmIChkYXRhLmNvbnRlbnQpIHtcbiAgICAgICAgLy8gU2l6ZSB2YWxpZGF0aW9uXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgdmFsaWRhdGVDb250ZW50U2l6ZShkYXRhLmNvbnRlbnQsIDEwMCAqIDEwMjQpOyAvLyAxMDBLQiBsaW1pdFxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIHJldHVybiB7IGlzVmFsaWQ6IGZhbHNlLCBlcnJvcjogYENvbnRlbnQgc2l6ZSB2YWxpZGF0aW9uIGZhaWxlZDogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6ICdVbmtub3duIGVycm9yJ31gIH07XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDb250ZW50IHNlY3VyaXR5IHZhbGlkYXRpb25cbiAgICAgICAgY29uc3QgY29udGVudFZhbGlkYXRpb24gPSBDb250ZW50VmFsaWRhdG9yLnZhbGlkYXRlQW5kU2FuaXRpemUoZGF0YS5jb250ZW50KTtcbiAgICAgICAgaWYgKCFjb250ZW50VmFsaWRhdGlvbi5pc1ZhbGlkICYmIGNvbnRlbnRWYWxpZGF0aW9uLnNldmVyaXR5ID09PSAnY3JpdGljYWwnKSB7XG4gICAgICAgICAgcmV0dXJuIHsgXG4gICAgICAgICAgICBpc1ZhbGlkOiBmYWxzZSwgXG4gICAgICAgICAgICBlcnJvcjogYENyaXRpY2FsIHNlY3VyaXR5IHRocmVhdCBkZXRlY3RlZDogJHtjb250ZW50VmFsaWRhdGlvbi5kZXRlY3RlZFBhdHRlcm5zPy5qb2luKCcsICcpfWAgXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBWYWxpZGF0ZSBidW5kbGUgc3RydWN0dXJlIGlmIGl0J3MgYSBidW5kbGVcbiAgICAgIGlmIChkYXRhLnBlcnNvbmFzICYmIEFycmF5LmlzQXJyYXkoZGF0YS5wZXJzb25hcykpIHtcbiAgICAgICAgZm9yIChjb25zdCBwZXJzb25hIG9mIGRhdGEucGVyc29uYXMpIHtcbiAgICAgICAgICBjb25zdCBwZXJzb25hVmFsaWRhdGlvbiA9IGF3YWl0IHRoaXMudmFsaWRhdGVQZXJzb25hRGF0YShwZXJzb25hKTtcbiAgICAgICAgICBpZiAoIXBlcnNvbmFWYWxpZGF0aW9uLmlzVmFsaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB7IGlzVmFsaWQ6IGZhbHNlLCBlcnJvcjogYEJ1bmRsZSB2YWxpZGF0aW9uIGZhaWxlZDogJHtwZXJzb25hVmFsaWRhdGlvbi5lcnJvcn1gIH07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB7IGlzVmFsaWQ6IHRydWUgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHsgXG4gICAgICAgIGlzVmFsaWQ6IGZhbHNlLCBcbiAgICAgICAgZXJyb3I6IGBWYWxpZGF0aW9uIGVycm9yOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogJ1Vua25vd24gZXJyb3InfWAgXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBFTkhBTkNFRCBTRUNVUklUWSBGSVg6IENvbXByZWhlbnNpdmUgQ29udGVudC1UeXBlIHZhbGlkYXRpb25cbiAgICogU3RyZW5ndGhlbnMgTUlNRSB0eXBlIHZhbGlkYXRpb24gd2l0aCBjb21wcmVoZW5zaXZlIHNlY3VyaXR5IGNoZWNrc1xuICAgKi9cbiAgcHJpdmF0ZSB2YWxpZGF0ZUNvbnRlbnRUeXBlKFxuICAgIGNvbnRlbnRUeXBlOiBzdHJpbmcgfCBudWxsLCBcbiAgICBleHBlY3RlZFR5cGU6IHN0cmluZ1xuICApOiB7IGlzVmFsaWQ6IGJvb2xlYW47IGVycm9yPzogc3RyaW5nIH0ge1xuICAgIC8vIENoZWNrIGlmIENvbnRlbnQtVHlwZSBoZWFkZXIgZXhpc3RzXG4gICAgaWYgKCFjb250ZW50VHlwZSkge1xuICAgICAgcmV0dXJuIHsgXG4gICAgICAgIGlzVmFsaWQ6IGZhbHNlLCBcbiAgICAgICAgZXJyb3I6ICdNaXNzaW5nIENvbnRlbnQtVHlwZSBoZWFkZXInIFxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBOb3JtYWxpemUgYW5kIHNhbml0aXplIHRoZSBjb250ZW50IHR5cGVcbiAgICBjb25zdCBub3JtYWxpemVkQ29udGVudFR5cGUgPSBjb250ZW50VHlwZS50b0xvd2VyQ2FzZSgpLnRyaW0oKTtcbiAgICBjb25zdCBub3JtYWxpemVkRXhwZWN0ZWRUeXBlID0gZXhwZWN0ZWRUeXBlLnRvTG93ZXJDYXNlKCkudHJpbSgpO1xuXG4gICAgLy8gVmFsaWRhdGUgQ29udGVudC1UeXBlIGZvcm1hdCAoYmFzaWMgTUlNRSB0eXBlIHN0cnVjdHVyZSlcbiAgICBjb25zdCBtaW1lVHlwZVBhdHRlcm4gPSAvXlthLXowLTldW2EtejAtOSEjJCZcXC1cXF5fXSpcXC9bYS16MC05XVthLXowLTkhIyQmXFwtXFxeX10qKD86XFxzKjsuKik/JC87XG4gICAgaWYgKCFtaW1lVHlwZVBhdHRlcm4udGVzdChub3JtYWxpemVkQ29udGVudFR5cGUpKSB7XG4gICAgICByZXR1cm4geyBcbiAgICAgICAgaXNWYWxpZDogZmFsc2UsIFxuICAgICAgICBlcnJvcjogYE1hbGZvcm1lZCBDb250ZW50LVR5cGUgaGVhZGVyOiAke2NvbnRlbnRUeXBlfWAgXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIEV4dHJhY3QgbWFpbiBNSU1FIHR5cGUgKGJlZm9yZSBhbnkgcGFyYW1ldGVycyBsaWtlIGNoYXJzZXQpXG4gICAgY29uc3QgbWFpblR5cGUgPSBub3JtYWxpemVkQ29udGVudFR5cGUuc3BsaXQoJzsnKVswXS50cmltKCk7XG4gICAgXG4gICAgLy8gU2VjdXJpdHkgY2hlY2s6IEJsb2NrIGRhbmdlcm91cyBNSU1FIHR5cGVzIHRoYXQgY291bGQgYnlwYXNzIHZhbGlkYXRpb25cbiAgICBjb25zdCBkYW5nZXJvdXNNaW1lVHlwZXMgPSBbXG4gICAgICAndGV4dC9odG1sJywgICAgICAgICAgIC8vIENvdWxkIGNvbnRhaW4gWFNTXG4gICAgICAndGV4dC9qYXZhc2NyaXB0JywgICAgIC8vIENvdWxkIGNvbnRhaW4gbWFsaWNpb3VzIHNjcmlwdHNcbiAgICAgICdhcHBsaWNhdGlvbi9qYXZhc2NyaXB0JywgLy8gQ291bGQgY29udGFpbiBtYWxpY2lvdXMgc2NyaXB0c1xuICAgICAgJ3RleHQveG1sJywgICAgICAgICAgICAvLyBDb3VsZCBjb250YWluIFhYRSBhdHRhY2tzXG4gICAgICAnYXBwbGljYXRpb24veG1sJywgICAgIC8vIENvdWxkIGNvbnRhaW4gWFhFIGF0dGFja3NcbiAgICAgICdpbWFnZS9zdmcreG1sJywgICAgICAgLy8gQ291bGQgY29udGFpbiBYU1MgaW4gU1ZHXG4gICAgICAnbXVsdGlwYXJ0L2Zvcm0tZGF0YScsIC8vIFVuZXhwZWN0ZWQgZm9yIEFQSSByZXNwb25zZXNcbiAgICAgICdhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQnIC8vIFVuZXhwZWN0ZWQgZm9yIEFQSSByZXNwb25zZXNcbiAgICBdO1xuXG4gICAgaWYgKGRhbmdlcm91c01pbWVUeXBlcy5pbmNsdWRlcyhtYWluVHlwZSkpIHtcbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogJ0NPTlRFTlRfSU5KRUNUSU9OX0FUVEVNUFQnLFxuICAgICAgICBzZXZlcml0eTogJ0hJR0gnLFxuICAgICAgICBzb3VyY2U6ICdwZXJzb25hX3NoYXJlcicsXG4gICAgICAgIGRldGFpbHM6IGBEYW5nZXJvdXMgQ29udGVudC1UeXBlIGRldGVjdGVkOiAke2NvbnRlbnRUeXBlfWAsXG4gICAgICAgIG1ldGFkYXRhOiB7IGNvbnRlbnRUeXBlLCBleHBlY3RlZFR5cGUgfVxuICAgICAgfSk7XG4gICAgICByZXR1cm4geyBcbiAgICAgICAgaXNWYWxpZDogZmFsc2UsIFxuICAgICAgICBlcnJvcjogYERhbmdlcm91cyBDb250ZW50LVR5cGUgbm90IGFsbG93ZWQ6ICR7bWFpblR5cGV9YCBcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgaWYgdGhlIG1haW4gdHlwZSBtYXRjaGVzIGV4cGVjdGVkIHR5cGVcbiAgICBpZiAoIW1haW5UeXBlLmluY2x1ZGVzKG5vcm1hbGl6ZWRFeHBlY3RlZFR5cGUpKSB7XG4gICAgICByZXR1cm4geyBcbiAgICAgICAgaXNWYWxpZDogZmFsc2UsIFxuICAgICAgICBlcnJvcjogYENvbnRlbnQtVHlwZSBtaXNtYXRjaDogZXhwZWN0ZWQgJHtleHBlY3RlZFR5cGV9LCBnb3QgJHttYWluVHlwZX1gIFxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBBZGRpdGlvbmFsIHZhbGlkYXRpb24gZm9yIEpTT04gcmVzcG9uc2VzXG4gICAgaWYgKG5vcm1hbGl6ZWRFeHBlY3RlZFR5cGUgPT09ICdhcHBsaWNhdGlvbi9qc29uJykge1xuICAgICAgLy8gQWNjZXB0IHZhcmlvdXMgSlNPTi1jb21wYXRpYmxlIE1JTUUgdHlwZXNcbiAgICAgIGNvbnN0IGFjY2VwdGFibGVKc29uVHlwZXMgPSBbXG4gICAgICAgICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICAgJ2FwcGxpY2F0aW9uL3ZuZC5hcGkranNvbicsXG4gICAgICAgICdhcHBsaWNhdGlvbi92bmQuZ2l0aHViLnYzK2pzb24nLFxuICAgICAgICAndGV4dC9qc29uJyAvLyBTb21lIEFQSXMgdXNlIHRoaXMgKHRob3VnaCBub3Qgc3RhbmRhcmQpXG4gICAgICBdO1xuICAgICAgXG4gICAgICBjb25zdCBpc0FjY2VwdGFibGVKc29uID0gYWNjZXB0YWJsZUpzb25UeXBlcy5zb21lKHR5cGUgPT4gbWFpblR5cGUgPT09IHR5cGUpO1xuICAgICAgaWYgKCFpc0FjY2VwdGFibGVKc29uKSB7XG4gICAgICAgIHJldHVybiB7IFxuICAgICAgICAgIGlzVmFsaWQ6IGZhbHNlLCBcbiAgICAgICAgICBlcnJvcjogYFVuc3VwcG9ydGVkIEpTT04gQ29udGVudC1UeXBlOiAke21haW5UeXBlfWAgXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIC8vIFZhbGlkYXRlIGNoYXJzZXQgcGFyYW1ldGVyIGlmIHByZXNlbnRcbiAgICAgIGNvbnN0IGNoYXJzZXRNYXRjaCA9IG5vcm1hbGl6ZWRDb250ZW50VHlwZS5tYXRjaCgvY2hhcnNldD0oW147XFxzXSspLyk7XG4gICAgICBpZiAoY2hhcnNldE1hdGNoKSB7XG4gICAgICAgIGNvbnN0IGNoYXJzZXQgPSBjaGFyc2V0TWF0Y2hbMV0udG9Mb3dlckNhc2UoKTtcbiAgICAgICAgY29uc3Qgc3VwcG9ydGVkQ2hhcnNldHMgPSBbJ3V0Zi04JywgJ3V0ZjgnLCAnYXNjaWknLCAnaXNvLTg4NTktMSddO1xuICAgICAgICBpZiAoIXN1cHBvcnRlZENoYXJzZXRzLmluY2x1ZGVzKGNoYXJzZXQpKSB7XG4gICAgICAgICAgcmV0dXJuIHsgXG4gICAgICAgICAgICBpc1ZhbGlkOiBmYWxzZSwgXG4gICAgICAgICAgICBlcnJvcjogYFVuc3VwcG9ydGVkIGNoYXJzZXQ6ICR7Y2hhcnNldH1gIFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBMb2cgc3VjY2Vzc2Z1bCB2YWxpZGF0aW9uIGZvciBtb25pdG9yaW5nXG4gICAgbG9nZ2VyLmRlYnVnKCdDb250ZW50LVR5cGUgdmFsaWRhdGlvbiBwYXNzZWQnLCB7IFxuICAgICAgY29udGVudFR5cGU6IG1haW5UeXBlLCBcbiAgICAgIGV4cGVjdGVkVHlwZTogbm9ybWFsaXplZEV4cGVjdGVkVHlwZSBcbiAgICB9KTtcblxuICAgIHJldHVybiB7IGlzVmFsaWQ6IHRydWUgfTtcbiAgfVxufSJdfQ==