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.

327 lines 41.7 kB
/** * Type-safe relationship definitions for Enhanced Index * * This module provides a comprehensive type system for managing relationships * between elements in the DollhouseMCP Enhanced Index. It implements a three-tier * type hierarchy that ensures both compile-time and runtime safety. * * ## Type Hierarchy: * 1. BaseRelationship - The storage format (what's persisted to disk) * 2. ParsedRelationship - Valid runtime format with extracted metadata * 3. InvalidRelationship - Error state with detailed diagnostics * * ## Key Features: * - Strongly-typed interfaces with discriminated unions * - Runtime type guards for safe type narrowing * - Detailed error messages with position information * - Batch processing utilities with performance optimizations * - Relationship deduplication and sorting algorithms * * ## Usage Example: * ```typescript * // Parse a relationship from storage * const stored: BaseRelationship = { element: 'personas:expert-coder' }; * const parsed = parseRelationship(stored); * * if (isParsedRelationship(parsed)) { * console.log(`Type: ${parsed.targetType}, Name: ${parsed.targetName}`); * } else { * console.error(`Parse failed: ${parsed.parseError}`); * } * ``` * * FIXES IMPLEMENTED (Issue #1103): * - Type-safe relationship variants with discriminated unions * - Compile-time validation through TypeScript's type system * - Runtime type guards for safe type narrowing * - Safe parsing utilities with detailed error reporting * - Security audit logging for relationship operations */ import { parseElementId, formatElementId } from '../../utils/elementId.js'; import { UnicodeValidator } from '../../security/validators/unicodeValidator.js'; /** * Type guard to check if a relationship is successfully parsed * * @param rel - The relationship to check * @returns True if the relationship is a ParsedRelationship with valid data * * @example * ```typescript * const rel = parseRelationship(baseRel); * if (isParsedRelationship(rel)) { * // TypeScript knows rel is ParsedRelationship here * console.log(rel.targetType, rel.targetName); * } * ``` */ export function isParsedRelationship(rel) { return 'isValid' in rel && rel.isValid === true && 'targetType' in rel && rel.targetType !== null && 'targetName' in rel && rel.targetName !== null; } /** * Type guard to check if a relationship failed to parse * * @param rel - The relationship to check * @returns True if the relationship is an InvalidRelationship with error details * * @example * ```typescript * const rel = parseRelationship(baseRel); * if (isInvalidRelationship(rel)) { * console.error(`Parse failed: ${rel.parseError}`); * } * ``` */ export function isInvalidRelationship(rel) { return 'isValid' in rel && rel.isValid === false; } /** * Type guard to check if a relationship is unparsed (base type only) * * @param rel - The relationship to check * @returns True if the relationship is a BaseRelationship without parsed fields * * @example * ```typescript * if (isBaseRelationship(rel)) { * // Need to parse this relationship before use * const parsed = parseRelationship(rel); * } * ``` */ export function isBaseRelationship(rel) { return !('isValid' in rel); } /** * Safely parse a base relationship into a typed relationship variant * * This function attempts to parse the element ID and extract type/name components. * If parsing fails, it returns an InvalidRelationship with detailed error context * including position information and what was expected. * * @param rel - The base relationship to parse * @returns ParsedRelationship if successful, InvalidRelationship with diagnostics if failed * * @example Success case * ```typescript * const base: BaseRelationship = { element: 'skills:debugging' }; * const result = parseRelationship(base); * // result: ParsedRelationship with targetType='skills', targetName='debugging' * ``` * * @example Error cases with detailed diagnostics * ```typescript * parseRelationship({ element: 'no-separator' }); * // Error: "missing separator ':'" * * parseRelationship({ element: ':missing-type' }); * // Error: "missing type before ':'" * * parseRelationship({ element: 'too:many:colons' }); * // Error: "multiple separators ':' found at positions [3, 8]" * ``` */ export function parseRelationship(rel) { if (!rel.element) { return { ...rel, targetType: null, targetName: null, isValid: false, parseError: 'Invalid element ID: missing or empty (expected format: "type:name")' }; } // FIX: DMCP-SEC-004 - Normalize Unicode before parsing to prevent attacks const normalized = UnicodeValidator.normalize(rel.element); if (!normalized.isValid) { return { ...rel, targetType: null, targetName: null, isValid: false, parseError: `Invalid element ID - Unicode security issue: ${normalized.detectedIssues?.join(', ')}` }; } const parsed = parseElementId(normalized.normalizedContent); if (!parsed) { // Provide detailed error context about what was found (use normalized for safety) const colonIndex = normalized.normalizedContent.indexOf(':'); let errorDetail; if (colonIndex === -1) { errorDetail = `Invalid element ID format: "${normalized.normalizedContent}" - missing separator ':' (expected format: "type:name")`; } else if (colonIndex === 0) { errorDetail = `Invalid element ID format: "${normalized.normalizedContent}" - missing type before ':' (expected format: "type:name")`; } else if (colonIndex === normalized.normalizedContent.length - 1) { errorDetail = `Invalid element ID format: "${normalized.normalizedContent}" - missing name after ':' (expected format: "type:name")`; } else if (normalized.normalizedContent.split(':').length > 2) { const positions = []; for (let i = 0; i < normalized.normalizedContent.length; i++) { if (normalized.normalizedContent[i] === ':') positions.push(i); } errorDetail = `Invalid element ID format: "${normalized.normalizedContent}" - multiple separators ':' found at positions [${positions.join(', ')}] (expected format: "type:name" with single ':')`; } else { errorDetail = `Invalid element ID format: "${normalized.normalizedContent}" (expected format: "type:name")`; } return { ...rel, targetType: null, targetName: null, isValid: false, parseError: errorDetail }; } return { ...rel, targetType: parsed.type, targetName: parsed.name, isValid: true }; } /** * Batch parse relationships with type safety * Filters out invalid relationships by default */ export function parseRelationships(relationships, includeInvalid = false) { const parsed = relationships.map(parseRelationship); if (includeInvalid) { return parsed; } // Filter to only valid relationships return parsed.filter(isParsedRelationship); } /** * Create a new relationship with validation */ export function createRelationship(targetType, targetName, relationType, strength, metadata) { // FIX: DMCP-SEC-004 - Normalize Unicode in user input to prevent homograph attacks // Previously: Accepting raw user input without normalization // Now: Normalizing all string inputs to prevent Unicode-based security attacks const normalizedType = UnicodeValidator.normalize(targetType); if (!normalizedType.isValid) { throw new Error(`Invalid target type - Unicode security issue: ${normalizedType.detectedIssues?.join(', ')}`); } const normalizedName = UnicodeValidator.normalize(targetName); if (!normalizedName.isValid) { throw new Error(`Invalid target name - Unicode security issue: ${normalizedName.detectedIssues?.join(', ')}`); } // Also normalize relationship type if provided let normalizedRelType; if (relationType) { const normalizedRel = UnicodeValidator.normalize(relationType); if (!normalizedRel.isValid) { throw new Error(`Invalid relationship type - Unicode security issue: ${normalizedRel.detectedIssues?.join(', ')}`); } normalizedRelType = normalizedRel.normalizedContent; } // Validate strength is in range if (strength !== undefined && (strength < 0 || strength > 1 || Number.isNaN(strength))) { throw new Error(`Relationship strength must be between 0 and 1, got ${strength}`); } const element = formatElementId(normalizedType.normalizedContent, normalizedName.normalizedContent); // Relationship creation is internal index construction, not a security event. // Aggregate counts logged in "Relationship discovery completed" summary. return { element, type: normalizedRelType, strength, metadata, targetType: normalizedType.normalizedContent, targetName: normalizedName.normalizedContent, isValid: true }; } /** * Validate a relationship has required fields */ export function validateRelationship(rel) { return !!(rel && typeof rel === 'object' && 'element' in rel && typeof rel.element === 'string' && rel.element.length > 0); } /** * Group relationships by target type for efficient processing */ export function groupRelationshipsByType(relationships) { const grouped = new Map(); for (const rel of relationships) { const existing = grouped.get(rel.targetType) || []; existing.push(rel); grouped.set(rel.targetType, existing); } return grouped; } /** * Find duplicate relationships (same target element) */ export function findDuplicateRelationships(relationships) { const elementMap = new Map(); for (const rel of relationships) { const existing = elementMap.get(rel.element) || []; existing.push(rel); elementMap.set(rel.element, existing); } // Return only groups with duplicates return Array.from(elementMap.values()).filter(group => group.length > 1); } /** * Merge duplicate relationships, keeping highest strength */ export function deduplicateRelationships(relationships) { const elementMap = new Map(); for (const rel of relationships) { const existing = elementMap.get(rel.element); if (!existing || (rel.strength || 0) > (existing.strength || 0)) { elementMap.set(rel.element, rel); } } return Array.from(elementMap.values()); } /** * Sort relationships by strength (descending) */ export function sortRelationshipsByStrength(relationships) { return [...relationships].sort((a, b) => { const strengthA = a.strength || 0; const strengthB = b.strength || 0; return strengthB - strengthA; }); } /** * Filter relationships by minimum strength threshold */ export function filterRelationshipsByStrength(relationships, minStrength) { return relationships.filter(rel => (rel.strength || 0) >= minStrength); } /** * Relationship type aliases for common patterns */ export const RelationshipTypes = { // Similarity relationships SIMILAR_TO: 'similar_to', // Usage relationships USES: 'uses', USED_BY: 'used_by', // Extension relationships EXTENDS: 'extends', EXTENDED_BY: 'extended_by', // Composition relationships CONTAINS: 'contains', CONTAINED_BY: 'contained_by', // Debugging relationships HELPS_DEBUG: 'helps_debug', DEBUGGED_BY: 'debugged_by', // Conflict relationships CONTRADICTS: 'contradicts', SUPPORTS: 'supports', // Semantic relationships SEMANTIC_SIMILARITY: 'semantic_similarity' }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVsYXRpb25zaGlwVHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcG9ydGZvbGlvL3R5cGVzL1JlbGF0aW9uc2hpcFR5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNDRztBQUVILE9BQU8sRUFBRSxjQUFjLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDM0UsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sK0NBQStDLENBQUM7QUFpR2pGOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsTUFBTSxVQUFVLG9CQUFvQixDQUFDLEdBQWlCO0lBQ3BELE9BQU8sU0FBUyxJQUFJLEdBQUcsSUFBSSxHQUFHLENBQUMsT0FBTyxLQUFLLElBQUk7UUFDeEMsWUFBWSxJQUFJLEdBQUcsSUFBSSxHQUFHLENBQUMsVUFBVSxLQUFLLElBQUk7UUFDOUMsWUFBWSxJQUFJLEdBQUcsSUFBSSxHQUFHLENBQUMsVUFBVSxLQUFLLElBQUksQ0FBQztBQUN4RCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILE1BQU0sVUFBVSxxQkFBcUIsQ0FBQyxHQUFpQjtJQUNyRCxPQUFPLFNBQVMsSUFBSSxHQUFHLElBQUksR0FBRyxDQUFDLE9BQU8sS0FBSyxLQUFLLENBQUM7QUFDbkQsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxNQUFNLFVBQVUsa0JBQWtCLENBQUMsR0FBaUI7SUFDbEQsT0FBTyxDQUFDLENBQUMsU0FBUyxJQUFJLEdBQUcsQ0FBQyxDQUFDO0FBQzdCLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTRCRztBQUNILE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxHQUFxQjtJQUNyRCxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2pCLE9BQU87WUFDTCxHQUFHLEdBQUc7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LFlBQVksRUFBRSxjQUFjO0lBRTVCLDBCQUEwQjtJQUMxQixXQUFXLEVBQUUsYUFBYTtJQUMxQixXQUFXLEVBQUUsYUFBYTtJQUUxQix5QkFBeUI7SUFDekIsV0FBVyxFQUFFLGFBQWE7SUFDMUIsUUFBUSxFQUFFLFVBQVU7SUFFcEIseUJBQXlCO0lBQ3pCLG1CQUFtQixFQUFFLHFCQUFxQjtDQUNsQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUeXBlLXNhZmUgcmVsYXRpb25zaGlwIGRlZmluaXRpb25zIGZvciBFbmhhbmNlZCBJbmRleFxuICpcbiAqIFRoaXMgbW9kdWxlIHByb3ZpZGVzIGEgY29tcHJlaGVuc2l2ZSB0eXBlIHN5c3RlbSBmb3IgbWFuYWdpbmcgcmVsYXRpb25zaGlwc1xuICogYmV0d2VlbiBlbGVtZW50cyBpbiB0aGUgRG9sbGhvdXNlTUNQIEVuaGFuY2VkIEluZGV4LiBJdCBpbXBsZW1lbnRzIGEgdGhyZWUtdGllclxuICogdHlwZSBoaWVyYXJjaHkgdGhhdCBlbnN1cmVzIGJvdGggY29tcGlsZS10aW1lIGFuZCBydW50aW1lIHNhZmV0eS5cbiAqXG4gKiAjIyBUeXBlIEhpZXJhcmNoeTpcbiAqIDEuIEJhc2VSZWxhdGlvbnNoaXAgLSBUaGUgc3RvcmFnZSBmb3JtYXQgKHdoYXQncyBwZXJzaXN0ZWQgdG8gZGlzaylcbiAqIDIuIFBhcnNlZFJlbGF0aW9uc2hpcCAtIFZhbGlkIHJ1bnRpbWUgZm9ybWF0IHdpdGggZXh0cmFjdGVkIG1ldGFkYXRhXG4gKiAzLiBJbnZhbGlkUmVsYXRpb25zaGlwIC0gRXJyb3Igc3RhdGUgd2l0aCBkZXRhaWxlZCBkaWFnbm9zdGljc1xuICpcbiAqICMjIEtleSBGZWF0dXJlczpcbiAqIC0gU3Ryb25nbHktdHlwZWQgaW50ZXJmYWNlcyB3aXRoIGRpc2NyaW1pbmF0ZWQgdW5pb25zXG4gKiAtIFJ1bnRpbWUgdHlwZSBndWFyZHMgZm9yIHNhZmUgdHlwZSBuYXJyb3dpbmdcbiAqIC0gRGV0YWlsZWQgZXJyb3IgbWVzc2FnZXMgd2l0aCBwb3NpdGlvbiBpbmZvcm1hdGlvblxuICogLSBCYXRjaCBwcm9jZXNzaW5nIHV0aWxpdGllcyB3aXRoIHBlcmZvcm1hbmNlIG9wdGltaXphdGlvbnNcbiAqIC0gUmVsYXRpb25zaGlwIGRlZHVwbGljYXRpb24gYW5kIHNvcnRpbmcgYWxnb3JpdGhtc1xuICpcbiAqICMjIFVzYWdlIEV4YW1wbGU6XG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBQYXJzZSBhIHJlbGF0aW9uc2hpcCBmcm9tIHN0b3JhZ2VcbiAqIGNvbnN0IHN0b3JlZDogQmFzZVJlbGF0aW9uc2hpcCA9IHsgZWxlbWVudDogJ3BlcnNvbmFzOmV4cGVydC1jb2RlcicgfTtcbiAqIGNvbnN0IHBhcnNlZCA9IHBhcnNlUmVsYXRpb25zaGlwKHN0b3JlZCk7XG4gKlxuICogaWYgKGlzUGFyc2VkUmVsYXRpb25zaGlwKHBhcnNlZCkpIHtcbiAqICAgY29uc29sZS5sb2coYFR5cGU6ICR7cGFyc2VkLnRhcmdldFR5cGV9LCBOYW1lOiAke3BhcnNlZC50YXJnZXROYW1lfWApO1xuICogfSBlbHNlIHtcbiAqICAgY29uc29sZS5lcnJvcihgUGFyc2UgZmFpbGVkOiAke3BhcnNlZC5wYXJzZUVycm9yfWApO1xuICogfVxuICogYGBgXG4gKlxuICogRklYRVMgSU1QTEVNRU5URUQgKElzc3VlICMxMTAzKTpcbiAqIC0gVHlwZS1zYWZlIHJlbGF0aW9uc2hpcCB2YXJpYW50cyB3aXRoIGRpc2NyaW1pbmF0ZWQgdW5pb25zXG4gKiAtIENvbXBpbGUtdGltZSB2YWxpZGF0aW9uIHRocm91Z2ggVHlwZVNjcmlwdCdzIHR5cGUgc3lzdGVtXG4gKiAtIFJ1bnRpbWUgdHlwZSBndWFyZHMgZm9yIHNhZmUgdHlwZSBuYXJyb3dpbmdcbiAqIC0gU2FmZSBwYXJzaW5nIHV0aWxpdGllcyB3aXRoIGRldGFpbGVkIGVycm9yIHJlcG9ydGluZ1xuICogLSBTZWN1cml0eSBhdWRpdCBsb2dnaW5nIGZvciByZWxhdGlvbnNoaXAgb3BlcmF0aW9uc1xuICovXG5cbmltcG9ydCB7IHBhcnNlRWxlbWVudElkLCBmb3JtYXRFbGVtZW50SWQgfSBmcm9tICcuLi8uLi91dGlscy9lbGVtZW50SWQuanMnO1xuaW1wb3J0IHsgVW5pY29kZVZhbGlkYXRvciB9IGZyb20gJy4uLy4uL3NlY3VyaXR5L3ZhbGlkYXRvcnMvdW5pY29kZVZhbGlkYXRvci5qcyc7XG5cbi8qKlxuICogQmFzZSByZWxhdGlvbnNoaXAgaW50ZXJmYWNlIC0gdGhlIHN0b3JhZ2UgZm9ybWF0XG4gKlxuICogVGhpcyBpcyB0aGUgZnVuZGFtZW50YWwgcmVsYXRpb25zaGlwIHN0cnVjdHVyZSB0aGF0IGdldHMgcGVyc2lzdGVkIHRvIGRpc2suXG4gKiBJdCBjb250YWlucyBvbmx5IHRoZSByYXcgZGF0YSB3aXRob3V0IGFueSBwYXJzZWQgb3IgY29tcHV0ZWQgZmllbGRzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCByZWxhdGlvbnNoaXA6IEJhc2VSZWxhdGlvbnNoaXAgPSB7XG4gKiAgIGVsZW1lbnQ6ICdza2lsbHM6ZGVidWdnaW5nJyxcbiAqICAgdHlwZTogJ3NpbWlsYXJfdG8nLFxuICogICBzdHJlbmd0aDogMC44NSxcbiAqICAgbWV0YWRhdGE6IHsgcmVhc29uOiAnQm90aCBpbnZvbHZlIGNvZGUgYW5hbHlzaXMnIH1cbiAqIH07XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCYXNlUmVsYXRpb25zaGlwIHtcbiAgLyoqIEVsZW1lbnQgSUQgaW4gZm9ybWF0IFwidHlwZTpuYW1lXCIgKGUuZy4sIFwicGVyc29uYXM6ZXhwZXJ0XCIsIFwic2tpbGxzOnJlZmFjdG9yXCIpICovXG4gIGVsZW1lbnQ6IHN0cmluZztcblxuICAvKiogU2VtYW50aWMgcmVsYXRpb25zaGlwIHR5cGUgZnJvbSBSZWxhdGlvbnNoaXBUeXBlcyBlbnVtIChlLmcuLCAndXNlcycsICdzaW1pbGFyX3RvJywgJ2V4dGVuZHMnKSAqL1xuICB0eXBlPzogc3RyaW5nO1xuXG4gIC8qKiBSZWxhdGlvbnNoaXAgc3RyZW5ndGgvY29uZmlkZW5jZSBzY29yZSBiZXR3ZWVuIDAuMCBhbmQgMS4wIChpbmNsdXNpdmUpICovXG4gIHN0cmVuZ3RoPzogbnVtYmVyO1xuXG4gIC8qKiBFeHRlbnNpYmxlIG1ldGFkYXRhIGZvciBjdXN0b20gcHJvcGVydGllcyAoZS5nLiwgc2ltaWxhcml0eSBzY29yZXMsIHRpbWVzdGFtcHMpICovXG4gIG1ldGFkYXRhPzogUmVjb3JkPHN0cmluZywgYW55Pjtcbn1cblxuLyoqXG4gKiBQYXJzZWQgcmVsYXRpb25zaGlwIHdpdGggZXh0cmFjdGVkIHR5cGUgYW5kIG5hbWUgY29tcG9uZW50c1xuICpcbiAqIFRoaXMgaXMgdGhlIHJ1bnRpbWUgZm9ybWF0IGFmdGVyIHN1Y2Nlc3NmdWxseSBwYXJzaW5nIGEgQmFzZVJlbGF0aW9uc2hpcC5cbiAqIEl0IGluY2x1ZGVzIGFsbCBiYXNlIGZpZWxkcyBwbHVzIGV4dHJhY3RlZCBtZXRhZGF0YSBmb3IgZWZmaWNpZW50IHF1ZXJ5aW5nLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBwYXJzZWQ6IFBhcnNlZFJlbGF0aW9uc2hpcCA9IHtcbiAqICAgZWxlbWVudDogJ3BlcnNvbmFzOmV4cGVydC1jb2RlcicsXG4gKiAgIHR5cGU6ICdzaW1pbGFyX3RvJyxcbiAqICAgc3RyZW5ndGg6IDAuOSxcbiAqICAgdGFyZ2V0VHlwZTogJ3BlcnNvbmFzJywgIC8vIEV4dHJhY3RlZCBmcm9tIGVsZW1lbnRcbiAqICAgdGFyZ2V0TmFtZTogJ2V4cGVydC1jb2RlcicsICAvLyBFeHRyYWN0ZWQgZnJvbSBlbGVtZW50XG4gKiAgIGlzVmFsaWQ6IHRydWUgIC8vIFR5cGUgZGlzY3JpbWluYXRvclxuICogfTtcbiAqIGBgYFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFBhcnNlZFJlbGF0aW9uc2hpcCBleHRlbmRzIEJhc2VSZWxhdGlvbnNoaXAge1xuICAvKiogRXh0cmFjdGVkIGVsZW1lbnQgdHlwZSAoZS5nLiwgJ3BlcnNvbmFzJywgJ3NraWxscycsICd0ZW1wbGF0ZXMnKSAqL1xuICB0YXJnZXRUeXBlOiBzdHJpbmc7XG5cbiAgLyoqIEV4dHJhY3RlZCBlbGVtZW50IG5hbWUgKGUuZy4sICdleHBlcnQtY29kZXInLCAnZGVidWdnaW5nJykgKi9cbiAgdGFyZ2V0TmFtZTogc3RyaW5nO1xuXG4gIC8qKiBUeXBlIGRpc2NyaW1pbmF0b3IgLSBhbHdheXMgdHJ1ZSBmb3IgdmFsaWQgcGFyc2VkIHJlbGF0aW9uc2hpcHMgKi9cbiAgaXNWYWxpZDogdHJ1ZTtcbn1cblxuLyoqXG4gKiBJbnZhbGlkIHJlbGF0aW9uc2hpcCBzdGF0ZSB3aXRoIGRpYWdub3N0aWMgaW5mb3JtYXRpb25cbiAqXG4gKiBUaGlzIHR5cGUgcmVwcmVzZW50cyBhIHJlbGF0aW9uc2hpcCB0aGF0IGZhaWxlZCB0byBwYXJzZSwgcHJlc2VydmluZ1xuICogdGhlIG9yaWdpbmFsIGRhdGEgd2hpbGUgcHJvdmlkaW5nIGRldGFpbGVkIGVycm9yIGNvbnRleHQgZm9yIGRlYnVnZ2luZy5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3QgaW52YWxpZDogSW52YWxpZFJlbGF0aW9uc2hpcCA9IHtcbiAqICAgZWxlbWVudDogJ21hbGZvcm1lZDplbGVtZW50OmlkJyxcbiAqICAgdGFyZ2V0VHlwZTogbnVsbCxcbiAqICAgdGFyZ2V0TmFtZTogbnVsbCxcbiAqICAgaXNWYWxpZDogZmFsc2UsXG4gKiAgIHBhcnNlRXJyb3I6ICdJbnZhbGlkIGVsZW1lbnQgSUQgZm9ybWF0OiBcIm1hbGZvcm1lZDplbGVtZW50OmlkXCIgLSBtdWx0aXBsZSBzZXBhcmF0b3JzLi4uJ1xuICogfTtcbiAqIGBgYFxuICovXG5leHBvcnQgaW50ZXJmYWNlIEludmFsaWRSZWxhdGlvbnNoaXAgZXh0ZW5kcyBCYXNlUmVsYXRpb25zaGlwIHtcbiAgLyoqIE51bGwgd2hlbiBwYXJzaW5nIGZhaWxzICovXG4gIHRhcmdldFR5cGU6IG51bGw7XG5cbiAgLyoqIE51bGwgd2hlbiBwYXJzaW5nIGZhaWxzICovXG4gIHRhcmdldE5hbWU6IG51bGw7XG5cbiAgLyoqIFR5cGUgZGlzY3JpbWluYXRvciAtIGFsd2F5cyBmYWxzZSBmb3IgaW52YWxpZCByZWxhdGlvbnNoaXBzICovXG4gIGlzVmFsaWQ6IGZhbHNlO1xuXG4gIC8qKiBEZXRhaWxlZCBlcnJvciBtZXNzYWdlIHdpdGggcG9zaXRpb24gaW5mb3JtYXRpb24gYW5kIGV4cGVjdGVkIGZvcm1hdCAqL1xuICBwYXJzZUVycm9yOiBzdHJpbmc7XG59XG5cbi8qKlxuICogVW5pb24gdHlwZSBmb3IgYWxsIHJlbGF0aW9uc2hpcCB2YXJpYW50c1xuICovXG5leHBvcnQgdHlwZSBSZWxhdGlvbnNoaXAgPSBCYXNlUmVsYXRpb25zaGlwIHwgUGFyc2VkUmVsYXRpb25zaGlwIHwgSW52YWxpZFJlbGF0aW9uc2hpcDtcblxuLyoqXG4gKiBUeXBlIGd1YXJkIHRvIGNoZWNrIGlmIGEgcmVsYXRpb25zaGlwIGlzIHN1Y2Nlc3NmdWxseSBwYXJzZWRcbiAqXG4gKiBAcGFyYW0gcmVsIC0gVGhlIHJlbGF0aW9uc2hpcCB0byBjaGVja1xuICogQHJldHVybnMgVHJ1ZSBpZiB0aGUgcmVsYXRpb25zaGlwIGlzIGEgUGFyc2VkUmVsYXRpb25zaGlwIHdpdGggdmFsaWQgZGF0YVxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCByZWwgPSBwYXJzZVJlbGF0aW9uc2hpcChiYXNlUmVsKTtcbiAqIGlmIChpc1BhcnNlZFJlbGF0aW9uc2hpcChyZWwpKSB7XG4gKiAgIC8vIFR5cGVTY3JpcHQga25vd3MgcmVsIGlzIFBhcnNlZFJlbGF0aW9uc2hpcCBoZXJlXG4gKiAgIGNvbnNvbGUubG9nKHJlbC50YXJnZXRUeXBlLCByZWwudGFyZ2V0TmFtZSk7XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzUGFyc2VkUmVsYXRpb25zaGlwKHJlbDogUmVsYXRpb25zaGlwKTogcmVsIGlzIFBhcnNlZFJlbGF0aW9uc2hpcCB7XG4gIHJldHVybiAnaXNWYWxpZCcgaW4gcmVsICYmIHJlbC5pc1ZhbGlkID09PSB0cnVlICYmXG4gICAgICAgICAndGFyZ2V0VHlwZScgaW4gcmVsICYmIHJlbC50YXJnZXRUeXBlICE9PSBudWxsICYmXG4gICAgICAgICAndGFyZ2V0TmFtZScgaW4gcmVsICYmIHJlbC50YXJnZXROYW1lICE9PSBudWxsO1xufVxuXG4vKipcbiAqIFR5cGUgZ3VhcmQgdG8gY2hlY2sgaWYgYSByZWxhdGlvbnNoaXAgZmFpbGVkIHRvIHBhcnNlXG4gKlxuICogQHBhcmFtIHJlbCAtIFRoZSByZWxhdGlvbnNoaXAgdG8gY2hlY2tcbiAqIEByZXR1cm5zIFRydWUgaWYgdGhlIHJlbGF0aW9uc2hpcCBpcyBhbiBJbnZhbGlkUmVsYXRpb25zaGlwIHdpdGggZXJyb3IgZGV0YWlsc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCByZWwgPSBwYXJzZVJlbGF0aW9uc2hpcChiYXNlUmVsKTtcbiAqIGlmIChpc0ludmFsaWRSZWxhdGlvbnNoaXAocmVsKSkge1xuICogICBjb25zb2xlLmVycm9yKGBQYXJzZSBmYWlsZWQ6ICR7cmVsLnBhcnNlRXJyb3J9YCk7XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzSW52YWxpZFJlbGF0aW9uc2hpcChyZWw6IFJlbGF0aW9uc2hpcCk6IHJlbCBpcyBJbnZhbGlkUmVsYXRpb25zaGlwIHtcbiAgcmV0dXJuICdpc1ZhbGlkJyBpbiByZWwgJiYgcmVsLmlzVmFsaWQgPT09IGZhbHNlO1xufVxuXG4vKipcbiAqIFR5cGUgZ3VhcmQgdG8gY2hlY2sgaWYgYSByZWxhdGlvbnNoaXAgaXMgdW5wYXJzZWQgKGJhc2UgdHlwZSBvbmx5KVxuICpcbiAqIEBwYXJhbSByZWwgLSBUaGUgcmVsYXRpb25zaGlwIHRvIGNoZWNrXG4gKiBAcmV0dXJucyBUcnVlIGlmIHRoZSByZWxhdGlvbnNoaXAgaXMgYSBCYXNlUmVsYXRpb25zaGlwIHdpdGhvdXQgcGFyc2VkIGZpZWxkc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpZiAoaXNCYXNlUmVsYXRpb25zaGlwKHJlbCkpIHtcbiAqICAgLy8gTmVlZCB0byBwYXJzZSB0aGlzIHJlbGF0aW9uc2hpcCBiZWZvcmUgdXNlXG4gKiAgIGNvbnN0IHBhcnNlZCA9IHBhcnNlUmVsYXRpb25zaGlwKHJlbCk7XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzQmFzZVJlbGF0aW9uc2hpcChyZWw6IFJlbGF0aW9uc2hpcCk6IHJlbCBpcyBCYXNlUmVsYXRpb25zaGlwIHtcbiAgcmV0dXJuICEoJ2lzVmFsaWQnIGluIHJlbCk7XG59XG5cbi8qKlxuICogU2FmZWx5IHBhcnNlIGEgYmFzZSByZWxhdGlvbnNoaXAgaW50byBhIHR5cGVkIHJlbGF0aW9uc2hpcCB2YXJpYW50XG4gKlxuICogVGhpcyBmdW5jdGlvbiBhdHRlbXB0cyB0byBwYXJzZSB0aGUgZWxlbWVudCBJRCBhbmQgZXh0cmFjdCB0eXBlL25hbWUgY29tcG9uZW50cy5cbiAqIElmIHBhcnNpbmcgZmFpbHMsIGl0IHJldHVybnMgYW4gSW52YWxpZFJlbGF0aW9uc2hpcCB3aXRoIGRldGFpbGVkIGVycm9yIGNvbnRleHRcbiAqIGluY2x1ZGluZyBwb3NpdGlvbiBpbmZvcm1hdGlvbiBhbmQgd2hhdCB3YXMgZXhwZWN0ZWQuXG4gKlxuICogQHBhcmFtIHJlbCAtIFRoZSBiYXNlIHJlbGF0aW9uc2hpcCB0byBwYXJzZVxuICogQHJldHVybnMgUGFyc2VkUmVsYXRpb25zaGlwIGlmIHN1Y2Nlc3NmdWwsIEludmFsaWRSZWxhdGlvbnNoaXAgd2l0aCBkaWFnbm9zdGljcyBpZiBmYWlsZWRcbiAqXG4gKiBAZXhhbXBsZSBTdWNjZXNzIGNhc2VcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGJhc2U6IEJhc2VSZWxhdGlvbnNoaXAgPSB7IGVsZW1lbnQ6ICdza2lsbHM6ZGVidWdnaW5nJyB9O1xuICogY29uc3QgcmVzdWx0ID0gcGFyc2VSZWxhdGlvbnNoaXAoYmFzZSk7XG4gKiAvLyByZXN1bHQ6IFBhcnNlZFJlbGF0aW9uc2hpcCB3aXRoIHRhcmdldFR5cGU9J3NraWxscycsIHRhcmdldE5hbWU9J2RlYnVnZ2luZydcbiAqIGBgYFxuICpcbiAqIEBleGFtcGxlIEVycm9yIGNhc2VzIHdpdGggZGV0YWlsZWQgZGlhZ25vc3RpY3NcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIHBhcnNlUmVsYXRpb25zaGlwKHsgZWxlbWVudDogJ25vLXNlcGFyYXRvcicgfSk7XG4gKiAvLyBFcnJvcjogXCJtaXNzaW5nIHNlcGFyYXRvciAnOidcIlxuICpcbiAqIHBhcnNlUmVsYXRpb25zaGlwKHsgZWxlbWVudDogJzptaXNzaW5nLXR5cGUnIH0pO1xuICogLy8gRXJyb3I6IFwibWlzc2luZyB0eXBlIGJlZm9yZSAnOidcIlxuICpcbiAqIHBhcnNlUmVsYXRpb25zaGlwKHsgZWxlbWVudDogJ3RvbzptYW55OmNvbG9ucycgfSk7XG4gKiAvLyBFcnJvcjogXCJtdWx0aXBsZSBzZXBhcmF0b3JzICc6JyBmb3VuZCBhdCBwb3NpdGlvbnMgWzMsIDhdXCJcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VSZWxhdGlvbnNoaXAocmVsOiBCYXNlUmVsYXRpb25zaGlwKTogUGFyc2VkUmVsYXRpb25zaGlwIHwgSW52YWxpZFJlbGF0aW9uc2hpcCB7XG4gIGlmICghcmVsLmVsZW1lbnQpIHtcbiAgICByZXR1cm4ge1xuICAgICAgLi4ucmVsLFxuICAgICAgdGFyZ2V0VHlwZTogbnVsbCxcbiAgICAgIHRhcmdldE5hbWU6IG51bGwsXG4gICAgICBpc1ZhbGlkOiBmYWxzZSxcbiAgICAgIHBhcnNlRXJyb3I6ICdJbnZhbGlkIGVsZW1lbnQgSUQ6IG1pc3Npbmcgb3IgZW1wdHkgKGV4cGVjdGVkIGZvcm1hdDogXCJ0eXBlOm5hbWVcIiknXG4gICAgfTtcbiAgfVxuXG4gIC8vIEZJWDogRE1DUC1TRUMtMDA0IC0gTm9ybWFsaXplIFVuaWNvZGUgYmVmb3JlIHBhcnNpbmcgdG8gcHJldmVudCBhdHRhY2tzXG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShyZWwuZWxlbWVudCk7XG4gIGlmICghbm9ybWFsaXplZC5pc1ZhbGlkKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLnJlbCxcbiAgICAgIHRhcmdldFR5cGU6IG51bGwsXG4gICAgICB0YXJnZXROYW1lOiBudWxsLFxuICAgICAgaXNWYWxpZDogZmFsc2UsXG4gICAgICBwYXJzZUVycm9yOiBgSW52YWxpZCBlbGVtZW50IElEIC0gVW5pY29kZSBzZWN1cml0eSBpc3N1ZTogJHtub3JtYWxpemVkLmRldGVjdGVkSXNzdWVzPy5qb2luKCcsICcpfWBcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgcGFyc2VkID0gcGFyc2VFbGVtZW50SWQobm9ybWFsaXplZC5ub3JtYWxpemVkQ29udGVudCk7XG5cbiAgaWYgKCFwYXJzZWQpIHtcbiAgICAvLyBQcm92aWRlIGRldGFpbGVkIGVycm9yIGNvbnRleHQgYWJvdXQgd2hhdCB3YXMgZm91bmQgKHVzZSBub3JtYWxpemVkIGZvciBzYWZldHkpXG4gICAgY29uc3QgY29sb25JbmRleCA9IG5vcm1hbGl6ZWQubm9ybWFsaXplZENvbnRlbnQuaW5kZXhPZignOicpO1xuICAgIGxldCBlcnJvckRldGFpbDogc3RyaW5nO1xuXG4gICAgaWYgKGNvbG9uSW5kZXggPT09IC0xKSB7XG4gICAgICBlcnJvckRldGFpbCA9IGBJbnZhbGlkIGVsZW1lbnQgSUQgZm9ybWF0OiBcIiR7bm9ybWFsaXplZC5ub3JtYWxpemVkQ29udGVudH1cIiAtIG1pc3Npbmcgc2VwYXJhdG9yICc6JyAoZXhwZWN0ZWQgZm9ybWF0OiBcInR5cGU6bmFtZVwiKWA7XG4gICAgfSBlbHNlIGlmIChjb2xvbkluZGV4ID09PSAwKSB7XG4gICAgICBlcnJvckRldGFpbCA9IGBJbnZhbGlkIGVsZW1lbnQgSUQgZm9ybWF0OiBcIiR7bm9ybWFsaXplZC5ub3JtYWxpemVkQ29udGVudH1cIiAtIG1pc3NpbmcgdHlwZSBiZWZvcmUgJzonIChleHBlY3RlZCBmb3JtYXQ6IFwidHlwZTpuYW1lXCIpYDtcbiAgICB9IGVsc2UgaWYgKGNvbG9uSW5kZXggPT09IG5vcm1hbGl6ZWQubm9ybWFsaXplZENvbnRlbnQubGVuZ3RoIC0gMSkge1xuICAgICAgZXJyb3JEZXRhaWwgPSBgSW52YWxpZCBlbGVtZW50IElEIGZvcm1hdDogXCIke25vcm1hbGl6ZWQubm9ybWFsaXplZENvbnRlbnR9XCIgLSBtaXNzaW5nIG5hbWUgYWZ0ZXIgJzonIChleHBlY3RlZCBmb3JtYXQ6IFwidHlwZTpuYW1lXCIpYDtcbiAgICB9IGVsc2UgaWYgKG5vcm1hbGl6ZWQubm9ybWFsaXplZENvbnRlbnQuc3BsaXQoJzonKS5sZW5ndGggPiAyKSB7XG4gICAgICBjb25zdCBwb3NpdGlvbnMgPSBbXTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbm9ybWFsaXplZC5ub3JtYWxpemVkQ29udGVudC5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAobm9ybWFsaXplZC5ub3JtYWxpemVkQ29udGVudFtpXSA9PT0gJzonKSBwb3NpdGlvbnMucHVzaChpKTtcbiAgICAgIH1cbiAgICAgIGVycm9yRGV0YWlsID0gYEludmFsaWQgZWxlbWVudCBJRCBmb3JtYXQ6IFwiJHtub3JtYWxpemVkLm5vcm1hbGl6ZWRDb250ZW50fVwiIC0gbXVsdGlwbGUgc2VwYXJhdG9ycyAnOicgZm91bmQgYXQgcG9zaXRpb25zIFske3Bvc2l0aW9ucy5qb2luKCcsICcpfV0gKGV4cGVjdGVkIGZvcm1hdDogXCJ0eXBlOm5hbWVcIiB3aXRoIHNpbmdsZSAnOicpYDtcbiAgICB9IGVsc2Uge1xuICAgICAgZXJyb3JEZXRhaWwgPSBgSW52YWxpZCBlbGVtZW50IElEIGZvcm1hdDogXCIke25vcm1hbGl6ZWQubm9ybWFsaXplZENvbnRlbnR9XCIgKGV4cGVjdGVkIGZvcm1hdDogXCJ0eXBlOm5hbWVcIilgO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICAuLi5yZWwsXG4gICAgICB0YXJnZXRUeXBlOiBudWxsLFxuICAgICAgdGFyZ2V0TmFtZTogbnVsbCxcbiAgICAgIGlzVmFsaWQ6IGZhbHNlLFxuICAgICAgcGFyc2VFcnJvcjogZXJyb3JEZXRhaWxcbiAgICB9O1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICAuLi5yZWwsXG4gICAgdGFyZ2V0VHlwZTogcGFyc2VkLnR5cGUsXG4gICAgdGFyZ2V0TmFtZTogcGFyc2VkLm5hbWUsXG4gICAgaXNWYWxpZDogdHJ1ZVxuICB9O1xufVxuXG4vKipcbiAqIEJhdGNoIHBhcnNlIHJlbGF0aW9uc2hpcHMgd2l0aCB0eXBlIHNhZmV0eVxuICogRmlsdGVycyBvdXQgaW52YWxpZCByZWxhdGlvbnNoaXBzIGJ5IGRlZmF1bHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlUmVsYXRpb25zaGlwcyhcbiAgcmVsYXRpb25zaGlwczogQmFzZVJlbGF0aW9uc2hpcFtdLFxuICBpbmNsdWRlSW52YWxpZDogYm9vbGVhbiA9IGZhbHNlXG4pOiBQYXJzZWRSZWxhdGlvbnNoaXBbXSB8IChQYXJzZWRSZWxhdGlvbnNoaXAgfCBJbnZhbGlkUmVsYXRpb25zaGlwKVtdIHtcbiAgY29uc3QgcGFyc2VkID0gcmVsYXRpb25zaGlwcy5tYXAocGFyc2VSZWxhdGlvbnNoaXApO1xuXG4gIGlmIChpbmNsdWRlSW52YWxpZCkge1xuICAgIHJldHVybiBwYXJzZWQ7XG4gIH1cblxuICAvLyBGaWx0ZXIgdG8gb25seSB2YWxpZCByZWxhdGlvbnNoaXBzXG4gIHJldHVybiBwYXJzZWQuZmlsdGVyKGlzUGFyc2VkUmVsYXRpb25zaGlwKTtcbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBuZXcgcmVsYXRpb25zaGlwIHdpdGggdmFsaWRhdGlvblxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlUmVsYXRpb25zaGlwKFxuICB0YXJnZXRUeXBlOiBzdHJpbmcsXG4gIHRhcmdldE5hbWU6IHN0cmluZyxcbiAgcmVsYXRpb25UeXBlPzogc3RyaW5nLFxuICBzdHJlbmd0aD86IG51bWJlcixcbiAgbWV0YWRhdGE/OiBSZWNvcmQ8c3RyaW5nLCBhbnk+XG4pOiBQYXJzZWRSZWxhdGlvbnNoaXAge1xuICAvLyBGSVg6IERNQ1AtU0VDLTAwNCAtIE5vcm1hbGl6ZSBVbmljb2RlIGluIHVzZXIgaW5wdXQgdG8gcHJldmVudCBob21vZ3JhcGggYXR0YWNrc1xuICAvLyBQcmV2aW91c2x5OiBBY2NlcHRpbmcgcmF3IHVzZXIgaW5wdXQgd2l0aG91dCBub3JtYWxpemF0aW9uXG4gIC8vIE5vdzogTm9ybWFsaXppbmcgYWxsIHN0cmluZyBpbnB1dHMgdG8gcHJldmVudCBVbmljb2RlLWJhc2VkIHNlY3VyaXR5IGF0dGFja3NcbiAgY29uc3Qgbm9ybWFsaXplZFR5cGUgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZSh0YXJnZXRUeXBlKTtcbiAgaWYgKCFub3JtYWxpemVkVHlwZS5pc1ZhbGlkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHRhcmdldCB0eXBlIC0gVW5pY29kZSBzZWN1cml0eSBpc3N1ZTogJHtub3JtYWxpemVkVHlwZS5kZXRlY3RlZElzc3Vlcz8uam9pbignLCAnKX1gKTtcbiAgfVxuXG4gIGNvbnN0IG5vcm1hbGl6ZWROYW1lID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUodGFyZ2V0TmFtZSk7XG4gIGlmICghbm9ybWFsaXplZE5hbWUuaXNWYWxpZCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB0YXJnZXQgbmFtZSAtIFVuaWNvZGUgc2VjdXJpdHkgaXNzdWU6ICR7bm9ybWFsaXplZE5hbWUuZGV0ZWN0ZWRJc3N1ZXM/LmpvaW4oJywgJyl9YCk7XG4gIH1cblxuICAvLyBBbHNvIG5vcm1hbGl6ZSByZWxhdGlvbnNoaXAgdHlwZSBpZiBwcm92aWRlZFxuICBsZXQgbm9ybWFsaXplZFJlbFR5cGU6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgaWYgKHJlbGF0aW9uVHlwZSkge1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRSZWwgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShyZWxhdGlvblR5cGUpO1xuICAgIGlmICghbm9ybWFsaXplZFJlbC5pc1ZhbGlkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgcmVsYXRpb25zaGlwIHR5cGUgLSBVbmljb2RlIHNlY3VyaXR5IGlzc3VlOiAke25vcm1hbGl6ZWRSZWwuZGV0ZWN0ZWRJc3N1ZXM/LmpvaW4oJywgJyl9YCk7XG4gICAgfVxuICAgIG5vcm1hbGl6ZWRSZWxUeXBlID0gbm9ybWFsaXplZFJlbC5ub3JtYWxpemVkQ29udGVudDtcbiAgfVxuXG4gIC8vIFZhbGlkYXRlIHN0cmVuZ3RoIGlzIGluIHJhbmdlXG4gIGlmIChzdHJlbmd0aCAhPT0gdW5kZWZpbmVkICYmIChzdHJlbmd0aCA8IDAgfHwgc3RyZW5ndGggPiAxIHx8IE51bWJlci5pc05hTihzdHJlbmd0aCkpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBSZWxhdGlvbnNoaXAgc3RyZW5ndGggbXVzdCBiZSBiZXR3ZWVuIDAgYW5kIDEsIGdvdCAke3N0cmVuZ3RofWApO1xuICB9XG5cbiAgY29uc3QgZWxlbWVudCA9IGZvcm1hdEVsZW1lbnRJZChub3JtYWxpemVkVHlwZS5ub3JtYWxpemVkQ29udGVudCwgbm9ybWFsaXplZE5hbWUubm9ybWFsaXplZENvbnRlbnQpO1xuXG4gIC8vIFJlbGF0aW9uc2hpcCBjcmVhdGlvbiBpcyBpbnRlcm5hbCBpbmRleCBjb25zdHJ1Y3Rpb24sIG5vdCBhIHNlY3VyaXR5IGV2ZW50LlxuICAvLyBBZ2dyZWdhdGUgY291bnRzIGxvZ2dlZCBpbiBcIlJlbGF0aW9uc2hpcCBkaXNjb3ZlcnkgY29tcGxldGVkXCIgc3VtbWFyeS5cblxuICByZXR1cm4ge1xuICAgIGVsZW1lbnQsXG4gICAgdHlwZTogbm9ybWFsaXplZFJlbFR5cGUsXG4gICAgc3RyZW5ndGgsXG4gICAgbWV0YWRhdGEsXG4gICAgdGFyZ2V0VHlwZTogbm9ybWFsaXplZFR5cGUubm9ybWFsaXplZENvbnRlbnQsXG4gICAgdGFyZ2V0TmFtZTogbm9ybWFsaXplZE5hbWUubm9ybWFsaXplZENvbnRlbnQsXG4gICAgaXNWYWxpZDogdHJ1ZVxuICB9O1xufVxuXG4vKipcbiAqIFZhbGlkYXRlIGEgcmVsYXRpb25zaGlwIGhhcyByZXF1aXJlZCBmaWVsZHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlUmVsYXRpb25zaGlwKHJlbDogYW55KTogcmVsIGlzIEJhc2VSZWxhdGlvbnNoaXAge1xuICByZXR1cm4gISEocmVsICYmXG4gICAgICAgICAgICB0eXBlb2YgcmVsID09PSAnb2JqZWN0JyAmJlxuICAgICAgICAgICAgJ2VsZW1lbnQnIGluIHJlbCAmJlxuICAgICAgICAgICAgdHlwZW9mIHJlbC5lbGVtZW50ID09PSAnc3RyaW5nJyAmJlxuICAgICAgICAgICAgcmVsLmVsZW1lbnQubGVuZ3RoID4gMCk7XG59XG5cbi8qKlxuICogR3JvdXAgcmVsYXRpb25zaGlwcyBieSB0YXJnZXQgdHlwZSBmb3IgZWZmaWNpZW50IHByb2Nlc3NpbmdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdyb3VwUmVsYXRpb25zaGlwc0J5VHlwZShcbiAgcmVsYXRpb25zaGlwczogUGFyc2VkUmVsYXRpb25zaGlwW11cbik6IE1hcDxzdHJpbmcsIFBhcnNlZFJlbGF0aW9uc2hpcFtdPiB7XG4gIGNvbnN0IGdyb3VwZWQgPSBuZXcgTWFwPHN0cmluZywgUGFyc2VkUmVsYXRpb25zaGlwW10+KCk7XG5cbiAgZm9yIChjb25zdCByZWwgb2YgcmVsYXRpb25zaGlwcykge1xuICAgIGNvbnN0IGV4aXN0aW5nID0gZ3JvdXBlZC5nZXQocmVsLnRhcmdldFR5cGUpIHx8IFtdO1xuICAgIGV4aXN0aW5nLnB1c2gocmVsKTtcbiAgICBncm91cGVkLnNldChyZWwudGFyZ2V0VHlwZSwgZXhpc3RpbmcpO1xuICB9XG5cbiAgcmV0dXJuIGdyb3VwZWQ7XG59XG5cbi8qKlxuICogRmluZCBkdXBsaWNhdGUgcmVsYXRpb25zaGlwcyAoc2FtZSB0YXJnZXQgZWxlbWVudClcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbmREdXBsaWNhdGVSZWxhdGlvbnNoaXBzKFxuICByZWxhdGlvbnNoaXBzOiBCYXNlUmVsYXRpb25zaGlwW11cbik6IEJhc2VSZWxhdGlvbnNoaXBbXVtdIHtcbiAgY29uc3QgZWxlbWVudE1hcCA9IG5ldyBNYXA8c3RyaW5nLCBCYXNlUmVsYXRpb25zaGlwW10+KCk7XG5cbiAgZm9yIChjb25zdCByZWwgb2YgcmVsYXRpb25zaGlwcykge1xuICAgIGNvbnN0IGV4aXN0aW5nID0gZWxlbWVudE1hcC5nZXQocmVsLmVsZW1lbnQpIHx8IFtdO1xuICAgIGV4aXN0aW5nLnB1c2gocmVsKTtcbiAgICBlbGVtZW50TWFwLnNldChyZWwuZWxlbWVudCwgZXhpc3RpbmcpO1xuICB9XG5cbiAgLy8gUmV0dXJuIG9ubHkgZ3JvdXBzIHdpdGggZHVwbGljYXRlc1xuICByZXR1cm4gQXJyYXkuZnJvbShlbGVtZW50TWFwLnZhbHVlcygpKS5maWx0ZXIoZ3JvdXAgPT4gZ3JvdXAubGVuZ3RoID4gMSk7XG59XG5cbi8qKlxuICogTWVyZ2UgZHVwbGljYXRlIHJlbGF0aW9uc2hpcHMsIGtlZXBpbmcgaGlnaGVzdCBzdHJlbmd0aFxuICovXG5leHBvcnQgZnVuY3Rpb24gZGVkdXBsaWNhdGVSZWxhdGlvbnNoaXBzKFxuICByZWxhdGlvbnNoaXBzOiBCYXNlUmVsYXRpb25zaGlwW11cbik6IEJhc2VSZWxhdGlvbnNoaXBbXSB7XG4gIGNvbnN0IGVsZW1lbnRNYXAgPSBuZXcgTWFwPHN0cmluZywgQmFzZVJlbGF0aW9uc2hpcD4oKTtcblxuICBmb3IgKGNvbnN0IHJlbCBvZiByZWxhdGlvbnNoaXBzKSB7XG4gICAgY29uc3QgZXhpc3RpbmcgPSBlbGVtZW50TWFwLmdldChyZWwuZWxlbWVudCk7XG5cbiAgICBpZiAoIWV4aXN0aW5nIHx8IChyZWwuc3RyZW5ndGggfHwgMCkgPiAoZXhpc3Rpbmcuc3RyZW5ndGggfHwgMCkpIHtcbiAgICAgIGVsZW1lbnRNYXAuc2V0KHJlbC5lbGVtZW50LCByZWwpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBBcnJheS5mcm9tKGVsZW1lbnRNYXAudmFsdWVzKCkpO1xufVxuXG4vKipcbiAqIFNvcnQgcmVsYXRpb25zaGlwcyBieSBzdHJlbmd0aCAoZGVzY2VuZGluZylcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNvcnRSZWxhdGlvbnNoaXBzQnlTdHJlbmd0aChcbiAgcmVsYXRpb25zaGlwczogQmFzZVJlbGF0aW9uc2hpcFtdXG4pOiBCYXNlUmVsYXRpb25zaGlwW10ge1xuICByZXR1cm4gWy4uLnJlbGF0aW9uc2hpcHNdLnNvcnQoKGEsIGIpID0+IHtcbiAgICBjb25zdCBzdHJlbmd0aEEgPSBhLnN0cmVuZ3RoIHx8IDA7XG4gICAgY29uc3Qgc3RyZW5ndGhCID0gYi5zdHJlbmd0aCB8fCAwO1xuICAgIHJldHVybiBzdHJlbmd0aEIgLSBzdHJlbmd0aEE7XG4gIH0pO1xufVxuXG4vKipcbiAqIEZpbHRlciByZWxhdGlvbnNoaXBzIGJ5IG1pbmltdW0gc3RyZW5ndGggdGhyZXNob2xkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaWx0ZXJSZWxhdGlvbnNoaXBzQnlTdHJlbmd0aChcbiAgcmVsYXRpb25zaGlwczogQmFzZVJlbGF0aW9uc2hpcFtdLFxuICBtaW5TdHJlbmd0aDogbnVtYmVyXG4pOiBCYXNlUmVsYXRpb25zaGlwW10ge1xuICByZXR1cm4gcmVsYXRpb25zaGlwcy5maWx0ZXIocmVsID0+IChyZWwuc3RyZW5ndGggfHwgMCkgPj0gbWluU3RyZW5ndGgpO1xufVxuXG4vKipcbiAqIFJlbGF0aW9uc2hpcCB0eXBlIGFsaWFzZXMgZm9yIGNvbW1vbiBwYXR0ZXJuc1xuICovXG5leHBvcnQgY29uc3QgUmVsYXRpb25zaGlwVHlwZXMgPSB7XG4gIC8vIFNpbWlsYXJpdHkgcmVsYXRpb25zaGlwc1xuICBTSU1JTEFSX1RPOiAnc2ltaWxhcl90bycsXG5cbiAgLy8gVXNhZ2UgcmVsYXRpb25zaGlwc1xuICBVU0VTOiAndXNlcycsXG4gIFVTRURfQlk6ICd1c2VkX2J5JyxcblxuICAvLyBFeHRlbnNpb24gcmVsYXRpb25zaGlwc1xuICBFWFRFTkRTOiAnZXh0ZW5kcycsXG4gIEVYVEVOREVEX0JZOiAnZXh0ZW5kZWRfYnknLFxuXG4gIC8vIENvbXBvc2l0aW9uIHJlbGF0aW9uc2hpcHNcbiAgQ09OVEFJTlM6ICdjb250YWlucycsXG4gIENPTlRBSU5FRF9CWTogJ2NvbnRhaW5lZF9ieScsXG5cbiAgLy8gRGVidWdnaW5nIHJlbGF0aW9uc2hpcHNcbiAgSEVMUFNfREVCVUc6ICdoZWxwc19kZWJ1ZycsXG4gIERFQlVHR0VEX0JZOiAnZGVidWdnZWRfYnknLFxuXG4gIC8vIENvbmZsaWN0IHJlbGF0aW9uc2hpcHNcbiAgQ09OVFJBRElDVFM6ICdjb250cmFkaWN0cycsXG4gIFNVUFBPUlRTOiAnc3VwcG9ydHMnLFxuXG4gIC8vIFNlbWFudGljIHJlbGF0aW9uc2hpcHNcbiAgU0VNQU5USUNfU0lNSUxBUklUWTogJ3NlbWFudGljX3NpbWlsYXJpdHknXG59IGFzIGNvbnN0O1xuXG5leHBvcnQgdHlwZSBSZWxhdGlvbnNoaXBUeXBlID0gdHlwZW9mIFJlbGF0aW9uc2hpcFR5cGVzW2tleW9mIHR5cGVvZiBSZWxhdGlvbnNoaXBUeXBlc107Il19