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.

158 lines 20.3 kB
/** * PortfolioSyncComparer - Compares local and GitHub portfolio elements * * Determines what actions need to be taken based on the sync mode: * - additive: Only add missing elements * - mirror: Make local exactly match GitHub * - backup: Treat GitHub as authoritative source */ import { logger } from '../utils/logger.js'; export class PortfolioSyncComparer { /** * Compare GitHub and local elements to determine sync actions */ compareElements(githubElements, localElements, mode) { const actions = { toAdd: [], toUpdate: [], toDelete: [], toSkip: [] }; logger.info('Comparing elements', { githubCount: this.countElements(githubElements), localCount: this.countElements(localElements), mode }); // Process each element type const allTypes = new Set([ ...githubElements.keys(), ...localElements.keys() ]); for (const type of allTypes) { const githubTypeElements = githubElements.get(type) || []; const localTypeElements = localElements.get(type) || []; this.compareTypeElements(type, githubTypeElements, localTypeElements, mode, actions); } logger.info('Comparison complete', { toAdd: actions.toAdd.length, toUpdate: actions.toUpdate.length, toDelete: actions.toDelete.length, toSkip: actions.toSkip.length }); return actions; } /** * Compare elements of a specific type */ compareTypeElements(type, githubElements, localElements, mode, actions) { // Create maps for efficient lookup const githubMap = new Map(githubElements.map(e => [this.normalizeElementName(e.name), e])); const localMap = new Map(localElements.map(e => [this.normalizeElementName(e.name || e.metadata?.name), e])); // Process GitHub elements (additions and updates) for (const [name, githubElement] of githubMap) { const localElement = localMap.get(name); if (!localElement) { // Element exists on GitHub but not locally actions.toAdd.push({ type, name: githubElement.name, path: githubElement.path, action: 'add', remoteSha: githubElement.sha }); } else if (mode === 'backup' || this.shouldUpdate(githubElement, localElement, mode)) { // Element needs updating actions.toUpdate.push({ type, name: githubElement.name, path: githubElement.path, action: 'update', reason: mode === 'backup' ? 'backup mode' : 'newer on GitHub', localSha: localElement.sha, remoteSha: githubElement.sha }); } else { // Element is up to date or should be skipped actions.toSkip.push({ type, name: githubElement.name, path: githubElement.path, action: 'skip', reason: 'up to date', localSha: localElement.sha, remoteSha: githubElement.sha }); } } // Process local elements (deletions - only in mirror mode) if (mode === 'mirror') { for (const [name, localElement] of localMap) { if (!githubMap.has(name)) { // Element exists locally but not on GitHub actions.toDelete.push({ type, name: localElement.name || localElement.metadata?.name || name, path: `${type}/${name}.md`, action: 'delete', reason: 'not on GitHub', localSha: localElement.sha }); } } } } /** * Determine if an element should be updated */ shouldUpdate(githubElement, localElement, mode) { // In backup mode, always update from GitHub if (mode === 'backup') { return true; } // In additive mode, never update existing elements if (mode === 'additive') { return false; } // In mirror mode, update if SHAs differ // If we don't have SHAs, compare modified dates if (githubElement.sha && localElement.sha) { return githubElement.sha !== localElement.sha; } // Compare modified dates if available if (githubElement.lastModified && localElement.lastModified) { const githubDate = new Date(githubElement.lastModified).getTime(); const localDate = new Date(localElement.lastModified).getTime(); return githubDate > localDate; } // If we can't determine, skip updating in mirror mode return false; } /** * Normalize element name for comparison * Handles different naming formats and extensions */ normalizeElementName(name) { if (!name) return ''; // Remove .md extension if present let normalized = name.replace(/\.md$/i, ''); // Convert to lowercase for comparison normalized = normalized.toLowerCase(); // Replace spaces with hyphens (some systems use different formats) normalized = normalized.replaceAll(/\s+/g, '-'); return normalized; } /** * Count total elements in a map */ countElements(elements) { let count = 0; for (const typeElements of elements.values()) { count += typeElements.length; } return count; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUG9ydGZvbGlvU3luY0NvbXBhcmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N5bmMvUG9ydGZvbGlvU3luY0NvbXBhcmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7O0dBT0c7QUFJSCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFxQjVDLE1BQU0sT0FBTyxxQkFBcUI7SUFDaEM7O09BRUc7SUFDSCxlQUFlLENBQ2IsY0FBb0QsRUFDcEQsYUFBc0MsRUFDdEMsSUFBYztRQUVkLE1BQU0sT0FBTyxHQUFnQjtZQUMzQixLQUFLLEVBQUUsRUFBRTtZQUNULFFBQVEsRUFBRSxFQUFFO1lBQ1osUUFBUSxFQUFFLEVBQUU7WUFDWixNQUFNLEVBQUUsRUFBRTtTQUNYLENBQUM7UUFFRixNQUFNLENBQUMsSUFBSSxDQUFDLG9CQUFvQixFQUFFO1lBQ2hDLFdBQVcsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBQztZQUMvQyxVQUFVLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUM7WUFDN0MsSUFBSTtTQUNMLENBQUMsQ0FBQztRQUVILDRCQUE0QjtRQUM1QixNQUFNLFFBQVEsR0FBRyxJQUFJLEdBQUcsQ0FBQztZQUN2QixHQUFHLGNBQWMsQ0FBQyxJQUFJLEVBQUU7WUFDeEIsR0FBRyxhQUFhLENBQUMsSUFBSSxFQUFFO1NBQ3hCLENBQUMsQ0FBQztRQUVILEtBQUssTUFBTSxJQUFJLElBQUksUUFBUSxFQUFFLENBQUM7WUFDNUIsTUFBTSxrQkFBa0IsR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUMxRCxNQUFNLGlCQUFpQixHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBRXhELElBQUksQ0FBQyxtQkFBbUIsQ0FDdEIsSUFBSSxFQUNKLGtCQUFrQixFQUNsQixp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SUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2xFLE1BQU0sU0FBUyxHQUFHLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNoRSxPQUFPLFVBQVUsR0FBRyxTQUFTLENBQUM7UUFDaEMsQ0FBQztRQUVELHNEQUFzRDtRQUN0RCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRDs7O09BR0c7SUFDSyxvQkFBb0IsQ0FBQyxJQUFZO1FBQ3ZDLElBQUksQ0FBQyxJQUFJO1lBQUUsT0FBTyxFQUFFLENBQUM7UUFFckIsa0NBQWtDO1FBQ2xDLElBQUksVUFBVSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRTVDLHNDQUFzQztRQUN0QyxVQUFVLEdBQUcsVUFBVSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBRXRDLG1FQUFtRTtRQUNuRSxVQUFVLEdBQUcsVUFBVSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFFaEQsT0FBTyxVQUFVLENBQUM7SUFDcEIsQ0FBQztJQUVEOztPQUVHO0lBQ0ssYUFBYSxDQUFDLFFBQWlDO1FBQ3JELElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztRQUNkLEtBQUssTUFBTSxZQUFZLElBQUksUUFBUSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUM7WUFDN0MsS0FBSyxJQUFJLFlBQVksQ0FBQyxNQUFNLENBQUM7UUFDL0IsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBQb3J0Zm9saW9TeW5jQ29tcGFyZXIgLSBDb21wYXJlcyBsb2NhbCBhbmQgR2l0SHViIHBvcnRmb2xpbyBlbGVtZW50c1xuICogXG4gKiBEZXRlcm1pbmVzIHdoYXQgYWN0aW9ucyBuZWVkIHRvIGJlIHRha2VuIGJhc2VkIG9uIHRoZSBzeW5jIG1vZGU6XG4gKiAtIGFkZGl0aXZlOiBPbmx5IGFkZCBtaXNzaW5nIGVsZW1lbnRzXG4gKiAtIG1pcnJvcjogTWFrZSBsb2NhbCBleGFjdGx5IG1hdGNoIEdpdEh1YlxuICogLSBiYWNrdXA6IFRyZWF0IEdpdEh1YiBhcyBhdXRob3JpdGF0aXZlIHNvdXJjZVxuICovXG5cbmltcG9ydCB7IEVsZW1lbnRUeXBlIH0gZnJvbSAnLi4vcG9ydGZvbGlvL3R5cGVzLmpzJztcbmltcG9ydCB7IEdpdEh1YkluZGV4RW50cnkgfSBmcm9tICcuLi9wb3J0Zm9saW8vR2l0SHViUG9ydGZvbGlvSW5kZXhlci5qcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuXG5leHBvcnQgdHlwZSBTeW5jTW9kZSA9ICdhZGRpdGl2ZScgfCAnbWlycm9yJyB8ICdiYWNrdXAnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFN5bmNBY3Rpb24ge1xuICB0eXBlOiBFbGVtZW50VHlwZTtcbiAgbmFtZTogc3RyaW5nO1xuICBwYXRoOiBzdHJpbmc7XG4gIGFjdGlvbjogJ2FkZCcgfCAndXBkYXRlJyB8ICdkZWxldGUnIHwgJ3NraXAnO1xuICByZWFzb24/OiBzdHJpbmc7XG4gIGxvY2FsU2hhPzogc3RyaW5nO1xuICByZW1vdGVTaGE/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3luY0FjdGlvbnMge1xuICB0b0FkZDogU3luY0FjdGlvbltdO1xuICB0b1VwZGF0ZTogU3luY0FjdGlvbltdO1xuICB0b0RlbGV0ZTogU3luY0FjdGlvbltdO1xuICB0b1NraXA6IFN5bmNBY3Rpb25bXTtcbn1cblxuZXhwb3J0IGNsYXNzIFBvcnRmb2xpb1N5bmNDb21wYXJlciB7XG4gIC8qKlxuICAgKiBDb21wYXJlIEdpdEh1YiBhbmQgbG9jYWwgZWxlbWVudHMgdG8gZGV0ZXJtaW5lIHN5bmMgYWN0aW9uc1xuICAgKi9cbiAgY29tcGFyZUVsZW1lbnRzKFxuICAgIGdpdGh1YkVsZW1lbnRzOiBNYXA8RWxlbWVudFR5cGUsIEdpdEh1YkluZGV4RW50cnlbXT4sXG4gICAgbG9jYWxFbGVtZW50czogTWFwPEVsZW1lbnRUeXBlLCBhbnlbXT4sXG4gICAgbW9kZTogU3luY01vZGVcbiAgKTogU3luY0FjdGlvbnMge1xuICAgIGNvbnN0IGFjdGlvbnM6IFN5bmNBY3Rpb25zID0ge1xuICAgICAgdG9BZGQ6IFtdLFxuICAgICAgdG9VcGRhdGU6IFtdLFxuICAgICAgdG9EZWxldGU6IFtdLFxuICAgICAgdG9Ta2lwOiBbXVxuICAgIH07XG5cbiAgICBsb2dnZXIuaW5mbygnQ29tcGFyaW5nIGVsZW1lbnRzJywgeyBcbiAgICAgIGdpdGh1YkNvdW50OiB0aGlzLmNvdW50RWxlbWVudHMoZ2l0aHViRWxlbWVudHMpLFxuICAgICAgbG9jYWxDb3VudDogdGhpcy5jb3VudEVsZW1lbnRzKGxvY2FsRWxlbWVudHMpLFxuICAgICAgbW9kZSBcbiAgICB9KTtcblxuICAgIC8vIFByb2Nlc3MgZWFjaCBlbGVtZW50IHR5cGVcbiAgICBjb25zdCBhbGxUeXBlcyA9IG5ldyBTZXQoW1xuICAgICAgLi4uZ2l0aHViRWxlbWVudHMua2V5cygpLFxuICAgICAgLi4ubG9jYWxFbGVtZW50cy5rZXlzKClcbiAgICBdKTtcblxuICAgIGZvciAoY29uc3QgdHlwZSBvZiBhbGxUeXBlcykge1xuICAgICAgY29uc3QgZ2l0aHViVHlwZUVsZW1lbnRzID0gZ2l0aHViRWxlbWVudHMuZ2V0KHR5cGUpIHx8IFtdO1xuICAgICAgY29uc3QgbG9jYWxUeXBlRWxlbWVudHMgPSBsb2NhbEVsZW1lbnRzLmdldCh0eXBlKSB8fCBbXTtcbiAgICAgIFxuICAgICAgdGhpcy5jb21wYXJlVHlwZUVsZW1lbnRzKFxuICAgICAgICB0eXBlLFxuICAgICAgICBnaXRodWJUeXBlRWxlbWVudHMsXG4gICAgICAgIGxvY2FsVHlwZUVsZW1lbnRzLFxuICAgICAgICBtb2RlLFxuICAgICAgICBhY3Rpb25zXG4gICAgICApO1xuICAgIH1cblxuICAgIGxvZ2dlci5pbmZvKCdDb21wYXJpc29uIGNvbXBsZXRlJywge1xuICAgICAgdG9BZGQ6IGFjdGlvbnMudG9BZGQubGVuZ3RoLFxuICAgICAgdG9VcGRhdGU6IGFjdGlvbnMudG9VcGRhdGUubGVuZ3RoLFxuICAgICAgdG9EZWxldGU6IGFjdGlvbnMudG9EZWxldGUubGVuZ3RoLFxuICAgICAgdG9Ta2lwOiBhY3Rpb25zLnRvU2tpcC5sZW5ndGhcbiAgICB9KTtcblxuICAgIHJldHVybiBhY3Rpb25zO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbXBhcmUgZWxlbWVudHMgb2YgYSBzcGVjaWZpYyB0eXBlXG4gICAqL1xuICBwcml2YXRlIGNvbXBhcmVUeXBlRWxlbWVudHMoXG4gICAgdHlwZTogRWxlbWVudFR5cGUsXG4gICAgZ2l0aHViRWxlbWVudHM6IEdpdEh1YkluZGV4RW50cnlbXSxcbiAgICBsb2NhbEVsZW1lbnRzOiBhbnlbXSxcbiAgICBtb2RlOiBTeW5jTW9kZSxcbiAgICBhY3Rpb25zOiBTeW5jQWN0aW9uc1xuICApOiB2b2lkIHtcbiAgICAvLyBDcmVhdGUgbWFwcyBmb3IgZWZmaWNpZW50IGxvb2t1cFxuICAgIGNvbnN0IGdpdGh1Yk1hcCA9IG5ldyBNYXAoXG4gICAgICBnaXRodWJFbGVtZW50cy5tYXAoZSA9PiBbdGhpcy5ub3JtYWxpemVFbGVtZW50TmFtZShlLm5hbWUpLCBlXSlcbiAgICApO1xuICAgIGNvbnN0IGxvY2FsTWFwID0gbmV3IE1hcChcbiAgICAgIGxvY2FsRWxlbWVudHMubWFwKGUgPT4gW3RoaXMubm9ybWFsaXplRWxlbWVudE5hbWUoZS5uYW1lIHx8IGUubWV0YWRhdGE/Lm5hbWUpLCBlXSlcbiAgICApO1xuXG4gICAgLy8gUHJvY2VzcyBHaXRIdWIgZWxlbWVudHMgKGFkZGl0aW9ucyBhbmQgdXBkYXRlcylcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBnaXRodWJFbGVtZW50XSBvZiBnaXRodWJNYXApIHtcbiAgICAgIGNvbnN0IGxvY2FsRWxlbWVudCA9IGxvY2FsTWFwLmdldChuYW1lKTtcbiAgICAgIFxuICAgICAgaWYgKCFsb2NhbEVsZW1lbnQpIHtcbiAgICAgICAgLy8gRWxlbWVudCBleGlzdHMgb24gR2l0SHViIGJ1dCBub3QgbG9jYWxseVxuICAgICAgICBhY3Rpb25zLnRvQWRkLnB1c2goe1xuICAgICAgICAgIHR5cGUsXG4gICAgICAgICAgbmFtZTogZ2l0aHViRWxlbWVudC5uYW1lLFxuICAgICAgICAgIHBhdGg6IGdpdGh1YkVsZW1lbnQucGF0aCxcbiAgICAgICAgICBhY3Rpb246ICdhZGQnLFxuICAgICAgICAgIHJlbW90ZVNoYTogZ2l0aHViRWxlbWVudC5zaGFcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKG1vZGUgPT09ICdiYWNrdXAnIHx8IHRoaXMuc2hvdWxkVXBkYXRlKGdpdGh1YkVsZW1lbnQsIGxvY2FsRWxlbWVudCwgbW9kZSkpIHtcbiAgICAgICAgLy8gRWxlbWVudCBuZWVkcyB1cGRhdGluZ1xuICAgICAgICBhY3Rpb25zLnRvVXBkYXRlLnB1c2goe1xuICAgICAgICAgIHR5cGUsXG4gICAgICAgICAgbmFtZTogZ2l0aHViRWxlbWVudC5uYW1lLFxuICAgICAgICAgIHBhdGg6IGdpdGh1YkVsZW1lbnQucGF0aCxcbiAgICAgICAgICBhY3Rpb246ICd1cGRhdGUnLFxuICAgICAgICAgIHJlYXNvbjogbW9kZSA9PT0gJ2JhY2t1cCcgPyAnYmFja3VwIG1vZGUnIDogJ25ld2VyIG9uIEdpdEh1YicsXG4gICAgICAgICAgbG9jYWxTaGE6IGxvY2FsRWxlbWVudC5zaGEsXG4gICAgICAgICAgcmVtb3RlU2hhOiBnaXRodWJFbGVtZW50LnNoYVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIEVsZW1lbnQgaXMgdXAgdG8gZGF0ZSBvciBzaG91bGQgYmUgc2tpcHBlZFxuICAgICAgICBhY3Rpb25zLnRvU2tpcC5wdXNoKHtcbiAgICAgICAgICB0eXBlLFxuICAgICAgICAgIG5hbWU6IGdpdGh1YkVsZW1lbnQubmFtZSxcbiAgICAgICAgICBwYXRoOiBnaXRodWJFbGVtZW50LnBhdGgsXG4gICAgICAgICAgYWN0aW9uOiAnc2tpcCcsXG4gICAgICAgICAgcmVhc29uOiAndXAgdG8gZGF0ZScsXG4gICAgICAgICAgbG9jYWxTaGE6IGxvY2FsRWxlbWVudC5zaGEsXG4gICAgICAgICAgcmVtb3RlU2hhOiBnaXRodWJFbGVtZW50LnNoYVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBQcm9jZXNzIGxvY2FsIGVsZW1lbnRzIChkZWxldGlvbnMgLSBvbmx5IGluIG1pcnJvciBtb2RlKVxuICAgIGlmIChtb2RlID09PSAnbWlycm9yJykge1xuICAgICAgZm9yIChjb25zdCBbbmFtZSwgbG9jYWxFbGVtZW50XSBvZiBsb2NhbE1hcCkge1xuICAgICAgICBpZiAoIWdpdGh1Yk1hcC5oYXMobmFtZSkpIHtcbiAgICAgICAgICAvLyBFbGVtZW50IGV4aXN0cyBsb2NhbGx5IGJ1dCBub3Qgb24gR2l0SHViXG4gICAgICAgICAgYWN0aW9ucy50b0RlbGV0ZS5wdXNoKHtcbiAgICAgICAgICAgIHR5cGUsXG4gICAgICAgICAgICBuYW1lOiBsb2NhbEVsZW1lbnQubmFtZSB8fCBsb2NhbEVsZW1lbnQubWV0YWRhdGE/Lm5hbWUgfHwgbmFtZSxcbiAgICAgICAgICAgIHBhdGg6IGAke3R5cGV9LyR7bmFtZX0ubWRgLFxuICAgICAgICAgICAgYWN0aW9uOiAnZGVsZXRlJyxcbiAgICAgICAgICAgIHJlYXNvbjogJ25vdCBvbiBHaXRIdWInLFxuICAgICAgICAgICAgbG9jYWxTaGE6IGxvY2FsRWxlbWVudC5zaGFcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmUgaWYgYW4gZWxlbWVudCBzaG91bGQgYmUgdXBkYXRlZFxuICAgKi9cbiAgcHJpdmF0ZSBzaG91bGRVcGRhdGUoXG4gICAgZ2l0aHViRWxlbWVudDogR2l0SHViSW5kZXhFbnRyeSxcbiAgICBsb2NhbEVsZW1lbnQ6IGFueSxcbiAgICBtb2RlOiBTeW5jTW9kZVxuICApOiBib29sZWFuIHtcbiAgICAvLyBJbiBiYWNrdXAgbW9kZSwgYWx3YXlzIHVwZGF0ZSBmcm9tIEdpdEh1YlxuICAgIGlmIChtb2RlID09PSAnYmFja3VwJykge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgLy8gSW4gYWRkaXRpdmUgbW9kZSwgbmV2ZXIgdXBkYXRlIGV4aXN0aW5nIGVsZW1lbnRzXG4gICAgaWYgKG1vZGUgPT09ICdhZGRpdGl2ZScpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBJbiBtaXJyb3IgbW9kZSwgdXBkYXRlIGlmIFNIQXMgZGlmZmVyXG4gICAgLy8gSWYgd2UgZG9uJ3QgaGF2ZSBTSEFzLCBjb21wYXJlIG1vZGlmaWVkIGRhdGVzXG4gICAgaWYgKGdpdGh1YkVsZW1lbnQuc2hhICYmIGxvY2FsRWxlbWVudC5zaGEpIHtcbiAgICAgIHJldHVybiBnaXRodWJFbGVtZW50LnNoYSAhPT0gbG9jYWxFbGVtZW50LnNoYTtcbiAgICB9XG5cbiAgICAvLyBDb21wYXJlIG1vZGlmaWVkIGRhdGVzIGlmIGF2YWlsYWJsZVxuICAgIGlmIChnaXRodWJFbGVtZW50Lmxhc3RNb2RpZmllZCAmJiBsb2NhbEVsZW1lbnQubGFzdE1vZGlmaWVkKSB7XG4gICAgICBjb25zdCBnaXRodWJEYXRlID0gbmV3IERhdGUoZ2l0aHViRWxlbWVudC5sYXN0TW9kaWZpZWQpLmdldFRpbWUoKTtcbiAgICAgIGNvbnN0IGxvY2FsRGF0ZSA9IG5ldyBEYXRlKGxvY2FsRWxlbWVudC5sYXN0TW9kaWZpZWQpLmdldFRpbWUoKTtcbiAgICAgIHJldHVybiBnaXRodWJEYXRlID4gbG9jYWxEYXRlO1xuICAgIH1cblxuICAgIC8vIElmIHdlIGNhbid0IGRldGVybWluZSwgc2tpcCB1cGRhdGluZyBpbiBtaXJyb3IgbW9kZVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBOb3JtYWxpemUgZWxlbWVudCBuYW1lIGZvciBjb21wYXJpc29uXG4gICAqIEhhbmRsZXMgZGlmZmVyZW50IG5hbWluZyBmb3JtYXRzIGFuZCBleHRlbnNpb25zXG4gICAqL1xuICBwcml2YXRlIG5vcm1hbGl6ZUVsZW1lbnROYW1lKG5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgaWYgKCFuYW1lKSByZXR1cm4gJyc7XG4gICAgXG4gICAgLy8gUmVtb3ZlIC5tZCBleHRlbnNpb24gaWYgcHJlc2VudFxuICAgIGxldCBub3JtYWxpemVkID0gbmFtZS5yZXBsYWNlKC9cXC5tZCQvaSwgJycpO1xuICAgIFxuICAgIC8vIENvbnZlcnQgdG8gbG93ZXJjYXNlIGZvciBjb21wYXJpc29uXG4gICAgbm9ybWFsaXplZCA9IG5vcm1hbGl6ZWQudG9Mb3dlckNhc2UoKTtcbiAgICBcbiAgICAvLyBSZXBsYWNlIHNwYWNlcyB3aXRoIGh5cGhlbnMgKHNvbWUgc3lzdGVtcyB1c2UgZGlmZmVyZW50IGZvcm1hdHMpXG4gICAgbm9ybWFsaXplZCA9IG5vcm1hbGl6ZWQucmVwbGFjZUFsbCgvXFxzKy9nLCAnLScpO1xuICAgIFxuICAgIHJldHVybiBub3JtYWxpemVkO1xuICB9XG5cbiAgLyoqXG4gICAqIENvdW50IHRvdGFsIGVsZW1lbnRzIGluIGEgbWFwXG4gICAqL1xuICBwcml2YXRlIGNvdW50RWxlbWVudHMoZWxlbWVudHM6IE1hcDxFbGVtZW50VHlwZSwgYW55W10+KTogbnVtYmVyIHtcbiAgICBsZXQgY291bnQgPSAwO1xuICAgIGZvciAoY29uc3QgdHlwZUVsZW1lbnRzIG9mIGVsZW1lbnRzLnZhbHVlcygpKSB7XG4gICAgICBjb3VudCArPSB0eXBlRWxlbWVudHMubGVuZ3RoO1xuICAgIH1cbiAgICByZXR1cm4gY291bnQ7XG4gIH1cbn0iXX0=