@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
JavaScript
/**
* 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQnVpbGRJbmZvU2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aWNlcy9CdWlsZEluZm9TZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7R0FTRztBQUVILE9BQU8sS0FBSyxhQUFhLE1BQU0sZUFBZSxDQUFDO0FBQy9DLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUU1QyxPQUFPLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFckcsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDOUQsT0FBTyxFQUNMLDZCQUE2QixFQUU3Qiw2QkFBNkIsR0FHOUIsTUFBTSw2QkFBNkIsQ0FBQztBQXVEckMsTUFBTSxPQUFPLGdCQUFnQjtJQUNWLFNBQVMsQ0FBTztJQUNoQixjQUFjLENBQXlCO0lBQ3hELHFFQUFxRTtJQUM3RCxZQUFZLEdBQXdCLElBQUksQ0FBQztJQUNqRCwyREFBMkQ7SUFDbkQsb0JBQW9CLEdBQTJCLElBQUksQ0FBQztJQUU1RCxZQUFZLGNBQXNDO1FBQ2hELElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUM1QixJQUFJLENBQUMsY0FBYyxHQUFHLGNBQWMsQ0FBQztJQUN2QyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsZUFBZSxDQUFDLEtBQW1CO1FBQ2pDLElBQUksQ0FBQyxZQUFZLEdBQUcsS0FBSyxDQUFDO0lBQzVCLENBQUM7SUFFRDs7T0FFRztJQUNILHVCQUF1QixDQUFDLE9BQXNCO1FBQzVDLElBQUksQ0FBQyxvQkFBb0IsR0FBRyxPQUFPLENBQUM7SUFDdEMsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSSxLQUFLLENBQUMsWUFBWTtRQUN2QixrRkFBa0Y7UUFDbEYsTUFBTSxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsVUFBVSxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDakIsSUFBSSxDQUFDLGFBQWEsRUFBRTtZQUNwQiw2QkFBNkIsRUFBRTtTQUNoQyxDQUFDLENBQUM7UUFFSCx5REFBeUQ7UUFDekQsTUFBTSxXQUFXLEdBQUcsRUFBRSxJQUFJLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBRSxlQUFlLEVBQUUsQ0FBQztRQUVyRSxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxLQUFLLFdBQVc7WUFDL0MsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLO1lBQ2xCLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxDQUFDO1FBRTdDLE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEtBQUssV0FBVztZQUNsRCxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUs7WUFDbEIsQ0FBQyxDQUFDLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUM7UUFDekMsTUFBTSxrQkFBa0IsR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxLQUFLLFdBQVc7WUFDMUQsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLO1lBQ2xCLENBQUMsQ0FBQztnQkFDQSxjQUFjLEVBQUUsRUFBRTtnQkFDbEIsWUFBWSxFQUFFLEVBQUU7Z0JBQ2hCLGFBQWEsRUFBRSxFQUFFO2dCQUNqQixnQkFBZ0IsRUFBRSxFQUFFO2dCQUNwQixlQUFlLEVBQUUsRUFBRTtnQkFDbkIsY0FBYyxFQUFFLElBQUk7Z0JBQ3BCLGlCQUFpQixFQUFFLElBQUk7YUFDeEIsQ0FBQztRQUNKLE1BQU0sb0JBQW9CLEdBQUcsNkJBQTZCLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUUvRSxNQUFNLG1CQUFtQixHQUFHLENBQUMsTUFBZSxFQUFVLEVBQUUsQ0FBQyxDQUN2RCxNQUFNLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxJQUFJLEtBQUssTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQy9FLENBQUM7UUFFRixtQ0FBbUM7UUFDbkMsTUFBTSxRQUFRLEdBQWEsRUFBRSxDQUFDO1FBQzlCLElBQUksT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUNyQyxRQUFRLENBQUMsSUFBSSxDQUFDLGFBQWEsbUJBQW1CLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN2RSxDQUFDO1FBQ0QsSUFBSSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxLQUFLLFVBQVUsRUFBRSxDQUFDO1lBQ3JDLFFBQVEsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLG1CQUFtQixDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDMUUsQ0FBQztRQUNELElBQUksT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUNyQyxRQUFRLENBQUMsSUFBSSxDQUFDLDBCQUEwQixtQkFBbUIsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3BGLENBQUM7UUFFRCxJQUFJLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDeEIsTUFBTSxDQUFDLEtBQUssQ0FBQyw2QkFBNkIsUUFBUSxDQUFDLE1BQU0sZ0JBQWdCLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ2xHLENBQUM7UUFFRCw0REFBNEQ7UUFDNUQsTUFBTSxjQUFjLEdBQUcsZUFBZSxDQUFDO1FBRXZDLDJDQUEyQztRQUMzQyxNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUN4RixNQUFNLFdBQVcsR0FBeUI7WUFDeEMsTUFBTSxFQUFFLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLGNBQWM7WUFDbkQscUJBQXFCLEVBQUUsZ0JBQWdCO1lBQ3ZDLFFBQVEsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUU7WUFDL0MsZUFBZSxFQUFFLElBQUksQ0FBQyxZQUFZLEVBQUUsU0FBUyxFQUFFO1NBQ2hELENBQUM7UUFDRixNQUFNLGVBQWUsR0FBRyxzQkFBc0IsRUFBRSxDQUFDO1FBRWpELE9BQU87WUFDTCxTQUFTLEVBQUUsZUFBZSxDQUFDLFNBQVM7WUFDcEMsZ0JBQWdCLEVBQUUsZUFBZSxDQUFDLGdCQUFnQjtZQUNsRCxhQUFhLEVBQUUsZUFBZSxDQUFDLE1BQU07WUFDckMsT0FBTyxFQUFFLFdBQVc7WUFDcEIsS0FBSyxFQUFFO2dCQUNMLFNBQVMsRUFBRSxjQUFjO2dCQUN6QixJQUFJLEVBQUUsVUFBVTtnQkFDaEIsU0FBUyxFQUFFLE9BQU8sQ0FBQyxNQUFNO2dCQUN6QixTQUFTLEVBQUUsT0FBTyxDQUFDLE1BQU07YUFDMUI7WUFDRCxPQUFPLEVBQUU7Z0JBQ1AsV0FBVyxFQUFFLE9BQU8sQ0FBQyxPQUFPO2dCQUM1QixRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVE7Z0JBQzFCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtnQkFDbEIsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLEVBQUU7Z0JBQ3hCLFdBQVcsRUFBRSxPQUFPLENBQUMsV0FBVyxFQUFFO2FBQ25DO1lBQ0QsV0FBVyxFQUFFO2dCQUNYLE9BQU8sRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVE7Z0JBQzdCLFlBQVksRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsS0FBSyxZQUFZO2dCQUNuRCxhQUFhLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEtBQUssYUFBYTtnQkFDckQsT0FBTyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxLQUFLLE1BQU0sSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssS0FBSyxHQUFHO2dCQUNsRSxRQUFRLEVBQUUsVUFBVSxDQUFDLFFBQVE7Z0JBQzdCLFVBQVUsRUFBRSxVQUFVLENBQUMsSUFBSTthQUM1QjtZQUNELE1BQU0sRUFBRTtnQkFDTixTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7Z0JBQ3pCLE1BQU0sRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUU7Z0JBQzdDLGFBQWEsRUFBRSxJQUFJLENBQUMseURBQXlEO2FBQzlFO1lBQ0QsZUFBZSxFQUFFO2dCQUNmLEdBQUcsa0JBQWtCO2dCQUNyQixNQUFNLEVBQUUsb0JBQW9CO2FBQzdCO1lBQ0QsT0FBTyxFQUFFLFdBQVc7U0FDckIsQ0FBQztJQUNKLENBQUM7SUFFRDs7OztPQUlHO0lBQ0ksZUFBZSxDQUFDLElBQWU7UUFDcEMsTUFBTSxLQUFLLEdBQWEsRUFBRSxDQUFDO1FBRTNCLEtBQUssQ0FBQyxJQUFJLENBQUMsMEJBQTBCLENBQUMsQ0FBQztRQUV2QyxlQUFlO1FBQ2YsS0FBSyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUM1QixLQUFLLENBQUMsSUFBSSxDQUFDLGVBQWUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQy9DLEtBQUssQ0FBQyxJQUFJLENBQUMsa0JBQWtCLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUNyRCxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRWYsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLENBQUMsYUFBYSxLQUFLLEtBQUs7WUFDdEQsQ0FBQyxDQUFDLHNCQUFzQjtZQUN4QixDQUFDLENBQUMsZ0NBQWdDLENBQUM7UUFDckMsTUFBTSxZQUFZLEdBQUc7WUFDbkIsZUFBZTtZQUNmLHFCQUFxQixJQUFJLENBQUMsU0FBUyxFQUFFO1lBQ3JDLDBCQUEwQixtQkFBbUIsRUFBRTtTQUNoRCxDQUFDO1FBQ0YsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLEtBQUssSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQzdDLFlBQVksQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSw2QkFBNkIsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUMsQ0FBQztRQUNsRixDQUFDO1FBQ0QsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLFlBQVksRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVoQyxhQUFhO1FBQ2IsS0FBSyxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUMzQixLQUFLLENBQUMsSUFBSSxDQUFDLGVBQWUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQzdDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUN6QixLQUFLLENBQUMsSUFBSSxDQUFDLG9CQUFvQixJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUM7UUFDekQsQ0FBQztRQUNELElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUN6QixLQUFLLENBQUMsSUFBSSxDQUFDLHVCQUF1QixJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsSUFBSSxDQUFDLENBQUM7UUFDOUQsQ0FBQztRQUNELElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUN6QixLQUFLLENBQUMsSUFBSSxDQUFDLHFCQUFxQixJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUM7UUFDMUQsQ0FBQztRQUNELEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFZixlQUFlO1FBQ2YsS0FBSyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUM1QixLQUFLLENBQUMsSUFBSSxDQUFDLGtCQUFrQixJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7UUFDekQsS0FBSyxDQUFDLElBQUksQ0FBQyxtQkFBbUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZELEtBQUssQ0FBQyxJQUFJLENBQUMsdUJBQXVCLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUN2RCxLQUFLLENBQUMsSUFBSSxDQUFDLHlCQUF5QixJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzlFLEtBQUssQ0FBQyxJQUFJLENBQUMsdUJBQXVCLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDckosS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUVmLG1CQUFtQjtRQUNuQixLQUFLLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDaEMsS0FBSyxDQUFDLElBQUksQ0FBQyxtQkFBbUIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLElBQUksU0FBUyxFQUFFLENBQUMsQ0FBQztRQUN2RSxLQUFLLENBQUMsSUFBSSxDQUFDLGVBQWUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztRQUN2SSxLQUFLLENBQUMsSUFBSSxDQUFDLGdCQUFnQixJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO1FBQ2hGLEtBQUssQ0FBQyxJQUFJLENBQUMsaUJBQWlCLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFDeEUsSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ2hDLEtBQUssQ0FBQyxJQUFJLENBQUMsb0JBQW9CLElBQUksQ0FBQyxXQUFXLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUNoRSxDQUFDO1FBQ0QsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUVmLGNBQWM7UUFDZCxLQUFLLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQzNCLEtBQUssQ0FBQyxJQUFJLENBQUMsa0JBQWtCLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNwRSxLQUFLLENBQUMsSUFBSSxDQUFDLGlCQUFpQixJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUM1RSxLQUFLLENBQUMsSUFBSSxDQUFDLHlCQUF5QixJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLENBQUM7UUFFcEcsSUFBSSxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDekIsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxjQUFjLENBQUMsTUFBTSxHQUFHLENBQUM7Z0JBQ25FLENBQUMsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO2dCQUNoRCxDQUFDLENBQUMsTUFBTSxDQUFDO1lBQ1gsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxZQUFZLENBQUMsTUFBTSxHQUFHLENBQUM7Z0JBQy9ELENBQUMsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO2dCQUM5QyxDQUFDLENBQUMsTUFBTSxDQUFDO1lBQ1gsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sR0FBRyxDQUFDO2dCQUN2RSxDQUFDLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO2dCQUNsRCxDQUFDLENBQUMsTUFBTSxDQUFDO1lBQ1gsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLGlCQUFpQixDQUFDO1lBQ2pFLE1BQU0sbUJBQW1CLEdBQUcsaUJBQWlCO2dCQUMzQyxDQUFDLENBQUMsaUJBQWlCLENBQUMsV0FBVztxQkFDNUIsTUFBTSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsT0FBTyxLQUFLLGNBQWMsSUFBSSxNQUFNLENBQUMsT0FBTyxLQUFLLE9BQU8sQ0FBQztxQkFDbkYsR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxJQUFJLEtBQUssTUFBTSxDQUFDLFdBQVcsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDO3FCQUM1RixJQUFJLENBQUMsSUFBSSxDQUFDO2dCQUNiLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFFUCxLQUFLLENBQUMsSUFBSSxDQUNSLEVBQUUsRUFDRix3QkFBd0IsRUFDeEIsaUJBQWlCLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsTUFBTSxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsRUFDNUcsMEJBQTBCLGNBQWMsRUFBRSxFQUMxQyx5QkFBeUIsWUFBWSxFQUFFLEVBQ3ZDLHVCQUF1QixnQkFBZ0IsRUFBRSxDQUMxQyxDQUFDO1lBRUYsSUFBSSxJQUFJLENBQUMsZUFBZSxDQUFDLGVBQWUsRUFBRSxDQUFDO2dCQUN6QyxLQUFLLENBQUMsSUFBSSxDQUFDLDBCQUEwQixJQUFJLENBQUMsZUFBZSxDQUFDLGVBQWUsRUFBRSxDQUFDLENBQUM7WUFDL0UsQ0FBQztZQUVELElBQUksaUJBQWlCLEVBQUUsQ0FBQztnQkFDdEIsS0FBSyxDQUFDLElBQUksQ0FDUiw2QkFBNkIsaUJBQWlCLENBQUMsV0FBVyxLQUFLLGlCQUFpQixDQUFDLFVBQVUsS0FBSyxFQUNoRyxrQ0FBa0MsaUJBQWlCLENBQUMsYUFBYSxFQUFFLEVBQ25FLGdDQUFnQyxtQkFBbUIsSUFBSSxNQUFNLEVBQUUsQ0FDaEUsQ0FBQztZQUNKLENBQUM7WUFFRCxJQUFJLElBQUksQ0FBQyxlQUFlLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3hDLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsY0FBYyxDQUFDO2dCQUMzRCxNQUFNLGlCQUFpQixHQUFHLGNBQWMsQ0FBQyxPQUFPO29CQUM5QyxDQUFDLENBQUMsR0FBRyxjQUFjLENBQUMsS0FBSyxNQUFNLGNBQWMsQ0FBQyxPQUFPLEVBQUU7b0JBQ3ZELENBQUMsQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDO2dCQUN6QixLQUFLLENBQUMsSUFBSSxDQUNSLGdDQUFnQyxjQUFjLENBQUMsU0FBUyxLQUFLLGlCQUFpQixHQUFHLEVBQ2pGLGdDQUFnQyxjQUFjLENBQUMsS0FBSyxFQUFFLEVBQ3RELHNDQUFzQyxjQUFjLENBQUMsY0FBYyxJQUFJLENBQUMsRUFBRSxFQUMxRSwyQ0FBMkMsY0FBYyxDQUFDLHdCQUF3QixJQUFJLENBQUMsRUFBRSxFQUN6Rix3Q0FBd0MsY0FBYyxDQUFDLHFCQUFxQixJQUFJLENBQUMsRUFBRSxDQUNwRixDQUFDO2dCQUNGLElBQUksY0FBYyxDQUFDLE1BQU0sRUFBRSxDQUFDO29CQUMxQixLQUFLLENBQUMsSUFBSSxDQUFDLGlDQUFpQyxjQUFjLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztnQkFDdkUsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBRUQsNkJBQTZCO1FBQzdCLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2pCLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDZixLQUFLLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1lBQzVCLEtBQUssQ0FBQyxJQUFJLENBQUMsaUJBQWlCLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxLQUFLLE9BQU8sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLENBQUM7WUFDOUYsS0FBSyxDQUFDLElBQUksQ0FBQyx5QkFBeUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZHLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxlQUFlLEVBQUUsQ0FBQztnQkFDakMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUM7Z0JBQzVDLEtBQUssQ0FBQyxJQUFJLENBQUMsd0JBQXdCLE1BQU0sQ0FBQyxjQUFjLElBQUksQ0FBQyxDQUFDO2dCQUM5RCxLQUFLLENBQUMsSUFBSSxDQUFDLHdCQUF3QixNQUFNLENBQUMsVUFBVSxJQUFJLENBQUMsQ0FBQztnQkFDMUQsS0FBSyxDQUFDLElBQUksQ0FBQyx3QkFBd0IsTUFBTSxDQUFDLE9BQU8sSUFBSSxDQUFDLENBQUM7Z0JBQ3ZELElBQUksTUFBTSxDQUFDLFdBQVcsS0FBSyxJQUFJLEVBQUUsQ0FBQztvQkFDaEMsS0FBSyxDQUFDLElBQUksQ0FBQywwQkFBMEIsTUFBTSxDQUFDLFdBQVcsSUFBSSxDQUFDLENBQUM7Z0JBQy9ELENBQUM7Z0JBQ0QsSUFBSSxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztvQkFDN0IsS0FBSyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztvQkFDNUIsS0FBSyxNQUFNLEtBQUssSUFBSSxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUM7d0JBQ2xDLE1BQU0sR0FBRyxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDO3dCQUNyRCxLQUFLLENBQUMsSUFBSSxDQUFDLE9BQU8sS0FBSyxDQUFDLElBQUksS0FBSyxLQUFLLENBQUMsVUFBVSxPQUFPLEdBQUcsR0FBRyxDQUFDLENBQUM7b0JBQ2xFLENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzFCLENBQUM7SUFFRDs7O09BR0c7SUFDSyxLQUFLLENBQUMsVUFBVTtRQUN0QixJQUFJLENBQUM7WUFDSCw2RUFBNkU7WUFDN0UsNEZBQTRGO1lBQzVGLE1BQU0sTUFBTSxHQUFHLGFBQWEsQ0FBQyxRQUFRLENBQUMsNEJBQTRCLEVBQUUsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNsRyxNQUFNLE1BQU0sR0FBRyxhQUFhLENBQUMsUUFBUSxDQUFDLGlDQUFpQyxFQUFFLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7WUFFdkcsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQztRQUM1QixDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsK0NBQStDO1lBQy9DLE9BQU8sRUFBRSxDQUFDO1FBQ1osQ0FBQztJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSyxLQUFLLENBQUMsYUFBYTtRQUN6QixJQUFJLENBQUM7WUFDSCw4RkFBOEY7WUFDOUYsaUZBQWlGO1lBQ2pGLE1BQU0sYUFBYSxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLEVBQUU7Z0JBQ3pFLE1BQU0sRUFBRSxnQ0FBZ0M7YUFDekMsQ0FBQyxDQUFDO1lBQ0gsTUFBTSxRQUFRLEdBQUcsYUFBYSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsSUFBSSxhQUFhLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBRTFGLElBQUksUUFBUSxFQUFFLENBQUM7Z0JBQ2IsMEJBQTBCO2dCQUMxQixNQUFNLFdBQVcsR0FBRyxhQUFhO3FCQUM5QixLQUFLLENBQUMsSUFBSSxDQUFDO3FCQUNYLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUM7b0JBQ3RDLEVBQUUsS0FBSyxDQUFDLEdBQUcsQ0FBQztxQkFDWCxHQUFHLEVBQUU7b0JBQ04sRUFBRSxTQUFTLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO2dCQUVyQixPQUFPO29CQUNMLFFBQVEsRUFBRSxJQUFJO29CQUNkLElBQUksRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLGlCQUFpQixXQUFXLEVBQUUsQ0FBQyxDQUFDLENBQUMsbUJBQW1CO2lCQUN6RSxDQUFDO1lBQ0osQ0FBQztZQUVELE9BQU8sRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUM7UUFDN0IsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLHVDQUF1QztZQUN2QyxPQUFPLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxDQUFDO1FBQzdCLENBQUM7SUFDSCxDQUFDO0lBRU8sWUFBWSxDQUFDLE9BQWU7UUFDbEMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLEdBQUcsS0FBSyxDQUFDLENBQUM7UUFDekMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLE9BQU8sR0FBRyxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztRQUNuRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ2xELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBRXRDLE1BQU0sS0FBSyxHQUFhLEVBQUUsQ0FBQztRQUMzQixJQUFJLElBQUksR0FBRyxDQUFDO1lBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLENBQUM7UUFDckMsSUFBSSxLQUFLLEdBQUcsQ0FBQztZQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLEdBQUcsQ0FBQyxDQUFDO1FBQ3ZDLElBQUksT0FBTyxHQUFHLENBQUM7WUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxHQUFHLENBQUMsQ0FBQztRQUMzQyxJQUFJLElBQUksR0FBRyxDQUFDLElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLENBQUM7UUFFM0QsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3pCLENBQUM7SUFFTyxZQUFZLENBQUMsS0FBYTtRQUNoQyxNQUFNLEVBQUUsR0FBRyxLQUFLLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztRQUMvQixPQUFPLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQy9CLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQnVpbGRJbmZvU2VydmljZSAtIFByb3ZpZGVzIGJ1aWxkIGFuZCBydW50aW1lIGluZm9ybWF0aW9uXG4gKiBTZXBhcmF0ZWQgZnJvbSBtYWluIGluZGV4LnRzIHRvIGF2b2lkIG1ha2luZyB0aGF0IGZpbGUgbGFyZ2VyXG4gKiBcbiAqIFNFQ1VSSVRZIEZJWCAoUFIgIzYxNCk6XG4gKiAxLiBETUNQLVNFQy0wMDQ6IEZBTFNFIFBPU0lUSVZFIFNVUFBSRVNTSU9OIC0gTm8gdXNlciBpbnB1dCBVbmljb2RlIG5vcm1hbGl6YXRpb24gbmVlZGVkXG4gKiAgICBUaGlzIHNlcnZpY2Ugb25seSBwcm9jZXNzZXMgc3lzdGVtIGluZm9ybWF0aW9uIChnaXQsIHBhY2thZ2UuanNvbiwgZW52aXJvbm1lbnQgdmFyaWFibGVzKVxuICogICAgVGhlIE1DUCB0b29sICdnZXRfYnVpbGRfaW5mbycgdGFrZXMgTk8gcGFyYW1ldGVycyAoZW1wdHkgaW5wdXRTY2hlbWEpXG4gKiAgICBObyB1c2VyLXByb3ZpZGVkIGRhdGEgZmxvd3MgdGhyb3VnaCB0aGlzIHNlcnZpY2UgdGhhdCByZXF1aXJlcyBVbmljb2RlIG5vcm1hbGl6YXRpb25cbiAqL1xuXG5pbXBvcnQgKiBhcyBjaGlsZF9wcm9jZXNzIGZyb20gJ2NoaWxkX3Byb2Nlc3MnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IElGaWxlT3BlcmF0aW9uc1NlcnZpY2UgfSBmcm9tICcuL0ZpbGVPcGVyYXRpb25zU2VydmljZS5qcyc7XG5pbXBvcnQgeyBQQUNLQUdFX05BTUUsIFBBQ0tBR0VfVkVSU0lPTiwgQlVJTERfVElNRVNUQU1QLCBCVUlMRF9UWVBFIH0gZnJvbSAnLi4vZ2VuZXJhdGVkL3ZlcnNpb24uanMnO1xuaW1wb3J0IHR5cGUgeyBTdGFydHVwVGltZXIsIFN0YXJ0dXBSZXBvcnQgfSBmcm9tICcuLi90ZWxlbWV0cnkvU3RhcnR1cFRpbWVyLmpzJztcbmltcG9ydCB7IHJlc29sdmVTZXNzaW9uSWRlbnRpdHkgfSBmcm9tICcuL3Nlc3Npb25JZGVudGl0eS5qcyc7XG5pbXBvcnQge1xuICBnZXRQZXJtaXNzaW9uSG9va0F1ZGl0U3VtbWFyeSxcbiAgdHlwZSBQZXJtaXNzaW9uSG9va0RpYWdub3N0aWNSZWNvcmQsXG4gIHN1bW1hcml6ZVBlcm1pc3Npb25Ib29rSGVhbHRoLFxuICB0eXBlIFBlcm1pc3Npb25Ib29rSGVhbHRoU3VtbWFyeSxcbiAgdHlwZSBQZXJtaXNzaW9uSG9va1N0YXJ0dXBSZXBhaXJTdW1tYXJ5LFxufSBmcm9tICcuLi91dGlscy9wZXJtaXNzaW9uSG9va3MuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEJ1aWxkSW5mbyB7XG4gIHNlc3Npb25JZDogc3RyaW5nO1xuICBydW50aW1lU2Vzc2lvbklkOiBzdHJpbmc7XG4gIHNlc3Npb25Tb3VyY2U6ICdlbnYnIHwgJ2Rlcml2ZWQnO1xuICBwYWNrYWdlOiB7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIHZlcnNpb246IHN0cmluZztcbiAgfTtcbiAgYnVpbGQ6IHtcbiAgICB0aW1lc3RhbXA/OiBzdHJpbmc7XG4gICAgdHlwZTogJ2dpdCcgfCAnbnBtJyB8ICd1bmtub3duJztcbiAgICBnaXRDb21taXQ/OiBzdHJpbmc7XG4gICAgZ2l0QnJhbmNoPzogc3RyaW5nO1xuICB9O1xuICBydW50aW1lOiB7XG4gICAgbm9kZVZlcnNpb246IHN0cmluZztcbiAgICBwbGF0Zm9ybTogc3RyaW5nO1xuICAgIGFyY2g6IHN0cmluZztcbiAgICB1cHRpbWU6IG51bWJlcjtcbiAgICBtZW1vcnlVc2FnZTogTm9kZUpTLk1lbW9yeVVzYWdlO1xuICB9O1xuICBlbnZpcm9ubWVudDoge1xuICAgIG5vZGVFbnY/OiBzdHJpbmc7XG4gICAgaXNQcm9kdWN0aW9uOiBib29sZWFuO1xuICAgIGlzRGV2ZWxvcG1lbnQ6IGJvb2xlYW47XG4gICAgaXNEZWJ1ZzogYm9vbGVhbjtcbiAgICBpc0RvY2tlcjogYm9vbGVhbjtcbiAgICBkb2NrZXJJbmZvPzogc3RyaW5nO1xuICB9O1xuICBzZXJ2ZXI6IHtcbiAgICBzdGFydFRpbWU6IERhdGU7XG4gICAgdXB0aW1lOiBudW1iZXI7XG4gICAgbWNwQ29ubmVjdGlvbjogYm9vbGVhbjtcbiAgfTtcbiAgcGVybWlzc2lvbkhvb2tzPzoge1xuICAgIGhlYWx0aDogUGVybWlzc2lvbkhvb2tIZWFsdGhTdW1tYXJ5O1xuICAgIGluc3RhbGxlZEhvc3RzOiBzdHJpbmdbXTtcbiAgICBjdXJyZW50SG9zdHM6IHN0cmluZ1tdO1xuICAgIHJlcGFpcmVkSG9zdHM6IHN0cmluZ1tdO1xuICAgIG5lZWRzUmVwYWlySG9zdHM6IHN0cmluZ1tdO1xuICAgIGRpYWdub3N0aWNzUGF0aDogc3RyaW5nO1xuICAgIGxhc3REaWFnbm9zdGljOiBQZXJtaXNzaW9uSG9va0RpYWdub3N0aWNSZWNvcmQgfCBudWxsO1xuICAgIGxhc3RTdGFydHVwUmVwYWlyOiBQZXJtaXNzaW9uSG9va1N0YXJ0dXBSZXBhaXJTdW1tYXJ5IHwgbnVsbDtcbiAgfTtcbiAgLyoqIElzc3VlICM3MDY6IFN0YXJ0dXAgdGltaW5nIGFuZCByZWFkaW5lc3Mgc3RhdHVzLiAqL1xuICBzdGFydHVwPzoge1xuICAgIHN0YXR1czogJ3JlYWR5JyB8ICdpbml0aWFsaXppbmcnO1xuICAgIGRlZmVycmVkU2V0dXBDb21wbGV0ZTogYm9vbGVhbjtcbiAgICB1cHRpbWVNczogbnVtYmVyO1xuICAgIHN0YXJ0dXBUaW1pbmdNcz86IFN0YXJ0dXBSZXBvcnQ7XG4gIH07XG59XG5cbmV4cG9ydCBjbGFzcyBCdWlsZEluZm9TZXJ2aWNlIHtcbiAgcHJpdmF0ZSByZWFkb25seSBzdGFydFRpbWU6IERhdGU7XG4gIHByaXZhdGUgcmVhZG9ubHkgZmlsZU9wZXJhdGlvbnM6IElGaWxlT3BlcmF0aW9uc1NlcnZpY2U7XG4gIC8qKiBJc3N1ZSAjNzA2OiBPcHRpb25hbCBzdGFydHVwIHRpbWVyIGZvciB0aW1pbmcgaW5zdHJ1bWVudGF0aW9uLiAqL1xuICBwcml2YXRlIHN0YXJ0dXBUaW1lcjogU3RhcnR1cFRpbWVyIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBJc3N1ZSAjNzA2OiBDYWxsYmFjayB0byBjaGVjayBkZWZlcnJlZCBzZXR1cCBzdGF0dXMuICovXG4gIHByaXZhdGUgZGVmZXJyZWRTZXR1cENoZWNrZXI6ICgoKSA9PiBib29sZWFuKSB8IG51bGwgPSBudWxsO1xuXG4gIGNvbnN0cnVjdG9yKGZpbGVPcGVyYXRpb25zOiBJRmlsZU9wZXJhdGlvbnNTZXJ2aWNlKSB7XG4gICAgdGhpcy5zdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xuICAgIHRoaXMuZmlsZU9wZXJhdGlvbnMgPSBmaWxlT3BlcmF0aW9ucztcbiAgfVxuXG4gIC8qKlxuICAgKiBJc3N1ZSAjNzA2OiBXaXJlIGluIHN0YXJ0dXAgaW5zdHJ1bWVudGF0aW9uIGFmdGVyIERJIGlzIHJlYWR5LlxuICAgKiBDYWxsZWQgZnJvbSBDb250YWluZXIgdG8gYXZvaWQgY2lyY3VsYXIgZGVwZW5kZW5jeSBhdCByZWdpc3RyYXRpb24gdGltZS5cbiAgICovXG4gIHNldFN0YXJ0dXBUaW1lcih0aW1lcjogU3RhcnR1cFRpbWVyKTogdm9pZCB7XG4gICAgdGhpcy5zdGFydHVwVGltZXIgPSB0aW1lcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBJc3N1ZSAjNzA2OiBXaXJlIGluIGRlZmVycmVkIHNldHVwIHN0YXR1cyBjaGVja2VyLlxuICAgKi9cbiAgc2V0RGVmZXJyZWRTZXR1cENoZWNrZXIoY2hlY2tlcjogKCkgPT4gYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuZGVmZXJyZWRTZXR1cENoZWNrZXIgPSBjaGVja2VyO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBjb21wcmVoZW5zaXZlIGJ1aWxkIGluZm9ybWF0aW9uXG4gICAqIFNFQ1VSSVRZIE5PVEU6IFRoaXMgbWV0aG9kIHByb2Nlc3NlcyBvbmx5IHN5c3RlbS1nZW5lcmF0ZWQgZGF0YVxuICAgKiBObyB1c2VyIGlucHV0IGlzIGludm9sdmVkIC0gYWxsIGRhdGEgY29tZXMgZnJvbSBmaWxlc3lzdGVtLCBnaXQsIGFuZCBOb2RlLmpzIHByb2Nlc3NcbiAgICpcbiAgICogVXNlcyBQcm9taXNlLmFsbFNldHRsZWQgdG8gY29sbGVjdCBwYXJ0aWFsIHJlc3VsdHMgZXZlbiBpZiBzb21lIHNvdXJjZXMgZmFpbCxcbiAgICogcHJvdmlkaW5nIG1heGltdW0gaW5mb3JtYXRpb24gYXZhaWxhYmlsaXR5IHdpdGggZ3JhY2VmdWwgZGVncmFkYXRpb24uXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgZ2V0QnVpbGRJbmZvKCk6IFByb21pc2U8QnVpbGRJbmZvPiB7XG4gICAgLy8gVXNlIFByb21pc2UuYWxsU2V0dGxlZCB0byBjb2xsZWN0IGFsbCBhdmFpbGFibGUgaW5mbywgZXZlbiBpZiBzb21lIHNvdXJjZXMgZmFpbFxuICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW1xuICAgICAgdGhpcy5nZXRHaXRJbmZvKCksXG4gICAgICB0aGlzLmdldERvY2tlckluZm8oKSxcbiAgICAgIGdldFBlcm1pc3Npb25Ib29rQXVkaXRTdW1tYXJ5KCksXG4gICAgXSk7XG5cbiAgICAvLyBQYWNrYWdlIGluZm8gY29tZXMgZnJvbSBidWlsZC10aW1lIGdlbmVyYXRlZCBjb25zdGFudHNcbiAgICBjb25zdCBwYWNrYWdlSW5mbyA9IHsgbmFtZTogUEFDS0FHRV9OQU1FLCB2ZXJzaW9uOiBQQUNLQUdFX1ZFUlNJT04gfTtcblxuICAgIGNvbnN0IGdpdEluZm8gPSByZXN1bHRzWzBdLnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCdcbiAgICAgID8gcmVzdWx0c1swXS52YWx1ZVxuICAgICAgOiB7IGNvbW1pdDogdW5kZWZpbmVkLCBicmFuY2g6IHVuZGVmaW5lZCB9O1xuXG4gICAgY29uc3QgZG9ja2VySW5mbyA9IHJlc3VsdHNbMV0uc3RhdHVzID09PSAnZnVsZmlsbGVkJ1xuICAgICAgPyByZXN1bHRzWzFdLnZhbHVlXG4gICAgICA6IHsgaXNEb2NrZXI6IGZhbHNlLCBpbmZvOiB1bmRlZmluZWQgfTtcbiAgICBjb25zdCBwZXJtaXNzaW9uSG9va0luZm8gPSByZXN1bHRzWzJdLnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCdcbiAgICAgID8gcmVzdWx0c1syXS52YWx1ZVxuICAgICAgOiB7XG4gICAgICAgIGluc3RhbGxlZEhvc3RzOiBbXSxcbiAgICAgICAgY3VycmVudEhvc3RzOiBbXSxcbiAgICAgICAgcmVwYWlyZWRIb3N0czogW10sXG4gICAgICAgIG5lZWRzUmVwYWlySG9zdHM6IFtdLFxuICAgICAgICBkaWFnbm9zdGljc1BhdGg6ICcnLFxuICAgICAgICBsYXN0RGlhZ25vc3RpYzogbnVsbCxcbiAgICAgICAgbGFzdFN0YXJ0dXBSZXBhaXI6IG51bGwsXG4gICAgICB9O1xuICAgIGNvbnN0IHBlcm1pc3Npb25Ib29rSGVhbHRoID0gc3VtbWFyaXplUGVybWlzc2lvbkhvb2tIZWFsdGgocGVybWlzc2lvbkhvb2tJbmZvKTtcblxuICAgIGNvbnN0IGZvcm1hdFNldHRsZWRSZWFzb24gPSAocmVhc29uOiB1bmtub3duKTogc3RyaW5nID0+IChcbiAgICAgIHJlYXNvbiBpbnN0YW5jZW9mIEVycm9yID8gYCR7cmVhc29uLm5hbWV9OiAke3JlYXNvbi5tZXNzYWdlfWAgOiBTdHJpbmcocmVhc29uKVxuICAgICk7XG5cbiAgICAvLyBMb2cgYW55IGZhaWx1cmVzIGZvciBkaWFnbm9zdGljc1xuICAgIGNvbnN0IGZhaWx1cmVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGlmIChyZXN1bHRzWzBdLnN0YXR1cyA9PT0gJ3JlamVjdGVkJykge1xuICAgICAgZmFpbHVyZXMucHVzaChgZ2l0IGluZm86ICR7Zm9ybWF0U2V0dGxlZFJlYXNvbihyZXN1bHRzWzBdLnJlYXNvbil9YCk7XG4gICAgfVxuICAgIGlmIChyZXN1bHRzWzFdLnN0YXR1cyA9PT0gJ3JlamVjdGVkJykge1xuICAgICAgZmFpbHVyZXMucHVzaChgZG9ja2VyIGluZm86ICR7Zm9ybWF0U2V0dGxlZFJlYXNvbihyZXN1bHRzWzFdLnJlYXNvbil9YCk7XG4gICAgfVxuICAgIGlmIChyZXN1bHRzWzJdLnN0YXR1cyA9PT0gJ3JlamVjdGVkJykge1xuICAgICAgZmFpbHVyZXMucHVzaChgcGVybWlzc2lvbiBob29rIGF1ZGl0OiAke2Zvcm1hdFNldHRsZWRSZWFzb24ocmVzdWx0c1syXS5yZWFzb24pfWApO1xuICAgIH1cblxuICAgIGlmIChmYWlsdXJlcy5sZW5ndGggPiAwKSB7XG4gICAgICBsb2dnZXIuZGVidWcoYEJ1aWxkIGluZm8gY29sbGVjdGlvbiBoYWQgJHtmYWlsdXJlcy5sZW5ndGh9IGZhaWx1cmUocyk6ICR7ZmFpbHVyZXMuam9pbignOyAnKX1gKTtcbiAgICB9XG5cbiAgICAvLyBCdWlsZCB0aW1lc3RhbXAgY29tZXMgZnJvbSBidWlsZC10aW1lIGdlbmVyYXRlZCBjb25zdGFudHNcbiAgICBjb25zdCBidWlsZFRpbWVzdGFtcCA9IEJVSUxEX1RJTUVTVEFNUDtcblxuICAgIC8vIElzc3VlICM3MDY6IFN0YXJ0dXAgdGltaW5nIGFuZCByZWFkaW5lc3NcbiAgICBjb25zdCBkZWZlcnJlZENvbXBsZXRlID0gdGhpcy5kZWZlcnJlZFNldHVwQ2hlY2tlciA/IHRoaXMuZGVmZXJyZWRTZXR1cENoZWNrZXIoKSA6IHRydWU7XG4gICAgY29uc3Qgc3RhcnR1cEluZm86IEJ1aWxkSW5mb1snc3RhcnR1cCddID0ge1xuICAgICAgc3RhdHVzOiBkZWZlcnJlZENvbXBsZXRlID8gJ3JlYWR5JyA6ICdpbml0aWFsaXppbmcnLFxuICAgICAgZGVmZXJyZWRTZXR1cENvbXBsZXRlOiBkZWZlcnJlZENvbXBsZXRlLFxuICAgICAgdXB0aW1lTXM6IERhdGUubm93KCkgLSB0aGlzLnN0YXJ0VGltZS5nZXRUaW1lKCksXG4gICAgICBzdGFydHVwVGltaW5nTXM6IHRoaXMuc3RhcnR1cFRpbWVyPy5nZXRSZXBvcnQoKSxcbiAgICB9O1xuICAgIGNvbnN0IHNlc3Npb25JZGVudGl0eSA9IHJlc29sdmVTZXNzaW9uSWRlbnRpdHkoKTtcblxuICAgIHJldHVybiB7XG4gICAgICBzZXNzaW9uSWQ6IHNlc3Npb25JZGVudGl0eS5zZXNzaW9uSWQsXG4gICAgICBydW50aW1lU2Vzc2lvbklkOiBzZXNzaW9uSWRlbnRpdHkucnVudGltZVNlc3Npb25JZCxcbiAgICAgIHNlc3Npb25Tb3VyY2U6IHNlc3Npb25JZGVudGl0eS5zb3VyY2UsXG4gICAgICBwYWNrYWdlOiBwYWNrYWdlSW5mbyxcbiAgICAgIGJ1aWxkOiB7XG4gICAgICAgIHRpbWVzdGFtcDogYnVpbGRUaW1lc3RhbXAsXG4gICAgICAgIHR5cGU6IEJVSUxEX1RZUEUsXG4gICAgICAgIGdpdENvbW1pdDogZ2l0SW5mby5jb21taXQsXG4gICAgICAgIGdpdEJyYW5jaDogZ2l0SW5mby5icmFuY2gsXG4gICAgICB9LFxuICAgICAgcnVudGltZToge1xuICAgICAgICBub2RlVmVyc2lvbjogcHJvY2Vzcy52ZXJzaW9uLFxuICAgICAgICBwbGF0Zm9ybTogcHJvY2Vzcy5wbGF0Zm9ybSxcbiAgICAgICAgYXJjaDogcHJvY2Vzcy5hcmNoLFxuICAgICAgICB1cHRpbWU6IHByb2Nlc3MudXB0aW1lKCksXG4gICAgICAgIG1lbW9yeVVzYWdlOiBwcm9jZXNzLm1lbW9yeVVzYWdlKClcbiAgICAgIH0sXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBub2RlRW52OiBwcm9jZXNzLmVudi5OT0RFX0VOVixcbiAgICAgICAgaXNQcm9kdWN0aW9uOiBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ3Byb2R1Y3Rpb24nLFxuICAgICAgICBpc0RldmVsb3BtZW50OiBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ2RldmVsb3BtZW50JyxcbiAgICAgICAgaXNEZWJ1ZzogcHJvY2Vzcy5lbnYuREVCVUcgPT09ICd0cnVlJyB8fCBwcm9jZXNzLmVudi5ERUJVRyA9PT0gJzEnLFxuICAgICAgICBpc0RvY2tlcjogZG9ja2VySW5mby5pc0RvY2tlcixcbiAgICAgICAgZG9ja2VySW5mbzogZG9ja2VySW5mby5pbmZvXG4gICAgICB9LFxuICAgICAgc2VydmVyOiB7XG4gICAgICAgIHN0YXJ0VGltZTogdGhpcy5zdGFydFRpbWUsXG4gICAgICAgIHVwdGltZTogRGF0ZS5ub3coKSAtIHRoaXMuc3RhcnRUaW1lLmdldFRpbWUoKSxcbiAgICAgICAgbWNwQ29ubmVjdGlvbjogdHJ1ZSAvLyBXZSdyZSBjb25uZWN0ZWQgaWYgdGhpcyBtZXRob2QgaXMgYmVpbmcgY2FsbGVkIHZpYSBNQ1BcbiAgICAgIH0sXG4gICAgICBwZXJtaXNzaW9uSG9va3M6IHtcbiAgICAgICAgLi4ucGVybWlzc2lvbkhvb2tJbmZvLFxuICAgICAgICBoZWFsdGg6IHBlcm1pc3Npb25Ib29rSGVhbHRoLFxuICAgICAgfSxcbiAgICAgIHN0YXJ0dXA6IHN0YXJ0dXBJbmZvLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogRm9ybWF0IGJ1aWxkIGluZm8gYXMgdXNlci1mcmllbmRseSBtYXJrZG93blxuICAgKiBTRUNVUklUWSBOT1RFOiBPbmx5IGZvcm1hdHMgc3lzdGVtLWdlbmVyYXRlZCBkYXRhIC0gbm8gdXNlciBpbnB1dCBwcm9jZXNzaW5nXG4gICAqIEFsbCBpbnB1dCBkYXRhIGNvbWVzIGZyb20gZ2V0QnVpbGRJbmZvKCkgd2hpY2ggb25seSByZWFkcyBzeXN0ZW0gaW5mb3JtYXRpb25cbiAgICovXG4gIHB1YmxpYyBmb3JtYXRCdWlsZEluZm8oaW5mbzogQnVpbGRJbmZvKTogc3RyaW5nIHtcbiAgICBjb25zdCBsaW5lczogc3RyaW5nW10gPSBbXTtcbiAgICBcbiAgICBsaW5lcy5wdXNoKCcjIPCflKcgQnVpbGQgSW5mb3JtYXRpb25cXG4nKTtcbiAgICBcbiAgICAvLyBQYWNrYWdlIGluZm9cbiAgICBsaW5lcy5wdXNoKCcjIyDwn5OmIFBhY2thZ2UnKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqTmFtZSoqOiAke2luZm8ucGFja2FnZS5uYW1lfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipWZXJzaW9uKio6ICR7aW5mby5wYWNrYWdlLnZlcnNpb259YCk7XG4gICAgbGluZXMucHVzaCgnJyk7XG5cbiAgICBjb25zdCBpZGVudGl0eVNvdXJjZUxhYmVsID0gaW5mby5zZXNzaW9uU291cmNlID09PSAnZW52J1xuICAgICAgPyAnRXhwbGljaXQgZW52aXJvbm1lbnQnXG4gICAgICA6ICdEZXJpdmVkIGZyb20gd29ya3NwYWNlIGNvbnRleHQnO1xuICAgIGNvbnN0IHNlc3Npb25MaW5lcyA9IFtcbiAgICAgICcjIyDwn6qqIFNlc3Npb24nLFxuICAgICAgYC0gKipTZXNzaW9uIElEKio6ICR7aW5mby5zZXNzaW9uSWR9YCxcbiAgICAgIGAtICoqSWRlbnRpdHkgU291cmNlKio6ICR7aWRlbnRpdHlTb3VyY2VMYWJlbH1gLFxuICAgIF07XG4gICAgaWYgKGluZm8ucnVudGltZVNlc3Npb25JZCAhPT0gaW5mby5zZXNzaW9uSWQpIHtcbiAgICAgIHNlc3Npb25MaW5lcy5zcGxpY2UoMiwgMCwgYC0gKipSdW50aW1lIFNlc3Npb24gSUQqKjogJHtpbmZvLnJ1bnRpbWVTZXNzaW9uSWR9YCk7XG4gICAgfVxuICAgIGxpbmVzLnB1c2goLi4uc2Vzc2lvbkxpbmVzLCAnJyk7XG4gICAgXG4gICAgLy8gQnVpbGQgaW5mb1xuICAgIGxpbmVzLnB1c2goJyMjIPCfj5fvuI8gQnVpbGQnKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqVHlwZSoqOiAke2luZm8uYnVpbGQudHlwZX1gKTtcbiAgICBpZiAoaW5mby5idWlsZC50aW1lc3RhbXApIHtcbiAgICAgIGxpbmVzLnB1c2goYC0gKipUaW1lc3RhbXAqKjogJHtpbmZvLmJ1aWxkLnRpbWVzdGFtcH1gKTtcbiAgICB9XG4gICAgaWYgKGluZm8uYnVpbGQuZ2l0Q29tbWl0KSB7XG4gICAgICBsaW5lcy5wdXNoKGAtICoqR2l0IENvbW1pdCoqOiBcXGAke2luZm8uYnVpbGQuZ2l0Q29tbWl0fVxcYGApO1xuICAgIH1cbiAgICBpZiAoaW5mby5idWlsZC5naXRCcmFuY2gpIHtcbiAgICAgIGxpbmVzLnB1c2goYC0gKipHaXQgQnJhbmNoKio6ICR7aW5mby5idWlsZC5naXRCcmFuY2h9YCk7XG4gICAgfVxuICAgIGxpbmVzLnB1c2goJycpO1xuICAgIFxuICAgIC8vIFJ1bnRpbWUgaW5mb1xuICAgIGxpbmVzLnB1c2goJyMjIPCfkrsgUnVudGltZScpO1xuICAgIGxpbmVzLnB1c2goYC0gKipOb2RlLmpzKio6ICR7aW5mby5ydW50aW1lLm5vZGVWZXJzaW9ufWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipQbGF0Zm9ybSoqOiAke2luZm8ucnVudGltZS5wbGF0Zm9ybX1gKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqQXJjaGl0ZWN0dXJlKio6ICR7aW5mby5ydW50aW1lLmFyY2h9YCk7XG4gICAgbGluZXMucHVzaChgLSAqKlByb2Nlc3MgVXB0aW1lKio6ICR7dGhpcy5mb3JtYXRVcHRpbWUoaW5mby5ydW50aW1lLnVwdGltZSl9YCk7XG4gICAgbGluZXMucHVzaChgLSAqKk1lbW9yeSBVc2FnZSoqOiAke3RoaXMuZm9ybWF0TWVtb3J5KGluZm8ucnVudGltZS5tZW1vcnlVc2FnZS5oZWFwVXNlZCl9IC8gJHt0aGlzLmZvcm1hdE1lbW9yeShpbmZvLnJ1bnRpbWUubWVtb3J5VXNhZ2UuaGVhcFRvdGFsKX1gKTtcbiAgICBsaW5lcy5wdXNoKCcnKTtcbiAgICBcbiAgICAvLyBFbnZpcm9ubWVudCBpbmZvXG4gICAgbGluZXMucHVzaCgnIyMg4pqZ77iPIEVudmlyb25tZW50Jyk7XG4gICAgbGluZXMucHVzaChgLSAqKk5PREVfRU5WKio6ICR7aW5mby5lbnZpcm9ubWVudC5ub2RlRW52IHx8ICdub3Qgc2V0J31gKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqTW9kZSoqOiAke2luZm8uZW52aXJvbm1lbnQuaXNQcm9kdWN0aW9uID8gJ1Byb2R1Y3Rpb24nIDogaW5mby5lbnZpcm9ubWVudC5pc0RldmVsb3BtZW50ID8gJ0RldmVsb3BtZW50JyA6ICdVbmtub3duJ31gKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqRGVidWcqKjogJHtpbmZvLmVudmlyb25tZW50LmlzRGVidWcgPyAnRW5hYmxlZCcgOiAnRGlzYWJsZWQnfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipEb2NrZXIqKjogJHtpbmZvLmVudmlyb25tZW50LmlzRG9ja2VyID8gJ1llcycgOiAnTm8nfWApO1xuICAgIGlmIChpbmZvLmVudmlyb25tZW50LmRvY2tlckluZm8pIHtcbiAgICAgIGxpbmVzLnB1c2goYC0gKipDb250YWluZXIqKjogJHtpbmZvLmVudmlyb25tZW50LmRvY2tlckluZm99YCk7XG4gICAgfVxuICAgIGxpbmVzLnB1c2goJycpO1xuICAgIFxuICAgIC8vIFNlcnZlciBpbmZvXG4gICAgbGluZXMucHVzaCgnIyMg8J+agCBTZXJ2ZXInKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqU3RhcnRlZCoqOiAke2luZm8uc2VydmVyLnN0YXJ0VGltZS50b0lTT1N0cmluZygpfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipVcHRpbWUqKjogJHt0aGlzLmZvcm1hdFVwdGltZShpbmZvLnNlcnZlci51cHRpbWUgLyAxMDAwKX1gKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqTUNQIENvbm5lY3Rpb24qKjogJHtpbmZvLnNlcnZlci5tY3BDb25uZWN0aW9uID8gJ+KchSBDb25uZWN0ZWQnIDogJ+KdjCBEaXNjb25uZWN0ZWQnfWApO1xuXG4gICAgaWYgKGluZm8ucGVybWlzc2lvbkhvb2tzKSB7XG4gICAgICBjb25zdCBpbnN0YWxsZWRIb3N0cyA9IGluZm8ucGVybWlzc2lvbkhvb2tzLmluc3RhbGxlZEhvc3RzLmxlbmd0aCA+IDBcbiAgICAgICAgPyBpbmZvLnBlcm1pc3Npb25Ib29rcy5pbnN0YWxsZWRIb3N0cy5qb2luKCcsICcpXG4gICAgICAgIDogJ05vbmUnO1xuICAgICAgY29uc3QgY3VycmVudEhvc3RzID0gaW5mby5wZXJtaXNzaW9uSG9va3MuY3VycmVudEhvc3RzLmxlbmd0aCA+IDBcbiAgICAgICAgPyBpbmZvLnBlcm1pc3Npb25Ib29rcy5jdXJyZW50SG9zdHMuam9pbignLCAnKVxuICAgICAgICA6ICdOb25lJztcbiAgICAgIGNvbnN0IG5lZWRzUmVwYWlySG9zdHMgPSBpbmZvLnBlcm1pc3Npb25Ib29rcy5uZWVkc1JlcGFpckhvc3RzLmxlbmd0aCA+IDBcbiAgICAgICAgPyBpbmZvLnBlcm1pc3Npb25Ib29rcy5uZWVkc1JlcGFpckhvc3RzLmpvaW4oJywgJylcbiAgICAgICAgOiAnTm9uZSc7XG4gICAgICBjb25zdCBsYXN0U3RhcnR1cFJlcGFpciA9IGluZm8ucGVybWlzc2lvbkhvb2tzLmxhc3RTdGFydHVwUmVwYWlyO1xuICAgICAgY29uc3Qgc3RhcnR1cFJlcGFpcklzc3VlcyA9IGxhc3RTdGFydHVwUmVwYWlyXG4gICAgICAgID8gbGFzdFN0YXJ0dXBSZXBhaXIuaG9zdFJlc3VsdHNcbiAgICAgICAgICAuZmlsdGVyKChyZXN1bHQpID0+IHJlc3VsdC5vdXRjb21lID09PSAnbmVlZHNfcmVwYWlyJyB8fCByZXN1bHQub3V0Y29tZSA9PT0gJ2Vycm9yJylcbiAgICAgICAgICAubWFwKChyZXN1bHQpID0+IHJlc3VsdC5yZXBhaXJFcnJvciA/IGAke3Jlc3VsdC5ob3N0fSAoJHtyZXN1bHQucmVwYWlyRXJyb3J9KWAgOiByZXN1bHQuaG9zdClcbiAgICAgICAgICAuam9pbignOyAnKVxuICAgICAgICA6ICcnO1xuXG4gICAgICBsaW5lcy5wdXNoKFxuICAgICAgICAnJyxcbiAgICAgICAgJyMjIPCflJAgUGVybWlzc2lvbiBIb29rcycsXG4gICAgICAgIGAtICoqSGVhbHRoKio6ICR7aW5mby5wZXJtaXNzaW9uSG9va3MuaGVhbHRoLnN0YXR1cy50b1VwcGVyQ2FzZSgpfSDigJQgJHtpbmZvLnBlcm1pc3Npb25Ib29rcy5oZWFsdGgubWVzc2FnZX1gLFxuICAgICAgICBgLSAqKkluc3RhbGxlZCBIb3N0cyoqOiAke2luc3RhbGxlZEhvc3RzfWAsXG4gICAgICAgIGAtICoqQ3VycmVudCBBc3NldHMqKjogJHtjdXJyZW50SG9zdHN9YCxcbiAgICAgICAgYC0gKipOZWVkcyBSZXBhaXIqKjogJHtuZWVkc1JlcGFpckhvc3RzfWAsXG4gICAgICApO1xuXG4gICAgICBpZiAoaW5mby5wZXJtaXNzaW9uSG9va3MuZGlhZ25vc3RpY3NQYXRoKSB7XG4gICAgICAgIGxpbmVzLnB1c2goYC0gKipEaWFnbm9zdGljcyBMb2cqKjogJHtpbmZvLnBlcm1pc3Npb25Ib29rcy5kaWFnbm9zdGljc1BhdGh9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChsYXN0U3RhcnR1cFJlcGFpcikge1xuICAgICAgICBsaW5lcy5wdXNoKFxuICAgICAgICAgIGAtICoqTGFzdCBTdGFydHVwIEF1ZGl0Kio6ICR7bGFzdFN0YXJ0dXBSZXBhaXIuY29tcGxldGVkQXR9ICgke2xhc3RTdGFydHVwUmVwYWlyLmR1cmF0aW9uTXN9bXMpYCxcbiAgICAgICAgICBgLSAqKlN0YXJ0dXAgUmVwYWlycyBBcHBsaWVkKio6ICR7bGFzdFN0YXJ0dXBSZXBhaXIucmVwYWlyZWRDb3VudH1gLFxuICAgICAgICAgIGAtICoqU3RhcnR1cCBSZXBhaXIgSXNzdWVzKio6ICR7c3RhcnR1cFJlcGFpcklzc3VlcyB8fCAnTm9uZSd9YCxcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGluZm8ucGVybWlzc2lvbkhvb2tzLmxhc3REaWFnbm9zdGljKSB7XG4gICAgICAgIGNvbnN0IGxhc3REaWFnbm9zdGljID0gaW5mby5wZXJtaXNzaW9uSG9va3MubGFzdERpYWdub3N0aWM7XG4gICAgICAgIGNvbnN0IGRpYWdub3N0aWNPdXRjb21lID0gbGFzdERpYWdub3N0aWMub3V0Y29tZVxuICAgICAgICAgID8gYCR7bGFzdERpYWdub3N0aWMuZXZlbnR9IC8gJHtsYXN0RGlhZ25vc3RpYy5vdXRjb21lfWBcbiAgICAgICAgICA6IGxhc3REaWFnbm9zdGljLmV2ZW50O1xuICAgICAgICBsaW5lcy5wdXNoKFxuICAgICAgICAgIGAtICoqTGFzdCBEaWFnbm9zdGljIEV2ZW50Kio6ICR7bGFzdERpYWdub3N0aWMudGltZXN0YW1wfSAoJHtkaWFnbm9zdGljT3V0Y29tZX0pYCxcbiAgICAgICAgICBgLSAqKkxhc3QgRGlhZ25vc3RpYyBTdGFnZSoqOiAke2xhc3REaWFnbm9zdGljLnN0YWdlfWAsXG4gICAgICAgICAgYC0gKipMYXN0IERpYWdub3N0aWMgSW5wdXQgQnl0ZXMqKjogJHtsYXN0RGlhZ25vc3RpYy5yYXdJbnB1dExlbmd0aCA/PyAwfWAsXG4gICAgICAgICAgYC0gKipMYXN0IERpYWdub3N0aWMgTm9ybWFsaXplZCBCeXRlcyoqOiAke2xhc3REaWFnbm9zdGljLm5vcm1hbGl6ZWRSZXNwb25zZUxlbmd0aCA/PyAwfWAsXG4gICAgICAgICAgYC0gKipMYXN0IERpYWdub3N0aWMgRW1pdHRlZCBCeXRlcyoqOiAke2xhc3REaWFnbm9zdGljLmVtaXR0ZWRSZXNwb25