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.

330 lines 55.4 kB
/** * BuildInfoService - Provides build and runtime information * Separated from main index.ts to avoid making that file larger * * SECURITY FIX (PR #614): * 1. DMCP-SEC-004: FALSE POSITIVE SUPPRESSION - No user input Unicode normalization needed * This service only processes system information (git, package.json, environment variables) * The MCP tool 'get_build_info' takes NO parameters (empty inputSchema) * No user-provided data flows through this service that requires Unicode normalization */ import * as child_process from 'child_process'; import { logger } from '../utils/logger.js'; import { PACKAGE_NAME, PACKAGE_VERSION, BUILD_TIMESTAMP, BUILD_TYPE } from '../generated/version.js'; import { resolveSessionIdentity } from './sessionIdentity.js'; import { getPermissionHookAuditSummary, summarizePermissionHookHealth, } from '../utils/permissionHooks.js'; export class BuildInfoService { startTime; fileOperations; /** Issue #706: Optional startup timer for timing instrumentation. */ startupTimer = null; /** Issue #706: Callback to check deferred setup status. */ deferredSetupChecker = null; constructor(fileOperations) { this.startTime = new Date(); this.fileOperations = fileOperations; } /** * Issue #706: Wire in startup instrumentation after DI is ready. * Called from Container to avoid circular dependency at registration time. */ setStartupTimer(timer) { this.startupTimer = timer; } /** * Issue #706: Wire in deferred setup status checker. */ setDeferredSetupChecker(checker) { this.deferredSetupChecker = checker; } /** * Get comprehensive build information * SECURITY NOTE: This method processes only system-generated data * No user input is involved - all data comes from filesystem, git, and Node.js process * * Uses Promise.allSettled to collect partial results even if some sources fail, * providing maximum information availability with graceful degradation. */ async getBuildInfo() { // Use Promise.allSettled to collect all available info, even if some sources fail const results = await Promise.allSettled([ this.getGitInfo(), this.getDockerInfo(), getPermissionHookAuditSummary(), ]); // Package info comes from build-time generated constants const packageInfo = { name: PACKAGE_NAME, version: PACKAGE_VERSION }; const gitInfo = results[0].status === 'fulfilled' ? results[0].value : { commit: undefined, branch: undefined }; const dockerInfo = results[1].status === 'fulfilled' ? results[1].value : { isDocker: false, info: undefined }; const permissionHookInfo = results[2].status === 'fulfilled' ? results[2].value : { installedHosts: [], currentHosts: [], repairedHosts: [], needsRepairHosts: [], diagnosticsPath: '', lastDiagnostic: null, lastStartupRepair: null, }; const permissionHookHealth = summarizePermissionHookHealth(permissionHookInfo); const formatSettledReason = (reason) => (reason instanceof Error ? `${reason.name}: ${reason.message}` : String(reason)); // Log any failures for diagnostics const failures = []; if (results[0].status === 'rejected') { failures.push(`git info: ${formatSettledReason(results[0].reason)}`); } if (results[1].status === 'rejected') { failures.push(`docker info: ${formatSettledReason(results[1].reason)}`); } if (results[2].status === 'rejected') { failures.push(`permission hook audit: ${formatSettledReason(results[2].reason)}`); } if (failures.length > 0) { logger.debug(`Build info collection had ${failures.length} failure(s): ${failures.join('; ')}`); } // Build timestamp comes from build-time generated constants const buildTimestamp = BUILD_TIMESTAMP; // Issue #706: Startup timing and readiness const deferredComplete = this.deferredSetupChecker ? this.deferredSetupChecker() : true; const startupInfo = { status: deferredComplete ? 'ready' : 'initializing', deferredSetupComplete: deferredComplete, uptimeMs: Date.now() - this.startTime.getTime(), startupTimingMs: this.startupTimer?.getReport(), }; const sessionIdentity = resolveSessionIdentity(); return { sessionId: sessionIdentity.sessionId, runtimeSessionId: sessionIdentity.runtimeSessionId, sessionSource: sessionIdentity.source, package: packageInfo, build: { timestamp: buildTimestamp, type: BUILD_TYPE, gitCommit: gitInfo.commit, gitBranch: gitInfo.branch, }, runtime: { nodeVersion: process.version, platform: process.platform, arch: process.arch, uptime: process.uptime(), memoryUsage: process.memoryUsage() }, environment: { nodeEnv: process.env.NODE_ENV, isProduction: process.env.NODE_ENV === 'production', isDevelopment: process.env.NODE_ENV === 'development', isDebug: process.env.DEBUG === 'true' || process.env.DEBUG === '1', isDocker: dockerInfo.isDocker, dockerInfo: dockerInfo.info }, server: { startTime: this.startTime, uptime: Date.now() - this.startTime.getTime(), mcpConnection: true // We're connected if this method is being called via MCP }, permissionHooks: { ...permissionHookInfo, health: permissionHookHealth, }, startup: startupInfo, }; } /** * Format build info as user-friendly markdown * SECURITY NOTE: Only formats system-generated data - no user input processing * All input data comes from getBuildInfo() which only reads system information */ formatBuildInfo(info) { const lines = []; lines.push('# 🔧 Build Information\n'); // Package info lines.push('## 📦 Package'); lines.push(`- **Name**: ${info.package.name}`); lines.push(`- **Version**: ${info.package.version}`); lines.push(''); const identitySourceLabel = info.sessionSource === 'env' ? 'Explicit environment' : 'Derived from workspace context'; const sessionLines = [ '## 🪪 Session', `- **Session ID**: ${info.sessionId}`, `- **Identity Source**: ${identitySourceLabel}`, ]; if (info.runtimeSessionId !== info.sessionId) { sessionLines.splice(2, 0, `- **Runtime Session ID**: ${info.runtimeSessionId}`); } lines.push(...sessionLines, ''); // Build info lines.push('## 🏗️ Build'); lines.push(`- **Type**: ${info.build.type}`); if (info.build.timestamp) { lines.push(`- **Timestamp**: ${info.build.timestamp}`); } if (info.build.gitCommit) { lines.push(`- **Git Commit**: \`${info.build.gitCommit}\``); } if (info.build.gitBranch) { lines.push(`- **Git Branch**: ${info.build.gitBranch}`); } lines.push(''); // Runtime info lines.push('## 💻 Runtime'); lines.push(`- **Node.js**: ${info.runtime.nodeVersion}`); lines.push(`- **Platform**: ${info.runtime.platform}`); lines.push(`- **Architecture**: ${info.runtime.arch}`); lines.push(`- **Process Uptime**: ${this.formatUptime(info.runtime.uptime)}`); lines.push(`- **Memory Usage**: ${this.formatMemory(info.runtime.memoryUsage.heapUsed)} / ${this.formatMemory(info.runtime.memoryUsage.heapTotal)}`); lines.push(''); // Environment info lines.push('## ⚙️ Environment'); lines.push(`- **NODE_ENV**: ${info.environment.nodeEnv || 'not set'}`); lines.push(`- **Mode**: ${info.environment.isProduction ? 'Production' : info.environment.isDevelopment ? 'Development' : 'Unknown'}`); lines.push(`- **Debug**: ${info.environment.isDebug ? 'Enabled' : 'Disabled'}`); lines.push(`- **Docker**: ${info.environment.isDocker ? 'Yes' : 'No'}`); if (info.environment.dockerInfo) { lines.push(`- **Container**: ${info.environment.dockerInfo}`); } lines.push(''); // Server info lines.push('## 🚀 Server'); lines.push(`- **Started**: ${info.server.startTime.toISOString()}`); lines.push(`- **Uptime**: ${this.formatUptime(info.server.uptime / 1000)}`); lines.push(`- **MCP Connection**: ${info.server.mcpConnection ? '✅ Connected' : '❌ Disconnected'}`); if (info.permissionHooks) { const installedHosts = info.permissionHooks.installedHosts.length > 0 ? info.permissionHooks.installedHosts.join(', ') : 'None'; const currentHosts = info.permissionHooks.currentHosts.length > 0 ? info.permissionHooks.currentHosts.join(', ') : 'None'; const needsRepairHosts = info.permissionHooks.needsRepairHosts.length > 0 ? info.permissionHooks.needsRepairHosts.join(', ') : 'None'; const lastStartupRepair = info.permissionHooks.lastStartupRepair; const startupRepairIssues = lastStartupRepair ? lastStartupRepair.hostResults .filter((result) => result.outcome === 'needs_repair' || result.outcome === 'error') .map((result) => result.repairError ? `${result.host} (${result.repairError})` : result.host) .join('; ') : ''; lines.push('', '## 🔐 Permission Hooks', `- **Health**: ${info.permissionHooks.health.status.toUpperCase()} — ${info.permissionHooks.health.message}`, `- **Installed Hosts**: ${installedHosts}`, `- **Current Assets**: ${currentHosts}`, `- **Needs Repair**: ${needsRepairHosts}`); if (info.permissionHooks.diagnosticsPath) { lines.push(`- **Diagnostics Log**: ${info.permissionHooks.diagnosticsPath}`); } if (lastStartupRepair) { lines.push(`- **Last Startup Audit**: ${lastStartupRepair.completedAt} (${lastStartupRepair.durationMs}ms)`, `- **Startup Repairs Applied**: ${lastStartupRepair.repairedCount}`, `- **Startup Repair Issues**: ${startupRepairIssues || 'None'}`); } if (info.permissionHooks.lastDiagnostic) { const lastDiagnostic = info.permissionHooks.lastDiagnostic; const diagnosticOutcome = lastDiagnostic.outcome ? `${lastDiagnostic.event} / ${lastDiagnostic.outcome}` : lastDiagnostic.event; lines.push(`- **Last Diagnostic Event**: ${lastDiagnostic.timestamp} (${diagnosticOutcome})`, `- **Last Diagnostic Stage**: ${lastDiagnostic.stage}`, `- **Last Diagnostic Input Bytes**: ${lastDiagnostic.rawInputLength ?? 0}`, `- **Last Diagnostic Normalized Bytes**: ${lastDiagnostic.normalizedResponseLength ?? 0}`, `- **Last Diagnostic Emitted Bytes**: ${lastDiagnostic.emittedResponseLength ?? 0}`); if (lastDiagnostic.reason) { lines.push(`- **Last Diagnostic Reason**: ${lastDiagnostic.reason}`); } } } // Issue #706: Startup timing if (info.startup) { lines.push(''); lines.push('## ⏱️ Startup'); lines.push(`- **Status**: ${info.startup.status === 'ready' ? '✅ Ready' : '⏳ Initializing'}`); lines.push(`- **Deferred Setup**: ${info.startup.deferredSetupComplete ? 'Complete' : 'In Progress'}`); if (info.startup.startupTimingMs) { const timing = info.startup.startupTimingMs; lines.push(`- **Critical Path**: ${timing.criticalPathMs}ms`); lines.push(`- **Deferred Work**: ${timing.deferredMs}ms`); lines.push(`- **Total Startup**: ${timing.totalMs}ms`); if (timing.connectAtMs !== null) { lines.push(`- **Time to Connect**: ${timing.connectAtMs}ms`); } if (timing.phases.length > 0) { lines.push('- **Phases**:'); for (const phase of timing.phases) { const tag = phase.critical ? 'critical' : 'deferred'; lines.push(` - ${phase.name}: ${phase.durationMs}ms (${tag})`); } } } } return lines.join('\n'); } /** * SECURITY NOTE: No Unicode normalization needed - executes system git commands * Data source: Git CLI output (system-controlled), no user input */ async getGitInfo() { try { // SECURITY NOTE: Git commands return system-controlled data - not user input // Git commit hashes and branch names are controlled by git, no Unicode normalization needed const commit = child_process.execSync('git rev-parse --short HEAD', { encoding: 'utf-8' }).trim(); const branch = child_process.execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim(); return { commit, branch }; } catch { // Not in a git repository or git not available return {}; } } /** * SECURITY NOTE: No Unicode normalization needed - reads container runtime files * Data source: System cgroup files (container-controlled), no user input */ async getDockerInfo() { try { // SECURITY NOTE: Reading system cgroup file - controlled by container runtime, not user input // Container runtime generates this file content, no Unicode normalization needed const cgroupContent = await this.fileOperations.readFile('/proc/1/cgroup', { source: 'BuildInfoService.getDockerInfo' }); const isDocker = cgroupContent.includes('docker') || cgroupContent.includes('containerd'); if (isDocker) { // Try to get container ID const containerId = cgroupContent .split('\n') .find(line => line.includes('docker')) ?.split('/') .pop() ?.substring(0, 12); return { isDocker: true, info: containerId ? `Container ID: ${containerId}` : 'Running in Docker' }; } return { isDocker: false }; } catch { // Not in Docker or /proc not available return { isDocker: false }; } } formatUptime(seconds) { const days = Math.floor(seconds / 86400); const hours = Math.floor((seconds % 86400) / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = Math.floor(seconds % 60); const parts = []; if (days > 0) parts.push(`${days}d`); if (hours > 0) parts.push(`${hours}h`); if (minutes > 0) parts.push(`${minutes}m`); if (secs > 0 || parts.length === 0) parts.push(`${secs}s`); return parts.join(' '); } formatMemory(bytes) { const mb = bytes / 1024 / 1024; return `${mb.toFixed(1)} MB`; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQnVpbGRJbmZvU2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aWNlcy9CdWlsZEluZm9TZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7R0FTRztBQUVILE9BQU8sS0FBSyxhQUFhLE1BQU0sZUFBZSxDQUFDO0FBQy9DLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUU1QyxPQUFPLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFckcsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDOUQsT0FBTyxFQUNMLDZCQUE2QixFQUU3Qiw2QkFBNkIsR0FHOUIsTUFBTSw2QkFBNkIsQ0FBQztBQXVEckMsTUFBTSxPQUFPLGdCQUFnQjtJQUNWLFNBQVMsQ0FBTztJQUNoQixjQUFjLENBQXlCO0lBQ3hELHFFQUFxRTtJQUM3RCxZQUFZLEdBQXdCLElBQUksQ0FBQztJQUNqRCwyREFBMkQ7SUFDbkQsb0JBQW9CLEdBQTJCLElBQUksQ0FBQztJQUU1RCxZQUFZLGNBQXNDO1FBQ2hELElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUM1QixJQUFJLENBQUMsY0FBYyxHQUFHLGNBQWMsQ0FBQztJQUN2QyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsZUFBZSxDQUFDLEtBQW1CO1FBQ2pDLElBQUksQ0FBQyxZQUFZLEdBQUcsS0FBSyxDQUFDO0lBQzVCLENBQUM7SUFFRDs7T0FFRztJQUNILHVCQUF1QixDQUFDLE9BQXNCO1FBQzVDLElBQUksQ0FBQyxvQkFBb0IsR0FBRyxPQUFPLENBQUM7SUFDdEMsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSSxLQUFLLENBQUMsWUFBWTtRQUN2QixrRkFBa0Y7UUFDbEYsTUFBTSxPQUFPLEdBQUcsTUFBTSxPQUFPLENB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LE9BQU8sR0FBRyxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztRQUNuRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ2xELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBRXRDLE1BQU0sS0FBSyxHQUFhLEVBQUUsQ0FBQztRQUMzQixJQUFJLElBQUksR0FBRyxDQUFDO1lBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLENBQUM7UUFDckMsSUFBSSxLQUFLLEdBQUcsQ0FBQztZQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLEdBQUcsQ0FBQyxDQUFDO1FBQ3ZDLElBQUksT0FBTyxHQUFHLENBQUM7WUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxHQUFHLENBQUMsQ0FBQztRQUMzQyxJQUFJLElBQUksR0FBRyxDQUFDLElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLENBQUM7UUFFM0QsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3pCLENBQUM7SUFFTyxZQUFZLENBQUMsS0FBYTtRQUNoQyxNQUFNLEVBQUUsR0FBRyxLQUFLLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztRQUMvQixPQUFPLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQy9CLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQnVpbGRJbmZvU2VydmljZSAtIFByb3ZpZGVzIGJ1aWxkIGFuZCBydW50aW1lIGluZm9ybWF0aW9uXG4gKiBTZXBhcmF0ZWQgZnJvbSBtYWluIGluZGV4LnRzIHRvIGF2b2lkIG1ha2luZyB0aGF0IGZpbGUgbGFyZ2VyXG4gKiBcbiAqIFNFQ1VSSVRZIEZJWCAoUFIgIzYxNCk6XG4gKiAxLiBETUNQLVNFQy0wMDQ6IEZBTFNFIFBPU0lUSVZFIFNVUFBSRVNTSU9OIC0gTm8gdXNlciBpbnB1dCBVbmljb2RlIG5vcm1hbGl6YXRpb24gbmVlZGVkXG4gKiAgICBUaGlzIHNlcnZpY2Ugb25seSBwcm9jZXNzZXMgc3lzdGVtIGluZm9ybWF0aW9uIChnaXQsIHBhY2thZ2UuanNvbiwgZW52aXJvbm1lbnQgdmFyaWFibGVzKVxuICogICAgVGhlIE1DUCB0b29sICdnZXRfYnVpbGRfaW5mbycgdGFrZXMgTk8gcGFyYW1ldGVycyAoZW1wdHkgaW5wdXRTY2hlbWEpXG4gKiAgICBObyB1c2VyLXByb3ZpZGVkIGRhdGEgZmxvd3MgdGhyb3VnaCB0aGlzIHNlcnZpY2UgdGhhdCByZXF1aXJlcyBVbmljb2RlIG5vcm1hbGl6YXRpb25cbiAqL1xuXG5pbXBvcnQgKiBhcyBjaGlsZF9wcm9jZXNzIGZyb20gJ2NoaWxkX3Byb2Nlc3MnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IElGaWxlT3BlcmF0aW9uc1NlcnZpY2UgfSBmcm9tICcuL0ZpbGVPcGVyYXRpb25zU2VydmljZS5qcyc7XG5pbXBvcnQgeyBQQUNLQUdFX05BTUUsIFBBQ0tBR0VfVkVSU0lPTiwgQlVJTERfVElNRVNUQU1QLCBCVUlMRF9UWVBFIH0gZnJvbSAnLi4vZ2VuZXJhdGVkL3ZlcnNpb24uanMnO1xuaW1wb3J0IHR5cGUgeyBTdGFydHVwVGltZXIsIFN0YXJ0dXBSZXBvcnQgfSBmcm9tICcuLi90ZWxlbWV0cnkvU3RhcnR1cFRpbWVyLmpzJztcbmltcG9ydCB7IHJlc29sdmVTZXNzaW9uSWRlbnRpdHkgfSBmcm9tICcuL3Nlc3Npb25JZGVudGl0eS5qcyc7XG5pbXBvcnQge1xuICBnZXRQZXJtaXNzaW9uSG9va0F1ZGl0U3VtbWFyeSxcbiAgdHlwZSBQZXJtaXNzaW9uSG9va0RpYWdub3N0aWNSZWNvcmQsXG4gIHN1bW1hcml6ZVBlcm1pc3Npb25Ib29rSGVhbHRoLFxuICB0eXBlIFBlcm1pc3Npb25Ib29rSGVhbHRoU3VtbWFyeSxcbiAgdHlwZSBQZXJtaXNzaW9uSG9va1N0YXJ0dXBSZXBhaXJTdW1tYXJ5LFxufSBmcm9tICcuLi91dGlscy9wZXJtaXNzaW9uSG9va3MuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEJ1aWxkSW5mbyB7XG4gIHNlc3Npb25JZDogc3RyaW5nO1xuICBydW50aW1lU2Vzc2lvbklkOiBzdHJpbmc7XG4gIHNlc3Npb25Tb3VyY2U6ICdlbnYnIHwgJ2Rlcml2ZWQnO1xuICBwYWNrYWdlOiB7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIHZlcnNpb246IHN0cmluZztcbiAgfTtcbiAgYnVpbGQ6IHtcbiAgICB0aW1lc3RhbXA/OiBzdHJpbmc7XG4gICAgdHlwZTogJ2dpdCcgfCAnbnBtJyB8ICd1bmtub3duJztcbiAgICBnaXRDb21taXQ/OiBzdHJpbmc7XG4gICAgZ2l0QnJhbmNoPzogc3RyaW5nO1xuICB9O1xuICBydW50aW1lOiB7XG4gICAgbm9kZVZlcnNpb246IHN0cmluZztcbiAgICBwbGF0Zm9ybTogc3RyaW5nO1xuICAgIGFyY2g6IHN0cmluZztcbiAgICB1cHRpbWU6IG51bWJlcjtcbiAgICBtZW1vcnlVc2FnZTogTm9kZUpTLk1lbW9yeVVzYWdlO1xuICB9O1xuICBlbnZpcm9ubWVudDoge1xuICAgIG5vZGVFbnY/OiBzdHJpbmc7XG4gICAgaXNQcm9kdWN0aW9uOiBib29sZWFuO1xuICAgIGlzRGV2ZWxvcG1lbnQ6IGJvb2xlYW47XG4gICAgaXNEZWJ1ZzogYm9vbGVhbjtcbiAgICBpc0RvY2tlcjogYm9vbGVhbjtcbiAgICBkb2NrZXJJbmZvPzogc3RyaW5nO1xuICB9O1xuICBzZXJ2ZXI6IHtcbiAgICBzdGFydFRpbWU6IERhdGU7XG4gICAgdXB0aW1lOiBudW1iZXI7XG4gICAgbWNwQ29ubmVjdGlvbjogYm9vbGVhbjtcbiAgfTtcbiAgcGVybWlzc2lvbkhvb2tzPzoge1xuICAgIGhlYWx0aDogUGVybWlzc2lvbkhvb2tIZWFsdGhTdW1tYXJ5O1xuICAgIGluc3RhbGxlZEhvc3RzOiBzdHJpbmdbXTtcbiAgICBjdXJyZW50SG9zdHM6IHN0cmluZ1tdO1xuICAgIHJlcGFpcmVkSG9zdHM6IHN0cmluZ1tdO1xuICAgIG5lZWRzUmVwYWlySG9zdHM6IHN0cmluZ1tdO1xuICAgIGRpYWdub3N0aWNzUGF0aDogc3RyaW5nO1xuICAgIGxhc3REaWFnbm9zdGljOiBQZXJtaXNzaW9uSG9va0RpYWdub3N0aWNSZWNvcmQgfCBudWxsO1xuICAgIGxhc3RTdGFydHVwUmVwYWlyOiBQZXJtaXNzaW9uSG9va1N0YXJ0dXBSZXBhaXJTdW1tYXJ5IHwgbnVsbDtcbiAgfTtcbiAgLyoqIElzc3VlICM3MDY6IFN0YXJ0dXAgdGltaW5nIGFuZCByZWFkaW5lc3Mgc3RhdHVzLiAqL1xuICBzdGFydHVwPzoge1xuICAgIHN0YXR1czogJ3JlYWR5JyB8ICdpbml0aWFsaXppbmcnO1xuICAgIGRlZmVycmVkU2V0dXBDb21wbGV0ZTogYm9vbGVhbjtcbiAgICB1cHRpbWVNczogbnVtYmVyO1xuICAgIHN0YXJ0dXBUaW1pbmdNcz86IFN0YXJ0dXBSZXBvcnQ7XG4gIH07XG59XG5cbmV4cG9ydCBjbGFzcyBCdWlsZEluZm9TZXJ2aWNlIHtcbiAgcHJpdmF0ZSByZWFkb25seSBzdGFydFRpbWU6IERhdGU7XG4gIHByaXZhdGUgcmVhZG9ubHkgZmlsZU9wZXJhdGlvbnM6IElGaWxlT3BlcmF0aW9uc1NlcnZpY2U7XG4gIC8qKiBJc3N1ZSAjNzA2OiBPcHRpb25hbCBzdGFydHVwIHRpbWVyIGZvciB0aW1pbmcgaW5zdHJ1bWVudGF0aW9uLiAqL1xuICBwcml2YXRlIHN0YXJ0dXBUaW1lcjogU3RhcnR1cFRpbWVyIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBJc3N1ZSAjNzA2OiBDYWxsYmFjayB0byBjaGVjayBkZWZlcnJlZCBzZXR1cCBzdGF0dXMuICovXG4gIHByaXZhdGUgZGVmZXJyZWRTZXR1cENoZWNrZXI6ICgoKSA9PiBib29sZWFuKSB8IG51bGwgPSBudWxsO1xuXG4gIGNvbnN0cnVjdG9yKGZpbGVPcGVyYXRpb25zOiBJRmlsZU9wZXJhdGlvbnNTZXJ2aWNlKSB7XG4gICAgdGhpcy5zdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xuICAgIHRoaXMuZmlsZU9wZXJhdGlvbnMgPSBmaWxlT3BlcmF0aW9ucztcbiAgfVxuXG4gIC8qKlxuICAgKiBJc3N1ZSAjNzA2OiBXaXJlIGluIHN0YXJ0dXAgaW5zdHJ1bWVudGF0aW9uIGFmdGVyIERJIGlzIHJlYWR5LlxuICAgKiBDYWxsZWQgZnJvbSBDb250YWluZXIgdG8gYXZvaWQgY2lyY3VsYXIgZGVwZW5kZW5jeSBhdCByZWdpc3RyYXRpb24gdGltZS5cbiAgICovXG4gIHNldFN0YXJ0dXBUaW1lcih0aW1lcjogU3RhcnR1cFRpbWVyKTogdm9pZCB7XG4gICAgdGhpcy5zdGFydHVwVGltZXIgPSB0aW1lcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBJc3N1ZSAjNzA2OiBXaXJlIGluIGRlZmVycmVkIHNldHVwIHN0YXR1cyBjaGVja2VyLlxuICAgKi9cbiAgc2V0RGVmZXJyZWRTZXR1cENoZWNrZXIoY2hlY2tlcjogKCkgPT4gYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuZGVmZXJyZWRTZXR1cENoZWNrZXIgPSBjaGVja2VyO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBjb21wcmVoZW5zaXZlIGJ1aWxkIGluZm9ybWF0aW9uXG4gICAqIFNFQ1VSSVRZIE5PVEU6IFRoaXMgbWV0aG9kIHByb2Nlc3NlcyBvbmx5IHN5c3RlbS1nZW5lcmF0ZWQgZGF0YVxuICAgKiBObyB1c2VyIGlucHV0IGlzIGludm9sdmVkIC0gYWxsIGRhdGEgY29tZXMgZnJvbSBmaWxlc3lzdGVtLCBnaXQsIGFuZCBOb2RlLmpzIHByb2Nlc3NcbiAgICpcbiAgICogVXNlcyBQcm9taXNlLmFsbFNldHRsZWQgdG8gY29sbGVjdCBwYXJ0aWFsIHJlc3VsdHMgZXZlbiBpZiBzb21lIHNvdXJjZXMgZmFpbCxcbiAgICogcHJvdmlkaW5nIG1heGltdW0gaW5mb3JtYXRpb24gYXZhaWxhYmlsaXR5IHdpdGggZ3JhY2VmdWwgZGVncmFkYXRpb24uXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgZ2V0QnVpbGRJbmZvKCk6IFByb21pc2U8QnVpbGRJbmZvPiB7XG4gICAgLy8gVXNlIFByb21pc2UuYWxsU2V0dGxlZCB0byBjb2xsZWN0IGFsbCBhdmFpbGFibGUgaW5mbywgZXZlbiBpZiBzb21lIHNvdXJjZXMgZmFpbFxuICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW1xuICAgICAgdGhpcy5nZXRHaXRJbmZvKCksXG4gICAgICB0aGlzLmdldERvY2tlckluZm8oKSxcbiAgICAgIGdldFBlcm1pc3Npb25Ib29rQXVkaXRTdW1tYXJ5KCksXG4gICAgXSk7XG5cbiAgICAvLyBQYWNrYWdlIGluZm8gY29tZXMgZnJvbSBidWlsZC10aW1lIGdlbmVyYXRlZCBjb25zdGFudHNcbiAgICBjb25zdCBwYWNrYWdlSW5mbyA9IHsgbmFtZTogUEFDS0FHRV9OQU1FLCB2ZXJzaW9uOiBQQUNLQUdFX1ZFUlNJT04gfTtcblxuICAgIGNvbnN0IGdpdEluZm8gPSByZXN1bHRzWzBdLnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCdcbiAgICAgID8gcmVzdWx0c1swXS52YWx1ZVxuICAgICAgOiB7IGNvbW1pdDogdW5kZWZpbmVkLCBicmFuY2g6IHVuZGVmaW5lZCB9O1xuXG4gICAgY29uc3QgZG9ja2VySW5mbyA9IHJlc3VsdHNbMV0uc3RhdHVzID09PSAnZnVsZmlsbGVkJ1xuICAgICAgPyByZXN1bHRzWzFdLnZhbHVlXG4gICAgICA6IHsgaXNEb2NrZXI6IGZhbHNlLCBpbmZvOiB1bmRlZmluZWQgfTtcbiAgICBjb25zdCBwZXJtaXNzaW9uSG9va0luZm8gPSByZXN1bHRzWzJdLnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCdcbiAgICAgID8gcmVzdWx0c1syXS52YWx1ZVxuICAgICAgOiB7XG4gICAgICAgIGluc3RhbGxlZEhvc3RzOiBbXSxcbiAgICAgICAgY3VycmVudEhvc3RzOiBbXSxcbiAgICAgICAgcmVwYWlyZWRIb3N0czogW10sXG4gICAgICAgIG5lZWRzUmVwYWlySG9zdHM6IFtdLFxuICAgICAgICBkaWFnbm9zdGljc1BhdGg6ICcnLFxuICAgICAgICBsYXN0RGlhZ25vc3RpYzogbnVsbCxcbiAgICAgICAgbGFzdFN0YXJ0dXBSZXBhaXI6IG51bGwsXG4gICAgICB9O1xuICAgIGNvbnN0IHBlcm1pc3Npb25Ib29rSGVhbHRoID0gc3VtbWFyaXplUGVybWlzc2lvbkhvb2tIZWFsdGgocGVybWlzc2lvbkhvb2tJbmZvKTtcblxuICAgIGNvbnN0IGZvcm1hdFNldHRsZWRSZWFzb24gPSAocmVhc29uOiB1bmtub3duKTogc3RyaW5nID0+IChcbiAgICAgIHJlYXNvbiBpbnN0YW5jZW9mIEVycm9yID8gYCR7cmVhc29uLm5hbWV9OiAke3JlYXNvbi5tZXNzYWdlfWAgOiBTdHJpbmcocmVhc29uKVxuICAgICk7XG5cbiAgICAvLyBMb2cgYW55IGZhaWx1cmVzIGZvciBkaWFnbm9zdGljc1xuICAgIGNvbnN0IGZhaWx1cmVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGlmIChyZXN1bHRzWzBdLnN0YXR1cyA9PT0gJ3JlamVjdGVkJykge1xuICAgICAgZmFpbHVyZXMucHVzaChgZ2l0IGluZm86ICR7Zm9ybWF0U2V0dGxlZFJlYXNvbihyZXN1bHRzWzBdLnJlYXNvbil9YCk7XG4gICAgfVxuICAgIGlmIChyZXN1bHRzWzFdLnN0YXR1cyA9PT0gJ3JlamVjdGVkJykge1xuICAgICAgZmFpbHVyZXMucHVzaChgZG9ja2VyIGluZm86ICR7Zm9ybWF0U2V0dGxlZFJlYXNvbihyZXN1bHRzWzFdLnJlYXNvbil9YCk7XG4gICAgfVxuICAgIGlmIChyZXN1bHRzWzJdLnN0YXR1cyA9PT0gJ3JlamVjdGVkJykge1xuICAgICAgZmFpbHVyZXMucHVzaChgcGVybWlzc2lvbiBob29rIGF1ZGl0OiAke2Zvcm1hdFNldHRsZWRSZWFzb24ocmVzdWx0c1syXS5yZWFzb24pfWApO1xuICAgIH1cblxuICAgIGlmIChmYWlsdXJlcy5sZW5ndGggPiAwKSB7XG4gICAgICBsb2dnZXIuZGVidWcoYEJ1aWxkIGluZm8gY29sbGVjdGlvbiBoYWQgJHtmYWlsdXJlcy5sZW5ndGh9IGZhaWx1cmUocyk6ICR7ZmFpbHVyZXMuam9pbignOyAnKX1gKTtcbiAgICB9XG5cbiAgICAvLyBCdWlsZCB0aW1lc3RhbXAgY29tZXMgZnJvbSBidWlsZC10aW1lIGdlbmVyYXRlZCBjb25zdGFudHNcbiAgICBjb25zdCBidWlsZFRpbWVzdGFtcCA9IEJVSUxEX1RJTUVTVEFNUDtcblxuICAgIC8vIElzc3VlICM3MDY6IFN0YXJ0dXAgdGltaW5nIGFuZCByZWFkaW5lc3NcbiAgICBjb25zdCBkZWZlcnJlZENvbXBsZXRlID0gdGhpcy5kZWZlcnJlZFNldHVwQ2hlY2tlciA/IHRoaXMuZGVmZXJyZWRTZXR1cENoZWNrZXIoKSA6IHRydWU7XG4gICAgY29uc3Qgc3RhcnR1cEluZm86IEJ1aWxkSW5mb1snc3RhcnR1cCddID0ge1xuICAgICAgc3RhdHVzOiBkZWZlcnJlZENvbXBsZXRlID8gJ3JlYWR5JyA6ICdpbml0aWFsaXppbmcnLFxuICAgICAgZGVmZXJyZWRTZXR1cENvbXBsZXRlOiBkZWZlcnJlZENvbXBsZXRlLFxuICAgICAgdXB0aW1lTXM6IERhdGUubm93KCkgLSB0aGlzLnN0YXJ0VGltZS5nZXRUaW1lKCksXG4gICAgICBzdGFydHVwVGltaW5nTXM6IHRoaXMuc3RhcnR1cFRpbWVyPy5nZXRSZXBvcnQoKSxcbiAgICB9O1xuICAgIGNvbnN0IHNlc3Npb25JZGVudGl0eSA9IHJlc29sdmVTZXNzaW9uSWRlbnRpdHkoKTtcblxuICAgIHJldHVybiB7XG4gICAgICBzZXNzaW9uSWQ6IHNlc3Npb25JZGVudGl0eS5zZXNzaW9uSWQsXG4gICAgICBydW50aW1lU2Vzc2lvbklkOiBzZXNzaW9uSWRlbnRpdHkucnVudGltZVNlc3Npb25JZCxcbiAgICAgIHNlc3Npb25Tb3VyY2U6IHNlc3Npb25JZGVudGl0eS5zb3VyY2UsXG4gICAgICBwYWNrYWdlOiBwYWNrYWdlSW5mbyxcbiAgICAgIGJ1aWxkOiB7XG4gICAgICAgIHRpbWVzdGFtcDogYnVpbGRUaW1lc3RhbXAsXG4gICAgICAgIHR5cGU6IEJVSUxEX1RZUEUsXG4gICAgICAgIGdpdENvbW1pdDogZ2l0SW5mby5jb21taXQsXG4gICAgICAgIGdpdEJyYW5jaDogZ2l0SW5mby5icmFuY2gsXG4gICAgICB9LFxuICAgICAgcnVudGltZToge1xuICAgICAgICBub2RlVmVyc2lvbjogcHJvY2Vzcy52ZXJzaW9uLFxuICAgICAgICBwbGF0Zm9ybTogcHJvY2Vzcy5wbGF0Zm9ybSxcbiAgICAgICAgYXJjaDogcHJvY2Vzcy5hcmNoLFxuICAgICAgICB1cHRpbWU6IHByb2Nlc3MudXB0aW1lKCksXG4gICAgICAgIG1lbW9yeVVzYWdlOiBwcm9jZXNzLm1lbW9yeVVzYWdlKClcbiAgICAgIH0sXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBub2RlRW52OiBwcm9jZXNzLmVudi5OT0RFX0VOVixcbiAgICAgICAgaXNQcm9kdWN0aW9uOiBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ3Byb2R1Y3Rpb24nLFxuICAgICAgICBpc0RldmVsb3BtZW50OiBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ2RldmVsb3BtZW50JyxcbiAgICAgICAgaXNEZWJ1ZzogcHJvY2Vzcy5lbnYuREVCVUcgPT09ICd0cnVlJyB8fCBwcm9jZXNzLmVudi5ERUJVRyA9PT0gJzEnLFxuICAgICAgICBpc0RvY2tlcjogZG9ja2VySW5mby5pc0RvY2tlcixcbiAgICAgICAgZG9ja2VySW5mbzogZG9ja2VySW5mby5pbmZvXG4gICAgICB9LFxuICAgICAgc2VydmVyOiB7XG4gICAgICAgIHN0YXJ0VGltZTogdGhpcy5zdGFydFRpbWUsXG4gICAgICAgIHVwdGltZTogRGF0ZS5ub3coKSAtIHRoaXMuc3RhcnRUaW1lLmdldFRpbWUoKSxcbiAgICAgICAgbWNwQ29ubmVjdGlvbjogdHJ1ZSAvLyBXZSdyZSBjb25uZWN0ZWQgaWYgdGhpcyBtZXRob2QgaXMgYmVpbmcgY2FsbGVkIHZpYSBNQ1BcbiAgICAgIH0sXG4gICAgICBwZXJtaXNzaW9uSG9va3M6IHtcbiAgICAgICAgLi4ucGVybWlzc2lvbkhvb2tJbmZvLFxuICAgICAgICBoZWFsdGg6IHBlcm1pc3Npb25Ib29rSGVhbHRoLFxuICAgICAgfSxcbiAgICAgIHN0YXJ0dXA6IHN0YXJ0dXBJbmZvLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogRm9ybWF0IGJ1aWxkIGluZm8gYXMgdXNlci1mcmllbmRseSBtYXJrZG93blxuICAgKiBTRUNVUklUWSBOT1RFOiBPbmx5IGZvcm1hdHMgc3lzdGVtLWdlbmVyYXRlZCBkYXRhIC0gbm8gdXNlciBpbnB1dCBwcm9jZXNzaW5nXG4gICAqIEFsbCBpbnB1dCBkYXRhIGNvbWVzIGZyb20gZ2V0QnVpbGRJbmZvKCkgd2hpY2ggb25seSByZWFkcyBzeXN0ZW0gaW5mb3JtYXRpb25cbiAgICovXG4gIHB1YmxpYyBmb3JtYXRCdWlsZEluZm8oaW5mbzogQnVpbGRJbmZvKTogc3RyaW5nIHtcbiAgICBjb25zdCBsaW5lczogc3RyaW5nW10gPSBbXTtcbiAgICBcbiAgICBsaW5lcy5wdXNoKCcjIPCflKcgQnVpbGQgSW5mb3JtYXRpb25cXG4nKTtcbiAgICBcbiAgICAvLyBQYWNrYWdlIGluZm9cbiAgICBsaW5lcy5wdXNoKCcjIyDwn5OmIFBhY2thZ2UnKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqTmFtZSoqOiAke2luZm8ucGFja2FnZS5uYW1lfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipWZXJzaW9uKio6ICR7aW5mby5wYWNrYWdlLnZlcnNpb259YCk7XG4gICAgbGluZXMucHVzaCgnJyk7XG5cbiAgICBjb25zdCBpZGVudGl0eVNvdXJjZUxhYmVsID0gaW5mby5zZXNzaW9uU291cmNlID09PSAnZW52J1xuICAgICAgPyAnRXhwbGljaXQgZW52aXJvbm1lbnQnXG4gICAgICA6ICdEZXJpdmVkIGZyb20gd29ya3NwYWNlIGNvbnRleHQnO1xuICAgIGNvbnN0IHNlc3Npb25MaW5lcyA9IFtcbiAgICAgICcjIyDwn6qqIFNlc3Npb24nLFxuICAgICAgYC0gKipTZXNzaW9uIElEKio6ICR7aW5mby5zZXNzaW9uSWR9YCxcbiAgICAgIGAtICoqSWRlbnRpdHkgU291cmNlKio6ICR7aWRlbnRpdHlTb3VyY2VMYWJlbH1gLFxuICAgIF07XG4gICAgaWYgKGluZm8ucnVudGltZVNlc3Npb25JZCAhPT0gaW5mby5zZXNzaW9uSWQpIHtcbiAgICAgIHNlc3Npb25MaW5lcy5zcGxpY2UoMiwgMCwgYC0gKipSdW50aW1lIFNlc3Npb24gSUQqKjogJHtpbmZvLnJ1bnRpbWVTZXNzaW9uSWR9YCk7XG4gICAgfVxuICAgIGxpbmVzLnB1c2goLi4uc2Vzc2lvbkxpbmVzLCAnJyk7XG4gICAgXG4gICAgLy8gQnVpbGQgaW5mb1xuICAgIGxpbmVzLnB1c2goJyMjIPCfj5fvuI8gQnVpbGQnKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqVHlwZSoqOiAke2luZm8uYnVpbGQudHlwZX1gKTtcbiAgICBpZiAoaW5mby5idWlsZC50aW1lc3RhbXApIHtcbiAgICAgIGxpbmVzLnB1c2goYC0gKipUaW1lc3RhbXAqKjogJHtpbmZvLmJ1aWxkLnRpbWVzdGFtcH1gKTtcbiAgICB9XG4gICAgaWYgKGluZm8uYnVpbGQuZ2l0Q29tbWl0KSB7XG4gICAgICBsaW5lcy5wdXNoKGAtICoqR2l0IENvbW1pdCoqOiBcXGAke2luZm8uYnVpbGQuZ2l0Q29tbWl0fVxcYGApO1xuICAgIH1cbiAgICBpZiAoaW5mby5idWlsZC5naXRCcmFuY2gpIHtcbiAgICAgIGxpbmVzLnB1c2goYC0gKipHaXQgQnJhbmNoKio6ICR7aW5mby5idWlsZC5naXRCcmFuY2h9YCk7XG4gICAgfVxuICAgIGxpbmVzLnB1c2goJycpO1xuICAgIFxuICAgIC8vIFJ1bnRpbWUgaW5mb1xuICAgIGxpbmVzLnB1c2goJyMjIPCfkrsgUnVudGltZScpO1xuICAgIGxpbmVzLnB1c2goYC0gKipOb2RlLmpzKio6ICR7aW5mby5ydW50aW1lLm5vZGVWZXJzaW9ufWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipQbGF0Zm9ybSoqOiAke2luZm8ucnVudGltZS5wbGF0Zm9ybX1gKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqQXJjaGl0ZWN0dXJlKio6ICR7aW5mby5ydW50aW1lLmFyY2h9YCk7XG4gICAgbGluZXMucHVzaChgLSAqKlByb2Nlc3MgVXB0aW1lKio6ICR7dGhpcy5mb3JtYXRVcHRpbWUoaW5mby5ydW50aW1lLnVwdGltZSl9YCk7XG4gICAgbGluZXMucHVzaChgLSAqKk1lbW9yeSBVc2FnZSoqOiAke3RoaXMuZm9ybWF0TWVtb3J5KGluZm8ucnVudGltZS5tZW1vcnlVc2FnZS5oZWFwVXNlZCl9IC8gJHt0aGlzLmZvcm1hdE1lbW9yeShpbmZvLnJ1bnRpbWUubWVtb3J5VXNhZ2UuaGVhcFRvdGFsKX1gKTtcbiAgICBsaW5lcy5wdXNoKCcnKTtcbiAgICBcbiAgICAvLyBFbnZpcm9ubWVudCBpbmZvXG4gICAgbGluZXMucHVzaCgnIyMg4pqZ77iPIEVudmlyb25tZW50Jyk7XG4gICAgbGluZXMucHVzaChgLSAqKk5PREVfRU5WKio6ICR7aW5mby5lbnZpcm9ubWVudC5ub2RlRW52IHx8ICdub3Qgc2V0J31gKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqTW9kZSoqOiAke2luZm8uZW52aXJvbm1lbnQuaXNQcm9kdWN0aW9uID8gJ1Byb2R1Y3Rpb24nIDogaW5mby5lbnZpcm9ubWVudC5pc0RldmVsb3BtZW50ID8gJ0RldmVsb3BtZW50JyA6ICdVbmtub3duJ31gKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqRGVidWcqKjogJHtpbmZvLmVudmlyb25tZW50LmlzRGVidWcgPyAnRW5hYmxlZCcgOiAnRGlzYWJsZWQnfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipEb2NrZXIqKjogJHtpbmZvLmVudmlyb25tZW50LmlzRG9ja2VyID8gJ1llcycgOiAnTm8nfWApO1xuICAgIGlmIChpbmZvLmVudmlyb25tZW50LmRvY2tlckluZm8pIHtcbiAgICAgIGxpbmVzLnB1c2goYC0gKipDb250YWluZXIqKjogJHtpbmZvLmVudmlyb25tZW50LmRvY2tlckluZm99YCk7XG4gICAgfVxuICAgIGxpbmVzLnB1c2goJycpO1xuICAgIFxuICAgIC8vIFNlcnZlciBpbmZvXG4gICAgbGluZXMucHVzaCgnIyMg8J+agCBTZXJ2ZXInKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqU3RhcnRlZCoqOiAke2luZm8uc2VydmVyLnN0YXJ0VGltZS50b0lTT1N0cmluZygpfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipVcHRpbWUqKjogJHt0aGlzLmZvcm1hdFVwdGltZShpbmZvLnNlcnZlci51cHRpbWUgLyAxMDAwKX1gKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqTUNQIENvbm5lY3Rpb24qKjogJHtpbmZvLnNlcnZlci5tY3BDb25uZWN0aW9uID8gJ+KchSBDb25uZWN0ZWQnIDogJ+KdjCBEaXNjb25uZWN0ZWQnfWApO1xuXG4gICAgaWYgKGluZm8ucGVybWlzc2lvbkhvb2tzKSB7XG4gICAgICBjb25zdCBpbnN0YWxsZWRIb3N0cyA9IGluZm8ucGVybWlzc2lvbkhvb2tzLmluc3RhbGxlZEhvc3RzLmxlbmd0aCA+IDBcbiAgICAgICAgPyBpbmZvLnBlcm1pc3Npb25Ib29rcy5pbnN0YWxsZWRIb3N0cy5qb2luKCcsICcpXG4gICAgICAgIDogJ05vbmUnO1xuICAgICAgY29uc3QgY3VycmVudEhvc3RzID0gaW5mby5wZXJtaXNzaW9uSG9va3MuY3VycmVudEhvc3RzLmxlbmd0aCA+IDBcbiAgICAgICAgPyBpbmZvLnBlcm1pc3Npb25Ib29rcy5jdXJyZW50SG9zdHMuam9pbignLCAnKVxuICAgICAgICA6ICdOb25lJztcbiAgICAgIGNvbnN0IG5lZWRzUmVwYWlySG9zdHMgPSBpbmZvLnBlcm1pc3Npb25Ib29rcy5uZWVkc1JlcGFpckhvc3RzLmxlbmd0aCA+IDBcbiAgICAgICAgPyBpbmZvLnBlcm1pc3Npb25Ib29rcy5uZWVkc1JlcGFpckhvc3RzLmpvaW4oJywgJylcbiAgICAgICAgOiAnTm9uZSc7XG4gICAgICBjb25zdCBsYXN0U3RhcnR1cFJlcGFpciA9IGluZm8ucGVybWlzc2lvbkhvb2tzLmxhc3RTdGFydHVwUmVwYWlyO1xuICAgICAgY29uc3Qgc3RhcnR1cFJlcGFpcklzc3VlcyA9IGxhc3RTdGFydHVwUmVwYWlyXG4gICAgICAgID8gbGFzdFN0YXJ0dXBSZXBhaXIuaG9zdFJlc3VsdHNcbiAgICAgICAgICAuZmlsdGVyKChyZXN1bHQpID0+IHJlc3VsdC5vdXRjb21lID09PSAnbmVlZHNfcmVwYWlyJyB8fCByZXN1bHQub3V0Y29tZSA9PT0gJ2Vycm9yJylcbiAgICAgICAgICAubWFwKChyZXN1bHQpID0+IHJlc3VsdC5yZXBhaXJFcnJvciA/IGAke3Jlc3VsdC5ob3N0fSAoJHtyZXN1bHQucmVwYWlyRXJyb3J9KWAgOiByZXN1bHQuaG9zdClcbiAgICAgICAgICAuam9pbignOyAnKVxuICAgICAgICA6ICcnO1xuXG4gICAgICBsaW5lcy5wdXNoKFxuICAgICAgICAnJyxcbiAgICAgICAgJyMjIPCflJAgUGVybWlzc2lvbiBIb29rcycsXG4gICAgICAgIGAtICoqSGVhbHRoKio6ICR7aW5mby5wZXJtaXNzaW9uSG9va3MuaGVhbHRoLnN0YXR1cy50b1VwcGVyQ2FzZSgpfSDigJQgJHtpbmZvLnBlcm1pc3Npb25Ib29rcy5oZWFsdGgubWVzc2FnZX1gLFxuICAgICAgICBgLSAqKkluc3RhbGxlZCBIb3N0cyoqOiAke2luc3RhbGxlZEhvc3RzfWAsXG4gICAgICAgIGAtICoqQ3VycmVudCBBc3NldHMqKjogJHtjdXJyZW50SG9zdHN9YCxcbiAgICAgICAgYC0gKipOZWVkcyBSZXBhaXIqKjogJHtuZWVkc1JlcGFpckhvc3RzfWAsXG4gICAgICApO1xuXG4gICAgICBpZiAoaW5mby5wZXJtaXNzaW9uSG9va3MuZGlhZ25vc3RpY3NQYXRoKSB7XG4gICAgICAgIGxpbmVzLnB1c2goYC0gKipEaWFnbm9zdGljcyBMb2cqKjogJHtpbmZvLnBlcm1pc3Npb25Ib29rcy5kaWFnbm9zdGljc1BhdGh9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChsYXN0U3RhcnR1cFJlcGFpcikge1xuICAgICAgICBsaW5lcy5wdXNoKFxuICAgICAgICAgIGAtICoqTGFzdCBTdGFydHVwIEF1ZGl0Kio6ICR7bGFzdFN0YXJ0dXBSZXBhaXIuY29tcGxldGVkQXR9ICgke2xhc3RTdGFydHVwUmVwYWlyLmR1cmF0aW9uTXN9bXMpYCxcbiAgICAgICAgICBgLSAqKlN0YXJ0dXAgUmVwYWlycyBBcHBsaWVkKio6ICR7bGFzdFN0YXJ0dXBSZXBhaXIucmVwYWlyZWRDb3VudH1gLFxuICAgICAgICAgIGAtICoqU3RhcnR1cCBSZXBhaXIgSXNzdWVzKio6ICR7c3RhcnR1cFJlcGFpcklzc3VlcyB8fCAnTm9uZSd9YCxcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGluZm8ucGVybWlzc2lvbkhvb2tzLmxhc3REaWFnbm9zdGljKSB7XG4gICAgICAgIGNvbnN0IGxhc3REaWFnbm9zdGljID0gaW5mby5wZXJtaXNzaW9uSG9va3MubGFzdERpYWdub3N0aWM7XG4gICAgICAgIGNvbnN0IGRpYWdub3N0aWNPdXRjb21lID0gbGFzdERpYWdub3N0aWMub3V0Y29tZVxuICAgICAgICAgID8gYCR7bGFzdERpYWdub3N0aWMuZXZlbnR9IC8gJHtsYXN0RGlhZ25vc3RpYy5vdXRjb21lfWBcbiAgICAgICAgICA6IGxhc3REaWFnbm9zdGljLmV2ZW50O1xuICAgICAgICBsaW5lcy5wdXNoKFxuICAgICAgICAgIGAtICoqTGFzdCBEaWFnbm9zdGljIEV2ZW50Kio6ICR7bGFzdERpYWdub3N0aWMudGltZXN0YW1wfSAoJHtkaWFnbm9zdGljT3V0Y29tZX0pYCxcbiAgICAgICAgICBgLSAqKkxhc3QgRGlhZ25vc3RpYyBTdGFnZSoqOiAke2xhc3REaWFnbm9zdGljLnN0YWdlfWAsXG4gICAgICAgICAgYC0gKipMYXN0IERpYWdub3N0aWMgSW5wdXQgQnl0ZXMqKjogJHtsYXN0RGlhZ25vc3RpYy5yYXdJbnB1dExlbmd0aCA/PyAwfWAsXG4gICAgICAgICAgYC0gKipMYXN0IERpYWdub3N0aWMgTm9ybWFsaXplZCBCeXRlcyoqOiAke2xhc3REaWFnbm9zdGljLm5vcm1hbGl6ZWRSZXNwb25zZUxlbmd0aCA/PyAwfWAsXG4gICAgICAgICAgYC0gKipMYXN0IERpYWdub3N0aWMgRW1pdHRlZCBCeXRlcyoqOiAke2xhc3REaWFnbm9zdGljLmVtaXR0ZWRSZXNwb25