@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
JavaScript
/**
* 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=