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.

316 lines 43.2 kB
/** * Secure YAML Parser for DollhouseMCP - For Markdown Files with YAML Frontmatter * * IMPORTANT: This parser is specifically designed for Markdown files with YAML frontmatter * (the format used by personas, skills, templates, and other elements). * * USE THIS FOR: * - Persona files (e.g., creative-writer.md) * - Skill files (e.g., code-review.md) * - Template files (e.g., meeting-notes.md) * - Any Markdown file with YAML frontmatter between --- markers * * DO NOT USE THIS FOR: * - Pure YAML configuration files (use js-yaml directly with FAILSAFE_SCHEMA) * - JSON files * - Plain text files without frontmatter * * FILE FORMAT EXPECTED: * ``` * --- * name: Element Name * description: Element description * version: 1.0.0 * --- * * # Markdown content here * The actual content/instructions go here... * ``` * * Provides safe YAML parsing that prevents deserialization attacks * by using a restricted schema and pre-validation. * * Security: SEC-003 - YAML parsing vulnerability protection */ import * as yaml from 'js-yaml'; import matter from 'gray-matter'; import { SecurityError } from '../errors/SecurityError.js'; import { ContentValidator } from './contentValidator.js'; import { SecurityMonitor } from './securityMonitor.js'; export class SecureYamlParser { static DEFAULT_OPTIONS = { maxYamlSize: 64 * 1024, // 64KB for YAML maxContentSize: 1024 * 1024, // 1MB for content validateContent: true, validateFields: true // By default, apply field validators }; // Allowed YAML types - using CORE_SCHEMA (safe subset with basic types like booleans and integers) static SAFE_SCHEMA = yaml.CORE_SCHEMA; // Additional validation for specific persona fields static FIELD_VALIDATORS = { name: (v) => typeof v === 'string' && v.length <= 100, description: (v) => typeof v === 'string', author: (v) => typeof v === 'string' && v.length <= 100, version: (v) => typeof v === 'string' && /^\d+\.\d+(\.\d+)?(-[a-zA-Z0-9.-]+)?$/.test(v), category: (v) => typeof v === 'string' && v.length <= 50, age_rating: (v) => ['all', '13+', '18+'].includes(v), price: (v) => typeof v === 'string' && (v === 'free' || /^\$\d+\.\d{2}$/.test(v)), ai_generated: (v) => typeof v === 'boolean' || v === 'true' || v === 'false', generation_method: (v) => ['human', 'ChatGPT', 'Claude', 'hybrid'].includes(v), created_date: (v) => { if (typeof v !== 'string') return false; // More flexible date validation - accept common formats // ISO8601, US format, European format, simple dates const datePatterns = [ /^\d{4}-\d{2}-\d{2}$/, // YYYY-MM-DD /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/, // ISO8601 with time /^\d{1,2}\/\d{1,2}\/\d{4}$/, // MM/DD/YYYY or M/D/YYYY /^\d{1,2}-\d{1,2}-\d{4}$/, // MM-DD-YYYY or M-D-YYYY /^\d{1,2}\.\d{1,2}\.\d{4}$/, // DD.MM.YYYY (European) /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+\d{1,2},?\s+\d{4}$/i // Month DD, YYYY ]; // Check if it matches common patterns first const matchesPattern = datePatterns.some(pattern => pattern.test(v.trim())); if (!matchesPattern) { // Fall back to Date.parse for other formats, but be more lenient const parsed = Date.parse(v); return !Number.isNaN(parsed) && parsed > 0; // Ensure it's a valid positive timestamp } return true; }, triggers: (v) => Array.isArray(v) && v.every(t => typeof t === 'string' && t.length <= 50), content_flags: (v) => Array.isArray(v) && v.every(f => typeof f === 'string' && f.length <= 50) }; /** * Parse a Markdown file with YAML frontmatter (Securely) * * @param input - The full content of a Markdown file with YAML frontmatter * @param options - Parsing options for security and validation * @returns ParsedContent with separated YAML data and Markdown content * * @example * ```typescript * // For a persona file: * const personaFile = `--- * name: Creative Writer * description: A creative writing assistant * --- * You are a creative writer...`; * * const result = SecureYamlParser.parse(personaFile); * // result.data = { name: 'Creative Writer', description: '...' } * // result.content = 'You are a creative writer...' * ``` */ static parse(input, options = {}) { const opts = { ...this.DEFAULT_OPTIONS, ...options }; // 1. Size validation if (input.length > (opts.maxContentSize || this.DEFAULT_OPTIONS.maxContentSize)) { throw new SecurityError('Content exceeds maximum allowed size', 'medium'); } // 2. Extract frontmatter boundaries // FIX: Support both Unix (\n) and Windows (\r\n) line endings const frontmatterMatch = input.match(/^---\r?\n([\s\S]*?)\r?\n---/); if (!frontmatterMatch) { // No frontmatter, return empty data return { data: {}, content: input }; } const yamlContent = frontmatterMatch[1]; const markdownContent = input.substring(frontmatterMatch[0].length); // 3. Validate YAML size if (yamlContent.length > (opts.maxYamlSize || this.DEFAULT_OPTIONS.maxYamlSize)) { throw new SecurityError('YAML frontmatter exceeds maximum allowed size', 'medium'); } // 4. Pre-parse security validation // FIX (Issue #1211): Only validate content if validateContent option is true if (opts.validateContent && !ContentValidator.validateYamlContent(yamlContent)) { SecurityMonitor.logSecurityEvent({ type: 'YAML_INJECTION_ATTEMPT', severity: 'CRITICAL', source: 'SecureYamlParser', details: 'Malicious YAML pattern detected during parsing' }); throw new SecurityError('Malicious YAML content detected', 'critical'); } // 5. Parse with safe schema let data; try { data = yaml.load(yamlContent, { schema: this.SAFE_SCHEMA, json: false, // Don't allow JSON-specific types onWarning: (warning) => { SecurityMonitor.logSecurityEvent({ type: 'YAML_PARSING_WARNING', severity: 'LOW', source: 'SecureYamlParser', details: `YAML warning: ${warning.message}` }); } }); } catch (error) { throw new SecurityError(`YAML parsing failed: ${error instanceof Error ? error.message : 'Unknown error'}`, 'high'); } // 6. Ensure data is an object if (typeof data !== 'object' || data === null || Array.isArray(data)) { throw new SecurityError('YAML must contain an object at root level', 'medium'); } // 7. Validate allowed keys if specified if (opts.allowedKeys) { const invalidKeys = Object.keys(data).filter(key => !opts.allowedKeys.includes(key)); if (invalidKeys.length > 0) { throw new SecurityError(`Invalid YAML keys detected: ${invalidKeys.join(', ')}`, 'medium'); } } // 8. Validate field types and content for (const [key, value] of Object.entries(data)) { const hasFieldValidator = Object.prototype.hasOwnProperty.call(this.FIELD_VALIDATORS, key); const fieldValidator = hasFieldValidator ? this.FIELD_VALIDATORS[key] : undefined; // Check field-specific validators only if field validation is enabled if (opts.validateFields && typeof fieldValidator === 'function' && !fieldValidator(value)) { throw new SecurityError(`Invalid value for field '${key}'`, 'medium'); } // Validate string fields for injection patterns if (typeof value === 'string' && opts.validateContent) { const validation = ContentValidator.validateAndSanitize(value, { contentContext: opts.contentContext, }); if (!validation.isValid && validation.severity === 'critical') { throw new SecurityError(`Security threat detected in field '${key}'`, 'critical'); } // Replace with sanitized content data[key] = validation.sanitizedContent; } } // 9. Validate markdown content if requested let finalContent = markdownContent; if (opts.validateContent) { const contentValidation = ContentValidator.validateAndSanitize(markdownContent, { contentContext: opts.contentContext, }); if (!contentValidation.isValid && contentValidation.severity === 'critical') { throw new SecurityError('Security threat detected in content', 'critical'); } finalContent = contentValidation.sanitizedContent || markdownContent; } return { data, content: finalContent }; } /** * Create a secure gray-matter compatible parser */ static createSecureMatterParser() { return { parse: (input) => { const result = this.parse(input); return { data: result.data, content: result.content, excerpt: result.excerpt, orig: input }; }, stringify: (content, data) => { // Validate data before stringifying const validation = ContentValidator.validateMetadata(data); if (!validation.isValid) { throw new SecurityError('Cannot stringify content with security threats', 'high'); } // Use safe YAML dump const yamlStr = yaml.dump(data, { schema: this.SAFE_SCHEMA, skipInvalid: true, noRefs: true, noCompatMode: true }); return `---\n${yamlStr}---\n${content}`; } }; } /** * Safe wrapper for gray-matter with security validations */ static safeMatter(input, options, secureOptions) { // First, use our secure parser (for validation) this.parse(input, secureOptions); // Then use gray-matter with custom engines return matter(input, { ...options, engines: { yaml: { parse: (str) => { // Use our secure YAML parsing const parsed = yaml.load(str, { schema: this.SAFE_SCHEMA, json: false }); // Ensure it's an object if (typeof parsed !== 'object' || parsed === null) { return {}; } return parsed; }, stringify: (obj) => { return yaml.dump(obj, { schema: this.SAFE_SCHEMA, skipInvalid: true, noRefs: true }); } } } }); } /** * Parse raw YAML content safely (not frontmatter, just plain YAML) * * USE THIS FOR: * - Export package data fields * - Configuration snippets * - Any pure YAML string that needs parsing * * This uses CORE_SCHEMA which only allows safe basic types: * - strings, numbers, booleans, null * - arrays and objects * - NO custom types, functions, or code execution * * @param yamlContent - Raw YAML string to parse * @param maxSize - Maximum allowed size (default 64KB) * @returns Parsed object * @throws SecurityError if content is too large or contains threats */ static parseRawYaml(yamlContent, maxSize = 64 * 1024) { // Size validation if (yamlContent.length > maxSize) { throw new SecurityError('YAML content exceeds maximum allowed size', 'medium'); } // Fix #908: YAML bomb detection — previously skipped, allowing bomb payloads // through MCP-AQL create dispatcher and web routes that use parseRawYaml(). if (!ContentValidator.validateYamlContent(yamlContent)) { SecurityMonitor.logSecurityEvent({ type: 'YAML_INJECTION_ATTEMPT', severity: 'CRITICAL', source: 'SecureYamlParser.parseRawYaml', details: 'Malicious YAML pattern detected in raw YAML content' }); throw new SecurityError('Malicious YAML content detected', 'critical'); } // Parse with safe schema const parsed = yaml.load(yamlContent, { schema: this.SAFE_SCHEMA, // CORE_SCHEMA - safe basic types only json: false }); // Ensure result is an object if (typeof parsed !== 'object' || parsed === null) { throw new SecurityError('YAML content must parse to an object', 'medium'); } return parsed; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VjdXJlWWFtbFBhcnNlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZWN1cml0eS9zZWN1cmVZYW1sUGFyc2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQ0c7QUFFSCxPQUFPLEtBQUssSUFBSSxNQUFNLFNBQVMsQ0FBQztBQUNoQyxPQUFPLE1BQU0sTUFBTSxhQUFhLENBQUM7QUFDakMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQzNELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQWtCdkQsTUFBTSxPQUFPLGdCQUFnQjtJQUNuQixNQUFNLENBQVUsZUFBZSxHQUF1QjtRQUM1RCxXQUFXLEVBQUUsRUFBRSxHQUFHLElBQUksRUFBTyxnQkFBZ0I7UUFDN0MsY0FBYyxFQUFFLElBQUksR0FBRyxJQUFJLEVBQUcsa0JBQWtCO1FBQ2hELGVBQWUsRUFBRSxJQUFJO1FBQ3JCLGNBQWMsRUFBRSxJQUFJLENBQVMscUNBQXFDO0tBQ25FLENBQUM7SUFFRixtR0FBbUc7SUFDM0YsTUFBTSxDQUFVLFdBQVcsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDO0lBRXZELG9EQUFvRDtJQUM1QyxNQUFNLENBQVUsZ0JBQWdCLEdBQTRDO1FBQ2xGLElBQUksRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssUUFBUSxJQUFJLENBQUMsQ0FBQyxNQUFNLElBQUksR0FBRztRQUNyRCxXQUFXLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLFFBQVE7UUFDekMsTUFBTSxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxRQUFRLElBQUksQ0FBQyxD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RUQseUJBQXlCO1FBQ3pCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFO1lBQ3BDLE1BQU0sRUFBRSxJQUFJLENBQUMsV0FBVyxFQUFHLHNDQUFzQztZQUNqRSxJQUFJLEVBQUUsS0FBSztTQUNaLENBQUMsQ0FBQztRQUVILDZCQUE2QjtRQUM3QixJQUFJLE9BQU8sTUFBTSxLQUFLLFFBQVEsSUFBSSxNQUFNLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDbEQsTUFBTSxJQUFJLGFBQWEsQ0FBQyxzQ0FBc0MsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUM1RSxDQUFDO1FBRUQsT0FBTyxNQUFpQyxDQUFDO0lBQzNDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNlY3VyZSBZQU1MIFBhcnNlciBmb3IgRG9sbGhvdXNlTUNQIC0gRm9yIE1hcmtkb3duIEZpbGVzIHdpdGggWUFNTCBGcm9udG1hdHRlclxuICogXG4gKiBJTVBPUlRBTlQ6IFRoaXMgcGFyc2VyIGlzIHNwZWNpZmljYWxseSBkZXNpZ25lZCBmb3IgTWFya2Rvd24gZmlsZXMgd2l0aCBZQU1MIGZyb250bWF0dGVyXG4gKiAodGhlIGZvcm1hdCB1c2VkIGJ5IHBlcnNvbmFzLCBza2lsbHMsIHRlbXBsYXRlcywgYW5kIG90aGVyIGVsZW1lbnRzKS5cbiAqIFxuICogVVNFIFRISVMgRk9SOlxuICogLSBQZXJzb25hIGZpbGVzIChlLmcuLCBjcmVhdGl2ZS13cml0ZXIubWQpXG4gKiAtIFNraWxsIGZpbGVzIChlLmcuLCBjb2RlLXJldmlldy5tZClcbiAqIC0gVGVtcGxhdGUgZmlsZXMgKGUuZy4sIG1lZXRpbmctbm90ZXMubWQpXG4gKiAtIEFueSBNYXJrZG93biBmaWxlIHdpdGggWUFNTCBmcm9udG1hdHRlciBiZXR3ZWVuIC0tLSBtYXJrZXJzXG4gKiBcbiAqIERPIE5PVCBVU0UgVEhJUyBGT1I6XG4gKiAtIFB1cmUgWUFNTCBjb25maWd1cmF0aW9uIGZpbGVzICh1c2UganMteWFtbCBkaXJlY3RseSB3aXRoIEZBSUxTQUZFX1NDSEVNQSlcbiAqIC0gSlNPTiBmaWxlc1xuICogLSBQbGFpbiB0ZXh0IGZpbGVzIHdpdGhvdXQgZnJvbnRtYXR0ZXJcbiAqIFxuICogRklMRSBGT1JNQVQgRVhQRUNURUQ6XG4gKiBgYGBcbiAqIC0tLVxuICogbmFtZTogRWxlbWVudCBOYW1lXG4gKiBkZXNjcmlwdGlvbjogRWxlbWVudCBkZXNjcmlwdGlvblxuICogdmVyc2lvbjogMS4wLjBcbiAqIC0tLVxuICogXG4gKiAjIE1hcmtkb3duIGNvbnRlbnQgaGVyZVxuICogVGhlIGFjdHVhbCBjb250ZW50L2luc3RydWN0aW9ucyBnbyBoZXJlLi4uXG4gKiBgYGBcbiAqIFxuICogUHJvdmlkZXMgc2FmZSBZQU1MIHBhcnNpbmcgdGhhdCBwcmV2ZW50cyBkZXNlcmlhbGl6YXRpb24gYXR0YWNrc1xuICogYnkgdXNpbmcgYSByZXN0cmljdGVkIHNjaGVtYSBhbmQgcHJlLXZhbGlkYXRpb24uXG4gKiBcbiAqIFNlY3VyaXR5OiBTRUMtMDAzIC0gWUFNTCBwYXJzaW5nIHZ1bG5lcmFiaWxpdHkgcHJvdGVjdGlvblxuICovXG5cbmltcG9ydCAqIGFzIHlhbWwgZnJvbSAnanMteWFtbCc7XG5pbXBvcnQgbWF0dGVyIGZyb20gJ2dyYXktbWF0dGVyJztcbmltcG9ydCB7IFNlY3VyaXR5RXJyb3IgfSBmcm9tICcuLi9lcnJvcnMvU2VjdXJpdHlFcnJvci5qcyc7XG5pbXBvcnQgeyBDb250ZW50VmFsaWRhdG9yIH0gZnJvbSAnLi9jb250ZW50VmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IFNlY3VyaXR5TW9uaXRvciB9IGZyb20gJy4vc2VjdXJpdHlNb25pdG9yLmpzJztcblxuZXhwb3J0IGludGVyZmFjZSBTZWN1cmVQYXJzZU9wdGlvbnMge1xuICBtYXhZYW1sU2l6ZT86IG51bWJlcjtcbiAgbWF4Q29udGVudFNpemU/OiBudW1iZXI7XG4gIGFsbG93ZWRLZXlzPzogc3RyaW5nW107XG4gIHZhbGlkYXRlQ29udGVudD86IGJvb2xlYW47XG4gIHZhbGlkYXRlRmllbGRzPzogYm9vbGVhbjsgLy8gV2hldGhlciB0byBhcHBseSBmaWVsZC1zcGVjaWZpYyB2YWxpZGF0b3JzIChmb3IgcGVyc29uYSBtZXRhZGF0YSlcbiAgLyoqIENvbnRlbnQgY29udGV4dCBmb3IgQ29udGVudFZhbGlkYXRvciDigJQgZXhlbXB0cyBsZWdpdGltYXRlIHBhdHRlcm5zIChlLmcuLCA8c2NyaXB0PiBpbiB0ZW1wbGF0ZXMpICovXG4gIGNvbnRlbnRDb250ZXh0PzogJ3BlcnNvbmEnIHwgJ3NraWxsJyB8ICd0ZW1wbGF0ZScgfCAnYWdlbnQnIHwgJ21lbW9yeSc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFyc2VkQ29udGVudCB7XG4gIGRhdGE6IFJlY29yZDxzdHJpbmcsIGFueT47XG4gIGNvbnRlbnQ6IHN0cmluZztcbiAgZXhjZXJwdD86IHN0cmluZztcbn1cblxuZXhwb3J0IGNsYXNzIFNlY3VyZVlhbWxQYXJzZXIge1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBERUZBVUxUX09QVElPTlM6IFNlY3VyZVBhcnNlT3B0aW9ucyA9IHtcbiAgICBtYXhZYW1sU2l6ZTogNjQgKiAxMDI0LCAgICAgIC8vIDY0S0IgZm9yIFlBTUxcbiAgICBtYXhDb250ZW50U2l6ZTogMTAyNCAqIDEwMjQsICAvLyAxTUIgZm9yIGNvbnRlbnRcbiAgICB2YWxpZGF0ZUNvbnRlbnQ6IHRydWUsXG4gICAgdmFsaWRhdGVGaWVsZHM6IHRydWUgICAgICAgICAvLyBCeSBkZWZhdWx0LCBhcHBseSBmaWVsZCB2YWxpZGF0b3JzXG4gIH07XG5cbiAgLy8gQWxsb3dlZCBZQU1MIHR5cGVzIC0gdXNpbmcgQ09SRV9TQ0hFTUEgKHNhZmUgc3Vic2V0IHdpdGggYmFzaWMgdHlwZXMgbGlrZSBib29sZWFucyBhbmQgaW50ZWdlcnMpXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IFNBRkVfU0NIRU1BID0geWFtbC5DT1JFX1NDSEVNQTtcblxuICAvLyBBZGRpdGlvbmFsIHZhbGlkYXRpb24gZm9yIHNwZWNpZmljIHBlcnNvbmEgZmllbGRzXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IEZJRUxEX1ZBTElEQVRPUlM6IFJlY29yZDxzdHJpbmcsICh2YWx1ZTogYW55KSA9PiBib29sZWFuPiA9IHtcbiAgICBuYW1lOiAodikgPT4gdHlwZW9mIHYgPT09ICdzdHJpbmcnICYmIHYubGVuZ3RoIDw9IDEwMCxcbiAgICBkZXNjcmlwdGlvbjogKHYpID0+IHR5cGVvZiB2ID09PSAnc3RyaW5nJyxcbiAgICBhdXRob3I6ICh2KSA9PiB0eXBlb2YgdiA9PT0gJ3N0cmluZycgJiYgdi5sZW5ndGggPD0gMTAwLFxuICAgIHZlcnNpb246ICh2KSA9PiB0eXBlb2YgdiA9PT0gJ3N0cmluZycgJiYgL15cXGQrXFwuXFxkKyhcXC5cXGQrKT8oLVthLXpBLVowLTkuLV0rKT8kLy50ZXN0KHYpLFxuICAgIGNhdGVnb3J5OiAodikgPT4gdHlwZW9mIHYgPT09ICdzdHJpbmcnICYmIHYubGVuZ3RoIDw9IDUwLFxuICAgIGFnZV9yYXRpbmc6ICh2KSA9PiBbJ2FsbCcsICcxMysnLCAnMTgrJ10uaW5jbHVkZXModiksXG4gICAgcHJpY2U6ICh2KSA9PiB0eXBlb2YgdiA9PT0gJ3N0cmluZycgJiYgKHYgPT09ICdmcmVlJyB8fCAvXlxcJFxcZCtcXC5cXGR7Mn0kLy50ZXN0KHYpKSxcbiAgICBhaV9nZW5lcmF0ZWQ6ICh2KSA9PiB0eXBlb2YgdiA9PT0gJ2Jvb2xlYW4nIHx8IHYgPT09ICd0cnVlJyB8fCB2ID09PSAnZmFsc2UnLFxuICAgIGdlbmVyYXRpb25fbWV0aG9kOiAodikgPT4gWydodW1hbicsICdDaGF0R1BUJywgJ0NsYXVkZScsICdoeWJyaWQnXS5pbmNsdWRlcyh2KSxcbiAgICBjcmVhdGVkX2RhdGU6ICh2KSA9PiB7XG4gICAgICBpZiAodHlwZW9mIHYgIT09ICdzdHJpbmcnKSByZXR1cm4gZmFsc2U7XG4gICAgICBcbiAgICAgIC8vIE1vcmUgZmxleGlibGUgZGF0ZSB2YWxpZGF0aW9uIC0gYWNjZXB0IGNvbW1vbiBmb3JtYXRzXG4gICAgICAvLyBJU084NjAxLCBVUyBmb3JtYXQsIEV1cm9wZWFuIGZvcm1hdCwgc2ltcGxlIGRhdGVzXG4gICAgICBjb25zdCBkYXRlUGF0dGVybnMgPSBbXG4gICAgICAgIC9eXFxkezR9LVxcZHsyfS1cXGR7Mn0kLywgLy8gWVlZWS1NTS1ERFxuICAgICAgICAvXlxcZHs0fS1cXGR7Mn0tXFxkezJ9VFxcZHsyfTpcXGR7Mn06XFxkezJ9LywgLy8gSVNPODYwMSB3aXRoIHRpbWVcbiAgICAgICAgL15cXGR7MSwyfVxcL1xcZHsxLDJ9XFwvXFxkezR9JC8sIC8vIE1NL0REL1lZWVkgb3IgTS9EL1lZWVlcbiAgICAgICAgL15cXGR7MSwyfS1cXGR7MSwyfS1cXGR7NH0kLywgLy8gTU0tREQtWVlZWSBvciBNLUQtWVlZWVxuICAgICAgICAvXlxcZHsxLDJ9XFwuXFxkezEsMn1cXC5cXGR7NH0kLywgLy8gREQuTU0uWVlZWSAoRXVyb3BlYW4pXG4gICAgICAgIC9eKEphbnxGZWJ8TWFyfEFwcnxNYXl8SnVufEp1bHxBdWd8U2VwfE9jdHxOb3Z8RGVjKVxccytcXGR7MSwyfSw/XFxzK1xcZHs0fSQvaSAvLyBNb250aCBERCwgWVlZWVxuICAgICAgXTtcbiAgICAgIFxuICAgICAgLy8gQ2hlY2sgaWYgaXQgbWF0Y2hlcyBjb21tb24gcGF0dGVybnMgZmlyc3RcbiAgICAgIGNvbnN0IG1hdGNoZXNQYXR0ZXJuID0gZGF0ZVBhdHRlcm5zLnNvbWUocGF0dGVybiA9PiBwYXR0ZXJuLnRlc3Qodi50cmltKCkpKTtcbiAgICAgIGlmICghbWF0Y2hlc1BhdHRlcm4pIHtcbiAgICAgICAgLy8gRmFsbCBiYWNrIHRvIERhdGUucGFyc2UgZm9yIG90aGVyIGZvcm1hdHMsIGJ1dCBiZSBtb3JlIGxlbmllbnRcbiAgICAgICAgY29uc3QgcGFyc2VkID0gRGF0ZS5wYXJzZSh2KTtcbiAgICAgICAgcmV0dXJuICFOdW1iZXIuaXNOYU4ocGFyc2VkKSAmJiBwYXJzZWQgPiAwOyAvLyBFbnN1cmUgaXQncyBhIHZhbGlkIHBvc2l0aXZlIHRpbWVzdGFtcFxuICAgICAgfVxuICAgICAgXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9LFxuICAgIHRyaWdnZXJzOiAodikgPT4gQXJyYXkuaXNBcnJheSh2KSAmJiB2LmV2ZXJ5KHQgPT4gdHlwZW9mIHQgPT09ICdzdHJpbmcnICYmIHQubGVuZ3RoIDw9IDUwKSxcbiAgICBjb250ZW50X2ZsYWdzOiAodikgPT4gQXJyYXkuaXNBcnJheSh2KSAmJiB2LmV2ZXJ5KGYgPT4gdHlwZW9mIGYgPT09ICdzdHJpbmcnICYmIGYubGVuZ3RoIDw9IDUwKVxuICB9O1xuXG4gIC8qKlxuICAgKiBQYXJzZSBhIE1hcmtkb3duIGZpbGUgd2l0aCBZQU1MIGZyb250bWF0dGVyIChTZWN1cmVseSlcbiAgICogXG4gICAqIEBwYXJhbSBpbnB1dCAtIFRoZSBmdWxsIGNvbnRlbnQgb2YgYSBNYXJrZG93biBmaWxlIHdpdGggWUFNTCBmcm9udG1hdHRlclxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIFBhcnNpbmcgb3B0aW9ucyBmb3Igc2VjdXJpdHkgYW5kIHZhbGlkYXRpb25cbiAgICogQHJldHVybnMgUGFyc2VkQ29udGVudCB3aXRoIHNlcGFyYXRlZCBZQU1MIGRhdGEgYW5kIE1hcmtkb3duIGNvbnRlbnRcbiAgICogXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gRm9yIGEgcGVyc29uYSBmaWxlOlxuICAgKiBjb25zdCBwZXJzb25hRmlsZSA9IGAtLS1cbiAgICogbmFtZTogQ3JlYXRpdmUgV3JpdGVyXG4gICAqIGRlc2NyaXB0aW9uOiBBIGNyZWF0aXZlIHdyaXRpbmcgYXNzaXN0YW50XG4gICAqIC0tLVxuICAgKiBZb3UgYXJlIGEgY3JlYXRpdmUgd3JpdGVyLi4uYDtcbiAgICogXG4gICAqIGNvbnN0IHJlc3VsdCA9IFNlY3VyZVlhbWxQYXJzZXIucGFyc2UocGVyc29uYUZpbGUpO1xuICAgKiAvLyByZXN1bHQuZGF0YSA9IHsgbmFtZTogJ0NyZWF0aXZlIFdyaXRlcicsIGRlc2NyaXB0aW9uOiAnLi4uJyB9XG4gICAqIC8vIHJlc3VsdC5jb250ZW50ID0gJ1lvdSBhcmUgYSBjcmVhdGl2ZSB3cml0ZXIuLi4nXG4gICAqIGBgYFxuICAgKi9cbiAgc3RhdGljIHBhcnNlKGlucHV0OiBzdHJpbmcsIG9wdGlvbnM6IFNlY3VyZVBhcnNlT3B0aW9ucyA9IHt9KTogUGFyc2VkQ29udGVudCB7XG4gICAgY29uc3Qgb3B0cyA9IHsgLi4udGhpcy5ERUZBVUxUX09QVElPTlMsIC4uLm9wdGlvbnMgfTtcblxuICAgIC8vIDEuIFNpemUgdmFsaWRhdGlvblxuICAgIGlmIChpbnB1dC5sZW5ndGggPiAob3B0cy5tYXhDb250ZW50U2l6ZSB8fCB0aGlzLkRFRkFVTFRfT1BUSU9OUy5tYXhDb250ZW50U2l6ZSEpKSB7XG4gICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFcnJvcignQ29udGVudCBleGNlZWRzIG1heGltdW0gYWxsb3dlZCBzaXplJywgJ21lZGl1bScpO1xuICAgIH1cblxuICAgIC8vIDIuIEV4dHJhY3QgZnJvbnRtYXR0ZXIgYm91bmRhcmllc1xuICAgIC8vIEZJWDogU3VwcG9ydCBib3RoIFVuaXggKFxcbikgYW5kIFdpbmRvd3MgKFxcclxcbikgbGluZSBlbmRpbmdzXG4gICAgY29uc3QgZnJvbnRtYXR0ZXJNYXRjaCA9IGlucHV0Lm1hdGNoKC9eLS0tXFxyP1xcbihbXFxzXFxTXSo/KVxccj9cXG4tLS0vKTtcbiAgICBpZiAoIWZyb250bWF0dGVyTWF0Y2gpIHtcbiAgICAgIC8vIE5vIGZyb250bWF0dGVyLCByZXR1cm4gZW1wdHkgZGF0YVxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZGF0YToge30sXG4gICAgICAgIGNvbnRlbnQ6IGlucHV0XG4gICAgICB9O1xuICAgIH1cblxuICAgIGNvbnN0IHlhbWxDb250ZW50ID0gZnJvbnRtYXR0ZXJNYXRjaFsxXTtcbiAgICBjb25zdCBtYXJrZG93bkNvbnRlbnQgPSBpbnB1dC5zdWJzdHJpbmcoZnJvbnRtYXR0ZXJNYXRjaFswXS5sZW5ndGgpO1xuXG4gICAgLy8gMy4gVmFsaWRhdGUgWUFNTCBzaXplXG4gICAgaWYgKHlhbWxDb250ZW50Lmxlbmd0aCA+IChvcHRzLm1heFlhbWxTaXplIHx8IHRoaXMuREVGQVVMVF9PUFRJT05TLm1heFlhbWxTaXplISkpIHtcbiAgICAgIHRocm93IG5ldyBTZWN1cml0eUVycm9yKCdZQU1MIGZyb250bWF0dGVyIGV4Y2VlZHMgbWF4aW11bSBhbGxvd2VkIHNpemUnLCAnbWVkaXVtJyk7XG4gICAgfVxuXG4gICAgLy8gNC4gUHJlLXBhcnNlIHNlY3VyaXR5IHZhbGlkYXRpb25cbiAgICAvLyBGSVggKElzc3VlICMxMjExKTogT25seSB2YWxpZGF0ZSBjb250ZW50IGlmIHZhbGlkYXRlQ29udGVudCBvcHRpb24gaXMgdHJ1ZVxuICAgIGlmIChvcHRzLnZhbGlkYXRlQ29udGVudCAmJiAhQ29udGVudFZhbGlkYXRvci52YWxpZGF0ZVlhbWxDb250ZW50KHlhbWxDb250ZW50KSkge1xuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnWUFNTF9JTkpFQ1RJT05fQVRURU1QVCcsXG4gICAgICAgIHNldmVyaXR5OiAnQ1JJVElDQUwnLFxuICAgICAgICBzb3VyY2U6ICdTZWN1cmVZYW1sUGFyc2VyJyxcbiAgICAgICAgZGV0YWlsczogJ01hbGljaW91cyBZQU1MIHBhdHRlcm4gZGV0ZWN0ZWQgZHVyaW5nIHBhcnNpbmcnXG4gICAgICB9KTtcbiAgICAgIHRocm93IG5ldyBTZWN1cml0eUVycm9yKCdNYWxpY2lvdXMgWUFNTCBjb250ZW50IGRldGVjdGVkJywgJ2NyaXRpY2FsJyk7XG4gICAgfVxuXG4gICAgLy8gNS4gUGFyc2Ugd2l0aCBzYWZlIHNjaGVtYVxuICAgIGxldCBkYXRhOiBhbnk7XG4gICAgdHJ5IHtcbiAgICAgIGRhdGEgPSB5YW1sLmxvYWQoeWFtbENvbnRlbnQsIHtcbiAgICAgICAgc2NoZW1hOiB0aGlzLlNBRkVfU0NIRU1BLFxuICAgICAgICBqc29uOiBmYWxzZSwgIC8vIERvbid0IGFsbG93IEpTT04tc3BlY2lmaWMgdHlwZXNcbiAgICAgICAgb25XYXJuaW5nOiAod2FybmluZykgPT4ge1xuICAgICAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgICAgIHR5cGU6ICdZQU1MX1BBUlNJTkdfV0FSTklORycsXG4gICAgICAgICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICAgICAgICBzb3VyY2U6ICdTZWN1cmVZYW1sUGFyc2VyJyxcbiAgICAgICAgICAgIGRldGFpbHM6IGBZQU1MIHdhcm5pbmc6ICR7d2FybmluZy5tZXNzYWdlfWBcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBTZWN1cml0eUVycm9yKGBZQU1MIHBhcnNpbmcgZmFpbGVkOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogJ1Vua25vd24gZXJyb3InfWAsICdoaWdoJyk7XG4gICAgfVxuXG4gICAgLy8gNi4gRW5zdXJlIGRhdGEgaXMgYW4gb2JqZWN0XG4gICAgaWYgKHR5cGVvZiBkYXRhICE9PSAnb2JqZWN0JyB8fCBkYXRhID09PSBudWxsIHx8IEFycmF5LmlzQXJyYXkoZGF0YSkpIHtcbiAgICAgIHRocm93IG5ldyBTZWN1cml0eUVycm9yKCdZQU1MIG11c3QgY29udGFpbiBhbiBvYmplY3QgYXQgcm9vdCBsZXZlbCcsICdtZWRpdW0nKTtcbiAgICB9XG5cbiAgICAvLyA3LiBWYWxpZGF0ZSBhbGxvd2VkIGtleXMgaWYgc3BlY2lmaWVkXG4gICAgaWYgKG9wdHMuYWxsb3dlZEtleXMpIHtcbiAgICAgIGNvbnN0IGludmFsaWRLZXlzID0gT2JqZWN0LmtleXMoZGF0YSkuZmlsdGVyKGtleSA9PiAhb3B0cy5hbGxvd2VkS2V5cyEuaW5jbHVkZXMoa2V5KSk7XG4gICAgICBpZiAoaW52YWxpZEtleXMubGVuZ3RoID4gMCkge1xuICAgICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFcnJvcihgSW52YWxpZCBZQU1MIGtleXMgZGV0ZWN0ZWQ6ICR7aW52YWxpZEtleXMuam9pbignLCAnKX1gLCAnbWVkaXVtJyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gOC4gVmFsaWRhdGUgZmllbGQgdHlwZXMgYW5kIGNvbnRlbnRcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhkYXRhKSkge1xuICAgICAgY29uc3QgaGFzRmllbGRWYWxpZGF0b3IgPSBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodGhpcy5GSUVMRF9WQUxJREFUT1JTLCBrZXkpO1xuICAgICAgY29uc3QgZmllbGRWYWxpZGF0b3IgPSBoYXNGaWVsZFZhbGlkYXRvciA/IHRoaXMuRklFTERfVkFMSURBVE9SU1trZXldIDogdW5kZWZpbmVkO1xuXG4gICAgICAvLyBDaGVjayBmaWVsZC1zcGVjaWZpYyB2YWxpZGF0b3JzIG9ubHkgaWYgZmllbGQgdmFsaWRhdGlvbiBpcyBlbmFibGVkXG4gICAgICBpZiAob3B0cy52YWxpZGF0ZUZpZWxkcyAmJiB0eXBlb2YgZmllbGRWYWxpZGF0b3IgPT09ICdmdW5jdGlvbicgJiYgIWZpZWxkVmFsaWRhdG9yKHZhbHVlKSkge1xuICAgICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFcnJvcihgSW52YWxpZCB2YWx1ZSBmb3IgZmllbGQgJyR7a2V5fSdgLCAnbWVkaXVtJyk7XG4gICAgICB9XG5cbiAgICAgIC8vIFZhbGlkYXRlIHN0cmluZyBmaWVsZHMgZm9yIGluamVjdGlvbiBwYXR0ZXJuc1xuICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgb3B0cy52YWxpZGF0ZUNvbnRlbnQpIHtcbiAgICAgICAgY29uc3QgdmFsaWRhdGlvbiA9IENvbnRlbnRWYWxpZGF0b3IudmFsaWRhdGVBbmRTYW5pdGl6ZSh2YWx1ZSwge1xuICAgICAgICAgIGNvbnRlbnRDb250ZXh0OiBvcHRzLmNvbnRlbnRDb250ZXh0LFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKCF2YWxpZGF0aW9uLmlzVmFsaWQgJiYgdmFsaWRhdGlvbi5zZXZlcml0eSA9PT0gJ2NyaXRpY2FsJykge1xuICAgICAgICAgIHRocm93IG5ldyBTZWN1cml0eUVycm9yKGBTZWN1cml0eSB0aHJlYXQgZGV0ZWN0ZWQgaW4gZmllbGQgJyR7a2V5fSdgLCAnY3JpdGljYWwnKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBSZXBsYWNlIHdpdGggc2FuaXRpemVkIGNvbnRlbnRcbiAgICAgICAgZGF0YVtrZXldID0gdmFsaWRhdGlvbi5zYW5pdGl6ZWRDb250ZW50O1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIDkuIFZhbGlkYXRlIG1hcmtkb3duIGNvbnRlbnQgaWYgcmVxdWVzdGVkXG4gICAgbGV0IGZpbmFsQ29udGVudCA9IG1hcmtkb3duQ29udGVudDtcbiAgICBpZiAob3B0cy52YWxpZGF0ZUNvbnRlbnQpIHtcbiAgICAgIGNvbnN0IGNvbnRlbnRWYWxpZGF0aW9uID0gQ29udGVudFZhbGlkYXRvci52YWxpZGF0ZUFuZFNhbml0aXplKG1hcmtkb3duQ29udGVudCwge1xuICAgICAgICBjb250ZW50Q29udGV4dDogb3B0cy5jb250ZW50Q29udGV4dCxcbiAgICAgIH0pO1xuICAgICAgaWYgKCFjb250ZW50VmFsaWRhdGlvbi5pc1ZhbGlkICYmIGNvbnRlbnRWYWxpZGF0aW9uLnNldmVyaXR5ID09PSAnY3JpdGljYWwnKSB7XG4gICAgICAgIHRocm93IG5ldyBTZWN1cml0eUVycm9yKCdTZWN1cml0eSB0aHJlYXQgZGV0ZWN0ZWQgaW4gY29udGVudCcsICdjcml0aWNhbCcpO1xuICAgICAgfVxuICAgICAgZmluYWxDb250ZW50ID0gY29udGVudFZhbGlkYXRpb24uc2FuaXRpemVkQ29udGVudCB8fCBtYXJrZG93bkNvbnRlbnQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGRhdGEsXG4gICAgICBjb250ZW50OiBmaW5hbENvbnRlbnRcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIHNlY3VyZSBncmF5LW1hdHRlciBjb21wYXRpYmxlIHBhcnNlclxuICAgKi9cbiAgc3RhdGljIGNyZWF0ZVNlY3VyZU1hdHRlclBhcnNlcigpIHtcbiAgICByZXR1cm4ge1xuICAgICAgcGFyc2U6IChpbnB1dDogc3RyaW5nKSA9PiB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMucGFyc2UoaW5wdXQpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGRhdGE6IHJlc3VsdC5kYXRhLFxuICAgICAgICAgIGNvbnRlbnQ6IHJlc3VsdC5jb250ZW50LFxuICAgICAgICAgIGV4Y2VycHQ6IHJlc3VsdC5leGNlcnB0LFxuICAgICAgICAgIG9yaWc6IGlucHV0XG4gICAgICAgIH07XG4gICAgICB9LFxuICAgICAgc3RyaW5naWZ5OiAoY29udGVudDogc3RyaW5nLCBkYXRhOiBhbnkpID0+IHtcbiAgICAgICAgLy8gVmFsaWRhdGUgZGF0YSBiZWZvcmUgc3RyaW5naWZ5aW5nXG4gICAgICAgIGNvbnN0IHZhbGlkYXRpb24gPSBDb250ZW50VmFsaWRhdG9yLnZhbGlkYXRlTWV0YWRhdGEoZGF0YSk7XG4gICAgICAgIGlmICghdmFsaWRhdGlvbi5pc1ZhbGlkKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IFNlY3VyaXR5RXJyb3IoJ0Nhbm5vdCBzdHJpbmdpZnkgY29udGVudCB3aXRoIHNlY3VyaXR5IHRocmVhdHMnLCAnaGlnaCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVXNlIHNhZmUgWUFNTCBkdW1wXG4gICAgICAgIGNvbnN0IHlhbWxTdHIgPSB5YW1sLmR1bXAoZGF0YSwge1xuICAgICAgICAgIHNjaGVtYTogdGhpcy5TQUZFX1NDSEVNQSxcbiAgICAgICAgICBza2lwSW52YWxpZDogdHJ1ZSxcbiAgICAgICAgICBub1JlZnM6IHRydWUsXG4gICAgICAgICAgbm9Db21wYXRNb2RlOiB0cnVlXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBgLS0tXFxuJHt5YW1sU3RyfS0tLVxcbiR7Y29udGVudH1gO1xuICAgICAgfVxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogU2FmZSB3cmFwcGVyIGZvciBncmF5LW1hdHRlciB3aXRoIHNlY3VyaXR5IHZhbGlkYXRpb25zXG4gICAqL1xuICBzdGF0aWMgc2FmZU1hdHRlcihpbnB1dDogc3RyaW5nLCBvcHRpb25zPzogbWF0dGVyLkdyYXlNYXR0ZXJPcHRpb248c3RyaW5nLCBhbnk+LCBzZWN1cmVPcHRpb25zPzogU2VjdXJlUGFyc2VPcHRpb25zKTogbWF0dGVyLkdyYXlNYXR0ZXJGaWxlPHN0cmluZz4ge1xuICAgIC8vIEZpcnN0LCB1c2Ugb3VyIHNlY3VyZSBwYXJzZXIgKGZvciB2YWxpZGF0aW9uKVxuICAgIHRoaXMucGFyc2UoaW5wdXQsIHNlY3VyZU9wdGlvbnMpO1xuXG4gICAgLy8gVGhlbiB1c2UgZ3JheS1tYXR0ZXIgd2l0aCBjdXN0b20gZW5naW5lc1xuICAgIHJldHVybiBtYXR0ZXIoaW5wdXQsIHtcbiAgICAgIC4uLm9wdGlvbnMsXG4gICAgICBlbmdpbmVzOiB7XG4gICAgICAgIHlhbWw6IHtcbiAgICAgICAgICBwYXJzZTogKHN0cjogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICAvLyBVc2Ugb3VyIHNlY3VyZSBZQU1MIHBhcnNpbmdcbiAgICAgICAgICAgIGNvbnN0IHBhcnNlZCA9IHlhbWwubG9hZChzdHIsIHtcbiAgICAgICAgICAgICAgc2NoZW1hOiB0aGlzLlNBRkVfU0NIRU1BLFxuICAgICAgICAgICAgICBqc29uOiBmYWxzZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAvLyBFbnN1cmUgaXQncyBhbiBvYmplY3RcbiAgICAgICAgICAgIGlmICh0eXBlb2YgcGFyc2VkICE9PSAnb2JqZWN0JyB8fCBwYXJzZWQgPT09IG51bGwpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHBhcnNlZCBhcyBvYmplY3Q7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBzdHJpbmdpZnk6IChvYmo6IGFueSkgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIHlhbWwuZHVtcChvYmosIHtcbiAgICAgICAgICAgICAgc2NoZW1hOiB0aGlzLlNBRkVfU0NIRU1BLFxuICAgICAgICAgICAgICBza2lwSW52YWxpZDogdHJ1ZSxcbiAgICAgICAgICAgICAgbm9SZWZzOiB0cnVlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQYXJzZSByYXcgWUFNTCBjb250ZW50IHNhZmVseSAobm90IGZyb250bWF0dGVyLCBqdXN0IHBsYWluIFlBTUwpXG4gICAqXG4gICAqIFVTRSBUSElTIEZPUjpcbiAgICogLSBFeHBvcnQgcGFja2FnZSBkYXRhIGZpZWxkc1xuICAgKiAtIENvbmZpZ3VyYXRpb24gc25pcHBldHNcbiAgICogLSBBbnkgcHVyZSBZQU1MIHN0cmluZyB0aGF0IG5lZWRzIHBhcnNpbmdcbiAgICpcbiAgICogVGhpcyB1c2VzIENPUkVfU0NIRU1BIHdoaWNoIG9ubHkgYWxsb3dzIHNhZmUgYmFzaWMgdHlwZXM6XG4gICAqIC0gc3RyaW5ncywgbnVtYmVycywgYm9vbGVhbnMsIG51bGxcbiAgICogLSBhcnJheXMgYW5kIG9iamVjdHNcbiAgICogLSBOTyBjdXN0b20gdHlwZXMsIGZ1bmN0aW9ucywgb3IgY29kZSBleGVjdXRpb25cbiAgICpcbiAgICogQHBhcmFtIHlhbWxDb250ZW50IC0gUmF3IFlBTUwgc3RyaW5nIHRvIHBhcnNlXG4gICAqIEBwYXJhbSBtYXhTaXplIC0gTWF4aW11bSBhbGxvd2VkIHNpemUgKGRlZmF1bHQgNjRLQilcbiAgICogQHJldHVybnMgUGFyc2VkIG9iamVjdFxuICAgKiBAdGhyb3dzIFNlY3VyaXR5RXJyb3IgaWYgY29udGVudCBpcyB0b28gbGFyZ2Ugb3IgY29udGFpbnMgdGhyZWF0c1xuICAgKi9cbiAgc3RhdGljIHBhcnNlUmF3WWFtbCh5YW1sQ29udGVudDogc3RyaW5nLCBtYXhTaXplOiBudW1iZXIgPSA2NCAqIDEwMjQpOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gICAgLy8gU2l6ZSB2YWxpZGF0aW9uXG4gICAgaWYgKHlhbWxDb250ZW50Lmxlbmd0aCA+IG1heFNpemUpIHtcbiAgICAgIHRocm93IG5ldyBTZWN1cml0eUVycm9yKCdZQU1MIGNvbnRlbnQgZXhjZWVkcyBtYXhpbXVtIGFsbG93ZWQgc2l6ZScsICdtZWRpdW0nKTtcbiAgICB9XG5cbiAgICAvLyBGaXggIzkwODogWUFNTCBib21iIGRldGVjdGlvbiDigJQgcHJldmlvdXNseSBza2lwcGVkLCBhbGxvd2luZyBib21iIHBheWxvYWRzXG4gICAgLy8gdGhyb3VnaCBNQ1AtQVFMIGNyZWF0ZSBkaXNwYXRjaGVyIGFuZCB3ZWIgcm91dGVzIHRoYXQgdXNlIHBhcnNlUmF3WWFtbCgpLlxuICAgIGlmICghQ29udGVudFZhbGlkYXRvci52YWxpZGF0ZVlhbWxDb250ZW50KHlhbWxDb250ZW50KSkge1xuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnWUFNTF9JTkpFQ1RJT05fQVRURU1QVCcsXG4gICAgICAgIHNldmVyaXR5OiAnQ1JJVElDQUwnLFxuICAgICAgICBzb3VyY2U6ICdTZWN1cmVZYW1sUGFyc2VyLnBhcnNlUmF3WWFtbCcsXG4gICAgICAgIGRldGFpbHM6ICdNYWxpY2lvdXMgWUFNTCBwYXR0ZXJuIGRldGVjdGVkIGluIHJhdyBZQU1MIGNvbnRlbnQnXG4gICAgICB9KTtcbiAgICAgIHRocm93IG5ldyBTZWN1cml0eUVycm9yKCdNYWxpY2lvdXMgWUFNTCBjb250ZW50IGRldGVjdGVkJywgJ2NyaXRpY2FsJyk7XG4gICAgfVxuXG4gICAgLy8gUGFyc2Ugd2l0aCBzYWZlIHNjaGVtYVxuICAgIGNvbnN0IHBhcnNlZCA9IHlhbWwubG9hZCh5YW1sQ29udGVudCwge1xuICAgICAgc2NoZW1hOiB0aGlzLlNBRkVfU0NIRU1BLCAgLy8gQ09SRV9TQ0hFTUEgLSBzYWZlIGJhc2ljIHR5cGVzIG9ubHlcbiAgICAgIGpzb246IGZhbHNlXG4gICAgfSk7XG5cbiAgICAvLyBFbnN1cmUgcmVzdWx0IGlzIGFuIG9iamVjdFxuICAgIGlmICh0eXBlb2YgcGFyc2VkICE9PSAnb2JqZWN0JyB8fCBwYXJzZWQgPT09IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBTZWN1cml0eUVycm9yKCdZQU1MIGNvbnRlbnQgbXVzdCBwYXJzZSB0byBhbiBvYmplY3QnLCAnbWVkaXVtJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHBhcnNlZCBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgfVxufVxuIl19