@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.
271 lines • 39 kB
JavaScript
/**
* Security Rules - Defines security patterns and checks
* Based on OWASP Top 10, CWE Top 25, and DollhouseMCP-specific security requirements
*/
export class SecurityRules {
/**
* OWASP Top 10 security rules
*/
getOWASPRules() {
return [
{
id: 'OWASP-A01-001',
name: 'Hardcoded Secrets',
description: 'Potential hardcoded secret or API key detected',
severity: 'critical',
category: 'code',
pattern: /(?:api[_-]?key|secret|password|token|private[_-]?key)\s*[:=]\s*["'][a-zA-Z0-9+/=_-]{10,}["']/gi,
remediation: 'Use environment variables or secure key management services instead of hardcoding secrets',
references: ['https://owasp.org/Top10/A01_2021-Broken_Access_Control/'],
tags: ['high-confidence']
},
{
id: 'OWASP-A03-001',
name: 'SQL Injection',
description: 'Potential SQL injection vulnerability',
severity: 'critical',
category: 'code',
pattern: /(?:query|execute)\s*\(\s*['"`].*\$\{[^}]+\}.*['"`]|['"`].*\+\s*[a-zA-Z_]\w*\s*\+.*['"`]\s*\)/g,
remediation: 'Use parameterized queries or prepared statements',
references: ['https://owasp.org/Top10/A03_2021-Injection/']
},
{
id: 'OWASP-A03-002',
name: 'Command Injection',
description: 'Potential command injection vulnerability',
severity: 'critical',
category: 'code',
pattern: /(?:exec|spawn|execSync|spawnSync)\s*\([^)]*(?:\$\{[^}]+\}|\+\s*[a-zA-Z_]\w*)/g,
remediation: 'Validate and sanitize all user input before using in system commands',
references: ['https://owasp.org/Top10/A03_2021-Injection/']
},
{
id: 'OWASP-A03-003',
name: 'Path Traversal',
description: 'Potential path traversal vulnerability',
severity: 'high',
category: 'code',
pattern: /(?:readFile|writeFile|readdir|mkdir|rm|unlink)[^(]*\([^)]*(?:\.\.[/\\].*\+|\+.*\.\.[/\\])/g,
remediation: 'Validate and sanitize file paths, use path.resolve() and check against allowed directories',
references: ['https://owasp.org/Top10/A03_2021-Injection/']
},
{
id: 'OWASP-A03-004',
name: 'XSS - Direct HTML Injection',
description: 'Potential XSS vulnerability through direct HTML injection',
severity: 'high',
category: 'code',
pattern: /innerHTML\s*=\s*[^'"`]*\$\{|dangerouslySetInnerHTML/g,
remediation: 'Use textContent or proper HTML escaping functions',
references: ['https://owasp.org/Top10/A03_2021-Injection/']
},
{
id: 'OWASP-A05-001',
name: 'Insecure Configuration',
description: 'Security-sensitive configuration detected',
severity: 'medium',
category: 'code',
pattern: /(?:NODE_TLS_REJECT_UNAUTHORIZED|strictSSL|rejectUnauthorized)\s*[:=]\s*(?:false|0|["']false["']|["']0["'])/gi,
remediation: 'Enable SSL/TLS certificate validation in production',
references: ['https://owasp.org/Top10/A05_2021-Security_Misconfiguration/']
},
{
id: 'OWASP-A07-001',
name: 'Weak Authentication',
description: 'Potential weak authentication mechanism',
severity: 'high',
category: 'code',
pattern: /(?:md5|sha1)\s*\(/gi,
remediation: 'Use strong hashing algorithms like bcrypt, scrypt, or Argon2 for passwords',
references: ['https://owasp.org/Top10/A07_2021-Identification_and_Authentication_Failures/']
}
];
}
/**
* CWE Top 25 security rules
*/
getCWERules() {
return [
{
id: 'CWE-79-001',
name: 'Reflected XSS',
description: 'User input reflected without encoding',
severity: 'high',
category: 'code',
pattern: /res\.(?:send|write|end)\s*\([^)]*(?:req\.(?:query|params|body)|request\.)/g,
remediation: 'Encode all user input before reflecting in responses',
references: ['https://cwe.mitre.org/data/definitions/79.html']
},
{
id: 'CWE-89-001',
name: 'SQL String Concatenation',
description: 'SQL query built using string concatenation',
severity: 'critical',
category: 'code',
pattern: /["'`].*(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER).*["'`]\s*\+\s*\w+/gi,
remediation: 'Use parameterized queries instead of string concatenation',
references: ['https://cwe.mitre.org/data/definitions/89.html']
},
{
id: 'CWE-22-001',
name: 'Path Manipulation',
description: 'File path constructed from user input',
severity: 'high',
category: 'code',
pattern: /path\.join\s*\([^)]*(?:req\.|request\.|params|query|body)/g,
remediation: 'Validate paths against a whitelist and use path.resolve()',
references: ['https://cwe.mitre.org/data/definitions/22.html']
},
{
id: 'CWE-798-001',
name: 'Hardcoded Credentials',
description: 'Credentials hardcoded in source',
severity: 'critical',
category: 'code',
pattern: /(?:username|user|login)\s*[:=]\s*["'][^"']+["'].*(?:password|pass|pwd)\s*[:=]\s*["'][^"']+["']/gi,
remediation: 'Store credentials in environment variables or secure vaults',
references: ['https://cwe.mitre.org/data/definitions/798.html']
}
];
}
/**
* DollhouseMCP-specific security rules
*/
getDollhouseMCPRules() {
return [
{
id: 'DMCP-SEC-001',
name: 'Unsafe Persona Loading',
description: 'Persona loaded without validation',
severity: 'high',
category: 'custom',
pattern: /loadPersona\s*\([^)]*\)\s*(?!.*validate)/g,
remediation: 'Always validate personas before loading using PersonaValidator',
references: ['DollhouseMCP Security Guidelines']
},
{
id: 'DMCP-SEC-002',
name: 'Token Validation Bypass',
description: 'Token used without validation',
severity: 'critical',
category: 'custom',
pattern: /(?:getToken|useToken|token\.use)\s*\([^)]*\)(?!.*(?:validate|verify|check))/gi,
remediation: 'Always validate tokens using TokenManager.validateToken()',
references: ['DollhouseMCP Security Guidelines']
},
{
id: 'DMCP-SEC-003',
name: 'Rate Limiting Missing',
description: 'API endpoint without rate limiting',
severity: 'medium',
category: 'custom',
check: (content, _context) => {
const findings = [];
// Check for MCP tool handlers without rate limiting
const toolPattern = /name:\s*["']([^"']+)["'].*handle:/gs;
const hasRateLimit = /rateLimiter|checkRateLimit|tokenBucket/i.test(content);
if (toolPattern.test(content) && !hasRateLimit) {
findings.push({
ruleId: 'DMCP-SEC-003',
severity: 'medium',
message: 'MCP tool handler without rate limiting',
remediation: 'Add rate limiting to prevent abuse',
confidence: 'high'
});
}
return findings;
},
remediation: 'Implement rate limiting for all MCP tools',
references: ['Issue #174 - Rate Limiting Implementation']
},
{
id: 'DMCP-SEC-004',
name: 'Unicode Validation Missing',
description: 'User input processed without Unicode normalization',
severity: 'medium',
category: 'custom',
check: (content, _context) => {
const findings = [];
// Check for user input processing without Unicode validation
const inputPattern = /(?:req\.|request\.|params|query|body|content)/;
const hasUnicodeCheck = /UnicodeValidator|normalizeUnicode/i.test(content);
if (inputPattern.test(content) && !hasUnicodeCheck) {
findings.push({
ruleId: 'DMCP-SEC-004',
severity: 'medium',
message: 'User input processed without Unicode normalization',
remediation: 'Use UnicodeValidator.normalize() on all user input',
confidence: 'medium'
});
}
return findings;
},
remediation: 'Apply Unicode normalization to prevent bypass attacks',
references: ['Issue #162 - Unicode Normalization']
},
{
id: 'DMCP-SEC-005',
name: 'Unvalidated YAML Content',
description: 'YAML content parsed without security validation',
severity: 'high',
category: 'custom',
pattern: /yaml\.load\s*\(|parse\s*\([^)]*\.ya?ml/gi,
remediation: 'Use SecureYamlParser for all YAML parsing',
references: ['DollhouseMCP Security Guidelines']
},
{
id: 'DMCP-SEC-006',
name: 'Security Event Not Logged',
description: 'Security-relevant operation without logging',
severity: 'low',
category: 'custom',
check: (content, _context) => {
const findings = [];
// FIX: Only flag files with actual executable code
// Skip files that are pure type definitions (interfaces, types only)
const hasExecutableCode = /(?:^|\n)\s*(?:export\s+)?(?:function|class|const\s+\w+\s*=\s*(?:async\s+)?\(|async\s+function)/m.test(content) ||
/(?:^|\n)\s*(?:public|private|protected|async)\s+\w+\s*\(/m.test(content);
if (!hasExecutableCode) {
return findings; // Skip pure type definition files
}
// Remove comments and strings to avoid false positives on keywords in documentation
// FIX: Preserve ${...} expressions in template literals to avoid false negatives
// When scanning for security calls like authenticate(`user-${id}`), we must preserve
// both the function call (authenticate) and the expression inside ${} (id).
// Otherwise we get false negatives where security-sensitive calls are missed.
const codeOnly = content
.replace(/\/\/.*$/gm, '') // Remove single-line comments
.replace(/\/\*[\s\S]*?\*\//g, '') // Remove multi-line comments
.replace(/'(?:[^'\\]|\\.)*'/g, '') // Remove single-quoted strings
.replace(/"(?:[^"\\]|\\.)*"/g, '') // Remove double-quoted strings
// For template literals: remove string content but preserve ${...} expressions
.replace(/`([^`]*)`/g, (_match, inner) => {
// Extract ${...} expressions and keep their content
const expressions = inner.match(/\$\{([^}]+)\}/g);
if (expressions) {
return expressions.map((e) => e.replace(/\$\{([^}]+)\}/, '$1')).join(' ');
}
return ''; // No expressions, remove the whole template literal
});
// Check for actual security operation function CALLS (not just keywords in text)
// Match: authenticate(...), validate(...), etc. - not just the words
const securityOpCalls = /\b(?:authenticate|authorize|validate|sanitize|encrypt|decrypt)\s*\(/i;
const hasLogging = /SecurityMonitor\.log|logSecurityEvent/i.test(content);
if (securityOpCalls.test(codeOnly) && !hasLogging) {
findings.push({
ruleId: 'DMCP-SEC-006',
severity: 'low',
message: 'Security operation without audit logging',
remediation: 'Add SecurityMonitor.logSecurityEvent() for audit trail',
confidence: 'medium'
});
}
return findings;
},
remediation: 'Log all security-relevant operations for audit trail',
references: ['DollhouseMCP Security Guidelines']
}
];
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VjdXJpdHlSdWxlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zZWN1cml0eS9hdWRpdC9ydWxlcy9TZWN1cml0eVJ1bGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQUlILE1BQU0sT0FBTyxhQUFhO0lBQ3hCOztPQUVHO0lBQ0gsYUFBYTtRQUNYLE9BQU87WUFDTDtnQkFDRSxFQUFFLEVBQUUsZUFBZTtnQkFDbkIsSUFBSSxFQUFFLG1CQUFtQjtnQkFDekIsV0FBVyxFQUFFLGdEQUFnRDtnQkFDN0QsUUFBUSxFQUFFLFVBQVU7Z0JBQ3BCLFFBQVEsRUFBRSxNQUFNO2dCQUNoQixPQUFPLEVBQUUsZ0dBQWdHO2dCQUN6RyxXQUFXLEVBQUUsMkZBQTJGO2dCQUN4RyxVQUFVLEVBQUUsQ0FBQyx5REFBeUQsQ0FBQztnQkFDdkUsSUFBSSxFQUFFLENBQUMsaUJBQWlCLENBQUM7YUFDMUI7WUFDRDtnQkFDRSxFQUFFLEVBQUUsZUFBZTtnQkFDbkIsSUFBSSxFQUFFLGVBQWU7Z0JBQ3JCLFdBQVcsRUFBRSx1Q0FBdUM7Z0JBQ3BELFFBQVEsRUFBRSxVQUFVO2dCQUNwQixRQUFRLEVBQUUsTUFBTTtnQkFDaEIsT0FBTyxFQUFFLCtGQUErRjtnQkFDeEcsV0FBVyxFQUFFLGtEQUFrRDtnQkFDL0QsVUFBVSxFQUFFLENBQUMsNkNBQTZDLENBQUM7YUFDNUQ7WUFDRDtnQkFDRSxFQUFFLEVBQUUsZUFBZTtnQkFDbkIsSUFBSSxFQUFFLG1CQUFtQjtnQkFDekIsV0FBVyxFQUFFLDJDQUEyQztnQkFDeEQsUUFBUSxFQUFFLFVBQVU7Z0JBQ3BCLFFBQVEsRUFBRSxNQUFNO2dCQUNoQixPQUFPLEVBQUUsK0VBQStFO2dCQUN4RixXQUFXLEVBQUUsc0VBQXNFO2dCQUNuRixVQUFVLEVBQUUsQ0FBQyw2Q0FBNkMsQ0FBQzthQUM1RDtZQUNEO2dCQUNFLEVBQUUsRUFBRSxlQUFlO2dCQUNuQixJQUFJLEVB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LEdBQUcsQ0FBQyxDQUFDLENBQVMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxlQUFlLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7d0JBQ3BGLENBQUM7d0JBQ0QsT0FBTyxFQUFFLENBQUMsQ0FBQyxvREFBb0Q7b0JBQ2pFLENBQUMsQ0FBQyxDQUFDO29CQUVMLGlGQUFpRjtvQkFDakYscUVBQXFFO29CQUNyRSxNQUFNLGVBQWUsR0FBRyxzRUFBc0UsQ0FBQztvQkFDL0YsTUFBTSxVQUFVLEdBQUcsd0NBQXdDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO29CQUUxRSxJQUFJLGVBQWUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQzt3QkFDbEQsUUFBUSxDQUFDLElBQUksQ0FBQzs0QkFDWixNQUFNLEVBQUUsY0FBYzs0QkFDdEIsUUFBUSxFQUFFLEtBQWM7NEJBQ3hCLE9BQU8sRUFBRSwwQ0FBMEM7NEJBQ25ELFdBQVcsRUFBRSx3REFBd0Q7NEJBQ3JFLFVBQVUsRUFBRSxRQUFpQjt5QkFDOUIsQ0FBQyxDQUFDO29CQUNMLENBQUM7b0JBRUQsT0FBTyxRQUFRLENBQUM7Z0JBQ2xCLENBQUM7Z0JBQ0QsV0FBVyxFQUFFLHNEQUFzRDtnQkFDbkUsVUFBVSxFQUFFLENBQUMsa0NBQWtDLENBQUM7YUFDakQ7U0FDRixDQUFDO0lBQ0osQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBTZWN1cml0eSBSdWxlcyAtIERlZmluZXMgc2VjdXJpdHkgcGF0dGVybnMgYW5kIGNoZWNrc1xuICogQmFzZWQgb24gT1dBU1AgVG9wIDEwLCBDV0UgVG9wIDI1LCBhbmQgRG9sbGhvdXNlTUNQLXNwZWNpZmljIHNlY3VyaXR5IHJlcXVpcmVtZW50c1xuICovXG5cbmltcG9ydCB0eXBlIHsgU2VjdXJpdHlSdWxlLCBTZWN1cml0eUZpbmRpbmcgfSBmcm9tICcuLi90eXBlcy5qcyc7XG5cbmV4cG9ydCBjbGFzcyBTZWN1cml0eVJ1bGVzIHtcbiAgLyoqXG4gICAqIE9XQVNQIFRvcCAxMCBzZWN1cml0eSBydWxlc1xuICAgKi9cbiAgZ2V0T1dBU1BSdWxlcygpOiBTZWN1cml0eVJ1bGVbXSB7XG4gICAgcmV0dXJuIFtcbiAgICAgIHtcbiAgICAgICAgaWQ6ICdPV0FTUC1BMDEtMDAxJyxcbiAgICAgICAgbmFtZTogJ0hhcmRjb2RlZCBTZWNyZXRzJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3RlbnRpYWwgaGFyZGNvZGVkIHNlY3JldCBvciBBUEkga2V5IGRldGVjdGVkJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdjcml0aWNhbCcsXG4gICAgICAgIGNhdGVnb3J5OiAnY29kZScsXG4gICAgICAgIHBhdHRlcm46IC8oPzphcGlbXy1dP2tleXxzZWNyZXR8cGFzc3dvcmR8dG9rZW58cHJpdmF0ZVtfLV0/a2V5KVxccypbOj1dXFxzKltcIiddW2EtekEtWjAtOSsvPV8tXXsxMCx9W1wiJ10vZ2ksXG4gICAgICAgIHJlbWVkaWF0aW9uOiAnVXNlIGVudmlyb25tZW50IHZhcmlhYmxlcyBvciBzZWN1cmUga2V5IG1hbmFnZW1lbnQgc2VydmljZXMgaW5zdGVhZCBvZiBoYXJkY29kaW5nIHNlY3JldHMnLFxuICAgICAgICByZWZlcmVuY2VzOiBbJ2h0dHBzOi8vb3dhc3Aub3JnL1RvcDEwL0EwMV8yMDIxLUJyb2tlbl9BY2Nlc3NfQ29udHJvbC8nXSxcbiAgICAgICAgdGFnczogWydoaWdoLWNvbmZpZGVuY2UnXVxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgaWQ6ICdPV0FTUC1BMDMtMDAxJyxcbiAgICAgICAgbmFtZTogJ1NRTCBJbmplY3Rpb24nLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1BvdGVudGlhbCBTUUwgaW5qZWN0aW9uIHZ1bG5lcmFiaWxpdHknLFxuICAgICAgICBzZXZlcml0eTogJ2NyaXRpY2FsJyxcbiAgICAgICAgY2F0ZWdvcnk6ICdjb2RlJyxcbiAgICAgICAgcGF0dGVybjogLyg/OnF1ZXJ5fGV4ZWN1dGUpXFxzKlxcKFxccypbJ1wiYF0uKlxcJFxce1tefV0rXFx9LipbJ1wiYF18WydcImBdLipcXCtcXHMqW2EtekEtWl9dXFx3KlxccypcXCsuKlsnXCJgXVxccypcXCkvZyxcbiAgICAgICAgcmVtZWRpYXRpb246ICdVc2UgcGFyYW1ldGVyaXplZCBxdWVyaWVzIG9yIHByZXBhcmVkIHN0YXRlbWVudHMnLFxuICAgICAgICByZWZlcmVuY2VzOiBbJ2h0dHBzOi8vb3dhc3Aub3JnL1RvcDEwL0EwM18yMDIxLUluamVjdGlvbi8nXVxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgaWQ6ICdPV0FTUC1BMDMtMDAyJyxcbiAgICAgICAgbmFtZTogJ0NvbW1hbmQgSW5qZWN0aW9uJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3RlbnRpYWwgY29tbWFuZCBpbmplY3Rpb24gdnVsbmVyYWJpbGl0eScsXG4gICAgICAgIHNldmVyaXR5OiAnY3JpdGljYWwnLFxuICAgICAgICBjYXRlZ29yeTogJ2NvZGUnLFxuICAgICAgICBwYXR0ZXJuOiAvKD86ZXhlY3xzcGF3bnxleGVjU3luY3xzcGF3blN5bmMpXFxzKlxcKFteKV0qKD86XFwkXFx7W159XStcXH18XFwrXFxzKlthLXpBLVpfXVxcdyopL2csXG4gICAgICAgIHJlbWVkaWF0aW9uOiAnVmFsaWRhdGUgYW5kIHNhbml0aXplIGFsbCB1c2VyIGlucHV0IGJlZm9yZSB1c2luZyBpbiBzeXN0ZW0gY29tbWFuZHMnLFxuICAgICAgICByZWZlcmVuY2VzOiBbJ2h0dHBzOi8vb3dhc3Aub3JnL1RvcDEwL0EwM18yMDIxLUluamVjdGlvbi8nXVxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgaWQ6ICdPV0FTUC1BMDMtMDAzJyxcbiAgICAgICAgbmFtZTogJ1BhdGggVHJhdmVyc2FsJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3RlbnRpYWwgcGF0aCB0cmF2ZXJzYWwgdnVsbmVyYWJpbGl0eScsXG4gICAgICAgIHNldmVyaXR5OiAnaGlnaCcsXG4gICAgICAgIGNhdGVnb3J5OiAnY29kZScsXG4gICAgICAgIHBhdHRlcm46IC8oPzpyZWFkRmlsZXx3cml0ZUZpbGV8cmVhZGRpcnxta2RpcnxybXx1bmxpbmspW14oXSpcXChbXildKig/OlxcLlxcLlsvXFxcXF0uKlxcK3xcXCsuKlxcLlxcLlsvXFxcXF0pL2csXG4gICAgICAgIHJlbWVkaWF0aW9uOiAnVmFsaWRhdGUgYW5kIHNhbml0aXplIGZpbGUgcGF0aHMsIHVzZSBwYXRoLnJlc29sdmUoKSBhbmQgY2hlY2sgYWdhaW5zdCBhbGxvd2VkIGRpcmVjdG9yaWVzJyxcbiAgICAgICAgcmVmZXJlbmNlczogWydodHRwczovL293YXNwLm9yZy9Ub3AxMC9BMDNfMjAyMS1JbmplY3Rpb24vJ11cbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGlkOiAnT1dBU1AtQTAzLTAwNCcsXG4gICAgICAgIG5hbWU6ICdYU1MgLSBEaXJlY3QgSFRNTCBJbmplY3Rpb24nLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1BvdGVudGlhbCBYU1MgdnVsbmVyYWJpbGl0eSB0aHJvdWdoIGRpcmVjdCBIVE1MIGluamVjdGlvbicsXG4gICAgICAgIHNldmVyaXR5OiAnaGlnaCcsXG4gICAgICAgIGNhdGVnb3J5OiAnY29kZScsXG4gICAgICAgIHBhdHRlcm46IC9pbm5lckhUTUxcXHMqPVxccypbXidcImBdKlxcJFxce3xkYW5nZXJvdXNseVNldElubmVySFRNTC9nLFxuICAgICAgICByZW1lZGlhdGlvbjogJ1VzZSB0ZXh0Q29udGVudCBvciBwcm9wZXIgSFRNTCBlc2NhcGluZyBmdW5jdGlvbnMnLFxuICAgICAgICByZWZlcmVuY2VzOiBbJ2h0dHBzOi8vb3dhc3Aub3JnL1RvcDEwL0EwM18yMDIxLUluamVjdGlvbi8nXVxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgaWQ6ICdPV0FTUC1BMDUtMDAxJyxcbiAgICAgICAgbmFtZTogJ0luc2VjdXJlIENvbmZpZ3VyYXRpb24nLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1NlY3VyaXR5LXNlbnNpdGl2ZSBjb25maWd1cmF0aW9uIGRldGVjdGVkJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdtZWRpdW0nLFxuICAgICAgICBjYXRlZ29yeTogJ2NvZGUnLFxuICAgICAgICBwYXR0ZXJuOiAvKD86Tk9ERV9UTFNfUkVKRUNUX1VOQVVUSE9SSVpFRHxzdHJpY3RTU0x8cmVqZWN0VW5hdXRob3JpemVkKVxccypbOj1dXFxzKig/OmZhbHNlfDB8W1wiJ11mYWxzZVtcIiddfFtcIiddMFtcIiddKS9naSxcbiAgICAgICAgcmVtZWRpYXRpb246ICdFbmFibGUgU1NML1RMUyBjZXJ0aWZpY2F0ZSB2YWxpZGF0aW9uIGluIHByb2R1Y3Rpb24nLFxuICAgICAgICByZWZlcmVuY2VzOiBbJ2h0dHBzOi8vb3dhc3Aub3JnL1RvcDEwL0EwNV8yMDIxLVNlY3VyaXR5X01pc2NvbmZpZ3VyYXRpb24vJ11cbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGlkOiAnT1dBU1AtQTA3LTAwMScsXG4gICAgICAgIG5hbWU6ICdXZWFrIEF1dGhlbnRpY2F0aW9uJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3RlbnRpYWwgd2VhayBhdXRoZW50aWNhdGlvbiBtZWNoYW5pc20nLFxuICAgICAgICBzZXZlcml0eTogJ2hpZ2gnLFxuICAgICAgICBjYXRlZ29yeTogJ2NvZGUnLFxuICAgICAgICBwYXR0ZXJuOiAvKD86bWQ1fHNoYTEpXFxzKlxcKC9naSxcbiAgICAgICAgcmVtZWRpYXRpb246ICdVc2Ugc3Ryb25nIGhhc2hpbmcgYWxnb3JpdGhtcyBsaWtlIGJjcnlwdCwgc2NyeXB0LCBvciBBcmdvbjIgZm9yIHBhc3N3b3JkcycsXG4gICAgICAgIHJlZmVyZW5jZXM6IFsnaHR0cHM6Ly9vd2FzcC5vcmcvVG9wMTAvQTA3XzIwMjEtSWRlbnRpZmljYXRpb25fYW5kX0F1dGhlbnRpY2F0aW9uX0ZhaWx1cmVzLyddXG4gICAgICB9XG4gICAgXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDV0UgVG9wIDI1IHNlY3VyaXR5IHJ1bGVzXG4gICAqL1xuICBnZXRDV0VSdWxlcygpOiBTZWN1cml0eVJ1bGVbXSB7XG4gICAgcmV0dXJuIFtcbiAgICAgIHtcbiAgICAgICAgaWQ6ICdDV0UtNzktMDAxJyxcbiAgICAgICAgbmFtZTogJ1JlZmxlY3RlZCBYU1MnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1VzZXIgaW5wdXQgcmVmbGVjdGVkIHdpdGhvdXQgZW5jb2RpbmcnLFxuICAgICAgICBzZXZlcml0eTogJ2hpZ2gnLFxuICAgICAgICBjYXRlZ29yeTogJ2NvZGUnLFxuICAgICAgICBwYXR0ZXJuOiAvcmVzXFwuKD86c2VuZHx3cml0ZXxlbmQpXFxzKlxcKFteKV0qKD86cmVxXFwuKD86cXVlcnl8cGFyYW1zfGJvZHkpfHJlcXVlc3RcXC4pL2csXG4gICAgICAgIHJlbWVkaWF0aW9uOiAnRW5jb2RlIGFsbCB1c2VyIGlucHV0IGJlZm9yZSByZWZsZWN0aW5nIGluIHJlc3BvbnNlcycsXG4gICAgICAgIHJlZmVyZW5jZXM6IFsnaHR0cHM6Ly9jd2UubWl0cmUub3JnL2RhdGEvZGVmaW5pdGlvbnMvNzkuaHRtbCddXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBpZDogJ0NXRS04OS0wMDEnLFxuICAgICAgICBuYW1lOiAnU1FMIFN0cmluZyBDb25jYXRlbmF0aW9uJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdTUUwgcXVlcnkgYnVpbHQgdXNpbmcgc3RyaW5nIGNvbmNhdGVuYXRpb24nLFxuICAgICAgICBzZXZlcml0eTogJ2NyaXRpY2FsJyxcbiAgICAgICAgY2F0ZWdvcnk6ICdjb2RlJyxcbiAgICAgICAgcGF0dGVybjogL1tcIidgXS4qKD86U0VMRUNUfElOU0VSVHxVUERBVEV8REVMRVRFfERST1B8Q1JFQVRFfEFMVEVSKS4qW1wiJ2BdXFxzKlxcK1xccypcXHcrL2dpLFxuICAgICAgICByZW1lZGlhdGlvbjogJ1VzZSBwYXJhbWV0ZXJpemVkIHF1ZXJpZXMgaW5zdGVhZCBvZiBzdHJpbmcgY29uY2F0ZW5hdGlvbicsXG4gICAgICAgIHJlZmVyZW5jZXM6IFsnaHR0cHM6Ly9jd2UubWl0cmUub3JnL2RhdGEvZGVmaW5pdGlvbnMvODkuaHRtbCddXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBpZDogJ0NXRS0yMi0wMDEnLFxuICAgICAgICBuYW1lOiAnUGF0aCBNYW5pcHVsYXRpb24nLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ0ZpbGUgcGF0aCBjb25zdHJ1Y3RlZCBmcm9tIHVzZXIgaW5wdXQnLFxuICAgICAgICBzZXZlcml0eTogJ2hpZ2gnLFxuICAgICAgICBjYXRlZ29yeTogJ2NvZGUnLFxuICAgICAgICBwYXR0ZXJuOiAvcGF0aFxcLmpvaW5cXHMqXFwoW14pXSooPzpyZXFcXC58cmVxdWVzdFxcLnxwYXJhbXN8cXVlcnl8Ym9keSkvZyxcbiAgICAgICAgcmVtZWRpYXRpb246ICdWYWxpZGF0ZSBwYXRocyBhZ2FpbnN0IGEgd2hpdGVsaXN0IGFuZCB1c2UgcGF0aC5yZXNvbHZlKCknLFxuICAgICAgICByZWZlcmVuY2VzOiBbJ2h0dHBzOi8vY3dlLm1pdHJlLm9yZy9kYXRhL2RlZmluaXRpb25zLzIyLmh0bWwnXVxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgaWQ6ICdDV0UtNzk4LTAwMScsXG4gICAgICAgIG5hbWU6ICdIYXJkY29kZWQgQ3JlZGVudGlhbHMnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ0NyZWRlbnRpYWxzIGhhcmRjb2RlZCBpbiBzb3VyY2UnLFxuICAgICAgICBzZXZlcml0eTogJ2NyaXRpY2FsJyxcbiAgICAgICAgY2F0ZWdvcnk6ICdjb2RlJyxcbiAgICAgICAgcGF0dGVybjogLyg/OnVzZXJuYW1lfHVzZXJ8bG9naW4pXFxzKls6PV1cXHMqW1wiJ11bXlwiJ10rW1wiJ10uKig/OnBhc3N3b3JkfHBhc3N8cHdkKVxccypbOj1dXFxzKltcIiddW15cIiddK1tcIiddL2dpLFxuICAgICAgICByZW1lZGlhdGlvbjogJ1N0b3JlIGNyZWRlbnRpYWxzIGluIGVudmlyb25tZW50IHZhcmlhYmxlcyBvciBzZWN1cmUgdmF1bHRzJyxcbiAgICAgICAgcmVmZXJlbmNlczogWydodHRwczovL2N3ZS5taXRyZS5vcmcvZGF0YS9kZWZpbml0aW9ucy83OTguaHRtbCddXG4gICAgICB9XG4gICAgXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEb2xsaG91c2VNQ1Atc3BlY2lmaWMgc2VjdXJpdHkgcnVsZXNcbiAgICovXG4gIGdldERvbGxob3VzZU1DUFJ1bGVzKCk6IFNlY3VyaXR5UnVsZVtdIHtcbiAgICByZXR1cm4gW1xuICAgICAge1xuICAgICAgICBpZDogJ0RNQ1AtU0VDLTAwMScsXG4gICAgICAgIG5hbWU6ICdVbnNhZmUgUGVyc29uYSBMb2FkaW5nJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdQZXJzb25hIGxvYWRlZCB3aXRob3V0IHZhbGlkYXRpb24nLFxuICAgICAgICBzZXZlcml0eTogJ2hpZ2gnLFxuICAgICAgICBjYXRlZ29yeTogJ2N1c3RvbScsXG4gICAgICAgIHBhdHRlcm46IC9sb2FkUGVyc29uYVxccypcXChbXildKlxcKVxccyooPyEuKnZhbGlkYXRlKS9nLFxuICAgICAgICByZW1lZGlhdGlvbjogJ0Fsd2F5cyB2YWxpZGF0ZSBwZXJzb25hcyBiZWZvcmUgbG9hZGluZyB1c2luZyBQZXJzb25hVmFsaWRhdG9yJyxcbiAgICAgICAgcmVmZXJlbmNlczogWydEb2xsaG91c2VNQ1AgU2VjdXJpdHkgR3VpZGVsaW5lcyddXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBpZDogJ0RNQ1AtU0VDLTAwMicsXG4gICAgICAgIG5hbWU6ICdUb2tlbiBWYWxpZGF0aW9uIEJ5cGFzcycsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVG9rZW4gdXNlZCB3aXRob3V0IHZhbGlkYXRpb24nLFxuICAgICAgICBzZXZlcml0eTogJ2NyaXRpY2FsJyxcbiAgICAgICAgY2F0ZWdvcnk6ICdjdXN0b20nLFxuICAgICAgICBwYXR0ZXJuOiAvKD86Z2V0VG9rZW58dXNlVG9rZW58dG9rZW5cXC51c2UpXFxzKlxcKFteKV0qXFwpKD8hLiooPzp2YWxpZGF0ZXx2ZXJpZnl8Y2hlY2spKS9naSxcbiAgICAgICAgcmVtZWRpYXRpb246ICdBbHdheXMgdmFsaWRhdGUgdG9rZW5zIHVzaW5nIFRva2VuTWFuYWdlci52YWxpZGF0ZVRva2VuKCknLFxuICAgICAgICByZWZlcmVuY2VzOiBbJ0RvbGxob3VzZU1DUCBTZWN1cml0eSBHdWlkZWxpbmVzJ11cbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGlkOiAnRE1DUC1TRUMtMDAzJyxcbiAgICAgICAgbmFtZTogJ1JhdGUgTGltaXRpbmcgTWlzc2luZycsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnQVBJIGVuZHBvaW50IHdpdGhvdXQgcmF0ZSBsaW1pdGluZycsXG4gICAgICAgIHNldmVyaXR5OiAnbWVkaXVtJyxcbiAgICAgICAgY2F0ZWdvcnk6ICdjdXN0b20nLFxuICAgICAgICBjaGVjazogKGNvbnRlbnQsIF9jb250ZXh0KSA9PiB7XG4gICAgICAgICAgY29uc3QgZmluZGluZ3M6IFNlY3VyaXR5RmluZGluZ1tdID0gW107XG4gICAgICAgICAgLy8gQ2hlY2sgZm9yIE1DUCB0b29sIGhhbmRsZXJzIHdpdGhvdXQgcmF0ZSBsaW1pdGluZ1xuICAgICAgICAgIGNvbnN0IHRvb2xQYXR0ZXJuID0gL25hbWU6XFxzKltcIiddKFteXCInXSspW1wiJ10uKmhhbmRsZTovZ3M7XG4gICAgICAgICAgY29uc3QgaGFzUmF0ZUxpbWl0ID0gL3JhdGVMaW1pdGVyfGNoZWNrUmF0ZUxpbWl0fHRva2VuQnVja2V0L2kudGVzdChjb250ZW50KTtcbiAgICAgICAgICBcbiAgICAgICAgICBpZiAodG9vbFBhdHRlcm4udGVzdChjb250ZW50KSAmJiAhaGFzUmF0ZUxpbWl0KSB7XG4gICAgICAgICAgICBmaW5kaW5ncy5wdXNoKHtcbiAgICAgICAgICAgICAgcnVsZUlkOiAnRE1DUC1TRUMtMDAzJyxcbiAgICAgICAgICAgICAgc2V2ZXJpdHk6ICdtZWRpdW0nIGFzIGNvbnN0LFxuICAgICAgICAgICAgICBtZXNzYWdlOiAnTUNQIHRvb2wgaGFuZGxlciB3aXRob3V0IHJhdGUgbGltaXRpbmcnLFxuICAgICAgICAgICAgICByZW1lZGlhdGlvbjogJ0FkZCByYXRlIGxpbWl0aW5nIHRvIHByZXZlbnQgYWJ1c2UnLFxuICAgICAgICAgICAgICBjb25maWRlbmNlOiAnaGlnaCcgYXMgY29uc3RcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgICBcbiAgICAgICAgICByZXR1cm4gZmluZGluZ3M7XG4gICAgICAgIH0sXG4gICAgICAgIHJlbWVkaWF0aW9uOiAnSW1wbGVtZW50IHJhdGUgbGltaXRpbmcgZm9yIGFsbCBNQ1AgdG9vbHMnLFxuICAgICAgICByZWZlcmVuY2VzOiBbJ0lzc3VlICMxNzQgLSBSYXRlIExpbWl0aW5nIEltcGxlbWVudGF0aW9uJ11cbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGlkOiAnRE1DUC1TRUMtMDA0JyxcbiAgICAgICAgbmFtZTogJ1VuaWNvZGUgVmFsaWRhdGlvbiBNaXNzaW5nJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdVc2VyIGlucHV0IHByb2Nlc3NlZCB3aXRob3V0IFVuaWNvZGUgbm9ybWFsaXphdGlvbicsXG4gICAgICAgIHNldmVyaXR5OiAnbWVkaXVtJyxcbiAgICAgICAgY2F0ZWdvcnk6ICdjdXN0b20nLFxuICAgICAgICBjaGVjazogKGNvbnRlbnQsIF9jb250ZXh0KSA9PiB7XG4gICAgICAgICAgY29uc3QgZmluZGluZ3M6IFNlY3VyaXR5RmluZGluZ1tdID0gW107XG4gICAgICAgICAgLy8gQ2hlY2sgZm9yIHVzZXIgaW5wdXQgcHJvY2Vzc2luZyB3aXRob3V0IFVuaWNvZGUgdmFsaWRhdGlvblxuICAgICAgICAgIGNvbnN0IGlucHV0UGF0dGVybiA9IC8oPzpyZXFcXC58cmVxdWVzdFxcLnxwYXJhbXN8cXVlcnl8Ym9keXxjb250ZW50KS87XG4gICAgICAgICAgY29uc3QgaGFzVW5pY29kZUNoZWNrID0gL1VuaWNvZGVWYWxpZGF0b3J8bm9ybWFsaXplVW5pY29kZS9pLnRlc3QoY29udGVudCk7XG4gICAgICAgICAgXG4gICAgICAgICAgaWYgKGlucHV0UGF0dGVybi50ZXN0KGNvbnRlbnQpICYmICFoYXNVbmljb2RlQ2hlY2spIHtcbiAgICAgICAgICAgIGZpbmRpbmdzLnB1c2goe1xuICAgICAgICAgICAgICBydWxlSWQ6ICdETUNQLVNFQy0wMDQnLFxuICAgICAgICAgICAgICBzZXZlcml0eTogJ21lZGl1bScgYXMgY29uc3QsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6ICdVc2VyIGlucHV0IHByb2Nlc3NlZCB3aXRob3V0IFVuaWNvZGUgbm9ybWFsaXphdGlvbicsXG4gICAgICAgICAgICAgIHJlbWVkaWF0aW9uOiAnVXNlIFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKCkgb24gYWxsIHVzZXIgaW5wdXQnLFxuICAgICAgICAgICAgICBjb25maWRlbmNlOiAnbWVkaXVtJyBhcyBjb25zdFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIFxuICAgICAgICAgIHJldHVybiBmaW5kaW5ncztcbiAgICAgICAgfSxcbiAgICAgICAgcmVtZWRpYXRpb246ICdBcHBseSBVbmljb2RlIG5vcm1hbGl6YXRpb24gdG8gcHJldmVudCBieXBhc3MgYXR0YWNrcycsXG4gICAgICAgIHJlZmVyZW5jZXM6IFsnSXNzdWUgIzE2MiAtIFVuaWNvZGUgTm9ybWFsaXphdGlvbiddXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBpZDogJ0RNQ1AtU0VDLTAwNScsXG4gICAgICAgIG5hbWU6ICdVbnZhbGlkYXRlZCBZQU1MIENvbnRlbnQnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1lBTUwgY29udGVudCBwYXJzZWQgd2l0aG91dCBzZWN1cml0eSB2YWxpZGF0aW9uJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdoaWdoJyxcbiAgICAgICAgY2F0ZWdvcnk6ICdjdXN0b20nLFxuICAgICAgICBwYXR0ZXJuOiAveWFtbFxcLmxvYWRcXHMqXFwofHBhcnNlXFxzKlxcKFteKV0qXFwueWE/bWwvZ2ksXG4gICAgICAgIHJlbWVkaWF0aW9uOiAnVXNlIFNlY3VyZVlhbWxQYXJzZXIgZm9yIGFsbCBZQU1MIHBhcnNpbmcnLFxuICAgICAgICByZWZlcmVuY2VzOiBbJ0RvbGxob3VzZU1DUCBTZWN1cml0eSBHdWlkZWxpbmVzJ11cbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGlkOiAnRE1DUC1TRUMtMDA2JyxcbiAgICAgICAgbmFtZTogJ1NlY3VyaXR5IEV2ZW50IE5vdCBMb2dnZWQnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1NlY3VyaXR5LXJlbGV2YW50IG9wZXJhdGlvbiB3aXRob3V0IGxvZ2dpbmcnLFxuICAgICAgICBzZXZlcml0eTogJ2xvdycsXG4gICAgICAgIGNhdGVnb3J5OiAnY3VzdG9tJyxcbiAgICAgICAgY2hlY2s6IChjb250ZW50LCBfY29udGV4dCkgPT4ge1xuICAgICAgICAgIGNvbnN0IGZpbmRpbmdzOiBTZWN1cml0eUZpbmRpbmdbXSA9IFtdO1xuXG4gICAgICAgICAgLy8gRklYOiBPbmx5IGZsYWcgZmlsZXMgd2l0aCBhY3R1YWwgZXhlY3V0YWJsZSBjb2RlXG4gICAgICAgICAgLy8gU2tpcCBmaWxlcyB0aGF0IGFyZSBwdXJlIHR5cGUgZGVmaW5pdGlvbnMgKGludGVyZmFjZXMsIHR5cGVzIG9ubHkpXG4gICAgICAgICAgY29uc3QgaGFzRXhlY3V0YWJsZUNvZGUgPVxuICAgICAgICAgICAgLyg/Ol58XFxuKVxccyooPzpleHBvcnRcXHMrKT8oPzpmdW5jdGlvbnxjbGFzc3xjb25zdFxccytcXHcrXFxzKj1cXHMqKD86YXN5bmNcXHMrKT9cXCh8YXN5bmNcXHMrZnVuY3Rpb24pL20udGVzdChjb250ZW50KSB8fFxuICAgICAgICAgICAgLyg/Ol58XFxuKVxccyooPzpwdWJsaWN8cHJpdmF0ZXxwcm90ZWN0ZWR8YXN5bmMpXFxzK1xcdytcXHMqXFwoL20udGVzdChjb250ZW50KTtcblxuICAgICAgICAgIGlmICghaGFzRXhlY3V0YWJsZUNvZGUpIHtcbiAgICAgICAgICAgIHJldHVybiBmaW5kaW5nczsgLy8gU2tpcCBwdXJlIHR5cGUgZGVmaW5pdGlvbiBmaWxlc1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIFJlbW92ZSBjb21tZW50cyBhbmQgc3RyaW5ncyB0byBhdm9pZCBmYWxzZSBwb3NpdGl2ZXMgb24ga2V5d29yZHMgaW4gZG9jdW1lbnRhdGlvblxuICAgICAgICAgIC8vIEZJWDogUHJlc2VydmUgJHsuLi59IGV4cHJlc3Npb25zIGluIHRlbXBsYXRlIGxpdGVyYWxzIHRvIGF2b2lkIGZhbHNlIG5lZ2F0aXZlc1xuICAgICAgICAgIC8vIFdoZW4gc2Nhbm5pbmcgZm9yIHNlY3VyaXR5IGNhbGxzIGxpa2UgYXV0aGVudGljYXRlKGB1c2VyLSR7aWR9YCksIHdlIG11c3QgcHJlc2VydmVcbiAgICAgICAgICAvLyBib3RoIHRoZSBmdW5jdGlvbiBjYWxsIChhdXRoZW50aWNhdGUpIGFuZCB0aGUgZXhwcmVzc2lvbiBpbnNpZGUgJHt9IChpZCkuXG4gICAgICAgICAgLy8gT3RoZXJ3aXNlIHdlIGdldCBmYWxzZSBuZWdhdGl2ZXMgd2hlcmUgc2VjdXJpdHktc2Vuc2l0aXZlIGNhbGxzIGFyZSBtaXNzZWQuXG4gICAgICAgICAgY29uc3QgY29kZU9ubHkgPSBjb250ZW50XG4gICAgICAgICAgICAucmVwbGFjZSgvXFwvXFwvLiokL2dtLCAnJykgLy8gUmVtb3ZlIHNpbmdsZS1saW5lIGNvbW1lbnRzXG4gICAgICAgICAgICAucmVwbGFjZSgvXFwvXFwqW1xcc1xcU10qP1xcKlxcLy9nLCAnJykgLy8gUmVtb3ZlIG11bHRpLWxpbmUgY29tbWVudHNcbiAgICAgICAgICAgIC5yZXBsYWNlKC8nKD86W14nXFxcXF18XFxcXC4pKicvZywgJycpIC8vIFJlbW92ZSBzaW5nbGUtcXVvdGVkIHN0cmluZ3NcbiAgICAgICAgICAgIC5yZXBsYWNlKC9cIig/OlteXCJcXFxcXXxcXFxcLikqXCIvZywgJycpIC8vIFJlbW92ZSBkb3VibGUtcXVvdGVkIHN0cmluZ3NcbiAgICAgICAgICAgIC8vIEZvciB0ZW1wbGF0ZSBsaXRlcmFsczogcmVtb3ZlIHN0cmluZyBjb250ZW50IGJ1dCBwcmVzZXJ2ZSAkey4uLn0gZXhwcmVzc2lvbnNcbiAgICAgICAgICAgIC5yZXBsYWNlKC9gKFteYF0qKWAvZywgKF9tYXRjaCwgaW5uZXI6IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgICAvLyBFeHRyYWN0ICR7Li4ufSBleHByZXNzaW9ucyBhbmQga2VlcCB0aGVpciBjb250ZW50XG4gICAgICAgICAgICAgIGNvbnN0IGV4cHJlc3Npb25zID0gaW5uZXIubWF0Y2goL1xcJFxceyhbXn1dKylcXH0vZyk7XG4gICAgICAgICAgICAgIGlmIChleHByZXNzaW9ucykge1xuICAgICAgICAgICAgICAgIHJldHVybiBleHByZXNzaW9ucy5tYXAoKGU6IHN0cmluZykgPT4gZS5yZXBsYWNlKC9cXCRcXHsoW159XSspXFx9LywgJyQxJykpLmpvaW4oJyAnKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICByZXR1cm4gJyc7IC8vIE5vIGV4cHJlc3Npb25zLCByZW1vdmUgdGhlIHdob2xlIHRlbXBsYXRlIGxpdGVyYWxcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgLy8gQ2hlY2sgZm9yIGFjdHVhbCBzZWN1cml0eSBvcGVyYXRpb24gZnVuY3Rpb24gQ0FMTFMgKG5vdCBqdXN0IGtleXdvcmRzIGluIHRleHQpXG4gICAgICAgICAgLy8gTWF0Y2g6IGF1dGhlbnRpY2F0ZSguLi4pLCB2YWxpZGF0ZSguLi4pLCBldGMuIC0gbm90IGp1c3QgdGhlIHdvcmRzXG4gICAgICAgICAgY29uc3Qgc2VjdXJpdHlPcENhbGxzID0gL1xcYig/OmF1dGhlbnRpY2F0ZXxhdXRob3JpemV8dmFsaWRhdGV8c2FuaXRpemV8ZW5jcnlwdHxkZWNyeXB0KVxccypcXCgvaTtcbiAgICAgICAgICBjb25zdCBoYXNMb2dnaW5nID0gL1NlY3VyaXR5TW9uaXRvclxcLmxvZ3xsb2dTZWN1cml0eUV2ZW50L2kudGVzdChjb250ZW50KTtcblxuICAgICAgICAgIGlmIChzZWN1cml0eU9wQ2FsbHMudGVzdChjb2RlT25seSkgJiYgIWhhc0xvZ2dpbmcpIHtcbiAgICAgICAgICAgIGZpbmRpbmdzLnB1c2goe1xuICAgICAgICAgICAgICBydWxlSWQ6ICdETUNQLVNFQy0wMDYnLFxuICAgICAgICAgICAgICBzZXZlcml0eTogJ2xvdycgYXMgY29uc3QsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6ICdTZWN1cml0eSBvcGVyYXRpb24gd2l0aG91dCBhdWRpdCBsb2dnaW5nJyxcbiAgICAgICAgICAgICAgcmVtZWRpYXRpb246ICdBZGQgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoKSBmb3IgYXVkaXQgdHJhaWwnLFxuICAgICAgICAgICAgICBjb25maWRlbmNlOiAnbWVkaXVtJyBhcyBjb25zdFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIGZpbmRpbmdzO1xuICAgICAgICB9LFxuICAgICAgICByZW1lZGlhdGlvbjogJ0xvZyBhbGwgc2VjdXJpdHktcmVsZXZhbnQgb3BlcmF0aW9ucyBmb3IgYXVkaXQgdHJhaWwnLFxuICAgICAgICByZWZlcmVuY2VzOiBbJ0RvbGxob3VzZU1DUCBTZWN1cml0eSBHdWlkZWxpbmVzJ11cbiAgICAgIH1cbiAgICBdO1xuICB9XG59Il19