UNPKG

@dollhousemcp/mcp-server

Version:

DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.

352 lines 49.8 kB
/** * MemoryStorageLayer - IStorageLayer implementation for multi-directory memory scanning. * * Memories use pure YAML across a multi-directory layout: * system/ — System-provided memories * adapters/ — Adapter-specific memories * YYYY-MM-DD/ — User-created date-folder memories * (root) — Legacy root-level memories * * Reuses the same internal components as ElementStorageLayer (MetadataIndex, * StorageManifest, FileStorageBackend) but with fundamentally different scan * logic: multi-directory enumeration + _index.json cold-start persistence. */ import * as path from 'path'; import { logger } from '../utils/logger.js'; import { StorageManifest } from './StorageManifest.js'; import { MetadataIndex } from './MetadataIndex.js'; import { FileStorageBackend } from './FileStorageBackend.js'; import { MemoryMetadataExtractor } from './MemoryMetadataExtractor.js'; import { MemoryIndexFile } from './MemoryIndexFile.js'; import { UnicodeValidator } from '../security/validators/unicodeValidator.js'; const EMPTY_DIFF = { added: [], modified: [], removed: [], unchanged: [] }; const DATE_FOLDER_PATTERN = /^\d{4}-\d{2}-\d{2}$/; export class MemoryStorageLayer { fileOps; backend; manifest = new StorageManifest(); index = new MetadataIndex(); indexFile; memoriesDir; scanCooldownMs; fileFilter; lastScanTimestamp = 0; scanInProgress = null; coldStartDone = false; constructor(fileOps, options) { this.fileOps = fileOps; this.memoriesDir = options.memoriesDir; this.scanCooldownMs = options.scanCooldownMs ?? 1000; this.fileFilter = options.fileFilter; if (options.storageBackend) { this.backend = options.storageBackend; } else { this.backend = new FileStorageBackend(fileOps); } const indexPath = path.join(this.memoriesDir, '_index.json'); this.indexFile = new MemoryIndexFile(indexPath, fileOps, { debounceMs: options.indexDebounceMs ?? 2000, }); } // ---- IStorageLayer implementation ---- async scan() { // Cold start: try loading from _index.json first if (!this.coldStartDone) { this.coldStartDone = true; return this.coldStart(); } const now = Date.now(); if (now - this.lastScanTimestamp < this.scanCooldownMs) { logger.debug(`MemoryStorageLayer.scan: COOLDOWN ACTIVE — skipping disk I/O (${this.scanCooldownMs - (now - this.lastScanTimestamp)}ms remaining)`); return EMPTY_DIFF; } // Deduplicate concurrent scans if (this.scanInProgress) { return this.scanInProgress; } this.scanInProgress = this.performScan(); try { return await this.scanInProgress; } finally { this.scanInProgress = null; } } async listSummaries() { await this.scan(); return this.deduplicateByName(this.index.getAll()); } async getIndexedPaths() { await this.scan(); const deduplicated = this.deduplicateByName(this.index.getAll()); return deduplicated.map(entry => entry.filePath); } /** * Deduplicate index entries by normalized name. * When the same memory appears in multiple date folders, keep the one * with the highest mtimeMs (most recently modified). * * Issue #654: Same memory files duplicated across ~150 date folders * inflated counts from ~750 unique to ~3,100+ loaded memories. */ deduplicateByName(entries) { const byName = new Map(); for (const entry of entries) { const key = UnicodeValidator.normalize(entry.name).normalizedContent.toLowerCase(); const existing = byName.get(key); if (!existing || entry.mtimeMs > existing.mtimeMs) { byName.set(key, entry); } } return [...byName.values()]; } getPathByName(name) { const normalizedName = UnicodeValidator.normalize(name).normalizedContent; return this.index.getPathByName(normalizedName); } hasCompletedScan() { return this.lastScanTimestamp > 0; } async notifySaved(relativePath, absolutePath) { try { const content = await this.backend.readFile(absolutePath); const meta = await this.backend.stat(absolutePath); const extracted = MemoryMetadataExtractor.extractMetadata(content, relativePath); const entry = { filePath: relativePath, name: extracted.name ?? 'unnamed', description: extracted.description ?? '', version: extracted.version ?? '1.0.0', author: extracted.author ?? '', tags: extracted.tags ?? [], mtimeMs: meta.mtimeMs, sizeBytes: meta.sizeBytes, autoLoad: extracted.autoLoad, priority: extracted.priority, memoryType: extracted.memoryType, totalEntries: extracted.totalEntries, }; this.index.set(entry); this.manifest.set(relativePath, meta.mtimeMs); this.indexFile.scheduleWrite(this.index.getAll()); } catch (error) { logger.debug('MemoryStorageLayer.notifySaved failed, invalidating', { relativePath, error: error instanceof Error ? error.message : String(error), }); this.invalidate(); } } notifyDeleted(relativePath) { this.index.remove(relativePath); this.manifest.remove(relativePath); this.indexFile.scheduleWrite(this.index.getAll()); } invalidate() { this.lastScanTimestamp = 0; } clear() { this.indexFile.dispose(); // Cancel pending debounced write (prevents ENOTEMPTY in tests) this.index.clear(); this.manifest.clear(); this.lastScanTimestamp = 0; } // ---- Memory-specific methods ---- /** * Return index entries where autoLoad === true, sorted by priority ascending. * Pure in-memory — does NOT trigger a scan. */ getAutoLoadEntries() { return this.index.getAll() .filter(entry => entry.autoLoad === true) .sort((a, b) => (a.priority ?? 999) - (b.priority ?? 999)); } /** * Full disk scan of all subdirectories + write _index.json. */ async rebuildIndex() { logger.info('MemoryStorageLayer: rebuilding index from disk...'); this.index.clear(); this.manifest.clear(); await this.performScan(); await this.indexFile.write(this.index.getAll()); logger.info(`MemoryStorageLayer: rebuild complete — ${this.index.size} entries indexed`); } /** * Flush pending _index.json write and release resources. */ async dispose() { await this.indexFile.flush(); this.indexFile.dispose(); } // ---- Private ---- /** * Cold start: try to restore from _index.json, then run incremental scan. * Falls back to full rebuild if index is missing/corrupt. */ async coldStart() { try { const cached = await this.indexFile.read(); if (cached) { // Populate index and manifest from cached data for (const [relPath, entry] of Object.entries(cached.entries)) { this.index.set(entry); this.manifest.set(relPath, entry.mtimeMs); } logger.info(`MemoryStorageLayer: cold start — loaded ${Object.keys(cached.entries).length} entries from _index.json`); // Run incremental scan to catch changes since _index.json was written return this.performScan(); } } catch (error) { logger.debug('MemoryStorageLayer: cold start _index.json read failed, rebuilding', { error: error instanceof Error ? error.message : String(error), }); } // No valid _index.json — full rebuild await this.rebuildIndex(); return EMPTY_DIFF; } /** * Discover all subdirectories to scan. * Returns ['system', 'adapters', ...dateFolders, ''] where '' = root. */ async discoverSubdirectories() { const subdirs = []; try { const entries = await this.fileOps.listDirectory(this.memoriesDir); const dateFolders = []; for (const entry of entries) { // Include known fixed directories if (entry === 'system' || entry === 'adapters') { subdirs.push(entry); } else if (DATE_FOLDER_PATTERN.test(entry)) { dateFolders.push(entry); } // Skip backups/, _index.json, and other non-memory directories } // Sort date folders chronologically (oldest first → newest last) // so that nameToPath in MetadataIndex ends up pointing to the newest copy dateFolders.sort((a, b) => a.localeCompare(b)); subdirs.push(...dateFolders); } catch (error) { if (error.code !== 'ENOENT') { logger.debug('MemoryStorageLayer: failed to list subdirectories', { error: error instanceof Error ? error.message : String(error), }); } } // Always include root (empty string = root directory) subdirs.push(''); return subdirs; } /** * Perform a full incremental scan across all subdirectories. */ async performScan() { try { const exists = await this.backend.directoryExists(this.memoriesDir); if (!exists) { const removedPaths = this.index.getPaths(); this.index.clear(); this.manifest.clear(); this.lastScanTimestamp = Date.now(); return { added: [], modified: [], removed: removedPaths, unchanged: [], }; } // 1. Discover subdirectories const subdirs = await this.discoverSubdirectories(); // 2. Enumerate all .yaml files across subdirectories const allRelativePaths = []; for (const subdir of subdirs) { const absDir = subdir ? path.join(this.memoriesDir, subdir) : this.memoriesDir; try { const files = await this.backend.listFiles(absDir, '.yaml'); for (const file of files) { // Apply file filter (e.g., exclude backup files) if (this.fileFilter && !this.fileFilter(file)) { continue; } // Prefix with subdir for relative path const relPath = subdir ? `${subdir}/${file}` : file; allRelativePaths.push(relPath); } } catch (error) { // Directory might not exist (e.g., no system/ folder yet) if (error.code !== 'ENOENT') { logger.debug(`MemoryStorageLayer: failed to list ${absDir}`, { error: error instanceof Error ? error.message : String(error), }); } } } // 3. Stat all files const stats = await this.backend.statMany(this.memoriesDir, allRelativePaths); // 4. Diff against manifest const diff = this.manifest.diff(stats); const hasChanges = diff.added.length > 0 || diff.modified.length > 0 || diff.removed.length > 0; if (hasChanges) { logger.debug(`MemoryStorageLayer.scan: DISK SCAN — ${allRelativePaths.length} files, ${diff.added.length} added, ${diff.modified.length} modified, ${diff.removed.length} removed`); } // 5. For added/modified: read file, extract metadata, update index const toIndex = [...diff.added, ...diff.modified]; let indexUpdated = false; await Promise.all(toIndex.map(async (relPath) => { try { const absPath = path.join(this.memoriesDir, relPath); const content = await this.backend.readFile(absPath); const extracted = MemoryMetadataExtractor.extractMetadata(content, relPath); const meta = stats.get(relPath); this.index.set({ filePath: relPath, name: extracted.name ?? 'unnamed', description: extracted.description ?? '', version: extracted.version ?? '1.0.0', author: extracted.author ?? '', tags: extracted.tags ?? [], mtimeMs: meta?.mtimeMs ?? 0, sizeBytes: meta?.sizeBytes ?? 0, autoLoad: extracted.autoLoad, priority: extracted.priority, memoryType: extracted.memoryType, totalEntries: extracted.totalEntries, }); indexUpdated = true; } catch (error) { logger.debug(`MemoryStorageLayer: failed to index ${relPath}`, { error: error instanceof Error ? error.message : String(error), }); } })); // 6. For removed: remove from index for (const relPath of diff.removed) { this.index.remove(relPath); indexUpdated = true; } // 7. Update manifest and timestamp this.manifest.update(stats); this.lastScanTimestamp = Date.now(); // 8. Schedule debounced _index.json write if index changed if (indexUpdated) { this.indexFile.scheduleWrite(this.index.getAll()); } return diff; } catch (error) { logger.error('MemoryStorageLayer.performScan failed', error); this.lastScanTimestamp = Date.now(); // Prevent retry storms return EMPTY_DIFF; } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWVtb3J5U3RvcmFnZUxheWVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N0b3JhZ2UvTWVtb3J5U3RvcmFnZUxheWVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7R0FZRztBQUVILE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQzdCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUk1QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzdELE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUV2RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQWU5RSxNQUFNLFVBQVUsR0FBdUIsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFLENBQUM7QUFDL0YsTUFBTSxtQkFBbUIsR0FBRyxxQkFBcUIsQ0FBQztBQUVsRCxNQUFNLE9BQU8sa0JBQWtCO0lBY1Y7SUFiRixPQUFPLENBQWtCO0lBQ3pCLFFBQVEsR0FBRyxJQUFJLGVBQWUsRUFBRSxDQUFDO0lBQ2pDLEtBQUssR0FBRyxJQUFJLGFBQWEsRUFBRSxDQUFDO0lBQzVCLFNBQVMsQ0FBa0I7SUFDM0IsV0FBVyxDQUFTO0lBQ3BCLGNBQWMsQ0FBUztJQUN2QixVQUFVLENBQWlDO0lBRXBELGlCQUFpQixHQUFHLENBQUMsQ0FBQztJQUN0QixjQUFjLEdBQXVDLElBQUksQ0FBQztJQUMxRCxhQUFhLEdBQUcs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QUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUMzQixZQUFZLEdBQUcsSUFBSSxDQUFDO1lBQ3RCLENBQUM7WUFFRCxtQ0FBbUM7WUFDbkMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDNUIsSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUVwQywyREFBMkQ7WUFDM0QsSUFBSSxZQUFZLEVBQUUsQ0FBQztnQkFDakIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1lBQ3BELENBQUM7WUFFRCxPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxDQUFDLEtBQUssQ0FBQyx1Q0FBdUMsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUM3RCxJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsdUJBQXVCO1lBQzVELE9BQU8sVUFBVSxDQUFDO1FBQ3BCLENBQUM7SUFDSCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1lbW9yeVN0b3JhZ2VMYXllciAtIElTdG9yYWdlTGF5ZXIgaW1wbGVtZW50YXRpb24gZm9yIG11bHRpLWRpcmVjdG9yeSBtZW1vcnkgc2Nhbm5pbmcuXG4gKlxuICogTWVtb3JpZXMgdXNlIHB1cmUgWUFNTCBhY3Jvc3MgYSBtdWx0aS1kaXJlY3RvcnkgbGF5b3V0OlxuICogICBzeXN0ZW0vICAgICAgIOKAlCBTeXN0ZW0tcHJvdmlkZWQgbWVtb3JpZXNcbiAqICAgYWRhcHRlcnMvICAgICDigJQgQWRhcHRlci1zcGVjaWZpYyBtZW1vcmllc1xuICogICBZWVlZLU1NLURELyAgIOKAlCBVc2VyLWNyZWF0ZWQgZGF0ZS1mb2xkZXIgbWVtb3JpZXNcbiAqICAgKHJvb3QpICAgICAgICDigJQgTGVnYWN5IHJvb3QtbGV2ZWwgbWVtb3JpZXNcbiAqXG4gKiBSZXVzZXMgdGhlIHNhbWUgaW50ZXJuYWwgY29tcG9uZW50cyBhcyBFbGVtZW50U3RvcmFnZUxheWVyIChNZXRhZGF0YUluZGV4LFxuICogU3RvcmFnZU1hbmlmZXN0LCBGaWxlU3RvcmFnZUJhY2tlbmQpIGJ1dCB3aXRoIGZ1bmRhbWVudGFsbHkgZGlmZmVyZW50IHNjYW5cbiAqIGxvZ2ljOiBtdWx0aS1kaXJlY3RvcnkgZW51bWVyYXRpb24gKyBfaW5kZXguanNvbiBjb2xkLXN0YXJ0IHBlcnNpc3RlbmNlLlxuICovXG5cbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHR5cGUgeyBJU3RvcmFnZUxheWVyIH0gZnJvbSAnLi9JU3RvcmFnZUxheWVyLmpzJztcbmltcG9ydCB0eXBlIHsgSVN0b3JhZ2VCYWNrZW5kIH0gZnJvbSAnLi9JU3RvcmFnZUJhY2tlbmQuanMnO1xuaW1wb3J0IHR5cGUgeyBFbGVtZW50SW5kZXhFbnRyeSwgTWFuaWZlc3REaWZmUmVzdWx0IH0gZnJvbSAnLi90eXBlcy5qcyc7XG5pbXBvcnQgeyBTdG9yYWdlTWFuaWZlc3QgfSBmcm9tICcuL1N0b3JhZ2VNYW5pZmVzdC5qcyc7XG5pbXBvcnQgeyBNZXRhZGF0YUluZGV4IH0gZnJvbSAnLi9NZXRhZGF0YUluZGV4LmpzJztcbmltcG9ydCB7IEZpbGVTdG9yYWdlQmFja2VuZCB9IGZyb20gJy4vRmlsZVN0b3JhZ2VCYWNrZW5kLmpzJztcbmltcG9ydCB7IE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yIH0gZnJvbSAnLi9NZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5qcyc7XG5pbXBvcnQgeyBNZW1vcnlJbmRleEZpbGUgfSBmcm9tICcuL01lbW9yeUluZGV4RmlsZS5qcyc7XG5pbXBvcnQgdHlwZSB7IEZpbGVPcGVyYXRpb25zU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL0ZpbGVPcGVyYXRpb25zU2VydmljZS5qcyc7XG5pbXBvcnQgeyBVbmljb2RlVmFsaWRhdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvdmFsaWRhdG9ycy91bmljb2RlVmFsaWRhdG9yLmpzJztcblxuZXhwb3J0IGludGVyZmFjZSBNZW1vcnlTdG9yYWdlTGF5ZXJPcHRpb25zIHtcbiAgLyoqIEFic29sdXRlIHBhdGggdG8gdGhlIG1lbW9yaWVzIGRpcmVjdG9yeSAqL1xuICBtZW1vcmllc0Rpcjogc3RyaW5nO1xuICAvKiogTWluaW11bSBtaWxsaXNlY29uZHMgYmV0d2VlbiBmdWxsIHNjYW5zIChkZWZhdWx0OiAxMDAwKSAqL1xuICBzY2FuQ29vbGRvd25Ncz86IG51bWJlcjtcbiAgLyoqIE92ZXJyaWRlIHRoZSBzdG9yYWdlIGJhY2tlbmQgKHVzZWZ1bCBmb3IgdGVzdGluZykgKi9cbiAgc3RvcmFnZUJhY2tlbmQ/OiBJU3RvcmFnZUJhY2tlbmQ7XG4gIC8qKiBEZWJvdW5jZSBpbnRlcnZhbCBmb3IgX2luZGV4Lmpzb24gd3JpdGVzIChkZWZhdWx0OiAyMDAwKSAqL1xuICBpbmRleERlYm91bmNlTXM/OiBudW1iZXI7XG4gIC8qKiBGaWxlIGZpbHRlciBwcmVkaWNhdGUgKGUuZy4sIGV4Y2x1ZGUgYmFja3VwIGZpbGVzKSAqL1xuICBmaWxlRmlsdGVyPzogKGZpbGVuYW1lOiBzdHJpbmcpID0+IGJvb2xlYW47XG59XG5cbmNvbnN0IEVNUFRZX0RJRkY6IE1hbmlmZXN0RGlmZlJlc3VsdCA9IHsgYWRkZWQ6IFtdLCBtb2RpZmllZDogW10sIHJlbW92ZWQ6IFtdLCB1bmNoYW5nZWQ6IFtdIH07XG5jb25zdCBEQVRFX0ZPTERFUl9QQVRURVJOID0gL15cXGR7NH0tXFxkezJ9LVxcZHsyfSQvO1xuXG5leHBvcnQgY2xhc3MgTWVtb3J5U3RvcmFnZUxheWVyIGltcGxlbWVudHMgSVN0b3JhZ2VMYXllciB7XG4gIHByaXZhdGUgcmVhZG9ubHkgYmFja2VuZDogSVN0b3JhZ2VCYWNrZW5kO1xuICBwcml2YXRlIHJlYWRvbmx5IG1hbmlmZXN0ID0gbmV3IFN0b3JhZ2VNYW5pZmVzdCgpO1xuICBwcml2YXRlIHJlYWRvbmx5IGluZGV4ID0gbmV3IE1ldGFkYXRhSW5kZXgoKTtcbiAgcHJpdmF0ZSByZWFkb25seSBpbmRleEZpbGU6IE1lbW9yeUluZGV4RmlsZTtcbiAgcHJpdmF0ZSByZWFkb25seSBtZW1vcmllc0Rpcjogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IHNjYW5Db29sZG93bk1zOiBudW1iZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgZmlsZUZpbHRlcj86IChmaWxlbmFtZTogc3RyaW5nKSA9PiBib29sZWFuO1xuXG4gIHByaXZhdGUgbGFzdFNjYW5UaW1lc3RhbXAgPSAwO1xuICBwcml2YXRlIHNjYW5JblByb2dyZXNzOiBQcm9taXNlPE1hbmlmZXN0RGlmZlJlc3VsdD4gfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBjb2xkU3RhcnREb25lID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBmaWxlT3BzOiBGaWxlT3BlcmF0aW9uc1NlcnZpY2UsXG4gICAgb3B0aW9uczogTWVtb3J5U3RvcmFnZUxheWVyT3B0aW9uc1xuICApIHtcbiAgICB0aGlzLm1lbW9yaWVzRGlyID0gb3B0aW9ucy5tZW1vcmllc0RpcjtcbiAgICB0aGlzLnNjYW5Db29sZG93bk1zID0gb3B0aW9ucy5zY2FuQ29vbGRvd25NcyA/PyAxMDAwO1xuICAgIHRoaXMuZmlsZUZpbHRlciA9IG9wdGlvbnMuZmlsZUZpbHRlcjtcblxuICAgIGlmIChvcHRpb25zLnN0b3JhZ2VCYWNrZW5kKSB7XG4gICAgICB0aGlzLmJhY2tlbmQgPSBvcHRpb25zLnN0b3JhZ2VCYWNrZW5kO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmJhY2tlbmQgPSBuZXcgRmlsZVN0b3JhZ2VCYWNrZW5kKGZpbGVPcHMpO1xuICAgIH1cblxuICAgIGNvbnN0IGluZGV4UGF0aCA9IHBhdGguam9pbih0aGlzLm1lbW9yaWVzRGlyLCAnX2luZGV4Lmpzb24nKTtcbiAgICB0aGlzLmluZGV4RmlsZSA9IG5ldyBNZW1vcnlJbmRleEZpbGUoaW5kZXhQYXRoLCBmaWxlT3BzLCB7XG4gICAgICBkZWJvdW5jZU1zOiBvcHRpb25zLmluZGV4RGVib3VuY2VNcyA/PyAyMDAwLFxuICAgIH0pO1xuICB9XG5cbiAgLy8gLS0tLSBJU3RvcmFnZUxheWVyIGltcGxlbWVudGF0aW9uIC0tLS1cblxuICBhc3luYyBzY2FuKCk6IFByb21pc2U8TWFuaWZlc3REaWZmUmVzdWx0PiB7XG4gICAgLy8gQ29sZCBzdGFydDogdHJ5IGxvYWRpbmcgZnJvbSBfaW5kZXguanNvbiBmaXJzdFxuICAgIGlmICghdGhpcy5jb2xkU3RhcnREb25lKSB7XG4gICAgICB0aGlzLmNvbGRTdGFydERvbmUgPSB0cnVlO1xuICAgICAgcmV0dXJuIHRoaXMuY29sZFN0YXJ0KCk7XG4gICAgfVxuXG4gICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICBpZiAobm93IC0gdGhpcy5sYXN0U2NhblRpbWVzdGFtcCA8IHRoaXMuc2NhbkNvb2xkb3duTXMpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhgTWVtb3J5U3RvcmFnZUxheWVyLnNjYW46IENPT0xET1dOIEFDVElWRSDigJQgc2tpcHBpbmcgZGlzayBJL08gKCR7dGhpcy5zY2FuQ29vbGRvd25NcyAtIChub3cgLSB0aGlzLmxhc3RTY2FuVGltZXN0YW1wKX1tcyByZW1haW5pbmcpYCk7XG4gICAgICByZXR1cm4gRU1QVFlfRElGRjtcbiAgICB9XG5cbiAgICAvLyBEZWR1cGxpY2F0ZSBjb25jdXJyZW50IHNjYW5zXG4gICAgaWYgKHRoaXMuc2NhbkluUHJvZ3Jlc3MpIHtcbiAgICAgIHJldHVybiB0aGlzLnNjYW5JblByb2dyZXNzO1xuICAgIH1cblxuICAgIHRoaXMuc2NhbkluUHJvZ3Jlc3MgPSB0aGlzLnBlcmZvcm1TY2FuKCk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLnNjYW5JblByb2dyZXNzO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLnNjYW5JblByb2dyZXNzID0gbnVsbDtcbiAgICB9XG4gIH1cblxuICBhc3luYyBsaXN0U3VtbWFyaWVzKCk6IFByb21pc2U8RWxlbWVudEluZGV4RW50cnlbXT4ge1xuICAgIGF3YWl0IHRoaXMuc2NhbigpO1xuICAgIHJldHVybiB0aGlzLmRlZHVwbGljYXRlQnlOYW1lKHRoaXMuaW5kZXguZ2V0QWxsKCkpO1xuICB9XG5cbiAgYXN5bmMgZ2V0SW5kZXhlZFBhdGhzKCk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICBhd2FpdCB0aGlzLnNjYW4oKTtcbiAgICBjb25zdCBkZWR1cGxpY2F0ZWQgPSB0aGlzLmRlZHVwbGljYXRlQnlOYW1lKHRoaXMuaW5kZXguZ2V0QWxsKCkpO1xuICAgIHJldHVybiBkZWR1cGxpY2F0ZWQubWFwKGVudHJ5ID0+IGVudHJ5LmZpbGVQYXRoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWR1cGxpY2F0ZSBpbmRleCBlbnRyaWVzIGJ5IG5vcm1hbGl6ZWQgbmFtZS5cbiAgICogV2hlbiB0aGUgc2FtZSBtZW1vcnkgYXBwZWFycyBpbiBtdWx0aXBsZSBkYXRlIGZvbGRlcnMsIGtlZXAgdGhlIG9uZVxuICAgKiB3aXRoIHRoZSBoaWdoZXN0IG10aW1lTXMgKG1vc3QgcmVjZW50bHkgbW9kaWZpZWQpLlxuICAgKlxuICAgKiBJc3N1ZSAjNjU0OiBTYW1lIG1lbW9yeSBmaWxlcyBkdXBsaWNhdGVkIGFjcm9zcyB+MTUwIGRhdGUgZm9sZGVyc1xuICAgKiBpbmZsYXRlZCBjb3VudHMgZnJvbSB+NzUwIHVuaXF1ZSB0byB+MywxMDArIGxvYWRlZCBtZW1vcmllcy5cbiAgICovXG4gIHByaXZhdGUgZGVkdXBsaWNhdGVCeU5hbWUoZW50cmllczogRWxlbWVudEluZGV4RW50cnlbXSk6IEVsZW1lbnRJbmRleEVudHJ5W10ge1xuICAgIGNvbnN0IGJ5TmFtZSA9IG5ldyBNYXA8c3RyaW5nLCBFbGVtZW50SW5kZXhFbnRyeT4oKTtcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgIGNvbnN0IGtleSA9IFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKGVudHJ5Lm5hbWUpLm5vcm1hbGl6ZWRDb250ZW50LnRvTG93ZXJDYXNlKCk7XG4gICAgICBjb25zdCBleGlzdGluZyA9IGJ5TmFtZS5nZXQoa2V5KTtcbiAgICAgIGlmICghZXhpc3RpbmcgfHwgZW50cnkubXRpbWVNcyA+IGV4aXN0aW5nLm10aW1lTXMpIHtcbiAgICAgICAgYnlOYW1lLnNldChrZXksIGVudHJ5KTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIFsuLi5ieU5hbWUudmFsdWVzKCldO1xuICB9XG5cbiAgZ2V0UGF0aEJ5TmFtZShuYW1lOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IG5vcm1hbGl6ZWROYW1lID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUobmFtZSkubm9ybWFsaXplZENvbnRlbnQ7XG4gICAgcmV0dXJuIHRoaXMuaW5kZXguZ2V0UGF0aEJ5TmFtZShub3JtYWxpemVkTmFtZSk7XG4gIH1cblxuICBoYXNDb21wbGV0ZWRTY2FuKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmxhc3RTY2FuVGltZXN0YW1wID4gMDtcbiAgfVxuXG4gIGFzeW5jIG5vdGlmeVNhdmVkKHJlbGF0aXZlUGF0aDogc3RyaW5nLCBhYnNvbHV0ZVBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgdGhpcy5iYWNrZW5kLnJlYWRGaWxlKGFic29sdXRlUGF0aCk7XG4gICAgICBjb25zdCBtZXRhID0gYXdhaXQgdGhpcy5iYWNrZW5kLnN0YXQoYWJzb2x1dGVQYXRoKTtcbiAgICAgIGNvbnN0IGV4dHJhY3RlZCA9IE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLmV4dHJhY3RNZXRhZGF0YShjb250ZW50LCByZWxhdGl2ZVBhdGgpO1xuXG4gICAgICBjb25zdCBlbnRyeTogRWxlbWVudEluZGV4RW50cnkgPSB7XG4gICAgICAgIGZpbGVQYXRoOiByZWxhdGl2ZVBhdGgsXG4gICAgICAgIG5hbWU6IGV4dHJhY3RlZC5uYW1lID8/ICd1bm5hbWVkJyxcbiAgICAgICAgZGVzY3JpcHRpb246IGV4dHJhY3RlZC5kZXNjcmlwdGlvbiA/PyAnJyxcbiAgICAgICAgdmVyc2lvbjogZXh0cmFjdGVkLnZlcnNpb24gPz8gJzEuMC4wJyxcbiAgICAgICAgYXV0aG9yOiBleHRyYWN0ZWQuYXV0aG9yID8/ICcnLFxuICAgICAgICB0YWdzOiBleHRyYWN0ZWQudGFncyA/PyBbXSxcbiAgICAgICAgbXRpbWVNczogbWV0YS5tdGltZU1zLFxuICAgICAgICBzaXplQnl0ZXM6IG1ldGEuc2l6ZUJ5dGVzLFxuICAgICAgICBhdXRvTG9hZDogZXh0cmFjdGVkLmF1dG9Mb2FkLFxuICAgICAgICBwcmlvcml0eTogZXh0cmFjdGVkLnByaW9yaXR5LFxuICAgICAgICBtZW1vcnlUeXBlOiBleHRyYWN0ZWQubWVtb3J5VHlwZSxcbiAgICAgICAgdG90YWxFbnRyaWVzOiBleHRyYWN0ZWQudG90YWxFbnRyaWVzLFxuICAgICAgfTtcblxuICAgICAgdGhpcy5pbmRleC5zZXQoZW50cnkpO1xuICAgICAgdGhpcy5tYW5pZmVzdC5zZXQocmVsYXRpdmVQYXRoLCBtZXRhLm10aW1lTXMpO1xuICAgICAgdGhpcy5pbmRleEZpbGUuc2NoZWR1bGVXcml0ZSh0aGlzLmluZGV4LmdldEFsbCgpKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmRlYnVnKCdNZW1vcnlTdG9yYWdlTGF5ZXIubm90aWZ5U2F2ZWQgZmFpbGVkLCBpbnZhbGlkYXRpbmcnLCB7XG4gICAgICAgIHJlbGF0aXZlUGF0aCxcbiAgICAgICAgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKSxcbiAgICAgIH0pO1xuICAgICAgdGhpcy5pbnZhbGlkYXRlKCk7XG4gICAgfVxuICB9XG5cbiAgbm90aWZ5RGVsZXRlZChyZWxhdGl2ZVBhdGg6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuaW5kZXgucmVtb3ZlKHJlbGF0aXZlUGF0aCk7XG4gICAgdGhpcy5tYW5pZmVzdC5yZW1vdmUocmVsYXRpdmVQYXRoKTtcbiAgICB0aGlzLmluZGV4RmlsZS5zY2hlZHVsZVdyaXRlKHRoaXMuaW5kZXguZ2V0QWxsKCkpO1xuICB9XG5cbiAgaW52YWxpZGF0ZSgpOiB2b2lkIHtcbiAgICB0aGlzLmxhc3RTY2FuVGltZXN0YW1wID0gMDtcbiAgfVxuXG4gIGNsZWFyKCk6IHZvaWQge1xuICAgIHRoaXMuaW5kZXhGaWxlLmRpc3Bvc2UoKTsgIC8vIENhbmNlbCBwZW5kaW5nIGRlYm91bmNlZCB3cml0ZSAocHJldmVudHMgRU5PVEVNUFRZIGluIHRlc3RzKVxuICAgIHRoaXMuaW5kZXguY2xlYXIoKTtcbiAgICB0aGlzLm1hbmlmZXN0LmNsZWFyKCk7XG4gICAgdGhpcy5sYXN0U2NhblRpbWVzdGFtcCA9IDA7XG4gIH1cblxuICAvLyAtLS0tIE1lbW9yeS1zcGVjaWZpYyBtZXRob2RzIC0tLS1cblxuICAvKipcbiAgICogUmV0dXJuIGluZGV4IGVudHJpZXMgd2hlcmUgYXV0b0xvYWQgPT09IHRydWUsIHNvcnRlZCBieSBwcmlvcml0eSBhc2NlbmRpbmcuXG4gICAqIFB1cmUgaW4tbWVtb3J5IOKAlCBkb2VzIE5PVCB0cmlnZ2VyIGEgc2Nhbi5cbiAgICovXG4gIGdldEF1dG9Mb2FkRW50cmllcygpOiBFbGVtZW50SW5kZXhFbnRyeVtdIHtcbiAgICByZXR1cm4gdGhpcy5pbmRleC5nZXRBbGwoKVxuICAgICAgLmZpbHRlcihlbnRyeSA9PiBlbnRyeS5hdXRvTG9hZCA9PT0gdHJ1ZSlcbiAgICAgIC5zb3J0KChhLCBiKSA9PiAoYS5wcmlvcml0eSA/PyA5OTkpIC0gKGIucHJpb3JpdHkgPz8gOTk5KSk7XG4gIH1cblxuICAvKipcbiAgICogRnVsbCBkaXNrIHNjYW4gb2YgYWxsIHN1YmRpcmVjdG9yaWVzICsgd3JpdGUgX2luZGV4Lmpzb24uXG4gICAqL1xuICBhc3luYyByZWJ1aWxkSW5kZXgoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgbG9nZ2VyLmluZm8oJ01lbW9yeVN0b3JhZ2VMYXllcjogcmVidWlsZGluZyBpbmRleCBmcm9tIGRpc2suLi4nKTtcbiAgICB0aGlzLmluZGV4LmNsZWFyKCk7XG4gICAgdGhpcy5tYW5pZmVzdC5jbGVhcigpO1xuXG4gICAgYXdhaXQgdGhpcy5wZXJmb3JtU2NhbigpO1xuICAgIGF3YWl0IHRoaXMuaW5kZXhGaWxlLndyaXRlKHRoaXMuaW5kZXguZ2V0QWxsKCkpO1xuXG4gICAgbG9nZ2VyLmluZm8oYE1lbW9yeVN0b3JhZ2VMYXllcjogcmVidWlsZCBjb21wbGV0ZSDigJQgJHt0aGlzLmluZGV4LnNpemV9IGVudHJpZXMgaW5kZXhlZGApO1xuICB9XG5cbiAgLyoqXG4gICAqIEZsdXNoIHBlbmRpbmcgX2luZGV4Lmpzb24gd3JpdGUgYW5kIHJlbGVhc2UgcmVzb3VyY2VzLlxuICAgKi9cbiAgYXN5bmMgZGlzcG9zZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmluZGV4RmlsZS5mbHVzaCgpO1xuICAgIHRoaXMuaW5kZXhGaWxlLmRpc3Bvc2UoKTtcbiAgfVxuXG4gIC8vIC0tLS0gUHJpdmF0ZSAtLS0tXG5cbiAgLyoqXG4gICAqIENvbGQgc3RhcnQ6IHRyeSB0byByZXN0b3JlIGZyb20gX2luZGV4Lmpzb24sIHRoZW4gcnVuIGluY3JlbWVudGFsIHNjYW4uXG4gICAqIEZhbGxzIGJhY2sgdG8gZnVsbCByZWJ1aWxkIGlmIGluZGV4IGlzIG1pc3NpbmcvY29ycnVwdC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgY29sZFN0YXJ0KCk6IFByb21pc2U8TWFuaWZlc3REaWZmUmVzdWx0PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGNhY2hlZCA9IGF3YWl0IHRoaXMuaW5kZXhGaWxlLnJlYWQoKTtcblxuICAgICAgaWYgKGNhY2hlZCkge1xuICAgICAgICAvLyBQb3B1bGF0ZSBpbmRleCBhbmQgbWFuaWZlc3QgZnJvbSBjYWNoZWQgZGF0YVxuICAgICAgICBmb3IgKGNvbnN0IFtyZWxQYXRoLCBlbnRyeV0gb2YgT2JqZWN0LmVudHJpZXMoY2FjaGVkLmVudHJpZXMpKSB7XG4gICAgICAgICAgdGhpcy5pbmRleC5zZXQoZW50cnkpO1xuICAgICAgICAgIHRoaXMubWFuaWZlc3Quc2V0KHJlbFBhdGgsIGVudHJ5Lm10aW1lTXMpO1xuICAgICAgICB9XG4gICAgICAgIGxvZ2dlci5pbmZvKGBNZW1vcnlTdG9yYWdlTGF5ZXI6IGNvbGQgc3RhcnQg4oCUIGxvYWRlZCAke09iamVjdC5rZXlzKGNhY2hlZC5lbnRyaWVzKS5sZW5ndGh9IGVudHJpZXMgZnJvbSBfaW5kZXguanNvbmApO1xuXG4gICAgICAgIC8vIFJ1biBpbmNyZW1lbnRhbCBzY2FuIHRvIGNhdGNoIGNoYW5nZXMgc2luY2UgX2luZGV4Lmpzb24gd2FzIHdyaXR0ZW5cbiAgICAgICAgcmV0dXJuIHRoaXMucGVyZm9ybVNjYW4oKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmRlYnVnKCdNZW1vcnlTdG9yYWdlTGF5ZXI6IGNvbGQgc3RhcnQgX2luZGV4Lmpzb24gcmVhZCBmYWlsZWQsIHJlYnVpbGRpbmcnLCB7XG4gICAgICAgIGVycm9yOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvciksXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBObyB2YWxpZCBfaW5kZXguanNvbiDigJQgZnVsbCByZWJ1aWxkXG4gICAgYXdhaXQgdGhpcy5yZWJ1aWxkSW5kZXgoKTtcbiAgICByZXR1cm4gRU1QVFlfRElGRjtcbiAgfVxuXG4gIC8qKlxuICAgKiBEaXNjb3ZlciBhbGwgc3ViZGlyZWN0b3JpZXMgdG8gc2Nhbi5cbiAgICogUmV0dXJucyBbJ3N5c3RlbScsICdhZGFwdGVycycsIC4uLmRhdGVGb2xkZXJzLCAnJ10gd2hlcmUgJycgPSByb290LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBkaXNjb3ZlclN1YmRpcmVjdG9yaWVzKCk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICBjb25zdCBzdWJkaXJzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGVudHJpZXMgPSBhd2FpdCB0aGlzLmZpbGVPcHMubGlzdERpcmVjdG9yeSh0aGlzLm1lbW9yaWVzRGlyKTtcblxuICAgICAgY29uc3QgZGF0ZUZvbGRlcnM6IHN0cmluZ1tdID0gW107XG4gICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgLy8gSW5jbHVkZSBrbm93biBmaXhlZCBkaXJlY3Rvcmllc1xuICAgICAgICBpZiAoZW50cnkgPT09ICdzeXN0ZW0nIHx8IGVudHJ5ID09PSAnYWRhcHRlcnMnKSB7XG4gICAgICAgICAgc3ViZGlycy5wdXNoKGVudHJ5KTtcbiAgICAgICAgfSBlbHNlIGlmIChEQVRFX0ZPTERFUl9QQVRURVJOLnRlc3QoZW50cnkpKSB7XG4gICAgICAgICAgZGF0ZUZvbGRlcnMucHVzaChlbnRyeSk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gU2tpcCBiYWNrdXBzLywgX2luZGV4Lmpzb24sIGFuZCBvdGhlciBub24tbWVtb3J5IGRpcmVjdG9yaWVzXG4gICAgICB9XG4gICAgICAvLyBTb3J0IGRhdGUgZm9sZGVycyBjaHJvbm9sb2dpY2FsbHkgKG9sZGVzdCBmaXJzdCDihpIgbmV3ZXN0IGxhc3QpXG4gICAgICAvLyBzbyB0aGF0IG5hbWVUb1BhdGggaW4gTWV0YWRhdGFJbmRleCBlbmRzIHVwIHBvaW50aW5nIHRvIHRoZSBuZXdlc3QgY29weVxuICAgICAgZGF0ZUZvbGRlcnMuc29ydCgoYSwgYikgPT4gYS5sb2NhbGVDb21wYXJlKGIpKTtcbiAgICAgIHN1YmRpcnMucHVzaCguLi5kYXRlRm9sZGVycyk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmICgoZXJyb3IgYXMgYW55KS5jb2RlICE9PSAnRU5PRU5UJykge1xuICAgICAgICBsb2dnZXIuZGVidWcoJ01lbW9yeVN0b3JhZ2VMYXllcjogZmFpbGVkIHRvIGxpc3Qgc3ViZGlyZWN0b3JpZXMnLCB7XG4gICAgICAgICAgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQWx3YXlzIGluY2x1ZGUgcm9vdCAoZW1wdHkgc3RyaW5nID0gcm9vdCBkaXJlY3RvcnkpXG4gICAgc3ViZGlycy5wdXNoKCcnKTtcblxuICAgIHJldHVybiBzdWJkaXJzO1xuICB9XG5cbiAgLyoqXG4gICAqIFBlcmZvcm0gYSBmdWxsIGluY3JlbWVudGFsIHNjYW4gYWNyb3NzIGFsbCBzdWJkaXJlY3Rvcmllcy5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcGVyZm9ybVNjYW4oKTogUHJvbWlzZTxNYW5pZmVzdERpZmZSZXN1bHQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgZXhpc3RzID0gYXdhaXQgdGhpcy5iYWNrZW5kLmRpcmVjdG9yeUV4aXN0cyh0aGlzLm1lbW9yaWVzRGlyKTtcbiAgICAgIGlmICghZXhpc3RzKSB7XG4gICAgICAgIGNvbnN0IHJlbW92ZWRQYXRocyA9IHRoaXMuaW5kZXguZ2V0UGF0aHMoKTtcbiAgICAgICAgdGhpcy5pbmRleC5jbGVhcigpO1xuICAgICAgICB0aGlzLm1hbmlmZXN0LmNsZWFyKCk7XG4gICAgICAgIHRoaXMubGFzdFNjYW5UaW1lc3RhbXAgPSBEYXRlLm5vdygpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGFkZGVkOiBbXSxcbiAgICAgICAgICBtb2RpZmllZDogW10sXG4gICAgICAgICAgcmVtb3ZlZDogcmVtb3ZlZFBhdGhzLFxuICAgICAgICAgIHVuY2hhbmdlZDogW10sXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIC8vIDEuIERpc2NvdmVyIHN1YmRpcmVjdG9yaWVzXG4gICAgICBjb25zdCBzdWJkaXJzID0gYXdhaXQgdGhpcy5kaXNjb3ZlclN1YmRpcmVjdG9yaWVzKCk7XG5cbiAgICAgIC8vIDIuIEVudW1lcmF0ZSBhbGwgLnlhbWwgZmlsZXMgYWNyb3NzIHN1YmRpcmVjdG9yaWVzXG4gICAgICBjb25zdCBhbGxSZWxhdGl2ZVBhdGhzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgICBmb3IgKGNvbnN0IHN1YmRpciBvZiBzdWJkaXJzKSB7XG4gICAgICAgIGNvbnN0IGFic0RpciA9IHN1YmRpciA/IHBhdGguam9pbih0aGlzLm1lbW9yaWVzRGlyLCBzdWJkaXIpIDogdGhpcy5tZW1vcmllc0RpcjtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IGZpbGVzID0gYXdhaXQgdGhpcy5iYWNrZW5kLmxpc3RGaWxlcyhhYnNEaXIsICcueWFtbCcpO1xuXG4gICAgICAgICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICAgICAgICAvLyBBcHBseSBmaWxlIGZpbHRlciAoZS5nLiwgZXhjbHVkZSBiYWNrdXAgZmlsZXMpXG4gICAgICAgICAgICBpZiAodGhpcy5maWxlRmlsdGVyICYmICF0aGlzLmZpbGVGaWx0ZXIoZmlsZSkpIHtcbiAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFByZWZpeCB3aXRoIHN1YmRpciBmb3IgcmVsYXRpdmUgcGF0aFxuICAgICAgICAgICAgY29uc3QgcmVsUGF0aCA9IHN1YmRpciA/IGAke3N1YmRpcn0vJHtmaWxlfWAgOiBmaWxlO1xuICAgICAgICAgICAgYWxsUmVsYXRpdmVQYXRocy5wdXNoKHJlbFBhdGgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAvLyBEaXJlY3RvcnkgbWlnaHQgbm90IGV4aXN0IChlLmcuLCBubyBzeXN0ZW0vIGZvbGRlciB5ZXQpXG4gICAgICAgICAgaWYgKChlcnJvciBhcyBhbnkpLmNvZGUgIT09ICdFTk9FTlQnKSB7XG4gICAgICAgICAgICBsb2dnZXIuZGVidWcoYE1lbW9yeVN0b3JhZ2VMYXllcjogZmFpbGVkIHRvIGxpc3QgJHthYnNEaXJ9YCwge1xuICAgICAgICAgICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIDMuIFN0YXQgYWxsIGZpbGVzXG4gICAgICBjb25zdCBzdGF0cyA9IGF3YWl0IHRoaXMuYmFja2VuZC5zdGF0TWFueSh0aGlzLm1lbW9yaWVzRGlyLCBhbGxSZWxhdGl2ZVBhdGhzKTtcblxuICAgICAgLy8gNC4gRGlmZiBhZ2FpbnN0IG1hbmlmZXN0XG4gICAgICBjb25zdCBkaWZmID0gdGhpcy5tYW5pZmVzdC5kaWZmKHN0YXRzKTtcblxuICAgICAgY29uc3QgaGFzQ2hhbmdlcyA9IGRpZmYuYWRkZWQubGVuZ3RoID4gMCB8fCBkaWZmLm1vZGlmaWVkLmxlbmd0aCA+IDAgfHwgZGlmZi5yZW1vdmVkLmxlbmd0aCA+IDA7XG4gICAgICBpZiAoaGFzQ2hhbmdlcykge1xuICAgICAgICBsb2dnZXIuZGVidWcoYE1lbW9yeVN0b3JhZ2VMYXllci5zY2FuOiBESVNLIFNDQU4g4oCUICR7YWxsUmVsYXRpdmVQYXRocy5sZW5ndGh9IGZpbGVzLCAke2RpZmYuYWRkZWQubGVuZ3RofSBhZGRlZCwgJHtkaWZmLm1vZGlmaWVkLmxlbmd0aH0gbW9kaWZpZWQsICR7ZGlmZi5yZW1vdmVkLmxlbmd0aH0gcmVtb3ZlZGApO1xuICAgICAgfVxuXG4gICAgICAvLyA1LiBGb3IgYWRkZWQvbW9kaWZpZWQ6IHJlYWQgZmlsZSwgZXh0cmFjdCBtZXRhZGF0YSwgdXBkYXRlIGluZGV4XG4gICAgICBjb25zdCB0b0luZGV4ID0gWy4uLmRpZmYuYWRkZWQsIC4uLmRpZmYubW9kaWZpZWRdO1xuICAgICAgbGV0IGluZGV4VXBkYXRlZCA9IGZhbHNlO1xuXG4gICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgdG9JbmRleC5tYXAoYXN5bmMgKHJlbFBhdGgpID0+IHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgYWJzUGF0aCA9IHBhdGguam9pbih0aGlzLm1lbW9yaWVzRGlyLCByZWxQYXRoKTtcbiAgICAgICAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCB0aGlzLmJhY2tlbmQucmVhZEZpbGUoYWJzUGF0aCk7XG4gICAgICAgICAgICBjb25zdCBleHRyYWN0ZWQgPSBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5leHRyYWN0TWV0YWRhdGEoY29udGVudCwgcmVsUGF0aCk7XG4gICAgICAgICAgICBjb25zdCBtZXRhID0gc3RhdHMuZ2V0KHJlbFBhdGgpO1xuXG4gICAgICAgICAgICB0aGlzLmluZGV4LnNldCh7XG4gICAgICAgICAgICAgIGZpbGVQYXRoOiByZWxQYXRoLFxuICAgICAgICAgICAgICBuYW1lOiBleHRyYWN0ZWQubmFtZSA/PyAndW5uYW1lZCcsXG4gICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBleHRyYWN0ZWQuZGVzY3JpcHRpb24gPz8gJycsXG4gICAgICAgICAgICAgIHZlcnNpb246IGV4dHJhY3RlZC52ZXJzaW9uID8/ICcxLjAuMCcsXG4gICAgICAgICAgICAgIGF1dGhvcjogZXh0cmFjdGVkLmF1dGhvciA/PyAnJyxcbiAgICAgICAgICAgICAgdGFnczogZXh0cmFjdGVkLnRhZ3MgPz8gW10sXG4gICAgICAgICAgICAgIG10aW1lTXM6IG1ldGE/Lm10aW1lTXMgPz8gMCxcbiAgICAgICAgICAgICAgc2l6ZUJ5dGVzOiBtZXRhPy5zaXplQnl0ZXMgPz8gMCxcbiAgICAgICAgICAgICAgYXV0b0xvYWQ6IGV4dHJhY3RlZC5hdXRvTG9hZCxcbiAgICAgICAgICAgICAgcHJpb3JpdHk6IGV4dHJhY3RlZC5wcmlvcml0eSxcbiAgICAgICAgICAgICAgbWVtb3J5VHlwZTogZXh0cmFjdGVkLm1lbW9yeVR5cGUsXG4gICAgICAgICAgICAgIHRvdGFsRW50cmllczogZXh0cmFjdGVkLnRvdGFsRW50cmllcyxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaW5kZXhVcGRhdGVkID0gdHJ1ZTtcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKGBNZW1vcnlTdG9yYWdlTGF5ZXI6IGZhaWxlZCB0byBpbmRleCAke3JlbFBhdGh9YCwge1xuICAgICAgICAgICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgKTtcblxuICAgICAgLy8gNi4gRm9yIHJlbW92ZWQ6IHJlbW92ZSBmcm9tIGluZGV4XG4gICAgICBmb3IgKGNvbnN0IHJlbFBhdGggb2YgZGlmZi5yZW1vdmVkKSB7XG4gICAgICAgIHRoaXMuaW5kZXgucmVtb3ZlKHJlbFBhdGgpO1xuICAgICAgICBpbmRleFVwZGF0ZWQgPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICAvLyA3LiBVcGRhdGUgbWFuaWZlc3QgYW5kIHRpbWVzdGFtcFxuICAgICAgdGhpcy5tYW5pZmVzdC51cGRhdGUoc3RhdHMpO1xuICAgICAgdGhpcy5sYXN0U2NhblRpbWVzdGFtcCA9IERhdGUubm93KCk7XG5cbiAgICAgIC8vIDguIFNjaGVkdWxlIGRlYm91bmNlZCBfaW5kZXguanNvbiB3cml0ZSBpZiBpbmRleCBjaGFuZ2VkXG4gICAgICBpZiAoaW5kZXhVcGRhdGVkKSB7XG4gICAgICAgIHRoaXMuaW5kZXhGaWxlLnNjaGVkdWxlV3JpdGUodGhpcy5pbmRleC5nZXRBbGwoKSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBkaWZmO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ01lbW9yeVN0b3JhZ2VMYXllci5wZXJmb3JtU2NhbiBmYWlsZWQnLCBlcnJvcik7XG4gICAgICB0aGlzLmxhc3RTY2FuVGltZXN0YW1wID0gRGF0ZS5ub3coKTsgLy8gUHJldmVudCByZXRyeSBzdG9ybXNcbiAgICAgIHJldHVybiBFTVBUWV9ESUZGO1xuICAgIH1cbiAgfVxufVxuIl19