@dollhousemcp/mcp-server 1.3.2 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +87 -5
  2. package/dist/collection/ElementInstaller.d.ts.map +1 -1
  3. package/dist/collection/ElementInstaller.js +3 -7
  4. package/dist/elements/index.d.ts +0 -2
  5. package/dist/elements/index.d.ts.map +1 -1
  6. package/dist/elements/index.js +1 -3
  7. package/dist/elements/skills/Skill.d.ts.map +1 -1
  8. package/dist/elements/skills/Skill.js +3 -2
  9. package/dist/elements/skills/SkillManager.d.ts +83 -0
  10. package/dist/elements/skills/SkillManager.d.ts.map +1 -0
  11. package/dist/elements/skills/SkillManager.js +383 -0
  12. package/dist/elements/skills/index.d.ts +1 -0
  13. package/dist/elements/skills/index.d.ts.map +1 -1
  14. package/dist/elements/skills/index.js +2 -1
  15. package/dist/index.d.ts +51 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +577 -3
  18. package/dist/portfolio/PortfolioManager.d.ts.map +1 -1
  19. package/dist/portfolio/PortfolioManager.js +1 -3
  20. package/dist/portfolio/types.d.ts +1 -3
  21. package/dist/portfolio/types.d.ts.map +1 -1
  22. package/dist/portfolio/types.js +1 -3
  23. package/dist/security/audit/config/suppressions.d.ts.map +1 -1
  24. package/dist/security/audit/config/suppressions.js +6 -1
  25. package/dist/server/ServerSetup.d.ts.map +1 -1
  26. package/dist/server/ServerSetup.js +5 -2
  27. package/dist/server/tools/CollectionTools.js +6 -6
  28. package/dist/server/tools/ElementTools.d.ts +11 -0
  29. package/dist/server/tools/ElementTools.d.ts.map +1 -0
  30. package/dist/server/tools/ElementTools.js +174 -0
  31. package/dist/server/tools/index.d.ts +1 -0
  32. package/dist/server/tools/index.d.ts.map +1 -1
  33. package/dist/server/tools/index.js +2 -1
  34. package/dist/server/types.d.ts +8 -0
  35. package/dist/server/types.d.ts.map +1 -1
  36. package/dist/server/types.js +1 -1
  37. package/package.json +1 -1
  38. package/dist/elements/ensembles/Ensemble.d.ts +0 -144
  39. package/dist/elements/ensembles/Ensemble.d.ts.map +0 -1
  40. package/dist/elements/ensembles/Ensemble.js +0 -860
  41. package/dist/elements/ensembles/EnsembleManager.d.ts +0 -85
  42. package/dist/elements/ensembles/EnsembleManager.d.ts.map +0 -1
  43. package/dist/elements/ensembles/EnsembleManager.js +0 -378
  44. package/dist/elements/ensembles/constants.d.ts +0 -73
  45. package/dist/elements/ensembles/constants.d.ts.map +0 -1
  46. package/dist/elements/ensembles/constants.js +0 -92
  47. package/dist/elements/ensembles/index.d.ts +0 -8
  48. package/dist/elements/ensembles/index.d.ts.map +0 -1
  49. package/dist/elements/ensembles/index.js +0 -8
  50. package/dist/elements/ensembles/types.d.ts +0 -92
  51. package/dist/elements/ensembles/types.d.ts.map +0 -1
  52. package/dist/elements/ensembles/types.js +0 -8
  53. package/dist/elements/memories/Memory.d.ts +0 -110
  54. package/dist/elements/memories/Memory.d.ts.map +0 -1
  55. package/dist/elements/memories/Memory.js +0 -470
  56. package/dist/elements/memories/MemoryManager.d.ts +0 -86
  57. package/dist/elements/memories/MemoryManager.d.ts.map +0 -1
  58. package/dist/elements/memories/MemoryManager.js +0 -435
  59. package/dist/elements/memories/constants.d.ts +0 -42
  60. package/dist/elements/memories/constants.d.ts.map +0 -1
  61. package/dist/elements/memories/constants.js +0 -49
  62. package/dist/elements/memories/index.d.ts +0 -6
  63. package/dist/elements/memories/index.d.ts.map +0 -1
  64. package/dist/elements/memories/index.js +0 -6
