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.

384 lines 52.1 kB
#!/usr/bin/env node /** * Cleanup utility for historical duplicate memory files. * * Issue #702: After Issue #699 fixed ongoing duplication, this utility * deduplicates already duplicated memory files across date folders. */ import fs from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; import { generateContentHash } from '../elements/memories/utils.js'; import { SecureYamlParser } from '../security/secureYamlParser.js'; import { UnicodeValidator } from '../security/validators/unicodeValidator.js'; const DATE_FOLDER_PATTERN = /^\d{4}-\d{2}-\d{2}$/; const YAML_FILE_PATTERN = /\.ya?ml$/i; const VOLATILE_METADATA_KEYS = new Set([ 'unique_id', 'uniqueid', 'author', 'updated', 'updatedat', 'updated_at', 'modified', 'modifiedat', 'modified_at', 'lastmodified', 'last_modified', 'savedat', 'saved_at', 'id' ]); function isBackupFile(filename) { return filename.toLowerCase().includes('backup'); } function normalizePathInput(input) { const normalized = UnicodeValidator.normalize(input); if (!normalized.isValid) { throw new Error(`Invalid path input: ${normalized.detectedIssues?.join(', ')}`); } return normalized.normalizedContent; } function stableSerialize(value) { if (value === null) return 'null'; if (value === undefined) return 'undefined'; if (typeof value !== 'object') { return JSON.stringify(value); } if (Array.isArray(value)) { return `[${value.map(item => stableSerialize(item)).join(',')}]`; } const objectValue = value; const keys = Object.keys(objectValue).sort((a, b) => a.localeCompare(b)); const serializedPairs = keys.map(key => `${JSON.stringify(key)}:${stableSerialize(objectValue[key])}`); return `{${serializedPairs.join(',')}}`; } function normalizeForHash(value) { if (value === null || value === undefined) return value; if (typeof value !== 'object') return value; if (Array.isArray(value)) { return value.map(item => normalizeForHash(item)); } const inputObj = value; const outputObj = {}; for (const [key, child] of Object.entries(inputObj)) { const normalizedKey = key.replace(/[^a-zA-Z0-9]/g, '').toLowerCase(); if (VOLATILE_METADATA_KEYS.has(normalizedKey)) { continue; } outputObj[key] = normalizeForHash(child); } return outputObj; } function getLatestEntryTimestamp(data) { const entries = Array.isArray(data.entries) ? data.entries : []; let latest = 0; for (const entry of entries) { if (!entry || typeof entry !== 'object') continue; const typedEntry = entry; const candidates = [ typedEntry.timestamp, typedEntry.created, typedEntry.createdAt, typedEntry.updatedAt ]; for (const candidate of candidates) { if (typeof candidate !== 'string') continue; const parsed = Date.parse(candidate); if (!Number.isNaN(parsed) && parsed > latest) { latest = parsed; } } } return latest; } function parseMemoryData(rawContent) { const wrapped = `---\n${rawContent}\n---\n`; const parsed = SecureYamlParser.parse(wrapped, { validateContent: false, validateFields: false }); return parsed.data ?? {}; } async function findMemoryCandidates(memoriesDir) { const rootEntries = await fs.readdir(memoriesDir, { withFileTypes: true }); const candidates = []; const errors = []; for (const entry of rootEntries) { if (!entry.isDirectory() || !DATE_FOLDER_PATTERN.test(entry.name)) { continue; } const folderPath = path.join(memoriesDir, entry.name); const files = await fs.readdir(folderPath, { withFileTypes: true }); for (const file of files) { if (!file.isFile()) continue; if (!YAML_FILE_PATTERN.test(file.name)) continue; if (isBackupFile(file.name)) continue; const absolutePath = path.join(folderPath, file.name); // Normalize to forward slashes for consistent cross-platform error messages and comparisons const relativePath = path.join(entry.name, file.name).split(path.sep).join('/'); const rawContent = await fs.readFile(absolutePath, 'utf-8'); const stats = await fs.stat(absolutePath); let data; try { data = parseMemoryData(rawContent); } catch (error) { errors.push(`Failed to parse ${relativePath}: ${error instanceof Error ? error.message : String(error)}`); continue; } const metadata = (data.metadata && typeof data.metadata === 'object') ? data.metadata : {}; const nameFromMeta = typeof metadata.name === 'string' ? metadata.name : undefined; const memoryName = nameFromMeta || path.basename(file.name, path.extname(file.name)); const memoryType = typeof metadata.memoryType === 'string' ? metadata.memoryType : 'user'; const identityKey = `${memoryType.toLowerCase()}::${memoryName.trim().toLowerCase()}`; const normalizedHash = generateContentHash(stableSerialize(normalizeForHash(data))); const entries = Array.isArray(data.entries) ? data.entries : []; candidates.push({ absolutePath, relativePath, identityKey, normalizedHash, memoryName, memoryType, entryCount: entries.length, latestEntryTs: getLatestEntryTimestamp(data), mtimeMs: stats.mtimeMs, sizeBytes: stats.size }); } } return { candidates, errors }; } function selectCanonicalAndRedundant(group) { const sorted = [...group].sort((a, b) => { if (a.entryCount !== b.entryCount) return b.entryCount - a.entryCount; if (a.latestEntryTs !== b.latestEntryTs) return b.latestEntryTs - a.latestEntryTs; if (a.mtimeMs !== b.mtimeMs) return b.mtimeMs - a.mtimeMs; return b.relativePath.localeCompare(a.relativePath); }); return { keep: sorted[0], remove: sorted.slice(1) }; } function createRunId(now) { return now.toISOString().replace(/[:.]/g, '-'); } async function writeJsonReport(reportPath, report) { const reportDir = path.dirname(reportPath); await fs.mkdir(reportDir, { recursive: true }); await fs.writeFile(reportPath, JSON.stringify(report, null, 2), 'utf-8'); } async function invalidateMemoryIndex(memoriesDir) { const indexPath = path.join(memoriesDir, '_index.json'); try { await fs.unlink(indexPath); return true; } catch (error) { if (error.code === 'ENOENT') { return false; } throw error; } } export async function cleanupDuplicateMemories(memoriesDirInput, options = {}) { const memoriesDir = normalizePathInput(memoriesDirInput); const apply = options.apply ?? false; let errors = []; let candidates = []; try { const scan = await findMemoryCandidates(memoriesDir); candidates = scan.candidates; errors = [...errors, ...scan.errors]; } catch (error) { throw new Error(`Failed scanning memory files: ${error instanceof Error ? error.message : String(error)}`); } const grouped = new Map(); for (const candidate of candidates) { const key = `${candidate.identityKey}::${candidate.normalizedHash}`; const list = grouped.get(key); if (list) { list.push(candidate); } else { grouped.set(key, [candidate]); } } const groups = []; const movePlan = []; let bytesReclaimedEstimate = 0; for (const [key, items] of grouped.entries()) { if (items.length < 2) continue; const { keep, remove } = selectCanonicalAndRedundant(items); if (remove.length === 0) continue; groups.push({ key, memoryName: keep.memoryName, memoryType: keep.memoryType, keep: keep.relativePath, remove: remove.map(item => item.relativePath) }); for (const removable of remove) { movePlan.push(removable); bytesReclaimedEstimate += removable.sizeBytes; } } const now = options.now ?? new Date(); const runId = createRunId(now); const defaultBackupDir = path.join(memoriesDir, 'backups', 'dedup', runId); const backupDir = options.backupDir ? normalizePathInput(options.backupDir) : defaultBackupDir; let filesMoved = 0; let indexInvalidated = false; if (apply && movePlan.length > 0) { for (const item of movePlan) { try { const destinationPath = path.join(backupDir, item.relativePath); await fs.mkdir(path.dirname(destinationPath), { recursive: true }); await fs.rename(item.absolutePath, destinationPath); filesMoved += 1; } catch (error) { errors.push(`Failed to move ${item.relativePath}: ${error instanceof Error ? error.message : String(error)}`); } } try { indexInvalidated = await invalidateMemoryIndex(memoriesDir); } catch (error) { errors.push(`Failed to invalidate _index.json: ${error instanceof Error ? error.message : String(error)}`); } } const report = { mode: apply ? 'apply' : 'dry-run', memoriesDir, backupDir: apply ? backupDir : undefined, scannedFiles: candidates.length, duplicateGroups: groups.length, filesToMove: movePlan.length, filesMoved, bytesReclaimedEstimate, indexInvalidated, groups, errors }; if (options.jsonReportPath) { await writeJsonReport(normalizePathInput(options.jsonReportPath), report); } return report; } function parseCliArgs(argv) { const args = [...argv]; let memoriesDir = path.join(os.homedir(), '.dollhouse/portfolio/memories'); const options = { apply: false }; if (args.length > 0 && !args[0].startsWith('--')) { memoriesDir = args.shift(); } for (let i = 0; i < args.length; i++) { const arg = args[i]; if (!arg) continue; if (arg === '--apply') { options.apply = true; continue; } if (arg === '--dry-run') { options.apply = false; continue; } if (arg === '--backup-dir') { const next = args[i + 1]; if (!next || next.startsWith('--')) { throw new Error('Missing value for --backup-dir'); } options.backupDir = next; i += 1; continue; } if (arg === '--json-report') { const next = args[i + 1]; if (!next || next.startsWith('--')) { throw new Error('Missing value for --json-report'); } options.jsonReportPath = next; i += 1; continue; } if (arg === '--help' || arg === '-h') { console.log('Usage: cleanup-duplicate-memories [memoriesDir] [--dry-run] [--apply] [--backup-dir <path>] [--json-report <path>]'); process.exit(0); } throw new Error(`Unknown argument: ${arg}`); } return { memoriesDir, options }; } function printReport(report) { console.log(''); console.log('Memory duplicate cleanup report'); console.log(`Mode: ${report.mode}`); console.log(`Memories directory: ${report.memoriesDir}`); if (report.backupDir) { console.log(`Backup directory: ${report.backupDir}`); } console.log(`Scanned files: ${report.scannedFiles}`); console.log(`Duplicate groups: ${report.duplicateGroups}`); console.log(`Files to move: ${report.filesToMove}`); console.log(`Files moved: ${report.filesMoved}`); console.log(`Estimated bytes reclaimed: ${report.bytesReclaimedEstimate}`); console.log(`Index invalidated: ${report.indexInvalidated ? 'yes' : 'no'}`); if (report.groups.length > 0) { console.log(''); console.log('Duplicate groups:'); for (const group of report.groups) { console.log(`- ${group.memoryName} (${group.memoryType})`); console.log(` keep: ${group.keep}`); for (const removePath of group.remove) { console.log(` remove: ${removePath}`); } } } if (report.errors.length > 0) { console.log(''); console.log('Errors:'); for (const error of report.errors) { console.log(`- ${error}`); } } console.log(''); } if (import.meta.url === `file://${process.argv[1]}`) { try { const { memoriesDir, options } = parseCliArgs(process.argv.slice(2)); const report = await cleanupDuplicateMemories(memoriesDir, options); printReport(report); } catch (error) { console.error(error instanceof Error ? error.message : String(error)); process.exit(1); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xlYW51cC1kdXBsaWNhdGUtbWVtb3JpZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvY2xlYW51cC1kdXBsaWNhdGUtbWVtb3JpZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUNBOzs7OztHQUtHO0FBRUgsT0FBTyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbEMsT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ3pCLE9BQU8sSUFBSSxNQUFNLFdBQVcsQ0FBQztBQUM3QixPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNwRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNuRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUU5RSxNQUFNLG1CQUFtQixHQUFHLHFCQUFxQixDQUFDO0FBQ2xELE1BQU0saUJBQWlCLEdBQUcsV0FBVyxDQUFDO0FBQ3RDLE1BQU0sc0JBQXNCLEdBQUcsSUFBSSxHQUFHLENBQUM7SUFDckMsV0FBVztJQUNYLFVBQVU7SUFDVixRQUFRO0lBQ1IsU0FBUztJQUNULFdBQVc7SUFDWCxZQUFZO0lBQ1osVUFBVTtJQUNWLFlBQVk7SUFDWixhQUFhO0lBQ2IsY0FBYztJQUNkLGVBQWU7SUFDZixTQUFTO0lBQ1QsVUFBVTtJQUNWLElBQUk7Q0FDTCxDQUFDLENBQUM7QUFpREgsU0FBUyxZQUFZLENBQUMsUUFBZ0I7SUFDcEMsT0FBTyxRQUFRLENBQUMsV0FBVyxFQUFFLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQ25ELENBQUM7QUFFRCxTQUFTLGtCQUFrQixDQUFDLEtBQWE7SUFDdkMsTUFBTSxVQUFVLEdBQUcsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3JELElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDeEIsTUFBTSxJQUFJLEtB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QUUsQ0FBQztZQUNsQyxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssS0FBSyxFQUFFLENBQUMsQ0FBQztRQUM1QixDQUFDO0lBQ0gsQ0FBQztJQUNELE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7QUFDbEIsQ0FBQztBQUVELElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLEtBQUssVUFBVSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQztJQUNwRCxJQUFJLENBQUM7UUFDSCxNQUFNLEVBQUUsV0FBVyxFQUFFLE9BQU8sRUFBRSxHQUFHLFlBQVksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3JFLE1BQU0sTUFBTSxHQUFHLE1BQU0sd0JBQXdCLENBQUMsV0FBVyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3BFLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN0QixDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDdEUsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsQixDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIiMhL3Vzci9iaW4vZW52IG5vZGVcbi8qKlxuICogQ2xlYW51cCB1dGlsaXR5IGZvciBoaXN0b3JpY2FsIGR1cGxpY2F0ZSBtZW1vcnkgZmlsZXMuXG4gKlxuICogSXNzdWUgIzcwMjogQWZ0ZXIgSXNzdWUgIzY5OSBmaXhlZCBvbmdvaW5nIGR1cGxpY2F0aW9uLCB0aGlzIHV0aWxpdHlcbiAqIGRlZHVwbGljYXRlcyBhbHJlYWR5IGR1cGxpY2F0ZWQgbWVtb3J5IGZpbGVzIGFjcm9zcyBkYXRlIGZvbGRlcnMuXG4gKi9cblxuaW1wb3J0IGZzIGZyb20gJ25vZGU6ZnMvcHJvbWlzZXMnO1xuaW1wb3J0IG9zIGZyb20gJ25vZGU6b3MnO1xuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCB7IGdlbmVyYXRlQ29udGVudEhhc2ggfSBmcm9tICcuLi9lbGVtZW50cy9tZW1vcmllcy91dGlscy5qcyc7XG5pbXBvcnQgeyBTZWN1cmVZYW1sUGFyc2VyIH0gZnJvbSAnLi4vc2VjdXJpdHkvc2VjdXJlWWFtbFBhcnNlci5qcyc7XG5pbXBvcnQgeyBVbmljb2RlVmFsaWRhdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvdmFsaWRhdG9ycy91bmljb2RlVmFsaWRhdG9yLmpzJztcblxuY29uc3QgREFURV9GT0xERVJfUEFUVEVSTiA9IC9eXFxkezR9LVxcZHsyfS1cXGR7Mn0kLztcbmNvbnN0IFlBTUxfRklMRV9QQVRURVJOID0gL1xcLnlhP21sJC9pO1xuY29uc3QgVk9MQVRJTEVfTUVUQURBVEFfS0VZUyA9IG5ldyBTZXQoW1xuICAndW5pcXVlX2lkJyxcbiAgJ3VuaXF1ZWlkJyxcbiAgJ2F1dGhvcicsXG4gICd1cGRhdGVkJyxcbiAgJ3VwZGF0ZWRhdCcsXG4gICd1cGRhdGVkX2F0JyxcbiAgJ21vZGlmaWVkJyxcbiAgJ21vZGlmaWVkYXQnLFxuICAnbW9kaWZpZWRfYXQnLFxuICAnbGFzdG1vZGlmaWVkJyxcbiAgJ2xhc3RfbW9kaWZpZWQnLFxuICAnc2F2ZWRhdCcsXG4gICdzYXZlZF9hdCcsXG4gICdpZCdcbl0pO1xuXG5pbnRlcmZhY2UgTWVtb3J5Q2FuZGlkYXRlIHtcbiAgYWJzb2x1dGVQYXRoOiBzdHJpbmc7XG4gIHJlbGF0aXZlUGF0aDogc3RyaW5nO1xuICBpZGVudGl0eUtleTogc3RyaW5nO1xuICBub3JtYWxpemVkSGFzaDogc3RyaW5nO1xuICBtZW1vcnlOYW1lOiBzdHJpbmc7XG4gIG1lbW9yeVR5cGU6IHN0cmluZztcbiAgZW50cnlDb3VudDogbnVtYmVyO1xuICBsYXRlc3RFbnRyeVRzOiBudW1iZXI7XG4gIG10aW1lTXM6IG51bWJlcjtcbiAgc2l6ZUJ5dGVzOiBudW1iZXI7XG59XG5cbmludGVyZmFjZSBDYW5kaWRhdGVTY2FuUmVzdWx0IHtcbiAgY2FuZGlkYXRlczogTWVtb3J5Q2FuZGlkYXRlW107XG4gIGVycm9yczogc3RyaW5nW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRHVwbGljYXRlR3JvdXAge1xuICBrZXk6IHN0cmluZztcbiAgbWVtb3J5TmFtZTogc3RyaW5nO1xuICBtZW1vcnlUeXBlOiBzdHJpbmc7XG4gIGtlZXA6IHN0cmluZztcbiAgcmVtb3ZlOiBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNZW1vcnlEdXBsaWNhdGVDbGVhbnVwUmVwb3J0IHtcbiAgbW9kZTogJ2RyeS1ydW4nIHwgJ2FwcGx5JztcbiAgbWVtb3JpZXNEaXI6IHN0cmluZztcbiAgYmFja3VwRGlyPzogc3RyaW5nO1xuICBzY2FubmVkRmlsZXM6IG51bWJlcjtcbiAgZHVwbGljYXRlR3JvdXBzOiBudW1iZXI7XG4gIGZpbGVzVG9Nb3ZlOiBudW1iZXI7XG4gIGZpbGVzTW92ZWQ6IG51bWJlcjtcbiAgYnl0ZXNSZWNsYWltZWRFc3RpbWF0ZTogbnVtYmVyO1xuICBpbmRleEludmFsaWRhdGVkOiBib29sZWFuO1xuICBncm91cHM6IER1cGxpY2F0ZUdyb3VwW107XG4gIGVycm9yczogc3RyaW5nW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2xlYW51cER1cGxpY2F0ZU1lbW9yaWVzT3B0aW9ucyB7XG4gIGFwcGx5PzogYm9vbGVhbjtcbiAgYmFja3VwRGlyPzogc3RyaW5nO1xuICBqc29uUmVwb3J0UGF0aD86IHN0cmluZztcbiAgbm93PzogRGF0ZTtcbn1cblxuZnVuY3Rpb24gaXNCYWNrdXBGaWxlKGZpbGVuYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIGZpbGVuYW1lLnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMoJ2JhY2t1cCcpO1xufVxuXG5mdW5jdGlvbiBub3JtYWxpemVQYXRoSW5wdXQoaW5wdXQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShpbnB1dCk7XG4gIGlmICghbm9ybWFsaXplZC5pc1ZhbGlkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHBhdGggaW5wdXQ6ICR7bm9ybWFsaXplZC5kZXRlY3RlZElzc3Vlcz8uam9pbignLCAnKX1gKTtcbiAgfVxuICByZXR1cm4gbm9ybWFsaXplZC5ub3JtYWxpemVkQ29udGVudDtcbn1cblxuZnVuY3Rpb24gc3RhYmxlU2VyaWFsaXplKHZhbHVlOiB1bmtub3duKTogc3RyaW5nIHtcbiAgaWYgKHZhbHVlID09PSBudWxsKSByZXR1cm4gJ251bGwnO1xuICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuICd1bmRlZmluZWQnO1xuXG4gIGlmICh0eXBlb2YgdmFsdWUgIT09ICdvYmplY3QnKSB7XG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHZhbHVlKTtcbiAgfVxuXG4gIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgIHJldHVybiBgWyR7dmFsdWUubWFwKGl0ZW0gPT4gc3RhYmxlU2VyaWFsaXplKGl0ZW0pKS5qb2luKCcsJyl9XWA7XG4gIH1cblxuICBjb25zdCBvYmplY3RWYWx1ZSA9IHZhbHVlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMob2JqZWN0VmFsdWUpLnNvcnQoKGEsIGIpID0+IGEubG9jYWxlQ29tcGFyZShiKSk7XG4gIGNvbnN0IHNlcmlhbGl6ZWRQYWlycyA9IGtleXMubWFwKGtleSA9PiBgJHtKU09OLnN0cmluZ2lmeShrZXkpfToke3N0YWJsZVNlcmlhbGl6ZShvYmplY3RWYWx1ZVtrZXldKX1gKTtcbiAgcmV0dXJuIGB7JHtzZXJpYWxpemVkUGFpcnMuam9pbignLCcpfX1gO1xufVxuXG5mdW5jdGlvbiBub3JtYWxpemVGb3JIYXNoKHZhbHVlOiB1bmtub3duKTogdW5rbm93biB7XG4gIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB2YWx1ZSA9PT0gdW5kZWZpbmVkKSByZXR1cm4gdmFsdWU7XG4gIGlmICh0eXBlb2YgdmFsdWUgIT09ICdvYmplY3QnKSByZXR1cm4gdmFsdWU7XG5cbiAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgcmV0dXJuIHZhbHVlLm1hcChpdGVtID0+IG5vcm1hbGl6ZUZvckhhc2goaXRlbSkpO1xuICB9XG5cbiAgY29uc3QgaW5wdXRPYmogPSB2YWx1ZSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgY29uc3Qgb3V0cHV0T2JqOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuICBmb3IgKGNvbnN0IFtrZXksIGNoaWxkXSBvZiBPYmplY3QuZW50cmllcyhpbnB1dE9iaikpIHtcbiAgICBjb25zdCBub3JtYWxpemVkS2V5ID0ga2V5LnJlcGxhY2UoL1teYS16QS1aMC05XS9nLCAnJykudG9Mb3dlckNhc2UoKTtcbiAgICBpZiAoVk9MQVRJTEVfTUVUQURBVEFfS0VZUy5oYXMobm9ybWFsaXplZEtleSkpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBvdXRwdXRPYmpba2V5XSA9IG5vcm1hbGl6ZUZvckhhc2goY2hpbGQpO1xuICB9XG4gIHJldHVybiBvdXRwdXRPYmo7XG59XG5cbmZ1bmN0aW9uIGdldExhdGVzdEVudHJ5VGltZXN0YW1wKGRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogbnVtYmVyIHtcbiAgY29uc3QgZW50cmllcyA9IEFycmF5LmlzQXJyYXkoZGF0YS5lbnRyaWVzKSA/IGRhdGEuZW50cmllcyA6IFtdO1xuICBsZXQgbGF0ZXN0ID0gMDtcblxuICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICBpZiAoIWVudHJ5IHx8IHR5cGVvZiBlbnRyeSAhPT0gJ29iamVjdCcpIGNvbnRpbnVlO1xuICAgIGNvbnN0IHR5cGVkRW50cnkgPSBlbnRyeSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICBjb25zdCBjYW5kaWRhdGVzID0gW1xuICAgICAgdHlwZWRFbnRyeS50aW1lc3RhbXAsXG4gICAgICB0eXBlZEVudHJ5LmNyZWF0ZWQsXG4gICAgICB0eXBlZEVudHJ5LmNyZWF0ZWRBdCxcbiAgICAgIHR5cGVkRW50cnkudXBkYXRlZEF0XG4gICAgXTtcbiAgICBmb3IgKGNvbnN0IGNhbmRpZGF0ZSBvZiBjYW5kaWRhdGVzKSB7XG4gICAgICBpZiAodHlwZW9mIGNhbmRpZGF0ZSAhPT0gJ3N0cmluZycpIGNvbnRpbnVlO1xuICAgICAgY29uc3QgcGFyc2VkID0gRGF0ZS5wYXJzZShjYW5kaWRhdGUpO1xuICAgICAgaWYgKCFOdW1iZXIuaXNOYU4ocGFyc2VkKSAmJiBwYXJzZWQgPiBsYXRlc3QpIHtcbiAgICAgICAgbGF0ZXN0ID0gcGFyc2VkO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBsYXRlc3Q7XG59XG5cbmZ1bmN0aW9uIHBhcnNlTWVtb3J5RGF0YShyYXdDb250ZW50OiBzdHJpbmcpOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIGNvbnN0IHdyYXBwZWQgPSBgLS0tXFxuJHtyYXdDb250ZW50fVxcbi0tLVxcbmA7XG4gIGNvbnN0IHBhcnNlZCA9IFNlY3VyZVlhbWxQYXJzZXIucGFyc2Uod3JhcHBlZCwge1xuICAgIHZhbGlkYXRlQ29udGVudDogZmFsc2UsXG4gICAgdmFsaWRhdGVGaWVsZHM6IGZhbHNlXG4gIH0pO1xuICByZXR1cm4gcGFyc2VkLmRhdGEgPz8ge307XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZpbmRNZW1vcnlDYW5kaWRhdGVzKG1lbW9yaWVzRGlyOiBzdHJpbmcpOiBQcm9taXNlPENhbmRpZGF0ZVNjYW5SZXN1bHQ+IHtcbiAgY29uc3Qgcm9vdEVudHJpZXMgPSBhd2FpdCBmcy5yZWFkZGlyKG1lbW9yaWVzRGlyLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSk7XG4gIGNvbnN0IGNhbmRpZGF0ZXM6IE1lbW9yeUNhbmRpZGF0ZVtdID0gW107XG4gIGNvbnN0IGVycm9yczogc3RyaW5nW10gPSBbXTtcblxuICBmb3IgKGNvbnN0IGVudHJ5IG9mIHJvb3RFbnRyaWVzKSB7XG4gICAgaWYgKCFlbnRyeS5pc0RpcmVjdG9yeSgpIHx8ICFEQVRFX0ZPTERFUl9QQVRURVJOLnRlc3QoZW50cnkubmFtZSkpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGNvbnN0IGZvbGRlclBhdGggPSBwYXRoLmpvaW4obWVtb3JpZXNEaXIsIGVudHJ5Lm5hbWUpO1xuICAgIGNvbnN0IGZpbGVzID0gYXdhaXQgZnMucmVhZGRpcihmb2xkZXJQYXRoLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSk7XG4gICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICBpZiAoIWZpbGUuaXNGaWxlKCkpIGNvbnRpbnVlO1xuICAgICAgaWYgKCFZQU1MX0ZJTEVfUEFUVEVSTi50ZXN0KGZpbGUubmFtZSkpIGNvbnRpbnVlO1xuICAgICAgaWYgKGlzQmFja3VwRmlsZShmaWxlLm5hbWUpKSBjb250aW51ZTtcblxuICAgICAgY29uc3QgYWJzb2x1dGVQYXRoID0gcGF0aC5qb2luKGZvbGRlclBhdGgsIGZpbGUubmFtZSk7XG4gICAgICAvLyBOb3JtYWxpemUgdG8gZm9yd2FyZCBzbGFzaGVzIGZvciBjb25zaXN0ZW50IGNyb3NzLXBsYXRmb3JtIGVycm9yIG1lc3NhZ2VzIGFuZCBjb21wYXJpc29uc1xuICAgICAgY29uc3QgcmVsYXRpdmVQYXRoID0gcGF0aC5qb2luKGVudHJ5Lm5hbWUsIGZpbGUubmFtZSkuc3BsaXQocGF0aC5zZXApLmpvaW4oJy8nKTtcbiAgICAgIGNvbnN0IHJhd0NvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZShhYnNvbHV0ZVBhdGgsICd1dGYtOCcpO1xuICAgICAgY29uc3Qgc3RhdHMgPSBhd2FpdCBmcy5zdGF0KGFic29sdXRlUGF0aCk7XG5cbiAgICAgIGxldCBkYXRhOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICAgIHRyeSB7XG4gICAgICAgIGRhdGEgPSBwYXJzZU1lbW9yeURhdGEocmF3Q29udGVudCk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBlcnJvcnMucHVzaChcbiAgICAgICAgICBgRmFpbGVkIHRvIHBhcnNlICR7cmVsYXRpdmVQYXRofTogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YFxuICAgICAgICApO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbWV0YWRhdGEgPSAoZGF0YS5tZXRhZGF0YSAmJiB0eXBlb2YgZGF0YS5tZXRhZGF0YSA9PT0gJ29iamVjdCcpXG4gICAgICAgID8gZGF0YS5tZXRhZGF0YSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPlxuICAgICAgICA6IHt9O1xuICAgICAgY29uc3QgbmFtZUZyb21NZXRhID0gdHlwZW9mIG1ldGFkYXRhLm5hbWUgPT09ICdzdHJpbmcnID8gbWV0YWRhdGEubmFtZSA6IHVuZGVmaW5lZDtcbiAgICAgIGNvbnN0IG1lbW9yeU5hbWUgPSBuYW1lRnJvbU1ldGEgfHwgcGF0aC5iYXNlbmFtZShmaWxlLm5hbWUsIHBhdGguZXh0bmFtZShmaWxlLm5hbWUpKTtcbiAgICAgIGNvbnN0IG1lbW9yeVR5cGUgPSB0eXBlb2YgbWV0YWRhdGEubWVtb3J5VHlwZSA9PT0gJ3N0cmluZycgPyBtZXRhZGF0YS5tZW1vcnlUeXBlIDogJ3VzZXInO1xuICAgICAgY29uc3QgaWRlbnRpdHlLZXkgPSBgJHttZW1vcnlUeXBlLnRvTG93ZXJDYXNlKCl9Ojoke21lbW9yeU5hbWUudHJpbSgpLnRvTG93ZXJDYXNlKCl9YDtcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWRIYXNoID0gZ2VuZXJhdGVDb250ZW50SGFzaChzdGFibGVTZXJpYWxpemUobm9ybWFsaXplRm9ySGFzaChkYXRhKSkpO1xuICAgICAgY29uc3QgZW50cmllcyA9IEFycmF5LmlzQXJyYXkoZGF0YS5lbnRyaWVzKSA/IGRhdGEuZW50cmllcyA6IFtdO1xuXG4gICAgICBjYW5kaWRhdGVzLnB1c2goe1xuICAgICAgICBhYnNvbHV0ZVBhdGgsXG4gICAgICAgIHJlbGF0aXZlUGF0aCxcbiAgICAgICAgaWRlbnRpdHlLZXksXG4gICAgICAgIG5vcm1hbGl6ZWRIYXNoLFxuICAgICAgICBtZW1vcnlOYW1lLFxuICAgICAgICBtZW1vcnlUeXBlLFxuICAgICAgICBlbnRyeUNvdW50OiBlbnRyaWVzLmxlbmd0aCxcbiAgICAgICAgbGF0ZXN0RW50cnlUczogZ2V0TGF0ZXN0RW50cnlUaW1lc3RhbXAoZGF0YSksXG4gICAgICAgIG10aW1lTXM6IHN0YXRzLm10aW1lTXMsXG4gICAgICAgIHNpemVCeXRlczogc3RhdHMuc2l6ZVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBjYW5kaWRhdGVzLFxuICAgIGVycm9yc1xuICB9O1xufVxuXG5mdW5jdGlvbiBzZWxlY3RDYW5vbmljYWxBbmRSZWR1bmRhbnQoZ3JvdXA6IE1lbW9yeUNhbmRpZGF0ZVtdKToge1xuICBrZWVwOiBNZW1vcnlDYW5kaWRhdGU7XG4gIHJlbW92ZTogTWVtb3J5Q2FuZGlkYXRlW107XG59IHtcbiAgY29uc3Qgc29ydGVkID0gWy4uLmdyb3VwXS5zb3J0KChhLCBiKSA9PiB7XG4gICAgaWYgKGEuZW50cnlDb3VudCAhPT0gYi5lbnRyeUNvdW50KSByZXR1cm4gYi5lbnRyeUNvdW50IC0gYS5lbnRyeUNvdW50O1xuICAgIGlmIChhLmxhdGVzdEVudHJ5VHMgIT09IGIubGF0ZXN0RW50cnlUcykgcmV0dXJuIGIubGF0ZXN0RW50cnlUcyAtIGEubGF0ZXN0RW50cnlUcztcbiAgICBpZiAoYS5tdGltZU1zICE9PSBiLm10aW1lTXMpIHJldHVybiBiLm10aW1lTXMgLSBhLm10aW1lTXM7XG4gICAgcmV0dXJuIGIucmVsYXRpdmVQYXRoLmxvY2FsZUNvbXBhcmUoYS5yZWxhdGl2ZVBhdGgpO1xuICB9KTtcbiAgcmV0dXJuIHtcbiAgICBrZWVwOiBzb3J0ZWRbMF0sXG4gICAgcmVtb3ZlOiBzb3J0ZWQuc2xpY2UoMSlcbiAgfTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlUnVuSWQobm93OiBEYXRlKTogc3RyaW5nIHtcbiAgcmV0dXJuIG5vdy50b0lTT1N0cmluZygpLnJlcGxhY2UoL1s6Ll0vZywgJy0nKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gd3JpdGVKc29uUmVwb3J0KHJlcG9ydFBhdGg6IHN0cmluZywgcmVwb3J0OiBNZW1vcnlEdXBsaWNhdGVDbGVhbnVwUmVwb3J0KTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHJlcG9ydERpciA9IHBhdGguZGlybmFtZShyZXBvcnRQYXRoKTtcbiAgYXdhaXQgZnMubWtkaXIocmVwb3J0RGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgYXdhaXQgZnMud3JpdGVGaWxlKHJlcG9ydFBhdGgsIEpTT04uc3RyaW5naWZ5KHJlcG9ydCwgbnVsbCwgMiksICd1dGYtOCcpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBpbnZhbGlkYXRlTWVtb3J5SW5kZXgobWVtb3JpZXNEaXI6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBjb25zdCBpbmRleFBhdGggPSBwYXRoLmpvaW4obWVtb3JpZXNEaXIsICdfaW5kZXguanNvbicpO1xuICB0cnkge1xuICAgIGF3YWl0IGZzLnVubGluayhpbmRleFBhdGgpO1xuICAgIHJldHVybiB0cnVlO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmICgoZXJyb3IgYXMgTm9kZUpTLkVycm5vRXhjZXB0aW9uKS5jb2RlID09PSAnRU5PRU5UJykge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICB0aHJvdyBlcnJvcjtcbiAgfVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYW51cER1cGxpY2F0ZU1lbW9yaWVzKFxuICBtZW1vcmllc0RpcklucHV0OiBzdHJpbmcsXG4gIG9wdGlvbnM6IENsZWFudXBEdXBsaWNhdGVNZW1vcmllc09wdGlvbnMgPSB7fVxuKTogUHJvbWlzZTxNZW1vcnlEdXBsaWNhdGVDbGVhbnVwUmVwb3J0PiB7XG4gIGNvbnN0IG1lbW9yaWVzRGlyID0gbm9ybWFsaXplUGF0aElucHV0KG1lbW9yaWVzRGlySW5wdXQpO1xuICBjb25zdCBhcHBseSA9IG9wdGlvbnMuYXBwbHkgPz8gZmFsc2U7XG4gIGxldCBlcnJvcnM6IHN0cmluZ1tdID0gW107XG5cbiAgbGV0IGNhbmRpZGF0ZXM6IE1lbW9yeUNhbmRpZGF0ZVtdID0gW107XG4gIHRyeSB7XG4gICAgY29uc3Qgc2NhbiA9IGF3YWl0IGZpbmRNZW1vcnlDYW5kaWRhdGVzKG1lbW9yaWVzRGlyKTtcbiAgICBjYW5kaWRhdGVzID0gc2Nhbi5jYW5kaWRhdGVzO1xuICAgIGVycm9ycyA9IFsuLi5lcnJvcnMsIC4uLnNjYW4uZXJyb3JzXTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCBzY2FubmluZyBtZW1vcnkgZmlsZXM6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWApO1xuICB9XG5cbiAgY29uc3QgZ3JvdXBlZCA9IG5ldyBNYXA8c3RyaW5nLCBNZW1vcnlDYW5kaWRhdGVbXT4oKTtcbiAgZm9yIChjb25zdCBjYW5kaWRhdGUgb2YgY2FuZGlkYXRlcykge1xuICAgIGNvbnN0IGtleSA9IGAke2NhbmRpZGF0ZS5pZGVudGl0eUtleX06OiR7Y2FuZGlkYXRlLm5vcm1hbGl6ZWRIYXNofWA7XG4gICAgY29uc3QgbGlzdCA9IGdyb3VwZWQuZ2V0KGtleSk7XG4gICAgaWYgKGxpc3QpIHtcbiAgICAgIGxpc3QucHVzaChjYW5kaWRhdGUpO1xuICAgIH0gZWxzZSB7XG4gICAgICBncm91cGVkLnNldChrZXksIFtjYW5kaWRhdGVdKTtcbiAgICB9XG4gIH1cblxuICBjb25zdCBncm91cHM6IER1cGxpY2F0ZUdyb3VwW10gPSBbXTtcbiAgY29uc3QgbW92ZVBsYW46IE1lbW9yeUNhbmRpZGF0ZVtdID0gW107XG4gIGxldCBieXRlc1JlY2xhaW1lZEVzdGltYXRlID0gMDtcblxuICBmb3IgKGNvbnN0IFtrZXksIGl0ZW1zXSBvZiBncm91cGVkLmVudHJpZXMoKSkge1xuICAgIGlmIChpdGVtcy5sZW5ndGggPCAyKSBjb250aW51ZTtcblxuICAgIGNvbnN0IHsga2VlcCwgcmVtb3ZlIH0gPSBzZWxlY3RDYW5vbmljYWxBbmRSZWR1bmRhbnQoaXRlbXMpO1xuICAgIGlmIChyZW1vdmUubGVuZ3RoID09PSAwKSBjb250aW51ZTtcblxuICAgIGdyb3Vwcy5wdXNoKHtcbiAgICAgIGtleSxcbiAgICAgIG1lbW9yeU5hbWU6IGtlZXAubWVtb3J5TmFtZSxcbiAgICAgIG1lbW9yeVR5cGU6IGtlZXAubWVtb3J5VHlwZSxcbiAgICAgIGtlZXA6IGtlZXAucmVsYXRpdmVQYXRoLFxuICAgICAgcmVtb3ZlOiByZW1vdmUubWFwKGl0ZW0gPT4gaXRlbS5yZWxhdGl2ZVBhdGgpXG4gICAgfSk7XG5cbiAgICBmb3IgKGNvbnN0IHJlbW92YWJsZSBvZiByZW1vdmUpIHtcbiAgICAgIG1vdmVQbGFuLnB1c2gocmVtb3ZhYmxlKTtcbiAgICAgIGJ5dGVzUmVjbGFpbWVkRXN0aW1hdGUgKz0gcmVtb3ZhYmxlLnNpemVCeXRlcztcbiAgICB9XG4gIH1cblxuICBjb25zdCBub3cgPSBvcHRpb25zLm5vdyA/PyBuZXcgRGF0ZSgpO1xuICBjb25zdCBydW5JZCA9IGNyZWF0ZVJ1bklkKG5vdyk7XG4gIGNvbnN0IGRlZmF1bHRCYWNrdXBEaXIgPSBwYXRoLmpvaW4obWVtb3JpZXNEaXIsICdiYWNrdXBzJywgJ2RlZHVwJywgcnVuSWQpO1xuICBjb25zdCBiYWNrdXBEaXIgPSBvcHRpb25zLmJhY2t1cERpciA/IG5vcm1hbGl6ZVBhdGhJbnB1dChvcHRpb25zLmJhY2t1cERpcikgOiBkZWZhdWx0QmFja3VwRGlyO1xuXG4gIGxldCBmaWxlc01vdmVkID0gMDtcbiAgbGV0IGluZGV4SW52YWxpZGF0ZWQgPSBmYWxzZTtcblxuICBpZiAoYXBwbHkgJiYgbW92ZVBsYW4ubGVuZ3RoID4gMCkge1xuICAgIGZvciAoY29uc3QgaXRlbSBvZiBtb3ZlUGxhbikge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgZGVzdGluYXRpb25QYXRoID0gcGF0aC5qb2luKGJhY2t1cERpciwgaXRlbS5yZWxhdGl2ZVBhdGgpO1xuICAgICAgICBhd2FpdCBmcy5ta2RpcihwYXRoLmRpcm5hbWUoZGVzdGluYXRpb25QYXRoKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICAgIGF3YWl0IGZzLnJlbmFtZShpdGVtLmFic29sdXRlUGF0aCwgZGVzdGluYXRpb25QYXRoKTtcbiAgICAgICAgZmlsZXNNb3ZlZCArPSAxO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goXG4gICAgICAgICAgYEZhaWxlZCB0byBtb3ZlICR7aXRlbS5yZWxhdGl2ZVBhdGh9OiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGluZGV4SW52YWxpZGF0ZWQgPSBhd2FpdCBpbnZhbGlkYXRlTWVtb3J5SW5kZXgobWVtb3JpZXNEaXIpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBlcnJvcnMucHVzaChgRmFpbGVkIHRvIGludmFsaWRhdGUgX2luZGV4Lmpzb246ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWApO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHJlcG9ydDogTWVtb3J5RHVwbGljYXRlQ2xlYW51cFJlcG9ydCA9IHtcbiAgICBtb2RlOiBhcHBseSA/ICdhcHBseScgOiAnZHJ5LXJ1bicsXG4gICAgbWVtb3JpZXNEaXIsXG4gICAgYmFja3VwRGlyOiBhcHBseSA/IGJhY2t1cERpciA6IHVuZGVmaW5lZCxcbiAgICBzY2FubmVkRmlsZXM6IGNhbmRpZGF0ZXMubGVuZ3RoLFxuICAgIGR1cGxpY2F0ZUdyb3VwczogZ3JvdXBzLmxlbmd0aCxcbiAgICBmaWxlc1RvTW92ZTogbW92ZVBsYW4ubGVuZ3RoLFxuICAgIGZpbGVzTW92ZWQsXG4gICAgYnl0ZXNSZWNsYWltZWRFc3RpbWF0ZSxcbiAgICBpbmRleEludmFsaWRhdGVkLFxuICAgIGdyb3VwcyxcbiAgICBlcnJvcnNcbiAgfTtcblxuICBpZiAob3B0aW9ucy5qc29uUmVwb3J0UGF0aCkge1xuICAgIGF3YWl0IHdyaXRlSnNvblJlcG9ydChub3JtYWxpemVQYXRoSW5wdXQob3B0aW9ucy5qc29uUmVwb3J0UGF0aCksIHJlcG9ydCk7XG4gIH1cblxuICByZXR1cm4gcmVwb3J0O1xufVxuXG5mdW5jdGlvbiBwYXJzZUNsaUFyZ3MoYXJndjogc3RyaW5nW10pOiB7XG4gIG1lbW9yaWVzRGlyOiBzdHJpbmc7XG4gIG9wdGlvbnM6IENsZWFudXBEdXBsaWNhdGVNZW1vcmllc09wdGlvbnM7XG59IHtcbiAgY29uc3QgYXJncyA9IFsuLi5hcmd2XTtcblxuICBsZXQgbWVtb3JpZXNEaXIgPSBwYXRoLmpvaW4ob3MuaG9tZWRpcigpLCAnLmRvbGxob3VzZS9wb3J0Zm9saW8vbWVtb3JpZXMnKTtcbiAgY29uc3Qgb3B0aW9uczogQ2xlYW51cER1cGxpY2F0ZU1lbW9yaWVzT3B0aW9ucyA9IHsgYXBwbHk6IGZhbHNlIH07XG5cbiAgaWYgKGFyZ3MubGVuZ3RoID4gMCAmJiAhYXJnc1swXS5zdGFydHNXaXRoKCctLScpKSB7XG4gICAgbWVtb3JpZXNEaXIgPSBhcmdzLnNoaWZ0KCkgYXMgc3RyaW5nO1xuICB9XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmdzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3QgYXJnID0gYXJnc1tpXTtcbiAgICBpZiAoIWFyZykgY29udGludWU7XG5cbiAgICBpZiAoYXJnID09PSAnLS1hcHBseScpIHtcbiAgICAgIG9wdGlvbnMuYXBwbHkgPSB0cnVlO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgaWYgKGFyZyA9PT0gJy0tZHJ5LXJ1bicpIHtcbiAgICAgIG9wdGlvbnMuYXBwbHkgPSBmYWxzZTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGlmIChhcmcgPT09ICctLWJhY2t1cC1kaXInKSB7XG4gICAgICBjb25zdCBuZXh0ID0gYXJnc1tpICsgMV07XG4gICAgICBpZiAoIW5leHQgfHwgbmV4dC5zdGFydHNXaXRoKCctLScpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyB2YWx1ZSBmb3IgLS1iYWNrdXAtZGlyJyk7XG4gICAgICB9XG4gICAgICBvcHRpb25zLmJhY2t1cERpciA9IG5leHQ7XG4gICAgICBpICs9IDE7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBpZiAoYXJnID09PSAnLS1qc29uLXJlcG9ydCcpIHtcbiAgICAgIGNvbnN0IG5leHQgPSBhcmdzW2kgKyAxXTtcbiAgICAgIGlmICghbmV4dCB8fCBuZXh0LnN0YXJ0c1dpdGgoJy0tJykpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIHZhbHVlIGZvciAtLWpzb24tcmVwb3J0Jyk7XG4gICAgICB9XG4gICAgICBvcHRpb25zLmpzb25SZXBvcnRQYXRoID0gbmV4dDtcbiAgICAgIGkgKz0gMTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGlmIChhcmcgPT09ICctLWhlbHAnIHx8IGFyZyA9PT0gJy1oJykge1xuICAgICAgY29uc29sZS5sb2coJ1VzYWdlOiBjbGVhbnVwLWR1cGxpY2F0ZS1tZW1vcmllcyBbbWVtb3JpZXNEaXJdIFstLWRyeS1ydW5dIFstLWFwcGx5XSBbLS1iYWNrdXAtZGlyIDxwYXRoPl0gWy0tanNvbi1yZXBvcnQgPHBhdGg+XScpO1xuICAgICAgcHJvY2Vzcy5leGl0KDApO1xuICAgIH1cblxuICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBhcmd1bWVudDogJHthcmd9YCk7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG1lbW9yaWVzRGlyLFxuICAgIG9wdGlvbnNcbiAgfTtcbn1cblxuZnVuY3Rpb24gcHJpbnRSZXBvcnQocmVwb3J0OiBNZW1vcnlEdXBsaWNhdGVDbGVhbnVwUmVwb3J0KTogdm9pZCB7XG4gIGNvbnNvbGUubG9nKCcnKTtcbiAgY29uc29sZS5sb2coJ01lbW9