@dollhousemcp/mcp-server 1.8.0 → 1.9.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 (56) hide show
  1. package/CHANGELOG.md +118 -0
  2. package/README.github.md +126 -8
  3. package/README.md +1 -1
  4. package/README.md.backup +50 -795
  5. package/README.npm.md +1 -1
  6. package/dist/collection/CollectionBrowser.d.ts.map +1 -1
  7. package/dist/collection/CollectionBrowser.js +6 -5
  8. package/dist/config/ConfigWizardDisplay.d.ts +64 -0
  9. package/dist/config/ConfigWizardDisplay.d.ts.map +1 -0
  10. package/dist/config/ConfigWizardDisplay.js +150 -0
  11. package/dist/config/WizardFirstResponse.d.ts +25 -0
  12. package/dist/config/WizardFirstResponse.d.ts.map +1 -0
  13. package/dist/config/WizardFirstResponse.js +118 -0
  14. package/dist/elements/memories/Memory.d.ts +190 -0
  15. package/dist/elements/memories/Memory.d.ts.map +1 -0
  16. package/dist/elements/memories/Memory.js +627 -0
  17. package/dist/elements/memories/MemoryManager.d.ts +136 -0
  18. package/dist/elements/memories/MemoryManager.d.ts.map +1 -0
  19. package/dist/elements/memories/MemoryManager.js +607 -0
  20. package/dist/elements/memories/MemorySearchIndex.d.ts +156 -0
  21. package/dist/elements/memories/MemorySearchIndex.d.ts.map +1 -0
  22. package/dist/elements/memories/MemorySearchIndex.js +690 -0
  23. package/dist/elements/memories/constants.d.ts +95 -0
  24. package/dist/elements/memories/constants.d.ts.map +1 -0
  25. package/dist/elements/memories/constants.js +102 -0
  26. package/dist/elements/memories/index.d.ts +7 -0
  27. package/dist/elements/memories/index.d.ts.map +1 -0
  28. package/dist/elements/memories/index.js +7 -0
  29. package/dist/elements/memories/utils.d.ts +68 -0
  30. package/dist/elements/memories/utils.d.ts.map +1 -0
  31. package/dist/elements/memories/utils.js +137 -0
  32. package/dist/generated/version.d.ts +2 -2
  33. package/dist/generated/version.js +3 -3
  34. package/dist/scripts/scripts/run-config-wizard.js +57 -0
  35. package/dist/scripts/src/config/ConfigManager.js +799 -0
  36. package/dist/scripts/src/config/ConfigWizard.js +368 -0
  37. package/dist/scripts/src/errors/SecurityError.js +47 -0
  38. package/dist/scripts/src/security/constants.js +28 -0
  39. package/dist/scripts/src/security/contentValidator.js +415 -0
  40. package/dist/scripts/src/security/errors.js +32 -0
  41. package/dist/scripts/src/security/regexValidator.js +217 -0
  42. package/dist/scripts/src/security/secureYamlParser.js +272 -0
  43. package/dist/scripts/src/security/securityMonitor.js +111 -0
  44. package/dist/scripts/src/security/validators/unicodeValidator.js +315 -0
  45. package/dist/scripts/src/utils/logger.js +288 -0
  46. package/dist/security/audit/SecurityAuditor.d.ts.map +1 -1
  47. package/dist/security/audit/SecurityAuditor.js +24 -2
  48. package/dist/security/audit/config/suppressions.d.ts.map +1 -1
  49. package/dist/security/audit/config/suppressions.js +91 -1
  50. package/dist/security/securityMonitor.d.ts +1 -1
  51. package/dist/security/securityMonitor.d.ts.map +1 -1
  52. package/dist/security/securityMonitor.js +1 -1
  53. package/dist/tools/getWelcomeMessage.d.ts +41 -0
  54. package/dist/tools/getWelcomeMessage.d.ts.map +1 -0
  55. package/dist/tools/getWelcomeMessage.js +109 -0
  56. package/package.json +1 -1
