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.

360 lines 52.9 kB
/** * EnsembleElementValidator - Specialized validator for Ensemble elements * * Extends GenericElementValidator to add Ensemble-specific validation: * - Element type validation against valid types * - Circular dependency detection * - Nested ensemble depth validation * - Activation strategy validation * - Conflict resolution validation */ import { ElementType } from '../../portfolio/types.js'; import { GenericElementValidator } from './GenericElementValidator.js'; import { ValidatorHelpers } from './ElementValidator.js'; import { ACTIVATION_STRATEGIES, CONFLICT_STRATEGIES, ELEMENT_ROLES, ACTIVATION_MODES, ENSEMBLE_LIMITS, ENSEMBLE_DEFAULTS } from '../../elements/ensembles/constants.js'; const VALID_ELEMENT_TYPES = [ ElementType.PERSONA, ElementType.SKILL, ElementType.TEMPLATE, ElementType.AGENT, ElementType.MEMORY, ElementType.ENSEMBLE ]; /** * Map singular type names to their plural ElementType equivalents * Allows users to specify 'skill' instead of 'skills', etc. */ const SINGULAR_TO_PLURAL_TYPE_MAP = { 'persona': ElementType.PERSONA, 'skill': ElementType.SKILL, 'template': ElementType.TEMPLATE, 'agent': ElementType.AGENT, 'memory': ElementType.MEMORY, 'ensemble': ElementType.ENSEMBLE, // Also include plural forms for direct lookup 'personas': ElementType.PERSONA, 'skills': ElementType.SKILL, 'templates': ElementType.TEMPLATE, 'agents': ElementType.AGENT, 'memories': ElementType.MEMORY, 'ensembles': ElementType.ENSEMBLE }; /** * Normalize element type to ElementType enum value * Accepts both singular ('skill') and plural ('skills') forms */ function normalizeElementType(type) { const normalized = type.toLowerCase(); return SINGULAR_TO_PLURAL_TYPE_MAP[normalized] || null; } export class EnsembleElementValidator extends GenericElementValidator { constructor(validationService, triggerValidationService, metadataService) { super(ElementType.ENSEMBLE, validationService, triggerValidationService, metadataService); } /** * Override validateCreate to add ensemble-specific validation */ async validateCreate(data, options) { // First run generic validation const baseResult = await super.validateCreate(data, options); const errors = [...baseResult.errors]; const warnings = [...baseResult.warnings]; const suggestions = [...(baseResult.suggestions || [])]; if (!data || typeof data !== 'object') { return baseResult; } const record = data; // Validate activation strategy if (record.activationStrategy || record.activation_strategy) { const strategy = record.activationStrategy || record.activation_strategy; const strategyResult = this.validateActivationStrategy(strategy); if (!strategyResult.isValid) { errors.push(...strategyResult.errors); } } // Validate conflict resolution if (record.conflictResolution || record.conflict_resolution) { const resolution = record.conflictResolution || record.conflict_resolution; const resolutionResult = this.validateConflictResolution(resolution); if (!resolutionResult.isValid) { errors.push(...resolutionResult.errors); } } // Validate context sharing if (record.contextSharing || record.context_sharing) { const sharing = record.contextSharing || record.context_sharing; const sharingResult = this.validateContextSharing(sharing); if (!sharingResult.isValid) { errors.push(...sharingResult.errors); } } // Validate ensemble elements if (record.elements) { // Use ternary to properly handle falsy values (|| treats false/0 as falsy) const allowNested = record.allowNested !== undefined ? record.allowNested : record.allow_nested; const maxNestingDepth = record.maxNestingDepth !== undefined ? record.maxNestingDepth : record.max_nesting_depth; const elementsResult = await this.validateEnsembleElements(record.elements, allowNested, maxNestingDepth); if (!elementsResult.isValid) { errors.push(...elementsResult.errors); } warnings.push(...elementsResult.warnings); } // Validate resource limits if present if (record.resourceLimits || record.resource_limits) { const limits = record.resourceLimits || record.resource_limits; const limitsResult = this.validateResourceLimits(limits); if (!limitsResult.isValid) { errors.push(...limitsResult.errors); } warnings.push(...limitsResult.warnings); } // Ensemble-specific suggestions if (!record.elements || (Array.isArray(record.elements) && record.elements.length === 0)) { warnings.push('Ensemble has no elements defined'); } if (!record.conflictResolution && !record.conflict_resolution) { suggestions.push('Consider specifying a conflict resolution strategy'); } return { isValid: errors.length === 0, errors, warnings, suggestions: suggestions.length > 0 ? suggestions : undefined }; } /** * Validate activation strategy */ validateActivationStrategy(strategy) { if (typeof strategy !== 'string') { return ValidatorHelpers.fail(['Activation strategy must be a string']); } if (!ACTIVATION_STRATEGIES.includes(strategy)) { return ValidatorHelpers.fail([ `Invalid activation strategy '${strategy}'. Valid options: ${ACTIVATION_STRATEGIES.join(', ')}` ]); } return ValidatorHelpers.pass(); } /** * Validate conflict resolution strategy */ validateConflictResolution(resolution) { if (typeof resolution !== 'string') { return ValidatorHelpers.fail(['Conflict resolution must be a string']); } if (!CONFLICT_STRATEGIES.includes(resolution)) { return ValidatorHelpers.fail([ `Invalid conflict resolution '${resolution}'. Valid options: ${CONFLICT_STRATEGIES.join(', ')}` ]); } return ValidatorHelpers.pass(); } /** * Validate context sharing mode */ validateContextSharing(sharing) { if (typeof sharing !== 'string') { return ValidatorHelpers.fail(['Context sharing must be a string']); } if (!['none', 'selective', 'full'].includes(sharing)) { return ValidatorHelpers.fail([ `Invalid context sharing mode '${sharing}'. Valid options: ${['none', 'selective', 'full'].join(', ')}` ]); } return ValidatorHelpers.pass(); } /** * Validate ensemble elements array */ async validateEnsembleElements(elements, allowNested, maxNestingDepth) { if (!Array.isArray(elements)) { return ValidatorHelpers.fail(['Elements must be an array']); } const errors = []; const warnings = []; if (elements.length === 0) { warnings.push('Ensemble has no elements'); return { isValid: true, errors, warnings }; } if (elements.length > ENSEMBLE_LIMITS.MAX_ELEMENTS) { errors.push(`Ensemble cannot have more than ${ENSEMBLE_LIMITS.MAX_ELEMENTS} elements`); } // Track element names for circular dependency detection const elementNames = new Set(); const dependencies = new Map(); for (let i = 0; i < elements.length; i++) { const element = elements[i]; if (!element || typeof element !== 'object') { errors.push(`Element at index ${i} must be an object`); continue; } const elem = element; // Support both element_name (new) and name (legacy) field names const elemName = elem.element_name || elem.name; // Validate element name if (!elemName) { errors.push(`Element at index ${i} is missing required 'element_name' (or 'name') field`); continue; } if (elementNames.has(elemName)) { errors.push(`Duplicate element name '${elemName}' at index ${i}`); } elementNames.add(elemName); // Support both element_type (new) and type (legacy) field names const elemType = elem.element_type || elem.type; // Validate element type - accept both singular and plural forms const normalizedElemType = elemType ? normalizeElementType(elemType) : null; if (!elemType) { errors.push(`Element '${elemName}' is missing required 'element_type' (or 'type') field`); } else { if (!normalizedElemType) { errors.push(`Element '${elemName}' has invalid type '${elemType}'. Valid types: ${VALID_ELEMENT_TYPES.join(', ')}`); } } // Check for nested ensembles - normalize type for comparison if (normalizedElemType === ElementType.ENSEMBLE) { if (allowNested !== true) { errors.push(`Nested ensemble '${elemName}' not allowed (set allowNested: true to enable)`); } else { // Validate nesting depth const depth = typeof maxNestingDepth === 'number' ? maxNestingDepth : ENSEMBLE_LIMITS.MAX_NESTING_DEPTH; if (depth <= 0) { errors.push(`Maximum nesting depth exceeded for ensemble '${elemName}'`); } } } // Validate element role if (elem.role && !ELEMENT_ROLES.includes(elem.role)) { errors.push(`Element '${elemName}' has invalid role '${elem.role}'. Valid roles: ${ELEMENT_ROLES.join(', ')}`); } else if (!elem.role) { // Issue #365: Warn when role defaults are applied warnings.push(`Element '${elemName}' has no role specified, will default to '${ENSEMBLE_DEFAULTS.ELEMENT_ROLE}'. Valid roles: ${ELEMENT_ROLES.join(', ')}`); } // Validate activation mode if (elem.activation && !ACTIVATION_MODES.includes(elem.activation)) { errors.push(`Element '${elemName}' has invalid activation '${elem.activation}'. Valid modes: ${ACTIVATION_MODES.join(', ')}`); } // Validate condition if activation is conditional if (elem.activation === 'conditional' && !elem.condition) { errors.push(`Element '${elemName}' has conditional activation but no condition specified`); } // Track dependencies for circular detection if (elem.dependencies && Array.isArray(elem.dependencies)) { dependencies.set(elemName, new Set(elem.dependencies)); // Check that dependencies exist for (const dep of elem.dependencies) { const depExists = elementNames.has(dep) || elements.some(e => { const el = e; return (el.element_name || el.name) === dep; }); if (!depExists) { warnings.push(`Element '${elemName}' depends on unknown element '${dep}'`); } } if (elem.dependencies.length > ENSEMBLE_LIMITS.MAX_DEPENDENCIES) { errors.push(`Element '${elemName}' has too many dependencies (${elem.dependencies.length} > ${ENSEMBLE_LIMITS.MAX_DEPENDENCIES})`); } } } // Detect circular dependencies const circularDeps = this.detectCircularDependencies(dependencies); if (circularDeps.length > 0) { errors.push(`Circular dependencies detected: ${circularDeps.join(' -> ')}`); } return { isValid: errors.length === 0, errors, warnings }; } /** * Detect circular dependencies in element graph */ detectCircularDependencies(dependencies) { const visited = new Set(); const recursionStack = new Set(); const path = []; const hasCycle = (node) => { visited.add(node); recursionStack.add(node); path.push(node); const deps = dependencies.get(node); if (deps) { for (const dep of deps) { if (!visited.has(dep)) { if (hasCycle(dep)) { return true; } } else if (recursionStack.has(dep)) { // Found cycle return true; } } } recursionStack.delete(node); path.pop(); return false; }; for (const node of dependencies.keys()) { if (!visited.has(node)) { if (hasCycle(node)) { // Return the cycle path const cycleStart = path.findIndex(n => path.lastIndexOf(n) !== path.indexOf(n)); if (cycleStart >= 0) { return path.slice(cycleStart); } return path; } } } return []; } /** * Validate resource limits */ validateResourceLimits(limits) { if (!limits || typeof limits !== 'object' || Array.isArray(limits)) { return ValidatorHelpers.fail(['Resource limits must be an object']); } const limitsObj = limits; const warnings = []; // Validate memory limit if (limitsObj.memoryMB !== undefined) { if (typeof limitsObj.memoryMB !== 'number' || limitsObj.memoryMB <= 0) { return ValidatorHelpers.fail(['Memory limit must be a positive number']); } if (limitsObj.memoryMB > 1024) { warnings.push(`High memory limit (${limitsObj.memoryMB}MB) may impact performance`); } } // Validate execution time if (limitsObj.executionTimeMs !== undefined) { if (typeof limitsObj.executionTimeMs !== 'number' || limitsObj.executionTimeMs <= 0) { return ValidatorHelpers.fail(['Execution time limit must be a positive number']); } if (limitsObj.executionTimeMs > 60000) { warnings.push(`Long execution time limit (${limitsObj.executionTimeMs}ms) may cause timeouts`); } } // Validate concurrent activations if (limitsObj.maxConcurrent !== undefined) { if (typeof limitsObj.maxConcurrent !== 'number' || limitsObj.maxConcurrent <= 0) { return ValidatorHelpers.fail(['Max concurrent must be a positive number']); } if (limitsObj.maxConcurrent > 10) { warnings.push(`High concurrent limit (${limitsObj.maxConcurrent}) may cause resource contention`); } } return { isValid: true, errors: [], warnings }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRW5zZW1ibGVFbGVtZW50VmFsaWRhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZpY2VzL3ZhbGlkYXRpb24vRW5zZW1ibGVFbGVtZW50VmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7R0FTRztBQUVILE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUN2RSxPQUFPLEVBQW9CLGdCQUFnQixFQUE0QixNQUFNLHVCQUF1QixDQUFDO0FBSXJHLE9BQU8sRUFDTCxxQkFBcUIsRUFDckIsbUJBQW1CLEVBQ25CLGFBQWEsRUFDYixnQkFBZ0IsRUFDaEIsZUFBZSxFQUNmLGlCQUFpQixFQUNsQixNQUFNLHVDQUF1QyxDQUFDO0FBRS9DLE1BQU0sbUJBQW1CLEdBQWtCO0lBQ3pDLFdBQVcsQ0FBQyxPQUFPO0lBQ25CLFdBQVcsQ0FBQyxLQUFLO0lBQ2pCLFdBQVcsQ0FBQyxRQUFRO0lBQ3BCLFdBQVcsQ0FBQyxLQUFLO0lBQ2pCLFdBQVcsQ0FBQyxNQUFNO0lBQ2xCLFdBQVcsQ0FBQyxRQUFRO0NBQ3JCLENBQUM7QUFFRjs7O0dBR0c7QUFDSCxNQUFNLDJCQUEyQixHQUFnQztJQUMvRCxTQUFTLEVBQUUsV0FBVyxDQUFDLE9BQU87SUFDOUIsT0FBTyxFQUFFLFdBQVcsQ0FBQyxLQUFLO0lBQzFCLFVBQVUsRUFBRSxXQUFXLENBQUMsUUFBUTtJQUNoQyxPQUFPLEVBQUUsV0FBVyxDQUFDLEtBQUs7SUFDMUIsUUFBUSxFQUFFLFdBQVcsQ0FBQyxNQUFNO0lBQzVCLFVBQVUsRUFBRSxXQUFXLENBQUMsUUFBUTtJQUNoQyw4Q0FBOEM7SUFDOUMsVUFBVSxFQUFFLFdBQVcsQ0FBQyxPQUFPO0lBQy9CLFFBQVEsRUFBRSxXQUFXLENBQUMsS0FBSztJQUMzQixXQUFXLEVBQUUsV0FBVyxD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Q0FBMEMsQ0FBQyxDQUFDLENBQUM7WUFDN0UsQ0FBQztZQUNELElBQUksU0FBUyxDQUFDLGFBQWEsR0FBRyxFQUFFLEVBQUUsQ0FBQztnQkFDakMsUUFBUSxDQUFDLElBQUksQ0FBQywwQkFBMEIsU0FBUyxDQUFDLGFBQWEsaUNBQWlDLENBQUMsQ0FBQztZQUNwRyxDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU87WUFDTCxPQUFPLEVBQUUsSUFBSTtZQUNiLE1BQU0sRUFBRSxFQUFFO1lBQ1YsUUFBUTtTQUNULENBQUM7SUFDSixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEVuc2VtYmxlRWxlbWVudFZhbGlkYXRvciAtIFNwZWNpYWxpemVkIHZhbGlkYXRvciBmb3IgRW5zZW1ibGUgZWxlbWVudHNcbiAqXG4gKiBFeHRlbmRzIEdlbmVyaWNFbGVtZW50VmFsaWRhdG9yIHRvIGFkZCBFbnNlbWJsZS1zcGVjaWZpYyB2YWxpZGF0aW9uOlxuICogLSBFbGVtZW50IHR5cGUgdmFsaWRhdGlvbiBhZ2FpbnN0IHZhbGlkIHR5cGVzXG4gKiAtIENpcmN1bGFyIGRlcGVuZGVuY3kgZGV0ZWN0aW9uXG4gKiAtIE5lc3RlZCBlbnNlbWJsZSBkZXB0aCB2YWxpZGF0aW9uXG4gKiAtIEFjdGl2YXRpb24gc3RyYXRlZ3kgdmFsaWRhdGlvblxuICogLSBDb25mbGljdCByZXNvbHV0aW9uIHZhbGlkYXRpb25cbiAqL1xuXG5pbXBvcnQgeyBFbGVtZW50VHlwZSB9IGZyb20gJy4uLy4uL3BvcnRmb2xpby90eXBlcy5qcyc7XG5pbXBvcnQgeyBHZW5lcmljRWxlbWVudFZhbGlkYXRvciB9IGZyb20gJy4vR2VuZXJpY0VsZW1lbnRWYWxpZGF0b3IuanMnO1xuaW1wb3J0IHsgVmFsaWRhdGlvblJlc3VsdCwgVmFsaWRhdG9ySGVscGVycywgRWxlbWVudFZhbGlkYXRpb25PcHRpb25zIH0gZnJvbSAnLi9FbGVtZW50VmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IFZhbGlkYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi9WYWxpZGF0aW9uU2VydmljZS5qcyc7XG5pbXBvcnQgeyBUcmlnZ2VyVmFsaWRhdGlvblNlcnZpY2UgfSBmcm9tICcuL1RyaWdnZXJWYWxpZGF0aW9uU2VydmljZS5qcyc7XG5pbXBvcnQgeyBNZXRhZGF0YVNlcnZpY2UgfSBmcm9tICcuLi9NZXRhZGF0YVNlcnZpY2UuanMnO1xuaW1wb3J0IHtcbiAgQUNUSVZBVElPTl9TVFJBVEVHSUVTLFxuICBDT05GTElDVF9TVFJBVEVHSUVTLFxuICBFTEVNRU5UX1JPTEVTLFxuICBBQ1RJVkFUSU9OX01PREVTLFxuICBFTlNFTUJMRV9MSU1JVFMsXG4gIEVOU0VNQkxFX0RFRkFVTFRTXG59IGZyb20gJy4uLy4uL2VsZW1lbnRzL2Vuc2VtYmxlcy9jb25zdGFudHMuanMnO1xuXG5jb25zdCBWQUxJRF9FTEVNRU5UX1RZUEVTOiBFbGVtZW50VHlwZVtdID0gW1xuICBFbGVtZW50VHlwZS5QRVJTT05BLFxuICBFbGVtZW50VHlwZS5TS0lMTCxcbiAgRWxlbWVudFR5cGUuVEVNUExBVEUsXG4gIEVsZW1lbnRUeXBlLkFHRU5ULFxuICBFbGVtZW50VHlwZS5NRU1PUlksXG4gIEVsZW1lbnRUeXBlLkVOU0VNQkxFXG5dO1xuXG4vKipcbiAqIE1hcCBzaW5ndWxhciB0eXBlIG5hbWVzIHRvIHRoZWlyIHBsdXJhbCBFbGVtZW50VHlwZSBlcXVpdmFsZW50c1xuICogQWxsb3dzIHVzZXJzIHRvIHNwZWNpZnkgJ3NraWxsJyBpbnN0ZWFkIG9mICdza2lsbHMnLCBldGMuXG4gKi9cbmNvbnN0IFNJTkdVTEFSX1RPX1BMVVJBTF9UWVBFX01BUDogUmVjb3JkPHN0cmluZywgRWxlbWVudFR5cGU+ID0ge1xuICAncGVyc29uYSc6IEVsZW1lbnRUeXBlLlBFUlNPTkEsXG4gICdza2lsbCc6IEVsZW1lbnRUeXBlLlNLSUxMLFxuICAndGVtcGxhdGUnOiBFbGVtZW50VHlwZS5URU1QTEFURSxcbiAgJ2FnZW50JzogRWxlbWVudFR5cGUuQUdFTlQsXG4gICdtZW1vcnknOiBFbGVtZW50VHlwZS5NRU1PUlksXG4gICdlbnNlbWJsZSc6IEVsZW1lbnRUeXBlLkVOU0VNQkxFLFxuICAvLyBBbHNvIGluY2x1ZGUgcGx1cmFsIGZvcm1zIGZvciBkaXJlY3QgbG9va3VwXG4gICdwZXJzb25hcyc6IEVsZW1lbnRUeXBlLlBFUlNPTkEsXG4gICdza2lsbHMnOiBFbGVtZW50VHlwZS5TS0lMTCxcbiAgJ3RlbXBsYXRlcyc6IEVsZW1lbnRUeXBlLlRFTVBMQVRFLFxuICAnYWdlbnRzJzogRWxlbWVudFR5cGUuQUdFTlQsXG4gICdtZW1vcmllcyc6IEVsZW1lbnRUeXBlLk1FTU9SWSxcbiAgJ2Vuc2VtYmxlcyc6IEVsZW1lbnRUeXBlLkVOU0VNQkxFXG59O1xuXG4vKipcbiAqIE5vcm1hbGl6ZSBlbGVtZW50IHR5cGUgdG8gRWxlbWVudFR5cGUgZW51bSB2YWx1ZVxuICogQWNjZXB0cyBib3RoIHNpbmd1bGFyICgnc2tpbGwnKSBhbmQgcGx1cmFsICgnc2tpbGxzJykgZm9ybXNcbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplRWxlbWVudFR5cGUodHlwZTogc3RyaW5nKTogRWxlbWVudFR5cGUgfCBudWxsIHtcbiAgY29uc3Qgbm9ybWFsaXplZCA9IHR5cGUudG9Mb3dlckNhc2UoKTtcbiAgcmV0dXJuIFNJTkdVTEFSX1RPX1BMVVJBTF9UWVBFX01BUFtub3JtYWxpemVkXSB8fCBudWxsO1xufVxuXG5pbnRlcmZhY2UgRW5zZW1ibGVFbGVtZW50IHtcbiAgLy8gU3VwcG9ydCBib3RoIG5ldyAoZWxlbWVudF9uYW1lL2VsZW1lbnRfdHlwZSkgYW5kIGxlZ2FjeSAobmFtZS90eXBlKSBmaWVsZCBuYW1lc1xuICBlbGVtZW50X25hbWU/OiBzdHJpbmc7XG4gIGVsZW1lbnRfdHlwZT86IHN0cmluZztcbiAgbmFtZT86IHN0cmluZzsgIC8vIExlZ2FjeSAtIGRlcHJlY2F0ZWRcbiAgdHlwZT86IHN0cmluZzsgIC8vIExlZ2FjeSAtIGRlcHJlY2F0ZWRcbiAgcm9sZT86IHN0cmluZztcbiAgYWN0aXZhdGlvbj86IHN0cmluZztcbiAgY29uZGl0aW9uPzogc3RyaW5nO1xuICBkZXBlbmRlbmNpZXM/OiBzdHJpbmdbXTtcbiAgcHVycG9zZT86IHN0cmluZztcbn1cblxuZXhwb3J0IGNsYXNzIEVuc2VtYmxlRWxlbWVudFZhbGlkYXRvciBleHRlbmRzIEdlbmVyaWNFbGVtZW50VmFsaWRhdG9yIHtcbiAgY29uc3RydWN0b3IoXG4gICAgdmFsaWRhdGlvblNlcnZpY2U6IFZhbGlkYXRpb25TZXJ2aWNlLFxuICAgIHRyaWdnZXJWYWxpZGF0aW9uU2VydmljZTogVHJpZ2dlclZhbGlkYXRpb25TZXJ2aWNlLFxuICAgIG1ldGFkYXRhU2VydmljZTogTWV0YWRhdGFTZXJ2aWNlXG4gICkge1xuICAgIHN1cGVyKEVsZW1lbnRUeXBlLkVOU0VNQkxFLCB2YWxpZGF0aW9uU2VydmljZSwgdHJpZ2dlclZhbGlkYXRpb25TZXJ2aWNlLCBtZXRhZGF0YVNlcnZpY2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIE92ZXJyaWRlIHZhbGlkYXRlQ3JlYXRlIHRvIGFkZCBlbnNlbWJsZS1zcGVjaWZpYyB2YWxpZGF0aW9uXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyB2YWxpZGF0ZUNyZWF0ZShcbiAgICBkYXRhOiB1bmtub3duLFxuICAgIG9wdGlvbnM/OiBFbGVtZW50VmFsaWRhdGlvbk9wdGlvbnNcbiAgKTogUHJvbWlzZTxWYWxpZGF0aW9uUmVzdWx0PiB7XG4gICAgLy8gRmlyc3QgcnVuIGdlbmVyaWMgdmFsaWRhdGlvblxuICAgIGNvbnN0IGJhc2VSZXN1bHQgPSBhd2FpdCBzdXBlci52YWxpZGF0ZUNyZWF0ZShkYXRhLCBvcHRpb25zKTtcbiAgICBjb25zdCBlcnJvcnMgPSBbLi4uYmFzZVJlc3VsdC5lcnJvcnNdO1xuICAgIGNvbnN0IHdhcm5pbmdzID0gWy4uLmJhc2VSZXN1bHQud2FybmluZ3NdO1xuICAgIGNvbnN0IHN1Z2dlc3Rpb25zID0gWy4uLihiYXNlUmVzdWx0LnN1Z2dlc3Rpb25zIHx8IFtdKV07XG5cbiAgICBpZiAoIWRhdGEgfHwgdHlwZW9mIGRhdGEgIT09ICdvYmplY3QnKSB7XG4gICAgICByZXR1cm4gYmFzZVJlc3VsdDtcbiAgICB9XG5cbiAgICBjb25zdCByZWNvcmQgPSBkYXRhIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuXG4gICAgLy8gVmFsaWRhdGUgYWN0aXZhdGlvbiBzdHJhdGVneVxuICAgIGlmIChyZWNvcmQuYWN0aXZhdGlvblN0cmF0ZWd5IHx8IHJlY29yZC5hY3RpdmF0aW9uX3N0cmF0ZWd5KSB7XG4gICAgICBjb25zdCBzdHJhdGVneSA9IHJlY29yZC5hY3RpdmF0aW9uU3RyYXRlZ3kgfHwgcmVjb3JkLmFjdGl2YXRpb25fc3RyYXRlZ3k7XG4gICAgICBjb25zdCBzdHJhdGVneVJlc3VsdCA9IHRoaXMudmFsaWRhdGVBY3RpdmF0aW9uU3RyYXRlZ3koc3RyYXRlZ3kpO1xuICAgICAgaWYgKCFzdHJhdGVneVJlc3VsdC5pc1ZhbGlkKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKC4uLnN0cmF0ZWd5UmVzdWx0LmVycm9ycyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gVmFsaWRhdGUgY29uZmxpY3QgcmVzb2x1dGlvblxuICAgIGlmIChyZWNvcmQuY29uZmxpY3RSZXNvbHV0aW9uIHx8IHJlY29yZC5jb25mbGljdF9yZXNvbHV0aW9uKSB7XG4gICAgICBjb25zdCByZXNvbHV0aW9uID0gcmVjb3JkLmNvbmZsaWN0UmVzb2x1dGlvbiB8fCByZWNvcmQuY29uZmxpY3RfcmVzb2x1dGlvbjtcbiAgICAgIGNvbnN0IHJlc29sdXRpb25SZXN1bHQgPSB0aGlzLnZhbGlkYXRlQ29uZmxpY3RSZXNvbHV0aW9uKHJlc29sdXRpb24pO1xuICAgICAgaWYgKCFyZXNvbHV0aW9uUmVzdWx0LmlzVmFsaWQpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goLi4ucmVzb2x1dGlvblJlc3VsdC5lcnJvcnMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIGNvbnRleHQgc2hhcmluZ1xuICAgIGlmIChyZWNvcmQuY29udGV4dFNoYXJpbmcgfHwgcmVjb3JkLmNvbnRleHRfc2hhcmluZykge1xuICAgICAgY29uc3Qgc2hhcmluZyA9IHJlY29yZC5jb250ZXh0U2hhcmluZyB8fCByZWNvcmQuY29udGV4dF9zaGFyaW5nO1xuICAgICAgY29uc3Qgc2hhcmluZ1Jlc3VsdCA9IHRoaXMudmFsaWRhdGVDb250ZXh0U2hhcmluZyhzaGFyaW5nKTtcbiAgICAgIGlmICghc2hhcmluZ1Jlc3VsdC5pc1ZhbGlkKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKC4uLnNoYXJpbmdSZXN1bHQuZXJyb3JzKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSBlbnNlbWJsZSBlbGVtZW50c1xuICAgIGlmIChyZWNvcmQuZWxlbWVudHMpIHtcbiAgICAgIC8vIFVzZSB0ZXJuYXJ5IHRvIHByb3Blcmx5IGhhbmRsZSBmYWxzeSB2YWx1ZXMgKHx8IHRyZWF0cyBmYWxzZS8wIGFzIGZhbHN5KVxuICAgICAgY29uc3QgYWxsb3dOZXN0ZWQgPSByZWNvcmQuYWxsb3dOZXN0ZWQgIT09IHVuZGVmaW5lZCA/IHJlY29yZC5hbGxvd05lc3RlZCA6IHJlY29yZC5hbGxvd19uZXN0ZWQ7XG4gICAgICBjb25zdCBtYXhOZXN0aW5nRGVwdGggPSByZWNvcmQubWF4TmVzdGluZ0RlcHRoICE9PSB1bmRlZmluZWQgPyByZWNvcmQubWF4TmVzdGluZ0RlcHRoIDogcmVjb3JkLm1heF9uZXN0aW5nX2RlcHRoO1xuICAgICAgY29uc3QgZWxlbWVudHNSZXN1bHQgPSBhd2FpdCB0aGlzLnZhbGlkYXRlRW5zZW1ibGVFbGVtZW50cyhcbiAgICAgICAgcmVjb3JkLmVsZW1lbnRzLFxuICAgICAgICBhbGxvd05lc3RlZCxcbiAgICAgICAgbWF4TmVzdGluZ0RlcHRoXG4gICAgICApO1xuICAgICAgaWYgKCFlbGVtZW50c1Jlc3VsdC5pc1ZhbGlkKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKC4uLmVsZW1lbnRzUmVzdWx0LmVycm9ycyk7XG4gICAgICB9XG4gICAgICB3YXJuaW5ncy5wdXNoKC4uLmVsZW1lbnRzUmVzdWx0Lndhcm5pbmdzKTtcbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSByZXNvdXJjZSBsaW1pdHMgaWYgcHJlc2VudFxuICAgIGlmIChyZWNvcmQucmVzb3VyY2VMaW1pdHMgfHwgcmVjb3JkLnJlc291cmNlX2xpbWl0cykge1xuICAgICAgY29uc3QgbGltaXRzID0gcmVjb3JkLnJlc291cmNlTGltaXRzIHx8IHJlY29yZC5yZXNvdXJjZV9saW1pdHM7XG4gICAgICBjb25zdCBsaW1pdHNSZXN1bHQgPSB0aGlzLnZhbGlkYXRlUmVzb3VyY2VMaW1pdHMobGltaXRzKTtcbiAgICAgIGlmICghbGltaXRzUmVzdWx0LmlzVmFsaWQpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goLi4ubGltaXRzUmVzdWx0LmVycm9ycyk7XG4gICAgICB9XG4gICAgICB3YXJuaW5ncy5wdXNoKC4uLmxpbWl0c1Jlc3VsdC53YXJuaW5ncyk7XG4gICAgfVxuXG4gICAgLy8gRW5zZW1ibGUtc3BlY2lmaWMgc3VnZ2VzdGlvbnNcbiAgICBpZiAoIXJlY29yZC5lbGVtZW50cyB8fCAoQXJyYXkuaXNBcnJheShyZWNvcmQuZWxlbWVudHMpICYmIHJlY29yZC5lbGVtZW50cy5sZW5ndGggPT09IDApKSB7XG4gICAgICB3YXJuaW5ncy5wdXNoKCdFbnNlbWJsZSBoYXMgbm8gZWxlbWVudHMgZGVmaW5lZCcpO1xuICAgIH1cblxuICAgIGlmICghcmVjb3JkLmNvbmZsaWN0UmVzb2x1dGlvbiAmJiAhcmVjb3JkLmNvbmZsaWN0X3Jlc29sdXRpb24pIHtcbiAgICAgIHN1Z2dlc3Rpb25zLnB1c2goJ0NvbnNpZGVyIHNwZWNpZnlpbmcgYSBjb25mbGljdCByZXNvbHV0aW9uIHN0cmF0ZWd5Jyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlzVmFsaWQ6IGVycm9ycy5sZW5ndGggPT09IDAsXG4gICAgICBlcnJvcnMsXG4gICAgICB3YXJuaW5ncyxcbiAgICAgIHN1Z2dlc3Rpb25zOiBzdWdnZXN0aW9ucy5sZW5ndGggPiAwID8gc3VnZ2VzdGlvbnMgOiB1bmRlZmluZWRcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGFjdGl2YXRpb24gc3RyYXRlZ3lcbiAgICovXG4gIHByaXZhdGUgdmFsaWRhdGVBY3RpdmF0aW9uU3RyYXRlZ3koc3RyYXRlZ3k6IHVua25vd24pOiBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICBpZiAodHlwZW9mIHN0cmF0ZWd5ICE9PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIFZhbGlkYXRvckhlbHBlcnMuZmFpbChbJ0FjdGl2YXRpb24gc3RyYXRlZ3kgbXVzdCBiZSBhIHN0cmluZyddKTtcbiAgICB9XG5cbiAgICBpZiAoIUFDVElWQVRJT05fU1RSQVRFR0lFUy5pbmNsdWRlcyhzdHJhdGVneSBhcyBhbnkpKSB7XG4gICAgICByZXR1cm4gVmFsaWRhdG9ySGVscGVycy5mYWlsKFtcbiAgICAgICAgYEludmFsaWQgYWN0aXZhdGlvbiBzdHJhdGVneSAnJHtzdHJhdGVneX0nLiBWYWxpZCBvcHRpb25zOiAke0FDVElWQVRJT05fU1RSQVRFR0lFUy5qb2luKCcsICcpfWBcbiAgICAgIF0pO1xuICAgIH1cblxuICAgIHJldHVybiBWYWxpZGF0b3JIZWxwZXJzLnBhc3MoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBjb25mbGljdCByZXNvbHV0aW9uIHN0cmF0ZWd5XG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlQ29uZmxpY3RSZXNvbHV0aW9uKHJlc29sdXRpb246IHVua25vd24pOiBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICBpZiAodHlwZW9mIHJlc29sdXRpb24gIT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gVmFsaWRhdG9ySGVscGVycy5mYWlsKFsnQ29uZmxpY3QgcmVzb2x1dGlvbiBtdXN0IGJlIGEgc3RyaW5nJ10pO1xuICAgIH1cblxuICAgIGlmICghQ09ORkxJQ1RfU1RSQVRFR0lFUy5pbmNsdWRlcyhyZXNvbHV0aW9uIGFzIGFueSkpIHtcbiAgICAgIHJldHVybiBWYWxpZGF0b3JIZWxwZXJzLmZhaWwoW1xuICAgICAgICBgSW52YWxpZCBjb25mbGljdCByZXNvbHV0aW9uICcke3Jlc29sdXRpb259Jy4gVmFsaWQgb3B0aW9uczogJHtDT05GTElDVF9TVFJBVEVHSUVTLmpvaW4oJywgJyl9YFxuICAgICAgXSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIFZhbGlkYXRvckhlbHBlcnMucGFzcygpO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGNvbnRleHQgc2hhcmluZyBtb2RlXG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlQ29udGV4dFNoYXJpbmcoc2hhcmluZzogdW5rbm93bik6IFZhbGlkYXRpb25SZXN1bHQge1xuICAgIGlmICh0eXBlb2Ygc2hhcmluZyAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHJldHVybiBWYWxpZGF0b3JIZWxwZXJzLmZhaWwoWydDb250ZXh0IHNoYXJpbmcgbXVzdCBiZSBhIHN0cmluZyddKTtcbiAgICB9XG5cbiAgICBpZiAoIVsnbm9uZScsICdzZWxlY3RpdmUnLCAnZnVsbCddLmluY2x1ZGVzKHNoYXJpbmcgYXMgYW55KSkge1xuICAgICAgcmV0dXJuIFZhbGlkYXRvckhlbHBlcnMuZmFpbChbXG4gICAgICAgIGBJbnZhbGlkIGNvbnRleHQgc2hhcmluZyBtb2RlICcke3NoYXJpbmd9Jy4gVmFsaWQgb3B0aW9uczogJHtbJ25vbmUnLCAnc2VsZWN0aXZlJywgJ2Z1bGwnXS5qb2luKCcsICcpfWBcbiAgICAgIF0pO1xuICAgIH1cblxuICAgIHJldHVybiBWYWxpZGF0b3JIZWxwZXJzLnBhc3MoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBlbnNlbWJsZSBlbGVtZW50cyBhcnJheVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB2YWxpZGF0ZUVuc2VtYmxlRWxlbWVudHMoXG4gICAgZWxlbWVudHM6IHVua25vd24sXG4gICAgYWxsb3dOZXN0ZWQ6IHVua25vd24sXG4gICAgbWF4TmVzdGluZ0RlcHRoOiB1bmtub3duXG4gICk6IFByb21pc2U8VmFsaWRhdGlvblJlc3VsdD4ge1xuICAgIGlmICghQXJyYXkuaXNBcnJheShlbGVtZW50cykpIHtcbiAgICAgIHJldHVybiBWYWxpZGF0b3JIZWxwZXJzLmZhaWwoWydFbGVtZW50cyBtdXN0IGJlIGFuIGFycmF5J10pO1xuICAgIH1cblxuICAgIGNvbnN0IGVycm9yczogc3RyaW5nW10gPSBbXTtcbiAgICBjb25zdCB3YXJuaW5nczogc3RyaW5nW10gPSBbXTtcblxuICAgIGlmIChlbGVtZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHdhcm5pbmdzLnB1c2goJ0Vuc2VtYmxlIGhhcyBubyBlbGVtZW50cycpO1xuICAgICAgcmV0dXJuIHsgaXNWYWxpZDogdHJ1ZSwgZXJyb3JzLCB3YXJuaW5ncyB9O1xuICAgIH1cblxuICAgIGlmIChlbGVtZW50cy5sZW5ndGggPiBFTlNFTUJMRV9MSU1JVFMuTUFYX0VMRU1FTlRTKSB7XG4gICAgICBlcnJvcnMucHVzaChgRW5zZW1ibGUgY2Fubm90IGhhdmUgbW9yZSB0aGFuICR7RU5TRU1CTEVfTElNSVRTLk1BWF9FTEVNRU5UU30gZWxlbWVudHNgKTtcbiAgICB9XG5cbiAgICAvLyBUcmFjayBlbGVtZW50IG5hbWVzIGZvciBjaXJjdWxhciBkZXBlbmRlbmN5IGRldGVjdGlvblxuICAgIGNvbnN0IGVsZW1lbnROYW1lcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgIGNvbnN0IGRlcGVuZGVuY2llcyA9IG5ldyBNYXA8c3RyaW5nLCBTZXQ8c3RyaW5nPj4oKTtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZWxlbWVudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBlbGVtZW50c1tpXTtcbiAgICAgIGlmICghZWxlbWVudCB8fCB0eXBlb2YgZWxlbWVudCAhPT0gJ29iamVjdCcpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goYEVsZW1lbnQgYXQgaW5kZXggJHtpfSBtdXN0IGJlIGFuIG9iamVjdGApO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZWxlbSA9IGVsZW1lbnQgYXMgRW5zZW1ibGVFbGVtZW50O1xuXG4gICAgICAvLyBTdXBwb3J0IGJvdGggZWxlbWVudF9uYW1lIChuZXcpIGFuZCBuYW1lIChsZWdhY3kpIGZpZWxkIG5hbWVzXG4gICAgICBjb25zdCBlbGVtTmFtZSA9IGVsZW0uZWxlbWVudF9uYW1lIHx8IGVsZW0ubmFtZTtcblxuICAgICAgLy8gVmFsaWRhdGUgZWxlbWVudCBuYW1lXG4gICAgICBpZiAoIWVsZW1OYW1lKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKGBFbGVtZW50IGF0IGluZGV4ICR7aX0gaXMgbWlzc2luZyByZXF1aXJlZCAnZWxlbWVudF9uYW1lJyAob3IgJ25hbWUnKSBmaWVsZGApO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKGVsZW1lbnROYW1lcy5oYXMoZWxlbU5hbWUpKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKGBEdXBsaWNhdGUgZWxlbWVudCBuYW1lICcke2VsZW1OYW1lfScgYXQgaW5kZXggJHtpfWApO1xuICAgICAgfVxuICAgICAgZWxlbWVudE5hbWVzLmFkZChlbGVtTmFtZSk7XG5cbiAgICAgIC8vIFN1cHBvcnQgYm90aCBlbGVtZW50X3R5cGUgKG5ldykgYW5kIHR5cGUgKGxlZ2FjeSkgZmllbGQgbmFtZXNcbiAgICAgIGNvbnN0IGVsZW1UeXBlID0gZWxlbS5lbGVtZW50X3R5cGUgfHwgZWxlbS50eXBlO1xuXG4gICAgICAvLyBWYWxpZGF0ZSBlbGVtZW50IHR5cGUgLSBhY2NlcHQgYm90aCBzaW5ndWxhciBhbmQgcGx1cmFsIGZvcm1zXG4gICAgICBjb25zdCBub3JtYWxpemVkRWxlbVR5cGUgPSBlbGVtVHlwZSA/IG5vcm1hbGl6ZUVsZW1lbnRUeXBlKGVsZW1UeXBlKSA6IG51bGw7XG4gICAgICBpZiAoIWVsZW1UeXBlKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKGBFbGVtZW50ICcke2VsZW1OYW1lfScgaXMgbWlzc2luZyByZXF1aXJlZCAnZWxlbWVudF90eXBlJyAob3IgJ3R5cGUnKSBmaWVsZGApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKCFub3JtYWxpemVkRWxlbVR5cGUpIHtcbiAgICAgICAgICBlcnJvcnMucHVzaChcbiAgICAgICAgICAgIGBFbGVtZW50ICcke2VsZW1OYW1lfScgaGFzIGludmFsaWQgdHlwZSAnJHtlbGVtVHlwZX0nLiBWYWxpZCB0eXBlczogJHtWQUxJRF9FTEVNRU5UX1RZUEVTLmpvaW4oJywgJyl9YFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gQ2hlY2sgZm9yIG5lc3RlZCBlbnNlbWJsZXMgLSBub3JtYWxpemUgdHlwZSBmb3IgY29tcGFyaXNvblxuICAgICAgaWYgKG5vcm1hbGl6ZWRFbGVtVHlwZSA9PT0gRWxlbWVudFR5cGUuRU5TRU1CTEUpIHtcbiAgICAgICAgaWYgKGFsbG93TmVzdGVkICE9PSB0cnVlKSB7XG4gICAgICAgICAgZXJyb3JzLnB1c2goYE5lc3RlZCBlbnNlbWJsZSAnJHtlbGVtTmFtZX0nIG5vdCBhbGxvd2VkIChzZXQgYWxsb3dOZXN0ZWQ6IHRydWUgdG8gZW5hYmxlKWApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIFZhbGlkYXRlIG5lc3RpbmcgZGVwdGhcbiAgICAgICAgICBjb25zdCBkZXB0aCA9IHR5cGVvZiBtYXhOZXN0aW5nRGVwdGggPT09ICdudW1iZXInID8gbWF4TmVzdGluZ0RlcHRoIDogRU5TRU1CTEVfTElNSVRTLk1BWF9ORVNUSU5HX0RFUFRIO1xuICAgICAgICAgIGlmIChkZXB0aCA8PSAwKSB7XG4gICAgICAgICAgICBlcnJvcnMucHVzaChgTWF4aW11bSBuZXN0aW5nIGRlcHRoIGV4Y2VlZGVkIGZvciBlbnNlbWJsZSAnJHtlbGVtTmFtZX0nYCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIFZhbGlkYXRlIGVsZW1lbnQgcm9sZVxuICAgICAgaWYgKGVsZW0ucm9sZSAmJiAhRUxFTUVOVF9ST0xFUy5pbmNsdWRlcyhlbGVtLnJvbGUgYXMgYW55KSkge1xuICAgICAgICBlcnJvcnMucHVzaChcbiAgICAgICAgICBgRWxlbWVudCAnJHtlbGVtTmFtZX0nIGhhcyBpbnZhbGlkIHJvbGUgJyR7ZWxlbS5yb2xlfScuIFZhbGlkIHJvbGVzOiAke0VMRU1FTlRfUk9MRVMuam9pbignLCAnKX1gXG4gICAgICAgICk7XG4gICAgICB9IGVsc2UgaWYgKCFlbGVtLnJvbGUpIHtcbiAgICAgICAgLy8gSXNzdWUgIzM2NTogV2FybiB3aGVuIHJvbGUgZGVmYXVsdHMgYXJlIGFwcGxpZWRcbiAgICAgICAgd2FybmluZ3MucHVzaChcbiAgICAgICAgICBgRWxlbWVudCAnJHtlbGVtTmFtZX0nIGhhcyBubyByb2xlIHNwZWNpZmllZCwgd2lsbCBkZWZhdWx0IHRvICcke0VOU0VNQkxFX0RFRkFVTFRTLkVMRU1FTlRfUk9MRX0nLiBWYWxpZCByb2xlczogJHtFTEVNRU5UX1JPTEVTLmpvaW4oJywgJyl9YFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBWYWxpZGF0ZSBhY3RpdmF0aW9uIG1vZGVcbiAgICAgIGlmIChlbGVtLmFjdGl2YXRpb24gJiYgIUFDVElWQVRJT05fTU9ERVMuaW5jbHVkZXMoZWxlbS5hY3RpdmF0aW9uIGFzIGFueSkpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goXG4gICAgICAgICAgYEVsZW1lbnQgJyR7ZWxlbU5hbWV9JyBoYXMgaW52YWxpZCBhY3RpdmF0aW9uICcke2VsZW0uYWN0aXZhdGlvbn0nLiBWYWxpZCBtb2RlczogJHtBQ1RJVkFUSU9OX01PREVTLmpvaW4oJywgJyl9YFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBWYWxpZGF0ZSBjb25kaXRpb24gaWYgYWN0aXZhdGlvbiBpcyBjb25kaXRpb25hbFxuICAgICAgaWYgKGVsZW0uYWN0aXZhdGlvbiA9PT0gJ2NvbmRpdGlvbmFsJyAmJiAhZWxlbS5jb25kaXRpb24pIHtcbiAgICAgICAgZXJyb3JzLnB1c2goYEVsZW1lbnQgJyR7ZWxlbU5hbWV9JyBoYXMgY29uZGl0aW9uYWwgYWN0aXZhdGlvbiBidXQgbm8gY29uZGl0aW9uIHNwZWNpZmllZGApO1xuICAgICAgfVxuXG4gICAgICAvLyBUcmFjayBkZXBlbmRlbmNpZXMgZm9yIGNpcmN1bGFyIGRldGVjdGlvblxuICAgICAgaWYgKGVsZW0uZGVwZW5kZW5jaWVzICYmIEFycmF5LmlzQXJyYXkoZWxlbS5kZXBlbmRlbmNpZXMpKSB7XG4gICAgICAgIGRlcGVuZGVuY2llcy5zZXQoZWxlbU5hbWUsIG5ldyBTZXQoZWxlbS5kZXBlbmRlbmNpZXMpKTtcblxuICAgICAgICAvLyBDaGVjayB0aGF0IGRlcGVuZGVuY2llcyBleGlzdFxuICAgICAgICBmb3IgKGNvbnN0IGRlcCBvZiBlbGVtLmRlcGVuZGVuY2llcykge1xuICAgICAgICAgIGNvbnN0IGRlcEV4aXN0cyA9IGVsZW1lbnROYW1lcy5oYXMoZGVwKSB8fCBlbGVtZW50cy5zb21lKGUgPT4ge1xuICAgICAgICAgICAgY29uc3QgZWwgPSBlIGFzIEVuc2VtYmxlRWxlbWVudDtcbiAgICAgICAgICAgIHJldHVybiAoZWwuZWxlbWVudF9uYW1lIHx8IGVsLm5hbWUpID09PSBkZXA7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgaWYgKCFkZXBFeGlzdHMpIHtcbiAgICAgICAgICAgIHdhcm5pbmdzLnB1c2goYEVsZW1lbnQgJyR7ZWxlbU5hbWV9JyBkZXBlbmRzIG9uIHVua25vd24gZWxlbWVudCAnJHtkZXB9J2ApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChlbGVtLmRlcGVuZGVuY2llcy5sZW5ndGggPiBFTlNFTUJMRV9MSU1JVFMuTUFYX0RFUEVOREVOQ0lFUykge1xuICAgICAgICAgIGVycm9ycy5wdXNoKFxuICAgICAgICAgICAgYEVsZW1lbnQgJyR7ZWxlbU5hbWV9JyBoYXMgdG9vIG1hbnkgZGVwZW5kZW5jaWVzICgke2VsZW0uZGVwZW5kZW5jaWVzLmxlbmd0aH0gPiAke0VOU0VNQkxFX0xJTUlUUy5NQVhfREVQRU5ERU5DSUVTfSlgXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIERldGVjdCBjaXJjdWxhciBkZXBlbmRlbmNpZXNcbiAgICBjb25zdCBjaXJjdWxhckRlcHMgPSB0aGlzLmRldGVjdENpcmN1bGFyRGVwZW5kZW5jaWVzKGRlcGVuZGVuY2llcyk7XG4gICAgaWYgKGNpcmN1bGFyRGVwcy5sZW5ndGggPiAwKSB7XG4gICAgICBlcnJvcnMucHVzaChgQ2lyY3VsYXIgZGVwZW5kZW5jaWVzIGRldGVjdGVkOiAke2NpcmN1bGFyRGVwcy5qb2luKCcgLT4gJyl9YCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlzVmFsaWQ6IGVycm9ycy5sZW5ndGggPT09IDAsXG4gICAgICBlcnJvcnMsXG4gICAgICB3YXJuaW5nc1xuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogRGV0ZWN0IGNpcmN1bGFyIGRlcGVuZGVuY2llcyBpbiBlbGVtZW50IGdyYXBoXG4gICAqL1xuICBwcml2YXRlIGRldGVjdENpcmN1bGFyRGVwZW5kZW5jaWVzKGRlcGVuZGVuY2llczogTWFwPHN0cmluZywgU2V0PHN0cmluZz4+KTogc3RyaW5nW10ge1xuICAgIGNvbnN0IHZpc2l0ZWQgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBjb25zdCByZWN1cnNpb25TdGFjayA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgIGNvbnN0IHBhdGg6IHN0cmluZ1tdID0gW107XG5cbiAgICBjb25zdCBoYXNDeWNsZSA9IChub2RlOiBzdHJpbmcpOiBib29sZWFuID0+IHtcbiAgICAgIHZpc2l0ZWQuYWRkKG5vZGUpO1xuICAgICAgcmVjdXJzaW9uU3RhY2suYWRkKG5vZGUpO1xuICAgICAgcGF0aC5wdXNoKG5vZGUpO1xuXG4gICAgICBjb25zdCBkZXBzID0gZGVwZW5kZW5jaWVzLmdldChub2RlKTtcbiAgICAgIGlmIChkZXBzKSB7XG4gICAgICAgIGZvciAoY29uc3QgZGVwIG9mIGRlcHMpIHtcbiAgICAgICAgICBpZiAoIXZpc2l0ZWQuaGFzKGRlcCkpIHtcbiAgICAgICAgICAgIGlmIChoYXNDeWNsZShkZXApKSB7XG4gICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSBpZiAocmVjdXJzaW9uU3RhY2suaGFzKGRlcCkpIHtcbiAgICAgICAgICAgIC8vIEZvdW5kIGN5Y2xlXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmVjdXJzaW9uU3RhY2suZGVsZXRlKG5vZGUpO1xuICAgICAgcGF0aC5wb3AoKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuXG4gICAgZm9yIChjb25zdCBub2RlIG