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.

341 lines 47 kB
/** * Persona import functionality with validation */ import * as path from 'path'; import { SecureYamlParser } from '../../security/secureYamlParser.js'; import { ContentValidator } from '../../security/contentValidator.js'; import { validateFilename, validatePath, validateContentSize } from '../../security/InputValidator.js'; import { UnicodeValidator } from '../../security/validators/unicodeValidator.js'; import { generateUniqueId } from '../../utils/filesystem.js'; import { logger } from '../../utils/logger.js'; import matter from 'gray-matter'; export class PersonaImporter { getCurrentUser; fileOperations; constructor(_personasDir, currentUser, _fileLockManager, fileOperations) { if (typeof currentUser === 'function') { this.getCurrentUser = currentUser; } else { this.getCurrentUser = () => currentUser; } this.fileOperations = fileOperations; } /** * Import a persona from various sources */ async importPersona(source, existingPersonas, overwrite = false) { try { // Determine source type let personaData = null; // Check if it's a file path if (source.startsWith('/') || source.startsWith('./') || source.endsWith('.md') || source.endsWith('.json')) { personaData = await this.importFromFile(source); } // Check if it's base64 encoded else if (this.isBase64(source)) { personaData = await this.importFromBase64(source); } // Try parsing as JSON directly else { try { const parsed = JSON.parse(source); if (this.isExportBundle(parsed)) { return this.importBundle(parsed, existingPersonas, overwrite); } else if (this.isExportedPersona(parsed)) { personaData = parsed; } } catch { // Not JSON, might be raw markdown return this.importFromMarkdown(source, existingPersonas, overwrite); } } if (!personaData) { return { success: false, message: "Could not parse import source. Please provide a file path, JSON string, or base64 encoded data." }; } // Validate and create persona return await this.createPersonaFromExport(personaData, existingPersonas, overwrite); } catch (error) { logger.error('Import error', error); return { success: false, message: `Import failed: ${error instanceof Error ? error.message : String(error)}` }; } } /** * Import from file path */ async importFromFile(filePath) { try { // Validate path const validatedPath = validatePath(filePath); const content = await this.fileOperations.readFile(validatedPath, { source: 'PersonaImporter.importFromFile' }); if (filePath.endsWith('.json')) { const parsed = JSON.parse(content); if (this.isExportedPersona(parsed)) { return parsed; } else if (this.isExportBundle(parsed)) { throw new Error("This is a bundle file. It will be imported as multiple personas."); } } else if (filePath.endsWith('.md')) { // Parse markdown file const { data, content: mdContent } = SecureYamlParser.safeMatter(content); const filename = path.basename(filePath); return { metadata: data, content: mdContent, filename: filename, exportedAt: new Date().toISOString() }; } } catch (error) { logger.error('File import error', error); throw error; } return null; } /** * Import from base64 string */ async importFromBase64(base64) { try { const json = Buffer.from(base64, 'base64').toString('utf-8'); const parsed = JSON.parse(json); if (this.isExportedPersona(parsed)) { return parsed; } else if (this.isExportBundle(parsed)) { throw new Error("This is a bundle. It will be imported as multiple personas."); } } catch (error) { logger.error('Base64 import error', error); } return null; } /** * Import from raw markdown content */ async importFromMarkdown(content, existingPersonas, overwrite) { try { // Validate content size validateContentSize(content, 100 * 1024); // 100KB limit // Try to parse as markdown with frontmatter const { data, content: mdContent } = SecureYamlParser.safeMatter(content); if (!data.name || !data.description) { return { success: false, message: "Invalid persona format. Must include name and description in YAML frontmatter." }; } const metadata = data; const filename = `${metadata.name.toLowerCase().replaceAll(/\s+/g, '-')}.md`; const exportedPersona = { metadata, content: mdContent, filename, exportedAt: new Date().toISOString(), exportedBy: this.getCurrentUser() || undefined }; return await this.createPersonaFromExport(exportedPersona, existingPersonas, overwrite); } catch (error) { return { success: false, message: `Failed to parse markdown: ${error instanceof Error ? error.message : String(error)}` }; } } /** * Import a bundle of personas */ async importBundle(bundle, existingPersonas, overwrite) { const results = { success: true, imported: [], failed: [], conflicts: [] }; for (const personaData of bundle.personas) { const result = await this.createPersonaFromExport(personaData, existingPersonas, overwrite); if (result.success) { results.imported.push(personaData.metadata.name); } else { results.failed.push(`${personaData.metadata.name}: ${result.message}`); if (result.conflicts) { results.conflicts.push(...result.conflicts); } } } return { success: results.failed.length === 0, message: this.formatBundleImportResult(results), conflicts: results.conflicts.length > 0 ? results.conflicts : undefined }; } /** * Create persona from exported data */ async createPersonaFromExport(exportData, existingPersonas, overwrite) { try { // Validate metadata const metadata = await this.validateAndEnrichMetadata(exportData.metadata); // Validate and normalize Unicode content first const unicodeResult = UnicodeValidator.normalize(exportData.content); if (unicodeResult.severity === 'critical') { throw new Error(`Critical Unicode security threat detected: ${unicodeResult.detectedIssues?.join(', ')}`); } const unicodeNormalizedContent = unicodeResult.normalizedContent; // Then validate content for other security threats const validationResult = ContentValidator.validateAndSanitize(unicodeNormalizedContent); if (!validationResult.isValid && validationResult.severity === 'critical') { throw new Error(`Critical security threat detected: ${validationResult.detectedPatterns?.join(', ')}`); } const sanitizedContent = validationResult.sanitizedContent || unicodeNormalizedContent; // Generate safe filename let filename = validateFilename(exportData.filename || `${metadata.name.toLowerCase().replaceAll(/\s+/g, '-')}.md`); // Check for conflicts const conflicts = this.findConflicts(metadata.name, filename, existingPersonas); if (conflicts.length > 0 && !overwrite) { return { success: false, message: `Persona already exists: ${conflicts.join(', ')}. Use overwrite=true to replace.`, conflicts }; } // Fix #917: Restore instructions from export data so they survive the round-trip. // Instructions are placed on metadata so PersonaManager.createElement() picks them up // via the v2 format path (instructions from metadata, body as content). if (exportData.instructions) { metadata.instructions = exportData.instructions; } // Create persona object const persona = { id: metadata.unique_id, type: 'persona', // ElementType.PERSONA version: metadata.version || '1.0', metadata, instructions: exportData.instructions || '', // Fix #917: Preserve instructions content: sanitizedContent, filename, unique_id: metadata.unique_id }; return { success: true, message: `Successfully imported "${metadata.name}"`, persona, filename }; } catch (error) { logger.error('Create persona error', error); return { success: false, message: `Failed to create persona: ${error instanceof Error ? error.message : String(error)}` }; } } /** * Validate and enrich metadata */ async validateAndEnrichMetadata(metadata) { // Ensure required fields if (!metadata.name || !metadata.description) { throw new Error("Missing required fields: name and description"); } // Validate and normalize Unicode in metadata fields const nameResult = UnicodeValidator.normalize(metadata.name); const descResult = UnicodeValidator.normalize(metadata.description); if (nameResult.severity === 'critical') { throw new Error(`Critical Unicode security threat in persona name: ${nameResult.detectedIssues?.join(', ')}`); } if (descResult.severity === 'critical') { throw new Error(`Critical Unicode security threat in persona description: ${descResult.detectedIssues?.join(', ')}`); } // Use normalized values metadata.name = nameResult.normalizedContent; metadata.description = descResult.normalizedContent; // Generate unique_id if missing if (!metadata.unique_id) { metadata.unique_id = generateUniqueId(metadata.name, this.getCurrentUser() || 'imported'); } // Set defaults metadata.version = metadata.version || '1.0'; const currentUser = this.getCurrentUser(); metadata.author = metadata.author || currentUser || 'imported'; metadata.category = metadata.category || 'custom'; metadata.created_date = metadata.created_date || new Date().toISOString(); // Validate with YAML parser for security using normalized metadata const validated = await SecureYamlParser.parse(matter.stringify('', metadata)); return validated.data; } /** * Find conflicts with existing personas */ findConflicts(name, filename, existingPersonas) { const conflicts = []; for (const [key, persona] of existingPersonas) { if (persona.metadata.name === name || persona.filename === filename) { conflicts.push(key); } } return conflicts; } /** * Check if string is base64 */ isBase64(str) { // Check length is multiple of 4 if (str.length % 4 !== 0) return false; // SECURITY FIX: Ensure base64 string is not empty // Previously: /^[A-Za-z0-9+/]*={0,2}$/ allowed empty strings // Now: Require at least one character before optional padding return /^[A-Za-z0-9+/]+={0,2}$/.test(str); } /** * Type guard for ExportedPersona */ isExportedPersona(obj) { return obj && typeof obj.metadata === 'object' && typeof obj.content === 'string' && typeof obj.filename === 'string'; } /** * Type guard for ExportBundle */ isExportBundle(obj) { return obj && typeof obj.version === 'string' && Array.isArray(obj.personas) && typeof obj.personaCount === 'number'; } /** * Format bundle import results */ formatBundleImportResult(results) { let message = `Bundle Import Summary:\n`; message += `✅ Successfully imported: ${results.imported.length} personas\n`; if (results.imported.length > 0) { message += `Imported:\n${results.imported.map((n) => ` - ${n}`).join('\n')}\n`; } if (results.failed.length > 0) { message += `\n❌ Failed: ${results.failed.length} personas\n`; message += `Errors:\n${results.failed.map((e) => ` - ${e}`).join('\n')}`; } return message; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVyc29uYUltcG9ydGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3BlcnNvbmEvZXhwb3J0LWltcG9ydC9QZXJzb25hSW1wb3J0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUc3QixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUN0RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUN0RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsWUFBWSxFQUFFLG1CQUFtQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDdkcsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sK0NBQStDLENBQUM7QUFDakYsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDN0QsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQy9DLE9BQU8sTUFBTSxNQUFNLGFBQWEsQ0FBQztBQW9CakMsTUFBTSxPQUFPLGVBQWU7SUFDVCxjQUFjLENBQXNCO0lBQ3BDLGNBQWMsQ0FBeUI7SUFFeEQsWUFDRSxZQUFvQixFQUNwQixXQUFnRCxFQUNoRCxnQkFBMEIsRUFDMUIsY0FBdUM7UUFFdkMsSUFBSSxPQUFPLFdBQVcsS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUN0QyxJQUFJLENBQUMsY0FBYyxHQUFHLFdBQWtDLENBQUM7UUFDM0QsQ0FBQzthQUFNLENBQUM7WUFDTixJQUFJLENBQUMsY0FBYyxHQUFHLEdBQUcsRUFBRSxDQUFDLFdBQVcsQ0FBQztRQUMxQyxDQUFDO1FBQ0QsSUFBSSxDQUFDLGNBQWMsR0FBRyxjQUFlLENBQUM7SUFDeEMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLGFBQWEsQ0FBQyxNQUFjLEVBQUUsZ0JBQTRCLEVBQUUsU0FBUyxHQUFHLEtB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Q0FBQztJQUN6QyxDQUFDO0lBRUQ7O09BRUc7SUFDSyx3QkFBd0IsQ0FBQyxPQUFZO1FBQzNDLElBQUksT0FBTyxHQUFHLDBCQUEwQixDQUFDO1FBQ3pDLE9BQU8sSUFBSSw0QkFBNEIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLGFBQWEsQ0FBQztRQUU1RSxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ2hDLE9BQU8sSUFBSSxjQUFjLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBUyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7UUFDMUYsQ0FBQztRQUVELElBQUksT0FBTyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDOUIsT0FBTyxJQUFJLGVBQWUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxNQUFNLGFBQWEsQ0FBQztZQUM3RCxPQUFPLElBQUksWUFBWSxPQUFPLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQVMsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ3BGLENBQUM7UUFFRCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFBlcnNvbmEgaW1wb3J0IGZ1bmN0aW9uYWxpdHkgd2l0aCB2YWxpZGF0aW9uXG4gKi9cblxuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IFBlcnNvbmEsIFBlcnNvbmFNZXRhZGF0YSB9IGZyb20gJy4uLy4uL3R5cGVzL3BlcnNvbmEuanMnO1xuaW1wb3J0IHsgRXhwb3J0ZWRQZXJzb25hLCBFeHBvcnRCdW5kbGUgfSBmcm9tICcuL1BlcnNvbmFFeHBvcnRlci5qcyc7XG5pbXBvcnQgeyBTZWN1cmVZYW1sUGFyc2VyIH0gZnJvbSAnLi4vLi4vc2VjdXJpdHkvc2VjdXJlWWFtbFBhcnNlci5qcyc7XG5pbXBvcnQgeyBDb250ZW50VmFsaWRhdG9yIH0gZnJvbSAnLi4vLi4vc2VjdXJpdHkvY29udGVudFZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyB2YWxpZGF0ZUZpbGVuYW1lLCB2YWxpZGF0ZVBhdGgsIHZhbGlkYXRlQ29udGVudFNpemUgfSBmcm9tICcuLi8uLi9zZWN1cml0eS9JbnB1dFZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBVbmljb2RlVmFsaWRhdG9yIH0gZnJvbSAnLi4vLi4vc2VjdXJpdHkvdmFsaWRhdG9ycy91bmljb2RlVmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IGdlbmVyYXRlVW5pcXVlSWQgfSBmcm9tICcuLi8uLi91dGlscy9maWxlc3lzdGVtLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uLy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQgbWF0dGVyIGZyb20gJ2dyYXktbWF0dGVyJztcbmltcG9ydCB7IElGaWxlT3BlcmF0aW9uc1NlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9GaWxlT3BlcmF0aW9uc1NlcnZpY2UuanMnO1xuXG4vLyBNYXAtbGlrZSBpbnRlcmZhY2UgZm9yIGV4aXN0aW5nIHBlcnNvbmFzIGxvb2t1cFxudHlwZSBQZXJzb25hTWFwID0gTWFwPHN0cmluZywgUGVyc29uYT4gfCB7XG4gIGhhczogKGtleTogc3RyaW5nKSA9PiBib29sZWFuO1xuICBrZXlzOiAoKSA9PiBJdGVyYWJsZTxzdHJpbmc+O1xuICBbU3ltYm9sLml0ZXJhdG9yXTogKCkgPT4gSXRlcmF0b3I8W3N0cmluZywgUGVyc29uYV0+O1xufTtcblxuZXhwb3J0IGludGVyZmFjZSBJbXBvcnRSZXN1bHQge1xuICBzdWNjZXNzOiBib29sZWFuO1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIHBlcnNvbmE/OiBQZXJzb25hO1xuICBmaWxlbmFtZT86IHN0cmluZztcbiAgY29uZmxpY3RzPzogc3RyaW5nW107XG59XG5cbnR5cGUgQ3VycmVudFVzZXJQcm92aWRlciA9ICgpID0+IHN0cmluZyB8IG51bGw7XG5cbmV4cG9ydCBjbGFzcyBQZXJzb25hSW1wb3J0ZXIge1xuICBwcml2YXRlIHJlYWRvbmx5IGdldEN1cnJlbnRVc2VyOiBDdXJyZW50VXNlclByb3ZpZGVyO1xuICBwcml2YXRlIHJlYWRvbmx5IGZpbGVPcGVyYXRpb25zOiBJRmlsZU9wZXJhdGlvbnNTZXJ2aWNlO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIF9wZXJzb25hc0Rpcjogc3RyaW5nLFxuICAgIGN1cnJlbnRVc2VyOiBzdHJpbmcgfCBudWxsIHwgQ3VycmVudFVzZXJQcm92aWRlcixcbiAgICBfZmlsZUxvY2tNYW5hZ2VyPzogdW5rbm93bixcbiAgICBmaWxlT3BlcmF0aW9ucz86IElGaWxlT3BlcmF0aW9uc1NlcnZpY2VcbiAgKSB7XG4gICAgaWYgKHR5cGVvZiBjdXJyZW50VXNlciA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgdGhpcy5nZXRDdXJyZW50VXNlciA9IGN1cnJlbnRVc2VyIGFzIEN1cnJlbnRVc2VyUHJvdmlkZXI7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuZ2V0Q3VycmVudFVzZXIgPSAoKSA9PiBjdXJyZW50VXNlcjtcbiAgICB9XG4gICAgdGhpcy5maWxlT3BlcmF0aW9ucyA9IGZpbGVPcGVyYXRpb25zITtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbXBvcnQgYSBwZXJzb25hIGZyb20gdmFyaW91cyBzb3VyY2VzXG4gICAqL1xuICBhc3luYyBpbXBvcnRQZXJzb25hKHNvdXJjZTogc3RyaW5nLCBleGlzdGluZ1BlcnNvbmFzOiBQZXJzb25hTWFwLCBvdmVyd3JpdGUgPSBmYWxzZSk6IFByb21pc2U8SW1wb3J0UmVzdWx0PiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIERldGVybWluZSBzb3VyY2UgdHlwZVxuICAgICAgbGV0IHBlcnNvbmFEYXRhOiBFeHBvcnRlZFBlcnNvbmEgfCBudWxsID0gbnVsbDtcblxuICAgICAgLy8gQ2hlY2sgaWYgaXQncyBhIGZpbGUgcGF0aFxuICAgICAgaWYgKHNvdXJjZS5zdGFydHNXaXRoKCcvJykgfHwgc291cmNlLnN0YXJ0c1dpdGgoJy4vJykgfHwgc291cmNlLmVuZHNXaXRoKCcubWQnKSB8fCBzb3VyY2UuZW5kc1dpdGgoJy5qc29uJykpIHtcbiAgICAgICAgcGVyc29uYURhdGEgPSBhd2FpdCB0aGlzLmltcG9ydEZyb21GaWxlKHNvdXJjZSk7XG4gICAgICB9IFxuICAgICAgLy8gQ2hlY2sgaWYgaXQncyBiYXNlNjQgZW5jb2RlZFxuICAgICAgZWxzZSBpZiAodGhpcy5pc0Jhc2U2NChzb3VyY2UpKSB7XG4gICAgICAgIHBlcnNvbmFEYXRhID0gYXdhaXQgdGhpcy5pbXBvcnRGcm9tQmFzZTY0KHNvdXJjZSk7XG4gICAgICB9XG4gICAgICAvLyBUcnkgcGFyc2luZyBhcyBKU09OIGRpcmVjdGx5XG4gICAgICBlbHNlIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCBwYXJzZWQgPSBKU09OLnBhcnNlKHNvdXJjZSk7XG4gICAgICAgICAgaWYgKHRoaXMuaXNFeHBvcnRCdW5kbGUocGFyc2VkKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuaW1wb3J0QnVuZGxlKHBhcnNlZCwgZXhpc3RpbmdQZXJzb25hcywgb3ZlcndyaXRlKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuaXNFeHBvcnRlZFBlcnNvbmEocGFyc2VkKSkge1xuICAgICAgICAgICAgcGVyc29uYURhdGEgPSBwYXJzZWQ7XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAvLyBOb3QgSlNPTiwgbWlnaHQgYmUgcmF3IG1hcmtkb3duXG4gICAgICAgICAgcmV0dXJuIHRoaXMuaW1wb3J0RnJvbU1hcmtkb3duKHNvdXJjZSwgZXhpc3RpbmdQZXJzb25hcywgb3ZlcndyaXRlKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoIXBlcnNvbmFEYXRhKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgbWVzc2FnZTogXCJDb3VsZCBub3QgcGFyc2UgaW1wb3J0IHNvdXJjZS4gUGxlYXNlIHByb3ZpZGUgYSBmaWxlIHBhdGgsIEpTT04gc3RyaW5nLCBvciBiYXNlNjQgZW5jb2RlZCBkYXRhLlwiXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIC8vIFZhbGlkYXRlIGFuZCBjcmVhdGUgcGVyc29uYVxuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuY3JlYXRlUGVyc29uYUZyb21FeHBvcnQocGVyc29uYURhdGEsIGV4aXN0aW5nUGVyc29uYXMsIG92ZXJ3cml0ZSk7XG5cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdJbXBvcnQgZXJyb3InLCBlcnJvcik7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgbWVzc2FnZTogYEltcG9ydCBmYWlsZWQ6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWBcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEltcG9ydCBmcm9tIGZpbGUgcGF0aFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBpbXBvcnRGcm9tRmlsZShmaWxlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxFeHBvcnRlZFBlcnNvbmEgfCBudWxsPiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFZhbGlkYXRlIHBhdGhcbiAgICAgIGNvbnN0IHZhbGlkYXRlZFBhdGggPSB2YWxpZGF0ZVBhdGgoZmlsZVBhdGgpO1xuICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IHRoaXMuZmlsZU9wZXJhdGlvbnMucmVhZEZpbGUodmFsaWRhdGVkUGF0aCwgeyBzb3VyY2U6ICdQZXJzb25hSW1wb3J0ZXIuaW1wb3J0RnJvbUZpbGUnIH0pO1xuXG4gICAgICBpZiAoZmlsZVBhdGguZW5kc1dpdGgoJy5qc29uJykpIHtcbiAgICAgICAgY29uc3QgcGFyc2VkID0gSlNPTi5wYXJzZShjb250ZW50KTtcbiAgICAgICAgaWYgKHRoaXMuaXNFeHBvcnRlZFBlcnNvbmEocGFyc2VkKSkge1xuICAgICAgICAgIHJldHVybiBwYXJzZWQ7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5pc0V4cG9ydEJ1bmRsZShwYXJzZWQpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVGhpcyBpcyBhIGJ1bmRsZSBmaWxlLiBJdCB3aWxsIGJlIGltcG9ydGVkIGFzIG11bHRpcGxlIHBlcnNvbmFzLlwiKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChmaWxlUGF0aC5lbmRzV2l0aCgnLm1kJykpIHtcbiAgICAgICAgLy8gUGFyc2UgbWFya2Rvd24gZmlsZVxuICAgICAgICBjb25zdCB7IGRhdGEsIGNvbnRlbnQ6IG1kQ29udGVudCB9ID0gU2VjdXJlWWFtbFBhcnNlci5zYWZlTWF0dGVyKGNvbnRlbnQpO1xuICAgICAgICBjb25zdCBmaWxlbmFtZSA9IHBhdGguYmFzZW5hbWUoZmlsZVBhdGgpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG1ldGFkYXRhOiBkYXRhIGFzIFBlcnNvbmFNZXRhZGF0YSxcbiAgICAgICAgICBjb250ZW50OiBtZENvbnRlbnQsXG4gICAgICAgICAgZmlsZW5hbWU6IGZpbGVuYW1lLFxuICAgICAgICAgIGV4cG9ydGVkQXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKVxuICAgICAgICB9O1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0ZpbGUgaW1wb3J0IGVycm9yJywgZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIEltcG9ydCBmcm9tIGJhc2U2NCBzdHJpbmdcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgaW1wb3J0RnJvbUJhc2U2NChiYXNlNjQ6IHN0cmluZyk6IFByb21pc2U8RXhwb3J0ZWRQZXJzb25hIHwgbnVsbD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBqc29uID0gQnVmZmVyLmZyb20oYmFzZTY0LCAnYmFzZTY0JykudG9TdHJpbmcoJ3V0Zi04Jyk7XG4gICAgICBjb25zdCBwYXJzZWQgPSBKU09OLnBhcnNlKGpzb24pO1xuICAgICAgXG4gICAgICBpZiAodGhpcy5pc0V4cG9ydGVkUGVyc29uYShwYXJzZWQpKSB7XG4gICAgICAgIHJldHVybiBwYXJzZWQ7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuaXNFeHBvcnRCdW5kbGUocGFyc2VkKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUaGlzIGlzIGEgYnVuZGxlLiBJdCB3aWxsIGJlIGltcG9ydGVkIGFzIG11bHRpcGxlIHBlcnNvbmFzLlwiKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdCYXNlNjQgaW1wb3J0IGVycm9yJywgZXJyb3IpO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbXBvcnQgZnJvbSByYXcgbWFya2Rvd24gY29udGVudFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBpbXBvcnRGcm9tTWFya2Rvd24oY29udGVudDogc3RyaW5nLCBleGlzdGluZ1BlcnNvbmFzOiBQZXJzb25hTWFwLCBvdmVyd3JpdGU6IGJvb2xlYW4pOiBQcm9taXNlPEltcG9ydFJlc3VsdD4ge1xuICAgIHRyeSB7XG4gICAgICAvLyBWYWxpZGF0ZSBjb250ZW50IHNpemVcbiAgICAgIHZhbGlkYXRlQ29udGVudFNpemUoY29udGVudCwgMTAwICogMTAyNCk7IC8vIDEwMEtCIGxpbWl0XG5cbiAgICAgIC8vIFRyeSB0byBwYXJzZSBhcyBtYXJrZG93biB3aXRoIGZyb250bWF0dGVyXG4gICAgICBjb25zdCB7IGRhdGEsIGNvbnRlbnQ6IG1kQ29udGVudCB9ID0gU2VjdXJlWWFtbFBhcnNlci5zYWZlTWF0dGVyKGNvbnRlbnQpO1xuICAgICAgXG4gICAgICBpZiAoIWRhdGEubmFtZSB8fCAhZGF0YS5kZXNjcmlwdGlvbikge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgIG1lc3NhZ2U6IFwiSW52YWxpZCBwZXJzb25hIGZvcm1hdC4gTXVzdCBpbmNsdWRlIG5hbWUgYW5kIGRlc2NyaXB0aW9uIGluIFlBTUwgZnJvbnRtYXR0ZXIuXCJcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbWV0YWRhdGEgPSBkYXRhIGFzIFBlcnNvbmFNZXRhZGF0YTtcbiAgICAgIGNvbnN0IGZpbGVuYW1lID0gYCR7bWV0YWRhdGEubmFtZS50b0xvd2VyQ2FzZSgpLnJlcGxhY2VBbGwoL1xccysvZywgJy0nKX0ubWRgO1xuXG4gICAgICBjb25zdCBleHBvcnRlZFBlcnNvbmE6IEV4cG9ydGVkUGVyc29uYSA9IHtcbiAgICAgICAgbWV0YWRhdGEsXG4gICAgICAgIGNvbnRlbnQ6IG1kQ29udGVudCxcbiAgICAgICAgZmlsZW5hbWUsXG4gICAgICAgIGV4cG9ydGVkQXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgICAgZXhwb3J0ZWRCeTogdGhpcy5nZXRDdXJyZW50VXNlcigpIHx8IHVuZGVmaW5lZFxuICAgICAgfTtcblxuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuY3JlYXRlUGVyc29uYUZyb21FeHBvcnQoZXhwb3J0ZWRQZXJzb25hLCBleGlzdGluZ1BlcnNvbmFzLCBvdmVyd3JpdGUpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgbWVzc2FnZTogYEZhaWxlZCB0byBwYXJzZSBtYXJrZG93bjogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSW1wb3J0IGEgYnVuZGxlIG9mIHBlcnNvbmFzXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGltcG9ydEJ1bmRsZShidW5kbGU6IEV4cG9ydEJ1bmRsZSwgZXhpc3RpbmdQZXJzb25hczogUGVyc29uYU1hcCwgb3ZlcndyaXRlOiBib29sZWFuKTogUHJvbWlzZTxJbXBvcnRSZXN1bHQ+IHtcbiAgICBjb25zdCByZXN1bHRzID0ge1xuICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgIGltcG9ydGVkOiBbXSBhcyBzdHJpbmdbXSxcbiAgICAgIGZhaWxlZDogW10gYXMgc3RyaW5nW10sXG4gICAgICBjb25mbGljdHM6IFtdIGFzIHN0cmluZ1tdXG4gICAgfTtcblxuICAgIGZvciAoY29uc3QgcGVyc29uYURhdGEgb2YgYnVuZGxlLnBlcnNvbmFzKSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLmNyZWF0ZVBlcnNvbmFGcm9tRXhwb3J0KHBlcnNvbmFEYXRhLCBleGlzdGluZ1BlcnNvbmFzLCBvdmVyd3JpdGUpO1xuICAgICAgXG4gICAgICBpZiAocmVzdWx0LnN1Y2Nlc3MpIHtcbiAgICAgICAgcmVzdWx0cy5pbXBvcnRlZC5wdXNoKHBlcnNvbmFEYXRhLm1ldGFkYXRhLm5hbWUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVzdWx0cy5mYWlsZWQucHVzaChgJHtwZXJzb25hRGF0YS5tZXRhZGF0YS5uYW1lfTogJHtyZXN1bHQubWVzc2FnZX1gKTtcbiAgICAgICAgaWYgKHJlc3VsdC5jb25mbGljdHMpIHtcbiAgICAgICAgICByZXN1bHRzLmNvbmZsaWN0cy5wdXNoKC4uLnJlc3VsdC5jb25mbGljdHMpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHN1Y2Nlc3M6IHJlc3VsdHMuZmFpbGVkLmxlbmd0aCA9PT0gMCxcbiAgICAgIG1lc3NhZ2U6IHRoaXMuZm9ybWF0QnVuZGxlSW1wb3J0UmVzdWx0KHJlc3VsdHMpLFxuICAgICAgY29uZmxpY3RzOiByZXN1bHRzLmNvbmZsaWN0cy5sZW5ndGggPiAwID8gcmVzdWx0cy5jb25mbGljdHMgOiB1bmRlZmluZWRcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBwZXJzb25hIGZyb20gZXhwb3J0ZWQgZGF0YVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjcmVhdGVQZXJzb25hRnJvbUV4cG9ydChcbiAgICBleHBvcnREYXRhOiBFeHBvcnRlZFBlcnNvbmEsXG4gICAgZXhpc3RpbmdQZXJzb25hczogUGVyc29uYU1hcCxcbiAgICBvdmVyd3JpdGU6IGJvb2xlYW5cbiAgKTogUHJvbWlzZTxJbXBvcnRSZXN1bHQ+IHtcbiAgICB0cnkge1xuICAgICAgLy8gVmFsaWRhdGUgbWV0YWRhdGFcbiAgICAgIGNvbnN0IG1ldGFkYXRhID0gYXdhaXQgdGhpcy52YWxpZGF0ZUFuZEVucmljaE1ldGFkYXRhKGV4cG9ydERhdGEubWV0YWRhdGEpO1xuICAgICAgXG4gICAgICAvLyBWYWxpZGF0ZSBhbmQgbm9ybWFsaXplIFVuaWNvZGUgY29udGVudCBmaXJzdFxuICAgICAgY29uc3QgdW5pY29kZVJlc3VsdCA9IFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKGV4cG9ydERhdGEuY29udGVudCk7XG4gICAgICBpZiAodW5pY29kZVJlc3VsdC5zZXZlcml0eSA9PT0gJ2NyaXRpY2FsJykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYENyaXRpY2FsIFVuaWNvZGUgc2VjdXJpdHkgdGhyZWF0IGRldGVjdGVkOiAke3VuaWNvZGVSZXN1bHQuZGV0ZWN0ZWRJc3N1ZXM/LmpvaW4oJywgJyl9YCk7XG4gICAgICB9XG4gICAgICBjb25zdCB1bmljb2RlTm9ybWFsaXplZENvbnRlbnQgPSB1bmljb2RlUmVzdWx0Lm5vcm1hbGl6ZWRDb250ZW50O1xuXG4gICAgICAvLyBUaGVuIHZhbGlkYXRlIGNvbnRlbnQgZm9yIG90aGVyIHNlY3VyaXR5IHRocmVhdHNcbiAgICAgIGNvbnN0IHZhbGlkYXRpb25SZXN1bHQgPSBDb250ZW50VmFsaWRhdG9yLnZhbGlkYXRlQW5kU2FuaXRpemUodW5pY29kZU5vcm1hbGl6ZWRDb250ZW50KTtcbiAgICAgIGlmICghdmFsaWRhdGlvblJlc3VsdC5pc1ZhbGlkICYmIHZhbGlkYXRpb25SZXN1bHQuc2V2ZXJpdHkgPT09ICdjcml0aWNhbCcpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDcml0aWNhbCBzZWN1cml0eSB0aHJlYXQgZGV0ZWN0ZWQ6ICR7dmFsaWRhdGlvblJlc3VsdC5kZXRlY3RlZFBhdHRlcm5zPy5qb2luKCcsICcpfWApO1xuICAgICAgfVxuICAgICAgY29uc3Qgc2FuaXRpemVkQ29udGVudCA9IHZhbGlkYXRpb25SZXN1bHQuc2FuaXRpemVkQ29udGVudCB8fCB1bmljb2RlTm9ybWFsaXplZENvbnRlbnQ7XG5cbiAgICAgIC8vIEdlbmVyYXRlIHNhZmUgZmlsZW5hbWVcbiAgICAgIGxldCBmaWxlbmFtZSA9IHZhbGlkYXRlRmlsZW5hbWUoZXhwb3J0RGF0YS5maWxlbmFtZSB8fCBgJHttZXRhZGF0YS5uYW1lLnRvTG93ZXJDYXNlKCkucmVwbGFjZUFsbCgvXFxzKy9nLCAnLScpfS5tZGApO1xuICAgICAgXG4gICAgICAvLyBDaGVjayBmb3IgY29uZmxpY3RzXG4gICAgICBjb25zdCBjb25mbGljdHMgPSB0aGlzLmZpbmRDb25mbGljdHMobWV0YWRhdGEubmFtZSwgZmlsZW5hbWUsIGV4aXN0aW5nUGVyc29uYXMpO1xuICAgICAgaWYgKGNvbmZsaWN0cy5sZW5ndGggPiAwICYmICFvdmVyd3JpdGUpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICBtZXNzYWdlOiBgUGVyc29uYSBhbHJlYWR5IGV4aXN0czogJHtjb25mbGljdHMuam9pbignLCAnKX0uIFVzZSBvdmVyd3JpdGU9dHJ1ZSB0byByZXBsYWNlLmAsXG4gICAgICAgICAgY29uZmxpY3RzXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIC8vIEZpeCAjOTE3OiBSZXN0b3JlIGluc3RydWN0aW9ucyBmcm9tIGV4cG9ydCBkYXRhIHNvIHRoZXkgc3Vydml2ZSB0aGUgcm91bmQtdHJpcC5cbiAgICAgIC8vIEluc3RydWN0aW9ucyBhcmUgcGxhY2VkIG9uIG1ldGFkYXRhIHNvIFBlcnNvbmFNYW5hZ2VyLmNyZWF0ZUVsZW1lbnQoKSBwaWNrcyB0aGVtIHVwXG4gICAgICAvLyB2aWEgdGhlIHYyIGZvcm1hdCBwYXRoIChpbnN0cnVjdGlvbnMgZnJvbSBtZXRhZGF0YSwgYm9keSBhcyBjb250ZW50KS5cbiAgICAgIGlmIChleHBvcnREYXRhLmluc3RydWN0aW9ucykge1xuICAgICAgICBtZXRhZGF0YS5pbnN0cnVjdGlvbnMgPSBleHBvcnREYXRhLmluc3RydWN0aW9ucztcbiAgICAgIH1cblxuICAgICAgLy8gQ3JlYXRlIHBlcnNvbmEgb2JqZWN0XG4gICAgICBjb25zdCBwZXJzb25hOiBQZXJzb25hID0ge1xuICAgICAgICBpZDogbWV0YWRhdGEudW5pcXVlX2lkISxcbiAgICAgICAgdHlwZTogJ3BlcnNvbmEnIGFzIGFueSwgLy8gRWxlbWVudFR5cGUuUEVSU09OQVxuICAgICAgICB2ZXJzaW9uOiBtZXRhZGF0YS52ZXJzaW9uIHx8ICcxLjAnLFxuICAgICAgICBtZXRhZGF0YSxcbiAgICAgICAgaW5zdHJ1Y3Rpb25zOiBleHBvcnREYXRhLmluc3RydWN0aW9ucyB8fCAnJywgIC8vIEZpeCAjOTE3OiBQcmVzZXJ2ZSBpbnN0cnVjdGlvbnNcbiAgICAgICAgY29udGVudDogc2FuaXRpemVkQ29udGVudCxcbiAgICAgICAgZmlsZW5hbWUsXG4gICAgICAgIHVuaXF1ZV9pZDogbWV0YWRhdGEudW5pcXVlX2lkIVxuICAgICAgfSBhcyBQZXJzb25hO1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IGltcG9ydGVkIFwiJHttZXRhZGF0YS5uYW1lfVwiYCxcbiAgICAgICAgcGVyc29uYSxcbiAgICAgICAgZmlsZW5hbWVcbiAgICAgIH07XG5cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdDcmVhdGUgcGVyc29uYSBlcnJvcicsIGVycm9yKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBtZXNzYWdlOiBgRmFpbGVkIHRvIGNyZWF0ZSBwZXJzb25hOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhbmQgZW5yaWNoIG1ldGFkYXRhXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHZhbGlkYXRlQW5kRW5yaWNoTWV0YWRhdGEobWV0YWRhdGE6IGFueSk6IFByb21pc2U8UGVyc29uYU1ldGFkYXRhPiB7XG4gICAgLy8gRW5zdXJlIHJlcXVpcmVkIGZpZWxkc1xuICAgIGlmICghbWV0YWRhdGEubmFtZSB8fCAhbWV0YWRhdGEuZGVzY3JpcHRpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIk1pc3NpbmcgcmVxdWlyZWQgZmllbGRzOiBuYW1lIGFuZCBkZXNjcmlwdGlvblwiKTtcbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSBhbmQgbm9ybWFsaXplIFVuaWNvZGUgaW4gbWV0YWRhdGEgZmllbGRzXG4gICAgY29uc3QgbmFtZVJlc3VsdCA9IFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKG1ldGFkYXRhLm5hbWUpO1xuICAgIGNvbnN0IGRlc2NSZXN1bHQgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShtZXRhZGF0YS5kZXNjcmlwdGlvbik7XG4gICAgXG4gICAgaWYgKG5hbWVSZXN1bHQuc2V2ZXJpdHkgPT09ICdjcml0aWNhbCcpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ3JpdGljYWwgVW5pY29kZSBzZWN1cml0eSB0aHJlYXQgaW4gcGVyc29uYSBuYW1lOiAke25hbWVSZXN1bHQuZGV0ZWN0ZWRJc3N1ZXM/LmpvaW4oJywgJyl9YCk7XG4gICAgfVxuICAgIGlmIChkZXNjUmVzdWx0LnNldmVyaXR5ID09PSAnY3JpdGljYWwnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENyaXRpY2FsIFVuaWNvZGUgc2VjdXJpdHkgdGhyZWF0IGluIHBlcnNvbmEgZGVzY3JpcHRpb246ICR7ZGVzY1Jlc3VsdC5kZXRlY3RlZElzc3Vlcz8uam9pbignLCAnKX1gKTtcbiAgICB9XG5cbiAgICAvLyBVc2Ugbm9ybWFsaXplZCB2YWx1ZXNcbiAgICBtZXRhZGF0YS5uYW1lID0gbmFtZVJlc3VsdC5ub3JtYWxpemVkQ29udGVudDtcbiAgICBtZXRhZGF0YS5kZXNjcmlwdGlvbiA9IGRlc2NSZXN1bHQubm9ybWFsaXplZENvbnRlbnQ7XG5cbiAgICAvLyBHZW5lcmF0ZSB1bmlxdWVfaWQgaWYgbWlzc2luZ1xuICAgIGlmICghbWV0YWRhdGEudW5pcXVlX2lkKSB7XG4gICAgICBtZXRhZGF0YS51bmlxdWVfaWQgPSBnZW5lcmF0ZVVuaXF1ZUlkKG1ldGFkYXRhLm5hbWUsIHRoaXMuZ2V0Q3VycmVudFVzZXIoKSB8fCAnaW1wb3J0ZWQnKTtcbiAgICB9XG5cbiAgICAvLyBTZXQgZGVmYXVsdHNcbiAgICBtZXRhZGF0YS52ZXJzaW9uID0gbWV0YWRhdGEudmVyc2lvbiB8fCAnMS4wJztcbiAgICBjb25zdCBjdXJyZW50VXNlciA9IHRoaXMuZ2V0Q3VycmVudFVzZXIoKTtcbiAgICBtZXRhZGF0YS5hdXRob3IgPSBtZXRhZGF0YS5hdXRob3IgfHwgY3VycmVudFVzZXIgfHwgJ2ltcG9ydGVkJztcbiAgICBtZXRhZGF0YS5jYXRlZ29yeSA9IG1ldGFkYXRhLmNhdGVnb3J5IHx8ICdjdXN0b20nO1xuICAgIG1ldGFkYXRhLmNyZWF0ZWRfZGF0ZSA9IG1ldGFkYXRhLmNyZWF0ZWRfZGF0ZSB8fCBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCk7XG5cbiAgICAvLyBWYWxpZGF0ZSB3aXRoIFlBTUwgcGFyc2VyIGZvciBzZWN1cml0eSB1c2luZyBub3JtYWxpemVkIG1ldGFkYXRhXG4gICAgY29uc3QgdmFsaWRhdGVkID0gYXdhaXQgU2VjdXJlWWFtbFBhcnNlci5wYXJzZShtYXR0ZXIuc3RyaW5naWZ5KCcnLCBtZXRhZGF0YSkpO1xuXG4gICAgcmV0dXJuIHZhbGlkYXRlZC5kYXRhIGFzIFBlcnNvbmFNZXRhZGF0YTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5kIGNvbmZsaWN0cyB3aXRoIGV4aXN0aW5nIHBlcnNvbmFzXG4gICAqL1xuICBwcml2YXRlIGZpbmRDb25mbGljdHMobmFtZTogc3RyaW5nLCBmaWxlbmFtZTogc3RyaW5nLCBleGlzdGluZ1BlcnNvbmFzOiBQZXJzb25hTWFwKTogc3RyaW5nW10ge1xuICAgIGNvbnN0IGNvbmZsaWN0czogc3RyaW5nW10gPSBbXTtcblxuICAgIGZvciAoY29uc3QgW2tleSwgcGVyc29uYV0gb2YgZXhpc3RpbmdQZXJzb25hcykge1xuICAgICAgaWYgKHBlcnNvbmEubWV0YWRhdGEubmFtZSA9PT0gbmFtZSB8fCBwZXJzb25hLmZpbGVuYW1lID09PSBmaWxlbmFtZSkge1xuICAgICAgICBjb25mbGljdHMucHVzaChrZXkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBjb25mbGljdHM7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgaWYgc3RyaW5nIGlzIGJhc2U2NFxuICAgKi9cbiAgcHJpdmF0ZSBpc0Jhc2U2NChzdHI6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIC8vIENoZWNrIGxlbmd0aCBpcyBtdWx0aXBsZSBvZiA0XG4gICAgaWYgKHN0ci5sZW5ndGggJSA0ICE9PSAwKSByZXR1cm4gZmFsc2U7XG4gICAgXG4gICAgLy8gU0VDVVJJVFkgRklYOiBFbnN1cmUgYmFzZTY0IHN0cmluZyBpcyBub3QgZW1wdHlcbiAgICAvLyBQcmV2aW91c2x5OiAvXltBLVphLXowLTkrL10qPXswLDJ9JC8gYWxsb3dlZCBlbXB0eSBzdHJpbmdzXG4gICAgLy8gTm93OiBSZXF1aXJlIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIgYmVmb3JlIG9wdGlvbmFsIHBhZGRpbmdcbiAgICByZXR1cm4gL15bQS1aYS16MC05Ky9dKz17MCwyfSQvLnRlc3Qoc3RyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUeXBlIGd1YXJkIGZvciBFeHBvcnRlZFBlcnNvbmFcbiAgICovXG4gIHByaXZhdGUgaXNFeHBvcnRlZFBlcnNvbmEob2JqOiBhbnkpOiBvYmogaXMgRXhwb3J0ZWRQZXJzb25hIHtcbiAgICByZXR1cm4gb2JqICYmIFxuICAgICAgdHlwZW9mIG9iai5tZXRhZGF0YSA9PT0gJ29iamVjdCcgJiZcbiAgICAgIHR5cGVvZiBvYmouY29udGVudCA9PT0gJ3N0cmluZycgJiZcbiAgICAgIHR5cGVvZiBvYmouZmlsZW5hbWUgPT09ICdzdHJpbmcnO1xuICB9XG5cbiAgLyoqXG4gICAqIFR5cGUgZ3VhcmQgZm9yIEV4cG9ydEJ1bmRsZVxuICAgKi9cbiAgcHJpdmF0ZSBpc0V4cG9ydEJ1bmRsZShvYmo6IGFueSk6IG9iaiBpcyBFeHBvcnRCdW5kbGUge1xuICAgIHJldHVybiBvYmogJiZcbiAgICAgIHR5cGVvZiBvYmoudmVyc2lvbiA9PT0gJ3N0cmluZycgJiZcbiAgICAgIEFycmF5LmlzQXJyYXkob2JqLnBlcnNvbmFzKSAmJlxuICAgICAgdHlwZW9mIG9iai5wZXJzb25hQ291bnQgPT09ICdudW1iZXInO1xuICB9XG5cbiAgLyoqXG4gICAqIEZvcm1hdCBidW5kbGUgaW1wb3J0IHJlc3VsdHNcbiAgICovXG4gIHByaXZhdGUgZm9ybWF0QnVuZGxlSW1wb3J0UmVzdWx0KHJlc3VsdHM6IGFueSk6IHN0cmluZyB7XG4gICAgbGV0IG1lc3NhZ2UgPSBgQnVuZGxlIEltcG9ydCBTdW1tYXJ5OlxcbmA7XG4gICAgbWVzc2FnZSArPSBg4pyFIFN1Y2Nlc3NmdWxseSBpbXBvcnRlZDogJHtyZXN1bHRzLmltcG9ydGVkLmxlbmd0aH0gcGVyc29uYXNcXG5gO1xuICAgIFxuICAgIGlmIChyZXN1bHRzLmltcG9ydGVkLmxlbmd0aCA+IDApIHtcbiAgICAgIG1lc3NhZ2UgKz0gYEltcG9ydGVkOlxcbiR7cmVzdWx0cy5pbXBvcnRlZC5tYXAoKG46IHN0cmluZykgPT4gYCAgLSAke259YCkuam9pbignXFxuJyl9XFxuYDtcbiAgICB9XG5cbiAgICBpZiAocmVzdWx0cy5mYWlsZWQubGVuZ3RoID4gMCkge1xuICAgICAgbWVzc2FnZSArPSBgXFxu4p2MIEZhaWxlZDogJHtyZXN1bHRzLmZhaWxlZC5sZW5ndGh9IHBlcnNvbmFzXFxuYDtcbiAgICAgIG1lc3NhZ2UgKz0gYEVycm9yczpcXG4ke3Jlc3VsdHMuZmFpbGVkLm1hcCgoZTogc3RyaW5nKSA9PiBgICAtICR7ZX1gKS5qb2luKCdcXG4nKX1gO1xuICAgIH1cblxuICAgIHJldHVybiBtZXNzYWdlO1xuICB9XG59XG4iXX0=