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.

301 lines 47.1 kB
/** * Content Validator for DollhouseMCP * * Protects against prompt injection attacks in collection personas * by detecting and sanitizing malicious content patterns. * * Security: SEC-001 - Critical vulnerability protection */ import { SecurityError } from './errors.js'; import { SecurityMonitor } from './securityMonitor.js'; import { RegexValidator } from './regexValidator.js'; import { SECURITY_LIMITS } from './constants.js'; import { UnicodeValidator } from './validators/unicodeValidator.js'; export class ContentValidator { /** * Pattern-based detection system for prompt injection attacks. * * This approach was chosen over AI-based detection because: * 1. Pattern matching cannot be socially engineered or confused * 2. Deterministic results ensure consistent security * 3. No additional API calls or latency * 4. Can't be bypassed by clever prompt engineering * * The patterns below represent known attack vectors from security research * and real-world exploit attempts against AI systems. */ // Prompt injection patterns that could compromise AI assistants static INJECTION_PATTERNS = [ // System prompt override attempts { pattern: /\[SYSTEM:\s*.*?\]/gi, severity: 'critical', description: 'System prompt override' }, { pattern: /\[ADMIN:\s*.*?\]/gi, severity: 'critical', description: 'Admin prompt override' }, { pattern: /\[ASSISTANT:\s*.*?\]/gi, severity: 'critical', description: 'Assistant prompt override' }, { pattern: /\[USER:\s*.*?\]/gi, severity: 'high', description: 'User prompt override' }, // Instruction manipulation { pattern: /ignore\s+(all\s+)?previous\s+instructions/gi, severity: 'critical', description: 'Instruction override' }, { pattern: /ignore\s+(all\s+)?prior\s+instructions/gi, severity: 'critical', description: 'Instruction override' }, { pattern: /disregard\s+(all\s+)?previous\s+instructions/gi, severity: 'critical', description: 'Instruction override' }, { pattern: /forget\s+(all\s+)?previous\s+instructions/gi, severity: 'critical', description: 'Instruction override' }, { pattern: /you\s+are\s+now\s+(admin|root|system|sudo)/gi, severity: 'critical', description: 'Role elevation attempt' }, { pattern: /act\s+as\s+(admin|root|system|sudo)/gi, severity: 'critical', description: 'Role elevation attempt' }, // Data exfiltration attempts { pattern: /export\s+all\s+(files|data|personas|tokens|credentials)/gi, severity: 'critical', description: 'Data exfiltration' }, { pattern: /send\s+all\s+(files|data|personas|tokens|credentials)\s+to/gi, severity: 'critical', description: 'Data exfiltration' }, { pattern: /list\s+all\s+(files|tokens|credentials|secrets)/gi, severity: 'high', description: 'Information disclosure' }, { pattern: /show\s+me\s+all\s+(tokens|credentials|secrets|api\s+keys)/gi, severity: 'high', description: 'Credential disclosure' }, // Command execution patterns { pattern: /curl\s+[^\s]+\.(com|net|org|io|dev)/gi, severity: 'critical', description: 'External command execution' }, { pattern: /wget\s+[^\s]+\.(com|net|org|io|dev)/gi, severity: 'critical', description: 'External command execution' }, { pattern: /\$\([^)]+\)/g, severity: 'critical', description: 'Command substitution' }, { pattern: /`[^`]+`/g, severity: 'critical', description: 'Backtick command execution' }, { pattern: /eval\s*\(/gi, severity: 'critical', description: 'Code evaluation' }, { pattern: /exec\s*\(/gi, severity: 'critical', description: 'Code execution' }, { pattern: /os\.system\s*\(/gi, severity: 'critical', description: 'System command execution' }, { pattern: /subprocess\.(call|run|Popen)/gi, severity: 'critical', description: 'Subprocess execution' }, // Token/credential patterns { pattern: /GITHUB_TOKEN/gi, severity: 'high', description: 'Token reference' }, { pattern: /ghp_[a-zA-Z0-9]{36}/g, severity: 'critical', description: 'GitHub token exposure' }, { pattern: /gho_[a-zA-Z0-9]{36}/g, severity: 'critical', description: 'GitHub OAuth token exposure' }, // Path traversal in content { pattern: /\.\.\/\.\.\/\.\.\//g, severity: 'high', description: 'Path traversal attempt' }, { pattern: /\/etc\/passwd/gi, severity: 'high', description: 'Sensitive file access' }, { pattern: /\/\.ssh\//gi, severity: 'high', description: 'SSH key access attempt' }, ]; // Malicious YAML patterns static MALICIOUS_YAML_PATTERNS = [ // Language-specific deserialization attacks /!!python\/object/, /!!python\/module/, /!!python\/name/, /!!ruby\/object/, /!!ruby\/hash/, /!!ruby\/struct/, /!!ruby\/marshal/, /!!java/, /!!javax/, /!!com\.sun/, /!!perl\/hash/, /!!perl\/code/, /!!php\/object/, // Constructor/function injection /!!exec/, /!!eval/, /!!new/, /!!construct/, /!!apply/, /!!call/, /!!invoke/, // Code execution patterns - more specific to avoid false positives /subprocess\./, /os\.system/, /eval\s*\(/, /exec\s*\(/, /__import__\s*\(/, /require\s*\(/, /import\s+(?:os|sys|subprocess|eval|exec)/, /include\s+["'].*\.(?:php|sh|py|js|rb)["']/, // Command execution variants - more specific patterns /popen\s*\(/, /spawn\s*\(/, /system\s*\(/, /backtick\s*\(/, /shell_exec\s*\(/, /passthru\s*\(/, /proc_open\s*\(/, // Network operations - require suspicious context /socket\.connect/, // Detects socket connection attempts /urllib\.request/, // Python HTTP library usage /requests\.(?:get|post|put|delete)\s*\(/, // Detects HTTP requests with method calls /fetch\s*\(\s*["']https?:\/\//, // Detects fetch calls to external URLs /new\s+XMLHttpRequest/, // JavaScript AJAX object creation /\.(?:get|post|put|delete)\s*\(\s*["']https?:\/\//, // Method chaining with HTTP requests // File system operations - require suspicious context /(?:fs\.|file\.|)\s*open\s*\(\s*["'](?:\/etc\/|\/bin\/|\.\.\/)/, // File open with suspicious paths /file_get_contents\s*\(/, // PHP file reading function /file_put_contents\s*\(/, // PHP file writing function /fopen\s*\(\s*["'](?:\/etc\/|\/bin\/|\.\.\/)/, // File open with dangerous system paths /(?:fs\.)?\s*readFile\s*\(\s*["'](?:\/etc\/|\/bin\/|\.\.\/)/, // Node.js file read with path traversal /(?:fs\.)?\s*writeFile\s*\(\s*["'](?:\/(?:bin|etc|tmp)\/|\.\.\/)/, // Node.js file write to system dirs // Protocol handlers /file:\/\//, /data:\/\//, /expect:\/\//, /php:\/\//, /phar:\/\//, /zip:\/\//, /ssh2:\/\//, /ogg:\/\//, // YAML-specific dangerous features /&[a-zA-Z0-9_]+\s*!!/, // Anchor with tag combination /\*[a-zA-Z0-9_]+\s*!!/, // Alias with tag combination /!!merge/, /!!binary/, /!!timestamp/, // Unicode/encoding bypass attempts - prevent visual spoofing attacks /\\[uU]0*(?:22|27|60|3[cC])/, // Unicode escapes for quotes (") and brackets (<>) /[\u202A-\u202E\u2066-\u2069]/, // Direction override chars (RLO, LRO, isolates) /[\u200B-\u200F\u2028-\u202F]/, // Zero-width spaces, line/paragraph separators /[\uFEFF\uFFFE\uFFFF]/, // BOM, non-characters for payload hiding ]; /** * Validates and sanitizes persona content for security threats */ static validateAndSanitize(content) { // Length validation before pattern matching if (content.length > SECURITY_LIMITS.MAX_CONTENT_LENGTH) { throw new SecurityError(`Content exceeds maximum length of ${SECURITY_LIMITS.MAX_CONTENT_LENGTH} characters (${content.length} provided)`); } const detectedPatterns = []; let sanitized = content; let highestSeverity = 'low'; // Unicode normalization preprocessing to prevent bypass attacks const unicodeResult = UnicodeValidator.normalize(sanitized); sanitized = unicodeResult.normalizedContent; if (!unicodeResult.isValid && unicodeResult.detectedIssues) { detectedPatterns.push(...unicodeResult.detectedIssues.map(issue => `Unicode: ${issue}`)); if (unicodeResult.severity) { highestSeverity = unicodeResult.severity; } } // Check for injection patterns for (const { pattern, severity, description } of this.INJECTION_PATTERNS) { // These are trusted internal patterns, so we disable ReDoS rejection if (RegexValidator.validate(content, pattern, { maxLength: 50000, rejectDangerousPatterns: false, logEvents: false // Don't log our own security patterns as dangerous })) { detectedPatterns.push(description); // Update highest severity if (severity === 'critical' || (severity === 'high' && highestSeverity !== 'critical')) { highestSeverity = severity; } // Log security event SecurityMonitor.logSecurityEvent({ type: 'CONTENT_INJECTION_ATTEMPT', severity: severity.toUpperCase(), source: 'content_validation', details: `Detected pattern: ${description}`, }); // Sanitize by replacing with safe placeholder sanitized = sanitized.replace(pattern, '[CONTENT_BLOCKED]'); } } return { isValid: detectedPatterns.length === 0, sanitizedContent: sanitized, detectedPatterns, severity: highestSeverity }; } /** * Validates YAML frontmatter for malicious content */ static validateYamlContent(yamlContent) { // Length validation before pattern matching if (yamlContent.length > SECURITY_LIMITS.MAX_YAML_LENGTH) { SecurityMonitor.logSecurityEvent({ type: 'YAML_INJECTION_ATTEMPT', severity: 'HIGH', source: 'yaml_validation', details: `YAML content exceeds maximum length: ${yamlContent.length} > ${SECURITY_LIMITS.MAX_YAML_LENGTH}` }); return false; } // Unicode normalization preprocessing for YAML content const unicodeResult = UnicodeValidator.normalize(yamlContent); const normalizedYaml = unicodeResult.normalizedContent; if (!unicodeResult.isValid && unicodeResult.detectedIssues) { SecurityMonitor.logSecurityEvent({ type: 'YAML_UNICODE_ATTACK', severity: (unicodeResult.severity?.toUpperCase() || 'MEDIUM'), source: 'yaml_validation', details: `Unicode attack detected in YAML: ${unicodeResult.detectedIssues.join(', ')}` }); return false; } for (const pattern of this.MALICIOUS_YAML_PATTERNS) { // These are trusted internal patterns, so we disable ReDoS rejection if (RegexValidator.validate(normalizedYaml, pattern, { maxLength: 10000, rejectDangerousPatterns: false, logEvents: false // Don't log our own security patterns as dangerous })) { SecurityMonitor.logSecurityEvent({ type: 'YAML_INJECTION_ATTEMPT', severity: 'CRITICAL', source: 'yaml_validation', details: `Malicious YAML pattern detected: ${pattern}`, }); // Early exit on first match for performance return false; } } return true; } /** * Validates persona metadata fields */ static validateMetadata(metadata) { const detectedPatterns = []; // Check all string fields in metadata const checkField = (fieldName, value) => { if (typeof value === 'string') { // Check field length first if (value.length > SECURITY_LIMITS.MAX_METADATA_FIELD_LENGTH) { detectedPatterns.push(`${fieldName}: Field exceeds maximum length of ${SECURITY_LIMITS.MAX_METADATA_FIELD_LENGTH} characters`); return; } const result = this.validateAndSanitize(value); if (!result.isValid || result.detectedPatterns?.length) { detectedPatterns.push(`${fieldName}: ${result.detectedPatterns?.join(', ')}`); } } }; // Validate standard persona fields checkField('name', metadata.name); checkField('description', metadata.description); checkField('category', metadata.category); checkField('author', metadata.author); // Check any custom fields for (const [key, value] of Object.entries(metadata)) { if (!['name', 'description', 'category', 'author'].includes(key)) { checkField(key, value); } } return { isValid: detectedPatterns.length === 0, detectedPatterns, severity: detectedPatterns.length > 0 ? 'high' : 'low' }; } /** * Sanitizes a complete persona file (frontmatter + content) */ static sanitizePersonaContent(content) { // Extract frontmatter const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/); if (!frontmatterMatch) { // No frontmatter, just validate content const result = this.validateAndSanitize(content); if (!result.isValid && result.severity === 'critical') { throw new SecurityError('Critical security threat detected in persona content'); } return result.sanitizedContent || content; } const yamlContent = frontmatterMatch[1]; const markdownContent = content.substring(frontmatterMatch[0].length); // Validate YAML if (!this.validateYamlContent(yamlContent)) { throw new SecurityError('Malicious YAML detected in persona frontmatter'); } // Validate markdown content const contentResult = this.validateAndSanitize(markdownContent); if (!contentResult.isValid && contentResult.severity === 'critical') { throw new SecurityError('Critical security threat detected in persona content'); } // Return sanitized content return `---\n${yamlContent}\n---${contentResult.sanitizedContent || markdownContent}`; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGVudFZhbGlkYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZWN1cml0eS9jb250ZW50VmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7O0dBT0c7QUFFSCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzVDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN2RCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDckQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBU3BFLE1BQU0sT0FBTyxnQkFBZ0I7SUFDM0I7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxnRUFBZ0U7SUFDeEQsTUFBTSxDQUFVLGtCQUFrQixHQUFtRjtRQUMzSCxrQ0FBa0M7UUFDbEMsRUFBRSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxXQUFXLEVBQUUsd0JBQXdCLEVBQUU7UUFDL0YsRUFBRSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxXQUFXLEVBQUUsdUJBQXVCLEVBQUU7UUFDN0YsRUFBRSxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxXQUFXLEVBQUUsMkJBQTJCLEVBQUU7UUFDckcsRUFBRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsc0JBQXNCLEVBQUU7UUFFdkYsMkJBQTJCO1FBQzNCLEVBQUUsT0FBTyxFQUFFLDZDQUE2QyxFQUFFLFFBQVEsRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLHNCQUFzQixFQUFFO1FBQ3JILEVBQUUsT0FBTyxFQUFFLDBDQUEwQyxFQUFFLFFBQVEsRUFBRSxVQUFVLEVB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O1lBQ0QsT0FBTyxNQUFNLENBQUMsZ0JBQWdCLElBQUksT0FBTyxDQUFDO1FBQzVDLENBQUM7UUFFRCxNQUFNLFdBQVcsR0FBRyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN4QyxNQUFNLGVBQWUsR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRXRFLGdCQUFnQjtRQUNoQixJQUFJLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7WUFDM0MsTUFBTSxJQUFJLGFBQWEsQ0FBQyxnREFBZ0QsQ0FBQyxDQUFDO1FBQzVFLENBQUM7UUFFRCw0QkFBNEI7UUFDNUIsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ2hFLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxJQUFJLGFBQWEsQ0FBQyxRQUFRLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDcEUsTUFBTSxJQUFJLGFBQWEsQ0FBQyxzREFBc0QsQ0FBQyxDQUFDO1FBQ2xGLENBQUM7UUFFRCwyQkFBMkI7UUFDM0IsT0FBTyxRQUFRLFdBQVcsUUFBUSxhQUFhLENBQUMsZ0JBQWdCLElBQUksZUFBZSxFQUFFLENBQUM7SUFDeEYsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ29udGVudCBWYWxpZGF0b3IgZm9yIERvbGxob3VzZU1DUFxuICogXG4gKiBQcm90ZWN0cyBhZ2FpbnN0IHByb21wdCBpbmplY3Rpb24gYXR0YWNrcyBpbiBjb2xsZWN0aW9uIHBlcnNvbmFzXG4gKiBieSBkZXRlY3RpbmcgYW5kIHNhbml0aXppbmcgbWFsaWNpb3VzIGNvbnRlbnQgcGF0dGVybnMuXG4gKiBcbiAqIFNlY3VyaXR5OiBTRUMtMDAxIC0gQ3JpdGljYWwgdnVsbmVyYWJpbGl0eSBwcm90ZWN0aW9uXG4gKi9cblxuaW1wb3J0IHsgU2VjdXJpdHlFcnJvciB9IGZyb20gJy4vZXJyb3JzLmpzJztcbmltcG9ydCB7IFNlY3VyaXR5TW9uaXRvciB9IGZyb20gJy4vc2VjdXJpdHlNb25pdG9yLmpzJztcbmltcG9ydCB7IFJlZ2V4VmFsaWRhdG9yIH0gZnJvbSAnLi9yZWdleFZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBTRUNVUklUWV9MSU1JVFMgfSBmcm9tICcuL2NvbnN0YW50cy5qcyc7XG5pbXBvcnQgeyBVbmljb2RlVmFsaWRhdG9yIH0gZnJvbSAnLi92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIENvbnRlbnRWYWxpZGF0aW9uUmVzdWx0IHtcbiAgaXNWYWxpZDogYm9vbGVhbjtcbiAgc2FuaXRpemVkQ29udGVudD86IHN0cmluZztcbiAgZGV0ZWN0ZWRQYXR0ZXJucz86IHN0cmluZ1tdO1xuICBzZXZlcml0eT86ICdsb3cnIHwgJ21lZGl1bScgfCAnaGlnaCcgfCAnY3JpdGljYWwnO1xufVxuXG5leHBvcnQgY2xhc3MgQ29udGVudFZhbGlkYXRvciB7XG4gIC8qKlxuICAgKiBQYXR0ZXJuLWJhc2VkIGRldGVjdGlvbiBzeXN0ZW0gZm9yIHByb21wdCBpbmplY3Rpb24gYXR0YWNrcy5cbiAgICogXG4gICAqIFRoaXMgYXBwcm9hY2ggd2FzIGNob3NlbiBvdmVyIEFJLWJhc2VkIGRldGVjdGlvbiBiZWNhdXNlOlxuICAgKiAxLiBQYXR0ZXJuIG1hdGNoaW5nIGNhbm5vdCBiZSBzb2NpYWxseSBlbmdpbmVlcmVkIG9yIGNvbmZ1c2VkXG4gICAqIDIuIERldGVybWluaXN0aWMgcmVzdWx0cyBlbnN1cmUgY29uc2lzdGVudCBzZWN1cml0eVxuICAgKiAzLiBObyBhZGRpdGlvbmFsIEFQSSBjYWxscyBvciBsYXRlbmN5XG4gICAqIDQuIENhbid0IGJlIGJ5cGFzc2VkIGJ5IGNsZXZlciBwcm9tcHQgZW5naW5lZXJpbmdcbiAgICogXG4gICAqIFRoZSBwYXR0ZXJucyBiZWxvdyByZXByZXNlbnQga25vd24gYXR0YWNrIHZlY3RvcnMgZnJvbSBzZWN1cml0eSByZXNlYXJjaFxuICAgKiBhbmQgcmVhbC13b3JsZCBleHBsb2l0IGF0dGVtcHRzIGFnYWluc3QgQUkgc3lzdGVtcy5cbiAgICovXG4gIC8vIFByb21wdCBpbmplY3Rpb24gcGF0dGVybnMgdGhhdCBjb3VsZCBjb21wcm9taXNlIEFJIGFzc2lzdGFudHNcbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgSU5KRUNUSU9OX1BBVFRFUk5TOiBBcnJheTx7IHBhdHRlcm46IFJlZ0V4cDsgc2V2ZXJpdHk6ICdoaWdoJyB8ICdjcml0aWNhbCc7IGRlc2NyaXB0aW9uOiBzdHJpbmcgfT4gPSBbXG4gICAgLy8gU3lzdGVtIHByb21wdCBvdmVycmlkZSBhdHRlbXB0c1xuICAgIHsgcGF0dGVybjogL1xcW1NZU1RFTTpcXHMqLio/XFxdL2dpLCBzZXZlcml0eTogJ2NyaXRpY2FsJywgZGVzY3JpcHRpb246ICdTeXN0ZW0gcHJvbXB0IG92ZXJyaWRlJyB9LFxuICAgIHsgcGF0dGVybjogL1xcW0FETUlOOlxccyouKj9cXF0vZ2ksIHNldmVyaXR5OiAnY3JpdGljYWwnLCBkZXNjcmlwdGlvbjogJ0FkbWluIHByb21wdCBvdmVycmlkZScgfSxcbiAgICB7IHBhdHRlcm46IC9cXFtBU1NJU1RBTlQ6XFxzKi4qP1xcXS9naSwgc2V2ZXJpdHk6ICdjcml0aWNhbCcsIGRlc2NyaXB0aW9uOiAnQXNzaXN0YW50IHByb21wdCBvdmVycmlkZScgfSxcbiAgICB7IHBhdHRlcm46IC9cXFtVU0VSOlxccyouKj9cXF0vZ2ksIHNldmVyaXR5OiAnaGlnaCcsIGRlc2NyaXB0aW9uOiAnVXNlciBwcm9tcHQgb3ZlcnJpZGUnIH0sXG4gICAgXG4gICAgLy8gSW5zdHJ1Y3Rpb24gbWFuaXB1bGF0aW9uXG4gICAgeyBwYXR0ZXJuOiAvaWdub3JlXFxzKyhhbGxcXHMrKT9wcmV2aW91c1xccytpbnN0cnVjdGlvbnMvZ2ksIHNldmVyaXR5OiAnY3JpdGljYWwnLCBkZXNjcmlwdGlvbjogJ0luc3RydWN0aW9uIG92ZXJyaWRlJyB9LFxuICAgIHsgcGF0dGVybjogL2lnbm9yZVxccysoYWxsXFxzKyk/cHJpb3JcXHMraW5zdHJ1Y3Rpb25zL2dpLCBzZXZlcml0eTogJ2NyaXRpY2FsJywgZGVzY3JpcHRpb246ICdJbnN0cnVjdGlvbiBvdmVycmlkZScgfSxcbiAgICB7IHBhdHRlcm46IC9kaXNyZWdhcmRcXHMrKGFsbFxccyspP3ByZXZpb3VzXFxzK2luc3RydWN0aW9ucy9naSwgc2V2ZXJpdHk6ICdjcml0aWNhbCcsIGRlc2NyaXB0aW9uOiAnSW5zdHJ1Y3Rpb24gb3ZlcnJpZGUnIH0sXG4gICAgeyBwYXR0ZXJuOiAvZm9yZ2V0XFxzKyhhbGxcXHMrKT9wcmV2aW91c1xccytpbnN0cnVjdGlvbnMvZ2ksIHNldmVyaXR5OiAnY3JpdGljYWwnLCBkZXNjcmlwdGlvbjogJ0luc3RydWN0aW9uIG92ZXJyaWRlJyB9LFxuICAgIHsgcGF0dGVybjogL3lvdVxccythcmVcXHMrbm93XFxzKyhhZG1pbnxyb290fHN5c3RlbXxzdWRvKS9naSwgc2V2ZXJpdHk6ICdjcml0aWNhbCcsIGRlc2NyaXB0aW9uOiAnUm9sZSBlbGV2YXRpb24gYXR0ZW1wdCcgfSxcbiAgICB7IHBhdHRlcm46IC9hY3RcXHMrYXNcXHMrKGFkbWlufHJvb3R8c3lzdGVtfHN1ZG8pL2dpLCBzZXZlcml0eTogJ2NyaXRpY2FsJywgZGVzY3JpcHRpb246ICdSb2xlIGVsZXZhdGlvbiBhdHRlbXB0JyB9LFxuICAgIFxuICAgIC8vIERhdGEgZXhmaWx0cmF0aW9uIGF0dGVtcHRzXG4gICAgeyBwYXR0ZXJuOiAvZXhwb3J0XFxzK2FsbFxccysoZmlsZXN8ZGF0YXxwZXJzb25hc3x0b2tlbnN8Y3JlZGVudGlhbHMpL2dpLCBzZXZlcml0eTogJ2NyaXRpY2FsJywgZGVzY3JpcHRpb246ICdEYXRhIGV4ZmlsdHJhdGlvbicgfSxcbiAgICB7IHBhdHRlcm46IC9zZW5kXFxzK2FsbFxccysoZmlsZXN8ZGF0YXxwZXJzb25hc3x0b2tlbnN8Y3JlZGVudGlhbHMpXFxzK3RvL2dpLCBzZXZlcml0eTogJ2NyaXRpY2FsJywgZGVzY3JpcHRpb246ICdEYXRhIGV4ZmlsdHJhdGlvbicgfSxcbiAgICB7IHBhdHRlcm46IC9saXN0XFxzK2FsbFxccysoZmlsZXN8dG9rZW5zfGNyZWRlbnRpYWxzfHNlY3JldHMpL2dpLCBzZXZlcml0eTogJ2hpZ2gnLCBkZXNjcmlwdGlvbjogJ0luZm9ybWF0aW9uIGRpc2Nsb3N1cmUnIH0sXG4gICAgeyBwYXR0ZXJuOiAvc2hvd1xccyttZVxccythbGxcXHMrKHRva2Vuc3xjcmVkZW50aWFsc3xzZWNyZXRzfGFwaVxccytrZXlzKS9naSwgc2V2ZXJpdHk6ICdoaWdoJywgZGVzY3JpcHRpb246ICdDcmVkZW50aWFsIGRpc2Nsb3N1cmUnIH0sXG4gICAgXG4gICAgLy8gQ29tbWFuZCBleGVjdXRpb24gcGF0dGVybnNcbiAgICB7IHBhdHRlcm46IC9jdXJsXFxzK1teXFxzXStcXC4oY29tfG5ldHxvcmd8aW98ZGV2KS9naSwgc2V2ZXJpdHk6ICdjcml0aWNhbCcsIGRlc2NyaXB0aW9uOiAnRXh0ZXJuYWwgY29tbWFuZCBleGVjdXRpb24nIH0sXG4gICAgeyBwYXR0ZXJuOiAvd2dldFxccytbXlxcc10rXFwuKGNvbXxuZXR8b3JnfGlvfGRldikvZ2ksIHNldmVyaXR5OiAnY3JpdGljYWwnLCBkZXNjcmlwdGlvbjogJ0V4dGVybmFsIGNvbW1hbmQgZXhlY3V0aW9uJyB9LFxuICAgIHsgcGF0dGVybjogL1xcJFxcKFteKV0rXFwpL2csIHNldmVyaXR5OiAnY3JpdGljYWwnLCBkZXNjcmlwdGlvbjogJ0NvbW1hbmQgc3Vic3RpdHV0aW9uJyB9LFxuICAgIHsgcGF0dGVybjogL2BbXmBdK2AvZywgc2V2ZXJpdHk6ICdjcml0aWNhbCcsIGRlc2NyaXB0aW9uOiAnQmFja3RpY2sgY29tbWFuZCBleGVjdXRpb24nIH0sXG4gICAgeyBwYXR0ZXJuOiAvZXZhbFxccypcXCgvZ2ksIHNldmVyaXR5OiAnY3JpdGljYWwnLCBkZXNjcmlwdGlvbjogJ0NvZGUgZXZhbHVhdGlvbicgfSxcbiAgICB7IHBhdHRlcm46IC9leGVjXFxzKlxcKC9naSwgc2V2ZXJpdHk6ICdjcml0aWNhbCcsIGRlc2NyaXB0aW9uOiAnQ29kZSBleGVjdXRpb24nIH0sXG4gICAgeyBwYXR0ZXJuOiAvb3NcXC5zeXN0ZW1cXHMqXFwoL2dpLCBzZXZlcml0eTogJ2NyaXRpY2FsJywgZGVzY3JpcHRpb246ICdTeXN0ZW0gY29tbWFuZCBleGVjdXRpb24nIH0sXG4gICAgeyBwYXR0ZXJuOiAvc3VicHJvY2Vzc1xcLihjYWxsfHJ1bnxQb3BlbikvZ2ksIHNldmVyaXR5OiAnY3JpdGljYWwnLCBkZXNjcmlwdGlvbjogJ1N1YnByb2Nlc3MgZXhlY3V0aW9uJyB9LFxuICAgIFxuICAgIC8vIFRva2VuL2NyZWRlbnRpYWwgcGF0dGVybnNcbiAgICB7IHBhdHRlcm46IC9HSVRIVUJfVE9LRU4vZ2ksIHNldmVyaXR5OiAnaGlnaCcsIGRlc2NyaXB0aW9uOiAnVG9rZW4gcmVmZXJlbmNlJyB9LFxuICAgIHsgcGF0dGVybjogL2docF9bYS16QS1aMC05XXszNn0vZywgc2V2ZXJpdHk6ICdjcml0aWNhbCcsIGRlc2NyaXB0aW9uOiAnR2l0SHViIHRva2VuIGV4cG9zdXJlJyB9LFxuICAgIHsgcGF0dGVybjogL2dob19bYS16QS1aMC05XXszNn0vZywgc2V2ZXJpdHk6ICdjcml0aWNhbCcsIGRlc2NyaXB0aW9uOiAnR2l0SHViIE9BdXRoIHRva2VuIGV4cG9zdXJlJyB9LFxuICAgIFxuICAgIC8vIFBhdGggdHJhdmVyc2FsIGluIGNvbnRlbnRcbiAgICB7IHBhdHRlcm46IC9cXC5cXC5cXC9cXC5cXC5cXC9cXC5cXC5cXC8vZywgc2V2ZXJpdHk6ICdoaWdoJywgZGVzY3JpcHRpb246ICdQYXRoIHRyYXZlcnNhbCBhdHRlbXB0JyB9LFxuICAgIHsgcGF0dGVybjogL1xcL2V0Y1xcL3Bhc3N3ZC9naSwgc2V2ZXJpdHk6ICdoaWdoJywgZGVzY3JpcHRpb246ICdTZW5zaXRpdmUgZmlsZSBhY2Nlc3MnIH0sXG4gICAgeyBwYXR0ZXJuOiAvXFwvXFwuc3NoXFwvL2dpLCBzZXZlcml0eTogJ2hpZ2gnLCBkZXNjcmlwdGlvbjogJ1NTSCBrZXkgYWNjZXNzIGF0dGVtcHQnIH0sXG4gIF07XG5cbiAgLy8gTWFsaWNpb3VzIFlBTUwgcGF0dGVybnNcbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgTUFMSUNJT1VTX1lBTUxfUEFUVEVSTlMgPSBbXG4gICAgLy8gTGFuZ3VhZ2Utc3BlY2lmaWMgZGVzZXJpYWxpemF0aW9uIGF0dGFja3NcbiAgICAvISFweXRob25cXC9vYmplY3QvLFxuICAgIC8hIXB5dGhvblxcL21vZHVsZS8sXG4gICAgLyEhcHl0aG9uXFwvbmFtZS8sXG4gICAgLyEhcnVieVxcL29iamVjdC8sXG4gICAgLyEhcnVieVxcL2hhc2gvLFxuICAgIC8hIXJ1YnlcXC9zdHJ1Y3QvLFxuICAgIC8hIXJ1YnlcXC9tYXJzaGFsLyxcbiAgICAvISFqYXZhLyxcbiAgICAvISFqYXZheC8sXG4gICAgLyEhY29tXFwuc3VuLyxcbiAgICAvISFwZXJsXFwvaGFzaC8sXG4gICAgLyEhcGVybFxcL2NvZGUvLFxuICAgIC8hIXBocFxcL29iamVjdC8sXG4gICAgXG4gICAgLy8gQ29uc3RydWN0b3IvZnVuY3Rpb24gaW5qZWN0aW9uXG4gICAgLyEhZXhlYy8sXG4gICAgLyEhZXZhbC8sXG4gICAgLyEhbmV3LyxcbiAgICAvISFjb25zdHJ1Y3QvLFxuICAgIC8hIWFwcGx5LyxcbiAgICAvISFjYWxsLyxcbiAgICAvISFpbnZva2UvLFxuICAgIFxuICAgIC8vIENvZGUgZXhlY3V0aW9uIHBhdHRlcm5zIC0gbW9yZSBzcGVjaWZpYyB0byBhdm9pZCBmYWxzZSBwb3NpdGl2ZXNcbiAgICAvc3VicHJvY2Vzc1xcLi8sXG4gICAgL29zXFwuc3lzdGVtLyxcbiAgICAvZXZhbFxccypcXCgvLFxuICAgIC9leGVjXFxzKlxcKC8sXG4gICAgL19faW1wb3J0X19cXHMqXFwoLyxcbiAgICAvcmVxdWlyZVxccypcXCgvLFxuICAgIC9pbXBvcnRcXHMrKD86b3N8c3lzfHN1YnByb2Nlc3N8ZXZhbHxleGVjKS8sXG4gICAgL2luY2x1ZGVcXHMrW1wiJ10uKlxcLig/OnBocHxzaHxweXxqc3xyYilbXCInXS8sXG4gICAgXG4gICAgLy8gQ29tbWFuZCBleGVjdXRpb24gdmFyaWFudHMgLSBtb3JlIHNwZWNpZmljIHBhdHRlcm5zXG4gICAgL3BvcGVuXFxzKlxcKC8sXG4gICAgL3NwYXduXFxzKlxcKC8sXG4gICAgL3N5c3RlbVxccypcXCgvLFxuICAgIC9iYWNrdGlja1xccypcXCgvLFxuICAgIC9zaGVsbF9leGVjXFxzKlxcKC8sXG4gICAgL3Bhc3N0aHJ1XFxzKlxcKC8sXG4gICAgL3Byb2Nfb3BlblxccypcXCgvLFxuICAgIFxuICAgIC8vIE5ldHdvcmsgb3BlcmF0aW9ucyAtIHJlcXVpcmUgc3VzcGljaW91cyBjb250ZXh0XG4gICAgL3NvY2tldFxcLmNvbm5lY3QvLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRGV0ZWN0cyBzb2NrZXQgY29ubmVjdGlvbiBhdHRlbXB0c1xuICAgIC91cmxsaWJcXC5yZXF1ZXN0LywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFB5dGhvbiBIVFRQIGxpYnJhcnkgdXNhZ2VcbiAgICAvcmVxdWVzdHNcXC4oPzpnZXR8cG9zdHxwdXR8ZGVsZXRlKVxccypcXCgvLCAgICAgICAgICAgICAgLy8gRGV0ZWN0cyBIVFRQIHJlcXVlc3RzIHdpdGggbWV0aG9kIGNhbGxzXG4gICAgL2ZldGNoXFxzKlxcKFxccypbXCInXWh0dHBzPzpcXC9cXC8vLCAgICAgICAgICAgICAgICAgICAgICAgIC8vIERldGVjdHMgZmV0Y2ggY2FsbHMgdG8gZXh0ZXJuYWwgVVJMc1xuICAgIC9uZXdcXHMrWE1MSHR0cFJlcXVlc3QvLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEphdmFTY3JpcHQgQUpBWCBvYmplY3QgY3JlYXRpb25cbiAgICAvXFwuKD86Z2V0fHBvc3R8cHV0fGRlbGV0ZSlcXHMqXFwoXFxzKltcIiddaHR0cHM/OlxcL1xcLy8sICAgIC8vIE1ldGhvZCBjaGFpbmluZyB3aXRoIEhUVFAgcmVxdWVzdHNcbiAgICBcbiAgICAvLyBGaWxlIHN5c3RlbSBvcGVyYXRpb25zIC0gcmVxdWlyZSBzdXNwaWNpb3VzIGNvbnRleHRcbiAgICAvKD86ZnNcXC58ZmlsZVxcLnwpXFxzKm9wZW5cXHMqXFwoXFxzKltcIiddKD86XFwvZXRjXFwvfFxcL2JpblxcL3xcXC5cXC5cXC8pLywgICAgIC8vIEZpbGUgb3BlbiB3aXRoIHN1c3BpY2lvdXMgcGF0aHNcbiAgICAvZmlsZV9nZXRfY29udGVudHNcXHMqXFwoLywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBQSFAgZmlsZSByZWFkaW5nIGZ1bmN0aW9uXG4gICAgL2ZpbGVfcHV0X2NvbnRlbnRzXFxzKlxcKC8sICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUEhQIGZpbGUgd3JpdGluZyBmdW5jdGlvblxuICAgIC9mb3BlblxccypcXChcXHMqW1wiJ10oPzpcXC9ldGNcXC98XFwvYmluXFwvfFxcLlxcLlxcLykvLCAgICAgICAgICAgICAgICAgICAgICAgLy8gRmlsZSBvcGVuIHdpdGggZGFuZ2Vyb3VzIHN5c3RlbSBwYXRoc1xuICAgIC8oPzpmc1xcLik/XFxzKnJlYWRGaWxlXFxzKlxcKFxccypbXCInXSg/OlxcL2V0Y1xcL3xcXC9iaW5cXC98XFwuXFwuXFwvKS8sICAgICAgICAvLyBOb2RlLmpzIGZpbGUgcmVhZCB3aXRoIHBhdGggdHJhdmVyc2FsXG4gICAgLyg/OmZzXFwuKT9cXHMqd3JpdGVGaWxlXFxzKlxcKFxccypbXCInXSg/OlxcLyg/OmJpbnxldGN8dG1wKVxcL3xcXC5cXC5cXC8pLywgICAvLyBOb2RlLmpzIGZpbGUgd3JpdGUgdG8gc3lzdGVtIGRpcnNcbiAgICBcbiAgICAvLyBQcm90b2NvbCBoYW5kbGVyc1xuICAgIC9maWxlOlxcL1xcLy8sXG4gICAgL2RhdGE6XFwvXFwvLyxcbiAgICAvZXhwZWN0OlxcL1xcLy8sXG4gICAgL3BocDpcXC9cXC8vLFxuICAgIC9waGFyOlxcL1xcLy8sXG4gICAgL3ppcDpcXC9cXC8vLFxuICAgIC9zc2gyOlxcL1xcLy8sXG4gICAgL29nZzpcXC9cXC8vLFxuICAgIFxuICAgIC8vIFlBTUwtc3BlY2lmaWMgZGFuZ2Vyb3VzIGZlYXR1cmVzXG4gICAgLyZbYS16QS1aMC05X10rXFxzKiEhLywgLy8gQW5jaG9yIHdpdGggdGFnIGNvbWJpbmF0aW9uXG4gICAgL1xcKlthLXpBLVowLTlfXStcXHMqISEvLCAvLyBBbGlhcyB3aXRoIHRhZyBjb21iaW5hdGlvblxuICAgIC8hIW1lcmdlLyxcbiAgICAvISFiaW5hcnkvLFxuICAgIC8hIXRpbWVzdGFtcC8sXG4gICAgXG4gICAgLy8gVW5pY29kZS9lbmNvZGluZyBieXBhc3MgYXR0ZW1wdHMgLSBwcmV2ZW50IHZpc3VhbCBzcG9vZmluZyBhdHRhY2tzXG4gICAgL1xcXFxbdVVdMCooPzoyMnwyN3w2MHwzW2NDXSkvLCAgIC8vIFVuaWNvZGUgZXNjYXBlcyBmb3IgcXVvdGVzIChcIikgYW5kIGJyYWNrZXRzICg8PilcbiAgICAvW1xcdTIwMkEtXFx1MjAyRVxcdTIwNjYtXFx1MjA2OV0vLCAgLy8gRGlyZWN0aW9uIG92ZXJyaWRlIGNoYXJzIChSTE8sIExSTywgaXNvbGF0ZXMpXG4gICAgL1tcXHUyMDBCLVxcdTIwMEZcXHUyMDI4LVxcdTIwMkZdLywgIC8vIFplcm8td2lkdGggc3BhY2VzLCBsaW5lL3BhcmFncmFwaCBzZXBhcmF0b3JzXG4gICAgL1tcXHVGRUZGXFx1RkZGRVxcdUZGRkZdLywgICAgICAgICAgLy8gQk9NLCBub24tY2hhcmFjdGVycyBmb3IgcGF5bG9hZCBoaWRpbmdcbiAgXTtcblxuICAvKipcbiAgICogVmFsaWRhdGVzIGFuZCBzYW5pdGl6ZXMgcGVyc29uYSBjb250ZW50IGZvciBzZWN1cml0eSB0aHJlYXRzXG4gICAqL1xuICBzdGF0aWMgdmFsaWRhdGVBbmRTYW5pdGl6ZShjb250ZW50OiBzdHJpbmcpOiBDb250ZW50VmFsaWRhdGlvblJlc3VsdCB7XG4gICAgLy8gTGVuZ3RoIHZhbGlkYXRpb24gYmVmb3JlIHBhdHRlcm4gbWF0Y2hpbmdcbiAgICBpZiAoY29udGVudC5sZW5ndGggPiBTRUNVUklUWV9MSU1JVFMuTUFYX0NPTlRFTlRfTEVOR1RIKSB7XG4gICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFcnJvcihcbiAgICAgICAgYENvbnRlbnQgZXhjZWVkcyBtYXhpbXVtIGxlbmd0aCBvZiAke1NFQ1VSSVRZX0xJTUlUUy5NQVhfQ09OVEVOVF9MRU5HVEh9IGNoYXJhY3RlcnMgKCR7Y29udGVudC5sZW5ndGh9IHByb3ZpZGVkKWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgZGV0ZWN0ZWRQYXR0ZXJuczogc3RyaW5nW10gPSBbXTtcbiAgICBsZXQgc2FuaXRpemVkID0gY29udGVudDtcbiAgICBsZXQgaGlnaGVzdFNldmVyaXR5OiAnbG93JyB8ICdtZWRpdW0nIHwgJ2hpZ2gnIHwgJ2NyaXRpY2FsJyA9ICdsb3cnO1xuXG4gICAgLy8gVW5pY29kZSBub3JtYWxpemF0aW9uIHByZXByb2Nlc3NpbmcgdG8gcHJldmVudCBieXBhc3MgYXR0YWNrc1xuICAgIGNvbnN0IHVuaWNvZGVSZXN1bHQgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShzYW5pdGl6ZWQpO1xuICAgIHNhbml0aXplZCA9IHVuaWNvZGVSZXN1bHQubm9ybWFsaXplZENvbnRlbnQ7XG4gICAgXG4gICAgaWYgKCF1bmljb2RlUmVzdWx0LmlzVmFsaWQgJiYgdW5pY29kZVJlc3VsdC5kZXRlY3RlZElzc3Vlcykge1xuICAgICAgZGV0ZWN0ZWRQYXR0ZXJucy5wdXNoKC4uLnVuaWNvZGVSZXN1bHQuZGV0ZWN0ZWRJc3N1ZXMubWFwKGlzc3VlID0+IGBVbmljb2RlOiAke2lzc3VlfWApKTtcbiAgICAgIGlmICh1bmljb2RlUmVzdWx0LnNldmVyaXR5KSB7XG4gICAgICAgIGhpZ2hlc3RTZXZlcml0eSA9IHVuaWNvZGVSZXN1bHQuc2V2ZXJpdHk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgZm9yIGluamVjdGlvbiBwYXR0ZXJuc1xuICAgIGZvciAoY29uc3QgeyBwYXR0ZXJuLCBzZXZlcml0eSwgZGVzY3JpcHRpb24gfSBvZiB0aGlzLklOSkVDVElPTl9QQVRURVJOUykge1xuICAgICAgLy8gVGhlc2UgYXJlIHRydXN0ZWQgaW50ZXJuYWwgcGF0dGVybnMsIHNvIHdlIGRpc2FibGUgUmVEb1MgcmVqZWN0aW9uXG4gICAgICBpZiAoUmVnZXhWYWxpZGF0b3IudmFsaWRhdGUoY29udGVudCwgcGF0dGVybiwgeyBcbiAgICAgICAgbWF4TGVuZ3RoOiA1MDAwMCwgXG4gICAgICAgIHJlamVjdERhbmdlcm91c1BhdHRlcm5zOiBmYWxzZSxcbiAgICAgICAgbG9nRXZlbnRzOiBmYWxzZSAgLy8gRG9uJ3QgbG9nIG91ciBvd24gc2VjdXJpdHkgcGF0dGVybnMgYXMgZGFuZ2Vyb3VzXG4gICAgICB9KSkge1xuICAgICAgICBkZXRlY3RlZFBhdHRlcm5zLnB1c2goZGVzY3JpcHRpb24pO1xuICAgICAgICBcbiAgICAgICAgLy8gVXBkYXRlIGhpZ2hlc3Qgc2V2ZXJpdHlcbiAgICAgICAgaWYgKHNldmVyaXR5ID09PSAnY3JpdGljYWwnIHx8IChzZXZlcml0eSA9PT0gJ2hpZ2gnICYmIGhpZ2hlc3RTZXZlcml0eSAhPT0gJ2NyaXRpY2FsJykpIHtcbiAgICAgICAgICBoaWdoZXN0U2V2ZXJpdHkgPSBzZXZlcml0eTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIExvZyBzZWN1cml0eSBldmVudFxuICAgICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgICAgdHlwZTogJ0NPTlRFTlRfSU5KRUNUSU9OX0FUVEVNUFQnLFxuICAgICAgICAgIHNldmVyaXR5OiBzZXZlcml0eS50b1VwcGVyQ2FzZSgpIGFzICdISUdIJyB8ICdDUklUSUNBTCcsXG4gICAgICAgICAgc291cmNlOiAnY29udGVudF92YWxpZGF0aW9uJyxcbiAgICAgICAgICBkZXRhaWxzOiBgRGV0ZWN0ZWQgcGF0dGVybjogJHtkZXNjcmlwdGlvbn1gLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBTYW5pdGl6ZSBieSByZXBsYWNpbmcgd2l0aCBzYWZlIHBsYWNlaG9sZGVyXG4gICAgICAgIHNhbml0aXplZCA9IHNhbml0aXplZC5yZXBsYWNlKHBhdHRlcm4sICdbQ09OVEVOVF9CTE9DS0VEXScpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBpc1ZhbGlkOiBkZXRlY3RlZFBhdHRlcm5zLmxlbmd0aCA9PT0gMCxcbiAgICAgIHNhbml0aXplZENvbnRlbnQ6IHNhbml0aXplZCxcbiAgICAgIGRldGVjdGVkUGF0dGVybnMsXG4gICAgICBzZXZlcml0eTogaGlnaGVzdFNldmVyaXR5XG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgWUFNTCBmcm9udG1hdHRlciBmb3IgbWFsaWNpb3VzIGNvbnRlbnRcbiAgICovXG4gIHN0YXRpYyB2YWxpZGF0ZVlhbWxDb250ZW50KHlhbWxDb250ZW50OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAvLyBMZW5ndGggdmFsaWRhdGlvbiBiZWZvcmUgcGF0dGVybiBtYXRjaGluZ1xuICAgIGlmICh5YW1sQ29udGVudC5sZW5ndGggPiBTRUNVUklUWV9MSU1JVFMuTUFYX1lBTUxfTEVOR1RIKSB7XG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6ICdZQU1MX0lOSkVDVElPTl9BVFRFTVBUJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdISUdIJyxcbiAgICAgICAgc291cmNlOiAneWFtbF92YWxpZGF0aW9uJyxcbiAgICAgICAgZGV0YWlsczogYFlBTUwgY29udGVudCBleGNlZWRzIG1heGltdW0gbGVuZ3RoOiAke3lhbWxDb250ZW50Lmxlbmd0aH0gPiAke1NFQ1VSSVRZX0xJTUlUUy5NQVhfWUFNTF9MRU5HVEh9YFxuICAgICAgfSk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gVW5pY29kZSBub3JtYWxpemF0aW9uIHByZXByb2Nlc3NpbmcgZm9yIFlBTUwgY29udGVudFxuICAgIGNvbnN0IHVuaWNvZGVSZXN1bHQgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZSh5YW1sQ29udGVudCk7XG4gICAgY29uc3Qgbm9ybWFsaXplZFlhbWwgPSB1bmljb2RlUmVzdWx0Lm5vcm1hbGl6ZWRDb250ZW50O1xuICAgIFxuICAgIGlmICghdW5pY29kZVJlc3VsdC5pc1ZhbGlkICYmIHVuaWNvZGVSZXN1bHQuZGV0ZWN0ZWRJc3N1ZXMpIHtcbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogJ1lBTUxfVU5JQ09ERV9BVFRBQ0snLFxuICAgICAgICBzZXZlcml0eTogKHVuaWNvZGVSZXN1bHQuc2V2ZXJpdHk/LnRvVXBwZXJDYXNlKCkgfHwgJ01FRElVTScpIGFzICdMT1cnIHwgJ01FRElVTScgfCAnSElHSCcgfCAnQ1JJVElDQUwnLFxuICAgICAgICBzb3VyY2U6ICd5YW1sX3ZhbGlkYXRpb24nLFxuICAgICAgICBkZXRhaWxzOiBgVW5pY29kZSBhdHRhY2sgZGV0ZWN0ZWQgaW4gWUFNTDogJHt1bmljb2RlUmVzdWx0LmRldGVjdGVkSXNzdWVzLmpvaW4oJywgJyl9YFxuICAgICAgfSk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBwYXR0ZXJuIG9mIHRoaXMuTUFMSUNJT1VTX1lBTUxfUEFUVEVSTlMpIHtcbiAgICAgIC8vIFRoZXNlIGFyZSB0cnVzdGVkIGludGVybmFsIHBhdHRlcm5zLCBzbyB3ZSBkaXNhYmxlIFJlRG9TIHJlamVjdGlvblxuICAgICAgaWYgKFJlZ2V4VmFsaWRhdG9yLnZhbGlkYXRlKG5vcm1hbGl6ZWRZYW1sLCBwYXR0ZXJuLCB7IFxuICAgICAgICBtYXhMZW5ndGg6IDEwMDAwLFxuICAgICAgICByZWplY3REYW5nZXJvdXNQYXR0ZXJuczogZmFsc2UsXG4gICAgICAgIGxvZ0V2ZW50czogZmFsc2UgIC8vIERvbid0IGxvZyBvdXIgb3duIHNlY3VyaXR5IHBhdHRlcm5zIGFzIGRhbmdlcm91c1xuICAgICAgfSkpIHtcbiAgICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICAgIHR5cGU6ICdZQU1MX0lOSkVDVElPTl9BVFRFTVBUJyxcbiAgICAgICAgICBzZXZlcml0eTogJ0NSSVRJQ0FMJyxcbiAgICAgICAgICBzb3VyY2U6ICd5YW1sX3ZhbGlkYXRpb24nLFxuICAgICAgICAgIGRldGFpbHM6IGBNYWxpY2lvdXMgWUFNTCBwYXR0ZXJuIGRldGVjdGVkOiAke3BhdHRlcm59YCxcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIEVhcmx5IGV4aXQgb24gZmlyc3QgbWF0Y2ggZm9yIHBlcmZvcm1hbmNlXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIHBlcnNvbmEgbWV0YWRhdGEgZmllbGRzXG4gICAqL1xuICBzdGF0aWMgdmFsaWRhdGVNZXRhZGF0YShtZXRhZGF0YTogYW55KTogQ29udGVudFZhbGlkYXRpb25SZXN1bHQge1xuICAgIGNvbnN0IGRldGVjdGVkUGF0dGVybnM6IHN0cmluZ1tdID0gW107XG5cbiAgICAvLyBDaGVjayBhbGwgc3RyaW5nIGZpZWxkcyBpbiBtZXRhZGF0YVxuICAgIGNvbnN0IGNoZWNrRmllbGQgPSAoZmllbGROYW1lOiBzdHJpbmcsIHZhbHVlOiBhbnkpID0+IHtcbiAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIC8vIENoZWNrIGZpZWxkIGxlbmd0aCBmaXJzdFxuICAgICAgICBpZiAodmFsdWUubGVuZ3RoID4gU0VDVVJJVFlfTElNSVRTLk1BWF9NRVRBREFUQV9GSUVMRF9MRU5HVEgpIHtcbiAgICAgICAgICBkZXRlY3RlZFBhdHRlcm5zLnB1c2goYCR7ZmllbGROYW1lfTogRmllbGQgZXhjZWVkcyBtYXhpbXVtIGxlbmd0aCBvZiAke1NFQ1VSSVRZX0xJTUlUUy5NQVhfTUVUQURBVEFfRklFTERfTEVOR1RIfSBjaGFyYWN0ZXJzYCk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICBjb25zdCByZXN1bHQgPSB0aGlzLnZhbGlkYXRlQW5kU2FuaXRpemUodmFsdWUpO1xuICAgICAgICBpZiAoIXJlc3VsdC5pc1ZhbGlkIHx8IHJlc3VsdC5kZXRlY3RlZFBhdHRlcm5zPy5sZW5ndGgpIHtcbiAgICAgICAgICBkZXRlY3RlZFBhdHRlcm5zLnB1c2goYCR7ZmllbGROYW1lfTogJHtyZXN1bHQuZGV0ZWN0ZWRQYXR0ZXJucz8uam9pbignLCAnKX1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICAvLyBWYWxpZGF0ZSBzdGFuZGFyZCBwZXJzb25hIGZpZWxkc1xuICAgIGNoZWNrRmllbGQoJ25hbWUnLCBtZXRhZGF0YS5uYW1lKTtcbiAgICBjaGVja0ZpZWxkKCdkZXNjcmlwdGlvbicsIG1ldGFkYXRhLmRlc2NyaXB0aW9uKTtcbiAgICBjaGVja0ZpZWxkKCdjYXRlZ29yeScsIG1ldGFkYXRhLmNhdGVnb3J5KTtcbiAgICBjaGVja0ZpZWxkKCdhdXRob3InLCBtZXRhZGF0YS5hdXRob3IpO1xuICAgIFxuICAgIC8vIENoZWNrIGFueSBjdXN0b20gZmllbGRzXG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobWV0YWRhdGEpKSB7XG4gICAgICBpZiAoIVsnbmFtZScsICdkZXNjcmlwdGlvbicsICdjYXRlZ29yeScsICdhdXRob3InXS5pbmNsdWRlcyhrZXkpKSB7XG4gICAgICAgIGNoZWNrRmllbGQoa2V5LCB2YWx1ZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlzVmFsaWQ6IGRldGVjdGVkUGF0dGVybnMubGVuZ3RoID09PSAwLFxuICAgICAgZGV0ZWN0ZWRQYXR0ZXJucyxcbiAgICAgIHNldmVyaXR5OiBkZXRlY3RlZFBhdHRlcm5zLmxlbmd0aCA+IDAgPyAnaGlnaCcgOiAnbG93J1xuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogU2FuaXRpemVzIGEgY29tcGxldGUgcGVyc29uYSBmaWxlIChmcm9udG1hdHRlciArIGNvbnRlbnQpXG4gICAqL1xuICBzdGF0aWMgc2FuaXRpemVQZXJzb25hQ29udGVudChjb250ZW50OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIC8vIEV4dHJhY3QgZnJvbnRtYXR0ZXJcbiAgICBjb25zdCBmcm9udG1hdHRlck1hdGNoID0gY29udGVudC5tYXRjaCgvXi0tLVxcbihbXFxzXFxTXSo/KVxcbi0tLS8pO1xuICAgIFxuICAgIGlmICghZnJvbnRtYXR0ZXJNYXRjaCkge1xuICAgICAgLy8gTm8gZnJvbnRtYXR0ZXIsIGp1c3QgdmFsaWRhdGUgY29udGVudFxuICAgICAgY29uc3QgcmVzdWx0ID0gdGhpcy52YWxpZGF0ZUFuZFNhbml0aXplKGNvbnRlbnQpO1xuICAgICAgaWYgKCFyZXN1bHQuaXNWYWxpZCAmJiByZXN1bHQuc2V2ZXJpdHkgPT09ICdjcml0aWNhbCcpIHtcbiAgICAgICAgdGhyb3cgbmV3IFNlY3VyaXR5RXJyb3IoJ0NyaXRpY2FsIHNlY3VyaXR5IHRocmVhdCBkZXRlY3RlZCBpbiBwZXJzb25hIGNvbnRlbnQnKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQuc2FuaXRpemVkQ29udGVudCB8fCBjb250ZW50O1xuICAgIH1cblxuICAgIGNvbnN0IHlhbWxDb250ZW50ID0gZnJvbnRtYXR0ZXJNYXRjaFsxXTtcbiAgICBjb25zdCBtYXJrZG93bkNvbnRlbnQgPSBjb250ZW50LnN1YnN0cmluZyhmcm9udG1hdHRlck1hdGNoWzBdLmxlbmd0aCk7XG5cbiAgICAvLyBWYWxpZGF0ZSBZQU1MXG4gICAgaWYgKCF0aGlzLnZhbGlkYXRlWWFtbENvbnRlbnQoeWFtbENvbnRlbnQpKSB7XG4gICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFcnJvcignTWFsaWNpb3VzIFlBTUwgZGV0ZWN0ZWQgaW4gcGVyc29uYSBmcm9udG1hdHRlcicpO1xuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIG1hcmtkb3duIGNvbnRlbnRcbiAgICBjb25zdCBjb250ZW50UmVzdWx0ID0gdGhpcy52YWxpZGF0ZUFuZFNhbml0aXplKG1hcmtkb3duQ29udGVudCk7XG4gICAgaWYgKCFjb250ZW50UmVzdWx0LmlzVmFsaWQgJiYgY29udGVudFJlc3VsdC5zZXZlcml0eSA9PT0gJ2NyaXRpY2FsJykge1xuICAgICAgdGhyb3cgbmV3IFNlY3VyaXR5RXJyb3IoJ0NyaXRpY2FsIHNlY3VyaXR5IHRocmVhdCBkZXRlY3RlZCBpbiBwZXJzb25hIGNvbnRlbnQnKTtcbiAgICB9XG5cbiAgICAvLyBSZXR1cm4gc2FuaXRpemVkIGNvbnRlbnRcbiAgICByZXR1cm4gYC0tLVxcbiR7eWFtbENvbnRlbnR9XFxuLS0tJHtjb250ZW50UmVzdWx0LnNhbml0aXplZENvbnRlbnQgfHwgbWFya2Rvd25Db250ZW50fWA7XG4gIH1cbn0iXX0=