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.

419 lines 59.6 kB
/** * AnthropicToDollhouseConverter - Converts multi-file Anthropic Skills to single-file DollhouseMCP skills * * This is the INVERSE of DollhouseToAnthropicConverter. * * Implements the reverse transformation: * Anthropic Skill (directory with separated components) → DollhouseMCP Skill (single .md file) * * Algorithm (inverse of decomposition): * 1. Read SKILL.md and extract minimal YAML frontmatter * 2. Enrich YAML with DollhouseMCP fields (version, created, modified, tags, etc.) * 3. Read all scripts/ files and embed as code blocks * 4. Read all reference/ files and embed as documentation sections * 5. Read all examples/ files and embed as example sections * 6. Read all themes/ files and embed as templates * 7. Combine all content into single .md file with rich frontmatter * 8. Return single-file content * * SECURITY MODEL: * - This is a FORMAT TRANSFORMER, not a security boundary * - Preserves content fidelity - no modification, sanitization, or validation during conversion * - YAML parsing uses CORE_SCHEMA to prevent deserialization attacks only * - Output validation happens when user loads skill via SkillManager.load() * - SkillManager.load() applies SecureYamlParser and full security validation * - Converted skills must pass DollhouseMCP security checks before activation */ import * as fs from 'node:fs'; import * as path from 'node:path'; import * as yaml from 'js-yaml'; import { SchemaMapper } from './SchemaMapper.js'; export class AnthropicToDollhouseConverter { schemaMapper; constructor() { this.schemaMapper = new SchemaMapper(); } /** * Convert an Anthropic Skill directory to a single DollhouseMCP skill file * * INVERSE ALGORITHM: * 1. Read SKILL.md and extract minimal YAML * 2. Enrich YAML with DollhouseMCP fields * 3. Read all scripts/ files and embed as code blocks * 4. Read all reference/ files and embed as documentation sections * 5. Read all examples/ files and embed as example sections * 6. Read all themes/ files and embed as templates * 7. Combine all content into single .md file * 8. Return single-file content */ async convertSkill(skillDirPath, options) { // Step 1: Read the Anthropic skill directory structure // NOTE: No Unicode normalization - preserves content fidelity // Output will be validated when loaded via SkillManager.load() const skillData = await this.readAnthropicStructure(skillDirPath); // Step 2: Check for preserved DollhouseMCP metadata, or enrich if not found let enrichedMetadata; if (skillData.metadata?.has('dollhouse.yaml')) { // Use preserved metadata for perfect roundtrip const preservedYAML = skillData.metadata.get('dollhouse.yaml'); // FIX (DMCP-SEC-005): Use CORE_SCHEMA to prevent YAML deserialization attacks enrichedMetadata = yaml.load(preservedYAML, { schema: yaml.CORE_SCHEMA }); // Apply any custom metadata overrides if (options?.customMetadata) { Object.assign(enrichedMetadata, options.customMetadata); } } else { // Fall back to enrichment if no preserved metadata enrichedMetadata = this.enrichMetadata(skillData.skillMD.metadata, options); } // Step 3-6: Combine all components const combinedContent = this.combineComponents(skillData); // Step 7: Create single .md file with rich frontmatter const dollhouseSkill = this.createDollhouseSkill(enrichedMetadata, combinedContent); return dollhouseSkill; } /** * Convert in-memory Anthropic skill structure to DollhouseMCP format */ convertFromStructure(structure, options) { // Parse SKILL.md // NOTE: No Unicode normalization - preserves content fidelity const { metadata, content } = this.parseSkillMD(structure['SKILL.md']); // Convert structure to directory format const skillData = this.buildSkillDataFromStructure(structure, metadata, content); // Get enriched metadata (either preserved or generated) const enrichedMetadata = this.getEnrichedMetadata(skillData, metadata, options); // Combine components and create final skill const combinedContent = this.combineComponents(skillData); return this.createDollhouseSkill(enrichedMetadata, combinedContent); } /** * Build skill data structure from Anthropic structure * REFACTORED: Extracted to reduce cognitive complexity */ buildSkillDataFromStructure(structure, metadata, content) { const skillData = { skillMD: { metadata, content }, scripts: new Map(), reference: new Map(), examples: new Map(), themes: new Map() }; // Process all structure components this.processStructureScripts(structure, skillData); this.processStructureDirectory(structure['reference/'], skillData.reference); this.processStructureDirectory(structure['examples/'], skillData.examples); this.processStructureDirectory(structure['themes/'], skillData.themes); this.processStructureMetadata(structure, skillData); if (structure['LICENSE.txt']) { skillData.license = structure['LICENSE.txt']; } return skillData; } /** * Process scripts from structure * REFACTORED: Extracted to reduce cognitive complexity */ processStructureScripts(structure, skillData) { if (!structure['scripts/']) return; for (const [filename, content] of Object.entries(structure['scripts/'])) { const language = this.inferLanguageFromFilename(filename); const cleanContent = this.removeShebangAndHeaders(content); skillData.scripts.set(filename, { content: cleanContent, language }); } } /** * Process generic directory structure (reference, examples, themes) * REFACTORED: Extracted to reduce cognitive complexity */ processStructureDirectory(sourceDir, targetMap) { if (!sourceDir) return; for (const [filename, content] of Object.entries(sourceDir)) { targetMap.set(filename, content); } } /** * Process metadata from structure * REFACTORED: Extracted to reduce cognitive complexity */ processStructureMetadata(structure, skillData) { if (!structure['metadata/']) return; skillData.metadata = new Map(); for (const [filename, content] of Object.entries(structure['metadata/'])) { skillData.metadata.set(filename, content); } } /** * Get enriched metadata (preserved or generated) * REFACTORED: Extracted to reduce cognitive complexity */ getEnrichedMetadata(skillData, metadata, options) { // Check for preserved DollhouseMCP metadata if (skillData.metadata?.has('dollhouse.yaml')) { return this.loadPreservedMetadata(skillData.metadata.get('dollhouse.yaml'), options); } // Fall back to enrichment if no preserved metadata return this.enrichMetadata(metadata, options); } /** * Load preserved metadata from YAML * REFACTORED: Extracted to reduce cognitive complexity */ loadPreservedMetadata(preservedYAML, options) { // FIX (DMCP-SEC-005): Use CORE_SCHEMA to prevent YAML deserialization attacks const enrichedMetadata = yaml.load(preservedYAML, { schema: yaml.CORE_SCHEMA }); // Apply any custom metadata overrides if (options?.customMetadata) { Object.assign(enrichedMetadata, options.customMetadata); } return enrichedMetadata; } /** * Read Anthropic skill directory structure from disk * REFACTORED: Simplified by extracting directory reading logic */ async readAnthropicStructure(skillDirPath) { this.validateSkillDirectory(skillDirPath); // Read and parse SKILL.md const { metadata, content } = this.readSkillMD(skillDirPath); // Initialize skill data structure const skillData = { skillMD: { metadata, content }, scripts: new Map(), reference: new Map(), examples: new Map(), themes: new Map() }; // Read all directory components this.readScriptsDirectory(skillDirPath, skillData); this.readFilesDirectory(skillDirPath, 'reference', skillData.reference); this.readFilesDirectory(skillDirPath, 'examples', skillData.examples); this.readFilesDirectory(skillDirPath, 'themes', skillData.themes); this.readMetadataDirectory(skillDirPath, skillData); this.readLicenseFile(skillDirPath, skillData); return skillData; } /** * Validate skill directory exists and has SKILL.md * REFACTORED: Extracted to reduce cognitive complexity */ validateSkillDirectory(skillDirPath) { if (!fs.existsSync(skillDirPath)) { throw new Error(`Skill directory not found: ${skillDirPath}`); } const skillMDPath = path.join(skillDirPath, 'SKILL.md'); if (!fs.existsSync(skillMDPath)) { throw new Error(`SKILL.md not found in ${skillDirPath}`); } } /** * Read and parse SKILL.md file * REFACTORED: Extracted to reduce cognitive complexity */ readSkillMD(skillDirPath) { const skillMDPath = path.join(skillDirPath, 'SKILL.md'); const skillMDContent = fs.readFileSync(skillMDPath, 'utf-8'); return this.parseSkillMD(skillMDContent); } /** * Read scripts directory and process script files * REFACTORED: Extracted to reduce cognitive complexity */ readScriptsDirectory(skillDirPath, skillData) { const scriptsDir = path.join(skillDirPath, 'scripts'); if (!fs.existsSync(scriptsDir)) return; const scriptFiles = fs.readdirSync(scriptsDir); for (const filename of scriptFiles) { const filePath = path.join(scriptsDir, filename); const content = fs.readFileSync(filePath, 'utf-8'); const language = this.inferLanguageFromFilename(filename); const cleanContent = this.removeShebangAndHeaders(content); skillData.scripts.set(filename, { content: cleanContent, language }); } } /** * Read generic files directory (reference, examples, themes) * REFACTORED: Extracted to reduce cognitive complexity and reuse code */ readFilesDirectory(skillDirPath, dirName, targetMap) { const dirPath = path.join(skillDirPath, dirName); if (!fs.existsSync(dirPath)) return; const files = fs.readdirSync(dirPath); for (const filename of files) { const filePath = path.join(dirPath, filename); const content = fs.readFileSync(filePath, 'utf-8'); targetMap.set(filename, content); } } /** * Read metadata directory * REFACTORED: Extracted to reduce cognitive complexity */ readMetadataDirectory(skillDirPath, skillData) { const metadataDir = path.join(skillDirPath, 'metadata'); if (!fs.existsSync(metadataDir)) return; skillData.metadata = new Map(); const metadataFiles = fs.readdirSync(metadataDir); for (const filename of metadataFiles) { const filePath = path.join(metadataDir, filename); const content = fs.readFileSync(filePath, 'utf-8'); skillData.metadata.set(filename, content); } } /** * Read LICENSE.txt file if it exists * REFACTORED: Extracted to reduce cognitive complexity */ readLicenseFile(skillDirPath, skillData) { const licensePath = path.join(skillDirPath, 'LICENSE.txt'); if (fs.existsSync(licensePath)) { skillData.license = fs.readFileSync(licensePath, 'utf-8'); } } /** * Parse SKILL.md and extract metadata and content */ parseSkillMD(skillMDContent) { const yamlMatch = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/.exec(skillMDContent); if (!yamlMatch) { throw new Error('No YAML frontmatter found in SKILL.md'); } // FIX (DMCP-SEC-005): Use CORE_SCHEMA to prevent YAML deserialization attacks const metadata = yaml.load(yamlMatch[1], { schema: yaml.CORE_SCHEMA }); const content = yamlMatch[2].trim(); return { metadata, content }; } /** * Enrich minimal Anthropic metadata with DollhouseMCP fields */ enrichMetadata(anthropicMeta, options) { // Infer tags and category from name/description const inferredTags = this.schemaMapper.inferTags(anthropicMeta.name, anthropicMeta.description); const inferredCategory = this.schemaMapper.inferCategory(anthropicMeta.name, anthropicMeta.description); // Use SchemaMapper to convert const enriched = this.schemaMapper.anthropicToDollhouse(anthropicMeta, { inferredTags, inferredCategory, inferredType: 'skill' }); // Apply custom metadata overrides if (options?.customMetadata) { Object.assign(enriched, options.customMetadata); } return enriched; } /** * Combine all Anthropic skill components into single markdown content */ combineComponents(skillData) { const sections = []; // Start with main content from SKILL.md sections.push(skillData.skillMD.content); // Add embedded scripts as code blocks if (skillData.scripts.size > 0) { sections.push('\n## Scripts\n'); for (const [filename, { content, language }] of skillData.scripts) { const title = this.filenameToTitle(filename); sections.push(`### ${title}\n`, '```' + language, content, '```\n'); } } // Add reference documentation sections if (skillData.reference.size > 0) { for (const [, content] of skillData.reference) { sections.push('\n' + content); } } // Add examples if (skillData.examples.size > 0) { sections.push('\n## Examples\n'); for (const [, content] of skillData.examples) { sections.push(content, '\n'); } } // Add themes/templates if (skillData.themes.size > 0) { sections.push('\n## Templates\n'); for (const [, content] of skillData.themes) { sections.push(content, '\n'); } } return sections.join('\n').trim(); } /** * Create final DollhouseMCP skill with rich frontmatter */ createDollhouseSkill(metadata, content) { const yamlString = yaml.dump(metadata); return `---\n${yamlString}---\n\n${content}\n`; } /** * Infer programming language from filename */ inferLanguageFromFilename(filename) { const ext = path.extname(filename).toLowerCase(); const languageMap = { '.sh': 'bash', '.bash': 'bash', '.py': 'python', '.js': 'javascript', '.ts': 'typescript', '.rb': 'ruby', '.pl': 'perl', '.php': 'php' }; return languageMap[ext] || 'text'; } /** * Remove shebang and auto-generated headers from extracted scripts */ removeShebangAndHeaders(content) { const lines = content.split('\n'); let startIndex = 0; // Skip shebang if (lines[0]?.startsWith('#!')) { startIndex = 1; } // Skip auto-generated header comments if (lines[startIndex]?.startsWith('# Extracted script')) { startIndex++; } // Skip empty lines after headers while (startIndex < lines.length && lines[startIndex]?.trim() === '') { startIndex++; } return lines.slice(startIndex).join('\n').trim(); } /** * Convert filename to readable title */ filenameToTitle(filename) { // Remove extension const nameWithoutExt = path.basename(filename, path.extname(filename)); // Convert hyphens/underscores to spaces and capitalize return nameWithoutExt .replaceAll(/[-_]/g, ' ') .split(' ') .map(word => word.charAt(0).toUpperCase() + word.slice(1)) .join(' '); } /** * Write DollhouseMCP skill to disk */ async writeToFile(skillContent, outputPath) { // Ensure output directory exists const outputDir = path.dirname(outputPath); if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } // Write skill file fs.writeFileSync(outputPath, skillContent, 'utf-8'); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQW50aHJvcGljVG9Eb2xsaG91c2VDb252ZXJ0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29udmVydGVycy9BbnRocm9waWNUb0RvbGxob3VzZUNvbnZlcnRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXlCRztBQUVILE9BQU8sS0FBSyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQzlCLE9BQU8sS0FBSyxJQUFJLE1BQU0sV0FBVyxDQUFDO0FBQ2xDLE9BQU8sS0FBSyxJQUFJLE1BQU0sU0FBUyxDQUFDO0FBQ2hDLE9BQU8sRUFBRSxZQUFZLEVBQStELE1BQU0sbUJBQW1CLENBQUM7QUFnQjlHLE1BQU0sT0FBTyw2QkFBNkI7SUFDckIsWUFBWSxDQUFlO0lBRTVDO1FBQ0ksSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO0lBQzNDLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7O09BWUc7SUFDSCxLQUFLLENBQUMsWUFBWSxDQUFDLFlBQW9CLEVBQUUsT0FHeEM7UUFDRyx1REFBdUQ7UUFDdkQsOERBQThEO1FBQzlELCtEQUErRDtRQUMvRCxNQUFNLFNBQVMsR0FBRyxNQUFNLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUVsRSw0RUFBNEU7UUFDNUUsSUFBSSxnQkFBMkMsQ0FBQztRQUNoRCxJQUFJLFNBQVMsQ0FBQyxRQUFRLEVBQUUsR0FBRyxDQUFDLGdCQUFnQixDQUFDLEVBQUUsQ0FBQztZQUM1QywrQ0FBK0M7WUFDL0MsTUFBTSxhQUFhLEdBQUcsU0FBUyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLENBQUUsQ0FBQztZQUNoRSw4RUFBOEU7WUFDOUUsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUE4QixDQUFD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Q3BDLG1CQUFtQjtRQUNuQixNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7UUFFdkUsdURBQXVEO1FBQ3ZELE9BQU8sY0FBYzthQUNoQixVQUFVLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQzthQUN4QixLQUFLLENBQUMsR0FBRyxDQUFDO2FBQ1YsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO2FBQ3pELElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNuQixDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsV0FBVyxDQUFDLFlBQW9CLEVBQUUsVUFBa0I7UUFDdEQsaUNBQWlDO1FBQ2pDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDM0MsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztZQUM1QixFQUFFLENBQUMsU0FBUyxDQUFDLFNBQVMsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQ2pELENBQUM7UUFFRCxtQkFBbUI7UUFDbkIsRUFBRSxDQUFDLGFBQWEsQ0FBQyxVQUFVLEVBQUUsWUFBWSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ3hELENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQW50aHJvcGljVG9Eb2xsaG91c2VDb252ZXJ0ZXIgLSBDb252ZXJ0cyBtdWx0aS1maWxlIEFudGhyb3BpYyBTa2lsbHMgdG8gc2luZ2xlLWZpbGUgRG9sbGhvdXNlTUNQIHNraWxsc1xuICpcbiAqIFRoaXMgaXMgdGhlIElOVkVSU0Ugb2YgRG9sbGhvdXNlVG9BbnRocm9waWNDb252ZXJ0ZXIuXG4gKlxuICogSW1wbGVtZW50cyB0aGUgcmV2ZXJzZSB0cmFuc2Zvcm1hdGlvbjpcbiAqIEFudGhyb3BpYyBTa2lsbCAoZGlyZWN0b3J5IHdpdGggc2VwYXJhdGVkIGNvbXBvbmVudHMpIOKGkiBEb2xsaG91c2VNQ1AgU2tpbGwgKHNpbmdsZSAubWQgZmlsZSlcbiAqXG4gKiBBbGdvcml0aG0gKGludmVyc2Ugb2YgZGVjb21wb3NpdGlvbik6XG4gKiAxLiBSZWFkIFNLSUxMLm1kIGFuZCBleHRyYWN0IG1pbmltYWwgWUFNTCBmcm9udG1hdHRlclxuICogMi4gRW5yaWNoIFlBTUwgd2l0aCBEb2xsaG91c2VNQ1AgZmllbGRzICh2ZXJzaW9uLCBjcmVhdGVkLCBtb2RpZmllZCwgdGFncywgZXRjLilcbiAqIDMuIFJlYWQgYWxsIHNjcmlwdHMvIGZpbGVzIGFuZCBlbWJlZCBhcyBjb2RlIGJsb2Nrc1xuICogNC4gUmVhZCBhbGwgcmVmZXJlbmNlLyBmaWxlcyBhbmQgZW1iZWQgYXMgZG9jdW1lbnRhdGlvbiBzZWN0aW9uc1xuICogNS4gUmVhZCBhbGwgZXhhbXBsZXMvIGZpbGVzIGFuZCBlbWJlZCBhcyBleGFtcGxlIHNlY3Rpb25zXG4gKiA2LiBSZWFkIGFsbCB0aGVtZXMvIGZpbGVzIGFuZCBlbWJlZCBhcyB0ZW1wbGF0ZXNcbiAqIDcuIENvbWJpbmUgYWxsIGNvbnRlbnQgaW50byBzaW5nbGUgLm1kIGZpbGUgd2l0aCByaWNoIGZyb250bWF0dGVyXG4gKiA4LiBSZXR1cm4gc2luZ2xlLWZpbGUgY29udGVudFxuICpcbiAqIFNFQ1VSSVRZIE1PREVMOlxuICogLSBUaGlzIGlzIGEgRk9STUFUIFRSQU5TRk9STUVSLCBub3QgYSBzZWN1cml0eSBib3VuZGFyeVxuICogLSBQcmVzZXJ2ZXMgY29udGVudCBmaWRlbGl0eSAtIG5vIG1vZGlmaWNhdGlvbiwgc2FuaXRpemF0aW9uLCBvciB2YWxpZGF0aW9uIGR1cmluZyBjb252ZXJzaW9uXG4gKiAtIFlBTUwgcGFyc2luZyB1c2VzIENPUkVfU0NIRU1BIHRvIHByZXZlbnQgZGVzZXJpYWxpemF0aW9uIGF0dGFja3Mgb25seVxuICogLSBPdXRwdXQgdmFsaWRhdGlvbiBoYXBwZW5zIHdoZW4gdXNlciBsb2FkcyBza2lsbCB2aWEgU2tpbGxNYW5hZ2VyLmxvYWQoKVxuICogLSBTa2lsbE1hbmFnZXIubG9hZCgpIGFwcGxpZXMgU2VjdXJlWWFtbFBhcnNlciBhbmQgZnVsbCBzZWN1cml0eSB2YWxpZGF0aW9uXG4gKiAtIENvbnZlcnRlZCBza2lsbHMgbXVzdCBwYXNzIERvbGxob3VzZU1DUCBzZWN1cml0eSBjaGVja3MgYmVmb3JlIGFjdGl2YXRpb25cbiAqL1xuXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdub2RlOmZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCAqIGFzIHlhbWwgZnJvbSAnanMteWFtbCc7XG5pbXBvcnQgeyBTY2hlbWFNYXBwZXIsIHR5cGUgQW50aHJvcGljU2tpbGxNZXRhZGF0YSwgdHlwZSBEb2xsaG91c2VNQ1BTa2lsbE1ldGFkYXRhIH0gZnJvbSAnLi9TY2hlbWFNYXBwZXIuanMnO1xuaW1wb3J0IHR5cGUgeyBBbnRocm9waWNTa2lsbFN0cnVjdHVyZSB9IGZyb20gJy4vRG9sbGhvdXNlVG9BbnRocm9waWNDb252ZXJ0ZXIuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEFudGhyb3BpY1NraWxsRGlyZWN0b3J5IHtcbiAgICBza2lsbE1EOiB7XG4gICAgICAgIG1ldGFkYXRhOiBBbnRocm9waWNTa2lsbE1ldGFkYXRhO1xuICAgICAgICBjb250ZW50OiBzdHJpbmc7XG4gICAgfTtcbiAgICBzY3JpcHRzOiBNYXA8c3RyaW5nLCB7IGNvbnRlbnQ6IHN0cmluZzsgbGFuZ3VhZ2U6IHN0cmluZyB9PjtcbiAgICByZWZlcmVuY2U6IE1hcDxzdHJpbmcsIHN0cmluZz47XG4gICAgZXhhbXBsZXM6IE1hcDxzdHJpbmcsIHN0cmluZz47XG4gICAgdGhlbWVzOiBNYXA8c3RyaW5nLCBzdHJpbmc+O1xuICAgIG1ldGFkYXRhPzogTWFwPHN0cmluZywgc3RyaW5nPjtcbiAgICBsaWNlbnNlPzogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgQW50aHJvcGljVG9Eb2xsaG91c2VDb252ZXJ0ZXIge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgc2NoZW1hTWFwcGVyOiBTY2hlbWFNYXBwZXI7XG5cbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy5zY2hlbWFNYXBwZXIgPSBuZXcgU2NoZW1hTWFwcGVyKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ29udmVydCBhbiBBbnRocm9waWMgU2tpbGwgZGlyZWN0b3J5IHRvIGEgc2luZ2xlIERvbGxob3VzZU1DUCBza2lsbCBmaWxlXG4gICAgICpcbiAgICAgKiBJTlZFUlNFIEFMR09SSVRITTpcbiAgICAgKiAxLiBSZWFkIFNLSUxMLm1kIGFuZCBleHRyYWN0IG1pbmltYWwgWUFNTFxuICAgICAqIDIuIEVucmljaCBZQU1MIHdpdGggRG9sbGhvdXNlTUNQIGZpZWxkc1xuICAgICAqIDMuIFJlYWQgYWxsIHNjcmlwdHMvIGZpbGVzIGFuZCBlbWJlZCBhcyBjb2RlIGJsb2Nrc1xuICAgICAqIDQuIFJlYWQgYWxsIHJlZmVyZW5jZS8gZmlsZXMgYW5kIGVtYmVkIGFzIGRvY3VtZW50YXRpb24gc2VjdGlvbnNcbiAgICAgKiA1LiBSZWFkIGFsbCBleGFtcGxlcy8gZmlsZXMgYW5kIGVtYmVkIGFzIGV4YW1wbGUgc2VjdGlvbnNcbiAgICAgKiA2LiBSZWFkIGFsbCB0aGVtZXMvIGZpbGVzIGFuZCBlbWJlZCBhcyB0ZW1wbGF0ZXNcbiAgICAgKiA3LiBDb21iaW5lIGFsbCBjb250ZW50IGludG8gc2luZ2xlIC5tZCBmaWxlXG4gICAgICogOC4gUmV0dXJuIHNpbmdsZS1maWxlIGNvbnRlbnRcbiAgICAgKi9cbiAgICBhc3luYyBjb252ZXJ0U2tpbGwoc2tpbGxEaXJQYXRoOiBzdHJpbmcsIG9wdGlvbnM/OiB7XG4gICAgICAgIHByZXNlcnZlU291cmNlPzogYm9vbGVhbjtcbiAgICAgICAgY3VzdG9tTWV0YWRhdGE/OiBQYXJ0aWFsPERvbGxob3VzZU1DUFNraWxsTWV0YWRhdGE+O1xuICAgIH0pOiBQcm9taXNlPHN0cmluZz4ge1xuICAgICAgICAvLyBTdGVwIDE6IFJlYWQgdGhlIEFudGhyb3BpYyBza2lsbCBkaXJlY3Rvcnkgc3RydWN0dXJlXG4gICAgICAgIC8vIE5PVEU6IE5vIFVuaWNvZGUgbm9ybWFsaXphdGlvbiAtIHByZXNlcnZlcyBjb250ZW50IGZpZGVsaXR5XG4gICAgICAgIC8vIE91dHB1dCB3aWxsIGJlIHZhbGlkYXRlZCB3aGVuIGxvYWRlZCB2aWEgU2tpbGxNYW5hZ2VyLmxvYWQoKVxuICAgICAgICBjb25zdCBza2lsbERhdGEgPSBhd2FpdCB0aGlzLnJlYWRBbnRocm9waWNTdHJ1Y3R1cmUoc2tpbGxEaXJQYXRoKTtcblxuICAgICAgICAvLyBTdGVwIDI6IENoZWNrIGZvciBwcmVzZXJ2ZWQgRG9sbGhvdXNlTUNQIG1ldGFkYXRhLCBvciBlbnJpY2ggaWYgbm90IGZvdW5kXG4gICAgICAgIGxldCBlbnJpY2hlZE1ldGFkYXRhOiBEb2xsaG91c2VNQ1BTa2lsbE1ldGFkYXRhO1xuICAgICAgICBpZiAoc2tpbGxEYXRhLm1ldGFkYXRhPy5oYXMoJ2RvbGxob3VzZS55YW1sJykpIHtcbiAgICAgICAgICAgIC8vIFVzZSBwcmVzZXJ2ZWQgbWV0YWRhdGEgZm9yIHBlcmZlY3Qgcm91bmR0cmlwXG4gICAgICAgICAgICBjb25zdCBwcmVzZXJ2ZWRZQU1MID0gc2tpbGxEYXRhLm1ldGFkYXRhLmdldCgnZG9sbGhvdXNlLnlhbWwnKSE7XG4gICAgICAgICAgICAvLyBGSVggKERNQ1AtU0VDLTAwNSk6IFVzZSBDT1JFX1NDSEVNQSB0byBwcmV2ZW50IFlBTUwgZGVzZXJpYWxpemF0aW9uIGF0dGFja3NcbiAgICAgICAgICAgIGVucmljaGVkTWV0YWRhdGEgPSB5YW1sLmxvYWQocHJlc2VydmVkWUFNTCwgeyBzY2hlbWE6IHlhbWwuQ09SRV9TQ0hFTUEgfSkgYXMgRG9sbGhvdXNlTUNQU2tpbGxNZXRhZGF0YTtcbiAgICAgICAgICAgIC8vIEFwcGx5IGFueSBjdXN0b20gbWV0YWRhdGEgb3ZlcnJpZGVzXG4gICAgICAgICAgICBpZiAob3B0aW9ucz8uY3VzdG9tTWV0YWRhdGEpIHtcbiAgICAgICAgICAgICAgICBPYmplY3QuYXNzaWduKGVucmljaGVkTWV0YWRhdGEsIG9wdGlvbnMuY3VzdG9tTWV0YWRhdGEpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gRmFsbCBiYWNrIHRvIGVucmljaG1lbnQgaWYgbm8gcHJlc2VydmVkIG1ldGFkYXRhXG4gICAgICAgICAgICBlbnJpY2hlZE1ldGFkYXRhID0gdGhpcy5lbnJpY2hNZXRhZGF0YShza2lsbERhdGEuc2tpbGxNRC5tZXRhZGF0YSwgb3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTdGVwIDMtNjogQ29tYmluZSBhbGwgY29tcG9uZW50c1xuICAgICAgICBjb25zdCBjb21iaW5lZENvbnRlbnQgPSB0aGlzLmNvbWJpbmVDb21wb25lbnRzKHNraWxsRGF0YSk7XG5cbiAgICAgICAgLy8gU3RlcCA3OiBDcmVhdGUgc2luZ2xlIC5tZCBmaWxlIHdpdGggcmljaCBmcm9udG1hdHRlclxuICAgICAgICBjb25zdCBkb2xsaG91c2VTa2lsbCA9IHRoaXMuY3JlYXRlRG9sbGhvdXNlU2tpbGwoZW5yaWNoZWRNZXRhZGF0YSwgY29tYmluZWRDb250ZW50KTtcblxuICAgICAgICByZXR1cm4gZG9sbGhvdXNlU2tpbGw7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ29udmVydCBpbi1tZW1vcnkgQW50aHJvcGljIHNraWxsIHN0cnVjdHVyZSB0byBEb2xsaG91c2VNQ1AgZm9ybWF0XG4gICAgICovXG4gICAgY29udmVydEZyb21TdHJ1Y3R1cmUoc3RydWN0dXJlOiBBbnRocm9waWNTa2lsbFN0cnVjdHVyZSwgb3B0aW9ucz86IHtcbiAgICAgICAgcHJlc2VydmVTb3VyY2U/OiBib29sZWFuO1xuICAgICAgICBjdXN0b21NZXRhZGF0YT86IFBhcnRpYWw8RG9sbGhvdXNlTUNQU2tpbGxNZXRhZGF0YT47XG4gICAgfSk6IHN0cmluZyB7XG4gICAgICAgIC8vIFBhcnNlIFNLSUxMLm1kXG4gICAgICAgIC8vIE5PVEU6IE5vIFVuaWNvZGUgbm9ybWFsaXphdGlvbiAtIHByZXNlcnZlcyBjb250ZW50IGZpZGVsaXR5XG4gICAgICAgIGNvbnN0IHsgbWV0YWRhdGEsIGNvbnRlbnQgfSA9IHRoaXMucGFyc2VTa2lsbE1EKHN0cnVjdHVyZVsnU0tJTEwubWQnXSk7XG5cbiAgICAgICAgLy8gQ29udmVydCBzdHJ1Y3R1cmUgdG8gZGlyZWN0b3J5IGZvcm1hdFxuICAgICAgICBjb25zdCBza2lsbERhdGEgPSB0aGlzLmJ1aWxkU2tpbGxEYXRhRnJvbVN0cnVjdHVyZShzdHJ1Y3R1cmUsIG1ldGFkYXRhLCBjb250ZW50KTtcblxuICAgICAgICAvLyBHZXQgZW5yaWNoZWQgbWV0YWRhdGEgKGVpdGhlciBwcmVzZXJ2ZWQgb3IgZ2VuZXJhdGVkKVxuICAgICAgICBjb25zdCBlbnJpY2hlZE1ldGFkYXRhID0gdGhpcy5nZXRFbnJpY2hlZE1ldGFkYXRhKHNraWxsRGF0YSwgbWV0YWRhdGEsIG9wdGlvbnMpO1xuXG4gICAgICAgIC8vIENvbWJpbmUgY29tcG9uZW50cyBhbmQgY3JlYXRlIGZpbmFsIHNraWxsXG4gICAgICAgIGNvbnN0IGNvbWJpbmVkQ29udGVudCA9IHRoaXMuY29tYmluZUNvbXBvbmVudHMoc2tpbGxEYXRhKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuY3JlYXRlRG9sbGhvdXNlU2tpbGwoZW5yaWNoZWRNZXRhZGF0YSwgY29tYmluZWRDb250ZW50KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBCdWlsZCBza2lsbCBkYXRhIHN0cnVjdHVyZSBmcm9tIEFudGhyb3BpYyBzdHJ1Y3R1cmVcbiAgICAgKiBSRUZBQ1RPUkVEOiBFeHRyYWN0ZWQgdG8gcmVkdWNlIGNvZ25pdGl2ZSBjb21wbGV4aXR5XG4gICAgICovXG4gICAgcHJpdmF0ZSBidWlsZFNraWxsRGF0YUZyb21TdHJ1Y3R1cmUoXG4gICAgICAgIHN0cnVjdHVyZTogQW50aHJvcGljU2tpbGxTdHJ1Y3R1cmUsXG4gICAgICAgIG1ldGFkYXRhOiBBbnRocm9waWNTa2lsbE1ldGFkYXRhLFxuICAgICAgICBjb250ZW50OiBzdHJpbmdcbiAgICApOiBBbnRocm9waWNTa2lsbERpcmVjdG9yeSB7XG4gICAgICAgIGNvbnN0IHNraWxsRGF0YTogQW50aHJvcGljU2tpbGxEaXJlY3RvcnkgPSB7XG4gICAgICAgICAgICBza2lsbE1EOiB7IG1ldGFkYXRhLCBjb250ZW50IH0sXG4gICAgICAgICAgICBzY3JpcHRzOiBuZXcgTWFwKCksXG4gICAgICAgICAgICByZWZlcmVuY2U6IG5ldyBNYXAoKSxcbiAgICAgICAgICAgIGV4YW1wbGVzOiBuZXcgTWFwKCksXG4gICAgICAgICAgICB0aGVtZXM6IG5ldyBNYXAoKVxuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFByb2Nlc3MgYWxsIHN0cnVjdHVyZSBjb21wb25lbnRzXG4gICAgICAgIHRoaXMucHJvY2Vzc1N0cnVjdHVyZVNjcmlwdHMoc3RydWN0dXJlLCBza2lsbERhdGEpO1xuICAgICAgICB0aGlzLnByb2Nlc3NTdHJ1Y3R1cmVEaXJlY3Rvcnkoc3RydWN0dXJlWydyZWZlcmVuY2UvJ10sIHNraWxsRGF0YS5yZWZlcmVuY2UpO1xuICAgICAgICB0aGlzLnByb2Nlc3NTdHJ1Y3R1cmVEaXJlY3Rvcnkoc3RydWN0dXJlWydleGFtcGxlcy8nXSwgc2tpbGxEYXRhLmV4YW1wbGVzKTtcbiAgICAgICAgdGhpcy5wcm9jZXNzU3RydWN0dXJlRGlyZWN0b3J5KHN0cnVjdHVyZVsndGhlbWVzLyddLCBza2lsbERhdGEudGhlbWVzKTtcbiAgICAgICAgdGhpcy5wcm9jZXNzU3RydWN0dXJlTWV0YWRhdGEoc3RydWN0dXJlLCBza2lsbERhdGEpO1xuXG4gICAgICAgIGlmIChzdHJ1Y3R1cmVbJ0xJQ0VOU0UudHh0J10pIHtcbiAgICAgICAgICAgIHNraWxsRGF0YS5saWNlbnNlID0gc3RydWN0dXJlWydMSUNFTlNFLnR4dCddO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHNraWxsRGF0YTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQcm9jZXNzIHNjcmlwdHMgZnJvbSBzdHJ1Y3R1cmVcbiAgICAgKiBSRUZBQ1RPUkVEOiBFeHRyYWN0ZWQgdG8gcmVkdWNlIGNvZ25pdGl2ZSBjb21wbGV4aXR5XG4gICAgICovXG4gICAgcHJpdmF0ZSBwcm9jZXNzU3RydWN0dXJlU2NyaXB0cyhzdHJ1Y3R1cmU6IEFudGhyb3BpY1NraWxsU3RydWN0dXJlLCBza2lsbERhdGE6IEFudGhyb3BpY1NraWxsRGlyZWN0b3J5KTogdm9pZCB7XG4gICAgICAgIGlmICghc3RydWN0dXJlWydzY3JpcHRzLyddKSByZXR1cm47XG5cbiAgICAgICAgZm9yIChjb25zdCBbZmlsZW5hbWUsIGNvbnRlbnRdIG9mIE9iamVjdC5lbnRyaWVzKHN0cnVjdHVyZVsnc2NyaXB0cy8nXSkpIHtcbiAgICAgICAgICAgIGNvbnN0IGxhbmd1YWdlID0gdGhpcy5pbmZlckxhbmd1YWdlRnJvbUZpbGVuYW1lKGZpbGVuYW1lKTtcbiAgICAgICAgICAgIGNvbnN0IGNsZWFuQ29udGVudCA9IHRoaXMucmVtb3ZlU2hlYmFuZ0FuZEhlYWRlcnMoY29udGVudCk7XG4gICAgICAgICAgICBza2lsbERhdGEuc2NyaXB0cy5zZXQoZmlsZW5hbWUsIHsgY29udGVudDogY2xlYW5Db250ZW50LCBsYW5ndWFnZSB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFByb2Nlc3MgZ2VuZXJpYyBkaXJlY3Rvcnkgc3RydWN0dXJlIChyZWZlcmVuY2UsIGV4YW1wbGVzLCB0aGVtZXMpXG4gICAgICogUkVGQUNUT1JFRDogRXh0cmFjdGVkIHRvIHJlZHVjZSBjb2duaXRpdmUgY29tcGxleGl0eVxuICAgICAqL1xuICAgIHByaXZhdGUgcHJvY2Vzc1N0cnVjdHVyZURpcmVjdG9yeShcbiAgICAgICAgc291cmNlRGlyOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHwgdW5kZWZpbmVkLFxuICAgICAgICB0YXJnZXRNYXA6IE1hcDxzdHJpbmcsIHN0cmluZz5cbiAgICApOiB2b2lkIHtcbiAgICAgICAgaWYgKCFzb3VyY2VEaXIpIHJldHVybjtcblxuICAgICAgICBmb3IgKGNvbnN0IFtmaWxlbmFtZSwgY29udGVudF0gb2YgT2JqZWN0LmVudHJpZXMoc291cmNlRGlyKSkge1xuICAgICAgICAgICAgdGFyZ2V0TWFwLnNldChmaWxlbmFtZSwgY29udGVudCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQcm9jZXNzIG1ldGFkYXRhIGZyb20gc3RydWN0dXJlXG4gICAgICogUkVGQUNUT1JFRDogRXh0cmFjdGVkIHRvIHJlZHVjZSBjb2duaXRpdmUgY29tcGxleGl0eVxuICAgICAqL1xuICAgIHByaXZhdGUgcHJvY2Vzc1N0cnVjdHVyZU1ldGFkYXRhKHN0cnVjdHVyZTogQW50aHJvcGljU2tpbGxTdHJ1Y3R1cmUsIHNraWxsRGF0YTogQW50aHJvcGljU2tpbGxEaXJlY3RvcnkpOiB2b2lkIHtcbiAgICAgICAgaWYgKCFzdHJ1Y3R1cmVbJ21ldGFkYXRhLyddKSByZXR1cm47XG5cbiAgICAgICAgc2tpbGxEYXRhLm1ldGFkYXRhID0gbmV3IE1hcCgpO1xuICAgICAgICBmb3IgKGNvbnN0IFtmaWxlbmFtZSwgY29udGVudF0gb2YgT2JqZWN0LmVudHJpZXMoc3RydWN0dXJlWydtZXRhZGF0YS8nXSkpIHtcbiAgICAgICAgICAgIHNraWxsRGF0YS5tZXRhZGF0YS5zZXQoZmlsZW5hbWUsIGNvbnRlbnQpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGVucmljaGVkIG1ldGFkYXRhIChwcmVzZXJ2ZWQgb3IgZ2VuZXJhdGVkKVxuICAgICAqIFJFRkFDVE9SRUQ6IEV4dHJhY3RlZCB0byByZWR1Y2UgY29nbml0aXZlIGNvbXBsZXhpdHlcbiAgICAgKi9cbiAgICBwcml2YXRlIGdldEVucmljaGVkTWV0YWRhdGEoXG4gICAgICAgIHNraWxsRGF0YTogQW50aHJvcGljU2tpbGxEaXJlY3RvcnksXG4gICAgICAgIG1ldGFkYXRhOiBBbnRocm9waWNTa2lsbE1ldGFkYXRhLFxuICAgICAgICBvcHRpb25zPzoge1xuICAgICAgICAgICAgcHJlc2VydmVTb3VyY2U/OiBib29sZWFuO1xuICAgICAgICAgICAgY3VzdG9tTWV0YWRhdGE/OiBQYXJ0aWFsPERvbGxob3VzZU1DUFNraWxsTWV0YWRhdGE+O1xuICAgICAgICB9XG4gICAgKTogRG9sbGhvdXNlTUNQU2tpbGxNZXRhZGF0YSB7XG4gICAgICAgIC8vIENoZWNrIGZvciBwcmVzZXJ2ZWQgRG9sbGhvdXNlTUNQIG1ldGFkYXRhXG4gICAgICAgIGlmIChza2lsbERhdGEubWV0YWRhdGE/LmhhcygnZG9sbGhvdXNlLnlhbWwnKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMubG9hZFByZXNlcnZlZE1ldGFkYXRhKHNraWxsRGF0YS5tZXRhZGF0YS5nZXQoJ2RvbGxob3VzZS55YW1sJykhLCBvcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEZhbGwgYmFjayB0byBlbnJpY2htZW50IGlmIG5vIHByZXNlcnZlZCBtZXRhZGF0YVxuICAgICAgICByZXR1cm4gdGhpcy5lbnJpY2hNZXRhZGF0YShtZXRhZGF0YSwgb3B0aW9ucyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTG9hZCBwcmVzZXJ2ZWQgbWV0YWRhdGEgZnJvbSBZQU1MXG4gICAgICogUkVGQUNUT1JFRDogRXh0cmFjdGVkIHRvIHJlZHVjZSBjb2duaXRpdmUgY29tcGxleGl0eVxuICAgICAqL1xuICAgIHByaXZhdGUgbG9hZFByZXNlcnZlZE1ldGFkYXRhKFxuICAgICAgICBwcmVzZXJ2ZWRZQU1MOiBzdHJpbmcsXG4gICAgICAgIG9wdGlvbnM/OiB7XG4gICAgICAgICAgICBjdXN0b21NZXRhZGF0YT86IFBhcnRpYWw8RG9sbGhvdXNlTUNQU2tpbGxNZXRhZGF0YT47XG4gICAgICAgIH1cbiAgICApOiBEb2xsaG91c2VNQ1BTa2lsbE1ldGFkYXRhIHtcbiAgICAgICAgLy8gRklYIChETUNQLVNFQy0wMDUpOiBVc2UgQ09SRV9TQ0hFTUEgdG8gcHJldmVudCBZQU1MIGRlc2VyaWFsaXphdGlvbiBhdHRhY2tzXG4gICAgICAgIGNvbnN0IGVucmljaGVkTWV0YWRhdGEgPSB5YW1sLmxvYWQocHJlc2VydmVkWUFNTCwgeyBzY2hlbWE6IHlhbWwuQ09SRV9TQ0hFTUEgfSkgYXMgRG9sbGhvdXNlTUNQU2tpbGxNZXRhZGF0YTtcblxuICAgICAgICAvLyBBcHBseSBhbnkgY3VzdG9tIG1ldGFkYXRhIG92ZXJyaWRlc1xuICAgICAgICBpZiAob3B0aW9ucz8uY3VzdG9tTWV0YWRhdGEpIHtcbiAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oZW5yaWNoZWRNZXRhZGF0YSwgb3B0aW9ucy5jdXN0b21NZXRhZGF0YSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZW5yaWNoZWRNZXRhZGF0YTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWFkIEFudGhyb3BpYyBza2lsbCBkaXJlY3Rvcnkgc3RydWN0dXJlIGZyb20gZGlza1xuICAgICAqIFJFRkFDVE9SRUQ6IFNpbXBsaWZpZWQgYnkgZXh0cmFjdGluZyBkaXJlY3RvcnkgcmVhZGluZyBsb2dpY1xuICAgICAqL1xuICAgIGFzeW5jIHJlYWRBbnRocm9waWNTdHJ1Y3R1cmUoc2tpbGxEaXJQYXRoOiBzdHJpbmcpOiBQcm9taXNlPEFudGhyb3BpY1NraWxsRGlyZWN0b3J5PiB7XG4gICAgICAgIHRoaXMudmFsaWRhdGVTa2lsbERpcmVjdG9yeShza2lsbERpclBhdGgpO1xuXG4gICAgICAgIC8vIFJlYWQgYW5kIHBhcnNlIFNLSUxMLm1kXG4gICAgICAgIGNvbnN0IHsgbWV0YWRhdGEsIGNvbnRlbnQgfSA9IHRoaXMucmVhZFNraWxsTUQoc2tpbGxEaXJQYXRoKTtcblxuICAgICAgICAvLyBJbml0aWFsaXplIHNraWxsIGRhdGEgc3RydWN0dXJlXG4gICAgICAgIGNvbnN0IHNraWxsRGF0YTogQW50aHJvcGljU2tpbGxEaXJlY3RvcnkgPSB7XG4gICAgICAgICAgICBza2lsbE1EOiB7IG1ldGFkYXRhLCBjb250ZW50IH0sXG4gICAgICAgICAgICBzY3JpcHRzOiBuZXcgTWFwKCksXG4gICAgICAgICAgICByZWZlcmVuY2U6IG5ldyBNYXAoKSxcbiAgICAgICAgICAgIGV4YW1wbGVzOiBuZXcgTWFwKCksXG4gICAgICAgICAgICB0aGVtZXM6IG5ldyBNYXAoKVxuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFJlYWQgYWxsIGRpcmVjdG9yeSBjb21wb25lbnRzXG4gICAgICAgIHRoaXMucmVhZFNjcmlwdHNEaXJlY3Rvcnkoc2tpbGxEaXJQYXRoLCBza2lsbERhdGEpO1xuICAgICAgICB0aGlzLnJlYWRGaWxlc0RpcmVjdG9yeShza2lsbERpclBhdGgsICdyZWZlcmVuY2UnLCBza2lsbERhdGEucmVmZXJlbmNlKTtcbiAgICAgICAgdGhpcy5yZWFkRmlsZXNEaXJlY3Rvcnkoc2tpbGxEaXJQYXRoLCAnZXhhbXBsZXMnLCBza2lsbERhdGEuZXhhbXBsZXMpO1xuICAgICAgICB0aGlzLnJlYWRGaWxlc0RpcmVjdG9yeShza2lsbERpclBhdGgsICd0aGVtZXMnLCBza2lsbERhdGEudGhlbWVzKTtcbiAgICAgICAgdGhpcy5yZWFkTWV0YWRhdGFEaXJlY3Rvcnkoc2tpbGxEaXJQYXRoLCBza2lsbERhdGEpO1xuICAgICAgICB0aGlzLnJlYWRMaWNlbnNlRmlsZShza2lsbERpclBhdGgsIHNraWxsRGF0YSk7XG5cbiAgICAgICAgcmV0dXJuIHNraWxsRGF0YTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBWYWxpZGF0ZSBza2lsbCBkaXJlY3RvcnkgZXhpc3RzIGFuZCBoYXMgU0tJTEwubWRcbiAgICAgKiBSRUZBQ1RPUkVEOiBFeHRyYWN0ZWQgdG8gcmVkdWNlIGNvZ25pdGl2ZSBjb21wbGV4aXR5XG4gICAgICovXG4gICAgcHJpdmF0ZSB2YWxpZGF0ZVNraWxsRGlyZWN0b3J5KHNraWxsRGlyUGF0aDogc3RyaW5nKTogdm9pZCB7XG4gICAgICAgIGlmICghZnMuZXhpc3RzU3luYyhza2lsbERpclBhdGgpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFNraWxsIGRpcmVjdG9yeSBub3QgZm91bmQ6ICR7c2tpbGxEaXJQYXRofWApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgc2tpbGxNRFBhdGggPSBwYXRoLmpvaW4oc2tpbGxEaXJQYXRoLCAnU0tJTEwubWQnKTtcbiAgICAgICAgaWYgKCFmcy5leGlzdHNTeW5jKHNraWxsTURQYXRoKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTS0lMTC5tZCBub3QgZm91bmQgaW4gJHtza2lsbERpclBhdGh9YCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWFkIGFuZCBwYXJzZSBTS0lMTC5tZCBmaWxlXG4gICAgICogUkVGQUNUT1JFRDogRXh0cmFjdGVkIHRvIHJlZHVjZSBjb2duaXRpdmUgY29tcGxleGl0eVxuICAgICAqL1xuICAgIHByaXZhdGUgcmVhZFNraWxsTUQoc2tpbGxEaXJQYXRoOiBzdHJpbmcpOiB7IG1ldGFkYXRhOiBBbnRocm9waWNTa2lsbE1ldGFkYXRhOyBjb250ZW50OiBzdHJpbmcgfSB7XG4gICAgICAgIGNvbnN0IHNraWxsTURQYXRoID0gcGF0aC5qb2luKHNraWxsRGlyUGF0aCwgJ1NLSUxMLm1kJyk7XG4gICAgICAgIGNvbnN0IHNraWxsTURDb250ZW50ID0gZnMucmVhZEZpbGVTeW5jKHNraWxsTURQYXRoLCAndXRmLTgnKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucGFyc2VTa2lsbE1EKHNraWxsTURDb250ZW50KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWFkIHNjcmlwdHMgZGlyZWN0b3J5IGFuZCBwcm9jZXNzIHNjcmlwdCBmaWxlc1xuICAgICAqIFJFRkFDVE9SRUQ6IEV4dHJhY3RlZCB0byByZWR1Y2UgY29nbml0aXZlIGNvbXBsZXhpdHlcbiAgICAgKi9cbiAgICBwcml2YXRlIHJlYWRTY3JpcHRzRGlyZWN0b3J5KHNraWxsRGlyUGF0aDogc3RyaW5nLCBza2lsbERhdGE6IEFudGhyb3BpY1NraWxsRGlyZWN0b3J5KTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHNjcmlwdHNEaXIgPSBwYXRoLmpvaW4oc2tpbGxEaXJQYXRoLCAnc2NyaXB0cycpO1xuICAgICAgICBpZiAoIWZzLmV4aXN0c1N5bmMoc2NyaXB0c0RpcikpIHJldHVybjtcblxuICAgICAgICBjb25zdCBzY3JpcHRGaWxlcyA9IGZzLnJlYWRkaXJTeW5jKHNjcmlwdHNEaXIpO1xuICAgICAgICBmb3IgKGNvbnN0IGZpbGVuYW1lIG9mIHNjcmlwdEZpbGVzKSB7XG4gICAgICAgICAgICBjb25zdCBmaWxlUGF0aCA9IHBhdGguam9pbihzY3JpcHRzRGlyLCBmaWxlbmFtZSk7XG4gICAgICAgICAgICBjb25zdCBjb250ZW50ID0gZnMucmVhZEZpbGVTeW5jKGZpbGVQYXRoLCAndXRmLTgnKTtcbiAgICAgICAgICAgIGNvbnN0IGxhbmd1YWdlID0gdGhpcy5pbmZlckxhbmd1YWdlRnJvbUZpbGVuYW1lKGZpbGVuYW1lKTtcbiAgICAgICAgICAgIGNvbnN0IGNsZWFuQ29udGVudCA9IHRoaXMucmVtb3ZlU2hlYmFuZ0FuZEhlYWRlcnMoY29udGVudCk7XG4gICAgICAgICAgICBza2lsbERhdGEuc2NyaXB0cy5zZXQoZmlsZW5hbWUsIHsgY29udGVudDogY2xlYW5Db250ZW50LCBsYW5ndWFnZSB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlYWQgZ2VuZXJpYyBmaWxlcyBkaXJlY3RvcnkgKHJlZmVyZW5jZSwgZXhhbXBsZXMsIHRoZW1lcylcbiAgICAgKiBSRUZBQ1RPUkVEOiBFeHRyYWN0ZWQgdG8gcmVkdWNlIGNvZ25pdGl2ZSBjb21wbGV4aXR5IGFuZCByZXVzZSBjb2RlXG4gICAgICovXG4gICAgcHJpdmF0ZSByZWFkRmlsZXNEaXJlY3RvcnkoXG4gICAgICAgIHNraWxsRGlyUGF0aDogc3RyaW5nLFxuICAgICAgICBkaXJOYW1lOiBzdHJpbmcsXG4gICAgICAgIHRhcmdldE1hcDogTWFwPHN0cmluZywgc3RyaW5nPlxuICAgICk6IHZvaWQge1xuICAgICAgICBjb25zdCBkaXJQYXRoID0gcGF0aC5qb2luKHNraWxsRGlyUGF0aCwgZGlyTmFtZSk7XG4gICA