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.

402 lines 50.1 kB
/** * SearchParamsNormalizer - Normalizes search operation parameters * * Transforms raw search input parameters into the format expected * by PortfolioHandler.searchAll(). * * Handles: * - Scope → sources array conversion * - Pagination (offset/limit → page/pageSize) * - Sort parameter normalization * - Filter parameter extraction * * @see Issue #243 - Unified search with normalizer architecture */ /** Valid scope values for search operations */ const VALID_SCOPES = ['local', 'github', 'collection']; /** Default pagination limit when not specified */ const DEFAULT_PAGE_SIZE = 20; /** Valid sort order values */ const VALID_SORT_ORDERS = ['asc', 'desc']; /** * Normalizer for search operation parameters. * * Converts various input formats into a consistent structure * for the search handler. * * @example * ```typescript * const normalizer = new SearchParamsNormalizer(); * const result = normalizer.normalize({ * query: 'creative writer', * scope: ['local', 'collection'], * pagination: { offset: 20, limit: 10 } * }, context); * * // Result: * // { * // success: true, * // params: { * // query: 'creative writer', * // sources: ['local', 'collection'], * // page: 3, * // pageSize: 10 * // } * // } * ``` */ export class SearchParamsNormalizer { name = 'searchParams'; /** * Normalize search parameters. * * @param params - Raw input parameters * @param _context - Operation context (unused but available for future use) * @returns Normalized parameters or error */ normalize(params, _context) { // Validate required query parameter if (!params.query || typeof params.query !== 'string' || params.query.trim().length === 0) { return { success: false, error: 'Search query is required and must be a non-empty string. ' + 'Example: { query: "creative writer" }', }; } // Normalize scope to sources array const scopeResult = this.normalizeScope(params.scope); if (!scopeResult.success) { return scopeResult; } // Normalize pagination const pagination = this.normalizePagination(params); if ('error' in pagination) { return { success: false, error: pagination.error }; } // Normalize sort const sort = this.normalizeSort(params); // Normalize filters const filters = this.normalizeFilters(params.filters); // Normalize options const options = this.normalizeOptions(params); // Build normalized output const normalized = { query: params.query.trim(), sources: scopeResult.sources, elementType: this.normalizeElementType(params), ...pagination, ...sort, }; // Only include filters/options if they have values if (Object.keys(filters).length > 0) { normalized.filters = filters; } if (Object.keys(options).length > 0) { normalized.options = options; } return { success: true, params: normalized }; } // =========================================================================== // Scope Normalization // =========================================================================== /** * Normalize scope parameter to sources array. * * @param scope - Raw scope value (string, array, 'all', or undefined) * @returns Normalized sources array or error * * @example * normalizeScope(undefined) // => ['local', 'github', 'collection'] * normalizeScope('all') // => ['local', 'github', 'collection'] * normalizeScope('local') // => ['local'] * normalizeScope(['local', 'collection']) // => ['local', 'collection'] */ normalizeScope(scope) { // Default: search all sources if (scope === undefined || scope === null || scope === 'all') { return { success: true, sources: [...VALID_SCOPES] }; } // Single scope as string if (typeof scope === 'string') { const validation = this.validateScopes([scope]); if (!validation.valid) { return { success: false, error: validation.error }; } return { success: true, sources: [scope] }; } // Multiple scopes as array if (Array.isArray(scope)) { const validation = this.validateScopes(scope); if (!validation.valid) { return { success: false, error: validation.error }; } // Type-safe filter ensures only strings are included (already validated above) return { success: true, sources: scope.filter((s) => typeof s === 'string') }; } return { success: false, error: 'Invalid scope parameter: must be a string, array of strings, or "all". ' + `Valid scopes: ${VALID_SCOPES.join(', ')}. ` + 'Examples: scope: "local" or scope: ["local", "collection"]', }; } /** * Validate that all scope values are valid. * * @param scopes - Array of scope values to validate * @returns Validation result */ validateScopes(scopes) { const invalidScopes = scopes.filter(s => typeof s !== 'string' || !VALID_SCOPES.includes(s)); if (invalidScopes.length > 0) { return { valid: false, error: `Invalid scope value(s): ${invalidScopes.map(s => JSON.stringify(s)).join(', ')}. ` + `Valid scopes: ${VALID_SCOPES.join(', ')}`, }; } return { valid: true }; } // =========================================================================== // Pagination Normalization // =========================================================================== /** * Normalize pagination parameters. * * Handles both: * - Pagination object: { offset, limit } * - Top-level params: page, limit * * Converts offset-based to page-based pagination. * * @param params - Raw parameters * @returns Normalized page and pageSize * * @example * // Offset-based * normalizePagination({ pagination: { offset: 20, limit: 10 } }) * // => { page: 3, pageSize: 10 } * * // Page-based * normalizePagination({ page: 2, limit: 25 }) * // => { page: 2, pageSize: 25 } */ normalizePagination(params) { const pagination = params.pagination; // Validate pagination values (Issue #227) if (pagination && typeof pagination === 'object') { if (pagination.offset !== undefined) { const offset = Number(pagination.offset); if (!Number.isFinite(offset) || !Number.isInteger(offset) || offset < 0) { return { error: `Invalid pagination: offset must be a whole number, 0 or greater (got: ${JSON.stringify(pagination.offset)}).\n` + 'Example: { pagination: { offset: 0, limit: 25 } }', }; } } if (pagination.limit !== undefined) { const limit = Number(pagination.limit); if (!Number.isFinite(limit) || !Number.isInteger(limit) || limit <= 0) { return { error: `Invalid pagination: limit must be a positive integer (got: ${JSON.stringify(pagination.limit)}).\n` + 'Example: { pagination: { offset: 0, limit: 25 } }', }; } } } if (params.page !== undefined) { const page = Number(params.page); if (!Number.isFinite(page) || !Number.isInteger(page) || page <= 0) { return { error: `Invalid pagination: page must be a positive integer (got: ${JSON.stringify(params.page)}).\n` + 'Example: { page: 1, limit: 25 }', }; } } if (params.limit !== undefined && pagination?.limit === undefined) { const limit = Number(params.limit); if (!Number.isFinite(limit) || !Number.isInteger(limit) || limit <= 0) { return { error: `Invalid pagination: limit must be a positive integer (got: ${JSON.stringify(params.limit)}).\n` + 'Example: { page: 1, limit: 25 }', }; } } // Reject conflicting page + offset (ambiguous intent) const hasPage = params.page !== undefined; const hasOffset = pagination?.offset !== undefined; if (hasPage && hasOffset) { return { error: "Conflicting pagination: cannot use both 'page' and 'offset'.\n" + 'Use either page-based ({ page: 2, limit: 25 }) or offset-based ({ pagination: { offset: 50, limit: 25 } }).', }; } // If pagination object with offset is provided, convert to page number if (pagination?.offset !== undefined) { const offset = Number(pagination.offset) || 0; const limit = Number(pagination.limit) || DEFAULT_PAGE_SIZE; return { page: Math.floor(offset / limit) + 1, pageSize: limit, }; } // Otherwise use top-level values or pagination.limit const page = params.page !== undefined ? Number(params.page) : undefined; const pageSize = (pagination?.limit !== undefined ? Number(pagination.limit) : undefined) || (params.limit !== undefined ? Number(params.limit) : undefined); const result = {}; if (page !== undefined && !isNaN(page)) { result.page = page; } if (pageSize !== undefined && !isNaN(pageSize)) { result.pageSize = pageSize; } return result; } // =========================================================================== // Sort Normalization // =========================================================================== /** * Normalize sort parameters. * * Handles: * - sort object: { field, order } * - sortBy/sortOrder top-level params * * @param params - Raw parameters * @returns Normalized sortBy and sortOrder * * @example * normalizeSort({ sort: { field: 'name', order: 'desc' } }) * // => { sortBy: 'name', sortOrder: 'desc' } * * normalizeSort({ sortBy: 'created', sortOrder: 'asc' }) * // => { sortBy: 'created', sortOrder: 'asc' } */ normalizeSort(params) { const result = {}; // Check for sort object const sort = params.sort; if (sort) { if (typeof sort.field === 'string') { result.sortBy = sort.field; } if (typeof sort.order === 'string' && VALID_SORT_ORDERS.includes(sort.order)) { result.sortOrder = sort.order; } } // Top-level params override sort object if (typeof params.sortBy === 'string') { result.sortBy = params.sortBy; } if (typeof params.sortOrder === 'string' && VALID_SORT_ORDERS.includes(params.sortOrder)) { result.sortOrder = params.sortOrder; } return result; } // =========================================================================== // Filter Normalization // =========================================================================== /** * Normalize filter parameters. * * Extracts and validates filter values. * * @param filters - Raw filters object * @returns Normalized filters * * @example * normalizeFilters({ tags: ['ai', 'creative'], author: 'user123' }) * // => { tags: ['ai', 'creative'], author: 'user123' } */ normalizeFilters(filters) { const result = {}; if (!filters || typeof filters !== 'object') { return result; } const f = filters; // Tags filter if (Array.isArray(f.tags)) { const validTags = f.tags.filter((t) => typeof t === 'string'); if (validTags.length > 0) { result.tags = validTags; } } // Author filter if (typeof f.author === 'string' && f.author.trim()) { result.author = f.author.trim(); } // Date filters if (typeof f.createdAfter === 'string') { result.createdAfter = f.createdAfter; } if (typeof f.createdBefore === 'string') { result.createdBefore = f.createdBefore; } return result; } // =========================================================================== // Options Normalization // =========================================================================== /** * Normalize search options. * * Handles both options object and legacy top-level boolean params. * * @param params - Raw parameters * @returns Normalized options */ normalizeOptions(params) { const result = {}; // Check for options object const options = params.options; // Helper to get boolean value from options or legacy params const getBoolean = (optKey, legacyKey) => { if (options && typeof options[optKey] === 'boolean') { return options[optKey]; } if (typeof params[legacyKey] === 'boolean') { return params[legacyKey]; } return undefined; }; // Map options const fuzzyMatch = getBoolean('fuzzyMatch', 'fuzzyMatch'); const includeKeywords = getBoolean('includeKeywords', 'includeKeywords'); const includeTags = getBoolean('includeTags', 'includeTags'); const includeTriggers = getBoolean('includeTriggers', 'includeTriggers'); const includeDescriptions = getBoolean('includeDescriptions', 'includeDescriptions'); if (fuzzyMatch !== undefined) result.fuzzyMatch = fuzzyMatch; if (includeKeywords !== undefined) result.includeKeywords = includeKeywords; if (includeTags !== undefined) result.includeTags = includeTags; if (includeTriggers !== undefined) result.includeTriggers = includeTriggers; if (includeDescriptions !== undefined) result.includeDescriptions = includeDescriptions; return result; } // =========================================================================== // Element Type Normalization // =========================================================================== /** * Normalize element type parameter. * * Handles both 'type' and legacy 'elementType' params. * * @param params - Raw parameters * @returns Normalized element type or undefined */ normalizeElementType(params) { if (typeof params.type === 'string') { return params.type; } if (typeof params.elementType === 'string') { return params.elementType; } return undefined; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VhcmNoUGFyYW1zTm9ybWFsaXplci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9oYW5kbGVycy9tY3AtYXFsL25vcm1hbGl6ZXJzL1NlYXJjaFBhcmFtc05vcm1hbGl6ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7R0FhRztBQVNILCtDQUErQztBQUMvQyxNQUFNLFlBQVksR0FBRyxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsWUFBWSxDQUFVLENBQUM7QUFHaEUsa0RBQWtEO0FBQ2xELE1BQU0saUJBQWlCLEdBQUcsRUFBRSxDQUFDO0FBRTdCLDhCQUE4QjtBQUM5QixNQUFNLGlCQUFpQixHQUFHLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBVSxDQUFDO0FBMEJuRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EwQkc7QUFDSCxNQUFNLE9BQU8sc0JBQXNCO0lBQ3hCLElBQUksR0FBRyxjQUFjLENBQUM7SUFFL0I7Ozs7OztPQU1HO0lBQ0gsU0FBUyxDQUNQLE1BQXVCLEVBQ3ZCLFFBQTJCO1FBRTNCLG9DQUFvQztRQUNwQyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssSUFBSSxPQUFPLE1BQU0sQ0FBQyxLQUFLLEtBQUssUUFBUSxJQUFJLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzFGLE9BQU87Z0JBQ0wsT0FBTyxFQUFFLEtBQUs7Z0JBQ2QsS0FBSyxFQUFFLDJEQUEyRDtvQkFDaEUsdUNBQXVDO2FBQzFDLENBQUM7UUFDSixDQUFDO1FBRUQsbUNBQW1DO1FBQ25DLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3RELElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDekIsT0FBTyxXQUFXLENBQUM7UUFDckIsQ0FBQztR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UztZQUFFLE1BQU0sQ0FBQyxtQkFBbUIsR0FBRyxtQkFBbUIsQ0FBQztRQUV4RixPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQsOEVBQThFO0lBQzlFLDZCQUE2QjtJQUM3Qiw4RUFBOEU7SUFFOUU7Ozs7Ozs7T0FPRztJQUNLLG9CQUFvQixDQUFDLE1BQXVCO1FBQ2xELElBQUksT0FBTyxNQUFNLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ3BDLE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQztRQUNyQixDQUFDO1FBQ0QsSUFBSSxPQUFPLE1BQU0sQ0FBQyxXQUFXLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDM0MsT0FBTyxNQUFNLENBQUMsV0FBVyxDQUFDO1FBQzVCLENBQUM7UUFDRCxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNlYXJjaFBhcmFtc05vcm1hbGl6ZXIgLSBOb3JtYWxpemVzIHNlYXJjaCBvcGVyYXRpb24gcGFyYW1ldGVyc1xuICpcbiAqIFRyYW5zZm9ybXMgcmF3IHNlYXJjaCBpbnB1dCBwYXJhbWV0ZXJzIGludG8gdGhlIGZvcm1hdCBleHBlY3RlZFxuICogYnkgUG9ydGZvbGlvSGFuZGxlci5zZWFyY2hBbGwoKS5cbiAqXG4gKiBIYW5kbGVzOlxuICogLSBTY29wZSDihpIgc291cmNlcyBhcnJheSBjb252ZXJzaW9uXG4gKiAtIFBhZ2luYXRpb24gKG9mZnNldC9saW1pdCDihpIgcGFnZS9wYWdlU2l6ZSlcbiAqIC0gU29ydCBwYXJhbWV0ZXIgbm9ybWFsaXphdGlvblxuICogLSBGaWx0ZXIgcGFyYW1ldGVyIGV4dHJhY3Rpb25cbiAqXG4gKiBAc2VlIElzc3VlICMyNDMgLSBVbmlmaWVkIHNlYXJjaCB3aXRoIG5vcm1hbGl6ZXIgYXJjaGl0ZWN0dXJlXG4gKi9cblxuaW1wb3J0IHR5cGUge1xuICBOb3JtYWxpemVyLFxuICBOb3JtYWxpemVyQ29udGV4dCxcbiAgTm9ybWFsaXplclJlc3VsdCxcbiAgTm9ybWFsaXplZFNlYXJjaFBhcmFtcyxcbn0gZnJvbSAnLi90eXBlcy5qcyc7XG5cbi8qKiBWYWxpZCBzY29wZSB2YWx1ZXMgZm9yIHNlYXJjaCBvcGVyYXRpb25zICovXG5jb25zdCBWQUxJRF9TQ09QRVMgPSBbJ2xvY2FsJywgJ2dpdGh1YicsICdjb2xsZWN0aW9uJ10gYXMgY29uc3Q7XG50eXBlIFZhbGlkU2NvcGUgPSB0eXBlb2YgVkFMSURfU0NPUEVTW251bWJlcl07XG5cbi8qKiBEZWZhdWx0IHBhZ2luYXRpb24gbGltaXQgd2hlbiBub3Qgc3BlY2lmaWVkICovXG5jb25zdCBERUZBVUxUX1BBR0VfU0laRSA9IDIwO1xuXG4vKiogVmFsaWQgc29ydCBvcmRlciB2YWx1ZXMgKi9cbmNvbnN0IFZBTElEX1NPUlRfT1JERVJTID0gWydhc2MnLCAnZGVzYyddIGFzIGNvbnN0O1xuXG4vKipcbiAqIFJhdyBpbnB1dCBwYXJhbWV0ZXJzIGZvciBzZWFyY2ggb3BlcmF0aW9ucy5cbiAqL1xuaW50ZXJmYWNlIFJhd1NlYXJjaFBhcmFtcyB7XG4gIHF1ZXJ5PzogdW5rbm93bjtcbiAgc2NvcGU/OiB1bmtub3duO1xuICB0eXBlPzogdW5rbm93bjtcbiAgcGFnZT86IHVua25vd247XG4gIGxpbWl0PzogdW5rbm93bjtcbiAgcGFnaW5hdGlvbj86IHVua25vd247XG4gIHNvcnQ/OiB1bmtub3duO1xuICBzb3J0Qnk/OiB1bmtub3duO1xuICBzb3J0T3JkZXI/OiB1bmtub3duO1xuICBmaWx0ZXJzPzogdW5rbm93bjtcbiAgb3B0aW9ucz86IHVua25vd247XG4gIC8vIExlZ2FjeSBwYXJhbWV0ZXIgbmFtZXNcbiAgZWxlbWVudFR5cGU/OiB1bmtub3duO1xuICBmdXp6eU1hdGNoPzogdW5rbm93bjtcbiAgaW5jbHVkZUtleXdvcmRzPzogdW5rbm93bjtcbiAgaW5jbHVkZVRhZ3M/OiB1bmtub3duO1xuICBpbmNsdWRlVHJpZ2dlcnM/OiB1bmtub3duO1xuICBpbmNsdWRlRGVzY3JpcHRpb25zPzogdW5rbm93bjtcbn1cblxuLyoqXG4gKiBOb3JtYWxpemVyIGZvciBzZWFyY2ggb3BlcmF0aW9uIHBhcmFtZXRlcnMuXG4gKlxuICogQ29udmVydHMgdmFyaW91cyBpbnB1dCBmb3JtYXRzIGludG8gYSBjb25zaXN0ZW50IHN0cnVjdHVyZVxuICogZm9yIHRoZSBzZWFyY2ggaGFuZGxlci5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3Qgbm9ybWFsaXplciA9IG5ldyBTZWFyY2hQYXJhbXNOb3JtYWxpemVyKCk7XG4gKiBjb25zdCByZXN1bHQgPSBub3JtYWxpemVyLm5vcm1hbGl6ZSh7XG4gKiAgIHF1ZXJ5OiAnY3JlYXRpdmUgd3JpdGVyJyxcbiAqICAgc2NvcGU6IFsnbG9jYWwnLCAnY29sbGVjdGlvbiddLFxuICogICBwYWdpbmF0aW9uOiB7IG9mZnNldDogMjAsIGxpbWl0OiAxMCB9XG4gKiB9LCBjb250ZXh0KTtcbiAqXG4gKiAvLyBSZXN1bHQ6XG4gKiAvLyB7XG4gKiAvLyAgIHN1Y2Nlc3M6IHRydWUsXG4gKiAvLyAgIHBhcmFtczoge1xuICogLy8gICAgIHF1ZXJ5OiAnY3JlYXRpdmUgd3JpdGVyJyxcbiAqIC8vICAgICBzb3VyY2VzOiBbJ2xvY2FsJywgJ2NvbGxlY3Rpb24nXSxcbiAqIC8vICAgICBwYWdlOiAzLFxuICogLy8gICAgIHBhZ2VTaXplOiAxMFxuICogLy8gICB9XG4gKiAvLyB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIFNlYXJjaFBhcmFtc05vcm1hbGl6ZXIgaW1wbGVtZW50cyBOb3JtYWxpemVyPFJhd1NlYXJjaFBhcmFtcywgTm9ybWFsaXplZFNlYXJjaFBhcmFtcz4ge1xuICByZWFkb25seSBuYW1lID0gJ3NlYXJjaFBhcmFtcyc7XG5cbiAgLyoqXG4gICAqIE5vcm1hbGl6ZSBzZWFyY2ggcGFyYW1ldGVycy5cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtcyAtIFJhdyBpbnB1dCBwYXJhbWV0ZXJzXG4gICAqIEBwYXJhbSBfY29udGV4dCAtIE9wZXJhdGlvbiBjb250ZXh0ICh1bnVzZWQgYnV0IGF2YWlsYWJsZSBmb3IgZnV0dXJlIHVzZSlcbiAgICogQHJldHVybnMgTm9ybWFsaXplZCBwYXJhbWV0ZXJzIG9yIGVycm9yXG4gICAqL1xuICBub3JtYWxpemUoXG4gICAgcGFyYW1zOiBSYXdTZWFyY2hQYXJhbXMsXG4gICAgX2NvbnRleHQ6IE5vcm1hbGl6ZXJDb250ZXh0XG4gICk6IE5vcm1hbGl6ZXJSZXN1bHQ8Tm9ybWFsaXplZFNlYXJjaFBhcmFtcz4ge1xuICAgIC8vIFZhbGlkYXRlIHJlcXVpcmVkIHF1ZXJ5IHBhcmFtZXRlclxuICAgIGlmICghcGFyYW1zLnF1ZXJ5IHx8IHR5cGVvZiBwYXJhbXMucXVlcnkgIT09ICdzdHJpbmcnIHx8IHBhcmFtcy5xdWVyeS50cmltKCkubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgZXJyb3I6ICdTZWFyY2ggcXVlcnkgaXMgcmVxdWlyZWQgYW5kIG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nLiAnICtcbiAgICAgICAgICAnRXhhbXBsZTogeyBxdWVyeTogXCJjcmVhdGl2ZSB3cml0ZXJcIiB9JyxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gTm9ybWFsaXplIHNjb3BlIHRvIHNvdXJjZXMgYXJyYXlcbiAgICBjb25zdCBzY29wZVJlc3VsdCA9IHRoaXMubm9ybWFsaXplU2NvcGUocGFyYW1zLnNjb3BlKTtcbiAgICBpZiAoIXNjb3BlUmVzdWx0LnN1Y2Nlc3MpIHtcbiAgICAgIHJldHVybiBzY29wZVJlc3VsdDtcbiAgICB9XG5cbiAgICAvLyBOb3JtYWxpemUgcGFnaW5hdGlvblxuICAgIGNvbnN0IHBhZ2luYXRpb24gPSB0aGlzLm5vcm1hbGl6ZVBhZ2luYXRpb24ocGFyYW1zKTtcbiAgICBpZiAoJ2Vycm9yJyBpbiBwYWdpbmF0aW9uKSB7XG4gICAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6IHBhZ2luYXRpb24uZXJyb3IgfTtcbiAgICB9XG5cbiAgICAvLyBOb3JtYWxpemUgc29ydFxuICAgIGNvbnN0IHNvcnQgPSB0aGlzLm5vcm1hbGl6ZVNvcnQocGFyYW1zKTtcblxuICAgIC8vIE5vcm1hbGl6ZSBmaWx0ZXJzXG4gICAgY29uc3QgZmlsdGVycyA9IHRoaXMubm9ybWFsaXplRmlsdGVycyhwYXJhbXMuZmlsdGVycyk7XG5cbiAgICAvLyBOb3JtYWxpemUgb3B0aW9uc1xuICAgIGNvbnN0IG9wdGlvbnMgPSB0aGlzLm5vcm1hbGl6ZU9wdGlvbnMocGFyYW1zKTtcblxuICAgIC8vIEJ1aWxkIG5vcm1hbGl6ZWQgb3V0cHV0XG4gICAgY29uc3Qgbm9ybWFsaXplZDogTm9ybWFsaXplZFNlYXJjaFBhcmFtcyA9IHtcbiAgICAgIHF1ZXJ5OiBwYXJhbXMucXVlcnkudHJpbSgpLFxuICAgICAgc291cmNlczogc2NvcGVSZXN1bHQuc291cmNlcyxcbiAgICAgIGVsZW1lbnRUeXBlOiB0aGlzLm5vcm1hbGl6ZUVsZW1lbnRUeXBlKHBhcmFtcyksXG4gICAgICAuLi5wYWdpbmF0aW9uLFxuICAgICAgLi4uc29ydCxcbiAgICB9O1xuXG4gICAgLy8gT25seSBpbmNsdWRlIGZpbHRlcnMvb3B0aW9ucyBpZiB0aGV5IGhhdmUgdmFsdWVzXG4gICAgaWYgKE9iamVjdC5rZXlzKGZpbHRlcnMpLmxlbmd0aCA+IDApIHtcbiAgICAgIG5vcm1hbGl6ZWQuZmlsdGVycyA9IGZpbHRlcnM7XG4gICAgfVxuICAgIGlmIChPYmplY3Qua2V5cyhvcHRpb25zKS5sZW5ndGggPiAwKSB7XG4gICAgICBub3JtYWxpemVkLm9wdGlvbnMgPSBvcHRpb25zO1xuICAgIH1cblxuICAgIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUsIHBhcmFtczogbm9ybWFsaXplZCB9O1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFNjb3BlIE5vcm1hbGl6YXRpb25cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIE5vcm1hbGl6ZSBzY29wZSBwYXJhbWV0ZXIgdG8gc291cmNlcyBhcnJheS5cbiAgICpcbiAgICogQHBhcmFtIHNjb3BlIC0gUmF3IHNjb3BlIHZhbHVlIChzdHJpbmcsIGFycmF5LCAnYWxsJywgb3IgdW5kZWZpbmVkKVxuICAgKiBAcmV0dXJucyBOb3JtYWxpemVkIHNvdXJjZXMgYXJyYXkgb3IgZXJyb3JcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogbm9ybWFsaXplU2NvcGUodW5kZWZpbmVkKSAgICAgICAgLy8gPT4gWydsb2NhbCcsICdnaXRodWInLCAnY29sbGVjdGlvbiddXG4gICAqIG5vcm1hbGl6ZVNjb3BlKCdhbGwnKSAgICAgICAgICAgIC8vID0+IFsnbG9jYWwnLCAnZ2l0aHViJywgJ2NvbGxlY3Rpb24nXVxuICAgKiBub3JtYWxpemVTY29wZSgnbG9jYWwnKSAgICAgICAgICAvLyA9PiBbJ2xvY2FsJ11cbiAgICogbm9ybWFsaXplU2NvcGUoWydsb2NhbCcsICdjb2xsZWN0aW9uJ10pIC8vID0+IFsnbG9jYWwnLCAnY29sbGVjdGlvbiddXG4gICAqL1xuICBwcml2YXRlIG5vcm1hbGl6ZVNjb3BlKHNjb3BlOiB1bmtub3duKTogeyBzdWNjZXNzOiB0cnVlOyBzb3VyY2VzOiBzdHJpbmdbXSB9IHwgeyBzdWNjZXNzOiBmYWxzZTsgZXJyb3I6IHN0cmluZyB9IHtcbiAgICAvLyBEZWZhdWx0OiBzZWFyY2ggYWxsIHNvdXJjZXNcbiAgICBpZiAoc2NvcGUgPT09IHVuZGVmaW5lZCB8fCBzY29wZSA9PT0gbnVsbCB8fCBzY29wZSA9PT0gJ2FsbCcpIHtcbiAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUsIHNvdXJjZXM6IFsuLi5WQUxJRF9TQ09QRVNdIH07XG4gICAgfVxuXG4gICAgLy8gU2luZ2xlIHNjb3BlIGFzIHN0cmluZ1xuICAgIGlmICh0eXBlb2Ygc2NvcGUgPT09ICdzdHJpbmcnKSB7XG4gICAgICBjb25zdCB2YWxpZGF0aW9uID0gdGhpcy52YWxpZGF0ZVNjb3Blcyhbc2NvcGVdKTtcbiAgICAgIGlmICghdmFsaWRhdGlvbi52YWxpZCkge1xuICAgICAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6IHZhbGlkYXRpb24uZXJyb3IgfTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUsIHNvdXJjZXM6IFtzY29wZV0gfTtcbiAgICB9XG5cbiAgICAvLyBNdWx0aXBsZSBzY29wZXMgYXMgYXJyYXlcbiAgICBpZiAoQXJyYXkuaXNBcnJheShzY29wZSkpIHtcbiAgICAgIGNvbnN0IHZhbGlkYXRpb24gPSB0aGlzLnZhbGlkYXRlU2NvcGVzKHNjb3BlKTtcbiAgICAgIGlmICghdmFsaWRhdGlvbi52YWxpZCkge1xuICAgICAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6IHZhbGlkYXRpb24uZXJyb3IgfTtcbiAgICAgIH1cbiAgICAgIC8vIFR5cGUtc2FmZSBmaWx0ZXIgZW5zdXJlcyBvbmx5IHN0cmluZ3MgYXJlIGluY2x1ZGVkIChhbHJlYWR5IHZhbGlkYXRlZCBhYm92ZSlcbiAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUsIHNvdXJjZXM6IHNjb3BlLmZpbHRlcigocyk6IHMgaXMgc3RyaW5nID0+IHR5cGVvZiBzID09PSAnc3RyaW5nJykgfTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICBlcnJvcjpcbiAgICAgICAgJ0ludmFsaWQgc2NvcGUgcGFyYW1ldGVyOiBtdXN0IGJlIGEgc3RyaW5nLCBhcnJheSBvZiBzdHJpbmdzLCBvciBcImFsbFwiLiAnICtcbiAgICAgICAgYFZhbGlkIHNjb3BlczogJHtWQUxJRF9TQ09QRVMuam9pbignLCAnKX0uIGAgK1xuICAgICAgICAnRXhhbXBsZXM6IHNjb3BlOiBcImxvY2FsXCIgb3Igc2NvcGU6IFtcImxvY2FsXCIsIFwiY29sbGVjdGlvblwiXScsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGF0IGFsbCBzY29wZSB2YWx1ZXMgYXJlIHZhbGlkLlxuICAgKlxuICAgKiBAcGFyYW0gc2NvcGVzIC0gQXJyYXkgb2Ygc2NvcGUgdmFsdWVzIHRvIHZhbGlkYXRlXG4gICAqIEByZXR1cm5zIFZhbGlkYXRpb24gcmVzdWx0XG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlU2NvcGVzKHNjb3BlczogdW5rbm93bltdKTogeyB2YWxpZDogdHJ1ZSB9IHwgeyB2YWxpZDogZmFsc2U7IGVycm9yOiBzdHJpbmcgfSB7XG4gICAgY29uc3QgaW52YWxpZFNjb3BlcyA9IHNjb3Blcy5maWx0ZXIoXG4gICAgICBzID0+IHR5cGVvZiBzICE9PSAnc3RyaW5nJyB8fCAhVkFMSURfU0NPUEVTLmluY2x1ZGVzKHMgYXMgVmFsaWRTY29wZSlcbiAgICApO1xuXG4gICAgaWYgKGludmFsaWRTY29wZXMubGVuZ3RoID4gMCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdmFsaWQ6IGZhbHNlLFxuICAgICAgICBlcnJvcjpcbiAgICAgICAgICBgSW52YWxpZCBzY29wZSB2YWx1ZShzKTogJHtpbnZhbGlkU2NvcGVzLm1hcChzID0+IEpTT04uc3RyaW5naWZ5KHMpKS5qb2luKCcsICcpfS4gYCArXG4gICAgICAgICAgYFZhbGlkIHNjb3BlczogJHtWQUxJRF9TQ09QRVMuam9pbignLCAnKX1gLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4geyB2YWxpZDogdHJ1ZSB9O1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFBhZ2luYXRpb24gTm9ybWFsaXphdGlvblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICAvKipcbiAgICogTm9ybWFsaXplIHBhZ2luYXRpb24gcGFyYW1ldGVycy5cbiAgICpcbiAgICogSGFuZGxlcyBib3RoOlxuICAgKiAtIFBhZ2luYXRpb24gb2JqZWN0OiB7IG9mZnNldCwgbGltaXQgfVxuICAgKiAtIFRvcC1sZXZlbCBwYXJhbXM6IHBhZ2UsIGxpbWl0XG4gICAqXG4gICAqIENvbnZlcnRzIG9mZnNldC1iYXNlZCB0byBwYWdlLWJhc2VkIHBhZ2luYXRpb24uXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBSYXcgcGFyYW1ldGVyc1xuICAgKiBAcmV0dXJucyBOb3JtYWxpemVkIHBhZ2UgYW5kIHBhZ2VTaXplXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIC8vIE9mZnNldC1iYXNlZFxuICAgKiBub3JtYWxpemVQYWdpbmF0aW9uKHsgcGFnaW5hdGlvbjogeyBvZmZzZXQ6IDIwLCBsaW1pdDogMTAgfSB9KVxuICAgKiAvLyA9PiB7IHBhZ2U6IDMsIHBhZ2VTaXplOiAxMCB9XG4gICAqXG4gICAqIC8vIFBhZ2UtYmFzZWRcbiAgICogbm9ybWFsaXplUGFnaW5hdGlvbih7IHBhZ2U6IDIsIGxpbWl0OiAyNSB9KVxuICAgKiAvLyA9PiB7IHBhZ2U6IDIsIHBhZ2VTaXplOiAyNSB9XG4gICAqL1xuICBwcml2YXRlIG5vcm1hbGl6ZVBhZ2luYXRpb24ocGFyYW1zOiBSYXdTZWFyY2hQYXJhbXMpOiB7XG4gICAgcGFnZT86IG51bWJlcjtcbiAgICBwYWdlU2l6ZT86IG51bWJlcjtcbiAgfSB8IHsgZXJyb3I6IHN0cmluZyB9IHtcbiAgICBjb25zdCBwYWdpbmF0aW9uID0gcGFyYW1zLnBhZ2luYXRpb24gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWQ7XG5cbiAgICAvLyBWYWxpZGF0ZSBwYWdpbmF0aW9uIHZhbHVlcyAoSXNzdWUgIzIyNylcbiAgICBpZiAocGFnaW5hdGlvbiAmJiB0eXBlb2YgcGFnaW5hdGlvbiA9PT0gJ29iamVjdCcpIHtcbiAgICAgIGlmIChwYWdpbmF0aW9uLm9mZnNldCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGNvbnN0IG9mZnNldCA9IE51bWJlcihwYWdpbmF0aW9uLm9mZnNldCk7XG4gICAgICAgIGlmICghTnVtYmVyLmlzRmluaXRlKG9mZnNldCkgfHwgIU51bWJlci5pc0ludGVnZXIob2Zmc2V0KSB8fCBvZmZzZXQgPCAwKSB7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGVycm9yOiBgSW52YWxpZCBwYWdpbmF0aW9uOiBvZmZzZXQgbXVzdCBiZSBhIHdob2xlIG51bWJlciwgMCBvciBncmVhdGVyIChnb3Q6ICR7SlNPTi5zdHJpbmdpZnkocGFnaW5hdGlvbi5vZmZzZXQpfSkuXFxuYCArXG4gICAgICAgICAgICAgICdFeGFtcGxlOiB7IHBhZ2luYXRpb246IHsgb2Zmc2V0OiAwLCBsaW1pdDogMjUgfSB9JyxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAocGFnaW5hdGlvbi5saW1pdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGNvbnN0IGxpbWl0ID0gTnVtYmVyKHBhZ2luYXRpb24ubGltaXQpO1xuICAgICAgICBpZiAoIU51bWJlci5pc0Zpbml0ZShsaW1pdCkgfHwgIU51bWJlci5pc0ludGVnZXIobGltaXQpIHx8IGxpbWl0IDw9IDApIHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgZXJyb3I6IGBJbnZhbGlkIHBhZ2luYXRpb246IGxpbWl0IG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyIChnb3Q6ICR7SlNPTi5zdHJpbmdpZnkocGFnaW5hdGlvbi5saW1pdCl9KS5cXG5gICtcbiAgICAgICAgICAgICAgJ0V4YW1wbGU6IHsgcGFnaW5hdGlvbjogeyBvZmZzZXQ6IDAsIGxpbWl0OiAyNSB9IH0nLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAocGFyYW1zLnBhZ2UgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgcGFnZSA9IE51bWJlcihwYXJhbXMucGFnZSk7XG4gICAgICBpZiAoIU51bWJlci5pc0Zpbml0ZShwYWdlKSB8fCAhTnVtYmVyLmlzSW50ZWdlcihwYWdlKSB8fCBwYWdlIDw9IDApIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBlcnJvcjogYEludmFsaWQgcGFnaW5hdGlvbjogcGFnZSBtdXN0IGJlIGEgcG9zaXRpdmUgaW50ZWdlciAoZ290OiAke0pTT04uc3RyaW5naWZ5KHBhcmFtcy5wYWdlKX0pLlxcbmAgK1xuICAgICAgICAgICAgJ0V4YW1wbGU6IHsgcGFnZTogMSwgbGltaXQ6IDI1IH0nLFxuICAgICAgICB9O1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChwYXJhbXMubGltaXQgIT09IHVuZGVmaW5lZCAmJiBwYWdpbmF0aW9uPy5saW1pdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBsaW1pdCA9IE51bWJlcihwYXJhbXMubGltaXQpO1xuICAgICAgaWYgKCFOdW1iZXIuaXNGaW5pdGUobGltaXQpIHx8ICFOdW1iZXIuaXNJbnRlZ2VyKGxpbWl0KSB8fCBsaW1pdCA8PSAwKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZXJyb3I6IGBJbnZhbGlkIHBhZ2luYXRpb246IGxpbWl0IG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyIChnb3Q6ICR7SlNPTi5zdHJpbmdpZnkocGFyYW1zLmxpbWl0KX0pLlxcbmAgK1xuICAgICAgICAgICAgJ0V4YW1wbGU6IHsgcGFnZTogMSwgbGltaXQ6IDI1IH0nLFxuICAgICAgICB9O1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFJlamVjdCBjb25mbGljdGluZyBwYWdlICsgb2Zmc2V0IChhbWJpZ3VvdXMgaW50ZW50KVxuICAgIGNvbnN0IGhhc1BhZ2UgPSBwYXJhbXMucGFnZSAhPT0gdW5kZWZpbmVkO1xuICAgIGNvbnN0IGhhc09mZnNldCA9IHBhZ2luYXRpb24/Lm9mZnNldCAhPT0gdW5kZWZpbmVkO1xuICAgIGlmIChoYXNQYWdlICYmIGhhc09mZnNldCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZXJyb3I6IFwiQ29uZmxpY3RpbmcgcGFnaW5hdGlvbjogY2Fubm90IHVzZSBib3RoICdwYWdlJyBhbmQgJ29mZnNldCcuXFxuXCIgK1xuICAgICAgICAgICdVc2UgZWl0aGVyIHBhZ2UtYmFzZWQgKHsgcGFnZTogMiwgbGltaXQ6IDI1IH0pIG9yIG9mZnNldC1iYXNlZCAoeyBwYWdpbmF0aW9uOiB7IG9mZnNldDogNTAsIGxpbWl0OiAyNSB9IH0pLicsXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIElmIHBhZ2luYXRpb24gb2JqZWN0IHdpdGggb2Zmc2V0IGlzIHByb3ZpZGVkLCBjb252ZXJ0IHRvIHBhZ2UgbnVtYmVyXG4gICAgaWYgKHBhZ2luYXRpb24/Lm9mZnNldCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBvZmZzZXQgPSBOdW1iZXIocGFnaW5hdGlvbi5vZmZzZXQpIHx8IDA7XG4gICAgICBjb25zdCBsaW1pdCA9IE51bWJlcihwYWdpbmF0aW9uLmxpbWl0KSB8fCBERUZBVUxUX1BBR0VfU0laRTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHBhZ2U6IE1hdGguZmxvb3Iob2Zmc2V0IC8gbGltaXQpICsgMSxcbiAgICAgICAgcGFnZVNpemU6IGxpbWl0LFxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBPdGhlcndpc2UgdXNlIHRvcC1sZXZlbCB2YWx1ZXMgb3IgcGFnaW5hdGlvbi5saW1pdFxuICAgIGNvbnN0IHBhZ2UgPSBwYXJhbXMucGFnZSAhPT0gdW5kZWZpbmVkID8gTnVtYmVyKHBhcmFtcy5wYWdlKSA6IHVuZGVmaW5lZDtcbiAgICBjb25zdCBwYWdlU2l6ZSA9XG4gICAgICAocGFnaW5hdGlvbj8ubGltaXQgIT09IHVuZGVmaW5lZCA/IE51bWJlcihwYWdpbmF0aW9uLmxpbWl0KSA6IHVuZGVmaW5lZCkgfHxcbiAgICAgIChwYXJhbXMubGltaXQgIT09IHVuZGVmaW5lZCA/IE51bWJlcihwYXJhbXMubGltaXQpIDogdW5kZWZpbmVkKTtcblxuICAgIGNvbnN0IHJlc3VsdDogeyBwYWdlPzogbnVtYmVyOyBwYWdlU2l6ZT86IG51bWJlciB9ID0ge307XG4gICAgaWYgKHBhZ2UgIT09IHVuZGVmaW5lZCAmJiAhaXNOYU4ocGFnZSkpIHtcbiAgICAgIHJlc3VsdC5wYWdlID0gcGFnZTtcbiAgICB9XG4gICAgaWYgKHBhZ2VTaXplICE9PSB1bmRlZmluZWQgJiYgIWlzTmFOKHBhZ2VTaXplKSkge1xuICAgICAgcmVzdWx0LnBhZ2VTaXplID0gcGFnZVNpemU7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBTb3J0IE5vcm1hbGl6YXRpb25cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIE5vcm1hbGl6ZSBzb3J0IHBhcmFtZXRlcnMuXG4gICAqXG4gICAqIEhhbmRsZXM6XG4gICAqIC0gc29ydCBvYmplY3Q6IHsgZmllbGQsIG9yZGVyIH1cbiAgICogLSBzb3J0Qnkvc29ydE9yZGVyIHRvcC1sZXZlbCBwYXJhbXNcbiAgICpcbiAgICogQHBhcmFtIHBhcmFtcyAtIFJhdyBwYXJhbWV0ZXJzXG4gICAqIEByZXR1cm5zIE5vcm1hbGl6ZWQgc29ydEJ5IGFuZCBzb3J0T3JkZXJcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogbm9ybWFsaXplU29ydCh7IHNvcnQ6IHsgZmllbGQ6ICduYW1lJywgb3JkZXI6ICdkZXNjJyB9IH0pXG4gICAqIC8vID0+IHsgc29ydEJ5OiAnbmFtZScsIHNvcnRPcmRlcjogJ2Rlc2MnIH1cbiAgICpcbiAgICogbm9ybWFsaXplU29ydCh7IHNvcnRCeTogJ2NyZWF0ZWQnLCBzb3J0T3JkZXI6ICdhc2MnIH0pXG4gICAqIC8vID0+IHsgc29ydEJ5OiAnY3JlYXRlZCcsIHNvcnRPcmRlcjogJ2FzYycgfVxuICAgKi9cbiAgcHJpdmF0ZSBub3JtYWxpemVTb3J0KHBhcmFtczogUmF3U2VhcmNoUGFyYW1zKToge1xuICAgIHNvcnRCeT86IHN0cmluZztcbiAgICBzb3J0T3JkZXI/OiAnYXNjJyB8ICdkZXNjJztcbiAgfSB7XG4gICAgY29uc3QgcmVzdWx0OiB7IHNvcnRCeT86IHN0cmluZzsgc29ydE9yZGVyPzogJ2FzYycgfCAnZGVzYycgfSA9IHt9O1xuXG4gICAgLy8gQ2hlY2sgZm9yIHNvcnQgb2JqZWN0XG4gICAgY29uc3Qgc29ydCA9IHBhcmFtcy5zb3J0IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkO1xuICAgIGlmIChzb3J0KSB7XG4gICAgICBpZiAodHlwZW9mIHNvcnQuZmllbGQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIHJlc3VsdC5zb3J0QnkgPSBzb3J0LmZpZWxkO1xuICAgICAgfVxuICAgICAgaWYgKHR5cGVvZiBzb3J0Lm9yZGVyID09PSAnc3RyaW5nJyAmJiBWQUxJRF9TT1JUX09SREVSUy5pbmNsdWRlcyhzb3J0Lm9yZGVyIGFzICdhc2MnIHwgJ2Rlc2MnKSkge1xuICAgICAgICByZXN1bHQuc29ydE9yZGVyID0gc29ydC5vcmRlciBhcyAnYXNjJyB8ICdkZXNjJztcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUb3AtbGV2ZWwgcGFyYW1zIG92ZXJyaWRlIHNvcnQgb2JqZWN0XG4gICAgaWYgKHR5cGVvZiBwYXJhbXMuc29ydEJ5ID09PSAnc3RyaW5nJykge1xuICAgICAgcmVzdWx0LnNvcnRCeSA9IHBhcmFtcy5zb3J0Qnk7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgcGFyYW1zLnNvcnRPcmRlciA9PT0gJ3N0cmluZycgJiYgVkFMSURfU09SVF9PUkRFUlMuaW5jbHVkZXMocGFyYW1zLnNvcnRPcmRlciBhcyAnYXNjJyB8ICdkZXNjJykpIHtcbiAgICAgIHJlc3VsdC5zb3J0T3JkZXIgPSBwYXJhbXMuc29ydE9yZGVyIGFzICdhc2MnIHwgJ2Rlc2MnO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gRmlsdGVyIE5vcm1hbGl6YXRpb25cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIE5vcm1hbGl6ZSBmaWx0ZXIgcGFyYW1ldGVycy5cbiAgICpcbiAgICogRXh0cmFjdHMgYW5kIHZhbGlkYXRlcyBmaWx0ZXIgdmFsdWVzLlxuICAgKlxuICAgKiBAcGFyYW0gZmlsdGVycyAtIFJhdyBmaWx0ZXJzIG9iamVjdFxuICAgKiBAcmV0dXJucyBOb3JtYWxpemVkIGZpbHRlcnNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogbm9ybWFsaXplRmlsdGVycyh7IHRhZ3M6IFsnYWknLCAnY3JlYXRpdmUnXSwgYXV0aG9yOiAndXNlcjEyMycgfSlcbiAgICogLy8gPT4geyB0YWdzOiBbJ2FpJywgJ2NyZWF0aXZlJ10sIGF1dGhvcjogJ3VzZXIxMjMnIH1cbiAgICovXG4gIHByaXZhdGUgbm9ybWFsaXplRmlsdGVycyhmaWx0ZXJzOiB1bmtub3duKTogTm9uTnVsbGFibGU8Tm9ybWFsaXplZFNlYXJjaFBhcmFtc1snZmlsdGVycyddPiB7XG4gICAgY29uc3QgcmVzdWx0OiBOb25OdWxsYWJsZTxOb3JtYWxpemVkU2VhcmNoUGFyYW1zWydmaWx0ZXJzJ10+ID0ge307XG5cbiAgICBpZiAoIWZpbHRlcnMgfHwgdHlwZW9mIGZpbHRlcnMgIT09ICdvYmplY3QnKSB7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIGNvbnN0IGYgPSBmaWx0ZXJzIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuXG4gICAgLy8gVGFncyBmaWx0ZXJcbiAgICBpZiAoQXJyYXkuaXNBcnJheShmLnRhZ3MpKSB7XG4gICAgICBjb25zdCB2YWxpZFRhZ3MgPSBmLnRhZ3MuZmlsdGVyKCh0KTogdCBpcyBzdHJpbmcgPT4gdHlwZW9mIHQgPT09ICdzdHJpbmcnKTtcbiAgICAgIGlmICh2YWxpZFRhZ3MubGVuZ3RoID4gMCkge1xuICAgICAgICByZXN1bHQudGFncyA9IHZhbGlkVGFncztcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBBdXRob3IgZmlsdGVyXG4gICAgaWYgKHR5cGVvZiBmLmF1dGhvciA9PT0gJ3N0cmluZycgJiYgZi5hdXRob3IudHJpbSgpKSB7XG4gICAgICByZXN1bHQuYXV0aG9yID0gZi5hdXRob3IudHJpbSgpO1xuICAgIH1cblxuICAgIC8vIERhdGUgZmlsdGVyc1xuICAgIGlmICh0eXBlb2YgZi5jcmVhdGVkQWZ0ZXIgPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXN1bHQuY3JlYXRlZEFmdGVyID0gZi5jcmVhdGVkQWZ0ZXI7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgZi5jcmVhdGVkQmVmb3JlID09PSAnc3RyaW5nJykge1xuICAgICAgcmVzdWx0LmNyZWF0ZWRCZWZvcmUgPSBmLmNyZWF0ZWRCZWZvcmU7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBPcHRpb25zIE5vcm1hbGl6YXRpb25cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIE5vcm1hbGl6ZSBzZWFyY2ggb3B0aW9ucy5cbiAgICpcbiAgICogSGFuZGxlcyBib3RoIG9wdGlvbnMgb2JqZWN0IGFuZCBsZWdhY3kgdG9wLWxldmVsIGJvb2xlYW4gcGFyYW1zLlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1zIC0gUmF3IHBhcmFtZXRlcnNcbiAgICogQHJldHVybnMgTm9ybWFsaXplZCBvcHRpb25zXG4gICAqL1xuICBwcml2YXRlIG5vcm1hbGl6ZU9wdGlvbnMocGFyYW1zOiBSYXdTZWFyY2hQYXJhbXMpOiBOb25OdWxsYWJsZTxOb3JtYWxpemVkU2VhcmNoUGFyYW1zWydvcHRpb25zJ10+IHtcbiAgICBjb25zdCByZXN1bHQ6IE5vbk51bGxhYmxlPE5vcm1hbGl6ZWRTZWFyY2hQYXJhbXNbJ29wdGlvbnMnXT4gPSB7fTtcblxuICAgIC8vIENoZWNrIGZvciBvcHRpb25zIG9iamVjdFxuICAgIGNvbnN0IG9wdGlvbnMgPSBwYXJhbXMub3B0aW9ucyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZDtcblxuICAgIC8vIEhlbHBlciB0byBnZXQgYm9vbGVhbiB2YWx1ZSBmcm9tIG9wdGlvbnMgb3IgbGVnYWN5IHBhcmFtc1xuICAgIGNvbnN0IGdldEJvb2xlYW4gPSAob3B0S2V5OiBzdHJpbmcsIGxlZ2FjeUtleToga2V5b2YgUmF3U2VhcmNoUGFyYW1zKTogYm9vbGVhbiB8IHVuZGVmaW5lZCA9PiB7XG4gICAgICBpZiAob3B0aW9ucyAmJiB0eXBlb2Ygb3B0aW9uc1tvcHRLZXldID09PSAnYm9vbGVhbicpIHtcbiAgICAgICAgcmV0dXJuIG9wdGlvbnNbb3B0S2V5XSBhcyBib29sZWFuO1xuICAgICAgfVxuICAgICAgaWYgKHR5cGVvZiBwYXJhbXNbbGVnYWN5S2V5XSA9PT0gJ2Jvb2xlYW4nKSB7XG4gICAgICAgIHJldHVybiBwYXJhbXNbbGVnYWN5S2V5XSBhcyBib29sZWFuO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9O1xuXG4gICAgLy8gTWFwIG9wdGlvbnNcbiAgICBjb25zdCBmdXp6eU1hdGNoID0gZ2V0Qm9vbGVhbignZnV6enlNYXRjaCcsICdmdXp6eU1hdGNoJyk7XG4gICAgY29uc3QgaW5jbHVkZUtleXdvcmRzID0gZ2V0Qm9vbGVhbignaW5jbHVkZUtleXdvcmRzJywgJ2luY2x1ZGVLZXl3b3JkcycpO1xuICAgIGNvbnN0IGluY2x1ZGVUYWdzID0gZ2V0Qm9vbGVhbignaW5jbHVkZVRhZ3MnLCAnaW5jbHVkZVRhZ3MnKTtcbiAgICBjb25zdCBpbmNsdWRlVHJpZ2dlcnMgPSBnZXRCb29sZWFuKCdpbmNsdWRlVHJpZ2dlcnMnLCAnaW5jbHVkZVRyaWdnZXJzJyk7XG4gICAgY29uc3QgaW5jbHVkZURlc2NyaXB0aW9ucyA9IGdldEJvb2xlYW4oJ2luY2x1ZGVEZXNjcmlwdGlvbnMnLCAnaW5jbHVkZURlc2NyaXB0aW9ucycpO1xuXG4gICAgaWYgKGZ1enp5TWF0Y2ggIT09IHVuZGVmaW5lZCkgcmVzdWx0LmZ1enp5TWF0Y2ggPSBmdXp6eU1hdGNoO1xuICAgIGlmIChpbmNsdWRlS2V5d29yZHMgIT09IHVuZGVmaW5lZCkgcmVzdWx0LmluY2x1ZGVLZXl3b3JkcyA9IGluY2x1ZGVLZXl3b3JkcztcbiAgICBpZiAoaW5jbHVkZVRhZ3MgIT09IHVuZGVmaW5lZCkgcmVzdWx0LmluY2x1ZGVUYWdzID0gaW5jbHVkZVRhZ3M7XG4gICAgaWYgKGluY2x1ZGVUcmlnZ2VycyAhPT0gdW5kZWZpbmVkKSByZXN1bHQuaW5jbHVkZVRyaWdnZXJzID0gaW5jbHVkZVRyaWdnZXJzO1xuICAgIGlmIChpbmNsdWRlRGVzY3JpcHRpb25zICE9PSB1bmRlZmluZWQpIHJlc3VsdC5pbmNsdWRlRGVzY3JpcHRpb25zID0gaW5jbHVkZURlc2NyaXB0aW9ucztcblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gRWxlbWVudCBUeXBlIE5vcm1hbGl6YXRpb25cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIE5vcm1hbGl6ZSBlbGVtZW50IHR5cGUgcGFyYW1ldGVyLlxuICAgKlxuICAgKiBIYW5kbGVzIGJvdGggJ3R5cGUnIGFuZCBsZWdhY3kgJ2VsZW1lbnRUeXBlJyBwYXJhbXMuXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBSYXcgcGFyYW1ldGVyc1xuICAgKiBAcmV0dXJucyBOb3JtYWxpemVkIGVsZW1lbnQgdHlwZSBvciB1bmRlZmluZWRcbiAgICovXG4gIHByaXZhdGUgbm9ybWFsaXplRWxlbWVudFR5cGUocGFyYW1zOiBSYXdTZWFyY2hQYXJhbXMpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGlmICh0eXBlb2YgcGFyYW1zLnR5cGUgPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gcGFyYW1zLnR5cGU7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgcGFyYW1zLmVsZW1lbnRUeXBlID09PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIHBhcmFtcy5lbGVtZW50V