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.

357 lines 49 kB
/** * NLP Scoring Manager - Jaccard similarity and Shannon entropy for semantic analysis * * Implements intelligent document similarity scoring using: * - Jaccard similarity for vocabulary overlap * - Shannon entropy for information density * - Combined scoring for meaningful semantic relationships * * Key insights from analysis: * - High Jaccard (>60%) + Moderate entropy (4.5-6.0) = Same technical domain * - High Jaccard + Low entropy (<3.0) = Stop word pollution, superficial * - Low Jaccard + Similar entropy = Different domains, equally complex * * Part of Enhanced Capability Index (#1085) */ import { logger } from '../utils/logger.js'; import { UnicodeValidator } from '../security/validators/unicodeValidator.js'; import { IndexConfigManager } from './config/IndexConfig.js'; export class NLPScoringManager { cache; cacheAccessOrder; // Track access order for LRU config; unicodeValidator; cleanupInterval; constructor(config, indexConfigManager = new IndexConfigManager()) { // Get config from central manager const indexConfig = indexConfigManager.getConfig(); this.config = { minTokenLength: indexConfig.nlp.minTokenLength, cacheExpiry: indexConfig.nlp.cacheExpiryMinutes * 60 * 1000, maxCacheSize: indexConfig.memory.maxCacheSize, entropyBands: indexConfig.nlp.entropyBands, jaccardThresholds: indexConfig.nlp.jaccardThresholds, ...config }; this.cache = new Map(); this.cacheAccessOrder = []; this.unicodeValidator = new UnicodeValidator(); // Periodic cleanup of expired entries this.cleanupInterval = setInterval(() => this.cleanExpiredCache(), 60000); // Every minute if (typeof this.cleanupInterval.unref === 'function') { this.cleanupInterval.unref(); } } /** * Clean and tokenize text for analysis * Works with any language - no hardcoded stop words */ cleanAndTokenize(text) { // Normalize Unicode for security const validation = UnicodeValidator.normalize(text); if (validation.detectedIssues && validation.detectedIssues.length > 0) { logger.warn('Unicode issues in NLP text', { issues: validation.detectedIssues }); } text = validation.normalizedContent; // Convert to lowercase and split on word boundaries // Keep Unicode letter characters for multilingual support const tokens = text.toLowerCase() .replaceAll(/[^\p{L}\p{N}\s_-]/gu, ' ') // Unicode-aware: keep letters, numbers, underscore, hyphen .split(/\s+/) .filter(token => token.length >= this.config.minTokenLength); return new Set(tokens); } /** * Calculate Jaccard similarity between two text strings * * Jaccard = |A ∩ B| / |A ∪ B| * * Returns value between 0 (no overlap) and 1 (identical) */ calculateJaccard(text1, text2) { const tokens1 = this.cleanAndTokenize(text1); const tokens2 = this.cleanAndTokenize(text2); if (tokens1.size === 0 && tokens2.size === 0) { return 1.0; // Both empty = identical } if (tokens1.size === 0 || tokens2.size === 0) { return 0.0; // One empty = no similarity } // Calculate intersection const intersection = new Set([...tokens1].filter(token => tokens2.has(token))); // Calculate union const union = new Set([...tokens1, ...tokens2]); return intersection.size / union.size; } /** * Calculate Shannon entropy for text * * H(X) = -Σ p(x) * log2(p(x)) * * Measures information density/vocabulary richness * Higher entropy = more diverse vocabulary */ calculateEntropy(text) { const tokens = Array.from(this.cleanAndTokenize(text)); if (tokens.length === 0) { return 0; } // Calculate token frequencies const frequencies = new Map(); for (const token of tokens) { frequencies.set(token, (frequencies.get(token) || 0) + 1); } // Calculate probabilities and entropy let entropy = 0; const totalTokens = tokens.length; for (const count of frequencies.values()) { const probability = count / totalTokens; if (probability > 0) { entropy -= probability * Math.log2(probability); } } return entropy; } /** * Calculate combined relevance score using Jaccard and entropy * * Interprets the relationship between similarity and complexity */ scoreRelevance(text1, text2) { // Check cache first const cacheKey = `${text1.substring(0, 50)}:::${text2.substring(0, 50)}`; const cached = this.cache.get(cacheKey); if (cached && Date.now() - cached.timestamp < this.config.cacheExpiry) { // Update access order for LRU cached.lastAccessed = Date.now(); this.updateAccessOrder(cacheKey); return cached.result; } // Calculate metrics const jaccard = this.calculateJaccard(text1, text2); const entropy1 = this.calculateEntropy(text1); const entropy2 = this.calculateEntropy(text2); const avgEntropy = (entropy1 + entropy2) / 2; // Get token sets for additional metrics const tokens1 = this.cleanAndTokenize(text1); const tokens2 = this.cleanAndTokenize(text2); const intersection = new Set([...tokens1].filter(token => tokens2.has(token))); // Interpret the combination let combinedScore; let interpretation; // High Jaccard + Moderate-High entropy = Excellent match (same domain) if (jaccard >= this.config.jaccardThresholds.high && avgEntropy >= this.config.entropyBands.low) { // Scale score based on entropy quality const entropyQuality = Math.min(1.0, (avgEntropy - 2.0) / 4.0); // 0 at entropy=2, 1 at entropy=6+ combinedScore = 0.7 + (jaccard - 0.6) * 0.5 + entropyQuality * 0.2; if (avgEntropy >= this.config.entropyBands.moderate) { interpretation = 'Excellent match - same technical domain with rich vocabulary'; } else { interpretation = 'Good match - high overlap but simpler vocabulary'; } } // High Jaccard + Very Low entropy = Common word pollution else if (jaccard >= this.config.jaccardThresholds.high && avgEntropy < 2.0) { combinedScore = 0.3 + jaccard * 0.2; // Penalize heavily interpretation = 'Superficial similarity - mostly common words'; } // Moderate Jaccard + Good entropy = Related concepts else if (jaccard >= this.config.jaccardThresholds.moderate && avgEntropy >= this.config.entropyBands.low) { combinedScore = 0.4 + jaccard * 0.4 + (avgEntropy / 10) * 0.2; interpretation = 'Moderate match - related concepts with good complexity'; } // Low Jaccard + Similar entropy = Different domains else if (jaccard < this.config.jaccardThresholds.low && Math.abs(entropy1 - entropy2) < 1.0) { combinedScore = jaccard * 0.5; interpretation = 'Different domains with similar complexity'; } // Low Jaccard + Different entropy = Unrelated else { combinedScore = jaccard * 0.3; interpretation = 'Low relevance - different topics and complexity'; } // Ensure score is between 0 and 1 combinedScore = Math.max(0, Math.min(1, combinedScore)); const result = { jaccard, entropy: avgEntropy, combinedScore, interpretation, tokenCount: tokens1.size + tokens2.size, overlapCount: intersection.size }; // Cache the result with LRU management this.addToCache(cacheKey, result); return result; } /** * Build a pairwise similarity matrix for multiple texts * * Useful for clustering and relationship discovery */ buildSimilarityMatrix(elements) { const matrix = new Map(); const keys = Array.from(elements.keys()); for (let i = 0; i < keys.length; i++) { const key1 = keys[i]; const text1 = elements.get(key1); if (!matrix.has(key1)) { matrix.set(key1, new Map()); } for (let j = i + 1; j < keys.length; j++) { const key2 = keys[j]; const text2 = elements.get(key2); // Calculate similarity const similarity = this.scoreRelevance(text1, text2); // Store bidirectionally matrix.get(key1).set(key2, similarity); if (!matrix.has(key2)) { matrix.set(key2, new Map()); } matrix.get(key2).set(key1, similarity); } } return matrix; } /** * Find most similar elements to a given text */ findSimilar(targetText, candidates, topK = 5) { const scores = []; for (const [name, text] of candidates.entries()) { const score = this.scoreRelevance(targetText, text); scores.push({ name, score }); } // Sort by combined score descending scores.sort((a, b) => b.score.combinedScore - a.score.combinedScore); return scores.slice(0, topK); } /** * Extract key terms from text based on entropy contribution * * Terms that contribute most to entropy are likely important */ extractKeyTerms(text, topK = 10) { const tokens = Array.from(this.cleanAndTokenize(text)); if (tokens.length === 0) { return []; } // Calculate token frequencies const frequencies = new Map(); for (const token of tokens) { frequencies.set(token, (frequencies.get(token) || 0) + 1); } // Calculate entropy contribution for each unique token const totalTokens = tokens.length; const contributions = []; for (const [token, count] of frequencies.entries()) { const probability = count / totalTokens; const contribution = -probability * Math.log2(probability); contributions.push({ token, contribution }); } // Sort by contribution descending contributions.sort((a, b) => b.contribution - a.contribution); return contributions.slice(0, topK).map(c => c.token); } /** * Add result to cache with LRU eviction */ addToCache(key, result) { const now = Date.now(); // Check if we need to evict if (this.cache.size >= this.config.maxCacheSize && !this.cache.has(key)) { // Find least recently used entry let lruKey = null; let oldestAccess = now; for (const [k, v] of this.cache.entries()) { if (v.lastAccessed < oldestAccess) { oldestAccess = v.lastAccessed; lruKey = k; } } if (lruKey) { this.cache.delete(lruKey); const idx = this.cacheAccessOrder.indexOf(lruKey); if (idx > -1) { this.cacheAccessOrder.splice(idx, 1); } logger.debug('Evicted LRU cache entry', { key: lruKey, cacheSize: this.cache.size }); } } // Add new entry this.cache.set(key, { result, timestamp: now, lastAccessed: now }); this.updateAccessOrder(key); } /** * Update access order for LRU tracking */ updateAccessOrder(key) { const idx = this.cacheAccessOrder.indexOf(key); if (idx > -1) { this.cacheAccessOrder.splice(idx, 1); } this.cacheAccessOrder.push(key); } /** * Clean expired cache entries */ cleanExpiredCache() { const now = Date.now(); let removed = 0; for (const [key, value] of this.cache.entries()) { if (now - value.timestamp > this.config.cacheExpiry) { this.cache.delete(key); const idx = this.cacheAccessOrder.indexOf(key); if (idx > -1) { this.cacheAccessOrder.splice(idx, 1); } removed++; } } if (removed > 0) { logger.debug('Cleaned expired cache entries', { removed, remaining: this.cache.size }); } } /** * Clear the cache */ clearCache() { const cleared = this.cache.size; this.cache.clear(); this.cacheAccessOrder = []; if (cleared > 0) { logger.debug('NLP scoring cache cleared', { entriesCleared: cleared }); } } /** * Get cache statistics */ getCacheStats() { let oldest = null; for (const entry of this.cache.values()) { if (oldest === null || entry.timestamp < oldest) { oldest = entry.timestamp; } } return { size: this.cache.size, oldestEntry: oldest }; } dispose() { if (this.cleanupInterval) { clearInterval(this.cleanupInterval); this.cleanupInterval = undefined; } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTkxQU2NvcmluZ01hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcG9ydGZvbGlvL05MUFNjb3JpbmdNYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBRUgsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBQzlFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBMkM3RCxNQUFNLE9BQU8saUJBQWlCO0lBQ3BCLEtBQUssQ0FBa0Y7SUFDdkYsZ0JBQWdCLENBQVcsQ0FBRSw2QkFBNkI7SUFDMUQsTUFBTSxDQUFnQjtJQUN0QixnQkFBZ0IsQ0FBbUI7SUFDbkMsZUFBZSxDQUFrQjtJQUV6QyxZQUNFLE1BQStCLEVBQy9CLHFCQUF5QyxJQUFJLGtCQUFrQixFQUFFO1FBRWpFLGtDQUFrQztRQUNsQyxNQUFNLFdBQVcsR0FBRyxrQkFBa0IsQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUVuRCxJQUFJLENBQUMsTUFBTSxHQUFHO1lBQ1osY0FBYyxFQUFFLFdBQVcsQ0FBQyxHQUFHLENBQUMsY0FBYztZQUM5QyxXQUFXLEVBQUUsV0FBVyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsR0FBRyxFQUFFLEdBQUcsSUFBSTtZQUMzRCxZQUFZLEVBQUUsV0FBVyxDQUFDLE1BQU0sQ0FBQyxZQUFZO1lBQzdDLFlBQVksRUFBRSxXQUFXLENBQUMsR0FBRyxDQUFDLFlBQVk7WUFDMUMsaUJBQWlCLEVBQUUsV0FBVyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUI7WUFDcEQsR0FBRyxNQUFNO1NBQ1YsQ0FBQztRQUVGLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsZ0JBQWdCLEdBQUcsRUFBRSxDQUFDO1FBQzNCLElBQUks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QUM7WUFDaEIsTUFBTSxDQUFDLEtBQUssQ0FBQywyQkFBMkIsRUFBRSxFQUFFLGNBQWMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ3pFLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxhQUFhO1FBQ2xCLElBQUksTUFBTSxHQUFrQixJQUFJLENBQUM7UUFFakMsS0FBSyxNQUFNLEtBQUssSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUM7WUFDeEMsSUFBSSxNQUFNLEtBQUssSUFBSSxJQUFJLEtBQUssQ0FBQyxTQUFTLEdBQUcsTUFBTSxFQUFFLENBQUM7Z0JBQ2hELE1BQU0sR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDO1lBQzNCLENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTztZQUNMLElBQUksRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUk7WUFDckIsV0FBVyxFQUFFLE1BQU07U0FDcEIsQ0FBQztJQUNKLENBQUM7SUFFTSxPQUFPO1FBQ1osSUFBSSxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDekIsYUFBYSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztZQUNwQyxJQUFJLENBQUMsZUFBZSxHQUFHLFNBQVMsQ0FBQztRQUNuQyxDQUFDO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBOTFAgU2NvcmluZyBNYW5hZ2VyIC0gSmFjY2FyZCBzaW1pbGFyaXR5IGFuZCBTaGFubm9uIGVudHJvcHkgZm9yIHNlbWFudGljIGFuYWx5c2lzXG4gKlxuICogSW1wbGVtZW50cyBpbnRlbGxpZ2VudCBkb2N1bWVudCBzaW1pbGFyaXR5IHNjb3JpbmcgdXNpbmc6XG4gKiAtIEphY2NhcmQgc2ltaWxhcml0eSBmb3Igdm9jYWJ1bGFyeSBvdmVybGFwXG4gKiAtIFNoYW5ub24gZW50cm9weSBmb3IgaW5mb3JtYXRpb24gZGVuc2l0eVxuICogLSBDb21iaW5lZCBzY29yaW5nIGZvciBtZWFuaW5nZnVsIHNlbWFudGljIHJlbGF0aW9uc2hpcHNcbiAqXG4gKiBLZXkgaW5zaWdodHMgZnJvbSBhbmFseXNpczpcbiAqIC0gSGlnaCBKYWNjYXJkICg+NjAlKSArIE1vZGVyYXRlIGVudHJvcHkgKDQuNS02LjApID0gU2FtZSB0ZWNobmljYWwgZG9tYWluXG4gKiAtIEhpZ2ggSmFjY2FyZCArIExvdyBlbnRyb3B5ICg8My4wKSA9IFN0b3Agd29yZCBwb2xsdXRpb24sIHN1cGVyZmljaWFsXG4gKiAtIExvdyBKYWNjYXJkICsgU2ltaWxhciBlbnRyb3B5ID0gRGlmZmVyZW50IGRvbWFpbnMsIGVxdWFsbHkgY29tcGxleFxuICpcbiAqIFBhcnQgb2YgRW5oYW5jZWQgQ2FwYWJpbGl0eSBJbmRleCAoIzEwODUpXG4gKi9cblxuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IFVuaWNvZGVWYWxpZGF0b3IgfSBmcm9tICcuLi9zZWN1cml0eS92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuaW1wb3J0IHsgSW5kZXhDb25maWdNYW5hZ2VyIH0gZnJvbSAnLi9jb25maWcvSW5kZXhDb25maWcuanMnO1xuXG4vKipcbiAqIFNjb3JpbmcgcmVzdWx0IHdpdGggZGV0YWlsZWQgbWV0cmljc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIFNjb3JpbmdSZXN1bHQge1xuICBqYWNjYXJkOiBudW1iZXI7ICAgICAgICAgICAvLyAwLjAgdG8gMS4wXG4gIGVudHJvcHk6IG51bWJlcjsgICAgICAgICAgIC8vIFR5cGljYWxseSAwIHRvIDggYml0cyBmb3IgdGV4dFxuICBjb21iaW5lZFNjb3JlOiBudW1iZXI7ICAgICAvLyAwLjAgdG8gMS4wXG4gIGludGVycHJldGF0aW9uOiBzdHJpbmc7ICAgIC8vIEh1bWFuLXJlYWRhYmxlIGV4cGxhbmF0aW9uXG4gIHRva2VuQ291bnQ6IG51bWJlcjsgICAgICAgIC8vIE51bWJlciBvZiB1bmlxdWUgdG9rZW5zXG4gIG92ZXJsYXBDb3VudDogbnVtYmVyOyAgICAgIC8vIE51bWJlciBvZiBvdmVybGFwcGluZyB0b2tlbnNcbn1cblxuLyoqXG4gKiBQYWlyd2lzZSBzaW1pbGFyaXR5IGJldHdlZW4gdHdvIGVsZW1lbnRzXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGFpcndpc2VTaW1pbGFyaXR5IHtcbiAgZWxlbWVudDE6IHN0cmluZztcbiAgZWxlbWVudDI6IHN0cmluZztcbiAgc2ltaWxhcml0eTogU2NvcmluZ1Jlc3VsdDtcbiAgdGltZXN0YW1wOiBzdHJpbmc7XG59XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBmb3Igc2NvcmluZyBhbGdvcml0aG1cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTY29yaW5nQ29uZmlnIHtcbiAgbWluVG9rZW5MZW5ndGg6IG51bWJlcjtcbiAgY2FjaGVFeHBpcnk6IG51bWJlcjtcbiAgbWF4Q2FjaGVTaXplOiBudW1iZXI7ICAvLyBNYXhpbXVtIGNhY2hlIGVudHJpZXMgZm9yIExSVSBldmljdGlvbiAgICAgIC8vIG1pbGxpc2Vjb25kc1xuICBlbnRyb3B5QmFuZHM6IHtcbiAgICBsb3c6IG51bWJlcjsgICAgICAgICAgIC8vIDwgMy4wIHR5cGljYWxseSAoaGlnaCByZXBldGl0aW9uL2NvbW1vbiB3b3JkcylcbiAgICBtb2RlcmF0ZTogbnVtYmVyOyAgICAgIC8vIDMuMCAtIDYuMCB0eXBpY2FsbHkgKGJhbGFuY2VkIHZvY2FidWxhcnkpXG4gICAgaGlnaDogbnVtYmVyOyAgICAgICAgICAvLyA+IDYuMCB0eXBpY2FsbHkgKGRpdmVyc2Ugc3BlY2lhbGl6ZWQgdGVybXMpXG4gIH07XG4gIGphY2NhcmRUaHJlc2hvbGRzOiB7XG4gICAgbG93OiBudW1iZXI7ICAgICAgICAgICAvLyA8IDAuMlxuICAgIG1vZGVyYXRlOiBudW1iZXI7ICAgICAgLy8gMC4yIC0gMC42XG4gICAgaGlnaDogbnVtYmVyOyAgICAgICAgICAvLyA+IDAuNlxuICB9O1xufVxuXG5leHBvcnQgY2xhc3MgTkxQU2NvcmluZ01hbmFnZXIge1xuICBwcml2YXRlIGNhY2hlOiBNYXA8c3RyaW5nLCB7IHJlc3VsdDogU2NvcmluZ1Jlc3VsdDsgdGltZXN0YW1wOiBudW1iZXI7IGxhc3RBY2Nlc3NlZDogbnVtYmVyIH0+O1xuICBwcml2YXRlIGNhY2hlQWNjZXNzT3JkZXI6IHN0cmluZ1tdOyAgLy8gVHJhY2sgYWNjZXNzIG9yZGVyIGZvciBMUlVcbiAgcHJpdmF0ZSBjb25maWc6IFNjb3JpbmdDb25maWc7XG4gIHByaXZhdGUgdW5pY29kZVZhbGlkYXRvcjogVW5pY29kZVZhbGlkYXRvcjtcbiAgcHJpdmF0ZSBjbGVhbnVwSW50ZXJ2YWw/OiBOb2RlSlMuVGltZW91dDtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBjb25maWc/OiBQYXJ0aWFsPFNjb3JpbmdDb25maWc+LFxuICAgIGluZGV4Q29uZmlnTWFuYWdlcjogSW5kZXhDb25maWdNYW5hZ2VyID0gbmV3IEluZGV4Q29uZmlnTWFuYWdlcigpXG4gICkge1xuICAgIC8vIEdldCBjb25maWcgZnJvbSBjZW50cmFsIG1hbmFnZXJcbiAgICBjb25zdCBpbmRleENvbmZpZyA9IGluZGV4Q29uZmlnTWFuYWdlci5nZXRDb25maWcoKTtcblxuICAgIHRoaXMuY29uZmlnID0ge1xuICAgICAgbWluVG9rZW5MZW5ndGg6IGluZGV4Q29uZmlnLm5scC5taW5Ub2tlbkxlbmd0aCxcbiAgICAgIGNhY2hlRXhwaXJ5OiBpbmRleENvbmZpZy5ubHAuY2FjaGVFeHBpcnlNaW51dGVzICogNjAgKiAxMDAwLFxuICAgICAgbWF4Q2FjaGVTaXplOiBpbmRleENvbmZpZy5tZW1vcnkubWF4Q2FjaGVTaXplLFxuICAgICAgZW50cm9weUJhbmRzOiBpbmRleENvbmZpZy5ubHAuZW50cm9weUJhbmRzLFxuICAgICAgamFjY2FyZFRocmVzaG9sZHM6IGluZGV4Q29uZmlnLm5scC5qYWNjYXJkVGhyZXNob2xkcyxcbiAgICAgIC4uLmNvbmZpZ1xuICAgIH07XG5cbiAgICB0aGlzLmNhY2hlID0gbmV3IE1hcCgpO1xuICAgIHRoaXMuY2FjaGVBY2Nlc3NPcmRlciA9IFtdO1xuICAgIHRoaXMudW5pY29kZVZhbGlkYXRvciA9IG5ldyBVbmljb2RlVmFsaWRhdG9yKCk7XG5cbiAgICAvLyBQZXJpb2RpYyBjbGVhbnVwIG9mIGV4cGlyZWQgZW50cmllc1xuICAgIHRoaXMuY2xlYW51cEludGVydmFsID0gc2V0SW50ZXJ2YWwoKCkgPT4gdGhpcy5jbGVhbkV4cGlyZWRDYWNoZSgpLCA2MDAwMCk7IC8vIEV2ZXJ5IG1pbnV0ZVxuXG4gICAgaWYgKHR5cGVvZiB0aGlzLmNsZWFudXBJbnRlcnZhbC51bnJlZiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgdGhpcy5jbGVhbnVwSW50ZXJ2YWwudW5yZWYoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2xlYW4gYW5kIHRva2VuaXplIHRleHQgZm9yIGFuYWx5c2lzXG4gICAqIFdvcmtzIHdpdGggYW55IGxhbmd1YWdlIC0gbm8gaGFyZGNvZGVkIHN0b3Agd29yZHNcbiAgICovXG4gIHByaXZhdGUgY2xlYW5BbmRUb2tlbml6ZSh0ZXh0OiBzdHJpbmcpOiBTZXQ8c3RyaW5nPiB7XG4gICAgLy8gTm9ybWFsaXplIFVuaWNvZGUgZm9yIHNlY3VyaXR5XG4gICAgY29uc3QgdmFsaWRhdGlvbiA9IFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKHRleHQpO1xuICAgIGlmICh2YWxpZGF0aW9uLmRldGVjdGVkSXNzdWVzICYmIHZhbGlkYXRpb24uZGV0ZWN0ZWRJc3N1ZXMubGVuZ3RoID4gMCkge1xuICAgICAgbG9nZ2VyLndhcm4oJ1VuaWNvZGUgaXNzdWVzIGluIE5MUCB0ZXh0JywgeyBpc3N1ZXM6IHZhbGlkYXRpb24uZGV0ZWN0ZWRJc3N1ZXMgfSk7XG4gICAgfVxuICAgIHRleHQgPSB2YWxpZGF0aW9uLm5vcm1hbGl6ZWRDb250ZW50O1xuXG4gICAgLy8gQ29udmVydCB0byBsb3dlcmNhc2UgYW5kIHNwbGl0IG9uIHdvcmQgYm91bmRhcmllc1xuICAgIC8vIEtlZXAgVW5pY29kZSBsZXR0ZXIgY2hhcmFjdGVycyBmb3IgbXVsdGlsaW5ndWFsIHN1cHBvcnRcbiAgICBjb25zdCB0b2tlbnMgPSB0ZXh0LnRvTG93ZXJDYXNlKClcbiAgICAgIC5yZXBsYWNlQWxsKC9bXlxccHtMfVxccHtOfVxcc18tXS9ndSwgJyAnKSAgLy8gVW5pY29kZS1hd2FyZToga2VlcCBsZXR0ZXJzLCBudW1iZXJzLCB1bmRlcnNjb3JlLCBoeXBoZW5cbiAgICAgIC5zcGxpdCgvXFxzKy8pXG4gICAgICAuZmlsdGVyKHRva2VuID0+IHRva2VuLmxlbmd0aCA+PSB0aGlzLmNvbmZpZy5taW5Ub2tlbkxlbmd0aCk7XG5cbiAgICByZXR1cm4gbmV3IFNldCh0b2tlbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGN1bGF0ZSBKYWNjYXJkIHNpbWlsYXJpdHkgYmV0d2VlbiB0d28gdGV4dCBzdHJpbmdzXG4gICAqXG4gICAqIEphY2NhcmQgPSB8QSDiiKkgQnwgLyB8QSDiiKogQnxcbiAgICpcbiAgICogUmV0dXJucyB2YWx1ZSBiZXR3ZWVuIDAgKG5vIG92ZXJsYXApIGFuZCAxIChpZGVudGljYWwpXG4gICAqL1xuICBwdWJsaWMgY2FsY3VsYXRlSmFjY2FyZCh0ZXh0MTogc3RyaW5nLCB0ZXh0Mjogc3RyaW5nKTogbnVtYmVyIHtcbiAgICBjb25zdCB0b2tlbnMxID0gdGhpcy5jbGVhbkFuZFRva2VuaXplKHRleHQxKTtcbiAgICBjb25zdCB0b2tlbnMyID0gdGhpcy5jbGVhbkFuZFRva2VuaXplKHRleHQyKTtcblxuICAgIGlmICh0b2tlbnMxLnNpemUgPT09IDAgJiYgdG9rZW5zMi5zaXplID09PSAwKSB7XG4gICAgICByZXR1cm4gMS4wOyAvLyBCb3RoIGVtcHR5ID0gaWRlbnRpY2FsXG4gICAgfVxuXG4gICAgaWYgKHRva2VuczEuc2l6ZSA9PT0gMCB8fCB0b2tlbnMyLnNpemUgPT09IDApIHtcbiAgICAgIHJldHVybiAwLjA7IC8vIE9uZSBlbXB0eSA9IG5vIHNpbWlsYXJpdHlcbiAgICB9XG5cbiAgICAvLyBDYWxjdWxhdGUgaW50ZXJzZWN0aW9uXG4gICAgY29uc3QgaW50ZXJzZWN0aW9uID0gbmV3IFNldChbLi4udG9rZW5zMV0uZmlsdGVyKHRva2VuID0+IHRva2VuczIuaGFzKHRva2VuKSkpO1xuXG4gICAgLy8gQ2FsY3VsYXRlIHVuaW9uXG4gICAgY29uc3QgdW5pb24gPSBuZXcgU2V0KFsuLi50b2tlbnMxLCAuLi50b2tlbnMyXSk7XG5cbiAgICByZXR1cm4gaW50ZXJzZWN0aW9uLnNpemUgLyB1bmlvbi5zaXplO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGN1bGF0ZSBTaGFubm9uIGVudHJvcHkgZm9yIHRleHRcbiAgICpcbiAgICogSChYKSA9IC3OoyBwKHgpICogbG9nMihwKHgpKVxuICAgKlxuICAgKiBNZWFzdXJlcyBpbmZvcm1hdGlvbiBkZW5zaXR5L3ZvY2FidWxhcnkgcmljaG5lc3NcbiAgICogSGlnaGVyIGVudHJvcHkgPSBtb3JlIGRpdmVyc2Ugdm9jYWJ1bGFyeVxuICAgKi9cbiAgcHVibGljIGNhbGN1bGF0ZUVudHJvcHkodGV4dDogc3RyaW5nKTogbnVtYmVyIHtcbiAgICBjb25zdCB0b2tlbnMgPSBBcnJheS5mcm9tKHRoaXMuY2xlYW5BbmRUb2tlbml6ZSh0ZXh0KSk7XG5cbiAgICBpZiAodG9rZW5zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIDA7XG4gICAgfVxuXG4gICAgLy8gQ2FsY3VsYXRlIHRva2VuIGZyZXF1ZW5jaWVzXG4gICAgY29uc3QgZnJlcXVlbmNpZXMgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xuICAgIGZvciAoY29uc3QgdG9rZW4gb2YgdG9rZW5zKSB7XG4gICAgICBmcmVxdWVuY2llcy5zZXQodG9rZW4sIChmcmVxdWVuY2llcy5nZXQodG9rZW4pIHx8IDApICsgMSk7XG4gICAgfVxuXG4gICAgLy8gQ2FsY3VsYXRlIHByb2JhYmlsaXRpZXMgYW5kIGVudHJvcHlcbiAgICBsZXQgZW50cm9weSA9IDA7XG4gICAgY29uc3QgdG90YWxUb2tlbnMgPSB0b2tlbnMubGVuZ3RoO1xuXG4gICAgZm9yIChjb25zdCBjb3VudCBvZiBmcmVxdWVuY2llcy52YWx1ZXMoKSkge1xuICAgICAgY29uc3QgcHJvYmFiaWxpdHkgPSBjb3VudCAvIHRvdGFsVG9rZW5zO1xuICAgICAgaWYgKHByb2JhYmlsaXR5ID4gMCkge1xuICAgICAgICBlbnRyb3B5IC09IHByb2JhYmlsaXR5ICogTWF0aC5sb2cyKHByb2JhYmlsaXR5KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZW50cm9weTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGUgY29tYmluZWQgcmVsZXZhbmNlIHNjb3JlIHVzaW5nIEphY2NhcmQgYW5kIGVudHJvcHlcbiAgICpcbiAgICogSW50ZXJwcmV0cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gc2ltaWxhcml0eSBhbmQgY29tcGxleGl0eVxuICAgKi9cbiAgcHVibGljIHNjb3JlUmVsZXZhbmNlKHRleHQxOiBzdHJpbmcsIHRleHQyOiBzdHJpbmcpOiBTY29yaW5nUmVzdWx0IHtcbiAgICAvLyBDaGVjayBjYWNoZSBmaXJzdFxuICAgIGNvbnN0IGNhY2hlS2V5ID0gYCR7dGV4dDEuc3Vic3RyaW5nKDAsIDUwKX06Ojoke3RleHQyLnN1YnN0cmluZygwLCA1MCl9YDtcbiAgICBjb25zdCBjYWNoZWQgPSB0aGlzLmNhY2hlLmdldChjYWNoZUtleSk7XG5cbiAgICBpZiAoY2FjaGVkICYmIERhdGUubm93KCkgLSBjYWNoZWQudGltZXN0YW1wIDwgdGhpcy5jb25maWcuY2FjaGVFeHBpcnkpIHtcbiAgICAgIC8vIFVwZGF0ZSBhY2Nlc3Mgb3JkZXIgZm9yIExSVVxuICAgICAgY2FjaGVkLmxhc3RBY2Nlc3NlZCA9IERhdGUubm93KCk7XG4gICAgICB0aGlzLnVwZGF0ZUFjY2Vzc09yZGVyKGNhY2hlS2V5KTtcbiAgICAgIHJldHVybiBjYWNoZWQucmVzdWx0O1xuICAgIH1cblxuICAgIC8vIENhbGN1bGF0ZSBtZXRyaWNzXG4gICAgY29uc3QgamFjY2FyZCA9IHRoaXMuY2FsY3VsYXRlSmFjY2FyZCh0ZXh0MSwgdGV4dDIpO1xuICAgIGNvbnN0IGVudHJvcHkxID0gdGhpcy5jYWxjdWxhdGVFbnRyb3B5KHRleHQxKTtcbiAgICBjb25zdCBlbnRyb3B5MiA9IHRoaXMuY2FsY3VsYXRlRW50cm9weSh0ZXh0Mik7XG4gICAgY29uc3QgYXZnRW50cm9weSA9IChlbnRyb3B5MSArIGVudHJvcHkyKSAvIDI7XG5cbiAgICAvLyBHZXQgdG9rZW4gc2V0cyBmb3IgYWRkaXRpb25hbCBtZXRyaWNzXG4gICAgY29uc3QgdG9rZW5zMSA9IHRoaXMuY2xlYW5BbmRUb2tlbml6ZSh0ZXh0MSk7XG4gICAgY29uc3QgdG9rZW5zMiA9IHRoaXMuY2xlYW5BbmRUb2tlbml6ZSh0ZXh0Mik7XG4gICAgY29uc3QgaW50ZXJzZWN0aW9uID0gbmV3IFNldChbLi4udG9rZW5zMV0uZmlsdGVyKHRva2VuID0+IHRva2VuczIuaGFzKHRva2VuKSkpO1xuXG4gICAgLy8gSW50ZXJwcmV0IHRoZSBjb21iaW5hdGlvblxuICAgIGxldCBjb21iaW5lZFNjb3JlOiBudW1iZXI7XG4gICAgbGV0IGludGVycHJldGF0aW9uOiBzdHJpbmc7XG5cbiAgICAvLyBIaWdoIEphY2NhcmQgKyBNb2RlcmF0ZS1IaWdoIGVudHJvcHkgPSBFeGNlbGxlbnQgbWF0Y2ggKHNhbWUgZG9tYWluKVxuICAgIGlmIChqYWNjYXJkID49IHRoaXMuY29uZmlnLmphY2NhcmRUaHJlc2hvbGRzLmhpZ2ggJiZcbiAgICAgICAgYXZnRW50cm9weSA+PSB0aGlzLmNvbmZpZy5lbnRyb3B5QmFuZHMubG93KSB7XG4gICAgICAvLyBTY2FsZSBzY29yZSBiYXNlZCBvbiBlbnRyb3B5IHF1YWxpdHlcbiAgICAgIGNvbnN0IGVudHJvcHlRdWFsaXR5ID0gTWF0aC5taW4oMS4wLCAoYXZnRW50cm9weSAtIDIuMCkgLyA0LjApOyAvLyAwIGF0IGVudHJvcHk9MiwgMSBhdCBlbnRyb3B5PTYrXG4gICAgICBjb21iaW5lZFNjb3JlID0gMC43ICsgKGphY2NhcmQgLSAwLjYpICogMC41ICsgZW50cm9weVF1YWxpdHkgKiAwLjI7XG5cbiAgICAgIGlmIChhdmdFbnRyb3B5ID49IHRoaXMuY29uZmlnLmVudHJvcHlCYW5kcy5tb2RlcmF0ZSkge1xuICAgICAgICBpbnRlcnByZXRhdGlvbiA9ICdFeGNlbGxlbnQgbWF0Y2ggLSBzYW1lIHRlY2huaWNhbCBkb21haW4gd2l0aCByaWNoIHZvY2FidWxhcnknO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaW50ZXJwcmV0YXRpb24gPSAnR29vZCBtYXRjaCAtIGhpZ2ggb3ZlcmxhcCBidXQgc2ltcGxlciB2b2NhYnVsYXJ5JztcbiAgICAgIH1cbiAgICB9XG4gICAgLy8gSGlnaCBKYWNjYXJkICsgVmVyeSBMb3cgZW50cm9weSA9IENvbW1vbiB3b3JkIHBvbGx1dGlvblxuICAgIGVsc2UgaWYgKGphY2NhcmQgPj0gdGhpcy5jb25maWcuamFjY2FyZFRocmVzaG9sZHMuaGlnaCAmJlxuICAgICAgICAgICAgIGF2Z0VudHJvcHkgPCAyLjApIHtcbiAgICAgIGNvbWJpbmVkU2NvcmUgPSAwLjMgKyBqYWNjYXJkICogMC4yOyAvLyBQZW5hbGl6ZSBoZWF2aWx5XG4gICAgICBpbnRlcnByZXRhdGlvbiA9ICdTdXBlcmZpY2lhbCBzaW1pbGFyaXR5IC0gbW9zdGx5IGNvbW1vbiB3b3Jkcyc7XG4gICAgfVxuICAgIC8vIE1vZGVyYXRlIEphY2NhcmQgKyBHb29kIGVudHJvcHkgPSBSZWxhdGVkIGNvbmNlcHRzXG4gICAgZWxzZSBpZiAoamFjY2FyZCA+PSB0aGlzLmNvbmZpZy5qYWNjYXJkVGhyZXNob2xkcy5tb2RlcmF0ZSAmJlxuICAgICAgICAgICAgIGF2Z0VudHJvcHkgPj0gdGhpcy5jb25maWcuZW50cm9weUJhbmRzLmxvdykge1xuICAgICAgY29tYmluZWRTY29yZSA9IDAuNCArIGphY2NhcmQgKiAwLjQgKyAoYXZnRW50cm9weSAvIDEwKSAqIDAuMjtcbiAgICAgIGludGVycHJldGF0aW9uID0gJ01vZGVyYXRlIG1hdGNoIC0gcmVsYXRlZCBjb25jZXB0cyB3aXRoIGdvb2QgY29tcGxleGl0eSc7XG4gICAgfVxuICAgIC8vIExvdyBKYWNjYXJkICsgU2ltaWxhciBlbnRyb3B5ID0gRGlmZmVyZW50IGRvbWFpbnNcbiAgICBlbHNlIGlmIChqYWNjYXJkIDwgdGhpcy5jb25maWcuamFjY2FyZFRocmVzaG9sZHMubG93ICYmXG4gICAgICAgICAgICAgTWF0aC5hYnMoZW50cm9weTEgLSBlbnRyb3B5MikgPCAxLjApIHtcbiAgICAgIGNvbWJpbmVkU2NvcmUgPSBqYWNjYXJkICogMC41O1xuICAgICAgaW50ZXJwcmV0YXRpb24gPSAnRGlmZmVyZW50IGRvbWFpbnMgd2l0aCBzaW1pbGFyIGNvbXBsZXhpdHknO1xuICAgIH1cbiAgICAvLyBMb3cgSmFjY2FyZCArIERpZmZlcmVudCBlbnRyb3B5ID0gVW5yZWxhdGVkXG4gICAgZWxzZSB7XG4gICAgICBjb21iaW5lZFNjb3JlID0gamFjY2FyZCAqIDAuMztcbiAgICAgIGludGVycHJldGF0aW9uID0gJ0xvdyByZWxldmFuY2UgLSBkaWZmZXJlbnQgdG9waWNzIGFuZCBjb21wbGV4aXR5JztcbiAgICB9XG5cbiAgICAvLyBFbnN1cmUgc2NvcmUgaXMgYmV0d2VlbiAwIGFuZCAxXG4gICAgY29tYmluZWRTY29yZSA9IE1hdGgubWF4KDAsIE1hdGgubWluKDEsIGNvbWJpbmVkU2NvcmUpKTtcblxuICAgIGNvbnN0IHJlc3VsdDogU2NvcmluZ1Jlc3VsdCA9IHtcbiAgICAgIGphY2NhcmQsXG4gICAgICBlbnRyb3B5OiBhdmdFbnRyb3B5LFxuICAgICAgY29tYmluZWRTY29yZSxcbiAgICAgIGludGVycHJldGF0aW9uLFxuICAgICAgdG9rZW5Db3VudDogdG9rZW5zMS5zaXplICsgdG9rZW5zMi5zaXplLFxuICAgICAgb3ZlcmxhcENvdW50OiBpbnRlcnNlY3Rpb24uc2l6ZVxuICAgIH07XG5cbiAgICAvLyBDYWNoZSB0aGUgcmVzdWx0IHdpdGggTFJVIG1hbmFnZW1lbnRcbiAgICB0aGlzLmFkZFRvQ2FjaGUoY2FjaGVLZXksIHJlc3VsdCk7XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkIGEgcGFpcndpc2Ugc2ltaWxhcml0eSBtYXRyaXggZm9yIG11bHRpcGxlIHRleHRzXG4gICAqXG4gICAqIFVzZWZ1bCBmb3IgY2x1c3RlcmluZyBhbmQgcmVsYXRpb25zaGlwIGRpc2NvdmVyeVxuICAgKi9cbiAgcHVibGljIGJ1aWxkU2ltaWxhcml0eU1hdHJpeChcbiAgICBlbGVtZW50czogTWFwPHN0cmluZywgc3RyaW5nPlxuICApOiBNYXA8c3RyaW5nLCBNYXA8c3RyaW5nLCBTY29yaW5nUmVzdWx0Pj4ge1xuICAgIGNvbnN0IG1hdHJpeCA9IG5ldyBNYXA8c3RyaW5nLCBNYXA8c3RyaW5nLCBTY29yaW5nUmVzdWx0Pj4oKTtcbiAgICBjb25zdCBrZXlzID0gQXJyYXkuZnJvbShlbGVtZW50cy5rZXlzKCkpO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBrZXkxID0ga2V5c1tpXTtcbiAgICAgIGNvbnN0IHRleHQxID0gZWxlbWVudHMuZ2V0KGtleTEpITtcblxuICAgICAgaWYgKCFtYXRyaXguaGFzKGtleTEpKSB7XG4gICAgICAgIG1hdHJpeC5zZXQoa2V5MSwgbmV3IE1hcCgpKTtcbiAgICAgIH1cblxuICAgICAgZm9yIChsZXQgaiA9IGkgKyAxOyBqIDwga2V5cy5sZW5ndGg7IGorKykge1xuICAgICAgICBjb25zdCBrZXkyID0ga2V5c1tqXTtcbiAgICAgICAgY29uc3QgdGV4dDIgPSBlbGVtZW50cy5nZXQoa2V5MikhO1xuXG4gICAgICAgIC8vIENhbGN1bGF0ZSBzaW1pbGFyaXR5XG4gICAgICAgIGNvbnN0IHNpbWlsYXJpdHkgPSB0aGlzLnNjb3JlUmVsZXZhbmNlKHRleHQxLCB0ZXh0Mik7XG5cbiAgICAgICAgLy8gU3RvcmUgYmlkaXJlY3Rpb25hbGx5XG4gICAgICAgIG1hdHJpeC5nZXQoa2V5MSkhLnNldChrZXkyLCBzaW1pbGFyaXR5KTtcblxuICAgICAgICBpZiAoIW1hdHJpeC5oYXMoa2V5MikpIHtcbiAgICAgICAgICBtYXRyaXguc2V0KGtleTIsIG5ldyBNYXAoKSk7XG4gICAgICAgIH1cbiAgICAgICAgbWF0cml4LmdldChrZXkyKSEuc2V0KGtleTEsIHNpbWlsYXJpdHkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBtYXRyaXg7XG4gIH1cblxuICAvKipcbiAgICogRmluZCBtb3N0IHNpbWlsYXIgZWxlbWVudHMgdG8gYSBnaXZlbiB0ZXh0XG4gICAqL1xuICBwdWJsaWMgZmluZFNpbWlsYXIoXG4gICAgdGFyZ2V0VGV4dDogc3RyaW5nLFxuICAgIGNhbmRpZGF0ZXM6IE1hcDxzdHJpbmcsIHN0cmluZz4sXG4gICAgdG9wSzogbnVtYmVyID0gNVxuICApOiBBcnJheTx7IG5hbWU6IHN0cmluZzsgc2NvcmU6IFNjb3JpbmdSZXN1bHQgfT4ge1xuICAgIGNvbnN0IHNjb3JlczogQXJyYXk8eyBuYW1lOiBzdHJpbmc7IHNjb3JlOiBTY29yaW5nUmVzdWx0IH0+ID0gW107XG5cbiAgICBmb3IgKGNvbnN0IFtuYW1lLCB0ZXh0XSBvZiBjYW5kaWRhdGVzLmVudHJpZXMoKSkge1xuICAgICAgY29uc3Qgc2NvcmUgPSB0aGlzLnNjb3JlUmVsZXZhbmNlKHRhcmdldFRleHQsIHRleHQpO1xuICAgICAgc2NvcmVzLnB1c2goeyBuYW1lLCBzY29yZSB9KTtcbiAgICB9XG5cbiAgICAvLyBTb3J0IGJ5IGNvbWJpbmVkIHNjb3JlIGRlc2NlbmRpbmdcbiAgICBzY29yZXMuc29ydCgoYSwgYikgPT4gYi5zY29yZS5jb21iaW5lZFNjb3JlIC0gYS5zY29yZS5jb21iaW5lZFNjb3JlKTtcblxuICAgIHJldHVybiBzY29yZXMuc2xpY2UoMCwgdG9wSyk7XG4gIH1cblxuICAvKipcbiAgICogRXh0cmFjdCBrZXkgdGVybXMgZnJvbSB0ZXh0IGJhc2VkIG9uIGVudHJvcHkgY29udHJpYnV0aW9uXG4gICAqXG4gICAqIFRlcm1zIHRoYXQgY29udHJpYnV0ZSBtb3N0IHRvIGVudHJvcHkgYXJlIGxpa2VseSBpbXBvcnRhbnRcbiAgICovXG4gIHB1YmxpYyBleHRyYWN0S2V5VGVybXModGV4dDogc3RyaW5nLCB0b3BLOiBudW1iZXIgPSAxMCk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCB0b2tlbnMgPSBBcnJheS5mcm9tKHRoaXMuY2xlYW5BbmRUb2tlbml6ZSh0ZXh0KSk7XG5cbiAgICBpZiAodG9rZW5zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIC8vIENhbGN1bGF0ZSB0b2tlbiBmcmVxdWVuY2llc1xuICAgIGNvbnN0IGZyZXF1ZW5jaWVzID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcbiAgICBmb3IgKGNvbnN0IHRva2VuIG9mIHRva2Vucykge1xuICAgICAgZnJlcXVlbmNpZXMuc2V0KHRva2VuLCAoZnJlcXVlbmNpZXMuZ2V0KHRva2VuKSB8fCAwKSArIDEpO1xuICAgIH1cblxuICAgIC8vIENhbGN1bGF0ZSBlbnRyb3B5IGNvbnRyaWJ1dGlvbiBmb3IgZWFjaCB1bmlxdWUgdG9rZW5cbiAgICBjb25zdCB0b3RhbFRva2VucyA9IHRva2Vucy5sZW5ndGg7XG4gICAgY29uc3QgY29udHJpYnV0aW9uczogQXJyYXk8eyB0b2tlbjogc3RyaW5nOyBjb250cmlidXRpb246IG51bWJlciB9PiA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBbdG9rZW4sIGNvdW50XSBvZiBmcmVxdWVuY2llcy5lbnRyaWVzKCkpIHtcbiAgICAgIGNvbnN0IHByb2JhYmlsaXR5ID0gY291bnQgLyB0b3RhbFRva2VucztcbiAgICAgIGNvbnN0IGNvbnRyaWJ1dGlvbiA9IC1wcm9iYWJpbGl0eSAqIE1hdGgubG9nMihwcm9iYWJpbGl0eSk7XG4gICAgICBjb250cmlidXRpb25zLnB1c2goeyB0b2tlbiwgY29udHJpYnV0aW9uIH0pO1xuICAgIH1cblxuICAgIC8vIFNvcnQgYnkgY29udHJpYnV0aW9uIGRlc2NlbmRpbmdcbiAgICBjb250cmlidXRpb25zLnNvcnQoKGEsIGIpID0+IGIuY29udHJpYnV0aW9uIC0gYS5jb250cmlidXRpb24pO1xuXG4gICAgcmV0dXJuIGNvbnRyaWJ1dGlvbnMuc2xpY2UoMCwgdG9wSykubWFwKGMgPT4gYy50b2tlbik7XG4gIH1cblxuICAvKipcbiAgICogQWRkIHJlc3VsdCB0byBjYWNoZSB3aXRoIExSVSBldmljdGlvblxuICAgKi9cbiAgcHJpdmF0ZSBhZGRUb0NhY2hlKGtleTogc3RyaW5nLCByZXN1bHQ6IFNjb3JpbmdSZXN1bHQpOiB2b2lkIHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuXG4gICAgLy8gQ2hlY2sgaWYgd2UgbmVlZCB0byBldmljdFxuICAgIGlmICh0aGlzLmNhY2hlLnNpemUgPj0gdGhpcy5jb25maWcubWF4Q2FjaGVTaXplICYmICF0aGlzLmNhY2hlLmhhcyhrZXkpKSB7XG4gICAgICAvLyBGaW5kIGxlYXN0IHJlY2VudGx5IHVzZWQgZW50cnlcbiAgICAgIGxldCBscnVLZXk6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAgICAgbGV0IG9sZGVzdEFjY2VzcyA9IG5vdztcblxuICAgICAgZm9yIChjb25zdCBbaywgdl0gb2YgdGhpcy5jYWNoZS5lbnRyaWVzKCkpIHtcbiAgICAgICAgaWYgKHYubGFzdEFjY2Vzc2VkIDwgb2xkZXN0QWNjZXNzKSB7XG4gICAgICAgICAgb2xkZXN0QWNjZXNzID0gdi5sYXN0QWNjZXNzZWQ7XG4gICAgICAgICAgbHJ1S2V5ID0gaztcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAobHJ1S2V5KSB7XG4gICAgICAgIHRoaXMuY2FjaGUuZGVsZXRlKGxydUtleSk7XG4gICAgICAgIGNvbnN0IGlkeCA9IHRoaXMuY2FjaGVBY2Nlc3NPcmRlci5pbmRleE9mKGxydUtleSk7XG4gICAgICAgIGlmIChpZHggPiAtMSkge1xuICAgICAgICAgIHRoaXMuY2FjaGVBY2Nlc3NPcmRlci5zcGxpY2UoaWR4LCAxKTtcbiAgICAgICAgfVxuICAgICAgICBsb2dnZXIuZGVidWcoJ0V2aWN0ZWQgTFJVIGNhY2hlIGVudHJ5JywgeyBrZXk6IGxydUtleSwgY2FjaGVTaXplOiB0aGlzLmNhY2hlLnNpemUgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQWRkIG5ldyBlbnRyeVxuICAgIHRoaXMuY2FjaGUuc2V0KGtleSwge1xuICAgICAgcmVzdWx0LFxuICAgICAgdGltZXN0YW1wOiBub3csXG4gICAgICBsYXN0QWNjZXNzZWQ6IG5vd1xuICAgIH0pO1xuICAgIHRoaXMudXBkYXRlQWNjZXNzT3JkZXIoa2V5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgYWNjZXNzIG9yZGVyIGZvciBMUlUgdHJhY2tpbmdcbiAgICovXG4gIHByaXZhdGUgdXBkYXRlQWNjZXNzT3JkZXIoa2V5OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBpZHggPSB0aGlzLmNhY2hlQWNjZXNzT3JkZXIuaW5kZXhPZihrZXkpO1xuICAgIGlmIChpZHggPiAtMSkge1xuICAgICAgdGhpcy5jYWNoZUFjY2Vzc09yZGVyLnNwbGljZShpZHgsIDEpO1xuICAgIH1cbiAgICB0aGlzLmNhY2hlQWNjZXNzT3JkZXIucHVzaChrZXkpO1xuICB9XG5cbiAgLyoqXG4gICAqIENsZWFuIGV4cGlyZWQgY2FjaGUgZW50cmllc1xuICAgKi9cbiAgcHJpdmF0ZSBjbGVhbkV4cGlyZWRDYWNoZSgpOiB2b2lkIHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIGxldCByZW1vdmVkID0gMDtcblxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIHRoaXMuY2FjaGUuZW50cmllcygpKSB7XG4gICAgICBpZiAobm93IC0gdmFsdWUudGltZXN0YW1wID4gdGhpcy5jb25maWcuY2FjaGVFeHBpcnkpIHtcbiAgICAgICAgdGhpcy5jYWNoZS5kZWxldGUoa2V5KTtcbiAgICAgICAgY29uc3QgaWR4ID0gdGhpcy5jYWNoZUFjY2Vzc09yZGVyLmluZGV4T2Yoa2V5KTtcbiAgICAgICAgaWYgKGlkeCA+IC0xKSB7XG4gICAgICAgICAgdGhpcy5jYWNoZUFjY2Vzc09yZGVyLnNwbGljZShpZHgsIDEpO1xuICAgICAgICB9XG4gICAgICAgIHJlbW92ZWQrKztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAocmVtb3ZlZCA+IDApIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZygnQ2xlYW5lZCBleHBpcmVkIGNhY2hlIGVudHJpZXMnLCB7IHJlbW92ZWQsIHJlbWFpbmluZzogdGhpcy5jYWNoZS5zaXplIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDbGVhciB0aGUgY2FjaGVcbiAgICovXG4gIHB1YmxpYyBjbGVhckNhY2hlKCk6IHZvaWQge1xuICAgIGNvbnN0IGNsZWFyZWQgPSB0aGlzLmNhY2hlLnNpemU7XG4gICAgdGhpcy5jYWNoZS5jbGVhcigpO1xuICAgIHRoaXMuY2FjaGVBY2Nlc3NPcmRlciA9IFtdO1xuICAgIGlmIChjbGVhcmVkID4gMCkge1xuICAgICAgbG9nZ2VyLmRlYnVnKCdOTFAgc2NvcmluZyBjYWNoZSBjbGVhcmVkJywgeyBlbnRyaWVzQ2xlYXJlZDogY2xlYXJlZCB9KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IGNhY2hlIHN0YXRpc3RpY3NcbiAgICovXG4gIHB1YmxpYyBnZXRDYWNoZVN0YXRzKCk6IHsgc2l6ZTogbnVtYmVyOyBvbGRlc3RFbnRyeTogbnVtYmVyIHwgbnVsbCB9IHtcbiAgICBsZXQgb2xkZXN0OiBudW1iZXIgfCBudWxsID0gbnVsbDtcblxuICAgIGZvciAoY29uc3QgZW50cnkgb2YgdGhpcy5jYWNoZS52YWx1ZXMoKSkge1xuICAgICAgaWYgKG9sZGVzdCA9PT0gbnVsbCB8fCBlbnRyeS50aW1lc3RhbXAgPCBvbGRlc3QpIHtcbiAgICAgICAgb2xkZXN0ID0gZW50cnkudGltZXN0YW1wO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBzaXplOiB0aGlzLmNhY2hlLnNpemUsXG4gICAgICBvbGRlc3RFbnRyeTogb2xkZXN0XG4gICAgfTtcbiAgfVxuXG4gIHB1YmxpYyBkaXNwb3NlKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmNsZWFudXBJbnRlcnZhbCkge1xuICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLmNsZWFudXBJbnRlcnZhbCk7XG4gICAgICB0aGlzLmNsZWFudXBJbnRlcnZhbCA9IHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cbn1cbiJdfQ==