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.

484 lines 60.6 kB
/** * FilterService - Element filtering implementation * * Provides stateless filtering capabilities for element arrays based on * metadata and other criteria. All filters combine with AND logic except * tagsAny which uses OR logic. * * SECURITY: * - All string inputs are sanitized using normalizeSearchTerm * - Date inputs are validated as ISO 8601 format * - Tag arrays are validated and limited * - Missing metadata fields are handled gracefully * - Validation failures are logged to SecurityMonitor * * @see src/services/query/types.ts for interface definitions */ import { ElementStatus } from '../../types/elements/IElement.js'; import { normalizeSearchTerm, validateSearchQuery } from '../../utils/searchUtils.js'; import { SecurityMonitor } from '../../security/securityMonitor.js'; /** * Maximum number of tags allowed in a single filter * Prevents array manipulation attacks and excessive processing */ const MAX_TAGS_PER_FILTER = 50; /** * Maximum length for author field * Prevents DoS through excessively long strings */ const MAX_AUTHOR_LENGTH = 100; /** * Maximum length for description filter */ const MAX_DESCRIPTION_FILTER_LENGTH = 500; /** * Maximum length for category filter */ const MAX_CATEGORY_LENGTH = 100; /** * Set of known filter keys for validation */ const KNOWN_FILTER_KEYS = new Set([ 'nameContains', 'tags', 'tagsAny', 'author', 'createdAfter', 'createdBefore', 'status', 'descriptionContains', 'category', ]); /** * FilterService implementation * * Stateless service for filtering element arrays. Safe for injection * via DI and concurrent use across multiple operations. * * @template T - Element type being filtered (must extend IElement) */ export class FilterService { /** * Filter an array of elements based on criteria * * All criteria are optional and combined with AND logic when multiple * filters are specified. The exception is tagsAny which uses OR logic * (element must have ANY of the specified tags). * * Elements with missing metadata fields pass the filter if that field * is not required by the criteria (graceful degradation). * * @param items - Array of elements to filter * @param criteria - Filter criteria to apply * @returns Filtered array (may be empty if no matches) * @throws {Error} If filter criteria contain invalid values * * @example * ```typescript * const filtered = filterService.filter(elements, { * nameContains: 'code review', * tags: ['typescript', 'linting'], * status: 'active' * }); * ``` */ filter(items, criteria) { // No criteria = no filtering if (!criteria) { return items; } // Validate criteria first this.validateCriteria(criteria); // Apply each filter in sequence let filtered = items; if (criteria.nameContains !== undefined) { filtered = this.filterByName(filtered, criteria.nameContains); } if (criteria.tags !== undefined && criteria.tags.length > 0) { filtered = this.filterByTags(filtered, criteria.tags); } if (criteria.tagsAny !== undefined && criteria.tagsAny.length > 0) { filtered = this.filterByTagsAny(filtered, criteria.tagsAny); } if (criteria.author !== undefined) { filtered = this.filterByAuthor(filtered, criteria.author); } if (criteria.createdAfter !== undefined) { filtered = this.filterByCreatedAfter(filtered, criteria.createdAfter); } if (criteria.createdBefore !== undefined) { filtered = this.filterByCreatedBefore(filtered, criteria.createdBefore); } if (criteria.status !== undefined && criteria.status !== 'all') { filtered = this.filterByStatus(filtered, criteria.status); } if (criteria.descriptionContains !== undefined) { filtered = this.filterByDescription(filtered, criteria.descriptionContains); } if (criteria.category !== undefined) { filtered = this.filterByCategory(filtered, criteria.category); } return filtered; } /** * Build a summary of which filters will be applied * * Useful for logging and debugging query execution. * Returns a sanitized copy of the criteria with count. * * @param criteria - Filter criteria * @returns Summary of applicable filters * * @example * ```typescript * const summary = filterService.summarizeFilters(criteria); * logger.debug('Applying filters', summary); * ``` */ summarizeFilters(criteria) { const applied = { count: 0 }; if (!criteria) { return applied; } if (criteria.nameContains !== undefined && criteria.nameContains.trim() !== '') { applied.nameContains = criteria.nameContains; applied.count++; } if (criteria.tags !== undefined && criteria.tags.length > 0) { applied.tags = [...criteria.tags]; applied.count++; } if (criteria.tagsAny !== undefined && criteria.tagsAny.length > 0) { applied.tagsAny = [...criteria.tagsAny]; applied.count++; } if (criteria.author !== undefined && criteria.author.trim() !== '') { applied.author = criteria.author; applied.count++; } if (criteria.createdAfter !== undefined) { applied.createdAfter = criteria.createdAfter; applied.count++; } if (criteria.createdBefore !== undefined) { applied.createdBefore = criteria.createdBefore; applied.count++; } if (criteria.status !== undefined && criteria.status !== 'all') { applied.status = criteria.status; applied.count++; } if (criteria.descriptionContains !== undefined && criteria.descriptionContains.trim() !== '') { applied.descriptionContains = criteria.descriptionContains; applied.count++; } if (criteria.category !== undefined && criteria.category.trim() !== '') { applied.category = criteria.category; applied.count++; } return applied; } /** * Validate filter criteria without applying them * * Checks all criteria for: * - Valid string lengths * - Valid date formats * - Valid tag arrays * - Valid status values * * Logs security events for validation failures. * * @param criteria - Filter criteria to validate * @returns True if criteria are valid * @throws {Error} If criteria are invalid with descriptive message * * @example * ```typescript * try { * filterService.validateCriteria(userInput); * } catch (error) { * logger.error('Invalid filter criteria', error); * } * ``` */ validateCriteria(criteria) { if (!criteria) { return true; } try { // Reject unknown filter keys const unknownKeys = Object.keys(criteria).filter(key => !KNOWN_FILTER_KEYS.has(key)); if (unknownKeys.length > 0) { const supported = [...KNOWN_FILTER_KEYS].sort((a, b) => a.localeCompare(b)).join(', '); throw new Error(`Unknown filter key(s): ${unknownKeys.join(', ')}. Supported filters: ${supported}`); } // Validate nameContains if (criteria.nameContains !== undefined) { if (typeof criteria.nameContains !== 'string') { throw new Error('nameContains must be a string'); } // Use validateSearchQuery which also sanitizes validateSearchQuery(criteria.nameContains); } // Validate tags (AND logic) if (criteria.tags !== undefined) { this.validateTagArray(criteria.tags, 'tags'); } // Validate tagsAny (OR logic) if (criteria.tagsAny !== undefined) { this.validateTagArray(criteria.tagsAny, 'tagsAny'); } // Validate author if (criteria.author !== undefined) { if (typeof criteria.author !== 'string') { throw new Error('author must be a string'); } if (criteria.author.length > MAX_AUTHOR_LENGTH) { throw new Error(`author exceeds maximum length of ${MAX_AUTHOR_LENGTH} characters`); } } // Validate dates if (criteria.createdAfter !== undefined) { this.validateISO8601Date(criteria.createdAfter, 'createdAfter'); } if (criteria.createdBefore !== undefined) { this.validateISO8601Date(criteria.createdBefore, 'createdBefore'); } // Validate status if (criteria.status !== undefined) { const validStatuses = ['active', 'inactive', 'all']; if (!validStatuses.includes(criteria.status)) { throw new Error(`status must be one of: ${validStatuses.join(', ')}`); } } // Validate descriptionContains if (criteria.descriptionContains !== undefined) { if (typeof criteria.descriptionContains !== 'string') { throw new Error('descriptionContains must be a string'); } if (criteria.descriptionContains.length > MAX_DESCRIPTION_FILTER_LENGTH) { throw new Error(`descriptionContains exceeds maximum length of ${MAX_DESCRIPTION_FILTER_LENGTH} characters`); } validateSearchQuery(criteria.descriptionContains); } // Validate category if (criteria.category !== undefined) { if (typeof criteria.category !== 'string') { throw new Error('category must be a string'); } if (criteria.category.length > MAX_CATEGORY_LENGTH) { throw new Error(`category exceeds maximum length of ${MAX_CATEGORY_LENGTH} characters`); } } return true; } catch (error) { // Log validation failure as security event SecurityMonitor.logSecurityEvent({ type: 'UNICODE_VALIDATION_ERROR', severity: 'MEDIUM', source: 'FilterService.validateCriteria', details: `Filter criteria validation failed: ${error instanceof Error ? error.message : String(error)}`, additionalData: { criteria: this.sanitizeCriteriaForLogging(criteria), }, }); // Re-throw for caller to handle throw error; } } // ============================================================================ // Private Filter Methods // ============================================================================ /** * Filter elements by name (case-insensitive partial match) */ filterByName(items, nameContains) { const normalized = normalizeSearchTerm(nameContains); return items.filter((item) => { const itemName = normalizeSearchTerm(item.metadata.name); return itemName.includes(normalized); }); } /** * Filter elements by tags (AND logic - must have ALL tags) */ filterByTags(items, tags) { const normalizedTags = tags.map((tag) => normalizeSearchTerm(tag)); return items.filter((item) => { const itemTags = item.metadata.tags || []; const normalizedItemTags = itemTags.map((tag) => normalizeSearchTerm(tag)); // Element must have ALL required tags return normalizedTags.every((requiredTag) => normalizedItemTags.some((itemTag) => itemTag === requiredTag)); }); } /** * Filter elements by tags (OR logic - must have ANY tag) */ filterByTagsAny(items, tagsAny) { const normalizedTags = tagsAny.map((tag) => normalizeSearchTerm(tag)); return items.filter((item) => { const itemTags = item.metadata.tags || []; const normalizedItemTags = itemTags.map((tag) => normalizeSearchTerm(tag)); // Element must have AT LEAST ONE of the specified tags return normalizedTags.some((anyTag) => normalizedItemTags.some((itemTag) => itemTag === anyTag)); }); } /** * Filter elements by author (exact match, case-insensitive) */ filterByAuthor(items, author) { const normalizedAuthor = normalizeSearchTerm(author); return items.filter((item) => { // If element has no author, it doesn't match if (!item.metadata.author) { return false; } const itemAuthor = normalizeSearchTerm(item.metadata.author); return itemAuthor === normalizedAuthor; }); } /** * Filter elements created after a date (inclusive) */ filterByCreatedAfter(items, createdAfter) { const afterDate = new Date(createdAfter); return items.filter((item) => { // If element has no created date, it doesn't match if (!item.metadata.created) { return false; } const itemDate = new Date(item.metadata.created); return itemDate >= afterDate; }); } /** * Filter elements created before a date (inclusive) */ filterByCreatedBefore(items, createdBefore) { const beforeDate = new Date(createdBefore); return items.filter((item) => { // If element has no created date, it doesn't match if (!item.metadata.created) { return false; } const itemDate = new Date(item.metadata.created); return itemDate <= beforeDate; }); } /** * Filter elements by status */ filterByStatus(items, status) { return items.filter((item) => { const itemStatus = item.getStatus(); if (status === 'active') { return itemStatus === ElementStatus.ACTIVE || itemStatus === ElementStatus.ACTIVATING; } else if (status === 'inactive') { return (itemStatus === ElementStatus.INACTIVE || itemStatus === ElementStatus.DEACTIVATING || itemStatus === ElementStatus.ERROR || itemStatus === ElementStatus.SUSPENDED); } return false; }); } /** * Filter elements by description (case-insensitive substring match) */ filterByDescription(items, descriptionContains) { const normalized = normalizeSearchTerm(descriptionContains); return items.filter((item) => { const itemDescription = item.metadata.description ? normalizeSearchTerm(item.metadata.description) : ''; return itemDescription.includes(normalized); }); } /** * Filter elements by category (case-insensitive exact match) */ filterByCategory(items, category) { const normalizedCategory = normalizeSearchTerm(category); return items.filter((item) => { const itemCategory = this.getMetadataField(item, 'category'); if (typeof itemCategory !== 'string') { return false; } return normalizeSearchTerm(itemCategory) === normalizedCategory; }); } /** * Safely access an arbitrary metadata field that may not be on the IElementMetadata interface. * Used for extension fields like 'category' that exist on some elements. * Checks metadata.custom first (standard extensibility), then metadata directly * using property descriptor access to avoid unsafe type assertions. */ getMetadataField(item, field) { if (item.metadata.custom && field in item.metadata.custom) { return item.metadata.custom[field]; } const descriptor = Object.getOwnPropertyDescriptor(item.metadata, field); return descriptor?.value; } // ============================================================================ // Private Validation Helpers // ============================================================================ /** * Validate a tag array */ validateTagArray(tags, fieldName) { if (!Array.isArray(tags)) { throw new Error(`${fieldName} must be an array`); } if (tags.length > MAX_TAGS_PER_FILTER) { throw new Error(`${fieldName} exceeds maximum of ${MAX_TAGS_PER_FILTER} tags`); } for (const tag of tags) { if (typeof tag !== 'string') { throw new Error(`${fieldName} must contain only strings`); } // Validate each tag as a search term validateSearchQuery(tag); } } /** * Validate ISO 8601 date string */ validateISO8601Date(dateString, fieldName) { if (typeof dateString !== 'string') { throw new Error(`${fieldName} must be a string`); } // Try to parse as Date const date = new Date(dateString); if (isNaN(date.getTime())) { throw new Error(`${fieldName} must be a valid ISO 8601 date`); } // Validate ISO 8601 format (basic check) // Accepts formats like: 2024-01-01, 2024-01-01T00:00:00Z, etc. const iso8601Pattern = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?(Z|[+-]\d{2}:\d{2})?)?$/; if (!iso8601Pattern.test(dateString)) { throw new Error(`${fieldName} must be in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)`); } } /** * Sanitize criteria for logging (remove potentially sensitive data) */ sanitizeCriteriaForLogging(criteria) { return { hasNameContains: criteria.nameContains !== undefined, hasTagsFilter: criteria.tags !== undefined && criteria.tags.length > 0, hasTagsAnyFilter: criteria.tagsAny !== undefined && criteria.tagsAny.length > 0, hasAuthorFilter: criteria.author !== undefined, hasCreatedAfterFilter: criteria.createdAfter !== undefined, hasCreatedBeforeFilter: criteria.createdBefore !== undefined, hasStatusFilter: criteria.status !== undefined, status: criteria.status, hasDescriptionContainsFilter: criteria.descriptionContains !== undefined, hasCategoryFilter: criteria.category !== undefined, }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmlsdGVyU2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zZXJ2aWNlcy9xdWVyeS9GaWx0ZXJTZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUVILE9BQU8sRUFBWSxhQUFhLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUMzRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUN0RixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFHcEU7OztHQUdHO0FBQ0gsTUFBTSxtQkFBbUIsR0FBRyxFQUFFLENBQUM7QUFFL0I7OztHQUdHO0FBQ0gsTUFBTSxpQkFBaUIsR0FBRyxHQUFHLENBQUM7QUFFOUI7O0dBRUc7QUFDSCxNQUFNLDZCQUE2QixHQUFHLEdBQUcsQ0FBQztBQUUxQzs7R0FFRztBQUNILE1BQU0sbUJBQW1CLEdBQUcsR0FBRyxDQUFDO0FBRWhDOztHQUVHO0FBQ0gsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLEdBQUcsQ0FBQztJQUNoQyxjQUFjO0lBQ2QsTUFBTTtJQUNOLFNBQVM7SUFDVCxRQUFRO0lBQ1IsY0FBYztJQUNkLGVBQWU7SUFDZixRQUFRO0lBQ1IscUJBQXFCO0lBQ3JCLFVBQVU7Q0FDWCxDQUFDLENBQUM7QUFFSDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxPQUFPLGFBQWE7SUFDeEI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O09BdUJHO0lBQ0gsTUFBTSxDQUFDLEtBQVUsRUFBRSxRQUF5QjtRQUMxQyw2QkFBNkI7UUFDN0IsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ2QsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO1FBRUQsMEJBQTBCO1FBQzFCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUVoQyxnQ0FBZ0M7UUFDaEMsSUFBSSxRQUFRLEdBQUcsS0FBSyxDQUFDO1FBRXJCLElBQUksUUFBUSxDQUFDLFlBQVksS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUN4QyxRQUFRLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ2hFLENBQUM7UUFFRCxJQUFJLFFBQVEsQ0FBQyxJQUFJLEtBQUssU0FBUyxJQUFJLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzVELFFBQVEsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDeEQsQ0FBQztRQUVELElBQUksUUFBUSxDQUFDLE9BQU8sS0FBSyxTQUFTLElBQUksUUFBUSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDbEUsUUFBUSxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM5RCxDQUFDO1FBRUQsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ2xDLFFBQVEsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDNUQsQ0FBQztRQUVELElBQUksUUFBUSxDQUFDLFlBQVksS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUN4QyxRQUFRLEdBQUcsSUFBSSxDQUFDLG9CQUFvQixDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDeEUsQ0FBQztRQUVELElBQUksUUFBUSxDQUFDLGFBQWEsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUN6QyxRQUFRLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDMUUsQ0FBQztRQUVELElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxTQUFTLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxLQUFLLEVBQUUsQ0FBQztZQUMvRCxRQUFRLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzVELENBQUM7UUFFRCxJQUFJLFFBQVEsQ0FBQyxtQkFBbUIsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUMvQyxRQUFRLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsbUJBQW1CLENBQUMsQ0FBQztRQUM5RSxDQUFDO1FBRUQsSUFBSSxRQUFRLENBQUMsUUFBUSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3BDLFFBQVEsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNoRSxDQUFDO1FBRUQsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7OztPQWNHO0lBQ0gsZ0JBQWdCLENBQUMsUUFBeUI7UUFDeEMsTUFBTSxPQUFPLEdBQW1CLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxDQUFDO1FBRTdDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNkLE9BQU8sT0FBTyxDQUFDO1FBQ2pCLENBQUM7UUFFRCxJQUFJLFFBQVEsQ0FBQyxZQUFZLEtBQUssU0FBUyxJQUFJLFFBQVEsQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUM7WUFDL0UsT0FBTyxDQUFDLFlBQVksR0FBRyxRQUFRLENBQUMsWUFBWSxDQUFDO1lBQzdDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNsQixDQUFDO1FBRUQsSUFBSSxRQUFRLENBQUMsSUFBSSxLQUFLLFNBQVMsSUFBSSxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUM1RCxPQUFPLENBQUMsSUFBSSxHQUFHLENBQUMsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDbEMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2xCLENBQUM7UUFFRCxJQUFJLFFBQVEsQ0FBQyxPQUFPLEtBQUssU0FBUyxJQUFJLFFBQVEsQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ2xFLE9BQU8sQ0FBQyxPQUFPLEdBQUcsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUN4QyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDbEIsQ0FBQztRQUVELElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxTQUFTLElBQUksUUFBUSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQztZQUNuRSxPQUFPLENBQUMsTUFBTSxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUM7WUFDakMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2xCLENBQUM7UUFFRCxJQUFJLFFBQVEsQ0FBQyxZQUFZLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDeEMsT0FBTyxDQUFDLFlBQVksR0FBRyxRQUFRLENBQUMsWUFBWSxDQUFDO1lBQzdDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNsQixDQUFDO1FBRUQsSUFBSSxRQUFRLENBQUMsYUFBYSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3pDLE9BQU8sQ0FBQyxhQUFhLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQztZQUMvQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDbEIsQ0FBQztRQUVELElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxTQUFTLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxLQUFLLEVBQUUsQ0FBQztZQUMvRCxPQUFPLENBQUMsTUFBTSxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUM7WUFDakMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2xCLENBQUM7UUFFRCxJQUFJLFFBQVEsQ0FBQyxtQkFBbUIsS0FBSyxTQUFTLElBQUksUUFBUSxDQUFDLG1CQUFtQixDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDO1lBQzdGLE9BQU8sQ0FBQyxtQkFBbUIsR0FBRyxRQUFRLENBQUMsbUJBQW1CLENBQUM7WUFDM0QsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2xCLENBQUM7UUFFRCxJQUFJLFFBQVEsQ0FBQyxRQUFRLEtBQUssU0FBUyxJQUFJLFFBQVEsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUM7WUFDdkUsT0FBTyxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDO1lBQ3JDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNsQixDQUFDO1FBRUQsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQXVCRztJQUNILGdCQUFnQixDQUFDLFFBQXlCO1FBQ3hDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNkLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELElBQUksQ0FBQztZQUNILDZCQUE2QjtZQUM3QixNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDckYsSUFBSSxXQUFXLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUMzQixNQUFNLFNBQVMsR0FBRyxDQUFDLEdBQUcsaUJBQWlCLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUN2RixNQUFNLElBQUksS0FBSyxDQUNiLDBCQUEwQixXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyx3QkFBd0IsU0FBUyxFQUFFLENBQ3BGLENBQUM7WUFDSixDQUFDO1lBRUQsd0JBQXdCO1lBQ3hCLElBQUksUUFBUSxDQUFDLFlBQVksS0FBSyxTQUFTLEVBQUUsQ0FBQztnQkFDeEMsSUFBSSxPQUFPLFFBQVEsQ0FBQyxZQUFZLEtBQUssUUFBUSxFQUFFLENBQUM7b0JBQzlDLE1BQU0sSUFBSSxLQUFLLENBQUMsK0JBQStCLENBQUMsQ0FBQztnQkFDbkQsQ0FBQztnQkFDRCwrQ0FBK0M7Z0JBQy9DLG1CQUFtQixDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUM3QyxDQUFDO1lBRUQsNEJBQTRCO1lBQzVCLElBQUksUUFBUSxDQUFDLElBQUksS0FBSyxTQUFTLEVBQUUsQ0FBQztnQkFDaEMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFDL0MsQ0FBQztZQUVELDhCQUE4QjtZQUM5QixJQUFJLFFBQVEsQ0FBQyxPQUFPLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQ25DLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1lBQ3JELENBQUM7WUFFRCxrQkFBa0I7WUFDbEIsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUNsQyxJQUFJLE9BQU8sUUFBUSxDQUFDLE1BQU0sS0FBSyxRQUFRLEVBQUUsQ0FBQztvQkFDeEMsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO2dCQUM3QyxDQUFDO2dCQUNELElBQUksUUFBUSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsaUJBQWlCLEVBQUUsQ0FBQztvQkFDL0MsTUFBTSxJQUFJLEtBQUssQ0FBQyxvQ0FBb0MsaUJBQWlCLGFBQWEsQ0FBQyxDQUFDO2dCQUN0RixDQUFDO1lBQ0gsQ0FBQztZQUVELGlCQUFpQjtZQUNqQixJQUFJLFFBQVEsQ0FBQyxZQUFZLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQ3hDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxRQUFRLENBQUMsWUFBWSxFQUFFLGNBQWMsQ0FBQyxDQUFDO1lBQ2xFLENBQUM7WUFFRCxJQUFJLFFBQVEsQ0FBQyxhQUFhLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQ3pDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxRQUFRLENBQUMsYUFBYSxFQUFFLGVBQWUsQ0FBQyxDQUFDO1lBQ3BFLENBQUM7WUFFRCxrQkFBa0I7WUFDbEIsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUNsQyxNQUFNLGFBQWEsR0FBRyxDQUFDLFFBQVEsRUFBRSxVQUFVLEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQ3BELElBQUksQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO29CQUM3QyxNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDeEUsQ0FBQztZQUNILENBQUM7WUFFRCwrQkFBK0I7WUFDL0IsSUFBSSxRQUFRLENBQUMsbUJBQW1CLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQy9DLElBQUksT0FBTyxRQUFRLENBQUMsbUJBQW1CLEtBQUssUUFBUSxFQUFFLENBQUM7b0JBQ3JELE1BQU0sSUFBSSxLQUFLLENBQUMsc0NBQXNDLENBQUMsQ0FBQztnQkFDMUQsQ0FBQztnQkFDRCxJQUFJLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLEdBQUcsNkJBQTZCLEVBQUUsQ0FBQztvQkFDeEUsTUFBTSxJQUFJLEtBQUssQ0FBQyxpREFBaUQsNkJBQTZCLGFBQWEsQ0FBQyxDQUFDO2dCQUMvRyxDQUFDO2dCQUNELG1CQUFtQixDQUFDLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1lBQ3BELENBQUM7WUFFRCxvQkFBb0I7WUFDcEIsSUFBSSxRQUFRLENBQUMsUUFBUSxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUNwQyxJQUFJLE9BQU8sUUFBUSxDQUFDLFFBQVEsS0FBSyxRQUFRLEVBQUUsQ0FBQztvQkFDMUMsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO2dCQUMvQyxDQUFDO2dCQUNELElBQUksUUFBUSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEdBQUcsbUJBQW1CLEVBQUUsQ0FBQztvQkFDbkQsTUFBTSxJQUFJLEtBQUssQ0FBQyxzQ0FBc0MsbUJBQW1CLGFBQWEsQ0FBQyxDQUFDO2dCQUMxRixDQUFDO1lBQ0gsQ0FBQztZQUVELE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZiwyQ0FBMkM7WUFDM0MsZUFBZSxDQUFDLGdCQUFnQixDQUFDO2dCQUMvQixJQUFJLEVBQUUsMEJBQTBCO2dCQUNoQyxRQUFRLEVBQUUsUUFBUTtnQkFDbEIsTUFBTSxFQUFFLGdDQUFnQztnQkFDeEMsT0FBTyxFQUFFLHNDQUFzQyxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUU7Z0JBQ3ZHLGNBQWMsRUFBRTtvQkFDZCxRQUFRLEVBQUUsSUFBSSxDQUFDLDBCQUEwQixDQUFDLFFBQVEsQ0FBQztpQkFDcEQ7YUFDRixDQUFDLENBQUM7WUFFSCxnQ0FBZ0M7WUFDaEMsTUFBTSxLQUFLLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztJQUVELCtFQUErRTtJQUMvRSx5QkFBeUI7SUFDekIsK0VBQStFO0lBRS9FOztPQUVHO0lBQ0ssWUFBWSxDQUFDLEtBQVUsRUFBRSxZQUFvQjtRQUNuRCxNQUFNLFVBQVUsR0FBRyxtQkFBbUIsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUNyRCxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtZQUMzQixNQUFNLFFBQVEsR0FBRyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3pELE9BQU8sUUFBUSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUN2QyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNLLFlBQVksQ0FBQyxLQUFVLEVBQUUsSUFBYztRQUM3QyxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBRW5FLE9BQU8sS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO1lBQzNCLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUMxQyxNQUFNLGtCQUFrQixHQUFHLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLG1CQUFtQixDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFFM0Usc0NBQXNDO1lBQ3RDLE9BQU8sY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQzFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsT0FBTyxLQUFLLFdBQVcsQ0FBQyxDQUM5RCxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxlQUFlLENBQUMsS0FBVSxFQUFFLE9BQWlCO1FBQ25ELE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLG1CQUFtQixDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFFdEUsT0FBTyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUU7WUFDM0IsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDO1lBQzFDLE1BQU0sa0JBQWtCLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsbUJBQW1CLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUUzRSx1REFBdUQ7WUFDdkQsT0FBTyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FDcEMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxPQUFPLEtBQUssTUFBTSxDQUFDLENBQ3pELENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNLLGNBQWMsQ0FBQyxLQUFVLEVBQUUsTUFBYztRQUMvQyxNQUFNLGdCQUFnQixHQUFHLG1CQUFtQixDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRXJELE9BQU8sS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO1lBQzNCLDZDQUE2QztZQUM3QyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDMUIsT0FBTyxLQUFLLENBQUM7WUFDZixDQUFDO1lBQ0QsTUFBTSxVQUFVLEdBQUcsbUJBQW1CLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUM3RCxPQUFPLFVBQVUsS0FBSyxnQkFBZ0IsQ0FBQztRQUN6QyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNLLG9CQUFvQixDQUFDLEtBQVUsRUFBRSxZQUFvQjtRQUMzRCxNQUFNLFNBQVMsR0FBRyxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUV6QyxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtZQUMzQixtREFBbUQ7WUFDbkQsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQzNCLE9BQU8sS0FBSyxDQUFDO1lBQ2YsQ0FBQztZQUVELE1BQU0sUUFBUSxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDakQsT0FBTyxRQUFRLElBQUksU0FBUyxDQUFDO1FBQy9CLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0sscUJBQXFCLENBQUMsS0FBVSxFQUFFLGFBQXFCO1FBQzdELE1BQU0sVUFBVSxHQUFHLElBQUksSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRTNDLE9BQU8sS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO1lBQzNCLG1EQUFtRDtZQUNuRCxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDM0IsT0FBTyxLQUFLLENBQUM7WUFDZixDQUFDO1lBRUQsTUFBTSxRQUFRLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNqRCxPQUFPLFFBQVEsSUFBSSxVQUFVLENBQUM7UUFDaEMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxjQUFjLENBQUMsS0FBVSxFQUFFLE1BQTZCO1FBQzlELE9BQU8sS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO1lBQzNCLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUVwQyxJQUFJLE1BQU0sS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDeEIsT0FBTyxVQUFVLEtBQUssYUFBYSxDQUFDLE1BQU0sSUFBSSxVQUFVLEtBQUssYUFBYSxDQUFDLFVBQVUsQ0FBQztZQUN4RixDQUFDO2lCQUFNLElBQUksTUFBTSxLQUFLLFVBQVUsRUFBRSxDQUFDO2dCQUNqQyxPQUFPLENBQ0wsVUFBVSxLQUFLLGFBQWEsQ0FBQyxRQUFRO29CQUNyQyxVQUFVLEtBQUssYUFBYSxDQUFDLFlBQVk7b0JBQ3pDLFVBQVUsS0FBSyxhQUFhLENBQUMsS0FBSztvQkFDbEMsVUFBVSxLQUFLLGFBQWEsQ0FBQyxTQUFTLENBQ3ZDLENBQUM7WUFDSixDQUFDO1lBRUQsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNLLG1CQUFtQixDQUFDLEtBQVUsRUFBRSxtQkFBMkI7UUFDakUsTUFBTSxVQUFVLEdBQUcsbUJBQW1CLENBQUMsbUJBQW1CLENBQUMsQ0FBQztRQUM1RCxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtZQUMzQixNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVc7Z0JBQy9DLENBQUMsQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQztnQkFDaEQsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNQLE9BQU8sZUFBZSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUM5QyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNLLGdCQUFnQixDQUFDLEtBQVUsRUFBRSxRQUFnQjtRQUNuRCxNQUFNLGtCQUFrQixHQUFHLG1CQUFtQixDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3pELE9BQU8sS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO1lBQzNCLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFDN0QsSUFBSSxPQUFPLFlBQVksS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDckMsT0FBTyxLQUFLLENBQUM7WUFDZixDQUFDO1lBQ0QsT0FBTyxtQkFBbUIsQ0FBQyxZQUFZLENBQUMsS0FBSyxrQkFBa0IsQ0FBQztRQUNsRSxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNLLGdCQUFnQixDQUFDLElBQU8sRUFBRSxLQUFhO1FBQzdDLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLElBQUksS0FBSyxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDMUQsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNyQyxDQUFDO1FBQ0QsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLHdCQUF3QixDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDekUsT0FBTyxVQUFVLEVBQUUsS0FBSyxDQUFDO0lBQzNCLENBQUM7SUFFRCwrRUFBK0U7SUFDL0UsNkJBQTZCO0lBQzdCLCtFQUErRTtJQUUvRTs7T0FFRztJQUNLLGdCQUFnQixDQUFDLElBQWEsRUFBRSxTQUFpQjtRQUN2RCxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ3pCLE1BQU0sSUFBSSxLQUFLLENBQUMsR0FBRyxTQUFTLG1CQUFtQixDQUFDLENBQUM7UUFDbkQsQ0FBQztRQUVELElBQUksSUFBSSxDQUFDLE1BQU0sR0FBRyxtQkFBbUIsRUFBRSxDQUFDO1lBQ3RDLE1BQU0sSUFBSSxLQUFLLENBQUMsR0FBRyxTQUFTLHVCQUF1QixtQkFBbUIsT0FBTyxDQUFDLENBQUM7UUFDakYsQ0FBQztRQUVELEtBQUssTUFBTSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7WUFDdkIsSUFBSSxPQUFPLEdBQUcsS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDNUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLFNBQVMsNEJBQTRCLENBQUMsQ0FBQztZQUM1RCxDQUFDO1lBRUQscUNBQXFDO1lBQ3JDLG1CQUFtQixDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzNCLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxtQkFBbUIsQ0FBQyxVQUFrQixFQUFFLFNBQWlCO1FBQy9ELElBQUksT0FBTyxVQUFVLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDbkMsTUFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLFNBQVMsbUJBQW1CLENBQUMsQ0FBQztRQUNuRCxDQUFDO1FBRUQsdUJBQXVCO1FBQ3ZCLE1BQU0sSUFBSSxHQUFHLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBRWxDLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxFQUFFLENBQUM7WUFDMUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLFNBQVMsZ0NBQWdDLENBQUMsQ0FBQztRQUNoRSxDQUFDO1FBRUQseUNBQXlDO1FBQ3pDLCtEQUErRDtRQUMvRCxNQUFNLGNBQWMsR0FBRyx3RUFBd0UsQ0FBQztRQUNoRyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQ3JDLE1BQU0sSUFBSSxLQUFLLENBQUMsR0FBRyxTQUFTLDBEQUEwRCxDQUFDLENBQUM7UUFDMUYsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLDBCQUEwQixDQUFDLFFBQXdCO1FBQ3pELE9BQU87WUFDTCxlQUFlLEVBQUUsUUFBUSxDQUFDLFlBQVksS0FBSyxTQUFTO1lBQ3BELGFBQWEsRUFBRSxRQUFRLENBQUMsSUFBSSxLQUFLLFNBQVMsSUFBSSxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDO1lBQ3RFLGdCQUFnQixFQUFFLFFBQVEsQ0FBQyxPQUFPLEtBQUssU0FBUyxJQUFJLFFBQVEsQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUM7WUFDL0UsZUFBZSxFQUFFLFFBQVEsQ0FBQyxNQUFNLEtBQUssU0FBUztZQUM5QyxxQkFBcUIsRUFBRSxRQUFRLENBQUMsWUFBWSxLQUFLLFNBQVM7WUFDMUQsc0JBQXNCLEVBQUUsUUFBUSxDQUFDLGFBQWEsS0FBSyxTQUFTO1lBQzVELGVBQWUsRUFBRSxRQUFRLENBQUMsTUFBTSxLQUFLLFNBQVM7WUFDOUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxNQUFNO1lBQ3ZCLDRCQUE0QixFQUFFLFFBQVEsQ0FBQyxtQkFBbUIsS0FBSyxTQUFTO1lBQ3hFLGlCQUFpQixFQUFFLFFBQVEsQ0FBQyxRQUFRLEtBQUssU0FBUztTQUNuRCxDQUFDO0lBQ0osQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBGaWx0ZXJTZXJ2aWNlIC0gRWxlbWVudCBmaWx0ZXJpbmcgaW1wbGVtZW50YXRpb25cbiAqXG4gKiBQcm92aWRlcyBzdGF0ZWxlc3MgZmlsdGVyaW5nIGNhcGFiaWxpdGllcyBmb3IgZWxlbWVudCBhcnJheXMgYmFzZWQgb25cbiAqIG1ldGFkYXRhIGFuZCBvdGhlciBjcml0ZXJpYS4gQWxsIGZpbHRlcnMgY29tYmluZSB3aXRoIEFORCBsb2dpYyBleGNlcHRcbiAqIHRhZ3NBbnkgd2hpY2ggdXNlcyBPUiBsb2dpYy5cbiAqXG4gKiBTRUNVUklUWTpcbiAqIC0gQWxsIHN0cmluZyBpbnB1dHMgYXJlIHNhbml0aXplZCB1c2luZyBub3JtYWxpemVTZWFyY2hUZXJtXG4gKiAtIERhdGUgaW5wdXRzIGFyZSB2YWxpZGF0ZWQgYXMgSVNPIDg2MDEgZm9ybWF0XG4gKiAtIFRhZyBhcnJheXMgYXJlIHZhbGlkYXRlZCBhbmQgbGltaXRlZFxuICogLSBNaXNzaW5nIG1ldGFkYXRhIGZpZWxkcyBhcmUgaGFuZGxlZCBncmFjZWZ1bGx5XG4gKiAtIFZhbGlkYXRpb24gZmFpbHVyZXMgYXJlIGxvZ2dlZCB0byBTZWN1cml0eU1vbml0b3JcbiAqXG4gKiBAc2VlIHNyYy9zZXJ2aWNlcy9xdWVyeS90eXBlcy50cyBmb3IgaW50ZXJmYWNlIGRlZmluaXRpb25zXG4gKi9cblxuaW1wb3J0IHsgSUVsZW1lbnQsIEVsZW1lbnRTdGF0dXMgfSBmcm9tICcuLi8uLi90eXBlcy9lbGVtZW50cy9JRWxlbWVudC5qcyc7XG5pbXBvcnQgeyBub3JtYWxpemVTZWFyY2hUZXJtLCB2YWxpZGF0ZVNlYXJjaFF1ZXJ5IH0gZnJvbSAnLi4vLi4vdXRpbHMvc2VhcmNoVXRpbHMuanMnO1xuaW1wb3J0IHsgU2VjdXJpdHlNb25pdG9yIH0gZnJvbSAnLi4vLi4vc2VjdXJpdHkvc2VjdXJpdHlNb25pdG9yLmpzJztcbmltcG9ydCB7IEZpbHRlckNyaXRlcmlhLCBBcHBsaWVkRmlsdGVycywgSUZpbHRlclNlcnZpY2UgfSBmcm9tICcuL3R5cGVzLmpzJztcblxuLyoqXG4gKiBNYXhpbXVtIG51bWJlciBvZiB0YWdzIGFsbG93ZWQgaW4gYSBzaW5nbGUgZmlsdGVyXG4gKiBQcmV2ZW50cyBhcnJheSBtYW5pcHVsYXRpb24gYXR0YWNrcyBhbmQgZXhjZXNzaXZlIHByb2Nlc3NpbmdcbiAqL1xuY29uc3QgTUFYX1RBR1NfUEVSX0ZJTFRFUiA9IDUwO1xuXG4vKipcbiAqIE1heGltdW0gbGVuZ3RoIGZvciBhdXRob3IgZmllbGRcbiAqIFByZXZlbnRzIERvUyB0aHJvdWdoIGV4Y2Vzc2l2ZWx5IGxvbmcgc3RyaW5nc1xuICovXG5jb25zdCBNQVhfQVVUSE9SX0xFTkdUSCA9IDEwMDtcblxuLyoqXG4gKiBNYXhpbXVtIGxlbmd0aCBmb3IgZGVzY3JpcHRpb24gZmlsdGVyXG4gKi9cbmNvbnN0IE1BWF9ERVNDUklQVElPTl9GSUxURVJfTEVOR1RIID0gNTAwO1xuXG4vKipcbiAqIE1heGltdW0gbGVuZ3RoIGZvciBjYXRlZ29yeSBmaWx0ZXJcbiAqL1xuY29uc3QgTUFYX0NBVEVHT1JZX0xFTkdUSCA9IDEwMDtcblxuLyoqXG4gKiBTZXQgb2Yga25vd24gZmlsdGVyIGtleXMgZm9yIHZhbGlkYXRpb25cbiAqL1xuY29uc3QgS05PV05fRklMVEVSX0tFWVMgPSBuZXcgU2V0KFtcbiAgJ25hbWVDb250YWlucycsXG4gICd0YWdzJyxcbiAgJ3RhZ3NBbnknLFxuICAnYXV0aG9yJyxcbiAgJ2NyZWF0ZWRBZnRlcicsXG4gICdjcmVhdGVkQmVmb3JlJyxcbiAgJ3N0YXR1cycsXG4gICdkZXNjcmlwdGlvbkNvbnRhaW5zJyxcbiAgJ2NhdGVnb3J5Jyxcbl0pO1xuXG4vKipcbiAqIEZpbHRlclNlcnZpY2UgaW1wbGVtZW50YXRpb25cbiAqXG4gKiBTdGF0ZWxlc3Mgc2VydmljZSBmb3IgZmlsdGVyaW5nIGVsZW1lbnQgYXJyYXlzLiBTYWZlIGZvciBpbmplY3Rpb25cbiAqIHZpYSBESSBhbmQgY29uY3VycmVudCB1c2UgYWNyb3NzIG11bHRpcGxlIG9wZXJhdGlvbnMuXG4gKlxuICogQHRlbXBsYXRlIFQgLSBFbGVtZW50IHR5cGUgYmVpbmcgZmlsdGVyZWQgKG11c3QgZXh0ZW5kIElFbGVtZW50KVxuICovXG5leHBvcnQgY2xhc3MgRmlsdGVyU2VydmljZTxUIGV4dGVuZHMgSUVsZW1lbnQgPSBJRWxlbWVudD4gaW1wbGVtZW50cyBJRmlsdGVyU2VydmljZTxUPiB7XG4gIC8qKlxuICAgKiBGaWx0ZXIgYW4gYXJyYXkgb2YgZWxlbWVudHMgYmFzZWQgb24gY3JpdGVyaWFcbiAgICpcbiAgICogQWxsIGNyaXRlcmlhIGFyZSBvcHRpb25hbCBhbmQgY29tYmluZWQgd2l0aCBBTkQgbG9naWMgd2hlbiBtdWx0aXBsZVxuICAgKiBmaWx0ZXJzIGFyZSBzcGVjaWZpZWQuIFRoZSBleGNlcHRpb24gaXMgdGFnc0FueSB3aGljaCB1c2VzIE9SIGxvZ2ljXG4gICAqIChlbGVtZW50IG11c3QgaGF2ZSBBTlkgb2YgdGhlIHNwZWNpZmllZCB0YWdzKS5cbiAgICpcbiAgICogRWxlbWVudHMgd2l0aCBtaXNzaW5nIG1ldGFkYXRhIGZpZWxkcyBwYXNzIHRoZSBmaWx0ZXIgaWYgdGhhdCBmaWVsZFxuICAgKiBpcyBub3QgcmVxdWlyZWQgYnkgdGhlIGNyaXRlcmlhIChncmFjZWZ1bCBkZWdyYWRhdGlvbikuXG4gICAqXG4gICAqIEBwYXJhbSBpdGVtcyAtIEFycmF5IG9mIGVsZW1lbnRzIHRvIGZpbHRlclxuICAgKiBAcGFyYW0gY3JpdGVyaWEgLSBGaWx0ZXIgY3JpdGVyaWEgdG8gYXBwbHlcbiAgICogQHJldHVybnMgRmlsdGVyZWQgYXJyYXkgKG1heSBiZSBlbXB0eSBpZiBubyBtYXRjaGVzKVxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgZmlsdGVyIGNyaXRlcmlhIGNvbnRhaW4gaW52YWxpZCB2YWx1ZXNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCBmaWx0ZXJlZCA9IGZpbHRlclNlcnZpY2UuZmlsdGVyKGVsZW1lbnRzLCB7XG4gICAqICAgbmFtZUNvbnRhaW5zOiAnY29kZSByZXZpZXcnLFxuICAgKiAgIHRhZ3M6IFsndHlwZXNjcmlwdCcsICdsaW50aW5nJ10sXG4gICAqICAgc3RhdHVzOiAnYWN0aXZlJ1xuICAgKiB9KTtcbiAgICogYGBgXG4gICAqL1xuICBmaWx0ZXIoaXRlbXM6IFRbXSwgY3JpdGVyaWE/OiBGaWx0ZXJDcml0ZXJpYSk6IFRbXSB7XG4gICAgLy8gTm8gY3JpdGVyaWEgPSBubyBmaWx0ZXJpbmdcbiAgICBpZiAoIWNyaXRlcmlhKSB7XG4gICAgICByZXR1cm4gaXRlbXM7XG4gICAgfVxuXG4gICAgLy8gVmFsaWRhdGUgY3JpdGVyaWEgZmlyc3RcbiAgICB0aGlzLnZhbGlkYXRlQ3JpdGVyaWEoY3JpdGVyaWEpO1xuXG4gICAgLy8gQXBwbHkgZWFjaCBmaWx0ZXIgaW4gc2VxdWVuY2VcbiAgICBsZXQgZmlsdGVyZWQgPSBpdGVtcztcblxuICAgIGlmIChjcml0ZXJpYS5uYW1lQ29udGFpbnMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgZmlsdGVyZWQgPSB0aGlzLmZpbHRlckJ5TmFtZShmaWx0ZXJlZCwgY3JpdGVyaWEubmFtZUNvbnRhaW5zKTtcbiAgICB9XG5cbiAgICBpZiAoY3JpdGVyaWEudGFncyAhPT0gdW5kZWZpbmVkICYmIGNyaXRlcmlhLnRhZ3MubGVuZ3RoID4gMCkge1xuICAgICAgZmlsdGVyZWQgPSB0aGlzLmZpbHRlckJ5VGFncyhmaWx0ZXJlZCwgY3JpdGVyaWEudGFncyk7XG4gICAgfVxuXG4gICAgaWYgKGNyaXRlcmlhLnRhZ3NBbnkgIT09IHVuZGVmaW5lZCAmJiBjcml0ZXJpYS50YWdzQW55Lmxlbmd0aCA+IDApIHtcbiAgICAgIGZpbHRlcmVkID0gdGhpcy5maWx0ZXJCeVRhZ3NBbnkoZmlsdGVyZWQsIGNyaXRlcmlhLnRhZ3NBbnkpO1xuICAgIH1cblxuICAgIGlmIChjcml0ZXJpYS5hdXRob3IgIT09IHVuZGVmaW5lZCkge1xuICAgICAgZmlsdGVyZWQgPSB0aGlzLmZpbHRlckJ5QXV0aG9yKGZpbHRlcmVkLCBjcml0ZXJpYS5hdXRob3IpO1xuICAgIH1cblxuICAgIGlmIChjcml0ZXJpYS5jcmVhdGVkQWZ0ZXIgIT09IHVuZGVmaW5lZCkge1xuICAgICAgZmlsdGVyZWQgPSB0aGlzLmZpbHRlckJ5Q3JlYXRlZEFmdGVyKGZpbHRlcmVkLCBjcml0ZXJpYS5jcmVhdGVkQWZ0ZXIpO1xuICAgIH1cblxuICAgIGlmIChjcml0ZXJpYS5jcmVhdGVkQmVmb3JlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGZpbHRlcmVkID0gdGhpcy5maWx0ZXJCeUNyZWF0ZWRCZWZvcmUoZmlsdGVyZWQsIGNyaXRlcmlhLmNyZWF0ZWRCZWZvcmUpO1xuICAgIH1cblxuICAgIGlmIChjcml0ZXJpYS5zdGF0dXMgIT09IHVuZGVmaW5lZCAmJiBjcml0ZXJpYS5zdGF0dXMgIT09ICdhbGwnKSB7XG4gICAgICBmaWx0ZXJlZCA9IHRoaXMuZmlsdGVyQnlTdGF0dXMoZmlsdGVyZWQsIGNyaXRlcmlhLnN0YXR1cyk7XG4gICAgfVxuXG4gICAgaWYgKGNyaXRlcmlhLmRlc2NyaXB0aW9uQ29udGFpbnMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgZmlsdGVyZWQgPSB0aGlzLmZpbHRlckJ5RGVzY3JpcHRpb24oZmlsdGVyZWQsIGNyaXRlcmlhLmRlc2NyaXB0aW9uQ29udGFpbnMpO1xuICAgIH1cblxuICAgIGlmIChjcml0ZXJpYS5jYXRlZ29yeSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBmaWx0ZXJlZCA9IHRoaXMuZmlsdGVyQnlDYXRlZ29yeShmaWx0ZXJlZCwgY3JpdGVyaWEuY2F0ZWdvcnkpO1xuICAgIH1cblxuICAgIHJldHVybiBmaWx0ZXJlZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZCBhIHN1bW1hcnkgb2Ygd2hpY2ggZmlsdGVycyB3aWxsIGJlIGFwcGxpZWRcbiAgICpcbiAgICogVXNlZnVsIGZvciBsb2dnaW5nIGFuZCBkZWJ1Z2dpbmcgcXVlcnkgZXhlY3V0aW9uLlxuICAgKiBSZXR1cm5zIGEgc2FuaXRpemVkIGNvcHkgb2YgdGhlIGNyaXRlcmlhIHdpdGggY291bnQuXG4gICAqXG4gICAqIEBwYXJhbSBjcml0ZXJpYSAtIEZpbHRlciBjcml0ZXJpYVxuICAgKiBAcmV0dXJucyBTdW1tYXJ5IG9mIGFwcGxpY2FibGUgZmlsdGVyc1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IHN1bW1hcnkgPSBmaWx0ZXJTZXJ2aWNlLnN1bW1hcml6ZUZpbHRlcnMoY3JpdGVyaWEpO1xuICAgKiBsb2dnZXIuZGVidWcoJ0FwcGx5aW5nIGZpbHRlcnMnLCBzdW1tYXJ5KTtcbiAgICogYGBgXG4gICAqL1xuICBzdW1tYXJpemVGaWx0ZXJzKGNyaXRlcmlhPzogRmlsdGVyQ3JpdGVyaWEpOiBBcHBsaWVkRmlsdGVycyB7XG4gICAgY29uc3QgYXBwbGllZDogQXBwbGllZEZpbHRlcnMgPSB7IGNvdW50OiAwIH07XG5cbiAgICBpZiAoIWNyaXRlcmlhKSB7XG4gICAgICByZXR1cm4gYXBwbGllZDtcbiAgICB9XG5cbiAgICBpZiAoY3JpdGVyaWEubmFtZUNvbnRhaW5zICE9PSB1bmRlZmluZWQgJiYgY3JpdGVyaWEubmFtZUNvbnRhaW5zLnRyaW0oKSAhPT0gJycpIHtcbiAgICAgIGFwcGxpZWQubmFtZUNvbnRhaW5zID0gY3JpdGVyaWEubmFtZUNvbnRhaW5zO1xuICAgICAgYXBwbGllZC5jb3VudCsrO1xuICAgIH1cblxuICAgIGlmIChjcml0ZXJpYS50YWdzICE9PSB1bmRlZmluZWQgJiYgY3JpdGVyaWEudGFncy5sZW5ndGggPiAwKSB7XG4gICAgICBhcHBsaWVkLnRhZ3MgPSBbLi4uY3JpdGVyaWEudGFnc107XG4gICAgICBhcHBsaWVkLmNvdW50Kys7XG4gICAgfVxuXG4gICAgaWYgKGNyaXRlcmlhLnRhZ3NBbnkgIT09IHVuZGVmaW5lZCAmJiBjcml0ZXJpYS50YWdzQW55Lmxlbmd0aCA+IDApIHtcbiAgICAgIGFwcGxpZWQudGFnc0FueSA9IFsuLi5jcml0ZXJpYS50YWdzQW55XTtcbiAgICAgIGFwcGxpZWQuY291bnQrKztcbiAgICB9XG5cbiAgICBpZiAoY3JpdGVyaWEuYXV0aG9yICE9PSB1bmRlZmluZWQgJiYgY3JpdGVyaWEuYXV0aG9yLnRyaW0oKSAhPT0gJycpIHtcbiAgICAgIGFwcGxpZWQuYXV0aG9yID0gY3JpdGVyaWEuYXV0aG9yO1xuICAgICAgYXBwbGllZC5jb3VudCsrO1xuICAgIH1cblxuICAgIGlmIChjcml0ZXJpYS5jcmVhdGVkQWZ0ZXIgIT09IHVuZGVmaW5lZCkge1xuICAgICAgYXBwbGllZC5jcmVhdGVkQWZ0ZXIgPSBjcml0ZXJpYS5jcmVhdGVkQWZ0ZXI7XG4gICAgICBhcHBsaWVkLmNvdW50Kys7XG4gICAgfVxuXG4gICAgaWYgKGNyaXRlcmlhLmNyZWF0ZWRCZWZvcmUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgYXBwbGllZC5jcmVhdGVkQmVmb3JlID0gY3JpdGVyaWEuY3JlYXRlZEJlZm9yZTtcbiAgICAgIGFwcGxpZWQuY291bnQrKztcbiAgICB9XG5cbiAgICBpZiAoY3JpdGVyaWEuc3RhdHVzICE9PSB1bmRlZmluZWQgJiYgY3JpdGVyaWEuc3RhdHVzICE9PSAnYWxsJykge1xuICAgICAgYXBwbGllZC5zdGF0dXMgPSBjcml0ZXJpYS5zdGF0dXM7XG4gICAgICBhcHBsaWVkLmNvdW50Kys7XG4gICAgfVxuXG4gICAgaWYgKGNyaXRlcmlhLmRlc2NyaXB0aW9uQ29udGFpbnMgIT09IHVuZGVmaW5lZCAmJiBjcml0ZXJpYS5kZXNjcmlwdGlvbkNvbnRhaW5zLnRyaW0oKSAhPT0gJycpIHtcbiAgICAgIGFwcGxpZWQuZGVzY3JpcHRpb25Db250YWlucyA9IGNyaXRlcmlhLmRlc2NyaXB0aW9uQ29udGFpbnM7XG4gICAgICBhcHBsaWVkLmNvdW50Kys7XG4gICAgfVxuXG4gICAgaWYgKGNyaXRlcmlhLmNhdGVnb3J5ICE9PSB1bmRlZmluZWQgJiYgY3JpdGVyaWEuY2F0ZWdvcnkudHJpbSgpICE9PSAnJykge1xuICAgICAgYXBwbGllZC5jYXRlZ29yeSA9IGNyaXRlcmlhLmNhdGVnb3J5O1xuICAgICAgYXBwbGllZC5jb3VudCsrO1xuICAgIH1cblxuICAgIHJldHVybiBhcHBsaWVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGZpbHRlciBjcml0ZXJpYSB3aXRob3V0IGFwcGx5aW5nIHRoZW1cbiAgICpcbiAgICogQ2hlY2tzIGFsbCBjcml0ZXJpYSBmb3I6XG4gICAqIC0gVmFsaWQgc3RyaW5nIGxlbmd0aHNcbiAgICogLSBWYWxpZCBkYXRlIGZvcm1hdHNcbiAgICogLSBWYWxpZCB0YWcgYXJyYXlzXG4gICAqIC0gVmFsaWQgc3RhdHVzIHZhbHVlc1xuICAgKlxuICAgKiBMb2dzIHNlY3VyaXR5IGV2ZW50cyBmb3IgdmFsaWRhdGlvbiBmYWlsdXJlcy5cbiAgICpcbiAgICogQHBhcmFtIGNyaXRlcmlhIC0gRmlsdGVyIGNyaXRlcmlhIHRvIHZhbGlkYXRlXG4gICAqIEByZXR1cm5zIFRydWUgaWYgY3JpdGVyaWEgYXJlIHZhbGlkXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiBjcml0ZXJpYSBhcmUgaW52YWxpZCB3aXRoIGRlc2NyaXB0aXZlIG1lc3NhZ2VcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiB0cnkge1xuICAgKiAgIGZpbHRlclNlcnZpY2UudmFsaWRhdGVDcml0ZXJpYSh1c2VySW5wdXQpO1xuICAgKiB9IGNhdGNoIChlcnJvcikge1xuICAgKiAgIGxvZ2dlci5lcnJvcignSW52YWxpZCBmaWx0ZXIgY3JpdGVyaWEnLCBlcnJvcik7XG4gICAqIH1cbiAgICogYGBgXG4gICAqL1xuICB2YWxpZGF0ZUNyaXRlcmlhKGNyaXRlcmlhPzogRmlsdGVyQ3JpdGVyaWEpOiBib29sZWFuIHtcbiAgICBpZiAoIWNyaXRlcmlhKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgLy8gUmVqZWN0IHVua25vd24gZmlsdGVyIGtleXNcbiAgICAgIGNvbnN0IHVua25vd25LZXlzID0gT2JqZWN0LmtleXMoY3JpdGVyaWEpLmZpbHRlcihrZXkgPT4gIUtOT1dOX0ZJTFRFUl9LRVlTLmhhcyhrZXkpKTtcbiAgICAgIGlmICh1bmtub3duS2V5cy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IHN1cHBvcnRlZCA9IFsuLi5LTk9XTl9GSUxURVJfS0VZU10uc29ydCgoYSwgYikgPT4gYS5sb2NhbGVDb21wYXJlKGIpKS5qb2luKCcsICcpO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYFVua25vd24gZmlsdGVyIGtleShzKTogJHt1bmtub3duS2V5cy5qb2luKCcsICcpfS4gU3VwcG9ydGVkIGZpbHRlcnM6ICR7c3VwcG9ydGVkfWBcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgLy8gVmFsaWRhdGUgbmFtZUNvbnRhaW5zXG4gICAgICBpZiAoY3JpdGVyaWEubmFtZUNvbnRhaW5zICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBjcml0ZXJpYS5uYW1lQ29udGFpbnMgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCduYW1lQ29udGFpbnMgbXVzdCBiZSBhIHN0cmluZycpO1xuICAgICAgICB9XG4gICAgICAgIC8vIFVzZSB2YWxpZGF0ZVNlYXJjaFF1ZXJ5IHdoaWNoIGFsc28gc2FuaXRpemVzXG4gICAgICAgIHZhbGlkYXRlU2VhcmNoUXVlcnkoY3JpdGVyaWEubmFtZUNvbnRhaW5zKTtcbiAgICAgIH1cblxuICAgICAgLy8gVmFsaWRhdGUgdGFncyAoQU5EIGxvZ2ljKVxuICAgICAgaWYgKGNyaXRlcmlhLnRhZ3MgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aGlzLnZhbGlkYXRlVGFnQXJyYXkoY3JpdGVyaWEudGFncywgJ3RhZ3MnKTtcbiAgICAgIH1cblxuICAgICAgLy8gVmFsaWRhdGUgdGFnc0FueSAoT1IgbG9naWMpXG4gICAgICBpZiAoY3JpdGVyaWEudGFnc0FueSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRoaXMudmFsaWRhdGVUYWdBcnJheShjcml0ZXJpYS50YWdzQW55LCAndGFnc0FueScpO1xuICAgICAgfVxuXG4gICAgICAvLyBWYWxpZGF0ZSBhdXRob3JcbiAgICAgIGlmIChjcml0ZXJpYS5hdXRob3IgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBpZiAodHlwZW9mIGNyaXRlcmlhLmF1dGhvciAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2F1dGhvciBtdXN0IGJlIGEgc3RyaW5nJyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNyaXRlcmlhLmF1dGhvci5sZW5ndGggPiBNQVhfQVVUSE9SX0xFTkdUSCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgYXV0aG9yIGV4Y2VlZHMgbWF4aW11bSBsZW5ndGggb2YgJHtNQVhfQVVUSE9SX0xFTkdUSH0gY2hhcmFjdGVyc2ApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIFZhbGlkYXRlIGRhdGVzXG4gICAgICBpZiAoY3JpdGVyaWEuY3JlYXRlZEFmdGVyICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy52YWxpZGF0ZUlTTzg2MDFEYXRlKGNyaXRlcmlhLmNyZWF0ZWRBZnRlciwgJ2NyZWF0ZWRBZnRlcicpO1xuICAgICAgfVxuXG4gICAgICBpZiAoY3JpdGVyaWEuY3JlYXRlZEJlZm9yZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRoaXMudmFsaWRhdGVJU084NjAxRGF0ZShjcml0ZXJpYS5jcmVhdGVkQmVmb3JlLCAnY3JlYXRlZEJlZm9yZScpO1xuICAgICAgfVxuXG4gICAgICAvLyBWYWxpZGF0ZSBzdGF0dXNcbiAgICAgIGlmIChjcml0ZXJpYS5zdGF0dXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb25zdCB2YWxpZFN0YXR1c2VzID0gWydhY3RpdmUnLCAnaW5hY3RpdmUnLCAnYWxsJ107XG4gICAgICAgIGlmICghdmFsaWRTdGF0dXNlcy5pbmNsdWRlcyhjcml0ZXJpYS5zdGF0dXMpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBzdGF0dXMgbXVzdCBiZSBvbmUgb2Y6ICR7dmFsaWRTdGF0dXNlcy5qb2luKCcsICcpfWApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIFZhbGlkYXRlIGRlc2NyaXB0aW9uQ29udGFpbnNcbiAgICAgIGlmIChjcml0ZXJpYS5kZXNjcmlwdGlvbkNvbnRhaW5zICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBjcml0ZXJpYS5kZXNjcmlwdGlvbkNvbnRhaW5zICE9PSAnc3RyaW5nJykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZGVzY3JpcHRpb25Db250YWlucyBtdXN0IGJlIGEgc3RyaW5nJyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNyaXRlcmlhLmRlc2NyaXB0aW9uQ29udGFpbnMubGVuZ3RoID4gTUFYX0RFU0NSSVBUSU9OX0ZJTFRFUl9MRU5HVEgpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGRlc2NyaXB0aW9uQ29udGFpbnMgZXhjZWVkcyBtYXhpbXVtIGxlbmd0aCBvZiAke01BWF9ERVNDUklQVElPTl9GSUxURVJfTEVOR1RIfSBjaGFyYWN0ZXJzYCk7XG4gICAgICAgIH1cbiAgICAgICAgdmFsaWRhdGVTZWFyY2hRdWVyeShjcml0ZXJpYS5kZXNjcmlwdGlvbkNvbnRhaW5zKTtcbiAgICAgIH1cblxuICAgICAgLy8gVmFsaWRhdGUgY2F0ZWdvcnlcbiAgICAgIGlmIChjcml0ZXJpYS5jYXRlZ29yeSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGlmICh0eXBlb2YgY3JpdGVyaWEuY2F0ZWdvcnkgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdjYXRlZ29yeSBtdXN0IGJlIGEgc3RyaW5nJyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNyaXRlcmlhLmNhdGVnb3J5Lmxlbmd0aCA+IE1BWF9DQVRFR09SWV9MRU5HVEgpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGNhdGVnb3J5IGV4Y2VlZHMgbWF4aW11bSBsZW5ndGggb2YgJHtNQVhfQ0FURUdPUllfTEVOR1RIfSBjaGFyYWN0ZXJzYCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIC8vIExvZyB2YWxpZGF0aW9uIGZhaWx1cmUgYXMgc2VjdXJpdHkgZXZlbnRcbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogJ1VOSUNPREVfVkFMSURBVElPTl9FUlJPUicsXG4gICAgICAgIHNldmVyaXR5OiAnTUVESVVNJyxcbiAgICAgICAgc291cmNlOiAnRmlsdGVyU2VydmljZS52YWxpZGF0ZUNyaXRlcmlhJyxcbiAgICAgICAgZGV0YWlsczogYEZpbHRlciBjcml0ZXJpYSB2YWxpZGF0aW9uIGZhaWxlZDogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YCxcbiAgICAgICAgYWRkaXRpb25hbERhdGE6IHtcbiAgICAgICAgICBjcml0ZXJpYTogdGhpcy5zYW5pdGl6ZUNyaXRlcmlhRm9yTG9nZ2luZyhjcml0ZXJpYSksXG4gICAgICAgIH0s