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.

222 lines 31.7 kB
/** * TemplateElementValidator - Specialized validator for Template elements * * Extends GenericElementValidator to add Template-specific validation: * - Output format validation * - Variable placeholder validation * - Template syntax validation */ import { ElementType } from '../../portfolio/types.js'; import { GenericElementValidator } from './GenericElementValidator.js'; import { ValidatorHelpers } from './ElementValidator.js'; import { SECURITY_LIMITS } from '../../security/constants.js'; const VALID_OUTPUT_FORMATS = ['text', 'markdown', 'json', 'yaml', 'html', 'xml']; const VARIABLE_PLACEHOLDER_REGEX = /\{\{[^}]+\}\}/g; // Issue #705: Module-level constants so regex objects are compiled once, not per validation call const SECTION_DETECTION_REGEX = /<(?:template|style|script)>[\s\S]*?<\/(?:template|style|script)>/i; const TEMPLATE_SECTION_EXTRACT_REGEX = /<template>([\s\S]*?)<\/template>/i; export class TemplateElementValidator extends GenericElementValidator { constructor(validationService, triggerValidationService, metadataService) { super(ElementType.TEMPLATE, validationService, triggerValidationService, metadataService); } /** * Override validateCreate to add template-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 output format if present if (record.output_format !== undefined) { const formatResult = this.validateOutputFormat(record.output_format); if (!formatResult.isValid) { errors.push(...formatResult.errors); } warnings.push(...formatResult.warnings); } // Validate template syntax in content if (record.content && typeof record.content === 'string') { const syntaxResult = this.validateTemplateSyntax(record.content); if (!syntaxResult.isValid) { errors.push(...syntaxResult.errors); } warnings.push(...syntaxResult.warnings); } // Validate variables if present if (record.variables !== undefined) { const varsResult = this.validateVariables(record.variables); if (!varsResult.isValid) { errors.push(...varsResult.errors); } warnings.push(...varsResult.warnings); } // Additional template-specific suggestions if (!record.output_format) { suggestions.push('Consider specifying an output_format (text, markdown, json, etc.)'); } return { isValid: errors.length === 0, errors, warnings, suggestions: suggestions.length > 0 ? suggestions : undefined }; } /** * Validate output format */ validateOutputFormat(format) { if (typeof format !== 'string') { return ValidatorHelpers.fail(['Output format must be a string']); } const sanitized = this.validationService.validateAndSanitizeInput(format, { maxLength: SECURITY_LIMITS.MAX_ENUM_FIELD_LENGTH, allowSpaces: false }); if (!sanitized.isValid) { return ValidatorHelpers.fail(sanitized.errors || ['Invalid output format']); } const normalizedFormat = sanitized.sanitizedValue.toLowerCase(); if (!VALID_OUTPUT_FORMATS.includes(normalizedFormat)) { return { isValid: true, errors: [], warnings: [`Unknown output format '${normalizedFormat}'. Valid formats: ${VALID_OUTPUT_FORMATS.join(', ')}`] }; } return ValidatorHelpers.pass(); } /** * Validate template syntax for variable placeholders */ validateTemplateSyntax(content) { const warnings = []; // Issue #705: In section mode, only validate {{ }} balance within the <template> section. // <style> and <script> sections are raw passthrough — }} is intentional there. // Uses module-level constants so regex objects are compiled once, not per validation call. const hasSections = SECTION_DETECTION_REGEX.test(content); const templateMatch = hasSections ? TEMPLATE_SECTION_EXTRACT_REGEX.exec(content) : null; const checkContent = hasSections ? (templateMatch ? templateMatch[1] : '') : content; // Find all variable placeholders const placeholders = checkContent.match(VARIABLE_PLACEHOLDER_REGEX) || []; const uniquePlaceholders = new Set(placeholders); if (uniquePlaceholders.size > 0) { // Check for unbalanced braces const openCount = (checkContent.match(/\{\{/g) || []).length; const closeCount = (checkContent.match(/\}\}/g) || []).length; if (openCount !== closeCount) { return ValidatorHelpers.fail(['Template has unbalanced variable placeholders (mismatched {{ and }})']); } // Warn about many variables if (uniquePlaceholders.size > 10) { warnings.push(`Template has ${uniquePlaceholders.size} unique variables - consider simplifying`); } } return { isValid: true, errors: [], warnings }; } /** * Validate template variables definition. * * Accepts two formats: * - Array format (frontmatter declarations): [{ name, type, required?, description? }] * - Object format (render-time values): { variableName: "value" } */ validateVariables(variables) { if (!variables) { return ValidatorHelpers.pass(); } if (typeof variables !== 'object') { return ValidatorHelpers.fail([ 'Variables must be either a declaration array (e.g. [{ name: "title", type: "string" }]) or a key-value object (e.g. { title: "My Page" }), not a primitive' ]); } // Array format: frontmatter variable declarations [{ name, type, required?, description? }] if (Array.isArray(variables)) { return this.validateVariableDeclarations(variables); } // Object format: render-time key-value pairs { variableName: "value" } return this.validateVariableValues(variables); } /** * Validate array-format variable declarations (frontmatter style). */ validateVariableDeclarations(variables) { const warnings = []; if (variables.length === 0) { warnings.push('Variables array is empty'); } else if (variables.length > 50) { warnings.push(`Template has ${variables.length} variables declared - consider reducing complexity`); } for (const entry of variables) { if (!entry || typeof entry !== 'object' || Array.isArray(entry)) { return ValidatorHelpers.fail([ 'Each variable declaration must be an object with at least { name, type } (e.g. { name: "title", type: "string", required: true })' ]); } const decl = entry; if (!decl.name || typeof decl.name !== 'string') { return ValidatorHelpers.fail([ 'Each variable declaration must have a "name" string field' ]); } if (!decl.type || typeof decl.type !== 'string') { return ValidatorHelpers.fail([ `Variable declaration "${decl.name}" must have a "type" string field` ]); } if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(decl.name)) { return ValidatorHelpers.fail([`Invalid variable name '${decl.name}' - must be alphanumeric with underscores`]); } } return { isValid: true, errors: [], warnings }; } /** * Validate object-format render-time variable values. */ validateVariableValues(vars) { const warnings = []; const varCount = Object.keys(vars).length; if (varCount === 0) { warnings.push('Variables object is empty — provide key-value pairs matching the template\'s {{variable}} placeholders'); } else if (varCount > 20) { warnings.push(`Template has ${varCount} variables defined - consider reducing complexity`); } // Validate each variable name for (const [key, value] of Object.entries(vars)) { if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) { return ValidatorHelpers.fail([`Invalid variable name '${key}' - must be alphanumeric with underscores`]); } if (key.length > 50) { warnings.push(`Variable name '${key}' is very long`); } // Check variable type if (value !== undefined && value !== null) { const valueType = typeof value; if (!['string', 'number', 'boolean', 'object'].includes(valueType)) { warnings.push(`Variable '${key}' has unusual type: ${valueType}`); } } } return { isValid: true, errors: [], warnings }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVGVtcGxhdGVFbGVtZW50VmFsaWRhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZpY2VzL3ZhbGlkYXRpb24vVGVtcGxhdGVFbGVtZW50VmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7O0dBT0c7QUFFSCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDdkQsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDdkUsT0FBTyxFQUFvQixnQkFBZ0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBSTNFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUU5RCxNQUFNLG9CQUFvQixHQUFHLENBQUMsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQztBQUNqRixNQUFNLDBCQUEwQixHQUFHLGdCQUFnQixDQUFDO0FBQ3BELGlHQUFpRztBQUNqRyxNQUFNLHVCQUF1QixHQUFHLG1FQUFtRSxDQUFDO0FBQ3BHLE1BQU0sOEJBQThCLEdBQUcsbUNBQW1DLENBQUM7QUFFM0UsTUFBTSxPQUFPLHdCQUF5QixTQUFRLHVCQUF1QjtJQUNuRSxZQUNFLGlCQUFvQyxFQUNwQyx3QkFBa0QsRUFDbEQsZUFBZ0M7UUFFaEMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxRQUFRLEVBQUUsaUJBQWlCLEVBQUUsd0JBQXdCLEVBQUUsZUFBZSxDQUFDLENBQUM7SUFDNUYsQ0FBQztJQUVEOztPQUVHO0lBQ00sS0FBSyxDQUFDLGNBQWMsQ0FDM0IsSUFBYSxFQUNiLE9BQWE7UUFFYiwrQkFBK0I7UUFDL0IsTUFBTSxVQUFVLEdBQUcsTUFBTSxLQUFLLENBQUMsY0FBYyxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztRQUM3RCxNQUFNLE1BQU0sR0FBRyxDQUFDLEdBQUcsVUFB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LElBQUksR0FBRyxDQUFDLE1BQU0sR0FBRyxFQUFFLEVBQUUsQ0FBQztnQkFDcEIsUUFBUSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxnQkFBZ0IsQ0FBQyxDQUFDO1lBQ3ZELENBQUM7WUFFRCxzQkFBc0I7WUFDdEIsSUFBSSxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssS0FBSyxJQUFJLEVBQUUsQ0FBQztnQkFDMUMsTUFBTSxTQUFTLEdBQUcsT0FBTyxLQUFLLENBQUM7Z0JBQy9CLElBQUksQ0FBQyxDQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLFFBQVEsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO29CQUNuRSxRQUFRLENBQUMsSUFBSSxDQUFDLGFBQWEsR0FBRyx1QkFBdUIsU0FBUyxFQUFFLENBQUMsQ0FBQztnQkFDcEUsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTztZQUNMLE9BQU8sRUFBRSxJQUFJO1lBQ2IsTUFBTSxFQUFFLEVBQUU7WUFDVixRQUFRO1NBQ1QsQ0FBQztJQUNKLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVGVtcGxhdGVFbGVtZW50VmFsaWRhdG9yIC0gU3BlY2lhbGl6ZWQgdmFsaWRhdG9yIGZvciBUZW1wbGF0ZSBlbGVtZW50c1xuICpcbiAqIEV4dGVuZHMgR2VuZXJpY0VsZW1lbnRWYWxpZGF0b3IgdG8gYWRkIFRlbXBsYXRlLXNwZWNpZmljIHZhbGlkYXRpb246XG4gKiAtIE91dHB1dCBmb3JtYXQgdmFsaWRhdGlvblxuICogLSBWYXJpYWJsZSBwbGFjZWhvbGRlciB2YWxpZGF0aW9uXG4gKiAtIFRlbXBsYXRlIHN5bnRheCB2YWxpZGF0aW9uXG4gKi9cblxuaW1wb3J0IHsgRWxlbWVudFR5cGUgfSBmcm9tICcuLi8uLi9wb3J0Zm9saW8vdHlwZXMuanMnO1xuaW1wb3J0IHsgR2VuZXJpY0VsZW1lbnRWYWxpZGF0b3IgfSBmcm9tICcuL0dlbmVyaWNFbGVtZW50VmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IFZhbGlkYXRpb25SZXN1bHQsIFZhbGlkYXRvckhlbHBlcnMgfSBmcm9tICcuL0VsZW1lbnRWYWxpZGF0b3IuanMnO1xuaW1wb3J0IHsgVmFsaWRhdGlvblNlcnZpY2UgfSBmcm9tICcuL1ZhbGlkYXRpb25TZXJ2aWNlLmpzJztcbmltcG9ydCB7IFRyaWdnZXJWYWxpZGF0aW9uU2VydmljZSB9IGZyb20gJy4vVHJpZ2dlclZhbGlkYXRpb25TZXJ2aWNlLmpzJztcbmltcG9ydCB7IE1ldGFkYXRhU2VydmljZSB9IGZyb20gJy4uL01ldGFkYXRhU2VydmljZS5qcyc7XG5pbXBvcnQgeyBTRUNVUklUWV9MSU1JVFMgfSBmcm9tICcuLi8uLi9zZWN1cml0eS9jb25zdGFudHMuanMnO1xuXG5jb25zdCBWQUxJRF9PVVRQVVRfRk9STUFUUyA9IFsndGV4dCcsICdtYXJrZG93bicsICdqc29uJywgJ3lhbWwnLCAnaHRtbCcsICd4bWwnXTtcbmNvbnN0IFZBUklBQkxFX1BMQUNFSE9MREVSX1JFR0VYID0gL1xce1xce1tefV0rXFx9XFx9L2c7XG4vLyBJc3N1ZSAjNzA1OiBNb2R1bGUtbGV2ZWwgY29uc3RhbnRzIHNvIHJlZ2V4IG9iamVjdHMgYXJlIGNvbXBpbGVkIG9uY2UsIG5vdCBwZXIgdmFsaWRhdGlvbiBjYWxsXG5jb25zdCBTRUNUSU9OX0RFVEVDVElPTl9SRUdFWCA9IC88KD86dGVtcGxhdGV8c3R5bGV8c2NyaXB0KT5bXFxzXFxTXSo/PFxcLyg/OnRlbXBsYXRlfHN0eWxlfHNjcmlwdCk+L2k7XG5jb25zdCBURU1QTEFURV9TRUNUSU9OX0VYVFJBQ1RfUkVHRVggPSAvPHRlbXBsYXRlPihbXFxzXFxTXSo/KTxcXC90ZW1wbGF0ZT4vaTtcblxuZXhwb3J0IGNsYXNzIFRlbXBsYXRlRWxlbWVudFZhbGlkYXRvciBleHRlbmRzIEdlbmVyaWNFbGVtZW50VmFsaWRhdG9yIHtcbiAgY29uc3RydWN0b3IoXG4gICAgdmFsaWRhdGlvblNlcnZpY2U6IFZhbGlkYXRpb25TZXJ2aWNlLFxuICAgIHRyaWdnZXJWYWxpZGF0aW9uU2VydmljZTogVHJpZ2dlclZhbGlkYXRpb25TZXJ2aWNlLFxuICAgIG1ldGFkYXRhU2VydmljZTogTWV0YWRhdGFTZXJ2aWNlXG4gICkge1xuICAgIHN1cGVyKEVsZW1lbnRUeXBlLlRFTVBMQVRFLCB2YWxpZGF0aW9uU2VydmljZSwgdHJpZ2dlclZhbGlkYXRpb25TZXJ2aWNlLCBtZXRhZGF0YVNlcnZpY2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIE92ZXJyaWRlIHZhbGlkYXRlQ3JlYXRlIHRvIGFkZCB0ZW1wbGF0ZS1zcGVjaWZpYyB2YWxpZGF0aW9uXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyB2YWxpZGF0ZUNyZWF0ZShcbiAgICBkYXRhOiB1bmtub3duLFxuICAgIG9wdGlvbnM/OiBhbnlcbiAgKTogUHJvbWlzZTxWYWxpZGF0aW9uUmVzdWx0PiB7XG4gICAgLy8gRmlyc3QgcnVuIGdlbmVyaWMgdmFsaWRhdGlvblxuICAgIGNvbnN0IGJhc2VSZXN1bHQgPSBhd2FpdCBzdXBlci52YWxpZGF0ZUNyZWF0ZShkYXRhLCBvcHRpb25zKTtcbiAgICBjb25zdCBlcnJvcnMgPSBbLi4uYmFzZVJlc3VsdC5lcnJvcnNdO1xuICAgIGNvbnN0IHdhcm5pbmdzID0gWy4uLmJhc2VSZXN1bHQud2FybmluZ3NdO1xuICAgIGNvbnN0IHN1Z2dlc3Rpb25zID0gWy4uLihiYXNlUmVzdWx0LnN1Z2dlc3Rpb25zIHx8IFtdKV07XG5cbiAgICBpZiAoIWRhdGEgfHwgdHlwZW9mIGRhdGEgIT09ICdvYmplY3QnKSB7XG4gICAgICByZXR1cm4gYmFzZVJlc3VsdDtcbiAgICB9XG5cbiAgICBjb25zdCByZWNvcmQgPSBkYXRhIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuXG4gICAgLy8gVmFsaWRhdGUgb3V0cHV0IGZvcm1hdCBpZiBwcmVzZW50XG4gICAgaWYgKHJlY29yZC5vdXRwdXRfZm9ybWF0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IGZvcm1hdFJlc3VsdCA9IHRoaXMudmFsaWRhdGVPdXRwdXRGb3JtYXQocmVjb3JkLm91dHB1dF9mb3JtYXQpO1xuICAgICAgaWYgKCFmb3JtYXRSZXN1bHQuaXNWYWxpZCkge1xuICAgICAgICBlcnJvcnMucHVzaCguLi5mb3JtYXRSZXN1bHQuZXJyb3JzKTtcbiAgICAgIH1cbiAgICAgIHdhcm5pbmdzLnB1c2goLi4uZm9ybWF0UmVzdWx0Lndhcm5pbmdzKTtcbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSB0ZW1wbGF0ZSBzeW50YXggaW4gY29udGVudFxuICAgIGlmIChyZWNvcmQuY29udGVudCAmJiB0eXBlb2YgcmVjb3JkLmNvbnRlbnQgPT09ICdzdHJpbmcnKSB7XG4gICAgICBjb25zdCBzeW50YXhSZXN1bHQgPSB0aGlzLnZhbGlkYXRlVGVtcGxhdGVTeW50YXgocmVjb3JkLmNvbnRlbnQpO1xuICAgICAgaWYgKCFzeW50YXhSZXN1bHQuaXNWYWxpZCkge1xuICAgICAgICBlcnJvcnMucHVzaCguLi5zeW50YXhSZXN1bHQuZXJyb3JzKTtcbiAgICAgIH1cbiAgICAgIHdhcm5pbmdzLnB1c2goLi4uc3ludGF4UmVzdWx0Lndhcm5pbmdzKTtcbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSB2YXJpYWJsZXMgaWYgcHJlc2VudFxuICAgIGlmIChyZWNvcmQudmFyaWFibGVzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IHZhcnNSZXN1bHQgPSB0aGlzLnZhbGlkYXRlVmFyaWFibGVzKHJlY29yZC52YXJpYWJsZXMpO1xuICAgICAgaWYgKCF2YXJzUmVzdWx0LmlzVmFsaWQpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goLi4udmFyc1Jlc3VsdC5lcnJvcnMpO1xuICAgICAgfVxuICAgICAgd2FybmluZ3MucHVzaCguLi52YXJzUmVzdWx0Lndhcm5pbmdzKTtcbiAgICB9XG5cbiAgICAvLyBBZGRpdGlvbmFsIHRlbXBsYXRlLXNwZWNpZmljIHN1Z2dlc3Rpb25zXG4gICAgaWYgKCFyZWNvcmQub3V0cHV0X2Zvcm1hdCkge1xuICAgICAgc3VnZ2VzdGlvbnMucHVzaCgnQ29uc2lkZXIgc3BlY2lmeWluZyBhbiBvdXRwdXRfZm9ybWF0ICh0ZXh0LCBtYXJrZG93biwganNvbiwgZXRjLiknKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgaXNWYWxpZDogZXJyb3JzLmxlbmd0aCA9PT0gMCxcbiAgICAgIGVycm9ycyxcbiAgICAgIHdhcm5pbmdzLFxuICAgICAgc3VnZ2VzdGlvbnM6IHN1Z2dlc3Rpb25zLmxlbmd0aCA+IDAgPyBzdWdnZXN0aW9ucyA6IHVuZGVmaW5lZFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgb3V0cHV0IGZvcm1hdFxuICAgKi9cbiAgcHJpdmF0ZSB2YWxpZGF0ZU91dHB1dEZvcm1hdChmb3JtYXQ6IHVua25vd24pOiBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICBpZiAodHlwZW9mIGZvcm1hdCAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHJldHVybiBWYWxpZGF0b3JIZWxwZXJzLmZhaWwoWydPdXRwdXQgZm9ybWF0IG11c3QgYmUgYSBzdHJpbmcnXSk7XG4gICAgfVxuXG4gICAgY29uc3Qgc2FuaXRpemVkID0gdGhpcy52YWxpZGF0aW9uU2VydmljZS52YWxpZGF0ZUFuZFNhbml0aXplSW5wdXQoZm9ybWF0LCB7XG4gICAgICBtYXhMZW5ndGg6IFNFQ1VSSVRZX0xJTUlUUy5NQVhfRU5VTV9GSUVMRF9MRU5HVEgsXG4gICAgICBhbGxvd1NwYWNlczogZmFsc2VcbiAgICB9KTtcblxuICAgIGlmICghc2FuaXRpemVkLmlzVmFsaWQpIHtcbiAgICAgIHJldHVybiBWYWxpZGF0b3JIZWxwZXJzLmZhaWwoc2FuaXRpemVkLmVycm9ycyB8fCBbJ0ludmFsaWQgb3V0cHV0IGZvcm1hdCddKTtcbiAgICB9XG5cbiAgICBjb25zdCBub3JtYWxpemVkRm9ybWF0ID0gc2FuaXRpemVkLnNhbml0aXplZFZhbHVlIS50b0xvd2VyQ2FzZSgpO1xuICAgIGlmICghVkFMSURfT1VUUFVUX0ZPUk1BVFMuaW5jbHVkZXMobm9ybWFsaXplZEZvcm1hdCkpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGlzVmFsaWQ6IHRydWUsXG4gICAgICAgIGVycm9yczogW10sXG4gICAgICAgIHdhcm5pbmdzOiBbYFVua25vd24gb3V0cHV0IGZvcm1hdCAnJHtub3JtYWxpemVkRm9ybWF0fScuIFZhbGlkIGZvcm1hdHM6ICR7VkFMSURfT1VUUFVUX0ZPUk1BVFMuam9pbignLCAnKX1gXVxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4gVmFsaWRhdG9ySGVscGVycy5wYXNzKCk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgdGVtcGxhdGUgc3ludGF4IGZvciB2YXJpYWJsZSBwbGFjZWhvbGRlcnNcbiAgICovXG4gIHByaXZhdGUgdmFsaWRhdGVUZW1wbGF0ZVN5bnRheChjb250ZW50OiBzdHJpbmcpOiBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICBjb25zdCB3YXJuaW5nczogc3RyaW5nW10gPSBbXTtcblxuICAgIC8vIElzc3VlICM3MDU6IEluIHNlY3Rpb24gbW9kZSwgb25seSB2YWxpZGF0ZSB7eyB9fSBiYWxhbmNlIHdpdGhpbiB0aGUgPHRlbXBsYXRlPiBzZWN0aW9uLlxuICAgIC8vIDxzdHlsZT4gYW5kIDxzY3JpcHQ+IHNlY3Rpb25zIGFyZSByYXcgcGFzc3Rocm91Z2gg4oCUIH19IGlzIGludGVudGlvbmFsIHRoZXJlLlxuICAgIC8vIFVzZXMgbW9kdWxlLWxldmVsIGNvbnN0YW50cyBzbyByZWdleCBvYmplY3RzIGFyZSBjb21waWxlZCBvbmNlLCBub3QgcGVyIHZhbGlkYXRpb24gY2FsbC5cbiAgICBjb25zdCBoYXNTZWN0aW9ucyA9IFNFQ1RJT05fREVURUNUSU9OX1JFR0VYLnRlc3QoY29udGVudCk7XG4gICAgY29uc3QgdGVtcGxhdGVNYXRjaCA9IGhhc1NlY3Rpb25zID8gVEVNUExBVEVfU0VDVElPTl9FWFRSQUNUX1JFR0VYLmV4ZWMoY29udGVudCkgOiBudWxsO1xuICAgIGNvbnN0IGNoZWNrQ29udGVudCA9IGhhc1NlY3Rpb25zID8gKHRlbXBsYXRlTWF0Y2ggPyB0ZW1wbGF0ZU1hdGNoWzFdIDogJycpIDogY29udGVudDtcblxuICAgIC8vIEZpbmQgYWxsIHZhcmlhYmxlIHBsYWNlaG9sZGVyc1xuICAgIGNvbnN0IHBsYWNlaG9sZGVycyA9IGNoZWNrQ29udGVudC5tYXRjaChWQVJJQUJMRV9QTEFDRUhPTERFUl9SRUdFWCkgfHwgW107XG4gICAgY29uc3QgdW5pcXVlUGxhY2Vob2xkZXJzID0gbmV3IFNldChwbGFjZWhvbGRlcnMpO1xuXG4gICAgaWYgKHVuaXF1ZVBsYWNlaG9sZGVycy5zaXplID4gMCkge1xuICAgICAgLy8gQ2hlY2sgZm9yIHVuYmFsYW5jZWQgYnJhY2VzXG4gICAgICBjb25zdCBvcGVuQ291bnQgPSAoY2hlY2tDb250ZW50Lm1hdGNoKC9cXHtcXHsvZykgfHwgW10pLmxlbmd0aDtcbiAgICAgIGNvbnN0IGNsb3NlQ291bnQgPSAoY2hlY2tDb250ZW50Lm1hdGNoKC9cXH1cXH0vZykgfHwgW10pLmxlbmd0aDtcblxuICAgICAgaWYgKG9wZW5Db3VudCAhPT0gY2xvc2VDb3VudCkge1xuICAgICAgICByZXR1cm4gVmFsaWRhdG9ySGVscGVycy5mYWlsKFsnVGVtcGxhdGUgaGFzIHVuYmFsYW5jZWQgdmFyaWFibGUgcGxhY2Vob2xkZXJzIChtaXNtYXRjaGVkIHt7IGFuZCB9fSknXSk7XG4gICAgICB9XG5cbiAgICAgIC8vIFdhcm4gYWJvdXQgbWFueSB2YXJpYWJsZXNcbiAgICAgIGlmICh1bmlxdWVQbGFjZWhvbGRlcnMuc2l6ZSA+IDEwKSB7XG4gICAgICAgIHdhcm5pbmdzLnB1c2goYFRlbXBsYXRlIGhhcyAke3VuaXF1ZVBsYWNlaG9sZGVycy5zaXplfSB1bmlxdWUgdmFyaWFibGVzIC0gY29uc2lkZXIgc2ltcGxpZnlpbmdgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgaXNWYWxpZDogdHJ1ZSxcbiAgICAgIGVycm9yczogW10sXG4gICAgICB3YXJuaW5nc1xuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgdGVtcGxhdGUgdmFyaWFibGVzIGRlZmluaXRpb24uXG4gICAqXG4gICAqIEFjY2VwdHMgdHdvIGZvcm1hdHM6XG4gICAqIC0gQXJyYXkgZm9ybWF0IChmcm9udG1hdHRlciBkZWNsYXJhdGlvbnMpOiBbeyBuYW1lLCB0eXBlLCByZXF1aXJlZD8sIGRlc2NyaXB0aW9uPyB9XVxuICAgKiAtIE9iamVjdCBmb3JtYXQgKHJlbmRlci10aW1lIHZhbHVlcyk6IHsgdmFyaWFibGVOYW1lOiBcInZhbHVlXCIgfVxuICAgKi9cbiAgcHJpdmF0ZSB2YWxpZGF0ZVZhcmlhYmxlcyh2YXJpYWJsZXM6IHVua25vd24pOiBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICBpZiAoIXZhcmlhYmxlcykge1xuICAgICAgcmV0dXJuIFZhbGlkYXRvckhlbHBlcnMucGFzcygpO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgdmFyaWFibGVzICE9PSAnb2JqZWN0Jykge1xuICAgICAgcmV0dXJuIFZhbGlkYXRvckhlbHBlcnMuZmFpbChbXG4gICAgICAgICdWYXJpYWJsZXMgbXVzdCBiZSBlaXRoZXIgYSBkZWNsYXJhdGlvbiBhcnJheSAoZS5nLiBbeyBuYW1lOiBcInRpdGxlXCIsIHR5cGU6IFwic3RyaW5nXCIgfV0pIG9yIGEga2V5LXZhbHVlIG9iamVjdCAoZS5nLiB7IHRpdGxlOiBcIk15IFBhZ2VcIiB9KSwgbm90IGEgcHJpbWl0aXZlJ1xuICAgICAgXSk7XG4gICAgfVxuXG4gICAgLy8gQXJyYXkgZm9ybWF0OiBmcm9udG1hdHRlciB2YXJpYWJsZSBkZWNsYXJhdGlvbnMgW3sgbmFtZSwgdHlwZSwgcmVxdWlyZWQ/LCBkZXNjcmlwdGlvbj8gfV1cbiAgICBpZiAoQXJyYXkuaXNBcnJheSh2YXJpYWJsZXMpKSB7XG4gICAgICByZXR1cm4gdGhpcy52YWxpZGF0ZVZhcmlhYmxlRGVjbGFyYXRpb25zKHZhcmlhYmxlcyk7XG4gICAgfVxuXG4gICAgLy8gT2JqZWN0IGZvcm1hdDogcmVuZGVyLXRpbWUga2V5LXZhbHVlIHBhaXJzIHsgdmFyaWFibGVOYW1lOiBcInZhbHVlXCIgfVxuICAgIHJldHVybiB0aGlzLnZhbGlkYXRlVmFyaWFibGVWYWx1ZXModmFyaWFibGVzIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhcnJheS1mb3JtYXQgdmFyaWFibGUgZGVjbGFyYXRpb25zIChmcm9udG1hdHRlciBzdHlsZSkuXG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlVmFyaWFibGVEZWNsYXJhdGlvbnModmFyaWFibGVzOiB1bmtub3duW10pOiBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICBjb25zdCB3YXJuaW5nczogc3RyaW5nW10gPSBbXTtcblxuICAgIGlmICh2YXJpYWJsZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICB3YXJuaW5ncy5wdXNoKCdWYXJpYWJsZXMgYXJyYXkgaXMgZW1wdHknKTtcbiAgICB9IGVsc2UgaWYgKHZhcmlhYmxlcy5sZW5ndGggPiA1MCkge1xuICAgICAgd2FybmluZ3MucHVzaChgVGVtcGxhdGUgaGFzICR7dmFyaWFibGVzLmxlbmd0aH0gdmFyaWFibGVzIGRlY2xhcmVkIC0gY29uc2lkZXIgcmVkdWNpbmcgY29tcGxleGl0eWApO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgZW50cnkgb2YgdmFyaWFibGVzKSB7XG4gICAgICBpZiAoIWVudHJ5IHx8IHR5cGVvZiBlbnRyeSAhPT0gJ29iamVjdCcgfHwgQXJyYXkuaXNBcnJheShlbnRyeSkpIHtcbiAgICAgICAgcmV0dXJuIFZhbGlkYXRvckhlbHBlcnMuZmFpbChbXG4gICAgICAgICAgJ0VhY2ggdmFyaWFibGUgZGVjbGFyYXRpb24gbXVzdCBiZSBhbiBvYmplY3Qgd2l0aCBhdCBsZWFzdCB7IG5hbWUsIHR5cGUgfSAoZS5nLiB7IG5hbWU6IFwidGl0bGVcIiwgdHlwZTogXCJzdHJpbmdcIiwgcmVxdWlyZWQ6IHRydWUgfSknXG4gICAgICAgIF0pO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBkZWNsID0gZW50cnkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG5cbiAgICAgIGlmICghZGVjbC5uYW1lIHx8IHR5cGVvZiBkZWNsLm5hbWUgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgIHJldHVybiBWYWxpZGF0b3JIZWxwZXJzLmZhaWwoW1xuICAgICAgICAgICdFYWNoIHZhcmlhYmxlIGRlY2xhcmF0aW9uIG11c3QgaGF2ZSBhIFwibmFtZVwiIHN0cmluZyBmaWVsZCdcbiAgICAgICAgXSk7XG4gICAgICB9XG5cbiAgICAgIGlmICghZGVjbC50eXBlIHx8IHR5cGVvZiBkZWNsLnR5cGUgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgIHJldHVybiBWYWxpZGF0b3JIZWxwZXJzLmZhaWwoW1xuICAgICAgICAgIGBWYXJpYWJsZSBkZWNsYXJhdGlvbiBcIiR7ZGVjbC5uYW1lfVwiIG11c3QgaGF2ZSBhIFwidHlwZVwiIHN0cmluZyBmaWVsZGBcbiAgICAgICAgXSk7XG4gICAgICB9XG5cbiAgICAgIGlmICghL15bYS16QS1aX11bYS16QS1aMC05X10qJC8udGVzdChkZWNsLm5hbWUpKSB7XG4gICAgICAgIHJldHVybiBWYWxpZGF0b3JIZWxwZXJzLmZhaWwoW2BJbnZhbGlkIHZhcmlhYmxlIG5hbWUgJyR7ZGVjbC5uYW1lfScgLSBtdXN0IGJlIGFscGhhbnVtZXJpYyB3aXRoIHVuZGVyc2NvcmVzYF0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBpc1ZhbGlkOiB0cnVlLFxuICAgICAgZXJyb3JzOiBbXSxcbiAgICAgIHdhcm5pbmdzXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBvYmplY3QtZm9ybWF0IHJlbmRlci10aW1lIHZhcmlhYmxlIHZhbHVlcy5cbiAgICovXG4gIHByaXZhdGUgdmFsaWRhdGVWYXJpYWJsZVZhbHVlcyh2YXJzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IFZhbGlkYXRpb25SZXN1bHQge1xuICAgIGNvbnN0IHdhcm5pbmdzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGNvbnN0IHZhckNvdW50ID0gT2JqZWN0LmtleXModmFycykubGVuZ3RoO1xuXG4gICAgaWYgKHZhckNvdW50ID09PSAwKSB7XG4gICAgICB3YXJuaW5ncy5wdXNoKCdWYXJpYWJsZXMgb2JqZWN0IGlzIGVtcHR5IOKAlCBwcm92aWRlIGtleS12YWx1ZSBwYWlycyBtYXRjaGluZyB0aGUgdGVtcGxhdGVcXCdzIHt7dmFyaWFibGV9fSBwbGFjZWhvbGRlcnMnKTtcbiAgICB9IGVsc2UgaWYgKHZhckNvdW50ID4gMjApIHtcbiAgICAgIHdhcm5pbmdzLnB1c2goYFRlbXBsYXRlIGhhcyAke3ZhckNvdW50fSB2YXJpYWJsZXMgZGVmaW5lZCAtIGNvbnNpZGVyIHJlZHVjaW5nIGNvbXBsZXhpdHlgKTtcbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSBlYWNoIHZhcmlhYmxlIG5hbWVcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyh2YXJzKSkge1xuICAgICAgaWYgKCEvXlthLXpBLVpfXVthLXpBLVowLTlfXSokLy50ZXN0KGtleSkpIHtcbiAgICAgICAgcmV0dXJuIFZhbGlkYXRvckhlbHBlcnMuZmFpbChbYEludmFsaWQgdmFyaWFibGUgbmFtZSAnJHtrZXl9JyAtIG11c3QgYmUgYWxwaGFudW1lcmljIHdpdGggdW5kZXJzY29yZXNgXSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChrZXkubGVuZ3RoID4gNTApIHtcbiAgICAgICAgd2FybmluZ3MucHVzaChgVmFyaWFibGUgbmFtZSAnJHtrZXl9JyBpcyB2ZXJ5IGxvbmdgKTtcbiAgICAgIH1cblxuICAgICAgLy8gQ2hlY2sgdmFyaWFibGUgdHlwZVxuICAgICAgaWYgKHZhbHVlICE9PSB1bmRlZmluZWQgJiYgdmFsdWUgIT09IG51bGwpIHtcbiAgICAgICAgY29uc3QgdmFsdWVUeXBlID0gdHlwZW9mIHZhbHVlO1xuICAgICAgICBpZiAoIVsnc3RyaW5nJywgJ251bWJlcicsICdib29sZWFuJywgJ29iamVjdCddLmluY2x1ZGVzKHZhbHVlVHlwZSkpIHtcbiAgICAgICAgICB3YXJuaW5ncy5wdXNoKGBWYXJpYWJsZSAnJHtrZXl9JyBoYXMgdW51c3VhbCB0eXBlOiAke3ZhbHVlVHlwZX1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBpc1ZhbGlkOiB0cnVlLFxuICAgICAgZXJyb3JzOiBbXSxcbiAgICAgIHdhcm5pbmdzXG4gICAgfTtcbiAgfVxufSJdfQ==