@@ -0,0 +1,607 @@
1
+ /**
2
+ * MemoryManager - Implementation of IElementManager for Memory elements
3
+ * Handles CRUD operations and lifecycle management for memories implementing IElement
4
+ *
5
+ * FIXES IMPLEMENTED:
6
+ * 1. CRITICAL: Fixed race conditions in file operations by using FileLockManager for atomic reads/writes
7
+ * 2. HIGH: Fixed unvalidated YAML parsing vulnerability by using SecureYamlParser
8
+ * 3. MEDIUM: All user inputs are now validated and sanitized
9
+ * 4. MEDIUM: Audit logging added for security operations
10
+ * 5. MEDIUM: Path validation prevents directory traversal attacks
11
+ */
12
+ import { Memory } from './Memory.js';
13
+ import { ElementType } from '../../portfolio/types.js';
14
+ import { PortfolioManager } from '../../portfolio/PortfolioManager.js';
15
+ import { FileLockManager } from '../../security/fileLockManager.js';
16
+ import { SecureYamlParser } from '../../security/secureYamlParser.js';
17
+ import { SecurityMonitor } from '../../security/securityMonitor.js';
18
+ import { sanitizeInput } from '../../security/InputValidator.js';
19
+ import { MEMORY_CONSTANTS, MEMORY_SECURITY_EVENTS } from './constants.js';
20
+ import * as path from 'path';
21
+ import * as fs from 'fs/promises';
22
+ import * as yaml from 'js-yaml';
23
+ import * as crypto from 'crypto';
24
+ export class MemoryManager {
25
+ portfolioManager;
26
+ memoriesDir;
27
+ memoryCache = new Map();
28
+ contentHashIndex = new Map();
29
+ // PERFORMANCE IMPROVEMENT: Cache for date folders to avoid directory scanning
30
+ // Invalidated when new folders are created
31
+ dateFoldersCache = null;
32
+ dateFoldersCacheTimestamp = 0;
33
+ constructor() {
34
+ this.portfolioManager = PortfolioManager.getInstance();
35
+ this.memoriesDir = this.portfolioManager.getElementDir(ElementType.MEMORY);
36
+ }
37
+ /**
38
+ * Load a memory from file
39
+ * SECURITY FIX #1: Uses FileLockManager.atomicReadFile() instead of fs.readFile()
40
+ * to prevent race conditions and ensure atomic file operations
41
+ * @param filePath Path to the memory file to load
42
+ * @returns Promise resolving to the loaded Memory instance
43
+ * @throws {Error} When file cannot be found or path validation fails
44
+ * @throws {Error} When YAML parsing fails or content is malformed
45
+ * @throws {Error} When memory validation fails after loading
46
+ */
47
+ async load(filePath) {
48
+ try {
49
+ let fullPath;
50
+ // Check if it's a relative path (no date folder)
51
+ if (!filePath.includes(path.sep) || !filePath.match(/^\d{4}-\d{2}-\d{2}/)) {
52
+ // Search in date folders
53
+ const dateFolders = await this.getDateFolders();
54
+ let found = false;
55
+ for (const dateFolder of dateFolders) {
56
+ const testPath = path.join(this.memoriesDir, dateFolder, filePath);
57
+ if (await fs.access(testPath).then(() => true).catch(() => false)) {
58
+ fullPath = testPath;
59
+ found = true;
60
+ break;
61
+ }
62
+ }
63
+ if (!found) {
64
+ // Fall back to root directory for backward compatibility during transition
65
+ fullPath = await this.validateAndResolvePath(filePath);
66
+ }
67
+ }
68
+ else {
69
+ fullPath = await this.validateAndResolvePath(filePath);
70
+ }
71
+ // Ensure fullPath is defined
72
+ if (!fullPath) {
73
+ throw new Error(`Could not resolve path: ${filePath}`);
74
+ }
75
+ // Check cache first
76
+ const cached = this.memoryCache.get(fullPath);
77
+ if (cached) {
78
+ return cached;
79
+ }
80
+ // CRITICAL FIX: Use atomic file read to prevent race conditions
81
+ // Previously: const content = await fs.readFile(fullPath, 'utf-8');
82
+ // Now: Uses FileLockManager with proper encoding object format
83
+ const content = await FileLockManager.atomicReadFile(fullPath, { encoding: 'utf-8' });
84
+ // HIGH SEVERITY FIX: Use SecureYamlParser to prevent YAML injection attacks
85
+ // Previously: Could use unsafe YAML parsing
86
+ // Now: Uses SecureYamlParser which validates content and prevents malicious patterns
87
+ const parsed = SecureYamlParser.parse(content, {
88
+ maxYamlSize: MEMORY_CONSTANTS.MAX_YAML_SIZE,
89
+ validateContent: true
90
+ });
91
+ // Extract metadata and content
92
+ const { metadata, content: memoryContent } = this.parseMemoryFile(parsed);
93
+ // Create memory instance
94
+ const memory = new Memory(metadata);
95
+ // Load saved entries if present
96
+ if (parsed.data && parsed.data.entries) {
97
+ memory.deserialize(JSON.stringify({
98
+ id: memory.id,
99
+ type: memory.type,
100
+ version: memory.version,
101
+ metadata: memory.metadata,
102
+ extensions: memory.extensions,
103
+ entries: parsed.data.entries
104
+ }));
105
+ }
106
+ // Cache the loaded memory
107
+ this.memoryCache.set(fullPath, memory);
108
+ // Log successful load
109
+ SecurityMonitor.logSecurityEvent({
110
+ type: MEMORY_SECURITY_EVENTS.MEMORY_LOADED,
111
+ severity: 'LOW',
112
+ source: 'MemoryManager.load',
113
+ details: `Loaded memory from ${path.basename(fullPath)}`
114
+ });
115
+ return memory;
116
+ }
117
+ catch (error) {
118
+ SecurityMonitor.logSecurityEvent({
119
+ type: MEMORY_SECURITY_EVENTS.MEMORY_LOAD_FAILED,
120
+ severity: 'MEDIUM',
121
+ source: 'MemoryManager.load',
122
+ details: `Failed to load memory from ${filePath}: ${error}`
123
+ });
124
+ throw new Error(`Failed to load memory: ${error}`);
125
+ }
126
+ }
127
+ /**
128
+ * Generate date-based path for memory storage
129
+ * Creates YYYY-MM-DD folder structure to prevent flat directory issues
130
+ * @param element Memory element to save
131
+ * @param fileName Optional custom filename
132
+ * @returns Full path to memory file
133
+ */
134
+ async generateMemoryPath(element, fileName) {
135
+ const date = new Date();
136
+ const dateFolder = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
137
+ const datePath = path.join(this.memoriesDir, dateFolder);
138
+ // Ensure date folder exists
139
+ await fs.mkdir(datePath, { recursive: true });
140
+ // PERFORMANCE IMPROVEMENT: Invalidate date folders cache since we created a new folder
141
+ this.dateFoldersCache = null;
142
+ // Generate filename
143
+ const baseName = fileName || `${element.metadata.name?.toLowerCase().replace(/\s+/g, '-') || 'memory'}.yaml`;
144
+ let finalName = baseName;
145
+ let version = 1;
146
+ // Handle collisions with version suffix
147
+ while (await fs.access(path.join(datePath, finalName)).then(() => true).catch(() => false)) {
148
+ version++;
149
+ finalName = baseName.replace('.yaml', `-v${version}.yaml`);
150
+ }
151
+ return path.join(datePath, finalName);
152
+ }
153
+ /**
154
+ * Calculate SHA-256 hash of memory content for deduplication
155
+ * Implements Issue #994 - Content-based deduplication
156
+ */
157
+ calculateContentHash(element) {
158
+ const content = JSON.stringify({
159
+ metadata: element.metadata,
160
+ entries: JSON.parse(element.serialize()).entries
161
+ });
162
+ return crypto.createHash('sha256').update(content).digest('hex');
163
+ }
164
+ /**
165
+ * Get all date folders in memories directory
166
+ * PERFORMANCE IMPROVEMENT: Uses cache to avoid repeated directory scanning
167
+ * Cache is invalidated when new folders are created or after 60 seconds
168
+ * @returns Array of date folder names
169
+ */
170
+ async getDateFolders() {
171
+ const now = Date.now();
172
+ const CACHE_TTL = 60000; // 60 seconds
173
+ // Return cached result if valid
174
+ if (this.dateFoldersCache !== null &&
175
+ (now - this.dateFoldersCacheTimestamp) < CACHE_TTL) {
176
+ return this.dateFoldersCache;
177
+ }
178
+ try {
179
+ const entries = await fs.readdir(this.memoriesDir, { withFileTypes: true });
180
+ const folders = entries
181
+ .filter(entry => entry.isDirectory() && /^\d{4}-\d{2}-\d{2}$/.test(entry.name))
182
+ .map(entry => entry.name)
183
+ .sort()
184
+ .reverse(); // Most recent first
185
+ // Cache the result
186
+ this.dateFoldersCache = folders;
187
+ this.dateFoldersCacheTimestamp = now;
188
+ return folders;
189
+ }
190
+ catch (error) {
191
+ if (error.code === 'ENOENT') {
192
+ // Cache empty result
193
+ this.dateFoldersCache = [];
194
+ this.dateFoldersCacheTimestamp = now;
195
+ return [];
196
+ }
197
+ throw error;
198
+ }
199
+ }
200
+ /**
201
+ * Save a memory to file
202
+ * SECURITY FIX #1: Uses FileLockManager.atomicWriteFile() for atomic operations
203
+ * @param element Memory element to save
204
+ * @param filePath Optional custom file path, defaults to date-based path
205
+ * @returns Promise that resolves when save is complete
206
+ * @throws {Error} When memory validation fails before saving
207
+ * @throws {Error} When path validation fails or file system errors occur
208
+ * @throws {Error} When atomic write operation fails
209
+ */
210
+ async save(element, filePath) {
211
+ try {
212
+ // Validate element
213
+ const validation = element.validate();
214
+ if (!validation.valid) {
215
+ throw new Error(`Invalid memory: ${validation.errors?.map(e => e.message).join(', ')}`);
216
+ }
217
+ // Calculate content hash for deduplication
218
+ const contentHash = this.calculateContentHash(element);
219
+ const existingPath = this.contentHashIndex.get(contentHash);
220
+ if (existingPath) {
221
+ // Log duplicate detection
222
+ SecurityMonitor.logSecurityEvent({
223
+ type: 'MEMORY_DUPLICATE_DETECTED',
224
+ severity: 'LOW',
225
+ source: 'MemoryManager.save',
226
+ details: `Duplicate content detected. Existing: ${existingPath}`
227
+ });
228
+ }
229
+ // Generate date-based path if not provided
230
+ const fullPath = filePath
231
+ ? await this.validateAndResolvePath(filePath)
232
+ : await this.generateMemoryPath(element);
233
+ // Ensure parent directory exists (for date folders)
234
+ await fs.mkdir(path.dirname(fullPath), { recursive: true });
235
+ // Get memory statistics
236
+ const stats = element.getStats();
237
+ // Prepare data for saving
238
+ const data = {
239
+ metadata: element.metadata,
240
+ extensions: element.extensions,
241
+ stats: {
242
+ totalEntries: stats.totalEntries,
243
+ totalSize: stats.totalSize,
244
+ oldestEntry: stats.oldestEntry?.toISOString(),
245
+ newestEntry: stats.newestEntry?.toISOString(),
246
+ topTags: Array.from(stats.tagFrequency.entries())
247
+ .sort((a, b) => b[1] - a[1])
248
+ .slice(0, 10)
249
+ .map(([tag, count]) => ({ tag, count }))
250
+ },
251
+ entries: JSON.parse(element.serialize()).entries
252
+ };
253
+ // SECURITY FIX: Use secure YAML dumping with safety options
254
+ // Previously: Could allow dangerous YAML features
255
+ // Now: Uses FAILSAFE_SCHEMA and security options to prevent code execution
256
+ const yamlContent = yaml.dump(data, {
257
+ schema: yaml.FAILSAFE_SCHEMA,
258
+ noRefs: true,
259
+ skipInvalid: true,
260
+ sortKeys: true
261
+ });
262
+ // CRITICAL FIX: Use atomic file write to prevent corruption
263
+ // Previously: await fs.writeFile(fullPath, yamlContent, 'utf-8');
264
+ // Now: Uses FileLockManager for atomic write with proper encoding
265
+ await FileLockManager.atomicWriteFile(fullPath, yamlContent, { encoding: 'utf-8' });
266
+ // Update cache
267
+ this.memoryCache.set(fullPath, element);
268
+ // Update content hash index
269
+ this.contentHashIndex.set(contentHash, fullPath);
270
+ // Log successful save
271
+ SecurityMonitor.logSecurityEvent({
272
+ type: MEMORY_SECURITY_EVENTS.MEMORY_SAVED,
273
+ severity: 'LOW',
274
+ source: 'MemoryManager.save',
275
+ details: `Saved memory to ${path.basename(fullPath)} with ${stats.totalEntries} entries`
276
+ });
277
+ }
278
+ catch (error) {
279
+ SecurityMonitor.logSecurityEvent({
280
+ type: MEMORY_SECURITY_EVENTS.MEMORY_SAVE_FAILED,
281
+ severity: 'HIGH',
282
+ source: 'MemoryManager.save',
283
+ details: `Failed to save memory to ${filePath}: ${error}`
284
+ });
285
+ throw new Error(`Failed to save memory: ${error}`);
286
+ }
287
+ }
288
+ /**
289
+ * List all available memories
290
+ */
291
+ async list() {
292
+ const memories = [];
293
+ try {
294
+ // Get all date folders
295
+ const dateFolders = await this.getDateFolders();
296
+ // Also check root directory for any legacy files
297
+ const rootFiles = await fs.readdir(this.memoriesDir)
298
+ .then(files => files.filter(f => f.endsWith('.yaml')))
299
+ .catch(() => []);
300
+ // Process root files first (legacy)
301
+ for (const file of rootFiles) {
302
+ try {
303
+ const memory = await this.load(file);
304
+ memories.push(memory);
305
+ }
306
+ catch (error) {
307
+ SecurityMonitor.logSecurityEvent({
308
+ type: MEMORY_SECURITY_EVENTS.MEMORY_LIST_ITEM_FAILED,
309
+ severity: 'LOW',
310
+ source: 'MemoryManager.list',
311
+ details: `Failed to load ${file}: ${error}`
312
+ });
313
+ }
314
+ }
315
+ // Process date folders
316
+ for (const dateFolder of dateFolders) {
317
+ const folderPath = path.join(this.memoriesDir, dateFolder);
318
+ const files = await fs.readdir(folderPath)
319
+ .then(files => files.filter(f => f.endsWith('.yaml')))
320
+ .catch(() => []);
321
+ for (const file of files) {
322
+ try {
323
+ const memory = await this.load(path.join(dateFolder, file));
324
+ memories.push(memory);
325
+ }
326
+ catch (error) {
327
+ SecurityMonitor.logSecurityEvent({
328
+ type: MEMORY_SECURITY_EVENTS.MEMORY_LIST_ITEM_FAILED,
329
+ severity: 'LOW',
330
+ source: 'MemoryManager.list',
331
+ details: `Failed to load ${dateFolder}/${file}: ${error}`
332
+ });
333
+ }
334
+ }
335
+ }
336
+ return memories;
337
+ }
338
+ catch (error) {
339
+ if (error.code === 'ENOENT') {
340
+ // Directory doesn't exist yet
341
+ return [];
342
+ }
343
+ throw error;
344
+ }
345
+ }
346
+ /**
347
+ * Find memories matching a predicate
348
+ */
349
+ async find(predicate) {
350
+ const memories = await this.list();
351
+ return memories.find(predicate);
352
+ }
353
+ /**
354
+ * Find multiple memories matching a predicate
355
+ */
356
+ async findMany(predicate) {
357
+ const memories = await this.list();
358
+ return memories.filter(predicate);
359
+ }
360
+ /**
361
+ * Delete a memory file
362
+ * SECURITY: Validates path and logs deletion
363
+ */
364
+ async delete(filePath) {
365
+ try {
366
+ const fullPath = await this.validateAndResolvePath(filePath);
367
+ // Check if file exists
368
+ await fs.access(fullPath);
369
+ // Delete the file
370
+ await fs.unlink(fullPath);
371
+ // Remove from cache
372
+ this.memoryCache.delete(fullPath);
373
+ SecurityMonitor.logSecurityEvent({
374
+ type: MEMORY_SECURITY_EVENTS.MEMORY_DELETED,
375
+ severity: 'MEDIUM',
376
+ source: 'MemoryManager.delete',
377
+ details: `Deleted memory file: ${path.basename(fullPath)}`
378
+ });
379
+ }
380
+ catch (error) {
381
+ if (error.code === 'ENOENT') {
382
+ // File doesn't exist, not an error for delete operation
383
+ return;
384
+ }
385
+ throw error;
386
+ }
387
+ }
388
+ /**
389
+ * Check if a memory file exists
390
+ */
391
+ async exists(filePath) {
392
+ try {
393
+ const fullPath = await this.validateAndResolvePath(filePath);
394
+ await fs.access(fullPath);
395
+ return true;
396
+ }
397
+ catch {
398
+ return false;
399
+ }
400
+ }
401
+ /**
402
+ * Create a new memory with metadata
403
+ */
404
+ async create(metadata) {
405
+ return new Memory(metadata);
406
+ }
407
+ /**
408
+ * Import a memory from JSON/YAML string
409
+ * SECURITY: Full validation of imported content
410
+ * @param data JSON or YAML string containing memory data
411
+ * @param format Format of the input data ('json' or 'yaml')
412
+ * @returns Promise resolving to the imported Memory instance
413
+ * @throws {Error} When JSON/YAML parsing fails
414
+ * @throws {Error} When imported data is missing required fields
415
+ * @throws {Error} When YAML content exceeds maximum allowed size
416
+ * @throws {Error} When imported memory fails validation
417
+ */
418
+ async importElement(data, format = 'yaml') {
419
+ try {
420
+ let parsed;
421
+ if (format === 'json') {
422
+ parsed = JSON.parse(data);
423
+ }
424
+ else {
425
+ // HIGH SEVERITY FIX: Use secure YAML parsing
426
+ // Memory import expects pure YAML (not frontmatter), so we parse it securely
427
+ try {
428
+ // First validate the YAML content size
429
+ if (data.length > MEMORY_CONSTANTS.MAX_YAML_SIZE) {
430
+ throw new Error('YAML content exceeds maximum allowed size');
431
+ }
432
+ // Create a wrapper to use SecureYamlParser with pure YAML
433
+ // Add minimal frontmatter markers to satisfy parser
434
+ const wrappedYaml = `---\n${data}\n---\n`;
435
+ const parseResult = SecureYamlParser.parse(wrappedYaml, {
436
+ maxYamlSize: MEMORY_CONSTANTS.MAX_YAML_SIZE,
437
+ validateContent: true
438
+ });
439
+ // Extract the parsed data (will be in the 'data' property)
440
+ parsed = parseResult.data;
441
+ }
442
+ catch (yamlError) {
443
+ throw new Error(`Invalid YAML: ${yamlError}`);
444
+ }
445
+ // Validate it's an object
446
+ if (!parsed || typeof parsed !== 'object') {
447
+ throw new Error('YAML must contain an object');
448
+ }
449
+ }
450
+ // Handle different structures from YAML parsing
451
+ let metadata = parsed.metadata;
452
+ let entries = parsed.entries || (parsed.data && parsed.data.entries);
453
+ // Validate required fields
454
+ if (!metadata || !metadata.name) {
455
+ throw new Error('Memory must have metadata with name');
456
+ }
457
+ // Create memory instance
458
+ const memory = new Memory(metadata);
459
+ // Load entries if present
460
+ if (entries) {
461
+ memory.deserialize(JSON.stringify({
462
+ id: memory.id,
463
+ type: memory.type,
464
+ version: memory.version,
465
+ metadata: memory.metadata,
466
+ extensions: memory.extensions,
467
+ entries: entries
468
+ }));
469
+ }
470
+ return memory;
471
+ }
472
+ catch (error) {
473
+ SecurityMonitor.logSecurityEvent({
474
+ type: MEMORY_SECURITY_EVENTS.MEMORY_IMPORT_FAILED,
475
+ severity: 'MEDIUM',
476
+ source: 'MemoryManager.importElement',
477
+ details: `Failed to import memory: ${error}`
478
+ });
479
+ throw new Error(`Failed to import memory: ${error}`);
480
+ }
481
+ }
482
+ /**
483
+ * Export a memory to YAML string
484
+ */
485
+ async exportElement(element) {
486
+ const stats = element.getStats();
487
+ const data = {
488
+ metadata: element.metadata,
489
+ extensions: element.extensions,
490
+ stats: {
491
+ totalEntries: stats.totalEntries,
492
+ totalSize: stats.totalSize,
493
+ oldestEntry: stats.oldestEntry?.toISOString(),
494
+ newestEntry: stats.newestEntry?.toISOString()
495
+ },
496
+ entries: JSON.parse(element.serialize()).entries
497
+ };
498
+ // SECURITY FIX: Use secure YAML dumping
499
+ return yaml.dump(data, {
500
+ schema: yaml.FAILSAFE_SCHEMA,
501
+ noRefs: true,
502
+ skipInvalid: true,
503
+ sortKeys: true
504
+ });
505
+ }
506
+ /**
507
+ * Validate a memory element
508
+ */
509
+ validate(element) {
510
+ return element.validate();
511
+ }
512
+ /**
513
+ * Validate and resolve a file path
514
+ * SECURITY: Prevents directory traversal attacks
515
+ */
516
+ validatePath(filePath) {
517
+ try {
518
+ // Perform synchronous validation checks
519
+ const normalized = path.normalize(filePath);
520
+ // Check for path traversal attempts
521
+ if (normalized.includes('..') || path.isAbsolute(normalized)) {
522
+ return false;
523
+ }
524
+ // Ensure proper extension
525
+ if (!normalized.endsWith('.md') && !normalized.endsWith('.yaml') && !normalized.endsWith('.yml')) {
526
+ return false;
527
+ }
528
+ return true;
529
+ }
530
+ catch {
531
+ return false;
532
+ }
533
+ }
534
+ /**
535
+ * Get the element type this manager handles
536
+ */
537
+ getElementType() {
538
+ return ElementType.MEMORY;
539
+ }
540
+ /**
541
+ * Get the file extension for memory files
542
+ */
543
+ getFileExtension() {
544
+ return '.yaml';
545
+ }
546
+ // Private helper methods
547
+ /**
548
+ * Validate and resolve a file path to prevent security issues
549
+ * @param filePath Path to validate and resolve
550
+ * @returns Promise resolving to the validated full path
551
+ * @throws {Error} When path contains traversal attempts (../)
552
+ * @throws {Error} When path is absolute or invalid
553
+ * @throws {Error} When file extension is not allowed (.md, .yaml, .yml)
554
+ * @throws {Error} When resolved path would be outside memories directory
555
+ */
556
+ async validateAndResolvePath(filePath) {
557
+ // SECURITY FIX: Comprehensive path validation
558
+ const normalized = path.normalize(filePath);
559
+ // Check for path traversal attempts
560
+ if (normalized.includes('..') || path.isAbsolute(normalized)) {
561
+ SecurityMonitor.logSecurityEvent({
562
+ type: 'PATH_TRAVERSAL_ATTEMPT',
563
+ severity: 'HIGH',
564
+ source: 'MemoryManager.validateAndResolvePath',
565
+ details: `Blocked path traversal attempt: ${filePath}`
566
+ });
567
+ throw new Error('Invalid file path: Path traversal detected');
568
+ }
569
+ // Ensure proper extension
570
+ if (!normalized.endsWith('.md') && !normalized.endsWith('.yaml') && !normalized.endsWith('.yml')) {
571
+ throw new Error('Memory files must have .md, .yaml, or .yml extension');
572
+ }
573
+ // Construct full path
574
+ const fullPath = path.join(this.memoriesDir, normalized);
575
+ // Verify it's within memories directory
576
+ const relative = path.relative(this.memoriesDir, fullPath);
577
+ if (relative.startsWith('..') || path.isAbsolute(relative)) {
578
+ throw new Error('File path must be within memories directory');
579
+ }
580
+ return fullPath;
581
+ }
582
+ parseMemoryFile(parsed) {
583
+ // Extract metadata with validation
584
+ const metadata = {
585
+ name: sanitizeInput(parsed.metadata?.name || 'Unnamed Memory', 100),
586
+ description: parsed.metadata?.description ?
587
+ sanitizeInput(parsed.metadata.description, 500) :
588
+ '',
589
+ version: parsed.metadata?.version || '1.0.0',
590
+ author: parsed.metadata?.author,
591
+ created: parsed.metadata?.created,
592
+ modified: new Date().toISOString(),
593
+ tags: Array.isArray(parsed.metadata?.tags) ?
594
+ parsed.metadata.tags.map((tag) => sanitizeInput(tag, MEMORY_CONSTANTS.MAX_TAG_LENGTH)) :
595
+ [],
596
+ storageBackend: parsed.metadata?.storageBackend || MEMORY_CONSTANTS.DEFAULT_STORAGE_BACKEND,
597
+ retentionDays: parsed.metadata?.retentionDays || MEMORY_CONSTANTS.DEFAULT_RETENTION_DAYS,
598
+ privacyLevel: parsed.metadata?.privacyLevel || MEMORY_CONSTANTS.DEFAULT_PRIVACY_LEVEL,
599
+ searchable: parsed.metadata?.searchable !== false,
600
+ maxEntries: parsed.metadata?.maxEntries || MEMORY_CONSTANTS.MAX_ENTRIES_DEFAULT
601
+ };
602
+ // Extract content (if any)
603
+ const content = parsed.content || '';
604
+ return { metadata, content };
605
+ }
606
+ }
607
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWVtb3J5TWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9lbGVtZW50cy9tZW1vcmllcy9NZW1vcnlNYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7O0dBVUc7QUFFSCxPQUFPLEVBQUUsTUFBTSxFQUErQixNQUFNLGFBQWEsQ0FBQztBQUdsRSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDdkUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ3BFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ3RFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUVwRSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDakUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLHNCQUFzQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDMUUsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxLQUFLLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDbEMsT0FBTyxLQUFLLElBQUksTUFBTSxTQUFTLENBQUM7QUFDaEMsT0FBTyxLQUFLLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFFakMsTUFBTSxPQUFPLGFBQWE7SUFDaEIsZ0JBQWdCLENBQW1CO0lBQ25DLFdBQVcsQ0FBUztJQUNwQixXQUFXLEdBQXdCLElBQUksR0FBRyxFQUFFLENBQUM7SUFDN0MsZ0JBQWdCLEdBQXdCLElBQUksR0FBRyxFQUFFLENBQUM7SUFFMUQsOEVBQThFO0lBQzlFLDJDQUEyQztJQUNuQyxnQkFBZ0IsR0FBb0IsSUFBSSxDQUFDO0lBQ3pDLHlCQUF5QixHQUFXLENBQUMsQ0FBQztJQUU5QztRQUNFLElBQUksQ0FBQyxn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LFFBQVEsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBVyxFQUFFLEVBQUUsQ0FBQyxhQUFhLENBQUMsR0FBRyxFQUFFLGdCQUFnQixDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDaEcsRUFBRTtZQUNKLGNBQWMsRUFBRSxNQUFNLENBQUMsUUFBUSxFQUFFLGNBQWMsSUFBSSxnQkFBZ0IsQ0FBQyx1QkFBdUI7WUFDM0YsYUFBYSxFQUFFLE1BQU0sQ0FBQyxRQUFRLEVBQUUsYUFBYSxJQUFJLGdCQUFnQixDQUFDLHNCQUFzQjtZQUN4RixZQUFZLEVBQUUsTUFBTSxDQUFDLFFBQVEsRUFBRSxZQUFZLElBQUksZ0JBQWdCLENBQUMscUJBQXFCO1lBQ3JGLFVBQVUsRUFBRSxNQUFNLENBQUMsUUFBUSxFQUFFLFVBQVUsS0FBSyxLQUFLO1lBQ2pELFVBQVUsRUFBRSxNQUFNLENBQUMsUUFBUSxFQUFFLFVBQVUsSUFBSSxnQkFBZ0IsQ0FBQyxtQkFBbUI7U0FDaEYsQ0FBQztRQUVGLDJCQUEyQjtRQUMzQixNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQztRQUVyQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxDQUFDO0lBQy9CLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTWVtb3J5TWFuYWdlciAtIEltcGxlbWVudGF0aW9uIG9mIElFbGVtZW50TWFuYWdlciBmb3IgTWVtb3J5IGVsZW1lbnRzXG4gKiBIYW5kbGVzIENSVUQgb3BlcmF0aW9ucyBhbmQgbGlmZWN5Y2xlIG1hbmFnZW1lbnQgZm9yIG1lbW9yaWVzIGltcGxlbWVudGluZyBJRWxlbWVudFxuICogXG4gKiBGSVhFUyBJTVBMRU1FTlRFRDpcbiAqIDEuIENSSVRJQ0FMOiBGaXhlZCByYWNlIGNvbmRpdGlvbnMgaW4gZmlsZSBvcGVyYXRpb25zIGJ5IHVzaW5nIEZpbGVMb2NrTWFuYWdlciBmb3IgYXRvbWljIHJlYWRzL3dyaXRlc1xuICogMi4gSElHSDogRml4ZWQgdW52YWxpZGF0ZWQgWUFNTCBwYXJzaW5nIHZ1bG5lcmFiaWxpdHkgYnkgdXNpbmcgU2VjdXJlWWFtbFBhcnNlclxuICogMy4gTUVESVVNOiBBbGwgdXNlciBpbnB1dHMgYXJlIG5vdyB2YWxpZGF0ZWQgYW5kIHNhbml0aXplZFxuICogNC4gTUVESVVNOiBBdWRpdCBsb2dnaW5nIGFkZGVkIGZvciBzZWN1cml0eSBvcGVyYXRpb25zXG4gKiA1LiBNRURJVU06IFBhdGggdmFsaWRhdGlvbiBwcmV2ZW50cyBkaXJlY3RvcnkgdHJhdmVyc2FsIGF0dGFja3NcbiAqL1xuXG5pbXBvcnQgeyBNZW1vcnksIE1lbW9yeU1ldGFkYXRhLCBNZW1vcnlFbnRyeSB9IGZyb20gJy4vTWVtb3J5LmpzJztcbmltcG9ydCB7IElFbGVtZW50TWFuYWdlciB9IGZyb20gJy4uLy4uL3R5cGVzL2VsZW1lbnRzL0lFbGVtZW50TWFuYWdlci5qcyc7XG5pbXBvcnQgeyBFbGVtZW50VmFsaWRhdGlvblJlc3VsdCB9IGZyb20gJy4uLy4uL3R5cGVzL2VsZW1lbnRzL0lFbGVtZW50LmpzJztcbmltcG9ydCB7IEVsZW1lbnRUeXBlIH0gZnJvbSAnLi4vLi4vcG9ydGZvbGlvL3R5cGVzLmpzJztcbmltcG9ydCB7IFBvcnRmb2xpb01hbmFnZXIgfSBmcm9tICcuLi8uLi9wb3J0Zm9saW8vUG9ydGZvbGlvTWFuYWdlci5qcyc7XG5pbXBvcnQgeyBGaWxlTG9ja01hbmFnZXIgfSBmcm9tICcuLi8uLi9zZWN1cml0eS9maWxlTG9ja01hbmFnZXIuanMnO1xuaW1wb3J0IHsgU2VjdXJlWWFtbFBhcnNlciB9IGZyb20gJy4uLy4uL3NlY3VyaXR5L3NlY3VyZVlhbWxQYXJzZXIuanMnO1xuaW1wb3J0IHsgU2VjdXJpdHlNb25pdG9yIH0gZnJvbSAnLi4vLi4vc2VjdXJpdHkvc2VjdXJpdHlNb25pdG9yLmpzJztcbmltcG9ydCB7IFVuaWNvZGVWYWxpZGF0b3IgfSBmcm9tICcuLi8uLi9zZWN1cml0eS92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuaW1wb3J0IHsgc2FuaXRpemVJbnB1dCB9IGZyb20gJy4uLy4uL3NlY3VyaXR5L0lucHV0VmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IE1FTU9SWV9DT05TVEFOVFMsIE1FTU9SWV9TRUNVUklUWV9FVkVOVFMgfSBmcm9tICcuL2NvbnN0YW50cy5qcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMvcHJvbWlzZXMnO1xuaW1wb3J0ICogYXMgeWFtbCBmcm9tICdqcy15YW1sJztcbmltcG9ydCAqIGFzIGNyeXB0byBmcm9tICdjcnlwdG8nO1xuXG5leHBvcnQgY2xhc3MgTWVtb3J5TWFuYWdlciBpbXBsZW1lbnRzIElFbGVtZW50TWFuYWdlcjxNZW1vcnk+IHtcbiAgcHJpdmF0ZSBwb3J0Zm9saW9NYW5hZ2VyOiBQb3J0Zm9saW9NYW5hZ2VyO1xuICBwcml2YXRlIG1lbW9yaWVzRGlyOiBzdHJpbmc7XG4gIHByaXZhdGUgbWVtb3J5Q2FjaGU6IE1hcDxzdHJpbmcsIE1lbW9yeT4gPSBuZXcgTWFwKCk7XG4gIHByaXZhdGUgY29udGVudEhhc2hJbmRleDogTWFwPHN0cmluZywgc3RyaW5nPiA9IG5ldyBNYXAoKTtcblxuICAvLyBQRVJGT1JNQU5DRSBJTVBST1ZFTUVOVDogQ2FjaGUgZm9yIGRhdGUgZm9sZGVycyB0byBhdm9pZCBkaXJlY3Rvcnkgc2Nhbm5pbmdcbiAgLy8gSW52YWxpZGF0ZWQgd2hlbiBuZXcgZm9sZGVycyBhcmUgY3JlYXRlZFxuICBwcml2YXRlIGRhdGVGb2xkZXJzQ2FjaGU6IHN0cmluZ1tdIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgZGF0ZUZvbGRlcnNDYWNoZVRpbWVzdGFtcDogbnVtYmVyID0gMDtcbiAgXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMucG9ydGZvbGlvTWFuYWdlciA9IFBvcnRmb2xpb01hbmFnZXIuZ2V0SW5zdGFuY2UoKTtcbiAgICB0aGlzLm1lbW9yaWVzRGlyID0gdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmdldEVsZW1lbnREaXIoRWxlbWVudFR5cGUuTUVNT1JZKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIExvYWQgYSBtZW1vcnkgZnJvbSBmaWxlXG4gICAqIFNFQ1VSSVRZIEZJWCAjMTogVXNlcyBGaWxlTG9ja01hbmFnZXIuYXRvbWljUmVhZEZpbGUoKSBpbnN0ZWFkIG9mIGZzLnJlYWRGaWxlKClcbiAgICogdG8gcHJldmVudCByYWNlIGNvbmRpdGlvbnMgYW5kIGVuc3VyZSBhdG9taWMgZmlsZSBvcGVyYXRpb25zXG4gICAqIEBwYXJhbSBmaWxlUGF0aCBQYXRoIHRvIHRoZSBtZW1vcnkgZmlsZSB0byBsb2FkXG4gICAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBsb2FkZWQgTWVtb3J5IGluc3RhbmNlXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBXaGVuIGZpbGUgY2Fubm90IGJlIGZvdW5kIG9yIHBhdGggdmFsaWRhdGlvbiBmYWlsc1xuICAgKiBAdGhyb3dzIHtFcnJvcn0gV2hlbiBZQU1MIHBhcnNpbmcgZmFpbHMgb3IgY29udGVudCBpcyBtYWxmb3JtZWRcbiAgICogQHRocm93cyB7RXJyb3J9IFdoZW4gbWVtb3J5IHZhbGlkYXRpb24gZmFpbHMgYWZ0ZXIgbG9hZGluZ1xuICAgKi9cbiAgYXN5bmMgbG9hZChmaWxlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxNZW1vcnk+IHtcbiAgICB0cnkge1xuICAgICAgbGV0IGZ1bGxQYXRoOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgICAgIC8vIENoZWNrIGlmIGl0J3MgYSByZWxhdGl2ZSBwYXRoIChubyBkYXRlIGZvbGRlcilcbiAgICAgIGlmICghZmlsZVBhdGguaW5jbHVkZXMocGF0aC5zZXApIHx8ICFmaWxlUGF0aC5tYXRjaCgvXlxcZHs0fS1cXGR7Mn0tXFxkezJ9LykpIHtcbiAgICAgICAgLy8gU2VhcmNoIGluIGRhdGUgZm9sZGVyc1xuICAgICAgICBjb25zdCBkYXRlRm9sZGVycyA9IGF3YWl0IHRoaXMuZ2V0RGF0ZUZvbGRlcnMoKTtcbiAgICAgICAgbGV0IGZvdW5kID0gZmFsc2U7XG5cbiAgICAgICAgZm9yIChjb25zdCBkYXRlRm9sZGVyIG9mIGRhdGVGb2xkZXJzKSB7XG4gICAgICAgICAgY29uc3QgdGVzdFBhdGggPSBwYXRoLmpvaW4odGhpcy5tZW1vcmllc0RpciwgZGF0ZUZvbGRlciwgZmlsZVBhdGgpO1xuICAgICAgICAgIGlmIChhd2FpdCBmcy5hY2Nlc3ModGVzdFBhdGgpLnRoZW4oKCkgPT4gdHJ1ZSkuY2F0Y2goKCkgPT4gZmFsc2UpKSB7XG4gICAgICAgICAgICBmdWxsUGF0aCA9IHRlc3RQYXRoO1xuICAgICAgICAgICAgZm91bmQgPSB0cnVlO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFmb3VuZCkge1xuICAgICAgICAgIC8vIEZhbGwgYmFjayB0byByb290IGRpcmVjdG9yeSBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eSBkdXJpbmcgdHJhbnNpdGlvblxuICAgICAgICAgIGZ1bGxQYXRoID0gYXdhaXQgdGhpcy52YWxpZGF0ZUFuZFJlc29sdmVQYXRoKGZpbGVQYXRoKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZnVsbFBhdGggPSBhd2FpdCB0aGlzLnZhbGlkYXRlQW5kUmVzb2x2ZVBhdGgoZmlsZVBhdGgpO1xuICAgICAgfVxuXG4gICAgICAvLyBFbnN1cmUgZnVsbFBhdGggaXMgZGVmaW5lZFxuICAgICAgaWYgKCFmdWxsUGF0aCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkIG5vdCByZXNvbHZlIHBhdGg6ICR7ZmlsZVBhdGh9YCk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIENoZWNrIGNhY2hlIGZpcnN0XG4gICAgICBjb25zdCBjYWNoZWQgPSB0aGlzLm1lbW9yeUNhY2hlLmdldChmdWxsUGF0aCk7XG4gICAgICBpZiAoY2FjaGVkKSB7XG4gICAgICAgIHJldHVybiBjYWNoZWQ7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIENSSVRJQ0FMIEZJWDogVXNlIGF0b21pYyBmaWxlIHJlYWQgdG8gcHJldmVudCByYWNlIGNvbmRpdGlvbnNcbiAgICAgIC8vIFByZXZpb3VzbHk6IGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZShmdWxsUGF0aCwgJ3V0Zi04Jyk7XG4gICAgICAvLyBOb3c6IFVzZXMgRmlsZUxvY2tNYW5hZ2VyIHdpdGggcHJvcGVyIGVuY29kaW5nIG9iamVjdCBmb3JtYXRcbiAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBGaWxlTG9ja01hbmFnZXIuYXRvbWljUmVhZEZpbGUoZnVsbFBhdGgsIHsgZW5jb2Rpbmc6ICd1dGYtOCcgfSk7XG4gICAgICBcbiAgICAgIC8vIEhJR0ggU0VWRVJJVFkgRklYOiBVc2UgU2VjdXJlWWFtbFBhcnNlciB0byBwcmV2ZW50IFlBTUwgaW5qZWN0aW9uIGF0dGFja3NcbiAgICAgIC8vIFByZXZpb3VzbHk6IENvdWxkIHVzZSB1bnNhZmUgWUFNTCBwYXJzaW5nXG4gICAgICAvLyBOb3c6IFVzZXMgU2VjdXJlWWFtbFBhcnNlciB3aGljaCB2YWxpZGF0ZXMgY29udGVudCBhbmQgcHJldmVudHMgbWFsaWNpb3VzIHBhdHRlcm5zXG4gICAgICBjb25zdCBwYXJzZWQgPSBTZWN1cmVZYW1sUGFyc2VyLnBhcnNlKGNvbnRlbnQsIHtcbiAgICAgICAgbWF4WWFtbFNpemU6IE1FTU9SWV9DT05TVEFOVFMuTUFYX1lBTUxfU0laRSxcbiAgICAgICAgdmFsaWRhdGVDb250ZW50OiB0cnVlXG4gICAgICB9KTtcbiAgICAgIFxuICAgICAgLy8gRXh0cmFjdCBtZXRhZGF0YSBhbmQgY29udGVudFxuICAgICAgY29uc3QgeyBtZXRhZGF0YSwgY29udGVudDogbWVtb3J5Q29udGVudCB9ID0gdGhpcy5wYXJzZU1lbW9yeUZpbGUocGFyc2VkKTtcbiAgICAgIFxuICAgICAgLy8gQ3JlYXRlIG1lbW9yeSBpbnN0YW5jZVxuICAgICAgY29uc3QgbWVtb3J5ID0gbmV3IE1lbW9yeShtZXRhZGF0YSk7XG4gICAgICBcbiAgICAgIC8vIExvYWQgc2F2ZWQgZW50cmllcyBpZiBwcmVzZW50XG4gICAgICBpZiAocGFyc2VkLmRhdGEgJiYgcGFyc2VkLmRhdGEuZW50cmllcykge1xuICAgICAgICBtZW1vcnkuZGVzZXJpYWxpemUoSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgIGlkOiBtZW1vcnkuaWQsXG4gICAgICAgICAgdHlwZTogbWVtb3J5LnR5cGUsXG4gICAgICAgICAgdmVyc2lvbjogbWVtb3J5LnZlcnNpb24sXG4gICAgICAgICAgbWV0YWRhdGE6IG1lbW9yeS5tZXRhZGF0YSxcbiAgICAgICAgICBleHRlbnNpb25zOiBtZW1vcnkuZXh0ZW5zaW9ucyxcbiAgICAgICAgICBlbnRyaWVzOiBwYXJzZWQuZGF0YS5lbnRyaWVzXG4gICAgICAgIH0pKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gQ2FjaGUgdGhlIGxvYWRlZCBtZW1vcnlcbiAgICAgIHRoaXMubWVtb3J5Q2FjaGUuc2V0KGZ1bGxQYXRoLCBtZW1vcnkpO1xuICAgICAgXG4gICAgICAvLyBMb2cgc3VjY2Vzc2Z1bCBsb2FkXG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6IE1FTU9SWV9TRUNVUklUWV9FVkVOVFMuTUVNT1JZX0xPQURFRCxcbiAgICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgICBzb3VyY2U6ICdNZW1vcnlNYW5hZ2VyLmxvYWQnLFxuICAgICAgICBkZXRhaWxzOiBgTG9hZGVkIG1lbW9yeSBmcm9tICR7cGF0aC5iYXNlbmFtZShmdWxsUGF0aCl9YFxuICAgICAgfSk7XG4gICAgICBcbiAgICAgIHJldHVybiBtZW1vcnk7XG4gICAgICBcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiBNRU1PUllfU0VDVVJJVFlfRVZFTlRTLk1FTU9SWV9MT0FEX0ZBSUxFRCxcbiAgICAgICAgc2V2ZXJpdHk6ICdNRURJVU0nLFxuICAgICAgICBzb3VyY2U6ICdNZW1vcnlNYW5hZ2VyLmxvYWQnLFxuICAgICAgICBkZXRhaWxzOiBgRmFpbGVkIHRvIGxvYWQgbWVtb3J5IGZyb20gJHtmaWxlUGF0aH06ICR7ZXJyb3J9YFxuICAgICAgfSk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBsb2FkIG1lbW9yeTogJHtlcnJvcn1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGUgZGF0ZS1iYXNlZCBwYXRoIGZvciBtZW1vcnkgc3RvcmFnZVxuICAgKiBDcmVhdGVzIFlZWVktTU0tREQgZm9sZGVyIHN0cnVjdHVyZSB0byBwcmV2ZW50IGZsYXQgZGlyZWN0b3J5IGlzc3Vlc1xuICAgKiBAcGFyYW0gZWxlbWVudCBNZW1vcnkgZWxlbWVudCB0byBzYXZlXG4gICAqIEBwYXJhbSBmaWxlTmFtZSBPcHRpb25hbCBjdXN0b20gZmlsZW5hbWVcbiAgICogQHJldHVybnMgRnVsbCBwYXRoIHRvIG1lbW9yeSBmaWxlXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGdlbmVyYXRlTWVtb3J5UGF0aChlbGVtZW50OiBNZW1vcnksIGZpbGVOYW1lPzogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBkYXRlID0gbmV3IERhdGUoKTtcbiAgICBjb25zdCBkYXRlRm9sZGVyID0gYCR7ZGF0ZS5nZXRGdWxsWWVhcigpfS0ke1N0cmluZyhkYXRlLmdldE1vbnRoKCkgKyAxKS5wYWRTdGFydCgyLCAnMCcpfS0ke1N0cmluZyhkYXRlLmdldERhdGUoKSkucGFkU3RhcnQoMiwgJzAnKX1gO1xuICAgIGNvbnN0IGRhdGVQYXRoID0gcGF0aC5qb2luKHRoaXMubWVtb3JpZXNEaXIsIGRhdGVGb2xkZXIpO1xuXG4gICAgLy8gRW5zdXJlIGRhdGUgZm9sZGVyIGV4aXN0c1xuICAgIGF3YWl0IGZzLm1rZGlyKGRhdGVQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuICAgIC8vIFBFUkZPUk1BTkNFIElNUFJPVkVNRU5UOiBJbnZhbGlkYXRlIGRhdGUgZm9sZGVycyBjYWNoZSBzaW5jZSB3ZSBjcmVhdGVkIGEgbmV3IGZvbGRlclxuICAgIHRoaXMuZGF0ZUZvbGRlcnNDYWNoZSA9IG51bGw7XG5cbiAgICAvLyBHZW5lcmF0ZSBmaWxlbmFtZVxuICAgIGNvbnN0IGJhc2VOYW1lID0gZmlsZU5hbWUgfHwgYCR7ZWxlbWVudC5tZXRhZGF0YS5uYW1lPy50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1xccysvZywgJy0nKSB8fCAnbWVtb3J5J30ueWFtbGA7XG4gICAgbGV0IGZpbmFsTmFtZSA9IGJhc2VOYW1lO1xuICAgIGxldCB2ZXJzaW9uID0gMTtcblxuICAgIC8vIEhhbmRsZSBjb2xsaXNpb25zIHdpdGggdmVyc2lvbiBzdWZmaXhcbiAgICB3aGlsZSAoYXdhaXQgZnMuYWNjZXNzKHBhdGguam9pbihkYXRlUGF0aCwgZmluYWxOYW1lKSkudGhlbigoKSA9PiB0cnVlKS5jYXRjaCgoKSA9PiBmYWxzZSkpIHtcbiAgICAgIHZlcnNpb24rKztcbiAgICAgIGZpbmFsTmFtZSA9IGJhc2VOYW1lLnJlcGxhY2UoJy55YW1sJywgYC12JHt2ZXJzaW9ufS55YW1sYCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHBhdGguam9pbihkYXRlUGF0aCwgZmluYWxOYW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGUgU0hBLTI1NiBoYXNoIG9mIG1lbW9yeSBjb250ZW50IGZvciBkZWR1cGxpY2F0aW9uXG4gICAqIEltcGxlbWVudHMgSXNzdWUgIzk5NCAtIENvbnRlbnQtYmFzZWQgZGVkdXBsaWNhdGlvblxuICAgKi9cbiAgcHJpdmF0ZSBjYWxjdWxhdGVDb250ZW50SGFzaChlbGVtZW50OiBNZW1vcnkpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNvbnRlbnQgPSBKU09OLnN0cmluZ2lmeSh7XG4gICAgICBtZXRhZGF0YTogZWxlbWVudC5tZXRhZGF0YSxcbiAgICAgIGVudHJpZXM6IEpTT04ucGFyc2UoZWxlbWVudC5zZXJpYWxpemUoKSkuZW50cmllc1xuICAgIH0pO1xuICAgIHJldHVybiBjcnlwdG8uY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKGNvbnRlbnQpLmRpZ2VzdCgnaGV4Jyk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFsbCBkYXRlIGZvbGRlcnMgaW4gbWVtb3JpZXMgZGlyZWN0b3J5XG4gICAqIFBFUkZPUk1BTkNFIElNUFJPVkVNRU5UOiBVc2VzIGNhY2hlIHRvIGF2b2lkIHJlcGVhdGVkIGRpcmVjdG9yeSBzY2FubmluZ1xuICAgKiBDYWNoZSBpcyBpbnZhbGlkYXRlZCB3aGVuIG5ldyBmb2xkZXJzIGFyZSBjcmVhdGVkIG9yIGFmdGVyIDYwIHNlY29uZHNcbiAgICogQHJldHVybnMgQXJyYXkgb2YgZGF0ZSBmb2xkZXIgbmFtZXNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2V0RGF0ZUZvbGRlcnMoKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gICAgY29uc3QgQ0FDSEVfVFRMID0gNjAwMDA7IC8vIDYwIHNlY29uZHNcblxuICAgIC8vIFJldHVybiBjYWNoZWQgcmVzdWx0IGlmIHZhbGlkXG4gICAgaWYgKHRoaXMuZGF0ZUZvbGRlcnNDYWNoZSAhPT0gbnVsbCAmJlxuICAgICAgICAobm93IC0gdGhpcy5kYXRlRm9sZGVyc0NhY2hlVGltZXN0YW1wKSA8IENBQ0hFX1RUTCkge1xuICAgICAgcmV0dXJuIHRoaXMuZGF0ZUZvbGRlcnNDYWNoZTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgZW50cmllcyA9IGF3YWl0IGZzLnJlYWRkaXIodGhpcy5tZW1vcmllc0RpciwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pO1xuICAgICAgY29uc3QgZm9sZGVycyA9IGVudHJpZXNcbiAgICAgICAgLmZpbHRlcihlbnRyeSA9PiBlbnRyeS5pc0RpcmVjdG9yeSgpICYmIC9eXFxkezR9LVxcZHsyfS1cXGR7Mn0kLy50ZXN0KGVudHJ5Lm5hbWUpKVxuICAgICAgICAubWFwKGVudHJ5ID0+IGVudHJ5Lm5hbWUpXG4gICAgICAgIC5zb3J0KClcbiAgICAgICAgLnJldmVyc2UoKTsgLy8gTW9zdCByZWNlbnQgZmlyc3RcblxuICAgICAgLy8gQ2FjaGUgdGhlIHJlc3VsdFxuICAgICAgdGhpcy5kYXRlRm9sZGVyc0NhY2hlID0gZm9sZGVycztcbiAgICAgIHRoaXMuZGF0ZUZvbGRlcnNDYWNoZVRpbWVzdGFtcCA9IG5vdztcblxuICAgICAgcmV0dXJuIGZvbGRlcnM7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmICgoZXJyb3IgYXMgYW55KS5jb2RlID09PSAnRU5PRU5UJykge1xuICAgICAgICAvLyBDYWNoZSBlbXB0eSByZXN1bHRcbiAgICAgICAgdGhpcy5kYXRlRm9sZGVyc0NhY2hlID0gW107XG4gICAgICAgIHRoaXMuZGF0ZUZvbGRlcnNDYWNoZVRpbWVzdGFtcCA9IG5vdztcbiAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgfVxuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNhdmUgYSBtZW1vcnkgdG8gZmlsZVxuICAgKiBTRUNVUklUWSBGSVggIzE6IFVzZXMgRmlsZUxvY2tNYW5hZ2VyLmF0b21pY1dyaXRlRmlsZSgpIGZvciBhdG9taWMgb3BlcmF0aW9uc1xuICAgKiBAcGFyYW0gZWxlbWVudCBNZW1vcnkgZWxlbWVudCB0byBzYXZlXG4gICAqIEBwYXJhbSBmaWxlUGF0aCBPcHRpb25hbCBjdXN0b20gZmlsZSBwYXRoLCBkZWZhdWx0cyB0byBkYXRlLWJhc2VkIHBhdGhcbiAgICogQHJldHVybnMgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gc2F2ZSBpcyBjb21wbGV0ZVxuICAgKiBAdGhyb3dzIHtFcnJvcn0gV2hlbiBtZW1vcnkgdmFsaWRhdGlvbiBmYWlscyBiZWZvcmUgc2F2aW5nXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBXaGVuIHBhdGggdmFsaWRhdGlvbiBmYWlscyBvciBmaWxlIHN5c3RlbSBlcnJvcnMgb2NjdXJcbiAgICogQHRocm93cyB7RXJyb3J9IFdoZW4gYXRvbWljIHdyaXRlIG9wZXJhdGlvbiBmYWlsc1xuICAgKi9cbiAgYXN5bmMgc2F2ZShlbGVtZW50OiBNZW1vcnksIGZpbGVQYXRoPzogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFZhbGlkYXRlIGVsZW1lbnRcbiAgICAgIGNvbnN0IHZhbGlkYXRpb24gPSBlbGVtZW50LnZhbGlkYXRlKCk7XG4gICAgICBpZiAoIXZhbGlkYXRpb24udmFsaWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIG1lbW9yeTogJHt2YWxpZGF0aW9uLmVycm9ycz8ubWFwKGUgPT4gZS5tZXNzYWdlKS5qb2luKCcsICcpfWApO1xuICAgICAgfVxuXG4gICAgICAvLyBDYWxjdWxhdGUgY29udGVudCBoYXNoIGZvciBkZWR1cGxpY2F0aW9uXG4gICAgICBjb25zdCBjb250ZW50SGFzaCA9IHRoaXMuY2FsY3VsYXRlQ29udGVudEhhc2goZWxlbWVudCk7XG4gICAgICBjb25zdCBleGlzdGluZ1BhdGggPSB0aGlzLmNvbnRlbnRIYXNoSW5kZXguZ2V0KGNvbnRlbnRIYXNoKTtcblxuICAgICAgaWYgKGV4aXN0aW5nUGF0aCkge1xuICAgICAgICAvLyBMb2cgZHVwbGljYXRlIGRldGVjdGlvblxuICAgICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgICAgdHlwZTogJ01FTU9SWV9EVVBMSUNBVEVfREVURUNURUQnLFxuICAgICAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgICAgICBzb3VyY2U6ICdNZW1vcnlNYW5hZ2VyLnNhdmUnLFxuICAgICAgICAgIGRldGFpbHM6IGBEdXBsaWNhdGUgY29udGVudCBkZXRlY3RlZC4gRXhpc3Rpbmc6ICR7ZXhpc3RpbmdQYXRofWBcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIC8vIEdlbmVyYXRlIGRhdGUtYmFzZWQgcGF0aCBpZiBub3QgcHJvdmlkZWRcbiAgICAgIGNvbnN0IGZ1bGxQYXRoID0gZmlsZVBhdGhcbiAgICAgICAgPyBhd2FpdCB0aGlzLnZhbGlkYXRlQW5kUmVzb2x2ZVBhdGgoZmlsZVBhdGgpXG4gICAgICAgIDogYXdhaXQgdGhpcy5nZW5lcmF0ZU1lbW9yeVBhdGgoZWxlbWVudCk7XG5cbiAgICAgIC8vIEVuc3VyZSBwYXJlbnQgZGlyZWN0b3J5IGV4aXN0cyAoZm9yIGRhdGUgZm9sZGVycylcbiAgICAgIGF3YWl0IGZzLm1rZGlyKHBhdGguZGlybmFtZShmdWxsUGF0aCksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgICAgXG4gICAgICAvLyBHZXQgbWVtb3J5IHN0YXRpc3RpY3NcbiAgICAgIGNvbnN0IHN0YXRzID0gZWxlbWVudC5nZXRTdGF0cygpO1xuICAgICAgXG4gICAgICAvLyBQcmVwYXJlIGRhdGEgZm9yIHNhdmluZ1xuICAgICAgY29uc3QgZGF0YSA9IHtcbiAgICAgICAgbWV0YWRhdGE6IGVsZW1lbnQubWV0YWRhdGEsXG4gICAgICAgIGV4dGVuc2lvbnM6IGVsZW1lbnQuZXh0ZW5zaW9ucyxcbiAgICAgICAgc3RhdHM6IHtcbiAgICAgICAgICB0b3RhbEVudHJpZXM6IHN0YXRzLnRvdGFsRW50cmllcyxcbiAgICAgICAgICB0b3RhbFNpemU6IHN0YXRzLnRvdGFsU2l6ZSxcbiAgICAgICAgICBvbGRlc3RFbnRyeTogc3RhdHMub2xkZXN0RW50cnk/LnRvSVNPU3RyaW5nKCksXG4gICAgICAgICAgbmV3ZXN0RW50cnk6IHN0YXRzLm5ld2VzdEVudHJ5Py50b0lTT1N0cmluZygpLFxuICAgICAgICAgIHRvcFRhZ3M6IEFycmF5LmZyb20oc3RhdHMudGFnRnJlcXVlbmN5LmVudHJpZXMoKSlcbiAgICAgICAgICAgIC5zb3J0KChhLCBiKSA9PiBiWzFdIC0gYVsxXSlcbiAgICAgICAgICAgIC5zbGljZSgwLCAxMClcbiAgICAgICAgICAgIC5tYXAoKFt0YWcsIGNvdW50XSkgPT4gKHsgdGFnLCBjb3VudCB9KSlcbiAgICAgICAgfSxcbiAgICAgICAgZW50cmllczogSlNPTi5wYXJzZShlbGVtZW50LnNlcmlhbGl6ZSgpKS5lbnRyaWVzXG4gICAgICB9O1xuICAgICAgXG4gICAgICAvLyBTRUNVUklUWSBGSVg6IFVzZSBzZWN1cmUgWUFNTCBkdW1waW5nIHdpdGggc2FmZXR5IG9wdGlvbnNcbiAgICAgIC8vIFByZXZpb3VzbHk6IENvdWxkIGFsbG93IGRhbmdlcm91cyBZQU1MIGZlYXR1cmVzXG4gICAgICAvLyBOb3c6IFVzZXMgRkFJTFNBRkVfU0NIRU1BIGFuZCBzZWN1cml0eSBvcHRpb25zIHRvIHByZXZlbnQgY29kZSBleGVjdXRpb25cbiAgICAgIGNvbnN0IHlhbWxDb250ZW50ID0geWFtbC5kdW1wKGRhdGEsIHtcbiAgICAgICAgc2NoZW1hOiB5YW1sLkZBSUxTQUZFX1NDSEVNQSxcbiAgICAgICAgbm9SZWZzOiB0cnVlLFxuICAgICAgICBza2lwSW52YWxpZDogdHJ1ZSxcbiAgICAgICAgc29ydEtleXM6IHRydWVcbiAgICAgIH0pO1xuICAgICAgXG4gICAgICAvLyBDUklUSUNBTCBGSVg6IFVzZSBhdG9taWMgZmlsZSB3cml0ZSB0byBwcmV2ZW50IGNvcnJ1cHRpb25cbiAgICAgIC8vIFByZXZpb3VzbHk6IGF3YWl0IGZzLndyaXRlRmlsZShmdWxsUGF0aCwgeWFtbENvbnRlbnQsICd1dGYtOCcpO1xuICAgICAgLy8gTm93OiBVc2VzIEZpbGVMb2NrTWFuYWdlciBmb3IgYXRvbWljIHdyaXRlIHdpdGggcHJvcGVyIGVuY29kaW5nXG4gICAgICBhd2FpdCBGaWxlTG9ja01hbmFnZXIuYXRvbWljV3JpdGVGaWxlKGZ1bGxQYXRoLCB5YW1sQ29udGVudCwgeyBlbmNvZGluZzogJ3V0Zi04JyB9KTtcbiAgICAgIFxuICAgICAgLy8gVXBkYXRlIGNhY2hlXG4gICAgICB0aGlzLm1lbW9yeUNhY2hlLnNldChmdWxsUGF0aCwgZWxlbWVudCk7XG5cbiAgICAgIC8vIFVwZGF0ZSBjb250ZW50IGhhc2ggaW5kZXhcbiAgICAgIHRoaXMuY29udGVudEhhc2hJbmRleC5zZXQoY29udGVudEhhc2gsIGZ1bGxQYXRoKTtcblxuICAgICAgLy8gTG9nIHN1Y2Nlc3NmdWwgc2F2ZVxuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiBNRU1PUllfU0VDVVJJVFlfRVZFTlRTLk1FTU9SWV9TQVZFRCxcbiAgICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgICBzb3VyY2U6ICdNZW1vcnlNYW5hZ2VyLnNhdmUnLFxuICAgICAgICBkZXRhaWxzOiBgU2F2ZWQgbWVtb3J5IHRvICR7cGF0aC5iYXNlbmFtZShmdWxsUGF0aCl9IHdpdGggJHtzdGF0cy50b3RhbEVudHJpZXN9IGVudHJpZXNgXG4gICAgICB9KTtcbiAgICAgIFxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6IE1FTU9SWV9TRUNVUklUWV9FVkVOVFMuTUVNT1JZX1NBVkVfRkFJTEVELFxuICAgICAgICBzZXZlcml0eTogJ0hJR0gnLFxuICAgICAgICBzb3VyY2U6ICdNZW1vcnlNYW5hZ2VyLnNhdmUnLFxuICAgICAgICBkZXRhaWxzOiBgRmFpbGVkIHRvIHNhdmUgbWVtb3J5IHRvICR7ZmlsZVBhdGh9OiAke2Vycm9yfWBcbiAgICAgIH0pO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gc2F2ZSBtZW1vcnk6ICR7ZXJyb3J9YCk7XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogTGlzdCBhbGwgYXZhaWxhYmxlIG1lbW9yaWVzXG4gICAqL1xuICBhc3luYyBsaXN0KCk6IFByb21pc2U8TWVtb3J5W10+IHtcbiAgICBjb25zdCBtZW1vcmllczogTWVtb3J5W10gPSBbXTtcblxuICAgIHRyeSB7XG4gICAgICAvLyBHZXQgYWxsIGRhdGUgZm9sZGVyc1xuICAgICAgY29uc3QgZGF0ZUZvbGRlcnMgPSBhd2FpdCB0aGlzLmdldERhdGVGb2xkZXJzKCk7XG5cbiAgICAgIC8vIEFsc28gY2hlY2sgcm9vdCBkaXJlY3RvcnkgZm9yIGFueSBsZWdhY3kgZmlsZXNcbiAgICAgIGNvbnN0IHJvb3RGaWxlcyA9IGF3YWl0IGZzLnJlYWRkaXIodGhpcy5tZW1vcmllc0RpcilcbiAgICAgICAgLnRoZW4oZmlsZXMgPT4gZmlsZXMuZmlsdGVyKGYgPT4gZi5lbmRzV2l0aCgnLnlhbWwnKSkpXG4gICAgICAgIC5jYXRjaCgoKSA9PiBbXSk7XG5cbiAgICAgIC8vIFByb2Nlc3Mgcm9vdCBmaWxlcyBmaXJzdCAobGVnYWN5KVxuICAgICAgZm9yIChjb25zdCBmaWxlIG9mIHJvb3RGaWxlcykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IG1lbW9yeSA9IGF3YWl0IHRoaXMubG9hZChmaWxlKTtcbiAgICAgICAgICBtZW1vcmllcy5wdXNoKG1lbW9yeSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICAgICAgdHlwZTogTUVNT1JZX1NFQ1VSSVRZX0VWRU5UUy5NRU1PUllfTElTVF9JVEVNX0ZBSUxFRCxcbiAgICAgICAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgICAgICAgIHNvdXJjZTogJ01lbW9yeU1hbmFnZXIubGlzdCcsXG4gICAgICAgICAgICBkZXRhaWxzOiBgRmFpbGVkIHRvIGxvYWQgJHtmaWxlfTogJHtlcnJvcn1gXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gUHJvY2VzcyBkYXRlIGZvbGRlcnNcbiAgICAgIGZvciAoY29uc3QgZGF0ZUZvbGRlciBvZiBkYXRlRm9sZGVycykge1xuICAgICAgICBjb25zdCBmb2xkZXJQYXRoID0gcGF0aC5qb2luKHRoaXMubWVtb3JpZXNEaXIsIGRhdGVGb2xkZXIpO1xuICAgICAgICBjb25zdCBmaWxlcyA9IGF3YWl0IGZzLnJlYWRkaXIoZm9sZGVyUGF0aClcbiAgICAgICAgICAudGhlbihmaWxlcyA9PiBmaWxlcy5maWx0ZXIoZiA9PiBmLmVuZHNXaXRoKCcueWFtbCcpKSlcbiAgICAgICAgICAuY2F0Y2goKCkgPT4gW10pO1xuXG4gICAgICAgIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBtZW1vcnkgPSBhd2FpdCB0aGlzLmxvYWQocGF0aC5qb2luKGRhdGVGb2xkZXIsIGZpbGUpKTtcbiAgICAgICAgICAgIG1lbW9yaWVzLnB1c2gobWVtb3J5KTtcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICAgICAgICB0eXBlOiBNRU1PUllfU0VDVVJJVFlfRVZFTlRTLk1FTU9SWV9MSVNUX0lURU1fRkFJTEVELFxuICAgICAgICAgICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICAgICAgICAgIHNvdXJjZTogJ01lbW9yeU1hbmFnZXIubGlzdCcsXG4gICAgICAgICAgICAgIGRldGFpbHM6IGBGYWlsZWQgdG8gbG9hZCAke2RhdGVGb2xkZXJ9LyR7ZmlsZX06ICR7ZXJyb3J9YFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBtZW1vcmllcztcbiAgICAgIFxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBpZiAoKGVycm9yIGFzIGFueSkuY29kZSA9PT0gJ0VOT0VOVCcpIHtcbiAgICAgICAgLy8gRGlyZWN0b3J5IGRvZXNuJ3QgZXhpc3QgeWV0XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIEZpbmQgbWVtb3JpZXMgbWF0Y2hpbmcgYSBwcmVkaWNhdGVcbiAgICovXG4gIGFzeW5jIGZpbmQocHJlZGljYXRlOiAoZWxlbWVudDogTWVtb3J5KSA9PiBib29sZWFuKTogUHJvbWlzZTxNZW1vcnkgfCB1bmRlZmluZWQ+IHtcbiAgICBjb25zdCBtZW1vcmllcyA9IGF3YWl0IHRoaXMubGlzdCgpO1xuICAgIHJldHVybiBtZW1vcmllcy5maW5kKHByZWRpY2F0ZSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBGaW5kIG11bHRpcGxlIG1lbW9yaWVzIG1hdGNoaW5nIGEgcHJlZGljYXRlXG4gICAqL1xuICBhc3luYyBmaW5kTWFueShwcmVkaWNhdGU6IChlbGVtZW50OiBNZW1vcnkpID0+IGJvb2xlYW4pOiBQcm9taXNlPE1lbW9yeVtdPiB7XG4gICAgY29uc3QgbWVtb3JpZXMgPSBhd2FpdCB0aGlzLmxpc3QoKTtcbiAgICByZXR1cm4gbWVtb3JpZXMuZmlsdGVyKHByZWRpY2F0ZSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBEZWxldGUgYSBtZW1vcnkgZmlsZVxuICAgKiBTRUNVUklUWTogVmFsaWRhdGVzIHBhdGggYW5kIGxvZ3MgZGVsZXRpb25cbiAgICovXG4gIGFzeW5jIGRlbGV0ZShmaWxlUGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGZ1bGxQYXRoID0gYXdhaXQgdGhpcy52YWxpZGF0ZUFuZFJlc29sdmVQYXRoKGZpbGVQYXRoKTtcbiAgICAgIFxuICAgICAgLy8gQ2hlY2sgaWYgZmlsZSBleGlzdHNcbiAgICAgIGF3YWl0IGZzLmFjY2VzcyhmdWxsUGF0aCk7XG4gICAgICBcbiAgICAgIC8vIERlbGV0ZSB0aGUgZmlsZVxuICAgICAgYXdhaXQgZnMudW5saW5rKGZ1bGxQYXRoKTtcbiAgICAgIFxuICAgICAgLy8gUmVtb3ZlIGZyb20gY2FjaGVcbiAgICAgIHRoaXMubWVtb3J5Q2FjaGUuZGVsZXRlKGZ1bGxQYXRoKTtcbiAgICAgIFxuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiBNRU1PUllfU0VDVVJJVFlfRVZFTlRTLk1FTU9SWV9ERUxFVEVELFxuICAgICAgICBzZXZlcml0eTogJ01FRElVTScsXG4gICAgICAgIHNvdXJjZTogJ01lbW9yeU1hbmFnZXIuZGVsZXRlJyxcbiAgICAgICAgZGV0YWlsczogYERlbGV0ZWQgbWVtb3J5IGZpbGU6ICR7cGF0aC5iYXNlbmFtZShmdWxsUGF0aCl9YFxuICAgICAgfSk7XG4gICAgICBcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKChlcnJvciBhcyBhbnkpLmNvZGUgPT09ICdFTk9FTlQnKSB7XG4gICAgICAgIC8vIEZpbGUgZG9lc24ndCBleGlzdCwgbm90IGFuIGVycm9yIGZvciBkZWxldGUgb3BlcmF0aW9uXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIENoZWNrIGlmIGEgbWVtb3J5IGZpbGUgZXhpc3RzXG4gICAqL1xuICBhc3luYyBleGlzdHMoZmlsZVBhdGg6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBmdWxsUGF0aCA9IGF3YWl0IHRoaXMudmFsaWRhdGVBbmRSZXNvbHZlUGF0aChmaWxlUGF0aCk7XG4gICAgICBhd2FpdCBmcy5hY2Nlc3MoZnVsbFBhdGgpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogQ3JlYXRlIGEgbmV3IG1lbW9yeSB3aXRoIG1ldGFkYXRhXG4gICAqL1xuICBhc3luYyBjcmVhdGUobWV0YWRhdGE6IFBhcnRpYWw8TWVtb3J5TWV0YWRhdGE+KTogUHJvbWlzZTxNZW1vcnk+IHtcbiAgICByZXR1cm4gbmV3IE1lbW9yeShtZXRhZGF0YSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBJbXBvcnQgYSBtZW1vcnkgZnJvbSBKU09OL1lBTUwgc3RyaW5nXG4gICAqIFNFQ1VSSVRZOiBGdWxsIHZhbGlkYXRpb24gb2YgaW1wb3J0ZWQgY29udGVudFxuICAgKiBAcGFyYW0gZGF0YSBKU09OIG9yIFlBTUwgc3RyaW5nIGNvbnRhaW5pbmcgbWVtb3J5IGRhdGFcbiAgICogQHBhcmFtIGZvcm1hdCBGb3JtYXQgb2YgdGhlIGlucHV0IGRhdGEgKCdqc29uJyBvciAneWFtbCcpXG4gICAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpbXBvcnRlZCBNZW1vcnkgaW5zdGFuY2VcbiAgICogQHRocm93cyB7RXJyb3J9IFdoZW4gSlNPTi9ZQU1MIHBhcnNpbmcgZmFpbHNcbiAgICogQHRocm93cyB7RXJyb3J9IFdoZW4gaW1wb3J0ZWQgZGF0YSBpcyBtaXNzaW5nIHJlcXVpcmVkIGZpZWxkc1xuICAgKiBAdGhyb3dzIHtFcnJvcn0gV2hlbiBZQU1MIGNvbnRlbnQgZXhjZWVkcyBtYXhpbXVtIGFsbG93ZWQgc2l6ZVxuICAgKiBAdGhyb3dzIHtFcnJvcn0gV2hlbiBpbXBvcnRlZCBtZW1vcnkgZmFpbHMgdmFsaWRhdGlvblxuICAgKi9cbiAgYXN5bmMgaW1wb3J0RWxlbWVudChkYXRhOiBzdHJpbmcsIGZvcm1hdDogJ2pzb24nIHwgJ3lhbWwnID0gJ3lhbWwnKTogUHJvbWlzZTxNZW1vcnk+IHtcbiAgICB0cnkge1xuICAgICAgbGV0IHBhcnNlZDogYW55O1xuICAgICAgXG4gICAgICBpZiAoZm9ybWF0ID09PSAnanNvbicpIHtcbiAgICAgICAgcGFyc2VkID0gSlNPTi5wYXJzZShkYXRhKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIEhJR0ggU0VWRVJJVFkgRklYOiBVc2Ugc2VjdXJlIFlBTUwgcGFyc2luZ1xuICAgICAgICAvLyBNZW1vcnkgaW1wb3J0IGV4cGVjdHMgcHVyZSBZQU1MIChub3QgZnJvbnRtYXR0ZXIpLCBzbyB3ZSBwYXJzZSBpdCBzZWN1cmVseVxuICAgICAgICB0cnkge1xuICAgICAgICAgIC8vIEZpcnN0IHZhbGlkYXRlIHRoZSBZQU1MIGNvbnRlbnQgc2l6ZVxuICAgICAgICAgIGlmIChkYXRhLmxlbmd0aCA+IE1FTU9SWV9DT05TVEFOVFMuTUFYX1lBTUxfU0laRSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdZQU1MIGNvbnRlbnQgZXhjZWVkcyBtYXhpbXVtIGFsbG93ZWQgc2l6ZScpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBcbiAgICAgICAgICAvLyBDcmVhdGUgYSB3cmFwcGVyIHRvIHVzZSBTZWN1cmVZYW1sUGFyc2VyIHdpdGggcHVyZSBZQU1MXG4gICAgICAgICAgLy8gQWRkIG1pbmltYWwgZnJvbnRtYXR0ZXIgbWFya2VycyB0byBzYXRpc2Z5IHBhcnNlclxuICAgICAgICAgIGNvbnN0IHdyYXBwZWRZYW1sID0gYC0tLVxcbiR7ZGF0YX1cXG4tLS1cXG5gO1xuICAgICAgICAgIFxuICAgICAgICAgIGNvbnN0IHBhcnNlUmVzdWx0ID0gU2VjdXJlWWFtbFBhcnNlci5wYXJzZSh3cmFwcGVkWWFtbCwge1xuICAgICAgICAgICAgbWF4WWFtbFNpemU6IE1FTU9SWV9DT05TVEFOVFMuTUFYX1lBTUxfU0laRSxcbiAgICAgICAgICAgIHZhbGlkYXRlQ29udGVudDogdHJ1ZVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIFxuICAgICAgICAgIC8vIEV4dHJhY3QgdGhlIHBhcnNlZCBkYXRhICh3aWxsIGJlIGluIHRoZSAnZGF0YScgcHJvcGVydHkpXG4gICAgICAgICAgcGFyc2VkID0gcGFyc2VSZXN1bHQuZGF0YTtcbiAgICAgICAgICBcbiAgICAgICAgfSBjYXRjaCAoeWFtbEVycm9yKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIFlBTUw6ICR7eWFtbEVycm9yfWApO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAvLyBWYWxpZGF0ZSBpdCdzIGFuIG9iamVjdFxuICAgICAgICBpZiAoIXBhcnNlZCB8fCB0eXBlb2YgcGFyc2VkICE9PSAnb2JqZWN0Jykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWUFNTCBtdXN0IGNvbnRhaW4gYW4gb2JqZWN0Jyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gSGFuZGxlIGRpZmZlcmVudCBzdHJ1Y3R1cmVzIGZyb20gWUFNTCBwYXJzaW5nXG4gICAgICBsZXQgbWV0YWRhdGEgPSBwYXJzZWQubWV0YWRhdGE7XG4gICAgICBsZXQgZW50cmllcyA9IHBhcnNlZC5lbnRyaWVzIHx8IChwYXJzZWQuZGF0YSAmJiBwYXJzZWQuZGF0YS5lbnRyaWVzKTtcbiAgICAgIFxuICAgICAgLy8gVmFsaWRhdGUgcmVxdWlyZWQgZmllbGRzXG4gICAgICBpZiAoIW1ldGFkYXRhIHx8ICFtZXRhZGF0YS5uYW1lKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTWVtb3J5IG11c3QgaGF2ZSBtZXRhZGF0YSB3aXRoIG5hbWUnKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gQ3JlYXRlIG1lbW9yeSBpbnN0YW5jZVxuICAgICAgY29uc3QgbWVtb3J5ID0gbmV3IE1lbW9yeShtZXRhZGF0YSk7XG4gICAgICBcbiAgICAgIC8vIExvYWQgZW50cmllcyBpZiBwcmVzZW50XG4gICAgICBpZiAoZW50cmllcykge1xuICAgICAgICBtZW1vcnkuZGVzZXJpYWxpemUoSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgIGlkOiBtZW1vcnkuaWQsXG4gICAgICAgICAgdHlwZTogbWVtb3J5LnR5cGUsXG4gICAgICAgICAgdmVyc2lvbjogbWVtb3J5LnZlcnNpb24sXG4gICAgICAgICAgbWV0YWRhdGE6IG1lbW9yeS5tZXRhZGF0YSxcbiAgICAgICAgICBleHRlbnNpb25zOiBtZW1vcnkuZXh0ZW5zaW9ucyxcbiAgICAgICAgICBlbnRyaWVzOiBlbnRyaWVzXG4gICAgICAgIH0pKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgcmV0dXJuIG1lbW9yeTtcbiAgICAgIFxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6IE1FTU9SWV9TRUNVUklUWV9FVkVOVFMuTUVNT1JZX0lNUE9SVF9GQUlMRUQsXG4gICAgICAgIHNldmVyaXR5OiAnTUVESVVNJyxcbiAgICAgICAgc291cmNlOiAnTWVtb3J5TWFuYWdlci5pbXBvcnRFbGVtZW50JyxcbiAgICAgICAgZGV0YWlsczogYEZhaWxlZCB0byBpbXBvcnQgbWVtb3J5OiAke2Vycm9yfWBcbiAgICAgIH0pO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gaW1wb3J0IG1lbW9yeTogJHtlcnJvcn1gKTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBFeHBvcnQgYSBtZW1vcnkgdG8gWUFNTCBzdHJpbmdcbiAgICovXG4gIGFzeW5jIGV4cG9ydEVsZW1lbnQoZWxlbWVudDogTWVtb3J5KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBzdGF0cyA9IGVsZW1lbnQuZ2V0U3RhdHMoKTtcbiAgICBjb25zdCBkYXRhID0ge1xuICAgICAgbWV0YWRhdGE6IGVsZW1lbnQubWV0YWRhdGEsXG4gICAgICBleHRlbnNpb25zOiBlbGVtZW50LmV4dGVuc2lvbnMsXG4gICAgICBzdGF0czoge1xuICAgICAgICB0b3RhbEVudHJpZXM6IHN0YXRzLnRvdGFsRW50cmllcyxcbiAgICAgICAgdG90YWxTaXplOiBzdGF0cy50b3RhbFNpemUsXG4gICAgICAgIG9sZGVzdEVudHJ5OiBzdGF0cy5vbGRlc3RFbnRyeT8udG9JU09TdHJpbmcoKSxcbiAgICAgICAgbmV3ZXN0RW50cnk6IHN0YXRzLm5ld2VzdEVudHJ5Py50b0lTT1N0cmluZygpXG4gICAgICB9LFxuICAgICAgZW50cmllczogSlNPTi5wYXJzZShlbGVtZW50LnNlcmlhbGl6ZSgpKS5lbnRyaWVzXG4gICAgfTtcbiAgICBcbiAgICAvLyBTRUNVUklUWSBGSVg6IFVzZSBzZWN1cmUgWUFNTCBkdW1waW5nXG4gICAgcmV0dXJuIHlhbWwuZHVtcChkYXRhLCB7XG4gICAgICBzY2hlbWE6IHlhbWwuRkFJTFNBRkVfU0NIRU1BLFxuICAgICAgbm9SZWZzOiB0cnVlLFxuICAgICAgc2tpcEludmFsaWQ6IHRydWUsXG4gICAgICBzb3J0S2V5czogdHJ1ZVxuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogVmFsaWRhdGUgYSBtZW1vcnkgZWxlbWVudFxuICAgKi9cbiAgdmFsaWRhdGUoZWxlbWVudDogTWVtb3J5KTogRWxlbWVudFZhbGlkYXRpb25SZXN1bHQge1xuICAgIHJldHVybiBlbGVtZW50LnZhbGlkYXRlKCk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhbmQgcmVzb2x2ZSBhIGZpbGUgcGF0aFxuICAgKiBTRUNVUklUWTogUHJldmVudHMgZGlyZWN0b3J5IHRyYXZlcnNhbCBhdHRhY2tzXG4gICAqL1xuICB2YWxpZGF0ZVBhdGgoZmlsZVBhdGg6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICAvLyBQZXJmb3JtIHN5bmNocm9ub3VzIHZhbGlkYXRpb24gY2hlY2tzXG4gICAgICBjb25zdCBub3JtYWxpemVkID0gcGF0aC5ub3JtYWxpemUoZmlsZVBhdGgpO1xuICAgICAgXG4gICAgICAvLyBDaGVjayBmb3IgcGF0aCB0cmF2ZXJzYWwgYXR0ZW1wdHNcbiAgICAgIGlmIChub3JtYWxpemVkLmluY2x1ZGVzKCcuLicpIHx8IHBhdGguaXNBYnNvbHV0ZShub3JtYWxpemVkKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIEVuc3VyZSBwcm9wZXIgZXh0ZW5zaW9uXG4gICAgICBpZiAoIW5vcm1hbGl6ZWQuZW5kc1dpdGgoJy5tZCcpICYmICFub3JtYWxpemVkLmVuZHNXaXRoKCcueWFtbCcpICYmICFub3JtYWxpemVkLmVuZHNXaXRoKCcueW1sJykpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIGVsZW1lbnQgdHlwZSB0aGlzIG1hbmFnZXIgaGFuZGxlc1xuICAgKi9cbiAgZ2V0RWxlbWVudFR5cGUoKTogRWxlbWVudFR5cGUge1xuICAgIHJldHVybiBFbGVtZW50VHlwZS5NRU1PUlk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIGZpbGUgZXh0ZW5zaW9uIGZvciBtZW1vcnkgZmlsZXNcbiAgICovXG4gIGdldEZpbGVFeHRlbnNpb24oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gJy55YW1sJztcbiAgfVxuICBcbiAgLy8gUHJpdmF0ZSBoZWxwZXIgbWV0aG9kc1xuICBcbiAgLyoqXG4gICAqIFZhbGlkYXRlIGFuZCByZXNvbHZlIGEgZmlsZSBwYXRoIHRvIHByZXZlbnQgc2VjdXJpdHkgaXNzdWVzXG4gICAqIEBwYXJhbSBmaWxlUGF0aCBQYXRoIHRvIHZhbGlkYXRlIGFuZCByZXNvbHZlXG4gICAqIEByZXR1cm5zIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB2YWxpZGF0ZWQgZnVsbCBwYXRoXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBXaGVuIHBhdGggY29udGFpbnMgdHJhdmVyc2FsIGF0dGVtcHRzICguLi8pXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBXaGVuIHBhdGggaXMgYWJzb2x1dGUgb3IgaW52YWxpZFxuICAgKiBAdGhyb3dzIHtFcnJvcn0gV2hlbiBmaWxlIGV4dGVuc2lvbiBpcyBub3QgYWxsb3dlZCAoLm1kLCAueWFtbCwgLnltbClcbiAgICogQHRocm93cyB7RXJyb3J9IFdoZW4gcmVzb2x2ZWQgcGF0aCB3b3VsZCBiZSBvdXRzaWRlIG1lbW9yaWVzIGRpcmVjdG9yeVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB2YWxpZGF0ZUFuZFJlc29sdmVQYXRoKGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIC8vIFNFQ1VSSVRZIEZJWDogQ29tcHJlaGVuc2l2ZSBwYXRoIHZhbGlkYXRpb25cbiAgICBjb25zdCBub3JtYWxpemVkID0gcGF0aC5ub3JtYWxpemUoZmlsZVBhdGgpO1xuICAgIFxuICAgIC8vIENoZWNrIGZvciBwYXRoIHRyYXZlcnNhbCBhdHRlbXB0c1xuICAgIGlmIChub3JtYWxpemVkLmluY2x1ZGVzKCcuLicpIHx8IHBhdGguaXNBYnNvbHV0ZShub3JtYWxpemVkKSkge1xuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnUEFUSF9UUkFWRVJTQUxfQVRURU1QVCcsXG4gICAgICAgIHNldmVyaXR5OiAnSElHSCcsXG4gICAgICAgIHNvdXJjZTogJ01lbW9yeU1hbmFnZXIudmFsaWRhdGVBbmRSZXNvbHZlUGF0aCcsXG4gICAgICAgIGRldGFpbHM6IGBCbG9ja2VkIHBhdGggdHJhdmVyc2FsIGF0dGVtcHQ6ICR7ZmlsZVBhdGh9YFxuICAgICAgfSk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgZmlsZSBwYXRoOiBQYXRoIHRyYXZlcnNhbCBkZXRlY3RlZCcpO1xuICAgIH1cbiAgICBcbiAgICAvLyBFbnN1cmUgcHJvcGVyIGV4dGVuc2lvblxuICAgIGlmICghbm9ybWFsaXplZC5lbmRzV2l0aCgnLm1kJykgJiYgIW5vcm1hbGl6ZWQuZW5kc1dpdGgoJy55YW1sJykgJiYgIW5vcm1hbGl6ZWQuZW5kc1dpdGgoJy55bWwnKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdNZW1vcnkgZmlsZXMgbXVzdCBoYXZlIC5tZCwgLnlhbWwsIG9yIC55bWwgZXh0ZW5zaW9uJyk7XG4gICAgfVxuICAgIFxuICAgIC8vIENvbnN0cnVjdCBmdWxsIHBhdGhcbiAgICBjb25zdCBmdWxsUGF0aCA9IHBhdGguam9pbih0aGlzLm1lbW9yaWVzRGlyLCBub3JtYWxpemVkKTtcbiAgICBcbiAgICAvLyBWZXJpZnkgaXQncyB3aXRoaW4gbWVtb3JpZXMgZGlyZWN0b3J5XG4gICAgY29uc3QgcmVsYXRpdmUgPSBwYXRoLnJlbGF0aXZlKHRoaXMubWVtb3JpZXNEaXIsIGZ1bGxQYXRoKTtcbiAgICBpZiAocmVsYXRpdmUuc3RhcnRzV2l0aCgnLi4nKSB8fCBwYXRoLmlzQWJzb2x1dGUocmVsYXRpdmUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ZpbGUgcGF0aCBtdXN0IGJlIHdpdGhpbiBtZW1vcmllcyBkaXJlY3RvcnknKTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGZ1bGxQYXRoO1xuICB9XG4gIFxuICBwcml2YXRlIHBhcnNlTWVtb3J5RmlsZShwYXJzZWQ6IGFueSk6IHsgbWV0YWRhdGE6IE1lbW9yeU1ldGFkYXRhOyBjb250ZW50OiBzdHJpbmcgfSB7XG4gICAgLy8gRXh0cmFjdCBtZXRhZGF0YSB3aXRoIHZhbGlkYXRpb25cbiAgICBjb25zdCBtZXRhZGF0YTogTWVtb3J5TWV0YWRhdGEgPSB7XG4gICAgICBuYW1lOiBzYW5pdGl6ZUlucHV0KHBhcnNlZC5tZXRhZGF0YT8ubmFtZSB8fCAnVW5uYW1lZCBNZW1vcnknLCAxMDApLFxuICAgICAgZGVzY3JpcHRpb246IHBhcnNlZC5tZXRhZGF0YT8uZGVzY3JpcHRpb24gPyBcbiAgICAgICAgc2FuaXRpemVJbnB1dChwYXJzZWQubWV0YWRhdGEuZGVzY3JpcHRpb24sIDUwMCkgOiBcbiAgICAgICAgJycsXG4gICAgICB2ZXJzaW9uOiBwYXJzZWQubWV0YWRhdGE/LnZlcnNpb24gfHwgJzEuMC4wJyxcbiAgICAgIGF1dGhvcjogcGFyc2VkLm1ldGFkYXRhPy5hdXRob3IsXG4gICAgICBjcmVhdGVkOiBwYXJzZWQubWV0YWRhdGE/LmNyZWF0ZWQsXG4gICAgICBtb2RpZmllZDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgdGFnczogQXJyYXkuaXNBcnJheShwYXJzZWQubWV0YWRhdGE/LnRhZ3MpID9cbiAgICAgICAgcGFyc2VkLm1ldGFkYXRhLnRhZ3MubWFwKCh0YWc6IHN0cmluZykgPT4gc2FuaXRpemVJbnB1dCh0YWcsIE1FTU9SWV9DT05TVEFOVFMuTUFYX1RBR19MRU5HVEgpKSA6XG4gICAgICAgIFtdLFxuICAgICAgc3RvcmFnZUJhY2tlbmQ6IHBhcnNlZC5tZXRhZGF0YT8uc3RvcmFnZUJhY2tlbmQgfHwgTUVNT1JZX0NPTlNUQU5UUy5ERUZBVUxUX1NUT1JBR0VfQkFDS0VORCxcbiAgICAgIHJldGVudGlvbkRheXM6IHBhcnNlZC5tZXRhZGF0YT8ucmV0ZW50aW9uRGF5cyB8fCBNRU1PUllfQ09OU1RBTlRTLkRFRkFVTFRfUkVURU5USU9OX0RBWVMsXG4gICAgICBwcml2YWN5TGV2ZWw6IHBhcnNlZC5tZXRhZGF0YT8ucHJpdmFjeUxldmVsIHx8IE1FTU9SWV9DT05TVEFOVFMuREVGQVVMVF9QUklWQUNZX0xFVkVMLFxuICAgICAgc2VhcmNoYWJsZTogcGFyc2VkLm1ldGFkYXRhPy5zZWFyY2hhYmxlICE9PSBmYWxzZSxcbiAgICAgIG1heEVudHJpZXM6IHBhcnNlZC5tZXRhZGF0YT8ubWF4RW50cmllcyB8fCBNRU1PUllfQ09OU1RBTlRTLk1BWF9FTlRSSUVTX0RFRkFVTFRcbiAgICB9O1xuICAgIFxuICAgIC8vIEV4dHJhY3QgY29udGVudCAoaWYgYW55KVxuICAgIGNvbnN0IGNvbnRlbnQgPSBwYXJzZWQuY29udGVudCB8fCAnJztcbiAgICBcbiAgICByZXR1cm4geyBtZXRhZGF0YSwgY29udGVudCB9O1xuICB9XG59Il19