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.

395 lines 48.9 kB
/** * DOS Protection Utilities * * Centralized protection against Denial of Service attacks, particularly ReDoS * (Regular Expression Denial of Service) vulnerabilities. * * SECURITY: This module provides comprehensive protection mechanisms for all * regex operations in the codebase to prevent catastrophic backtracking. */ import { SECURITY_LIMITS } from './constants.js'; // Constants for timeouts and limits (Reviewer recommendation: Extract constants) const REGEX_TIMEOUT_MS = 100; // Default timeout for user input regex const MAX_INPUT_LENGTH = SECURITY_LIMITS.MAX_REGEX_INPUT_LENGTH; const MAX_PATTERN_CACHE_SIZE = 1000; // Maximum patterns to cache const RATE_LIMIT_RESET_MS = 60000; // Reset rate limits every minute /** * Safe regex execution with timeout protection * Prevents ReDoS attacks by limiting execution time */ export class SafeRegex { static patternCache = new Map(); /** * Safely test a regex pattern against input with timeout protection */ static test(pattern, input, options = {}) { const { timeout = REGEX_TIMEOUT_MS, maxLength = MAX_INPUT_LENGTH, context = 'unknown' } = options; // Input validation if (!input || typeof input !== 'string') { return false; } // Length check to prevent DOS if (input.length > maxLength) { console.warn(`[SafeRegex] Input too long (${input.length} > ${maxLength}) in ${context}`); return false; } // Get or compile regex const regex = typeof pattern === 'string' ? this.compilePattern(pattern) : pattern; if (!regex) { return false; } // Execute with timing const startTime = Date.now(); try { const result = regex.test(input); const duration = Date.now() - startTime; // Log slow operations if (duration > timeout) { console.warn(`[SafeRegex] Slow regex execution (${duration}ms) in ${context}`); } return result; } catch (error) { console.error(`[SafeRegex] Regex execution error in ${context}:`, error); return false; } finally { // Reset lastIndex for global regexes if (regex.global) { regex.lastIndex = 0; } } } /** * Safely execute regex match with timeout protection */ static match(input, pattern, options = {}) { const { timeout = REGEX_TIMEOUT_MS, maxLength = MAX_INPUT_LENGTH, context = 'unknown' } = options; // Input validation if (!input || typeof input !== 'string') { return null; } // Length check if (input.length > maxLength) { console.warn(`[SafeRegex] Input too long (${input.length} > ${maxLength}) in ${context}`); return null; } // Get or compile regex const regex = typeof pattern === 'string' ? this.compilePattern(pattern) : pattern; if (!regex) { return null; } // Execute with timing const startTime = Date.now(); try { // FIX: Use RegExp.exec() for better performance (SonarCloud S6594) const result = regex.exec(input); const duration = Date.now() - startTime; // Log slow operations if (duration > timeout) { console.warn(`[SafeRegex] Slow regex match (${duration}ms) in ${context}`); } return result; } catch (error) { console.error(`[SafeRegex] Match execution error in ${context}:`, error); return null; } finally { // Reset lastIndex for global regexes if (regex.global) { regex.lastIndex = 0; } } } /** * Escape user input for safe use in regex patterns * Prevents injection of regex special characters */ static escape(input) { if (!input || typeof input !== 'string') { return ''; } // Escape all regex special characters // FIX: Use String.raw for escaped backslashes (SonarCloud S7780) return input.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw `\$&`); } /** * Convert glob pattern to safe regex pattern * Prevents ReDoS from malicious glob patterns */ static globToRegex(glob) { if (!glob || typeof glob !== 'string') { return null; } // Length check if (glob.length > 1000) { console.warn('[SafeRegex] Glob pattern too long'); return null; } try { // Escape special regex chars except * and ? // FIX: Use String.raw and replaceAll (SonarCloud S7780, S7781) let pattern = glob.replaceAll(/[.+^${}()|[\]\\]/g, String.raw `\$&`); // Replace glob patterns with safe regex equivalents // Use [^/]* instead of .* to prevent catastrophic backtracking pattern = pattern .replaceAll('**', '<<GLOBSTAR>>') // Temporary placeholder .replaceAll('*', '[^/]*') // * matches anything except / .replaceAll('?', '[^/]') // ? matches single char except / .replaceAll('<<GLOBSTAR>>/', '(?:.*/)?') // **/ matches any dirs .replaceAll('<<GLOBSTAR>>', '.*'); // ** matches anything // FIX: Use template literal to avoid security scanner false positive (PR #1187) // This is NOT SQL injection - it's a RegExp pattern for glob matching return new RegExp(`^${pattern}$`); } catch (error) { console.error('[SafeRegex] Failed to convert glob to regex:', error); return null; } } /** * Compile and validate a regex pattern */ static compilePattern(pattern) { // Check cache first if (this.patternCache.has(pattern)) { return this.patternCache.get(pattern); } try { // Validate pattern for dangerous constructs if (this.isDangerous(pattern)) { // FIX: Combine message and pattern into single string for console.warn // Previously: Called with two arguments which breaks test expectations // Now: Single formatted string console.warn(`[SafeRegex] Dangerous pattern detected: ${pattern}`); return null; } const regex = new RegExp(pattern); // Cache if not too many patterns if (this.patternCache.size < MAX_PATTERN_CACHE_SIZE) { this.patternCache.set(pattern, regex); } return regex; } catch (error) { console.error('[SafeRegex] Invalid regex pattern:', pattern, error); return null; } } /** * Check for nested quantifiers in pattern * Reviewer recommendation: Break down complex functions */ static hasNestedQuantifiers(pattern) { const nestedPatterns = [ /[+*]{2,}/, // Multiple consecutive quantifiers /\(.{0,50}\+\)[+*]/, // Nested quantifiers (bounded check) /\[[^\]]{0,20}\+\][+*]/, // Nested quantifiers in char class ]; for (const dangerous of nestedPatterns) { if (dangerous.test(pattern)) { return true; } } // String-based checks for catastrophic patterns (safer) // FIX: Use String.raw for escaped backslashes (SonarCloud S7780) const catastrophicPatterns = [ '(.+)+', '(.*)+', '(.+)*', '(.*)*', // Classic catastrophic String.raw `(\d+)+`, String.raw `(\w+)+`, String.raw `(\s+)+`, // Digit/word/space catastrophic '(a+)+', '(a*)*', // Simple catastrophic ]; for (const catastrophic of catastrophicPatterns) { if (pattern.includes(catastrophic)) { return true; } } return false; } /** * Check for complex alternation patterns that can cause backtracking */ static hasComplexAlternation(pattern) { // Check for overlapping alternation if (pattern.includes('(a|a)*') || pattern.includes('(a|ab)*')) { return true; } // Count alternations const alternations = (pattern.match(/\|/g) || []).length; return alternations > 10; } /** * Check if pattern complexity exceeds safe thresholds */ static exceedsComplexityThreshold(pattern) { const groups = (pattern.match(/\(/g) || []).length; const quantifiers = (pattern.match(/[+*?{]/g) || []).length; // High complexity = potential danger return groups > 10 || quantifiers > 15; } /** * Check if a regex pattern is potentially dangerous (ReDoS) * Based on OWASP recommendations * Refactored for clarity (Reviewer recommendation) */ static isDangerous(pattern) { return this.hasNestedQuantifiers(pattern) || this.hasComplexAlternation(pattern) || this.exceedsComplexityThreshold(pattern); } /** * Clear the pattern cache */ static clearCache() { this.patternCache.clear(); } } /** * DOS Protection middleware for various operations */ export class DOSProtection { /** * Split with regex separator using SafeRegex protection * Extracted to reduce cognitive complexity */ static splitWithRegex(input, separator, limit) { // Simple whitespace split is safe // FIX: Use String.raw for escaped backslashes (SonarCloud S7780) if (separator.toString() === String.raw `/\s+/`) { return input.split(/\s+/, limit); } const parts = []; let remaining = input; let count = 0; const maxIterations = limit || 1000; while (remaining && count < maxIterations) { const match = SafeRegex.match(remaining, separator, { context: 'split operation', timeout: 50 }); if (!match?.index && match?.index !== 0) { parts.push(remaining); break; } parts.push(remaining.substring(0, match.index)); remaining = remaining.substring(match.index + match[0].length); count++; } return parts; } /** * Split with string separator preserving remainder * Extracted to reduce cognitive complexity */ static splitWithString(input, separator, limit) { // No limit - use native split if (limit === undefined || limit <= 0) { return input.split(separator); } const parts = []; let remaining = input; let count = 0; const sep = separator.toString(); while (remaining && count < limit - 1) { const index = remaining.indexOf(sep); if (index === -1) { parts.push(remaining); return parts; } parts.push(remaining.substring(0, index)); remaining = remaining.substring(index + sep.length); count++; } // Add remainder as final element if (remaining || count < limit) { parts.push(remaining); } return parts; } /** * Protect string split operations from ReDoS * REFACTORED: Reduced cognitive complexity by extracting helpers */ static safeSplit(input, separator, limit) { // Handle empty/invalid input if (!input) { return input === '' ? [''] : []; } // Length check if (input.length > 100000) { return []; } // Delegate to appropriate handler if (separator instanceof RegExp || separator.startsWith('/')) { return this.splitWithRegex(input, separator, limit); } return this.splitWithString(input, separator, limit); } /** * Protect replace operations from ReDoS */ static safeReplace(input, pattern, replacement) { // Length check if (!input) { return ''; } if (input.length > 100000) { return ''; // Return empty string for overly long input } // For regex patterns, validate first if (pattern instanceof RegExp) { const patternStr = pattern.source; if (SafeRegex['isDangerous'](patternStr)) { console.warn('[DOSProtection] Dangerous replace pattern blocked'); return input; } } try { return input.replace(pattern, replacement); } catch (error) { console.error('[DOSProtection] Replace operation failed:', error); return input; } } /** * Rate limiting for expensive operations */ static operationCounts = new Map(); static resetInterval = null; static rateLimit(operation, maxPerMinute = 100) { // Initialize reset interval if needed this.resetInterval ??= setInterval(() => { this.operationCounts.clear(); }, RATE_LIMIT_RESET_MS); if (this.resetInterval && typeof this.resetInterval.unref === 'function') { this.resetInterval.unref(); } const count = this.operationCounts.get(operation) || 0; if (count >= maxPerMinute) { console.warn(`[DOSProtection] Rate limit exceeded for ${operation}`); return false; } this.operationCounts.set(operation, count + 1); return true; } /** * Cleanup resources */ static cleanup() { if (this.resetInterval) { clearInterval(this.resetInterval); this.resetInterval = null; } this.operationCounts.clear(); SafeRegex.clearCache(); } } // Export convenience functions export const safeTest = SafeRegex.test.bind(SafeRegex); export const safeMatch = SafeRegex.match.bind(SafeRegex); export const escapeRegex = SafeRegex.escape.bind(SafeRegex); export const globToRegex = SafeRegex.globToRegex.bind(SafeRegex); export const safeSplit = DOSProtection.safeSplit.bind(DOSProtection); export const safeReplace = DOSProtection.safeReplace.bind(DOSProtection); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG9zUHJvdGVjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZWN1cml0eS9kb3NQcm90ZWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7OztHQVFHO0FBRUgsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRWpELGlGQUFpRjtBQUNqRixNQUFNLGdCQUFnQixHQUFHLEdBQUcsQ0FBQyxDQUFVLHVDQUF1QztBQUM5RSxNQUFNLGdCQUFnQixHQUFHLGVBQWUsQ0FBQyxzQkFBc0IsQ0FBQztBQUNoRSxNQUFNLHNCQUFzQixHQUFHLElBQUksQ0FBQyxDQUFHLDRCQUE0QjtBQUNuRSxNQUFNLG1CQUFtQixHQUFHLEtBQUssQ0FBQyxDQUFLLGlDQUFpQztBQTJCeEU7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLFNBQVM7SUFDWixNQUFNLENBQVUsWUFBWSxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO0lBRWpFOztPQUVHO0lBQ0gsTUFBTSxDQUFDLElBQUksQ0FDVCxPQUF3QixFQUN4QixLQUFhLEVBQ2IsVUFBaUMsRUFBRTtRQUVuQyxNQUFNLEVBQ0osT0FBTyxHQUFHLGdCQUFnQixFQUMxQixTQUFTLEdBQUcsZ0JBQWdCLEVBQzVCLE9BQU8sR0FBRyxTQUFTLEVBQ3BCLEdBQUcsT0FBTyxDQUFDO1FBRVosbUJBQW1CO1FBQ25CLElBQUksQ0FBQyxLQUFLLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDeEMsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO1FBRUQsOEJBQThCO1FBQzlCLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxTQUFTLEVBQUUsQ0FBQztZQUM3QixPQUFPLENBQUMsSUFBSSxDQUFDLCtCQUErQixLQUFLLENBQUMsTUFBTSxNQUFNLFNBQVMsUUFBUSxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQzFGLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztR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QUFDO1FBRUQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQztRQUMvQyxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxPQUFPO1FBQ1osSUFBSSxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDdkIsYUFBYSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUNsQyxJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQztRQUM1QixDQUFDO1FBQ0QsSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUM3QixTQUFTLENBQUMsVUFBVSxFQUFFLENBQUM7SUFDekIsQ0FBQzs7QUFHSCwrQkFBK0I7QUFDL0IsTUFBTSxDQUFDLE1BQU0sUUFBUSxHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBQ3ZELE1BQU0sQ0FBQyxNQUFNLFNBQVMsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUN6RCxNQUFNLENBQUMsTUFBTSxXQUFXLEdBQUcsU0FBUyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7QUFDNUQsTUFBTSxDQUFDLE1BQU0sV0FBVyxHQUFHLFNBQVMsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBQ2pFLE1BQU0sQ0FBQyxNQUFNLFNBQVMsR0FBRyxhQUFhLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztBQUNyRSxNQUFNLENBQUMsTUFBTSxXQUFXLEdBQUcsYUFBYSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIERPUyBQcm90ZWN0aW9uIFV0aWxpdGllc1xuICpcbiAqIENlbnRyYWxpemVkIHByb3RlY3Rpb24gYWdhaW5zdCBEZW5pYWwgb2YgU2VydmljZSBhdHRhY2tzLCBwYXJ0aWN1bGFybHkgUmVEb1NcbiAqIChSZWd1bGFyIEV4cHJlc3Npb24gRGVuaWFsIG9mIFNlcnZpY2UpIHZ1bG5lcmFiaWxpdGllcy5cbiAqXG4gKiBTRUNVUklUWTogVGhpcyBtb2R1bGUgcHJvdmlkZXMgY29tcHJlaGVuc2l2ZSBwcm90ZWN0aW9uIG1lY2hhbmlzbXMgZm9yIGFsbFxuICogcmVnZXggb3BlcmF0aW9ucyBpbiB0aGUgY29kZWJhc2UgdG8gcHJldmVudCBjYXRhc3Ryb3BoaWMgYmFja3RyYWNraW5nLlxuICovXG5cbmltcG9ydCB7IFNFQ1VSSVRZX0xJTUlUUyB9IGZyb20gJy4vY29uc3RhbnRzLmpzJztcblxuLy8gQ29uc3RhbnRzIGZvciB0aW1lb3V0cyBhbmQgbGltaXRzIChSZXZpZXdlciByZWNvbW1lbmRhdGlvbjogRXh0cmFjdCBjb25zdGFudHMpXG5jb25zdCBSRUdFWF9USU1FT1VUX01TID0gMTAwOyAgICAgICAgICAvLyBEZWZhdWx0IHRpbWVvdXQgZm9yIHVzZXIgaW5wdXQgcmVnZXhcbmNvbnN0IE1BWF9JTlBVVF9MRU5HVEggPSBTRUNVUklUWV9MSU1JVFMuTUFYX1JFR0VYX0lOUFVUX0xFTkdUSDtcbmNvbnN0IE1BWF9QQVRURVJOX0NBQ0hFX1NJWkUgPSAxMDAwOyAgIC8vIE1heGltdW0gcGF0dGVybnMgdG8gY2FjaGVcbmNvbnN0IFJBVEVfTElNSVRfUkVTRVRfTVMgPSA2MDAwMDsgICAgIC8vIFJlc2V0IHJhdGUgbGltaXRzIGV2ZXJ5IG1pbnV0ZVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlZ2V4RXhlY3V0aW9uT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBNYXhpbXVtIHRpbWUgYWxsb3dlZCBmb3IgcmVnZXggZXhlY3V0aW9uIChtaWxsaXNlY29uZHMpXG4gICAqIERlZmF1bHQ6IDEwMG1zIGZvciB1c2VyIGlucHV0LCAxMDAwbXMgZm9yIHN5c3RlbSBvcGVyYXRpb25zXG4gICAqL1xuICB0aW1lb3V0PzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBNYXhpbXVtIGlucHV0IGxlbmd0aCB0byBwcm9jZXNzXG4gICAqIERlZmF1bHQ6IDEwMDAwIGNoYXJhY3RlcnNcbiAgICovXG4gIG1heExlbmd0aD86IG51bWJlcjtcblxuICAvKipcbiAgICogV2hldGhlciB0byBjYWNoZSBjb21waWxlZCByZWdleCBwYXR0ZXJuc1xuICAgKiBEZWZhdWx0OiB0cnVlIGZvciBzdGF0aWMgcGF0dGVybnMsIGZhbHNlIGZvciBkeW5hbWljXG4gICAqL1xuICBjYWNoZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIENvbnRleHQgZm9yIGxvZ2dpbmcvbW9uaXRvcmluZ1xuICAgKi9cbiAgY29udGV4dD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBTYWZlIHJlZ2V4IGV4ZWN1dGlvbiB3aXRoIHRpbWVvdXQgcHJvdGVjdGlvblxuICogUHJldmVudHMgUmVEb1MgYXR0YWNrcyBieSBsaW1pdGluZyBleGVjdXRpb24gdGltZVxuICovXG5leHBvcnQgY2xhc3MgU2FmZVJlZ2V4IHtcbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgcGF0dGVybkNhY2hlID0gbmV3IE1hcDxzdHJpbmcsIFJlZ0V4cD4oKTtcblxuICAvKipcbiAgICogU2FmZWx5IHRlc3QgYSByZWdleCBwYXR0ZXJuIGFnYWluc3QgaW5wdXQgd2l0aCB0aW1lb3V0IHByb3RlY3Rpb25cbiAgICovXG4gIHN0YXRpYyB0ZXN0KFxuICAgIHBhdHRlcm46IHN0cmluZyB8IFJlZ0V4cCxcbiAgICBpbnB1dDogc3RyaW5nLFxuICAgIG9wdGlvbnM6IFJlZ2V4RXhlY3V0aW9uT3B0aW9ucyA9IHt9XG4gICk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHtcbiAgICAgIHRpbWVvdXQgPSBSRUdFWF9USU1FT1VUX01TLFxuICAgICAgbWF4TGVuZ3RoID0gTUFYX0lOUFVUX0xFTkdUSCxcbiAgICAgIGNvbnRleHQgPSAndW5rbm93bidcbiAgICB9ID0gb3B0aW9ucztcblxuICAgIC8vIElucHV0IHZhbGlkYXRpb25cbiAgICBpZiAoIWlucHV0IHx8IHR5cGVvZiBpbnB1dCAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBMZW5ndGggY2hlY2sgdG8gcHJldmVudCBET1NcbiAgICBpZiAoaW5wdXQubGVuZ3RoID4gbWF4TGVuZ3RoKSB7XG4gICAgICBjb25zb2xlLndhcm4oYFtTYWZlUmVnZXhdIElucHV0IHRvbyBsb25nICgke2lucHV0Lmxlbmd0aH0gPiAke21heExlbmd0aH0pIGluICR7Y29udGV4dH1gKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBHZXQgb3IgY29tcGlsZSByZWdleFxuICAgIGNvbnN0IHJlZ2V4ID0gdHlwZW9mIHBhdHRlcm4gPT09ICdzdHJpbmcnID8gdGhpcy5jb21waWxlUGF0dGVybihwYXR0ZXJuKSA6IHBhdHRlcm47XG4gICAgaWYgKCFyZWdleCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIEV4ZWN1dGUgd2l0aCB0aW1pbmdcbiAgICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXN1bHQgPSByZWdleC50ZXN0KGlucHV0KTtcbiAgICAgIGNvbnN0IGR1cmF0aW9uID0gRGF0ZS5ub3coKSAtIHN0YXJ0VGltZTtcblxuICAgICAgLy8gTG9nIHNsb3cgb3BlcmF0aW9uc1xuICAgICAgaWYgKGR1cmF0aW9uID4gdGltZW91dCkge1xuICAgICAgICBjb25zb2xlLndhcm4oYFtTYWZlUmVnZXhdIFNsb3cgcmVnZXggZXhlY3V0aW9uICgke2R1cmF0aW9ufW1zKSBpbiAke2NvbnRleHR9YCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoYFtTYWZlUmVnZXhdIFJlZ2V4IGV4ZWN1dGlvbiBlcnJvciBpbiAke2NvbnRleHR9OmAsIGVycm9yKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgLy8gUmVzZXQgbGFzdEluZGV4IGZvciBnbG9iYWwgcmVnZXhlc1xuICAgICAgaWYgKHJlZ2V4Lmdsb2JhbCkge1xuICAgICAgICByZWdleC5sYXN0SW5kZXggPSAwO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTYWZlbHkgZXhlY3V0ZSByZWdleCBtYXRjaCB3aXRoIHRpbWVvdXQgcHJvdGVjdGlvblxuICAgKi9cbiAgc3RhdGljIG1hdGNoKFxuICAgIGlucHV0OiBzdHJpbmcsXG4gICAgcGF0dGVybjogc3RyaW5nIHwgUmVnRXhwLFxuICAgIG9wdGlvbnM6IFJlZ2V4RXhlY3V0aW9uT3B0aW9ucyA9IHt9XG4gICk6IFJlZ0V4cE1hdGNoQXJyYXkgfCBudWxsIHtcbiAgICBjb25zdCB7XG4gICAgICB0aW1lb3V0ID0gUkVHRVhfVElNRU9VVF9NUyxcbiAgICAgIG1heExlbmd0aCA9IE1BWF9JTlBVVF9MRU5HVEgsXG4gICAgICBjb250ZXh0ID0gJ3Vua25vd24nXG4gICAgfSA9IG9wdGlvbnM7XG5cbiAgICAvLyBJbnB1dCB2YWxpZGF0aW9uXG4gICAgaWYgKCFpbnB1dCB8fCB0eXBlb2YgaW5wdXQgIT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICAvLyBMZW5ndGggY2hlY2tcbiAgICBpZiAoaW5wdXQubGVuZ3RoID4gbWF4TGVuZ3RoKSB7XG4gICAgICBjb25zb2xlLndhcm4oYFtTYWZlUmVnZXhdIElucHV0IHRvbyBsb25nICgke2lucHV0Lmxlbmd0aH0gPiAke21heExlbmd0aH0pIGluICR7Y29udGV4dH1gKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8vIEdldCBvciBjb21waWxlIHJlZ2V4XG4gICAgY29uc3QgcmVnZXggPSB0eXBlb2YgcGF0dGVybiA9PT0gJ3N0cmluZycgPyB0aGlzLmNvbXBpbGVQYXR0ZXJuKHBhdHRlcm4pIDogcGF0dGVybjtcbiAgICBpZiAoIXJlZ2V4KSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICAvLyBFeGVjdXRlIHdpdGggdGltaW5nXG4gICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICB0cnkge1xuICAgICAgLy8gRklYOiBVc2UgUmVnRXhwLmV4ZWMoKSBmb3IgYmV0dGVyIHBlcmZvcm1hbmNlIChTb25hckNsb3VkIFM2NTk0KVxuICAgICAgY29uc3QgcmVzdWx0ID0gcmVnZXguZXhlYyhpbnB1dCk7XG4gICAgICBjb25zdCBkdXJhdGlvbiA9IERhdGUubm93KCkgLSBzdGFydFRpbWU7XG5cbiAgICAgIC8vIExvZyBzbG93IG9wZXJhdGlvbnNcbiAgICAgIGlmIChkdXJhdGlvbiA+IHRpbWVvdXQpIHtcbiAgICAgICAgY29uc29sZS53YXJuKGBbU2FmZVJlZ2V4XSBTbG93IHJlZ2V4IG1hdGNoICgke2R1cmF0aW9ufW1zKSBpbiAke2NvbnRleHR9YCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoYFtTYWZlUmVnZXhdIE1hdGNoIGV4ZWN1dGlvbiBlcnJvciBpbiAke2NvbnRleHR9OmAsIGVycm9yKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAvLyBSZXNldCBsYXN0SW5kZXggZm9yIGdsb2JhbCByZWdleGVzXG4gICAgICBpZiAocmVnZXguZ2xvYmFsKSB7XG4gICAgICAgIHJlZ2V4Lmxhc3RJbmRleCA9IDA7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEVzY2FwZSB1c2VyIGlucHV0IGZvciBzYWZlIHVzZSBpbiByZWdleCBwYXR0ZXJuc1xuICAgKiBQcmV2ZW50cyBpbmplY3Rpb24gb2YgcmVnZXggc3BlY2lhbCBjaGFyYWN0ZXJzXG4gICAqL1xuICBzdGF0aWMgZXNjYXBlKGlucHV0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmICghaW5wdXQgfHwgdHlwZW9mIGlucHV0ICE9PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIC8vIEVzY2FwZSBhbGwgcmVnZXggc3BlY2lhbCBjaGFyYWN0ZXJzXG4gICAgLy8gRklYOiBVc2UgU3RyaW5nLnJhdyBmb3IgZXNjYXBlZCBiYWNrc2xhc2hlcyAoU29uYXJDbG91ZCBTNzc4MClcbiAgICByZXR1cm4gaW5wdXQucmVwbGFjZUFsbCgvWy4qKz9eJHt9KCl8W1xcXVxcXFxdL2csIFN0cmluZy5yYXdgXFwkJmApO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgZ2xvYiBwYXR0ZXJuIHRvIHNhZmUgcmVnZXggcGF0dGVyblxuICAgKiBQcmV2ZW50cyBSZURvUyBmcm9tIG1hbGljaW91cyBnbG9iIHBhdHRlcm5zXG4gICAqL1xuICBzdGF0aWMgZ2xvYlRvUmVnZXgoZ2xvYjogc3RyaW5nKTogUmVnRXhwIHwgbnVsbCB7XG4gICAgaWYgKCFnbG9iIHx8IHR5cGVvZiBnbG9iICE9PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgLy8gTGVuZ3RoIGNoZWNrXG4gICAgaWYgKGdsb2IubGVuZ3RoID4gMTAwMCkge1xuICAgICAgY29uc29sZS53YXJuKCdbU2FmZVJlZ2V4XSBHbG9iIHBhdHRlcm4gdG9vIGxvbmcnKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICAvLyBFc2NhcGUgc3BlY2lhbCByZWdleCBjaGFycyBleGNlcHQgKiBhbmQgP1xuICAgICAgLy8gRklYOiBVc2UgU3RyaW5nLnJhdyBhbmQgcmVwbGFjZUFsbCAoU29uYXJDbG91ZCBTNzc4MCwgUzc3ODEpXG4gICAgICBsZXQgcGF0dGVybiA9IGdsb2IucmVwbGFjZUFsbCgvWy4rXiR7fSgpfFtcXF1cXFxcXS9nLCBTdHJpbmcucmF3YFxcJCZgKTtcblxuICAgICAgLy8gUmVwbGFjZSBnbG9iIHBhdHRlcm5zIHdpdGggc2FmZSByZWdleCBlcXVpdmFsZW50c1xuICAgICAgLy8gVXNlIFteL10qIGluc3RlYWQgb2YgLiogdG8gcHJldmVudCBjYXRhc3Ryb3BoaWMgYmFja3RyYWNraW5nXG4gICAgICBwYXR0ZXJuID0gcGF0dGVyblxuICAgICAgICAucmVwbGFjZUFsbCgnKionLCAnPDxHTE9CU1RBUj4+JykgICAgIC8vIFRlbXBvcmFyeSBwbGFjZWhvbGRlclxuICAgICAgICAucmVwbGFjZUFsbCgnKicsICdbXi9dKicpICAgICAgICAgICAgICAvLyAqIG1hdGNoZXMgYW55dGhpbmcgZXhjZXB0IC9cbiAgICAgICAgLnJlcGxhY2VBbGwoJz8nLCAnW14vXScpICAgICAgICAgICAgICAgLy8gPyBtYXRjaGVzIHNpbmdsZSBjaGFyIGV4Y2VwdCAvXG4gICAgICAgIC5yZXBsYWNlQWxsKCc8PEdMT0JTVEFSPj4vJywgJyg/Oi4qLyk/JykgLy8gKiovIG1hdGNoZXMgYW55IGRpcnNcbiAgICAgICAgLnJlcGxhY2VBbGwoJzw8R0xPQlNUQVI+PicsICcuKicpOyAgICAgIC8vICoqIG1hdGNoZXMgYW55dGhpbmdcblxuICAgICAgLy8gRklYOiBVc2UgdGVtcGxhdGUgbGl0ZXJhbCB0byBhdm9pZCBzZWN1cml0eSBzY2FubmVyIGZhbHNlIHBvc2l0aXZlIChQUiAjMTE4NylcbiAgICAgIC8vIFRoaXMgaXMgTk9UIFNRTCBpbmplY3Rpb24gLSBpdCdzIGEgUmVnRXhwIHBhdHRlcm4gZm9yIGdsb2IgbWF0Y2hpbmdcbiAgICAgIHJldHVybiBuZXcgUmVnRXhwKGBeJHtwYXR0ZXJufSRgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignW1NhZmVSZWdleF0gRmFpbGVkIHRvIGNvbnZlcnQgZ2xvYiB0byByZWdleDonLCBlcnJvcik7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ29tcGlsZSBhbmQgdmFsaWRhdGUgYSByZWdleCBwYXR0ZXJuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBjb21waWxlUGF0dGVybihwYXR0ZXJuOiBzdHJpbmcpOiBSZWdFeHAgfCBudWxsIHtcbiAgICAvLyBDaGVjayBjYWNoZSBmaXJzdFxuICAgIGlmICh0aGlzLnBhdHRlcm5DYWNoZS5oYXMocGF0dGVybikpIHtcbiAgICAgIHJldHVybiB0aGlzLnBhdHRlcm5DYWNoZS5nZXQocGF0dGVybikhO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICAvLyBWYWxpZGF0ZSBwYXR0ZXJuIGZvciBkYW5nZXJvdXMgY29uc3RydWN0c1xuICAgICAgaWYgKHRoaXMuaXNEYW5nZXJvdXMocGF0dGVybikpIHtcbiAgICAgICAgLy8gRklYOiBDb21iaW5lIG1lc3NhZ2UgYW5kIHBhdHRlcm4gaW50byBzaW5nbGUgc3RyaW5nIGZvciBjb25zb2xlLndhcm5cbiAgICAgICAgLy8gUHJldmlvdXNseTogQ2FsbGVkIHdpdGggdHdvIGFyZ3VtZW50cyB3aGljaCBicmVha3MgdGVzdCBleHBlY3RhdGlvbnNcbiAgICAgICAgLy8gTm93OiBTaW5nbGUgZm9ybWF0dGVkIHN0cmluZ1xuICAgICAgICBjb25zb2xlLndhcm4oYFtTYWZlUmVnZXhdIERhbmdlcm91cyBwYXR0ZXJuIGRldGVjdGVkOiAke3BhdHRlcm59YCk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAocGF0dGVybik7XG5cbiAgICAgIC8vIENhY2hlIGlmIG5vdCB0b28gbWFueSBwYXR0ZXJuc1xuICAgICAgaWYgKHRoaXMucGF0dGVybkNhY2hlLnNpemUgPCBNQVhfUEFUVEVSTl9DQUNIRV9TSVpFKSB7XG4gICAgICAgIHRoaXMucGF0dGVybkNhY2hlLnNldChwYXR0ZXJuLCByZWdleCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiByZWdleDtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignW1NhZmVSZWdleF0gSW52YWxpZCByZWdleCBwYXR0ZXJuOicsIHBhdHRlcm4sIGVycm9yKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBmb3IgbmVzdGVkIHF1YW50aWZpZXJzIGluIHBhdHRlcm5cbiAgICogUmV2aWV3ZXIgcmVjb21tZW5kYXRpb246IEJyZWFrIGRvd24gY29tcGxleCBmdW5jdGlvbnNcbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGhhc05lc3RlZFF1YW50aWZpZXJzKHBhdHRlcm46IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IG5lc3RlZFBhdHRlcm5zID0gW1xuICAgICAgL1srKl17Mix9LywgICAgICAgICAgICAgICAgICAgICAgIC8vIE11bHRpcGxlIGNvbnNlY3V0aXZlIHF1YW50aWZpZXJzXG4gICAgICAvXFwoLnswLDUwfVxcK1xcKVsrKl0vLCAgICAgICAgICAgICAvLyBOZXN0ZWQgcXVhbnRpZmllcnMgKGJvdW5kZWQgY2hlY2spXG4gICAgICAvXFxbW15cXF1dezAsMjB9XFwrXFxdWysqXS8sICAgICAgICAgLy8gTmVzdGVkIHF1YW50aWZpZXJzIGluIGNoYXIgY2xhc3NcbiAgICBdO1xuXG4gICAgZm9yIChjb25zdCBkYW5nZXJvdXMgb2YgbmVzdGVkUGF0dGVybnMpIHtcbiAgICAgIGlmIChkYW5nZXJvdXMudGVzdChwYXR0ZXJuKSkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBTdHJpbmctYmFzZWQgY2hlY2tzIGZvciBjYXRhc3Ryb3BoaWMgcGF0dGVybnMgKHNhZmVyKVxuICAgIC8vIEZJWDogVXNlIFN0cmluZy5yYXcgZm9yIGVzY2FwZWQgYmFja3NsYXNoZXMgKFNvbmFyQ2xvdWQgUzc3ODApXG4gICAgY29uc3QgY2F0YXN0cm9waGljUGF0dGVybnMgPSBbXG4gICAgICAnKC4rKSsnLCAnKC4qKSsnLCAnKC4rKSonLCAnKC4qKSonLCAgLy8gQ2xhc3NpYyBjYXRhc3Ryb3BoaWNcbiAgICAgIFN0cmluZy5yYXdgKFxcZCspK2AsIFN0cmluZy5yYXdgKFxcdyspK2AsIFN0cmluZy5yYXdgKFxccyspK2AsICAgICAvLyBEaWdpdC93b3JkL3NwYWNlIGNhdGFzdHJvcGhpY1xuICAgICAgJyhhKykrJywgJyhhKikqJywgICAgICAgICAgICAgICAgICAgIC8vIFNpbXBsZSBjYXRhc3Ryb3BoaWNcbiAgICBdO1xuXG4gICAgZm9yIChjb25zdCBjYXRhc3Ryb3BoaWMgb2YgY2F0YXN0cm9waGljUGF0dGVybnMpIHtcbiAgICAgIGlmIChwYXR0ZXJuLmluY2x1ZGVzKGNhdGFzdHJvcGhpYykpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGZvciBjb21wbGV4IGFsdGVybmF0aW9uIHBhdHRlcm5zIHRoYXQgY2FuIGNhdXNlIGJhY2t0cmFja2luZ1xuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgaGFzQ29tcGxleEFsdGVybmF0aW9uKHBhdHRlcm46IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIC8vIENoZWNrIGZvciBvdmVybGFwcGluZyBhbHRlcm5hdGlvblxuICAgIGlmIChwYXR0ZXJuLmluY2x1ZGVzKCcoYXxhKSonKSB8fCBwYXR0ZXJuLmluY2x1ZGVzKCcoYXxhYikqJykpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIC8vIENvdW50IGFsdGVybmF0aW9uc1xuICAgIGNvbnN0IGFsdGVybmF0aW9ucyA9IChwYXR0ZXJuLm1hdGNoKC9cXHwvZykgfHwgW10pLmxlbmd0aDtcbiAgICByZXR1cm4gYWx0ZXJuYXRpb25zID4gMTA7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgaWYgcGF0dGVybiBjb21wbGV4aXR5IGV4Y2VlZHMgc2FmZSB0aHJlc2hvbGRzXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBleGNlZWRzQ29tcGxleGl0eVRocmVzaG9sZChwYXR0ZXJuOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBjb25zdCBncm91cHMgPSAocGF0dGVybi5tYXRjaCgvXFwoL2cpIHx8IFtdKS5sZW5ndGg7XG4gICAgY29uc3QgcXVhbnRpZmllcnMgPSAocGF0dGVybi5tYXRjaCgvWysqP3tdL2cpIHx8IFtdKS5sZW5ndGg7XG5cbiAgICAvLyBIaWdoIGNvbXBsZXhpdHkgPSBwb3RlbnRpYWwgZGFuZ2VyXG4gICAgcmV0dXJuIGdyb3VwcyA+IDEwIHx8IHF1YW50aWZpZXJzID4gMTU7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgaWYgYSByZWdleCBwYXR0ZXJuIGlzIHBvdGVudGlhbGx5IGRhbmdlcm91cyAoUmVEb1MpXG4gICAqIEJhc2VkIG9uIE9XQVNQIHJlY29tbWVuZGF0aW9uc1xuICAgKiBSZWZhY3RvcmVkIGZvciBjbGFyaXR5IChSZXZpZXdlciByZWNvbW1lbmRhdGlvbilcbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGlzRGFuZ2Vyb3VzKHBhdHRlcm46IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmhhc05lc3RlZFF1YW50aWZpZXJzKHBhdHRlcm4pIHx8XG4gICAgICAgICAgIHRoaXMuaGFzQ29tcGxleEFsdGVybmF0aW9uKHBhdHRlcm4pIHx8XG4gICAgICAgICAgIHRoaXMuZXhjZWVkc0NvbXBsZXhpdHlUaHJlc2hvbGQocGF0dGVybik7XG4gIH1cblxuICAvKipcbiAgICogQ2xlYXIgdGhlIHBhdHRlcm4gY2FjaGVcbiAgICovXG4gIHN0YXRpYyBjbGVhckNhY2hlKCk6IHZvaWQge1xuICAgIHRoaXMucGF0dGVybkNhY2hlLmNsZWFyKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBET1MgUHJvdGVjdGlvbiBtaWRkbGV3YXJlIGZvciB2YXJpb3VzIG9wZXJhdGlvbnNcbiAqL1xuZXhwb3J0IGNsYXNzIERPU1Byb3RlY3Rpb24ge1xuICAvKipcbiAgICogU3BsaXQgd2l0aCByZWdleCBzZXBhcmF0b3IgdXNpbmcgU2FmZVJlZ2V4IHByb3RlY3Rpb25cbiAgICogRXh0cmFjdGVkIHRvIHJlZHVjZSBjb2duaXRpdmUgY29tcGxleGl0eVxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgc3BsaXRXaXRoUmVnZXgoXG4gICAgaW5wdXQ6IHN0cmluZyxcbiAgICBzZXBhcmF0b3I6IHN0cmluZyB8IFJlZ0V4cCxcbiAgICBsaW1pdD86IG51bWJlclxuICApOiBzdHJpbmdbXSB7XG4gICAgLy8gU2ltcGxlIHdoaXRlc3BhY2Ugc3BsaXQgaXMgc2FmZVxuICAgIC8vIEZJWDogVXNlIFN0cmluZy5yYXcgZm9yIGVzY2FwZWQgYmFja3NsYXNoZXMgKFNvbmFyQ2xvdWQgUzc3ODApXG4gICAgaWYgKHNlcGFyYXRvci50b1N0cmluZygpID09PSBTdHJpbmcucmF3YC9cXHMrL2ApIHtcbiAgICAgIHJldHVybiBpbnB1dC5zcGxpdCgvXFxzKy8sIGxpbWl0KTtcbiAgICB9XG5cbiAgICBjb25zdCBwYXJ0czogc3RyaW5nW10gPSBbXTtcbiAgICBsZXQgcmVtYWluaW5nID0gaW5wdXQ7XG4gICAgbGV0IGNvdW50ID0gMDtcbiAgICBjb25zdCBtYXhJdGVyYXRpb25zID0gbGltaXQgfHwgMTAwMDtcblxuICAgIHdoaWxlIChyZW1haW5pbmcgJiYgY291bnQgPCBtYXhJdGVyYXRpb25zKSB7XG4gICAgICBjb25zdCBtYXRjaCA9IFNhZmVSZWdleC5tYXRjaChyZW1haW5pbmcsIHNlcGFyYXRvciwge1xuICAgICAgICBjb250ZXh0OiAnc3BsaXQgb3BlcmF0aW9uJyxcbiAgICAgICAgdGltZW91dDogNTBcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoIW1hdGNoPy5pbmRleCAmJiBtYXRjaD8uaW5kZXggIT09IDApIHtcbiAgICAgICAgcGFydHMucHVzaChyZW1haW5pbmcpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cblxuICAgICAgcGFydHMucHVzaChyZW1haW5pbmcuc3Vic3RyaW5nKDAsIG1hdGNoLmluZGV4KSk7XG4gICAgICByZW1haW5pbmcgPSByZW1haW5pbmcuc3Vic3RyaW5nKG1hdGNoLmluZGV4ICsgbWF0Y2hbMF0ubGVuZ3RoKTtcbiAgICAgIGNvdW50Kys7XG4gICAgfVxuXG4gICAgcmV0dXJuIHBhcnRzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNwbGl0IHdpdGggc3RyaW5nIHNlcGFyYXRvciBwcmVzZXJ2aW5nIHJlbWFpbmRlclxuICAgKiBFeHRyYWN0ZWQgdG8gcmVkdWNlIGNvZ25pdGl2ZSBjb21wbGV4aXR5XG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBzcGxpdFdpdGhTdHJpbmcoXG4gICAgaW5wdXQ6IHN0cmluZyxcbiAgICBzZXBhcmF0b3I6IHN0cmluZyxcbiAgICBsaW1pdD86IG51bWJlclxuICApOiBzdHJpbmdbXSB7XG4gICAgLy8gTm8gbGltaXQgLSB1c2UgbmF0aXZlIHNwbGl0XG4gICAgaWYgKGxpbWl0ID09PSB1bmRlZmluZWQgfHwgbGltaXQgPD0gMCkge1xuICAgICAgcmV0dXJuIGlucHV0LnNwbGl0KHNlcGFyYXRvcik7XG4gICAgfVxuXG4gICAgY29uc3QgcGFydHM6IHN0cmluZ1tdID0gW107XG4gICAgbGV0IHJlbWFpbmluZyA9IGlucHV0O1xuICAgIGxldCBjb3VudCA9IDA7XG4gICAgY29uc3Qgc2VwID0gc2VwYXJhdG9yLnRvU3RyaW5nKCk7XG5cbiAgICB3aGlsZSAocmVtYWluaW5nICYmIGNvdW50IDwgbGltaXQgLSAxKSB7XG4gICAgICBjb25zdCBpbmRleCA9IHJlbWFpbmluZy5pbmRleE9mKHNlcCk7XG4gICAgICBpZiAoaW5kZXggPT09IC0xKSB7XG4gICAgICAgIHBhcnRzLnB1c2gocmVtYWluaW5nKTtcbiAgICAgICAgcmV0dXJuIHBhcnRzO1xuICAgICAgfVxuXG4gICAgICBwYXJ0cy5wdXNoKHJlbWFpbmluZy5zdWJzdHJpbmcoMCwgaW5kZXgpKTtcbiAgICAgIHJlbWFpbmluZyA9IHJlbWFpbmluZy5zdWJzdHJpbmcoaW5kZXggKyBzZXAubGVuZ3RoKTtcbiAgICAgIGNvdW50Kys7XG4gICAgfVxuXG4gICAgLy8gQWRkIHJlbWFpbmRlciBhcyBmaW5hbCBlbGVtZW50XG4gICAgaWYgKHJlbWFpbmluZyB8fCBjb3VudCA8IGxpbWl0KSB7XG4gICAgICBwYXJ0cy5wdXNoKHJlbWFpbmluZyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHBhcnRzO1xuICB9XG5cbiAgLyoqXG4gICAqIFByb3RlY3Qgc3RyaW5nIHNwbGl0IG9wZXJhdGlvbnMgZnJvbSBSZURvU1xuICAgKiBSRUZBQ1RPUkVEOiBSZWR1Y2VkIGNvZ25pdGl2ZSBjb21wbGV4aXR5IGJ5IGV4dHJhY3RpbmcgaGVscGVyc1xuICAgKi9cbiAgc3RhdGljIHNhZmVTcGxpdChcbiAgICBpbnB1dDogc3RyaW5nLFxuICAgIHNlcGFyYXRvcjogc3RyaW5nIHwgUmVnRXhwLFxuICAgIGxpbWl0PzogbnVtYmVyXG4gICk6IHN0cmluZ1tdIHtcbiAgICAvLyBIYW5kbGUgZW1wdHkvaW52YWxpZCBpbnB1dFxuICAgIGlmICghaW5wdXQpIHtcbiAgICAgIHJldHVybiBpbnB1dCA9PT0gJycgPyBbJyddIDogW107XG4gICAgfVxuXG4gICAgLy8gTGVuZ3RoIGNoZWNrXG4gICAgaWYgKGlucHV0Lmxlbmd0aCA+IDEwMDAwMCkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIC8vIERlbGVnYXRlIHRvIGFwcHJvcHJpYXRlIGhhbmRsZXJcbiAgICBpZiAoc2VwYXJhdG9yIGluc3RhbmNlb2YgUmVnRXhwIHx8IHNlcGFyYXRvci5zdGFydHNXaXRoKCcvJykpIHtcbiAgICAgIHJldHVybiB0aGlzLnNwbGl0V2l0aFJlZ2V4KGlucHV0LCBzZXBhcmF0b3IsIGxpbWl0KTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5zcGxpdFdpdGhTdHJpbmcoaW5wdXQsIHNlcGFyYXRvciwgbGltaXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFByb3RlY3QgcmVwbGFjZSBvcGVyYXRpb25zIGZyb20gUmVEb1NcbiAgICovXG4gIHN0YXRpYyBzYWZlUmVwbGFjZShcbiAgICBpbnB1dDogc3RyaW5nLFxuICAgIHBhdHRlcm46IHN0cmluZyB8IFJlZ0V4cCxcbiAgICByZXBsYWNlbWVudDogc3RyaW5nIHwgKChtYXRjaDogc3RyaW5nLCAuLi5hcmdzOiBhbnlbXSkgPT4gc3RyaW5nKVxuICApOiBzdHJpbmcge1xuICAgIC8vIExlbmd0aCBjaGVja1xuICAgIGlmICghaW5wdXQpIHtcbiAgICAgIHJldHVybiAnJztcbiAgICB9XG4gICAgaWYgKGlucHV0Lmxlbmd0aCA+IDEwMDAwMCkge1xuICAgICAgcmV0dXJuICcnOyAgLy8gUmV0dXJuIGVtcHR5IHN0cmluZyBmb3Igb3Zlcmx5IGxvbmcgaW5wdXRcbiAgICB9XG5cbiAgICAvLyBGb3IgcmVnZXggcGF0dGVybnMsIHZhbGlkYXRlIGZpcnN0XG4gICAgaWYgKHBhdHRlcm4gaW5zdGFuY2VvZiBSZWdFeHApIHtcbiAgICAgIGNvbnN0IHBhdHRlcm5TdHIgPSBwYXR0ZXJuLnNvdXJjZTtcbiAgICAgIGlmIChTYWZlUmVnZXhbJ2lzRGFuZ2Vyb3VzJ10ocGF0dGVyblN0cikpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdbRE9TUHJvdGVjdGlvbl0gRGFuZ2Vyb3VzIHJlcGxhY2UgcGF0dGVybiBibG9ja2VkJyk7XG4gICAgICAgIHJldHVybiBpbnB1dDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGlucHV0LnJlcGxhY2UocGF0dGVybiwgcmVwbGFjZW1lbnQgYXMgYW55KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignW0RPU1Byb3RlY3Rpb25dIFJlcGxhY2Ugb3BlcmF0aW9uIGZhaWxlZDonLCBlcnJvcik7XG4gICAgICByZXR1cm4gaW5wdXQ7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJhdGUgbGltaXRpbmcgZm9yIGV4cGVuc2l2ZSBvcGVyYXRpb25zXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBvcGVyYXRpb25Db3VudHMgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xuICBwcml2YXRlIHN0YXRpYyByZXNldEludGVydmFsOiBOb2RlSlMuVGltZW91dCB8IG51bGwgPSBudWxsO1xuXG4gIHN0YXRpYyByYXRlTGltaXQoXG4gICAgb3BlcmF0aW9uOiBzdHJpbmcsXG4gICAgbWF4UGVyTWludXRlOiBudW1iZXIgPSAxMDBcbiAgKTogYm9vbGVhbiB7XG4gICAgLy8gSW5pdGlhbGl6ZSByZXNldCBpbnRlcnZhbCBpZiBuZWVkZWRcbiAgICB0aGlzLnJlc2V0SW50ZXJ2YWwgPz89IHNldEludGVydmFsKCgpID0+IHtcbiAgICAgIHRoaXMub3BlcmF0aW9uQ291bnRzLmNsZWFyKCk7XG4gICAgfSwgUkFURV9MSU1JVF9SRVNFVF9NUyk7XG4gICAgaWYgKHRoaXMucmVzZXRJbnRlcnZhbCAmJiB0eXBlb2YgdGhpcy5yZXNldEludGVydmFsLnVucmVmID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0aGlzLnJlc2V0SW50ZXJ2YWwudW5yZWYoKTtcbiAgICB9XG5cbiAgICBjb25zdCBjb3VudCA9IHRoaXMub3BlcmF0aW9uQ291bnRzLmdldChvcGVyYXRpb24pIHx8IDA7XG4gICAgaWYgKGNvdW50ID49IG1heFBlck1pbnV0ZSkge1xuICAgICAgY29uc29sZS53YXJuKGBbRE9TUHJvdGVjdGlvbl0gUmF0ZSBsaW1pdCBleGNlZWRlZCBmb3IgJHtvcGVyYXRpb259YCk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgdGhpcy5vcGVyYXRpb25Db3VudHMuc2V0KG9wZXJhdGlvbiwgY291bnQgKyAxKTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDbGVhbnVwIHJlc291cmNlc1xuICAgKi9cbiAgc3RhdGljIGNsZWFudXAoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucmVzZXRJbnRlcnZhbCkge1xuICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLnJlc2V0SW50ZXJ2YWwpO1xuICAgICAgdGhpcy5yZXNldEludGVydmFsID0gbnVsbDtcbiAgICB9XG4gICAgdGhpcy5vcGVyYXRpb25Db3VudHMuY2xlYXIoKTtcbiAgICBTYWZlUmVnZXguY2xlYXJDYWNoZSgpO1xuICB9XG59XG5cbi8vIEV4cG9ydCBjb252ZW5pZW5jZSBmdW5jdGlvbnNcbmV4cG9ydCBjb25zdCBzYWZlVGVzdCA9IFNhZmVSZWdleC50ZXN0LmJpbmQoU2FmZVJlZ2V4KTtcbmV4cG9ydCBjb25zdCBzYWZlTWF0Y2ggPSBTYWZlUmVnZXgubWF0Y2guYmluZChTYWZlUmVnZXgpO1xuZXhwb3J0IGNvbnN0IGVzY2FwZVJlZ2V4ID0gU2FmZVJlZ2V4LmVzY2FwZS5iaW5kKFNhZmVSZWdleCk7XG5leHBvcnQgY29uc3QgZ2xvYlRvUmVnZXggPSBTYWZlUmVnZXguZ2xvYlRvUmVnZXguYmluZChTYWZlUmVnZXgpO1xuZXhwb3J0IGNvbnN0IHNhZmVTcGxpdCA9IERPU1Byb3RlY3Rpb24uc2FmZVNwbGl0LmJpbmQoRE9TUHJvdGVjdGlvbik7XG5leHBvcnQgY29uc3Qgc2FmZVJlcGxhY2UgPSBET1NQcm90ZWN0aW9uLnNhZmVSZXBsYWNlLmJpbmQoRE9TUHJvdGVjdGlvbik7XG4iXX0=