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.

303 lines 41.3 kB
/** * SkillElementValidator - Specialized validator for Skill elements * * Extends GenericElementValidator to add Skill-specific validation: * - Complexity enum validation (beginner/intermediate/advanced/expert) * - Proficiency level range validation (0-100) * - Languages and domains array validation * - Parameters array validation with type-specific rules * - Examples array validation * - Version semver format validation */ import { ElementType } from '../../portfolio/types.js'; import { GenericElementValidator } from './GenericElementValidator.js'; import { ValidatorHelpers } from './ElementValidator.js'; const VALID_COMPLEXITY_LEVELS = ['beginner', 'intermediate', 'advanced', 'expert']; const VALID_PARAMETER_TYPES = ['string', 'number', 'boolean', 'enum']; const SEMVER_REGEX = /^\d+\.\d+\.\d+(?:-[\w.]+)?(?:\+[\w.]+)?$/; /** * Specialized validator for Skill elements. * Validates skill-specific fields: complexity, proficiency_level, languages, * domains, parameters, examples, and version (semver). */ export class SkillElementValidator extends GenericElementValidator { constructor(validationService, triggerValidationService, metadataService) { super(ElementType.SKILL, validationService, triggerValidationService, metadataService); } /** * Override validateCreate to add skill-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 ? [...baseResult.suggestions] : []; if (!data || typeof data !== 'object') { return baseResult; } const record = data; // Validate complexity enum if (record.complexity !== undefined) { const complexityResult = this.validateComplexity(record.complexity); if (!complexityResult.isValid) { errors.push(...complexityResult.errors); } } // Validate proficiency_level range (0-100) if (record.proficiency_level !== undefined) { const proficiencyResult = this.validateProficiencyLevel(record.proficiency_level); if (!proficiencyResult.isValid) { errors.push(...proficiencyResult.errors); } } // Validate languages array if (record.languages !== undefined) { const languagesResult = this.validateStringArray(record.languages, 'languages'); if (!languagesResult.isValid) { errors.push(...languagesResult.errors); } } // Validate domains array if (record.domains !== undefined) { const domainsResult = this.validateStringArray(record.domains, 'domains'); if (!domainsResult.isValid) { errors.push(...domainsResult.errors); } } // Validate parameters array if (record.parameters !== undefined) { const paramsResult = this.validateParameters(record.parameters); if (!paramsResult.isValid) { errors.push(...paramsResult.errors); } warnings.push(...paramsResult.warnings); } // Validate examples array if (record.examples !== undefined) { const examplesResult = this.validateExamples(record.examples); if (!examplesResult.isValid) { errors.push(...examplesResult.errors); } } // Validate version semver format if (record.version !== undefined) { const versionResult = this.validateVersion(record.version); if (!versionResult.isValid) { errors.push(...versionResult.errors); } } // Note: empty domains/examples warnings are emitted by Skill.validate() // to avoid duplication in the combined validateElement output. return { isValid: errors.length === 0, errors, warnings, suggestions: suggestions.length > 0 ? suggestions : undefined }; } /** * Override validateMetadata to add skill-specific metadata validation */ async validateMetadata(metadata, options) { // Start with base metadata validation const baseResult = await super.validateMetadata(metadata, { ...options, requiredFields: options?.requiredFields ?? ['name', 'description'] }); const errors = [...baseResult.errors]; const warnings = [...baseResult.warnings]; if (!metadata || typeof metadata !== 'object') { return baseResult; } const record = metadata; // Validate complexity enum if (record.complexity !== undefined) { const complexityResult = this.validateComplexity(record.complexity); if (!complexityResult.isValid) { errors.push(...complexityResult.errors); } } // Validate proficiency_level range (0-100) if (record.proficiency_level !== undefined) { const proficiencyResult = this.validateProficiencyLevel(record.proficiency_level); if (!proficiencyResult.isValid) { errors.push(...proficiencyResult.errors); } } // Validate languages array if (record.languages !== undefined) { const languagesResult = this.validateStringArray(record.languages, 'languages'); if (!languagesResult.isValid) { errors.push(...languagesResult.errors); } } // Validate domains array if (record.domains !== undefined) { const domainsResult = this.validateStringArray(record.domains, 'domains'); if (!domainsResult.isValid) { errors.push(...domainsResult.errors); } } // Validate parameters array if (record.parameters !== undefined) { const paramsResult = this.validateParameters(record.parameters); if (!paramsResult.isValid) { errors.push(...paramsResult.errors); } warnings.push(...paramsResult.warnings); } // Validate examples array if (record.examples !== undefined) { const examplesResult = this.validateExamples(record.examples); if (!examplesResult.isValid) { errors.push(...examplesResult.errors); } } // Validate version semver format if (record.version !== undefined) { const versionResult = this.validateVersion(record.version); if (!versionResult.isValid) { errors.push(...versionResult.errors); } } // Note: empty domains/examples warnings are emitted by Skill.validate() // to avoid duplication in the combined validateElement output. return { isValid: errors.length === 0, errors, warnings }; } /** * Validate complexity enum value */ validateComplexity(complexity) { if (typeof complexity !== 'string') { return ValidatorHelpers.fail(['Complexity must be a string']); } if (!VALID_COMPLEXITY_LEVELS.includes(complexity)) { return ValidatorHelpers.fail([ `Invalid complexity '${complexity}'. Valid options: ${VALID_COMPLEXITY_LEVELS.join(', ')}` ]); } return ValidatorHelpers.pass(); } /** * Validate proficiency_level is a number in range 0-100 */ validateProficiencyLevel(level) { if (typeof level !== 'number') { return ValidatorHelpers.fail(['Proficiency level must be a number']); } if (level < 0 || level > 100) { return ValidatorHelpers.fail([ `Proficiency level must be between 0 and 100, got ${level}` ]); } return ValidatorHelpers.pass(); } /** * Validate that a field is an array of strings */ validateStringArray(value, fieldName) { if (!Array.isArray(value)) { return ValidatorHelpers.fail([`${fieldName} must be an array`]); } for (let i = 0; i < value.length; i++) { if (typeof value[i] !== 'string') { return ValidatorHelpers.fail([ `${fieldName}[${i}] must be a string` ]); } } return ValidatorHelpers.pass(); } /** * Validate parameters array with type-specific rules */ validateParameters(parameters) { if (!Array.isArray(parameters)) { return ValidatorHelpers.fail(['Parameters must be an array']); } const errors = []; const warnings = []; for (let i = 0; i < parameters.length; i++) { const param = parameters[i]; if (!param || typeof param !== 'object') { errors.push(`Parameter at index ${i} must be an object`); continue; } const p = param; // name is required and must be non-empty string if (!p.name || typeof p.name !== 'string' || p.name.trim().length === 0) { errors.push(`Parameter at index ${i} is missing required non-empty 'name' field`); } // type is required and must be one of the valid types if (!p.type || typeof p.type !== 'string') { errors.push(`Parameter at index ${i} is missing required 'type' field`); } else if (!VALID_PARAMETER_TYPES.includes(p.type)) { errors.push(`Parameter '${p.name || i}' has invalid type '${p.type}'. Valid types: ${VALID_PARAMETER_TYPES.join(', ')}`); } // description is required if (!p.description || typeof p.description !== 'string') { errors.push(`Parameter '${p.name || i}' is missing required 'description' field`); } // enum-type parameters need options array if (p.type === 'enum') { if (!p.options || !Array.isArray(p.options) || p.options.length === 0) { errors.push(`Parameter '${p.name || i}' has type 'enum' but is missing or has empty 'options' array`); } } } return { isValid: errors.length === 0, errors, warnings }; } /** * Validate examples array */ validateExamples(examples) { if (!Array.isArray(examples)) { return ValidatorHelpers.fail(['Examples must be an array']); } const errors = []; for (let i = 0; i < examples.length; i++) { const example = examples[i]; if (!example || typeof example !== 'object') { errors.push(`Example at index ${i} must be an object`); continue; } const ex = example; if (!ex.title || typeof ex.title !== 'string') { errors.push(`Example at index ${i} is missing required 'title' field`); } if (!ex.description || typeof ex.description !== 'string') { errors.push(`Example at index ${i} is missing required 'description' field`); } } return { isValid: errors.length === 0, errors, warnings: [] }; } /** * Validate version follows semver format */ validateVersion(version) { if (typeof version !== 'string') { return ValidatorHelpers.fail(['Version must be a string']); } if (!SEMVER_REGEX.test(version)) { return ValidatorHelpers.fail([ `Version '${version}' is not valid semver format (expected: major.minor.patch, e.g., 1.0.0)` ]); } return ValidatorHelpers.pass(); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2tpbGxFbGVtZW50VmFsaWRhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZpY2VzL3ZhbGlkYXRpb24vU2tpbGxFbGVtZW50VmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7O0dBVUc7QUFFSCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDdkQsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDdkUsT0FBTyxFQUFvQixnQkFBZ0IsRUFBdUQsTUFBTSx1QkFBdUIsQ0FBQztBQUtoSSxNQUFNLHVCQUF1QixHQUFHLENBQUMsVUFBVSxFQUFFLGNBQWMsRUFBRSxVQUFVLEVBQUUsUUFBUSxDQUFVLENBQUM7QUFDNUYsTUFBTSxxQkFBcUIsR0FBRyxDQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLE1BQU0sQ0FBVSxDQUFDO0FBQy9FLE1BQU0sWUFBWSxHQUFHLDBDQUEwQyxDQUFDO0FBRWhFOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8scUJBQXNCLFNBQVEsdUJBQXVCO0lBQ2hFLFlBQ0UsaUJBQW9DLEVBQ3BDLHdCQUFrRCxFQUNsRCxlQUFnQztRQUVoQyxLQUFLLENBQUMsV0FBVyxDQUFDLEtBQUssRUFBRSxpQkFBaUIsRUFBRSx3QkFBd0IsRUFBRSxlQUFlLENBQUMsQ0FBQztJQUN6RixDQUFDO0lBRUQ7O09BRUc7SUFDTSxLQUFLLENBQUMsY0FBYyxDQUMzQixJQUFhLEVBQ2IsT0FBa0M7UUFFbEMsK0JBQStCO1FBQy9CLE1BQU0sVUFBVSxHQUFHLE1BQU0sS0FBSyxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDN0QsTUFBTSxNQUFNLEdBQUcsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN0QyxNQUFNLFFBQVEsR0FBRyxDQUFDLEdBQUcsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQzFDLE1BQU0sV0FBVyxHQUFHLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUU5RSxJQUFJLENBQUMsSUFBSSxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ3RDLE9BQU8sVUFBVSxDQUFDO1FBQ3BCLENBQUM7UUFFRCxNQUFNLE1BQU0sR0FBRyxJQUErQixDQUFDO1FBRS9DLDJCQUEyQjtRQUMzQixJQUFJLE1BQU0sQ0FBQyxVQUFVLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDcEMsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ3BFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDOUIsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQzFDLENBQUM7UUFDSCxDQUFDO1FBRUQsMkNBQTJDO1FBQzNDLElBQUksTUFBTSxDQUFDLGlCQUFpQixLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzNDLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1lBQ2xGLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDL0IsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQzNDLENBQUM7UUFDSCxDQUFDO1FBRUQsMkJBQTJCO1FBQzNCLElBQUksTUFBTSxDQUFDLFNBQVMsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNuQyxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxXQUFXLENBQUMsQ0FBQztZQUNoRixJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUM3QixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsZUFBZSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3pDLENBQUM7UUFDSCxDQUFDO1FBRUQseUJBQXlCO1FBQ3pCLElBQUksTUFBTSxDQUFDLE9BQU8sS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNqQyxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsQ0FBQztZQUMxRSxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUMzQixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3ZDLENBQUM7UUFDSCxDQUFDO1FBRUQsNEJBQTRCO1FBQzVCLElBQUksTUFBTSxDQUFDLFVBQVUsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNwQyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ2hFLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQzFCLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDdEMsQ0FBQztZQUNELFFBQVEsQ0FBQyxJQUFJLENBQUMsR0FBRyxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDMUMsQ0FBQztRQUVELDBCQUEwQjtRQUMxQixJQUFJLE1BQU0sQ0FBQyxRQUFRLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDbEMsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUM5RCxJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUM1QixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsY0FBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3hDLENBQUM7UUFDSCxDQUFDO1FBRUQsaUNBQWlDO1FBQ2pDLElBQUksTUFBTSxDQUFDLE9BQU8sS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNqQyxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUMzRCxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUMzQixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3ZDLENBQUM7UUFDSCxDQUFDO1FBRUQsd0VBQXdFO1FBQ3hFLCtEQUErRDtRQUUvRCxPQUFPO1lBQ0wsT0FBTyxFQUFFLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUM1QixNQUFNO1lBQ04sUUFBUTtZQUNSLFdBQVcsRUFBRSxXQUFXLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxTQUFTO1NBQzlELENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDTSxLQUFLLENBQUMsZ0JBQWdCLENBQzdCLFFBQWlCLEVBQ2pCLE9BQW1DO1FBRW5DLHNDQUFzQztRQUN0QyxNQUFNLFVBQVUsR0FBRyxNQUFNLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUU7WUFDeEQsR0FBRyxPQUFPO1lBQ1YsY0FBYyxFQUFFLE9BQU8sRUFBRSxjQUFjLElBQUksQ0FBQyxNQUFNLEVBQUUsYUFBYSxDQUFDO1NBQ25FLENBQUMsQ0FBQztRQUVILE1BQU0sTUFBTSxHQUFHLENBQUMsR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDdEMsTUFBTSxRQUFRLEdBQUcsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUUxQyxJQUFJLENBQUMsUUFBUSxJQUFJLE9BQU8sUUFBUSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzlDLE9BQU8sVUFBVSxDQUFDO1FBQ3BCLENBQUM7UUFFRCxNQUFNLE1BQU0sR0FBRyxRQUFtQyxDQUFDO1FBRW5ELDJCQUEyQjtRQUMzQixJQUFJLE1BQU0sQ0FBQyxVQUFVLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDcEMsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ3BFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDOUIsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQzFDLENBQUM7UUFDSCxDQUFDO1FBRUQsMkNBQTJDO1FBQzNDLElBQUksTUFBTSxDQUFDLGlCQUFpQixLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzNDLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1lBQ2xGLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDL0IsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQzNDLENBQUM7UUFDSCxDQUFDO1FBRUQsMkJBQTJCO1FBQzNCLElBQUksTUFBTSxDQUFDLFNBQVMsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNuQyxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxXQUFXLENBQUMsQ0FBQztZQUNoRixJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUM3QixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsZUFBZSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3pDLENBQUM7UUFDSCxDQUFDO1FBRUQseUJBQXlCO1FBQ3pCLElBQUksTUFBTSxDQUFDLE9BQU8sS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNqQyxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsQ0FBQztZQUMxRSxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUMzQixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3ZDLENBQUM7UUFDSCxDQUFDO1FBRUQsNEJBQTRCO1FBQzVCLElBQUksTUFBTSxDQUFDLFVBQVUsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNwQyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ2hFLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQzFCLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDdEMsQ0FBQztZQUNELFFBQVEsQ0FBQyxJQUFJLENBQUMsR0FBRyxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDMUMsQ0FBQztRQUVELDBCQUEwQjtRQUMxQixJQUFJLE1BQU0sQ0FBQyxRQUFRLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDbEMsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUM5RCxJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUM1QixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsY0FBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3hDLENBQUM7UUFDSCxDQUFDO1FBRUQsaUNBQWlDO1FBQ2pDLElBQUksTUFBTSxDQUFDLE9BQU8sS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNqQyxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUMzRCxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUMzQixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3ZDLENBQUM7UUFDSCxDQUFDO1FBRUQsd0VBQXdFO1FBQ3hFLCtEQUErRDtRQUUvRCxPQUFPO1lBQ0wsT0FBTyxFQUFFLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUM1QixNQUFNO1lBQ04sUUFBUTtTQUNULENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSyxrQkFBa0IsQ0FBQyxVQUFtQjtRQUM1QyxJQUFJLE9BQU8sVUFBVSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ25DLE9BQU8sZ0JBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsNkJBQTZCLENBQUMsQ0FBQyxDQUFDO1FBQ2hFLENBQUM7UUFFRCxJQUFJLENBQUUsdUJBQTZDLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDekUsT0FBTyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUM7Z0JBQzNCLHVCQUF1QixVQUFVLHFCQUFxQix1QkFBdUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUU7YUFDM0YsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELE9BQU8sZ0JBQWdCLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDakMsQ0FBQztJQUVEOztPQUVHO0lBQ0ssd0JBQXdCLENBQUMsS0FBYztRQUM3QyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzlCLE9BQU8sZ0JBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsb0NBQW9DLENBQUMsQ0FBQyxDQUFDO1FBQ3ZFLENBQUM7UUFFRCxJQUFJLEtBQUssR0FBRyxDQUFDLElBQUksS0FBSyxHQUFHLEdBQUcsRUFBRSxDQUFDO1lBQzdCLE9BQU8sZ0JBQWdCLENBQUMsSUFBSSxDQUFDO2dCQUMzQixvREFBb0QsS0FBSyxFQUFFO2FBQzVELENBQUMsQ0FBQztRQUNMLENBQUM7UUFFRCxPQUFPLGdCQUFnQixDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7T0FFRztJQUNLLG1CQUFtQixDQUFDLEtBQWMsRUFBRSxTQUFpQjtRQUMzRCxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzFCLE9BQU8sZ0JBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxTQUFTLG1CQUFtQixDQUFDLENBQUMsQ0FBQztRQUNsRSxDQUFDO1FBRUQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUN0QyxJQUFJLE9BQU8sS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUNqQyxPQUFPLGdCQUFnQixDQUFDLElBQUksQ0FBQztvQkFDM0IsR0FBRyxTQUFTLElBQUksQ0FBQyxvQkFBb0I7aUJBQ3RDLENBQUMsQ0FBQztZQUNMLENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTyxnQkFBZ0IsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNqQyxDQUFDO0lBRUQ7O09BRUc7SUFDSyxrQkFBa0IsQ0FBQyxVQUFtQjtRQUM1QyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQy9CLE9BQU8sZ0JBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsNkJBQTZCLENBQUMsQ0FBQyxDQUFDO1FBQ2hFLENBQUM7UUFFRCxNQUFNLE1BQU0sR0FBYSxFQUFFLENBQUM7UUFDNUIsTUFBTSxRQUFRLEdBQWEsRUFBRSxDQUFDO1FBRTlCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDM0MsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRTVCLElBQUksQ0FBQyxLQUFLLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQ3hDLE1BQU0sQ0FBQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsb0JBQW9CLENBQUMsQ0FBQztnQkFDekQsU0FBUztZQUNYLENBQUM7WUFFRCxNQUFNLENBQUMsR0FBRyxLQUFnQyxDQUFDO1lBRTNDLGdEQUFnRDtZQUNoRCxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxPQUFPLENBQUMsQ0FBQyxJQUFJLEtBQUssUUFBUSxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUN4RSxNQUFNLENBQUMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLDZDQUE2QyxDQUFDLENBQUM7WUFDcEYsQ0FBQztZQUVELHNEQUFzRDtZQUN0RCxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxPQUFPLENBQUMsQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQzFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsbUNBQW1DLENBQUMsQ0FBQztZQUMxRSxDQUFDO2lCQUFNLElBQUksQ0FBRSxxQkFBMkMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQzFFLE1BQU0sQ0FBQyxJQUFJLENBQ1QsY0FBYyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsdUJBQXVCLENBQUMsQ0FBQyxJQUFJLG1CQUFtQixxQkFBcUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FDNUcsQ0FBQztZQUNKLENBQUM7WUFFRCwwQkFBMEI7WUFDMUIsSUFBSSxDQUFDLENBQUMsQ0FBQyxXQUFXLElBQUksT0FBTyxDQUFDLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUN4RCxNQUFNLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDLDJDQUEyQyxDQUFDLENBQUM7WUFDcEYsQ0FBQztZQUVELDBDQUEwQztZQUMxQyxJQUFJLENBQUMsQ0FBQyxJQUFJLEtBQUssTUFBTSxFQUFFLENBQUM7Z0JBQ3RCLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7b0JBQ3RFLE1BQU0sQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsK0RBQStELENBQUMsQ0FBQztnQkFDeEcsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTztZQUNMLE9BQU8sRUFBRSxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUM7WUFDNUIsTUFBTTtZQUNOLFFBQVE7U0FDVCxDQUFDO0lBQ0osQ0FBQztJQUVEOztPQUVHO0lBQ0ssZ0JBQWdCLENBQUMsUUFBaUI7UUFDeEMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUM3QixPQUFPLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDLDJCQUEyQixDQUFDLENBQUMsQ0FBQztRQUM5RCxDQUFDO1FBRUQsTUFBTSxNQUFNLEdBQWEsRUFBRSxDQUFDO1FBRTVCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDekMsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRTVCLElBQUksQ0FBQyxPQUFPLElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQzVDLE1BQU0sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsb0JBQW9CLENBQUMsQ0FBQztnQkFDdkQsU0FBUztZQUNYLENBQUM7WUFFRCxNQUFNLEVBQUUsR0FBRyxPQUFrQyxDQUFDO1lBRTlDLElBQUksQ0FBQyxFQUFFLENBQUMsS0FBSyxJQUFJLE9BQU8sRUFBRSxDQUFDLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDOUMsTUFBTSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxvQ0FBb0MsQ0FBQyxDQUFDO1lBQ3pFLENBQUM7WUFFRCxJQUFJLENBQUMsRUFBRSxDQUFDLFdBQVcsSUFBSSxPQUFPLEVBQUUsQ0FBQyxXQUFXLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQzFELE1BQU0sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsMENBQTBDLENBQUMsQ0FBQztZQUMvRSxDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU87WUFDTCxPQUFPLEVBQUUsTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQzVCLE1BQU07WUFDTixRQUFRLEVBQUUsRUFBRTtTQUNiLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSyxlQUFlLENBQUMsT0FBZ0I7UUFDdEMsSUFBSSxPQUFPLE9BQU8sS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUNoQyxPQUFPLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDLDBCQUEwQixDQUFDLENBQUMsQ0FBQztRQUM3RCxDQUFDO1FBRUQsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNoQyxPQUFPLGdCQUFnQixDQUFDLElBQUksQ0FBQztnQkFDM0IsWUFBWSxPQUFPLHlFQUF5RTthQUM3RixDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsT0FBTyxnQkFBZ0IsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNqQyxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNraWxsRWxlbWVudFZhbGlkYXRvciAtIFNwZWNpYWxpemVkIHZhbGlkYXRvciBmb3IgU2tpbGwgZWxlbWVudHNcbiAqXG4gKiBFeHRlbmRzIEdlbmVyaWNFbGVtZW50VmFsaWRhdG9yIHRvIGFkZCBTa2lsbC1zcGVjaWZpYyB2YWxpZGF0aW9uOlxuICogLSBDb21wbGV4aXR5IGVudW0gdmFsaWRhdGlvbiAoYmVnaW5uZXIvaW50ZXJtZWRpYXRlL2FkdmFuY2VkL2V4cGVydClcbiAqIC0gUHJvZmljaWVuY3kgbGV2ZWwgcmFuZ2UgdmFsaWRhdGlvbiAoMC0xMDApXG4gKiAtIExhbmd1YWdlcyBhbmQgZG9tYWlucyBhcnJheSB2YWxpZGF0aW9uXG4gKiAtIFBhcmFtZXRlcnMgYXJyYXkgdmFsaWRhdGlvbiB3aXRoIHR5cGUtc3BlY2lmaWMgcnVsZXNcbiAqIC0gRXhhbXBsZXMgYXJyYXkgdmFsaWRhdGlvblxuICogLSBWZXJzaW9uIHNlbXZlciBmb3JtYXQgdmFsaWRhdGlvblxuICovXG5cbmltcG9ydCB7IEVsZW1lbnRUeXBlIH0gZnJvbSAnLi4vLi4vcG9ydGZvbGlvL3R5cGVzLmpzJztcbmltcG9ydCB7IEdlbmVyaWNFbGVtZW50VmFsaWRhdG9yIH0gZnJvbSAnLi9HZW5lcmljRWxlbWVudFZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBWYWxpZGF0aW9uUmVzdWx0LCBWYWxpZGF0b3JIZWxwZXJzLCBFbGVtZW50VmFsaWRhdGlvbk9wdGlvbnMsIE1ldGFkYXRhVmFsaWRhdGlvbk9wdGlvbnMgfSBmcm9tICcuL0VsZW1lbnRWYWxpZGF0b3IuanMnO1xuaW1wb3J0IHsgVmFsaWRhdGlvblNlcnZpY2UgfSBmcm9tICcuL1ZhbGlkYXRpb25TZXJ2aWNlLmpzJztcbmltcG9ydCB7IFRyaWdnZXJWYWxpZGF0aW9uU2VydmljZSB9IGZyb20gJy4vVHJpZ2dlclZhbGlkYXRpb25TZXJ2aWNlLmpzJztcbmltcG9ydCB7IE1ldGFkYXRhU2VydmljZSB9IGZyb20gJy4uL01ldGFkYXRhU2VydmljZS5qcyc7XG5cbmNvbnN0IFZBTElEX0NPTVBMRVhJVFlfTEVWRUxTID0gWydiZWdpbm5lcicsICdpbnRlcm1lZGlhdGUnLCAnYWR2YW5jZWQnLCAnZXhwZXJ0J10gYXMgY29uc3Q7XG5jb25zdCBWQUxJRF9QQVJBTUVURVJfVFlQRVMgPSBbJ3N0cmluZycsICdudW1iZXInLCAnYm9vbGVhbicsICdlbnVtJ10gYXMgY29uc3Q7XG5jb25zdCBTRU1WRVJfUkVHRVggPSAvXlxcZCtcXC5cXGQrXFwuXFxkKyg/Oi1bXFx3Ll0rKT8oPzpcXCtbXFx3Ll0rKT8kLztcblxuLyoqXG4gKiBTcGVjaWFsaXplZCB2YWxpZGF0b3IgZm9yIFNraWxsIGVsZW1lbnRzLlxuICogVmFsaWRhdGVzIHNraWxsLXNwZWNpZmljIGZpZWxkczogY29tcGxleGl0eSwgcHJvZmljaWVuY3lfbGV2ZWwsIGxhbmd1YWdlcyxcbiAqIGRvbWFpbnMsIHBhcmFtZXRlcnMsIGV4YW1wbGVzLCBhbmQgdmVyc2lvbiAoc2VtdmVyKS5cbiAqL1xuZXhwb3J0IGNsYXNzIFNraWxsRWxlbWVudFZhbGlkYXRvciBleHRlbmRzIEdlbmVyaWNFbGVtZW50VmFsaWRhdG9yIHtcbiAgY29uc3RydWN0b3IoXG4gICAgdmFsaWRhdGlvblNlcnZpY2U6IFZhbGlkYXRpb25TZXJ2aWNlLFxuICAgIHRyaWdnZXJWYWxpZGF0aW9uU2VydmljZTogVHJpZ2dlclZhbGlkYXRpb25TZXJ2aWNlLFxuICAgIG1ldGFkYXRhU2VydmljZTogTWV0YWRhdGFTZXJ2aWNlXG4gICkge1xuICAgIHN1cGVyKEVsZW1lbnRUeXBlLlNLSUxMLCB2YWxpZGF0aW9uU2VydmljZSwgdHJpZ2dlclZhbGlkYXRpb25TZXJ2aWNlLCBtZXRhZGF0YVNlcnZpY2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIE92ZXJyaWRlIHZhbGlkYXRlQ3JlYXRlIHRvIGFkZCBza2lsbC1zcGVjaWZpYyB2YWxpZGF0aW9uXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyB2YWxpZGF0ZUNyZWF0ZShcbiAgICBkYXRhOiB1bmtub3duLFxuICAgIG9wdGlvbnM/OiBFbGVtZW50VmFsaWRhdGlvbk9wdGlvbnNcbiAgKTogUHJvbWlzZTxWYWxpZGF0aW9uUmVzdWx0PiB7XG4gICAgLy8gRmlyc3QgcnVuIGdlbmVyaWMgdmFsaWRhdGlvblxuICAgIGNvbnN0IGJhc2VSZXN1bHQgPSBhd2FpdCBzdXBlci52YWxpZGF0ZUNyZWF0ZShkYXRhLCBvcHRpb25zKTtcbiAgICBjb25zdCBlcnJvcnMgPSBbLi4uYmFzZVJlc3VsdC5lcnJvcnNdO1xuICAgIGNvbnN0IHdhcm5pbmdzID0gWy4uLmJhc2VSZXN1bHQud2FybmluZ3NdO1xuICAgIGNvbnN0IHN1Z2dlc3Rpb25zID0gYmFzZVJlc3VsdC5zdWdnZXN0aW9ucyA/IFsuLi5iYXNlUmVzdWx0LnN1Z2dlc3Rpb25zXSA6IFtdO1xuXG4gICAgaWYgKCFkYXRhIHx8IHR5cGVvZiBkYXRhICE9PSAnb2JqZWN0Jykge1xuICAgICAgcmV0dXJuIGJhc2VSZXN1bHQ7XG4gICAgfVxuXG4gICAgY29uc3QgcmVjb3JkID0gZGF0YSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcblxuICAgIC8vIFZhbGlkYXRlIGNvbXBsZXhpdHkgZW51bVxuICAgIGlmIChyZWNvcmQuY29tcGxleGl0eSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBjb21wbGV4aXR5UmVzdWx0ID0gdGhpcy52YWxpZGF0ZUNvbXBsZXhpdHkocmVjb3JkLmNvbXBsZXhpdHkpO1xuICAgICAgaWYgKCFjb21wbGV4aXR5UmVzdWx0LmlzVmFsaWQpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goLi4uY29tcGxleGl0eVJlc3VsdC5lcnJvcnMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIHByb2ZpY2llbmN5X2xldmVsIHJhbmdlICgwLTEwMClcbiAgICBpZiAocmVjb3JkLnByb2ZpY2llbmN5X2xldmVsICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IHByb2ZpY2llbmN5UmVzdWx0ID0gdGhpcy52YWxpZGF0ZVByb2ZpY2llbmN5TGV2ZWwocmVjb3JkLnByb2ZpY2llbmN5X2xldmVsKTtcbiAgICAgIGlmICghcHJvZmljaWVuY3lSZXN1bHQuaXNWYWxpZCkge1xuICAgICAgICBlcnJvcnMucHVzaCguLi5wcm9maWNpZW5jeVJlc3VsdC5lcnJvcnMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIGxhbmd1YWdlcyBhcnJheVxuICAgIGlmIChyZWNvcmQubGFuZ3VhZ2VzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IGxhbmd1YWdlc1Jlc3VsdCA9IHRoaXMudmFsaWRhdGVTdHJpbmdBcnJheShyZWNvcmQubGFuZ3VhZ2VzLCAnbGFuZ3VhZ2VzJyk7XG4gICAgICBpZiAoIWxhbmd1YWdlc1Jlc3VsdC5pc1ZhbGlkKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKC4uLmxhbmd1YWdlc1Jlc3VsdC5lcnJvcnMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIGRvbWFpbnMgYXJyYXlcbiAgICBpZiAocmVjb3JkLmRvbWFpbnMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgZG9tYWluc1Jlc3VsdCA9IHRoaXMudmFsaWRhdGVTdHJpbmdBcnJheShyZWNvcmQuZG9tYWlucywgJ2RvbWFpbnMnKTtcbiAgICAgIGlmICghZG9tYWluc1Jlc3VsdC5pc1ZhbGlkKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKC4uLmRvbWFpbnNSZXN1bHQuZXJyb3JzKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSBwYXJhbWV0ZXJzIGFycmF5XG4gICAgaWYgKHJlY29yZC5wYXJhbWV0ZXJzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IHBhcmFtc1Jlc3VsdCA9IHRoaXMudmFsaWRhdGVQYXJhbWV0ZXJzKHJlY29yZC5wYXJhbWV0ZXJzKTtcbiAgICAgIGlmICghcGFyYW1zUmVzdWx0LmlzVmFsaWQpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goLi4ucGFyYW1zUmVzdWx0LmVycm9ycyk7XG4gICAgICB9XG4gICAgICB3YXJuaW5ncy5wdXNoKC4uLnBhcmFtc1Jlc3VsdC53YXJuaW5ncyk7XG4gICAgfVxuXG4gICAgLy8gVmFsaWRhdGUgZXhhbXBsZXMgYXJyYXlcbiAgICBpZiAocmVjb3JkLmV4YW1wbGVzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IGV4YW1wbGVzUmVzdWx0ID0gdGhpcy52YWxpZGF0ZUV4YW1wbGVzKHJlY29yZC5leGFtcGxlcyk7XG4gICAgICBpZiAoIWV4YW1wbGVzUmVzdWx0LmlzVmFsaWQpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goLi4uZXhhbXBsZXNSZXN1bHQuZXJyb3JzKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSB2ZXJzaW9uIHNlbXZlciBmb3JtYXRcbiAgICBpZiAocmVjb3JkLnZlcnNpb24gIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgdmVyc2lvblJlc3VsdCA9IHRoaXMudmFsaWRhdGVWZXJzaW9uKHJlY29yZC52ZXJzaW9uKTtcbiAgICAgIGlmICghdmVyc2lvblJlc3VsdC5pc1ZhbGlkKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKC4uLnZlcnNpb25SZXN1bHQuZXJyb3JzKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBOb3RlOiBlbXB0eSBkb21haW5zL2V4YW1wbGVzIHdhcm5pbmdzIGFyZSBlbWl0dGVkIGJ5IFNraWxsLnZhbGlkYXRlKClcbiAgICAvLyB0byBhdm9pZCBkdXBsaWNhdGlvbiBpbiB0aGUgY29tYmluZWQgdmFsaWRhdGVFbGVtZW50IG91dHB1dC5cblxuICAgIHJldHVybiB7XG4gICAgICBpc1ZhbGlkOiBlcnJvcnMubGVuZ3RoID09PSAwLFxuICAgICAgZXJyb3JzLFxuICAgICAgd2FybmluZ3MsXG4gICAgICBzdWdnZXN0aW9uczogc3VnZ2VzdGlvbnMubGVuZ3RoID4gMCA/IHN1Z2dlc3Rpb25zIDogdW5kZWZpbmVkXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPdmVycmlkZSB2YWxpZGF0ZU1ldGFkYXRhIHRvIGFkZCBza2lsbC1zcGVjaWZpYyBtZXRhZGF0YSB2YWxpZGF0aW9uXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyB2YWxpZGF0ZU1ldGFkYXRhKFxuICAgIG1ldGFkYXRhOiB1bmtub3duLFxuICAgIG9wdGlvbnM/OiBNZXRhZGF0YVZhbGlkYXRpb25PcHRpb25zXG4gICk6IFByb21pc2U8VmFsaWRhdGlvblJlc3VsdD4ge1xuICAgIC8vIFN0YXJ0IHdpdGggYmFzZSBtZXRhZGF0YSB2YWxpZGF0aW9uXG4gICAgY29uc3QgYmFzZVJlc3VsdCA9IGF3YWl0IHN1cGVyLnZhbGlkYXRlTWV0YWRhdGEobWV0YWRhdGEsIHtcbiAgICAgIC4uLm9wdGlvbnMsXG4gICAgICByZXF1aXJlZEZpZWxkczogb3B0aW9ucz8ucmVxdWlyZWRGaWVsZHMgPz8gWyduYW1lJywgJ2Rlc2NyaXB0aW9uJ11cbiAgICB9KTtcblxuICAgIGNvbnN0IGVycm9ycyA9IFsuLi5iYXNlUmVzdWx0LmVycm9yc107XG4gICAgY29uc3Qgd2FybmluZ3MgPSBbLi4uYmFzZVJlc3VsdC53YXJuaW5nc107XG5cbiAgICBpZiAoIW1ldGFkYXRhIHx8IHR5cGVvZiBtZXRhZGF0YSAhPT0gJ29iamVjdCcpIHtcbiAgICAgIHJldHVybiBiYXNlUmVzdWx0O1xuICAgIH1cblxuICAgIGNvbnN0IHJlY29yZCA9IG1ldGFkYXRhIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuXG4gICAgLy8gVmFsaWRhdGUgY29tcGxleGl0eSBlbnVtXG4gICAgaWYgKHJlY29yZC5jb21wbGV4aXR5ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IGNvbXBsZXhpdHlSZXN1bHQgPSB0aGlzLnZhbGlkYXRlQ29tcGxleGl0eShyZWNvcmQuY29tcGxleGl0eSk7XG4gICAgICBpZiAoIWNvbXBsZXhpdHlSZXN1bHQuaXNWYWxpZCkge1xuICAgICAgICBlcnJvcnMucHVzaCguLi5jb21wbGV4aXR5UmVzdWx0LmVycm9ycyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gVmFsaWRhdGUgcHJvZmljaWVuY3lfbGV2ZWwgcmFuZ2UgKDAtMTAwKVxuICAgIGlmIChyZWNvcmQucHJvZmljaWVuY3lfbGV2ZWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgcHJvZmljaWVuY3lSZXN1bHQgPSB0aGlzLnZhbGlkYXRlUHJvZmljaWVuY3lMZXZlbChyZWNvcmQucHJvZmljaWVuY3lfbGV2ZWwpO1xuICAgICAgaWYgKCFwcm9maWNpZW5jeVJlc3VsdC5pc1ZhbGlkKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKC4uLnByb2ZpY2llbmN5UmVzdWx0LmVycm9ycyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gVmFsaWRhdGUgbGFuZ3VhZ2VzIGFycmF5XG4gICAgaWYgKHJlY29yZC5sYW5ndWFnZXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgbGFuZ3VhZ2VzUmVzdWx0ID0gdGhpcy52YWxpZGF0ZVN0cmluZ0FycmF5KHJlY29yZC5sYW5ndWFnZXMsICdsYW5ndWFnZXMnKTtcbiAgICAgIGlmICghbGFuZ3VhZ2VzUmVzdWx0LmlzVmFsaWQpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goLi4ubGFuZ3VhZ2VzUmVzdWx0LmVycm9ycyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gVmFsaWRhdGUgZG9tYWlucyBhcnJheVxuICAgIGlmIChyZWNvcmQuZG9tYWlucyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBkb21haW5zUmVzdWx0ID0gdGhpcy52YWxpZGF0ZVN0cmluZ0FycmF5KHJlY29yZC5kb21haW5zLCAnZG9tYWlucycpO1xuICAgICAgaWYgKCFkb21haW5zUmVzdWx0LmlzVmFsaWQpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goLi4uZG9tYWluc1Jlc3VsdC5lcnJvcnMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIHBhcmFtZXRlcnMgYXJyYXlcbiAgICBpZiAocmVjb3JkLnBhcmFtZXRlcnMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgcGFyYW1zUmVzdWx0ID0gdGhpcy52YWxpZGF0ZVBhcmFtZXRlcnMocmVjb3JkLnBhcmFtZXRlcnMpO1xuICAgICAgaWYgKCFwYXJhbXNSZXN1bHQuaXNWYWxpZCkge1xuICAgICAgICBlcnJvcnMucHVzaCguLi5wYXJhbXNSZXN1bHQuZXJyb3JzKTtcbiAgICAgIH1cbiAgICAgIHdhcm5pbmdzLnB1c2goLi4ucGFyYW1zUmVzdWx0Lndhcm5pbmdzKTtcbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSBleGFtcGxlcyBhcnJheVxuICAgIGlmIChyZWNvcmQuZXhhbXBsZXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgZXhhbXBsZXNSZXN1bHQgPSB0aGlzLnZhbGlkYXRlRXhhbXBsZXMocmVjb3JkLmV4YW1wbGVzKTtcbiAgICAgIGlmICghZXhhbXBsZXNSZXN1bHQuaXNWYWxpZCkge1xuICAgICAgICBlcnJvcnMucHVzaCguLi5leGFtcGxlc1Jlc3VsdC5lcnJvcnMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIHZlcnNpb24gc2VtdmVyIGZvcm1hdFxuICAgIGlmIChyZWNvcmQudmVyc2lvbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCB2ZXJzaW9uUmVzdWx0ID0gdGhpcy52YWxpZGF0ZVZlcnNpb24ocmVjb3JkLnZlcnNpb24pO1xuICAgICAgaWYgKCF2ZXJzaW9uUmVzdWx0LmlzVmFsaWQpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goLi4udmVyc2lvblJlc3VsdC5lcnJvcnMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIE5vdGU6IGVtcHR5IGRvbWFpbnMvZXhhbXBsZXMgd2FybmluZ3MgYXJlIGVtaXR0ZWQgYnkgU2tpbGwudmFsaWRhdGUoKVxuICAgIC8vIHRvIGF2b2lkIGR1cGxpY2F0aW9uIGluIHRoZSBjb21iaW5lZCB2YWxpZGF0ZUVsZW1lbnQgb3V0cHV0LlxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlzVmFsaWQ6IGVycm9ycy5sZW5ndGggPT09IDAsXG4gICAgICBlcnJvcnMsXG4gICAgICB3YXJuaW5nc1xuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgY29tcGxleGl0eSBlbnVtIHZhbHVlXG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlQ29tcGxleGl0eShjb21wbGV4aXR5OiB1bmtub3duKTogVmFsaWRhdGlvblJlc3VsdCB7XG4gICAgaWYgKHR5cGVvZiBjb21wbGV4aXR5ICE9PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIFZhbGlkYXRvckhlbHBlcnMuZmFpbChbJ0NvbXBsZXhpdHkgbXVzdCBiZSBhIHN0cmluZyddKTtcbiAgICB9XG5cbiAgICBpZiAoIShWQUxJRF9DT01QTEVYSVRZX0xFVkVMUyBhcyByZWFkb25seSBzdHJpbmdbXSkuaW5jbHVkZXMoY29tcGxleGl0eSkpIHtcbiAgICAgIHJldHVybiBWYWxpZGF0b3JIZWxwZXJzLmZhaWwoW1xuICAgICAgICBgSW52YWxpZCBjb21wbGV4aXR5ICcke2NvbXBsZXhpdHl9Jy4gVmFsaWQgb3B0aW9uczogJHtWQUxJRF9DT01QTEVYSVRZX0xFVkVMUy5qb2luKCcsICcpfWBcbiAgICAgIF0pO1xuICAgIH1cblxuICAgIHJldHVybiBWYWxpZGF0b3JIZWxwZXJzLnBhc3MoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBwcm9maWNpZW5jeV9sZXZlbCBpcyBhIG51bWJlciBpbiByYW5nZSAwLTEwMFxuICAgKi9cbiAgcHJpdmF0ZSB2YWxpZGF0ZVByb2ZpY2llbmN5TGV2ZWwobGV2ZWw6IHVua25vd24pOiBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICBpZiAodHlwZW9mIGxldmVsICE9PSAnbnVtYmVyJykge1xuICAgICAgcmV0dXJuIFZhbGlkYXRvckhlbHBlcnMuZmFpbChbJ1Byb2ZpY2llbmN5IGxldmVsIG11c3QgYmUgYSBudW1iZXInXSk7XG4gICAgfVxuXG4gICAgaWYgKGxldmVsIDwgMCB8fCBsZXZlbCA+IDEwMCkge1xuICAgICAgcmV0dXJuIFZhbGlkYXRvckhlbHBlcnMuZmFpbChbXG4gICAgICAgIGBQcm9maWNpZW5jeSBsZXZlbCBtdXN0IGJlIGJldHdlZW4gMCBhbmQgMTAwLCBnb3QgJHtsZXZlbH1gXG4gICAgICBdKTtcbiAgICB9XG5cbiAgICByZXR1cm4gVmFsaWRhdG9ySGVscGVycy5wYXNzKCk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgdGhhdCBhIGZpZWxkIGlzIGFuIGFycmF5IG9mIHN0cmluZ3NcbiAgICovXG4gIHByaXZhdGUgdmFsaWRhdGVTdHJpbmdBcnJheSh2YWx1ZTogdW5rbm93biwgZmllbGROYW1lOiBzdHJpbmcpOiBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICBpZiAoIUFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICByZXR1cm4gVmFsaWRhdG9ySGVscGVycy5mYWlsKFtgJHtmaWVsZE5hbWV9IG11c3QgYmUgYW4gYXJyYXlgXSk7XG4gICAgfVxuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB2YWx1ZS5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKHR5cGVvZiB2YWx1ZVtpXSAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgcmV0dXJuIFZhbGlkYXRvckhlbHBlcnMuZmFpbChbXG4gICAgICAgICAgYCR7ZmllbGROYW1lfVske2l9XSBtdXN0IGJlIGEgc3RyaW5nYFxuICAgICAgICBdKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gVmFsaWRhdG9ySGVscGVycy5wYXNzKCk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgcGFyYW1ldGVycyBhcnJheSB3aXRoIHR5cGUtc3BlY2lmaWMgcnVsZXNcbiAgICovXG4gIHByaXZhdGUgdmFsaWRhdGVQYXJhbWV0ZXJzKHBhcmFtZXRlcnM6IHVua25vd24pOiBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICBpZiAoIUFycmF5LmlzQXJyYXkocGFyYW1ldGVycykpIHtcbiAgICAgIHJldHVybiBWYWxpZGF0b3JIZWxwZXJzLmZhaWwoWydQYXJhbWV0ZXJzIG11c3QgYmUgYW4gYXJyYXknXSk7XG4gICAgfVxuXG4gICAgY29uc3QgZXJyb3JzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGNvbnN0IHdhcm5pbmdzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwYXJhbWV0ZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBwYXJhbSA9IHBhcmFtZXRlcnNbaV07XG5cbiAgICAgIGlmICghcGFyYW0gfHwgdHlwZW9mIHBhcmFtICE9PSAnb2JqZWN0Jykge1xuICAgICAgICBlcnJvcnMucHVzaChgUGFyYW1ldGVyIGF0IGluZGV4ICR7aX0gbXVzdCBiZSBhbiBvYmplY3RgKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHAgPSBwYXJhbSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcblxuICAgICAgLy8gbmFtZSBpcyByZXF1aXJlZCBhbmQgbXVzdCBiZSBub24tZW1wdHkgc3RyaW5nXG4gICAgICBpZiAoIXAubmFtZSB8fCB0eXBlb2YgcC5uYW1lICE9PSAnc3RyaW5nJyB8fCBwLm5hbWUudHJpbSgpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBlcnJvcnMucHVzaChgUGFyYW1ldGVyIGF0IGluZGV4ICR7aX0gaXMgbWlzc2luZyByZXF1aXJlZCBub24tZW1wdHkgJ25hbWUnIGZpZWxkYCk7XG4gICAgICB9XG5cbiAgICAgIC8vIHR5cGUgaXMgcmVxdWlyZWQgYW5kIG11c3QgYmUgb25lIG9mIHRoZSB2YWxpZCB0eXBlc1xuICAgICAgaWYgKCFwLnR5cGUgfHwgdHlwZW9mIHAudHlwZSAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goYFBhcmFtZXRlciBhdCBpbmRleCAke2l9IGlzIG1pc3NpbmcgcmVxdWlyZWQgJ3R5cGUnIGZpZWxkYCk7XG4gICAgICB9IGVsc2UgaWYgKCEoVkFMSURfUEFSQU1FVEVSX1RZUEVTIGFzIHJlYWRvbmx5IHN0cmluZ1tdKS5pbmNsdWRlcyhwLnR5cGUpKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKFxuICAgICAgICAgIGBQYXJhbWV0ZXIgJyR7cC5uYW1lIHx8IGl9JyBoYXMgaW52YWxpZCB0eXBlICcke3AudHlwZX0nLiBWYWxpZCB0eXBlczogJHtWQUxJRF9QQVJBTUVURVJfVFlQRVMuam9pbignLCAnKX1gXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIC8vIGRlc2NyaXB0aW9uIGlzIHJlcXVpcmVkXG4gICAgICBpZiAoIXAuZGVzY3JpcHRpb24gfHwgdHlwZW9mIHAuZGVzY3JpcHRpb24gIT09ICdzdHJpbmcnKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKGBQYXJhbWV0ZXIgJyR7cC5uYW1lIHx8IGl9JyBpcyBtaXNzaW5nIHJlcXVpcmVkICdkZXNjcmlwdGlvbicgZmllbGRgKTtcbiAgICAgIH1cblxuICAgICAgLy8gZW51bS10eXBlIHBhcmFtZXRlcnMgbmVlZCBvcHRpb25zIGFycmF5XG4gICAgICBpZiAocC50eXBlID09PSAnZW51bScpIHtcbiAgICAgICAgaWYgKCFwLm9wdGlvbnMgfHwgIUFycmF5LmlzQXJyYXkocC5vcHRpb25zKSB8fCBwLm9wdGlvbnMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgZXJyb3JzLnB1c2goYFBhcmFtZXRlciAnJHtwLm5hbWUgfHwgaX0nIGhhcyB0eXBlICdlbnVtJyBidXQgaXMgbWlzc2luZyBvciBoYXMgZW1wdHkgJ29wdGlvbnMnIGFycmF5YCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgaXNWYWxpZDogZXJyb3JzLmxlbmd0aCA9PT0gMCxcbiAgICAgIGVycm9ycyxcbiAgICAgIHdhcm5pbmdzXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBleGFtcGxlcyBhcnJheVxuICAgKi9cbiAgcHJpdmF0ZSB2YWxpZGF0ZUV4YW1wbGVzKGV4YW1wbGVzOiB1bmtub3duKTogVmFsaWRhdGlvblJlc3VsdCB7XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KGV4YW1wbGVzKSkge1xuICAgICAgcmV0dXJuIFZhbGlkYXRvckhlbHBlcnMuZmFpbChbJ0V4YW1wbGVzIG11c3QgYmUgYW4gYXJyYXknXSk7XG4gICAgfVxuXG4gICAgY29uc3QgZXJyb3JzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBleGFtcGxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgZXhhbXBsZSA9IGV4YW1wbGVzW2ldO1xuXG4gICAgICBpZiAoIWV4YW1wbGUgfHwgdHlwZW9mIGV4YW1wbGUgIT09ICdvYmplY3QnKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKGBFeGFtcGxlIGF0IGluZGV4ICR7aX0gbXVzdCBiZSBhbiBvYmplY3RgKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGV4ID0gZXhhbXBsZSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcblxuICAgICAgaWYgKCFleC50aXRsZSB8fCB0eXBlb2YgZXgudGl0bGUgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKGBFeGFtcGxlIGF0IGluZGV4ICR7aX0gaXMgbWlzc2luZyByZXF1aXJlZCAndGl0bGUnIGZpZWxkYCk7XG4gICAgICB9XG5cbiAgICAgIGlmICghZXguZGVzY3JpcHRpb24gfHwgdHlwZW9mIGV4LmRlc2NyaXB0aW9uICE9PSAnc3RyaW5nJykge1xuICAgICAgICBlcnJvcnMucHVzaChgRXhhbXBsZSBhdCBpbmRleCAke2l9IGlzIG1pc3NpbmcgcmVxdWlyZWQgJ2Rlc2NyaXB0aW9uJyBmaWVsZGApO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBpc1ZhbGlkOiBlcnJvcnMubGVuZ3RoID09PSAwLFxuICAgICAgZXJyb3JzLFxuICAgICAgd2FybmluZ3M6IFtdXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB2ZXJzaW9uIGZvbGxvd3Mgc2VtdmVyIGZvcm1hdFxuICAgKi9cbiAgcHJpdmF0ZSB2YWxpZGF0ZVZlcnNpb24odmVyc2lvbjogdW5rbm93bik6IFZhbGlkYXRpb25SZXN1bHQge1xuICAgIGlmICh0eXBlb2YgdmVyc2lvbiAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHJldHVybiBWYWxpZGF0b3JIZWxwZXJzLmZhaWwoWydWZXJzaW9uIG11c3QgYmUgYSBzdHJpbmcnXSk7XG4gICAgfVxuXG4gICAgaWYgKCFTRU1WRVJfUkVHRVgudGVzdCh2ZXJzaW9uKSkge1xuICAgICAgcmV0dXJuIFZhbGlkYXRvckhlbHBlcnMuZmFpbChbXG4gICAgICAgIGBWZXJzaW9uICcke3ZlcnNpb259JyBpcyBub3QgdmFsaWQgc2VtdmVyIGZvcm1hdCAoZXhwZWN0ZWQ6IG1ham9yLm1pbm9yLnBhdGNoLCBlLmcuLCAxLjAuMClgXG4gICAgICBdKTtcbiAgICB9XG5cbiAgICByZXR1cm4gVmFsaWRhdG9ySGVscGVycy5wYXNzKCk7XG4gIH1cbn1cbiJdfQ==