@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
JavaScript
/**
* 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