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.

279 lines (277 loc) 33.9 kB
/** * Capability Index Resource Handler * * Exposes the capability index as an MCP resource for injection into LLM context. * Provides both summary (action_triggers only) and full index variants. * * ⚠️ MERGE STATUS: PORTED BUT NOT INTEGRATED (October 2025) * * This file was ported from main branch (v1.9.18-v1.9.24) but is NOT currently * integrated into the refactored DI architecture. Integration is planned for a * future phase once the Enhanced Index system is fully operational. * * CURRENT STATE: * - ✅ File ported and preserved for future use * - ❌ NOT registered in DI Container * - ❌ NOT registered with MCP server * - ❌ NOT accessible to users * * ⚠️ ORIGINAL STATUS: NON-FUNCTIONAL IN CLAUDE CODE (October 2025) * * This is a FUTURE-PROOF implementation. MCP Resources are currently: * - ✅ Fully implemented and MCP specification compliant * - ❌ NOT working in Claude Code (discovery only, never read) * - ⚠️ Manual attachment only in Claude Desktop/VS Code * * WHY IMPLEMENT NOW? * - Early adopter advantage when clients add full support * - Manual attachment works in Claude Desktop/VS Code * - Zero overhead when disabled (default configuration) * * DEFAULT: DISABLED FOR SAFETY * Resources are disabled by default to avoid token overhead and ensure * no surprises for users. Must be explicitly enabled in configuration. * * WHEN WILL THIS BE USEFUL? * When Claude Code and other MCP clients implement the missing * resources/read functionality and automatic resource injection. * Expected timeline: Unknown. * * For detailed research, see: * docs/development/MCP_RESOURCES_SUPPORT_RESEARCH_2025-10-16.md * * For user documentation, see: * docs/configuration/MCP_RESOURCES.md * * FUTURE INTEGRATION TASKS: * - [ ] Register in DI Container (src/di/Container.ts) * - [ ] Add configuration option for enabling resources * - [ ] Register resource handlers with MCP server when enabled * - [ ] Add unit tests for resource generation * - [ ] Add integration tests for MCP resource protocol */ // FIX: Added node: prefix to built-in Node.js imports // Previously: import fs from 'fs/promises'; etc. // Now: import fs from 'node:fs/promises'; for Node.js convention import path from 'node:path'; import yaml from 'js-yaml'; import os from 'node:os'; import { logger } from '../../utils/logger.js'; /** * Capability Index Resource Handler * * Provides three MCP resources: * 1. Summary (~2.5-3.5K tokens) - action_triggers only * 2. Full (~35-45K tokens) - complete index with all details * 3. Stats (JSON) - size metrics and token estimates * * WHY DISABLED BY DEFAULT: * 1. Current MCP clients don't actually read resources (Claude Code discovery only) * 2. Avoids unexpected token overhead when clients do implement reading * 3. Provides opt-in behavior for users who want to test manually in Claude Desktop * * TO ENABLE: * Set in config: resources.enabled = true * Or environment: DOLLHOUSE_RESOURCES_ENABLED=true * * NOTE: This class always provides resource handlers for MCP protocol compliance, * but the resources are only registered with the MCP server if explicitly enabled. */ export class CapabilityIndexResource { capabilityIndexPath; cachedIndex = null; cacheTimestamp = 0; CACHE_TTL = 60000; // 60 seconds fileOperations; constructor(fileOperations) { this.fileOperations = fileOperations; // Respect environment variable if set (for testing), otherwise use default const portfolioDir = process.env.DOLLHOUSE_PORTFOLIO_DIR || path.join(os.homedir(), '.dollhouse', 'portfolio'); this.capabilityIndexPath = path.join(portfolioDir, 'capability-index.yaml'); } /** * Load and parse capability index from filesystem * Uses 60-second cache to avoid excessive file reads * * @returns Parsed capability index * @throws Error if file cannot be read or parsed */ async loadCapabilityIndex() { const now = Date.now(); // Return cached version if still valid if (this.cachedIndex && (now - this.cacheTimestamp) < this.CACHE_TTL) { return this.cachedIndex; } try { // Check if file exists const fileExists = await this.fileOperations.exists(this.capabilityIndexPath); if (!fileExists) { throw new Error(`Capability index not found at ${this.capabilityIndexPath}`); } // Read and parse YAML with safe schema to prevent code execution const content = await this.fileOperations.readFile(this.capabilityIndexPath, { source: 'CapabilityIndexResource.loadCapabilityIndex' }); const parsed = yaml.load(content, { schema: yaml.FAILSAFE_SCHEMA }); // Cache the result this.cachedIndex = parsed; this.cacheTimestamp = now; logger.info(`Loaded capability index: ${parsed.metadata.total_elements} elements`); return parsed; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); logger.error(`Failed to load capability index: ${errorMessage}`); throw new Error(`Capability index not available: ${errorMessage}`); } } /** * Generate summary version of capability index (metadata + action_triggers only) * Estimated: 2,500-3,500 tokens * * @returns YAML string with header and summary content */ async generateSummary() { const index = await this.loadCapabilityIndex(); const summary = { metadata: index.metadata, action_triggers: index.action_triggers }; // Convert to YAML for readability const yamlContent = yaml.dump(summary, { indent: 2, lineWidth: 120, noRefs: true }); // Add header comment const header = `# Capability Index Summary # This is a lightweight summary of the capability index for LLM context injection. # Contains action verb → element mappings for quick tool selection guidance. # Full index available at: dollhouse://capability-index/full # Total elements: ${index.metadata.total_elements} `; return header + yamlContent; } /** * Generate full capability index * Estimated: 35,000-45,000 tokens * * @returns YAML string with header and full index content */ async generateFull() { const index = await this.loadCapabilityIndex(); // Convert to YAML for readability const yamlContent = yaml.dump(index, { indent: 2, lineWidth: 120, noRefs: true }); // Add header comment const header = `# Capability Index (Full) # Complete capability index including all element details, relationships, and semantic data. # This is a large resource (~35-45K tokens) - use only with large context models. # Summary version available at: dollhouse://capability-index/summary # Total elements: ${index.metadata.total_elements} `; return header + yamlContent; } /** * Get statistics about the capability index for measurement * Provides size metrics and rough token estimates using: * (chars/4 + words*1.3)/2 formula * * @returns Statistics object with size and token estimates */ async getStatistics() { const summary = await this.generateSummary(); const full = await this.generateFull(); return { summarySize: summary.length, summaryWords: summary.split(/\s+/).length, summaryLines: summary.split('\n').length, fullSize: full.length, fullWords: full.split(/\s+/).length, fullLines: full.split('\n').length, // Rough token estimates (chars/4 + words*1.3)/2 estimatedSummaryTokens: Math.round((summary.length / 4 + summary.split(/\s+/).length * 1.3) / 2), estimatedFullTokens: Math.round((full.length / 4 + full.split(/\s+/).length * 1.3) / 2) }; } /** * MCP Resource Handler: List available resources * * Returns three resources: * - summary: Lightweight index (~2.5-3.5K tokens) * - full: Complete index (~35-45K tokens) * - stats: Size and token metrics (JSON) * * @returns Resource list with URIs, names, descriptions, and MIME types */ async listResources() { return { resources: [ { uri: 'dollhouse://capability-index/summary', name: 'Capability Index Summary', description: 'Lightweight capability index with action verb → element mappings. Estimated ~2.5-3.5K tokens. Recommended for models with 200K+ context.', mimeType: 'text/yaml' }, { uri: 'dollhouse://capability-index/full', name: 'Capability Index (Full)', description: 'Complete capability index with all element details, relationships, and semantic data. Estimated ~35-45K tokens. Recommended for models with 500K+ context.', mimeType: 'text/yaml' }, { uri: 'dollhouse://capability-index/stats', name: 'Capability Index Statistics', description: 'Measurement data about capability index size and token estimates.', mimeType: 'application/json' } ] }; } /** * MCP Resource Handler: Read a specific resource * * @param uri - Resource URI to read (must match one from listResources) * @returns Resource content with URI, MIME type, and text * @throws Error if URI is not recognized */ async readResource(uri) { let content; let mimeType; switch (uri) { case 'dollhouse://capability-index/summary': content = await this.generateSummary(); mimeType = 'text/yaml'; break; case 'dollhouse://capability-index/full': content = await this.generateFull(); mimeType = 'text/yaml'; break; case 'dollhouse://capability-index/stats': { // FIX: Wrapped lexical declaration in curly braces // Previously: const declaration in case block without braces // Now: Properly scoped with block statement const stats = await this.getStatistics(); content = JSON.stringify(stats, null, 2); mimeType = 'application/json'; break; } default: throw new Error(`Unknown capability index resource: ${uri}`); } return { contents: [ { uri, mimeType, text: content } ] }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2FwYWJpbGl0eUluZGV4UmVzb3VyY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmVyL3Jlc291cmNlcy9DYXBhYmlsaXR5SW5kZXhSZXNvdXJjZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbURHO0FBRUgsc0RBQXNEO0FBQ3RELGlEQUFpRDtBQUNqRCxpRUFBaUU7QUFDakUsT0FBTyxJQUFJLE1BQU0sV0FBVyxDQUFDO0FBQzdCLE9BQU8sSUFBSSxNQUFNLFNBQVMsQ0FBQztBQUMzQixPQUFPLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDekIsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBcUUvQzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUNILE1BQU0sT0FBTyx1QkFBdUI7SUFDakIsbUJBQW1CLENBQVM7SUFDckMsV0FBVyxHQUEyQixJQUFJLENBQUM7SUFDM0MsY0FBYyxHQUFXLENBQUMsQ0FBQztJQUNsQixTQUFTLEdBQUcsS0FBSyxDQUFDLENBQUMsYUFBYTtJQUNoQyxjQUFjLENBQXlCO0lBRXhELFlBQVksY0FBc0M7UUFDaEQsSUFBSSxDQUFDLGNBQWMsR0FBRyxjQUFjLENBQUM7UUFFckMsMkVBQTJFO1FBQzNFLE1BQU0sWUFBWSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQXVCO2VBQ25ELElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxFQUFFLFlBQVksRUFBRSxXQUFXLENBQUMsQ0FBQztRQUV4RCxJQUFJLENBQUMsbUJBQW1CLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FDbEMsWUFBWSxFQUNaLHVCQUF1QixDQUN4QixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNLLEtBQUssQ0FBQyxtQkFBbUI7UUFDL0IsTUFBTSxHQUFH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LE1BQU0sSUFBSSxLQUFLLENBQUMsc0NBQXNDLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDakUsQ0FBQztRQUVELE9BQU87WUFDTCxRQUFRLEVBQUU7Z0JBQ1I7b0JBQ0UsR0FBRztvQkFDSCxRQUFRO29CQUNSLElBQUksRUFBRSxPQUFPO2lCQUNkO2FBQ0Y7U0FDRixDQUFDO0lBQ0osQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDYXBhYmlsaXR5IEluZGV4IFJlc291cmNlIEhhbmRsZXJcbiAqXG4gKiBFeHBvc2VzIHRoZSBjYXBhYmlsaXR5IGluZGV4IGFzIGFuIE1DUCByZXNvdXJjZSBmb3IgaW5qZWN0aW9uIGludG8gTExNIGNvbnRleHQuXG4gKiBQcm92aWRlcyBib3RoIHN1bW1hcnkgKGFjdGlvbl90cmlnZ2VycyBvbmx5KSBhbmQgZnVsbCBpbmRleCB2YXJpYW50cy5cbiAqXG4gKiDimqDvuI8gTUVSR0UgU1RBVFVTOiBQT1JURUQgQlVUIE5PVCBJTlRFR1JBVEVEIChPY3RvYmVyIDIwMjUpXG4gKlxuICogVGhpcyBmaWxlIHdhcyBwb3J0ZWQgZnJvbSBtYWluIGJyYW5jaCAodjEuOS4xOC12MS45LjI0KSBidXQgaXMgTk9UIGN1cnJlbnRseVxuICogaW50ZWdyYXRlZCBpbnRvIHRoZSByZWZhY3RvcmVkIERJIGFyY2hpdGVjdHVyZS4gSW50ZWdyYXRpb24gaXMgcGxhbm5lZCBmb3IgYVxuICogZnV0dXJlIHBoYXNlIG9uY2UgdGhlIEVuaGFuY2VkIEluZGV4IHN5c3RlbSBpcyBmdWxseSBvcGVyYXRpb25hbC5cbiAqXG4gKiBDVVJSRU5UIFNUQVRFOlxuICogLSDinIUgRmlsZSBwb3J0ZWQgYW5kIHByZXNlcnZlZCBmb3IgZnV0dXJlIHVzZVxuICogLSDinYwgTk9UIHJlZ2lzdGVyZWQgaW4gREkgQ29udGFpbmVyXG4gKiAtIOKdjCBOT1QgcmVnaXN0ZXJlZCB3aXRoIE1DUCBzZXJ2ZXJcbiAqIC0g4p2MIE5PVCBhY2Nlc3NpYmxlIHRvIHVzZXJzXG4gKlxuICog4pqg77iPIE9SSUdJTkFMIFNUQVRVUzogTk9OLUZVTkNUSU9OQUwgSU4gQ0xBVURFIENPREUgKE9jdG9iZXIgMjAyNSlcbiAqXG4gKiBUaGlzIGlzIGEgRlVUVVJFLVBST09GIGltcGxlbWVudGF0aW9uLiBNQ1AgUmVzb3VyY2VzIGFyZSBjdXJyZW50bHk6XG4gKiAtIOKchSBGdWxseSBpbXBsZW1lbnRlZCBhbmQgTUNQIHNwZWNpZmljYXRpb24gY29tcGxpYW50XG4gKiAtIOKdjCBOT1Qgd29ya2luZyBpbiBDbGF1ZGUgQ29kZSAoZGlzY292ZXJ5IG9ubHksIG5ldmVyIHJlYWQpXG4gKiAtIOKaoO+4jyBNYW51YWwgYXR0YWNobWVudCBvbmx5IGluIENsYXVkZSBEZXNrdG9wL1ZTIENvZGVcbiAqXG4gKiBXSFkgSU1QTEVNRU5UIE5PVz9cbiAqIC0gRWFybHkgYWRvcHRlciBhZHZhbnRhZ2Ugd2hlbiBjbGllbnRzIGFkZCBmdWxsIHN1cHBvcnRcbiAqIC0gTWFudWFsIGF0dGFjaG1lbnQgd29ya3MgaW4gQ2xhdWRlIERlc2t0b3AvVlMgQ29kZVxuICogLSBaZXJvIG92ZXJoZWFkIHdoZW4gZGlzYWJsZWQgKGRlZmF1bHQgY29uZmlndXJhdGlvbilcbiAqXG4gKiBERUZBVUxUOiBESVNBQkxFRCBGT1IgU0FGRVRZXG4gKiBSZXNvdXJjZXMgYXJlIGRpc2FibGVkIGJ5IGRlZmF1bHQgdG8gYXZvaWQgdG9rZW4gb3ZlcmhlYWQgYW5kIGVuc3VyZVxuICogbm8gc3VycHJpc2VzIGZvciB1c2Vycy4gTXVzdCBiZSBleHBsaWNpdGx5IGVuYWJsZWQgaW4gY29uZmlndXJhdGlvbi5cbiAqXG4gKiBXSEVOIFdJTEwgVEhJUyBCRSBVU0VGVUw/XG4gKiBXaGVuIENsYXVkZSBDb2RlIGFuZCBvdGhlciBNQ1AgY2xpZW50cyBpbXBsZW1lbnQgdGhlIG1pc3NpbmdcbiAqIHJlc291cmNlcy9yZWFkIGZ1bmN0aW9uYWxpdHkgYW5kIGF1dG9tYXRpYyByZXNvdXJjZSBpbmplY3Rpb24uXG4gKiBFeHBlY3RlZCB0aW1lbGluZTogVW5rbm93bi5cbiAqXG4gKiBGb3IgZGV0YWlsZWQgcmVzZWFyY2gsIHNlZTpcbiAqIGRvY3MvZGV2ZWxvcG1lbnQvTUNQX1JFU09VUkNFU19TVVBQT1JUX1JFU0VBUkNIXzIwMjUtMTAtMTYubWRcbiAqXG4gKiBGb3IgdXNlciBkb2N1bWVudGF0aW9uLCBzZWU6XG4gKiBkb2NzL2NvbmZpZ3VyYXRpb24vTUNQX1JFU09VUkNFUy5tZFxuICpcbiAqIEZVVFVSRSBJTlRFR1JBVElPTiBUQVNLUzpcbiAqIC0gWyBdIFJlZ2lzdGVyIGluIERJIENvbnRhaW5lciAoc3JjL2RpL0NvbnRhaW5lci50cylcbiAqIC0gWyBdIEFkZCBjb25maWd1cmF0aW9uIG9wdGlvbiBmb3IgZW5hYmxpbmcgcmVzb3VyY2VzXG4gKiAtIFsgXSBSZWdpc3RlciByZXNvdXJjZSBoYW5kbGVycyB3aXRoIE1DUCBzZXJ2ZXIgd2hlbiBlbmFibGVkXG4gKiAtIFsgXSBBZGQgdW5pdCB0ZXN0cyBmb3IgcmVzb3VyY2UgZ2VuZXJhdGlvblxuICogLSBbIF0gQWRkIGludGVncmF0aW9uIHRlc3RzIGZvciBNQ1AgcmVzb3VyY2UgcHJvdG9jb2xcbiAqL1xuXG4vLyBGSVg6IEFkZGVkIG5vZGU6IHByZWZpeCB0byBidWlsdC1pbiBOb2RlLmpzIGltcG9ydHNcbi8vIFByZXZpb3VzbHk6IGltcG9ydCBmcyBmcm9tICdmcy9wcm9taXNlcyc7IGV0Yy5cbi8vIE5vdzogaW1wb3J0IGZzIGZyb20gJ25vZGU6ZnMvcHJvbWlzZXMnOyBmb3IgTm9kZS5qcyBjb252ZW50aW9uXG5pbXBvcnQgcGF0aCBmcm9tICdub2RlOnBhdGgnO1xuaW1wb3J0IHlhbWwgZnJvbSAnanMteWFtbCc7XG5pbXBvcnQgb3MgZnJvbSAnbm9kZTpvcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi8uLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgSUZpbGVPcGVyYXRpb25zU2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL0ZpbGVPcGVyYXRpb25zU2VydmljZS5qcyc7XG5cbi8qKlxuICogTWV0YWRhdGEgYWJvdXQgdGhlIGNhcGFiaWxpdHkgaW5kZXhcbiAqL1xuaW50ZXJmYWNlIENhcGFiaWxpdHlJbmRleE1ldGFkYXRhIHtcbiAgdmVyc2lvbjogc3RyaW5nO1xuICBjcmVhdGVkOiBzdHJpbmc7XG4gIGxhc3RfdXBkYXRlZDogc3RyaW5nO1xuICB0b3RhbF9lbGVtZW50czogbnVtYmVyO1xufVxuXG4vKipcbiAqIEZ1bGwgY2FwYWJpbGl0eSBpbmRleCBzdHJ1Y3R1cmVcbiAqL1xuaW50ZXJmYWNlIENhcGFiaWxpdHlJbmRleCB7XG4gIG1ldGFkYXRhOiBDYXBhYmlsaXR5SW5kZXhNZXRhZGF0YTtcbiAgYWN0aW9uX3RyaWdnZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT47XG4gIGVsZW1lbnRzPzogYW55OyAvLyBMYXJnZSBzZWN0aW9uIHdlIG1pZ2h0IGV4Y2x1ZGUgaW4gc3VtbWFyeVxufVxuXG4vKipcbiAqIFN0YXRpc3RpY3MgYWJvdXQgdGhlIGNhcGFiaWxpdHkgaW5kZXggc2l6ZSBhbmQgdG9rZW4gZXN0aW1hdGVzXG4gKi9cbmludGVyZmFjZSBDYXBhYmlsaXR5SW5kZXhTdGF0aXN0aWNzIHtcbiAgc3VtbWFyeVNpemU6IG51bWJlcjtcbiAgc3VtbWFyeVdvcmRzOiBudW1iZXI7XG4gIHN1bW1hcnlMaW5lczogbnVtYmVyO1xuICBmdWxsU2l6ZTogbnVtYmVyO1xuICBmdWxsV29yZHM6IG51bWJlcjtcbiAgZnVsbExpbmVzOiBudW1iZXI7XG4gIGVzdGltYXRlZFN1bW1hcnlUb2tlbnM6IG51bWJlcjtcbiAgZXN0aW1hdGVkRnVsbFRva2VuczogbnVtYmVyO1xufVxuXG4vKipcbiAqIE1DUCBSZXNvdXJjZSBzdHJ1Y3R1cmVcbiAqL1xuaW50ZXJmYWNlIE1DUFJlc291cmNlIHtcbiAgdXJpOiBzdHJpbmc7XG4gIG5hbWU6IHN0cmluZztcbiAgZGVzY3JpcHRpb246IHN0cmluZztcbiAgbWltZVR5cGU6IHN0cmluZztcbn1cblxuLyoqXG4gKiBNQ1AgUmVzb3VyY2UgbGlzdCByZXNwb25zZVxuICovXG5pbnRlcmZhY2UgTUNQUmVzb3VyY2VMaXN0UmVzcG9uc2Uge1xuICByZXNvdXJjZXM6IE1DUFJlc291cmNlW107XG59XG5cbi8qKlxuICogTUNQIFJlc291cmNlIGNvbnRlbnQgaXRlbVxuICovXG5pbnRlcmZhY2UgTUNQUmVzb3VyY2VDb250ZW50IHtcbiAgdXJpOiBzdHJpbmc7XG4gIG1pbWVUeXBlOiBzdHJpbmc7XG4gIHRleHQ6IHN0cmluZztcbn1cblxuLyoqXG4gKiBNQ1AgUmVzb3VyY2UgcmVhZCByZXNwb25zZVxuICovXG5pbnRlcmZhY2UgTUNQUmVzb3VyY2VSZWFkUmVzcG9uc2Uge1xuICBjb250ZW50czogTUNQUmVzb3VyY2VDb250ZW50W107XG59XG5cbi8qKlxuICogQ2FwYWJpbGl0eSBJbmRleCBSZXNvdXJjZSBIYW5kbGVyXG4gKlxuICogUHJvdmlkZXMgdGhyZWUgTUNQIHJlc291cmNlczpcbiAqIDEuIFN1bW1hcnkgKH4yLjUtMy41SyB0b2tlbnMpIC0gYWN0aW9uX3RyaWdnZXJzIG9ubHlcbiAqIDIuIEZ1bGwgKH4zNS00NUsgdG9rZW5zKSAtIGNvbXBsZXRlIGluZGV4IHdpdGggYWxsIGRldGFpbHNcbiAqIDMuIFN0YXRzIChKU09OKSAtIHNpemUgbWV0cmljcyBhbmQgdG9rZW4gZXN0aW1hdGVzXG4gKlxuICogV0hZIERJU0FCTEVEIEJZIERFRkFVTFQ6XG4gKiAxLiBDdXJyZW50IE1DUCBjbGllbnRzIGRvbid0IGFjdHVhbGx5IHJlYWQgcmVzb3VyY2VzIChDbGF1ZGUgQ29kZSBkaXNjb3Zlcnkgb25seSlcbiAqIDIuIEF2b2lkcyB1bmV4cGVjdGVkIHRva2VuIG92ZXJoZWFkIHdoZW4gY2xpZW50cyBkbyBpbXBsZW1lbnQgcmVhZGluZ1xuICogMy4gUHJvdmlkZXMgb3B0LWluIGJlaGF2aW9yIGZvciB1c2VycyB3aG8gd2FudCB0byB0ZXN0IG1hbnVhbGx5IGluIENsYXVkZSBEZXNrdG9wXG4gKlxuICogVE8gRU5BQkxFOlxuICogU2V0IGluIGNvbmZpZzogcmVzb3VyY2VzLmVuYWJsZWQgPSB0cnVlXG4gKiBPciBlbnZpcm9ubWVudDogRE9MTEhPVVNFX1JFU09VUkNFU19FTkFCTEVEPXRydWVcbiAqXG4gKiBOT1RFOiBUaGlzIGNsYXNzIGFsd2F5cyBwcm92aWRlcyByZXNvdXJjZSBoYW5kbGVycyBmb3IgTUNQIHByb3RvY29sIGNvbXBsaWFuY2UsXG4gKiBidXQgdGhlIHJlc291cmNlcyBhcmUgb25seSByZWdpc3RlcmVkIHdpdGggdGhlIE1DUCBzZXJ2ZXIgaWYgZXhwbGljaXRseSBlbmFibGVkLlxuICovXG5leHBvcnQgY2xhc3MgQ2FwYWJpbGl0eUluZGV4UmVzb3VyY2Uge1xuICBwcml2YXRlIHJlYWRvbmx5IGNhcGFiaWxpdHlJbmRleFBhdGg6IHN0cmluZztcbiAgcHJpdmF0ZSBjYWNoZWRJbmRleDogQ2FwYWJpbGl0eUluZGV4IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgY2FjaGVUaW1lc3RhbXA6IG51bWJlciA9IDA7XG4gIHByaXZhdGUgcmVhZG9ubHkgQ0FDSEVfVFRMID0gNjAwMDA7IC8vIDYwIHNlY29uZHNcbiAgcHJpdmF0ZSByZWFkb25seSBmaWxlT3BlcmF0aW9uczogSUZpbGVPcGVyYXRpb25zU2VydmljZTtcblxuICBjb25zdHJ1Y3RvcihmaWxlT3BlcmF0aW9uczogSUZpbGVPcGVyYXRpb25zU2VydmljZSkge1xuICAgIHRoaXMuZmlsZU9wZXJhdGlvbnMgPSBmaWxlT3BlcmF0aW9ucztcblxuICAgIC8vIFJlc3BlY3QgZW52aXJvbm1lbnQgdmFyaWFibGUgaWYgc2V0IChmb3IgdGVzdGluZyksIG90aGVyd2lzZSB1c2UgZGVmYXVsdFxuICAgIGNvbnN0IHBvcnRmb2xpb0RpciA9IHByb2Nlc3MuZW52LkRPTExIT1VTRV9QT1JURk9MSU9fRElSXG4gICAgICB8fCBwYXRoLmpvaW4ob3MuaG9tZWRpcigpLCAnLmRvbGxob3VzZScsICdwb3J0Zm9saW8nKTtcblxuICAgIHRoaXMuY2FwYWJpbGl0eUluZGV4UGF0aCA9IHBhdGguam9pbihcbiAgICAgIHBvcnRmb2xpb0RpcixcbiAgICAgICdjYXBhYmlsaXR5LWluZGV4LnlhbWwnXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2FkIGFuZCBwYXJzZSBjYXBhYmlsaXR5IGluZGV4IGZyb20gZmlsZXN5c3RlbVxuICAgKiBVc2VzIDYwLXNlY29uZCBjYWNoZSB0byBhdm9pZCBleGNlc3NpdmUgZmlsZSByZWFkc1xuICAgKlxuICAgKiBAcmV0dXJucyBQYXJzZWQgY2FwYWJpbGl0eSBpbmRleFxuICAgKiBAdGhyb3dzIEVycm9yIGlmIGZpbGUgY2Fubm90IGJlIHJlYWQgb3IgcGFyc2VkXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGxvYWRDYXBhYmlsaXR5SW5kZXgoKTogUHJvbWlzZTxDYXBhYmlsaXR5SW5kZXg+IHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuXG4gICAgLy8gUmV0dXJuIGNhY2hlZCB2ZXJzaW9uIGlmIHN0aWxsIHZhbGlkXG4gICAgaWYgKHRoaXMuY2FjaGVkSW5kZXggJiYgKG5vdyAtIHRoaXMuY2FjaGVUaW1lc3RhbXApIDwgdGhpcy5DQUNIRV9UVEwpIHtcbiAgICAgIHJldHVybiB0aGlzLmNhY2hlZEluZGV4O1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICAvLyBDaGVjayBpZiBmaWxlIGV4aXN0c1xuICAgICAgY29uc3QgZmlsZUV4aXN0cyA9IGF3YWl0IHRoaXMuZmlsZU9wZXJhdGlvbnMuZXhpc3RzKHRoaXMuY2FwYWJpbGl0eUluZGV4UGF0aCk7XG4gICAgICBpZiAoIWZpbGVFeGlzdHMpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYXBhYmlsaXR5IGluZGV4IG5vdCBmb3VuZCBhdCAke3RoaXMuY2FwYWJpbGl0eUluZGV4UGF0aH1gKTtcbiAgICAgIH1cblxuICAgICAgLy8gUmVhZCBhbmQgcGFyc2UgWUFNTCB3aXRoIHNhZmUgc2NoZW1hIHRvIHByZXZlbnQgY29kZSBleGVjdXRpb25cbiAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCB0aGlzLmZpbGVPcGVyYXRpb25zLnJlYWRGaWxlKHRoaXMuY2FwYWJpbGl0eUluZGV4UGF0aCwge1xuICAgICAgICBzb3VyY2U6ICdDYXBhYmlsaXR5SW5kZXhSZXNvdXJjZS5sb2FkQ2FwYWJpbGl0eUluZGV4J1xuICAgICAgfSk7XG4gICAgICBjb25zdCBwYXJzZWQgPSB5YW1sLmxvYWQoY29udGVudCwgeyBzY2hlbWE6IHlhbWwuRkFJTFNBRkVfU0NIRU1BIH0pIGFzIENhcGFiaWxpdHlJbmRleDtcblxuICAgICAgLy8gQ2FjaGUgdGhlIHJlc3VsdFxuICAgICAgdGhpcy5jYWNoZWRJbmRleCA9IHBhcnNlZDtcbiAgICAgIHRoaXMuY2FjaGVUaW1lc3RhbXAgPSBub3c7XG5cbiAgICAgIGxvZ2dlci5pbmZvKGBMb2FkZWQgY2FwYWJpbGl0eSBpbmRleDogJHtwYXJzZWQubWV0YWRhdGEudG90YWxfZWxlbWVudHN9IGVsZW1lbnRzYCk7XG5cbiAgICAgIHJldHVybiBwYXJzZWQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKTtcbiAgICAgIGxvZ2dlci5lcnJvcihgRmFpbGVkIHRvIGxvYWQgY2FwYWJpbGl0eSBpbmRleDogJHtlcnJvck1lc3NhZ2V9YCk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENhcGFiaWxpdHkgaW5kZXggbm90IGF2YWlsYWJsZTogJHtlcnJvck1lc3NhZ2V9YCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIHN1bW1hcnkgdmVyc2lvbiBvZiBjYXBhYmlsaXR5IGluZGV4IChtZXRhZGF0YSArIGFjdGlvbl90cmlnZ2VycyBvbmx5KVxuICAgKiBFc3RpbWF0ZWQ6IDIsNTAwLTMsNTAwIHRva2Vuc1xuICAgKlxuICAgKiBAcmV0dXJucyBZQU1MIHN0cmluZyB3aXRoIGhlYWRlciBhbmQgc3VtbWFyeSBjb250ZW50XG4gICAqL1xuICBhc3luYyBnZW5lcmF0ZVN1bW1hcnkoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBpbmRleCA9IGF3YWl0IHRoaXMubG9hZENhcGFiaWxpdHlJbmRleCgpO1xuXG4gICAgY29uc3Qgc3VtbWFyeSA9IHtcbiAgICAgIG1ldGFkYXRhOiBpbmRleC5tZXRhZGF0YSxcbiAgICAgIGFjdGlvbl90cmlnZ2VyczogaW5kZXguYWN0aW9uX3RyaWdnZXJzXG4gICAgfTtcblxuICAgIC8vIENvbnZlcnQgdG8gWUFNTCBmb3IgcmVhZGFiaWxpdHlcbiAgICBjb25zdCB5YW1sQ29udGVudCA9IHlhbWwuZHVtcChzdW1tYXJ5LCB7XG4gICAgICBpbmRlbnQ6IDIsXG4gICAgICBsaW5lV2lkdGg6IDEyMCxcbiAgICAgIG5vUmVmczogdHJ1ZVxuICAgIH0pO1xuXG4gICAgLy8gQWRkIGhlYWRlciBjb21tZW50XG4gICAgY29uc3QgaGVhZGVyID0gYCMgQ2FwYWJpbGl0eSBJbmRleCBTdW1tYXJ5XG4jIFRoaXMgaXMgYSBsaWdodHdlaWdodCBzdW1tYXJ5IG9mIHRoZSBjYXBhYmlsaXR5IGluZGV4IGZvciBMTE0gY29udGV4dCBpbmplY3Rpb24uXG4jIENvbnRhaW5zIGFjdGlvbiB2ZXJiIOKGkiBlbGVtZW50IG1hcHBpbmdzIGZvciBxdWljayB0b29sIHNlbGVjdGlvbiBndWlkYW5jZS5cbiMgRnVsbCBpbmRleCBhdmFpbGFibGUgYXQ6IGRvbGxob3VzZTovL2NhcGFiaWxpdHktaW5kZXgvZnVsbFxuIyBUb3RhbCBlbGVtZW50czogJHtpbmRleC5tZXRhZGF0YS50b3RhbF9lbGVtZW50c31cblxuYDtcblxuICAgIHJldHVybiBoZWFkZXIgKyB5YW1sQ29udGVudDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBmdWxsIGNhcGFiaWxpdHkgaW5kZXhcbiAgICogRXN0aW1hdGVkOiAzNSwwMDAtNDUsMDAwIHRva2Vuc1xuICAgKlxuICAgKiBAcmV0dXJucyBZQU1MIHN0cmluZyB3aXRoIGhlYWRlciBhbmQgZnVsbCBpbmRleCBjb250ZW50XG4gICAqL1xuICBhc3luYyBnZW5lcmF0ZUZ1bGwoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBpbmRleCA9IGF3YWl0IHRoaXMubG9hZENhcGFiaWxpdHlJbmRleCgpO1xuXG4gICAgLy8gQ29udmVydCB0byBZQU1MIGZvciByZWFkYWJpbGl0eVxuICAgIGNvbnN0IHlhbWxDb250ZW50ID0geWFtbC5kdW1wKGluZGV4LCB7XG4gICAgICBpbmRlbnQ6IDIsXG4gICAgICBsaW5lV2lkdGg6IDEyMCxcbiAgICAgIG5vUmVmczogdHJ1ZVxuICAgIH0pO1xuXG4gICAgLy8gQWRkIGhlYWRlciBjb21tZW50XG4gICAgY29uc3QgaGVhZGVyID0gYCMgQ2FwYWJpbGl0eSBJbmRleCAoRnVsbClcbiMgQ29tcGxldGUgY2FwYWJpbGl0eSBpbmRleCBpbmNsdWRpbmcgYWxsIGVsZW1lbnQgZGV0YWlscywgcmVsYXRpb25zaGlwcywgYW5kIHNlbWFudGljIGRhdGEuXG4jIFRoaXMgaXMgYSBsYXJnZSByZXNvdXJjZSAofjM1LTQ1SyB0b2tlbnMpIC0gdXNlIG9ubHkgd2l0aCBsYXJnZSBjb250ZXh0IG1vZGVscy5cbiMgU3VtbWFyeSB2ZXJzaW9uIGF2YWlsYWJsZSBhdDogZG9sbGhvdXNlOi8vY2FwYWJpbGl0eS1pbmRleC9zdW1tYXJ5XG4jIFRvdGFsIGVsZW1lbnRzOiAke2luZGV4Lm1ldGFkYXRhLnRvdGFsX2VsZW1lbnRzfVxuXG5gO1xuXG4gICAgcmV0dXJuIGhlYWRlciArIHlhbWxDb250ZW50O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBzdGF0aXN0aWNzIGFib3V0IHRoZSBjYXBhYmlsaXR5IGluZGV4IGZvciBtZWFzdXJlbWVudFxuICAgKiBQcm92aWRlcyBzaXplIG1ldHJpY3MgYW5kIHJvdWdoIHRva2VuIGVzdGltYXRlcyB1c2luZzpcbiAgICogKGNoYXJzLzQgKyB3b3JkcyoxLjMpLzIgZm9ybXVsYVxuICAgKlxuICAgKiBAcmV0dXJucyBTdGF0aXN0aWNzIG9iamVjdCB3aXRoIHNpemUgYW5kIHRva2VuIGVzdGltYXRlc1xuICAgKi9cbiAgYXN5bmMgZ2V0U3RhdGlzdGljcygpOiBQcm9taXNlPENhcGFiaWxpdHlJbmRleFN0YXRpc3RpY3M+IHtcbiAgICBjb25zdCBzdW1tYXJ5ID0gYXdhaXQgdGhpcy5nZW5lcmF0ZVN1bW1hcnkoKTtcbiAgICBjb25zdCBmdWxsID0gYXdhaXQgdGhpcy5nZW5lcmF0ZUZ1bGwoKTtcblxuICAgIHJldHVybiB7XG4gICAgICBzdW1tYXJ5U2l6ZTogc3VtbWFyeS5sZW5ndGgsXG4gICAgICBzdW1tYXJ5V29yZHM6IHN1bW1hcnkuc3BsaXQoL1xccysvKS5sZW5ndGgsXG4gICAgICBzdW1tYXJ5TGluZXM6IHN1bW1hcnkuc3BsaXQoJ1xcbicpLmxlbmd0aCxcbiAgICAgIGZ1bGxTaXplOiBmdWxsLmxlbmd0aCxcbiAgICAgIGZ1bGxXb3JkczogZnVsbC5zcGxpdCgvXFxzKy8pLmxlbmd0aCxcbiAgICAgIGZ1bGxMaW5lczogZnVsbC5zcGxpdCgnXFxuJykubGVuZ3RoLFxuICAgICAgLy8gUm91Z2ggdG9rZW4gZXN0aW1hdGVzIChjaGFycy80ICsgd29yZHMqMS4zKS8yXG4gICAgICBlc3RpbWF0ZWRTdW1tYXJ5VG9rZW5zOiBNYXRoLnJvdW5kKChzdW1tYXJ5Lmxlbmd0aCAvIDQgKyBzdW1tYXJ5LnNwbGl0KC9cXHMrLykubGVuZ3RoICogMS4zKSAvIDIpLFxuICAgICAgZXN0aW1hdGVkRnVsbFRva2VuczogTWF0aC5yb3VuZCgoZnVsbC5sZW5ndGggLyA0ICsgZnVsbC5zcGxpdCgvXFxzKy8pLmxlbmd0aCAqIDEuMykgLyAyKVxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogTUNQIFJlc291cmNlIEhhbmRsZXI6IExpc3QgYXZhaWxhYmxlIHJlc291cmNlc1xuICAgKlxuICAgKiBSZXR1cm5zIHRocmVlIHJlc291cmNlczpcbiAgICogLSBzdW1tYXJ5OiBMaWdodHdlaWdodCBpbmRleCAofjIuNS0zLjVLIHRva2VucylcbiAgICogLSBmdWxsOiBDb21wbGV0ZSBpbmRleCAofjM1LTQ1SyB0b2tlbnMpXG4gICAqIC0gc3RhdHM6IFNpemUgYW5kIHRva2VuIG1ldHJpY3MgKEpTT04pXG4gICAqXG4gICAqIEByZXR1cm5zIFJlc291cmNlIGxpc3Qgd2l0aCBVUklzLCBuYW1lcywgZGVzY3JpcHRpb25zLCBhbmQgTUlNRSB0eXBlc1xuICAgKi9cbiAgYXN5bmMgbGlzdFJlc291cmNlcygpOiBQcm9taXNlPE1DUFJlc291cmNlTGlzdFJlc3BvbnNlPiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHJlc291cmNlczogW1xuICAgICAgICB7XG4gICAgICAgICAgdXJpOiAnZG9sbGhvdXNlOi8vY2FwYWJpbGl0eS1pbmRleC9zdW1tYXJ5JyxcbiAgICAgICAgICBuYW1lOiAnQ2FwYWJpbGl0eSBJbmRleCBTdW1tYXJ5JyxcbiAgICAgICAgICBkZXNjcmlwdGlvbjogJ0xpZ2h0d2VpZ2h0IGNhcGFiaWxpdHkgaW5kZXggd2l0aCBhY3Rpb24gdmVyYiDihpIgZWxlbWVudCBtYXBwaW5ncy4gRXN0aW1hdGVkIH4yLjUtMy41SyB0b2tlbnMuIFJlY29tbWVuZGVkIGZvciBtb2RlbHMgd2l0aCAyMDBLKyBjb250ZXh0LicsXG4gICAgICAgICAgbWltZVR5cGU6ICd0ZXh0L3lhbWwnXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICB1cmk6ICdkb2xsaG91c2U6Ly9jYXBhYmlsaXR5LWluZGV4L2Z1bGwnLFxuICAgICAgICAgIG5hbWU6ICdDYXBhYmlsaXR5IEluZGV4IChGdWxsKScsXG4gICAgICAgICAgZGVzY3JpcHRpb246ICdDb21wbGV0ZSBjYXBhYmlsaXR5IGluZGV4IHdpdGggYWxsIGVsZW1lbnQgZGV0YWlscywgcmVsYXRpb25zaGlwcywgYW5kIHNlbWFudGljIGRhdGEuIEVzdGltYXRlZCB+MzUtNDVLIHRva2Vucy4gUmVjb21tZW5kZWQgZm9yIG1vZGVscyB3aXRoIDUwMEsrIGNvbnRleHQuJyxcbiAgICAgICAgICBtaW1lVHlwZTogJ3RleHQveWFtbCdcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIHVyaTogJ2RvbGxob3VzZTovL2NhcGFiaWxpdHktaW5kZXgvc3RhdHMnLFxuICAgICAgICAgIG5hbWU6ICdDYXBhYmlsaXR5IEluZGV4IFN0YXRpc3RpY3MnLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiAnTWVhc3VyZW1lbnQgZGF0YSBhYm91dCBjYXBhYmlsaXR5IGluZGV4IHNpemUgYW5kIHRva2VuIGVzdGltYXRlcy4nLFxuICAgICAgICAgIG1pbWVUeXBlOiAnYXBwbGljYXRpb24vanNvbidcbiAgICAgICAgfVxuICAgICAgXVxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogTUNQIFJlc291cmNlIEhhbmRsZXI6IFJlYWQgYSBzcGVjaWZpYyByZXNvdXJjZVxuICAgKlxuICAgKiBAcGFyYW0gdXJpIC0gUmVzb3VyY2UgVVJJIHRvIHJlYWQgKG11c3QgbWF0Y2ggb25lIGZyb20gbGlzdFJlc291cmNlcylcbiAgICogQHJldHVybnMgUmVzb3VyY2UgY29udGVudCB3aXRoIFVSSSwgTUlNRSB0eXBlLCBhbmQgdGV4dFxuICAgKiBAdGhyb3dzIEVycm9yIGlmIFVSSSBpcyBub3QgcmVjb2duaXplZFxuICAgKi9cbiAgYXN5bmMgcmVhZFJlc291cmNlKHVyaTogc3RyaW5nKTogUHJvbWlzZTxNQ1BSZXNvdXJjZVJlYWRSZXNwb25zZT4ge1xuICAgIGxldCBjb250ZW50OiBzdHJpbmc7XG4gICAgbGV0IG1pbWVUeXBlOiBzdHJpbmc7XG5cbiAgICBzd2l0Y2ggKHVyaSkge1xuICAgICAgY2FzZSAnZG9sbGhvdXNlOi8vY2FwYWJpbGl0eS1pbmRleC9zdW1tYXJ5JzpcbiAgICAgICAgY29udGVudCA9IGF3YWl0IHRoaXMuZ2VuZXJhdGVTdW1tYXJ5KCk7XG4gICAgICAgIG1pbWVUeXBlID0gJ3RleHQveWFtbCc7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICdkb2xsaG91c2U6Ly9jYXBhYmlsaXR5LWluZGV4L2Z1bGwnOlxuICAgICAgICBjb250ZW50ID0gYXdhaXQgdGhpcy5nZW5lcmF0ZUZ1bGwoKTtcbiAgICAgICAgbWltZVR5cGUgPSAndGV4dC95YW1sJztcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJ2RvbGxob3VzZTovL2NhcGFiaWxpdHktaW5kZXgvc3RhdHMnOiB7XG4gICAgICAgIC8vIEZJWDogV3JhcHBlZCBsZXhpY2FsIGRlY2xhcmF0aW9uIGluIGN1cmx5IGJyYWNlc1xuICAgICAgICAvLyBQcmV2aW91c2x5OiBjb25zdCBkZWNsYXJhdGlvbiBpbiBjYXNlIGJsb2NrIHdpdGhvdXQgYnJhY2VzXG4gICAgICAgIC8vIE5vdzogUHJvcGVybHkgc2NvcGVkIHdpdGggYmxvY2sgc3RhdGVtZW50XG4gICAgICAgIGNvbnN0IHN0YXRzID0gYXdhaXQgdGhpcy5nZXRTdGF0aXN0aWNzKCk7XG4gICAgICAgIGNvbnRlbnQgPSBKU09OLnN0cmluZ2lmeShzdGF0cywgbnVsbCwgMik7XG4gICAgICAgIG1pbWVUeXBlID0gJ2FwcGxpY2F0aW9uL2pzb24nO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIGNhcGFiaWxpdHkgaW5kZXggcmVzb3VyY2U6ICR7dXJpfWApO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBjb250ZW50czogW1xuICAgICAgICB7XG4gICAgICAgICAgdXJpLFxuICAgICAgICAgIG1pbWVUeXBlLFxuICAgICAgICAgIHRleHQ6IGNvbnRlbnRcbiAgICAgICAgfVxuICAgICAgXVxuICAgIH07XG4gIH1cbn1cbiJdfQ==