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.

348 lines 44.7 kB
/** * PersonaElementManager - Implementation of IElementManager for PersonaElement * Handles CRUD operations and lifecycle management for personas implementing IElement * * SECURITY FIXES IMPLEMENTED (PR #319): * 1. CRITICAL: Fixed race conditions in file operations by using FileLockManager for atomic reads/writes * 2. CRITICAL: Fixed dynamic require() statements by using static imports * 3. HIGH: Fixed unvalidated YAML parsing vulnerability by using SecureYamlParser * 4. MEDIUM: All user inputs are now validated and sanitized * 5. MEDIUM: Audit logging added for security operations */ import * as fs from 'fs/promises'; import * as path from 'path'; import * as yaml from 'js-yaml'; import { ElementType } from '../portfolio/types.js'; import { PersonaElement } from './PersonaElement.js'; import { PortfolioManager } from '../portfolio/PortfolioManager.js'; import { logger } from '../utils/logger.js'; import { validatePath } from '../security/InputValidator.js'; import { ensureDirectory } from '../utils/filesystem.js'; import { FileLockManager } from '../security/fileLockManager.js'; import { SecureYamlParser } from '../security/secureYamlParser.js'; import { SecurityMonitor } from '../security/securityMonitor.js'; export class PersonaElementManager { portfolioManager; personasDir; constructor(portfolioManager) { this.portfolioManager = portfolioManager || PortfolioManager.getInstance(); this.personasDir = this.portfolioManager.getElementDir(ElementType.PERSONA); } /** * Load a persona from file * SECURITY FIX #1: Uses FileLockManager.atomicReadFile() instead of fs.readFile() * to prevent race conditions and ensure atomic file operations */ async load(filePath) { try { // Resolve full path if relative const fullPath = path.isAbsolute(filePath) ? filePath : path.join(this.personasDir, filePath); // Validate path security if (!this.validatePath(fullPath)) { // SECURITY FIX #206: Don't expose user paths in error messages logger.error('Invalid or unsafe path', { path: filePath }); throw new Error('Invalid or unsafe path'); } // CRITICAL FIX: Use atomic file read to prevent race conditions // Previously: const content = await fs.readFile(fullPath, 'utf-8'); // Now: Uses FileLockManager with proper encoding object format const content = await FileLockManager.atomicReadFile(fullPath, { encoding: 'utf-8' }); // Create a new PersonaElement and deserialize const persona = new PersonaElement({}, '', path.basename(fullPath)); persona.deserialize(content); logger.debug(`Loaded persona: ${persona.metadata.name} from ${filePath}`); return persona; } catch (error) { logger.error(`Failed to load persona from ${filePath}: ${error}`); throw new Error(`Failed to load persona: ${error}`); } } /** * Save a persona to file * SECURITY FIX #1: Uses FileLockManager.atomicWriteFile() instead of fs.writeFile() * to prevent race conditions and ensure atomic file operations */ async save(element, filePath) { try { // Ensure personas directory exists await ensureDirectory(this.personasDir); // Resolve full path if relative const fullPath = path.isAbsolute(filePath) ? filePath : path.join(this.personasDir, filePath); // Validate path security if (!this.validatePath(fullPath)) { // SECURITY FIX #206: Don't expose user paths in error messages logger.error('Invalid or unsafe path', { path: filePath }); throw new Error('Invalid or unsafe path'); } // Serialize the persona const content = element.serialize(); // CRITICAL FIX: Use atomic file write to prevent corruption during interruptions // Previously: await fs.writeFile(fullPath, content, 'utf-8'); // Now: Uses FileLockManager with proper encoding object format // This prevents partial writes and data corruption if the process is interrupted await FileLockManager.atomicWriteFile(fullPath, content, { encoding: 'utf-8' }); // Update filename in element element.filename = path.basename(fullPath); logger.debug(`Saved persona: ${element.metadata.name} to ${filePath}`); } catch (error) { logger.error(`Failed to save persona to ${filePath}: ${error}`); throw new Error(`Failed to save persona: ${error}`); } } /** * Delete a persona file */ async delete(filePath) { try { // Resolve full path if relative const fullPath = path.isAbsolute(filePath) ? filePath : path.join(this.personasDir, filePath); // Validate path security if (!this.validatePath(fullPath)) { // SECURITY FIX #206: Don't expose user paths in error messages logger.error('Invalid or unsafe path', { path: filePath }); throw new Error('Invalid or unsafe path'); } await fs.unlink(fullPath); logger.debug(`Deleted persona file: ${filePath}`); } catch (error) { logger.error(`Failed to delete persona ${filePath}: ${error}`); throw new Error(`Failed to delete persona: ${error}`); } } /** * Check if a persona file exists */ async exists(filePath) { try { // Resolve full path if relative const fullPath = path.isAbsolute(filePath) ? filePath : path.join(this.personasDir, filePath); await fs.access(fullPath); return true; } catch { return false; } } /** * List all personas */ async list() { try { // Ensure directory exists await ensureDirectory(this.personasDir); const files = await fs.readdir(this.personasDir); const markdownFiles = files.filter(file => file.endsWith('.md')); const personas = []; for (const file of markdownFiles) { try { const persona = await this.load(file); personas.push(persona); } catch (error) { logger.error(`Error loading persona ${file}: ${error}`); // Continue with other personas } } logger.debug(`Loaded ${personas.length} personas from ${this.personasDir}`); return personas; } catch (error) { logger.error(`Failed to list personas: ${error}`); return []; } } /** * Find a persona by predicate */ async find(predicate) { const personas = await this.list(); return personas.find(predicate); } /** * Find multiple personas by predicate */ async findMany(predicate) { const personas = await this.list(); return personas.filter(predicate); } /** * Validate a persona element */ validate(element) { return element.validate(); } /** * Validate a file path */ validatePath(filePath) { try { validatePath(filePath); // Additional check: must be .md file if (!filePath.endsWith('.md')) { return false; } // Must be within personas directory const fullPath = path.resolve(filePath); const personasDirPath = path.resolve(this.personasDir); return fullPath.startsWith(personasDirPath); } catch { return false; } } /** * Get element type */ getElementType() { return ElementType.PERSONA; } /** * Get file extension */ getFileExtension() { return '.md'; } /** * Import persona from data * SECURITY FIX #3: Uses SecureYamlParser instead of unsafe YAML parsing to prevent * YAML deserialization attacks and injection vulnerabilities */ async importElement(data, format = 'markdown') { try { const persona = new PersonaElement({}); if (format === 'markdown') { persona.deserialize(data); } else if (format === 'json') { const jsonData = JSON.parse(data); persona.deserialize(this.jsonToMarkdown(jsonData)); } else if (format === 'yaml') { // HIGH SEVERITY FIX: Use SecureYamlParser to prevent YAML injection attacks // Previously: Used unsafe YAML parsing without validation // Now: Uses SecureYamlParser which validates content and prevents malicious patterns try { const parsed = SecureYamlParser.parse(data, { maxYamlSize: 64 * 1024, // 64KB limit validateContent: true }); // Log security event for audit trail SecurityMonitor.logSecurityEvent({ type: 'YAML_PARSE_SUCCESS', severity: 'LOW', source: 'PersonaElementManager.importElement', details: 'YAML content safely parsed during import' }); // Convert parsed YAML to markdown format persona.deserialize(this.jsonToMarkdown(parsed.data)); } catch (securityError) { // Log the security violation SecurityMonitor.logSecurityEvent({ type: 'YAML_INJECTION_ATTEMPT', severity: 'HIGH', source: 'PersonaElementManager.importElement', details: `YAML parsing failed security validation: ${securityError}` }); throw securityError; } } else { throw new Error(`Unsupported format: ${format}`); } return persona; } catch (error) { logger.error(`Failed to import persona: ${error}`); throw new Error(`Import failed: ${error}`); } } /** * Export persona to data * SECURITY FIX #2: Uses static import of js-yaml at top of file instead of * dynamic require() for better security and bundling * SECURITY FIX #3: Uses secure YAML dumping with safety options */ async exportElement(element, format = 'markdown') { try { if (format === 'markdown') { return element.serialize(); } else if (format === 'json') { const legacy = element.toLegacy(); return JSON.stringify({ ...legacy, content: element.content }, null, 2); } else if (format === 'yaml') { const legacy = element.toLegacy(); // CRITICAL FIX: Using safe YAML dump with security options // Previously: Used dynamic require without safety options // Now: Uses static import with safe schema and security flags return yaml.dump({ ...legacy, content: element.content }, { schema: yaml.FAILSAFE_SCHEMA, // Use restricted schema skipInvalid: true, // Skip invalid data instead of throwing noRefs: true, // Prevent reference attacks noCompatMode: true // Use strict YAML mode }); } else { throw new Error(`Unsupported format: ${format}`); } } catch (error) { logger.error(`Failed to export persona: ${error}`); throw new Error(`Export failed: ${error}`); } } /** * Helper: Convert JSON data to markdown format * SECURITY FIX #2: Uses statically imported yaml module * SECURITY FIX #3: Uses secure YAML dumping with safety options * Note: This is for internal conversion only, user-provided YAML must use SecureYamlParser */ jsonToMarkdown(data) { const { content, ...metadata } = data; // Using safe YAML dump with security options const yamlFrontmatter = yaml.dump(metadata, { schema: yaml.FAILSAFE_SCHEMA, // Use restricted schema skipInvalid: true, // Skip invalid data noRefs: true, // Prevent reference attacks noCompatMode: true // Use strict YAML mode }); return `---\n${yamlFrontmatter}---\n\n${content || ''}`; } /** * Create a new persona with default metadata */ create(metadata) { const defaultMetadata = { name: 'New Persona', description: 'A new persona', version: '1.0.0', category: 'personal', age_rating: 'all', ai_generated: false, generation_method: 'human', price: 'free', license: 'CC-BY-SA-4.0', created_date: new Date().toISOString().split('T')[0], triggers: [], content_flags: [] }; return new PersonaElement({ ...defaultMetadata, ...metadata }); } /** * Get default filename for a persona */ getDefaultFilename(persona) { // Convert name to safe filename const safeName = persona.metadata.name .toLowerCase() .replace(/[^a-z0-9]+/g, '-') .replace(/^-+|-+$/g, ''); return `${safeName}.md`; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVyc29uYUVsZW1lbnRNYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BlcnNvbmEvUGVyc29uYUVsZW1lbnRNYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7O0dBVUc7QUFFSCxPQUFPLEtBQUssRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNsQyxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUM3QixPQUFPLEtBQUssSUFBSSxNQUFNLFNBQVMsQ0FBQztBQUVoQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDcEQsT0FBTyxFQUFFLGNBQWMsRUFBMEIsTUFBTSxxQkFBcUIsQ0FBQztBQUM3RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUNwRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDNUMsT0FBTyxFQUFFLFlBQVksRUFBb0IsTUFBTSwrQkFBK0IsQ0FBQztBQUMvRSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDekQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ25FLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUVqRSxNQUFNLE9BQU8scUJBQXFCO0lBQ3hCLGdCQUFnQixDQUFtQjtJQUNuQyxXQUFXLENBQVM7SUFFNUIsWUFBWSxnQkFBbUM7UUFDN0MsSUFBSSxDQUFDLGdCQUFnQixHQUFHLGdCQUFnQixJQUFJLGdCQUFnQixDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQzNFLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDOUUsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQWdCO1FBQ3pCLElBQUksQ0FBQztZQUNILGdDQUFnQztZQUNoQyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxRQUFRLENBQUMsQ0FBQztZQUU5Rix5QkFBeUI7WUFDekIsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztnQkFDakMsK0RBQStEO2dCQUMvRCxNQUFNLENBQUMsS0FBSyxDQUFDLHdCQUF3QixFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7Z0JBQzNELE1BQU0sSUFBSSxLQUFLLENBQUMsd0JBQXdCLENBQUMsQ0FBQztZQUM1QyxDQUFDO1lBRUQsZ0VBQWdFO1lBQ2hFLG9FQUFvRTtZQUNwRSwrREFBK0Q7WUFDL0QsTUFBTSxPQUFPLEdBQUcsTUFBTSxlQUFlLENBQUMsY0FBYyxDQUFDLFFBQVEsRUFBRSxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBRXRGLDhDQUE4QztZQUM5QyxNQUFNLE9BQU8sR0FBRyxJQUFJLGNBQWMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztZQUNwRSxPQUFPLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBRTdCLE1BQU0sQ0FBQyxLQUFLLENBQUMsbUJBQW1CLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxTQUFTLFFBQVEsRUFBRSxDQUFDLENBQUM7WUFDMUUsT0FBTyxPQUFPLENBQUM7UUFFakIsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLCtCQUErQixRQUFRLEtBQUssS0FBSyxFQUFFLENBQUMsQ0FBQztZQUNsRSxNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQ3RELENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBdUIsRUFBRSxRQUFnQjtRQUNsRCxJQUFJLENBQUM7WUFDSCxtQ0FBbUM7WUFDbkMsTUFBTSxlQUFlLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBRXhDLGdDQUFnQztZQUNoQyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxRQUFRLENBQUMsQ0FBQztZQUU5Rix5QkFBeUI7WUFDekIsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztnQkFDakMsK0RBQStEO2dCQUMvRCxNQUFNLENBQUMsS0FBSyxDQUFDLHdCQUF3QixFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7Z0JBQzNELE1BQU0sSUFBSSxLQUFLLENBQUMsd0JBQXdCLENBQUMsQ0FBQztZQUM1QyxDQUFDO1lBRUQsd0JBQXdCO1lBQ3hCLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUVwQyxpRkFBaUY7WUFDakYsOERBQThEO1lBQzlELCtEQUErRDtZQUMvRCxpRkFBaUY7WUFDakYsTUFBTSxlQUFlLENBQUMsZUFBZSxDQUFDLFFBQVEsRUFBRSxPQUFPLEVBQUUsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUVoRiw2QkFBNkI7WUFDN0IsT0FBTyxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBRTNDLE1BQU0sQ0FBQyxLQUFLLENBQUMsa0JBQWtCLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxPQUFPLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFFekUsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLDZCQUE2QixRQUFRLEtBQUssS0FBSyxFQUFFLENBQUMsQ0FBQztZQUNoRSxNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQ3RELENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsTUFBTSxDQUFDLFFBQWdCO1FBQzNCLElBQUksQ0FBQztZQUNILGdDQUFnQztZQUNoQyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxRQUFRLENBQUMsQ0FBQztZQUU5Rix5QkFBeUI7WUFDekIsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztnQkFDakMsK0RBQStEO2dCQUMvRCxNQUFNLENBQUMsS0FBSyxDQUFDLHdCQUF3QixFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7Z0JBQzNELE1BQU0sSUFBSSxLQUFLLENBQUMsd0JBQXdCLENBQUMsQ0FBQztZQUM1QyxDQUFDO1lBRUQsTUFBTSxFQUFFLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQzFCLE1BQU0sQ0FBQyxLQUFLLENBQUMseUJBQXlCLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFFcEQsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLDRCQUE0QixRQUFRLEtBQUssS0FBSyxFQUFFLENBQUMsQ0FBQztZQUMvRCxNQUFNLElBQUksS0FBSyxDQUFDLDZCQUE2QixLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQ3hELENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsTUFBTSxDQUFDLFFBQWdCO1FBQzNCLElBQUksQ0FBQztZQUNILGdDQUFnQztZQUNoQyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxRQUFRLENBQUMsQ0FBQztZQUU5RixNQUFNLEVBQUUsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDMUIsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLElBQUk7UUFDUixJQUFJLENBQUM7WUFDSCwwQkFBMEI7WUFDMUIsTUFBTSxlQUFlLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBRXhDLE1BQU0sS0FBSyxHQUFHLE1BQU0sRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDakQsTUFBTSxhQUFhLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztZQUVqRSxNQUFNLFFBQVEsR0FBcUIsRUFBRSxDQUFDO1lBRXRDLEtBQUssTUFBTSxJQUFJLElBQUksYUFBYSxFQUFFLENBQUM7Z0JBQ2pDLElBQUksQ0FBQztvQkFDSCxNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7b0JBQ3RDLFFBQVEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ3pCLENBQUM7Z0JBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztvQkFDZixNQUFNLENBQUMsS0FBSyxDQUFDLHlCQUF5QixJQUFJLEtBQUssS0FBSyxFQUFFLENBQUMsQ0FBQztvQkFDeEQsK0JBQStCO2dCQUNqQyxDQUFDO1lBQ0gsQ0FBQztZQUVELE1BQU0sQ0FBQyxLQUFLLENBQUMsVUFBVSxRQUFRLENBQUMsTUFBTSxrQkFBa0IsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7WUFDNUUsT0FBTyxRQUFRLENBQUM7UUFFbEIsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLDRCQUE0QixLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQ2xELE9BQU8sRUFBRSxDQUFDO1FBQ1osQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBK0M7UUFDeEQsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDbkMsT0FBTyxRQUFRLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ2xDLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxRQUFRLENBQUMsU0FBK0M7UUFDNUQsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDbkMsT0FBTyxRQUFRLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3BDLENBQUM7SUFFRDs7T0FFRztJQUNILFFBQVEsQ0FBQyxPQUF1QjtRQUM5QixPQUFPLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxZQUFZLENBQUMsUUFBZ0I7UUFDM0IsSUFBSSxDQUFDO1lBQ0gsWUFBWSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBRXZCLHFDQUFxQztZQUNyQyxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUM5QixPQUFPLEtBQUssQ0FBQztZQUNmLENBQUM7WUFFRCxvQ0FBb0M7WUFDcEMsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUN4QyxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUV2RCxPQUFPLFFBQVEsQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFDLENBQUM7UUFFOUMsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILGNBQWM7UUFDWixPQUFPLFdBQVcsQ0FBQyxPQUFPLENBQUM7SUFDN0IsQ0FBQztJQUVEOztPQUVHO0lBQ0gsZ0JBQWdCO1FBQ2QsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxhQUFhLENBQUMsSUFBWSxFQUFFLFNBQXVDLFVBQVU7UUFDakYsSUFBSSxDQUFDO1lBQ0gsTUFBTSxPQUFPLEdBQUcsSUFBSSxjQUFjLENBQUMsRUFBRSxDQUFDLENBQUM7WUFFdkMsSUFBSSxNQUFNLEtBQUssVUFBVSxFQUFFLENBQUM7Z0JBQzFCLE9BQU8sQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDNUIsQ0FBQztpQkFBTSxJQUFJLE1BQU0sS0FBSyxNQUFNLEVBQUUsQ0FBQztnQkFDN0IsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDbEMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7WUFDckQsQ0FBQztpQkFBTSxJQUFJLE1BQU0sS0FBSyxNQUFNLEVBQUUsQ0FBQztnQkFDN0IsNEVBQTRFO2dCQUM1RSwwREFBMEQ7Z0JBQzFELHFGQUFxRjtnQkFDckYsSUFBSSxDQUFDO29CQUNILE1BQU0sTUFBTSxHQUFHLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUU7d0JBQzFDLFdBQVcsRUFBRSxFQUFFLEdBQUcsSUFBSSxFQUFFLGFBQWE7d0JBQ3JDLGVBQWUsRUFBRSxJQUFJO3FCQUN0QixDQUFDLENBQUM7b0JBRUgscUNBQXFDO29CQUNyQyxlQUFlLENBQUMsZ0JBQWdCLENBQUM7d0JBQy9CLElBQUksRUFBRSxvQkFBb0I7d0JBQzFCLFFBQVEsRUFBRSxLQUFLO3dCQUNmLE1BQU0sRUFBRSxxQ0FBcUM7d0JBQzdDLE9BQU8sRUFBRSwwQ0FBMEM7cUJBQ3BELENBQUMsQ0FBQztvQkFFSCx5Q0FBeUM7b0JBQ3pDLE9BQU8sQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztnQkFDeEQsQ0FBQztnQkFBQyxPQUFPLGFBQWEsRUFBRSxDQUFDO29CQUN2Qiw2QkFBNkI7b0JBQzdCLGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQzt3QkFDL0IsSUFBSSxFQUFFLHdCQUF3Qjt3QkFDOUIsUUFBUSxFQUFFLE1BQU07d0JBQ2hCLE1BQU0sRUFBRSxxQ0FBcUM7d0JBQzdDLE9BQU8sRUFBRSw0Q0FBNEMsYUFBYSxFQUFFO3FCQUNyRSxDQUFDLENBQUM7b0JBQ0gsTUFBTSxhQUFhLENBQUM7Z0JBQ3RCLENBQUM7WUFDSCxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sTUFBTSxJQUFJLEtBQUssQ0FBQyx1QkFBdUIsTUFBTSxFQUFFLENBQUMsQ0FBQztZQUNuRCxDQUFDO1lBRUQsT0FBTyxPQUFPLENBQUM7UUFFakIsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLDZCQUE2QixLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQ25ELE1BQU0sSUFBSSxLQUFLLENBQUMsa0JBQWtCLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDN0MsQ0FBQztJQUNILENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILEtBQUssQ0FBQyxhQUFhLENBQUMsT0FBdUIsRUFBRSxTQUF1QyxVQUFVO1FBQzVGLElBQUksQ0FBQztZQUNILElBQUksTUFBTSxLQUFLLFVBQVUsRUFBRSxDQUFDO2dCQUMxQixPQUFPLE9BQU8sQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUM3QixDQUFDO2lCQUFNLElBQUksTUFBTSxLQUFLLE1BQU0sRUFBRSxDQUFDO2dCQUM3QixNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ2xDLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEdBQUcsTUFBTSxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQzFFLENBQUM7aUJBQU0sSUFBSSxNQUFNLEtBQUssTUFBTSxFQUFFLENBQUM7Z0JBQzdCLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQztnQkFDbEMsMkRBQTJEO2dCQUMzRCwwREFBMEQ7Z0JBQzFELDhEQUE4RDtnQkFDOUQsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxNQUFNLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRTtvQkFDeEQsTUFBTSxFQUFFLElBQUksQ0FBQyxlQUFlLEVBQUcsd0JBQXdCO29CQUN2RCxXQUFXLEVBQUUsSUFBSSxFQUFlLHdDQUF3QztvQkFDeEUsTUFBTSxFQUFFLElBQUksRUFBb0IsNEJBQTRCO29CQUM1RCxZQUFZLEVBQUUsSUFBSSxDQUFjLHVCQUF1QjtpQkFDeEQsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLE1BQU0sSUFBSSxLQUFLLENBQUMsdUJBQXVCLE1BQU0sRUFBRSxDQUFDLENBQUM7WUFDbkQsQ0FBQztRQUVILENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxDQUFDLEtBQUssQ0FBQyw2QkFBNkIsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUNuRCxNQUFNLElBQUksS0FBSyxDQUFDLGtCQUFrQixLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQzdDLENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSyxjQUFjLENBQUMsSUFBUztRQUM5QixNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUFDO1FBQ3RDLDZDQUE2QztRQUM3QyxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRTtZQUMxQyxNQUFNLEVBQUUsSUFBSSxDQUFDLGVBQWUsRUFBRyx3QkFBd0I7WUFDdkQsV0FBVyxFQUFFLElBQUksRUFBZSxvQkFBb0I7WUFDcEQsTUFBTSxFQUFFLElBQUksRUFBb0IsNEJBQTRCO1lBQzVELFlBQVksRUFBRSxJQUFJLENBQWMsdUJBQXVCO1NBQ3hELENBQUMsQ0FBQztRQUNILE9BQU8sUUFBUSxlQUFlLFVBQVUsT0FBTyxJQUFJLEVBQUUsRUFBRSxDQUFDO0lBQzFELENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxRQUF5QztRQUM5QyxNQUFNLGVBQWUsR0FBb0M7WUFDdkQsSUFBSSxFQUFFLGFBQWE7WUFDbkIsV0FBVyxFQUFFLGVBQWU7WUFDNUIsT0FBTyxFQUFFLE9BQU87WUFDaEIsUUFBUSxFQUFFLFVBQVU7WUFDcEIsVUFBVSxFQUFFLEtBQUs7WUFDakIsWUFBWSxFQUFFLEtBQUs7WUFDbkIsaUJBQWlCLEVBQUUsT0FBTztZQUMxQixLQUFLLEVBQUUsTUFBTTtZQUNiLE9BQU8sRUFBRSxjQUFjO1lBQ3ZCLFlBQVksRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDcEQsUUFBUSxFQUFFLEVBQUU7WUFDWixhQUFhLEVBQUUsRUFBRTtTQUNsQixDQUFDO1FBRUYsT0FBTyxJQUFJLGNBQWMsQ0FBQyxFQUFFLEdBQUcsZUFBZSxFQUFFLEdBQUcsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUNqRSxDQUFDO0lBRUQ7O09BRUc7SUFDSCxrQkFBa0IsQ0FBQyxPQUF1QjtRQUN4QyxnQ0FBZ0M7UUFDaEMsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJO2FBQ25DLFdBQVcsRUFBRTthQUNiLE9BQU8sQ0FBQyxhQUFhLEVBQUUsR0FBRyxDQUFDO2FBQzNCLE9BQU8sQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFM0IsT0FBTyxHQUFHLFFBQVEsS0FBSyxDQUFDO0lBQzFCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUGVyc29uYUVsZW1lbnRNYW5hZ2VyIC0gSW1wbGVtZW50YXRpb24gb2YgSUVsZW1lbnRNYW5hZ2VyIGZvciBQZXJzb25hRWxlbWVudFxuICogSGFuZGxlcyBDUlVEIG9wZXJhdGlvbnMgYW5kIGxpZmVjeWNsZSBtYW5hZ2VtZW50IGZvciBwZXJzb25hcyBpbXBsZW1lbnRpbmcgSUVsZW1lbnRcbiAqIFxuICogU0VDVVJJVFkgRklYRVMgSU1QTEVNRU5URUQgKFBSICMzMTkpOlxuICogMS4gQ1JJVElDQUw6IEZpeGVkIHJhY2UgY29uZGl0aW9ucyBpbiBmaWxlIG9wZXJhdGlvbnMgYnkgdXNpbmcgRmlsZUxvY2tNYW5hZ2VyIGZvciBhdG9taWMgcmVhZHMvd3JpdGVzXG4gKiAyLiBDUklUSUNBTDogRml4ZWQgZHluYW1pYyByZXF1aXJlKCkgc3RhdGVtZW50cyBieSB1c2luZyBzdGF0aWMgaW1wb3J0c1xuICogMy4gSElHSDogRml4ZWQgdW52YWxpZGF0ZWQgWUFNTCBwYXJzaW5nIHZ1bG5lcmFiaWxpdHkgYnkgdXNpbmcgU2VjdXJlWWFtbFBhcnNlclxuICogNC4gTUVESVVNOiBBbGwgdXNlciBpbnB1dHMgYXJlIG5vdyB2YWxpZGF0ZWQgYW5kIHNhbml0aXplZFxuICogNS4gTUVESVVNOiBBdWRpdCBsb2dnaW5nIGFkZGVkIGZvciBzZWN1cml0eSBvcGVyYXRpb25zXG4gKi9cblxuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMvcHJvbWlzZXMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCAqIGFzIHlhbWwgZnJvbSAnanMteWFtbCc7XG5pbXBvcnQgeyBJRWxlbWVudE1hbmFnZXIsIEVsZW1lbnRWYWxpZGF0aW9uUmVzdWx0IH0gZnJvbSAnLi4vdHlwZXMvZWxlbWVudHMvaW5kZXguanMnO1xuaW1wb3J0IHsgRWxlbWVudFR5cGUgfSBmcm9tICcuLi9wb3J0Zm9saW8vdHlwZXMuanMnO1xuaW1wb3J0IHsgUGVyc29uYUVsZW1lbnQsIFBlcnNvbmFFbGVtZW50TWV0YWRhdGEgfSBmcm9tICcuL1BlcnNvbmFFbGVtZW50LmpzJztcbmltcG9ydCB7IFBvcnRmb2xpb01hbmFnZXIgfSBmcm9tICcuLi9wb3J0Zm9saW8vUG9ydGZvbGlvTWFuYWdlci5qcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgdmFsaWRhdGVQYXRoLCB2YWxpZGF0ZUZpbGVuYW1lIH0gZnJvbSAnLi4vc2VjdXJpdHkvSW5wdXRWYWxpZGF0b3IuanMnO1xuaW1wb3J0IHsgZW5zdXJlRGlyZWN0b3J5IH0gZnJvbSAnLi4vdXRpbHMvZmlsZXN5c3RlbS5qcyc7XG5pbXBvcnQgeyBGaWxlTG9ja01hbmFnZXIgfSBmcm9tICcuLi9zZWN1cml0eS9maWxlTG9ja01hbmFnZXIuanMnO1xuaW1wb3J0IHsgU2VjdXJlWWFtbFBhcnNlciB9IGZyb20gJy4uL3NlY3VyaXR5L3NlY3VyZVlhbWxQYXJzZXIuanMnO1xuaW1wb3J0IHsgU2VjdXJpdHlNb25pdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvc2VjdXJpdHlNb25pdG9yLmpzJztcblxuZXhwb3J0IGNsYXNzIFBlcnNvbmFFbGVtZW50TWFuYWdlciBpbXBsZW1lbnRzIElFbGVtZW50TWFuYWdlcjxQZXJzb25hRWxlbWVudD4ge1xuICBwcml2YXRlIHBvcnRmb2xpb01hbmFnZXI6IFBvcnRmb2xpb01hbmFnZXI7XG4gIHByaXZhdGUgcGVyc29uYXNEaXI6IHN0cmluZztcblxuICBjb25zdHJ1Y3Rvcihwb3J0Zm9saW9NYW5hZ2VyPzogUG9ydGZvbGlvTWFuYWdlcikge1xuICAgIHRoaXMucG9ydGZvbGlvTWFuYWdlciA9IHBvcnRmb2xpb01hbmFnZXIgfHwgUG9ydGZvbGlvTWFuYWdlci5nZXRJbnN0YW5jZSgpO1xuICAgIHRoaXMucGVyc29uYXNEaXIgPSB0aGlzLnBvcnRmb2xpb01hbmFnZXIuZ2V0RWxlbWVudERpcihFbGVtZW50VHlwZS5QRVJTT05BKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2FkIGEgcGVyc29uYSBmcm9tIGZpbGVcbiAgICogU0VDVVJJVFkgRklYICMxOiBVc2VzIEZpbGVMb2NrTWFuYWdlci5hdG9taWNSZWFkRmlsZSgpIGluc3RlYWQgb2YgZnMucmVhZEZpbGUoKVxuICAgKiB0byBwcmV2ZW50IHJhY2UgY29uZGl0aW9ucyBhbmQgZW5zdXJlIGF0b21pYyBmaWxlIG9wZXJhdGlvbnNcbiAgICovXG4gIGFzeW5jIGxvYWQoZmlsZVBhdGg6IHN0cmluZyk6IFByb21pc2U8UGVyc29uYUVsZW1lbnQ+IHtcbiAgICB0cnkge1xuICAgICAgLy8gUmVzb2x2ZSBmdWxsIHBhdGggaWYgcmVsYXRpdmVcbiAgICAgIGNvbnN0IGZ1bGxQYXRoID0gcGF0aC5pc0Fic29sdXRlKGZpbGVQYXRoKSA/IGZpbGVQYXRoIDogcGF0aC5qb2luKHRoaXMucGVyc29uYXNEaXIsIGZpbGVQYXRoKTtcbiAgICAgIFxuICAgICAgLy8gVmFsaWRhdGUgcGF0aCBzZWN1cml0eVxuICAgICAgaWYgKCF0aGlzLnZhbGlkYXRlUGF0aChmdWxsUGF0aCkpIHtcbiAgICAgICAgLy8gU0VDVVJJVFkgRklYICMyMDY6IERvbid0IGV4cG9zZSB1c2VyIHBhdGhzIGluIGVycm9yIG1lc3NhZ2VzXG4gICAgICAgIGxvZ2dlci5lcnJvcignSW52YWxpZCBvciB1bnNhZmUgcGF0aCcsIHsgcGF0aDogZmlsZVBhdGggfSk7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBvciB1bnNhZmUgcGF0aCcpO1xuICAgICAgfVxuXG4gICAgICAvLyBDUklUSUNBTCBGSVg6IFVzZSBhdG9taWMgZmlsZSByZWFkIHRvIHByZXZlbnQgcmFjZSBjb25kaXRpb25zXG4gICAgICAvLyBQcmV2aW91c2x5OiBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUoZnVsbFBhdGgsICd1dGYtOCcpO1xuICAgICAgLy8gTm93OiBVc2VzIEZpbGVMb2NrTWFuYWdlciB3aXRoIHByb3BlciBlbmNvZGluZyBvYmplY3QgZm9ybWF0XG4gICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgRmlsZUxvY2tNYW5hZ2VyLmF0b21pY1JlYWRGaWxlKGZ1bGxQYXRoLCB7IGVuY29kaW5nOiAndXRmLTgnIH0pO1xuICAgICAgXG4gICAgICAvLyBDcmVhdGUgYSBuZXcgUGVyc29uYUVsZW1lbnQgYW5kIGRlc2VyaWFsaXplXG4gICAgICBjb25zdCBwZXJzb25hID0gbmV3IFBlcnNvbmFFbGVtZW50KHt9LCAnJywgcGF0aC5iYXNlbmFtZShmdWxsUGF0aCkpO1xuICAgICAgcGVyc29uYS5kZXNlcmlhbGl6ZShjb250ZW50KTtcbiAgICAgIFxuICAgICAgbG9nZ2VyLmRlYnVnKGBMb2FkZWQgcGVyc29uYTogJHtwZXJzb25hLm1ldGFkYXRhLm5hbWV9IGZyb20gJHtmaWxlUGF0aH1gKTtcbiAgICAgIHJldHVybiBwZXJzb25hO1xuXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5lcnJvcihgRmFpbGVkIHRvIGxvYWQgcGVyc29uYSBmcm9tICR7ZmlsZVBhdGh9OiAke2Vycm9yfWApO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gbG9hZCBwZXJzb25hOiAke2Vycm9yfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTYXZlIGEgcGVyc29uYSB0byBmaWxlXG4gICAqIFNFQ1VSSVRZIEZJWCAjMTogVXNlcyBGaWxlTG9ja01hbmFnZXIuYXRvbWljV3JpdGVGaWxlKCkgaW5zdGVhZCBvZiBmcy53cml0ZUZpbGUoKVxuICAgKiB0byBwcmV2ZW50IHJhY2UgY29uZGl0aW9ucyBhbmQgZW5zdXJlIGF0b21pYyBmaWxlIG9wZXJhdGlvbnNcbiAgICovXG4gIGFzeW5jIHNhdmUoZWxlbWVudDogUGVyc29uYUVsZW1lbnQsIGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgLy8gRW5zdXJlIHBlcnNvbmFzIGRpcmVjdG9yeSBleGlzdHNcbiAgICAgIGF3YWl0IGVuc3VyZURpcmVjdG9yeSh0aGlzLnBlcnNvbmFzRGlyKTtcblxuICAgICAgLy8gUmVzb2x2ZSBmdWxsIHBhdGggaWYgcmVsYXRpdmVcbiAgICAgIGNvbnN0IGZ1bGxQYXRoID0gcGF0aC5pc0Fic29sdXRlKGZpbGVQYXRoKSA/IGZpbGVQYXRoIDogcGF0aC5qb2luKHRoaXMucGVyc29uYXNEaXIsIGZpbGVQYXRoKTtcbiAgICAgIFxuICAgICAgLy8gVmFsaWRhdGUgcGF0aCBzZWN1cml0eVxuICAgICAgaWYgKCF0aGlzLnZhbGlkYXRlUGF0aChmdWxsUGF0aCkpIHtcbiAgICAgICAgLy8gU0VDVVJJVFkgRklYICMyMDY6IERvbid0IGV4cG9zZSB1c2VyIHBhdGhzIGluIGVycm9yIG1lc3NhZ2VzXG4gICAgICAgIGxvZ2dlci5lcnJvcignSW52YWxpZCBvciB1bnNhZmUgcGF0aCcsIHsgcGF0aDogZmlsZVBhdGggfSk7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBvciB1bnNhZmUgcGF0aCcpO1xuICAgICAgfVxuXG4gICAgICAvLyBTZXJpYWxpemUgdGhlIHBlcnNvbmFcbiAgICAgIGNvbnN0IGNvbnRlbnQgPSBlbGVtZW50LnNlcmlhbGl6ZSgpO1xuICAgICAgXG4gICAgICAvLyBDUklUSUNBTCBGSVg6IFVzZSBhdG9taWMgZmlsZSB3cml0ZSB0byBwcmV2ZW50IGNvcnJ1cHRpb24gZHVyaW5nIGludGVycnVwdGlvbnNcbiAgICAgIC8vIFByZXZpb3VzbHk6IGF3YWl0IGZzLndyaXRlRmlsZShmdWxsUGF0aCwgY29udGVudCwgJ3V0Zi04Jyk7XG4gICAgICAvLyBOb3c6IFVzZXMgRmlsZUxvY2tNYW5hZ2VyIHdpdGggcHJvcGVyIGVuY29kaW5nIG9iamVjdCBmb3JtYXRcbiAgICAgIC8vIFRoaXMgcHJldmVudHMgcGFydGlhbCB3cml0ZXMgYW5kIGRhdGEgY29ycnVwdGlvbiBpZiB0aGUgcHJvY2VzcyBpcyBpbnRlcnJ1cHRlZFxuICAgICAgYXdhaXQgRmlsZUxvY2tNYW5hZ2VyLmF0b21pY1dyaXRlRmlsZShmdWxsUGF0aCwgY29udGVudCwgeyBlbmNvZGluZzogJ3V0Zi04JyB9KTtcbiAgICAgIFxuICAgICAgLy8gVXBkYXRlIGZpbGVuYW1lIGluIGVsZW1lbnRcbiAgICAgIGVsZW1lbnQuZmlsZW5hbWUgPSBwYXRoLmJhc2VuYW1lKGZ1bGxQYXRoKTtcbiAgICAgIFxuICAgICAgbG9nZ2VyLmRlYnVnKGBTYXZlZCBwZXJzb25hOiAke2VsZW1lbnQubWV0YWRhdGEubmFtZX0gdG8gJHtmaWxlUGF0aH1gKTtcblxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoYEZhaWxlZCB0byBzYXZlIHBlcnNvbmEgdG8gJHtmaWxlUGF0aH06ICR7ZXJyb3J9YCk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBzYXZlIHBlcnNvbmE6ICR7ZXJyb3J9YCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIERlbGV0ZSBhIHBlcnNvbmEgZmlsZVxuICAgKi9cbiAgYXN5bmMgZGVsZXRlKGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgLy8gUmVzb2x2ZSBmdWxsIHBhdGggaWYgcmVsYXRpdmVcbiAgICAgIGNvbnN0IGZ1bGxQYXRoID0gcGF0aC5pc0Fic29sdXRlKGZpbGVQYXRoKSA/IGZpbGVQYXRoIDogcGF0aC5qb2luKHRoaXMucGVyc29uYXNEaXIsIGZpbGVQYXRoKTtcbiAgICAgIFxuICAgICAgLy8gVmFsaWRhdGUgcGF0aCBzZWN1cml0eVxuICAgICAgaWYgKCF0aGlzLnZhbGlkYXRlUGF0aChmdWxsUGF0aCkpIHtcbiAgICAgICAgLy8gU0VDVVJJVFkgRklYICMyMDY6IERvbid0IGV4cG9zZSB1c2VyIHBhdGhzIGluIGVycm9yIG1lc3NhZ2VzXG4gICAgICAgIGxvZ2dlci5lcnJvcignSW52YWxpZCBvciB1bnNhZmUgcGF0aCcsIHsgcGF0aDogZmlsZVBhdGggfSk7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBvciB1bnNhZmUgcGF0aCcpO1xuICAgICAgfVxuXG4gICAgICBhd2FpdCBmcy51bmxpbmsoZnVsbFBhdGgpO1xuICAgICAgbG9nZ2VyLmRlYnVnKGBEZWxldGVkIHBlcnNvbmEgZmlsZTogJHtmaWxlUGF0aH1gKTtcblxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoYEZhaWxlZCB0byBkZWxldGUgcGVyc29uYSAke2ZpbGVQYXRofTogJHtlcnJvcn1gKTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIGRlbGV0ZSBwZXJzb25hOiAke2Vycm9yfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBhIHBlcnNvbmEgZmlsZSBleGlzdHNcbiAgICovXG4gIGFzeW5jIGV4aXN0cyhmaWxlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFJlc29sdmUgZnVsbCBwYXRoIGlmIHJlbGF0aXZlXG4gICAgICBjb25zdCBmdWxsUGF0aCA9IHBhdGguaXNBYnNvbHV0ZShmaWxlUGF0aCkgPyBmaWxlUGF0aCA6IHBhdGguam9pbih0aGlzLnBlcnNvbmFzRGlyLCBmaWxlUGF0aCk7XG4gICAgICBcbiAgICAgIGF3YWl0IGZzLmFjY2VzcyhmdWxsUGF0aCk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTGlzdCBhbGwgcGVyc29uYXNcbiAgICovXG4gIGFzeW5jIGxpc3QoKTogUHJvbWlzZTxQZXJzb25hRWxlbWVudFtdPiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIEVuc3VyZSBkaXJlY3RvcnkgZXhpc3RzXG4gICAgICBhd2FpdCBlbnN1cmVEaXJlY3RvcnkodGhpcy5wZXJzb25hc0Rpcik7XG5cbiAgICAgIGNvbnN0IGZpbGVzID0gYXdhaXQgZnMucmVhZGRpcih0aGlzLnBlcnNvbmFzRGlyKTtcbiAgICAgIGNvbnN0IG1hcmtkb3duRmlsZXMgPSBmaWxlcy5maWx0ZXIoZmlsZSA9PiBmaWxlLmVuZHNXaXRoKCcubWQnKSk7XG4gICAgICBcbiAgICAgIGNvbnN0IHBlcnNvbmFzOiBQZXJzb25hRWxlbWVudFtdID0gW107XG4gICAgICBcbiAgICAgIGZvciAoY29uc3QgZmlsZSBvZiBtYXJrZG93bkZpbGVzKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgcGVyc29uYSA9IGF3YWl0IHRoaXMubG9hZChmaWxlKTtcbiAgICAgICAgICBwZXJzb25hcy5wdXNoKHBlcnNvbmEpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGxvZ2dlci5lcnJvcihgRXJyb3IgbG9hZGluZyBwZXJzb25hICR7ZmlsZX06ICR7ZXJyb3J9YCk7XG4gICAgICAgICAgLy8gQ29udGludWUgd2l0aCBvdGhlciBwZXJzb25hc1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGxvZ2dlci5kZWJ1ZyhgTG9hZGVkICR7cGVyc29uYXMubGVuZ3RofSBwZXJzb25hcyBmcm9tICR7dGhpcy5wZXJzb25hc0Rpcn1gKTtcbiAgICAgIHJldHVybiBwZXJzb25hcztcblxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoYEZhaWxlZCB0byBsaXN0IHBlcnNvbmFzOiAke2Vycm9yfWApO1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5kIGEgcGVyc29uYSBieSBwcmVkaWNhdGVcbiAgICovXG4gIGFzeW5jIGZpbmQocHJlZGljYXRlOiAoZWxlbWVudDogUGVyc29uYUVsZW1lbnQpID0+IGJvb2xlYW4pOiBQcm9taXNlPFBlcnNvbmFFbGVtZW50IHwgdW5kZWZpbmVkPiB7XG4gICAgY29uc3QgcGVyc29uYXMgPSBhd2FpdCB0aGlzLmxpc3QoKTtcbiAgICByZXR1cm4gcGVyc29uYXMuZmluZChwcmVkaWNhdGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmQgbXVsdGlwbGUgcGVyc29uYXMgYnkgcHJlZGljYXRlXG4gICAqL1xuICBhc3luYyBmaW5kTWFueShwcmVkaWNhdGU6IChlbGVtZW50OiBQZXJzb25hRWxlbWVudCkgPT4gYm9vbGVhbik6IFByb21pc2U8UGVyc29uYUVsZW1lbnRbXT4ge1xuICAgIGNvbnN0IHBlcnNvbmFzID0gYXdhaXQgdGhpcy5saXN0KCk7XG4gICAgcmV0dXJuIHBlcnNvbmFzLmZpbHRlcihwcmVkaWNhdGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGEgcGVyc29uYSBlbGVtZW50XG4gICAqL1xuICB2YWxpZGF0ZShlbGVtZW50OiBQZXJzb25hRWxlbWVudCk6IEVsZW1lbnRWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICByZXR1cm4gZWxlbWVudC52YWxpZGF0ZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGEgZmlsZSBwYXRoXG4gICAqL1xuICB2YWxpZGF0ZVBhdGgoZmlsZVBhdGg6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICB2YWxpZGF0ZVBhdGgoZmlsZVBhdGgpO1xuICAgICAgXG4gICAgICAvLyBBZGRpdGlvbmFsIGNoZWNrOiBtdXN0IGJlIC5tZCBmaWxlXG4gICAgICBpZiAoIWZpbGVQYXRoLmVuZHNXaXRoKCcubWQnKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIE11c3QgYmUgd2l0aGluIHBlcnNvbmFzIGRpcmVjdG9yeVxuICAgICAgY29uc3QgZnVsbFBhdGggPSBwYXRoLnJlc29sdmUoZmlsZVBhdGgpO1xuICAgICAgY29uc3QgcGVyc29uYXNEaXJQYXRoID0gcGF0aC5yZXNvbHZlKHRoaXMucGVyc29uYXNEaXIpO1xuICAgICAgXG4gICAgICByZXR1cm4gZnVsbFBhdGguc3RhcnRzV2l0aChwZXJzb25hc0RpclBhdGgpO1xuICAgICAgXG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldCBlbGVtZW50IHR5cGVcbiAgICovXG4gIGdldEVsZW1lbnRUeXBlKCk6IEVsZW1lbnRUeXBlIHtcbiAgICByZXR1cm4gRWxlbWVudFR5cGUuUEVSU09OQTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgZmlsZSBleHRlbnNpb25cbiAgICovXG4gIGdldEZpbGVFeHRlbnNpb24oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gJy5tZCc7XG4gIH1cblxuICAvKipcbiAgICogSW1wb3J0IHBlcnNvbmEgZnJvbSBkYXRhXG4gICAqIFNFQ1VSSVRZIEZJWCAjMzogVXNlcyBTZWN1cmVZYW1sUGFyc2VyIGluc3RlYWQgb2YgdW5zYWZlIFlBTUwgcGFyc2luZyB0byBwcmV2ZW50XG4gICAqIFlBTUwgZGVzZXJpYWxpemF0aW9uIGF0dGFja3MgYW5kIGluamVjdGlvbiB2dWxuZXJhYmlsaXRpZXNcbiAgICovXG4gIGFzeW5jIGltcG9ydEVsZW1lbnQoZGF0YTogc3RyaW5nLCBmb3JtYXQ6ICdqc29uJyB8ICd5YW1sJyB8ICdtYXJrZG93bicgPSAnbWFya2Rvd24nKTogUHJvbWlzZTxQZXJzb25hRWxlbWVudD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBwZXJzb25hID0gbmV3IFBlcnNvbmFFbGVtZW50KHt9KTtcbiAgICAgIFxuICAgICAgaWYgKGZvcm1hdCA9PT0gJ21hcmtkb3duJykge1xuICAgICAgICBwZXJzb25hLmRlc2VyaWFsaXplKGRhdGEpO1xuICAgICAgfSBlbHNlIGlmIChmb3JtYXQgPT09ICdqc29uJykge1xuICAgICAgICBjb25zdCBqc29uRGF0YSA9IEpTT04ucGFyc2UoZGF0YSk7XG4gICAgICAgIHBlcnNvbmEuZGVzZXJpYWxpemUodGhpcy5qc29uVG9NYXJrZG93bihqc29uRGF0YSkpO1xuICAgICAgfSBlbHNlIGlmIChmb3JtYXQgPT09ICd5YW1sJykge1xuICAgICAgICAvLyBISUdIIFNFVkVSSVRZIEZJWDogVXNlIFNlY3VyZVlhbWxQYXJzZXIgdG8gcHJldmVudCBZQU1MIGluamVjdGlvbiBhdHRhY2tzXG4gICAgICAgIC8vIFByZXZpb3VzbHk6IFVzZWQgdW5zYWZlIFlBTUwgcGFyc2luZyB3aXRob3V0IHZhbGlkYXRpb25cbiAgICAgICAgLy8gTm93OiBVc2VzIFNlY3VyZVlhbWxQYXJzZXIgd2hpY2ggdmFsaWRhdGVzIGNvbnRlbnQgYW5kIHByZXZlbnRzIG1hbGljaW91cyBwYXR0ZXJuc1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHBhcnNlZCA9IFNlY3VyZVlhbWxQYXJzZXIucGFyc2UoZGF0YSwge1xuICAgICAgICAgICAgbWF4WWFtbFNpemU6IDY0ICogMTAyNCwgLy8gNjRLQiBsaW1pdFxuICAgICAgICAgICAgdmFsaWRhdGVDb250ZW50OiB0cnVlXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gTG9nIHNlY3VyaXR5IGV2ZW50IGZvciBhdWRpdCB0cmFpbFxuICAgICAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgICAgIHR5cGU6ICdZQU1MX1BBUlNFX1NVQ0NFU1MnLFxuICAgICAgICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgICAgICAgc291cmNlOiAnUGVyc29uYUVsZW1lbnRNYW5hZ2VyLmltcG9ydEVsZW1lbnQnLFxuICAgICAgICAgICAgZGV0YWlsczogJ1lBTUwgY29udGVudCBzYWZlbHkgcGFyc2VkIGR1cmluZyBpbXBvcnQnXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gQ29udmVydCBwYXJzZWQgWUFNTCB0byBtYXJrZG93biBmb3JtYXRcbiAgICAgICAgICBwZXJzb25hLmRlc2VyaWFsaXplKHRoaXMuanNvblRvTWFya2Rvd24ocGFyc2VkLmRhdGEpKTtcbiAgICAgICAgfSBjYXRjaCAoc2VjdXJpdHlFcnJvcikge1xuICAgICAgICAgIC8vIExvZyB0aGUgc2VjdXJpdHkgdmlvbGF0aW9uXG4gICAgICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICAgICAgdHlwZTogJ1lBTUxfSU5KRUNUSU9OX0FUVEVNUFQnLFxuICAgICAgICAgICAgc2V2ZXJpdHk6ICdISUdIJyxcbiAgICAgICAgICAgIHNvdXJjZTogJ1BlcnNvbmFFbGVtZW50TWFuYWdlci5pbXBvcnRFbGVtZW50JyxcbiAgICAgICAgICAgIGRldGFpbHM6IGBZQU1MIHBhcnNpbmcgZmFpbGVkIHNlY3VyaXR5IHZhbGlkYXRpb246ICR7c2VjdXJpdHlFcnJvcn1gXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhyb3cgc2VjdXJpdHlFcnJvcjtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBmb3JtYXQ6ICR7Zm9ybWF0fWApO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gcGVyc29uYTtcblxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoYEZhaWxlZCB0byBpbXBvcnQgcGVyc29uYTogJHtlcnJvcn1gKTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW1wb3J0IGZhaWxlZDogJHtlcnJvcn1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRXhwb3J0IHBlcnNvbmEgdG8gZGF0YVxuICAgKiBTRUNVUklUWSBGSVggIzI6IFVzZXMgc3RhdGljIGltcG9ydCBvZiBqcy15YW1sIGF0IHRvcCBvZiBmaWxlIGluc3RlYWQgb2ZcbiAgICogZHluYW1pYyByZXF1aXJlKCkgZm9yIGJldHRlciBzZWN1cml0eSBhbmQgYnVuZGxpbmdcbiAgICogU0VDVVJJVFkgRklYICMzOiBVc2VzIHNlY3VyZSBZQU1MIGR1bXBpbmcgd2l0aCBzYWZldHkgb3B0aW9uc1xuICAgKi9cbiAgYXN5bmMgZXhwb3J0RWxlbWVudChlbGVtZW50OiBQZXJzb25hRWxlbWVudCwgZm9ybWF0OiAnanNvbicgfCAneWFtbCcgfCAnbWFya2Rvd24nID0gJ21hcmtkb3duJyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgdHJ5IHtcbiAgICAgIGlmIChmb3JtYXQgPT09ICdtYXJrZG93bicpIHtcbiAgICAgICAgcmV0dXJuIGVsZW1lbnQuc2VyaWFsaXplKCk7XG4gICAgICB9IGVsc2UgaWYgKGZvcm1hdCA9PT0gJ2pzb24nKSB7XG4gICAgICAgIGNvbnN0IGxlZ2FjeSA9IGVsZW1lbnQudG9MZWdhY3koKTtcbiAgICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHsgLi4ubGVnYWN5LCBjb250ZW50OiBlbGVtZW50LmNvbnRlbnQgfSwgbnVsbCwgMik7XG4gICAgICB9IGVsc2UgaWYgKGZvcm1hdCA9PT0gJ3lhbWwnKSB7XG4gICAgICAgIGNvbnN0IGxlZ2FjeSA9IGVsZW1lbnQudG9MZWdhY3koKTtcbiAgICAgICAgLy8gQ1JJVElDQUwgRklYOiBVc2luZyBzYWZlIFlBTUwgZHVtcCB3aXRoIHNlY3VyaXR5IG9wdGlvbnNcbiAgICAgICAgLy8gUHJldmlvdXNseTogVXNlZCBkeW5hbWljIHJlcXVpcmUgd2l0aG91dCBzYWZldHkgb3B0aW9uc1xuICAgICAgICAvLyBOb3c6IFVzZXMgc3RhdGljIGltcG9ydCB3aXRoIHNhZmUgc2NoZW1hIGFuZCBzZWN1cml0eSBmbGFnc1xuICAgICAgICByZXR1cm4geWFtbC5kdW1wKHsgLi4ubGVnYWN5LCBjb250ZW50OiBlbGVtZW50LmNvbnRlbnQgfSwge1xuICAgICAgICAgIHNjaGVtYTogeWFtbC5GQUlMU0FGRV9TQ0hFTUEsICAvLyBVc2UgcmVzdHJpY3RlZCBzY2hlbWFcbiAgICAgICAgICBza2lwSW52YWxpZDogdHJ1ZSwgICAgICAgICAgICAgIC8vIFNraXAgaW52YWxpZCBkYXRhIGluc3RlYWQgb2YgdGhyb3dpbmdcbiAgICAgICAgICBub1JlZnM6IHRydWUsICAgICAgICAgICAgICAgICAgIC8vIFByZXZlbnQgcmVmZXJlbmNlIGF0dGFja3NcbiAgICAgICAgICBub0NvbXBhdE1vZGU6IHRydWUgICAgICAgICAgICAgIC8vIFVzZSBzdHJpY3QgWUFNTCBtb2RlXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBmb3JtYXQ6ICR7Zm9ybWF0fWApO1xuICAgICAgfVxuXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5lcnJvcihgRmFpbGVkIHRvIGV4cG9ydCBwZXJzb25hOiAke2Vycm9yfWApO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBvcnQgZmFpbGVkOiAke2Vycm9yfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXI6IENvbnZlcnQgSlNPTiBkYXRhIHRvIG1hcmtkb3duIGZvcm1hdFxuICAgKiBTRUNVUklUWSBGSVggIzI6IFVzZXMgc3RhdGljYWxseSBpbXBvcnRlZCB5YW1sIG1vZHVsZVxuICAgKiBTRUNVUklUWSBGSVggIzM6IFVzZXMgc2VjdXJlIFlBTUwgZHVtcGluZyB3aXRoIHNhZmV0eSBvcHRpb25zXG4gICAqIE5vdGU6IFRoaXMgaXMgZm9yIGludGVybmFsIGNvbnZlcnNpb24gb25seSwgdXNlci1wcm92aWRlZCBZQU1MIG11c3QgdXNlIFNlY3VyZVlhbWxQYXJzZXJcbiAgICovXG4gIHByaXZhdGUganNvblRvTWFya2Rvd24oZGF0YTogYW55KTogc3RyaW5nIHtcbiAgICBjb25zdCB7IGNvbnRlbnQsIC4uLm1ldGFkYXRhIH0gPSBkYXRhO1xuICAgIC8vIFVzaW5nIHNhZmUgWUFNTCBkdW1wIHdpdGggc2VjdXJpdHkgb3B0aW9uc1xuICAgIGNvbnN0IHlhbWxGcm9udG1hdHRlciA9IHlhbWwuZHVtcChtZXRhZGF0YSwge1xuICAgICAgc2NoZW1hOiB5YW1sLkZBSUxTQUZFX1NDSEVNQSwgIC8vIFVzZSByZXN0cmljdGVkIHNjaGVtYVxuICAgICAgc2tpcEludmFsaWQ6IHRydWUsICAgICAgICAgICAgICAvLyBTa2lwIGludmFsaWQgZGF0YVxuICAgICAgbm9SZWZzOiB0cnVlLCAgICAgICAgICAgICAgICAgICAvLyBQcmV2ZW50IHJlZmVyZW5jZSBhdHRhY2tzXG4gICAgICBub0NvbXBhdE1vZGU6IHRydWUgICAgICAgICAgICAgIC8vIFVzZSBzdHJpY3QgWUFNTCBtb2RlXG4gICAgfSk7XG4gICAgcmV0dXJuIGAtLS1cXG4ke3lhbWxGcm9udG1hdHRlcn0tLS1cXG5cXG4ke2NvbnRlbnQgfHwgJyd9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBuZXcgcGVyc29uYSB3aXRoIGRlZmF1bHQgbWV0YWRhdGFcbiAgICovXG4gIGNyZWF0ZShtZXRhZGF0YTogUGFydGlhbDxQZXJzb25hRWxlbWVudE1ldGFkYXRhPik6IFBlcnNvbmFFbGVtZW50IHtcbiAgICBjb25zdCBkZWZhdWx0TWV0YWRhdGE6IFBhcnRpYWw8UGVyc29uYUVsZW1lbnRNZXRhZGF0YT4gPSB7XG4gICAgICBuYW1lOiAnTmV3IFBlcnNvbmEnLFxuICAgICAgZGVzY3JpcHRpb246ICdBIG5ldyBwZXJzb25hJyxcbiAgICAgIHZlcnNpb246ICcxLjAuMCcsXG4gICAgICBjYXRlZ29yeTogJ3BlcnNvbmFsJyxcbiAgICAgIGFnZV9yYXRpbmc6ICdhbGwnLFxuICAgICAgYWlfZ2VuZXJhdGVkOiBmYWxzZSxcbiAgICAgIGdlbmVyYXRpb25fbWV0aG9kOiAnaHVtYW4nLFxuICAgICAgcHJpY2U6ICdmcmVlJyxcbiAgICAgIGxpY2Vuc2U6ICdDQy1CWS1TQS00LjAnLFxuICAgICAgY3JlYXRlZF9kYXRlOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkuc3BsaXQoJ1QnKVswXSxcbiAgICAgIHRyaWdnZXJzOiBbXSxcbiAgICAgIGNvbnRlbnRfZmxhZ3M6IFtdXG4gICAgfTtcblxuICAgIHJldHVybiBuZXcgUGVyc29uYUVsZW1lbnQoeyAuLi5kZWZhdWx0TWV0YWRhdGEsIC4uLm1ldGFkYXRhIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBkZWZhdWx0IGZpbGVuYW1lIGZvciBhIHBlcnNvbmFcbiAgICovXG4gIGdldERlZmF1bHRGaWxlbmFtZShwZXJzb25hOiBQZXJzb25hRWxlbWVudCk6IHN0cmluZyB7XG4gICAgLy8gQ29udmVydCBuYW1lIHRvIHNhZmUgZmlsZW5hbWVcbiAgICBjb25zdCBzYWZlTmFtZSA9IHBlcnNvbmEubWV0YWRhdGEubmFtZVxuICAgICAgLnRvTG93ZXJDYXNlKClcbiAgICAgIC5yZXBsYWNlKC9bXmEtejAtOV0rL2csICctJylcbiAgICAgIC5yZXBsYWNlKC9eLSt8LSskL2csICcnKTtcbiAgICBcbiAgICByZXR1cm4gYCR7c2FmZU5hbWV9Lm1kYDtcbiAgfVxufSJdfQ==