UNPKG

llmverify

Version:

AI Output Verification Toolkit — Local-first LLM safety, hallucination detection, PII redaction, prompt injection defense, and runtime monitoring. Zero telemetry. OWASP LLM Top 10 aligned.

341 lines 49.1 kB
"use strict"; /** * Consistency Engine * * Checks for internal consistency, contradictions, and behavioral drift. * All processing is local - no external API calls. * * @module engines/consistency * @author Haiec * @license MIT */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ConsistencyEngine = void 0; const text_1 = require("../../utils/text"); const similarity_1 = require("../../utils/similarity"); // Sentiment indicators for drift detection const POSITIVE_SENTIMENT = /\b(?:good|great|excellent|amazing|wonderful|fantastic|love|happy|pleased|satisfied|success|benefit|advantage|improve|best)\b/gi; const NEGATIVE_SENTIMENT = /\b(?:bad|terrible|awful|horrible|hate|angry|frustrated|disappointed|failure|problem|issue|worst|damage|harm|risk)\b/gi; const NEUTRAL_MARKERS = /\b(?:however|although|but|nevertheless|on the other hand|conversely|alternatively)\b/gi; // Style indicators const FORMAL_MARKERS = /\b(?:therefore|furthermore|consequently|moreover|thus|hence|accordingly|subsequently|notwithstanding)\b/gi; const INFORMAL_MARKERS = /\b(?:gonna|wanna|kinda|sorta|yeah|nope|cool|awesome|stuff|things|basically|literally|actually|like)\b/gi; // Technical indicators const TECHNICAL_MARKERS = /\b(?:algorithm|function|parameter|variable|implementation|interface|protocol|architecture|framework|module|API|database|server|client)\b/gi; // Numerical patterns for consistency const NUMERICAL_PATTERN = /\b\d+(?:\.\d+)?(?:\s*(?:%|percent|million|billion|thousand|hundred))?\b/gi; class ConsistencyEngine { constructor(config) { this.config = config; this.LIMITATIONS = [ 'Pattern-based consistency checking', 'May miss subtle contradictions', 'English language only', 'Context-dependent accuracy', 'Requires sufficient text length for meaningful analysis' ]; this.METHODOLOGY = 'Analyzes text sections for internal consistency using similarity metrics, ' + 'sentiment analysis, style detection, and contradiction pattern matching. ' + 'Identifies potential logical conflicts, semantic drift, tone shifts, and ' + 'numerical inconsistencies across sections.'; } async check(content) { const sections = (0, text_1.splitParagraphs)(content); if (sections.length < 2) { return this.createMinimalResult(sections); } // Calculate similarity matrix const matrix = this.calculateSimilarityMatrix(sections); // Calculate average similarity const avgSimilarity = this.calculateAverageSimilarity(matrix); // Detect contradictions const contradictions = this.detectContradictions(sections); // Enhanced drift detection const sentimentDrift = this.detectSentimentDrift(sections); const styleDrift = this.detectStyleDrift(sections); const lengthDrift = this.detectLengthDrift(sections); const numericalInconsistencies = this.detectNumericalInconsistencies(sections); // Combine drift signals const driftScore = ((sentimentDrift ? 0.3 : 0) + (styleDrift ? 0.3 : 0) + (lengthDrift ? 0.2 : 0) + (numericalInconsistencies.length > 0 ? 0.2 : 0) + (avgSimilarity < 0.5 ? 0.3 : 0)); // Determine stability const stable = avgSimilarity > 0.6 && contradictions.length === 0 && driftScore < 0.3; const drift = driftScore >= 0.4 || avgSimilarity < 0.4; // Calculate confidence const confidence = this.calculateConfidence(sections.length, contradictions.length); // Add drift details to contradictions if detected if (sentimentDrift) { contradictions.push({ section1: 0, section2: sections.length - 1, claim1: 'Initial sentiment', claim2: 'Final sentiment', type: 'sentiment_drift', confidence: 0.7 }); } if (styleDrift) { contradictions.push({ section1: 0, section2: sections.length - 1, claim1: 'Initial style', claim2: 'Final style', type: 'style_drift', confidence: 0.7 }); } for (const numIssue of numericalInconsistencies) { contradictions.push(numIssue); } return { sections, avgSimilarity, similarityMatrix: this.config.output.verbose ? matrix : undefined, stable, drift, contradictions, confidence, limitations: this.LIMITATIONS, methodology: this.METHODOLOGY }; } /** * Detect sentiment drift across sections */ detectSentimentDrift(sections) { if (sections.length < 2) return false; const sentiments = sections.map(s => this.calculateSentiment(s)); // Check for significant sentiment shift const firstHalf = sentiments.slice(0, Math.floor(sentiments.length / 2)); const secondHalf = sentiments.slice(Math.floor(sentiments.length / 2)); const avgFirst = firstHalf.reduce((a, b) => a + b, 0) / firstHalf.length; const avgSecond = secondHalf.reduce((a, b) => a + b, 0) / secondHalf.length; // Significant drift if sentiment changes by more than 0.4 on -1 to 1 scale return Math.abs(avgFirst - avgSecond) > 0.4; } /** * Calculate sentiment score for a section (-1 to 1) */ calculateSentiment(text) { const positiveMatches = (text.match(POSITIVE_SENTIMENT) || []).length; const negativeMatches = (text.match(NEGATIVE_SENTIMENT) || []).length; const total = positiveMatches + negativeMatches; if (total === 0) return 0; return (positiveMatches - negativeMatches) / total; } /** * Detect style drift (formal to informal or vice versa) */ detectStyleDrift(sections) { if (sections.length < 2) return false; const styles = sections.map(s => this.calculateStyleScore(s)); // Check for significant style shift const firstStyle = styles[0]; const lastStyle = styles[styles.length - 1]; // Significant drift if style changes from formal to informal or vice versa return Math.abs(firstStyle - lastStyle) > 0.5; } /** * Calculate style score (-1 = informal, 1 = formal) */ calculateStyleScore(text) { const formalMatches = (text.match(FORMAL_MARKERS) || []).length; const informalMatches = (text.match(INFORMAL_MARKERS) || []).length; const technicalMatches = (text.match(TECHNICAL_MARKERS) || []).length; // Technical content tends to be more formal const adjustedFormal = formalMatches + (technicalMatches * 0.5); const total = adjustedFormal + informalMatches; if (total === 0) return 0; return (adjustedFormal - informalMatches) / total; } /** * Detect significant length drift */ detectLengthDrift(sections) { if (sections.length < 2) return false; const lengths = sections.map(s => s.length); const avgLength = lengths.reduce((a, b) => a + b, 0) / lengths.length; // Check if any section is drastically different in length for (const len of lengths) { const ratio = len / avgLength; if (ratio < 0.2 || ratio > 5) { return true; } } return false; } /** * Detect numerical inconsistencies */ detectNumericalInconsistencies(sections) { const inconsistencies = []; const numbersByContext = new Map(); // Extract numbers with their context for (let i = 0; i < sections.length; i++) { const section = sections[i]; const numbers = section.match(NUMERICAL_PATTERN) || []; for (const num of numbers) { // Get surrounding context (5 words before and after) const index = section.indexOf(num); const before = section.substring(Math.max(0, index - 50), index); const after = section.substring(index + num.length, index + num.length + 50); // Extract key context words const contextWords = (before + ' ' + after) .toLowerCase() .split(/\s+/) .filter(w => w.length > 4) .slice(0, 5) .join(' '); if (contextWords.length > 0) { if (!numbersByContext.has(contextWords)) { numbersByContext.set(contextWords, []); } numbersByContext.get(contextWords).push({ value: num, section: i }); } } } // Check for conflicting numbers in same context for (const [context, occurrences] of numbersByContext) { if (occurrences.length > 1) { const uniqueValues = new Set(occurrences.map(o => o.value)); if (uniqueValues.size > 1) { // Different numbers in same context const values = Array.from(uniqueValues); inconsistencies.push({ section1: occurrences[0].section, section2: occurrences[occurrences.length - 1].section, claim1: `${values[0]} (context: ${context})`, claim2: `${values[1]} (context: ${context})`, type: 'numerical', confidence: 0.6 }); } } } return inconsistencies; } createMinimalResult(sections) { return { sections, avgSimilarity: 1, stable: true, drift: false, contradictions: [], confidence: { value: 0.3, interval: [0.1, 0.5], method: 'heuristic' }, limitations: [ ...this.LIMITATIONS, 'Insufficient text for meaningful consistency analysis' ], methodology: this.METHODOLOGY }; } calculateSimilarityMatrix(sections) { const n = sections.length; const matrix = Array(n).fill(null).map(() => Array(n).fill(0)); for (let i = 0; i < n; i++) { for (let j = 0; j < n; j++) { if (i === j) { matrix[i][j] = 1; } else if (j > i) { const sim = (0, similarity_1.combinedSimilarity)(sections[i], sections[j]); matrix[i][j] = sim; matrix[j][i] = sim; } } } return matrix; } calculateAverageSimilarity(matrix) { const n = matrix.length; if (n < 2) return 1; let sum = 0; let count = 0; for (let i = 0; i < n; i++) { for (let j = i + 1; j < n; j++) { sum += matrix[i][j]; count++; } } return count > 0 ? sum / count : 1; } detectContradictions(sections) { const contradictions = []; const contradictionPatterns = [ { positive: /\bis\b/i, negative: /\bis not\b|\bisn't\b/i }, { positive: /\bwill\b/i, negative: /\bwill not\b|\bwon't\b/i }, { positive: /\btrue\b/i, negative: /\bfalse\b/i }, { positive: /\balways\b/i, negative: /\bnever\b/i }, { positive: /\ball\b/i, negative: /\bnone\b|\bno\b/i }, { positive: /\bincreased?\b/i, negative: /\bdecreased?\b/i }, { positive: /\bmore\b/i, negative: /\bless\b|\bfewer\b/i } ]; for (let i = 0; i < sections.length; i++) { for (let j = i + 1; j < sections.length; j++) { const section1 = sections[i].toLowerCase(); const section2 = sections[j].toLowerCase(); for (const pattern of contradictionPatterns) { const s1HasPos = pattern.positive.test(section1); const s1HasNeg = pattern.negative.test(section1); const s2HasPos = pattern.positive.test(section2); const s2HasNeg = pattern.negative.test(section2); if ((s1HasPos && s2HasNeg) || (s1HasNeg && s2HasPos)) { // Check for subject overlap const words1 = new Set(section1.split(/\s+/).filter(w => w.length > 4)); const words2 = new Set(section2.split(/\s+/).filter(w => w.length > 4)); const overlap = [...words1].filter(w => words2.has(w)); if (overlap.length >= 2) { contradictions.push({ section1: i, section2: j, claim1: this.extractRelevantClaim(sections[i], pattern), claim2: this.extractRelevantClaim(sections[j], pattern), type: 'logical', confidence: 0.6 + (overlap.length * 0.05) }); break; } } } } } return contradictions; } extractRelevantClaim(section, _pattern) { // Extract first sentence as representative claim const sentences = section.split(/[.!?]/); return sentences[0]?.trim().substring(0, 100) || section.substring(0, 100); } calculateConfidence(sectionCount, contradictionCount) { let value = 0.5; // More sections = higher confidence if (sectionCount >= 5) value += 0.2; else if (sectionCount >= 3) value += 0.1; // Clear contradictions = higher confidence in result if (contradictionCount > 0) value += 0.1; const margin = 0.15; return { value: Math.min(0.85, value), interval: [Math.max(0, value - margin), Math.min(1, value + margin)], method: 'heuristic' }; } } exports.ConsistencyEngine = ConsistencyEngine; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZW5naW5lcy9jb25zaXN0ZW5jeS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7OztHQVNHOzs7QUFJSCwyQ0FBbUQ7QUFDbkQsdURBQTREO0FBRTVELDJDQUEyQztBQUMzQyxNQUFNLGtCQUFrQixHQUFHLGdJQUFnSSxDQUFDO0FBQzVKLE1BQU0sa0JBQWtCLEdBQUcsdUhBQXVILENBQUM7QUFDbkosTUFBTSxlQUFlLEdBQUcsd0ZBQXdGLENBQUM7QUFFakgsbUJBQW1CO0FBQ25CLE1BQU0sY0FBYyxHQUFHLDJHQUEyRyxDQUFDO0FBQ25JLE1BQU0sZ0JBQWdCLEdBQUcseUdBQXlHLENBQUM7QUFFbkksdUJBQXVCO0FBQ3ZCLE1BQU0saUJBQWlCLEdBQUcsNElBQTRJLENBQUM7QUFFdksscUNBQXFDO0FBQ3JDLE1BQU0saUJBQWlCLEdBQUcsMkVBQTJFLENBQUM7QUFFdEcsTUFBYSxpQkFBaUI7SUFlNUIsWUFBb0IsTUFBYztRQUFkLFdBQU0sR0FBTixNQUFNLENBQVE7UUFkakIsZ0JBQVcsR0FBRztZQUM3QixvQ0FBb0M7WUFDcEMsZ0NBQWdDO1lBQ2hDLHVCQUF1QjtZQUN2Qiw0QkFBNEI7WUFDNUIseURBQXlEO1NBQzFELENBQUM7UUFFZSxnQkFBVyxHQUMxQiw0RUFBNEU7WUFDNUUsMkVBQTJFO1lBQzNFLDJFQUEyRTtZQUMzRSw0Q0FBNEMsQ0FBQztJQUVWLENBQUM7SUFFdEMsS0FBSyxDQUFDLEtBQUssQ0FBQyxPQUFlO1FBQ3pCLE1BQU0sUUFBUSxHQUFHLElBQUEsc0JBQWUsRUFBQyxPQUFPLENBQUMsQ0FBQztRQUUxQyxJQUFJLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDeEIsT0FBTyxJQUFJLENBQUMsbUJBQW1CLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDNUMsQ0FBQztRQUVELDhCQUE4QjtRQUM5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QUUsS0FBSyxHQUFHLE1BQU0sQ0FBQyxDQUFDO1lBQ3BFLE1BQU0sRUFBRSxXQUFXO1NBQ3BCLENBQUM7SUFDSixDQUFDO0NBQ0Y7QUE1V0QsOENBNFdDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb25zaXN0ZW5jeSBFbmdpbmVcbiAqIFxuICogQ2hlY2tzIGZvciBpbnRlcm5hbCBjb25zaXN0ZW5jeSwgY29udHJhZGljdGlvbnMsIGFuZCBiZWhhdmlvcmFsIGRyaWZ0LlxuICogQWxsIHByb2Nlc3NpbmcgaXMgbG9jYWwgLSBubyBleHRlcm5hbCBBUEkgY2FsbHMuXG4gKiBcbiAqIEBtb2R1bGUgZW5naW5lcy9jb25zaXN0ZW5jeVxuICogQGF1dGhvciBIYWllY1xuICogQGxpY2Vuc2UgTUlUXG4gKi9cblxuaW1wb3J0IHsgQ29uZmlnIH0gZnJvbSAnLi4vLi4vdHlwZXMvY29uZmlnJztcbmltcG9ydCB7IENvbnNpc3RlbmN5UmVzdWx0LCBDb250cmFkaWN0aW9uLCBDb25maWRlbmNlU2NvcmUgfSBmcm9tICcuLi8uLi90eXBlcy9yZXN1bHRzJztcbmltcG9ydCB7IHNwbGl0UGFyYWdyYXBocyB9IGZyb20gJy4uLy4uL3V0aWxzL3RleHQnO1xuaW1wb3J0IHsgY29tYmluZWRTaW1pbGFyaXR5IH0gZnJvbSAnLi4vLi4vdXRpbHMvc2ltaWxhcml0eSc7XG5cbi8vIFNlbnRpbWVudCBpbmRpY2F0b3JzIGZvciBkcmlmdCBkZXRlY3Rpb25cbmNvbnN0IFBPU0lUSVZFX1NFTlRJTUVOVCA9IC9cXGIoPzpnb29kfGdyZWF0fGV4Y2VsbGVudHxhbWF6aW5nfHdvbmRlcmZ1bHxmYW50YXN0aWN8bG92ZXxoYXBweXxwbGVhc2VkfHNhdGlzZmllZHxzdWNjZXNzfGJlbmVmaXR8YWR2YW50YWdlfGltcHJvdmV8YmVzdClcXGIvZ2k7XG5jb25zdCBORUdBVElWRV9TRU5USU1FTlQgPSAvXFxiKD86YmFkfHRlcnJpYmxlfGF3ZnVsfGhvcnJpYmxlfGhhdGV8YW5ncnl8ZnJ1c3RyYXRlZHxkaXNhcHBvaW50ZWR8ZmFpbHVyZXxwcm9ibGVtfGlzc3VlfHdvcnN0fGRhbWFnZXxoYXJtfHJpc2spXFxiL2dpO1xuY29uc3QgTkVVVFJBTF9NQVJLRVJTID0gL1xcYig/Omhvd2V2ZXJ8YWx0aG91Z2h8YnV0fG5ldmVydGhlbGVzc3xvbiB0aGUgb3RoZXIgaGFuZHxjb252ZXJzZWx5fGFsdGVybmF0aXZlbHkpXFxiL2dpO1xuXG4vLyBTdHlsZSBpbmRpY2F0b3JzXG5jb25zdCBGT1JNQUxfTUFSS0VSUyA9IC9cXGIoPzp0aGVyZWZvcmV8ZnVydGhlcm1vcmV8Y29uc2VxdWVudGx5fG1vcmVvdmVyfHRodXN8aGVuY2V8YWNjb3JkaW5nbHl8c3Vic2VxdWVudGx5fG5vdHdpdGhzdGFuZGluZylcXGIvZ2k7XG5jb25zdCBJTkZPUk1BTF9NQVJLRVJTID0gL1xcYig/Omdvbm5hfHdhbm5hfGtpbmRhfHNvcnRhfHllYWh8bm9wZXxjb29sfGF3ZXNvbWV8c3R1ZmZ8dGhpbmdzfGJhc2ljYWxseXxsaXRlcmFsbHl8YWN0dWFsbHl8bGlrZSlcXGIvZ2k7XG5cbi8vIFRlY2huaWNhbCBpbmRpY2F0b3JzXG5jb25zdCBURUNITklDQUxfTUFSS0VSUyA9IC9cXGIoPzphbGdvcml0aG18ZnVuY3Rpb258cGFyYW1ldGVyfHZhcmlhYmxlfGltcGxlbWVudGF0aW9ufGludGVyZmFjZXxwcm90b2NvbHxhcmNoaXRlY3R1cmV8ZnJhbWV3b3JrfG1vZHVsZXxBUEl8ZGF0YWJhc2V8c2VydmVyfGNsaWVudClcXGIvZ2k7XG5cbi8vIE51bWVyaWNhbCBwYXR0ZXJucyBmb3IgY29uc2lzdGVuY3lcbmNvbnN0IE5VTUVSSUNBTF9QQVRURVJOID0gL1xcYlxcZCsoPzpcXC5cXGQrKT8oPzpcXHMqKD86JXxwZXJjZW50fG1pbGxpb258YmlsbGlvbnx0aG91c2FuZHxodW5kcmVkKSk/XFxiL2dpO1xuXG5leHBvcnQgY2xhc3MgQ29uc2lzdGVuY3lFbmdpbmUge1xuICBwcml2YXRlIHJlYWRvbmx5IExJTUlUQVRJT05TID0gW1xuICAgICdQYXR0ZXJuLWJhc2VkIGNvbnNpc3RlbmN5IGNoZWNraW5nJyxcbiAgICAnTWF5IG1pc3Mgc3VidGxlIGNvbnRyYWRpY3Rpb25zJyxcbiAgICAnRW5nbGlzaCBsYW5ndWFnZSBvbmx5JyxcbiAgICAnQ29udGV4dC1kZXBlbmRlbnQgYWNjdXJhY3knLFxuICAgICdSZXF1aXJlcyBzdWZmaWNpZW50IHRleHQgbGVuZ3RoIGZvciBtZWFuaW5nZnVsIGFuYWx5c2lzJ1xuICBdO1xuICBcbiAgcHJpdmF0ZSByZWFkb25seSBNRVRIT0RPTE9HWSA9IFxuICAgICdBbmFseXplcyB0ZXh0IHNlY3Rpb25zIGZvciBpbnRlcm5hbCBjb25zaXN0ZW5jeSB1c2luZyBzaW1pbGFyaXR5IG1ldHJpY3MsICcgK1xuICAgICdzZW50aW1lbnQgYW5hbHlzaXMsIHN0eWxlIGRldGVjdGlvbiwgYW5kIGNvbnRyYWRpY3Rpb24gcGF0dGVybiBtYXRjaGluZy4gJyArXG4gICAgJ0lkZW50aWZpZXMgcG90ZW50aWFsIGxvZ2ljYWwgY29uZmxpY3RzLCBzZW1hbnRpYyBkcmlmdCwgdG9uZSBzaGlmdHMsIGFuZCAnICtcbiAgICAnbnVtZXJpY2FsIGluY29uc2lzdGVuY2llcyBhY3Jvc3Mgc2VjdGlvbnMuJztcbiAgXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgY29uZmlnOiBDb25maWcpIHt9XG4gIFxuICBhc3luYyBjaGVjayhjb250ZW50OiBzdHJpbmcpOiBQcm9taXNlPENvbnNpc3RlbmN5UmVzdWx0PiB7XG4gICAgY29uc3Qgc2VjdGlvbnMgPSBzcGxpdFBhcmFncmFwaHMoY29udGVudCk7XG4gICAgXG4gICAgaWYgKHNlY3Rpb25zLmxlbmd0aCA8IDIpIHtcbiAgICAgIHJldHVybiB0aGlzLmNyZWF0ZU1pbmltYWxSZXN1bHQoc2VjdGlvbnMpO1xuICAgIH1cbiAgICBcbiAgICAvLyBDYWxjdWxhdGUgc2ltaWxhcml0eSBtYXRyaXhcbiAgICBjb25zdCBtYXRyaXggPSB0aGlzLmNhbGN1bGF0ZVNpbWlsYXJpdHlNYXRyaXgoc2VjdGlvbnMpO1xuICAgIFxuICAgIC8vIENhbGN1bGF0ZSBhdmVyYWdlIHNpbWlsYXJpdHlcbiAgICBjb25zdCBhdmdTaW1pbGFyaXR5ID0gdGhpcy5jYWxjdWxhdGVBdmVyYWdlU2ltaWxhcml0eShtYXRyaXgpO1xuICAgIFxuICAgIC8vIERldGVjdCBjb250cmFkaWN0aW9uc1xuICAgIGNvbnN0IGNvbnRyYWRpY3Rpb25zID0gdGhpcy5kZXRlY3RDb250cmFkaWN0aW9ucyhzZWN0aW9ucyk7XG4gICAgXG4gICAgLy8gRW5oYW5jZWQgZHJpZnQgZGV0ZWN0aW9uXG4gICAgY29uc3Qgc2VudGltZW50RHJpZnQgPSB0aGlzLmRldGVjdFNlbnRpbWVudERyaWZ0KHNlY3Rpb25zKTtcbiAgICBjb25zdCBzdHlsZURyaWZ0ID0gdGhpcy5kZXRlY3RTdHlsZURyaWZ0KHNlY3Rpb25zKTtcbiAgICBjb25zdCBsZW5ndGhEcmlmdCA9IHRoaXMuZGV0ZWN0TGVuZ3RoRHJpZnQoc2VjdGlvbnMpO1xuICAgIGNvbnN0IG51bWVyaWNhbEluY29uc2lzdGVuY2llcyA9IHRoaXMuZGV0ZWN0TnVtZXJpY2FsSW5jb25zaXN0ZW5jaWVzKHNlY3Rpb25zKTtcbiAgICBcbiAgICAvLyBDb21iaW5lIGRyaWZ0IHNpZ25hbHNcbiAgICBjb25zdCBkcmlmdFNjb3JlID0gKFxuICAgICAgKHNlbnRpbWVudERyaWZ0ID8gMC4zIDogMCkgK1xuICAgICAgKHN0eWxlRHJpZnQgPyAwLjMgOiAwKSArXG4gICAgICAobGVuZ3RoRHJpZnQgPyAwLjIgOiAwKSArXG4gICAgICAobnVtZXJpY2FsSW5jb25zaXN0ZW5jaWVzLmxlbmd0aCA+IDAgPyAwLjIgOiAwKSArXG4gICAgICAoYXZnU2ltaWxhcml0eSA8IDAuNSA/IDAuMyA6IDApXG4gICAgKTtcbiAgICBcbiAgICAvLyBEZXRlcm1pbmUgc3RhYmlsaXR5XG4gICAgY29uc3Qgc3RhYmxlID0gYXZnU2ltaWxhcml0eSA+IDAuNiAmJiBjb250cmFkaWN0aW9ucy5sZW5ndGggPT09IDAgJiYgZHJpZnRTY29yZSA8IDAuMztcbiAgICBjb25zdCBkcmlmdCA9IGRyaWZ0U2NvcmUgPj0gMC40IHx8IGF2Z1NpbWlsYXJpdHkgPCAwLjQ7XG4gICAgXG4gICAgLy8gQ2FsY3VsYXRlIGNvbmZpZGVuY2VcbiAgICBjb25zdCBjb25maWRlbmNlID0gdGhpcy5jYWxjdWxhdGVDb25maWRlbmNlKHNlY3Rpb25zLmxlbmd0aCwgY29udHJhZGljdGlvbnMubGVuZ3RoKTtcbiAgICBcbiAgICAvLyBBZGQgZHJpZnQgZGV0YWlscyB0byBjb250cmFkaWN0aW9ucyBpZiBkZXRlY3RlZFxuICAgIGlmIChzZW50aW1lbnREcmlmdCkge1xuICAgICAgY29udHJhZGljdGlvbnMucHVzaCh7XG4gICAgICAgIHNlY3Rpb24xOiAwLFxuICAgICAgICBzZWN0aW9uMjogc2VjdGlvbnMubGVuZ3RoIC0gMSxcbiAgICAgICAgY2xhaW0xOiAnSW5pdGlhbCBzZW50aW1lbnQnLFxuICAgICAgICBjbGFpbTI6ICdGaW5hbCBzZW50aW1lbnQnLFxuICAgICAgICB0eXBlOiAnc2VudGltZW50X2RyaWZ0JyxcbiAgICAgICAgY29uZmlkZW5jZTogMC43XG4gICAgICB9KTtcbiAgICB9XG4gICAgXG4gICAgaWYgKHN0eWxlRHJpZnQpIHtcbiAgICAgIGNvbnRyYWRpY3Rpb25zLnB1c2goe1xuICAgICAgICBzZWN0aW9uMTogMCxcbiAgICAgICAgc2VjdGlvbjI6IHNlY3Rpb25zLmxlbmd0aCAtIDEsXG4gICAgICAgIGNsYWltMTogJ0luaXRpYWwgc3R5bGUnLFxuICAgICAgICBjbGFpbTI6ICdGaW5hbCBzdHlsZScsXG4gICAgICAgIHR5cGU6ICdzdHlsZV9kcmlmdCcsXG4gICAgICAgIGNvbmZpZGVuY2U6IDAuN1xuICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIGZvciAoY29uc3QgbnVtSXNzdWUgb2YgbnVtZXJpY2FsSW5jb25zaXN0ZW5jaWVzKSB7XG4gICAgICBjb250cmFkaWN0aW9ucy5wdXNoKG51bUlzc3VlKTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHtcbiAgICAgIHNlY3Rpb25zLFxuICAgICAgYXZnU2ltaWxhcml0eSxcbiAgICAgIHNpbWlsYXJpdHlNYXRyaXg6IHRoaXMuY29uZmlnLm91dHB1dC52ZXJib3NlID8gbWF0cml4IDogdW5kZWZpbmVkLFxuICAgICAgc3RhYmxlLFxuICAgICAgZHJpZnQsXG4gICAgICBjb250cmFkaWN0aW9ucyxcbiAgICAgIGNvbmZpZGVuY2UsXG4gICAgICBsaW1pdGF0aW9uczogdGhpcy5MSU1JVEFUSU9OUyxcbiAgICAgIG1ldGhvZG9sb2d5OiB0aGlzLk1FVEhPRE9MT0dZXG4gICAgfTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIERldGVjdCBzZW50aW1lbnQgZHJpZnQgYWNyb3NzIHNlY3Rpb25zXG4gICAqL1xuICBwcml2YXRlIGRldGVjdFNlbnRpbWVudERyaWZ0KHNlY3Rpb25zOiBzdHJpbmdbXSk6IGJvb2xlYW4ge1xuICAgIGlmIChzZWN0aW9ucy5sZW5ndGggPCAyKSByZXR1cm4gZmFsc2U7XG4gICAgXG4gICAgY29uc3Qgc2VudGltZW50cyA9IHNlY3Rpb25zLm1hcChzID0+IHRoaXMuY2FsY3VsYXRlU2VudGltZW50KHMpKTtcbiAgICBcbiAgICAvLyBDaGVjayBmb3Igc2lnbmlmaWNhbnQgc2VudGltZW50IHNoaWZ0XG4gICAgY29uc3QgZmlyc3RIYWxmID0gc2VudGltZW50cy5zbGljZSgwLCBNYXRoLmZsb29yKHNlbnRpbWVudHMubGVuZ3RoIC8gMikpO1xuICAgIGNvbnN0IHNlY29uZEhhbGYgPSBzZW50aW1lbnRzLnNsaWNlKE1hdGguZmxvb3Ioc2VudGltZW50cy5sZW5ndGggLyAyKSk7XG4gICAgXG4gICAgY29uc3QgYXZnRmlyc3QgPSBmaXJzdEhhbGYucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCkgLyBmaXJzdEhhbGYubGVuZ3RoO1xuICAgIGNvbnN0IGF2Z1NlY29uZCA9IHNlY29uZEhhbGYucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCkgLyBzZWNvbmRIYWxmLmxlbmd0aDtcbiAgICBcbiAgICAvLyBTaWduaWZpY2FudCBkcmlmdCBpZiBzZW50aW1lbnQgY2hhbmdlcyBieSBtb3JlIHRoYW4gMC40IG9uIC0xIHRvIDEgc2NhbGVcbiAgICByZXR1cm4gTWF0aC5hYnMoYXZnRmlyc3QgLSBhdmdTZWNvbmQpID4gMC40O1xuICB9XG4gIFxuICAvKipcbiAgICogQ2FsY3VsYXRlIHNlbnRpbWVudCBzY29yZSBmb3IgYSBzZWN0aW9uICgtMSB0byAxKVxuICAgKi9cbiAgcHJpdmF0ZSBjYWxjdWxhdGVTZW50aW1lbnQodGV4dDogc3RyaW5nKTogbnVtYmVyIHtcbiAgICBjb25zdCBwb3NpdGl2ZU1hdGNoZXMgPSAodGV4dC5tYXRjaChQT1NJVElWRV9TRU5USU1FTlQpIHx8IFtdKS5sZW5ndGg7XG4gICAgY29uc3QgbmVnYXRpdmVNYXRjaGVzID0gKHRleHQubWF0Y2goTkVHQVRJVkVfU0VOVElNRU5UKSB8fCBbXSkubGVuZ3RoO1xuICAgIGNvbnN0IHRvdGFsID0gcG9zaXRpdmVNYXRjaGVzICsgbmVnYXRpdmVNYXRjaGVzO1xuICAgIFxuICAgIGlmICh0b3RhbCA9PT0gMCkgcmV0dXJuIDA7XG4gICAgcmV0dXJuIChwb3NpdGl2ZU1hdGNoZXMgLSBuZWdhdGl2ZU1hdGNoZXMpIC8gdG90YWw7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBEZXRlY3Qgc3R5bGUgZHJpZnQgKGZvcm1hbCB0byBpbmZvcm1hbCBvciB2aWNlIHZlcnNhKVxuICAgKi9cbiAgcHJpdmF0ZSBkZXRlY3RTdHlsZURyaWZ0KHNlY3Rpb25zOiBzdHJpbmdbXSk6IGJvb2xlYW4ge1xuICAgIGlmIChzZWN0aW9ucy5sZW5ndGggPCAyKSByZXR1cm4gZmFsc2U7XG4gICAgXG4gICAgY29uc3Qgc3R5bGVzID0gc2VjdGlvbnMubWFwKHMgPT4gdGhpcy5jYWxjdWxhdGVTdHlsZVNjb3JlKHMpKTtcbiAgICBcbiAgICAvLyBDaGVjayBmb3Igc2lnbmlmaWNhbnQgc3R5bGUgc2hpZnRcbiAgICBjb25zdCBmaXJzdFN0eWxlID0gc3R5bGVzWzBdO1xuICAgIGNvbnN0IGxhc3RTdHlsZSA9IHN0eWxlc1tzdHlsZXMubGVuZ3RoIC0gMV07XG4gICAgXG4gICAgLy8gU2lnbmlmaWNhbnQgZHJpZnQgaWYgc3R5bGUgY2hhbmdlcyBmcm9tIGZvcm1hbCB0byBpbmZvcm1hbCBvciB2aWNlIHZlcnNhXG4gICAgcmV0dXJuIE1hdGguYWJzKGZpcnN0U3R5bGUgLSBsYXN0U3R5bGUpID4gMC41O1xuICB9XG4gIFxuICAvKipcbiAgICogQ2FsY3VsYXRlIHN0eWxlIHNjb3JlICgtMSA9IGluZm9ybWFsLCAxID0gZm9ybWFsKVxuICAgKi9cbiAgcHJpdmF0ZSBjYWxjdWxhdGVTdHlsZVNjb3JlKHRleHQ6IHN0cmluZyk6IG51bWJlciB7XG4gICAgY29uc3QgZm9ybWFsTWF0Y2hlcyA9ICh0ZXh0Lm1hdGNoKEZPUk1BTF9NQVJLRVJTKSB8fCBbXSkubGVuZ3RoO1xuICAgIGNvbnN0IGluZm9ybWFsTWF0Y2hlcyA9ICh0ZXh0Lm1hdGNoKElORk9STUFMX01BUktFUlMpIHx8IFtdKS5sZW5ndGg7XG4gICAgY29uc3QgdGVjaG5pY2FsTWF0Y2hlcyA9ICh0ZXh0Lm1hdGNoKFRFQ0hOSUNBTF9NQVJLRVJTKSB8fCBbXSkubGVuZ3RoO1xuICAgIFxuICAgIC8vIFRlY2huaWNhbCBjb250ZW50IHRlbmRzIHRvIGJlIG1vcmUgZm9ybWFsXG4gICAgY29uc3QgYWRqdXN0ZWRGb3JtYWwgPSBmb3JtYWxNYXRjaGVzICsgKHRlY2huaWNhbE1hdGNoZXMgKiAwLjUpO1xuICAgIGNvbnN0IHRvdGFsID0gYWRqdXN0ZWRGb3JtYWwgKyBpbmZvcm1hbE1hdGNoZXM7XG4gICAgXG4gICAgaWYgKHRvdGFsID09PSAwKSByZXR1cm4gMDtcbiAgICByZXR1cm4gKGFkanVzdGVkRm9ybWFsIC0gaW5mb3JtYWxNYXRjaGVzKSAvIHRvdGFsO1xuICB9XG4gIFxuICAvKipcbiAgICogRGV0ZWN0IHNpZ25pZmljYW50IGxlbmd0aCBkcmlmdFxuICAgKi9cbiAgcHJpdmF0ZSBkZXRlY3RMZW5ndGhEcmlmdChzZWN0aW9uczogc3RyaW5nW10pOiBib29sZWFuIHtcbiAgICBpZiAoc2VjdGlvbnMubGVuZ3RoIDwgMikgcmV0dXJuIGZhbHNlO1xuICAgIFxuICAgIGNvbnN0IGxlbmd0aHMgPSBzZWN0aW9ucy5tYXAocyA9PiBzLmxlbmd0aCk7XG4gICAgY29uc3QgYXZnTGVuZ3RoID0gbGVuZ3Rocy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKSAvIGxlbmd0aHMubGVuZ3RoO1xuICAgIFxuICAgIC8vIENoZWNrIGlmIGFueSBzZWN0aW9uIGlzIGRyYXN0aWNhbGx5IGRpZmZlcmVudCBpbiBsZW5ndGhcbiAgICBmb3IgKGNvbnN0IGxlbiBvZiBsZW5ndGhzKSB7XG4gICAgICBjb25zdCByYXRpbyA9IGxlbiAvIGF2Z0xlbmd0aDtcbiAgICAgIGlmIChyYXRpbyA8IDAuMiB8fCByYXRpbyA+IDUpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIERldGVjdCBudW1lcmljYWwgaW5jb25zaXN0ZW5jaWVzXG4gICAqL1xuICBwcml2YXRlIGRldGVjdE51bWVyaWNhbEluY29uc2lzdGVuY2llcyhzZWN0aW9uczogc3RyaW5nW10pOiBDb250cmFkaWN0aW9uW10ge1xuICAgIGNvbnN0IGluY29uc2lzdGVuY2llczogQ29udHJhZGljdGlvbltdID0gW107XG4gICAgY29uc3QgbnVtYmVyc0J5Q29udGV4dDogTWFwPHN0cmluZywgQXJyYXk8eyB2YWx1ZTogc3RyaW5nOyBzZWN0aW9uOiBudW1iZXIgfT4+ID0gbmV3IE1hcCgpO1xuICAgIFxuICAgIC8vIEV4dHJhY3QgbnVtYmVycyB3aXRoIHRoZWlyIGNvbnRleHRcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNlY3Rpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBzZWN0aW9uID0gc2VjdGlvbnNbaV07XG4gICAgICBjb25zdCBudW1iZXJzID0gc2VjdGlvbi5tYXRjaChOVU1FUklDQUxfUEFUVEVSTikgfHwgW107XG4gICAgICBcbiAgICAgIGZvciAoY29uc3QgbnVtIG9mIG51bWJlcnMpIHtcbiAgICAgICAgLy8gR2V0IHN1cnJvdW5kaW5nIGNvbnRleHQgKDUgd29yZHMgYmVmb3JlIGFuZCBhZnRlcilcbiAgICAgICAgY29uc3QgaW5kZXggPSBzZWN0aW9uLmluZGV4T2YobnVtKTtcbiAgICAgICAgY29uc3QgYmVmb3JlID0gc2VjdGlvbi5zdWJzdHJpbmcoTWF0aC5tYXgoMCwgaW5kZXggLSA1MCksIGluZGV4KTtcbiAgICAgICAgY29uc3QgYWZ0ZXIgPSBzZWN0aW9uLnN1YnN0cmluZyhpbmRleCArIG51bS5sZW5ndGgsIGluZGV4ICsgbnVtLmxlbmd0aCArIDUwKTtcbiAgICAgICAgXG4gICAgICAgIC8vIEV4dHJhY3Qga2V5IGNvbnRleHQgd29yZHNcbiAgICAgICAgY29uc3QgY29udGV4dFdvcmRzID0gKGJlZm9yZSArICcgJyArIGFmdGVyKVxuICAgICAgICAgIC50b0xvd2VyQ2FzZSgpXG4gICAgICAgICAgLnNwbGl0KC9cXHMrLylcbiAgICAgICAgICAuZmlsdGVyKHcgPT4gdy5sZW5ndGggPiA0KVxuICAgICAgICAgIC5zbGljZSgwLCA1KVxuICAgICAgICAgIC5qb2luKCcgJyk7XG4gICAgICAgIFxuICAgICAgICBpZiAoY29udGV4dFdvcmRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICBpZiAoIW51bWJlcnNCeUNvbnRleHQuaGFzKGNvbnRleHRXb3JkcykpIHtcbiAgICAgICAgICAgIG51bWJlcnNCeUNvbnRleHQuc2V0KGNvbnRleHRXb3JkcywgW10pO1xuICAgICAgICAgIH1cbiAgICAgICAgICBudW1iZXJzQnlDb250ZXh0LmdldChjb250ZXh0V29yZHMpIS5wdXNoKHsgdmFsdWU6IG51bSwgc2VjdGlvbjogaSB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICAvLyBDaGVjayBmb3IgY29uZmxpY3RpbmcgbnVtYmVycyBpbiBzYW1lIGNvbnRleHRcbiAgICBmb3IgKGNvbnN0IFtjb250ZXh0LCBvY2N1cnJlbmNlc10gb2YgbnVtYmVyc0J5Q29udGV4dCkge1xuICAgICAgaWYgKG9jY3VycmVuY2VzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgY29uc3QgdW5pcXVlVmFsdWVzID0gbmV3IFNldChvY2N1cnJlbmNlcy5tYXAobyA9PiBvLnZhbHVlKSk7XG4gICAgICAgIGlmICh1bmlxdWVWYWx1ZXMuc2l6ZSA+IDEpIHtcbiAgICAgICAgICAvLyBEaWZmZXJlbnQgbnVtYmVycyBpbiBzYW1lIGNvbnRleHRcbiAgICAgICAgICBjb25zdCB2YWx1ZXMgPSBBcnJheS5mcm9tKHVuaXF1ZVZhbHVlcyk7XG4gICAgICAgICAgaW5jb25zaXN0ZW5jaWVzLnB1c2goe1xuICAgICAgICAgICAgc2VjdGlvbjE6IG9jY3VycmVuY2VzWzBdLnNlY3Rpb24sXG4gICAgICAgICAgICBzZWN0aW9uMjogb2NjdXJyZW5jZXNbb2NjdXJyZW5jZXMubGVuZ3RoIC0gMV0uc2VjdGlvbixcbiAgICAgICAgICAgIGNsYWltMTogYCR7dmFsdWVzWzBdfSAoY29udGV4dDogJHtjb250ZXh0fSlgLFxuICAgICAgICAgICAgY2xhaW0yOiBgJHt2YWx1ZXNbMV19IChjb250ZXh0OiAke2NvbnRleHR9KWAsXG4gICAgICAgICAgICB0eXBlOiAnbnVtZXJpY2FsJyxcbiAgICAgICAgICAgIGNvbmZpZGVuY2U6IDAuNlxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBpbmNvbnNpc3RlbmNpZXM7XG4gIH1cbiAgXG4gIHByaXZhdGUgY3JlYXRlTWluaW1hbFJlc3VsdChzZWN0aW9uczogc3RyaW5nW10pOiBDb25zaXN0ZW5jeVJlc3VsdCB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHNlY3Rpb25zLFxuICAgICAgYXZnU2ltaWxhcml0eTogMSxcbiAgICAgIHN0YWJsZTogdHJ1ZSxcbiAgICAgIGRyaWZ0OiBmYWxzZSxcbiAgICAgIGNvbnRyYWRpY3Rpb25zOiBbXSxcbiAgICAgIGNvbmZpZGVuY2U6IHtcbiAgICAgICAgdmFsdWU6IDAuMyxcbiAgICAgICAgaW50ZXJ2YWw6IFswLjEsIDAuNV0sXG4gICAgICAgIG1ldGhvZDogJ2hldXJpc3RpYydcbiAgICAgIH0sXG4gICAgICBsaW1pdGF0aW9uczogW1xuICAgICAgICAuLi50aGlzLkxJTUlUQVRJT05TLFxuICAgICAgICAnSW5zdWZmaWNpZW50IHRleHQgZm9yIG1lYW5pbmdmdWwgY29uc2lzdGVuY3kgYW5hbHlzaXMnXG4gICAgICBdLFxuICAgICAgbWV0aG9kb2xvZ3k6IHRoaXMuTUVUSE9ET0xPR1lcbiAgICB9O1xuICB9XG4gIFxuICBwcml2YXRlIGNhbGN1bGF0ZVNpbWlsYXJpdHlNYXRyaXgoc2VjdGlvbnM6IHN0cmluZ1tdKTogbnVtYmVyW11bXSB7XG4gICAgY29uc3QgbiA9IHNlY3Rpb25zLmxlbmd0aDtcbiAgICBjb25zdCBtYXRyaXg6IG51bWJlcltdW10gPSBBcnJheShuKS5maWxsKG51bGwpLm1hcCgoKSA9PiBBcnJheShuKS5maWxsKDApKTtcbiAgICBcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG47IGkrKykge1xuICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBuOyBqKyspIHtcbiAgICAgICAgaWYgKGkgPT09IGopIHtcbiAgICAgICAgICBtYXRyaXhbaV1bal0gPSAxO1xuICAgICAgICB9IGVsc2UgaWYgKGogPiBpKSB7XG4gICAgICAgICAgY29uc3Qgc2ltID0gY29tYmluZWRTaW1pbGFyaXR5KHNlY3Rpb25zW2ldLCBzZWN0aW9uc1tqXSk7XG4gICAgICAgICAgbWF0cml4W2ldW2pdID0gc2ltO1xuICAgICAgICAgIG1hdHJpeFtqXVtpXSA9IHNpbTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICByZXR1cm4gbWF0cml4O1xuICB9XG4gIFxuICBwcml2YXRlIGNhbGN1bGF0ZUF2ZXJhZ2VTaW1pbGFyaXR5KG1hdHJpeDogbnVtYmVyW11bXSk6IG51bWJlciB7XG4gICAgY29uc3QgbiA9IG1hdHJpeC5sZW5ndGg7XG4gICAgaWYgKG4gPCAyKSByZXR1cm4gMTtcbiAgICBcbiAgICBsZXQgc3VtID0gMDtcbiAgICBsZXQgY291bnQgPSAwO1xuICAgIFxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbjsgaSsrKSB7XG4gICAgICBmb3IgKGxldCBqID0gaSArIDE7IGogPCBuOyBqKyspIHtcbiAgICAgICAgc3VtICs9IG1hdHJpeFtpXVtqXTtcbiAgICAgICAgY291bnQrKztcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGNvdW50ID4gMCA/IHN1bSAvIGNvdW50IDogMTtcbiAgfVxuICBcbiAgcHJpdmF0ZSBkZXRlY3RDb250cmFkaWN0aW9ucyhzZWN0aW9uczogc3RyaW5nW10pOiBDb250cmFkaWN0aW9uW10ge1xuICAgIGNvbnN0IGNvbnRyYWRpY3Rpb25zOiBDb250cmFkaWN0aW9uW10gPSBbXTtcbiAgICBcbiAgICBjb25zdCBjb250cmFkaWN0aW9uUGF0dGVybnMgPSBbXG4gICAgICB7IHBvc2l0aXZlOiAvXFxiaXNcXGIvaSwgbmVnYXRpdmU6IC9cXGJpcyBub3RcXGJ8XFxiaXNuJ3RcXGIvaSB9LFxuICAgICAgeyBwb3NpdGl2ZTogL1xcYndpbGxcXGIvaSwgbmVnYXRpdmU6IC9cXGJ3aWxsIG5vdFxcYnxcXGJ3b24ndFxcYi9pIH0sXG4gICAgICB7IHBvc2l0aXZlOiAvXFxidHJ1ZVxcYi9pLCBuZWdhdGl2ZTogL1xcYmZhbHNlXFxiL2kgfSxcbiAgICAgIHsgcG9zaXRpdmU6IC9cXGJhbHdheXNcXGIvaSwgbmVnYXRpdmU6IC9cXGJuZXZlclxcYi9pIH0sXG4gICAgICB7IHBvc2l0aXZlOiAvXFxiYWxsXFxiL2ksIG5lZ2F0aXZlOiAvXFxibm9uZVxcYnxcXGJub1xcYi9pIH0sXG4gICAgICB7IHBvc2l0aXZlOiAvXFxiaW5jcmVhc2VkP1xcYi9pLCBuZWdhdGl2ZTogL1xcYmRlY3JlYXNlZD9cXGIvaSB9LFxuICAgICAgeyBwb3NpdGl2ZTogL1xcYm1vcmVcXGIvaSwgbmVnYXRpdmU6IC9cXGJsZXNzXFxifFxcYmZld2VyXFxiL2kgfVxuICAgIF07XG4gICAgXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZWN0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgZm9yIChsZXQgaiA9IGkgKyAxOyBqIDwgc2VjdGlvbnMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgY29uc3Qgc2VjdGlvbjEgPSBzZWN0aW9uc1tpXS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICBjb25zdCBzZWN0aW9uMiA9IHNlY3Rpb25zW2pdLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIFxuICAgICAgICBmb3IgKGNvbnN0IHBhdHRlcm4gb2YgY29udHJhZGljdGlvblBhdHRlcm5zKSB7XG4gICAgICAgICAgY29uc3QgczFIYXNQb3MgPSBwYXR0ZXJuLnBvc2l0aXZlLnRlc3Qoc2VjdGlvbjEpO1xuICAgICAgICAgIGNvbnN0IHMxSGFzTmVnID0gcGF0dGVybi5uZWdhdGl2ZS50ZXN0KHNlY3Rpb24xKTtcbiAgICAgICAgICBjb25zdCBzMkhhc1BvcyA9IHBhdHRlcm4ucG9zaXRpdmUudGVzdChzZWN0aW9uMik7XG4gICAgICAgICAgY29uc3QgczJIYXNOZWcgPSBwYXR0ZXJuLm5lZ2F0aXZlLnRlc3Qoc2VjdGlvbjIpO1xuICAgICAgICAgIFxuICAgICAgICAgIGlmICgoczFIYXNQb3MgJiYgczJIYXNOZWcpIHx8IChzMUhhc05lZyAmJiBzMkhhc1BvcykpIHtcbiAgICAgICAgICAgIC8vIENoZWNrIGZvciBzdWJqZWN0IG92ZXJsYXBcbiAgICAgICAgICAgIGNvbnN0IHdvcmRzMSA9IG5ldyBTZXQoc2VjdGlvbjEuc3BsaXQoL1xccysvKS5maWx0ZXIodyA9PiB3Lmxlbmd0aCA+IDQpKTtcbiAgICAgICAgICAgIGNvbnN0IHdvcmRzMiA9IG5ldyBTZXQoc2VjdGlvbjIuc3BsaXQoL1xccysvKS5maWx0ZXIodyA9PiB3Lmxlbmd0aCA+IDQpKTtcbiAgICAgICAgICAgIGNvbnN0IG92ZXJsYXAgPSBbLi4ud29yZHMxXS5maWx0ZXIodyA9PiB3b3JkczIuaGFzKHcpKTtcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgaWYgKG92ZXJsYXAubGVuZ3RoID49IDIpIHtcbiAgICAgICAgICAgICAgY29udHJhZGljdGlvbnMucHVzaCh7XG4gICAgICAgICAgICAgICAgc2VjdGlvbjE6IGksXG4gICAgICAgICAgICAgICAgc2VjdGlvbjI6IGosXG4gICAgICAgICAgICAgICAgY2xhaW0xOiB0aGlzLmV4dHJhY3RSZWxldmFudENsYWltKHNlY3Rpb25zW2ldLCBwYXR0ZXJuKSxcbiAgICAgICAgICAgICAgICBjbGFpbTI6IHRoaXMuZXh0cmFjdFJlbGV2YW50Q2xhaW0oc2VjdGlvbnNbal0sIHBhdHRlcm4pLFxuICAgICAgICAgICAgICAgIHR5cGU6ICdsb2dpY2FsJyxcbiAgICAgICAgICAgICAgICBjb25maWRlbmNlOiAwLjYgKyAob3ZlcmxhcC5sZW5ndGggKiAwLjA1KVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBjb250cmFkaWN0aW9ucztcbiAgfVxuICBcbiAgcHJpdmF0ZSBleHRyYWN0UmVsZXZhbnRDbGFpbShzZWN0aW9uOiBzdHJpbmcsIF9wYXR0ZXJuOiB7IHBvc2l0aXZlOiBSZWdFeHA7IG5lZ2F0aXZlOiBSZWdFeHAgfSk6IHN0cmluZyB7XG4gICAgLy8gRXh0cmFjdCBmaXJzdCBzZW50ZW5jZSBhcyByZXByZXNlbnRhdGl2ZSBjbGFpbVxuICAgIGNvbnN0IHNlbnRlbmNlcyA9IHNlY3Rpb24uc3BsaXQoL1suIT9dLyk7XG4gICAgcmV0dXJuIHNlbnRlbmNlc1swXT8udHJpbSgpLnN1YnN0cmluZygwLCAxMDApIHx8IHNlY3Rpb24uc3Vic3RyaW5nKDAsIDEwMCk7XG4gIH1cbiAgXG4gIHByaXZhdGUgY2FsY3VsYXRlQ29uZmlkZW5jZShzZWN0aW9uQ291bnQ6IG51bWJlciwgY29udHJhZGljdGlvbkNvdW50OiBudW1iZXIpOiBDb25maWRlbmNlU2NvcmUge1xuICAgIGxldCB2YWx1ZSA9IDAuNTtcbiAgICBcbiAgICAvLyBNb3JlIHNlY3Rpb25zID0gaGlnaGVyIGNvbmZpZGVuY2VcbiAgICBpZiAoc2VjdGlvbkNvdW50ID49IDUpIHZhbHVlICs9IDAuMjtcbiAgICBlbHNlIGlmIChzZWN0aW9uQ291bnQgPj0gMykgdmFsdWUgKz0gMC4xO1xuICAgIFxuICAgIC8vIENsZWFyIGNvbnRyYWRpY3Rpb25zID0gaGlnaGVyIGNvbmZpZGVuY2UgaW4gcmVzdWx0XG4gICAgaWYgKGNvbnRyYWRpY3Rpb25Db3VudCA+IDApIHZhbHVlICs9IDAuMTtcbiAgICBcbiAgICBjb25zdCBtYXJnaW4gPSAwLjE1O1xuICAgIFxuICAgIHJldHVybiB7XG4gICAgICB2YWx1ZTogTWF0aC5taW4oMC44NSwgdmFsdWUpLFxuICAgICAgaW50ZXJ2YWw6IFtNYXRoLm1heCgwLCB2YWx1ZSAtIG1hcmdpbiksIE1hdGgubWluKDEsIHZhbHVlICsgbWFyZ2luKV0sXG4gICAgICBtZXRob2Q6ICdoZXVyaXN0aWMnXG4gICAgfTtcbiAgfVxufVxuIl19