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.

335 lines 45.5 kB
/** * 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==