@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
JavaScript
/**
* 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