@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.
335 lines • 45.5 kB
JavaScript
/**
* Security Auditor - Core orchestrator for security scanning
* Implements automated security auditing for DollhouseMCP (Issue #53)
*/
// import { SecurityMonitor } from '../securityMonitor.js';
import { logger } from '../../utils/logger.js';
import { CodeScanner } from './scanners/CodeScanner.js';
import { DependencyScanner } from './scanners/DependencyScanner.js';
import { ConfigurationScanner } from './scanners/ConfigurationScanner.js';
import { ConsoleReporter } from './reporters/ConsoleReporter.js';
import { MarkdownReporter } from './reporters/MarkdownReporter.js';
import { JsonReporter } from './reporters/JsonReporter.js';
import { shouldSuppress } from './config/suppressions.js';
import { ErrorHandler } from '../../utils/ErrorHandler.js';
import * as path from 'path';
export class SecurityAuditor {
config;
scanners = [];
suppressions = new Map();
fileOperations;
logListener;
addLogListener(fn) {
this.logListener = fn;
}
constructor(config, fileOperations) {
this.config = config;
this.fileOperations = fileOperations;
this.initializeScanners();
this.loadSuppressions();
}
/**
* Initialize enabled scanners based on configuration
*/
initializeScanners() {
if (this.config.scanners.code.enabled) {
this.scanners.push(new CodeScanner(this.config.scanners.code));
}
if (this.config.scanners.dependencies.enabled) {
this.scanners.push(new DependencyScanner(this.config.scanners.dependencies));
}
if (this.config.scanners.configuration.enabled) {
this.scanners.push(new ConfigurationScanner(this.config.scanners.configuration));
}
// Audit logging would go here if SecurityMonitor supported audit events
logger.info(`SecurityAuditor: Initialized ${this.scanners.length} security scanners`);
}
/**
* Load suppression rules from configuration
*/
loadSuppressions() {
if (!this.config.suppressions)
return;
for (const suppression of this.config.suppressions) {
const key = suppression.file || '*';
if (!this.suppressions.has(key)) {
this.suppressions.set(key, new Set());
}
this.suppressions.get(key).add(suppression.rule);
}
}
/**
* Run security audit on the project
*/
async audit(projectRoot = process.cwd()) {
const startTime = Date.now();
const context = { projectRoot };
const allFindings = [];
const errors = [];
const scannedFilesSet = new Set();
logger.info(`SecurityAuditor: Starting security audit of ${projectRoot}`);
this.logListener?.('info', 'Start security audit', { projectRoot });
// Run all enabled scanners
for (const scanner of this.scanners) {
try {
const findings = await scanner.scan(context);
const filteredFindings = this.filterSuppressions(findings);
allFindings.push(...filteredFindings);
// Track unique files that were scanned
for (const finding of findings) {
if (finding.file) {
scannedFilesSet.add(finding.file);
}
}
}
catch (error) {
const errorMessage = `Scanner ${scanner.name} failed: ${error instanceof Error ? error.message : String(error)}`;
errors.push(errorMessage);
ErrorHandler.logError('SecurityAuditor.auditProject', error, { projectRoot });
}
}
const duration = Date.now() - startTime;
const result = this.createScanResult(allFindings, duration, scannedFilesSet.size, errors);
// Log audit completion
logger.info(`SecurityAuditor: Audit completed: ${result.summary.total} findings in ${duration}ms`);
// Notify listener per finding
for (const finding of allFindings) {
const findingLevel = finding.severity === 'critical' || finding.severity === 'high' ? 'error'
: finding.severity === 'medium' ? 'warn' : 'info';
this.logListener?.(findingLevel, finding.message, {
ruleId: finding.ruleId,
severity: finding.severity,
file: finding.file,
line: finding.line,
});
}
this.logListener?.('info', 'Complete security audit', {
total: result.summary.total,
duration,
bySeverity: result.summary.bySeverity,
});
// Generate reports
await this.generateReports(result);
// Check if build should fail
if (this.shouldFailBuild(result)) {
throw new Error(`Security audit failed: ${result.summary.bySeverity.critical} critical, ${result.summary.bySeverity.high} high severity issues found`);
}
return result;
}
/**
* Filter out suppressed findings
*/
filterSuppressions(findings) {
const suppressedFindings = [];
const filtered = findings.filter(finding => {
try {
// Check comprehensive suppressions (includes both file-based and pattern-based)
if (shouldSuppress(finding.ruleId, finding.file)) {
// Log suppression for audit trail if verbose mode is enabled
if (this.config.reporting?.verbose) {
suppressedFindings.push({
rule: finding.ruleId,
file: finding.file
});
}
return false;
}
// Check legacy config-based suppressions if they exist
// This maintains backward compatibility with existing configs
if (this.config.suppressions && this.config.suppressions.length > 0) {
const globalSuppressions = this.suppressions.get('*');
if (globalSuppressions?.has(finding.ruleId)) {
if (this.config.reporting?.verbose) {
suppressedFindings.push({
rule: finding.ruleId,
file: finding.file,
reason: 'Config-based global suppression'
});
}
return false;
}
if (finding.file) {
const fileSuppressions = this.suppressions.get(finding.file);
if (fileSuppressions?.has(finding.ruleId)) {
if (this.config.reporting?.verbose) {
suppressedFindings.push({
rule: finding.ruleId,
file: finding.file,
reason: 'Config-based file suppression'
});
}
return false;
}
}
}
return true;
}
catch (error) {
// If suppression check fails, log error but don't suppress the finding
ErrorHandler.logError('SecurityAuditor.applySuppression', error, {
ruleId: finding.ruleId,
file: finding.file
});
return true;
}
});
// Log suppression summary if verbose and suppressions were applied
if (this.config.reporting?.verbose && suppressedFindings.length > 0) {
logger.debug(`SecurityAuditor: Suppressed ${suppressedFindings.length} findings:`);
suppressedFindings.forEach(s => {
logger.debug(` - ${s.rule} in ${s.file || 'global'}${s.reason ? ` (${s.reason})` : ''}`);
});
}
return filtered;
}
/**
* Create scan result summary
*/
createScanResult(findings, duration, scannedFiles, errors) {
const bySeverity = {
info: 0,
low: 0,
medium: 0,
high: 0,
critical: 0
};
const byCategory = {};
for (const finding of findings) {
bySeverity[finding.severity]++;
// Extract category from ruleId (e.g., SEC-CODE-001 -> CODE)
const category = finding.ruleId.split('-')[1] || 'OTHER';
byCategory[category] = (byCategory[category] || 0) + 1;
}
return {
timestamp: new Date(),
duration,
scannedFiles,
findings,
summary: {
total: findings.length,
bySeverity,
byCategory
},
errors: errors.length > 0 ? errors : undefined
};
}
/**
* Generate reports in configured formats
*/
async generateReports(result) {
for (const format of this.config.reporting.formats) {
try {
switch (format) {
case 'console': {
const consoleReporter = new ConsoleReporter(result);
// Console reporter output is meant to be shown directly to user
// Using console.log here is intentional for formatting
console.log(consoleReporter.generate());
break;
}
case 'markdown': {
const markdownReporter = new MarkdownReporter(result);
const mdReport = markdownReporter.generate();
await this.fileOperations.writeFile('security-audit-report.md', mdReport, {
source: 'SecurityAuditor.generateReports'
});
break;
}
case 'json': {
const jsonReporter = new JsonReporter(result);
const jsonReport = JSON.stringify(jsonReporter.generate(), null, 2);
await this.fileOperations.writeFile('security-audit-report.json', jsonReport, {
source: 'SecurityAuditor.generateReports'
});
break;
}
// SARIF format would be implemented similarly
}
}
catch (error) {
ErrorHandler.logError('SecurityAuditor.generateReports', error, { format });
}
}
}
/**
* Determine if the build should fail based on findings
*/
shouldFailBuild(result) {
const thresholds = {
info: 5,
low: 4,
medium: 3,
high: 2,
critical: 1
};
const failThreshold = thresholds[this.config.reporting.failOnSeverity];
for (const [severity, count] of Object.entries(result.summary.bySeverity)) {
if (count > 0 && thresholds[severity] <= failThreshold) {
return true;
}
}
return false;
}
/**
* Get default configuration
*/
static async getDefaultConfig(fileOperations) {
// Load suppressions from file if it exists
let customSuppressions = [];
const ops = fileOperations;
try {
const projectRoot = process.cwd();
const suppressionsPath = path.join(projectRoot, 'src', 'security', 'audit', 'config', 'security-suppressions.json');
if (await ops.exists(suppressionsPath)) {
const suppressionsContent = await ops.readFile(suppressionsPath, {
source: 'SecurityAuditor.getDefaultConfig'
});
const suppressionsData = JSON.parse(suppressionsContent);
// Convert relative paths to patterns for matching
customSuppressions = (suppressionsData.suppressions || []).map((s) => ({
...s,
// Convert file path to a pattern that works with minimatch
file: s.file?.includes('/') ? `**/${s.file}` : s.file
}));
}
}
catch {
// Suppressions file doesn't exist or is invalid - that's OK
}
return {
enabled: true,
scanners: {
code: {
enabled: true,
rules: ['OWASP-Top-10', 'CWE-Top-25', 'DollhouseMCP-Security'],
exclude: ['**/node_modules/**', '**/dist/**', '**/coverage/**']
},
dependencies: {
enabled: true,
severityThreshold: 'high',
checkLicenses: true,
allowedLicenses: ['MIT', 'Apache-2.0', 'BSD-3-Clause', 'ISC', 'AGPL-3.0']
},
configuration: {
enabled: true,
checkFiles: ['*.yml', '*.yaml', '*.json', '.env.example']
}
},
reporting: {
formats: ['console', 'markdown'],
createIssues: true,
commentOnPr: true,
failOnSeverity: 'high'
},
suppressions: [
{
rule: 'SEC-TEST-001',
file: '__tests__/**/*',
reason: 'Test files may contain security test patterns'
},
...customSuppressions
]
};
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VjdXJpdHlBdWRpdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlY3VyaXR5L2F1ZGl0L1NlY3VyaXR5QXVkaXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFFSCwyREFBMkQ7QUFDM0QsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBUy9DLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNwRSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUMxRSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDakUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbkUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQzNELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDM0QsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFHN0IsTUFBTSxPQUFPLGVBQWU7SUFDbEIsTUFBTSxDQUFzQjtJQUM1QixRQUFRLEdBQXNCLEVBQUUsQ0FBQztJQUNqQyxZQUFZLEdBQTZCLElBQUksR0FBRyxFQUFFLENBQUM7SUFDMUMsY0FBYyxDQUF5QjtJQUNoRCxXQUFXLENBQXlHO0lBRTVILGNBQWMsQ0FBQyxFQUF5RztRQUN0SCxJQUFJLENBQUMsV0FBVyxHQUFHLEVBQUUsQ0FBQztJQUN4QixDQUFDO0lBRUQsWUFBWSxNQUEyQixFQUFFLGNBQXNDO1FBQzdFLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxjQUFjLEdBQUcsY0FBYyxDQUFDO1FB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ZSxFQUFFLENBQUMsS0FBSyxFQUFFLFlBQVksRUFBRSxjQUFjLEVBQUUsS0FBSyxFQUFFLFVBQVUsQ0FBQztpQkFDMUU7Z0JBQ0QsYUFBYSxFQUFFO29CQUNiLE9BQU8sRUFBRSxJQUFJO29CQUNiLFVBQVUsRUFBRSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLGNBQWMsQ0FBQztpQkFDMUQ7YUFDRjtZQUNELFNBQVMsRUFBRTtnQkFDVCxPQUFPLEVBQUUsQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDO2dCQUNoQyxZQUFZLEVBQUUsSUFBSTtnQkFDbEIsV0FBVyxFQUFFLElBQUk7Z0JBQ2pCLGNBQWMsRUFBRSxNQUFNO2FBQ3ZCO1lBQ0QsWUFBWSxFQUFFO2dCQUNaO29CQUNFLElBQUksRUFBRSxjQUFjO29CQUNwQixJQUFJLEVBQUUsZ0JBQWdCO29CQUN0QixNQUFNLEVBQUUsK0NBQStDO2lCQUN4RDtnQkFDRCxHQUFHLGtCQUFrQjthQUN0QjtTQUNGLENBQUM7SUFDSixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNlY3VyaXR5IEF1ZGl0b3IgLSBDb3JlIG9yY2hlc3RyYXRvciBmb3Igc2VjdXJpdHkgc2Nhbm5pbmdcbiAqIEltcGxlbWVudHMgYXV0b21hdGVkIHNlY3VyaXR5IGF1ZGl0aW5nIGZvciBEb2xsaG91c2VNQ1AgKElzc3VlICM1MylcbiAqL1xuXG4vLyBpbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi9zZWN1cml0eU1vbml0b3IuanMnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB0eXBlIHsgXG4gIFNlY3VyaXR5QXVkaXRDb25maWcsIFxuICBTY2FuQ29udGV4dCwgXG4gIFNjYW5SZXN1bHQsIFxuICBTZWN1cml0eUZpbmRpbmcsIFxuICBTZWN1cml0eVNjYW5uZXIsXG4gIFNldmVyaXR5TGV2ZWwgXG59IGZyb20gJy4vdHlwZXMuanMnO1xuaW1wb3J0IHsgQ29kZVNjYW5uZXIgfSBmcm9tICcuL3NjYW5uZXJzL0NvZGVTY2FubmVyLmpzJztcbmltcG9ydCB7IERlcGVuZGVuY3lTY2FubmVyIH0gZnJvbSAnLi9zY2FubmVycy9EZXBlbmRlbmN5U2Nhbm5lci5qcyc7XG5pbXBvcnQgeyBDb25maWd1cmF0aW9uU2Nhbm5lciB9IGZyb20gJy4vc2Nhbm5lcnMvQ29uZmlndXJhdGlvblNjYW5uZXIuanMnO1xuaW1wb3J0IHsgQ29uc29sZVJlcG9ydGVyIH0gZnJvbSAnLi9yZXBvcnRlcnMvQ29uc29sZVJlcG9ydGVyLmpzJztcbmltcG9ydCB7IE1hcmtkb3duUmVwb3J0ZXIgfSBmcm9tICcuL3JlcG9ydGVycy9NYXJrZG93blJlcG9ydGVyLmpzJztcbmltcG9ydCB7IEpzb25SZXBvcnRlciB9IGZyb20gJy4vcmVwb3J0ZXJzL0pzb25SZXBvcnRlci5qcyc7XG5pbXBvcnQgeyBzaG91bGRTdXBwcmVzcyB9IGZyb20gJy4vY29uZmlnL3N1cHByZXNzaW9ucy5qcyc7XG5pbXBvcnQgeyBFcnJvckhhbmRsZXIgfSBmcm9tICcuLi8uLi91dGlscy9FcnJvckhhbmRsZXIuanMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IElGaWxlT3BlcmF0aW9uc1NlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9GaWxlT3BlcmF0aW9uc1NlcnZpY2UuanMnO1xuXG5leHBvcnQgY2xhc3MgU2VjdXJpdHlBdWRpdG9yIHtcbiAgcHJpdmF0ZSBjb25maWc6IFNlY3VyaXR5QXVkaXRDb25maWc7XG4gIHByaXZhdGUgc2Nhbm5lcnM6IFNlY3VyaXR5U2Nhbm5lcltdID0gW107XG4gIHByaXZhdGUgc3VwcHJlc3Npb25zOiBNYXA8c3RyaW5nLCBTZXQ8c3RyaW5nPj4gPSBuZXcgTWFwKCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgZmlsZU9wZXJhdGlvbnM6IElGaWxlT3BlcmF0aW9uc1NlcnZpY2U7XG4gIHByaXZhdGUgbG9nTGlzdGVuZXI/OiAobGV2ZWw6ICdkZWJ1ZycgfCAnaW5mbycgfCAnd2FybicgfCAnZXJyb3InLCBtZXNzYWdlOiBzdHJpbmcsIGRhdGE/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikgPT4gdm9pZDtcblxuICBhZGRMb2dMaXN0ZW5lcihmbjogKGxldmVsOiAnZGVidWcnIHwgJ2luZm8nIHwgJ3dhcm4nIHwgJ2Vycm9yJywgbWVzc2FnZTogc3RyaW5nLCBkYXRhPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pID0+IHZvaWQpOiB2b2lkIHtcbiAgICB0aGlzLmxvZ0xpc3RlbmVyID0gZm47XG4gIH1cblxuICBjb25zdHJ1Y3Rvcihjb25maWc6IFNlY3VyaXR5QXVkaXRDb25maWcsIGZpbGVPcGVyYXRpb25zOiBJRmlsZU9wZXJhdGlvbnNTZXJ2aWNlKSB7XG4gICAgdGhpcy5jb25maWcgPSBjb25maWc7XG4gICAgdGhpcy5maWxlT3BlcmF0aW9ucyA9IGZpbGVPcGVyYXRpb25zO1xuICAgIHRoaXMuaW5pdGlhbGl6ZVNjYW5uZXJzKCk7XG4gICAgdGhpcy5sb2FkU3VwcHJlc3Npb25zKCk7XG4gIH1cblxuICAvKipcbiAgICogSW5pdGlhbGl6ZSBlbmFibGVkIHNjYW5uZXJzIGJhc2VkIG9uIGNvbmZpZ3VyYXRpb25cbiAgICovXG4gIHByaXZhdGUgaW5pdGlhbGl6ZVNjYW5uZXJzKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmNvbmZpZy5zY2FubmVycy5jb2RlLmVuYWJsZWQpIHtcbiAgICAgIHRoaXMuc2Nhbm5lcnMucHVzaChuZXcgQ29kZVNjYW5uZXIodGhpcy5jb25maWcuc2Nhbm5lcnMuY29kZSkpO1xuICAgIH1cbiAgICBcbiAgICBpZiAodGhpcy5jb25maWcuc2Nhbm5lcnMuZGVwZW5kZW5jaWVzLmVuYWJsZWQpIHtcbiAgICAgIHRoaXMuc2Nhbm5lcnMucHVzaChuZXcgRGVwZW5kZW5jeVNjYW5uZXIodGhpcy5jb25maWcuc2Nhbm5lcnMuZGVwZW5kZW5jaWVzKSk7XG4gICAgfVxuICAgIFxuICAgIGlmICh0aGlzLmNvbmZpZy5zY2FubmVycy5jb25maWd1cmF0aW9uLmVuYWJsZWQpIHtcbiAgICAgIHRoaXMuc2Nhbm5lcnMucHVzaChuZXcgQ29uZmlndXJhdGlvblNjYW5uZXIodGhpcy5jb25maWcuc2Nhbm5lcnMuY29uZmlndXJhdGlvbikpO1xuICAgIH1cblxuICAgIC8vIEF1ZGl0IGxvZ2dpbmcgd291bGQgZ28gaGVyZSBpZiBTZWN1cml0eU1vbml0b3Igc3VwcG9ydGVkIGF1ZGl0IGV2ZW50c1xuICAgIGxvZ2dlci5pbmZvKGBTZWN1cml0eUF1ZGl0b3I6IEluaXRpYWxpemVkICR7dGhpcy5zY2FubmVycy5sZW5ndGh9IHNlY3VyaXR5IHNjYW5uZXJzYCk7XG4gIH1cblxuICAvKipcbiAgICogTG9hZCBzdXBwcmVzc2lvbiBydWxlcyBmcm9tIGNvbmZpZ3VyYXRpb25cbiAgICovXG4gIHByaXZhdGUgbG9hZFN1cHByZXNzaW9ucygpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuY29uZmlnLnN1cHByZXNzaW9ucykgcmV0dXJuO1xuXG4gICAgZm9yIChjb25zdCBzdXBwcmVzc2lvbiBvZiB0aGlzLmNvbmZpZy5zdXBwcmVzc2lvbnMpIHtcbiAgICAgIGNvbnN0IGtleSA9IHN1cHByZXNzaW9uLmZpbGUgfHwgJyonO1xuICAgICAgaWYgKCF0aGlzLnN1cHByZXNzaW9ucy5oYXMoa2V5KSkge1xuICAgICAgICB0aGlzLnN1cHByZXNzaW9ucy5zZXQoa2V5LCBuZXcgU2V0KCkpO1xuICAgICAgfVxuICAgICAgdGhpcy5zdXBwcmVzc2lvbnMuZ2V0KGtleSkhLmFkZChzdXBwcmVzc2lvbi5ydWxlKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUnVuIHNlY3VyaXR5IGF1ZGl0IG9uIHRoZSBwcm9qZWN0XG4gICAqL1xuICBhc3luYyBhdWRpdChwcm9qZWN0Um9vdDogc3RyaW5nID0gcHJvY2Vzcy5jd2QoKSk6IFByb21pc2U8U2NhblJlc3VsdD4ge1xuICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgY29uc3QgY29udGV4dDogU2NhbkNvbnRleHQgPSB7IHByb2plY3RSb290IH07XG4gICAgY29uc3QgYWxsRmluZGluZ3M6IFNlY3VyaXR5RmluZGluZ1tdID0gW107XG4gICAgY29uc3QgZXJyb3JzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGNvbnN0IHNjYW5uZWRGaWxlc1NldCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gICAgbG9nZ2VyLmluZm8oYFNlY3VyaXR5QXVkaXRvcjogU3RhcnRpbmcgc2VjdXJpdHkgYXVkaXQgb2YgJHtwcm9qZWN0Um9vdH1gKTtcbiAgICB0aGlzLmxvZ0xpc3RlbmVyPy4oJ2luZm8nLCAnU3RhcnQgc2VjdXJpdHkgYXVkaXQnLCB7IHByb2plY3RSb290IH0pO1xuXG4gICAgLy8gUnVuIGFsbCBlbmFibGVkIHNjYW5uZXJzXG4gICAgZm9yIChjb25zdCBzY2FubmVyIG9mIHRoaXMuc2Nhbm5lcnMpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGZpbmRpbmdzID0gYXdhaXQgc2Nhbm5lci5zY2FuKGNvbnRleHQpO1xuICAgICAgICBjb25zdCBmaWx0ZXJlZEZpbmRpbmdzID0gdGhpcy5maWx0ZXJTdXBwcmVzc2lvbnMoZmluZGluZ3MpO1xuICAgICAgICBhbGxGaW5kaW5ncy5wdXNoKC4uLmZpbHRlcmVkRmluZGluZ3MpO1xuICAgICAgICAvLyBUcmFjayB1bmlxdWUgZmlsZXMgdGhhdCB3ZXJlIHNjYW5uZWRcbiAgICAgICAgZm9yIChjb25zdCBmaW5kaW5nIG9mIGZpbmRpbmdzKSB7XG4gICAgICAgICAgaWYgKGZpbmRpbmcuZmlsZSkge1xuICAgICAgICAgICAgc2Nhbm5lZEZpbGVzU2V0LmFkZChmaW5kaW5nLmZpbGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc3QgZXJyb3JNZXNzYWdlID0gYFNjYW5uZXIgJHtzY2FubmVyLm5hbWV9IGZhaWxlZDogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YDtcbiAgICAgICAgZXJyb3JzLnB1c2goZXJyb3JNZXNzYWdlKTtcbiAgICAgICAgRXJyb3JIYW5kbGVyLmxvZ0Vycm9yKCdTZWN1cml0eUF1ZGl0b3IuYXVkaXRQcm9qZWN0JywgZXJyb3IsIHsgcHJvamVjdFJvb3QgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgZHVyYXRpb24gPSBEYXRlLm5vdygpIC0gc3RhcnRUaW1lO1xuICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMuY3JlYXRlU2NhblJlc3VsdChhbGxGaW5kaW5ncywgZHVyYXRpb24sIHNjYW5uZWRGaWxlc1NldC5zaXplLCBlcnJvcnMpO1xuXG4gICAgLy8gTG9nIGF1ZGl0IGNvbXBsZXRpb25cbiAgICBsb2dnZXIuaW5mbyhgU2VjdXJpdHlBdWRpdG9yOiBBdWRpdCBjb21wbGV0ZWQ6ICR7cmVzdWx0LnN1bW1hcnkudG90YWx9IGZpbmRpbmdzIGluICR7ZHVyYXRpb259bXNgKTtcblxuICAgIC8vIE5vdGlmeSBsaXN0ZW5lciBwZXIgZmluZGluZ1xuICAgIGZvciAoY29uc3QgZmluZGluZyBvZiBhbGxGaW5kaW5ncykge1xuICAgICAgY29uc3QgZmluZGluZ0xldmVsID0gZmluZGluZy5zZXZlcml0eSA9PT0gJ2NyaXRpY2FsJyB8fCBmaW5kaW5nLnNldmVyaXR5ID09PSAnaGlnaCcgPyAnZXJyb3InXG4gICAgICAgIDogZmluZGluZy5zZXZlcml0eSA9PT0gJ21lZGl1bScgPyAnd2FybicgOiAnaW5mbyc7XG4gICAgICB0aGlzLmxvZ0xpc3RlbmVyPy4oZmluZGluZ0xldmVsLCBmaW5kaW5nLm1lc3NhZ2UsIHtcbiAgICAgICAgcnVsZUlkOiBmaW5kaW5nLnJ1bGVJZCxcbiAgICAgICAgc2V2ZXJpdHk6IGZpbmRpbmcuc2V2ZXJpdHksXG4gICAgICAgIGZpbGU6IGZpbmRpbmcuZmlsZSxcbiAgICAgICAgbGluZTogZmluZGluZy5saW5lLFxuICAgICAgfSk7XG4gICAgfVxuICAgIHRoaXMubG9nTGlzdGVuZXI/LignaW5mbycsICdDb21wbGV0ZSBzZWN1cml0eSBhdWRpdCcsIHtcbiAgICAgIHRvdGFsOiByZXN1bHQuc3VtbWFyeS50b3RhbCxcbiAgICAgIGR1cmF0aW9uLFxuICAgICAgYnlTZXZlcml0eTogcmVzdWx0LnN1bW1hcnkuYnlTZXZlcml0eSxcbiAgICB9KTtcblxuICAgIC8vIEdlbmVyYXRlIHJlcG9ydHNcbiAgICBhd2FpdCB0aGlzLmdlbmVyYXRlUmVwb3J0cyhyZXN1bHQpO1xuXG4gICAgLy8gQ2hlY2sgaWYgYnVpbGQgc2hvdWxkIGZhaWxcbiAgICBpZiAodGhpcy5zaG91bGRGYWlsQnVpbGQocmVzdWx0KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBTZWN1cml0eSBhdWRpdCBmYWlsZWQ6ICR7cmVzdWx0LnN1bW1hcnkuYnlTZXZlcml0eS5jcml0aWNhbH0gY3JpdGljYWwsICR7cmVzdWx0LnN1bW1hcnkuYnlTZXZlcml0eS5oaWdofSBoaWdoIHNldmVyaXR5IGlzc3VlcyBmb3VuZGApO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICogRmlsdGVyIG91dCBzdXBwcmVzc2VkIGZpbmRpbmdzXG4gICAqL1xuICBwcml2YXRlIGZpbHRlclN1cHByZXNzaW9ucyhmaW5kaW5nczogU2VjdXJpdHlGaW5kaW5nW10pOiBTZWN1cml0eUZpbmRpbmdbXSB7XG4gICAgY29uc3Qgc3VwcHJlc3NlZEZpbmRpbmdzOiBBcnJheTx7cnVsZTogc3RyaW5nOyBmaWxlPzogc3RyaW5nOyByZWFzb24/OiBzdHJpbmd9PiA9IFtdO1xuICAgIFxuICAgIGNvbnN0IGZpbHRlcmVkID0gZmluZGluZ3MuZmlsdGVyKGZpbmRpbmcgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gQ2hlY2sgY29tcHJlaGVuc2l2ZSBzdXBwcmVzc2lvbnMgKGluY2x1ZGVzIGJvdGggZmlsZS1iYXNlZCBhbmQgcGF0dGVybi1iYXNlZClcbiAgICAgICAgaWYgKHNob3VsZFN1cHByZXNzKGZpbmRpbmcucnVsZUlkLCBmaW5kaW5nLmZpbGUpKSB7XG4gICAgICAgICAgLy8gTG9nIHN1cHByZXNzaW9uIGZvciBhdWRpdCB0cmFpbCBpZiB2ZXJib3NlIG1vZGUgaXMgZW5hYmxlZFxuICAgICAgICAgIGlmICh0aGlzLmNvbmZpZy5yZXBvcnRpbmc/LnZlcmJvc2UpIHtcbiAgICAgICAgICAgIHN1cHByZXNzZWRGaW5kaW5ncy5wdXNoKHtcbiAgICAgICAgICAgICAgcnVsZTogZmluZGluZy5ydWxlSWQsXG4gICAgICAgICAgICAgIGZpbGU6IGZpbmRpbmcuZmlsZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgLy8gQ2hlY2sgbGVnYWN5IGNvbmZpZy1iYXNlZCBzdXBwcmVzc2lvbnMgaWYgdGhleSBleGlzdFxuICAgICAgICAvLyBUaGlzIG1haW50YWlucyBiYWNrd2FyZCBjb21wYXRpYmlsaXR5IHdpdGggZXhpc3RpbmcgY29uZmlnc1xuICAgICAgICBpZiAodGhpcy5jb25maWcuc3VwcHJlc3Npb25zICYmIHRoaXMuY29uZmlnLnN1cHByZXNzaW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgY29uc3QgZ2xvYmFsU3VwcHJlc3Npb25zID0gdGhpcy5zdXBwcmVzc2lvbnMuZ2V0KCcqJyk7XG4gICAgICAgICAgaWYgKGdsb2JhbFN1cHByZXNzaW9ucz8uaGFzKGZpbmRpbmcucnVsZUlkKSkge1xuICAgICAgICAgICAgaWYgKHRoaXMuY29uZmlnLnJlcG9ydGluZz8udmVyYm9zZSkge1xuICAgICAgICAgICAgICBzdXBwcmVzc2VkRmluZGluZ3MucHVzaCh7XG4gICAgICAgICAgICAgICAgcnVsZTogZmluZGluZy5ydWxlSWQsXG4gICAgICAgICAgICAgICAgZmlsZTogZmluZGluZy5maWxlLFxuICAgICAgICAgICAgICAgIHJlYXNvbjogJ0NvbmZpZy1iYXNlZCBnbG9iYWwgc3VwcHJlc3Npb24nXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChmaW5kaW5nLmZpbGUpIHtcbiAgICAgICAgICAgIGNvbnN0IGZpbGVTdXBwcmVzc2lvbnMgPSB0aGlzLnN1cHByZXNzaW9ucy5nZXQoZmluZGluZy5maWxlKTtcbiAgICAgICAgICAgIGlmIChmaWxlU3VwcHJlc3Npb25zPy5oYXMoZmluZGluZy5ydWxlSWQpKSB7XG4gICAgICAgICAgICAgIGlmICh0aGlzLmNvbmZpZy5yZXBvcnRpbmc/LnZlcmJvc2UpIHtcbiAgICAgICAgICAgICAgICBzdXBwcmVzc2VkRmluZGluZ3MucHVzaCh7XG4gICAgICAgICAgICAgICAgICBydWxlOiBmaW5kaW5nLnJ1bGVJZCxcbiAgICAgICAgICAgICAgICAgIGZpbGU6IGZpbmRpbmcuZmlsZSxcbiAgICAgICAgICAgICAgICAgIHJlYXNvbjogJ0NvbmZpZy1iYXNlZCBmaWxlIHN1cHByZXNzaW9uJ1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIC8vIElmIHN1cHByZXNzaW9uIGNoZWNrIGZhaWxzLCBsb2cgZXJyb3IgYnV0IGRvbid0IHN1cHByZXNzIHRoZSBmaW5kaW5nXG4gICAgICAgIEVycm9ySGFuZGxlci5sb2dFcnJvcignU2VjdXJpdHlBdWRpdG9yLmFwcGx5U3VwcHJlc3Npb24nLCBlcnJvciwgeyBcbiAgICAgICAgICBydWxlSWQ6IGZpbmRpbmcucnVsZUlkLCBcbiAgICAgICAgICBmaWxlOiBmaW5kaW5nLmZpbGUgXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBcbiAgICAvLyBMb2cgc3VwcHJlc3Npb24gc3VtbWFyeSBpZiB2ZXJib3NlIGFuZCBzdXBwcmVzc2lvbnMgd2VyZSBhcHBsaWVkXG4gICAgaWYgKHRoaXMuY29uZmlnLnJlcG9ydGluZz8udmVyYm9zZSAmJiBzdXBwcmVzc2VkRmluZGluZ3MubGVuZ3RoID4gMCkge1xuICAgICAgbG9nZ2VyLmRlYnVnKGBTZWN1cml0eUF1ZGl0b3I6IFN1cHByZXNzZWQgJHtzdXBwcmVzc2VkRmluZGluZ3MubGVuZ3RofSBmaW5kaW5nczpgKTtcbiAgICAgIHN1cHByZXNzZWRGaW5kaW5ncy5mb3JFYWNoKHMgPT4ge1xuICAgICAgICBsb2dnZXIuZGVidWcoYCAgLSAke3MucnVsZX0gaW4gJHtzLmZpbGUgfHwgJ2dsb2JhbCd9JHtzLnJlYXNvbiA/IGAgKCR7cy5yZWFzb259KWAgOiAnJ31gKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gZmlsdGVyZWQ7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIHNjYW4gcmVzdWx0IHN1bW1hcnlcbiAgICovXG4gIHByaXZhdGUgY3JlYXRlU2NhblJlc3VsdChcbiAgICBmaW5kaW5nczogU2VjdXJpdHlGaW5kaW5nW10sIFxuICAgIGR1cmF0aW9uOiBudW1iZXIsIFxuICAgIHNjYW5uZWRGaWxlczogbnVtYmVyLFxuICAgIGVycm9yczogc3RyaW5nW11cbiAgKTogU2NhblJlc3VsdCB7XG4gICAgY29uc3QgYnlTZXZlcml0eTogUmVjb3JkPFNldmVyaXR5TGV2ZWwsIG51bWJlcj4gPSB7XG4gICAgICBpbmZvOiAwLFxuICAgICAgbG93OiAwLFxuICAgICAgbWVkaXVtOiAwLFxuICAgICAgaGlnaDogMCxcbiAgICAgIGNyaXRpY2FsOiAwXG4gICAgfTtcblxuICAgIGNvbnN0IGJ5Q2F0ZWdvcnk6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gPSB7fTtcblxuICAgIGZvciAoY29uc3QgZmluZGluZyBvZiBmaW5kaW5ncykge1xuICAgICAgYnlTZXZlcml0eVtmaW5kaW5nLnNldmVyaXR5XSsrO1xuICAgICAgXG4gICAgICAvLyBFeHRyYWN0IGNhdGVnb3J5IGZyb20gcnVsZUlkIChlLmcuLCBTRUMtQ09ERS0wMDEgLT4gQ09ERSlcbiAgICAgIGNvbnN0IGNhdGVnb3J5ID0gZmluZGluZy5ydWxlSWQuc3BsaXQoJy0nKVsxXSB8fCAnT1RIRVInO1xuICAgICAgYnlDYXRlZ29yeVtjYXRlZ29yeV0gPSAoYnlDYXRlZ29yeVtjYXRlZ29yeV0gfHwgMCkgKyAxO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKCksXG4gICAgICBkdXJhdGlvbixcbiAgICAgIHNjYW5uZWRGaWxlcyxcbiAgICAgIGZpbmRpbmdzLFxuICAgICAgc3VtbWFyeToge1xuICAgICAgICB0b3RhbDogZmluZGluZ3MubGVuZ3RoLFxuICAgICAgICBieVNldmVyaXR5LFxuICAgICAgICBieUNhdGVnb3J5XG4gICAgICB9LFxuICAgICAgZXJyb3JzOiBlcnJvcnMubGVuZ3RoID4gMCA/IGVycm9ycyA6IHVuZGVmaW5lZFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGUgcmVwb3J0cyBpbiBjb25maWd1cmVkIGZvcm1hdHNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2VuZXJhdGVSZXBvcnRzKHJlc3VsdDogU2NhblJlc3VsdCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGZvciAoY29uc3QgZm9ybWF0IG9mIHRoaXMuY29uZmlnLnJlcG9ydGluZy5mb3JtYXRzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBzd2l0Y2ggKGZvcm1hdCkge1xuICAgICAgICAgIGNhc2UgJ2NvbnNvbGUnOiB7XG4gICAgICAgICAgICBjb25zdCBjb25zb2xlUmVwb3J0ZXIgPSBuZXcgQ29uc29sZVJlcG9ydGVyKHJlc3VsdCk7XG4gICAgICAgICAgICAvLyBDb25zb2xlIHJlcG9ydGVyIG91dHB1dCBpcyBtZWFudCB0byBiZSBzaG93biBkaXJlY3RseSB0byB1c2VyXG4gICAgICAgICAgICAvLyBVc2luZyBjb25zb2xlLmxvZyBoZXJlIGlzIGludGVudGlvbmFsIGZvciBmb3JtYXR0aW5nXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhjb25zb2xlUmVwb3J0ZXIuZ2VuZXJhdGUoKSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjYXNlICdtYXJrZG93bic6IHtcbiAgICAgICAgICAgIGNvbnN0IG1hcmtkb3duUmVwb3J0ZXIgPSBuZXcgTWFya2Rvd25SZXBvcnRlcihyZXN1bHQpO1xuICAgICAgICAgICAgY29uc3QgbWRSZXBvcnQgPSBtYXJrZG93blJlcG9ydGVyLmdlbmVyYXRlKCkgYXMgc3RyaW5nO1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5maWxlT3BlcmF0aW9ucy53cml0ZUZpbGUoJ3NlY3VyaXR5LWF1ZGl0LXJlcG9ydC5tZCcsIG1kUmVwb3J0LCB7XG4gICAgICAgICAgICAgIHNvdXJjZTogJ1NlY3VyaXR5QXVkaXRvci5nZW5lcmF0ZVJlcG9ydHMnXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNhc2UgJ2pzb24nOiB7XG4gICAgICAgICAgICBjb25zdCBqc29uUmVwb3J0ZXIgPSBuZXcgSnNvblJlcG9ydGVyKHJlc3VsdCk7XG4gICAgICAgICAgICBjb25zdCBqc29uUmVwb3J0ID0gSlNPTi5zdHJpbmdpZnkoanNvblJlcG9ydGVyLmdlbmVyYXRlKCksIG51bGwsIDIpO1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5maWxlT3BlcmF0aW9ucy53cml0ZUZpbGUoJ3NlY3VyaXR5LWF1ZGl0LXJlcG9ydC5qc29uJywganNvblJlcG9ydCwge1xuICAgICAgICAgICAgICBzb3VyY2U6ICdTZWN1cml0eUF1ZGl0b3IuZ2VuZXJhdGVSZXBvcnRzJ1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgICAgICBcbiAgICAgICAgICAvLyBTQVJJRiBmb3JtYXQgd291bGQgYmUgaW1wbGVtZW50ZWQgc2ltaWxhcmx5XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIEVycm9ySGFuZGxlci5sb2dFcnJvcignU2VjdXJpdHlBdWRpdG9yLmdlbmVyYXRlUmVwb3J0cycsIGVycm9yLCB7IGZvcm1hdCB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRGV0ZXJtaW5lIGlmIHRoZSBidWlsZCBzaG91bGQgZmFpbCBiYXNlZCBvbiBmaW5kaW5nc1xuICAgKi9cbiAgcHJpdmF0ZSBzaG91bGRGYWlsQnVpbGQocmVzdWx0OiBTY2FuUmVzdWx0KTogYm9vbGVhbiB7XG4gICAgY29uc3QgdGhyZXNob2xkczogUmVjb3JkPFNldmVyaXR5TGV2ZWwsIG51bWJlcj4gPSB7XG4gICAgICBpbmZvOiA1LFxuICAgICAgbG93OiA0LFxuICAgICAgbWVkaXVtOiAzLFxuICAgICAgaGlnaDogMixcbiAgICAgIGNyaXRpY2FsOiAxXG4gICAgfTtcblxuICAgIGNvbnN0IGZhaWxUaHJlc2hvbGQgPSB0aHJlc2hvbGRzW3RoaXMuY29uZmlnLnJlcG9ydGluZy5mYWlsT25TZXZlcml0eV07XG4gICAgXG4gICAgZm9yIChjb25zdCBbc2V2ZXJpdHksIGNvdW50XSBvZiBPYmplY3QuZW50cmllcyhyZXN1bHQuc3VtbWFyeS5ieVNldmVyaXR5KSkge1xuICAgICAgaWYgKGNvdW50ID4gMCAmJiB0aHJlc2hvbGRzW3NldmVyaXR5IGFzIFNldmVyaXR5TGV2ZWxdIDw9IGZhaWxUaHJlc2hvbGQpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBkZWZhdWx0IGNvbmZpZ3VyYXRpb25cbiAgICovXG4gIHN0YXRpYyBhc3luYyBnZXREZWZhdWx0Q29uZmlnKGZpbGVPcGVyYXRpb25zOiBJRmlsZU9wZXJhdGlvbnNTZXJ2aWNlKTogUHJvbWlzZTxTZWN1cml0eUF1ZGl0Q29uZmlnPiB7XG4gICAgLy8gTG9hZCBzdXBwcmVzc2lvbnMgZnJvbSBmaWxlIGlmIGl0IGV4aXN0c1xuICAgIGxldCBjdXN0b21TdXBwcmVzc2lvbnM6IGFueVtdID0gW107XG4gICAgY29uc3Qgb3BzID0gZmlsZU9wZXJhdGlvbnM7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcHJvamVjdFJvb3QgPSBwcm9jZXNzLmN3ZCgpO1xuICAgICAgY29uc3Qgc3VwcHJlc3Npb25zUGF0aCA9IHBhdGguam9pbihwcm9qZWN0Um9vdCwgJ3NyYycsICdzZWN1cml0eScsICdhdWRpdCcsICdjb25maWcnLCAnc2VjdXJpdHktc3VwcHJlc3Npb25zLmpzb24nKTtcblxuICAgICAgaWYgKGF3YWl0IG9wcy5leGlzdHMoc3VwcHJlc3Npb25zUGF0aCkpIHtcbiAgICAgICAgY29uc3Qgc3VwcHJlc3Npb25zQ29udGVudCA9IGF3YWl0IG9wcy5yZWFkRmlsZShzdXBwcmVzc2lvbnNQYXRoLCB7XG4gICAgICAgICAgc291cmNlOiAnU2VjdXJpdHlBdWRpdG9yLmdldERlZmF1bHRDb25maWcnXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBzdXBwcmVzc2lvbnNEYXRhID0gSlNPTi5wYXJzZShzdXBwcmVzc2lvbnNDb250ZW50KTtcbiAgICAgICAgLy8gQ29udmVydCByZWxhdGl2ZSBwYXRocyB0byBwYXR0ZXJucyBmb3IgbWF0Y2hpbmdcbiAgICAgICAgY3VzdG9tU3VwcHJlc3Npb25zID0gKHN1cHByZXNzaW9uc0RhdGEuc3VwcHJlc3Npb25zIHx8IFtdKS5tYXAoKHM6IGFueSkgPT4gKHtcbiAgICAgICAgICAuLi5zLFxuICAgICAgICAgIC8vIENvbnZlcnQgZmlsZSBwYXRoIHRvIGEgcGF0dGVybiB0aGF0IHdvcmtzIHdpdGggbWluaW1hdGNoXG4gICAgICAgICAgZmlsZTogcy5maWxlPy5pbmNsdWRlcygnLycpID8gYCoqLyR7cy5maWxlfWAgOiBzLmZpbGVcbiAgICAgICAgfSkpO1xuICAgICAgfVxuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gU3VwcHJlc3Npb25zIGZpbGUgZG9lc24ndCBleGlzdCBvciBpcyBpbnZhbGlkIC0gdGhhdCdzIE9LXG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgICBzY2FubmVyczoge1xuICAgICAgICBjb2RlOiB7XG4gICAgICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgICBydWxlczogWydPV0FTUC1Ub3AtMTAnLCAnQ1dFLVRvcC0yNScsICdEb2xsaG91c2VNQ1AtU2VjdXJpdHknXSxcbiAgICAgICAgICBleGNsdWRlOiBbJyoqL25vZGVfbW9kdWxlcy8qKicsICcqKi9kaXN0LyoqJywgJyoqL2NvdmVyYWdlLyoqJ11cbiAgICAgICAgfSxcbiAgICAgICAgZGVwZW5kZW5jaWVzOiB7XG4gICAgICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgICBzZXZlcml0eVRocmVzaG9sZDogJ2hpZ2gnLFxuICAgICAgICAgIGNoZWNrTGljZW5zZXM6IHRydWUsXG4gICAgICAgICAgYWxsb3dlZExpY2Vuc2VzOiBbJ01JVCcsICdBcGFjaGUtMi4wJywgJ0JTRC0zLUNsYXVzZScsICdJU0MnLCAnQUdQTC0zLjAnXVxuICAgICAgICB9LFxuICAgICAgICBjb25maWd1cmF0aW9uOiB7XG4gICAgICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgICBjaGVja0ZpbGVzOiBbJyoueW1sJywgJyoueWFtbCcsICcqLmpzb24nLCAnLmVudi5leGFtcGxlJ11cbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIHJlcG9ydGluZzoge1xuICAgICAgICBmb3JtYXRzOiBbJ2NvbnNvbGUnLCAnbWFya2Rvd24nXSxcbiAgICAgICAgY3JlYXRlSXNzdWVzOiB0cnVlLFxuICAgICAgICBjb21tZW50T25QcjogdHJ1ZSxcbiAgICAgICAgZmFpbE9uU2V2ZXJpdHk6ICdoaWdoJ1xuICAgICAgfSxcbiAgICAgIHN1cHByZXNzaW9uczogW1xuICAgICAgICB7XG4gICAgICAgICAgcnVsZTogJ1NFQy1URVNULTAwMScsXG4gICAgICAgICAgZmlsZTogJ19fdGVzdHNfXy8qKi8qJyxcbiAgICAgICAgICByZWFzb246ICdUZXN0IGZpbGVzIG1heSBjb250YWluIHNlY3VyaXR5IHRlc3QgcGF0dGVybnMnXG4gICAgICAgIH0sXG4gICAgICAgIC4uLmN1c3RvbVN1cHByZXNzaW9uc1xuICAgICAgXVxuICAgIH07XG4gIH1cbn1cbiJdfQ==