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.

273 lines 27.8 kB
/** * FieldValidator - Comprehensive field validation utilities * * Provides reusable validation rules for element metadata fields across all element types. * Each validator returns null on success or a ValidationError object on failure. * * Validation Rules: * - required: Field must be present and non-empty * - type: Field must match expected JavaScript type * - enum: Field value must be in allowed list * - array: Field must be array with optional minLength * - semver: Field must be valid semantic version * - length: String length within min/max bounds * - pattern: Field must match regex pattern * * @module utils/validation */ import * as semver from 'semver'; /** * FieldValidator class providing static validation methods */ export class FieldValidator { /** * Validate that a field is present and non-empty * * @param value - Value to validate * @param field - Field name for error reporting * @returns ValidationError if invalid, null if valid * * @example * FieldValidator.required(data.name, 'name') * // Returns: null if valid, { field: 'name', message: '...' } if invalid */ static required(value, field) { // Check for undefined, null, or empty string after trimming if (value === undefined || value === null) { return { field, message: `${field} is required` }; } // For strings, check if empty after trimming if (typeof value === 'string' && value.trim() === '') { return { field, message: `${field} is required and cannot be empty` }; } return null; } /** * Validate that a field matches the expected JavaScript type * * @param value - Value to validate * @param expectedType - Expected type ('string', 'number', 'boolean', 'object', 'array') * @param field - Field name for error reporting * @returns ValidationError if invalid, null if valid * * @example * FieldValidator.type(data.age, 'number', 'age') * // Returns: null if valid, { field: 'age', message: '...' } if invalid */ static type(value, expectedType, field) { if (value === undefined || value === null) { return null; // Use 'required' validator to check for presence } // Special handling for arrays if (expectedType === 'array') { if (!Array.isArray(value)) { return { field, message: `${field} must be an array` }; } return null; } const actualType = typeof value; if (actualType !== expectedType) { return { field, message: `${field} must be of type ${expectedType}, got ${actualType}` }; } return null; } /** * Validate that a field value is in the allowed list * * @param value - Value to validate * @param allowed - Array of allowed values * @param field - Field name for error reporting * @returns ValidationError if invalid, null if valid * * @example * FieldValidator.enum(data.category, ['creative', 'professional'], 'category') * // Returns: null if valid, { field: 'category', message: '...' } if invalid */ static enum(value, allowed, field) { if (value === undefined || value === null) { return null; // Use 'required' validator to check for presence } if (!allowed.includes(value)) { return { field, message: `${field} must be one of: ${allowed.join(', ')}. Got: ${value}` }; } return null; } /** * Validate that a field is an array with optional minimum length * * @param value - Value to validate * @param field - Field name for error reporting * @param minLength - Optional minimum array length * @returns ValidationError if invalid, null if valid * * @example * FieldValidator.array(data.elements, 'elements', 1) * // Returns: null if valid, { field: 'elements', message: '...' } if invalid */ static array(value, field, minLength) { if (value === undefined || value === null) { return null; // Use 'required' validator to check for presence } if (!Array.isArray(value)) { return { field, message: `${field} must be an array` }; } if (minLength !== undefined && value.length < minLength) { return { field, message: `${field} must have at least ${minLength} item${minLength === 1 ? '' : 's'}` }; } return null; } /** * Validate that a field is a valid semantic version * * Uses the semver package to validate version strings. * * @param value - Value to validate * @param field - Field name for error reporting * @returns ValidationError if invalid, null if valid * * @example * FieldValidator.semver(data.version, 'version') * // Returns: null if valid, { field: 'version', message: '...' } if invalid */ static semverVersion(value, field) { if (value === undefined || value === null) { return null; // Use 'required' validator to check for presence } if (typeof value !== 'string') { return { field, message: `${field} must be a string` }; } if (!semver.valid(value)) { return { field, message: `${field} must be a valid semantic version (e.g., 1.0.0)` }; } return null; } /** * Validate that a string length is within specified bounds * * @param value - Value to validate * @param field - Field name for error reporting * @param min - Minimum length (inclusive) * @param max - Maximum length (inclusive) * @returns ValidationError if invalid, null if valid * * @example * FieldValidator.length(data.name, 'name', 1, 100) * // Returns: null if valid, { field: 'name', message: '...' } if invalid */ static length(value, field, min, max) { if (value === undefined || value === null) { return null; // Use 'required' validator to check for presence } if (typeof value !== 'string') { return { field, message: `${field} must be a string` }; } const length = value.length; if (length < min) { return { field, message: `${field} must be at least ${min} character${min === 1 ? '' : 's'} long` }; } if (length > max) { return { field, message: `${field} must be at most ${max} character${max === 1 ? '' : 's'} long` }; } return null; } /** * Validate that a field matches a regular expression pattern * * @param value - Value to validate * @param pattern - Regular expression pattern * @param field - Field name for error reporting * @param patternDescription - Human-readable description of the pattern * @returns ValidationError if invalid, null if valid * * @example * FieldValidator.pattern(data.email, /^[^@]+@[^@]+$/, 'email', 'valid email address') * // Returns: null if valid, { field: 'email', message: '...' } if invalid */ static pattern(value, pattern, field, patternDescription) { if (value === undefined || value === null) { return null; // Use 'required' validator to check for presence } if (typeof value !== 'string') { return { field, message: `${field} must be a string` }; } if (!pattern.test(value)) { const description = patternDescription ? ` (${patternDescription})` : ''; return { field, message: `${field} must match the required pattern${description}` }; } return null; } /** * Validate a number is within a specified range * * @param value - Value to validate * @param field - Field name for error reporting * @param min - Minimum value (inclusive) * @param max - Maximum value (inclusive) * @returns ValidationError if invalid, null if valid * * @example * FieldValidator.range(data.proficiency, 'proficiency', 0, 100) * // Returns: null if valid, { field: 'proficiency', message: '...' } if invalid */ static range(value, field, min, max) { if (value === undefined || value === null) { return null; // Use 'required' validator to check for presence } if (typeof value !== 'number') { return { field, message: `${field} must be a number` }; } if (value < min || value > max) { return { field, message: `${field} must be between ${min} and ${max}` }; } return null; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmllbGRWYWxpZGF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdXRpbHMvdmFsaWRhdGlvbi9GaWVsZFZhbGlkYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQUVILE9BQU8sS0FBSyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBVWpDOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGNBQWM7SUFDekI7Ozs7Ozs7Ozs7T0FVRztJQUNILE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBVSxFQUFFLEtBQWE7UUFDdkMsNERBQTREO1FBQzVELElBQUksS0FBSyxLQUFLLFNBQVMsSUFBSSxLQUFLLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDMUMsT0FBTztnQkFDTCxLQUFLO2dCQUNMLE9BQU8sRUFBRSxHQUFHLEtBQUssY0FBYzthQUNoQyxDQUFDO1FBQ0osQ0FBQztRQUVELDZDQUE2QztRQUM3QyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUM7WUFDckQsT0FBTztnQkFDTCxLQUFLO2dCQUNMLE9BQU8sRUFBRSxHQUFHLEtBQUssa0NBQWtDO2FBQ3BELENBQUM7UUFDSixDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQVUsRUFBRSxZQUFvQixFQUFFLEtBQWE7UUFDekQsSUFBSSxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUMxQyxPQUFPLElBQUksQ0FBQyxDQUFDLGlEQUFpRDtRQUNoRSxDQUFDO1FBRUQsOEJBQThCO1FBQzlCLElBQUksWUFBWSxLQUFLLE9BQU8sRUFBRSxDQUFDO1lBQzdCLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFF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RUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN6QixNQUFNLFdBQVcsR0FBRyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsS0FBSyxrQkFBa0IsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDekUsT0FBTztnQkFDTCxLQUFLO2dCQUNMLE9BQU8sRUFBRSxHQUFHLEtBQUssbUNBQW1DLFdBQVcsRUFBRTthQUNsRSxDQUFDO1FBQ0osQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7T0FZRztJQUNILE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBVSxFQUFFLEtBQWEsRUFBRSxHQUFXLEVBQUUsR0FBVztRQUM5RCxJQUFJLEtBQUssS0FBSyxTQUFTLElBQUksS0FBSyxLQUFLLElBQUksRUFBRSxDQUFDO1lBQzFDLE9BQU8sSUFBSSxDQUFDLENBQUMsaURBQWlEO1FBQ2hFLENBQUM7UUFFRCxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzlCLE9BQU87Z0JBQ0wsS0FBSztnQkFDTCxPQUFPLEVBQUUsR0FBRyxLQUFLLG1CQUFtQjthQUNyQyxDQUFDO1FBQ0osQ0FBQztRQUVELElBQUksS0FBSyxHQUFHLEdBQUcsSUFBSSxLQUFLLEdBQUcsR0FBRyxFQUFFLENBQUM7WUFDL0IsT0FBTztnQkFDTCxLQUFLO2dCQUNMLE9BQU8sRUFBRSxHQUFHLEtBQUssb0JBQW9CLEdBQUcsUUFBUSxHQUFHLEVBQUU7YUFDdEQsQ0FBQztRQUNKLENBQUM7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRmllbGRWYWxpZGF0b3IgLSBDb21wcmVoZW5zaXZlIGZpZWxkIHZhbGlkYXRpb24gdXRpbGl0aWVzXG4gKlxuICogUHJvdmlkZXMgcmV1c2FibGUgdmFsaWRhdGlvbiBydWxlcyBmb3IgZWxlbWVudCBtZXRhZGF0YSBmaWVsZHMgYWNyb3NzIGFsbCBlbGVtZW50IHR5cGVzLlxuICogRWFjaCB2YWxpZGF0b3IgcmV0dXJucyBudWxsIG9uIHN1Y2Nlc3Mgb3IgYSBWYWxpZGF0aW9uRXJyb3Igb2JqZWN0IG9uIGZhaWx1cmUuXG4gKlxuICogVmFsaWRhdGlvbiBSdWxlczpcbiAqIC0gcmVxdWlyZWQ6IEZpZWxkIG11c3QgYmUgcHJlc2VudCBhbmQgbm9uLWVtcHR5XG4gKiAtIHR5cGU6IEZpZWxkIG11c3QgbWF0Y2ggZXhwZWN0ZWQgSmF2YVNjcmlwdCB0eXBlXG4gKiAtIGVudW06IEZpZWxkIHZhbHVlIG11c3QgYmUgaW4gYWxsb3dlZCBsaXN0XG4gKiAtIGFycmF5OiBGaWVsZCBtdXN0IGJlIGFycmF5IHdpdGggb3B0aW9uYWwgbWluTGVuZ3RoXG4gKiAtIHNlbXZlcjogRmllbGQgbXVzdCBiZSB2YWxpZCBzZW1hbnRpYyB2ZXJzaW9uXG4gKiAtIGxlbmd0aDogU3RyaW5nIGxlbmd0aCB3aXRoaW4gbWluL21heCBib3VuZHNcbiAqIC0gcGF0dGVybjogRmllbGQgbXVzdCBtYXRjaCByZWdleCBwYXR0ZXJuXG4gKlxuICogQG1vZHVsZSB1dGlscy92YWxpZGF0aW9uXG4gKi9cblxuaW1wb3J0ICogYXMgc2VtdmVyIGZyb20gJ3NlbXZlcic7XG5cbi8qKlxuICogVmFsaWRhdGlvbiBlcnJvciBzdHJ1Y3R1cmVcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBWYWxpZGF0aW9uRXJyb3Ige1xuICBmaWVsZDogc3RyaW5nO1xuICBtZXNzYWdlOiBzdHJpbmc7XG59XG5cbi8qKlxuICogRmllbGRWYWxpZGF0b3IgY2xhc3MgcHJvdmlkaW5nIHN0YXRpYyB2YWxpZGF0aW9uIG1ldGhvZHNcbiAqL1xuZXhwb3J0IGNsYXNzIEZpZWxkVmFsaWRhdG9yIHtcbiAgLyoqXG4gICAqIFZhbGlkYXRlIHRoYXQgYSBmaWVsZCBpcyBwcmVzZW50IGFuZCBub24tZW1wdHlcbiAgICpcbiAgICogQHBhcmFtIHZhbHVlIC0gVmFsdWUgdG8gdmFsaWRhdGVcbiAgICogQHBhcmFtIGZpZWxkIC0gRmllbGQgbmFtZSBmb3IgZXJyb3IgcmVwb3J0aW5nXG4gICAqIEByZXR1cm5zIFZhbGlkYXRpb25FcnJvciBpZiBpbnZhbGlkLCBudWxsIGlmIHZhbGlkXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIEZpZWxkVmFsaWRhdG9yLnJlcXVpcmVkKGRhdGEubmFtZSwgJ25hbWUnKVxuICAgKiAvLyBSZXR1cm5zOiBudWxsIGlmIHZhbGlkLCB7IGZpZWxkOiAnbmFtZScsIG1lc3NhZ2U6ICcuLi4nIH0gaWYgaW52YWxpZFxuICAgKi9cbiAgc3RhdGljIHJlcXVpcmVkKHZhbHVlOiBhbnksIGZpZWxkOiBzdHJpbmcpOiBWYWxpZGF0aW9uRXJyb3IgfCBudWxsIHtcbiAgICAvLyBDaGVjayBmb3IgdW5kZWZpbmVkLCBudWxsLCBvciBlbXB0eSBzdHJpbmcgYWZ0ZXIgdHJpbW1pbmdcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCB8fCB2YWx1ZSA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZmllbGQsXG4gICAgICAgIG1lc3NhZ2U6IGAke2ZpZWxkfSBpcyByZXF1aXJlZGBcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gRm9yIHN0cmluZ3MsIGNoZWNrIGlmIGVtcHR5IGFmdGVyIHRyaW1taW5nXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUudHJpbSgpID09PSAnJykge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZmllbGQsXG4gICAgICAgIG1lc3NhZ2U6IGAke2ZpZWxkfSBpcyByZXF1aXJlZCBhbmQgY2Fubm90IGJlIGVtcHR5YFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGF0IGEgZmllbGQgbWF0Y2hlcyB0aGUgZXhwZWN0ZWQgSmF2YVNjcmlwdCB0eXBlXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFZhbHVlIHRvIHZhbGlkYXRlXG4gICAqIEBwYXJhbSBleHBlY3RlZFR5cGUgLSBFeHBlY3RlZCB0eXBlICgnc3RyaW5nJywgJ251bWJlcicsICdib29sZWFuJywgJ29iamVjdCcsICdhcnJheScpXG4gICAqIEBwYXJhbSBmaWVsZCAtIEZpZWxkIG5hbWUgZm9yIGVycm9yIHJlcG9ydGluZ1xuICAgKiBAcmV0dXJucyBWYWxpZGF0aW9uRXJyb3IgaWYgaW52YWxpZCwgbnVsbCBpZiB2YWxpZFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBGaWVsZFZhbGlkYXRvci50eXBlKGRhdGEuYWdlLCAnbnVtYmVyJywgJ2FnZScpXG4gICAqIC8vIFJldHVybnM6IG51bGwgaWYgdmFsaWQsIHsgZmllbGQ6ICdhZ2UnLCBtZXNzYWdlOiAnLi4uJyB9IGlmIGludmFsaWRcbiAgICovXG4gIHN0YXRpYyB0eXBlKHZhbHVlOiBhbnksIGV4cGVjdGVkVHlwZTogc3RyaW5nLCBmaWVsZDogc3RyaW5nKTogVmFsaWRhdGlvbkVycm9yIHwgbnVsbCB7XG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09IG51bGwpIHtcbiAgICAgIHJldHVybiBudWxsOyAvLyBVc2UgJ3JlcXVpcmVkJyB2YWxpZGF0b3IgdG8gY2hlY2sgZm9yIHByZXNlbmNlXG4gICAgfVxuXG4gICAgLy8gU3BlY2lhbCBoYW5kbGluZyBmb3IgYXJyYXlzXG4gICAgaWYgKGV4cGVjdGVkVHlwZSA9PT0gJ2FycmF5Jykge1xuICAgICAgaWYgKCFBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGZpZWxkLFxuICAgICAgICAgIG1lc3NhZ2U6IGAke2ZpZWxkfSBtdXN0IGJlIGFuIGFycmF5YFxuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgY29uc3QgYWN0dWFsVHlwZSA9IHR5cGVvZiB2YWx1ZTtcbiAgICBpZiAoYWN0dWFsVHlwZSAhPT0gZXhwZWN0ZWRUeXBlKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBmaWVsZCxcbiAgICAgICAgbWVzc2FnZTogYCR7ZmllbGR9IG11c3QgYmUgb2YgdHlwZSAke2V4cGVjdGVkVHlwZX0sIGdvdCAke2FjdHVhbFR5cGV9YFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGF0IGEgZmllbGQgdmFsdWUgaXMgaW4gdGhlIGFsbG93ZWQgbGlzdFxuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgLSBWYWx1ZSB0byB2YWxpZGF0ZVxuICAgKiBAcGFyYW0gYWxsb3dlZCAtIEFycmF5IG9mIGFsbG93ZWQgdmFsdWVzXG4gICAqIEBwYXJhbSBmaWVsZCAtIEZpZWxkIG5hbWUgZm9yIGVycm9yIHJlcG9ydGluZ1xuICAgKiBAcmV0dXJucyBWYWxpZGF0aW9uRXJyb3IgaWYgaW52YWxpZCwgbnVsbCBpZiB2YWxpZFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBGaWVsZFZhbGlkYXRvci5lbnVtKGRhdGEuY2F0ZWdvcnksIFsnY3JlYXRpdmUnLCAncHJvZmVzc2lvbmFsJ10sICdjYXRlZ29yeScpXG4gICAqIC8vIFJldHVybnM6IG51bGwgaWYgdmFsaWQsIHsgZmllbGQ6ICdjYXRlZ29yeScsIG1lc3NhZ2U6ICcuLi4nIH0gaWYgaW52YWxpZFxuICAgKi9cbiAgc3RhdGljIGVudW0odmFsdWU6IGFueSwgYWxsb3dlZDogc3RyaW5nW10sIGZpZWxkOiBzdHJpbmcpOiBWYWxpZGF0aW9uRXJyb3IgfCBudWxsIHtcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCB8fCB2YWx1ZSA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuIG51bGw7IC8vIFVzZSAncmVxdWlyZWQnIHZhbGlkYXRvciB0byBjaGVjayBmb3IgcHJlc2VuY2VcbiAgICB9XG5cbiAgICBpZiAoIWFsbG93ZWQuaW5jbHVkZXModmFsdWUpKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBmaWVsZCxcbiAgICAgICAgbWVzc2FnZTogYCR7ZmllbGR9IG11c3QgYmUgb25lIG9mOiAke2FsbG93ZWQuam9pbignLCAnKX0uIEdvdDogJHt2YWx1ZX1gXG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIHRoYXQgYSBmaWVsZCBpcyBhbiBhcnJheSB3aXRoIG9wdGlvbmFsIG1pbmltdW0gbGVuZ3RoXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFZhbHVlIHRvIHZhbGlkYXRlXG4gICAqIEBwYXJhbSBmaWVsZCAtIEZpZWxkIG5hbWUgZm9yIGVycm9yIHJlcG9ydGluZ1xuICAgKiBAcGFyYW0gbWluTGVuZ3RoIC0gT3B0aW9uYWwgbWluaW11bSBhcnJheSBsZW5ndGhcbiAgICogQHJldHVybnMgVmFsaWRhdGlvbkVycm9yIGlmIGludmFsaWQsIG51bGwgaWYgdmFsaWRcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogRmllbGRWYWxpZGF0b3IuYXJyYXkoZGF0YS5lbGVtZW50cywgJ2VsZW1lbnRzJywgMSlcbiAgICogLy8gUmV0dXJuczogbnVsbCBpZiB2YWxpZCwgeyBmaWVsZDogJ2VsZW1lbnRzJywgbWVzc2FnZTogJy4uLicgfSBpZiBpbnZhbGlkXG4gICAqL1xuICBzdGF0aWMgYXJyYXkodmFsdWU6IGFueSwgZmllbGQ6IHN0cmluZywgbWluTGVuZ3RoPzogbnVtYmVyKTogVmFsaWRhdGlvbkVycm9yIHwgbnVsbCB7XG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09IG51bGwpIHtcbiAgICAgIHJldHVybiBudWxsOyAvLyBVc2UgJ3JlcXVpcmVkJyB2YWxpZGF0b3IgdG8gY2hlY2sgZm9yIHByZXNlbmNlXG4gICAgfVxuXG4gICAgaWYgKCFBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZmllbGQsXG4gICAgICAgIG1lc3NhZ2U6IGAke2ZpZWxkfSBtdXN0IGJlIGFuIGFycmF5YFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBpZiAobWluTGVuZ3RoICE9PSB1bmRlZmluZWQgJiYgdmFsdWUubGVuZ3RoIDwgbWluTGVuZ3RoKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBmaWVsZCxcbiAgICAgICAgbWVzc2FnZTogYCR7ZmllbGR9IG11c3QgaGF2ZSBhdCBsZWFzdCAke21pbkxlbmd0aH0gaXRlbSR7bWluTGVuZ3RoID09PSAxID8gJycgOiAncyd9YFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGF0IGEgZmllbGQgaXMgYSB2YWxpZCBzZW1hbnRpYyB2ZXJzaW9uXG4gICAqXG4gICAqIFVzZXMgdGhlIHNlbXZlciBwYWNrYWdlIHRvIHZhbGlkYXRlIHZlcnNpb24gc3RyaW5ncy5cbiAgICpcbiAgICogQHBhcmFtIHZhbHVlIC0gVmFsdWUgdG8gdmFsaWRhdGVcbiAgICogQHBhcmFtIGZpZWxkIC0gRmllbGQgbmFtZSBmb3IgZXJyb3IgcmVwb3J0aW5nXG4gICAqIEByZXR1cm5zIFZhbGlkYXRpb25FcnJvciBpZiBpbnZhbGlkLCBudWxsIGlmIHZhbGlkXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIEZpZWxkVmFsaWRhdG9yLnNlbXZlcihkYXRhLnZlcnNpb24sICd2ZXJzaW9uJylcbiAgICogLy8gUmV0dXJuczogbnVsbCBpZiB2YWxpZCwgeyBmaWVsZDogJ3ZlcnNpb24nLCBtZXNzYWdlOiAnLi4uJyB9IGlmIGludmFsaWRcbiAgICovXG4gIHN0YXRpYyBzZW12ZXJWZXJzaW9uKHZhbHVlOiBhbnksIGZpZWxkOiBzdHJpbmcpOiBWYWxpZGF0aW9uRXJyb3IgfCBudWxsIHtcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCB8fCB2YWx1ZSA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuIG51bGw7IC8vIFVzZSAncmVxdWlyZWQnIHZhbGlkYXRvciB0byBjaGVjayBmb3IgcHJlc2VuY2VcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZmllbGQsXG4gICAgICAgIG1lc3NhZ2U6IGAke2ZpZWxkfSBtdXN0IGJlIGEgc3RyaW5nYFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBpZiAoIXNlbXZlci52YWxpZCh2YWx1ZSkpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGZpZWxkLFxuICAgICAgICBtZXNzYWdlOiBgJHtmaWVsZH0gbXVzdCBiZSBhIHZhbGlkIHNlbWFudGljIHZlcnNpb24gKGUuZy4sIDEuMC4wKWBcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgdGhhdCBhIHN0cmluZyBsZW5ndGggaXMgd2l0aGluIHNwZWNpZmllZCBib3VuZHNcbiAgICpcbiAgICogQHBhcmFtIHZhbHVlIC0gVmFsdWUgdG8gdmFsaWRhdGVcbiAgICogQHBhcmFtIGZpZWxkIC0gRmllbGQgbmFtZSBmb3IgZXJyb3IgcmVwb3J0aW5nXG4gICAqIEBwYXJhbSBtaW4gLSBNaW5pbXVtIGxlbmd0aCAoaW5jbHVzaXZlKVxuICAgKiBAcGFyYW0gbWF4IC0gTWF4aW11bSBsZW5ndGggKGluY2x1c2l2ZSlcbiAgICogQHJldHVybnMgVmFsaWRhdGlvbkVycm9yIGlmIGludmFsaWQsIG51bGwgaWYgdmFsaWRcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogRmllbGRWYWxpZGF0b3IubGVuZ3RoKGRhdGEubmFtZSwgJ25hbWUnLCAxLCAxMDApXG4gICAqIC8vIFJldHVybnM6IG51bGwgaWYgdmFsaWQsIHsgZmllbGQ6ICduYW1lJywgbWVzc2FnZTogJy4uLicgfSBpZiBpbnZhbGlkXG4gICAqL1xuICBzdGF0aWMgbGVuZ3RoKHZhbHVlOiBhbnksIGZpZWxkOiBzdHJpbmcsIG1pbjogbnVtYmVyLCBtYXg6IG51bWJlcik6IFZhbGlkYXRpb25FcnJvciB8IG51bGwge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHZhbHVlID09PSBudWxsKSB7XG4gICAgICByZXR1cm4gbnVsbDsgLy8gVXNlICdyZXF1aXJlZCcgdmFsaWRhdG9yIHRvIGNoZWNrIGZvciBwcmVzZW5jZVxuICAgIH1cblxuICAgIGlmICh0eXBlb2YgdmFsdWUgIT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBmaWVsZCxcbiAgICAgICAgbWVzc2FnZTogYCR7ZmllbGR9IG11c3QgYmUgYSBzdHJpbmdgXG4gICAgICB9O1xuICAgIH1cblxuICAgIGNvbnN0IGxlbmd0aCA9IHZhbHVlLmxlbmd0aDtcblxuICAgIGlmIChsZW5ndGggPCBtaW4pIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGZpZWxkLFxuICAgICAgICBtZXNzYWdlOiBgJHtmaWVsZH0gbXVzdCBiZSBhdCBsZWFzdCAke21pbn0gY2hhcmFjdGVyJHttaW4gPT09IDEgPyAnJyA6ICdzJ30gbG9uZ2BcbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKGxlbmd0aCA+IG1heCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZmllbGQsXG4gICAgICAgIG1lc3NhZ2U6IGAke2ZpZWxkfSBtdXN0IGJlIGF0IG1vc3QgJHttYXh9IGNoYXJhY3RlciR7bWF4ID09PSAxID8gJycgOiAncyd9IGxvbmdgXG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIHRoYXQgYSBmaWVsZCBtYXRjaGVzIGEgcmVndWxhciBleHByZXNzaW9uIHBhdHRlcm5cbiAgICpcbiAgICogQHBhcmFtIHZhbHVlIC0gVmFsdWUgdG8gdmFsaWRhdGVcbiAgICogQHBhcmFtIHBhdHRlcm4gLSBSZWd1bGFyIGV4cHJlc3Npb24gcGF0dGVyblxuICAgKiBAcGFyYW0gZmllbGQgLSBGaWVsZCBuYW1lIGZvciBlcnJvciByZXBvcnRpbmdcbiAgICogQHBhcmFtIHBhdHRlcm5EZXNjcmlwdGlvbiAtIEh1bWFuLXJlYWRhYmxlIGRlc2NyaXB0aW9uIG9mIHRoZSBwYXR0ZXJuXG4gICAqIEByZXR1cm5zIFZhbGlkYXRpb25FcnJvciBpZiBpbnZhbGlkLCBudWxsIGlmIHZhbGlkXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIEZpZWxkVmFsaWRhdG9yLnBhdHRlcm4oZGF0YS5lbWFpbCwgL15bXkBdK0BbXkBdKyQvLCAnZW1haWwnLCAndmFsaWQgZW1haWwgYWRkcmVzcycpXG4gICAqIC8vIFJldHVybnM6IG51bGwgaWYgdmFsaWQsIHsgZmllbGQ6ICdlbWFpbCcsIG1lc3NhZ2U6ICcuLi4nIH0gaWYgaW52YWxpZFxuICAgKi9cbiAgc3RhdGljIHBhdHRlcm4oXG4gICAgdmFsdWU6IGFueSxcbiAgICBwYXR0ZXJuOiBSZWdFeHAsXG4gICAgZmllbGQ6IHN0cmluZyxcbiAgICBwYXR0ZXJuRGVzY3JpcHRpb24/OiBzdHJpbmdcbiAgKTogVmFsaWRhdGlvbkVycm9yIHwgbnVsbCB7XG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09IG51bGwpIHtcbiAgICAgIHJldHVybiBudWxsOyAvLyBVc2UgJ3JlcXVpcmVkJyB2YWxpZGF0b3IgdG8gY2hlY2sgZm9yIHByZXNlbmNlXG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGZpZWxkLFxuICAgICAgICBtZXNzYWdlOiBgJHtmaWVsZH0gbXVzdCBiZSBhIHN0cmluZ2BcbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKCFwYXR0ZXJuLnRlc3QodmFsdWUpKSB7XG4gICAgICBjb25zdCBkZXNjcmlwdGlvbiA9IHBhdHRlcm5EZXNjcmlwdGlvbiA/IGAgKCR7cGF0dGVybkRlc2NyaXB0aW9ufSlgIDogJyc7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBmaWVsZCxcbiAgICAgICAgbWVzc2FnZTogYCR7ZmllbGR9IG11c3QgbWF0Y2ggdGhlIHJlcXVpcmVkIHBhdHRlcm4ke2Rlc2NyaXB0aW9ufWBcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgYSBudW1iZXIgaXMgd2l0aGluIGEgc3BlY2lmaWVkIHJhbmdlXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFZhbHVlIHRvIHZhbGlkYXRlXG4gICAqIEBwYXJhbSBmaWVsZCAtIEZpZWxkIG5hbWUgZm9yIGVycm9yIHJlcG9ydGluZ1xuICAgKiBAcGFyYW0gbWluIC0gTWluaW11bSB2YWx1ZSAoaW5jbHVzaXZlKVxuICAgKiBAcGFyYW0gbWF4IC0gTWF4aW11bSB2YWx1ZSAoaW5jbHVzaXZlKVxuICAgKiBAcmV0dXJucyBWYWxpZGF0aW9uRXJyb3IgaWYgaW52YWxpZCwgbnVsbCBpZiB2YWxpZFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBGaWVsZFZhbGlkYXRvci5yYW5nZShkYXRhLnByb2ZpY2llbmN5LCAncHJvZmljaWVuY3knLCAwLCAxMDApXG4gICAqIC8vIFJldHVybnM6IG51bGwgaWYgdmFsaWQsIHsgZmllbGQ6ICdwcm9maWNpZW5jeScsIG1lc3NhZ2U6ICcuLi4nIH0gaWYgaW52YWxpZFxuICAgKi9cbiAgc3RhdGljIHJhbmdlKHZhbHVlOiBhbnksIGZpZWxkOiBzdHJpbmcsIG1pbjogbnVtYmVyLCBtYXg6IG51bWJlcik6IFZhbGlkYXRpb25FcnJvciB8IG51bGwge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHZhbHVlID09PSBudWxsKSB7XG4gICAgICByZXR1cm4gbnVsbDsgLy8gVXNlICdyZXF1aXJlZCcgdmFsaWRhdG9yIHRvIGNoZWNrIGZvciBwcmVzZW5jZVxuICAgIH1cblxuICAgIGlmICh0eXBlb2YgdmFsdWUgIT09ICdudW1iZXInKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBmaWVsZCxcbiAgICAgICAgbWVzc2FnZTogYCR7ZmllbGR9IG11c3QgYmUgYSBudW1iZXJgXG4gICAgICB9O1xuICAgIH1cblxuICAgIGlmICh2YWx1ZSA8IG1pbiB8fCB2YWx1ZSA+IG1heCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZmllbGQsXG4gICAgICAgIG1lc3NhZ2U6IGAke2ZpZWxkfSBtdXN0IGJlIGJldHdlZW4gJHttaW59IGFuZCAke21heH1gXG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG59XG4iXX0=