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.

511 lines 68.3 kB
/** * Verb Trigger Manager - Maps action verbs to elements * * This manager handles verb-based action triggers that map user intent * to specific elements. Uses action verbs (debug, fix, create) instead * of nouns for better intent matching. * * Key principles: * - Verbs have higher attention probability than nouns * - Multiple verbs can map to the same element * - Verbs are extracted from queries and element metadata * - Supports synonyms and related verb forms */ import { logger } from '../utils/logger.js'; import { SecurityMonitor } from '../security/securityMonitor.js'; import { UnicodeValidator } from '../security/validators/unicodeValidator.js'; /** * Verb taxonomy - Common verbs grouped by intent */ export const VERB_TAXONOMY = { // Debugging & Fixing debugging: ['debug', 'fix', 'troubleshoot', 'diagnose', 'solve', 'resolve', 'repair'], // Creating & Writing creation: ['create', 'write', 'generate', 'make', 'build', 'construct', 'compose'], // Explanation & Learning explanation: ['explain', 'teach', 'clarify', 'describe', 'simplify', 'elaborate', 'define'], // Analysis & Investigation analysis: ['analyze', 'investigate', 'examine', 'inspect', 'review', 'assess', 'evaluate'], // Memory & Recall recall: ['remember', 'recall', 'retrieve', 'find', 'locate', 'search', 'lookup'], // Execution & Running execution: ['run', 'execute', 'start', 'launch', 'activate', 'trigger', 'invoke'], // Testing & Validation testing: ['test', 'verify', 'validate', 'check', 'confirm', 'ensure', 'prove'], // Configuration & Setup configuration: ['configure', 'setup', 'install', 'initialize', 'prepare', 'arrange'], // Security & Protection security: ['secure', 'protect', 'audit', 'scan', 'encrypt', 'authenticate', 'authorize'], // Optimization & Improvement optimization: ['optimize', 'improve', 'enhance', 'refactor', 'streamline', 'accelerate'], // Documentation documentation: ['document', 'annotate', 'comment', 'record', 'note', 'log'], // Collaboration collaboration: ['share', 'collaborate', 'sync', 'merge', 'integrate', 'combine'] }; export class VerbTriggerManager { verbCache = new Map(); config; constructor(config = {}) { this.config = { confidenceThreshold: config.confidenceThreshold || 0.5, includeSynonyms: config.includeSynonyms !== false, maxElementsPerVerb: config.maxElementsPerVerb || 10, customVerbs: config.customVerbs || {} }; logger.debug('VerbTriggerManager initialized', { config: this.config }); } /** * Extract verbs from a user query */ extractVerbs(query) { // Unicode validation for security const validation = UnicodeValidator.normalize(query); if (validation.detectedIssues && validation.detectedIssues.length > 0) { SecurityMonitor.logSecurityEvent({ type: 'UNICODE_VALIDATION_ERROR', severity: 'MEDIUM', source: 'VerbTriggerManager.extractVerbs', details: `Unicode issues in query: ${validation.detectedIssues.join(', ')}` }); } const verbs = []; const normalizedQuery = validation.normalizedContent.toLowerCase(); // Check each word against our verb taxonomy const words = normalizedQuery.split(/\s+/); for (const word of words) { // Direct verb check if (this.isKnownVerb(word)) { verbs.push(word); } // Check for imperative forms (common in commands) // "debug this", "fix the error", "create a test" const imperativePatterns = [ /^(debug|fix|create|write|test|run|explain|analyze)/, /(ing)$/ // Gerunds: debugging, testing, creating ]; for (const pattern of imperativePatterns) { if (pattern.test(word) && !verbs.includes(word)) { const baseVerb = this.getBaseVerb(word); if (baseVerb) verbs.push(baseVerb); } } } // Also check for verb phrases const verbPhrases = [ 'figure out', 'work out', 'sort out', 'find out', 'set up', 'clean up', 'follow up', 'break down', 'write down', 'track down' ]; for (const phrase of verbPhrases) { if (normalizedQuery.includes(phrase)) { // Map phrases to base verbs const baseVerb = this.mapPhraseToVerb(phrase); if (baseVerb && !verbs.includes(baseVerb)) { verbs.push(baseVerb); } } } // Include custom verbs from config for (const customVerb of Object.keys(this.config.customVerbs || {})) { if (normalizedQuery.includes(customVerb) && !verbs.includes(customVerb)) { verbs.push(customVerb); } } logger.debug('Extracted verbs from query', { query, verbs }); return verbs; } /** * Check if a word is a known verb */ isKnownVerb(word) { for (const verbs of Object.values(VERB_TAXONOMY)) { if (verbs.includes(word)) return true; } return false; } /** * Get base form of a verb (remove -ing, -ed, etc.) * * Transforms verb variations back to their base form to enable flexible matching. * For example, "debugging", "debugged", "debugs" all map to "debug". */ getBaseVerb(word) { // Handle common verb endings with regex transformations const transformations = [ // Handle gerunds with doubled consonants (debugging→debug, running→run, planning→plan) // Pattern: /([bcdfghjklmnpqrstvwxyz])\1ing$/ captures doubled consonant + "ing" // Replacement: '$1' keeps only single consonant [/([bcdfghjklmnpqrstvwxyz])\1ing$/, '$1'], [/ing$/, ''], // creating -> create, testing -> test [/ying$/, 'y'], // applying -> apply [/ied$/, 'y'], // simplified -> simplify [/ed$/, ''], // created -> create [/ted$/, 't'], // started -> start [/ses$/, 's'], // analyses -> analyse [/zes$/, 'ze'], // analyzes -> analyze [/ves$/, 've'], // improves -> improve ]; for (const [pattern, replacement] of transformations) { if (pattern.test(word)) { const base = word.replace(pattern, replacement); if (this.isKnownVerb(base)) return base; } } // Check if it's already a base verb if (this.isKnownVerb(word)) return word; return null; } /** * Map verb phrases to base verbs */ mapPhraseToVerb(phrase) { const phraseMap = { 'figure out': 'solve', 'work out': 'solve', 'sort out': 'fix', 'find out': 'discover', 'set up': 'configure', 'clean up': 'refactor', 'follow up': 'track', 'break down': 'analyze', 'write down': 'document', 'track down': 'find' }; return phraseMap[phrase] || null; } /** * Get elements that match a specific verb * @param verb The verb to search for * @param index The index to search in (passed to avoid circular dependency) */ getElementsForVerb(verb, index) { return this.getElementsForVerbInternal(verb, index, new Set()); } /** * Internal version with visited tracking to prevent infinite recursion */ getElementsForVerbInternal(verb, index, visited) { // Check if we've already processed this verb (prevents infinite recursion) if (visited.has(verb)) { return []; } visited.add(verb); // Check cache first if (this.verbCache.has(verb)) { return this.verbCache.get(verb); } const elements = []; // 1. Check custom verb mappings first (highest priority) // Custom verbs get confidence 0.95 to ensure they override index-based mappings. // This allows runtime customization of verb-to-element mappings, enabling users // to define their own action triggers that take precedence over system defaults. // FIX: Use optional chain for better maintainability (SonarCloud L288) if (this.config.customVerbs?.[verb]) { for (const elementName of this.config.customVerbs[verb]) { const elementType = this.findElementType(elementName, index); elements.push({ name: elementName, type: elementType, confidence: 0.95, // Very high confidence for custom mappings source: 'explicit' }); } } // 2. Check explicit verb mappings in action_triggers if (index.action_triggers[verb]) { for (const elementName of index.action_triggers[verb]) { const elementType = this.findElementType(elementName, index); let confidence = 0.9; // Default for action_triggers // Try to get actual confidence from element.actions. // This preserves the confidence value defined in the element's action definition // rather than using a hardcoded default. Each element can specify different // confidence levels for different actions based on how well-suited it is for // that particular verb (e.g., a debugging tool might have 0.95 for "debug" // but only 0.6 for "analyze"). if (elementType !== 'unknown') { const element = index.elements[elementType]?.[elementName]; if (element?.actions) { // Find the action definition for this specific verb const actionDef = Object.values(element.actions).find((a) => a.verb === verb); if (actionDef?.confidence !== undefined) { confidence = actionDef.confidence; // Use element's defined confidence } } } elements.push({ name: elementName, type: elementType, confidence, // Now uses actual confidence from element definition source: 'explicit' }); } } // 3. Check element actions for this verb for (const [type, typeElements] of Object.entries(index.elements)) { for (const [name, element] of Object.entries(typeElements)) { if (element.actions) { for (const action of Object.values(element.actions)) { if (action.verb === verb) { const existing = elements.find(e => e.name === name); if (!existing) { elements.push({ name, type, confidence: action.confidence || 0.7, source: 'explicit' }); } } } } } } // 4. Check synonyms if enabled (with depth limit) if (this.config.includeSynonyms && visited.size < 5) { // Max recursion depth of 5 const synonyms = this.getSynonyms(verb); for (const synonym of synonyms) { if (synonym !== verb && !visited.has(synonym)) { // Pass the visited set to recursive calls const synonymElements = this.getElementsForVerbInternal(synonym, index, visited); for (const elem of synonymElements) { const existing = elements.find(e => e.name === elem.name); if (!existing) { elements.push({ ...elem, confidence: elem.confidence * 0.8, // Lower confidence for synonyms source: 'inferred' }); } } } } } // 5. Infer from element names (e.g., "debug-detective" -> "debug") for (const [type, typeElements] of Object.entries(index.elements)) { for (const [name] of Object.entries(typeElements)) { const elementNameLower = name.toLowerCase(); if (elementNameLower.includes(verb) || elementNameLower.includes(this.getBaseVerb(verb) || verb)) { const existing = elements.find(e => e.name === name); if (!existing) { elements.push({ name, type, confidence: 0.6, // Medium confidence for name-based source: 'name-based' }); } } } } // 6. Infer from descriptions for (const [type, typeElements] of Object.entries(index.elements)) { for (const [name, element] of Object.entries(typeElements)) { if (element.core.description) { const descLower = element.core.description.toLowerCase(); if (descLower.includes(verb) || descLower.includes(this.getBaseVerb(verb) || verb)) { const existing = elements.find(e => e.name === name); if (!existing) { elements.push({ name, type, confidence: 0.4, // Lower confidence for description-based source: 'description-based' }); } } } } } // Filter by confidence threshold const filtered = elements.filter(e => e.confidence >= this.config.confidenceThreshold); // Sort by confidence (highest first) filtered.sort((a, b) => b.confidence - a.confidence); // Limit results const limited = filtered.slice(0, this.config.maxElementsPerVerb); // Cache the results this.verbCache.set(verb, limited); return limited; } /** * Find element type by name * FIX: Handle case where index.elements might be undefined */ findElementType(elementName, index) { if (!index.elements) { return 'unknown'; } for (const [type, elements] of Object.entries(index.elements)) { if (elements[elementName]) { return type; } } return 'unknown'; } /** * Get synonyms for a verb */ getSynonyms(verb) { for (const [, verbs] of Object.entries(VERB_TAXONOMY)) { if (verbs.includes(verb)) { return verbs; } } return [verb]; } /** * Get verb category */ getVerbCategory(verb) { for (const [category, verbs] of Object.entries(VERB_TAXONOMY)) { if (verbs.includes(verb)) { return category; } } return null; } /** * Process a query and get all verb matches * @param query The query to process * @param index The index to search in */ processQuery(query, index) { const verbs = this.extractVerbs(query); const matches = []; for (const verb of verbs) { const elements = this.getElementsForVerb(verb, index); if (elements.length > 0) { matches.push({ verb, elements, category: this.getVerbCategory(verb) || undefined }); } } logger.info('Processed query for verb triggers', { query, verbsFound: verbs.length, matchesFound: matches.length }); return matches; } /** * Add custom verb mapping */ addCustomVerb(verb, elements) { if (!this.config.customVerbs) { this.config.customVerbs = {}; } this.config.customVerbs[verb] = elements; // Clear cache for this verb this.verbCache.delete(verb); logger.debug('Added custom verb mapping', { verb, elements }); } /** * Clear verb cache (useful after index updates) */ clearCache() { const cleared = this.verbCache.size; this.verbCache.clear(); if (cleared > 0) { logger.debug('Verb cache cleared', { entriesCleared: cleared }); } } /** * Get all verbs that map to a specific element * @param elementName The element to get verbs for * @param index The index to search in (passed to avoid circular dependency) */ getVerbsForElement(elementName, index) { const verbs = []; // Check action_triggers (use optional chain for robustness) // FIX: Handle case where action_triggers might be undefined if (index.action_triggers) { for (const [verb, elements] of Object.entries(index.action_triggers)) { if (elements.includes(elementName)) { verbs.push(verb); } } } // Check element's own actions // FIX: Handle case where index.elements might be undefined if (index.elements) { for (const typeElements of Object.values(index.elements)) { const element = typeElements[elementName]; if (element?.actions) { for (const action of Object.values(element.actions)) { const actionVerb = action.verb; if (actionVerb && !verbs.includes(actionVerb)) { verbs.push(actionVerb); } } } } } // Check name-based inference const elementNameLower = elementName.toLowerCase(); for (const verbList of Object.values(VERB_TAXONOMY)) { for (const verb of verbList) { if (elementNameLower.includes(verb) && !verbs.includes(verb)) { verbs.push(verb); } } } return verbs; } /** * Generate suggested verbs for an element based on its type and name */ suggestVerbsForElement(element) { const suggestions = []; const name = element.core.name.toLowerCase(); const type = element.core.type; // Type-based suggestions switch (type) { case 'personas': if (name.includes('debug')) { suggestions.push('debug', 'fix', 'troubleshoot'); } if (name.includes('creative') || name.includes('writer')) { suggestions.push('write', 'create', 'compose'); } if (name.includes('analyst')) { suggestions.push('analyze', 'examine', 'investigate'); } if (name.includes('explain')) { suggestions.push('explain', 'teach', 'simplify'); } break; case 'memories': suggestions.push('remember', 'recall', 'retrieve'); if (name.includes('session')) { suggestions.push('review', 'find'); } break; case 'skills': suggestions.push('use', 'apply', 'execute'); break; case 'templates': suggestions.push('create', 'generate', 'fill'); break; case 'agents': suggestions.push('run', 'execute', 'activate'); break; } // Name-based suggestions for (const [, verbs] of Object.entries(VERB_TAXONOMY)) { for (const verb of verbs) { if (name.includes(verb) && !suggestions.includes(verb)) { suggestions.push(verb); } } } return [...new Set(suggestions)]; // Remove duplicates } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVmVyYlRyaWdnZXJNYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BvcnRmb2xpby9WZXJiVHJpZ2dlck1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7OztHQVlHO0FBRUgsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRTVDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNqRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUU5RTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRztJQUMzQixxQkFBcUI7SUFDckIsU0FBUyxFQUFFLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxjQUFjLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsUUFBUSxDQUFDO0lBRXJGLHFCQUFxQjtJQUNyQixRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxTQUFTLENBQUM7SUFFbEYseUJBQXlCO0lBQ3pCLFdBQVcsRUFBRSxDQUFDLFNBQVMsRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLFFBQVEsQ0FBQztJQUUzRiwyQkFBMkI7SUFDM0IsUUFBUSxFQUFFLENBQUMsU0FBUyxFQUFFLGFBQWEsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsVUFBVSxDQUFDO0lBRTFGLGtCQUFrQjtJQUNsQixNQUFNLEVBQUUsQ0FBQyxVQUFVLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxRQUFRLENBQUM7SUFFaEYsc0JBQXNCO0lBQ3RCLFNBQVMsRUFBRSxDQUFDLEtBQUssRUFBRSxTQUFT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QUFDLENBQUM7Z0JBQ25ELElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO29CQUM3QixXQUFXLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDckMsQ0FBQztnQkFDRCxNQUFNO1lBRVIsS0FBSyxRQUFRO2dCQUNYLFdBQVcsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRSxTQUFTLENBQUMsQ0FBQztnQkFDNUMsTUFBTTtZQUVSLEtBQUssV0FBVztnQkFDZCxXQUFXLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUM7Z0JBQy9DLE1BQU07WUFFUixLQUFLLFFBQVE7Z0JBQ1gsV0FBVyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLFVBQVUsQ0FBQyxDQUFDO2dCQUMvQyxNQUFNO1FBQ1YsQ0FBQztRQUVELHlCQUF5QjtRQUN6QixLQUFLLE1BQU0sQ0FBQyxFQUFFLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQztZQUN0RCxLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssRUFBRSxDQUFDO2dCQUN6QixJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7b0JBQ3ZELFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ3pCLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBRSxvQkFBb0I7SUFDekQsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBWZXJiIFRyaWdnZXIgTWFuYWdlciAtIE1hcHMgYWN0aW9uIHZlcmJzIHRvIGVsZW1lbnRzXG4gKlxuICogVGhpcyBtYW5hZ2VyIGhhbmRsZXMgdmVyYi1iYXNlZCBhY3Rpb24gdHJpZ2dlcnMgdGhhdCBtYXAgdXNlciBpbnRlbnRcbiAqIHRvIHNwZWNpZmljIGVsZW1lbnRzLiBVc2VzIGFjdGlvbiB2ZXJicyAoZGVidWcsIGZpeCwgY3JlYXRlKSBpbnN0ZWFkXG4gKiBvZiBub3VucyBmb3IgYmV0dGVyIGludGVudCBtYXRjaGluZy5cbiAqXG4gKiBLZXkgcHJpbmNpcGxlczpcbiAqIC0gVmVyYnMgaGF2ZSBoaWdoZXIgYXR0ZW50aW9uIHByb2JhYmlsaXR5IHRoYW4gbm91bnNcbiAqIC0gTXVsdGlwbGUgdmVyYnMgY2FuIG1hcCB0byB0aGUgc2FtZSBlbGVtZW50XG4gKiAtIFZlcmJzIGFyZSBleHRyYWN0ZWQgZnJvbSBxdWVyaWVzIGFuZCBlbGVtZW50IG1ldGFkYXRhXG4gKiAtIFN1cHBvcnRzIHN5bm9ueW1zIGFuZCByZWxhdGVkIHZlcmIgZm9ybXNcbiAqL1xuXG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgRW5oYW5jZWRJbmRleCwgRWxlbWVudERlZmluaXRpb24sIEFjdGlvbkRlZmluaXRpb24gfSBmcm9tICcuL3R5cGVzL0luZGV4VHlwZXMuanMnO1xuaW1wb3J0IHsgU2VjdXJpdHlNb25pdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvc2VjdXJpdHlNb25pdG9yLmpzJztcbmltcG9ydCB7IFVuaWNvZGVWYWxpZGF0b3IgfSBmcm9tICcuLi9zZWN1cml0eS92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuXG4vKipcbiAqIFZlcmIgdGF4b25vbXkgLSBDb21tb24gdmVyYnMgZ3JvdXBlZCBieSBpbnRlbnRcbiAqL1xuZXhwb3J0IGNvbnN0IFZFUkJfVEFYT05PTVkgPSB7XG4gIC8vIERlYnVnZ2luZyAmIEZpeGluZ1xuICBkZWJ1Z2dpbmc6IFsnZGVidWcnLCAnZml4JywgJ3Ryb3VibGVzaG9vdCcsICdkaWFnbm9zZScsICdzb2x2ZScsICdyZXNvbHZlJywgJ3JlcGFpciddLFxuXG4gIC8vIENyZWF0aW5nICYgV3JpdGluZ1xuICBjcmVhdGlvbjogWydjcmVhdGUnLCAnd3JpdGUnLCAnZ2VuZXJhdGUnLCAnbWFrZScsICdidWlsZCcsICdjb25zdHJ1Y3QnLCAnY29tcG9zZSddLFxuXG4gIC8vIEV4cGxhbmF0aW9uICYgTGVhcm5pbmdcbiAgZXhwbGFuYXRpb246IFsnZXhwbGFpbicsICd0ZWFjaCcsICdjbGFyaWZ5JywgJ2Rlc2NyaWJlJywgJ3NpbXBsaWZ5JywgJ2VsYWJvcmF0ZScsICdkZWZpbmUnXSxcblxuICAvLyBBbmFseXNpcyAmIEludmVzdGlnYXRpb25cbiAgYW5hbHlzaXM6IFsnYW5hbHl6ZScsICdpbnZlc3RpZ2F0ZScsICdleGFtaW5lJywgJ2luc3BlY3QnLCAncmV2aWV3JywgJ2Fzc2VzcycsICdldmFsdWF0ZSddLFxuXG4gIC8vIE1lbW9yeSAmIFJlY2FsbFxuICByZWNhbGw6IFsncmVtZW1iZXInLCAncmVjYWxsJywgJ3JldHJpZXZlJywgJ2ZpbmQnLCAnbG9jYXRlJywgJ3NlYXJjaCcsICdsb29rdXAnXSxcblxuICAvLyBFeGVjdXRpb24gJiBSdW5uaW5nXG4gIGV4ZWN1dGlvbjogWydydW4nLCAnZXhlY3V0ZScsICdzdGFydCcsICdsYXVuY2gnLCAnYWN0aXZhdGUnLCAndHJpZ2dlcicsICdpbnZva2UnXSxcblxuICAvLyBUZXN0aW5nICYgVmFsaWRhdGlvblxuICB0ZXN0aW5nOiBbJ3Rlc3QnLCAndmVyaWZ5JywgJ3ZhbGlkYXRlJywgJ2NoZWNrJywgJ2NvbmZpcm0nLCAnZW5zdXJlJywgJ3Byb3ZlJ10sXG5cbiAgLy8gQ29uZmlndXJhdGlvbiAmIFNldHVwXG4gIGNvbmZpZ3VyYXRpb246IFsnY29uZmlndXJlJywgJ3NldHVwJywgJ2luc3RhbGwnLCAnaW5pdGlhbGl6ZScsICdwcmVwYXJlJywgJ2FycmFuZ2UnXSxcblxuICAvLyBTZWN1cml0eSAmIFByb3RlY3Rpb25cbiAgc2VjdXJpdHk6IFsnc2VjdXJlJywgJ3Byb3RlY3QnLCAnYXVkaXQnLCAnc2NhbicsICdlbmNyeXB0JywgJ2F1dGhlbnRpY2F0ZScsICdhdXRob3JpemUnXSxcblxuICAvLyBPcHRpbWl6YXRpb24gJiBJbXByb3ZlbWVudFxuICBvcHRpbWl6YXRpb246IFsnb3B0aW1pemUnLCAnaW1wcm92ZScsICdlbmhhbmNlJywgJ3JlZmFjdG9yJywgJ3N0cmVhbWxpbmUnLCAnYWNjZWxlcmF0ZSddLFxuXG4gIC8vIERvY3VtZW50YXRpb25cbiAgZG9jdW1lbnRhdGlvbjogWydkb2N1bWVudCcsICdhbm5vdGF0ZScsICdjb21tZW50JywgJ3JlY29yZCcsICdub3RlJywgJ2xvZyddLFxuXG4gIC8vIENvbGxhYm9yYXRpb25cbiAgY29sbGFib3JhdGlvbjogWydzaGFyZScsICdjb2xsYWJvcmF0ZScsICdzeW5jJywgJ21lcmdlJywgJ2ludGVncmF0ZScsICdjb21iaW5lJ11cbn07XG5cbi8qKlxuICogVmVyYiB0cmlnZ2VyIGNvbmZpZ3VyYXRpb25cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBWZXJiVHJpZ2dlckNvbmZpZyB7XG4gIC8vIE1pbmltdW0gY29uZmlkZW5jZSB0byB0cmlnZ2VyXG4gIGNvbmZpZGVuY2VUaHJlc2hvbGQ/OiBudW1iZXI7XG5cbiAgLy8gV2hldGhlciB0byBpbmNsdWRlIHN5bm9ueW1zXG4gIGluY2x1ZGVTeW5vbnltcz86IGJvb2xlYW47XG5cbiAgLy8gTWF4aW11bSBlbGVtZW50cyB0byByZXR1cm4gcGVyIHZlcmJcbiAgbWF4RWxlbWVudHNQZXJWZXJiPzogbnVtYmVyO1xuXG4gIC8vIEN1c3RvbSB2ZXJiIG1hcHBpbmdzXG4gIGN1c3RvbVZlcmJzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nW10+O1xufVxuXG4vKipcbiAqIFZlcmIgbWF0Y2ggcmVzdWx0XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVmVyYk1hdGNoIHtcbiAgdmVyYjogc3RyaW5nO1xuICBlbGVtZW50czogRWxlbWVudE1hdGNoW107XG4gIGNhdGVnb3J5Pzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEVsZW1lbnRNYXRjaCB7XG4gIG5hbWU6IHN0cmluZztcbiAgdHlwZTogc3RyaW5nO1xuICBjb25maWRlbmNlOiBudW1iZXI7XG4gIHNvdXJjZTogJ2V4cGxpY2l0JyB8ICdpbmZlcnJlZCcgfCAnbmFtZS1iYXNlZCcgfCAnZGVzY3JpcHRpb24tYmFzZWQnO1xufVxuXG5leHBvcnQgY2xhc3MgVmVyYlRyaWdnZXJNYW5hZ2VyIHtcbiAgcHJpdmF0ZSB2ZXJiQ2FjaGU6IE1hcDxzdHJpbmcsIEVsZW1lbnRNYXRjaFtdPiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBjb25maWc6IFZlcmJUcmlnZ2VyQ29uZmlnO1xuXG4gIGNvbnN0cnVjdG9yKGNvbmZpZzogVmVyYlRyaWdnZXJDb25maWcgPSB7fSkge1xuICAgIHRoaXMuY29uZmlnID0ge1xuICAgICAgY29uZmlkZW5jZVRocmVzaG9sZDogY29uZmlnLmNvbmZpZGVuY2VUaHJlc2hvbGQgfHwgMC41LFxuICAgICAgaW5jbHVkZVN5bm9ueW1zOiBjb25maWcuaW5jbHVkZVN5bm9ueW1zICE9PSBmYWxzZSxcbiAgICAgIG1heEVsZW1lbnRzUGVyVmVyYjogY29uZmlnLm1heEVsZW1lbnRzUGVyVmVyYiB8fCAxMCxcbiAgICAgIGN1c3RvbVZlcmJzOiBjb25maWcuY3VzdG9tVmVyYnMgfHwge31cbiAgICB9O1xuXG4gICAgbG9nZ2VyLmRlYnVnKCdWZXJiVHJpZ2dlck1hbmFnZXIgaW5pdGlhbGl6ZWQnLCB7IGNvbmZpZzogdGhpcy5jb25maWcgfSk7XG4gIH1cblxuICAvKipcbiAgICogRXh0cmFjdCB2ZXJicyBmcm9tIGEgdXNlciBxdWVyeVxuICAgKi9cbiAgcHVibGljIGV4dHJhY3RWZXJicyhxdWVyeTogc3RyaW5nKTogc3RyaW5nW10ge1xuICAgIC8vIFVuaWNvZGUgdmFsaWRhdGlvbiBmb3Igc2VjdXJpdHlcbiAgICBjb25zdCB2YWxpZGF0aW9uID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUocXVlcnkpO1xuICAgIGlmICh2YWxpZGF0aW9uLmRldGVjdGVkSXNzdWVzICYmIHZhbGlkYXRpb24uZGV0ZWN0ZWRJc3N1ZXMubGVuZ3RoID4gMCkge1xuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnVU5JQ09ERV9WQUxJREFUSU9OX0VSUk9SJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdNRURJVU0nLFxuICAgICAgICBzb3VyY2U6ICdWZXJiVHJpZ2dlck1hbmFnZXIuZXh0cmFjdFZlcmJzJyxcbiAgICAgICAgZGV0YWlsczogYFVuaWNvZGUgaXNzdWVzIGluIHF1ZXJ5OiAke3ZhbGlkYXRpb24uZGV0ZWN0ZWRJc3N1ZXMuam9pbignLCAnKX1gXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBjb25zdCB2ZXJiczogc3RyaW5nW10gPSBbXTtcbiAgICBjb25zdCBub3JtYWxpemVkUXVlcnkgPSB2YWxpZGF0aW9uLm5vcm1hbGl6ZWRDb250ZW50LnRvTG93ZXJDYXNlKCk7XG5cbiAgICAvLyBDaGVjayBlYWNoIHdvcmQgYWdhaW5zdCBvdXIgdmVyYiB0YXhvbm9teVxuICAgIGNvbnN0IHdvcmRzID0gbm9ybWFsaXplZFF1ZXJ5LnNwbGl0KC9cXHMrLyk7XG5cbiAgICBmb3IgKGNvbnN0IHdvcmQgb2Ygd29yZHMpIHtcbiAgICAgIC8vIERpcmVjdCB2ZXJiIGNoZWNrXG4gICAgICBpZiAodGhpcy5pc0tub3duVmVyYih3b3JkKSkge1xuICAgICAgICB2ZXJicy5wdXNoKHdvcmQpO1xuICAgICAgfVxuXG4gICAgICAvLyBDaGVjayBmb3IgaW1wZXJhdGl2ZSBmb3JtcyAoY29tbW9uIGluIGNvbW1hbmRzKVxuICAgICAgLy8gXCJkZWJ1ZyB0aGlzXCIsIFwiZml4IHRoZSBlcnJvclwiLCBcImNyZWF0ZSBhIHRlc3RcIlxuICAgICAgY29uc3QgaW1wZXJhdGl2ZVBhdHRlcm5zID0gW1xuICAgICAgICAvXihkZWJ1Z3xmaXh8Y3JlYXRlfHdyaXRlfHRlc3R8cnVufGV4cGxhaW58YW5hbHl6ZSkvLFxuICAgICAgICAvKGluZykkLyAgLy8gR2VydW5kczogZGVidWdnaW5nLCB0ZXN0aW5nLCBjcmVhdGluZ1xuICAgICAgXTtcblxuICAgICAgZm9yIChjb25zdCBwYXR0ZXJuIG9mIGltcGVyYXRpdmVQYXR0ZXJucykge1xuICAgICAgICBpZiAocGF0dGVybi50ZXN0KHdvcmQpICYmICF2ZXJicy5pbmNsdWRlcyh3b3JkKSkge1xuICAgICAgICAgIGNvbnN0IGJhc2VWZXJiID0gdGhpcy5nZXRCYXNlVmVyYih3b3JkKTtcbiAgICAgICAgICBpZiAoYmFzZVZlcmIpIHZlcmJzLnB1c2goYmFzZVZlcmIpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQWxzbyBjaGVjayBmb3IgdmVyYiBwaHJhc2VzXG4gICAgY29uc3QgdmVyYlBocmFzZXMgPSBbXG4gICAgICAnZmlndXJlIG91dCcsICd3b3JrIG91dCcsICdzb3J0IG91dCcsICdmaW5kIG91dCcsXG4gICAgICAnc2V0IHVwJywgJ2NsZWFuIHVwJywgJ2ZvbGxvdyB1cCcsXG4gICAgICAnYnJlYWsgZG93bicsICd3cml0ZSBkb3duJywgJ3RyYWNrIGRvd24nXG4gICAgXTtcblxuICAgIGZvciAoY29uc3QgcGhyYXNlIG9mIHZlcmJQaHJhc2VzKSB7XG4gICAgICBpZiAobm9ybWFsaXplZFF1ZXJ5LmluY2x1ZGVzKHBocmFzZSkpIHtcbiAgICAgICAgLy8gTWFwIHBocmFzZXMgdG8gYmFzZSB2ZXJic1xuICAgICAgICBjb25zdCBiYXNlVmVyYiA9IHRoaXMubWFwUGhyYXNlVG9WZXJiKHBocmFzZSk7XG4gICAgICAgIGlmIChiYXNlVmVyYiAmJiAhdmVyYnMuaW5jbHVkZXMoYmFzZVZlcmIpKSB7XG4gICAgICAgICAgdmVyYnMucHVzaChiYXNlVmVyYik7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBJbmNsdWRlIGN1c3RvbSB2ZXJicyBmcm9tIGNvbmZpZ1xuICAgIGZvciAoY29uc3QgY3VzdG9tVmVyYiBvZiBPYmplY3Qua2V5cyh0aGlzLmNvbmZpZy5jdXN0b21WZXJicyB8fCB7fSkpIHtcbiAgICAgIGlmIChub3JtYWxpemVkUXVlcnkuaW5jbHVkZXMoY3VzdG9tVmVyYikgJiYgIXZlcmJzLmluY2x1ZGVzKGN1c3RvbVZlcmIpKSB7XG4gICAgICAgIHZlcmJzLnB1c2goY3VzdG9tVmVyYik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgbG9nZ2VyLmRlYnVnKCdFeHRyYWN0ZWQgdmVyYnMgZnJvbSBxdWVyeScsIHsgcXVlcnksIHZlcmJzIH0pO1xuICAgIHJldHVybiB2ZXJicztcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBhIHdvcmQgaXMgYSBrbm93biB2ZXJiXG4gICAqL1xuICBwcml2YXRlIGlzS25vd25WZXJiKHdvcmQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGZvciAoY29uc3QgdmVyYnMgb2YgT2JqZWN0LnZhbHVlcyhWRVJCX1RBWE9OT01ZKSkge1xuICAgICAgaWYgKHZlcmJzLmluY2x1ZGVzKHdvcmQpKSByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBiYXNlIGZvcm0gb2YgYSB2ZXJiIChyZW1vdmUgLWluZywgLWVkLCBldGMuKVxuICAgKlxuICAgKiBUcmFuc2Zvcm1zIHZlcmIgdmFyaWF0aW9ucyBiYWNrIHRvIHRoZWlyIGJhc2UgZm9ybSB0byBlbmFibGUgZmxleGlibGUgbWF0Y2hpbmcuXG4gICAqIEZvciBleGFtcGxlLCBcImRlYnVnZ2luZ1wiLCBcImRlYnVnZ2VkXCIsIFwiZGVidWdzXCIgYWxsIG1hcCB0byBcImRlYnVnXCIuXG4gICAqL1xuICBwcml2YXRlIGdldEJhc2VWZXJiKHdvcmQ6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICAgIC8vIEhhbmRsZSBjb21tb24gdmVyYiBlbmRpbmdzIHdpdGggcmVnZXggdHJhbnNmb3JtYXRpb25zXG4gICAgY29uc3QgdHJhbnNmb3JtYXRpb25zOiBbUmVnRXhwLCBzdHJpbmddW10gPSBbXG4gICAgICAvLyBIYW5kbGUgZ2VydW5kcyB3aXRoIGRvdWJsZWQgY29uc29uYW50cyAoZGVidWdnaW5n4oaSZGVidWcsIHJ1bm5pbmfihpJydW4sIHBsYW5uaW5n4oaScGxhbilcbiAgICAgIC8vIFBhdHRlcm