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.

179 lines 18.6 kB
"use strict"; /** * Claim Extractor * * Extracts claims from text for risk analysis. * * @module engines/hallucination/claim-extractor * @author Haiec * @license MIT */ Object.defineProperty(exports, "__esModule", { value: true }); exports.extractClaims = extractClaims; const text_1 = require("../../utils/text"); /** * Extract claims from text */ function extractClaims(text) { const sentences = (0, text_1.splitSentences)(text); const claims = []; let currentIndex = 0; for (const sentence of sentences) { const startIndex = text.indexOf(sentence, currentIndex); const endIndex = startIndex + sentence.length; const claim = analyzeSentence(sentence, startIndex, endIndex); if (claim) { claims.push(claim); } currentIndex = endIndex; } return claims; } /** * Analyze a sentence to determine if it's a claim */ function analyzeSentence(sentence, start, end) { const trimmed = sentence.trim(); if (trimmed.length < 10) return null; const type = classifySentence(trimmed); const verifiable = isVerifiable(trimmed, type); const riskIndicators = { lackOfSpecificity: calculateSpecificityRisk(trimmed), missingCitation: checkMissingCitation(trimmed, type), vagueLanguage: checkVagueLanguage(trimmed), contradictionSignal: false // Set during consistency check }; const confidence = calculateClaimConfidence(riskIndicators); return { text: trimmed, span: [start, end], type, verifiable, riskIndicators, confidence, limitations: [ 'Pattern-based claim extraction', 'May miss implicit claims', 'Context not fully analyzed' ] }; } /** * Classify sentence type */ function classifySentence(sentence) { const lower = sentence.toLowerCase(); // Instructions if (/^(please|you should|you must|do not|don't|always|never)\b/i.test(lower)) { return 'instruction'; } // Opinions if (/\b(i think|i believe|in my opinion|seems|appears|might|could|may)\b/i.test(lower)) { return 'opinion'; } // Metadata if (/^(note:|warning:|important:|disclaimer:)/i.test(lower)) { return 'metadata'; } // Default to factual return 'factual'; } /** * Check if claim is verifiable */ function isVerifiable(sentence, type) { if (type === 'opinion' || type === 'instruction') { return false; } // Contains numbers or dates if (/\d+/.test(sentence)) { return true; } // Contains proper nouns (capitalized words not at start) if (/\s[A-Z][a-z]+/.test(sentence)) { return true; } return true; } /** * Calculate specificity risk (0-1, higher = more risky) */ function calculateSpecificityRisk(sentence) { let risk = 0.5; // Base risk // Reduce risk if contains specific numbers if (/\b\d+(\.\d+)?%?\b/.test(sentence)) { risk -= 0.2; } // Reduce risk if contains dates if (/\b(19|20)\d{2}\b|\b(january|february|march|april|may|june|july|august|september|october|november|december)\b/i.test(sentence)) { risk -= 0.15; } // Reduce risk if contains proper nouns const properNouns = sentence.match(/\b[A-Z][a-z]+\b/g) || []; if (properNouns.length > 1) { risk -= 0.1; } // Increase risk for vague quantifiers if (/\b(many|some|few|several|various|numerous|countless)\b/i.test(sentence)) { risk += 0.15; } // Increase risk for hedging language if (/\b(generally|usually|often|sometimes|typically)\b/i.test(sentence)) { risk += 0.1; } return Math.max(0, Math.min(1, risk)); } /** * Check for missing citation */ function checkMissingCitation(sentence, type) { if (type !== 'factual') return false; // Has citation markers if (/\[\d+\]|\(\d{4}\)|according to|source:|cited from/i.test(sentence)) { return false; } // Contains strong factual claims without citation const strongClaims = /\b(studies show|research indicates|scientists found|data shows|evidence suggests|proven|confirmed)\b/i; return strongClaims.test(sentence); } /** * Check for vague language */ function checkVagueLanguage(sentence) { const vaguePatterns = [ /\b(somehow|something|somewhere|someone|somewhat)\b/i, /\b(kind of|sort of|type of)\b/i, /\b(stuff|things|etc\.?)\b/i, /\b(basically|essentially|virtually)\b/i ]; return vaguePatterns.some(p => p.test(sentence)); } /** * Calculate confidence score for claim analysis */ function calculateClaimConfidence(riskIndicators) { // Base confidence for pattern-based analysis const baseConfidence = 0.65; // Adjust based on clarity of signals let adjustment = 0; if (riskIndicators.lackOfSpecificity > 0.7 || riskIndicators.lackOfSpecificity < 0.3) { adjustment += 0.1; // Clear signal } if (riskIndicators.missingCitation) { adjustment += 0.05; } const value = Math.min(0.85, baseConfidence + adjustment); const margin = 0.15; return { value, interval: [Math.max(0, value - margin), Math.min(1, value + margin)], method: 'heuristic', factors: { patternStrength: value, contextClarity: 0.6 } }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhaW0tZXh0cmFjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2VuZ2luZXMvaGFsbHVjaW5hdGlvbi9jbGFpbS1leHRyYWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7OztHQVFHOztBQVFILHNDQW1CQztBQXhCRCwyQ0FBa0Q7QUFFbEQ7O0dBRUc7QUFDSCxTQUFnQixhQUFhLENBQUMsSUFBWTtJQUN4QyxNQUFNLFNBQVMsR0FBRyxJQUFBLHFCQUFjLEVBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkMsTUFBTSxNQUFNLEdBQVksRUFBRSxDQUFDO0lBRTNCLElBQUksWUFBWSxHQUFHLENBQUMsQ0FBQztJQUVyQixLQUFLLE1BQU0sUUFBUSxJQUFJLFNBQVMsRUFBRSxDQUFDO1FBQ2pDLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLFlBQVksQ0FBQyxDQUFDO1FBQ3hELE1BQU0sUUFBUSxHQUFHLFVBQVUsR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDO1FBRTlDLE1BQU0sS0FBSyxHQUFHLGVBQWUsQ0FBQyxRQUFRLEVBQUUsVUFBVSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQzlELElBQUksS0FBSyxFQUFFLENBQUM7WUFDVixNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3JCLENBQUM7UUFFRCxZQUFZLEdBQUcsUUFBUSxDQUFDO0lBQzFCLENBQUM7SUFFRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFTLGVBQWUsQ0FDdEIsUUFBZ0IsRUFDaEIsS0FBYSxFQUNiLEdBQVc7SUFFWCxNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDaEMsSUFBSSxPQUFPLENBQUMsTUFBTSxHQUFHLEVBQUU7UUFBRSxPQUFPLElBQUksQ0FBQztJQUVyQyxNQUFNLElBQUksR0FBRyxnQkFBZ0Is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RyxJQUFJLGNBQWMsQ0FBQyxpQkFBaUIsR0FBRyxHQUFHLEVBQUUsQ0FBQztRQUNyRixVQUFVLElBQUksR0FBRyxDQUFDLENBQUMsZUFBZTtJQUNwQyxDQUFDO0lBRUQsSUFBSSxjQUFjLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDbkMsVUFBVSxJQUFJLElBQUksQ0FBQztJQUNyQixDQUFDO0lBRUQsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsY0FBYyxHQUFHLFVBQVUsQ0FBQyxDQUFDO0lBQzFELE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQztJQUVwQixPQUFPO1FBQ0wsS0FBSztRQUNMLFFBQVEsRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEtBQUssR0FBRyxNQUFNLENBQUMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxLQUFLLEdBQUcsTUFBTSxDQUFDLENBQUM7UUFDcEUsTUFBTSxFQUFFLFdBQVc7UUFDbkIsT0FBTyxFQUFFO1lBQ1AsZUFBZSxFQUFFLEtBQUs7WUFDdEIsY0FBYyxFQUFFLEdBQUc7U0FDcEI7S0FDRixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ2xhaW0gRXh0cmFjdG9yXG4gKiBcbiAqIEV4dHJhY3RzIGNsYWltcyBmcm9tIHRleHQgZm9yIHJpc2sgYW5hbHlzaXMuXG4gKiBcbiAqIEBtb2R1bGUgZW5naW5lcy9oYWxsdWNpbmF0aW9uL2NsYWltLWV4dHJhY3RvclxuICogQGF1dGhvciBIYWllY1xuICogQGxpY2Vuc2UgTUlUXG4gKi9cblxuaW1wb3J0IHsgQ2xhaW0sIENvbmZpZGVuY2VTY29yZSB9IGZyb20gJy4uLy4uL3R5cGVzL3Jlc3VsdHMnO1xuaW1wb3J0IHsgc3BsaXRTZW50ZW5jZXMgfSBmcm9tICcuLi8uLi91dGlscy90ZXh0JztcblxuLyoqXG4gKiBFeHRyYWN0IGNsYWltcyBmcm9tIHRleHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RDbGFpbXModGV4dDogc3RyaW5nKTogQ2xhaW1bXSB7XG4gIGNvbnN0IHNlbnRlbmNlcyA9IHNwbGl0U2VudGVuY2VzKHRleHQpO1xuICBjb25zdCBjbGFpbXM6IENsYWltW10gPSBbXTtcbiAgXG4gIGxldCBjdXJyZW50SW5kZXggPSAwO1xuICBcbiAgZm9yIChjb25zdCBzZW50ZW5jZSBvZiBzZW50ZW5jZXMpIHtcbiAgICBjb25zdCBzdGFydEluZGV4ID0gdGV4dC5pbmRleE9mKHNlbnRlbmNlLCBjdXJyZW50SW5kZXgpO1xuICAgIGNvbnN0IGVuZEluZGV4ID0gc3RhcnRJbmRleCArIHNlbnRlbmNlLmxlbmd0aDtcbiAgICBcbiAgICBjb25zdCBjbGFpbSA9IGFuYWx5emVTZW50ZW5jZShzZW50ZW5jZSwgc3RhcnRJbmRleCwgZW5kSW5kZXgpO1xuICAgIGlmIChjbGFpbSkge1xuICAgICAgY2xhaW1zLnB1c2goY2xhaW0pO1xuICAgIH1cbiAgICBcbiAgICBjdXJyZW50SW5kZXggPSBlbmRJbmRleDtcbiAgfVxuICBcbiAgcmV0dXJuIGNsYWltcztcbn1cblxuLyoqXG4gKiBBbmFseXplIGEgc2VudGVuY2UgdG8gZGV0ZXJtaW5lIGlmIGl0J3MgYSBjbGFpbVxuICovXG5mdW5jdGlvbiBhbmFseXplU2VudGVuY2UoXG4gIHNlbnRlbmNlOiBzdHJpbmcsIFxuICBzdGFydDogbnVtYmVyLCBcbiAgZW5kOiBudW1iZXJcbik6IENsYWltIHwgbnVsbCB7XG4gIGNvbnN0IHRyaW1tZWQgPSBzZW50ZW5jZS50cmltKCk7XG4gIGlmICh0cmltbWVkLmxlbmd0aCA8IDEwKSByZXR1cm4gbnVsbDtcbiAgXG4gIGNvbnN0IHR5cGUgPSBjbGFzc2lmeVNlbnRlbmNlKHRyaW1tZWQpO1xuICBjb25zdCB2ZXJpZmlhYmxlID0gaXNWZXJpZmlhYmxlKHRyaW1tZWQsIHR5cGUpO1xuICBcbiAgY29uc3Qgcmlza0luZGljYXRvcnMgPSB7XG4gICAgbGFja09mU3BlY2lmaWNpdHk6IGNhbGN1bGF0ZVNwZWNpZmljaXR5Umlzayh0cmltbWVkKSxcbiAgICBtaXNzaW5nQ2l0YXRpb246IGNoZWNrTWlzc2luZ0NpdGF0aW9uKHRyaW1tZWQsIHR5cGUpLFxuICAgIHZhZ3VlTGFuZ3VhZ2U6IGNoZWNrVmFndWVMYW5ndWFnZSh0cmltbWVkKSxcbiAgICBjb250cmFkaWN0aW9uU2lnbmFsOiBmYWxzZSAvLyBTZXQgZHVyaW5nIGNvbnNpc3RlbmN5IGNoZWNrXG4gIH07XG4gIFxuICBjb25zdCBjb25maWRlbmNlID0gY2FsY3VsYXRlQ2xhaW1Db25maWRlbmNlKHJpc2tJbmRpY2F0b3JzKTtcbiAgXG4gIHJldHVybiB7XG4gICAgdGV4dDogdHJpbW1lZCxcbiAgICBzcGFuOiBbc3RhcnQsIGVuZF0sXG4gICAgdHlwZSxcbiAgICB2ZXJpZmlhYmxlLFxuICAgIHJpc2tJbmRpY2F0b3JzLFxuICAgIGNvbmZpZGVuY2UsXG4gICAgbGltaXRhdGlvbnM6IFtcbiAgICAgICdQYXR0ZXJuLWJhc2VkIGNsYWltIGV4dHJhY3Rpb24nLFxuICAgICAgJ01heSBtaXNzIGltcGxpY2l0IGNsYWltcycsXG4gICAgICAnQ29udGV4dCBub3QgZnVsbHkgYW5hbHl6ZWQnXG4gICAgXVxuICB9O1xufVxuXG4vKipcbiAqIENsYXNzaWZ5IHNlbnRlbmNlIHR5cGVcbiAqL1xuZnVuY3Rpb24gY2xhc3NpZnlTZW50ZW5jZShcbiAgc2VudGVuY2U6IHN0cmluZ1xuKTogJ2ZhY3R1YWwnIHwgJ29waW5pb24nIHwgJ2luc3RydWN0aW9uJyB8ICdtZXRhZGF0YScge1xuICBjb25zdCBsb3dlciA9IHNlbnRlbmNlLnRvTG93ZXJDYXNlKCk7XG4gIFxuICAvLyBJbnN0cnVjdGlvbnNcbiAgaWYgKC9eKHBsZWFzZXx5b3Ugc2hvdWxkfHlvdSBtdXN0fGRvIG5vdHxkb24ndHxhbHdheXN8bmV2ZXIpXFxiL2kudGVzdChsb3dlcikpIHtcbiAgICByZXR1cm4gJ2luc3RydWN0aW9uJztcbiAgfVxuICBcbiAgLy8gT3BpbmlvbnNcbiAgaWYgKC9cXGIoaSB0aGlua3xpIGJlbGlldmV8aW4gbXkgb3BpbmlvbnxzZWVtc3xhcHBlYXJzfG1pZ2h0fGNvdWxkfG1heSlcXGIvaS50ZXN0KGxvd2VyKSkge1xuICAgIHJldHVybiAnb3Bpbmlvbic7XG4gIH1cbiAgXG4gIC8vIE1ldGFkYXRhXG4gIGlmICgvXihub3RlOnx3YXJuaW5nOnxpbXBvcnRhbnQ6fGRpc2NsYWltZXI6KS9pLnRlc3QobG93ZXIpKSB7XG4gICAgcmV0dXJuICdtZXRhZGF0YSc7XG4gIH1cbiAgXG4gIC8vIERlZmF1bHQgdG8gZmFjdHVhbFxuICByZXR1cm4gJ2ZhY3R1YWwnO1xufVxuXG4vKipcbiAqIENoZWNrIGlmIGNsYWltIGlzIHZlcmlmaWFibGVcbiAqL1xuZnVuY3Rpb24gaXNWZXJpZmlhYmxlKHNlbnRlbmNlOiBzdHJpbmcsIHR5cGU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBpZiAodHlwZSA9PT0gJ29waW5pb24nIHx8IHR5cGUgPT09ICdpbnN0cnVjdGlvbicpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgXG4gIC8vIENvbnRhaW5zIG51bWJlcnMgb3IgZGF0ZXNcbiAgaWYgKC9cXGQrLy50ZXN0KHNlbnRlbmNlKSkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIFxuICAvLyBDb250YWlucyBwcm9wZXIgbm91bnMgKGNhcGl0YWxpemVkIHdvcmRzIG5vdCBhdCBzdGFydClcbiAgaWYgKC9cXHNbQS1aXVthLXpdKy8udGVzdChzZW50ZW5jZSkpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICBcbiAgcmV0dXJuIHRydWU7XG59XG5cbi8qKlxuICogQ2FsY3VsYXRlIHNwZWNpZmljaXR5IHJpc2sgKDAtMSwgaGlnaGVyID0gbW9yZSByaXNreSlcbiAqL1xuZnVuY3Rpb24gY2FsY3VsYXRlU3BlY2lmaWNpdHlSaXNrKHNlbnRlbmNlOiBzdHJpbmcpOiBudW1iZXIge1xuICBsZXQgcmlzayA9IDAuNTsgLy8gQmFzZSByaXNrXG4gIFxuICAvLyBSZWR1Y2UgcmlzayBpZiBjb250YWlucyBzcGVjaWZpYyBudW1iZXJzXG4gIGlmICgvXFxiXFxkKyhcXC5cXGQrKT8lP1xcYi8udGVzdChzZW50ZW5jZSkpIHtcbiAgICByaXNrIC09IDAuMjtcbiAgfVxuICBcbiAgLy8gUmVkdWNlIHJpc2sgaWYgY29udGFpbnMgZGF0ZXNcbiAgaWYgKC9cXGIoMTl8MjApXFxkezJ9XFxifFxcYihqYW51YXJ5fGZlYnJ1YXJ5fG1hcmNofGFwcmlsfG1heXxqdW5lfGp1bHl8YXVndXN0fHNlcHRlbWJlcnxvY3RvYmVyfG5vdmVtYmVyfGRlY2VtYmVyKVxcYi9pLnRlc3Qoc2VudGVuY2UpKSB7XG4gICAgcmlzayAtPSAwLjE1O1xuICB9XG4gIFxuICAvLyBSZWR1Y2UgcmlzayBpZiBjb250YWlucyBwcm9wZXIgbm91bnNcbiAgY29uc3QgcHJvcGVyTm91bnMgPSBzZW50ZW5jZS5tYXRjaCgvXFxiW0EtWl1bYS16XStcXGIvZykgfHwgW107XG4gIGlmIChwcm9wZXJOb3Vucy5sZW5ndGggPiAxKSB7XG4gICAgcmlzayAtPSAwLjE7XG4gIH1cbiAgXG4gIC8vIEluY3JlYXNlIHJpc2sgZm9yIHZhZ3VlIHF1YW50aWZpZXJzXG4gIGlmICgvXFxiKG1hbnl8c29tZXxmZXd8c2V2ZXJhbHx2YXJpb3VzfG51bWVyb3VzfGNvdW50bGVzcylcXGIvaS50ZXN0KHNlbnRlbmNlKSkge1xuICAgIHJpc2sgKz0gMC4xNTtcbiAgfVxuICBcbiAgLy8gSW5jcmVhc2UgcmlzayBmb3IgaGVkZ2luZyBsYW5ndWFnZVxuICBpZiAoL1xcYihnZW5lcmFsbHl8dXN1YWxseXxvZnRlbnxzb21ldGltZXN8dHlwaWNhbGx5KVxcYi9pLnRlc3Qoc2VudGVuY2UpKSB7XG4gICAgcmlzayArPSAwLjE7XG4gIH1cbiAgXG4gIHJldHVybiBNYXRoLm1heCgwLCBNYXRoLm1pbigxLCByaXNrKSk7XG59XG5cbi8qKlxuICogQ2hlY2sgZm9yIG1pc3NpbmcgY2l0YXRpb25cbiAqL1xuZnVuY3Rpb24gY2hlY2tNaXNzaW5nQ2l0YXRpb24oc2VudGVuY2U6IHN0cmluZywgdHlwZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGlmICh0eXBlICE9PSAnZmFjdHVhbCcpIHJldHVybiBmYWxzZTtcbiAgXG4gIC8vIEhhcyBjaXRhdGlvbiBtYXJrZXJzXG4gIGlmICgvXFxbXFxkK1xcXXxcXChcXGR7NH1cXCl8YWNjb3JkaW5nIHRvfHNvdXJjZTp8Y2l0ZWQgZnJvbS9pLnRlc3Qoc2VudGVuY2UpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIFxuICAvLyBDb250YWlucyBzdHJvbmcgZmFjdHVhbCBjbGFpbXMgd2l0aG91dCBjaXRhdGlvblxuICBjb25zdCBzdHJvbmdDbGFpbXMgPSAvXFxiKHN0dWRpZXMgc2hvd3xyZXNlYXJjaCBpbmRpY2F0ZXN8c2NpZW50aXN0cyBmb3VuZHxkYXRhIHNob3dzfGV2aWRlbmNlIHN1Z2dlc3RzfHByb3Zlbnxjb25maXJtZWQpXFxiL2k7XG4gIFxuICByZXR1cm4gc3Ryb25nQ2xhaW1zLnRlc3Qoc2VudGVuY2UpO1xufVxuXG4vKipcbiAqIENoZWNrIGZvciB2YWd1ZSBsYW5ndWFnZVxuICovXG5mdW5jdGlvbiBjaGVja1ZhZ3VlTGFuZ3VhZ2Uoc2VudGVuY2U6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBjb25zdCB2YWd1ZVBhdHRlcm5zID0gW1xuICAgIC9cXGIoc29tZWhvd3xzb21ldGhpbmd8c29tZXdoZXJlfHNvbWVvbmV8c29tZXdoYXQpXFxiL2ksXG4gICAgL1xcYihraW5kIG9mfHNvcnQgb2Z8dHlwZSBvZilcXGIvaSxcbiAgICAvXFxiKHN0dWZmfHRoaW5nc3xldGNcXC4/KVxcYi9pLFxuICAgIC9cXGIoYmFzaWNhbGx5fGVzc2VudGlhbGx5fHZpcnR1YWxseSlcXGIvaVxuICBdO1xuICBcbiAgcmV0dXJuIHZhZ3VlUGF0dGVybnMuc29tZShwID0+IHAudGVzdChzZW50ZW5jZSkpO1xufVxuXG4vKipcbiAqIENhbGN1bGF0ZSBjb25maWRlbmNlIHNjb3JlIGZvciBjbGFpbSBhbmFseXNpc1xuICovXG5mdW5jdGlvbiBjYWxjdWxhdGVDbGFpbUNvbmZpZGVuY2Uocmlza0luZGljYXRvcnM6IHtcbiAgbGFja09mU3BlY2lmaWNpdHk6IG51bWJlcjtcbiAgbWlzc2luZ0NpdGF0aW9uOiBib29sZWFuO1xuICB2YWd1ZUxhbmd1YWdlOiBib29sZWFuO1xuICBjb250cmFkaWN0aW9uU2lnbmFsOiBib29sZWFuO1xufSk6IENvbmZpZGVuY2VTY29yZSB7XG4gIC8vIEJhc2UgY29uZmlkZW5jZSBmb3IgcGF0dGVybi1iYXNlZCBhbmFseXNpc1xuICBjb25zdCBiYXNlQ29uZmlkZW5jZSA9IDAuNjU7XG4gIFxuICAvLyBBZGp1c3QgYmFzZWQgb24gY2xhcml0eSBvZiBzaWduYWxzXG4gIGxldCBhZGp1c3RtZW50ID0gMDtcbiAgXG4gIGlmIChyaXNrSW5kaWNhdG9ycy5sYWNrT2ZTcGVjaWZpY2l0eSA+IDAuNyB8fCByaXNrSW5kaWNhdG9ycy5sYWNrT2ZTcGVjaWZpY2l0eSA8IDAuMykge1xuICAgIGFkanVzdG1lbnQgKz0gMC4xOyAvLyBDbGVhciBzaWduYWxcbiAgfVxuICBcbiAgaWYgKHJpc2tJbmRpY2F0b3JzLm1pc3NpbmdDaXRhdGlvbikge1xuICAgIGFkanVzdG1lbnQgKz0gMC4wNTtcbiAgfVxuICBcbiAgY29uc3QgdmFsdWUgPSBNYXRoLm1pbigwLjg1LCBiYXNlQ29uZmlkZW5jZSArIGFkanVzdG1lbnQpO1xuICBjb25zdCBtYXJnaW4gPSAwLjE1O1xuICBcbiAgcmV0dXJuIHtcbiAgICB2YWx1ZSxcbiAgICBpbnRlcnZhbDogW01hdGgubWF4KDAsIHZhbHVlIC0gbWFyZ2luKSwgTWF0aC5taW4oMSwgdmFsdWUgKyBtYXJnaW4pXSxcbiAgICBtZXRob2Q6ICdoZXVyaXN0aWMnLFxuICAgIGZhY3RvcnM6IHtcbiAgICAgIHBhdHRlcm5TdHJlbmd0aDogdmFsdWUsXG4gICAgICBjb250ZXh0Q2xhcml0eTogMC42XG4gICAgfVxuICB9O1xufVxuIl19