@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.
308 lines • 43.2 kB
JavaScript
/**
* DollhouseToAnthropicConverter - Converts single-file DollhouseMCP skills to multi-file Anthropic Skills
*
* Based on the exact algorithm documented in:
* business/documents/legal/evidence/anthropic-skills-decomposition-analysis.md (lines 108-163)
*
* Implements the mechanical transformation:
* DollhouseMCP Skill (single .md file) → Anthropic Skill (directory with separated components)
*
* SECURITY MODEL:
* - This is a FORMAT TRANSFORMER, not a security boundary
* - Preserves content fidelity - no modification, sanitization, or validation
* - YAML parsing uses CORE_SCHEMA to prevent deserialization attacks only
* - Security validation happens at SkillManager.load() time, not conversion time
* - Input skills should already be validated (they're from DollhouseMCP system)
*/
import * as fs from 'node:fs';
import * as yaml from 'js-yaml';
import { SchemaMapper } from './SchemaMapper.js';
import { ContentExtractor } from './ContentExtractor.js';
import { resolvePathWithinBase } from '../utils/pathSecurity.js';
export class DollhouseToAnthropicConverter {
schemaMapper;
contentExtractor;
constructor() {
this.schemaMapper = new SchemaMapper();
this.contentExtractor = new ContentExtractor();
}
/**
* Convert a DollhouseMCP skill (.md file) to Anthropic Skill format (directory structure)
*
* EXACT ALGORITHM from evidence/anthropic-skills-decomposition-analysis.md:
* 1. Extract YAML frontmatter
* 2. Simplify YAML (keep only name + description)
* 3. Extract main instructions
* 4. Extract embedded code blocks → scripts/
* 5. Extract reference sections → reference/
* 6. Extract templates → themes/ or examples/
* 7. Create SKILL.md with references
* 8. Return directory structure
*/
async convertSkill(skillContent, options) {
// Step 1: Extract YAML frontmatter
// NOTE: No Unicode normalization - preserves content fidelity for mechanical transformation
// Security validation happens when loading converted skills via SkillManager.load()
const { metadata, bodyContent } = this.extractYAMLFrontmatter(skillContent);
// Step 2: Simplify YAML (keep only name + description, optionally license)
const minimalYAML = this.schemaMapper.dollhouseToAnthropic(metadata);
// Step 3-6: Extract all components
const sections = this.contentExtractor.extractSections(bodyContent);
// Organize extracted sections by type
const scripts = {};
const reference = {};
const themes = {};
const examples = {};
let mainInstructions = '';
const sectionReferences = [];
// Step 4: Extract code blocks → scripts/
const codeBlocks = sections.filter(s => s.type === 'code');
for (const block of codeBlocks) {
if (block.filename) {
const filename = block.filename;
scripts[filename] = this.formatScriptFile(block.content, block.language || '');
sectionReferences.push(`See \`scripts/${filename}\` for ${block.title}`);
}
}
// Step 5: Extract documentation sections → reference/
const docSections = this.extractDocumentationSections(bodyContent);
for (const [title, content] of Object.entries(docSections)) {
const filename = this.slugify(title) + '.md';
reference[filename] = content;
sectionReferences.push(`See \`reference/${filename}\` for ${title}`);
}
// Step 6: Extract examples
const exampleSection = this.contentExtractor.extractDocumentationSection(bodyContent, 'example');
if (exampleSection) {
examples['installation-example.md'] = exampleSection;
sectionReferences.push(`See \`examples/installation-example.md\` for complete walkthrough`);
}
// Step 3: Extract main instructions (preserve structural content, remove extracted sections)
mainInstructions = this.extractMainInstructions(bodyContent, sections);
// Step 7: Create SKILL.md with references to separated files
const skillMD = this.createSkillMD(minimalYAML, mainInstructions, sectionReferences);
// Step 8: Return directory structure
const result = {
'SKILL.md': skillMD
};
if (Object.keys(scripts).length > 0) {
result['scripts/'] = scripts;
}
if (Object.keys(reference).length > 0) {
result['reference/'] = reference;
}
if (Object.keys(themes).length > 0) {
result['themes/'] = themes;
}
if (Object.keys(examples).length > 0) {
result['examples/'] = examples;
}
if (options?.includelicense && metadata.license) {
result['LICENSE.txt'] = this.createLicenseFile(metadata.license, metadata.author);
}
// Always preserve full DollhouseMCP metadata for perfect roundtrip
result['metadata/'] = {
'dollhouse.yaml': yaml.dump(metadata)
};
return result;
}
/**
* Write the Anthropic skill structure to disk
* REFACTORED: Simplified by extracting directory writing logic
*/
async writeToDirectory(structure, outputDir) {
// Create output directory
this.ensureDirectoryExists(outputDir);
// Write SKILL.md
fs.writeFileSync(resolvePathWithinBase(outputDir, 'SKILL.md'), structure['SKILL.md']);
// Write all component directories
this.writeScriptsDirectory(structure, outputDir);
this.writeFilesDirectory(structure['reference/'], outputDir, 'reference');
this.writeFilesDirectory(structure['themes/'], outputDir, 'themes');
this.writeFilesDirectory(structure['examples/'], outputDir, 'examples');
this.writeFilesDirectory(structure['metadata/'], outputDir, 'metadata');
// Write license file
if (structure['LICENSE.txt']) {
fs.writeFileSync(resolvePathWithinBase(outputDir, 'LICENSE.txt'), structure['LICENSE.txt']);
}
}
/**
* Ensure directory exists, creating it if necessary
* REFACTORED: Extracted to reduce cognitive complexity
*/
ensureDirectoryExists(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
/**
* Write scripts directory with security considerations
* REFACTORED: Extracted to reduce cognitive complexity
*/
writeScriptsDirectory(structure, outputDir) {
if (!structure['scripts/'])
return;
const scriptsDir = resolvePathWithinBase(outputDir, 'scripts');
fs.mkdirSync(scriptsDir, { recursive: true });
for (const [filename, content] of Object.entries(structure['scripts/'])) {
fs.writeFileSync(resolvePathWithinBase(scriptsDir, filename), content);
// SECURITY (SonarCloud S2612): Do NOT auto-chmod scripts executable
// - Scripts from DollhouseMCP are markdown code blocks, not executable files
// - Format transformer shouldn't make security decisions (chmod = security decision)
// - Principle of least privilege: user can chmod if needed
// - Prevents automatic execution of potentially malicious converted scripts
}
}
/**
* Write generic files directory (reference, themes, examples, metadata)
* REFACTORED: Extracted to reduce cognitive complexity and reuse code
*/
writeFilesDirectory(files, outputDir, dirName) {
if (!files)
return;
const targetDir = resolvePathWithinBase(outputDir, dirName);
fs.mkdirSync(targetDir, { recursive: true });
for (const [filename, content] of Object.entries(files)) {
fs.writeFileSync(resolvePathWithinBase(targetDir, filename), content);
}
}
/**
* Extract YAML frontmatter from markdown
*/
extractYAMLFrontmatter(content) {
const yamlMatch = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/.exec(content);
if (!yamlMatch) {
throw new Error('No YAML frontmatter found');
}
// FIX (DMCP-SEC-005): Use CORE_SCHEMA to prevent YAML deserialization attacks
const metadata = yaml.load(yamlMatch[1], { schema: yaml.CORE_SCHEMA });
const bodyContent = yamlMatch[2];
return { metadata, bodyContent };
}
/**
* Create SKILL.md content with simplified metadata and references
*/
createSkillMD(metadata, mainInstructions, references) {
const yamlString = yaml.dump(metadata);
let skillMD = `---\n${yamlString}---\n\n${mainInstructions}`;
// Add references section if there are extracted components
if (references.length > 0) {
skillMD += '\n\n## Additional Resources\n\n';
skillMD += references.join('\n');
}
return skillMD;
}
/**
* Extract main instructions (content before code blocks and special sections)
*/
extractMainInstructions(content, extractedSections) {
// For now, return content up to first code block or extracted section
// This is simplified - a full implementation would reconstruct with references
const lines = content.split('\n');
const mainLines = [];
let inExtractedSection = false;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// Check if we're entering an extracted section
const isExtracted = extractedSections.some(s => i >= s.startLine && i <= s.endLine);
if (isExtracted) {
inExtractedSection = true;
continue;
}
if (!inExtractedSection || line.startsWith('#')) {
mainLines.push(line);
inExtractedSection = false;
}
}
return mainLines.join('\n').trim();
}
/**
* Extract documentation sections (Input Formats, Error Handling, etc.)
*/
extractDocumentationSections(content) {
const sections = {};
// Common documentation section patterns
const sectionPatterns = [
'Input Formats',
'Error Handling',
'Supported Clients',
'Command Building',
'Configuration',
'Troubleshooting'
];
for (const pattern of sectionPatterns) {
const section = this.contentExtractor.extractDocumentationSection(content, pattern);
if (section) {
sections[pattern] = section;
}
}
return sections;
}
/**
* Format script file with proper shebang and headers
*/
formatScriptFile(content, language) {
const shebang = this.getShebang(language);
const header = this.getScriptHeader(content);
return `${shebang}\n${header}\n${content}`;
}
/**
* Get appropriate shebang for script language
*/
getShebang(language) {
const shebangs = {
bash: '#!/bin/bash',
sh: '#!/bin/sh',
python: '#!/usr/bin/env python3',
py: '#!/usr/bin/env python3',
node: '#!/usr/bin/env node',
javascript: '#!/usr/bin/env node',
js: '#!/usr/bin/env node'
};
return shebangs[language.toLowerCase()] || '#!/bin/bash';
}
/**
* Get script header comment
*/
getScriptHeader(content) {
// Extract first comment if present
const firstLine = content.split('\n')[0];
if (firstLine.startsWith('#') || firstLine.startsWith('//')) {
return firstLine;
}
return '# Extracted script';
}
/**
* Get file extension for language
*/
getExtension(language) {
const extensions = {
bash: 'sh',
sh: 'sh',
python: 'py',
py: 'py',
javascript: 'js',
js: 'js',
typescript: 'ts',
ts: 'ts'
};
return extensions[language.toLowerCase()] || 'txt';
}
/**
* Create slugified filename from title
*/
slugify(title) {
return title
.toLowerCase()
.replaceAll(/[^a-z0-9\s-]/g, '')
.replaceAll(/\s+/g, '-');
}
/**
* Create LICENSE.txt file
*/
createLicenseFile(license, author) {
const authorSuffix = author ? `\n\nAuthor: ${author}` : '';
return `${license}${authorSuffix}`;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRG9sbGhvdXNlVG9BbnRocm9waWNDb252ZXJ0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29udmVydGVycy9Eb2xsaG91c2VUb0FudGhyb3BpY0NvbnZlcnRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFFSCxPQUFPLEtBQUssRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUM5QixPQUFPLEtBQUssSUFBSSxNQUFNLFNBQVMsQ0FBQztBQUNoQyxPQUFPLEVBQUUsWUFBWSxFQUErRCxNQUFNLG1CQUFtQixDQUFDO0FBQzlHLE9BQU8sRUFBRSxnQkFBZ0IsRUFBeUIsTUFBTSx1QkFBdUIsQ0FBQztBQUNoRixPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQVlqRSxNQUFNLE9BQU8sNkJBQTZCO0lBQ3JCLFlBQVksQ0FBZTtJQUMzQixnQkFBZ0IsQ0FBbUI7SUFFcEQ7UUFDSSxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFDdkMsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksZ0JBQWdCLEVBQUUsQ0FBQztJQUNuRCxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7OztPQVlHO0lBQ0gsS0FBSyxDQUFDLFlBQVksQ0FBQyxZQUFvQixFQUFFLE9BR3hDO1FBQ0csbUNBQW1DO1FBQ25DLDRGQUE0RjtRQUM1RixvRkFBb0Y7UUFDcEYsTUFBTSxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsR0FBRyxJQUFJLENBQUMsc0JBQXNCLENBQUMsWUFBWSxDQUFDLENBQUM7UUFFNUUsMkVBQTJFO1FBQzNFLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsb0JBQW9CLENBQUMsUUFBUSxDQUFDLENBQUM7UUFFckUsbUNBQW1DO1FBQ25DLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxlQUFlLENBQUMsV0FBVyxDQUFDLENB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Q0FBQztJQUNqQyxDQUFDO0lBRUQ7O09BRUc7SUFDSyxpQkFBaUIsQ0FBQyxPQUFlLEVBQUUsTUFBZTtRQUN0RCxNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLGVBQWUsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUMzRCxPQUFPLEdBQUcsT0FBTyxHQUFHLFlBQVksRUFBRSxDQUFDO0lBQ3ZDLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRG9sbGhvdXNlVG9BbnRocm9waWNDb252ZXJ0ZXIgLSBDb252ZXJ0cyBzaW5nbGUtZmlsZSBEb2xsaG91c2VNQ1Agc2tpbGxzIHRvIG11bHRpLWZpbGUgQW50aHJvcGljIFNraWxsc1xuICpcbiAqIEJhc2VkIG9uIHRoZSBleGFjdCBhbGdvcml0aG0gZG9jdW1lbnRlZCBpbjpcbiAqIGJ1c2luZXNzL2RvY3VtZW50cy9sZWdhbC9ldmlkZW5jZS9hbnRocm9waWMtc2tpbGxzLWRlY29tcG9zaXRpb24tYW5hbHlzaXMubWQgKGxpbmVzIDEwOC0xNjMpXG4gKlxuICogSW1wbGVtZW50cyB0aGUgbWVjaGFuaWNhbCB0cmFuc2Zvcm1hdGlvbjpcbiAqIERvbGxob3VzZU1DUCBTa2lsbCAoc2luZ2xlIC5tZCBmaWxlKSDihpIgQW50aHJvcGljIFNraWxsIChkaXJlY3Rvcnkgd2l0aCBzZXBhcmF0ZWQgY29tcG9uZW50cylcbiAqXG4gKiBTRUNVUklUWSBNT0RFTDpcbiAqIC0gVGhpcyBpcyBhIEZPUk1BVCBUUkFOU0ZPUk1FUiwgbm90IGEgc2VjdXJpdHkgYm91bmRhcnlcbiAqIC0gUHJlc2VydmVzIGNvbnRlbnQgZmlkZWxpdHkgLSBubyBtb2RpZmljYXRpb24sIHNhbml0aXphdGlvbiwgb3IgdmFsaWRhdGlvblxuICogLSBZQU1MIHBhcnNpbmcgdXNlcyBDT1JFX1NDSEVNQSB0byBwcmV2ZW50IGRlc2VyaWFsaXphdGlvbiBhdHRhY2tzIG9ubHlcbiAqIC0gU2VjdXJpdHkgdmFsaWRhdGlvbiBoYXBwZW5zIGF0IFNraWxsTWFuYWdlci5sb2FkKCkgdGltZSwgbm90IGNvbnZlcnNpb24gdGltZVxuICogLSBJbnB1dCBza2lsbHMgc2hvdWxkIGFscmVhZHkgYmUgdmFsaWRhdGVkICh0aGV5J3JlIGZyb20gRG9sbGhvdXNlTUNQIHN5c3RlbSlcbiAqL1xuXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdub2RlOmZzJztcbmltcG9ydCAqIGFzIHlhbWwgZnJvbSAnanMteWFtbCc7XG5pbXBvcnQgeyBTY2hlbWFNYXBwZXIsIHR5cGUgRG9sbGhvdXNlTUNQU2tpbGxNZXRhZGF0YSwgdHlwZSBBbnRocm9waWNTa2lsbE1ldGFkYXRhIH0gZnJvbSAnLi9TY2hlbWFNYXBwZXIuanMnO1xuaW1wb3J0IHsgQ29udGVudEV4dHJhY3RvciwgdHlwZSBFeHRyYWN0ZWRTZWN0aW9uIH0gZnJvbSAnLi9Db250ZW50RXh0cmFjdG9yLmpzJztcbmltcG9ydCB7IHJlc29sdmVQYXRoV2l0aGluQmFzZSB9IGZyb20gJy4uL3V0aWxzL3BhdGhTZWN1cml0eS5qcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQW50aHJvcGljU2tpbGxTdHJ1Y3R1cmUge1xuICAgICdTS0lMTC5tZCc6IHN0cmluZztcbiAgICAnc2NyaXB0cy8nPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbiAgICAncmVmZXJlbmNlLyc/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICAgICd0aGVtZXMvJz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gICAgJ2V4YW1wbGVzLyc/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICAgICdtZXRhZGF0YS8nPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbiAgICAnTElDRU5TRS50eHQnPzogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgRG9sbGhvdXNlVG9BbnRocm9waWNDb252ZXJ0ZXIge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgc2NoZW1hTWFwcGVyOiBTY2hlbWFNYXBwZXI7XG4gICAgcHJpdmF0ZSByZWFkb25seSBjb250ZW50RXh0cmFjdG9yOiBDb250ZW50RXh0cmFjdG9yO1xuXG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHRoaXMuc2NoZW1hTWFwcGVyID0gbmV3IFNjaGVtYU1hcHBlcigpO1xuICAgICAgICB0aGlzLmNvbnRlbnRFeHRyYWN0b3IgPSBuZXcgQ29udGVudEV4dHJhY3RvcigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENvbnZlcnQgYSBEb2xsaG91c2VNQ1Agc2tpbGwgKC5tZCBmaWxlKSB0byBBbnRocm9waWMgU2tpbGwgZm9ybWF0IChkaXJlY3Rvcnkgc3RydWN0dXJlKVxuICAgICAqXG4gICAgICogRVhBQ1QgQUxHT1JJVEhNIGZyb20gZXZpZGVuY2UvYW50aHJvcGljLXNraWxscy1kZWNvbXBvc2l0aW9uLWFuYWx5c2lzLm1kOlxuICAgICAqIDEuIEV4dHJhY3QgWUFNTCBmcm9udG1hdHRlclxuICAgICAqIDIuIFNpbXBsaWZ5IFlBTUwgKGtlZXAgb25seSBuYW1lICsgZGVzY3JpcHRpb24pXG4gICAgICogMy4gRXh0cmFjdCBtYWluIGluc3RydWN0aW9uc1xuICAgICAqIDQuIEV4dHJhY3QgZW1iZWRkZWQgY29kZSBibG9ja3Mg4oaSIHNjcmlwdHMvXG4gICAgICogNS4gRXh0cmFjdCByZWZlcmVuY2Ugc2VjdGlvbnMg4oaSIHJlZmVyZW5jZS9cbiAgICAgKiA2LiBFeHRyYWN0IHRlbXBsYXRlcyDihpIgdGhlbWVzLyBvciBleGFtcGxlcy9cbiAgICAgKiA3LiBDcmVhdGUgU0tJTEwubWQgd2l0aCByZWZlcmVuY2VzXG4gICAgICogOC4gUmV0dXJuIGRpcmVjdG9yeSBzdHJ1Y3R1cmVcbiAgICAgKi9cbiAgICBhc3luYyBjb252ZXJ0U2tpbGwoc2tpbGxDb250ZW50OiBzdHJpbmcsIG9wdGlvbnM/OiB7XG4gICAgICAgIGluY2x1ZGVsaWNlbnNlPzogYm9vbGVhbjtcbiAgICAgICAgcHJlc2VydmVDb21tZW50cz86IGJvb2xlYW47XG4gICAgfSk6IFByb21pc2U8QW50aHJvcGljU2tpbGxTdHJ1Y3R1cmU+IHtcbiAgICAgICAgLy8gU3RlcCAxOiBFeHRyYWN0IFlBTUwgZnJvbnRtYXR0ZXJcbiAgICAgICAgLy8gTk9URTogTm8gVW5pY29kZSBub3JtYWxpemF0aW9uIC0gcHJlc2VydmVzIGNvbnRlbnQgZmlkZWxpdHkgZm9yIG1lY2hhbmljYWwgdHJhbnNmb3JtYXRpb25cbiAgICAgICAgLy8gU2VjdXJpdHkgdmFsaWRhdGlvbiBoYXBwZW5zIHdoZW4gbG9hZGluZyBjb252ZXJ0ZWQgc2tpbGxzIHZpYSBTa2lsbE1hbmFnZXIubG9hZCgpXG4gICAgICAgIGNvbnN0IHsgbWV0YWRhdGEsIGJvZHlDb250ZW50IH0gPSB0aGlzLmV4dHJhY3RZQU1MRnJvbnRtYXR0ZXIoc2tpbGxDb250ZW50KTtcblxuICAgICAgICAvLyBTdGVwIDI6IFNpbXBsaWZ5IFlBTUwgKGtlZXAgb25seSBuYW1lICsgZGVzY3JpcHRpb24sIG9wdGlvbmFsbHkgbGljZW5zZSlcbiAgICAgICAgY29uc3QgbWluaW1hbFlBTUwgPSB0aGlzLnNjaGVtYU1hcHBlci5kb2xsaG91c2VUb0FudGhyb3BpYyhtZXRhZGF0YSk7XG5cbiAgICAgICAgLy8gU3RlcCAzLTY6IEV4dHJhY3QgYWxsIGNvbXBvbmVudHNcbiAgICAgICAgY29uc3Qgc2VjdGlvbnMgPSB0aGlzLmNvbnRlbnRFeHRyYWN0b3IuZXh0cmFjdFNlY3Rpb25zKGJvZHlDb250ZW50KTtcblxuICAgICAgICAvLyBPcmdhbml6ZSBleHRyYWN0ZWQgc2VjdGlvbnMgYnkgdHlwZVxuICAgICAgICBjb25zdCBzY3JpcHRzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG4gICAgICAgIGNvbnN0IHJlZmVyZW5jZTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICAgICAgICBjb25zdCB0aGVtZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgICAgICAgY29uc3QgZXhhbXBsZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcblxuICAgICAgICBsZXQgbWFpbkluc3RydWN0aW9ucyA9ICcnO1xuICAgICAgICBjb25zdCBzZWN0aW9uUmVmZXJlbmNlczogc3RyaW5nW10gPSBbXTtcblxuICAgICAgICAvLyBTdGVwIDQ6IEV4dHJhY3QgY29kZSBibG9ja3Mg4oaSIHNjcmlwdHMvXG4gICAgICAgIGNvbnN0IGNvZGVCbG9ja3MgPSBzZWN0aW9ucy5maWx0ZXIocyA9PiBzLnR5cGUgPT09ICdjb2RlJyk7XG4gICAgICAgIGZvciAoY29uc3QgYmxvY2sgb2YgY29kZUJsb2Nrcykge1xuICAgICAgICAgICAgaWYgKGJsb2NrLmZpbGVuYW1lKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZmlsZW5hbWUgPSBibG9jay5maWxlbmFtZTtcbiAgICAgICAgICAgICAgICBzY3JpcHRzW2ZpbGVuYW1lXSA9IHRoaXMuZm9ybWF0U2NyaXB0RmlsZShibG9jay5jb250ZW50LCBibG9jay5sYW5ndWFnZSB8fCAnJyk7XG4gICAgICAgICAgICAgICAgc2VjdGlvblJlZmVyZW5jZXMucHVzaChgU2VlIFxcYHNjcmlwdHMvJHtmaWxlbmFtZX1cXGAgZm9yICR7YmxvY2sudGl0bGV9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTdGVwIDU6IEV4dHJhY3QgZG9jdW1lbnRhdGlvbiBzZWN0aW9ucyDihpIgcmVmZXJlbmNlL1xuICAgICAgICBjb25zdCBkb2NTZWN0aW9ucyA9IHRoaXMuZXh0cmFjdERvY3VtZW50YXRpb25TZWN0aW9ucyhib2R5Q29udGVudCk7XG4gICAgICAgIGZvciAoY29uc3QgW3RpdGxlLCBjb250ZW50XSBvZiBPYmplY3QuZW50cmllcyhkb2NTZWN0aW9ucykpIHtcbiAgICAgICAgICAgIGNvbnN0IGZpbGVuYW1lID0gdGhpcy5zbHVnaWZ5KHRpdGxlKSArICcubWQnO1xuICAgICAgICAgICAgcmVmZXJlbmNlW2ZpbGVuYW1lXSA9IGNvbnRlbnQ7XG4gICAgICAgICAgICBzZWN0aW9uUmVmZXJlbmNlcy5wdXNoKGBTZWUgXFxgcmVmZXJlbmNlLyR7ZmlsZW5hbWV9XFxgIGZvciAke3RpdGxlfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU3RlcCA2OiBFeHRyYWN0IGV4YW1wbGVzXG4gICAgICAgIGNvbnN0IGV4YW1wbGVTZWN0aW9uID0gdGhpcy5jb250ZW50RXh0cmFjdG9yLmV4dHJhY3REb2N1bWVudGF0aW9uU2VjdGlvbihib2R5Q29udGVudCwgJ2V4YW1wbGUnKTtcbiAgICAgICAgaWYgKGV4YW1wbGVTZWN0aW9uKSB7XG4gICAgICAgICAgICBleGFtcGxlc1snaW5zdGFsbGF0aW9uLWV4YW1wbGUubWQnXSA9IGV4YW1wbGVTZWN0aW9uO1xuICAgICAgICAgICAgc2VjdGlvblJlZmVyZW5jZXMucHVzaChgU2VlIFxcYGV4YW1wbGVzL2luc3RhbGxhdGlvbi1leGFtcGxlLm1kXFxgIGZvciBjb21wbGV0ZSB3YWxrdGhyb3VnaGApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU3RlcCAzOiBFeHRyYWN0IG1haW4gaW5zdHJ1Y3Rpb25zIChwcmVzZXJ2ZSBzdHJ1Y3R1cmFsIGNvbnRlbnQsIHJlbW92ZSBleHRyYWN0ZWQgc2VjdGlvbnMpXG4gICAgICAgIG1haW5JbnN0cnVjdGlvbnMgPSB0aGlzLmV4dHJhY3RNYWluSW5zdHJ1Y3Rpb25zKGJvZHlDb250ZW50LCBzZWN0aW9ucyk7XG5cbiAgICAgICAgLy8gU3RlcCA3OiBDcmVhdGUgU0tJTEwubWQgd2l0aCByZWZlcmVuY2VzIHRvIHNlcGFyYXRlZCBmaWxlc1xuICAgICAgICBjb25zdCBza2lsbE1EID0gdGhpcy5jcmVhdGVTa2lsbE1EKG1pbmltYWxZQU1MLCBtYWluSW5zdHJ1Y3Rpb25zLCBzZWN0aW9uUmVmZXJlbmNlcyk7XG5cbiAgICAgICAgLy8gU3RlcCA4OiBSZXR1cm4gZGlyZWN0b3J5IHN0cnVjdHVyZVxuICAgICAgICBjb25zdCByZXN1bHQ6IEFudGhyb3BpY1NraWxsU3RydWN0dXJlID0ge1xuICAgICAgICAgICAgJ1NLSUxMLm1kJzogc2tpbGxNRFxuICAgICAgICB9O1xuXG4gICAgICAgIGlmIChPYmplY3Qua2V5cyhzY3JpcHRzKS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICByZXN1bHRbJ3NjcmlwdHMvJ10gPSBzY3JpcHRzO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKE9iamVjdC5rZXlzKHJlZmVyZW5jZSkubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgcmVzdWx0WydyZWZlcmVuY2UvJ10gPSByZWZlcmVuY2U7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoT2JqZWN0LmtleXModGhlbWVzKS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICByZXN1bHRbJ3RoZW1lcy8nXSA9IHRoZW1lcztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChPYmplY3Qua2V5cyhleGFtcGxlcykubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgcmVzdWx0WydleGFtcGxlcy8nXSA9IGV4YW1wbGVzO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG9wdGlvbnM/LmluY2x1ZGVsaWNlbnNlICYmIG1ldGFkYXRhLmxpY2Vuc2UpIHtcbiAgICAgICAgICAgIHJlc3VsdFsnTElDRU5TRS50eHQnXSA9IHRoaXMuY3JlYXRlTGljZW5zZUZpbGUobWV0YWRhdGEubGljZW5zZSwgbWV0YWRhdGEuYXV0aG9yKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEFsd2F5cyBwcmVzZXJ2ZSBmdWxsIERvbGxob3VzZU1DUCBtZXRhZGF0YSBmb3IgcGVyZmVjdCByb3VuZHRyaXBcbiAgICAgICAgcmVzdWx0WydtZXRhZGF0YS8nXSA9IHtcbiAgICAgICAgICAgICdkb2xsaG91c2UueWFtbCc6IHlhbWwuZHVtcChtZXRhZGF0YSlcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFdyaXRlIHRoZSBBbnRocm9waWMgc2tpbGwgc3RydWN0dXJlIHRvIGRpc2tcbiAgICAgKiBSRUZBQ1RPUkVEOiBTaW1wbGlmaWVkIGJ5IGV4dHJhY3RpbmcgZGlyZWN0b3J5IHdyaXRpbmcgbG9naWNcbiAgICAgKi9cbiAgICBhc3luYyB3cml0ZVRvRGlyZWN0b3J5KHN0cnVjdHVyZTogQW50aHJvcGljU2tpbGxTdHJ1Y3R1cmUsIG91dHB1dERpcjogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIC8vIENyZWF0ZSBvdXRwdXQgZGlyZWN0b3J5XG4gICAgICAgIHRoaXMuZW5zdXJlRGlyZWN0b3J5RXhpc3RzKG91dHB1dERpcik7XG5cbiAgICAgICAgLy8gV3JpdGUgU0tJTEwubWRcbiAgICAgICAgZnMud3JpdGVGaWxlU3luYyhyZXNvbHZlUGF0aFdpdGhpbkJhc2Uob3V0cHV0RGlyLCAnU0tJTEwubWQnKSwgc3RydWN0dXJlWydTS0lMTC5tZCddKTtcblxuICAgICAgICAvLyBXcml0ZSBhbGwgY29tcG9uZW50IGRpcmVjdG9yaWVzXG4gICAgICAgIHRoaXMud3JpdGVTY3JpcHRzRGlyZWN0b3J5KHN0cnVjdHVyZSwgb3V0cHV0RGlyKTtcbiAgICAgICAgdGhpcy53cml0ZUZpbGVzRGlyZWN0b3J5KHN0cnVjdHVyZVsncmVmZXJlbmNlLyddLCBvdXRwdXREaXIsICdyZWZlcmVuY2UnKTtcbiAgICAgICAgdGhpcy53cml0ZUZpbGVzRGlyZWN0b3J5KHN0cnVjdHVyZVsndGhlbWVzLyddLCBvdXRwdXREaXIsICd0aGVtZXMnKTtcbiAgICAgICAgdGhpcy53cml0ZUZpbGVzRGlyZWN0b3J5KHN0cnVjdHVyZVsnZXhhbXBsZXMvJ10sIG91dHB1dERpciwgJ2V4YW1wbGVzJyk7XG4gICAgICAgIHRoaXMud3JpdGVGaWxlc0RpcmVjdG9yeShzdHJ1Y3R1cmVbJ21ldGFkYXRhLyddLCBvdXRwdXREaXIsICdtZXRhZGF0YScpO1xuXG4gICAgICAgIC8vIFdyaXRlIGxpY2Vuc2UgZmlsZVxuICAgICAgICBpZiAoc3RydWN0dXJlWydMSUNFTlNFLnR4dCddKSB7XG4gICAgICAgICAgICBmcy53cml0ZUZpbGVTeW5jKHJlc29sdmVQYXRoV2l0aGluQmFzZShvdXRwdXREaXIsICdMSUNFTlNFLnR4dCcpLCBzdHJ1Y3R1cmVbJ0xJQ0VOU0UudHh0J10pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRW5zdXJlIGRpcmVjdG9yeSBleGlzdHMsIGNyZWF0aW5nIGl0IGlmIG5lY2Vzc2FyeVxuICAgICAqIFJFRkFDVE9SRUQ6IEV4dHJhY3RlZCB0byByZWR1Y2UgY29nbml0aXZlIGNvbXBsZXhpdHlcbiAgICAgKi9cbiAgICBwcml2YXRlIGVuc3VyZURpcmVjdG9yeUV4aXN0cyhkaXJQYXRoOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgaWYgKCFmcy5leGlzdHNTeW5jKGRpclBhdGgpKSB7XG4gICAgICAgICAgICBmcy5ta2RpclN5bmMoZGlyUGF0aCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBXcml0ZSBzY3JpcHRzIGRpcmVjdG9yeSB3aXRoIHNlY3VyaXR5IGNvbnNpZGVyYXRpb25zXG4gICAgICogUkVGQUNUT1JFRDogRXh0cmFjdGVkIHRvIHJlZHVjZSBjb2duaXRpdmUgY29tcGxleGl0eVxuICAgICAqL1xuICAgIHByaXZhdGUgd3JpdGVTY3JpcHRzRGlyZWN0b3J5KHN0cnVjdHVyZTogQW50aHJvcGljU2tpbGxTdHJ1Y3R1cmUsIG91dHB1dERpcjogc3RyaW5nKTogdm9pZCB7XG4gICAgICAgIGlmICghc3RydWN0dXJlWydzY3JpcHRzLyddKSByZXR1cm47XG5cbiAgICAgICAgY29uc3Qgc2NyaXB0c0RpciA9IHJlc29sdmVQYXRoV2l0aGluQmFzZShvdXRwdXREaXIsICdzY3JpcHRzJyk7XG4gICAgICAgIGZzLm1rZGlyU3luYyhzY3JpcHRzRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuICAgICAgICBmb3IgKGNvbnN0IFtmaWxlbmFtZSwgY29udGVudF0gb2YgT2JqZWN0LmVudHJpZXMoc3RydWN0dXJlWydzY3JpcHRzLyddKSkge1xuICAgICAgICAgICAgZnMud3JpdGVGaWxlU3luYyhyZXNvbHZlUGF0aFdpdGhpbkJhc2Uoc2NyaXB0c0RpciwgZmlsZW5hbWUpLCBjb250ZW50KTtcbiAgICAgICAgICAgIC8vIFNFQ1VSSVRZIChTb25hckNsb3VkIFMyNjEyKTogRG8gTk9UIGF1dG8tY2htb2Qgc2NyaXB0cyBleGVjdXRhYmxlXG4gICAgICAgICAgICAvLyAtIFNjcmlwdHMgZnJvbSBEb2xsaG91c2VNQ1AgYXJlIG1hcmtkb3duIGNvZGUgYmxvY2tzLCBub3QgZXhlY3V0YWJsZSBmaWxlc1xuICAgICAgICAgICAgLy8gLSBGb3JtYXQgdHJhbnNmb3JtZXIgc2hvdWxkbid0IG1ha2Ugc2VjdXJpdHkgZGVjaXNpb25zIChjaG1vZCA9IHNlY3VyaXR5IGRlY2lzaW9uKVxuICAgICAgICAgICAgLy8gLSBQcmluY2lwbGUgb2YgbGVhc3QgcHJpdmlsZWdlOiB1c2VyIGNhbiBjaG1vZCBpZiBuZWVkZWRcbiAgICAgICAgICAgIC8vIC0gUHJldmVudHMgYXV0b21hdGljIGV4ZWN1dGlvbiBvZiBwb3RlbnRpYWxseSBtYWxpY2lvdXMgY29udmVydGVkIHNjcmlwdHNcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFdyaXRlIGdlbmVyaWMgZmlsZXMgZGlyZWN0b3J5IChyZWZlcmVuY2UsIHRoZW1lcywgZXhhbXBsZXMsIG1ldGFkYXRhKVxuICAgICAqIFJFRkFDVE9SRUQ6IEV4dHJhY3RlZCB0byByZWR1Y2UgY29nbml0aXZlIGNvbXBsZXhpdHkgYW5kIHJldXNlIGNvZGVcbiAgICAgKi9cbiAgICBwcml2YXRlIHdyaXRlRmlsZXNEaXJlY3RvcnkoXG4gICAgICAgIGZpbGVzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHwgdW5kZWZpbmVkLFxuICAgICAgICBvdXRwdXREaXI6IHN0cmluZyxcbiAgICAgICAgZGlyTmFtZTogc3RyaW5nXG4gICAgKTogdm9pZCB7XG4gICAgICAgIGlmICghZmlsZXMpIHJldHVybjtcblxuICAgICAgICBjb25zdCB0YXJnZXREaXIgPSByZXNvbHZlUGF0aFdpdGhpbkJhc2Uob3V0cHV0RGlyLCBkaXJOYW1lKTtcbiAgICAgICAgZnMubWtkaXJTeW5jKHRhcmdldERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cbiAgICAgICAgZm9yIChjb25zdCBbZmlsZW5hbWUsIGNvbnRlbnRdIG9mIE9iamVjdC5lbnRyaWVzKGZpbGVzKSkge1xuICAgICAgICAgICAgZnMud3JpdGVGaWxlU3luYyhyZXNvbHZlUGF0aFdpdGhpbkJhc2UodGFyZ2V0RGlyLCBmaWxlbmFtZSksIGNvbnRlbnQpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRXh0cmFjdCBZQU1MIGZyb250bWF0dGVyIGZyb20gbWFya2Rvd25cbiAgICAgKi9cbiAgICBwcml2YXRlIGV4dHJhY3RZQU1MRnJvbnRtYXR0ZXIoY29udGVudDogc3RyaW5nKToge1xuICAgICAgICBtZXRhZGF0YTogRG9sbGhvdXNlTUNQU2tpbGxNZXRhZGF0YTtcbiAgICAgICAgYm9keUNvbnRlbnQ6IHN0cmluZztcbiAgICB9IHtcbiAgICAgICAgY29uc3QgeWFtbE1hdGNoID0gL14tLS1cXG4oW1xcc1xcU10qPylcXG4tLS1cXG4oW1xcc1xcU10qKSQvLmV4ZWMoY29udGVudCk7XG5cbiAgICAgICAgaWYgKCF5YW1sTWF0Y2gpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gWUFNTCBmcm9udG1hdHRlciBmb3VuZCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRklYIChETUNQLVNFQy0wMDUpOiBVc2UgQ09SRV9TQ0hFTUEgdG8gcHJldmVudCBZQU1MIGRlc2VyaWFsaXphdGlvbiBhdHRhY2tzXG4gICAgICAgIGNvbnN0IG1ldGFkYXRhID0geWFtbC5sb2FkKHlhbWxNYXRjaFsxXSwgeyBzY2hlbWE6IHlhbWwuQ09SRV9TQ0hFTUEgfSkgYXMgRG9sbGhvdXNlTUNQU2tpbGxNZXRhZGF0YTtcbiAgICAgICAgY29uc3QgYm9keUNvbnRlbnQgPSB5YW1sTWF0Y2hbMl07XG5cbiAgICAgICAgcmV0dXJuIHsgbWV0YWRhdGEsIGJvZHlDb250ZW50IH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIFNLSUxMLm1kIGNvbnRlbnQgd2l0aCBzaW1wbGlmaWVkIG1ldGFkYXRhIGFuZCByZWZlcmVuY2VzXG4gICAgICovXG4gICAgcHJpdmF0ZSBjcmVhdGVTa2lsbE1EKFxuICAgICAgICBtZXRhZGF0YTogQW50aHJvcGljU2tpbGxNZXRhZGF0YSxcbiAgICAgICAgbWFpbkluc3RydWN0aW9uczogc3RyaW5nLFxuICAgICAgICByZWZlcmVuY2VzOiBzdHJpbmdbXVxuICAgICk6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IHlhbWxTdHJpbmcgPSB5YW1sLmR1bXAobWV0YWRhdGEpO1xuXG4gICAgICAgIGxldCBza2lsbE1EID0gYC0tLVxcbiR7eWFtbFN0cmluZ30tLS1cXG5cXG4ke21haW5JbnN0cnVjdGlvbnN9YDtcblxuICAgICAgICAvLyBBZGQgcmVmZXJlbmNlcyBzZWN0aW9uIGlmIHRoZXJlIGFyZSBleHRyYWN0ZWQgY29tcG9uZW50c1xuICAgICAgICBpZiAocmVmZXJlbmNlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBza2lsbE1EICs9ICdcXG5cXG4jIyBBZGRpdGlvbmFsIFJlc291cmNlc1xcblxcbic7XG4gICAgICAgICAgICBza2lsbE1EICs9IHJlZmVyZW5jZXMuam9pbignXFxuJyk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gc2tpbGxNRDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBFeHRyYWN0IG1haW4gaW5zdHJ1Y3Rpb25zIChjb250ZW50IGJlZm9yZSBjb2RlIGJsb2NrcyBhbmQgc3BlY2lhbCBzZWN0aW9ucylcbiAgICAgKi9cbiAgICBwcml2YXRlIGV4dHJhY3RNYWluSW5zdHJ1Y3Rpb25zKGNvbnRlbnQ6IHN0cmluZywgZXh0cmFjdGVkU2VjdGlvbnM6IEV4dHJhY3RlZFNlY3Rpb25bXSk6IHN0cmluZyB7XG4gICAgICAgIC8vIEZvciBub3csIHJldHVybiBjb250ZW50IHVwIHRvIGZpcnN0IGNvZGUgYmxvY2sgb3IgZXh0cmFjdGVkIHNlY3Rpb25cbiAgICAgICAgLy8gVGhpcyBpcyBzaW1wbGlmaWVkIC0gYSBmdWxsIGltcGxlbWVudGF0aW9uIHdvdWxkIHJlY29uc3RydWN0IHdpdGggcmVmZXJlbmNlc1xuICAgICAgICBjb25zdCBsaW5lcyA9IGNvbnRlbnQuc3BsaXQoJ1xcbicpO1xuICAgICAgICBjb25zdCBtYWluTGluZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICAgICAgbGV0IGluRXh0cmFjdGVkU2VjdGlvbiA9IGZhbHNlO1xuXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGxpbmUgPSBsaW5lc1tpXTtcblxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgd2UncmUgZW50ZXJpbmcgYW4gZXh0cmFjdGVkIHNlY3Rpb25cbiAgICAgICAgICAgIGNvbnN0IGlzRXh0cmFjdGVkID0gZXh0cmFjdGVkU2VjdGlvbnMuc29tZShcbiAgICAgICAgICAgICAgICBzID0+IGkgPj0gcy5zdGFydExpbmUgJiYgaSA8PSBzLmVuZExpbmVcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIGlmIChpc0V4dHJhY3RlZCkge1xuICAgICAgICAgICAgICAgIGluRXh0cmFjdGVkU2VjdGlvbiA9IHRydWU7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghaW5FeHRyYWN0ZWRTZWN0aW9uIHx8IGxpbmUuc3RhcnRzV2l0aCgnIycpKSB7XG4gICAgICAgICAgICAgICAgbWFpbkxpbmVzLnB1c2gobGluZSk7XG4gICAgICAgICAgICAgICAgaW5FeHRyYWN0ZWRTZWN0aW9uID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbWFpbkxpbmVzLmpvaW4oJ1xcbicpLnRyaW0oKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBFeHRyYWN0IGRvY3VtZW50YXRpb24gc2VjdGlvbnMgKElucHV0IEZvcm1hdHMsIEVycm9yIEhhbmRsaW5nLCBldGMuKVxuICAgICAqL1xuICAgIHByaXZhdGUgZXh0cmFjdERvY3VtZW50YXRpb25TZWN0aW9ucyhjb250ZW50OiBzdHJpbmcpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgICAgICAgY29uc3Qgc2VjdGlvbnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcblxuICAgICAgICAvLyBDb21tb24gZG9jdW1lbnRhdGlvbiBzZWN0aW9uIHBhdHRlcm5zXG4gICAgICAgIGNvbnN0IHNlY3Rpb25QYXR0ZXJucyA9IFtcbiAgICAgICAgICAgICdJbnB1dCBGb3JtYXRzJyxcbiAgICAgICAgICAgICdFcnJvciBIYW5kbGluZycsXG4gICAgICAgICAgICAnU3VwcG9ydGVkIENsaWVudHMnLFxuICAgICAgICAgICAgJ0NvbW1hbmQgQnVpbGRpbmcnLFxuICAgICAgICAgICAgJ0NvbmZpZ3VyYXRpb24nLFxuICAgICAgICAgICAgJ1Ryb3VibGVzaG9vdGluZydcbiAgICAgICAgXTtcblxuICAgICAgICBmb3IgKGNvbnN0IHBhdHRlcm4gb2Ygc2VjdGlvblBhdHRlcm5zKSB7XG4gICAgICAgICAgICBjb25zdCBzZWN0aW9uID0gdGhpcy5jb250ZW50RXh0cmFjdG9yLmV4dHJhY3REb2N1bWVudGF0aW9uU2VjdGlvbihjb250ZW50LCBwYXR0ZXJuKTtcbiAgICAgICAgICAgIGlmIChzZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgc2VjdGlvbnNbcGF0dGVybl0gPSBzZWN0aW9uO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHNlY3Rpb25zO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEZvcm1hdCBzY3JpcHQgZmlsZSB3aXRoIHByb3BlciBzaGViYW5nIGFuZCBoZWFkZXJzXG4gICAgICovXG4gICAgcHJpdmF0ZSBmb3JtYXRTY3JpcHRGaWxlKGNvbnRlbnQ6IHN0cmluZywgbGFuZ3VhZ2U6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IHNoZWJhbmcgPSB0aGlzLmdldFNoZWJhbmcobGFuZ3VhZ2UpO1xuICAgICAgICBjb25zdCBoZWFkZXIgPSB0aGlzLmdldFNjcmlwdEhlYWRlcihjb250ZW50KTtcblxuICAgICAgICByZXR1cm4gYCR7c2hlYmFuZ31cXG4ke2hlYWRlcn1cXG4ke2NvbnRlbnR9YDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgYXBwcm9wcmlhdGUgc2hlYmFuZyBmb3Igc2NyaXB0IGxhbmd1YWdlXG4gICAgICovXG4gICAgcHJpdmF0ZSBnZXRTaGViYW5nKGxhbmd1YWdlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICBjb25zdCBzaGViYW5nczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICAgICAgICAgIGJhc2g6ICcjIS9iaW4vYmFzaCcsXG4gICAgICAgICAgICBzaDogJyMhL2Jpbi9zaCcsXG4gICAgICAgICAgICBweXRob246ICcjIS91c3IvYmluL2VudiBweXRob24zJyxcbiAgICAgICAgICAgIHB5OiAnIyEvdXNyL2Jpbi9lbnYgcHl0aG9uMycsXG4gICAgICAgICAgICBub2RlOiAnIyEvdXNyL2Jpbi9lbnYgbm9kZScsXG4gICAgICAgICAgICBqYXZhc2NyaXB0OiAnIyEvdXNyL2Jpbi9lbnYgbm9kZScsXG4gICAgICAgICAgICBqczogJyMhL3Vzci9iaW4vZW52IG5vZGUnXG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIHNoZWJhbmdzW2xhbmd1YWdlLnRvTG93ZXJDYXNlKCldIHx8ICcjIS9iaW4vYmFzaCc7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHNjcmlwdCBoZWFkZXIgY29tbWVudFxuICAgICAqL1xuICAgIHByaXZhdGUgZ2V0U2NyaXB0SGVhZGVyKGNvbnRlbnQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgICAgIC8vIEV4dHJhY3QgZmlyc3QgY29tbWVudCBpZiBwcmVzZW50XG4gICAgICAgIGNvbnN0IGZpcnN0TGluZSA9IGNvbnRlbnQuc3BsaXQoJ1xcbicpWzBdO1xuICAgICAgICBpZiAoZmlyc3RMaW5lLnN0YXJ0c1dpdGgoJyMnKSB8fCBmaXJzdExpbmUuc3RhcnRzV2l0aCgnLy8nKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZpcnN0TGluZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gJyMgRXh0cmFjdGVkIHNjcmlwdCc7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGZpbGUgZXh0ZW5zaW9uIGZvciBsYW5ndWFnZVxuICAgICAqL1xuICAgIHByaXZhdGUgZ2V0RXh0ZW5zaW9uKGxhbmd1YWdlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICBjb25zdCBleHRlbnNpb25zOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgICAgICAgICAgYmFzaDogJ3NoJyxcbiAgICAgICAgICAgIHNoOiAnc2gnLFxuICAgICAgICAgICAgcHl0aG9uOiAncHknLFxuICAgICAgICAgICAgcHk6ICdweScsXG4gICAgICAgICAgICBqYXZhc2NyaXB0OiAnanMnLFxuICAgICAgICAgICAganM6ICdqcycsXG4gICAgICAgICAgICB0eXBlc2NyaXB0OiAndHMnLFxuICAgICAgICAgICAgdHM6ICd0cydcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gZXh0ZW5zaW9uc1tsYW5ndWFnZS50b0xvd2VyQ2FzZSgpXSB8fCAndHh0JztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgc2x1Z2lmaWVkIGZpbGVuYW1lIGZyb20gdGl0bGVcbiAgICAgKi9cbiAgICBwcml2YXRlIHNsdWdpZnkodGl0bGU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aXRsZVxuICAgICAgICAgICAgLnRvTG93ZXJDYXNlKClcbiAgICAgICAgICAgIC5yZXBsYWNlQWxsKC9bXmEtejAtOVxccy1dL2csICcnKVxuICAgICAgICAgICAgLnJlcGxhY2VBbGwoL1xccysvZywgJy0nKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgTElDRU5TRS50eHQgZmlsZVxuICAgICAqL1xuICAgIHByaXZhdGUgY3JlYXRlTGljZW5zZUZpbGUobGljZW5zZTogc3RyaW5nLCBhdXRob3I/OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICBjb25zdCBhdXRob3JTdWZmaXggPSBhdXRob3IgPyBgXFxuXFxuQXV0aG9yOiAke2F1dGhvcn1gIDogJyc7XG4gICAgICAgIHJldHVybiBgJHtsaWNlbnNlfSR7YXV0aG9yU3VmZml4fWA7XG4gICAgfVxufVxuIl19