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.

288 lines 41.5 kB
import * as path from 'path'; import { ElementType } from '../../portfolio/PortfolioManager.js'; import { findElementFlexibly, normalizeElementTypeInput, formatValidElementTypesList, getElementFilename, getElementTypeLabel, resolveElementByName } from './helpers.js'; import { logger } from '../../utils/logger.js'; import { ElementNotFoundError } from '../../utils/ErrorHandler.js'; export async function deleteElement(context, args) { await context.ensureInitialized(); try { const { name, type, deleteData } = args; const { type: normalizedType } = normalizeElementTypeInput(type); if (!normalizedType) { return invalidType(type); } // FIX: Issue #281 - PERSONA now uses standard flow (PersonaManager.delete() handles auto-deactivation) if (normalizedType === ElementType.MEMORY) { return await deleteMemory(context, name, deleteData); } return await deleteStandardElement(context, normalizedType, name, deleteData); } catch (error) { // FIX: Issue #275 - Re-throw ElementNotFoundError so callers can handle it if (error instanceof ElementNotFoundError) { throw error; } logger.error('ElementCRUDHandler.deleteElement', error); const message = error instanceof Error ? error.message : 'Unknown error'; return { content: [{ type: "text", text: `❌ Failed to delete element: ${message}` }] }; } } async function deleteStandardElement(context, type, name, deleteData) { const manager = getManagerForType(context, type); if (!manager) { return unsupportedType(type); } const element = await resolveElementByName(manager, type, name); if (!element) { // FIX: Issue #275 - Throw error instead of returning content for missing elements const label = getElementTypeLabel(type); throw new ElementNotFoundError(label, name); } const fileOps = context.fileOperations; const elementName = element.metadata?.name || name; const dataFiles = await collectDataFiles(context.portfolioManager, type, elementName, fileOps); // Multi-turn interaction: prompt user if data files exist and no preference given. if (dataFiles.length > 0 && deleteData === undefined) { return promptForDataFiles(type, dataFiles); } // Issue #615: When deleteData is provided (follow-up call after prompt), // re-validate that the element still exists. State may have changed between // the initial prompt and the user's confirmation response. if (deleteData !== undefined) { const recheck = await resolveElementByName(manager, type, name); if (!recheck) { const label = getElementTypeLabel(type); throw new ElementNotFoundError(label, name); } } const filePathCandidate = element.filePath || element.filename; const filename = typeof filePathCandidate === 'string' && filePathCandidate.length > 0 ? filePathCandidate : getElementFilename(type, elementName); await manager.delete(filename); if (deleteData && dataFiles.length > 0) { const results = await removeDataFiles(context.portfolioManager, dataFiles, fileOps); return successWithDataFiles(type, name, results); } if (deleteData === false && dataFiles.length > 0) { return successPreserveData(type, name, dataFiles); } return success(type, elementName); } // FIX: Issue #281 - deletePersona removed, PERSONA now uses standard deleteStandardElement flow async function deleteMemory(context, name, deleteData) { const memories = await context.memoryManager.list(); const memory = findElementFlexibly(name, memories); if (!memory) { // FIX: Issue #275 - Throw error instead of returning content for missing elements throw new ElementNotFoundError('Memory', name); } // Deactivate if currently active if (memory.getStatus && memory.getStatus() === 'active' && memory.deactivate) { await memory.deactivate(); } const fileOps = context.fileOperations; const memoryDir = context.portfolioManager.getElementDir(ElementType.MEMORY); const memoryName = memory.metadata.name; // Build list of candidate file paths and find the actual file const fileCandidates = await buildMemoryPathCandidates(memory, memoryDir, fileOps); const memoryPath = await firstExisting(fileOps, fileCandidates); if (!memoryPath) { return { content: [{ type: "text", text: `❌ Memory file '${memoryName}.yaml' not found in portfolio` }] }; } // Back up the memory file before deleting (non-fatal) let movedByBackup = false; if (context.backupService) { try { const result = await context.backupService.backupBeforeDelete(memoryPath, ElementType.MEMORY); movedByBackup = !!result.movedOriginal; } catch (err) { logger.warn(`[deleteMemory] Backup failed: ${err}`); } } // Only delete if backup didn't already move the file if (!movedByBackup) { await fileOps.deleteFile(memoryPath, ElementType.MEMORY, { source: 'deleteElement.deleteMemory' }); } // Invalidate memory manager caches so the storage layer index // reflects the deletion (the handler bypasses memoryManager.delete()). context.memoryManager.clearCache(); // Clean up storage data if requested if (deleteData) { await cleanupMemoryStorage(memoryDir, memoryName, fileOps); } logger.info(`Memory deleted: ${memoryName}${deleteData ? ' (with storage)' : ''}`); return { content: [{ type: "text", text: `✅ Successfully deleted memory '${memoryName}'${deleteData ? ' and its storage data' : ''}` }] }; } /** * Build list of candidate file paths where a memory file might exist. * Checks persisted path, date-organized folders, and root memory directory. */ async function buildMemoryPathCandidates(memory, memoryDir, fileOps) { const candidates = []; const memoryName = memory.metadata.name; // Check for persisted file path on the memory object const persistedPath = typeof memory.getFilePath === 'function' ? memory.getFilePath() : memory.filePath; if (persistedPath && typeof persistedPath === 'string') { candidates.push(path.isAbsolute(persistedPath) ? persistedPath : path.join(memoryDir, persistedPath)); } // Add today's date folder and root folder as fallbacks const today = new Date().toISOString().split('T')[0]; candidates.push(path.join(memoryDir, today, `${memoryName}.yaml`)); candidates.push(path.join(memoryDir, `${memoryName}.yaml`)); // Scan for date-organized directories and add them (most recent first) try { const dirs = await fileOps.listDirectory(memoryDir); const dateDirs = dirs.filter(d => /^\d{4}-\d{2}-\d{2}$/.test(d)); for (const dir of dateDirs.reverse()) { candidates.unshift(path.join(memoryDir, dir, `${memoryName}.yaml`)); } } catch { // Directory listing failed - continue with existing candidates } return candidates; } /** * Clean up memory storage data file (.storage directory). * Silently ignores missing files (ENOENT). */ async function cleanupMemoryStorage(memoryDir, memoryName, fileOps) { const storagePath = path.join(memoryDir, '.storage', `${memoryName}.json`); try { await fileOps.deleteFile(storagePath); } catch (error) { if (error.code !== 'ENOENT') { logger.debug(`Memory storage deletion warning: ${error.message}`); } } } function invalidType(type) { return { content: [{ type: "text", text: `❌ Invalid element type: ${type}\nValid types: ${formatValidElementTypesList()}` }] }; } function unsupportedType(type) { const labelPlural = getElementTypeLabel(type, { plural: true }); return { content: [{ type: "text", text: `❌ Element type '${labelPlural}' is not yet supported for deletion` }] }; } function success(type, name) { const label = getElementTypeLabel(type); return { content: [{ type: "text", text: `✅ Successfully deleted ${label} '${name}'` }] }; } function promptForDataFiles(type, dataFiles) { const label = getElementTypeLabel(type); return { content: [{ type: "text", text: `⚠️ This ${label} has associated data files:\n${dataFiles.join('\n')}\n\nWould you like to delete these data files as well?\n\n• To delete everything (element + data), say: "Yes, delete all data"\n• To keep the data files, say: "No, keep the data"\n• To cancel, say: "Cancel"` }] }; } function successWithDataFiles(type, name, results) { const label = getElementTypeLabel(type); return { content: [{ type: "text", text: `✅ Successfully deleted ${label} '${name}'\n\nAssociated data files:\n${results.join('\n')}` }] }; } function successPreserveData(type, name, dataFiles) { const label = getElementTypeLabel(type); return { content: [{ type: "text", text: `✅ Successfully deleted ${label} '${name}'\n\n⚠️ Associated data files were preserved:\n${dataFiles.join('\n')}` }] }; } function getManagerForType(context, type) { switch (type) { // FIX: Issue #281 - PERSONA now uses standard flow case ElementType.PERSONA: return context.personaManager; case ElementType.SKILL: return context.skillManager; case ElementType.TEMPLATE: return context.templateManager; case ElementType.AGENT: return context.agentManager; case ElementType.ENSEMBLE: return context.ensembleManager; default: return null; } } async function collectDataFiles(portfolio, type, name, fileOps) { if (type !== ElementType.AGENT) { return []; } const stateDir = path.join(portfolio.getElementDir(ElementType.AGENT), '.state'); const stateFile = path.join(stateDir, `${name}-state.json`); try { const stat = await fileOps.stat(stateFile); return [`- .state/${path.basename(stateFile)} (${(stat.size / 1024).toFixed(2)} KB)`]; } catch { return []; } } async function removeDataFiles(portfolio, files, fileOps) { const results = []; const agentDir = portfolio.getElementDir(ElementType.AGENT); for (const entry of files) { const relativePath = entry.replace(/^-\s*/, '').split(' ')[0]; const fullPath = path.join(agentDir, relativePath); try { await fileOps.deleteFile(fullPath, ElementType.AGENT, { source: 'deleteElement.removeDataFiles' }); results.push(`${entry} ✓ deleted`); } catch (error) { logger.warn(`Failed to delete associated data file ${relativePath}: ${error}`); results.push(`${entry} ⚠️ deletion failed`); } } return results; } async function firstExisting(fileOps, paths) { for (const candidate of paths) { if (await fileOps.exists(candidate)) { return candidate; } } return null; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVsZXRlRWxlbWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9oYW5kbGVycy9lbGVtZW50LWNydWQvZGVsZXRlRWxlbWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUM3QixPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFHbEUsT0FBTyxFQUNMLG1CQUFtQixFQUNuQix5QkFBeUIsRUFDekIsMkJBQTJCLEVBQzNCLGtCQUFrQixFQUNsQixtQkFBbUIsRUFDbkIsb0JBQW9CLEVBRXJCLE1BQU0sY0FBYyxDQUFDO0FBQ3RCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUUvQyxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQVluRSxNQUFNLENBQUMsS0FBSyxVQUFVLGFBQWEsQ0FBQyxPQUEyQixFQUFFLElBQXVCO0lBQ3RGLE1BQU0sT0FBTyxDQUFDLGlCQUFpQixFQUFFLENBQUM7SUFFbEMsSUFBSSxDQUFDO1FBQ0gsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLEdBQUcsSUFBSSxDQUFDO1FBRXhDLE1BQU0sRUFBRSxJQUFJLEVBQUUsY0FBYyxFQUFFLEdBQUcseUJBQXlCLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFakUsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3BCLE9BQU8sV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzNCLENBQUM7UUFFRCx1R0FBdUc7UUFDdkcsSUFBSSxjQUFjLEtBQUssV0FBVyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQzFDLE9BQU8sTUFBTSxZQUFZLENBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQztRQUN2RCxDQUFDO1FBRUQsT0FBTyxNQUFNLHFCQUFxQixDQUFDLE9BQU8sRUFBRSxjQUFjLEVBQUUsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQ2hGLENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsMkVBQTJFO1FBQzNFLElBQUksS0FBSyxZQUFZLG9CQUFvQixFQUFFLENBQUM7WUFDMUMsTUFBTSxLQUFLLENBQUM7UUFDZCxDQUFDO1FBQ0QsTUFBTSxDQUFDLEtBQUssQ0FBQyxrQ0FBa0MsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUN4RCxNQUFNLE9BQU8sR0FBRyxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUM7UUFDekUsT0FBTztZQUNMLE9BQU8sRUFBRSxDQUFDO29CQUNSLElBQUksRUFBRSxNQUFNO29CQUNaLElBQUksRUFBRSwrQkFBK0IsT0FBTyxFQUFFO2lCQUMvQyxDQUFDO1NBQ0gsQ0FBQztJQUNKLENBQUM7QUFDSCxDQUFDO0FBRUQsS0FBSyxVQUFVLHFCQUFxQixDQUNsQyxPQUEyQixFQUMzQixJQUFpQixFQUNqQixJQUFZLEVBQ1osVUFBb0I7SUFFcEIsTUFBTSxPQUFPLEdBQUcsaUJBQWlCLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ2pELElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNiLE9BQU8sZUFBZSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQy9CLENBQUM7SUFFRCxNQUFNLE9BQU8sR0FBRyxNQUFNLG9CQUFvQixDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFFaEUsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2Isa0ZBQWtGO1FBQ2xGLE1BQU0sS0FBSyxHQUFHLG1CQUFtQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3hDLE1BQU0sSUFBSSxvQkFBb0IsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDOUMsQ0FBQztJQUVELE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxjQUFjLENBQUM7SUFDdkMsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLFFBQVEsRUFBRSxJQUFJLElBQUksSUFBSSxDQUFDO0lBQ25ELE1BQU0sU0FBUyxHQUFHLE1BQU0sZ0JBQWdCLENBQUMsT0FBTyxDQUFDLGdCQUFnQixFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFFL0YsbUZBQW1GO0lBQ25GLElBQUksU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksVUFBVSxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3JELE9BQU8sa0JBQWtCLENBQUMsSUFBSSxFQUFFLFNBQVMsQ0FBQyxDQUFDO0lBQzdDLENBQUM7SUFFRCx5RUFBeUU7SUFDekUsNEVBQTRFO0lBQzVFLDJEQUEyRDtJQUMzRCxJQUFJLFVBQVUsS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUM3QixNQUFNLE9BQU8sR0FBRyxNQUFNLG9CQUFvQixDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDaEUsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2IsTUFBTSxLQUFLLEdBQUcsbUJBQW1CLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDeEMsTUFBTSxJQUFJLG9CQUFvQixDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQztRQUM5QyxDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU0saUJBQWlCLEdBQUksT0FBZSxDQUFDLFFBQVEsSUFBSyxPQUFlLENBQUMsUUFBUSxDQUFDO0lBQ2pGLE1BQU0sUUFBUSxHQUFHLE9BQU8saUJBQWlCLEtBQUssUUFBUSxJQUFJLGlCQUFpQixDQUFDLE1BQU0sR0FBRyxDQUFDO1FBQ3BGLENBQUMsQ0FBQyxpQkFBaUI7UUFDbkIsQ0FBQyxDQUFDLGtCQUFrQixDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsQ0FBQztJQUUxQyxNQUFNLE9BQU8sQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7SUFFL0IsSUFBSSxVQUFVLElBQUksU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN2QyxNQUFNLE9BQU8sR0FBRyxNQUFNLGVBQWUsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3BGLE9BQU8sb0JBQW9CLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNuRCxDQUFDO0lBRUQsSUFBSSxVQUFVLEtBQUssS0FBSyxJQUFJLFNBQVMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDakQsT0FBTyxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLFNBQVMsQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFFRCxPQUFPLE9BQU8sQ0FBQyxJQUFJLEVBQUUsV0FBVyxDQUFDLENBQUM7QUFDcEMsQ0FBQztBQUVELGdHQUFnRztBQUVoRyxLQUFLLFVBQVUsWUFBWSxDQUN6QixPQUEyQixFQUMzQixJQUFZLEVBQ1osVUFBb0I7SUFFcEIsTUFBTSxRQUFRLEdBQUcsTUFBTSxPQUFPLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3BELE1BQU0sTUFBTSxHQUFHLG1CQUFtQixDQUFDLElBQUksRUFBRSxRQUFRLENBQUMsQ0FBQztJQUVuRCxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDWixrRkFBa0Y7UUFDbEYsTUFBTSxJQUFJLG9CQUFvQixDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQsaUNBQWlDO0lBQ2pDLElBQUksTUFBTSxDQUFDLFNBQVMsSUFBSSxNQUFNLENBQUMsU0FBUyxFQUFFLEtBQUssUUFBUSxJQUFJLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUM3RSxNQUFNLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBRUQsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLGNBQWMsQ0FBQztJQUN2QyxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUM3RSxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQztJQUV4Qyw4REFBOEQ7SUFDOUQsTUFBTSxjQUFjLEdBQUcsTUFBTSx5QkFBeUIsQ0FBQyxNQUFNLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ25GLE1BQU0sVUFBVSxHQUFHLE1BQU0sYUFBYSxDQUFDLE9BQU8sRUFBRSxjQUFjLENBQUMsQ0FBQztJQUVoRSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDaEIsT0FBTztZQUNMLE9BQU8sRUFBRSxDQUFDO29CQUNSLElBQUksRUFBRSxNQUFNO29CQUNaLElBQUksRUFBRSxrQkFBa0IsVUFBVSwrQkFBK0I7aUJBQ2xFLENBQUM7U0FDSCxDQUFDO0lBQ0osQ0FBQztJQUVELHNEQUFzRDtJQUN0RCxJQUFJLGFBQWEsR0FBRyxLQUFLLENBQUM7SUFDMUIsSUFBSSxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDMUIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxNQUFNLEdBQUcsTUFBTSxPQUFPLENBQUMsYUFBYSxDQUFDLGtCQUFrQixDQUFDLFVBQVUsRUFBRSxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDOUYsYUFBYSxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDO1FBQ3pDLENBQUM7UUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ2IsTUFBTSxDQUFDLElBQUksQ0FBQyxpQ0FBaUMsR0FBRyxFQUFFLENBQUMsQ0FBQztRQUN0RCxDQUFDO0lBQ0gsQ0FBQztJQUVELHFEQUFxRDtJQUNyRCxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDbkIsTUFBTSxPQUFPLENBQUMsVUFBVSxDQUFDLFVBQVUsRUFBRSxXQUFXLENBQUMsTUFBTSxFQUFFLEVBQUUsTUFBTSxFQUFFLDRCQUE0QixFQUFFLENBQUMsQ0FBQztJQUNyRyxDQUFDO0lBRUQsOERBQThEO0lBQzlELHVFQUF1RTtJQUN2RSxPQUFPLENBQUMsYUFBYSxDQUFDLFVBQVUsRUFBRSxDQUFDO0lBRW5DLHFDQUFxQztJQUNyQyxJQUFJLFVBQVUsRUFBRSxDQUFDO1FBQ2YsTUFBTSxvQkFBb0IsQ0FBQyxTQUFTLEVBQUUsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFRCxNQUFNLENBQUMsSUFBSSxDQUFDLG1CQUFtQixVQUFVLEdBQUcsVUFBVSxDQUFDLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNuRixPQUFPO1FBQ0wsT0FBTyxFQUFFLENBQUM7Z0JBQ1IsSUFBSSxFQUFFLE1BQU07Z0JBQ1osSUFBSSxFQUFFLGtDQUFrQyxVQUFVLElBQUksVUFBVSxDQUFDLENBQUMsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO2FBQ2xHLENBQUM7S0FDSCxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7R0FHRztBQUNILEtBQUssVUFBVSx5QkFBeUIsQ0FDdEMsTUFBVyxFQUNYLFNBQWlCLEVBQ2pCLE9BQStCO0lBRS9CLE1BQU0sVUFBVSxHQUFhLEVBQUUsQ0FBQztJQUNoQyxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQztJQUV4QyxxREFBcUQ7SUFDckQsTUFBTSxhQUFhLEdBQUcsT0FBTyxNQUFNLENBQUMsV0FBVyxLQUFLLFVBQVU7UUFDNUQsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUU7UUFDdEIsQ0FBQyxDQUFFLE1BQWMsQ0FBQyxRQUFRLENBQUM7SUFFN0IsSUFBSSxhQUFhLElBQUksT0FBTyxhQUFhLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDdkQsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLGFBQWEsQ0FBQyxDQUFDLENBQUM7SUFDeEcsQ0FBQztJQUVELHVEQUF1RDtJQUN2RCxNQUFNLEtBQUssR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNyRCxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEtBQUssRUFBRSxHQUFHLFVBQVUsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUNuRSxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEdBQUcsVUFBVSxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBRTVELHVFQUF1RTtJQUN2RSxJQUFJLENBQUM7UUFDSCxNQUFNLElBQUksR0FBRyxNQUFNLE9BQU8sQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDcEQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLHFCQUFxQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2pFLEtBQUssTUFBTSxHQUFHLElBQUksUUFBUSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUM7WUFDckMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxHQUFHLEVBQUUsR0FBRyxVQUFVLE9BQU8sQ0FBQyxDQUFDLENBQUM7UUFDdEUsQ0FBQztJQUNILENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCwrREFBK0Q7SUFDakUsQ0FBQztJQUVELE9BQU8sVUFBVSxDQUFDO0FBQ3BCLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxLQUFLLFVBQVUsb0JBQW9CLENBQ2pDLFNBQWlCLEVBQ2pCLFVBQWtCLEVBQ2xCLE9BQStCO0lBRS9CLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFVBQVUsRUFBRSxHQUFHLFVBQVUsT0FBTyxDQUFDLENBQUM7SUFDM0UsSUFBSSxDQUFDO1FBQ0gsTUFBTSxPQUFPLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3hDLENBQUM7SUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO1FBQ3BCLElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUM1QixNQUFNLENBQUMsS0FBSyxDQUFDLG9DQUFvQyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUNwRSxDQUFDO0lBQ0gsQ0FBQztBQUNILENBQUM7QUFFRCxTQUFTLFdBQVcsQ0FBQyxJQUFZO0lBQy9CLE9BQU87UUFDTCxPQUFPLEVBQUUsQ0FBQztnQkFDUixJQUFJLEVBQUUsTUFBTTtnQkFDWixJQUFJLEVBQUUsMkJBQTJCLElBQUksa0JBQWtCLDJCQUEyQixFQUFFLEVBQUU7YUFDdkYsQ0FBQztLQUNILENBQUM7QUFDSixDQUFDO0FBRUQsU0FBUyxlQUFlLENBQUMsSUFBaUI7SUFDeEMsTUFBTSxXQUFXLEdBQUcsbUJBQW1CLENBQUMsSUFBSSxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDaEUsT0FBTztRQUNMLE9BQU8sRUFBRSxDQUFDO2dCQUNSLElBQUksRUFBRSxNQUFNO2dCQUNaLElBQUksRUFBRSxtQkFBbUIsV0FBVyxxQ0FBcUM7YUFDMUUsQ0FBQztLQUNILENBQUM7QUFDSixDQUFDO0FBRUQsU0FBUyxPQUFPLENBQUMsSUFBaUIsRUFBRSxJQUFZO0lBQzlDLE1BQU0sS0FBSyxHQUFHLG1CQUFtQixDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3hDLE9BQU87UUFDTCxPQUFPLEVBQUUsQ0FBQztnQkFDUixJQUFJLEVBQUUsTUFBTTtnQkFDWixJQUFJLEVBQUUsMEJBQTBCLEtBQUssS0FBSyxJQUFJLEdBQUc7YUFDbEQsQ0FBQztLQUNILENBQUM7QUFDSixDQUFDO0FBRUQsU0FBUyxrQkFBa0IsQ0FBQyxJQUFpQixFQUFFLFNBQW1CO0lBQ2hFLE1BQU0sS0FBSyxHQUFHLG1CQUFtQixDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3hDLE9BQU87UUFDTCxPQUFPLEVBQUUsQ0FBQztnQkFDUixJQUFJLEVBQUUsTUFBTTtnQkFDWixJQUFJLEVBQUUsWUFBWSxLQUFLLGdDQUFnQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxnTkFBZ047YUFDNVIsQ0FBQztLQUNILENBQUM7QUFDSixDQUFDO0FBRUQsU0FBUyxvQkFBb0IsQ0FBQyxJQUFpQixFQUFFLElBQVksRUFBRSxPQUFpQjtJQUM5RSxNQUFNLEtBQUssR0FBRyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN4QyxPQUFPO1FBQ0wsT0FBTyxFQUFFLENBQUM7Z0JBQ1IsSUFBSSxFQUFFLE1BQU07Z0JBQ1osSUFBSSxFQUFFLDBCQUEwQixLQUFLLEtBQUssSUFBSSxnQ0FBZ0MsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRTthQUNuRyxDQUFDO0tBQ0gsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFTLG1CQUFtQixDQUFDLElBQWlCLEVBQUUsSUFBWSxFQUFFLFNBQW1CO0lBQy9FLE1BQU0sS0FBSyxHQUFHLG1CQUFtQixDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3hDLE9BQU87UUFDTCxPQUFPLEVBQUUsQ0FBQztnQkFDUixJQUFJLEVBQUUsTUFBTTtnQkFDWixJQUFJLEVBQUUsMEJBQTBCLEtBQUssS0FBSyxJQUFJLGtEQUFrRCxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFO2FBQ3ZILENBQUM7S0FDSCxDQUFDO0FBQ0osQ0FBQztBQUVELFNBQVMsaUJBQWlCLENBQUMsT0FBMkIsRUFBRSxJQUFpQjtJQUN2RSxRQUFRLElBQUksRUFBRSxDQUFDO1FBQ2IsbURBQW1EO1FBQ25ELEtBQUssV0FBVyxDQUFDLE9BQU87WUFDdEIsT0FBTyxPQUFPLENBQUMsY0FBK0MsQ0FBQztRQUNqRSxLQUFLLFdBQVcsQ0FBQyxLQUFLO1lBQ3BCLE9BQU8sT0FBTyxDQUFDLFlBQTZDLENBQUM7UUFDL0QsS0FBSyxXQUFXLENBQUMsUUFBUTtZQUN2QixPQUFPLE9BQU8sQ0FBQyxlQUFnRCxDQUFDO1FBQ2xFLEtBQUssV0FBVyxDQUFDLEtBQUs7WUFDcEIsT0FBTyxPQUFPLENBQUMsWUFBNkMsQ0FBQztRQUMvRCxLQUFLLFdBQVcsQ0FBQyxRQUFRO1lBQ3ZCLE9BQU8sT0FBTyxDQUFDLGVBQWdELENBQUM7UUFDbEU7WUFDRSxPQUFPLElBQUksQ0FBQztJQUNoQixDQUFDO0FBQ0gsQ0FBQztBQUVELEtBQUssVUFBVSxnQkFBZ0IsQ0FDN0IsU0FBMkIsRUFDM0IsSUFBaUIsRUFDakIsSUFBWSxFQUNaLE9BQStCO0lBRS9CLElBQUksSUFBSSxLQUFLLFdBQVcsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUMvQixPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFFRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ2pGLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLEdBQUcsSUFBSSxhQUFhLENBQUMsQ0FBQztJQUU1RCxJQUFJLENBQUM7UUFDSCxNQUFNLElBQUksR0FBRyxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDM0MsT0FBTyxDQUFDLFlBQVksSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN4RixDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0FBQ0gsQ0FBQztBQUVELEtBQUssVUFBVSxlQUFlLENBQzVCLFNBQTJCLEVBQzNCLEtBQWUsRUFDZixPQUErQjtJQUUvQixNQUFNLE9BQU8sR0FBYSxFQUFFLENBQUM7SUFDN0IsTUFBTSxRQUFRLEdBQUcsU0FBUyxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUM7SUFFNUQsS0FBSyxNQUFNLEtBQUssSUFBSSxLQUFLLEVBQUUsQ0FBQztRQUMxQixNQUFNLFlBQVksR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDOUQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsWUFBWSxDQUFDLENBQUM7UUFFbkQsSUFBSSxDQUFDO1lBQ0gsTUFBTSxPQUFPLENBQUMsVUFBVSxDQUFDLFFBQVEsRUFBRSxXQUFXLENBQUMsS0FBSyxFQUFFLEVBQUUsTUFBTSxFQUFFLCtCQUErQixFQUFFLENBQUMsQ0FBQztZQUNuRyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSyxZQUFZLENBQUMsQ0FBQztRQUNyQyxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sQ0FBQyxJQUFJLENBQUMseUNBQXlDLFlBQVksS0FBSyxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQy9FLE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLHFCQUFxQixDQUFDLENBQUM7UUFDOUMsQ0FBQztJQUNILENBQUM7SUFFRCxPQUFPLE9BQU8sQ0FBQztBQUNqQixDQUFDO0FBRUQsS0FBSyxVQUFVLGFBQWEsQ0FBQyxPQUErQixFQUFFLEtBQWU7SUFDM0UsS0FBSyxNQUFNLFNBQVMsSUFBSSxLQUFLLEVBQUUsQ0FBQztRQUM5QixJQUFJLE1BQU0sT0FBTyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1lBQ3BDLE9BQU8sU0FBUyxDQUFDO1FBQ25CLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IEVsZW1lbnRUeXBlIH0gZnJvbSAnLi4vLi4vcG9ydGZvbGlvL1BvcnRmb2xpb01hbmFnZXIuanMnO1xuaW1wb3J0IHR5cGUgeyBQb3J0Zm9saW9NYW5hZ2VyIH0gZnJvbSAnLi4vLi4vcG9ydGZvbGlvL1BvcnRmb2xpb01hbmFnZXIuanMnO1xuaW1wb3J0IHsgRWxlbWVudENydWRDb250ZXh0IH0gZnJvbSAnLi90eXBlcy5qcyc7XG5pbXBvcnQge1xuICBmaW5kRWxlbWVudEZsZXhpYmx5LFxuICBub3JtYWxpemVFbGVtZW50VHlwZUlucHV0LFxuICBmb3JtYXRWYWxpZEVsZW1lbnRUeXBlc0xpc3QsXG4gIGdldEVsZW1lbnRGaWxlbmFtZSxcbiAgZ2V0RWxlbWVudFR5cGVMYWJlbCxcbiAgcmVzb2x2ZUVsZW1lbnRCeU5hbWUsXG4gIEVsZW1lbnRNYW5hZ2VyT3BlcmF0aW9uc1xufSBmcm9tICcuL2hlbHBlcnMuanMnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB0eXBlIHsgSUZpbGVPcGVyYXRpb25zU2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL0ZpbGVPcGVyYXRpb25zU2VydmljZS5qcyc7XG5pbXBvcnQgeyBFbGVtZW50Tm90Rm91bmRFcnJvciB9IGZyb20gJy4uLy4uL3V0aWxzL0Vycm9ySGFuZGxlci5qcyc7XG5cbnR5cGUgRWxlbWVudE1hbmFnZXJXaXRoRGVsZXRlPFQ+ID0gRWxlbWVudE1hbmFnZXJPcGVyYXRpb25zPFQ+ICYge1xuICBkZWxldGUoZmlsZVBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD47XG59O1xuXG5pbnRlcmZhY2UgRGVsZXRlRWxlbWVudEFyZ3Mge1xuICBuYW1lOiBzdHJpbmc7XG4gIHR5cGU6IHN0cmluZztcbiAgZGVsZXRlRGF0YT86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBkZWxldGVFbGVtZW50KGNvbnRleHQ6IEVsZW1lbnRDcnVkQ29udGV4dCwgYXJnczogRGVsZXRlRWxlbWVudEFyZ3MpIHtcbiAgYXdhaXQgY29udGV4dC5lbnN1cmVJbml0aWFsaXplZCgpO1xuXG4gIHRyeSB7XG4gICAgY29uc3QgeyBuYW1lLCB0eXBlLCBkZWxldGVEYXRhIH0gPSBhcmdzO1xuXG4gICAgY29uc3QgeyB0eXBlOiBub3JtYWxpemVkVHlwZSB9ID0gbm9ybWFsaXplRWxlbWVudFR5cGVJbnB1dCh0eXBlKTtcblxuICAgIGlmICghbm9ybWFsaXplZFR5cGUpIHtcbiAgICAgIHJldHVybiBpbnZhbGlkVHlwZSh0eXBlKTtcbiAgICB9XG5cbiAgICAvLyBGSVg6IElzc3VlICMyODEgLSBQRVJTT05BIG5vdyB1c2VzIHN0YW5kYXJkIGZsb3cgKFBlcnNvbmFNYW5hZ2VyLmRlbGV0ZSgpIGhhbmRsZXMgYXV0by1kZWFjdGl2YXRpb24pXG4gICAgaWYgKG5vcm1hbGl6ZWRUeXBlID09PSBFbGVtZW50VHlwZS5NRU1PUlkpIHtcbiAgICAgIHJldHVybiBhd2FpdCBkZWxldGVNZW1vcnkoY29udGV4dCwgbmFtZSwgZGVsZXRlRGF0YSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGF3YWl0IGRlbGV0ZVN0YW5kYXJkRWxlbWVudChjb250ZXh0LCBub3JtYWxpemVkVHlwZSwgbmFtZSwgZGVsZXRlRGF0YSk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgLy8gRklYOiBJc3N1ZSAjMjc1IC0gUmUtdGhyb3cgRWxlbWVudE5vdEZvdW5kRXJyb3Igc28gY2FsbGVycyBjYW4gaGFuZGxlIGl0XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRWxlbWVudE5vdEZvdW5kRXJyb3IpIHtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgICBsb2dnZXIuZXJyb3IoJ0VsZW1lbnRDUlVESGFuZGxlci5kZWxldGVFbGVtZW50JywgZXJyb3IpO1xuICAgIGNvbnN0IG1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6ICdVbmtub3duIGVycm9yJztcbiAgICByZXR1cm4ge1xuICAgICAgY29udGVudDogW3tcbiAgICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICAgIHRleHQ6IGDinYwgRmFpbGVkIHRvIGRlbGV0ZSBlbGVtZW50OiAke21lc3NhZ2V9YFxuICAgICAgfV1cbiAgICB9O1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGRlbGV0ZVN0YW5kYXJkRWxlbWVudChcbiAgY29udGV4dDogRWxlbWVudENydWRDb250ZXh0LFxuICB0eXBlOiBFbGVtZW50VHlwZSxcbiAgbmFtZTogc3RyaW5nLFxuICBkZWxldGVEYXRhPzogYm9vbGVhblxuKSB7XG4gIGNvbnN0IG1hbmFnZXIgPSBnZXRNYW5hZ2VyRm9yVHlwZShjb250ZXh0LCB0eXBlKTtcbiAgaWYgKCFtYW5hZ2VyKSB7XG4gICAgcmV0dXJuIHVuc3VwcG9ydGVkVHlwZSh0eXBlKTtcbiAgfVxuXG4gIGNvbnN0IGVsZW1lbnQgPSBhd2FpdCByZXNvbHZlRWxlbWVudEJ5TmFtZShtYW5hZ2VyLCB0eXBlLCBuYW1lKTtcblxuICBpZiAoIWVsZW1lbnQpIHtcbiAgICAvLyBGSVg6IElzc3VlICMyNzUgLSBUaHJvdyBlcnJvciBpbnN0ZWFkIG9mIHJldHVybmluZyBjb250ZW50IGZvciBtaXNzaW5nIGVsZW1lbnRzXG4gICAgY29uc3QgbGFiZWwgPSBnZXRFbGVtZW50VHlwZUxhYmVsKHR5cGUpO1xuICAgIHRocm93IG5ldyBFbGVtZW50Tm90Rm91bmRFcnJvcihsYWJlbCwgbmFtZSk7XG4gIH1cblxuICBjb25zdCBmaWxlT3BzID0gY29udGV4dC5maWxlT3BlcmF0aW9ucztcbiAgY29uc3QgZWxlbWVudE5hbWUgPSBlbGVtZW50Lm1ldGFkYXRhPy5uYW1lIHx8IG5hbWU7XG4gIGNvbnN0IGRhdGFGaWxlcyA9IGF3YWl0IGNvbGxlY3REYXRhRmlsZXMoY29udGV4dC5wb3J0Zm9saW9NYW5hZ2VyLCB0eXBlLCBlbGVtZW50TmFtZSwgZmlsZU9wcyk7XG5cbiAgLy8gTXVsdGktdHVybiBpbnRlcmFjdGlvbjogcHJvbXB0IHVzZXIgaWYgZGF0YSBmaWxlcyBleGlzdCBhbmQgbm8gcHJlZmVyZW5jZSBnaXZlbi5cbiAgaWYgKGRhdGFGaWxlcy5sZW5ndGggPiAwICYmIGRlbGV0ZURhdGEgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiBwcm9tcHRGb3JEYXRhRmlsZXModHlwZSwgZGF0YUZpbGVzKTtcbiAgfVxuXG4gIC8vIElzc3VlICM2MTU6IFdoZW4gZGVsZXRlRGF0YSBpcyBwcm92aWRlZCAoZm9sbG93LXVwIGNhbGwgYWZ0ZXIgcHJvbXB0KSxcbiAgLy8gcmUtdmFsaWRhdGUgdGhhdCB0aGUgZWxlbWVudCBzdGlsbCBleGlzdHMuIFN0YXRlIG1heSBoYXZlIGNoYW5nZWQgYmV0d2VlblxuICAvLyB0aGUgaW5pdGlhbCBwcm9tcHQgYW5kIHRoZSB1c2VyJ3MgY29uZmlybWF0aW9uIHJlc3BvbnNlLlxuICBpZiAoZGVsZXRlRGF0YSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgcmVjaGVjayA9IGF3YWl0IHJlc29sdmVFbGVtZW50QnlOYW1lKG1hbmFnZXIsIHR5cGUsIG5hbWUpO1xuICAgIGlmICghcmVjaGVjaykge1xuICAgICAgY29uc3QgbGFiZWwgPSBnZXRFbGVtZW50VHlwZUxhYmVsKHR5cGUpO1xuICAgICAgdGhyb3cgbmV3IEVsZW1lbnROb3RGb3VuZEVycm9yKGxhYmVsLCBuYW1lKTtcbiAgICB9XG4gIH1cblxuICBjb25zdCBmaWxlUGF0aENhbmRpZGF0ZSA9IChlbGVtZW50IGFzIGFueSkuZmlsZVBhdGggfHwgKGVsZW1lbnQgYXMgYW55KS5maWxlbmFtZTtcbiAgY29uc3QgZmlsZW5hbWUgPSB0eXBlb2YgZmlsZVBhdGhDYW5kaWRhdGUgPT09ICdzdHJpbmcnICYmIGZpbGVQYXRoQ2FuZGlkYXRlLmxlbmd0aCA+IDBcbiAgICA/IGZpbGVQYXRoQ2FuZGlkYXRlXG4gICAgOiBnZXRFbGVtZW50RmlsZW5hbWUodHlwZSwgZWxlbWVudE5hbWUpO1xuXG4gIGF3YWl0IG1hbmFnZXIuZGVsZXRlKGZpbGVuYW1lKTtcblxuICBpZiAoZGVsZXRlRGF0YSAmJiBkYXRhRmlsZXMubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCByZW1vdmVEYXRhRmlsZXMoY29udGV4dC5wb3J0Zm9saW9NYW5hZ2VyLCBkYXRhRmlsZXMsIGZpbGVPcHMpO1xuICAgIHJldHVybiBzdWNjZXNzV2l0aERhdGFGaWxlcyh0eXBlLCBuYW1lLCByZXN1bHRzKTtcbiAgfVxuXG4gIGlmIChkZWxldGVEYXRhID09PSBmYWxzZSAmJiBkYXRhRmlsZXMubGVuZ3RoID4gMCkge1xuICAgIHJldHVybiBzdWNjZXNzUHJlc2VydmVEYXRhKHR5cGUsIG5hbWUsIGRhdGFGaWxlcyk7XG4gIH1cblxuICByZXR1cm4gc3VjY2Vzcyh0eXBlLCBlbGVtZW50TmFtZSk7XG59XG5cbi8vIEZJWDogSXNzdWUgIzI4MSAtIGRlbGV0ZVBlcnNvbmEgcmVtb3ZlZCwgUEVSU09OQSBub3cgdXNlcyBzdGFuZGFyZCBkZWxldGVTdGFuZGFyZEVsZW1lbnQgZmxvd1xuXG5hc3luYyBmdW5jdGlvbiBkZWxldGVNZW1vcnkoXG4gIGNvbnRleHQ6IEVsZW1lbnRDcnVkQ29udGV4dCxcbiAgbmFtZTogc3RyaW5nLFxuICBkZWxldGVEYXRhPzogYm9vbGVhblxuKSB7XG4gIGNvbnN0IG1lbW9yaWVzID0gYXdhaXQgY29udGV4dC5tZW1vcnlNYW5hZ2VyLmxpc3QoKTtcbiAgY29uc3QgbWVtb3J5ID0gZmluZEVsZW1lbnRGbGV4aWJseShuYW1lLCBtZW1vcmllcyk7XG5cbiAgaWYgKCFtZW1vcnkpIHtcbiAgICAvLyBGSVg6IElzc3VlICMyNzUgLSBUaHJvdyBlcnJvciBpbnN0ZWFkIG9mIHJldHVybmluZyBjb250ZW50IGZvciBtaXNzaW5nIGVsZW1lbnRzXG4gICAgdGhyb3cgbmV3IEVsZW1lbnROb3RGb3VuZEVycm9yKCdNZW1vcnknLCBuYW1lKTtcbiAgfVxuXG4gIC8vIERlYWN0aXZhdGUgaWYgY3VycmVudGx5IGFjdGl2ZVxuICBpZiAobWVtb3J5LmdldFN0YXR1cyAmJiBtZW1vcnkuZ2V0U3RhdHVzKCkgPT09ICdhY3RpdmUnICYmIG1lbW9yeS5kZWFjdGl2YXRlKSB7XG4gICAgYXdhaXQgbWVtb3J5LmRlYWN0aXZhdGUoKTtcbiAgfVxuXG4gIGNvbnN0IGZpbGVPcHMgPSBjb250ZXh0LmZpbGVPcGVyYXRpb25zO1xuICBjb25zdCBtZW1vcnlEaXIgPSBjb250ZXh0LnBvcnRmb2xpb01hbmFnZXIuZ2V0RWxlbWVudERpcihFbGVtZW50VHlwZS5NRU1PUlkpO1xuICBjb25zdCBtZW1vcnlOYW1lID0gbWVtb3J5Lm1ldGFkYXRhLm5hbWU7XG5cbiAgLy8gQnVpbGQgbGlzdCBvZiBjYW5kaWRhdGUgZmlsZSBwYXRocyBhbmQgZmluZCB0aGUgYWN0dWFsIGZpbGVcbiAgY29uc3QgZmlsZUNhbmRpZGF0ZXMgPSBhd2FpdCBidWlsZE1lbW9yeVBhdGhDYW5kaWRhdGVzKG1lbW9yeSwgbWVtb3J5RGlyLCBmaWxlT3BzKTtcbiAgY29uc3QgbWVtb3J5UGF0aCA9IGF3YWl0IGZpcnN0RXhpc3RpbmcoZmlsZU9wcywgZmlsZUNhbmRpZGF0ZXMpO1xuXG4gIGlmICghbWVtb3J5UGF0aCkge1xuICAgIHJldHVybiB7XG4gICAgICBjb250ZW50OiBbe1xuICAgICAgICB0eXBlOiBcInRleHRcIixcbiAgICAgICAgdGV4dDogYOKdjCBNZW1vcnkgZmlsZSAnJHttZW1vcnlOYW1lfS55YW1sJyBub3QgZm91bmQgaW4gcG9ydGZvbGlvYFxuICAgICAgfV1cbiAgICB9O1xuICB9XG5cbiAgLy8gQmFjayB1cCB0aGUgbWVtb3J5IGZpbGUgYmVmb3JlIGRlbGV0aW5nIChub24tZmF0YWwpXG4gIGxldCBtb3ZlZEJ5QmFja3VwID0gZmFsc2U7XG4gIGlmIChjb250ZXh0LmJhY2t1cFNlcnZpY2UpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY29udGV4dC5iYWNrdXBTZXJ2aWNlLmJhY2t1cEJlZm9yZURlbGV0ZShtZW1vcnlQYXRoLCBFbGVtZW50VHlwZS5NRU1PUlkpO1xuICAgICAgbW92ZWRCeUJhY2t1cCA9ICEhcmVzdWx0Lm1vdmVkT3JpZ2luYWw7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBsb2dnZXIud2FybihgW2RlbGV0ZU1lbW9yeV0gQmFja3VwIGZhaWxlZDogJHtlcnJ9YCk7XG4gICAgfVxuICB9XG5cbiAgLy8gT25seSBkZWxldGUgaWYgYmFja3VwIGRpZG4ndCBhbHJlYWR5IG1vdmUgdGhlIGZpbGVcbiAgaWYgKCFtb3ZlZEJ5QmFja3VwKSB7XG4gICAgYXdhaXQgZmlsZU9wcy5kZWxldGVGaWxlKG1lbW9yeVBhdGgsIEVsZW1lbnRUeXBlLk1FTU9SWSwgeyBzb3VyY2U6ICdkZWxldGVFbGVtZW50LmRlbGV0ZU1lbW9yeScgfSk7XG4gIH1cblxuICAvLyBJbnZhbGlkYXRlIG1lbW9yeSBtYW5hZ2VyIGNhY2hlcyBzbyB0aGUgc3RvcmFnZSBsYXllciBpbmRleFxuICAvLyByZWZsZWN0cyB0aGUgZGVsZXRpb24gKHRoZSBoYW5kbGVyIGJ5cGFzc2VzIG1lbW9yeU1hbmFnZXIuZGVsZXRlKCkpLlxuICBjb250ZXh0Lm1lbW9yeU1hbmFnZXIuY2xlYXJDYWNoZSgpO1xuXG4gIC8vIENsZWFuIHVwIHN0b3JhZ2UgZGF0YSBpZiByZXF1ZXN0ZWRcbiAgaWYgKGRlbGV0ZURhdGEpIHtcbiAgICBhd2FpdCBjbGVhbnVwTWVtb3J5U3RvcmFnZShtZW1vcnlEaXIsIG1lbW9yeU5hbWUsIGZpbGVPcHMpO1xuICB9XG5cbiAgbG9nZ2VyLmluZm8oYE1lbW9yeSBkZWxldGVkOiAke21lbW9yeU5hbWV9JHtkZWxldGVEYXRhID8gJyAod2l0aCBzdG9yYWdlKScgOiAnJ31gKTtcbiAgcmV0dXJuIHtcbiAgICBjb250ZW50OiBbe1xuICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICB0ZXh0OiBg4pyFIFN1Y2Nlc3NmdWxseSBkZWxldGVkIG1lbW9yeSAnJHttZW1vcnlOYW1lfScke2RlbGV0ZURhdGEgPyAnIGFuZCBpdHMgc3RvcmFnZSBkYXRhJyA6ICcnfWBcbiAgICB9XVxuICB9O1xufVxuXG4vKipcbiAqIEJ1aWxkIGxpc3Qgb2YgY2FuZGlkYXRlIGZpbGUgcGF0aHMgd2hlcmUgYSBtZW1vcnkgZmlsZSBtaWdodCBleGlzdC5cbiAqIENoZWNrcyBwZXJzaXN0ZWQgcGF0aCwgZGF0ZS1vcmdhbml6ZWQgZm9sZGVycywgYW5kIHJvb3QgbWVtb3J5IGRpcmVjdG9yeS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gYnVpbGRNZW1vcnlQYXRoQ2FuZGlkYXRlcyhcbiAgbWVtb3J5OiBhbnksXG4gIG1lbW9yeURpcjogc3RyaW5nLFxuICBmaWxlT3BzOiBJRmlsZU9wZXJhdGlvbnNTZXJ2aWNlXG4pOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gIGNvbnN0IGNhbmRpZGF0ZXM6IHN0cmluZ1tdID0gW107XG4gIGNvbnN0IG1lbW9yeU5hbWUgPSBtZW1vcnkubWV0YWRhdGEubmFtZTtcblxuICAvLyBDaGVjayBmb3IgcGVyc2lzdGVkIGZpbGUgcGF0aCBvbiB0aGUgbWVtb3J5IG9iamVjdFxuICBjb25zdCBwZXJzaXN0ZWRQYXRoID0gdHlwZW9mIG1lbW9yeS5nZXRGaWxlUGF0aCA9PT0gJ2Z1bmN0aW9uJ1xuICAgID8gbWVtb3J5LmdldEZpbGVQYXRoKClcbiAgICA6IChtZW1vcnkgYXMgYW55KS5maWxlUGF0aDtcblxuICBpZiAocGVyc2lzdGVkUGF0aCAmJiB0eXBlb2YgcGVyc2lzdGVkUGF0aCA9PT0gJ3N0cmluZycpIHtcbiAgICBjYW5kaWRhdGVzLnB1c2gocGF0aC5pc0Fic29sdXRlKHBlcnNpc3RlZFBhdGgpID8gcGVyc2lzdGVkUGF0aCA6IHBhdGguam9pbihtZW1vcnlEaXIsIHBlcnNpc3RlZFBhdGgpKTtcbiAgfVxuXG4gIC8vIEFkZCB0b2RheSdzIGRhdGUgZm9sZGVyIGFuZCByb290IGZvbGRlciBhcyBmYWxsYmFja3NcbiAgY29uc3QgdG9kYXkgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkuc3BsaXQoJ1QnKVswXTtcbiAgY2FuZGlkYXRlcy5wdXNoKHBhdGguam9pbihtZW1vcnlEaXIsIHRvZGF5LCBgJHttZW1vcnlOYW1lfS55YW1sYCkpO1xuICBjYW5kaWRhdGVzLnB1c2gocGF0aC5qb2luKG1lbW9yeURpciwgYCR7bWVtb3J5TmFtZX0ueWFtbGApKTtcblxuICAvLyBTY2FuIGZvciBkYXRlLW9yZ2FuaXplZCBkaXJlY3RvcmllcyBhbmQgYWRkIHRoZW0gKG1vc3QgcmVjZW50IGZpcnN0KVxuICB0cnkge1xuICAgIGNvbnN0IGRpcnMgPSBhd2FpdCBmaWxlT3BzLmxpc3REaXJlY3RvcnkobWVtb3J5RGlyKTtcbiAgICBjb25zdCBkYXRlRGlycyA9IGRpcnMuZmlsdGVyKGQgPT4gL15cXGR7NH0tXFxkezJ9LVxcZHsyfSQvLnRlc3QoZCkpO1xuICAgIGZvciAoY29uc3QgZGlyIG9mIGRhdGVEaXJzLnJldmVyc2UoKSkge1xuICAgICAgY2FuZGlkYXRlcy51bnNoaWZ0KHBhdGguam9pbihtZW1vcnlEaXIsIGRpciwgYCR7bWVtb3J5TmFtZX0ueWFtbGApKTtcbiAgICB9XG4gIH0gY2F0Y2gge1xuICAgIC8vIERpcmVjdG9yeSBsaXN0aW5nIGZhaWxlZCAtIGNvbnRpbnVlIHdpdGggZXhpc3RpbmcgY2FuZGlkYXRlc1xuICB9XG5cbiAgcmV0dXJuIGNhbmRpZGF0ZXM7XG59XG5cbi8qKlxuICogQ2xlYW4gdXAgbWVtb3J5IHN0b3JhZ2UgZGF0YSBmaWxlICguc3RvcmFnZSBkaXJlY3RvcnkpLlxuICogU2lsZW50bHkgaWdub3JlcyBtaXNzaW5nIGZpbGVzIChFTk9FTlQpLlxuICovXG5hc3luYyBmdW5jdGlvbiBjbGVhbnVwTWVtb3J5U3RvcmFnZShcbiAgbWVtb3J5RGlyOiBzdHJpbmcsXG4gIG1lbW9yeU5hbWU6IHN0cmluZyxcbiAgZmlsZU9wczogSUZpbGVPcGVyYXRpb25zU2VydmljZVxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHN0b3JhZ2VQYXRoID0gcGF0aC5qb2luKG1lbW9yeURpciwgJy5zdG9yYWdlJywgYCR7bWVtb3J5TmFtZX0uanNvbmApO1xuICB0cnkge1xuICAgIGF3YWl0IGZpbGVPcHMuZGVsZXRlRmlsZShzdG9yYWdlUGF0aCk7XG4gIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICBpZiAoZXJyb3IuY29kZSAhPT0gJ0VOT0VOVCcpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhgTWVtb3J5IHN0b3JhZ2UgZGVsZXRpb24gd2FybmluZzogJHtlcnJvci5tZXNzYWdlfWApO1xuICAgIH1cbiAgfVxufVxuXG5mdW5jdGlvbiBpbnZhbGlkVHlwZSh0eXBlOiBzdHJpbmcpIHtcbiAgcmV0dXJuIHtcbiAgICBjb250ZW50OiBbe1xuICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICB0ZXh0OiBg4p2MIEludmFsaWQgZWxlbWVudCB0eXBlOiAke3R5cGV9XFxuVmFsaWQgdHlwZXM6ICR7Zm9ybWF0VmFsaWRFbGVtZW50VHlwZXNMaXN0KCl9YFxuICAgIH1dXG4gIH07XG59XG5cbmZ1bmN0aW9uIHVuc3VwcG9ydGVkVHlwZSh0eXBlOiBFbGVtZW50VHlwZSkge1xuICBjb25zdCBsYWJlbFBsdXJhbCA9IGdldEVsZW1lbnRUeXBlTGFiZWwodHlwZSwgeyBwbHVyYWw6IHRydWUgfSk7XG4gIHJldHVybiB7XG4gICAgY29udGVudDogW3tcbiAgICAgIHR5cGU6IFwidGV4dFwiLFxuICAgICAgdGV4dDogYOKdjCBFbGVtZW50IHR5cGUgJyR7bGFiZWxQbHVyYWx9JyBpcyBub3QgeWV0IHN1cHBvcnRlZCBmb3IgZGVsZXRpb25gXG4gICAgfV1cbiAgfTtcbn1cblxuZnVuY3Rpb24gc3VjY2Vzcyh0eXBlOiBFbGVtZW50VHlwZSwgbmFtZTogc3RyaW5nKSB7XG4gIGNvbnN0IGxhYmVsID0gZ2V0RWxlbWVudFR5cGVMYWJlbCh0eXBlKTtcbiAgcmV0dXJuIHtcbiAgICBjb250ZW50OiBbe1xuICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICB0ZXh0OiBg4pyFIFN1Y2Nlc3NmdWxseSBkZWxldGVkICR7bGFiZWx9ICcke25hbWV9J2BcbiAgICB9XVxuICB9O1xufVxuXG5mdW5jdGlvbiBwcm9tcHRGb3JEYXRhRmlsZXModHlwZTogRWxlbWVudFR5cGUsIGRhdGFGaWxlczogc3RyaW5nW10pIHtcbiAgY29uc3QgbGFiZWwgPSBnZXRFbGVtZW50VHlwZUxhYmVsKHR5cGUpO1xuICByZXR1cm4ge1xuICAgIGNvbnRlbnQ6IFt7XG4gICAgICB0eXBlOiBcInRleHRcIixcbiAgICAgIHRleHQ6IGDimqDvuI8gIFRoaXMgJHtsYWJlbH0gaGFzIGFzc29jaWF0ZWQgZGF0YSBmaWxlczpcXG4ke2RhdGFGaWxlcy5qb2luKCdcXG4nKX1cXG5cXG5Xb3VsZCB5b3UgbGlrZSB0byBkZWxldGUgdGhlc2UgZGF0YSBmaWxlcyBhcyB3ZWxsP1xcblxcbuKAoiBUbyBkZWxldGUgZXZlcnl0aGluZyAoZWxlbWVudCArIGRhdGEpLCBzYXk6IFwiWWVzLCBkZWxldGUgYWxsIGRhdGFcIlxcbuKAoiBUbyBrZWVwIHRoZSBkYXRhIGZpbGVzLCBzYXk6IFwiTm8sIGtlZXAgdGhlIGRhdGFcIlxcbuKAoiBUbyBjYW5jZWwsIHNheTogXCJDYW5jZWxcImBcbiAgICB9XVxuICB9O1xufVxuXG5mdW5jdGlvbiBzdWNjZXNzV2l0aERhdGFGaWxlcyh0eXBlOiBFbGVtZW50VHlwZSwgbmFtZTogc3RyaW5nLCByZXN1bHRzOiBzdHJpbmdbXSkge1xuICBjb25zdCBsYWJlbCA9IGdldEVsZW1lbnRUeXBlTGFiZWwodHlwZSk7XG4gIHJldHVybiB7XG4gICAgY29udGVudDogW3tcbiAgICAgIHR5cGU6IFwidGV4dFwiLFxuICAgICAgdGV4dDogYOKchSBTdWNjZXNzZnVsbHkgZGVsZXRlZCAke2xhYmVsfSAnJHtuYW1lfSdcXG5cXG5Bc3NvY2lhdGVkIGRhdGEgZmlsZXM6XFxuJHtyZXN1bHRzLmpvaW4oJ1xcbicpfWBcbiAgICB9XVxuICB9O1xufVxuXG5mdW5jdGlvbiBzdWNjZXNzUHJlc2VydmVEYXRhKHR5cGU6IEVsZW1lbnRUeXBlLCBuYW1lOiBzdHJpbmcsIGRhdGFGaWxlczogc3RyaW5nW10pIHtcbiAgY29uc3QgbGFiZWwgPSBnZXRFbGVtZW50VHlwZUxhYmVsKHR5cGUpO1xuICByZXR1cm4ge1xuICAgIGNvbnRlbnQ6IFt7XG4gICAgICB0eXBlOiBcInRleHRcIixcbiAgICAgIHRleHQ6IGDinIUgU3VjY2Vzc2Z1bGx5IGRlbGV0ZWQgJHtsYWJlbH0gJyR7bmFtZX0nXFxuXFxu4pqg77iPIEFzc29jaWF0ZWQgZGF0YSBmaWxlcyB3ZXJlIHByZXNlcnZlZDpcXG4ke2RhdGFGaWxlcy5qb2luKCdcXG4nKX1gXG4gICAgfV1cbiAgfTtcbn1cblxuZnVuY3Rpb24gZ2V0TWFuYWdlckZvclR5cGUoY29udGV4dDogRWxlbWVudENydWRDb250ZXh0LCB0eXBlOiBFbGVtZW50VHlwZSk6IEVsZW1lbnRNYW5hZ2VyV2l0aERlbGV0ZTxhbnk+IHwgbnVsbCB7XG4gIHN3aXRjaCAodHlwZSkge1xuICAgIC8vIEZJWDogSXNzdWUgIzI4MSAtIFBFUlNPTkEgbm93IHVzZXMgc3RhbmRhcmQgZmxvd1xuICAgIGNhc2UgRWxlbWVudFR5cGUuUEVSU09OQTpcbiAgICAgIHJldHVybiBjb250ZXh0LnBlcnNvbmFNYW5hZ2VyIGFzIEVsZW1lbnRNYW5hZ2VyV2l0aERlbGV0ZTxhbnk+O1xuICAgIGNhc2UgRWxlbWVudFR5cGUuU0tJTEw6XG4gICAgICByZXR1cm4gY29udGV4dC5za2lsbE1hbmFnZXIgYXMgRWxlbWVudE1hbmFnZXJXaXRoRGVsZXRlPGFueT47XG4gICAgY2FzZSBFbGVtZW50VHlwZS5URU1QTEFURTpcbiAgICAgIHJldHVybiBjb250ZXh0LnRlbXBsYXRlTWFuYWdlciBhcyBFbGVtZW50TWFuYWdlcldpdGhEZWxldGU8YW55PjtcbiAgICBjYXNlIEVsZW1lbnRUeXBlLkFHRU5UOlxuICAgICAgcmV0dXJuIGNvbnRleHQuYWdlbnRNYW5hZ2VyIGFzIEVsZW1lbnRNYW5hZ2VyV2l0aERlbGV0ZTxhbnk+O1xuICAgIGNhc2UgRWxlbWVudFR5cGUuRU5TRU1CTEU6XG4gICAgICByZXR1cm4gY29udGV4dC5lbnNlbWJsZU1hbmFnZXIgYXMgRWxlbWVudE1hbmFnZXJXaXRoRGVsZXRlPGFueT47XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBudWxsO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNvbGxlY3REYXRhRmlsZXMoXG4gIHBvcnRmb2xpbzogUG9ydGZvbGlvTWFuYWdlcixcbiAgdHlwZTogRWxlbWVudFR5cGUsXG4gIG5hbWU6IHN0cmluZyxcbiAgZmlsZU9wczogSUZpbGVPcGVyYXRpb25zU2VydmljZVxuKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICBpZiAodHlwZSAhPT0gRWxlbWVudFR5cGUuQUdFTlQpIHtcbiAgICByZXR1cm4gW107XG4gIH1cblxuICBjb25zdCBzdGF0ZURpciA9IHBhdGguam9pbihwb3J0Zm9saW8uZ2V0RWxlbWVudERpcihFbGVtZW50VHlwZS5BR0VOVCksICcuc3RhdGUnKTtcbiAgY29uc3Qgc3RhdGVGaWxlID0gcGF0aC5qb2luKHN0YXRlRGlyLCBgJHtuYW1lfS1zdGF0ZS5qc29uYCk7XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBzdGF0ID0gYXdhaXQgZmlsZU9wcy5zdGF0KHN0YXRlRmlsZSk7XG4gICAgcmV0dXJuIFtgLSAuc3RhdGUvJHtwYXRoLmJhc2VuYW1lKHN0YXRlRmlsZSl9ICgkeyhzdGF0LnNpemUgLyAxMDI0KS50b0ZpeGVkKDIpfSBLQilgXTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJlbW92ZURhdGFGaWxlcyhcbiAgcG9ydGZvbGlvOiBQb3J0Zm9saW9NYW5hZ2VyLFxuICBmaWxlczogc3RyaW5nW10sXG4gIGZpbGVPcHM6IElGaWxlT3BlcmF0aW9uc1NlcnZpY2Vcbikge1xuICBjb25zdCByZXN1bHRzOiBzdHJpbmdbXSA9IFtdO1xuICBjb25zdCBhZ2VudERpciA9IHBvcnRmb2xpby5nZXRFbGVtZW50RGlyKEVsZW1lbnRUeXBlLkFHRU5UKTtcblxuICBmb3IgKGNvbnN0IGVudHJ5IG9mIGZpbGVzKSB7XG4gICAgY29uc3QgcmVsYXRpdmVQYXRoID0gZW50cnkucmVwbGFjZSgvXi1cXHMqLywgJycpLnNwbGl0KCcgJylbMF07XG4gICAgY29uc3QgZnVsbFBhdGggPSBwYXRoLmpvaW4oYWdlbnREaXIsIHJlbGF0aXZlUGF0aCk7XG5cbiAgICB0cnkge1xuICAgICAgYXdhaXQgZmlsZU9wcy5kZWxldGVGaWxlKGZ1bGxQYXRoLCBFbGVtZW50VHlwZS5BR0VOVCwgeyBzb3VyY2U6ICdkZWxldGVFbGVtZW50LnJlbW92ZURhdGFGaWxlcycgfSk7XG4gICAgICByZXN1bHRzLnB1c2goYCR7ZW50cnl9IOKckyBkZWxldGVkYCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci53YXJuKGBGYWlsZWQgdG8gZGVsZXRlIGFzc29jaWF0ZWQgZGF0YSBmaWxlICR7cmVsYXRpdmVQYXRofTogJHtlcnJvcn1gKTtcbiAgICAgIHJlc3VsdHMucHVzaChgJHtlbnRyeX0g4pqg77iPIGRlbGV0aW9uIGZhaWxlZGApO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiByZXN1bHRzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBmaXJzdEV4aXN0aW5nKGZpbGVPcHM6IElGaWxlT3BlcmF0aW9uc1NlcnZpY2UsIHBhdGhzOiBzdHJpbmdbXSkge1xuICBmb3IgKGNvbnN0IGNhbmRpZGF0ZSBvZiBwYXRocykge1xuICAgIGlmIChhd2FpdCBmaWxlT3BzLmV4aXN0cyhjYW5kaWRhdGUpKSB7XG4gICAgICByZXR1cm4gY2FuZGlkYXRlO1xuICAgIH1cbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cbiJdfQ==