@@ -1,470 +0,0 @@
1
- /**
2
- * Memory Element - Persistent context storage for continuity and learning
3
- *
4
- * Provides multiple storage backends, retention policies, and search capabilities
5
- * for maintaining context across sessions and interactions.
6
- *
7
- * SECURITY MEASURES IMPLEMENTED:
8
- * 1. Input sanitization for all memory content
9
- * 2. Memory size limits to prevent unbounded growth
10
- * 3. Path validation for file-based storage
11
- * 4. Retention policy enforcement
12
- * 5. Privacy level access control
13
- * 6. Audit logging for all operations
14
- */
15
- import { BaseElement } from '../BaseElement.js';
16
- import { ElementType } from '../../portfolio/types.js';
17
- import { UnicodeValidator } from '../../security/validators/unicodeValidator.js';
18
- import { SecurityMonitor } from '../../security/securityMonitor.js';
19
- import { sanitizeInput } from '../../security/InputValidator.js';
20
- import { MEMORY_CONSTANTS, MEMORY_SECURITY_EVENTS } from './constants.js';
21
- import DOMPurify from 'dompurify';
22
- import { JSDOM } from 'jsdom';
23
- // Initialize DOMPurify with JSDOM
24
- const window = new JSDOM('').window;
25
- const purify = DOMPurify(window);
26
- // Configure DOMPurify for memory content - strip all HTML but keep text
27
- purify.setConfig({
28
- ALLOWED_TAGS: [], // No HTML tags allowed
29
- ALLOWED_ATTR: [], // No attributes allowed
30
- KEEP_CONTENT: true // Keep text content
31
- });
32
- /**
33
- * Sanitize content for memory storage
34
- * More permissive than sanitizeInput - allows punctuation, quotes, etc.
35
- * but still prevents XSS and control characters
36
- */
37
- function sanitizeMemoryContent(content, maxLength) {
38
- if (!content || typeof content !== 'string') {
39
- return '';
40
- }
41
- // First normalize Unicode
42
- const normalized = UnicodeValidator.normalize(content).normalizedContent;
43
- // Use DOMPurify to strip any HTML/XSS attempts but keep text
44
- const cleaned = purify.sanitize(normalized);
45
- // Remove only control characters and null bytes
46
- return cleaned
47
- .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '') // Remove control chars except \t \n \r
48
- .substring(0, maxLength)
49
- .trim();
50
- }
51
- export class Memory extends BaseElement {
52
- // Memory-specific properties
53
- entries = new Map();
54
- storageBackend;
55
- retentionDays;
56
- privacyLevel;
57
- searchable;
58
- maxEntries;
59
- constructor(metadata = {}) {
60
- // SECURITY FIX: Sanitize all inputs during construction
61
- const sanitizedMetadata = {
62
- ...metadata,
63
- name: metadata.name ?
64
- sanitizeInput(UnicodeValidator.normalize(metadata.name).normalizedContent, 100) :
65
- 'Unnamed Memory',
66
- description: metadata.description ?
67
- sanitizeInput(UnicodeValidator.normalize(metadata.description).normalizedContent, 500) :
68
- undefined
69
- };
70
- super(ElementType.MEMORY, sanitizedMetadata);
71
- // Initialize memory-specific properties with defaults
72
- this.storageBackend = metadata.storageBackend || MEMORY_CONSTANTS.DEFAULT_STORAGE_BACKEND;
73
- this.retentionDays = metadata.retentionDays || MEMORY_CONSTANTS.DEFAULT_RETENTION_DAYS;
74
- // Validate privacy level - default to private if invalid
75
- this.privacyLevel = (metadata.privacyLevel && MEMORY_CONSTANTS.PRIVACY_LEVELS.includes(metadata.privacyLevel))
76
- ? metadata.privacyLevel
77
- : MEMORY_CONSTANTS.DEFAULT_PRIVACY_LEVEL;
78
- this.searchable = metadata.searchable !== false;
79
- this.maxEntries = Math.min(metadata.maxEntries || MEMORY_CONSTANTS.MAX_ENTRIES_DEFAULT, MEMORY_CONSTANTS.MAX_ENTRIES_DEFAULT);
80
- // Set up extensions
81
- this.extensions = {
82
- storageBackend: this.storageBackend,
83
- retentionDays: this.retentionDays,
84
- privacyLevel: this.privacyLevel,
85
- searchable: this.searchable,
86
- maxEntries: this.maxEntries,
87
- encryptionEnabled: metadata.encryptionEnabled || false
88
- };
89
- // Log memory creation
90
- SecurityMonitor.logSecurityEvent({
91
- type: MEMORY_SECURITY_EVENTS.MEMORY_CREATED,
92
- severity: 'LOW',
93
- source: 'Memory.constructor',
94
- details: `Memory created: ${this.metadata.name} with ${this.storageBackend} backend`
95
- });
96
- }
97
- /**
98
- * Add a new memory entry
99
- * SECURITY: Validates and sanitizes all input, enforces size limits
100
- */
101
- async addEntry(content, tags, metadata) {
102
- // Validate memory size limits
103
- if (this.entries.size >= this.maxEntries) {
104
- // SECURITY FIX: Enforce retention policy when at capacity
105
- await this.enforceRetentionPolicy();
106
- // If still at capacity after retention, remove oldest to make room
107
- if (this.entries.size >= this.maxEntries) {
108
- const oldestEntry = Array.from(this.entries.values())
109
- .sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime())[0];
110
- if (oldestEntry) {
111
- this.entries.delete(oldestEntry.id);
112
- }
113
- }
114
- }
115
- // SECURITY FIX: Validate and sanitize content
116
- const sanitizedContent = sanitizeMemoryContent(content, MEMORY_CONSTANTS.MAX_ENTRY_SIZE);
117
- if (!sanitizedContent || sanitizedContent.trim().length === 0) {
118
- throw new Error('Memory content cannot be empty');
119
- }
120
- // SECURITY FIX: Validate and sanitize tags
121
- const sanitizedTags = tags ? this.sanitizeTags(tags) : [];
122
- // Create memory entry
123
- const entry = {
124
- id: `mem_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
125
- timestamp: new Date(),
126
- content: sanitizedContent,
127
- tags: sanitizedTags,
128
- metadata: this.sanitizeMetadata(metadata),
129
- privacyLevel: this.privacyLevel,
130
- expiresAt: this.calculateExpiryDate()
131
- };
132
- // Store entry
133
- this.entries.set(entry.id, entry);
134
- this._isDirty = true;
135
- // Log memory addition
136
- SecurityMonitor.logSecurityEvent({
137
- type: MEMORY_SECURITY_EVENTS.MEMORY_ADDED,
138
- severity: 'LOW',
139
- source: 'Memory.addEntry',
140
- details: `Added memory entry ${entry.id} with ${sanitizedTags.length} tags`
141
- });
142
- return entry;
143
- }
144
- /**
145
- * Search memory entries
146
- * SECURITY: Respects privacy levels and sanitizes search queries
147
- */
148
- async search(options = {}) {
149
- // SECURITY FIX: Sanitize search query (use regular sanitizeInput for queries)
150
- const sanitizedQuery = options.query ?
151
- sanitizeInput(UnicodeValidator.normalize(options.query).normalizedContent, 200) :
152
- undefined;
153
- // PERFORMANCE OPTIMIZATION: Single-pass filtering to reduce allocations
154
- let results = [];
155
- const queryLower = sanitizedQuery?.toLowerCase();
156
- const searchTags = options.tags && options.tags.length > 0 ? this.sanitizeTags(options.tags) : null;
157
- // Single iteration through entries with all filters applied
158
- for (const entry of this.entries.values()) {
159
- // Privacy level check
160
- if (options.privacyLevel &&
161
- !this.canAccessPrivacyLevel(entry.privacyLevel || MEMORY_CONSTANTS.DEFAULT_PRIVACY_LEVEL, options.privacyLevel)) {
162
- continue;
163
- }
164
- // Query text check
165
- if (queryLower) {
166
- const contentMatch = entry.content.toLowerCase().includes(queryLower);
167
- const tagMatch = entry.tags?.some(tag => tag.toLowerCase().includes(queryLower));
168
- if (!contentMatch && !tagMatch) {
169
- continue;
170
- }
171
- }
172
- // Tag filter check
173
- if (searchTags && !searchTags.some(searchTag => entry.tags?.includes(searchTag))) {
174
- continue;
175
- }
176
- // Date range checks
177
- if (options.startDate && entry.timestamp < options.startDate) {
178
- continue;
179
- }
180
- if (options.endDate && entry.timestamp > options.endDate) {
181
- continue;
182
- }
183
- // Entry passes all filters
184
- results.push(entry);
185
- }
186
- // Sort by timestamp (newest first) - using string comparison for IDs as secondary sort
187
- results.sort((a, b) => {
188
- const timeDiff = b.timestamp.getTime() - a.timestamp.getTime();
189
- if (timeDiff !== 0)
190
- return timeDiff;
191
- // If timestamps are exactly the same, sort by ID (which contains timestamp)
192
- return b.id.localeCompare(a.id);
193
- });
194
- // Apply limit
195
- if (options.limit && options.limit > 0) {
196
- results = results.slice(0, options.limit);
197
- }
198
- // Log search operation
199
- SecurityMonitor.logSecurityEvent({
200
- type: MEMORY_SECURITY_EVENTS.MEMORY_SEARCHED,
201
- severity: 'LOW',
202
- source: 'Memory.search',
203
- details: `Searched memories with query: ${sanitizedQuery || 'none'}, found ${results.length} results`
204
- });
205
- return results;
206
- }
207
- /**
208
- * Get a specific memory entry by ID
209
- */
210
- async getEntry(id) {
211
- return this.entries.get(id);
212
- }
213
- /**
214
- * Delete a memory entry
215
- * SECURITY: Validates permissions and logs deletion
216
- */
217
- async deleteEntry(id) {
218
- const entry = this.entries.get(id);
219
- if (!entry) {
220
- return false;
221
- }
222
- // SECURITY: Check if sensitive memories can be deleted
223
- if (entry.privacyLevel === 'sensitive') {
224
- SecurityMonitor.logSecurityEvent({
225
- type: MEMORY_SECURITY_EVENTS.SENSITIVE_MEMORY_DELETED,
226
- severity: 'MEDIUM',
227
- source: 'Memory.deleteEntry',
228
- details: `Sensitive memory ${id} deleted`
229
- });
230
- }
231
- this.entries.delete(id);
232
- this._isDirty = true;
233
- return true;
234
- }
235
- /**
236
- * Enforce retention policy by removing expired entries
237
- * SECURITY: Ensures memory doesn't grow unbounded
238
- */
239
- async enforceRetentionPolicy() {
240
- const now = new Date();
241
- let deletedCount = 0;
242
- // Remove expired entries
243
- for (const [id, entry] of this.entries) {
244
- if (entry.expiresAt && entry.expiresAt < now) {
245
- this.entries.delete(id);
246
- deletedCount++;
247
- }
248
- }
249
- // If still at or over capacity, remove oldest entries to make room for one more
250
- if (this.entries.size >= this.maxEntries) {
251
- const sortedEntries = Array.from(this.entries.entries())
252
- .sort((a, b) => a[1].timestamp.getTime() - b[1].timestamp.getTime());
253
- // Remove one extra to make room for new entry
254
- const toDelete = Math.max(1, this.entries.size - this.maxEntries + 1);
255
- for (let i = 0; i < toDelete && i < sortedEntries.length; i++) {
256
- this.entries.delete(sortedEntries[i][0]);
257
- deletedCount++;
258
- }
259
- }
260
- if (deletedCount > 0) {
261
- this._isDirty = true;
262
- SecurityMonitor.logSecurityEvent({
263
- type: MEMORY_SECURITY_EVENTS.RETENTION_POLICY_ENFORCED,
264
- severity: 'LOW',
265
- source: 'Memory.enforceRetentionPolicy',
266
- details: `Removed ${deletedCount} expired memories`
267
- });
268
- }
269
- return deletedCount;
270
- }
271
- /**
272
- * Clear all memory entries
273
- * SECURITY: Requires confirmation and logs the action
274
- */
275
- async clearAll(confirm = false) {
276
- if (!confirm) {
277
- throw new Error('Memory clear requires confirmation');
278
- }
279
- const count = this.entries.size;
280
- this.entries.clear();
281
- this._isDirty = true;
282
- SecurityMonitor.logSecurityEvent({
283
- type: MEMORY_SECURITY_EVENTS.MEMORY_CLEARED,
284
- severity: 'HIGH',
285
- source: 'Memory.clearAll',
286
- details: `Cleared all ${count} memory entries`
287
- });
288
- }
289
- /**
290
- * Get memory statistics
291
- */
292
- getStats() {
293
- let totalSize = 0;
294
- let oldestEntry;
295
- let newestEntry;
296
- const tagFrequency = new Map();
297
- for (const entry of this.entries.values()) {
298
- totalSize += entry.content.length;
299
- if (!oldestEntry || entry.timestamp < oldestEntry) {
300
- oldestEntry = entry.timestamp;
301
- }
302
- if (!newestEntry || entry.timestamp > newestEntry) {
303
- newestEntry = entry.timestamp;
304
- }
305
- entry.tags?.forEach(tag => {
306
- tagFrequency.set(tag, (tagFrequency.get(tag) || 0) + 1);
307
- });
308
- }
309
- return {
310
- totalEntries: this.entries.size,
311
- totalSize,
312
- oldestEntry,
313
- newestEntry,
314
- tagFrequency
315
- };
316
- }
317
- /**
318
- * Validate the memory element
319
- */
320
- validate() {
321
- const result = super.validate();
322
- // Initialize errors array if not present
323
- if (!result.errors) {
324
- result.errors = [];
325
- }
326
- // Additional memory-specific validation
327
- if (this.retentionDays < MEMORY_CONSTANTS.MIN_RETENTION_DAYS || this.retentionDays > MEMORY_CONSTANTS.MAX_RETENTION_DAYS) {
328
- result.errors.push({
329
- field: 'retentionDays',
330
- message: `Retention days must be between ${MEMORY_CONSTANTS.MIN_RETENTION_DAYS} and ${MEMORY_CONSTANTS.MAX_RETENTION_DAYS}`,
331
- severity: 'error'
332
- });
333
- }
334
- if (this.maxEntries < 1 || this.maxEntries > MEMORY_CONSTANTS.MAX_ENTRIES_DEFAULT) {
335
- result.errors.push({
336
- field: 'maxEntries',
337
- message: `Max entries must be between 1 and ${MEMORY_CONSTANTS.MAX_ENTRIES_DEFAULT}`,
338
- severity: 'error'
339
- });
340
- }
341
- // Check memory size
342
- const stats = this.getStats();
343
- if (stats.totalSize > MEMORY_CONSTANTS.MAX_MEMORY_SIZE) {
344
- result.errors.push({
345
- field: 'memory',
346
- message: `Total memory size (${stats.totalSize}) exceeds limit (${MEMORY_CONSTANTS.MAX_MEMORY_SIZE})`,
347
- severity: 'error'
348
- });
349
- }
350
- // Update validity based on our checks
351
- return {
352
- ...result,
353
- valid: result.errors.length === 0
354
- };
355
- }
356
- /**
357
- * Serialize memory to string
358
- */
359
- serialize() {
360
- const data = {
361
- id: this.id,
362
- type: this.type,
363
- version: this.version,
364
- metadata: this.metadata,
365
- extensions: this.extensions,
366
- entries: Array.from(this.entries.values())
367
- };
368
- return JSON.stringify(data, null, 2);
369
- }
370
- /**
371
- * Deserialize memory from string
372
- * SECURITY: Validates all loaded data
373
- */
374
- deserialize(data) {
375
- try {
376
- const parsed = JSON.parse(data);
377
- // Validate basic structure
378
- if (!parsed.id || !parsed.type || parsed.type !== ElementType.MEMORY) {
379
- throw new Error('Invalid memory data format');
380
- }
381
- // Update properties
382
- this.id = parsed.id;
383
- this.version = parsed.version || '1.0.0';
384
- this.metadata = parsed.metadata || {};
385
- this.extensions = parsed.extensions || {};
386
- // Clear and reload entries
387
- this.entries.clear();
388
- if (Array.isArray(parsed.entries)) {
389
- for (const entry of parsed.entries) {
390
- if (this.isValidEntry(entry)) {
391
- // Re-sanitize on load
392
- entry.content = sanitizeMemoryContent(entry.content, MEMORY_CONSTANTS.MAX_ENTRY_SIZE);
393
- entry.tags = this.sanitizeTags(entry.tags || []);
394
- entry.timestamp = new Date(entry.timestamp);
395
- if (entry.expiresAt) {
396
- entry.expiresAt = new Date(entry.expiresAt);
397
- }
398
- this.entries.set(entry.id, entry);
399
- }
400
- }
401
- }
402
- // Enforce retention policy after loading
403
- this.enforceRetentionPolicy();
404
- }
405
- catch (error) {
406
- SecurityMonitor.logSecurityEvent({
407
- type: MEMORY_SECURITY_EVENTS.MEMORY_DESERIALIZE_FAILED,
408
- severity: 'HIGH',
409
- source: 'Memory.deserialize',
410
- details: `Failed to deserialize memory: ${error}`
411
- });
412
- throw new Error(`Failed to deserialize memory: ${error}`);
413
- }
414
- }
415
- // Private helper methods
416
- calculateExpiryDate() {
417
- const expiry = new Date();
418
- expiry.setDate(expiry.getDate() + this.retentionDays);
419
- return expiry;
420
- }
421
- sanitizeTags(tags) {
422
- // SECURITY FIX: Limit number of tags and sanitize each
423
- const limitedTags = tags.slice(0, MEMORY_CONSTANTS.MAX_TAGS_PER_ENTRY);
424
- return limitedTags
425
- .map(tag => {
426
- const normalized = UnicodeValidator.normalize(tag).normalizedContent;
427
- return sanitizeInput(normalized, MEMORY_CONSTANTS.MAX_TAG_LENGTH);
428
- })
429
- .filter(tag => tag && tag.length > 0);
430
- }
431
- sanitizeMetadata(metadata) {
432
- if (!metadata)
433
- return undefined;
434
- // SECURITY FIX: Sanitize metadata values
435
- const sanitized = {};
436
- const maxKeys = MEMORY_CONSTANTS.MAX_METADATA_KEYS;
437
- let keyCount = 0;
438
- for (const [key, value] of Object.entries(metadata)) {
439
- if (keyCount >= maxKeys)
440
- break;
441
- const sanitizedKey = sanitizeInput(key, MEMORY_CONSTANTS.MAX_METADATA_KEY_LENGTH);
442
- if (sanitizedKey && typeof value === 'string') {
443
- sanitized[sanitizedKey] = sanitizeInput(value, MEMORY_CONSTANTS.MAX_METADATA_VALUE_LENGTH);
444
- keyCount++;
445
- }
446
- else if (sanitizedKey && typeof value === 'number') {
447
- sanitized[sanitizedKey] = value;
448
- keyCount++;
449
- }
450
- // Skip other types for security
451
- }
452
- return sanitized;
453
- }
454
- canAccessPrivacyLevel(entryLevel, requestedLevel) {
455
- const levels = MEMORY_CONSTANTS.PRIVACY_LEVELS;
456
- const entryIndex = levels.indexOf(entryLevel);
457
- const requestedIndex = levels.indexOf(requestedLevel);
458
- // Can only access entries at or below the requested privacy level
459
- // e.g., if requesting 'private', can see 'public' and 'private' but not 'sensitive'
460
- return entryIndex <= requestedIndex;
461
- }
462
- isValidEntry(entry) {
463
- return entry &&
464
- typeof entry.id === 'string' &&
465
- typeof entry.content === 'string' &&
466
- entry.timestamp &&
467
- (!entry.tags || Array.isArray(entry.tags));
468
- }
469
- }
470
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWVtb3J5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2VsZW1lbnRzL21lbW9yaWVzL01lbW9yeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7OztHQWFHO0FBRUgsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRWhELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUV2RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQztBQUNqRixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDcEUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxzQkFBc0IsRUFBZ0MsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4RyxPQUFPLFNBQVMsTUFBTSxXQUFXLENBQUM7QUFDbEMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLE9BQU8sQ0FBQztBQUc5QixrQ0FBa0M7QUFDbEMsTUFBTSxNQUFNLEdBQUcsSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDO0FBQ3BDLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxNQUFhLENBQUMsQ0FBQztBQUV4Qyx3RUFBd0U7QUFDeEUsTUFBTSxDQUFDLFNBQVMsQ0FBQztJQUNmLFlBQVksRUFBRSxFQUFFLEVBQUcsdUJBQXVCO0lBQzFDLFlBQVksRUFBRSxFQUFFLEVBQUcsd0JBQXdCO0lBQzNDLFlBQVksRUFBRSxJQUFJLENBQUMsb0JBQW9CO0NBQ3hDLENBQUMsQ0FBQztBQUVIOzs7O0dBSUc7QUFDSCxTQUFTLHFCQUFxQixDQUFDLE9BQWUsRUFBRSxTQUFpQjtJQUMvRCxJQUFJLENBQUMsT0FBTyxJQUFJLE9BQU8sT0FBTyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzVDLE9BQU8sRUFBRSxDQUFDO0lBQ1os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QyxDQUFDO0lBQy9DLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTWVtb3J5IEVsZW1lbnQgLSBQZXJzaXN0ZW50IGNvbnRleHQgc3RvcmFnZSBmb3IgY29udGludWl0eSBhbmQgbGVhcm5pbmdcbiAqIFxuICogUHJvdmlkZXMgbXVsdGlwbGUgc3RvcmFnZSBiYWNrZW5kcywgcmV0ZW50aW9uIHBvbGljaWVzLCBhbmQgc2VhcmNoIGNhcGFiaWxpdGllc1xuICogZm9yIG1haW50YWluaW5nIGNvbnRleHQgYWNyb3NzIHNlc3Npb25zIGFuZCBpbnRlcmFjdGlvbnMuXG4gKiBcbiAqIFNFQ1VSSVRZIE1FQVNVUkVTIElNUExFTUVOVEVEOlxuICogMS4gSW5wdXQgc2FuaXRpemF0aW9uIGZvciBhbGwgbWVtb3J5IGNvbnRlbnRcbiAqIDIuIE1lbW9yeSBzaXplIGxpbWl0cyB0byBwcmV2ZW50IHVuYm91bmRlZCBncm93dGhcbiAqIDMuIFBhdGggdmFsaWRhdGlvbiBmb3IgZmlsZS1iYXNlZCBzdG9yYWdlXG4gKiA0LiBSZXRlbnRpb24gcG9saWN5IGVuZm9yY2VtZW50XG4gKiA1LiBQcml2YWN5IGxldmVsIGFjY2VzcyBjb250cm9sXG4gKiA2LiBBdWRpdCBsb2dnaW5nIGZvciBhbGwgb3BlcmF0aW9uc1xuICovXG5cbmltcG9ydCB7IEJhc2VFbGVtZW50IH0gZnJvbSAnLi4vQmFzZUVsZW1lbnQuanMnO1xuaW1wb3J0IHsgSUVsZW1lbnQsIEVsZW1lbnRWYWxpZGF0aW9uUmVzdWx0LCBWYWxpZGF0aW9uRXJyb3IgfSBmcm9tICcuLi8uLi90eXBlcy9lbGVtZW50cy9pbmRleC5qcyc7XG5pbXBvcnQgeyBFbGVtZW50VHlwZSB9IGZyb20gJy4uLy4uL3BvcnRmb2xpby90eXBlcy5qcyc7XG5pbXBvcnQgeyBJRWxlbWVudE1ldGFkYXRhIH0gZnJvbSAnLi4vLi4vdHlwZXMvZWxlbWVudHMvSUVsZW1lbnQuanMnO1xuaW1wb3J0IHsgVW5pY29kZVZhbGlkYXRvciB9IGZyb20gJy4uLy4uL3NlY3VyaXR5L3ZhbGlkYXRvcnMvdW5pY29kZVZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi8uLi9zZWN1cml0eS9zZWN1cml0eU1vbml0b3IuanMnO1xuaW1wb3J0IHsgc2FuaXRpemVJbnB1dCB9IGZyb20gJy4uLy4uL3NlY3VyaXR5L0lucHV0VmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IE1FTU9SWV9DT05TVEFOVFMsIE1FTU9SWV9TRUNVUklUWV9FVkVOVFMsIFByaXZhY3lMZXZlbCwgU3RvcmFnZUJhY2tlbmQgfSBmcm9tICcuL2NvbnN0YW50cy5qcyc7XG5pbXBvcnQgRE9NUHVyaWZ5IGZyb20gJ2RvbXB1cmlmeSc7XG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5cbi8vIEluaXRpYWxpemUgRE9NUHVyaWZ5IHdpdGggSlNET01cbmNvbnN0IHdpbmRvdyA9IG5ldyBKU0RPTSgnJykud2luZG93O1xuY29uc3QgcHVyaWZ5ID0gRE9NUHVyaWZ5KHdpbmRvdyBhcyBhbnkpO1xuXG4vLyBDb25maWd1cmUgRE9NUHVyaWZ5IGZvciBtZW1vcnkgY29udGVudCAtIHN0cmlwIGFsbCBIVE1MIGJ1dCBrZWVwIHRleHRcbnB1cmlmeS5zZXRDb25maWcoe1xuICBBTExPV0VEX1RBR1M6IFtdLCAgLy8gTm8gSFRNTCB0YWdzIGFsbG93ZWRcbiAgQUxMT1dFRF9BVFRSOiBbXSwgIC8vIE5vIGF0dHJpYnV0ZXMgYWxsb3dlZFxuICBLRUVQX0NPTlRFTlQ6IHRydWUgLy8gS2VlcCB0ZXh0IGNvbnRlbnRcbn0pO1xuXG4vKipcbiAqIFNhbml0aXplIGNvbnRlbnQgZm9yIG1lbW9yeSBzdG9yYWdlXG4gKiBNb3JlIHBlcm1pc3NpdmUgdGhhbiBzYW5pdGl6ZUlucHV0IC0gYWxsb3dzIHB1bmN0dWF0aW9uLCBxdW90ZXMsIGV0Yy5cbiAqIGJ1dCBzdGlsbCBwcmV2ZW50cyBYU1MgYW5kIGNvbnRyb2wgY2hhcmFjdGVyc1xuICovXG5mdW5jdGlvbiBzYW5pdGl6ZU1lbW9yeUNvbnRlbnQoY29udGVudDogc3RyaW5nLCBtYXhMZW5ndGg6IG51bWJlcik6IHN0cmluZyB7XG4gIGlmICghY29udGVudCB8fCB0eXBlb2YgY29udGVudCAhPT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gJyc7XG4gIH1cbiAgXG4gIC8vIEZpcnN0IG5vcm1hbGl6ZSBVbmljb2RlXG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShjb250ZW50KS5ub3JtYWxpemVkQ29udGVudDtcbiAgXG4gIC8vIFVzZSBET01QdXJpZnkgdG8gc3RyaXAgYW55IEhUTUwvWFNTIGF0dGVtcHRzIGJ1dCBrZWVwIHRleHRcbiAgY29uc3QgY2xlYW5lZCA9IHB1cmlmeS5zYW5pdGl6ZShub3JtYWxpemVkKTtcbiAgXG4gIC8vIFJlbW92ZSBvbmx5IGNvbnRyb2wgY2hhcmFjdGVycyBhbmQgbnVsbCBieXRlc1xuICByZXR1cm4gY2xlYW5lZFxuICAgIC5yZXBsYWNlKC9bXFx4MDAtXFx4MDhcXHgwQlxceDBDXFx4MEUtXFx4MUZcXHg3Rl0vZywgJycpIC8vIFJlbW92ZSBjb250cm9sIGNoYXJzIGV4Y2VwdCBcXHQgXFxuIFxcclxuICAgIC5zdWJzdHJpbmcoMCwgbWF4TGVuZ3RoKVxuICAgIC50cmltKCk7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWVtb3J5TWV0YWRhdGEgZXh0ZW5kcyBJRWxlbWVudE1ldGFkYXRhIHtcbiAgc3RvcmFnZUJhY2tlbmQ/OiBTdG9yYWdlQmFja2VuZDtcbiAgcmV0ZW50aW9uRGF5cz86IG51bWJlcjtcbiAgcHJpdmFjeUxldmVsPzogUHJpdmFjeUxldmVsO1xuICBzZWFyY2hhYmxlPzogYm9vbGVhbjtcbiAgbWF4RW50cmllcz86IG51bWJlcjtcbiAgZW5jcnlwdGlvbkVuYWJsZWQ/OiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE1lbW9yeUVudHJ5IHtcbiAgaWQ6IHN0cmluZztcbiAgdGltZXN0YW1wOiBEYXRlO1xuICBjb250ZW50OiBzdHJpbmc7XG4gIHRhZ3M/OiBzdHJpbmdbXTtcbiAgbWV0YWRhdGE/OiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICBleHBpcmVzQXQ/OiBEYXRlO1xuICBwcml2YWN5TGV2ZWw/OiBQcml2YWN5TGV2ZWw7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWVtb3J5U2VhcmNoT3B0aW9ucyB7XG4gIHF1ZXJ5Pzogc3RyaW5nO1xuICB0YWdzPzogc3RyaW5nW107XG4gIHN0YXJ0RGF0ZT86IERhdGU7XG4gIGVuZERhdGU/OiBEYXRlO1xuICBsaW1pdD86IG51bWJlcjtcbiAgcHJpdmFjeUxldmVsPzogUHJpdmFjeUxldmVsO1xufVxuXG5leHBvcnQgY2xhc3MgTWVtb3J5IGV4dGVuZHMgQmFzZUVsZW1lbnQgaW1wbGVtZW50cyBJRWxlbWVudCB7XG4gIC8vIE1lbW9yeS1zcGVjaWZpYyBwcm9wZXJ0aWVzXG4gIHByaXZhdGUgZW50cmllczogTWFwPHN0cmluZywgTWVtb3J5RW50cnk+ID0gbmV3IE1hcCgpO1xuICBwcml2YXRlIHN0b3JhZ2VCYWNrZW5kOiBTdG9yYWdlQmFja2VuZDtcbiAgcHJpdmF0ZSByZXRlbnRpb25EYXlzOiBudW1iZXI7XG4gIHByaXZhdGUgcHJpdmFjeUxldmVsOiBQcml2YWN5TGV2ZWw7XG4gIHByaXZhdGUgc2VhcmNoYWJsZTogYm9vbGVhbjtcbiAgcHJpdmF0ZSBtYXhFbnRyaWVzOiBudW1iZXI7XG4gIFxuICBjb25zdHJ1Y3RvcihtZXRhZGF0YTogUGFydGlhbDxNZW1vcnlNZXRhZGF0YT4gPSB7fSkge1xuICAgIC8vIFNFQ1VSSVRZIEZJWDogU2FuaXRpemUgYWxsIGlucHV0cyBkdXJpbmcgY29uc3RydWN0aW9uXG4gICAgY29uc3Qgc2FuaXRpemVkTWV0YWRhdGEgPSB7XG4gICAgICAuLi5tZXRhZGF0YSxcbiAgICAgIG5hbWU6IG1ldGFkYXRhLm5hbWUgPyBcbiAgICAgICAgc2FuaXRpemVJbnB1dChVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShtZXRhZGF0YS5uYW1lKS5ub3JtYWxpemVkQ29udGVudCwgMTAwKSA6IFxuICAgICAgICAnVW5uYW1lZCBNZW1vcnknLFxuICAgICAgZGVzY3JpcHRpb246IG1ldGFkYXRhLmRlc2NyaXB0aW9uID8gXG4gICAgICAgIHNhbml0aXplSW5wdXQoVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUobWV0YWRhdGEuZGVzY3JpcHRpb24pLm5vcm1hbGl6ZWRDb250ZW50LCA1MDApIDogXG4gICAgICAgIHVuZGVmaW5lZFxuICAgIH07XG4gICAgXG4gICAgc3VwZXIoRWxlbWVudFR5cGUuTUVNT1JZLCBzYW5pdGl6ZWRNZXRhZGF0YSk7XG4gICAgXG4gICAgLy8gSW5pdGlhbGl6ZSBtZW1vcnktc3BlY2lmaWMgcHJvcGVydGllcyB3aXRoIGRlZmF1bHRzXG4gICAgdGhpcy5zdG9yYWdlQmFja2VuZCA9IG1ldGFkYXRhLnN0b3JhZ2VCYWNrZW5kIHx8IE1FTU9SWV9DT05TVEFOVFMuREVGQVVMVF9TVE9SQUdFX0JBQ0tFTkQ7XG4gICAgdGhpcy5yZXRlbnRpb25EYXlzID0gbWV0YWRhdGEucmV0ZW50aW9uRGF5cyB8fCBNRU1PUllfQ09OU1RBTlRTLkRFRkFVTFRfUkVURU5USU9OX0RBWVM7XG4gICAgLy8gVmFsaWRhdGUgcHJpdmFjeSBsZXZlbCAtIGRlZmF1bHQgdG8gcHJpdmF0ZSBpZiBpbnZhbGlkXG4gICAgdGhpcy5wcml2YWN5TGV2ZWwgPSAobWV0YWRhdGEucHJpdmFjeUxldmVsICYmIE1FTU9SWV9DT05TVEFOVFMuUFJJVkFDWV9MRVZFTFMuaW5jbHVkZXMobWV0YWRhdGEucHJpdmFjeUxldmVsKSkgXG4gICAgICA/IG1ldGFkYXRhLnByaXZhY3lMZXZlbCBcbiAgICAgIDogTUVNT1JZX0NPTlNUQU5UUy5ERUZBVUxUX1BSSVZBQ1lfTEVWRUw7XG4gICAgdGhpcy5zZWFyY2hhYmxlID0gbWV0YWRhdGEuc2VhcmNoYWJsZSAhPT0gZmFsc2U7XG4gICAgdGhpcy5tYXhFbnRyaWVzID0gTWF0aC5taW4oXG4gICAgICBtZXRhZGF0YS5tYXhFbnRyaWVzIHx8IE1FTU9SWV9DT05TVEFOVFMuTUFYX0VOVFJJRVNfREVGQVVMVCxcbiAgICAgIE1FTU9SWV9DT05TVEFOVFMuTUFYX0VOVFJJRVNfREVGQVVMVFxuICAgICk7XG4gICAgXG4gICAgLy8gU2V0IHVwIGV4dGVuc2lvbnNcbiAgICB0aGlzLmV4dGVuc2lvbnMgPSB7XG4gICAgICBzdG9yYWdlQmFja2VuZDogdGhpcy5zdG9yYWdlQmFja2VuZCxcbiAgICAgIHJldGVudGlvbkRheXM6IHRoaXMucmV0ZW50aW9uRGF5cyxcbiAgICAgIHByaXZhY3lMZXZlbDogdGhpcy5wcml2YWN5TGV2ZWwsXG4gICAgICBzZWFyY2hhYmxlOiB0aGlzLnNlYXJjaGFibGUsXG4gICAgICBtYXhFbnRyaWVzOiB0aGlzLm1heEVudHJpZXMsXG4gICAgICBlbmNyeXB0aW9uRW5hYmxlZDogbWV0YWRhdGEuZW5jcnlwdGlvbkVuYWJsZWQgfHwgZmFsc2VcbiAgICB9O1xuICAgIFxuICAgIC8vIExvZyBtZW1vcnkgY3JlYXRpb25cbiAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICB0eXBlOiBNRU1PUllfU0VDVVJJVFlfRVZFTlRTLk1FTU9SWV9DUkVBVEVELFxuICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgc291cmNlOiAnTWVtb3J5LmNvbnN0cnVjdG9yJyxcbiAgICAgIGRldGFpbHM6IGBNZW1vcnkgY3JlYXRlZDogJHt0aGlzLm1ldGFkYXRhLm5hbWV9IHdpdGggJHt0aGlzLnN0b3JhZ2VCYWNrZW5kfSBiYWNrZW5kYFxuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogQWRkIGEgbmV3IG1lbW9yeSBlbnRyeVxuICAgKiBTRUNVUklUWTogVmFsaWRhdGVzIGFuZCBzYW5pdGl6ZXMgYWxsIGlucHV0LCBlbmZvcmNlcyBzaXplIGxpbWl0c1xuICAgKi9cbiAgcHVibGljIGFzeW5jIGFkZEVudHJ5KGNvbnRlbnQ6IHN0cmluZywgdGFncz86IHN0cmluZ1tdLCBtZXRhZGF0YT86IFJlY29yZDxzdHJpbmcsIGFueT4pOiBQcm9taXNlPE1lbW9yeUVudHJ5PiB7XG4gICAgLy8gVmFsaWRhdGUgbWVtb3J5IHNpemUgbGltaXRzXG4gICAgaWYgKHRoaXMuZW50cmllcy5zaXplID49IHRoaXMubWF4RW50cmllcykge1xuICAgICAgLy8gU0VDVVJJVFkgRklYOiBFbmZvcmNlIHJldGVudGlvbiBwb2xpY3kgd2hlbiBhdCBjYXBhY2l0eVxuICAgICAgYXdhaXQgdGhpcy5lbmZvcmNlUmV0ZW50aW9uUG9saWN5KCk7XG4gICAgICBcbiAgICAgIC8vIElmIHN0aWxsIGF0IGNhcGFjaXR5IGFmdGVyIHJldGVudGlvbiwgcmVtb3ZlIG9sZGVzdCB0byBtYWtlIHJvb21cbiAgICAgIGlmICh0aGlzLmVudHJpZXMuc2l6ZSA+PSB0aGlzLm1heEVudHJpZXMpIHtcbiAgICAgICAgY29uc3Qgb2xkZXN0RW50cnkgPSBBcnJheS5mcm9tKHRoaXMuZW50cmllcy52YWx1ZXMoKSlcbiAgICAgICAgICAuc29ydCgoYSwgYikgPT4gYS50aW1lc3RhbXAuZ2V0VGltZSgpIC0gYi50aW1lc3RhbXAuZ2V0VGltZSgpKVswXTtcbiAgICAgICAgaWYgKG9sZGVzdEVudHJ5KSB7XG4gICAgICAgICAgdGhpcy5lbnRyaWVzLmRlbGV0ZShvbGRlc3RFbnRyeS5pZCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gU0VDVVJJVFkgRklYOiBWYWxpZGF0ZSBhbmQgc2FuaXRpemUgY29udGVudFxuICAgIGNvbnN0IHNhbml0aXplZENvbnRlbnQgPSBzYW5pdGl6ZU1lbW9yeUNvbnRlbnQoY29udGVudCwgTUVNT1JZX0NPTlNUQU5UUy5NQVhfRU5UUllfU0laRSk7XG4gICAgXG4gICAgaWYgKCFzYW5pdGl6ZWRDb250ZW50IHx8IHNhbml0aXplZENvbnRlbnQudHJpbSgpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdNZW1vcnkgY29udGVudCBjYW5ub3QgYmUgZW1wdHknKTtcbiAgICB9XG4gICAgXG4gICAgLy8gU0VDVVJJVFkgRklYOiBWYWxpZGF0ZSBhbmQgc2FuaXRpemUgdGFnc1xuICAgIGNvbnN0IHNhbml0aXplZFRhZ3MgPSB0YWdzID8gdGhpcy5zYW5pdGl6ZVRhZ3ModGFncykgOiBbXTtcbiAgICBcbiAgICAvLyBDcmVhdGUgbWVtb3J5IGVudHJ5XG4gICAgY29uc3QgZW50cnk6IE1lbW9yeUVudHJ5ID0ge1xuICAgICAgaWQ6IGBtZW1fJHtEYXRlLm5vdygpfV8ke01hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnN1YnN0cigyLCA5KX1gLFxuICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLFxuICAgICAgY29udGVudDogc2FuaXRpemVkQ29udGVudCxcbiAgICAgIHRhZ3M6IHNhbml0aXplZFRhZ3MsXG4gICAgICBtZXRhZGF0YTogdGhpcy5zYW5pdGl6ZU1ldGFkYXRhKG1ldGFkYXRhKSxcbiAgICAgIHByaXZhY3lMZXZlbDogdGhpcy5wcml2YWN5TGV2ZWwsXG4gICAgICBleHBpcmVzQXQ6IHRoaXMuY2FsY3VsYXRlRXhwaXJ5RGF0ZSgpXG4gICAgfTtcbiAgICBcbiAgICAvLyBTdG9yZSBlbnRyeVxuICAgIHRoaXMuZW50cmllcy5zZXQoZW50cnkuaWQsIGVudHJ5KTtcbiAgICB0aGlzLl9pc0RpcnR5ID0gdHJ1ZTtcbiAgICBcbiAgICAvLyBMb2cgbWVtb3J5IGFkZGl0aW9uXG4gICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgdHlwZTogTUVNT1JZX1NFQ1VSSVRZX0VWRU5UUy5NRU1PUllfQURERUQsXG4gICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICBzb3VyY2U6ICdNZW1vcnkuYWRkRW50cnknLFxuICAgICAgZGV0YWlsczogYEFkZGVkIG1lbW9yeSBlbnRyeSAke2VudHJ5LmlkfSB3aXRoICR7c2FuaXRpemVkVGFncy5sZW5ndGh9IHRhZ3NgXG4gICAgfSk7XG4gICAgXG4gICAgcmV0dXJuIGVudHJ5O1xuICB9XG4gIFxuICAvKipcbiAgICogU2VhcmNoIG1lbW9yeSBlbnRyaWVzXG4gICAqIFNFQ1VSSVRZOiBSZXNwZWN0cyBwcml2YWN5IGxldmVscyBhbmQgc2FuaXRpemVzIHNlYXJjaCBxdWVyaWVzXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgc2VhcmNoKG9wdGlvbnM6IE1lbW9yeVNlYXJjaE9wdGlvbnMgPSB7fSk6IFByb21pc2U8TWVtb3J5RW50cnlbXT4ge1xuICAgIC8vIFNFQ1VSSVRZIEZJWDogU2FuaXRpemUgc2VhcmNoIHF1ZXJ5ICh1c2UgcmVndWxhciBzYW5pdGl6ZUlucHV0IGZvciBxdWVyaWVzKVxuICAgIGNvbnN0IHNhbml0aXplZFF1ZXJ5ID0gb3B0aW9ucy5xdWVyeSA/IFxuICAgICAgc2FuaXRpemVJbnB1dChVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShvcHRpb25zLnF1ZXJ5KS5ub3JtYWxpemVkQ29udGVudCwgMjAwKSA6IFxuICAgICAgdW5kZWZpbmVkO1xuICAgIFxuICAgIC8vIFBFUkZPUk1BTkNFIE9QVElNSVpBVElPTjogU2luZ2xlLXBhc3MgZmlsdGVyaW5nIHRvIHJlZHVjZSBhbGxvY2F0aW9uc1xuICAgIGxldCByZXN1bHRzOiBNZW1vcnlFbnRyeVtdID0gW107XG4gICAgY29uc3QgcXVlcnlMb3dlciA9IHNhbml0aXplZFF1ZXJ5Py50b0xvd2VyQ2FzZSgpO1xuICAgIGNvbnN0IHNlYXJjaFRhZ3MgPSBvcHRpb25zLnRhZ3MgJiYgb3B0aW9ucy50YWdzLmxlbmd0aCA+IDAgPyB0aGlzLnNhbml0aXplVGFncyhvcHRpb25zLnRhZ3MpIDogbnVsbDtcbiAgICBcbiAgICAvLyBTaW5nbGUgaXRlcmF0aW9uIHRocm91Z2ggZW50cmllcyB3aXRoIGFsbCBmaWx0ZXJzIGFwcGxpZWRcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIHRoaXMuZW50cmllcy52YWx1ZXMoKSkge1xuICAgICAgLy8gUHJpdmFjeSBsZXZlbCBjaGVja1xuICAgICAgaWYgKG9wdGlvbnMucHJpdmFjeUxldmVsICYmIFxuICAgICAgICAgICF0aGlzLmNhbkFjY2Vzc1ByaXZhY3lMZXZlbChlbnRyeS5wcml2YWN5TGV2ZWwgfHwgTUVNT1JZX0NPTlNUQU5UUy5ERUZBVUxUX1BSSVZBQ1lfTEVWRUwsIG9wdGlvbnMucHJpdmFjeUxldmVsKSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gUXVlcnkgdGV4dCBjaGVja1xuICAgICAgaWYgKHF1ZXJ5TG93ZXIpIHtcbiAgICAgICAgY29uc3QgY29udGVudE1hdGNoID0gZW50cnkuY29udGVudC50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKHF1ZXJ5TG93ZXIpO1xuICAgICAgICBjb25zdCB0YWdNYXRjaCA9IGVudHJ5LnRhZ3M/LnNvbWUodGFnID0+IHRhZy50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKHF1ZXJ5TG93ZXIpKTtcbiAgICAgICAgaWYgKCFjb250ZW50TWF0Y2ggJiYgIXRhZ01hdGNoKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gVGFnIGZpbHRlciBjaGVja1xuICAgICAgaWYgKHNlYXJjaFRhZ3MgJiYgIXNlYXJjaFRhZ3Muc29tZShzZWFyY2hUYWcgPT4gZW50cnkudGFncz8uaW5jbHVkZXMoc2VhcmNoVGFnKSkpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIERhdGUgcmFuZ2UgY2hlY2tzXG4gICAgICBpZiAob3B0aW9ucy5zdGFydERhdGUgJiYgZW50cnkudGltZXN0YW1wIDwgb3B0aW9ucy5zdGFydERhdGUpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBpZiAob3B0aW9ucy5lbmREYXRlICYmIGVudHJ5LnRpbWVzdGFtcCA+IG9wdGlvbnMuZW5kRGF0ZSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gRW50cnkgcGFzc2VzIGFsbCBmaWx0ZXJzXG4gICAgICByZXN1bHRzLnB1c2goZW50cnkpO1xuICAgIH1cbiAgICBcbiAgICAvLyBTb3J0IGJ5IHRpbWVzdGFtcCAobmV3ZXN0IGZpcnN0KSAtIHVzaW5nIHN0cmluZyBjb21wYXJpc29uIGZvciBJRHMgYXMgc2Vjb25kYXJ5IHNvcnRcbiAgICByZXN1bHRzLnNvcnQoKGEsIGIpID0+IHtcbiAgICAgIGNvbnN0IHRpbWVEaWZmID0gYi50aW1lc3RhbXAuZ2V0VGltZSgpIC0gYS50aW1lc3RhbXAuZ2V0VGltZSgpO1xuICAgICAgaWYgKHRpbWVEaWZmICE9PSAwKSByZXR1cm4gdGltZURpZmY7XG4gICAgICAvLyBJZiB0aW1lc3RhbXBzIGFyZSBleGFjdGx5IHRoZSBzYW1lLCBzb3J0IGJ5IElEICh3aGljaCBjb250YWlucyB0aW1lc3RhbXApXG4gICAgICByZXR1cm4gYi5pZC5sb2NhbGVDb21wYXJlKGEuaWQpO1xuICAgIH0pO1xuICAgIFxuICAgIC8vIEFwcGx5IGxpbWl0XG4gICAgaWYgKG9wdGlvbnMubGltaXQgJiYgb3B0aW9ucy5saW1pdCA+IDApIHtcbiAgICAgIHJlc3VsdHMgPSByZXN1bHRzLnNsaWNlKDAsIG9wdGlvbnMubGltaXQpO1xuICAgIH1cbiAgICBcbiAgICAvLyBMb2cgc2VhcmNoIG9wZXJhdGlvblxuICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgIHR5cGU6IE1FTU9SWV9TRUNVUklUWV9FVkVOVFMuTUVNT1JZX1NFQVJDSEVELFxuICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgc291cmNlOiAnTWVtb3J5LnNlYXJjaCcsXG4gICAgICBkZXRhaWxzOiBgU2VhcmNoZWQgbWVtb3JpZXMgd2l0aCBxdWVyeTogJHtzYW5pdGl6ZWRRdWVyeSB8fCAnbm9uZSd9LCBmb3VuZCAke3Jlc3VsdHMubGVuZ3RofSByZXN1bHRzYFxuICAgIH0pO1xuICAgIFxuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGEgc3BlY2lmaWMgbWVtb3J5IGVudHJ5IGJ5IElEXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgZ2V0RW50cnkoaWQ6IHN0cmluZyk6IFByb21pc2U8TWVtb3J5RW50cnkgfCB1bmRlZmluZWQ+IHtcbiAgICByZXR1cm4gdGhpcy5lbnRyaWVzLmdldChpZCk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBEZWxldGUgYSBtZW1vcnkgZW50cnlcbiAgICogU0VDVVJJVFk6IFZhbGlkYXRlcyBwZXJtaXNzaW9ucyBhbmQgbG9ncyBkZWxldGlvblxuICAgKi9cbiAgcHVibGljIGFzeW5jIGRlbGV0ZUVudHJ5KGlkOiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCBlbnRyeSA9IHRoaXMuZW50cmllcy5nZXQoaWQpO1xuICAgIGlmICghZW50cnkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgXG4gICAgLy8gU0VDVVJJVFk6IENoZWNrIGlmIHNlbnNpdGl2ZSBtZW1vcmllcyBjYW4gYmUgZGVsZXRlZFxuICAgIGlmIChlbnRyeS5wcml2YWN5TGV2ZWwgPT09ICdzZW5zaXRpdmUnKSB7XG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6IE1FTU9SWV9TRUNVUklUWV9FVkVOVFMuU0VOU0lUSVZFX01FTU9SWV9ERUxFVEVELFxuICAgICAgICBzZXZlcml0eTogJ01FRElVTScsXG4gICAgICAgIHNvdXJjZTogJ01lbW9yeS5kZWxldGVFbnRyeScsXG4gICAgICAgIGRldGFpbHM6IGBTZW5zaXRpdmUgbWVtb3J5ICR7aWR9IGRlbGV0ZWRgXG4gICAgICB9KTtcbiAgICB9XG4gICAgXG4gICAgdGhpcy5lbnRyaWVzLmRlbGV0ZShpZCk7XG4gICAgdGhpcy5faXNEaXJ0eSA9IHRydWU7XG4gICAgXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBFbmZvcmNlIHJldGVudGlvbiBwb2xpY3kgYnkgcmVtb3ZpbmcgZXhwaXJlZCBlbnRyaWVzXG4gICAqIFNFQ1VSSVRZOiBFbnN1cmVzIG1lbW9yeSBkb2Vzbid0IGdyb3cgdW5ib3VuZGVkXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgZW5mb3JjZVJldGVudGlvblBvbGljeSgpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XG4gICAgbGV0IGRlbGV0ZWRDb3VudCA9IDA7XG4gICAgXG4gICAgLy8gUmVtb3ZlIGV4cGlyZWQgZW50cmllc1xuICAgIGZvciAoY29uc3QgW2lkLCBlbnRyeV0gb2YgdGhpcy5lbnRyaWVzKSB7XG4gICAgICBpZiAoZW50cnkuZXhwaXJlc0F0ICYmIGVudHJ5LmV4cGlyZXNBdCA8IG5vdykge1xuICAgICAgICB0aGlzLmVudHJpZXMuZGVsZXRlKGlkKTtcbiAgICAgICAgZGVsZXRlZENvdW50Kys7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIElmIHN0aWxsIGF0IG9yIG92ZXIgY2FwYWNpdHksIHJlbW92ZSBvbGRlc3QgZW50cmllcyB0byBtYWtlIHJvb20gZm9yIG9uZSBtb3JlXG4gICAgaWYgKHRoaXMuZW50cmllcy5zaXplID49IHRoaXMubWF4RW50cmllcykge1xuICAgICAgY29uc3Qgc29ydGVkRW50cmllcyA9IEFycmF5LmZyb20odGhpcy5lbnRyaWVzLmVudHJpZXMoKSlcbiAgICAgICAgLnNvcnQoKGEsIGIpID0+IGFbMV0udGltZXN0YW1wLmdldFRpbWUoKSAtIGJbMV0udGltZXN0YW1wLmdldFRpbWUoKSk7XG4gICAgICBcbiAgICAgIC8vIFJlbW92ZSBvbmUgZXh0cmEgdG8gbWFrZSByb29tIGZvciBuZXcgZW50cnlcbiAgICAgIGNvbnN0IHRvRGVsZXRlID0gTWF0aC5tYXgoMSwgdGhpcy5lbnRyaWVzLnNpemUgLSB0aGlzLm1heEVudHJpZXMgKyAxKTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdG9EZWxldGUgJiYgaSA8IHNvcnRlZEVudHJpZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdGhpcy5lbnRyaWVzLmRlbGV0ZShzb3J0ZWRFbnRyaWVzW2ldWzBdKTtcbiAgICAgICAgZGVsZXRlZENvdW50Kys7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIGlmIChkZWxldGVkQ291bnQgPiAwKSB7XG4gICAgICB0aGlzLl9pc0RpcnR5ID0gdHJ1ZTtcbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogTUVNT1JZX1NFQ1VSSVRZX0VWRU5UUy5SRVRFTlRJT05fUE9MSUNZX0VORk9SQ0VELFxuICAgICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICAgIHNvdXJjZTogJ01lbW9yeS5lbmZvcmNlUmV0ZW50aW9uUG9saWN5JyxcbiAgICAgICAgZGV0YWlsczogYFJlbW92ZWQgJHtkZWxldGVkQ291bnR9IGV4cGlyZWQgbWVtb3JpZXNgXG4gICAgICB9KTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGRlbGV0ZWRDb3VudDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIENsZWFyIGFsbCBtZW1vcnkgZW50cmllc1xuICAgKiBTRUNVUklUWTogUmVxdWlyZXMgY29uZmlybWF0aW9uIGFuZCBsb2dzIHRoZSBhY3Rpb25cbiAgICovXG4gIHB1YmxpYyBhc3luYyBjbGVhckFsbChjb25maXJtOiBib29sZWFuID0gZmFsc2UpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIWNvbmZpcm0pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTWVtb3J5IGNsZWFyIHJlcXVpcmVzIGNvbmZpcm1hdGlvbicpO1xuICAgIH1cbiAgICBcbiAgICBjb25zdCBjb3VudCA9IHRoaXMuZW50cmllcy5zaXplO1xuICAgIHRoaXMuZW50cmllcy5jbGVhcigpO1xuICAgIHRoaXMuX2lzRGlydHkgPSB0cnVlO1xuICAgIFxuICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgIHR5cGU6IE1FTU9SWV9TRUNVUklUWV9FVkVOVFMuTUVNT1JZX0NMRUFSRUQsXG4gICAgICBzZXZlcml0eTogJ0hJR0gnLFxuICAgICAgc291cmNlOiAnTWVtb3J5LmNsZWFyQWxsJyxcbiAgICAgIGRldGFpbHM6IGBDbGVhcmVkIGFsbCAke2NvdW50fSBtZW1vcnkgZW50cmllc2BcbiAgICB9KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBtZW1vcnkgc3RhdGlzdGljc1xuICAgKi9cbiAgcHVibGljIGdldFN0YXRzKCk6IHtcbiAgICB0b3RhbEVudHJpZXM6IG51bWJlcjtcbiAgICB0b3RhbFNpemU6IG51bWJlcjtcbiAgICBvbGRlc3RFbnRyeT86IERhdGU7XG4gICAgbmV3ZXN0RW50cnk/OiBEYXRlO1xuICAgIHRhZ0ZyZXF1ZW5jeTogTWFwPHN0cmluZywgbnVtYmVyPjtcbiAgfSB7XG4gICAgbGV0IHRvdGFsU2l6ZSA9IDA7XG4gICAgbGV0IG9sZGVzdEVudHJ5OiBEYXRlIHwgdW5kZWZpbmVkO1xuICAgIGxldCBuZXdlc3RFbnRyeTogRGF0ZSB8IHVuZGVmaW5lZDtcbiAgICBjb25zdCB0YWdGcmVxdWVuY3kgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xuICAgIFxuICAgIGZvciAoY29uc3QgZW50cnkgb2YgdGhpcy5lbnRyaWVzLnZhbHVlcygpKSB7XG4gICAgICB0b3RhbFNpemUgKz0gZW50cnkuY29udGVudC5sZW5ndGg7XG4gICAgICBcbiAgICAgIGlmICghb2xkZXN0RW50cnkgfHwgZW50cnkudGltZXN0YW1wIDwgb2xkZXN0RW50cnkpIHtcbiAgICAgICAgb2xkZXN0RW50cnkgPSBlbnRyeS50aW1lc3RhbXA7XG4gICAgICB9XG4gICAgICBpZiAoIW5ld2VzdEVudHJ5IHx8IGVudHJ5LnRpbWVzdGFtcCA+IG5ld2VzdEVudHJ5KSB7XG4gICAgICAgIG5ld2VzdEVudHJ5ID0gZW50cnkudGltZXN0YW1wO1xuICAgICAgfVxuICAgICAgXG4gICAgICBlbnRyeS50YWdzPy5mb3JFYWNoKHRhZyA9PiB7XG4gICAgICAgIHRhZ0ZyZXF1ZW5jeS5zZXQodGFnLCAodGFnRnJlcXVlbmN5LmdldCh0YWcpIHx8IDApICsgMSk7XG4gICAgICB9KTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHtcbiAgICAgIHRvdGFsRW50cmllczogdGhpcy5lbnRyaWVzLnNpemUsXG4gICAgICB0b3RhbFNpemUsXG4gICAgICBvbGRlc3RFbnRyeSxcbiAgICAgIG5ld2VzdEVudHJ5LFxuICAgICAgdGFnRnJlcXVlbmN5XG4gICAgfTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFZhbGlkYXRlIHRoZSBtZW1vcnkgZWxlbWVudFxuICAgKi9cbiAgcHVibGljIG92ZXJyaWRlIHZhbGlkYXRlKCk6IEVsZW1lbnRWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICBjb25zdCByZXN1bHQgPSBzdXBlci52YWxpZGF0ZSgpO1xuICAgIFxuICAgIC8vIEluaXRpYWxpemUgZXJyb3JzIGFycmF5IGlmIG5vdCBwcmVzZW50XG4gICAgaWYgKCFyZXN1bHQuZXJyb3JzKSB7XG4gICAgICByZXN1bHQuZXJyb3JzID0gW107XG4gICAgfVxuICAgIFxuICAgIC8vIEFkZGl0aW9uYWwgbWVtb3J5LXNwZWNpZmljIHZhbGlkYXRpb25cbiAgICBpZiAodGhpcy5yZXRlbnRpb25EYXlzIDwgTUVNT1JZX0NPTlNUQU5UUy5NSU5fUkVURU5USU9OX0RBWVMgfHwgdGhpcy5yZXRlbnRpb25EYXlzID4gTUVNT1JZX0NPTlNUQU5UUy5NQVhfUkVURU5USU9OX0RBWVMpIHtcbiAgICAgIHJlc3VsdC5lcnJvcnMucHVzaCh7XG4gICAgICAgIGZpZWxkOiAncmV0ZW50aW9uRGF5cycsXG4gICAgICAgIG1lc3NhZ2U6IGBSZXRlbnRpb24gZGF5cyBtdXN0IGJlIGJldHdlZW4gJHtNRU1PUllfQ09OU1RBTlRTLk1JTl9SRVRFTlRJT05fREFZU30gYW5kICR7TUVNT1JZX0NPTlNUQU5UUy5NQVhfUkVURU5USU9OX0RBWVN9YCxcbiAgICAgICAgc2V2ZXJpdHk6ICdlcnJvcidcbiAgICAgIH0gYXMgVmFsaWRhdGlvbkVycm9yKTtcbiAgICB9XG4gICAgXG4gICAgaWYgKHRoaXMubWF4RW50cmllcyA8IDEgfHwgdGhpcy5tYXhFbnRyaWVzID4gTUVNT1JZX0NPTlNUQU5UUy5NQVhfRU5UUklFU19ERUZBVUxUKSB7XG4gICAgICByZXN1bHQuZXJyb3JzLnB1c2goe1xuICAgICAgICBmaWVsZDogJ21heEVudHJpZXMnLFxuICAgICAgICBtZXNzYWdlOiBgTWF4IGVudHJpZXMgbXVzdCBiZSBiZXR3ZWVuIDEgYW5kICR7TUVNT1JZX0NPTlNUQU5UUy5NQVhfRU5UUklFU19ERUZBVUxUfWAsXG4gICAgICAgIHNldmVyaXR5OiAnZXJyb3InXG4gICAgICB9IGFzIFZhbGlkYXRpb25FcnJvcik7XG4gICAgfVxuICAgIFxuICAgIC8vIENoZWNrIG1lbW9yeSBzaXplXG4gICAgY29uc3Qgc3RhdHMgPSB0aGlzLmdldFN0YXRzKCk7XG4gICAgaWYgKHN0YXRzLnRvdGFsU2l6ZSA+IE1FTU9SWV9DT05TVEFOVFMuTUFYX01FTU9SWV9TSVpFKSB7XG4gICAgICByZXN1bHQuZXJyb3JzLnB1c2goe1xuICAgICAgICBmaWVsZDogJ21lbW9yeScsXG4gICAgICAgIG1lc3NhZ2U6IGBUb3RhbCBtZW1vcnkgc2l6ZSAoJHtzdGF0cy50b3RhbFNpemV9KSBleGNlZWRzIGxpbWl0ICgke01FTU9SWV9DT05TVEFOVFMuTUFYX01FTU9SWV9TSVpFfSlgLFxuICAgICAgICBzZXZlcml0eTogJ2Vycm9yJ1xuICAgICAgfSBhcyBWYWxpZGF0aW9uRXJyb3IpO1xuICAgIH1cbiAgICBcbiAgICAvLyBVcGRhdGUgdmFsaWRpdHkgYmFzZWQgb24gb3VyIGNoZWNrc1xuICAgIHJldHVybiB7XG4gICAgICAuLi5yZXN1bHQsXG4gICAgICB2YWxpZDogcmVzdWx0LmVycm9ycy5sZW5ndGggPT09IDBcbiAgICB9O1xuICB9XG4gIFxuICAvKipcbiAgICogU2VyaWFsaXplIG1lbW9yeSB0byBzdHJpbmdcbiAgICovXG4gIHB1YmxpYyBvdmVycmlkZSBzZXJpYWxpemUoKTogc3RyaW5nIHtcbiAgICBjb25zdCBkYXRhID0ge1xuICAgICAgaWQ6IHRoaXMuaWQsXG4gICAgICB0eXBlOiB0aGlzLnR5cGUsXG4gICAgICB2ZXJzaW9uOiB0aGlzLnZlcnNpb24sXG4gICAgICBtZXRhZGF0YTogdGhpcy5tZXRhZGF0YSxcbiAgICAgIGV4dGVuc2lvbnM6IHRoaXMuZXh0ZW5zaW9ucyxcbiAgICAgIGVudHJpZXM6IEFycmF5LmZyb20odGhpcy5lbnRyaWVzLnZhbHVlcygpKVxuICAgIH07XG4gICAgXG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGRhdGEsIG51bGwsIDIpO1xuICB9XG4gIFxuICAvKipcbiAgICogRGVzZXJpYWxpemUgbWVtb3J5IGZyb20gc3RyaW5nXG4gICAqIFNFQ1VSSVRZOiBWYWxpZGF0ZXMgYWxsIGxvYWRlZCBkYXRhXG4gICAqL1xuICBwdWJsaWMgb3ZlcnJpZGUgZGVzZXJpYWxpemUoZGF0YTogc3RyaW5nKTogdm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2UoZGF0YSk7XG4gICAgICBcbiAgICAgIC8vIFZhbGlkYXRlIGJhc2ljIHN0cnVjdHVyZVxuICAgICAgaWYgKCFwYXJzZWQuaWQgfHwgIXBhcnNlZC50eXBlIHx8IHBhcnNlZC50eXBlICE9PSBFbGVtZW50VHlwZS5NRU1PUlkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIG1lbW9yeSBkYXRhIGZvcm1hdCcpO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBVcGRhdGUgcHJvcGVydGllc1xuICAgICAgdGhpcy5pZCA9IHBhcnNlZC5pZDtcbiAgICAgIHRoaXMudmVyc2lvbiA9IHBhcnNlZC52ZXJzaW9uIHx8ICcxLjAuMCc7XG4gICAgICB0aGlzLm1ldGFkYXRhID0gcGFyc2VkLm1ldGFkYXRhIHx8IHt9O1xuICAgICAgdGhpcy5leHRlbnNpb25zID0gcGFyc2VkLmV4dGVuc2lvbnMgfHwge307XG4gICAgICBcbiAgICAgIC8vIENsZWFyIGFuZCByZWxvYWQgZW50cmllc1xuICAgICAgdGhpcy5lbnRyaWVzLmNsZWFyKCk7XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShwYXJzZWQuZW50cmllcykpIHtcbiAgICAgICAgZm9yIChjb25zdCBlbnRyeSBvZiBwYXJzZWQuZW50cmllcykge1xuICAgICAgICAgIGlmICh0aGlzLmlzVmFsaWRFbnRyeShlbnRyeSkpIHtcbiAgICAgICAgICAgIC8vIFJlLXNhbml0aXplIG9uIGxvYWRcbiAgICAgICAgICAgIGVudHJ5LmNvbnRlbnQgPSBzYW5pdGl6ZU1lbW9yeUNvbnRlbnQoZW50cnkuY29udGVudCwgTUVNT1JZX0NPTlNUQU5UUy5NQVhfRU5UUllfU0laRSk7XG4gICAgICAgICAgICBlbnRyeS50YWdzID0gdGhpcy5zYW5pdGl6ZVRhZ3MoZW50cnkudGFncyB8fCBbXSk7XG4gICAgICAgICAgICBlbnRyeS50aW1lc3RhbXAgPSBuZXcgRGF0ZShlbnRyeS50aW1lc3RhbXApO1xuICAgICAgICAgICAgaWYgKGVudHJ5LmV4cGlyZXNBdCkge1xuICAgICAgICAgICAgICBlbnRyeS5leHBpcmVzQXQgPSBuZXcgRGF0ZShlbnRyeS5leHBpcmVzQXQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5lbnRyaWVzLnNldChlbnRyeS5pZCwgZW50cnkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBFbmZvcmNlIHJldGVudGlvbiBwb2xpY3kgYWZ0ZXIgbG9hZGluZ1xuICAgICAgdGhpcy5lbmZvcmNlUmV0ZW50aW9uUG9saWN5KCk7XG4gICAgICBcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiBNRU1PUllfU0VDVVJJVFlfRVZFTlRTLk1FTU9SWV9ERVNFUklBTElaRV9GQUlMRUQsXG4gICAgICAgIHNldmVyaXR5OiAnSElHSCcsXG4gICAgICAgIHNvdXJjZTogJ01lbW9yeS5kZXNlcmlhbGl6ZScsXG4gICAgICAgIGRldGFpbHM6IGBGYWlsZWQgdG8gZGVzZXJpYWxpemUgbWVtb3J5OiAke2Vycm9yfWBcbiAgICAgIH0pO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gZGVzZXJpYWxpemUgbWVtb3J5OiAke2Vycm9yfWApO1xuICAgIH1cbiAgfVxuICBcbiAgLy8gUHJpdmF0ZSBoZWxwZXIgbWV0aG9kc1xuICBcbiAgcHJpdmF0ZSBjYWxjdWxhdGVFeHBpcnlEYXRlKCk6IERhdGUge1xuICAgIGNvbnN0IGV4cGlyeSA9IG5ldyBEYXRlKCk7XG4gICAgZXhwaXJ5LnNldERhdGUoZXhwaXJ5LmdldERhdGUoKSArIHRoaXMucmV0ZW50aW9uRGF5cyk7XG4gICAgcmV0dXJuIGV4cGlyeTtcbiAgfVxuICBcbiAgcHJpdmF0ZSBzYW5pdGl6ZVRhZ3ModGFnczogc3RyaW5nW10pOiBzdHJpbmdbXSB7XG4gICAgLy8gU0VDVVJJVFkgRklYOiBMaW1pdCBudW1iZXIgb2YgdGFncyBhbmQgc2FuaXRpemUgZWFjaFxuICAgIGNvbnN0IGxpbWl0ZWRUYWdzID0gdGFncy5zbGljZSgwLCBNRU1PUllfQ09OU1RBTlRTLk1BWF9UQUdTX1BFUl9FTlRSWSk7XG4gICAgXG4gICAgcmV0dXJuIGxpbWl0ZWRUYWdzXG4gICAgICAubWFwKHRhZyA9PiB7XG4gICAgICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZSh0YWcpLm5vcm1hbGl6ZWRDb250ZW50O1xuICAgICAgICByZXR1cm4gc2FuaXRpemVJbnB1dChub3JtYWxpemVkLCBNRU1PUllfQ09OU1RBTlRTLk1BWF9UQUdfTEVOR1RIKTtcbiAgICAgIH0pXG4gICAgICAuZmlsdGVyKHRhZyA9PiB0YWcgJiYgdGFnLmxlbmd0aCA+IDApO1xuICB9XG4gIFxuICBwcml2YXRlIHNhbml0aXplTWV0YWRhdGEobWV0YWRhdGE/OiBSZWNvcmQ8c3RyaW5nLCBhbnk+KTogUmVjb3JkPHN0cmluZywgYW55PiB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKCFtZXRhZGF0YSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBcbiAgICAvLyBTRUNVUklUWSBGSVg6IFNhbml0aXplIG1ldGFkYXRhIHZhbHVlc1xuICAgIGNvbnN0IHNhbml0aXplZDogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICAgIGNvbnN0IG1heEtleXMgPSBNRU1PUllfQ09OU1RBTlRTLk1BWF9NRVRBREFUQV9LRVlTO1xuICAgIGxldCBrZXlDb3VudCA9IDA7XG4gICAgXG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobWV0YWRhdGEpKSB7XG4gICAgICBpZiAoa2V5Q291bnQgPj0gbWF4S2V5cykgYnJlYWs7XG4gICAgICBcbiAgICAgIGNvbnN0IHNhbml0aXplZEtleSA9IHNhbml0aXplSW5wdXQoa2V5LCBNRU1PUllfQ09OU1RBTlRTLk1BWF9NRVRBREFUQV9LRVlfTEVOR1RIKTtcbiAgICAgIGlmIChzYW5pdGl6ZWRLZXkgJiYgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xuICAgICAgICBzYW5pdGl6ZWRbc2FuaXRpemVkS2V5XSA9IHNhbml0aXplSW5wdXQodmFsdWUsIE1FTU9SWV9DT05TVEFOVFMuTUFYX01FVEFEQVRBX1ZBTFVFX0xFTkdUSCk7XG4gICAgICAgIGtleUNvdW50Kys7XG4gICAgICB9IGVsc2UgaWYgKHNhbml0aXplZEtleSAmJiB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSB7XG4gICAgICAgIHNhbml0aXplZFtzYW5pdGl6ZWRLZXldID0gdmFsdWU7XG4gICAgICAgIGtleUNvdW50Kys7XG4gICAgICB9XG4gICAgICAvLyBTa2lwIG90aGVyIHR5cGVzIGZvciBzZWN1cml0eVxuICAgIH1cbiAgICBcbiAgICByZXR1cm4gc2FuaXRpemVkO1xuICB9XG4gIFxuICBwcml2YXRlIGNhbkFjY2Vzc1ByaXZhY3lMZXZlbChlbnRyeUxldmVsOiBzdHJpbmcsIHJlcXVlc3RlZExldmVsOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBjb25zdCBsZXZlbHMgPSBNRU1PUllfQ09OU1RBTlRTLlBSSVZBQ1lfTEVWRUxTO1xuICAgIGNvbnN0IGVudHJ5SW5kZXggPSBsZXZlbHMuaW5kZXhPZihlbnRyeUxldmVsIGFzIFByaXZhY3lMZXZlbCk7XG4gICAgY29uc3QgcmVxdWVzdGVkSW5kZXggPSBsZXZlbHMuaW5kZXhPZihyZXF1ZXN0ZWRMZXZlbCBhcyBQcml2YWN5TGV2ZWwpO1xuICAgIFxuICAgIC8vIENhbiBvbmx5IGFjY2VzcyBlbnRyaWVzIGF0IG9yIGJlbG93IHRoZSByZXF1ZXN0ZWQgcHJpdmFjeSBsZXZlbFxuICAgIC8vIGUuZy4sIGlmIHJlcXVlc3RpbmcgJ3ByaXZhdGUnLCBjYW4gc2VlICdwdWJsaWMnIGFuZCAncHJpdmF0ZScgYnV0IG5vdCAnc2Vuc2l0aXZlJ1xuICAgIHJldHVybiBlbnRyeUluZGV4IDw9IHJlcXVlc3RlZEluZGV4O1xuICB9XG4gIFxuICBwcml2YXRlIGlzVmFsaWRFbnRyeShlbnRyeTogYW55KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGVudHJ5ICYmXG4gICAgICB0eXBlb2YgZW50cnkuaWQgPT09ICdzdHJpbmcnICYmXG4gICAgICB0eXBlb2YgZW50cnkuY29udGVudCA9PT0gJ3N0cmluZycgJiZcbiAgICAgIGVudHJ5LnRpbWVzdGFtcCAmJlxuICAgICAgKCFlbnRyeS50YWdzIHx8IEFycmF5LmlzQXJyYXkoZW50cnkudGFncykpO1xuICB9XG59Il19
@@ -1,86 +0,0 @@
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, MemoryMetadata } from './Memory.js';
13
- import { IElementManager } from '../../types/elements/IElementManager.js';
14
- import { ElementValidationResult } from '../../types/elements/IElement.js';
15
- import { ElementType } from '../../portfolio/types.js';
16
- export declare class MemoryManager implements IElementManager<Memory> {
17
- private portfolioManager;
18
- private memoriesDir;
19
- private memoryCache;
20
- constructor();
21
- /**
22
- * Load a memory from file
23
- * SECURITY FIX #1: Uses FileLockManager.atomicReadFile() instead of fs.readFile()
24
- * to prevent race conditions and ensure atomic file operations
25
- */
26
- load(filePath: string): Promise<Memory>;
27
- /**
28
- * Save a memory to file
29
- * SECURITY FIX #1: Uses FileLockManager.atomicWriteFile() for atomic operations
30
- */
31
- save(element: Memory, filePath: string): Promise<void>;
32
- /**
33
- * List all available memories
34
- */
35
- list(): Promise<Memory[]>;
36
- /**
37
- * Find memories matching a predicate
38
- */
39
- find(predicate: (element: Memory) => boolean): Promise<Memory | undefined>;
40
- /**
41
- * Find multiple memories matching a predicate
42
- */
43
- findMany(predicate: (element: Memory) => boolean): Promise<Memory[]>;
44
- /**
45
- * Delete a memory file
46
- * SECURITY: Validates path and logs deletion
47
- */
48
- delete(filePath: string): Promise<void>;
49
- /**
50
- * Check if a memory file exists
51
- */
52
- exists(filePath: string): Promise<boolean>;
53
- /**
54
- * Create a new memory with metadata
55
- */
56
- create(metadata: Partial<MemoryMetadata>): Promise<Memory>;
57
- /**
58
- * Import a memory from JSON/YAML string
59
- * SECURITY: Full validation of imported content
60
- */
61
- importElement(data: string, format?: 'json' | 'yaml'): Promise<Memory>;
62
- /**
63
- * Export a memory to YAML string
64
- */
65
- exportElement(element: Memory): Promise<string>;
66
- /**
67
- * Validate a memory element
68
- */
69
- validate(element: Memory): ElementValidationResult;
70
- /**
71
- * Validate and resolve a file path
72
- * SECURITY: Prevents directory traversal attacks
73
- */
74
- validatePath(filePath: string): boolean;
75
- /**
76
- * Get the element type this manager handles
77
- */
78
- getElementType(): ElementType;
79
- /**
80
- * Get the file extension for memory files
81
- */
82
- getFileExtension(): string;
83
- private validateAndResolvePath;
84
- private parseMemoryFile;
85
- }
86
- //# sourceMappingURL=MemoryManager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"MemoryManager.d.ts","sourceRoot":"","sources":["../../../src/elements/memories/MemoryManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,MAAM,EAAE,cAAc,EAAe,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAYvD,qBAAa,aAAc,YAAW,eAAe,CAAC,MAAM,CAAC;IAC3D,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAkC;;IAOrD;;;;OAIG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkE7C;;;OAGG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoE5D;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAiC/B;;OAEG;IACG,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAKhF;;OAEG;IACG,QAAQ,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAK1E;;;OAGG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B7C;;OAEG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUhD;;OAEG;IACG,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAIhE;;;OAGG;IACG,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,GAAG,MAAe,GAAG,OAAO,CAAC,MAAM,CAAC;IA0EpF;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAuBrD;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,uBAAuB;IAIlD;;;OAGG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAqBvC;;OAEG;IACH,cAAc,IAAI,WAAW;IAI7B;;OAEG;IACH,gBAAgB,IAAI,MAAM;YAMZ,sBAAsB;IAgCpC,OAAO,CAAC,eAAe;CA0BxB"}