@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,690 @@
1
+ /**
2
+ * Memory Search Index - High-performance indexed search for Memory elements
3
+ *
4
+ * Addresses issue #984: Implement search indexing for Memory element scalability
5
+ *
6
+ * Features:
7
+ * - Tag index for O(1) tag-based queries
8
+ * - Content index using inverted index pattern
9
+ * - Temporal index for date range queries
10
+ * - Privacy level index for filtered access
11
+ * - Incremental index updates
12
+ * - Optional persistence
13
+ * - Configurable thresholds
14
+ */
15
+ import { MEMORY_CONSTANTS, MEMORY_SECURITY_EVENTS } from './constants.js';
16
+ import { logger } from '../../utils/logger.js';
17
+ import { UnicodeValidator } from '../../security/validators/unicodeValidator.js';
18
+ import { SecurityMonitor } from '../../security/securityMonitor.js';
19
+ /**
20
+ * Inverted index for content search
21
+ */
22
+ class ContentIndex {
23
+ termToEntries = new Map();
24
+ entryToTerms = new Map();
25
+ config;
26
+ constructor(config) {
27
+ this.config = config;
28
+ }
29
+ /**
30
+ * Add an entry to the content index
31
+ */
32
+ addEntry(entryId, content) {
33
+ const terms = this.extractTerms(content, { entryId });
34
+ // Store terms for this entry
35
+ this.entryToTerms.set(entryId, terms);
36
+ // Update inverted index
37
+ for (const term of terms) {
38
+ let entries = this.termToEntries.get(term);
39
+ if (!entries) {
40
+ entries = new Set();
41
+ this.termToEntries.set(term, entries);
42
+ }
43
+ entries.add(entryId);
44
+ }
45
+ }
46
+ /**
47
+ * Remove an entry from the index
48
+ */
49
+ removeEntry(entryId) {
50
+ const terms = this.entryToTerms.get(entryId);
51
+ if (!terms)
52
+ return;
53
+ // Remove from inverted index
54
+ for (const term of terms) {
55
+ const entries = this.termToEntries.get(term);
56
+ if (entries) {
57
+ entries.delete(entryId);
58
+ if (entries.size === 0) {
59
+ this.termToEntries.delete(term);
60
+ }
61
+ }
62
+ }
63
+ // Remove entry terms
64
+ this.entryToTerms.delete(entryId);
65
+ }
66
+ /**
67
+ * Search for entries containing query terms
68
+ */
69
+ search(query) {
70
+ const queryTerms = this.extractTerms(query);
71
+ const scores = new Map();
72
+ for (const term of queryTerms) {
73
+ const entries = this.termToEntries.get(term);
74
+ if (entries) {
75
+ for (const entryId of entries) {
76
+ scores.set(entryId, (scores.get(entryId) || 0) + 1);
77
+ }
78
+ }
79
+ }
80
+ return scores;
81
+ }
82
+ /**
83
+ * Extract searchable terms from content
84
+ * SECURITY FIX: Added audit logging for Unicode validation operations
85
+ */
86
+ extractTerms(content, context) {
87
+ // Normalize for security
88
+ const normalized = UnicodeValidator.normalize(content);
89
+ if (!normalized.isValid) {
90
+ logger.warn('Invalid Unicode in content for indexing', {
91
+ entryId: context?.entryId
92
+ });
93
+ // SECURITY FIX: Log security event for audit trail (DMCP-SEC-006)
94
+ SecurityMonitor.logSecurityEvent({
95
+ type: MEMORY_SECURITY_EVENTS.MEMORY_UNICODE_VALIDATION_FAILED,
96
+ severity: 'LOW',
97
+ source: 'MemorySearchIndex.extractTerms',
98
+ details: `Invalid Unicode detected during term extraction${context?.entryId ? ` for entry ${context.entryId}` : ''}`,
99
+ metadata: {
100
+ entryId: context?.entryId,
101
+ issueCount: 0 // UnicodeValidationResult doesn't expose issues
102
+ }
103
+ });
104
+ return new Set();
105
+ }
106
+ const text = normalized.normalizedContent.toLowerCase();
107
+ const terms = new Set();
108
+ // Simple tokenization (can be improved with better NLP)
109
+ const words = text.match(/\b\w+\b/g) || [];
110
+ let termCount = 0;
111
+ for (const word of words) {
112
+ if (word.length >= (this.config.minTermLength || 2)) {
113
+ terms.add(word);
114
+ termCount++;
115
+ if (termCount >= (this.config.maxTermsPerEntry || 100)) {
116
+ break;
117
+ }
118
+ }
119
+ }
120
+ return terms;
121
+ }
122
+ clear() {
123
+ this.termToEntries.clear();
124
+ this.entryToTerms.clear();
125
+ }
126
+ get size() {
127
+ return this.termToEntries.size;
128
+ }
129
+ }
130
+ /**
131
+ * Date range index using sorted array for efficient range queries
132
+ */
133
+ class TemporalIndex {
134
+ entries = [];
135
+ addEntry(entryId, date) {
136
+ const timestamp = date.getTime();
137
+ // Binary search for insertion point
138
+ let left = 0;
139
+ let right = this.entries.length;
140
+ while (left < right) {
141
+ const mid = Math.floor((left + right) / 2);
142
+ if (this.entries[mid].timestamp < timestamp) {
143
+ left = mid + 1;
144
+ }
145
+ else {
146
+ right = mid;
147
+ }
148
+ }
149
+ // Insert at correct position to maintain sort
150
+ this.entries.splice(left, 0, { id: entryId, timestamp });
151
+ }
152
+ removeEntry(entryId) {
153
+ const index = this.entries.findIndex(e => e.id === entryId);
154
+ if (index >= 0) {
155
+ this.entries.splice(index, 1);
156
+ }
157
+ }
158
+ /**
159
+ * Find entries within date range
160
+ */
161
+ searchRange(from, to) {
162
+ const results = new Set();
163
+ const fromTime = from?.getTime() || 0;
164
+ const toTime = to?.getTime() || Date.now();
165
+ // Binary search for start
166
+ let start = 0;
167
+ let end = this.entries.length;
168
+ while (start < end) {
169
+ const mid = Math.floor((start + end) / 2);
170
+ if (this.entries[mid].timestamp < fromTime) {
171
+ start = mid + 1;
172
+ }
173
+ else {
174
+ end = mid;
175
+ }
176
+ }
177
+ // Collect all entries in range
178
+ for (let i = start; i < this.entries.length; i++) {
179
+ const entry = this.entries[i];
180
+ if (entry.timestamp > toTime)
181
+ break;
182
+ results.add(entry.id);
183
+ }
184
+ return results;
185
+ }
186
+ clear() {
187
+ this.entries = [];
188
+ }
189
+ get size() {
190
+ return this.entries.length;
191
+ }
192
+ serialize() {
193
+ return this.entries;
194
+ }
195
+ deserialize(data) {
196
+ this.entries = data || [];
197
+ }
198
+ }
199
+ /**
200
+ * Main search index for Memory elements
201
+ */
202
+ export class MemorySearchIndex {
203
+ config;
204
+ // Indexes
205
+ tagIndex = new Map();
206
+ privacyIndex = new Map();
207
+ contentIndex = null;
208
+ temporalIndex = new TemporalIndex();
209
+ // Cached entries for scoring
210
+ entriesCache = new Map();
211
+ // Index state
212
+ isBuilt = false;
213
+ isBuilding = false;
214
+ buildQueue = null;
215
+ stats = {
216
+ isIndexed: false,
217
+ entryCount: 0,
218
+ tagCount: 0,
219
+ termCount: 0,
220
+ memoryUsageBytes: 0
221
+ };
222
+ // Memory management
223
+ maxMemoryBytes;
224
+ memoryUsageBytes = 0;
225
+ constructor(config = {}) {
226
+ this.config = {
227
+ indexThreshold: config.indexThreshold || 100,
228
+ enableContentIndex: config.enableContentIndex !== false,
229
+ maxTermsPerEntry: config.maxTermsPerEntry || 100,
230
+ minTermLength: config.minTermLength || 2,
231
+ enablePersistence: config.enablePersistence || false,
232
+ maxMemoryMB: config.maxMemoryMB || 100,
233
+ enableLRUEviction: config.enableLRUEviction !== false
234
+ };
235
+ // Configure memory limit (default 100MB, configurable)
236
+ this.maxMemoryBytes = (this.config.maxMemoryMB || 100) * 1024 * 1024;
237
+ if (this.config.enableContentIndex) {
238
+ this.contentIndex = new ContentIndex(this.config);
239
+ }
240
+ logger.debug('MemorySearchIndex created', this.config);
241
+ }
242
+ /**
243
+ * Build or rebuild the index from entries
244
+ * FIX: Added race condition protection with isBuilding flag and build queue
245
+ */
246
+ async buildIndex(entries) {
247
+ // If already building, wait for the current build to complete
248
+ if (this.isBuilding && this.buildQueue) {
249
+ logger.debug('Index build already in progress, waiting...');
250
+ return this.buildQueue;
251
+ }
252
+ // Create build promise to handle concurrent calls
253
+ this.buildQueue = this._doBuildIndex(entries);
254
+ return this.buildQueue;
255
+ }
256
+ async _doBuildIndex(entries) {
257
+ // Prevent concurrent builds
258
+ if (this.isBuilding) {
259
+ logger.warn('Attempted concurrent index build, skipping');
260
+ return;
261
+ }
262
+ this.isBuilding = true;
263
+ const startTime = Date.now();
264
+ try {
265
+ // Clear existing indexes
266
+ this.clear();
267
+ // Check if we should index based on threshold
268
+ if (entries.size < (this.config.indexThreshold || 100)) {
269
+ logger.debug('Not building index - below threshold', {
270
+ entryCount: entries.size,
271
+ threshold: this.config.indexThreshold
272
+ });
273
+ return;
274
+ }
275
+ // Build indexes
276
+ for (const [id, entry] of entries) {
277
+ this.addToIndex(id, entry);
278
+ }
279
+ // Calculate memory usage
280
+ this.updateMemoryUsage();
281
+ // SECURITY FIX: Log security event for index build operation (DMCP-SEC-006)
282
+ SecurityMonitor.logSecurityEvent({
283
+ type: MEMORY_SECURITY_EVENTS.MEMORY_CREATED, // Using CREATED for index build
284
+ severity: 'LOW',
285
+ source: 'MemorySearchIndex.buildIndex',
286
+ details: `Memory search index built successfully with ${entries.size} entries`,
287
+ metadata: {
288
+ entryCount: entries.size,
289
+ tagCount: this.tagIndex.size,
290
+ memoryUsageBytes: this.memoryUsageBytes
291
+ }
292
+ });
293
+ // Update stats
294
+ const buildTime = Date.now() - startTime;
295
+ this.stats = {
296
+ isIndexed: true,
297
+ entryCount: entries.size,
298
+ tagCount: this.tagIndex.size,
299
+ termCount: this.contentIndex?.size || 0,
300
+ lastBuilt: new Date(),
301
+ buildTimeMs: buildTime,
302
+ memoryUsageBytes: this.memoryUsageBytes
303
+ };
304
+ this.isBuilt = true;
305
+ logger.info('Memory search index built', this.stats);
306
+ }
307
+ catch (error) {
308
+ logger.error('Failed to build memory search index', error);
309
+ // Reset state on failure
310
+ this.clear();
311
+ throw error;
312
+ }
313
+ finally {
314
+ this.isBuilding = false;
315
+ this.buildQueue = null;
316
+ }
317
+ }
318
+ /**
319
+ * Add a single entry to the index (incremental update)
320
+ */
321
+ addEntry(entry) {
322
+ if (!this.isBuilt)
323
+ return;
324
+ this.addToIndex(entry.id, entry);
325
+ this.stats.entryCount++;
326
+ logger.debug('Entry added to index', { id: entry.id });
327
+ }
328
+ /**
329
+ * Remove an entry from the index
330
+ */
331
+ removeEntry(entryId) {
332
+ if (!this.isBuilt)
333
+ return;
334
+ const entry = this.entriesCache.get(entryId);
335
+ if (!entry)
336
+ return;
337
+ // Remove from tag index
338
+ if (entry.metadata?.tags) {
339
+ for (const tag of entry.metadata.tags) {
340
+ const entries = this.tagIndex.get(tag);
341
+ if (entries) {
342
+ entries.delete(entryId);
343
+ if (entries.size === 0) {
344
+ this.tagIndex.delete(tag);
345
+ }
346
+ }
347
+ }
348
+ }
349
+ // Remove from privacy index
350
+ const privacyLevel = entry.metadata?.privacyLevel || entry.privacyLevel || MEMORY_CONSTANTS.DEFAULT_PRIVACY_LEVEL;
351
+ const privacyEntries = this.privacyIndex.get(privacyLevel);
352
+ if (privacyEntries) {
353
+ privacyEntries.delete(entryId);
354
+ }
355
+ // Remove from content index
356
+ this.contentIndex?.removeEntry(entryId);
357
+ // Remove from temporal index
358
+ this.temporalIndex.removeEntry(entryId);
359
+ // Remove from cache
360
+ this.entriesCache.delete(entryId);
361
+ this.stats.entryCount--;
362
+ logger.debug('Entry removed from index', { id: entryId });
363
+ }
364
+ /**
365
+ * Search the index with multiple criteria
366
+ */
367
+ search(query, entries) {
368
+ if (!this.isBuilt) {
369
+ logger.debug('Index not built, falling back to linear search');
370
+ return this.linearSearch(query, entries);
371
+ }
372
+ // Start with all entries or filtered by privacy
373
+ let candidateIds = null;
374
+ // Filter by privacy level
375
+ if (query.privacyLevel) {
376
+ candidateIds = new Set(this.privacyIndex.get(query.privacyLevel) || []);
377
+ }
378
+ // Filter by tags (intersection)
379
+ if (query.tags && query.tags.length > 0) {
380
+ const tagResults = new Set();
381
+ for (const tag of query.tags) {
382
+ const entries = this.tagIndex.get(tag.toLowerCase());
383
+ if (entries) {
384
+ if (candidateIds) {
385
+ // Intersection with existing candidates
386
+ for (const id of entries) {
387
+ if (candidateIds.has(id)) {
388
+ tagResults.add(id);
389
+ }
390
+ }
391
+ }
392
+ else {
393
+ // First filter
394
+ entries.forEach(id => tagResults.add(id));
395
+ }
396
+ }
397
+ }
398
+ candidateIds = tagResults;
399
+ }
400
+ // Filter by date range
401
+ if (query.dateFrom || query.dateTo) {
402
+ const dateResults = this.temporalIndex.searchRange(query.dateFrom, query.dateTo);
403
+ if (candidateIds) {
404
+ // Intersection
405
+ const intersection = new Set();
406
+ for (const id of candidateIds) {
407
+ if (dateResults.has(id)) {
408
+ intersection.add(id);
409
+ }
410
+ }
411
+ candidateIds = intersection;
412
+ }
413
+ else {
414
+ candidateIds = dateResults;
415
+ }
416
+ }
417
+ // Score by content if provided
418
+ const contentScores = query.content && this.contentIndex
419
+ ? this.contentIndex.search(query.content)
420
+ : new Map();
421
+ // Build results
422
+ const results = [];
423
+ const searchEntries = candidateIds || new Set(entries.keys());
424
+ for (const id of searchEntries) {
425
+ const entry = entries.get(id);
426
+ if (!entry)
427
+ continue;
428
+ // Calculate score
429
+ let score = 1;
430
+ // Content relevance score
431
+ if (contentScores.has(id)) {
432
+ score += contentScores.get(id) * 2;
433
+ }
434
+ // Tag match bonus
435
+ if (query.tags && entry.metadata?.tags) {
436
+ const matchedTags = query.tags.filter(tag => entry.metadata?.tags?.includes(tag));
437
+ score += matchedTags.length;
438
+ }
439
+ results.push({
440
+ entry,
441
+ score,
442
+ matches: {
443
+ tags: query.tags?.filter(tag => entry.metadata?.tags?.includes(tag)),
444
+ terms: query.content ? ['indexed'] : undefined
445
+ }
446
+ });
447
+ }
448
+ // Sort by score and apply pagination
449
+ results.sort((a, b) => b.score - a.score);
450
+ const offset = query.offset || 0;
451
+ const limit = query.limit || 100;
452
+ return results.slice(offset, offset + limit);
453
+ }
454
+ /**
455
+ * Fallback linear search when index is not available
456
+ */
457
+ linearSearch(query, entries) {
458
+ const results = [];
459
+ for (const [id, entry] of entries) {
460
+ // Check privacy level
461
+ if (query.privacyLevel && entry.metadata?.privacyLevel !== query.privacyLevel) {
462
+ continue;
463
+ }
464
+ // Check date range
465
+ if (query.dateFrom && entry.metadata?.timestamp && entry.metadata.timestamp < query.dateFrom) {
466
+ continue;
467
+ }
468
+ if (query.dateTo && entry.metadata?.timestamp && entry.metadata.timestamp > query.dateTo) {
469
+ continue;
470
+ }
471
+ // Check tags
472
+ if (query.tags && query.tags.length > 0) {
473
+ const hasAllTags = query.tags.every(tag => entry.metadata?.tags?.includes(tag));
474
+ if (!hasAllTags)
475
+ continue;
476
+ }
477
+ // Check content (simple substring match)
478
+ let score = 1;
479
+ if (query.content) {
480
+ const normalized = UnicodeValidator.normalize(query.content);
481
+ if (normalized.isValid) {
482
+ const searchTerm = normalized.normalizedContent.toLowerCase();
483
+ if (entry.content.toLowerCase().includes(searchTerm)) {
484
+ score += 2;
485
+ }
486
+ }
487
+ }
488
+ results.push({
489
+ entry,
490
+ score,
491
+ matches: {
492
+ tags: query.tags?.filter(tag => entry.metadata?.tags?.includes(tag))
493
+ }
494
+ });
495
+ }
496
+ // Sort and paginate
497
+ results.sort((a, b) => b.score - a.score);
498
+ const offset = query.offset || 0;
499
+ const limit = query.limit || 100;
500
+ return results.slice(offset, offset + limit);
501
+ }
502
+ /**
503
+ * Internal helper to add entry to all indexes
504
+ */
505
+ addToIndex(id, entry) {
506
+ // Cache entry
507
+ this.entriesCache.set(id, entry);
508
+ // Add to tag index
509
+ if (entry.metadata?.tags) {
510
+ for (const tag of entry.metadata.tags) {
511
+ const normalizedTag = tag.toLowerCase();
512
+ let entries = this.tagIndex.get(normalizedTag);
513
+ if (!entries) {
514
+ entries = new Set();
515
+ this.tagIndex.set(normalizedTag, entries);
516
+ }
517
+ entries.add(id);
518
+ }
519
+ }
520
+ // Add to privacy index
521
+ const privacyLevel = entry.metadata?.privacyLevel || entry.privacyLevel || MEMORY_CONSTANTS.DEFAULT_PRIVACY_LEVEL;
522
+ let privacyEntries = this.privacyIndex.get(privacyLevel);
523
+ if (!privacyEntries) {
524
+ privacyEntries = new Set();
525
+ this.privacyIndex.set(privacyLevel, privacyEntries);
526
+ }
527
+ privacyEntries.add(id);
528
+ // Add to content index
529
+ if (this.contentIndex) {
530
+ this.contentIndex.addEntry(id, entry.content);
531
+ }
532
+ // Add to temporal index
533
+ this.temporalIndex.addEntry(id, entry.metadata?.timestamp || entry.timestamp);
534
+ }
535
+ /**
536
+ * Clear all indexes
537
+ */
538
+ clear() {
539
+ this.tagIndex.clear();
540
+ this.privacyIndex.clear();
541
+ this.contentIndex?.clear();
542
+ this.temporalIndex.clear();
543
+ this.entriesCache.clear();
544
+ this.isBuilt = false;
545
+ this.stats = {
546
+ isIndexed: false,
547
+ entryCount: 0,
548
+ tagCount: 0,
549
+ termCount: 0
550
+ };
551
+ }
552
+ /**
553
+ * Get index statistics
554
+ */
555
+ getStats() {
556
+ return { ...this.stats };
557
+ }
558
+ /**
559
+ * Check if index is built
560
+ */
561
+ get isIndexed() {
562
+ return this.isBuilt;
563
+ }
564
+ /**
565
+ * Calculate and update memory usage
566
+ * FIX: Added memory monitoring for content index
567
+ */
568
+ updateMemoryUsage() {
569
+ let totalBytes = 0;
570
+ // Estimate tag index memory
571
+ for (const [tag, entries] of this.tagIndex) {
572
+ totalBytes += tag.length * 2; // UTF-16 encoding
573
+ totalBytes += entries.size * 32; // Estimated ID size
574
+ }
575
+ // Estimate content index memory
576
+ if (this.contentIndex) {
577
+ // Rough estimate: each term + entry IDs
578
+ totalBytes += this.contentIndex.size * 100;
579
+ }
580
+ // Estimate temporal index memory
581
+ totalBytes += this.temporalIndex.size * 48; // Date + ID
582
+ // Estimate cache memory
583
+ for (const entry of this.entriesCache.values()) {
584
+ totalBytes += JSON.stringify(entry).length * 2;
585
+ }
586
+ this.memoryUsageBytes = totalBytes;
587
+ // Check if we're exceeding memory limit
588
+ if (totalBytes > this.maxMemoryBytes) {
589
+ logger.warn('Memory search index exceeding limit', {
590
+ usedMB: Math.round(totalBytes / 1024 / 1024),
591
+ limitMB: Math.round(this.maxMemoryBytes / 1024 / 1024)
592
+ });
593
+ // Trigger LRU eviction if enabled
594
+ if (this.config.enableLRUEviction) {
595
+ this.evictLRUEntries();
596
+ }
597
+ }
598
+ }
599
+ /**
600
+ * Evict least recently used entries to free memory
601
+ * FIX: Added LRU eviction for memory management
602
+ */
603
+ evictLRUEntries() {
604
+ // Get entries sorted by access time (would need to track this)
605
+ // For now, evict oldest 20% of entries
606
+ const entriesToEvict = Math.floor(this.entriesCache.size * 0.2);
607
+ const entriesArray = Array.from(this.entriesCache.keys());
608
+ for (let i = 0; i < entriesToEvict; i++) {
609
+ const idToEvict = entriesArray[i];
610
+ this.removeEntry(idToEvict);
611
+ }
612
+ logger.info('Evicted LRU entries', {
613
+ evictedCount: entriesToEvict,
614
+ remainingCount: this.entriesCache.size
615
+ });
616
+ }
617
+ /**
618
+ * Serialize index to JSON for persistence
619
+ * FIX: Added index serialization for cold start optimization
620
+ */
621
+ serialize() {
622
+ if (!this.isBuilt) {
623
+ throw new Error('Cannot serialize unbuilt index');
624
+ }
625
+ const indexData = {
626
+ version: '1.0.0',
627
+ stats: this.stats,
628
+ tagIndex: Array.from(this.tagIndex.entries()).map(([tag, ids]) => ({
629
+ tag,
630
+ ids: Array.from(ids)
631
+ })),
632
+ privacyIndex: Array.from(this.privacyIndex.entries()).map(([level, ids]) => ({
633
+ level,
634
+ ids: Array.from(ids)
635
+ })),
636
+ temporalIndex: this.temporalIndex.serialize(),
637
+ // Note: Content index is not serialized due to size
638
+ // It will be rebuilt on load if needed
639
+ };
640
+ return JSON.stringify(indexData);
641
+ }
642
+ /**
643
+ * Deserialize index from JSON
644
+ * FIX: Added index deserialization for faster startup
645
+ */
646
+ deserialize(data, entries) {
647
+ try {
648
+ const indexData = JSON.parse(data);
649
+ // Validate version
650
+ if (indexData.version !== '1.0.0') {
651
+ throw new Error(`Unsupported index version: ${indexData.version}`);
652
+ }
653
+ // Clear existing indexes
654
+ this.clear();
655
+ // Restore tag index
656
+ for (const { tag, ids } of indexData.tagIndex) {
657
+ this.tagIndex.set(tag, new Set(ids));
658
+ }
659
+ // Restore privacy index
660
+ for (const { level, ids } of indexData.privacyIndex) {
661
+ this.privacyIndex.set(level, new Set(ids));
662
+ }
663
+ // Restore temporal index
664
+ this.temporalIndex.deserialize(indexData.temporalIndex);
665
+ // Restore entries cache from provided entries
666
+ for (const [id, entry] of entries) {
667
+ if (indexData.tagIndex.some((item) => item.ids.includes(id))) {
668
+ this.entriesCache.set(id, entry);
669
+ }
670
+ }
671
+ // Rebuild content index if enabled (can't serialize efficiently)
672
+ if (this.config.enableContentIndex) {
673
+ this.contentIndex = new ContentIndex(this.config);
674
+ for (const [id, entry] of this.entriesCache) {
675
+ this.contentIndex.addEntry(id, entry.content);
676
+ }
677
+ }
678
+ // Update stats
679
+ this.stats = indexData.stats;
680
+ this.isBuilt = true;
681
+ logger.info('Memory search index deserialized', this.stats);
682
+ }
683
+ catch (error) {
684
+ logger.error('Failed to deserialize index, rebuilding', error);
685
+ // Fall back to building from scratch
686
+ this.buildIndex(entries);
687
+ }
688
+ }
689
+ }
690
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWVtb3J5U2VhcmNoSW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZWxlbWVudHMvbWVtb3JpZXMvTWVtb3J5U2VhcmNoSW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUdILE9BQU8sRUFBZ0IsZ0JBQWdCLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4RixPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDL0MsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sK0NBQStDLENBQUM7QUFDakYsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBMkVwRTs7R0FFRztBQUNILE1BQU0sWUFBWTtJQUNSLGFBQWEsR0FBRyxJQUFJLEdBQUcsRUFBdUIsQ0FBQztJQUMvQyxZQUFZLEdBQUcsSUFBSSxHQUFHLEVBQXVCLENBQUM7SUFDckMsTUFBTSxDQUFvQjtJQUUzQyxZQUFZLE1BQXlCO1FBQ25DLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO0lBQ3ZCLENBQUM7SUFFRDs7T0FFRztJQUNILFFBQVEsQ0FBQyxPQUFlLEVBQUUsT0FBZTtRQUN2QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sRUFBRSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFFdEQsNkJBQTZCO1FBQzdCLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUV0Qyx3QkFBd0I7UUFDeEIsS0FBSyxNQUFNLElBQUksSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUN6QixJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUMzQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ2IsT0FBTyxHQUFHLElBQUksR0FBRyxFQUFFLENBQUM7Z0JBQ3BCLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztZQUN4QyxDQUFDO1lBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN2QixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0gsV0FBVyxDQUFDLE9BQWU7UUFDekIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDN0MsSUFBSSxDQUFDLEtBQUs7WUFBRSxPQUFPO1FBRW5CLDZCQUE2QjtRQUM3QixLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ3pCLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzdDLElBQUksT0FBTyxFQUFFLENBQUM7Z0JBQ1osT0FBTyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDeEIsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLENBQUMsRUFBRSxDQUFDO29CQUN2QixJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDbEMsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBRUQscUJBQXFCO1FBQ3JCLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3BDLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxLQUFhO1FBQ2xCLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDNUMsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQWtCLENBQUM7UUFFekMsS0FBSyxNQUFNLElBQUksSUFBSSxVQUFVLEVBQUUsQ0FBQztZQUM5QixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUM3QyxJQUFJLE9BQU8sRUFBRSxDQUFDO2dCQUNaLEtBQUssTUFBTSxPQUFPLElBQUksT0FBTyxFQUFFLENBQUM7b0JBQzlCLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztnQkFDdEQsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVEOzs7T0FHRztJQUNLLFlBQVksQ0FBQyxPQUFlLEVBQUUsT0FBOEI7UUFDbEUseUJBQXlCO1FBQ3pCLE1BQU0sVUFBVSxHQUFHLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN2RCxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3hCLE1BQU0sQ0FBQyxJQUFJLENBQUMseUNBQXlDLEVBQUU7Z0JBQ3JELE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTzthQUMxQixDQUFDLENBQUM7WUFFSCxrRUFBa0U7WUFDbEUsZUFBZSxDQUFDLGdCQUFnQixDQUFDO2dCQUMvQixJQUFJLEVBQUUsc0JBQXNCLENBQUMsZ0NBQWdDO2dCQUM3RCxRQUFRLEVBQUUsS0FBSztnQkFDZixNQUFNLEVBQUUsZ0NBQWdDO2dCQUN4QyxPQUFPLEVBQUUsa0RBQWtELE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLGNBQWMsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7Z0JBQ3BILFFBQVEsRUFBRTtvQkFDUixPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU87b0JBQ3pCLFVBQVUsRUFBRSxDQUFDLENBQUUsZ0RBQWdEO2lCQUNoRTthQUNGLENBQUMsQ0FBQztZQUVILE9BQU8sSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUNuQixDQUFDO1FBRUQsTUFBTSxJQUFJLEdBQUcsVUFBVSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ3hELE1BQU0sS0FBSyxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7UUFFaEMsd0RBQXdEO1FBQ3hELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDO1FBRTNDLElBQUksU0FBUyxHQUFHLENBQUMsQ0FBQztRQUNsQixLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ3pCLElBQUksSUFBSSxDQUFDLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUM7Z0JBQ3BELEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ2hCLFNBQVMsRUFBRSxDQUFDO2dCQUNaLElBQUksU0FBUyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsSUFBSSxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUN2RCxNQUFNO2dCQUNSLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVELEtBQUs7UUFDSCxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzNCLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDNUIsQ0FBQztJQUVELElBQUksSUFBSTtRQUNOLE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUM7SUFDakMsQ0FBQztDQUNGO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLGFBQWE7SUFDVCxPQUFPLEdBQTZDLEVBQUUsQ0FBQztJQUUvRCxRQUFRLENBQUMsT0FBZSxFQUFFLElBQVU7UUFDbEMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBRWpDLG9DQUFvQztRQUNwQyxJQUFJLElBQUksR0FBRyxDQUFDLENBQUM7UUFDYixJQUFJLEtBQUssR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQztRQUVoQyxPQUFPLElBQUksR0FBRyxLQUFLLEVBQUUsQ0FBQztZQUNwQixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQzNDLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxTQUFTLEdBQUcsU0FBUyxFQUFFLENBQUM7Z0JBQzVDLElBQUksR0FBRyxHQUFHLEdBQUcsQ0FBQyxDQUFDO1lBQ2pCLENBQUM7aUJBQU0sQ0FBQztnQkFDTixLQUFLLEdBQUcsR0FBRyxDQUFDO1lBQ2QsQ0FBQztRQUNILENBQUM7UUFFRCw4Q0FBOEM7UUFDOUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztJQUMzRCxDQUFDO0lBRUQsV0FBVyxDQUFDLE9BQWU7UUFDekIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLE9BQU8sQ0FBQyxDQUFDO1FBQzVELElBQUksS0FBSyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ2YsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ2hDLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxXQUFXLENBQUMsSUFBVyxFQUFFLEVBQVM7UUFDaEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztRQUNsQyxNQUFNLFFBQVEsR0FBRyxJQUFJLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ3RDLE1BQU0sTUFBTSxHQUFHLEVBQUUsRUFBRSxPQUFPLEVBQUUsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFFM0MsMEJBQTBCO1FBQzFCLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztRQUNkLElBQUksR0FBRyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDO1FBRTlCLE9BQU8sS0FBSyxHQUFHLEdBQUcsRUFBRSxDQUFDO1lBQ25CLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLEdBQUcsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDMUMsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFNBQVMsR0FBRyxRQUFRLEVBQUUsQ0FBQztnQkFDM0MsS0FBSyxHQUFHLEdBQUcsR0FBRyxDQUFDLENBQUM7WUFDbEIsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLEdBQUcsR0FBRyxHQUFHLENBQUM7WUFDWixDQUFDO1FBQ0gsQ0FBQztRQUVELCtCQUErQjtRQUMvQixLQUFLLElBQUksQ0FBQyxHQUFHLEtBQUssRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNqRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzlCLElBQUksS0FBSyxDQUFDLFNBQVMsR0FBRyxNQUFNO2dCQUFFLE1BQU07WUFDcEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDeEIsQ0FBQztRQUVELE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7SUFFRCxLQUFLO1FBQ0gsSUFBSSxDQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7SUFDcEIsQ0FBQztJQUVELElBQUksSUFBSTtRQUNOLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7SUFDN0IsQ0FBQztJQUVELFNBQVM7UUFDUCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDdEIsQ0FBQztJQUVELFdBQVcsQ0FBQyxJQUFTO1FBQ25CLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztJQUM1QixDQUFDO0NBQ0Y7QUFFRDs7R0FFRztBQUNILE1BQU0sT0FBTyxpQkFBaUI7SUFDWCxNQUFNLENBQW9CO0lBRTNDLFVBQVU7SUFDRixRQUFRLEdBQUcsSUFBSSxHQUFHLEVBQXVCLENBQUM7SUFDMUMsWUFBWSxHQUFHLElBQUksR0FBRyxFQUE2QixDQUFDO0lBQ3BELFlBQVksR0FBd0IsSUFBSSxDQUFDO0lBQ3pDLGFBQWEsR0FBRyxJQUFJLGFBQWEsRUFBRSxDQUFDO0lBRTVDLDZCQUE2QjtJQUNyQixZQUFZLEdBQUcsSUFBSSxHQUFHLEVBQXVCLENBQUM7SUFFdEQsY0FBYztJQUNOLE9BQU8sR0FBRyxLQUFLLENBQUM7SUFDaEIsVUFBVSxHQUFHLEtBQUssQ0FBQztJQUNuQixVQUFVLEdBQXlCLElBQUksQ0FBQztJQUN4QyxLQUFLLEdBQXFCO1FBQ2hDLFNBQVMsRUFBRSxLQUFLO1FBQ2hCLFVBQVUsRUFBRSxDQUFDO1FBQ2IsUUFBUSxFQUFFLENBQUM7UUFDWCxTQUFTLEVBQUUsQ0FBQztRQUNaLGdCQUFnQixFQUFFLENBQUM7S0FDcEIsQ0FBQztJQUVGLG9CQUFvQjtJQUNILGNBQWMsQ0FBUztJQUNoQyxnQkFBZ0IsR0FBRyxDQUFDLENBQUM7SUFFN0IsWUFBWSxTQUE0QixFQUFFO1FBQ3hDLElBQUksQ0FBQyxNQUFNLEdBQUc7WUFDWixjQUFjLEVBQUUsTUFBTSxDQUFDLGNBQWMsSUFBSSxHQUFHO1lBQzVDLGtCQUFrQixFQUFFLE1BQU0sQ0FBQyxrQkFBa0IsS0FBSyxLQUFLO1lBQ3ZELGdCQUFnQixFQUFFLE1BQU0sQ0FBQyxnQkFBZ0IsSUFBSSxHQUFHO1lBQ2hELGFBQWEsRUFBRSxNQUFNLENBQUMsYUFBYSxJQUFJLENBQUM7WUFDeEMsaUJBQWlCLEVBQUUsTUFBTSxDQUFDLGlCQUFpQixJQUFJLEtBQUs7WUFDcEQsV0FBVyxFQUFFLE1BQU0sQ0FBQyxXQUFXLElBQUksR0FBRztZQUN0QyxpQkFBaUIsRUFBRSxNQUFNLENBQUMsaUJBQWlCLEtBQUssS0FBSztTQUN0RCxDQUFDO1FBRUYsdURBQXVEO1FBQ3ZELElBQUksQ0FBQyxjQUFjLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsSUFBSSxHQUFHLENBQUMsR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBRXJFLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQ25DLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxZQUFZLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFFRCxNQUFNLENBQUMsS0FBSyxDQUFDLDJCQUEyQixFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLFVBQVUsQ0FBQyxPQUFpQztRQUNoRCw4REFBOEQ7UUFDOUQsSUFBSSxJQUFJLENBQUMsVUFBVSxJQUFJLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUN2QyxNQUFNLENBQUMsS0FBSyxDQUFDLDZDQUE2QyxDQUFDLENBQUM7WUFDNUQsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO1FBQ3pCLENBQUM7UUFFRCxrREFBa0Q7UUFDbEQsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzlDLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQztJQUN6QixDQUFDO0lBRU8sS0FBSyxDQUFDLGFBQWEsQ0FBQyxPQUFpQztRQUMzRCw0QkFBNEI7UUFDNUIsSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDcEIsTUFBTSxDQUFDLElBQUksQ0FBQyw0Q0FBNEMsQ0FBQyxDQUFDO1lBQzFELE9BQU87UUFDVCxDQUFDO1FBRUQsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUM7UUFDdkIsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBRTdCLElBQUksQ0FBQztZQUNILHlCQUF5QjtZQUN6QixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFFYiw4Q0FBOEM7WUFDOUMsSUFBSSxPQUFPLENBQUMsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLElBQUksR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDdkQsTUFBTSxDQUFDLEtBQUssQ0FBQyxzQ0FBc0MsRUFBRTtvQkFDbkQsVUFBVSxFQUFFLE9BQU8sQ0FBQyxJQUFJO29CQUN4QixTQUFTLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjO2lCQUN0QyxDQUFDLENBQUM7Z0JBQ0gsT0FBTztZQUNULENBQUM7WUFFRCxnQkFBZ0I7WUFDaEIsS0FBSyxNQUFNLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxJQUFJLE9BQU8sRUFBRSxDQUFDO2dCQUNsQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUM3QixDQUFDO1lBRUQseUJBQXlCO1lBQ3pCLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBRXpCLDRFQUE0RTtZQUM1RSxlQUFlLENBQUMsZ0JBQWdCLENBQUM7Z0JBQy9CLElBQUksRUFBRSxzQkFBc0IsQ0FBQyxjQUFxQixFQUFHLGdDQUFnQztnQkFDckYsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsTUFBTSxFQUFFLDhCQUE4QjtnQkFDdEMsT0FBTyxFQUFFLCtDQUErQyxPQUFPLENBQUMsSUFBSSxVQUFVO2dCQUM5RSxRQUFRLEVBQUU7b0JBQ1IsVUFBVSxFQUFFLE9BQU8sQ0FBQyxJQUFJO29CQUN4QixRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJO29CQUM1QixnQkFBZ0IsRUFBRSxJQUFJLENBQUMsZ0JBQWdCO2lCQUN4QzthQUNGLENBQUMsQ0FBQztZQUVILGVBQWU7WUFDZixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsU0FBUyxDQUFDO1lBQ3pDLElBQUksQ0FBQyxLQUFLLEdBQUc7Z0JBQ1gsU0FBUyxFQUFFLElBQUk7Z0JBQ2YsVUFBVSxFQUFFLE9BQU8sQ0FBQyxJQUFJO2dCQUN4QixRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJO2dCQUM1QixTQUFTLEVBQUUsSUFBSSxDQUFDLFlBQVksRUFBRSxJQUFJLElBQUksQ0FBQztnQkFDdkMsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFO2dCQUNyQixXQUFXLEVBQUUsU0FBUztnQkFDdEIsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLGdCQUFnQjthQUN4QyxDQUFDO1lBRUYsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7WUFFcEIsTUFBTSxDQUFDLElBQUksQ0FBQywyQkFBMkIsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDdkQsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLHFDQUFxQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzNELHlCQUF5QjtZQUN6QixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDYixNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7Z0JBQVMsQ0FBQztZQUNULElBQUksQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDO1lBQ3hCLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDO1FBQ3pCLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxRQUFRLENBQUMsS0FBa0I7UUFDekIsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPO1lBQUUsT0FBTztRQUUxQixJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDakMsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUV4QixNQUFNLENBQUMsS0FBSyxDQUFDLHNCQUFzQixFQUFFLEVBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFRDs7T0FFRztJQUNILFdBQVcsQ0FBQyxPQUFlO1FBQ3pCLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTztZQUFFLE9BQU87UUFFMUIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDN0MsSUFBSSxDQUFDLEtBQUs7WUFBRSxPQUFPO1FBRW5CLHdCQUF3QjtRQUN4QixJQUFJLEtBQUssQ0FBQyxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUM7WUFDekIsS0FBSyxNQUFNLEdBQUcsSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUN0QyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDdkMsSUFBSSxPQUFPLEVBQUUsQ0FBQztvQkFDWixPQUFPLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO29CQUN4QixJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssQ0FBQyxFQUFFLENBQUM7d0JBQ3ZCLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO29CQUM1QixDQUFDO2dCQUNILENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUVELDRCQUE0QjtRQUM1QixNQUFNLFlBQVksR0FBRyxLQUFLLENBQUMsUUFBUSxFQUFFLFlBQVksSUFBSSxLQUFLLENBQUMsWUFBWSxJQUFJLGdCQUFnQixDQUFDLHFCQUFxQixDQUFDO1FBQ2xILE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQzNELElBQUksY0FBYyxFQUFFLENBQUM7WUFDbkIsY0FBYyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNqQyxDQUFDO1FBRUQsNEJBQTRCO1FBQzVCLElBQUksQ0FBQyxZQUFZLEVBQUUsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRXhDLDZCQUE2QjtRQUM3QixJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUV4QyxvQkFBb0I7UUFDcEIsSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFbEMsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUV4QixNQUFNLENBQUMsS0FBSyxDQUFDLDBCQUEwQixFQUFFLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDNUQsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLEtBQWtCLEVBQUUsT0FBaUM7UUFDMUQsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNsQixNQUFNLENBQUMsS0FBSyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7WUFDL0QsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztRQUMzQyxDQUFDO1FBRUQsZ0RBQWdEO1FBQ2hELElBQUksWUFBWSxHQUF1QixJQUFJLENBQUM7UUFFNUMsMEJBQTBCO1FBQzFCLElBQUksS0FBSyxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ3ZCLFlBQVksR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFDMUUsQ0FBQztRQUVELGdDQUFnQztRQUNoQyxJQUFJLEtBQUssQ0FBQyxJQUFJLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDeEMsTUFBTSxVQUFVLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztZQUNyQyxLQUFLLE1BQU0sR0FBRyxJQUFJLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztnQkFDN0IsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7Z0JBQ3JELElBQUksT0FBTyxFQUFFLENBQUM7b0JBQ1osSUFBSSxZQUFZLEVBQUUsQ0FBQzt3QkFDakIsd0NBQXdDO3dCQUN4QyxLQUFLLE1BQU0sRUFBRSxJQUFJLE9BQU8sRUFBRSxDQUFDOzRCQUN6QixJQUFJLFlBQVksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztnQ0FDekIsVUFBVSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQzs0QkFDckIsQ0FBQzt3QkFDSCxDQUFDO29CQUNILENBQUM7eUJBQU0sQ0FBQzt3QkFDTixlQUFlO3dCQUNmLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7b0JBQzVDLENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7WUFDRCxZQUFZLEdBQUcsVUFBVSxDQUFDO1FBQzVCLENBQUM7UUFFRCx1QkFBdUI7UUFDdkIsSUFBSSxLQUFLLENBQUMsUUFBUSxJQUFJLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNuQyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUNqRixJQUFJLFlBQVksRUFBRSxDQUFDO2dCQUNqQixlQUFlO2dCQUNmLE1BQU0sWUFBWSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7Z0JBQ3ZDLEtBQUssTUFBTSxFQUFFLElBQUksWUFBWSxFQUFFLENBQUM7b0JBQzlCLElBQUksV0FBVyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO3dCQUN4QixZQUFZLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO29CQUN2QixDQUFDO2dCQUNILENBQUM7Z0JBQ0QsWUFBWSxHQUFHLFlBQVksQ0FBQztZQUM5QixDQUFDO2lCQUFNLENBQUM7Z0JBQ04sWUFBWSxHQUFHLFdBQVcsQ0FBQztZQUM3QixDQUFDO1FBQ0gsQ0FBQztRQUVELCtCQUErQjtRQUMvQixNQUFNLGFBQWEsR0FBRyxLQUFLLENBQUMsT0FBTyxJQUFJLElBQUksQ0FBQyxZQUFZO1lBQ3RELENBQUMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDO1lBQ3pDLENBQUMsQ0FBQyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztRQUU5QixnQkFBZ0I7UUFDaEIsTUFBTSxPQUFPLEdBQW1CLEVBQUUsQ0FBQztRQUNuQyxNQUFNLGFBQWEsR0FBRyxZQUFZLElBQUksSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFFOUQsS0FBSyxNQUFNLEVBQUUsSUFBSSxhQUFhLEVBQUUsQ0FBQztZQUMvQixNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQzlCLElBQUksQ0FBQyxLQUFLO2dCQUFFLFNBQVM7WUFFckIsa0JBQWtCO1lBQ2xCLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztZQUVkLDBCQUEwQjtZQUMxQixJQUFJLGFBQWEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztnQkFDMUIsS0FBSyxJQUFJLGFBQWEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQ3RDLENBQUM7WUFFRCxrQkFBa0I7WUFDbEIsSUFBSSxLQUFLLENBQUMsSUFBSSxJQUFJLEtBQUssQ0FBQyxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUM7Z0JBQ3ZDLE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQzFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsSUFBSSxFQUFFLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FDcEMsQ0FBQztnQkFDRixLQUFLLElBQUksV0FBVyxDQUFDLE1BQU0sQ0FBQztZQUM5QixDQUFDO1lBRUQsT0FBTyxDQUFDLElBQUksQ0FBQztnQkFDWCxLQUFLO2dCQUNMLEtBQUs7Z0JBQ0wsT0FBTyxFQUFFO29CQUNQLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsSUFBSSxFQUFFLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztvQkFDcEUsS0FBSyxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVM7aUJBQy9DO2FBQ0YsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELHFDQUFxQztRQUNyQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFMUMsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sSUFBSSxDQUFDLENBQUM7UUFDakMsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUssSUFBSSxHQUFHLENBQUM7UUFFakMsT0FBTyxPQUFPLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVEOztPQUVHO0lBQ0ssWUFBWSxDQUFDLEtBQWtCLEVBQUUsT0FBaUM7UUFDeEUsTUFBTSxPQUFPLEdBQW1CLEVBQUUsQ0FBQztRQUVuQyxLQUFLLE1BQU0sQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLElBQUksT0FBTyxFQUFFLENBQUM7WUFDbEMsc0JBQXNCO1lBQ3RCLElBQUksS0FBSyxDQUFDLFlBQVksSUFBSSxLQUFLLENBQUMsUUFBUSxFQUFFLFlBQVksS0FBSyxLQUFLLENBQUMsWUFBWSxFQUFFLENBQUM7Z0JBQzlFLFNBQVM7WUFDWCxDQUFDO1lBRUQsbUJBQW1CO1lBQ25CLElBQUksS0FBSyxDQUFDLFFBQVEsSUFBSSxLQUFLLENBQUMsUUFBUSxFQUFFLFNBQVMsSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLFNBQVMsR0FBRyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQzdGLFNBQVM7WUFDWCxDQUFDO1lBQ0QsSUFBSSxLQUFLLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQyxRQUFRLEVBQUUsU0FBUyxJQUFJLEtBQUssQ0FBQyxRQUFRLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDekYsU0FBUztZQUNYLENBQUM7WUFFRCxhQUFhO1lBQ2IsSUFBSSxLQUFLLENBQUMsSUFBSSxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUN4QyxNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUN4QyxLQUFLLENBQUMsUUFBUSxFQUFFLElBQUksRUFBRSxRQUFRLENBQUMsR0FBRyxDQUFDLENBQ3BDLENBQUM7Z0JBQ0YsSUFBSSxDQUFDLFVBQVU7b0JBQUUsU0FBUztZQUM1QixDQUFDO1lBRUQseUNBQXlDO1lBQ3pDLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztZQUNkLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNsQixNQUFNLFVBQVUsR0FBRyxnQkFBZ0IsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUM3RCxJQUFJLFVBQVUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztvQkFDdkIsTUFBTSxVQUFVLEdBQUcsVUFBVSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsRUFBRSxDQUFDO29CQUM5RCxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7d0JBQ3JELEtBQUssSUFBSSxDQUFDLENBQUM7b0JBQ2IsQ0FBQztnQkFDSCxDQUFDO1lBQ0gsQ0FBQztZQUVELE9BQU8sQ0FBQyxJQUFJLENBQUM7Z0JBQ1gsS0FBSztnQkFDTCxLQUFLO2dCQUNMLE9BQU8sRUFBRTtvQkFDUCxJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLElBQUksRUFBRSxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUM7aUJBQ3JFO2FBQ0YsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELG9CQUFvQjtRQUNwQixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDMUMsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sSUFBSSxDQUFDLENBQUM7UUFDakMsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUssSUFBSSxHQUFHLENBQUM7UUFFakMsT0FBTyxPQUFPLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVEOztPQUVHO0lBQ0ssVUFBVSxDQUFDLEVBQVUsRUFBRSxLQUFrQjtRQUMvQyxjQUFjO1FBQ2QsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRWpDLG1CQUFtQjtRQUNuQixJQUFJLEtBQUssQ0FBQyxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUM7WUFDekIsS0FBSyxNQUFNLEdBQUcsSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUN0QyxNQUFNLGFBQWEsR0FBRyxHQUFHLENBQUMsV0FBVyxFQUFFLENBQUM7Z0JBQ3hDLElBQUksT0FBTyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUMvQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7b0JBQ2IsT0FBTyxHQUFHLElBQUksR0FBRyxFQUFFLENBQUM7b0JBQ3BCLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLGFBQWEsRUFBRSxPQUFPLENBQUMsQ0FBQztnQkFDNUMsQ0FBQztnQkFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ2xCLENBQUM7UUFDSCxDQUFDO1FBRUQsdUJBQXVCO1FBQ3ZCLE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxRQUFRLEVBQUUsWUFBWSxJQUFJLEtBQUssQ0FBQyxZQUFZLElBQUksZ0JBQWdCLENBQUMscUJBQXFCLENBQUM7UUFDbEgsSUFBSSxjQUFjLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDekQsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3BCLGNBQWMsR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO1lBQzNCLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxjQUFjLENBQUMsQ0FBQztRQUN0RCxDQUFDO1FBQ0QsY0FBYyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUV2Qix1QkFBdUI7UUFDdkIsSUFBSSxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDdEIsSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNoRCxDQUFDO1FBRUQsd0JBQXdCO1FBQ3hCLElBQUksQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUMsUUFBUSxFQUFFLFNBQVMsSUFBSSxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDaEYsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSztRQUNILElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDdEIsSUFBSSxDQUFDLFlBQVksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUMxQixJQUFJLENBQUMsWUFBWSxFQUFFLEtBQUssRUFBRSxDQUFDO1FBQzNCLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDM0IsSUFBSSxDQUFDLFlBQVksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUMxQixJQUFJLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQztRQUNyQixJQUFJLENBQUMsS0FBSyxHQUFHO1lBQ1gsU0FBUyxFQUFFLEtBQUs7WUFDaEIsVUFBVSxFQUFFLENBQUM7WUFDYixRQUFRLEVBQUUsQ0FBQztZQUNYLFNBQVMsRUFBRSxDQUFDO1NBQ2IsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNILFFBQVE7UUFDTixPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVEOztPQUVHO0lBQ0gsSUFBSSxTQUFTO1FBQ1gsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDO0lBQ3RCLENBQUM7SUFFRDs7O09BR0c7SUFDSyxpQkFBaUI7UUFDdkIsSUFBSSxVQUFVLEdBQUcsQ0FBQyxDQUFDO1FBRW5CLDRCQUE0QjtRQUM1QixLQUFLLE1BQU0sQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQzNDLFVBQVUsSUFBSSxHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLGtCQUFrQjtZQUNoRCxVQUFVLElBQUksT0FBTyxDQUFDLElBQUksR0FBRyxFQUFFLENBQUMsQ0FBQyxvQkFBb0I7UUFDdkQsQ0FBQztRQUVELGdDQUFnQztRQUNoQyxJQUFJLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUN0Qix3Q0FBd0M7WUFDeEMsVUFBVSxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxHQUFHLEdBQUcsQ0FBQztRQUM3QyxDQUFDO1FBRUQsaUNBQWlDO1FBQ2pDLFVBQVUsSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksR0FBRyxFQUFFLENBQUMsQ0FBQyxZQUFZO1FBRXhELHdCQUF3QjtRQUN4QixLQUFLLE1BQU0sS0FBSyxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQztZQUMvQyxVQUFVLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQ2pELENBQUM7UUFFRCxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsVUFBVSxDQUFDO1FBRW5DLHdDQUF3QztRQUN4QyxJQUFJLFVBQVUsR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDckMsTUFBTSxDQUFDLElBQUksQ0FBQyxxQ0FBcUMsRUFBRTtnQkFDakQsTUFBTSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7Z0JBQzVDLE9BQU8sRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQzthQUN2RCxDQUFDLENBQUM7WUFFSCxrQ0FBa0M7WUFDbEMsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLGlCQUFpQixFQUFFLENBQUM7Z0JBQ2xDLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUN6QixDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSyxlQUFlO1FBQ3JCLCtEQUErRDtRQUMvRCx1Q0FBdUM7UUFDdkMsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQztRQUNoRSxNQUFNLFlBQVksR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUUxRCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsY0FBYyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDeEMsTUFBTSxTQUFTLEdBQUcsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ2xDLElBQUksQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDOUIsQ0FBQztRQUVELE1BQU0sQ0FBQyxJQUFJLENBQUMscUJBQXFCLEVBQUU7WUFDakMsWUFBWSxFQUFFLGNBQWM7WUFDNUIsY0FBYyxFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSTtTQUN2QyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsU0FBUztRQUNQLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDbEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFFRCxNQUFNLFNBQVMsR0FBRztZQUNoQixPQUFPLEVBQUUsT0FBTztZQUNoQixLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7WUFDakIsUUFBUSxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO2dCQUNqRSxHQUFHO2dCQUNILEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQzthQUNyQixDQUFDLENBQUM7WUFDSCxZQUFZLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQzNFLEtBQUs7Z0JBQ0wsR0FBRyxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDO2FBQ3JCLENBQUMsQ0FBQztZQUNILGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLFNBQVMsRUFBRTtZQUM3QyxvREFBb0Q7WUFDcEQsdUNBQXVDO1NBQ3hDLENBQUM7UUFFRixPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUVEOzs7T0FHRztJQUNILFdBQVcsQ0FBQyxJQUFZLEVBQUUsT0FBaUM7UUFDekQsSUFBSSxDQUFDO1lBQ0gsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUVuQyxtQkFBbUI7WUFDbkIsSUFBSSxTQUFTLENBQUMsT0FBTyxLQUFLLE9BQU8sRUFBRSxDQUFDO2dCQUNsQyxNQUFNLElBQUksS0FBSyxDQUFDLDhCQUE4QixTQUFTLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUNyRSxDQUFDO1lBRUQseUJBQXlCO1lBQ3pCLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUViLG9CQUFvQjtZQUNwQixLQUFLLE1BQU0sRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLElBQUksU0FBUyxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUM5QyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsSUFBSSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUN2QyxDQUFDO1lBRUQsd0JBQXdCO1lBQ3hCLEtBQUssTUFBTSxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsSUFBSSxTQUFTLENBQUMsWUFBWSxFQUFFLENBQUM7Z0JBQ3BELElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLEtBQXFCLEVBQUUsSUFBSSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUM3RCxDQUFDO1lBRUQseUJBQXlCO1lBQ3pCLElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUV4RCw4Q0FBOEM7WUFDOUMsS0FBSyxNQUFNLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxJQUFJLE9BQU8sRUFBRSxDQUFDO2dCQUNsQyxJQUFJLFNBQVMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBUyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUM7b0JBQ2xFLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztnQkFDbkMsQ0FBQztZQUNILENBQUM7WUFFRCxpRUFBaUU7WUFDakUsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixFQUFFLENBQUM7Z0JBQ25DLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxZQUFZLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUNsRCxLQUFLLE1BQU0sQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO29CQUM1QyxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUNoRCxDQUFDO1lBQ0gsQ0FBQztZQUVELGVBQWU7WUFDZixJQUFJLENBQUMsS0FBSyxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUM7WUFDN0IsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7WUFFcEIsTUFBTSxDQUFDLElBQUksQ0FBQyxrQ0FBa0MsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDOUQsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLHlDQUF5QyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQy9ELHFDQUFxQztZQUNyQyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzNCLENBQUM7SUFDSCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1lbW9yeSBTZWFyY2ggSW5kZXggLSBIaWdoLXBlcmZvcm1hbmNlIGluZGV4ZWQgc2VhcmNoIGZvciBNZW1vcnkgZWxlbWVudHNcbiAqXG4gKiBBZGRyZXNzZXMgaXNzdWUgIzk4NDogSW1wbGVtZW50IHNlYXJjaCBpbmRleGluZyBmb3IgTWVtb3J5IGVsZW1lbnQgc2NhbGFiaWxpdHlcbiAqXG4gKiBGZWF0dXJlczpcbiAqIC0gVGFnIGluZGV4IGZvciBPKDEpIHRhZy1iYXNlZCBxdWVyaWVzXG4gKiAtIENvbnRlbnQgaW5kZXggdXNpbmcgaW52ZXJ0ZWQgaW5kZXggcGF0dGVyblxuICogLSBUZW1wb3JhbCBpbmRleCBmb3IgZGF0ZSByYW5nZSBxdWVyaWVzXG4gKiAtIFByaXZhY3kgbGV2ZWwgaW5kZXggZm9yIGZpbHRlcmVkIGFjY2Vzc1xuICogLSBJbmNyZW1lbnRhbCBpbmRleCB1cGRhdGVzXG4gKiAtIE9wdGlvbmFsIHBlcnNpc3RlbmNlXG4gKiAtIENvbmZpZ3VyYWJsZSB0aHJlc2hvbGRzXG4gKi9cblxuaW1wb3J0IHsgTWVtb3J5RW50cnkgfSBmcm9tICcuL01lbW9yeS5qcyc7XG5pbXBvcnQgeyBQcml2YWN5TGV2ZWwsIE1FTU9SWV9DT05TVEFOVFMsIE1FTU9SWV9TRUNVUklUWV9FVkVOVFMgfSBmcm9tICcuL2NvbnN0YW50cy5qcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi8uLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgVW5pY29kZVZhbGlkYXRvciB9IGZyb20gJy4uLy4uL3NlY3VyaXR5L3ZhbGlkYXRvcnMvdW5pY29kZVZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi8uLi9zZWN1cml0eS9zZWN1cml0eU1vbml0b3IuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFNlYXJjaEluZGV4Q29uZmlnIHtcbiAgLyoqXG4gICAqIEVuYWJsZSBpbmRleGluZyB3aGVuIG1lbW9yeSBoYXMgbW9yZSB0aGFuIHRoaXMgbWFueSBlbnRyaWVzXG4gICAqIERlZmF1bHQ6IDEwMFxuICAgKi9cbiAgaW5kZXhUaHJlc2hvbGQ/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIEVuYWJsZSBjb250ZW50IGluZGV4IChtb3JlIG1lbW9yeSBpbnRlbnNpdmUpXG4gICAqIERlZmF1bHQ6IHRydWVcbiAgICovXG4gIGVuYWJsZUNvbnRlbnRJbmRleD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIE1heGltdW0gbnVtYmVyIG9mIHRlcm1zIHRvIGluZGV4IHBlciBlbnRyeVxuICAgKiBEZWZhdWx0OiAxMDBcbiAgICovXG4gIG1heFRlcm1zUGVyRW50cnk/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIE1pbmltdW0gdGVybSBsZW5ndGggdG8gaW5kZXhcbiAgICogRGVmYXVsdDogMlxuICAgKi9cbiAgbWluVGVybUxlbmd0aD86IG51bWJlcjtcblxuICAvKipcbiAgICogRW5hYmxlIGluZGV4IHBlcnNpc3RlbmNlIHRvIGRpc2tcbiAgICogRGVmYXVsdDogZmFsc2VcbiAgICovXG4gIGVuYWJsZVBlcnNpc3RlbmNlPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogTWF4aW11bSBtZW1vcnkgdXNhZ2UgaW4gTUJcbiAgICogRGVmYXVsdDogMTAwXG4gICAqL1xuICBtYXhNZW1vcnlNQj86IG51bWJlcjtcblxuICAvKipcbiAgICogRW5hYmxlIExSVSBldmljdGlvbiB3aGVuIG1lbW9yeSBsaW1pdCBpcyByZWFjaGVkXG4gICAqIERlZmF1bHQ6IHRydWVcbiAgICovXG4gIGVuYWJsZUxSVUV2aWN0aW9uPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTZWFyY2hJbmRleFN0YXRzIHtcbiAgaXNJbmRleGVkOiBib29sZWFuO1xuICBlbnRyeUNvdW50OiBudW1iZXI7XG4gIHRhZ0NvdW50OiBudW1iZXI7XG4gIHRlcm1Db3VudDogbnVtYmVyO1xuICBsYXN0QnVpbHQ/OiBEYXRlO1xuICBidWlsZFRpbWVNcz86IG51bWJlcjtcbiAgbWVtb3J5VXNhZ2VCeXRlcz86IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTZWFyY2hRdWVyeSB7XG4gIHRhZ3M/OiBzdHJpbmdbXTtcbiAgY29udGVudD86IHN0cmluZztcbiAgZGF0ZUZyb20/OiBEYXRlO1xuICBkYXRlVG8/OiBEYXRlO1xuICBwcml2YWN5TGV2ZWw/OiBQcml2YWN5TGV2ZWw7XG4gIGxpbWl0PzogbnVtYmVyO1xuICBvZmZzZXQ/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2VhcmNoUmVzdWx0IHtcbiAgZW50cnk6IE1lbW9yeUVudHJ5O1xuICBzY29yZTogbnVtYmVyO1xuICBtYXRjaGVzOiB7XG4gICAgdGFncz86IHN0cmluZ1tdO1xuICAgIHRlcm1zPzogc3RyaW5nW107XG4gIH07XG59XG5cbi8qKlxuICogSW52ZXJ0ZWQgaW5kZXggZm9yIGNvbnRlbnQgc2VhcmNoXG4gKi9cbmNsYXNzIENvbnRlbnRJbmRleCB7XG4gIHByaXZhdGUgdGVybVRvRW50cmllcyA9IG5ldyBNYXA8c3RyaW5nLCBTZXQ8c3RyaW5nPj4oKTtcbiAgcHJpdmF0ZSBlbnRyeVRvVGVybXMgPSBuZXcgTWFwPHN0cmluZywgU2V0PHN0cmluZz4+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgY29uZmlnOiBTZWFyY2hJbmRleENvbmZpZztcblxuICBjb25zdHJ1Y3Rvcihjb25maWc6IFNlYXJjaEluZGV4Q29uZmlnKSB7XG4gICAgdGhpcy5jb25maWcgPSBjb25maWc7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGFuIGVudHJ5IHRvIHRoZSBjb250ZW50IGluZGV4XG4gICAqL1xuICBhZGRFbnRyeShlbnRyeUlkOiBzdHJpbmcsIGNvbnRlbnQ6IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnN0IHRlcm1zID0gdGhpcy5leHRyYWN0VGVybXMoY29udGVudCwgeyBlbnRyeUlkIH0pO1xuXG4gICAgLy8gU3RvcmUgdGVybXMgZm9yIHRoaXMgZW50cnlcbiAgICB0aGlzLmVudHJ5VG9UZXJtcy5zZXQoZW50cnlJZCwgdGVybXMpO1xuXG4gICAgLy8gVXBkYXRlIGludmVydGVkIGluZGV4XG4gICAgZm9yIChjb25zdCB0ZXJtIG9mIHRlcm1zKSB7XG4gICAgICBsZXQgZW50cmllcyA9IHRoaXMudGVybVRvRW50cmllcy5nZXQodGVybSk7XG4gICAgICBpZiAoIWVudHJpZXMpIHtcbiAgICAgICAgZW50cmllcyA9IG5ldyBTZXQoKTtcbiAgICAgICAgdGhpcy50ZXJtVG9FbnRyaWVzLnNldCh0ZXJtLCBlbnRyaWVzKTtcbiAgICAgIH1cbiAgICAgIGVudHJpZXMuYWRkKGVudHJ5SWQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgYW4gZW50cnkgZnJvbSB0aGUgaW5kZXhcbiAgICovXG4gIHJlbW92ZUVudHJ5KGVudHJ5SWQ6IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnN0IHRlcm1zID0gdGhpcy5lbnRyeVRvVGVybXMuZ2V0KGVudHJ5SWQpO1xuICAgIGlmICghdGVybXMpIHJldHVybjtcblxuICAgIC8vIFJlbW92ZSBmcm9tIGludmVydGVkIGluZGV4XG4gICAgZm9yIChjb25zdCB0ZXJtIG9mIHRlcm1zKSB7XG4gICAgICBjb25zdCBlbnRyaWVzID0gdGhpcy50ZXJtVG9FbnRyaWVzLmdldCh0ZXJtKTtcbiAgICAgIGlmIChlbnRyaWVzKSB7XG4gICAgICAgIGVudHJpZXMuZGVsZXRlKGVudHJ5SWQpO1xuICAgICAgICBpZiAoZW50cmllcy5zaXplID09PSAwKSB7XG4gICAgICAgICAgdGhpcy50ZXJtVG9FbnRyaWVzLmRlbGV0ZSh0ZXJtKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFJlbW92ZSBlbnRyeSB0ZXJtc1xuICAgIHRoaXMuZW50cnlUb1Rlcm1zLmRlbGV0ZShlbnRyeUlkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZWFyY2ggZm9yIGVudHJpZXMgY29udGFpbmluZyBxdWVyeSB0ZXJtc1xuICAgKi9cbiAgc2VhcmNoKHF1ZXJ5OiBzdHJpbmcpOiBNYXA8c3RyaW5nLCBudW1iZXI+IHtcbiAgICBjb25zdCBxdWVyeVRlcm1zID0gdGhpcy5leHRyYWN0VGVybXMocXVlcnkpO1xuICAgIGNvbnN0IHNjb3JlcyA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG5cbiAgICBmb3IgKGNvbnN0IHRlcm0gb2YgcXVlcnlUZXJtcykge1xuICAgICAgY29uc3QgZW50cmllcyA9IHRoaXMudGVybVRvRW50cmllcy5nZXQodGVybSk7XG4gICAgICBpZiAoZW50cmllcykge1xuICAgICAgICBmb3IgKGNvbnN0IGVudHJ5SWQgb2YgZW50cmllcykge1xuICAgICAgICAgIHNjb3Jlcy5zZXQoZW50cnlJZCwgKHNjb3Jlcy5nZXQoZW50cnlJZCkgfHwgMCkgKyAxKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBzY29yZXM7XG4gIH1cblxuICAvKipcbiAgICogRXh0cmFjdCBzZWFyY2hhYmxlIHRlcm1zIGZyb20gY29udGVudFxuICAgKiBTRUNVUklUWSBGSVg6IEFkZGVkIGF1ZGl0IGxvZ2dpbmcgZm9yIFVuaWNvZGUgdmFsaWRhdGlvbiBvcGVyYXRpb25zXG4gICAqL1xuICBwcml2YXRlIGV4dHJhY3RUZXJtcyhjb250ZW50OiBzdHJpbmcsIGNvbnRleHQ/OiB7IGVudHJ5SWQ/OiBzdHJpbmcgfSk6IFNldDxzdHJpbmc+IHtcbiAgICAvLyBOb3JtYWxpemUgZm9yIHNlY3VyaXR5XG4gICAgY29uc3Qgbm9ybWFsaXplZCA9IFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKGNvbnRlbnQpO1xuICAgIGlmICghbm9ybWFsaXplZC5pc1ZhbGlkKSB7XG4gICAgICBsb2dnZXIud2FybignSW52YWxpZCBVbmljb2RlIGluIGNvbnRlbnQgZm9yIGluZGV4aW5nJywge1xuICAgICAgICBlbnRyeUlkOiBjb250ZXh0Py5lbnRyeUlkXG4gICAgICB9KTtcblxuICAgICAgLy8gU0VDVVJJVFkgRklYOiBMb2cgc2VjdXJpdHkgZXZlbnQgZm9yIGF1ZGl0IHRyYWlsIChETUNQLVNFQy0wMDYpXG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6IE1FTU9SWV9TRUNVUklUWV9FVkVOVFMuTUVNT1JZX1VOSUNPREVfVkFMSURBVElPTl9GQUlMRUQsXG4gICAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgICAgc291cmNlOiAnTWVtb3J5U2VhcmNoSW5kZXguZXh0cmFjdFRlcm1zJyxcbiAgICAgICAgZGV0YWlsczogYEludmFsaWQgVW5pY29kZSBkZXRlY3RlZCBkdXJpbmcgdGVybSBleHRyYWN0aW9uJHtjb250ZXh0Py5lbnRyeUlkID8gYCBmb3IgZW50cnkgJHtjb250ZXh0LmVudHJ5SWR9YCA6ICcnfWAsXG4gICAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgICAgZW50cnlJZDogY29udGV4dD8uZW50cnlJZCxcbiAgICAgICAgICBpc3N1ZUNvdW50OiAwICAvLyBVbmljb2RlVmFsaWRhdGlvblJlc3VsdCBkb2Vzbid0IGV4cG9zZSBpc3N1ZXNcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiBuZXcgU2V0KCk7XG4gICAgfVxuXG4gICAgY29uc3QgdGV4dCA9IG5vcm1hbGl6ZWQubm9ybWFsaXplZENvbnRlbnQudG9Mb3dlckNhc2UoKTtcbiAgICBjb25zdCB0ZXJtcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gICAgLy8gU2ltcGxlIHRva2VuaXphdGlvbiAoY2FuIGJlIGltcHJvdmVkIHdpdGggYmV0dGVyIE5MUClcbiAgICBjb25zdCB3b3JkcyA9IHRleHQubWF0Y2goL1xcYlxcdytcXGIvZykgfHwgW107XG5cbiAgICBsZXQgdGVybUNvdW50ID0gMDtcbiAgICBmb3IgKGNvbnN0IHdvcmQgb2Ygd29yZHMpIHtcbiAgICAgIGlmICh3b3JkLmxlbmd0aCA+PSAodGhpcy5jb25maWcubWluVGVybUxlbmd0aCB8fCAyKSkge1xuICAgICAgICB0ZXJtcy5hZGQod29yZCk7XG4gICAgICAgIHRlcm1Db3VudCsrO1xuICAgICAgICBpZiAodGVybUNvdW50ID49ICh0aGlzLmNvbmZpZy5tYXhUZXJtc1BlckVudHJ5IHx8IDEwMCkpIHtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0ZXJtcztcbiAgfVxuXG4gIGNsZWFyKCk6IHZvaWQge1xuICAgIHRoaXMudGVybVRvRW50cmllcy5jbGVhcigpO1xuICAgIHRoaXMuZW50cnlUb1Rlcm1zLmNsZWFyKCk7XG4gIH1cblxuICBnZXQgc2l6ZSgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnRlcm1Ub0VudHJpZXMuc2l6ZTtcbiAgfVxufVxuXG4vKipcbiAqIERhdGUgcmFuZ2UgaW5kZXggdXNpbmcgc29ydGVkIGFycmF5IGZvciBlZmZpY2llbnQgcmFuZ2UgcXVlcmllc1xuICovXG5jbGFzcyBUZW1wb3JhbEluZGV4IHtcbiAgcHJpdmF0ZSBlbnRyaWVzOiBBcnJheTx7IGlkOiBzdHJpbmc7IHRpbWVzdGFtcDogbnVtYmVyIH0+ID0gW107XG5cbiAgYWRkRW50cnkoZW50cnlJZDogc3RyaW5nLCBkYXRlOiBEYXRlKTogdm9pZCB7XG4gICAgY29uc3QgdGltZXN0YW1wID0gZGF0ZS5nZXRUaW1lKCk7XG5cbiAgICAvLyBCaW5hcnkgc2VhcmNoIGZvciBpbnNlcnRpb24gcG9pbnRcbiAgICBsZXQgbGVmdCA9IDA7XG4gICAgbGV0IHJpZ2h0ID0gdGhpcy5lbnRyaWVzLmxlbmd0aDtcblxuICAgIHdoaWxlIChsZWZ0IDwgcmlnaHQpIHtcbiAgICAgIGNvbnN0IG1pZCA9IE1hdGguZmxvb3IoKGxlZnQgKyByaWdodCkgLyAyKTtcbiAgICAgIGlmICh0aGlzLmVudHJpZXNbbWlkXS50aW1lc3RhbXAgPCB0aW1lc3RhbXApIHtcbiAgICAgICAgbGVmdCA9IG1pZCArIDE7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByaWdodCA9IG1pZDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBJbnNlcnQgYXQgY29ycmVjdCBwb3NpdGlvbiB0byBtYWludGFpbiBzb3J0XG4gICAgdGhpcy5lbnRyaWVzLnNwbGljZShsZWZ0LCAwLCB7IGlkOiBlbnRyeUlkLCB0aW1lc3RhbXAgfSk7XG4gIH1cblxuICByZW1vdmVFbnRyeShlbnRyeUlkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBpbmRleCA9IHRoaXMuZW50cmllcy5maW5kSW5kZXgoZSA9PiBlLmlkID09PSBlbnRyeUlkKTtcbiAgICBpZiAoaW5kZXggPj0gMCkge1xuICAgICAgdGhpcy5lbnRyaWVzLnNwbGljZShpbmRleCwgMSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEZpbmQgZW50cmllcyB3aXRoaW4gZGF0ZSByYW5nZVxuICAgKi9cbiAgc2VhcmNoUmFuZ2UoZnJvbT86IERhdGUsIHRvPzogRGF0ZSk6IFNldDxzdHJpbmc+IHtcbiAgICBjb25zdCByZXN1bHRzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgY29uc3QgZnJvbVRpbWUgPSBmcm9tPy5nZXRUaW1lKCkgfHwgMDtcbiAgICBjb25zdCB0b1RpbWUgPSB0bz8uZ2V0VGltZSgpIHx8IERhdGUubm93KCk7XG5cbiAgICAvLyBCaW5hcnkgc2VhcmNoIGZvciBzdGFydFxuICAgIGxldCBzdGFydCA9IDA7XG4gICAgbGV0IGVuZCA9IHRoaXMuZW50cmllcy5sZW5ndGg7XG5cbiAgICB3aGlsZSAoc3RhcnQgPCBlbmQpIHtcbiAgICAgIGNvbnN0IG1pZCA9IE1hdGguZmxvb3IoKHN0YXJ0ICsgZW5kKSAvIDIpO1xuICAgICAgaWYgKHRoaXMuZW50cmllc1ttaWRdLnRpbWVzdGFtcCA8IGZyb21UaW1lKSB7XG4gICAgICAgIHN0YXJ0ID0gbWlkICsgMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGVuZCA9IG1pZDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDb2xsZWN0IGFsbCBlbnRyaWVzIGluIHJhbmdlXG4gICAgZm9yIChsZXQgaSA9IHN0YXJ0OyBpIDwgdGhpcy5lbnRyaWVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBlbnRyeSA9IHRoaXMuZW50cmllc1tpXTtcbiAgICAgIGlmIChlbnRyeS50aW1lc3RhbXAgPiB0b1RpbWUpIGJyZWFrO1xuICAgICAgcmVzdWx0cy5hZGQoZW50cnkuaWQpO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG5cbiAgY2xlYXIoKTogdm9pZCB7XG4gICAgdGhpcy5lbnRyaWVzID0gW107XG4gIH1cblxuICBnZXQgc2l6ZSgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmVudHJpZXMubGVuZ3RoO1xuICB9XG5cbiAgc2VyaWFsaXplKCk6IGFueSB7XG4gICAgcmV0dXJuIHRoaXMuZW50cmllcztcbiAgfVxuXG4gIGRlc2VyaWFsaXplKGRhdGE6IGFueSk6IHZvaWQge1xuICAgIHRoaXMuZW50cmllcyA9IGRhdGEgfHwgW107XG4gIH1cbn1cblxuLyoqXG4gKiBNYWluIHNlYXJjaCBpbmRleCBmb3IgTWVtb3J5IGVsZW1lbnRzXG4gKi9cbmV4cG9ydCBjbGFzcyBNZW1vcnlTZWFyY2hJbmRleCB7XG4gIHByaXZhdGUgcmVhZG9ubHkgY29uZmlnOiBTZWFyY2hJbmRleENvbmZpZztcblxuICAvLyBJbmRleGVzXG4gIHByaXZhdGUgdGFnSW5kZXggPSBuZXcgTWFwPHN0cmluZywgU2V0PHN0cmluZz4+KCk7XG4gIHByaXZhdGUgcHJpdmFjeUluZGV4ID0gbmV3IE1hcDxQcml2YWN5TGV2ZWwsIFNldDxzdHJpbmc+PigpO1xuICBwcml2YXRlIGNvbnRlbnRJbmRleDogQ29udGVudEluZGV4IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgdGVtcG9yYWxJbmRleCA9IG5ldyBUZW1wb3JhbEluZGV4KCk7XG5cbiAgLy8gQ2FjaGVkIGVudHJpZXMgZm9yIHNjb3JpbmdcbiAgcHJpdmF0ZSBlbnRyaWVzQ2FjaGUgPSBuZXcgTWFwPHN0cmluZywgTWVtb3J5RW50cnk+KCk7XG5cbiAgLy8gSW5kZXggc3RhdGVcbiAgcHJpdmF0ZSBpc0J1aWx0ID0gZmFsc2U7XG4gIHByaXZhdGUgaXNCdWlsZGluZyA9IGZhbHNlO1xuICBwcml2YXRlIGJ1aWxkUXVldWU6IFByb21pc2U8dm9pZD4gfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBzdGF0czogU2VhcmNoSW5kZXhTdGF0cyA9IHtcbiAgICBpc0luZGV4ZWQ6IGZhbHNlLFxuICAgIGVudHJ5Q291bnQ6IDAsXG4gICAgdGFnQ291bnQ6IDAsXG4gICAgdGVybUNvdW50OiAwLFxuICAgIG1lbW9yeVVzYWdlQnl0ZXM6IDBcbiAgfTtcblxuICAvLyBNZW1vcnkgbWFuYWdlbWVudFxuICBwcml2YXRlIHJlYWRvbmx5IG1heE1lbW9yeUJ5dGVzOiBudW1iZXI7XG4gIHByaXZhdGUgbWVtb3J5VXNhZ2VCeXRlcyA9IDA7XG5cbiAgY29uc3RydWN0b3IoY29uZmlnOiBTZWFyY2hJbmRleENvbmZpZyA9IHt9KSB7XG4gICAgdGhpcy5jb25maWcgPSB7XG4gICAgICBpbmRleFRocmVzaG9sZDogY29uZmlnLmluZGV4VGhyZXNob2xkIHx8IDEwMCxcbiAgICAgIGVuYWJsZUNvbnRlbnRJbmRleDogY29uZmlnLmVuYWJsZUNvbnRlbnRJbmRleCAhPT0gZmFsc2UsXG4gICAgICBtYXhUZXJtc1BlckVudHJ5OiBjb25maWcubWF4VGVybXNQZXJFbnRyeSB8fCAxMDAsXG4gICAgICBtaW5UZXJtTGVuZ3RoOiBjb25maWcubWluVGVybUxlbmd0aCB8fCAyLFxuICAgICAgZW5hYmxlUGVyc2lzdGVuY2U6IGNvbmZpZy5lbmFibGVQZXJzaXN0ZW5jZSB8fCBmYWxzZSxcbiAgICAgIG1heE1lbW9yeU1COiBjb25maWcubWF4TWVtb3J5TUIgfHwgMTAwLFxuICAgICAgZW5hYmxlTFJVRXZpY3Rpb246IGNvbmZpZy5lbmFibGVMUlVFdmljdGlvbiAhPT0gZmFsc2VcbiAgICB9O1xuXG4gICAgLy8gQ29uZmlndXJlIG1lbW9yeSBsaW1pdCAoZGVmYXVsdCAxMDBNQiwgY29uZmlndXJhYmxlKVxuICAgIHRoaXMubWF4TWVtb3J5Qnl0ZXMgPSAodGhpcy5jb25maWcubWF4TWVtb3J5TUIgfHwgMTAwKSAqIDEwMjQgKiAxMDI0O1xuXG4gICAgaWYgKHRoaXMuY29uZmlnLmVuYWJsZUNvbnRlbnRJbmRleCkge1xuICAgICAgdGhpcy5jb250ZW50SW5kZXggPSBuZXcgQ29udGVudEluZGV4KHRoaXMuY29uZmlnKTtcbiAgICB9XG5cbiAgICBsb2dnZXIuZGVidWcoJ01lbW9yeVNlYXJjaEluZGV4IGNyZWF0ZWQnLCB0aGlzLmNvbmZpZyk7XG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgb3IgcmVidWlsZCB0aGUgaW5kZXggZnJvbSBlbnRyaWVzXG4gICAqIEZJWDogQWRkZWQgcmFjZSBjb25kaXRpb24gcHJvdGVjdGlvbiB3aXRoIGlzQnVpbGRpbmcgZmxhZyBhbmQgYnVpbGQgcXVldWVcbiAgICovXG4gIGFzeW5jIGJ1aWxkSW5kZXgoZW50cmllczogTWFwPHN0cmluZywgTWVtb3J5RW50cnk+KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gSWYgYWxyZWFkeSBidWlsZGluZywgd2FpdCBmb3IgdGhlIGN1cnJlbnQgYnVpbGQgdG8gY29tcGxldGVcbiAgICBpZiAodGhpcy5pc0J1aWxkaW5nICYmIHRoaXMuYnVpbGRRdWV1ZSkge1xuICAgICAgbG9nZ2VyLmRlYnVnKCdJbmRleCBidWlsZCBhbHJlYWR5IGluIHByb2dyZXNzLCB3YWl0aW5nLi4uJyk7XG4gICAgICByZXR1cm4gdGhpcy5idWlsZFF1ZXVlO1xuICAgIH1cblxuICAgIC8vIENyZWF0ZSBidWlsZCBwcm9taXNlIHRvIGhhbmRsZSBjb25jdXJyZW50IGNhbGxzXG4gICAgdGhpcy5idWlsZFF1ZXVlID0gdGhpcy5fZG9CdWlsZEluZGV4KGVudHJpZXMpO1xuICAgIHJldHVybiB0aGlzLmJ1aWxkUXVldWU7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIF9kb0J1aWxkSW5kZXgoZW50cmllczogTWFwPHN0cmluZywgTWVtb3J5RW50cnk+KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gUHJldmVudCBjb25jdXJyZW50IGJ1aWxkc1xuICAgIGlmICh0aGlzLmlzQnVpbGRpbmcpIHtcbiAgICAgIGxvZ2dlci53YXJuKCdBdHRlbXB0ZWQgY29uY3VycmVudCBpbmRleCBidWlsZCwgc2tpcHBpbmcnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmlzQnVpbGRpbmcgPSB0cnVlO1xuICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG5cbiAgICB0cnkge1xuICAgICAgLy8gQ2xlYXIgZXhpc3RpbmcgaW5kZXhlc1xuICAgICAgdGhpcy5jbGVhcigpO1xuXG4gICAgICAvLyBDaGVjayBpZiB3ZSBzaG91bGQgaW5kZXggYmFzZWQgb24gdGhyZXNob2xkXG4gICAgICBpZiAoZW50cmllcy5zaXplIDwgKHRoaXMuY29uZmlnLmluZGV4VGhyZXNob2xkIHx8IDEwMCkpIHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKCdOb3QgYnVpbGRpbmcgaW5kZXggLSBiZWxvdyB0aHJlc2hvbGQnLCB7XG4gICAgICAgICAgZW50cnlDb3VudDogZW50cmllcy5zaXplLFxuICAgICAgICAgIHRocmVzaG9sZDogdGhpcy5jb25maWcuaW5kZXhUaHJlc2hvbGRcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgLy8gQnVpbGQgaW5kZXhlc1xuICAgICAgZm9yIChjb25zdCBbaWQsIGVudHJ5XSBvZiBlbnRyaWVzKSB7XG4gICAgICAgIHRoaXMuYWRkVG9JbmRleChpZCwgZW50cnkpO1xuICAgICAgfVxuXG4gICAgICAvLyBDYWxjdWxhdGUgbWVtb3J5IHVzYWdlXG4gICAgICB0aGlzLnVwZGF0ZU1lbW9yeVVzYWdlKCk7XG5cbiAgICAgIC8vIFNFQ1VSSVRZIEZJWDogTG9nIHNlY3VyaXR5IGV2ZW50IGZvciBpbmRleCBidWlsZCBvcGVyYXRpb24gKERNQ1AtU0VDLTAwNilcbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogTUVNT1JZX1NFQ1VSSVRZX0VWRU5UUy5NRU1PUllfQ1JFQVRFRCBhcyBhbnksICAvLyBVc2luZyBDUkVBVEVEIGZvciBpbmRleCBidWlsZFxuICAgICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICAgIHNvdXJjZTogJ01lbW9yeVNlYXJjaEluZGV4LmJ1aWxkSW5kZXgnLFxuICAgICAgICBkZXRhaWxzOiBgTWVtb3J5IHNlYXJjaCBpbmRleCBidWlsdCBzdWNjZXNzZnVsbHkgd2l0aCAke2VudHJpZXMuc2l6ZX0gZW50cmllc2AsXG4gICAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgICAgZW50cnlDb3VudDogZW50cmllcy5zaXplLFxuICAgICAgICAgIHRhZ0NvdW50OiB0aGlzLnRhZ0luZGV4LnNpemUsXG4gICAgICAgICAgbWVtb3J5VXNhZ2VCeXRlczogdGhpcy5tZW1vcnlVc2FnZUJ5dGVzXG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICAvLyBVcGRhdGUgc3RhdHNcbiAgICAgIGNvbnN0IGJ1aWxkVGltZSA9IERhdGUubm93KCkgLSBzdGFydFRpbWU7XG4gICAgICB0aGlzLnN0YXRzID0ge1xuICAgICAgICBpc0luZGV4ZWQ6IHRydWUsXG4gICAgICAgIGVudHJ5Q291bnQ6IGVudHJpZXMuc2l6ZSxcbiAgICAgICAgdGFnQ291bnQ6IHRoaXMudGFnSW5kZXguc2l6ZSxcbiAgICAgICAgdGVybUNvdW50OiB0aGlzLmNvbnRlbnRJbmRleD8uc2l6ZSB8fCAwLFxuICAgICAgICBsYXN0QnVpbHQ6IG5ldyBEYXRlKCksXG4gICAgICAgIGJ1aWxkVGltZU1zOiBidWlsZFRpbWUsXG4gICAgICAgIG1lbW9yeVVzYWdlQnl0ZXM6IHRoaXMubWVtb3J5VXNhZ2VCeXRlc1xuICAgICAgfTtcblxuICAgICAgdGhpcy5pc0J1aWx0ID0gdHJ1ZTtcblxuICAgICAgbG9nZ2VyLmluZm8oJ01lbW9yeSBzZWFyY2ggaW5kZXggYnVpbHQnLCB0aGlzLnN0YXRzKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdGYWlsZWQgdG8gYnVpbGQgbWVtb3J5IHNlYXJjaCBpbmRleCcsIGVycm9yKTtcbiAgICAgIC8vIFJlc2V0IHN0YXRlIG9uIGZhaWx1cmVcbiAgICAgIHRoaXMuY2xlYXIoKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLmlzQnVpbGRpbmcgPSBmYWxzZTtcbiAgICAgIHRoaXMuYnVpbGRRdWV1ZSA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIHNpbmdsZSBlbnRyeSB0byB0aGUgaW5kZXggKGluY3JlbWVudGFsIHVwZGF0ZSlcbiAgICovXG4gIGFkZEVudHJ5KGVudHJ5OiBNZW1vcnlFbnRyeSk6IHZvaWQge1xuICAgIGlmICghdGhpcy5pc0J1aWx0KSByZXR1cm47XG5cbiAgICB0aGlzLmFkZFRvSW5kZXgoZW50cnkuaWQsIGVudHJ5KTtcbiAgICB0aGlzLnN0YXRzLmVudHJ5Q291bnQrKztcblxuICAgIGxvZ2dlci5kZWJ1ZygnRW50cnkgYWRkZWQgdG8gaW5kZXgnLCB7IGlkOiBlbnRyeS5pZCB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgYW4gZW50cnkgZnJvbSB0aGUgaW5kZXhcbiAgICovXG4gIHJlbW92ZUVudHJ5KGVudHJ5SWQ6IHN0cmluZyk6IHZvaWQge1xuICAgIGlmICghdGhpcy5pc0J1aWx0KSByZXR1cm47XG5cbiAgICBjb25zdCBlbnRyeSA9IHRoaXMuZW50cmllc0NhY2hlLmdldChlbnRyeUlkKTtcbiAgICBpZiAoIWVudHJ5KSByZXR1cm47XG5cbiAgICAvLyBSZW1vdmUgZnJvbSB0YWcgaW5kZXhcbiAgICBpZiAoZW50cnkubWV0YWRhdGE/LnRhZ3MpIHtcbiAgICAgIGZvciAoY29uc3QgdGFnIG9mIGVudHJ5Lm1ldGFkYXRhLnRhZ3MpIHtcbiAgICAgICAgY29uc3QgZW50cmllcyA9IHRoaXMudGFnSW5kZXguZ2V0KHRhZyk7XG4gICAgICAgIGlmIChlbnRyaWVzKSB7XG4gICAgICAgICAgZW50cmllcy5kZWxldGUoZW50cnlJZCk7XG4gICAgICAgICAgaWYgKGVudHJpZXMuc2l6ZSA9PT0gMCkge1xuICAgICAgICAgICAgdGhpcy50YWdJbmRleC5kZWxldGUodGFnKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBSZW1vdmUgZnJvbSBwcml2YWN5IGluZGV4XG4gICAgY29uc3QgcHJpdmFjeUxldmVsID0gZW50cnkubWV0YWRhdGE/LnByaXZhY3lMZXZlbCB8fCBlbnRyeS5wcml2YWN5TGV2ZWwgfHwgTUVNT1JZX0NPTlNUQU5UUy5ERUZBVUxUX1BSSVZBQ1lfTEVWRUw7XG4gICAgY29uc3QgcHJpdmFjeUVudHJpZXMgPSB0aGlzLnByaXZhY3lJbmRleC5nZXQocHJpdmFjeUxldmVsKTtcbiAgICBpZiAocHJpdmFjeUVudHJpZXMpIHtcbiAgICAgIHByaXZhY3lFbnRyaWVzLmRlbGV0ZShlbnRyeUlkKTtcbiAgICB9XG5cbiAgICAvLyBSZW1vdmUgZnJvbSBjb250ZW50IGluZGV4XG4gICAgdGhpcy5jb250ZW50SW5kZXg/LnJlbW92ZUVudHJ5KGVudHJ5SWQpO1xuXG4gICAgLy8gUmVtb3ZlIGZyb20gdGVtcG9yYWwgaW5kZXhcbiAgICB0aGlzLnRlbXBvcmFsSW5kZXgucmVtb3ZlRW50cnkoZW50cnlJZCk7XG5cbiAgICAvLyBSZW1vdmUgZnJvbSBjYWNoZVxuICAgIHRoaXMuZW50cmllc0NhY2hlLmRlbGV0ZShlbnRyeUlkKTtcblxuICAgIHRoaXMuc3RhdHMuZW50cnlDb3VudC0tO1xuXG4gICAgbG9nZ2VyLmRlYnVnKCdFbnRyeSByZW1vdmVkIGZyb20gaW5kZXgnLCB7IGlkOiBlbnRyeUlkIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFNlYXJjaCB0aGUgaW5kZXggd2l0aCBtdWx0aXBsZSBjcml0ZXJpYVxuICAgKi9cbiAgc2VhcmNoKHF1ZXJ5OiBTZWFyY2hRdWVyeSwgZW50cmllczogTWFwPHN0cmluZywgTWVtb3J5RW50cnk+KTogU2VhcmNoUmVzdWx0W10ge1xuICAgIGlmICghdGhpcy5pc0J1aWx0KSB7XG4gICAgICBsb2dnZXIuZGVidWcoJ0luZGV4IG5vdCBidWlsdCwgZmFsbGluZyBiYWNrIHRvIGxpbmVhciBzZWFyY2gnKTtcbiAgICAgIHJldHVybiB0aGlzLmxpbmVhclNlYXJjaChxdWVyeSwgZW50cmllcyk7XG4gICAgfVxuXG4gICAgLy8gU3RhcnQgd2l0aCBhbGwgZW50cmllcyBvciBmaWx0ZXJlZCBieSBwcml2YWN5XG4gICAgbGV0IGNhbmRpZGF0ZUlkczogU2V0PHN0cmluZz4gfCBudWxsID0gbnVsbDtcblxuICAgIC8vIEZpbHRlciBieSBwcml2YWN5IGxldmVsXG4gICAgaWYgKHF1ZXJ5LnByaXZhY3lMZXZlbCkge1xuICAgICAgY2FuZGlkYXRlSWRzID0gbmV3IFNldCh0aGlzLnByaXZhY3lJbmRleC5nZXQocXVlcnkucHJpdmFjeUxldmVsKSB8fCBbXSk7XG4gICAgfVxuXG4gICAgLy8gRmlsdGVyIGJ5IHRhZ3MgKGludGVyc2VjdGlvbilcbiAgICBpZiAocXVlcnkudGFncyAmJiBxdWVyeS50YWdzLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IHRhZ1Jlc3VsdHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICAgIGZvciAoY29uc3QgdGFnIG9mIHF1ZXJ5LnRhZ3MpIHtcbiAgICAgICAgY29uc3QgZW50cmllcyA9IHRoaXMudGFnSW5kZXguZ2V0KHRhZy50b0xvd2VyQ2FzZSgpKTtcbiAgICAgICAgaWYgKGVudHJpZXMpIHtcbiAgICAgICAgICBpZiAoY2FuZGlkYXRlSWRzKSB7XG4gICAgICAgICAgICAvLyBJbnRlcnNlY3Rpb24gd2l0aCBleGlzdGluZyBjYW5kaWRhdGVzXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGlkIG9mIGVudHJpZXMpIHtcbiAgICAgICAgICAgICAgaWYgKGNhbmRpZGF0ZUlkcy5oYXMoaWQpKSB7XG4gICAgICAgICAgICAgICAgdGFnUmVzdWx0cy5hZGQoaWQpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIEZpcnN0IGZpbHRlclxuICAgICAgICAgICAgZW50cmllcy5mb3JFYWNoKGlkID0+IHRhZ1Jlc3VsdHMuYWRkKGlkKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBjYW5kaWRhdGVJZHMgPSB0YWdSZXN1bHRzO1xuICAgIH1cblxuICAgIC8vIEZpbHRlciBieSBkYXRlIHJhbmdlXG4gICAgaWYgKHF1ZXJ5LmRhdGVGcm9tIHx8IHF1ZXJ5LmRhdGVUbykge1xuICAgICAgY29uc3QgZGF0ZVJlc3VsdHMgPSB0aGlzLnRlbXBvcmFsSW5kZXguc2VhcmNoUmFuZ2UocXVlcnkuZGF0ZUZyb20sIHF1ZXJ5LmRhdGVUbyk7XG4gICAgICBpZiAoY2FuZGlkYXRlSWRzKSB7XG4gICAgICAgIC8vIEludGVyc2VjdGlvblxuICAgICAgICBjb25zdCBpbnRlcnNlY3Rpb24gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICAgICAgZm9yIChjb25zdCBpZCBvZiBjYW5kaWRhdGVJZHMpIHtcbiAgICAgICAgICBpZiAoZGF0ZVJlc3VsdHMuaGFzKGlkKSkge1xuICAgICAgICAgICAgaW50ZXJzZWN0aW9uLmFkZChpZCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNhbmRpZGF0ZUlkcyA9IGludGVyc2VjdGlvbjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNhbmRpZGF0ZUlkcyA9IGRhdGVSZXN1bHRzO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFNjb3JlIGJ5IGNvbnRlbnQgaWYgcHJvdmlkZWRcbiAgICBjb25zdCBjb250ZW50U2NvcmVzID0gcXVlcnkuY29udGVudCAmJiB0aGlzLmNvbnRlbnRJbmRleFxuICAgICAgPyB0aGlzLmNvbnRlbnRJbmRleC5zZWFyY2gocXVlcnkuY29udGVudClcbiAgICAgIDogbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcblxuICAgIC8vIEJ1aWxkIHJlc3VsdHNcbiAgICBjb25zdCByZXN1bHRzOiBTZWFyY2hSZXN1bHRbXSA9IFtdO1xuICAgIGNvbnN0IHNlYXJjaEVudHJpZXMgPSBjYW5kaWRhdGVJZHMgfHwgbmV3IFNldChlbnRyaWVzLmtleXMoKSk7XG5cbiAgICBmb3IgKGNvbnN0IGlkIG9mIHNlYXJjaEVudHJpZXMpIHtcbiAgICAgIGNvbnN0IGVudHJ5ID0gZW50cmllcy5nZXQoaWQpO1xuICAgICAgaWYgKCFlbnRyeSkgY29udGludWU7XG5cbiAgICAgIC8vIENhbGN1bGF0ZSBzY29yZVxuICAgICAgbGV0IHNjb3JlID0gMTtcblxuICAgICAgLy8gQ29udGVudCByZWxldmFuY2Ugc2NvcmVcbiAgICAgIGlmIChjb250ZW50U2NvcmVzLmhhcyhpZCkpIHtcbiAgICAgICAgc2NvcmUgKz0gY29udGVudFNjb3Jlcy5nZXQoaWQpISAqIDI7XG4gICAgICB9XG5cbiAgICAgIC8vIFRhZyBtYXRjaCBib251c1xuICAgICAgaWYgKHF1ZXJ5LnRhZ3MgJiYgZW50cnkubWV0YWRhdGE/LnRhZ3MpIHtcbiAgICAgICAgY29uc3QgbWF0Y2hlZFRhZ3MgPSBxdWVyeS50YWdzLmZpbHRlcih0YWcgPT5cbiAgICAgICAgICBlbnRyeS5tZXRhZGF0YT8udGFncz8uaW5jbHVkZXModGFnKVxuICAgICAgICApO1xuICAgICAgICBzY29yZSArPSBtYXRjaGVkVGFncy5sZW5ndGg7XG4gICAgICB9XG5cbiAgICAgIHJlc3VsdHMucHVzaCh7XG4gICAgICAgIGVudHJ5LFxuICAgICAgICBzY29yZSxcbiAgICAgICAgbWF0Y2hlczoge1xuICAgICAgICAgIHRhZ3M6IHF1ZXJ5LnRhZ3M/LmZpbHRlcih0YWcgPT4gZW50cnkubWV0YWRhdGE/LnRhZ3M/LmluY2x1ZGVzKHRhZykpLFxuICAgICAgICAgIHRlcm1zOiBxdWVyeS5jb250ZW50ID8gWydpbmRleGVkJ10gOiB1bmRlZmluZWRcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gU29ydCBieSBzY29yZSBhbmQgYXBwbHkgcGFnaW5hdGlvblxuICAgIHJlc3VsdHMuc29ydCgoYSwgYikgPT4gYi5zY29yZSAtIGEuc2NvcmUpO1xuXG4gICAgY29uc3Qgb2Zmc2V0ID0gcXVlcnkub2Zmc2V0IHx8IDA7XG4gICAgY29uc3QgbGltaXQgPSBxdWVyeS5saW1pdCB8fCAxMDA7XG5cbiAgICByZXR1cm4gcmVzdWx0cy5zbGljZShvZmZzZXQsIG9mZnNldCArIGxpbWl0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGYWxsYmFjayBsaW5lYXIgc2VhcmNoIHdoZW4gaW5kZXggaXMgbm90IGF2YWlsYWJsZVxuICAgKi9cbiAgcHJpdmF0ZSBsaW5lYXJTZWFyY2gocXVlcnk6IFNlYXJjaFF1ZXJ5LCBlbnRyaWVzOiBNYXA8c3RyaW5nLCBNZW1vcnlFbnRyeT4pOiBTZWFyY2hSZXN1bHRbXSB7XG4gICAgY29uc3QgcmVzdWx0czogU2VhcmNoUmVzdWx0W10gPSBbXTtcblxuICAgIGZvciAoY29uc3QgW2lkLCBlbnRyeV0gb2YgZW50cmllcykge1xuICAgICAgLy8gQ2hlY2sgcHJpdmFjeSBsZXZlbFxuICAgICAgaWYgKHF1ZXJ5LnByaXZhY3lMZXZlbCAmJiBlbnRyeS5tZXRhZGF0YT8ucHJpdmFjeUxldmVsICE9PSBxdWVyeS5wcml2YWN5TGV2ZWwpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIC8vIENoZWNrIGRhdGUgcmFuZ2VcbiAgICAgIGlmIChxdWVyeS5kYXRlRnJvbSAmJiBlbnRyeS5tZXRhZGF0YT8udGltZXN0YW1wICYmIGVudHJ5Lm1ldGFkYXRhLnRpbWVzdGFtcCA8IHF1ZXJ5LmRhdGVGcm9tKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKHF1ZXJ5LmRhdGVUbyAmJiBlbnRyeS5tZXRhZGF0YT8udGltZXN0YW1wICYmIGVudHJ5Lm1ldGFkYXRhLnRpbWVzdGFtcCA+IHF1ZXJ5LmRhdGVUbykge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgLy8gQ2hlY2sgdGFnc1xuICAgICAgaWYgKHF1ZXJ5LnRhZ3MgJiYgcXVlcnkudGFncy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IGhhc0FsbFRhZ3MgPSBxdWVyeS50YWdzLmV2ZXJ5KHRhZyA9PlxuICAgICAgICAgIGVudHJ5Lm1ldGFkYXRhPy50YWdzPy5pbmNsdWRlcyh0YWcpXG4gICAgICAgICk7XG4gICAgICAgIGlmICghaGFzQWxsVGFncykgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIC8vIENoZWNrIGNvbnRlbnQgKHNpbXBsZSBzdWJzdHJpbmcgbWF0Y2gpXG4gICAgICBsZXQgc2NvcmUgPSAxO1xuICAgICAgaWYgKHF1ZXJ5LmNvbnRlbnQpIHtcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZCA9IFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKHF1ZXJ5LmNvbnRlbnQpO1xuICAgICAgICBpZiAobm9ybWFsaXplZC5pc1ZhbGlkKSB7XG4gICAgICAgICAgY29uc3Qgc2VhcmNoVGVybSA9IG5vcm1hbGl6ZWQubm9ybWFsaXplZENvbnRlbnQudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICBpZiAoZW50cnkuY29udGVudC50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKHNlYXJjaFRlcm0pKSB7XG4gICAgICAgICAgICBzY29yZSArPSAyO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXN1bHRzLnB1c2goe1xuICAgICAgICBlbnRyeSxcbiAgICAgICAgc2NvcmUsXG4gICAgICAgIG1hdGNoZXM6IHtcbiAgICAgICAgICB0YWdzOiBxdWVyeS50YWdzPy5maWx0ZXIodGFnID0+IGVudHJ5Lm1ldGFkYXRhPy50YWdzPy5pbmNsdWRlcyh0YWcpKVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBTb3J0IGFuZCBwYWdpbmF0ZVxuICAgIHJlc3VsdHMuc29ydCgoYSwgYikgPT4gYi5zY29yZSAtIGEuc2NvcmUpO1xuICAgIGNvbnN0IG9mZnNldCA9IHF1ZXJ5Lm9mZnNldCB8fCAwO1xuICAgIGNvbnN0IGxpbWl0ID0gcXVlcnkubGltaXQgfHwgMTAwO1xuXG4gICAgcmV0dXJuIHJlc3VsdHMuc2xpY2Uob2Zmc2V0LCBvZmZzZXQgKyBsaW1pdCk7XG4gIH1cblxuICAvKipcbiAgICogSW50ZXJuYWwgaGVscGVyIHRvIGFkZCBlbnRyeSB0byBhbGwgaW5kZXhlc1xuICAgKi9cbiAgcHJpdmF0ZSBhZGRUb0luZGV4KGlkOiBzdHJpbmcsIGVudHJ5OiBNZW1vcnlFbnRyeSk6IHZvaWQge1xuICAgIC8vIENhY2hlIGVudHJ5XG4gICAgdGhpcy5lbnRyaWVzQ2FjaGUuc2V0KGlkLCBlbnRyeSk7XG5cbiAgICAvLyBBZGQgdG8gdGFnIGluZGV4XG4gICAgaWYgKGVudHJ5Lm1ldGFkYXRhPy50YWdzKSB7XG4gICAgICBmb3IgKGNvbnN0IHRhZyBvZiBlbnRyeS5tZXRhZGF0YS50YWdzKSB7XG4gICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRUYWcgPSB0YWcudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgbGV0IGVudHJpZXMgPSB0aGlzLnRhZ0luZGV4LmdldChub3JtYWxpemVkVGFnKTtcbiAgICAgICAgaWYgKCFlbnRyaWVzKSB7XG4gICAgICAgICAgZW50cmllcyA9IG5ldyBTZXQoKTtcbiAgICAgICAgICB0aGlzLnRhZ0luZGV4LnNldChub3JtYWxpemVkVGFnLCBlbnRyaWVzKTtcbiAgICAgICAgfVxuICAgICAgICBlbnRyaWVzLmFkZChpZCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQWRkIHRvIHByaXZhY3kgaW5kZXhcbiAgICBjb25zdCBwcml2YWN5TGV2ZWwgPSBlbnRyeS5tZXRhZGF0YT8ucHJpdmFjeUxldmVsIHx8IGVudHJ5LnByaXZhY3lMZXZlbCB8fCBNRU1PUllfQ09OU1RBTlRTLkRFRkFVTFRfUFJJVkFDWV9MRVZFTDtcbiAgICBsZXQgcHJpdmFjeUVudHJpZXMgPSB0aGlzLnByaXZhY3lJbmRleC5nZXQocHJpdmFjeUxldmVsKTtcbiAgICBpZiAoIXByaXZhY3lFbnRyaWVzKSB7XG4gICAgICBwcml2YWN5RW50cmllcyA9IG5ldyBTZXQoKTtcbiAgICAgIHRoaXMucHJpdmFjeUluZGV4LnNldChwcml2YWN5TGV2ZWwsIHByaXZhY3lFbnRyaWVzKTtcbiAgICB9XG4gICAgcHJpdmFjeUVudHJpZXMuYWRkKGlkKTtcblxuICAgIC8vIEFkZCB0byBjb250ZW50IGluZGV4XG4gICAgaWYgKHRoaXMuY29udGVudEluZGV4KSB7XG4gICAgICB0aGlzLmNvbnRlbnRJbmRleC5hZGRFbnRyeShpZCwgZW50cnkuY29udGVudCk7XG4gICAgfVxuXG4gICAgLy8gQWRkIHRvIHRlbXBvcmFsIGluZGV4XG4gICAgdGhpcy50ZW1wb3JhbEluZGV4LmFkZEVudHJ5KGlkLCBlbnRyeS5tZXRhZGF0YT8udGltZXN0YW1wIHx8IGVudHJ5LnRpbWVzdGFtcCk7XG4gIH1cblxuICAvKipcbiAgICogQ2xlYXIgYWxsIGluZGV4ZXNcbiAgICovXG4gIGNsZWFyKCk6IHZvaWQge1xuICAgIHRoaXMudGFnSW5kZXguY2xlYXIoKTtcbiAgICB0aGlzLnByaXZhY3lJbmRleC5jbGVhcigpO1xuICAgIHRoaXMuY29udGVudEluZGV4Py5jbGVhcigpO1xuICAgIHRoaXMudGVtcG9yYWxJbmRleC5jbGVhcigpO1xuICAgIHRoaXMuZW50cmllc0NhY2hlLmNsZWFyKCk7XG4gICAgdGhpcy5pc0J1aWx0ID0gZmFsc2U7XG4gICAgdGhpcy5zdGF0cyA9IHtcbiAgICAgIGlzSW5kZXhlZDogZmFsc2UsXG4gICAgICBlbnRyeUNvdW50OiAwLFxuICAgICAgdGFnQ291bnQ6IDAsXG4gICAgICB0ZXJtQ291bnQ6IDBcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBpbmRleCBzdGF0aXN0aWNzXG4gICAqL1xuICBnZXRTdGF0cygpOiBTZWFyY2hJbmRleFN0YXRzIHtcbiAgICByZXR1cm4geyAuLi50aGlzLnN0YXRzIH07XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgaWYgaW5kZXggaXMgYnVpbHRcbiAgICovXG4gIGdldCBpc0luZGV4ZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNCdWlsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGUgYW5kIHVwZGF0ZSBtZW1vcnkgdXNhZ2VcbiAgICogRklYOiBBZGRlZCBtZW1vcnkgbW9uaXRvcmluZyBmb3IgY29udGVudCBpbmRleFxuICAgKi9cbiAgcHJpdmF0ZSB1cGRhdGVNZW1vcnlVc2FnZSgpOiB2b2lkIHtcbiAgICBsZXQgdG90YWxCeXRlcyA9IDA7XG5cbiAgICAvLyBFc3RpbWF0ZSB0YWcgaW5kZXggbWVtb3J5XG4gICAgZm9yIChjb25zdCBbdGFnLCBlbnRyaWVzXSBvZiB0aGlzLnRhZ0luZGV4KSB7XG4gICAgICB0b3RhbEJ5dGVzICs9IHRhZy5sZW5ndGggKiAyOyAvLyBVVEYtMTYgZW5jb2RpbmdcbiAgICAgIHRvdGFsQnl0ZXMgKz0gZW50cmllcy5zaXplICogMzI7IC8vIEVzdGltYXRlZCBJRCBzaXplXG4gICAgfVxuXG4gICAgLy8gRXN0aW1hdGUgY29udGVudCBpbmRleCBtZW1vcnlcbiAgICBpZiAodGhpcy5jb250ZW50SW5kZXgpIHtcbiAgICAgIC8vIFJvdWdoIGVzdGltYXRlOiBlYWNoIHRlcm0gKyBlbnRyeSBJRHNcbiAgICAgIHRvdGFsQnl0ZXMgKz0gdGhpcy5jb250ZW50SW5kZXguc2l6ZSAqIDEwMDtcbiAgICB9XG5cbiAgICAvLyBFc3RpbWF0ZSB0ZW1wb3JhbCBpbmRleCBtZW1vcnlcbiAgICB0b3RhbEJ5dGVzICs9IHRoaXMudGVtcG9yYWxJbmRleC5zaXplICogNDg7IC8vIERhdGUgKyBJRFxuXG4gICAgLy8gRXN0aW1hdGUgY2FjaGUgbWVtb3J5XG4gICAgZm9yIChjb25zdCBlbnRyeSBvZiB0aGlzLmVudHJpZXNDYWNoZS52YWx1ZXMoKSkge1xuICAgICAgdG90YWxCeXRlcyArPSBKU09OLnN0cmluZ2lmeShlbnRyeSkubGVuZ3RoICogMjtcbiAgICB9XG5cbiAgICB0aGlzLm1lbW9yeVVzYWdlQnl0ZXMgPSB0b3RhbEJ5dGVzO1xuXG4gICAgLy8gQ2hlY2sgaWYgd2UncmUgZXhjZWVkaW5nIG1lbW9yeSBsaW1pdFxuICAgIGlmICh0b3RhbEJ5dGVzID4gdGhpcy5tYXhNZW1vcnlCeXRlcykge1xuICAgICAgbG9nZ2VyLndhcm4oJ01lbW9yeSBzZWFyY2ggaW5kZXggZXhjZWVkaW5nIGxpbWl0Jywge1xuICAgICAgICB1c2VkTUI6IE1hdGgucm91bmQodG90YWxCeXRlcyAvIDEwMjQgLyAxMDI0KSxcbiAgICAgICAgbGltaXRNQjogTWF0aC5yb3VuZCh0aGlzLm1heE1lbW9yeUJ5dGVzIC8gMTAyNCAvIDEwMjQpXG4gICAgICB9KTtcblxuICAgICAgLy8gVHJpZ2dlciBMUlUgZXZpY3Rpb24gaWYgZW5hYmxlZFxuICAgICAgaWYgKHRoaXMuY29uZmlnLmVuYWJsZUxSVUV2aWN0aW9uKSB7XG4gICAgICAgIHRoaXMuZXZpY3RMUlVFbnRyaWVzKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEV2aWN0IGxlYXN0IHJlY2VudGx5IHVzZWQgZW50cmllcyB0byBmcmVlIG1lbW9yeVxuICAgKiBGSVg6IEFkZGVkIExSVSBldmljdGlvbiBmb3IgbWVtb3J5IG1hbmFnZW1lbnRcbiAgICovXG4gIHByaXZhdGUgZXZpY3RMUlVFbnRyaWVzKCk6IHZvaWQge1xuICAgIC8vIEdldCBlbnRyaWVzIHNvcnRlZCBieSBhY2Nlc3MgdGltZSAod291bGQgbmVlZCB0byB0cmFjayB0aGlzKVxuICAgIC8vIEZvciBub3csIGV2aWN0IG9sZGVzdCAyMCUgb2YgZW50cmllc1xuICAgIGNvbnN0IGVudHJpZXNUb0V2aWN0ID0gTWF0aC5mbG9vcih0aGlzLmVudHJpZXNDYWNoZS5zaXplICogMC4yKTtcbiAgICBjb25zdCBlbnRyaWVzQXJyYXkgPSBBcnJheS5mcm9tKHRoaXMuZW50cmllc0NhY2hlLmtleXMoKSk7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGVudHJpZXNUb0V2aWN0OyBpKyspIHtcbiAgICAgIGNvbnN0IGlkVG9FdmljdCA9IGVudHJpZXNBcnJheVtpXTtcbiAgICAgIHRoaXMucmVtb3ZlRW50cnkoaWRUb0V2aWN0KTtcbiAgICB9XG5cbiAgICBsb2dnZXIuaW5mbygnRXZpY3RlZCBMUlUgZW50cmllcycsIHtcbiAgICAgIGV2aWN0ZWRDb3VudDogZW50cmllc1RvRXZpY3QsXG4gICAgICByZW1haW5pbmdDb3VudDogdGhpcy5lbnRyaWVzQ2FjaGUuc2l6ZVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFNlcmlhbGl6ZSBpbmRleCB0byBKU09OIGZvciBwZXJzaXN0ZW5jZVxuICAgKiBGSVg6IEFkZGVkIGluZGV4IHNlcmlhbGl6YXRpb24gZm9yIGNvbGQgc3RhcnQgb3B0aW1pemF0aW9uXG4gICAqL1xuICBzZXJpYWxpemUoKTogc3RyaW5nIHtcbiAgICBpZiAoIXRoaXMuaXNCdWlsdCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3Qgc2VyaWFsaXplIHVuYnVpbHQgaW5kZXgnKTtcbiAgICB9XG5cbiAgICBjb25zdCBpbmRleERhdGEgPSB7XG4gICAgICB2ZXJzaW9uOiAnMS4wLjAnLFxuICAgICAgc3RhdHM6IHRoaXMuc3RhdHMsXG4gICAgICB0YWdJbmRleDogQXJyYXkuZnJvbSh0aGlzLnRhZ0luZGV4LmVudHJpZXMoKSkubWFwKChbdGFnLCBpZHNdKSA9PiAoe1xuICAgICAgICB0YWcsXG4gICAgICAgIGlkczogQXJyYXkuZnJvbShpZHMpXG4gICAgICB9KSksXG4gICAgICBwcml2YWN5SW5kZXg6IEFycmF5LmZyb20odGhpcy5wcml2YWN5SW5kZXguZW50cmllcygpKS5tYXAoKFtsZXZlbCwgaWRzXSkgPT4gKHtcbiAgICAgICAgbGV2ZWwsXG4gICAgICAgIGlkczogQXJyYXkuZnJvbShpZHMpXG4gICAgICB9KSksXG4gICAgICB0ZW1wb3JhbEluZGV4OiB0aGlzLnRlbXBvcmFsSW5kZXguc2VyaWFsaXplKCksXG4gICAgICAvLyBOb3RlOiBDb250ZW50IGluZGV4IGlzIG5vdCBzZXJpYWxpemVkIGR1ZSB0byBzaXplXG4gICAgICAvLyBJdCB3aWxsIGJlIHJlYnVpbHQgb24gbG9hZCBpZiBuZWVkZWRcbiAgICB9O1xuXG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGluZGV4RGF0YSk7XG4gIH1cblxuICAvKipcbiAgICogRGVzZXJpYWxpemUgaW5kZXggZnJvbSBKU09OXG4gICAqIEZJWDogQWRkZWQgaW5kZXggZGVzZXJpYWxpemF0aW9uIGZvciBmYXN0ZXIgc3RhcnR1cFxuICAgKi9cbiAgZGVzZXJpYWxpemUoZGF0YTogc3RyaW5nLCBlbnRyaWVzOiBNYXA8c3RyaW5nLCBNZW1vcnlFbnRyeT4pOiB2b2lkIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgaW5kZXhEYXRhID0gSlNPTi5wYXJzZShkYXRhKTtcblxuICAgICAgLy8gVmFsaWRhdGUgdmVyc2lvblxuICAgICAgaWYgKGluZGV4RGF0YS52ZXJzaW9uICE9PSAnMS4wLjAnKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5zdXBwb3J0ZWQgaW5kZXggdmVyc2lvbjogJHtpbmRleERhdGEudmVyc2lvbn1gKTtcbiAgICAgIH1cblxuICAgICAgLy8gQ2xlYXIgZXhpc3RpbmcgaW5kZXhlc1xuICAgICAgdGhpcy5jbGVhcigpO1xuXG4gICAgICAvLyBSZXN0b3JlIHRhZyBpbmRleFxuICAgICAgZm9yIChjb25zdCB7IHRhZywgaWRzIH0gb2YgaW5kZXhEYXRhLnRhZ0luZGV4KSB7XG4gICAgICAgIHRoaXMudGFnSW5kZXguc2V0KHRhZywgbmV3IFNldChpZHMpKTtcbiAgICAgIH1cblxuICAgICAgLy8gUmVzdG9yZSBwcml2YWN5IGluZGV4XG4gICAgICBmb3IgKGNvbnN0IHsgbGV2ZWwsIGlkcyB9IG9mIGluZGV4RGF0YS5wcml2YWN5SW5kZXgpIHtcbiAgICAgICAgdGhpcy5wcml2YWN5SW5kZXguc2V0KGxldmVsIGFzIFByaXZhY3lMZXZlbCwgbmV3IFNldChpZHMpKTtcbiAgICAgIH1cblxuICAgICAgLy8gUmVzdG9yZSB0ZW1wb3JhbCBpbmRleFxuICAgICAgdGhpcy50ZW1wb3JhbEluZGV4LmRlc2VyaWFsaXplKGluZGV4RGF0YS50ZW1wb3JhbEluZGV4KTtcblxuICAgICAgLy8gUmVzdG9yZSBlbnRyaWVzIGNhY2hlIGZyb20gcHJvdmlkZWQgZW50cmllc1xuICAgICAgZm9yIChjb25zdCBbaWQsIGVudHJ5XSBvZiBlbnRyaWVzKSB7XG4gICAgICAgIGlmIChpbmRleERhdGEudGFnSW5kZXguc29tZSgoaXRlbTogYW55KSA9PiBpdGVtLmlkcy5pbmNsdWRlcyhpZCkpKSB7XG4gICAgICAgICAgdGhpcy5lbnRyaWVzQ2FjaGUuc2V0KGlkLCBlbnRyeSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gUmVidWlsZCBjb250ZW50IGluZGV4IGlmIGVuYWJsZWQgKGNhbid0IHNlcmlhbGl6ZSBlZmZpY2llbnRseSlcbiAgICAgIGlmICh0aGlzLmNvbmZpZy5lbmFibGVDb250ZW50SW5kZXgpIHtcbiAgICAgICAgdGhpcy5jb250ZW50SW5kZXggPSBuZXcgQ29udGVudEluZGV4KHRoaXMuY29uZmlnKTtcbiAgICAgICAgZm9yIChjb25zdCBbaWQsIGVudHJ5XSBvZiB0aGlzLmVudHJpZXNDYWNoZSkge1xuICAgICAgICAgIHRoaXMuY29udGVudEluZGV4LmFkZEVudHJ5KGlkLCBlbnRyeS5jb250ZW50KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBVcGRhdGUgc3RhdHNcbiAgICAgIHRoaXMuc3RhdHMgPSBpbmRleERhdGEuc3RhdHM7XG4gICAgICB0aGlzLmlzQnVpbHQgPSB0cnVlO1xuXG4gICAgICBsb2dnZXIuaW5mbygnTWVtb3J5IHNlYXJjaCBpbmRleCBkZXNlcmlhbGl6ZWQnLCB0aGlzLnN0YXRzKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdGYWlsZWQgdG8gZGVzZXJpYWxpemUgaW5kZXgsIHJlYnVpbGRpbmcnLCBlcnJvcik7XG4gICAgICAvLyBGYWxsIGJhY2sgdG8gYnVpbGRpbmcgZnJvbSBzY3JhdGNoXG4gICAgICB0aGlzLmJ1aWxkSW5kZXgoZW50cmllcyk7XG4gICAgfVxuICB9XG59Il19