@mickdarling/dollhousemcp
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.
260 lines • 43.5 kB
JavaScript
/**
* Manage server updates and rollbacks
*/
import { safeExec } from '../utils/git.js';
import { VersionManager } from './VersionManager.js';
import { UpdateChecker } from './UpdateChecker.js';
import { DependencyChecker } from './DependencyChecker.js';
import { BackupManager } from './BackupManager.js';
export class UpdateManager {
versionManager;
updateChecker;
dependencyChecker;
backupManager;
rootDir;
constructor(rootDir) {
this.rootDir = rootDir || process.cwd();
this.versionManager = new VersionManager();
this.updateChecker = new UpdateChecker(this.versionManager);
this.dependencyChecker = new DependencyChecker(this.versionManager);
this.backupManager = new BackupManager(this.rootDir);
}
/**
* Check for available updates
*/
async checkForUpdates() {
try {
const result = await this.updateChecker.checkForUpdates();
const text = this.updateChecker.formatUpdateCheckResult(result);
return { text };
}
catch (error) {
const text = this.updateChecker.formatUpdateCheckResult(null, error);
return { text };
}
}
/**
* Perform server update
*/
async updateServer(createBackup = true, personaIndicator = '') {
const progress = [];
try {
// Step 1: Check dependencies
progress.push({ step: 'dependencies', message: 'Checking system dependencies...', isComplete: false });
const dependencies = await this.dependencyChecker.checkDependencies();
if (!dependencies.git.installed || dependencies.git.error) {
return {
text: personaIndicator + '❌ **Update Failed**\n\n' +
'Git is required for updates but is not available.\n' +
dependencies.git.error || 'Git is not installed.'
};
}
if (!dependencies.npm.installed || dependencies.npm.error) {
return {
text: personaIndicator + '❌ **Update Failed**\n\n' +
'npm is required for updates but is not available.\n' +
dependencies.npm.error || 'npm is not installed.'
};
}
progress[0].isComplete = true;
// Step 2: Create backup if requested
if (createBackup) {
progress.push({ step: 'backup', message: 'Creating backup...', isComplete: false });
const currentVersion = await this.versionManager.getCurrentVersion();
const backup = await this.backupManager.createBackup(currentVersion);
progress[1].isComplete = true;
progress[1].message = `Backup created at: ${backup.timestamp}`;
}
// Step 3: Git fetch
progress.push({ step: 'fetch', message: 'Fetching latest changes...', isComplete: false });
await safeExec('git', ['fetch', 'origin'], { cwd: this.rootDir });
progress[progress.length - 1].isComplete = true;
// Step 4: Check for uncommitted changes
progress.push({ step: 'check', message: 'Checking for uncommitted changes...', isComplete: false });
const { stdout: statusOutput } = await safeExec('git', ['status', '--porcelain'], { cwd: this.rootDir });
if (statusOutput.trim()) {
return {
text: personaIndicator + '❌ **Update Failed**\n\n' +
'You have uncommitted changes. Please commit or stash them before updating.\n\n' +
'Modified files:\n' + statusOutput
};
}
progress[progress.length - 1].isComplete = true;
// Step 5: Git pull
progress.push({ step: 'pull', message: 'Pulling latest changes...', isComplete: false });
const { stdout: pullOutput } = await safeExec('git', ['pull', 'origin', 'main'], { cwd: this.rootDir });
progress[progress.length - 1].isComplete = true;
// Check if already up to date
if (pullOutput.includes('Already up to date')) {
return {
text: personaIndicator + '✅ **Already Up to Date**\n\n' +
'Your DollhouseMCP installation is already at the latest version.\n\n' +
'No changes were pulled from the repository.'
};
}
// Step 6: npm install
progress.push({ step: 'install', message: 'Installing dependencies...', isComplete: false });
await safeExec('npm', ['install'], { cwd: this.rootDir });
progress[progress.length - 1].isComplete = true;
// Step 7: Build
progress.push({ step: 'build', message: 'Building TypeScript...', isComplete: false });
await safeExec('npm', ['run', 'build'], { cwd: this.rootDir });
progress[progress.length - 1].isComplete = true;
// Step 8: Cleanup old backups
if (createBackup) {
progress.push({ step: 'cleanup', message: 'Cleaning up old backups...', isComplete: false });
const deletedCount = await this.backupManager.cleanupOldBackups();
progress[progress.length - 1].isComplete = true;
progress[progress.length - 1].message = `Cleaned up ${deletedCount} old backup(s)`;
}
// Format success message
const successParts = [
personaIndicator + '✅ **Update Complete!**\n\n',
'**Update Summary:**\n'
];
progress.forEach(p => {
successParts.push(`${p.isComplete ? '✅' : '❌'} ${p.message}\n`);
});
successParts.push('\n**Next Steps:**\n', '1. The server will restart automatically\n', '2. All personas will be reloaded\n', '3. Check `get_server_status` to verify the new version\n\n', '💡 **Tip:** If you encounter issues, use `rollback_update true` to restore the previous version.');
return { text: successParts.join('') };
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
return {
text: personaIndicator + '❌ **Update Failed**\n\n' +
'Error: ' + errorMessage + '\n\n' +
'**Progress:**\n' +
progress.map(p => `${p.isComplete ? '✅' : '❌'} ${p.message}`).join('\n') + '\n\n' +
'**Recovery Options:**\n' +
'• Try running the update again\n' +
'• Check your internet connection\n' +
'• Ensure you have proper permissions\n' +
'• If a backup was created, use `rollback_update true` to restore'
};
}
}
/**
* Rollback to previous version
*/
async rollbackUpdate(force = false, personaIndicator = '') {
try {
// Get latest backup
const latestBackup = await this.backupManager.getLatestBackup();
if (!latestBackup) {
return {
text: personaIndicator + '❌ **No Backups Found**\n\n' +
'There are no backups available to restore.\n\n' +
'Backups are created automatically when you run `update_server true`.'
};
}
// Check if rollback is needed
if (!force) {
try {
// Test if the server is working by checking version
await this.versionManager.getCurrentVersion();
return {
text: personaIndicator + '⚠️ **Rollback Confirmation Required**\n\n' +
'The server appears to be working normally.\n\n' +
`**Latest Backup:** ${latestBackup.timestamp}\n` +
`**Backup Version:** ${latestBackup.version || 'Unknown'}\n\n` +
'To force rollback anyway, use: `rollback_update true`\n\n' +
'⚠️ **Warning:** This will restore all files to the backup state.'
};
}
catch {
// Server is broken, proceed with rollback
}
}
// Perform rollback
await this.backupManager.restoreBackup(latestBackup.path);
// Reinstall dependencies
await safeExec('npm', ['install'], { cwd: this.rootDir });
// Rebuild
await safeExec('npm', ['run', 'build'], { cwd: this.rootDir });
return {
text: personaIndicator + '✅ **Rollback Complete!**\n\n' +
`Restored from backup: ${latestBackup.timestamp}\n` +
`Backup version: ${latestBackup.version || 'Unknown'}\n\n` +
'**What was restored:**\n' +
'• All source files\n' +
'• Configuration files\n' +
'• Dependencies reinstalled\n' +
'• TypeScript rebuilt\n\n' +
'**Next Steps:**\n' +
'1. The server will restart automatically\n' +
'2. Check `get_server_status` to verify the version\n' +
'3. Test your personas to ensure everything works'
};
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
return {
text: personaIndicator + '❌ **Rollback Failed**\n\n' +
'Error: ' + errorMessage + '\n\n' +
'**Manual Recovery:**\n' +
'1. Check the backups directory: ../dollhousemcp-backups/\n' +
'2. Manually restore files if needed\n' +
'3. Run `npm install` and `npm run build`\n' +
'4. Contact support if issues persist'
};
}
}
/**
* Get current server status
*/
async getServerStatus(personaIndicator = '') {
try {
const currentVersion = await this.versionManager.getCurrentVersion();
const dependencies = await this.dependencyChecker.checkDependencies();
const backups = await this.backupManager.listBackups();
const rateLimitStatus = this.updateChecker.getRateLimitStatus();
// Get git status
let gitStatus = 'Unknown';
let gitBranch = 'Unknown';
let lastCommit = 'Unknown';
try {
const { stdout: branchOutput } = await safeExec('git', ['branch', '--show-current'], { cwd: this.rootDir });
gitBranch = branchOutput.trim() || 'detached';
const { stdout: statusOutput } = await safeExec('git', ['status', '--porcelain'], { cwd: this.rootDir });
gitStatus = statusOutput.trim() ? 'Modified' : 'Clean';
const { stdout: logOutput } = await safeExec('git', ['log', '-1', '--oneline'], { cwd: this.rootDir });
lastCommit = logOutput.trim();
}
catch {
// Git commands failed, use defaults
}
const statusParts = [
personaIndicator + '📊 **DollhouseMCP Server Status**\n\n',
'**Version Information:**\n',
`• Current Version: ${currentVersion}\n`,
`• Git Branch: ${gitBranch}\n`,
`• Git Status: ${gitStatus}\n`,
`• Last Commit: ${lastCommit}\n\n`,
'**Dependencies:**\n',
this.dependencyChecker.formatDependencyStatus(dependencies),
'\n\n**Backups:**\n',
`• Total Backups: ${backups.length}\n`
];
if (backups.length > 0) {
statusParts.push(`• Latest Backup: ${backups[0].timestamp} (v${backups[0].version || 'unknown'})\n`);
statusParts.push(`• Oldest Backup: ${backups[backups.length - 1].timestamp}\n`);
}
statusParts.push('\n**Rate Limit Status:**\n', `• Update Checks Remaining: ${rateLimitStatus.remainingRequests}/10 per hour\n`, `• Rate Limit Resets: ${rateLimitStatus.resetTime.toLocaleTimeString()}\n`);
if (!rateLimitStatus.allowed && rateLimitStatus.waitTimeSeconds) {
statusParts.push(`• ⏳ Wait ${rateLimitStatus.waitTimeSeconds} seconds before next check\n`);
}
statusParts.push('\n**Available Commands:**\n', '• `check_for_updates` - Check for new versions\n', '• `update_server true` - Update to latest version\n', '• `rollback_update true` - Restore from backup\n');
return { text: statusParts.join('') };
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
return {
text: personaIndicator + '❌ **Status Check Failed**\n\n' +
'Error: ' + errorMessage + '\n\n' +
'The server may be in an inconsistent state.\n' +
'Try running `update_server true` to fix issues.'
};
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVXBkYXRlTWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91cGRhdGUvVXBkYXRlTWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUdILE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMzQyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDckQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQzNELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQVFuRCxNQUFNLE9BQU8sYUFBYTtJQUNoQixjQUFjLENBQWlCO0lBQy9CLGFBQWEsQ0FBZ0I7SUFDN0IsaUJBQWlCLENBQW9CO0lBQ3JDLGFBQWEsQ0FBZ0I7SUFDN0IsT0FBTyxDQUFTO0lBRXhCLFlBQVksT0FBZ0I7UUFDMUIsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLElBQUksT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ3hDLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxjQUFjLEVBQUUsQ0FBQztRQUMzQyxJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksYUFBYSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUM1RCxJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDcEUsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLGFBQWEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDdkQsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLGVBQWU7UUFDbkIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLGVBQWUsRUFBRSxD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a0RBQWtELENBQ25ELENBQUM7WUFFRixPQUFPLEVBQUUsSUFBSSxFQUFFLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztRQUV4QyxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sWUFBWSxHQUFHLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUU1RSxPQUFPO2dCQUNMLElBQUksRUFBRSxnQkFBZ0IsR0FBRywrQkFBK0I7b0JBQ3RELFNBQVMsR0FBRyxZQUFZLEdBQUcsTUFBTTtvQkFDakMsK0NBQStDO29CQUMvQyxpREFBaUQ7YUFDcEQsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1hbmFnZSBzZXJ2ZXIgdXBkYXRlcyBhbmQgcm9sbGJhY2tzXG4gKi9cblxuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IHNhZmVFeGVjIH0gZnJvbSAnLi4vdXRpbHMvZ2l0LmpzJztcbmltcG9ydCB7IFZlcnNpb25NYW5hZ2VyIH0gZnJvbSAnLi9WZXJzaW9uTWFuYWdlci5qcyc7XG5pbXBvcnQgeyBVcGRhdGVDaGVja2VyIH0gZnJvbSAnLi9VcGRhdGVDaGVja2VyLmpzJztcbmltcG9ydCB7IERlcGVuZGVuY3lDaGVja2VyIH0gZnJvbSAnLi9EZXBlbmRlbmN5Q2hlY2tlci5qcyc7XG5pbXBvcnQgeyBCYWNrdXBNYW5hZ2VyIH0gZnJvbSAnLi9CYWNrdXBNYW5hZ2VyLmpzJztcblxuZXhwb3J0IGludGVyZmFjZSBVcGRhdGVQcm9ncmVzcyB7XG4gIHN0ZXA6IHN0cmluZztcbiAgbWVzc2FnZTogc3RyaW5nO1xuICBpc0NvbXBsZXRlOiBib29sZWFuO1xufVxuXG5leHBvcnQgY2xhc3MgVXBkYXRlTWFuYWdlciB7XG4gIHByaXZhdGUgdmVyc2lvbk1hbmFnZXI6IFZlcnNpb25NYW5hZ2VyO1xuICBwcml2YXRlIHVwZGF0ZUNoZWNrZXI6IFVwZGF0ZUNoZWNrZXI7XG4gIHByaXZhdGUgZGVwZW5kZW5jeUNoZWNrZXI6IERlcGVuZGVuY3lDaGVja2VyO1xuICBwcml2YXRlIGJhY2t1cE1hbmFnZXI6IEJhY2t1cE1hbmFnZXI7XG4gIHByaXZhdGUgcm9vdERpcjogc3RyaW5nO1xuICBcbiAgY29uc3RydWN0b3Iocm9vdERpcj86IHN0cmluZykge1xuICAgIHRoaXMucm9vdERpciA9IHJvb3REaXIgfHwgcHJvY2Vzcy5jd2QoKTtcbiAgICB0aGlzLnZlcnNpb25NYW5hZ2VyID0gbmV3IFZlcnNpb25NYW5hZ2VyKCk7XG4gICAgdGhpcy51cGRhdGVDaGVja2VyID0gbmV3IFVwZGF0ZUNoZWNrZXIodGhpcy52ZXJzaW9uTWFuYWdlcik7XG4gICAgdGhpcy5kZXBlbmRlbmN5Q2hlY2tlciA9IG5ldyBEZXBlbmRlbmN5Q2hlY2tlcih0aGlzLnZlcnNpb25NYW5hZ2VyKTtcbiAgICB0aGlzLmJhY2t1cE1hbmFnZXIgPSBuZXcgQmFja3VwTWFuYWdlcih0aGlzLnJvb3REaXIpO1xuICB9XG4gIFxuICAvKipcbiAgICogQ2hlY2sgZm9yIGF2YWlsYWJsZSB1cGRhdGVzXG4gICAqL1xuICBhc3luYyBjaGVja0ZvclVwZGF0ZXMoKTogUHJvbWlzZTx7IHRleHQ6IHN0cmluZyB9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMudXBkYXRlQ2hlY2tlci5jaGVja0ZvclVwZGF0ZXMoKTtcbiAgICAgIGNvbnN0IHRleHQgPSB0aGlzLnVwZGF0ZUNoZWNrZXIuZm9ybWF0VXBkYXRlQ2hlY2tSZXN1bHQocmVzdWx0KTtcbiAgICAgIHJldHVybiB7IHRleHQgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc3QgdGV4dCA9IHRoaXMudXBkYXRlQ2hlY2tlci5mb3JtYXRVcGRhdGVDaGVja1Jlc3VsdChudWxsLCBlcnJvciBhcyBFcnJvcik7XG4gICAgICByZXR1cm4geyB0ZXh0IH07XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogUGVyZm9ybSBzZXJ2ZXIgdXBkYXRlXG4gICAqL1xuICBhc3luYyB1cGRhdGVTZXJ2ZXIoY3JlYXRlQmFja3VwOiBib29sZWFuID0gdHJ1ZSwgcGVyc29uYUluZGljYXRvcjogc3RyaW5nID0gJycpOiBQcm9taXNlPHsgdGV4dDogc3RyaW5nIH0+IHtcbiAgICBjb25zdCBwcm9ncmVzczogVXBkYXRlUHJvZ3Jlc3NbXSA9IFtdO1xuICAgIFxuICAgIHRyeSB7XG4gICAgICAvLyBTdGVwIDE6IENoZWNrIGRlcGVuZGVuY2llc1xuICAgICAgcHJvZ3Jlc3MucHVzaCh7IHN0ZXA6ICdkZXBlbmRlbmNpZXMnLCBtZXNzYWdlOiAnQ2hlY2tpbmcgc3lzdGVtIGRlcGVuZGVuY2llcy4uLicsIGlzQ29tcGxldGU6IGZhbHNlIH0pO1xuICAgICAgY29uc3QgZGVwZW5kZW5jaWVzID0gYXdhaXQgdGhpcy5kZXBlbmRlbmN5Q2hlY2tlci5jaGVja0RlcGVuZGVuY2llcygpO1xuICAgICAgXG4gICAgICBpZiAoIWRlcGVuZGVuY2llcy5naXQuaW5zdGFsbGVkIHx8IGRlcGVuZGVuY2llcy5naXQuZXJyb3IpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB0ZXh0OiBwZXJzb25hSW5kaWNhdG9yICsgJ+KdjCAqKlVwZGF0ZSBGYWlsZWQqKlxcblxcbicgK1xuICAgICAgICAgICAgJ0dpdCBpcyByZXF1aXJlZCBmb3IgdXBkYXRlcyBidXQgaXMgbm90IGF2YWlsYWJsZS5cXG4nICtcbiAgICAgICAgICAgIGRlcGVuZGVuY2llcy5naXQuZXJyb3IgfHwgJ0dpdCBpcyBub3QgaW5zdGFsbGVkLidcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgaWYgKCFkZXBlbmRlbmNpZXMubnBtLmluc3RhbGxlZCB8fCBkZXBlbmRlbmNpZXMubnBtLmVycm9yKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdGV4dDogcGVyc29uYUluZGljYXRvciArICfinYwgKipVcGRhdGUgRmFpbGVkKipcXG5cXG4nICtcbiAgICAgICAgICAgICducG0gaXMgcmVxdWlyZWQgZm9yIHVwZGF0ZXMgYnV0IGlzIG5vdCBhdmFpbGFibGUuXFxuJyArXG4gICAgICAgICAgICBkZXBlbmRlbmNpZXMubnBtLmVycm9yIHx8ICducG0gaXMgbm90IGluc3RhbGxlZC4nXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIHByb2dyZXNzWzBdLmlzQ29tcGxldGUgPSB0cnVlO1xuICAgICAgXG4gICAgICAvLyBTdGVwIDI6IENyZWF0ZSBiYWNrdXAgaWYgcmVxdWVzdGVkXG4gICAgICBpZiAoY3JlYXRlQmFja3VwKSB7XG4gICAgICAgIHByb2dyZXNzLnB1c2goeyBzdGVwOiAnYmFja3VwJywgbWVzc2FnZTogJ0NyZWF0aW5nIGJhY2t1cC4uLicsIGlzQ29tcGxldGU6IGZhbHNlIH0pO1xuICAgICAgICBcbiAgICAgICAgY29uc3QgY3VycmVudFZlcnNpb24gPSBhd2FpdCB0aGlzLnZlcnNpb25NYW5hZ2VyLmdldEN1cnJlbnRWZXJzaW9uKCk7XG4gICAgICAgIGNvbnN0IGJhY2t1cCA9IGF3YWl0IHRoaXMuYmFja3VwTWFuYWdlci5jcmVhdGVCYWNrdXAoY3VycmVudFZlcnNpb24pO1xuICAgICAgICBcbiAgICAgICAgcHJvZ3Jlc3NbMV0uaXNDb21wbGV0ZSA9IHRydWU7XG4gICAgICAgIHByb2dyZXNzWzFdLm1lc3NhZ2UgPSBgQmFja3VwIGNyZWF0ZWQgYXQ6ICR7YmFja3VwLnRpbWVzdGFtcH1gO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBTdGVwIDM6IEdpdCBmZXRjaFxuICAgICAgcHJvZ3Jlc3MucHVzaCh7IHN0ZXA6ICdmZXRjaCcsIG1lc3NhZ2U6ICdGZXRjaGluZyBsYXRlc3QgY2hhbmdlcy4uLicsIGlzQ29tcGxldGU6IGZhbHNlIH0pO1xuICAgICAgYXdhaXQgc2FmZUV4ZWMoJ2dpdCcsIFsnZmV0Y2gnLCAnb3JpZ2luJ10sIHsgY3dkOiB0aGlzLnJvb3REaXIgfSk7XG4gICAgICBwcm9ncmVzc1twcm9ncmVzcy5sZW5ndGggLSAxXS5pc0NvbXBsZXRlID0gdHJ1ZTtcbiAgICAgIFxuICAgICAgLy8gU3RlcCA0OiBDaGVjayBmb3IgdW5jb21taXR0ZWQgY2hhbmdlc1xuICAgICAgcHJvZ3Jlc3MucHVzaCh7IHN0ZXA6ICdjaGVjaycsIG1lc3NhZ2U6ICdDaGVja2luZyBmb3IgdW5jb21taXR0ZWQgY2hhbmdlcy4uLicsIGlzQ29tcGxldGU6IGZhbHNlIH0pO1xuICAgICAgY29uc3QgeyBzdGRvdXQ6IHN0YXR1c091dHB1dCB9ID0gYXdhaXQgc2FmZUV4ZWMoJ2dpdCcsIFsnc3RhdHVzJywgJy0tcG9yY2VsYWluJ10sIHsgY3dkOiB0aGlzLnJvb3REaXIgfSk7XG4gICAgICBcbiAgICAgIGlmIChzdGF0dXNPdXRwdXQudHJpbSgpKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdGV4dDogcGVyc29uYUluZGljYXRvciArICfinYwgKipVcGRhdGUgRmFpbGVkKipcXG5cXG4nICtcbiAgICAgICAgICAgICdZb3UgaGF2ZSB1bmNvbW1pdHRlZCBjaGFuZ2VzLiBQbGVhc2UgY29tbWl0IG9yIHN0YXNoIHRoZW0gYmVmb3JlIHVwZGF0aW5nLlxcblxcbicgK1xuICAgICAgICAgICAgJ01vZGlmaWVkIGZpbGVzOlxcbicgKyBzdGF0dXNPdXRwdXRcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIHByb2dyZXNzW3Byb2dyZXNzLmxlbmd0aCAtIDFdLmlzQ29tcGxldGUgPSB0cnVlO1xuICAgICAgXG4gICAgICAvLyBTdGVwIDU6IEdpdCBwdWxsXG4gICAgICBwcm9ncmVzcy5wdXNoKHsgc3RlcDogJ3B1bGwnLCBtZXNzYWdlOiAnUHVsbGluZyBsYXRlc3QgY2hhbmdlcy4uLicsIGlzQ29tcGxldGU6IGZhbHNlIH0pO1xuICAgICAgY29uc3QgeyBzdGRvdXQ6IHB1bGxPdXRwdXQgfSA9IGF3YWl0IHNhZmVFeGVjKCdnaXQnLCBbJ3B1bGwnLCAnb3JpZ2luJywgJ21haW4nXSwgeyBjd2Q6IHRoaXMucm9vdERpciB9KTtcbiAgICAgIHByb2dyZXNzW3Byb2dyZXNzLmxlbmd0aCAtIDFdLmlzQ29tcGxldGUgPSB0cnVlO1xuICAgICAgXG4gICAgICAvLyBDaGVjayBpZiBhbHJlYWR5IHVwIHRvIGRhdGVcbiAgICAgIGlmIChwdWxsT3V0cHV0LmluY2x1ZGVzKCdBbHJlYWR5IHVwIHRvIGRhdGUnKSkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHRleHQ6IHBlcnNvbmFJbmRpY2F0b3IgKyAn4pyFICoqQWxyZWFkeSBVcCB0byBEYXRlKipcXG5cXG4nICtcbiAgICAgICAgICAgICdZb3VyIERvbGxob3VzZU1DUCBpbnN0YWxsYXRpb24gaXMgYWxyZWFkeSBhdCB0aGUgbGF0ZXN0IHZlcnNpb24uXFxuXFxuJyArXG4gICAgICAgICAgICAnTm8gY2hhbmdlcyB3ZXJlIHB1bGxlZCBmcm9tIHRoZSByZXBvc2l0b3J5LidcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gU3RlcCA2OiBucG0gaW5zdGFsbFxuICAgICAgcHJvZ3Jlc3MucHVzaCh7IHN0ZXA6ICdpbnN0YWxsJywgbWVzc2FnZTogJ0luc3RhbGxpbmcgZGVwZW5kZW5jaWVzLi4uJywgaXNDb21wbGV0ZTogZmFsc2UgfSk7XG4gICAgICBhd2FpdCBzYWZlRXhlYygnbnBtJywgWydpbnN0YWxsJ10sIHsgY3dkOiB0aGlzLnJvb3REaXIgfSk7XG4gICAgICBwcm9ncmVzc1twcm9ncmVzcy5sZW5ndGggLSAxXS5pc0NvbXBsZXRlID0gdHJ1ZTtcbiAgICAgIFxuICAgICAgLy8gU3RlcCA3OiBCdWlsZFxuICAgICAgcHJvZ3Jlc3MucHVzaCh7IHN0ZXA6ICdidWlsZCcsIG1lc3NhZ2U6ICdCdWlsZGluZyBUeXBlU2NyaXB0Li4uJywgaXNDb21wbGV0ZTogZmFsc2UgfSk7XG4gICAgICBhd2FpdCBzYWZlRXhlYygnbnBtJywgWydydW4nLCAnYnVpbGQnXSwgeyBjd2Q6IHRoaXMucm9vdERpciB9KTtcbiAgICAgIHByb2dyZXNzW3Byb2dyZXNzLmxlbmd0aCAtIDFdLmlzQ29tcGxldGUgPSB0cnVlO1xuICAgICAgXG4gICAgICAvLyBTdGVwIDg6IENsZWFudXAgb2xkIGJhY2t1cHNcbiAgICAgIGlmIChjcmVhdGVCYWNrdXApIHtcbiAgICAgICAgcHJvZ3Jlc3MucHVzaCh7IHN0ZXA6ICdjbGVhbnVwJywgbWVzc2FnZTogJ0NsZWFuaW5nIHVwIG9sZCBiYWNrdXBzLi4uJywgaXNDb21wbGV0ZTogZmFsc2UgfSk7XG4gICAgICAgIGNvbnN0IGRlbGV0ZWRDb3VudCA9IGF3YWl0IHRoaXMuYmFja3VwTWFuYWdlci5jbGVhbnVwT2xkQmFja3VwcygpO1xuICAgICAgICBwcm9ncmVzc1twcm9ncmVzcy5sZW5ndGggLSAxXS5pc0NvbXBsZXRlID0gdHJ1ZTtcbiAgICAgICAgcHJvZ3Jlc3NbcHJvZ3Jlc3MubGVuZ3RoIC0gMV0ubWVzc2FnZSA9IGBDbGVhbmVkIHVwICR7ZGVsZXRlZENvdW50fSBvbGQgYmFja3VwKHMpYDtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gRm9ybWF0IHN1Y2Nlc3MgbWVzc2FnZVxuICAgICAgY29uc3Qgc3VjY2Vzc1BhcnRzID0gW1xuICAgICAgICBwZXJzb25hSW5kaWNhdG9yICsgJ+KchSAqKlVwZGF0ZSBDb21wbGV0ZSEqKlxcblxcbicsXG4gICAgICAgICcqKlVwZGF0ZSBTdW1tYXJ5OioqXFxuJ1xuICAgICAgXTtcbiAgICAgIFxuICAgICAgcHJvZ3Jlc3MuZm9yRWFjaChwID0+IHtcbiAgICAgICAgc3VjY2Vzc1BhcnRzLnB1c2goYCR7cC5pc0NvbXBsZXRlID8gJ+KchScgOiAn4p2MJ30gJHtwLm1lc3NhZ2V9XFxuYCk7XG4gICAgICB9KTtcbiAgICAgIFxuICAgICAgc3VjY2Vzc1BhcnRzLnB1c2goXG4gICAgICAgICdcXG4qKk5leHQgU3RlcHM6KipcXG4nLFxuICAgICAgICAnMS4gVGhlIHNlcnZlciB3aWxsIHJlc3RhcnQgYXV0b21hdGljYWxseVxcbicsXG4gICAgICAgICcyLiBBbGwgcGVyc29uYXMgd2lsbCBiZSByZWxvYWRlZFxcbicsXG4gICAgICAgICczLiBDaGVjayBgZ2V0X3NlcnZlcl9zdGF0dXNgIHRvIHZlcmlmeSB0aGUgbmV3IHZlcnNpb25cXG5cXG4nLFxuICAgICAgICAn8J+SoSAqKlRpcDoqKiBJZiB5b3UgZW5jb3VudGVyIGlzc3VlcywgdXNlIGByb2xsYmFja191cGRhdGUgdHJ1ZWAgdG8gcmVzdG9yZSB0aGUgcHJldmlvdXMgdmVyc2lvbi4nXG4gICAgICApO1xuICAgICAgXG4gICAgICByZXR1cm4geyB0ZXh0OiBzdWNjZXNzUGFydHMuam9pbignJykgfTtcbiAgICAgIFxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcik7XG4gICAgICBcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHRleHQ6IHBlcnNvbmFJbmRpY2F0b3IgKyAn4p2MICoqVXBkYXRlIEZhaWxlZCoqXFxuXFxuJyArXG4gICAgICAgICAgJ0Vycm9yOiAnICsgZXJyb3JNZXNzYWdlICsgJ1xcblxcbicgK1xuICAgICAgICAgICcqKlByb2dyZXNzOioqXFxuJyArIFxuICAgICAgICAgIHByb2dyZXNzLm1hcChwID0+IGAke3AuaXNDb21wbGV0ZSA/ICfinIUnIDogJ+KdjCd9ICR7cC5tZXNzYWdlfWApLmpvaW4oJ1xcbicpICsgJ1xcblxcbicgK1xuICAgICAgICAgICcqKlJlY292ZXJ5IE9wdGlvbnM6KipcXG4nICtcbiAgICAgICAgICAn4oCiIFRyeSBydW5uaW5nIHRoZSB1cGRhdGUgYWdhaW5cXG4nICtcbiAgICAgICAgICAn4oCiIENoZWNrIHlvdXIgaW50ZXJuZXQgY29ubmVjdGlvblxcbicgK1xuICAgICAgICAgICfigKIgRW5zdXJlIHlvdSBoYXZlIHByb3BlciBwZXJtaXNzaW9uc1xcbicgK1xuICAgICAgICAgICfigKIgSWYgYSBiYWNrdXAgd2FzIGNyZWF0ZWQsIHVzZSBgcm9sbGJhY2tfdXBkYXRlIHRydWVgIHRvIHJlc3RvcmUnXG4gICAgICB9O1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFJvbGxiYWNrIHRvIHByZXZpb3VzIHZlcnNpb25cbiAgICovXG4gIGFzeW5jIHJvbGxiYWNrVXBkYXRlKGZvcmNlOiBib29sZWFuID0gZmFsc2UsIHBlcnNvbmFJbmRpY2F0b3I6IHN0cmluZyA9ICcnKTogUHJvbWlzZTx7IHRleHQ6IHN0cmluZyB9PiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIEdldCBsYXRlc3QgYmFja3VwXG4gICAgICBjb25zdCBsYXRlc3RCYWNrdXAgPSBhd2FpdCB0aGlzLmJhY2t1cE1hbmFnZXIuZ2V0TGF0ZXN0QmFja3VwKCk7XG4gICAgICBcbiAgICAgIGlmICghbGF0ZXN0QmFja3VwKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdGV4dDogcGVyc29uYUluZGljYXRvciArICfinYwgKipObyBCYWNrdXBzIEZvdW5kKipcXG5cXG4nICtcbiAgICAgICAgICAgICdUaGVyZSBhcmUgbm8gYmFja3VwcyBhdmFpbGFibGUgdG8gcmVzdG9yZS5cXG5cXG4nICtcbiAgICAgICAgICAgICdCYWNrdXBzIGFyZSBjcmVhdGVkIGF1dG9tYXRpY2FsbHkgd2hlbiB5b3UgcnVuIGB1cGRhdGVfc2VydmVyIHRydWVgLidcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gQ2hlY2sgaWYgcm9sbGJhY2sgaXMgbmVlZGVkXG4gICAgICBpZiAoIWZvcmNlKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gVGVzdCBpZiB0aGUgc2VydmVyIGlzIHdvcmtpbmcgYnkgY2hlY2tpbmcgdmVyc2lvblxuICAgICAgICAgIGF3YWl0IHRoaXMudmVyc2lvbk1hbmFnZXIuZ2V0Q3VycmVudFZlcnNpb24oKTtcbiAgICAgICAgICBcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgdGV4dDogcGVyc29uYUluZGljYXRvciArICfimqDvuI8gKipSb2xsYmFjayBDb25maXJtYXRpb24gUmVxdWlyZWQqKlxcblxcbicgK1xuICAgICAgICAgICAgICAnVGhlIHNlcnZlciBhcHBlYXJzIHRvIGJlIHdvcmtpbmcgbm9ybWFsbHkuXFxuXFxuJyArXG4gICAgICAgICAgICAgIGAqKkxhdGVzdCBCYWNrdXA6KiogJHtsYXRlc3RCYWNrdXAudGltZXN0YW1wfVxcbmAgK1xuICAgICAgICAgICAgICBgKipCYWNrdXAgVmVyc2lvbjoqKiAke2xhdGVzdEJhY2t1cC52ZXJzaW9uIHx8ICdVbmtub3duJ31cXG5cXG5gICtcbiAgICAgICAgICAgICAgJ1RvIGZvcmNlIHJvbGxiYWNrIGFueXdheSwgdXNlOiBgcm9sbGJhY2tfdXBkYXRlIHRydWVgXFxuXFxuJyArXG4gICAgICAgICAgICAgICfimqDvuI8gKipXYXJuaW5nOioqIFRoaXMgd2lsbCByZXN0b3JlIGFsbCBmaWxlcyB0byB0aGUgYmFja3VwIHN0YXRlLidcbiAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAvLyBTZXJ2ZXIgaXMgYnJva2VuLCBwcm9jZWVkIHdpdGggcm9sbGJhY2tcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBQZXJmb3JtIHJvbGxiYWNrXG4gICAgICBhd2FpdCB0aGlzLmJhY2t1cE1hbmFnZXIucmVzdG9yZUJhY2t1cChsYXRlc3RCYWNrdXAucGF0aCk7XG4gICAgICBcbiAgICAgIC8vIFJlaW5zdGFsbCBkZXBlbmRlbmNpZXNcbiAgICAgIGF3YWl0IHNhZmVFeGVjKCducG0nLCBbJ2luc3RhbGwnXSwgeyBjd2Q6IHRoaXMucm9vdERpciB9KTtcbiAgICAgIFxuICAgICAgLy8gUmVidWlsZFxuICAgICAgYXdhaXQgc2FmZUV4ZWMoJ25wbScsIFsncnVuJywgJ2J1aWxkJ10sIHsgY3dkOiB0aGlzLnJvb3REaXIgfSk7XG4gICAgICBcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHRleHQ6IHBlcnNvbmFJbmRpY2F0b3IgKyAn4pyFICoqUm9sbGJhY2sgQ29tcGxldGUhKipcXG5cXG4nICtcbiAgICAgICAgICBgUmVzdG9yZWQgZnJvbSBiYWNrdXA6ICR7bGF0ZXN0QmFja3VwLnRpbWVzdGFtcH1cXG5gICtcbiAgICAgICAgICBgQmFja3VwIHZlcnNpb246ICR7bGF0ZXN0QmFja3VwLnZlcnNpb24gfHwgJ1Vua25vd24nfVxcblxcbmAgK1xuICAgICAgICAgICcqKldoYXQgd2FzIHJlc3RvcmVkOioqXFxuJyArXG4gICAgICAgICAgJ+KAoiBBbGwgc291cmNlIGZpbGVzXFxuJyArXG4gICAgICAgICAgJ+KAoiBDb25maWd1cmF0aW9uIGZpbGVzXFxuJyArXG4gICAgICAgICAgJ+KAoiBEZXBlbmRlbmNpZXMgcmVpbnN0YWxsZWRcXG4nICtcbiAgICAgICAgICAn4oCiIFR5cGVTY3JpcHQgcmVidWlsdFxcblxcbicgK1xuICAgICAgICAgICcqKk5leHQgU3RlcHM6KipcXG4nICtcbiAgICAgICAgICAnMS4gVGhlIHNlcnZlciB3aWxsIHJlc3RhcnQgYXV0b21hdGljYWxseVxcbicgK1xuICAgICAgICAgICcyLiBDaGVjayBgZ2V0X3NlcnZlcl9zdGF0dXNgIHRvIHZlcmlmeSB0aGUgdmVyc2lvblxcbicgK1xuICAgICAgICAgICczLiBUZXN0IHlvdXIgcGVyc29uYXMgdG8gZW5zdXJlIGV2ZXJ5dGhpbmcgd29ya3MnXG4gICAgICB9O1xuICAgICAgXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKTtcbiAgICAgIFxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdGV4dDogcGVyc29uYUluZGljYXRvciArICfinYwgKipSb2xsYmFjayBGYWlsZWQqKlxcblxcbicgK1xuICAgICAgICAgICdFcnJvcjogJyArIGVycm9yTWVzc2FnZSArICdcXG5cXG4nICtcbiAgICAgICAgICAnKipNYW51YWwgUmVjb3Zlcnk6KipcXG4nICtcbiAgICAgICAgICAnMS4gQ2hlY2sgdGhlIGJhY2t1cHMgZGlyZWN0b3J5OiAuLi9kb2xsaG91c2VtY3AtYmFja3Vwcy9cXG4nICtcbiAgICAgICAgICAnMi4gTWFudWFsbHkgcmVzdG9yZSBmaWxlcyBpZiBuZWVkZWRcXG4nICtcbiAgICAgICAgICAnMy4gUnVuIGBucG0gaW5zdGFsbGAgYW5kIGBucG0gcnVuIGJ1aWxkYFxcbicgK1xuICAgICAgICAgICc0LiBDb250YWN0IHN1cHBvcnQgaWYgaXNzdWVzIHBlcnNpc3QnXG4gICAgICB9O1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBjdXJyZW50IHNlcnZlciBzdGF0dXNcbiAgICovXG4gIGFzeW5jIGdldFNlcnZlclN0YXR1cyhwZXJzb25hSW5kaWNhdG9yOiBzdHJpbmcgPSAnJyk6IFByb21pc2U8eyB0ZXh0OiBzdHJpbmcgfT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjdXJyZW50VmVyc2lvbiA9IGF3YWl0IHRoaXMudmVyc2lvbk1hbmFnZXIuZ2V0Q3VycmVudFZlcnNpb24oKTtcbiAgICAgIGNvbnN0IGRlcGVuZGVuY2llcyA9IGF3YWl0IHRoaXMuZGVwZW5kZW5jeUNoZWNrZXIuY2hlY2tEZXBlbmRlbmNpZXMoKTtcbiAgICAgIGNvbnN0IGJhY2t1cHMgPSBhd2FpdCB0aGlzLmJhY2t1cE1hbmFnZXIubGlzdEJhY2t1cHMoKTtcbiAgICAgIGNvbnN0IHJhdGVMaW1pdFN0YXR1cyA9IHRoaXMudXBkYXRlQ2hlY2tlci5nZXRSYXRlTGltaXRTdGF0dXMoKTtcbiAgICAgIFxuICAgICAgLy8gR2V0IGdpdCBzdGF0dXNcbiAgICAgIGxldCBnaXRTdGF0dXMgPSAnVW5rbm93bic7XG4gICAgICBsZXQgZ2l0QnJhbmNoID0gJ1Vua25vd24nO1xuICAgICAgbGV0IGxhc3RDb21taXQgPSAnVW5rbm93bic7XG4gICAgICBcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHsgc3Rkb3V0OiBicmFuY2hPdXRwdXQgfSA9IGF3YWl0IHNhZmVFeGVjKCdnaXQnLCBbJ2JyYW5jaCcsICctLXNob3ctY3VycmVudCddLCB7IGN3ZDogdGhpcy5yb290RGlyIH0pO1xuICAgICAgICBnaXRCcmFuY2ggPSBicmFuY2hPdXRwdXQudHJpbSgpIHx8ICdkZXRhY2hlZCc7XG4gICAgICAgIFxuICAgICAgICBjb25zdCB7IHN0ZG91dDogc3RhdHVzT3V0cHV0IH0gPSBhd2FpdCBzYWZlRXhlYygnZ2l0JywgWydzdGF0dXMnLCAnLS1wb3JjZWxhaW4nXSwgeyBjd2Q6IHRoaXMucm9vdERpciB9KTtcbiAgICAgICAgZ2l0U3RhdHVzID0gc3RhdHVzT3V0cHV0LnRyaW0oKSA/ICdNb2RpZmllZCcgOiAnQ2xlYW4nO1xuICAgICAgICBcbiAgICAgICAgY29uc3QgeyBzdGRvdXQ6IGxvZ091dHB1dCB9ID0gYXdhaXQgc2FmZUV4ZWMoJ2dpdCcsIFsnbG9nJywgJy0xJywgJy0tb25lbGluZSddLCB7IGN3ZDogdGhpcy5yb290RGlyIH0pO1xuICAgICAgICBsYXN0Q29tbWl0ID0gbG9nT3V0cHV0LnRyaW0oKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBHaXQgY29tbWFuZHMgZmFpbGVkLCB1c2UgZGVmYXVsdHNcbiAgICAgIH1cbiAgICAgIFxuICAgICAgY29uc3Qgc3RhdHVzUGFydHMgPSBbXG4gICAgICAgIHBlcnNvbmFJbmRpY2F0b3IgKyAn8J+TiiAqKkRvbGxob3VzZU1DUCBTZXJ2ZXIgU3RhdHVzKipcXG5cXG4nLFxuICAgICAgICAnKipWZXJzaW9uIEluZm9ybWF0aW9uOioqXFxuJyxcbiAgICAgICAgYOKAoiBDdXJyZW50IFZlcnNpb246ICR7Y3VycmVudFZlcnNpb259XFxuYCxcbiAgICAgICAgYOKAoiBHaXQgQnJhbmNoOiAke2dpdEJyYW5jaH1cXG5gLFxuICAgICAgICBg4oCiIEdpdCBTdGF0dXM6ICR7Z2l0U3RhdHVzfVxcbmAsXG4gICAgICAgIGDigKIgTGFzdCBDb21taXQ6ICR7bGFzdENvbW1pdH1cXG5cXG5gLFxuICAgICAgICAnKipEZXBlbmRlbmNpZXM6KipcXG4nLFxuICAgICAgICB0aGlzLmRlcGVuZGVuY3lDaGVja2VyLmZvcm1hdERlcGVuZGVuY3lTdGF0dXMoZGVwZW5kZW5jaWVzKSxcbiAgICAgICAgJ1xcblxcbioqQmFja3VwczoqKlxcbicsXG4gICAgICAgIGDigKIgVG90YWwgQmFja3VwczogJHtiYWNrdXBzLmxlbmd0aH1cXG5gXG4gICAgICBdO1xuICAgICAgXG4gICAgICBpZiAoYmFja3Vwcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHN0YXR1c1BhcnRzLnB1c2goYOKAoiBMYXRlc3QgQmFja3VwOiAke2JhY2t1cHNbMF0udGltZXN0YW1wfSAodiR7YmFja3Vwc1swXS52ZXJzaW9uIHx8ICd1bmtub3duJ30pXFxuYCk7XG4gICAgICAgIHN0YXR1c1BhcnRzLnB1c2goYOKAoiBPbGRlc3QgQmFja3VwOiAke2JhY2t1cHNbYmFja3Vwcy5sZW5ndGggLSAxXS50aW1lc3RhbXB9XFxuYCk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIHN0YXR1c1BhcnRzLnB1c2goXG4gICAgICAgICdcXG4qKlJhdGUgTGltaXQgU3RhdHVzOioqXFxuJyxcbiAgICAgICAgYOKAoiBVcGRhdGUgQ2hlY2tzIFJlbWFpbmluZzogJHtyYXRlTGltaXRTdGF0dXMucmVtYWluaW5nUmVxdWVzdHN9LzEwIHBlciBob3VyXFxuYCxcbiAgICAgICAgYOKAoiBSYXRlIExpbWl0IFJlc2V0czogJHtyYXRlTGltaXRTdGF0dXMucmVzZXRUaW1lLnRvTG9jYWxlVGltZVN0cmluZygpfVxcbmBcbiAgICAgICk7XG4gICAgICBcbiAgICAgIGlmICghcmF0ZUxpbWl0U3RhdHVzLmFsbG93ZWQgJiYgcmF0ZUxpbWl0U3RhdHVzLndhaXRUaW1lU2Vjb25kcykge1xuICAgICAgICBzdGF0dXNQYXJ0cy5wdXNoKGDigKIg4o+zIFdhaXQgJHtyYXRlTGltaXRTdGF0dXMud2FpdFRpbWVTZWNvbmRzfSBzZWNvbmRzIGJlZm9yZSBuZXh0IGNoZWNrXFxuYCk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIHN0YXR1c1BhcnRzLnB1c2goXG4gICAgICAgICdcXG4qKkF2YWlsYWJsZSBDb21tYW5kczoqKlxcbicsXG4gICAgICAgICfigKIgYGNoZWNrX2Zvcl91cGRhdGVzYCAtIENoZWNrIGZvciBuZXcgdmVyc2lvbnNcXG4nLFxuICAgICAgICAn4oCiIGB1cGRhdGVfc2VydmVyIHRydWVgIC0gVXBkYXRlIHRvIGxhdGVzdCB2ZXJzaW9uXFxuJyxcbiAgICAgICAgJ+KAoiBgcm9sbGJhY2tfdXBkYXRlIHRydWVgIC0gUmVzdG9yZSBmcm9tIGJhY2t1cFxcbidcbiAgICAgICk7XG4gICAgICBcbiAgICAgIHJldHVybiB7IHRleHQ6IHN0YXR1c1BhcnRzLmpvaW4oJycpIH07XG4gICAgICBcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc3QgZXJyb3JNZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpO1xuICAgICAgXG4gICAgICByZXR1cm4ge1xuICAgICAgICB0ZXh0OiBwZXJzb25hSW5kaWNhdG9yICsgJ+KdjCAqKlN0YXR1cyBDaGVjayBGYWlsZWQqKlxcblxcbicgK1xuICAgICAgICAgICdFcnJvcjogJyArIGVycm9yTWVzc2FnZSArICdcXG5cXG4nICtcbiAgICAgICAgICAnVGhlIHNlcnZlciBtYXkgYmUgaW4gYW4gaW5jb25zaXN0ZW50IHN0YXRlLlxcbicgK1xuICAgICAgICAgICdUcnkgcnVubmluZyBgdXBkYXRlX3NlcnZlciB0cnVlYCB0byBmaXggaXNzdWVzLidcbiAgICAgIH07XG4gICAgfVxuICB9XG59Il19