@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.
163 lines • 24.2 kB
JavaScript
/**
* Migration Manager - Handles migration from legacy structure to portfolio structure
*/
import * as fs from 'fs/promises';
import * as path from 'path';
import { ElementType } from './types.js';
import { logger } from '../utils/logger.js';
import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
export class MigrationManager {
portfolioManager;
constructor(portfolioManager) {
this.portfolioManager = portfolioManager;
}
/**
* Check if migration is needed
*/
async needsMigration() {
const hasLegacy = await this.portfolioManager.hasLegacyPersonas();
const portfolioExists = await this.portfolioManager.exists();
// Need migration if we have legacy personas but no portfolio yet
return hasLegacy && !portfolioExists;
}
/**
* Perform migration from legacy to portfolio structure
*/
async migrate(options) {
const result = {
success: true,
migratedCount: 0,
errors: [],
backedUp: false
};
try {
// Check if migration is needed
if (!await this.needsMigration()) {
logger.info('[MigrationManager] No migration needed');
return result;
}
logger.info('[MigrationManager] Starting migration from legacy personas to portfolio structure');
// Create backup if requested
if (options?.backup) {
const backupPath = await this.createBackup();
result.backedUp = true;
result.backupPath = backupPath;
logger.info(`[MigrationManager] Created backup at: ${backupPath}`);
}
// Initialize portfolio structure
await this.portfolioManager.initialize();
// Get legacy personas
const legacyDir = this.portfolioManager.getLegacyPersonasDir();
const files = await fs.readdir(legacyDir);
const personaFiles = files.filter(file => file.endsWith('.md'));
logger.info(`[MigrationManager] Found ${personaFiles.length} personas to migrate`);
// Migrate each persona
for (const file of personaFiles) {
try {
await this.migratePersona(file);
result.migratedCount++;
}
catch (error) {
const errorMsg = `Failed to migrate ${file}: ${error instanceof Error ? error.message : String(error)}`;
logger.error(`[MigrationManager] ${errorMsg}`);
result.errors.push(errorMsg);
result.success = false;
}
}
// If all migrations successful, optionally clean up legacy directory
if (result.success && result.migratedCount > 0) {
logger.info(`[MigrationManager] Successfully migrated ${result.migratedCount} personas`);
// Note: We don't automatically delete the legacy directory
// User should manually remove it after confirming migration success
}
}
catch (error) {
result.success = false;
const errorMsg = `Migration failed: ${error instanceof Error ? error.message : String(error)}`;
result.errors.push(errorMsg);
// Log with full error details including stack trace
if (error instanceof Error) {
logger.error(`[MigrationManager] ${errorMsg}`, {
stack: error.stack,
name: error.name,
cause: error.cause
});
}
else {
logger.error(`[MigrationManager] ${errorMsg}`, { rawError: error });
}
}
return result;
}
/**
* Migrate a single persona file
*/
async migratePersona(filename) {
// Normalize filename to prevent Unicode attacks
const filenameValidation = UnicodeValidator.normalize(filename);
const normalizedFilename = filenameValidation.normalizedContent;
if (normalizedFilename !== filename) {
logger.warn(`[MigrationManager] Filename normalized from "${filename}" to "${normalizedFilename}"`);
}
if (!filenameValidation.isValid) {
logger.warn(`[MigrationManager] Filename has Unicode issues: ${filenameValidation.detectedIssues?.join(', ')}`);
}
const legacyPath = path.join(this.portfolioManager.getLegacyPersonasDir(), filename);
const newPath = this.portfolioManager.getElementPath(ElementType.PERSONA, normalizedFilename);
// Read the content
const content = await fs.readFile(legacyPath, 'utf-8');
// Normalize content to prevent Unicode issues
const contentValidation = UnicodeValidator.normalize(content);
const normalizedContent = contentValidation.normalizedContent;
if (!contentValidation.isValid) {
logger.warn(`[MigrationManager] Content has Unicode issues in ${filename}: ${contentValidation.detectedIssues?.join(', ')}`);
}
// Write to new location
await fs.writeFile(newPath, normalizedContent, 'utf-8');
logger.debug(`[MigrationManager] Migrated: ${filename}`);
}
/**
* Create backup of legacy personas
*/
async createBackup() {
const legacyDir = this.portfolioManager.getLegacyPersonasDir();
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const backupDir = `${legacyDir}_backup_${timestamp}`;
// Create backup directory
await fs.mkdir(backupDir, { recursive: true });
// Copy all files
const files = await fs.readdir(legacyDir);
for (const file of files) {
const srcPath = path.join(legacyDir, file);
const destPath = path.join(backupDir, file);
const stats = await fs.stat(srcPath);
if (stats.isFile()) {
await fs.copyFile(srcPath, destPath);
}
}
return backupDir;
}
/**
* Get migration status report
*/
async getMigrationStatus() {
const hasLegacyPersonas = await this.portfolioManager.hasLegacyPersonas();
let legacyPersonaCount = 0;
if (hasLegacyPersonas) {
const legacyDir = this.portfolioManager.getLegacyPersonasDir();
const files = await fs.readdir(legacyDir);
legacyPersonaCount = files.filter(file => file.endsWith('.md')).length;
}
const portfolioExists = await this.portfolioManager.exists();
const portfolioStats = portfolioExists
? await this.portfolioManager.getStatistics()
: Object.values(ElementType).reduce((acc, type) => ({ ...acc, [type]: 0 }), {});
return {
hasLegacyPersonas,
legacyPersonaCount,
portfolioExists,
portfolioStats
};
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWlncmF0aW9uTWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wb3J0Zm9saW8vTWlncmF0aW9uTWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILE9BQU8sS0FBSyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2xDLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBRTdCLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDekMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBVTlFLE1BQU0sT0FBTyxnQkFBZ0I7SUFDbkIsZ0JBQWdCLENBQW1CO0lBRTNDLFlBQVksZ0JBQWtDO1FBQzVDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxnQkFBZ0IsQ0FBQztJQUMzQyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsY0FBYztRQUN6QixNQUFNLFNBQVMsR0FBRyxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ2xFLE1BQU0sZUFBZSxHQUFHLE1BQU0sSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sRUFBRSxDQUFDO1FBRTdELGlFQUFpRTtRQUNqRSxPQUFPLFNBQVMsSUFBSSxDQUFDLGVBQWUsQ0FBQztJQUN2QyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQThCO1FBQ2pELE1BQU0sTUFBTSxHQUFvQjtZQUM5QixPQUFPLEVBQUUsSUFBSTtZQUNiLGFBQWEsRUFBRSxDQUFDO1lBQ2hCLE1BQU0sRUFBRSxFQUFFO1lBQ1YsUUFBUSxFQUFFLEtBQUs7U0FDaEIsQ0FBQztRQUVGLElBQUksQ0FBQztZQUNILCtCQUErQjtZQUMvQixJQUFJLENBQUMsTUFBTSxJQUFJLENBQUMsY0FBYyxFQUFF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SUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBZ0MsQ0FBQztRQUVqSCxPQUFPO1lBQ0wsaUJBQWlCO1lBQ2pCLGtCQUFrQjtZQUNsQixlQUFlO1lBQ2YsY0FBYztTQUNmLENBQUM7SUFDSixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1pZ3JhdGlvbiBNYW5hZ2VyIC0gSGFuZGxlcyBtaWdyYXRpb24gZnJvbSBsZWdhY3kgc3RydWN0dXJlIHRvIHBvcnRmb2xpbyBzdHJ1Y3R1cmVcbiAqL1xuXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcy9wcm9taXNlcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgUG9ydGZvbGlvTWFuYWdlciB9IGZyb20gJy4vUG9ydGZvbGlvTWFuYWdlci5qcyc7XG5pbXBvcnQgeyBFbGVtZW50VHlwZSB9IGZyb20gJy4vdHlwZXMuanMnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IFVuaWNvZGVWYWxpZGF0b3IgfSBmcm9tICcuLi9zZWN1cml0eS92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIE1pZ3JhdGlvblJlc3VsdCB7XG4gIHN1Y2Nlc3M6IGJvb2xlYW47XG4gIG1pZ3JhdGVkQ291bnQ6IG51bWJlcjtcbiAgZXJyb3JzOiBzdHJpbmdbXTtcbiAgYmFja2VkVXA6IGJvb2xlYW47XG4gIGJhY2t1cFBhdGg/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjbGFzcyBNaWdyYXRpb25NYW5hZ2VyIHtcbiAgcHJpdmF0ZSBwb3J0Zm9saW9NYW5hZ2VyOiBQb3J0Zm9saW9NYW5hZ2VyO1xuICBcbiAgY29uc3RydWN0b3IocG9ydGZvbGlvTWFuYWdlcjogUG9ydGZvbGlvTWFuYWdlcikge1xuICAgIHRoaXMucG9ydGZvbGlvTWFuYWdlciA9IHBvcnRmb2xpb01hbmFnZXI7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDaGVjayBpZiBtaWdyYXRpb24gaXMgbmVlZGVkXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgbmVlZHNNaWdyYXRpb24oKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgaGFzTGVnYWN5ID0gYXdhaXQgdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmhhc0xlZ2FjeVBlcnNvbmFzKCk7XG4gICAgY29uc3QgcG9ydGZvbGlvRXhpc3RzID0gYXdhaXQgdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmV4aXN0cygpO1xuICAgIFxuICAgIC8vIE5lZWQgbWlncmF0aW9uIGlmIHdlIGhhdmUgbGVnYWN5IHBlcnNvbmFzIGJ1dCBubyBwb3J0Zm9saW8geWV0XG4gICAgcmV0dXJuIGhhc0xlZ2FjeSAmJiAhcG9ydGZvbGlvRXhpc3RzO1xuICB9XG4gIFxuICAvKipcbiAgICogUGVyZm9ybSBtaWdyYXRpb24gZnJvbSBsZWdhY3kgdG8gcG9ydGZvbGlvIHN0cnVjdHVyZVxuICAgKi9cbiAgcHVibGljIGFzeW5jIG1pZ3JhdGUob3B0aW9ucz86IHsgYmFja3VwPzogYm9vbGVhbiB9KTogUHJvbWlzZTxNaWdyYXRpb25SZXN1bHQ+IHtcbiAgICBjb25zdCByZXN1bHQ6IE1pZ3JhdGlvblJlc3VsdCA9IHtcbiAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICBtaWdyYXRlZENvdW50OiAwLFxuICAgICAgZXJyb3JzOiBbXSxcbiAgICAgIGJhY2tlZFVwOiBmYWxzZVxuICAgIH07XG4gICAgXG4gICAgdHJ5IHtcbiAgICAgIC8vIENoZWNrIGlmIG1pZ3JhdGlvbiBpcyBuZWVkZWRcbiAgICAgIGlmICghYXdhaXQgdGhpcy5uZWVkc01pZ3JhdGlvbigpKSB7XG4gICAgICAgIGxvZ2dlci5pbmZvKCdbTWlncmF0aW9uTWFuYWdlcl0gTm8gbWlncmF0aW9uIG5lZWRlZCcpO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfVxuICAgICAgXG4gICAgICBsb2dnZXIuaW5mbygnW01pZ3JhdGlvbk1hbmFnZXJdIFN0YXJ0aW5nIG1pZ3JhdGlvbiBmcm9tIGxlZ2FjeSBwZXJzb25hcyB0byBwb3J0Zm9saW8gc3RydWN0dXJlJyk7XG4gICAgICBcbiAgICAgIC8vIENyZWF0ZSBiYWNrdXAgaWYgcmVxdWVzdGVkXG4gICAgICBpZiAob3B0aW9ucz8uYmFja3VwKSB7XG4gICAgICAgIGNvbnN0IGJhY2t1cFBhdGggPSBhd2FpdCB0aGlzLmNyZWF0ZUJhY2t1cCgpO1xuICAgICAgICByZXN1bHQuYmFja2VkVXAgPSB0cnVlO1xuICAgICAgICByZXN1bHQuYmFja3VwUGF0aCA9IGJhY2t1cFBhdGg7XG4gICAgICAgIGxvZ2dlci5pbmZvKGBbTWlncmF0aW9uTWFuYWdlcl0gQ3JlYXRlZCBiYWNrdXAgYXQ6ICR7YmFja3VwUGF0aH1gKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gSW5pdGlhbGl6ZSBwb3J0Zm9saW8gc3RydWN0dXJlXG4gICAgICBhd2FpdCB0aGlzLnBvcnRmb2xpb01hbmFnZXIuaW5pdGlhbGl6ZSgpO1xuICAgICAgXG4gICAgICAvLyBHZXQgbGVnYWN5IHBlcnNvbmFzXG4gICAgICBjb25zdCBsZWdhY3lEaXIgPSB0aGlzLnBvcnRmb2xpb01hbmFnZXIuZ2V0TGVnYWN5UGVyc29uYXNEaXIoKTtcbiAgICAgIGNvbnN0IGZpbGVzID0gYXdhaXQgZnMucmVhZGRpcihsZWdhY3lEaXIpO1xuICAgICAgY29uc3QgcGVyc29uYUZpbGVzID0gZmlsZXMuZmlsdGVyKGZpbGUgPT4gZmlsZS5lbmRzV2l0aCgnLm1kJykpO1xuICAgICAgXG4gICAgICBsb2dnZXIuaW5mbyhgW01pZ3JhdGlvbk1hbmFnZXJdIEZvdW5kICR7cGVyc29uYUZpbGVzLmxlbmd0aH0gcGVyc29uYXMgdG8gbWlncmF0ZWApO1xuICAgICAgXG4gICAgICAvLyBNaWdyYXRlIGVhY2ggcGVyc29uYVxuICAgICAgZm9yIChjb25zdCBmaWxlIG9mIHBlcnNvbmFGaWxlcykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IHRoaXMubWlncmF0ZVBlcnNvbmEoZmlsZSk7XG4gICAgICAgICAgcmVzdWx0Lm1pZ3JhdGVkQ291bnQrKztcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zdCBlcnJvck1zZyA9IGBGYWlsZWQgdG8gbWlncmF0ZSAke2ZpbGV9OiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gO1xuICAgICAgICAgIGxvZ2dlci5lcnJvcihgW01pZ3JhdGlvbk1hbmFnZXJdICR7ZXJyb3JNc2d9YCk7XG4gICAgICAgICAgcmVzdWx0LmVycm9ycy5wdXNoKGVycm9yTXNnKTtcbiAgICAgICAgICByZXN1bHQuc3VjY2VzcyA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIElmIGFsbCBtaWdyYXRpb25zIHN1Y2Nlc3NmdWwsIG9wdGlvbmFsbHkgY2xlYW4gdXAgbGVnYWN5IGRpcmVjdG9yeVxuICAgICAgaWYgKHJlc3VsdC5zdWNjZXNzICYmIHJlc3VsdC5taWdyYXRlZENvdW50ID4gMCkge1xuICAgICAgICBsb2dnZXIuaW5mbyhgW01pZ3JhdGlvbk1hbmFnZXJdIFN1Y2Nlc3NmdWxseSBtaWdyYXRlZCAke3Jlc3VsdC5taWdyYXRlZENvdW50fSBwZXJzb25hc2ApO1xuICAgICAgICAvLyBOb3RlOiBXZSBkb24ndCBhdXRvbWF0aWNhbGx5IGRlbGV0ZSB0aGUgbGVnYWN5IGRpcmVjdG9yeVxuICAgICAgICAvLyBVc2VyIHNob3VsZCBtYW51YWxseSByZW1vdmUgaXQgYWZ0ZXIgY29uZmlybWluZyBtaWdyYXRpb24gc3VjY2Vzc1xuICAgICAgfVxuICAgICAgXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJlc3VsdC5zdWNjZXNzID0gZmFsc2U7XG4gICAgICBjb25zdCBlcnJvck1zZyA9IGBNaWdyYXRpb24gZmFpbGVkOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gO1xuICAgICAgcmVzdWx0LmVycm9ycy5wdXNoKGVycm9yTXNnKTtcbiAgICAgIFxuICAgICAgLy8gTG9nIHdpdGggZnVsbCBlcnJvciBkZXRhaWxzIGluY2x1ZGluZyBzdGFjayB0cmFjZVxuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKGBbTWlncmF0aW9uTWFuYWdlcl0gJHtlcnJvck1zZ31gLCB7IFxuICAgICAgICAgIHN0YWNrOiBlcnJvci5zdGFjayxcbiAgICAgICAgICBuYW1lOiBlcnJvci5uYW1lLFxuICAgICAgICAgIGNhdXNlOiBlcnJvci5jYXVzZVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcihgW01pZ3JhdGlvbk1hbmFnZXJdICR7ZXJyb3JNc2d9YCwgeyByYXdFcnJvcjogZXJyb3IgfSk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBNaWdyYXRlIGEgc2luZ2xlIHBlcnNvbmEgZmlsZVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBtaWdyYXRlUGVyc29uYShmaWxlbmFtZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gTm9ybWFsaXplIGZpbGVuYW1lIHRvIHByZXZlbnQgVW5pY29kZSBhdHRhY2tzXG4gICAgY29uc3QgZmlsZW5hbWVWYWxpZGF0aW9uID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUoZmlsZW5hbWUpO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRGaWxlbmFtZSA9IGZpbGVuYW1lVmFsaWRhdGlvbi5ub3JtYWxpemVkQ29udGVudDtcbiAgICBcbiAgICBpZiAobm9ybWFsaXplZEZpbGVuYW1lICE9PSBmaWxlbmFtZSkge1xuICAgICAgbG9nZ2VyLndhcm4oYFtNaWdyYXRpb25NYW5hZ2VyXSBGaWxlbmFtZSBub3JtYWxpemVkIGZyb20gXCIke2ZpbGVuYW1lfVwiIHRvIFwiJHtub3JtYWxpemVkRmlsZW5hbWV9XCJgKTtcbiAgICB9XG4gICAgXG4gICAgaWYgKCFmaWxlbmFtZVZhbGlkYXRpb24uaXNWYWxpZCkge1xuICAgICAgbG9nZ2VyLndhcm4oYFtNaWdyYXRpb25NYW5hZ2VyXSBGaWxlbmFtZSBoYXMgVW5pY29kZSBpc3N1ZXM6ICR7ZmlsZW5hbWVWYWxpZGF0aW9uLmRldGVjdGVkSXNzdWVzPy5qb2luKCcsICcpfWApO1xuICAgIH1cbiAgICBcbiAgICBjb25zdCBsZWdhY3lQYXRoID0gcGF0aC5qb2luKHRoaXMucG9ydGZvbGlvTWFuYWdlci5nZXRMZWdhY3lQZXJzb25hc0RpcigpLCBmaWxlbmFtZSk7XG4gICAgY29uc3QgbmV3UGF0aCA9IHRoaXMucG9ydGZvbGlvTWFuYWdlci5nZXRFbGVtZW50UGF0aChFbGVtZW50VHlwZS5QRVJTT05BLCBub3JtYWxpemVkRmlsZW5hbWUpO1xuICAgIFxuICAgIC8vIFJlYWQgdGhlIGNvbnRlbnRcbiAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUobGVnYWN5UGF0aCwgJ3V0Zi04Jyk7XG4gICAgXG4gICAgLy8gTm9ybWFsaXplIGNvbnRlbnQgdG8gcHJldmVudCBVbmljb2RlIGlzc3Vlc1xuICAgIGNvbnN0IGNvbnRlbnRWYWxpZGF0aW9uID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUoY29udGVudCk7XG4gICAgY29uc3Qgbm9ybWFsaXplZENvbnRlbnQgPSBjb250ZW50VmFsaWRhdGlvbi5ub3JtYWxpemVkQ29udGVudDtcbiAgICBcbiAgICBpZiAoIWNvbnRlbnRWYWxpZGF0aW9uLmlzVmFsaWQpIHtcbiAgICAgIGxvZ2dlci53YXJuKGBbTWlncmF0aW9uTWFuYWdlcl0gQ29udGVudCBoYXMgVW5pY29kZSBpc3N1ZXMgaW4gJHtmaWxlbmFtZX06ICR7Y29udGVudFZhbGlkYXRpb24uZGV0ZWN0ZWRJc3N1ZXM/LmpvaW4oJywgJyl9YCk7XG4gICAgfVxuICAgIFxuICAgIC8vIFdyaXRlIHRvIG5ldyBsb2NhdGlvblxuICAgIGF3YWl0IGZzLndyaXRlRmlsZShuZXdQYXRoLCBub3JtYWxpemVkQ29udGVudCwgJ3V0Zi04Jyk7XG4gICAgXG4gICAgbG9nZ2VyLmRlYnVnKGBbTWlncmF0aW9uTWFuYWdlcl0gTWlncmF0ZWQ6ICR7ZmlsZW5hbWV9YCk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDcmVhdGUgYmFja3VwIG9mIGxlZ2FjeSBwZXJzb25hc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjcmVhdGVCYWNrdXAoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBsZWdhY3lEaXIgPSB0aGlzLnBvcnRmb2xpb01hbmFnZXIuZ2V0TGVnYWN5UGVyc29uYXNEaXIoKTtcbiAgICBjb25zdCB0aW1lc3RhbXAgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkucmVwbGFjZSgvWzouXS9nLCAnLScpO1xuICAgIGNvbnN0IGJhY2t1cERpciA9IGAke2xlZ2FjeURpcn1fYmFja3VwXyR7dGltZXN0YW1wfWA7XG4gICAgXG4gICAgLy8gQ3JlYXRlIGJhY2t1cCBkaXJlY3RvcnlcbiAgICBhd2FpdCBmcy5ta2RpcihiYWNrdXBEaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIFxuICAgIC8vIENvcHkgYWxsIGZpbGVzXG4gICAgY29uc3QgZmlsZXMgPSBhd2FpdCBmcy5yZWFkZGlyKGxlZ2FjeURpcik7XG4gICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICBjb25zdCBzcmNQYXRoID0gcGF0aC5qb2luKGxlZ2FjeURpciwgZmlsZSk7XG4gICAgICBjb25zdCBkZXN0UGF0aCA9IHBhdGguam9pbihiYWNrdXBEaXIsIGZpbGUpO1xuICAgICAgXG4gICAgICBjb25zdCBzdGF0cyA9IGF3YWl0IGZzLnN0YXQoc3JjUGF0aCk7XG4gICAgICBpZiAoc3RhdHMuaXNGaWxlKCkpIHtcbiAgICAgICAgYXdhaXQgZnMuY29weUZpbGUoc3JjUGF0aCwgZGVzdFBhdGgpO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICByZXR1cm4gYmFja3VwRGlyO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IG1pZ3JhdGlvbiBzdGF0dXMgcmVwb3J0XG4gICAqL1xuICBwdWJsaWMgYXN5bmMgZ2V0TWlncmF0aW9uU3RhdHVzKCk6IFByb21pc2U8e1xuICAgIGhhc0xlZ2FjeVBlcnNvbmFzOiBib29sZWFuO1xuICAgIGxlZ2FjeVBlcnNvbmFDb3VudDogbnVtYmVyO1xuICAgIHBvcnRmb2xpb0V4aXN0czogYm9vbGVhbjtcbiAgICBwb3J0Zm9saW9TdGF0czogUmVjb3JkPEVsZW1lbnRUeXBlLCBudW1iZXI+O1xuICB9PiB7XG4gICAgY29uc3QgaGFzTGVnYWN5UGVyc29uYXMgPSBhd2FpdCB0aGlzLnBvcnRmb2xpb01hbmFnZXIuaGFzTGVnYWN5UGVyc29uYXMoKTtcbiAgICBsZXQgbGVnYWN5UGVyc29uYUNvdW50ID0gMDtcbiAgICBcbiAgICBpZiAoaGFzTGVnYWN5UGVyc29uYXMpIHtcbiAgICAgIGNvbnN0IGxlZ2FjeURpciA9IHRoaXMucG9ydGZvbGlvTWFuYWdlci5nZXRMZWdhY3lQZXJzb25hc0RpcigpO1xuICAgICAgY29uc3QgZmlsZXMgPSBhd2FpdCBmcy5yZWFkZGlyKGxlZ2FjeURpcik7XG4gICAgICBsZWdhY3lQZXJzb25hQ291bnQgPSBmaWxlcy5maWx0ZXIoZmlsZSA9PiBmaWxlLmVuZHNXaXRoKCcubWQnKSkubGVuZ3RoO1xuICAgIH1cbiAgICBcbiAgICBjb25zdCBwb3J0Zm9saW9FeGlzdHMgPSBhd2FpdCB0aGlzLnBvcnRmb2xpb01hbmFnZXIuZXhpc3RzKCk7XG4gICAgY29uc3QgcG9ydGZvbGlvU3RhdHMgPSBwb3J0Zm9saW9FeGlzdHMgXG4gICAgICA/IGF3YWl0IHRoaXMucG9ydGZvbGlvTWFuYWdlci5nZXRTdGF0aXN0aWNzKClcbiAgICAgIDogT2JqZWN0LnZhbHVlcyhFbGVtZW50VHlwZSkucmVkdWNlKChhY2MsIHR5cGUpID0+ICh7IC4uLmFjYywgW3R5cGVdOiAwIH0pLCB7fSkgYXMgUmVjb3JkPEVsZW1lbnRUeXBlLCBudW1iZXI+O1xuICAgIFxuICAgIHJldHVybiB7XG4gICAgICBoYXNMZWdhY3lQZXJzb25hcyxcbiAgICAgIGxlZ2FjeVBlcnNvbmFDb3VudCxcbiAgICAgIHBvcnRmb2xpb0V4aXN0cyxcbiAgICAgIHBvcnRmb2xpb1N0YXRzXG4gICAgfTtcbiAgfVxufSJdfQ==