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.
311 lines • 37.5 kB
JavaScript
;
/**
* Risk Analyzer
*
* Analyzes risk indicators for claims using pattern-based heuristics.
* All processing is local - no external API calls.
*
* @module engines/hallucination/risk-analyzer
* @author Haiec
* @license MIT
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.analyzeRiskIndicators = analyzeRiskIndicators;
exports.checkContradictions = checkContradictions;
// Patterns for detecting fabricated statistics
const FABRICATED_STAT_PATTERNS = [
/\b\d{1,2}\.\d{1,2}%\b/, // Overly precise percentages like 73.47%
/\bexactly \d+/i, // "exactly 1234"
/\b\d{4,}(?:,\d{3})+\b/, // Large specific numbers like 10,847
/\b(?:9[5-9]|100)(?:\.\d+)?%/, // Suspiciously high percentages 95-100%
];
// Patterns for detecting overconfident language
const OVERCONFIDENT_PATTERNS = [
/\b(?:absolutely|definitely|certainly|undoubtedly|unquestionably)\b/i,
/\b(?:100%|guaranteed|proven fact|without doubt)\b/i,
/\b(?:always|never|impossible|inevitable)\b/i,
/\b(?:no doubt|beyond question|indisputable)\b/i,
/\b(?:everyone knows|it is certain|there is no question)\b/i,
];
// Patterns for detecting fake authority appeals
const FAKE_AUTHORITY_PATTERNS = [
/\b(?:studies show|research proves|scientists confirm|experts agree)\b/i,
/\b(?:according to (?:a |recent )?(?:study|research|survey))\b/i,
/\b(?:it has been (?:proven|shown|demonstrated))\b/i,
/\b(?:universally accepted|widely known|common knowledge)\b/i,
];
// Patterns for detecting temporal inconsistencies
const TEMPORAL_PATTERNS = [
/\b(19|20)\d{2}\b/g, // Years
/\b(?:yesterday|today|tomorrow|last (?:week|month|year)|next (?:week|month|year))\b/gi,
];
// Patterns for detecting numerical claims
const NUMERICAL_CLAIM_PATTERNS = [
/\b\d+(?:\.\d+)?(?:\s*(?:million|billion|trillion|thousand))?\b/gi,
/\b(?:\$|USD|EUR)\s*\d+/gi,
/\b\d+(?:\.\d+)?%/g,
];
/**
* Analyze risk indicators for a claim with enhanced detection
*/
function analyzeRiskIndicators(claim, _config) {
const text = claim.text;
// Calculate additional risk factors
const fabricatedStatRisk = detectFabricatedStatistics(text);
const overconfidenceRisk = detectOverconfidence(text);
const fakeAuthorityRisk = detectFakeAuthority(text);
const temporalRisk = detectTemporalIssues(text);
const numericalRisk = detectNumericalRisk(text);
const hedgingScore = detectHedging(text);
const specificitScore = detectSpecificity(text);
// Combine risks into updated indicators
const combinedRisk = (fabricatedStatRisk * 0.25 +
overconfidenceRisk * 0.20 +
fakeAuthorityRisk * 0.20 +
temporalRisk * 0.10 +
numericalRisk * 0.15 +
(1 - hedgingScore) * 0.05 +
(1 - specificitScore) * 0.05);
// Update lack of specificity based on new analysis
const updatedSpecificity = Math.max(claim.riskIndicators.lackOfSpecificity, 1 - specificitScore);
return {
...claim,
riskIndicators: {
...claim.riskIndicators,
lackOfSpecificity: updatedSpecificity,
// Add new risk factors as custom properties
fabricatedStatRisk,
overconfidenceRisk,
fakeAuthorityRisk,
combinedRisk
}
};
}
/**
* Detect fabricated statistics patterns
*/
function detectFabricatedStatistics(text) {
let risk = 0;
for (const pattern of FABRICATED_STAT_PATTERNS) {
if (pattern.test(text)) {
risk += 0.3;
}
}
// Check for suspiciously precise large numbers
const numbers = text.match(/\b\d{3,}\b/g) || [];
for (const num of numbers) {
// Numbers ending in 7, 3, or other "random-looking" digits are suspicious
if (/[1379]$/.test(num) && num.length > 3) {
risk += 0.1;
}
}
return Math.min(1, risk);
}
/**
* Detect overconfident language
*/
function detectOverconfidence(text) {
let risk = 0;
for (const pattern of OVERCONFIDENT_PATTERNS) {
if (pattern.test(text)) {
risk += 0.25;
}
}
// Check for multiple exclamation marks
const exclamations = (text.match(/!/g) || []).length;
if (exclamations > 1) {
risk += 0.1 * exclamations;
}
// Check for ALL CAPS words (excluding acronyms)
const capsWords = text.match(/\b[A-Z]{4,}\b/g) || [];
if (capsWords.length > 0) {
risk += 0.1 * capsWords.length;
}
return Math.min(1, risk);
}
/**
* Detect fake authority appeals
*/
function detectFakeAuthority(text) {
let risk = 0;
for (const pattern of FAKE_AUTHORITY_PATTERNS) {
if (pattern.test(text)) {
risk += 0.2;
}
}
// Check for vague expert references
if (/\b(?:experts|scientists|researchers|studies)\b/i.test(text)) {
// Without specific names or citations
if (!/\b(?:Dr\.|Prof\.|[A-Z][a-z]+ et al\.|\(\d{4}\)|\[\d+\])/i.test(text)) {
risk += 0.2;
}
}
// Check for "many people" type appeals
if (/\b(?:many people|most people|everyone|nobody)\b/i.test(text)) {
risk += 0.15;
}
return Math.min(1, risk);
}
/**
* Detect temporal inconsistencies
*/
function detectTemporalIssues(text) {
let risk = 0;
// Extract all years
const years = text.match(/\b(19|20)\d{2}\b/g) || [];
const yearNums = years.map(y => parseInt(y, 10));
// Check for future dates presented as facts
const currentYear = new Date().getFullYear();
for (const year of yearNums) {
if (year > currentYear) {
risk += 0.3;
}
}
// Check for impossible timelines (year X before year Y where X > Y)
if (yearNums.length >= 2) {
const sorted = [...yearNums].sort((a, b) => a - b);
// Check if text implies wrong order
if (/before|prior to|preceded/i.test(text)) {
const firstMentioned = yearNums[0];
const secondMentioned = yearNums[1];
if (firstMentioned > secondMentioned) {
risk += 0.4;
}
}
}
return Math.min(1, risk);
}
/**
* Detect numerical claim risks
*/
function detectNumericalRisk(text) {
let risk = 0;
// Count numerical claims
const numbers = text.match(NUMERICAL_CLAIM_PATTERNS[0]) || [];
const currencies = text.match(NUMERICAL_CLAIM_PATTERNS[1]) || [];
const percentages = text.match(NUMERICAL_CLAIM_PATTERNS[2]) || [];
const totalNumerical = numbers.length + currencies.length + percentages.length;
// High density of numbers without sources is risky
const words = text.split(/\s+/).length;
const numericalDensity = totalNumerical / words;
if (numericalDensity > 0.15) {
risk += 0.3;
}
// Check for round numbers (often fabricated)
for (const num of numbers) {
const n = parseInt(num.replace(/,/g, ''), 10);
if (n > 100 && n % 100 === 0) {
risk += 0.05;
}
if (n > 1000 && n % 1000 === 0) {
risk += 0.1;
}
}
return Math.min(1, risk);
}
/**
* Detect hedging language (reduces risk)
*/
function detectHedging(text) {
const hedgingPatterns = [
/\b(?:may|might|could|possibly|perhaps|probably)\b/i,
/\b(?:suggests|indicates|appears|seems)\b/i,
/\b(?:approximately|about|around|roughly|estimated)\b/i,
/\b(?:in my opinion|I think|I believe)\b/i,
/\b(?:it is possible|there is a chance)\b/i,
];
let hedgingScore = 0;
for (const pattern of hedgingPatterns) {
if (pattern.test(text)) {
hedgingScore += 0.2;
}
}
return Math.min(1, hedgingScore);
}
/**
* Detect specificity (higher is better)
*/
function detectSpecificity(text) {
let score = 0.3; // Base score
// Proper nouns add specificity
const properNouns = text.match(/\b[A-Z][a-z]+(?:\s+[A-Z][a-z]+)*\b/g) || [];
score += Math.min(0.3, properNouns.length * 0.1);
// Dates add specificity
if (/\b(?:January|February|March|April|May|June|July|August|September|October|November|December)\s+\d{1,2},?\s+\d{4}\b/i.test(text)) {
score += 0.2;
}
// Citations add specificity
if (/\(\d{4}\)|\[\d+\]|et al\./i.test(text)) {
score += 0.2;
}
// URLs add specificity
if (/https?:\/\/\S+/i.test(text)) {
score += 0.1;
}
return Math.min(1, score);
}
/**
* Check for contradiction signals between claims
*/
function checkContradictions(claims) {
const contradictionPairs = [];
for (let i = 0; i < claims.length; i++) {
for (let j = i + 1; j < claims.length; j++) {
if (detectContradiction(claims[i], claims[j])) {
contradictionPairs.push([i, j]);
}
}
}
// Mark claims involved in contradictions
const updatedClaims = claims.map((claim, index) => {
const isInvolved = contradictionPairs.some(([a, b]) => a === index || b === index);
if (isInvolved) {
return {
...claim,
riskIndicators: {
...claim.riskIndicators,
contradictionSignal: true
}
};
}
return claim;
});
return updatedClaims;
}
/**
* Detect potential contradiction between two claims
*/
function detectContradiction(claim1, claim2) {
const text1 = claim1.text.toLowerCase();
const text2 = claim2.text.toLowerCase();
// Check for negation patterns
const negationPatterns = [
{ positive: /\bis\b/, negative: /\bis not\b|\bisn't\b/ },
{ positive: /\bwill\b/, negative: /\bwill not\b|\bwon't\b/ },
{ positive: /\bcan\b/, negative: /\bcannot\b|\bcan't\b/ },
{ positive: /\bdoes\b/, negative: /\bdoes not\b|\bdoesn't\b/ },
{ positive: /\bhas\b/, negative: /\bhas not\b|\bhasn't\b/ },
{ positive: /\btrue\b/, negative: /\bfalse\b/ },
{ positive: /\byes\b/, negative: /\bno\b/ },
{ positive: /\balways\b/, negative: /\bnever\b/ },
{ positive: /\ball\b/, negative: /\bnone\b/ }
];
for (const pattern of negationPatterns) {
const match1Pos = pattern.positive.test(text1);
const match1Neg = pattern.negative.test(text1);
const match2Pos = pattern.positive.test(text2);
const match2Neg = pattern.negative.test(text2);
// One has positive, other has negative
if ((match1Pos && match2Neg) || (match1Neg && match2Pos)) {
// Check if they're about the same subject (simple overlap check)
const words1 = new Set(text1.split(/\s+/).filter(w => w.length > 4));
const words2 = new Set(text2.split(/\s+/).filter(w => w.length > 4));
const overlap = [...words1].filter(w => words2.has(w));
if (overlap.length >= 2) {
return true;
}
}
}
return false;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmlzay1hbmFseXplci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9lbmdpbmVzL2hhbGx1Y2luYXRpb24vcmlzay1hbmFseXplci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7OztHQVNHOztBQThDSCxzREF5Q0M7QUEyTUQsa0RBK0JDO0FBNVRELCtDQUErQztBQUMvQyxNQUFNLHdCQUF3QixHQUFHO0lBQy9CLHVCQUF1QixFQUFHLHlDQUF5QztJQUNuRSxnQkFBZ0IsRUFBVSxpQkFBaUI7SUFDM0MsdUJBQXVCLEVBQUcscUNBQXFDO0lBQy9ELDZCQUE2QixFQUFHLHdDQUF3QztDQUN6RSxDQUFDO0FBRUYsZ0RBQWdEO0FBQ2hELE1BQU0sc0JBQXNCLEdBQUc7SUFDN0IscUVBQXFFO0lBQ3JFLG9EQUFvRDtJQUNwRCw2Q0FBNkM7SUFDN0MsZ0RBQWdEO0lBQ2hELDREQUE0RDtDQUM3RCxDQUFDO0FBRUYsZ0RBQWdEO0FBQ2hELE1BQU0sdUJBQXVCLEdBQUc7SUFDOUIsd0VBQXdFO0lBQ3hFLGdFQUFnRTtJQUNoRSxvREFBb0Q7SUFDcEQsNkRBQTZEO0NBQzlELENBQUM7QUFFRixrREFBa0Q7QUFDbEQsTUFBTSxpQkFBaUIsR0FBRztJQUN4QixtQkFBbUIsRUFBRyxRQUFRO0lBQzlCLHNGQUFzRjtDQUN2RixDQUFDO0FBRUYsMENBQTBDO0FBQzFDLE1BQU0sd0JBQXdCLEdBQUc7SUFDL0Isa0VBQWtFO0lBQ2xFLDBCQUEwQjtJQUMxQixtQkFBbUI7Q0FDcEIsQ0FBQztBQUVGOztHQUVHO0FBQ0gsU0FBZ0IscUJBQXFCLENBQUMsS0FBWSxFQUFFLE9BQWU7SUFDakUsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQztJQUV4QixvQ0FBb0M7SUFDcEMsTUFBTSxrQkFBa0IsR0FBRywwQkFBMEIsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUM1RCxNQUFNLGtCQUFrQixHQUFHLG9CQUFvQixDQUFD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QUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDL0MsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFL0MsdUNBQXVDO1FBQ3ZDLElBQUksQ0FBQyxTQUFTLElBQUksU0FBUyxDQUFDLElBQUksQ0FBQyxTQUFTLElBQUksU0FBUyxDQUFDLEVBQUUsQ0FBQztZQUN6RCxpRUFBaUU7WUFDakUsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDckUsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFFckUsTUFBTSxPQUFPLEdBQUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUV2RCxJQUFJLE9BQU8sQ0FBQyxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQ3hCLE9BQU8sSUFBSSxDQUFDO1lBQ2QsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBSaXNrIEFuYWx5emVyXG4gKiBcbiAqIEFuYWx5emVzIHJpc2sgaW5kaWNhdG9ycyBmb3IgY2xhaW1zIHVzaW5nIHBhdHRlcm4tYmFzZWQgaGV1cmlzdGljcy5cbiAqIEFsbCBwcm9jZXNzaW5nIGlzIGxvY2FsIC0gbm8gZXh0ZXJuYWwgQVBJIGNhbGxzLlxuICogXG4gKiBAbW9kdWxlIGVuZ2luZXMvaGFsbHVjaW5hdGlvbi9yaXNrLWFuYWx5emVyXG4gKiBAYXV0aG9yIEhhaWVjXG4gKiBAbGljZW5zZSBNSVRcbiAqL1xuXG5pbXBvcnQgeyBDbGFpbSB9IGZyb20gJy4uLy4uL3R5cGVzL3Jlc3VsdHMnO1xuaW1wb3J0IHsgQ29uZmlnIH0gZnJvbSAnLi4vLi4vdHlwZXMvY29uZmlnJztcblxuLy8gUGF0dGVybnMgZm9yIGRldGVjdGluZyBmYWJyaWNhdGVkIHN0YXRpc3RpY3NcbmNvbnN0IEZBQlJJQ0FURURfU1RBVF9QQVRURVJOUyA9IFtcbiAgL1xcYlxcZHsxLDJ9XFwuXFxkezEsMn0lXFxiLywgIC8vIE92ZXJseSBwcmVjaXNlIHBlcmNlbnRhZ2VzIGxpa2UgNzMuNDclXG4gIC9cXGJleGFjdGx5IFxcZCsvaSwgICAgICAgICAvLyBcImV4YWN0bHkgMTIzNFwiXG4gIC9cXGJcXGR7NCx9KD86LFxcZHszfSkrXFxiLywgIC8vIExhcmdlIHNwZWNpZmljIG51bWJlcnMgbGlrZSAxMCw4NDdcbiAgL1xcYig/OjlbNS05XXwxMDApKD86XFwuXFxkKyk/JS8sICAvLyBTdXNwaWNpb3VzbHkgaGlnaCBwZXJjZW50YWdlcyA5NS0xMDAlXG5dO1xuXG4vLyBQYXR0ZXJucyBmb3IgZGV0ZWN0aW5nIG92ZXJjb25maWRlbnQgbGFuZ3VhZ2VcbmNvbnN0IE9WRVJDT05GSURFTlRfUEFUVEVSTlMgPSBbXG4gIC9cXGIoPzphYnNvbHV0ZWx5fGRlZmluaXRlbHl8Y2VydGFpbmx5fHVuZG91YnRlZGx5fHVucXVlc3Rpb25hYmx5KVxcYi9pLFxuICAvXFxiKD86MTAwJXxndWFyYW50ZWVkfHByb3ZlbiBmYWN0fHdpdGhvdXQgZG91YnQpXFxiL2ksXG4gIC9cXGIoPzphbHdheXN8bmV2ZXJ8aW1wb3NzaWJsZXxpbmV2aXRhYmxlKVxcYi9pLFxuICAvXFxiKD86bm8gZG91YnR8YmV5b25kIHF1ZXN0aW9ufGluZGlzcHV0YWJsZSlcXGIvaSxcbiAgL1xcYig/OmV2ZXJ5b25lIGtub3dzfGl0IGlzIGNlcnRhaW58dGhlcmUgaXMgbm8gcXVlc3Rpb24pXFxiL2ksXG5dO1xuXG4vLyBQYXR0ZXJucyBmb3IgZGV0ZWN0aW5nIGZha2UgYXV0aG9yaXR5IGFwcGVhbHNcbmNvbnN0IEZBS0VfQVVUSE9SSVRZX1BBVFRFUk5TID0gW1xuICAvXFxiKD86c3R1ZGllcyBzaG93fHJlc2VhcmNoIHByb3Zlc3xzY2llbnRpc3RzIGNvbmZpcm18ZXhwZXJ0cyBhZ3JlZSlcXGIvaSxcbiAgL1xcYig/OmFjY29yZGluZyB0byAoPzphIHxyZWNlbnQgKT8oPzpzdHVkeXxyZXNlYXJjaHxzdXJ2ZXkpKVxcYi9pLFxuICAvXFxiKD86aXQgaGFzIGJlZW4gKD86cHJvdmVufHNob3dufGRlbW9uc3RyYXRlZCkpXFxiL2ksXG4gIC9cXGIoPzp1bml2ZXJzYWxseSBhY2NlcHRlZHx3aWRlbHkga25vd258Y29tbW9uIGtub3dsZWRnZSlcXGIvaSxcbl07XG5cbi8vIFBhdHRlcm5zIGZvciBkZXRlY3RpbmcgdGVtcG9yYWwgaW5jb25zaXN0ZW5jaWVzXG5jb25zdCBURU1QT1JBTF9QQVRURVJOUyA9IFtcbiAgL1xcYigxOXwyMClcXGR7Mn1cXGIvZywgIC8vIFllYXJzXG4gIC9cXGIoPzp5ZXN0ZXJkYXl8dG9kYXl8dG9tb3Jyb3d8bGFzdCAoPzp3ZWVrfG1vbnRofHllYXIpfG5leHQgKD86d2Vla3xtb250aHx5ZWFyKSlcXGIvZ2ksXG5dO1xuXG4vLyBQYXR0ZXJucyBmb3IgZGV0ZWN0aW5nIG51bWVyaWNhbCBjbGFpbXNcbmNvbnN0IE5VTUVSSUNBTF9DTEFJTV9QQVRURVJOUyA9IFtcbiAgL1xcYlxcZCsoPzpcXC5cXGQrKT8oPzpcXHMqKD86bWlsbGlvbnxiaWxsaW9ufHRyaWxsaW9ufHRob3VzYW5kKSk/XFxiL2dpLFxuICAvXFxiKD86XFwkfFVTRHxFVVIpXFxzKlxcZCsvZ2ksXG4gIC9cXGJcXGQrKD86XFwuXFxkKyk/JS9nLFxuXTtcblxuLyoqXG4gKiBBbmFseXplIHJpc2sgaW5kaWNhdG9ycyBmb3IgYSBjbGFpbSB3aXRoIGVuaGFuY2VkIGRldGVjdGlvblxuICovXG5leHBvcnQgZnVuY3Rpb24gYW5hbHl6ZVJpc2tJbmRpY2F0b3JzKGNsYWltOiBDbGFpbSwgX2NvbmZpZzogQ29uZmlnKTogQ2xhaW0ge1xuICBjb25zdCB0ZXh0ID0gY2xhaW0udGV4dDtcbiAgXG4gIC8vIENhbGN1bGF0ZSBhZGRpdGlvbmFsIHJpc2sgZmFjdG9yc1xuICBjb25zdCBmYWJyaWNhdGVkU3RhdFJpc2sgPSBkZXRlY3RGYWJyaWNhdGVkU3RhdGlzdGljcyh0ZXh0KTtcbiAgY29uc3Qgb3ZlcmNvbmZpZGVuY2VSaXNrID0gZGV0ZWN0T3ZlcmNvbmZpZGVuY2UodGV4dCk7XG4gIGNvbnN0IGZha2VBdXRob3JpdHlSaXNrID0gZGV0ZWN0RmFrZUF1dGhvcml0eSh0ZXh0KTtcbiAgY29uc3QgdGVtcG9yYWxSaXNrID0gZGV0ZWN0VGVtcG9yYWxJc3N1ZXModGV4dCk7XG4gIGNvbnN0IG51bWVyaWNhbFJpc2sgPSBkZXRlY3ROdW1lcmljYWxSaXNrKHRleHQpO1xuICBjb25zdCBoZWRnaW5nU2NvcmUgPSBkZXRlY3RIZWRnaW5nKHRleHQpO1xuICBjb25zdCBzcGVjaWZpY2l0U2NvcmUgPSBkZXRlY3RTcGVjaWZpY2l0eSh0ZXh0KTtcbiAgXG4gIC8vIENvbWJpbmUgcmlza3MgaW50byB1cGRhdGVkIGluZGljYXRvcnNcbiAgY29uc3QgY29tYmluZWRSaXNrID0gKFxuICAgIGZhYnJpY2F0ZWRTdGF0UmlzayAqIDAuMjUgK1xuICAgIG92ZXJjb25maWRlbmNlUmlzayAqIDAuMjAgK1xuICAgIGZha2VBdXRob3JpdHlSaXNrICogMC4yMCArXG4gICAgdGVtcG9yYWxSaXNrICogMC4xMCArXG4gICAgbnVtZXJpY2FsUmlzayAqIDAuMTUgK1xuICAgICgxIC0gaGVkZ2luZ1Njb3JlKSAqIDAuMDUgK1xuICAgICgxIC0gc3BlY2lmaWNpdFNjb3JlKSAqIDAuMDVcbiAgKTtcbiAgXG4gIC8vIFVwZGF0ZSBsYWNrIG9mIHNwZWNpZmljaXR5IGJhc2VkIG9uIG5ldyBhbmFseXNpc1xuICBjb25zdCB1cGRhdGVkU3BlY2lmaWNpdHkgPSBNYXRoLm1heChcbiAgICBjbGFpbS5yaXNrSW5kaWNhdG9ycy5sYWNrT2ZTcGVjaWZpY2l0eSxcbiAgICAxIC0gc3BlY2lmaWNpdFNjb3JlXG4gICk7XG4gIFxuICByZXR1cm4ge1xuICAgIC4uLmNsYWltLFxuICAgIHJpc2tJbmRpY2F0b3JzOiB7XG4gICAgICAuLi5jbGFpbS5yaXNrSW5kaWNhdG9ycyxcbiAgICAgIGxhY2tPZlNwZWNpZmljaXR5OiB1cGRhdGVkU3BlY2lmaWNpdHksXG4gICAgICAvLyBBZGQgbmV3IHJpc2sgZmFjdG9ycyBhcyBjdXN0b20gcHJvcGVydGllc1xuICAgICAgZmFicmljYXRlZFN0YXRSaXNrLFxuICAgICAgb3ZlcmNvbmZpZGVuY2VSaXNrLFxuICAgICAgZmFrZUF1dGhvcml0eVJpc2ssXG4gICAgICBjb21iaW5lZFJpc2tcbiAgICB9IGFzIGFueVxuICB9O1xufVxuXG4vKipcbiAqIERldGVjdCBmYWJyaWNhdGVkIHN0YXRpc3RpY3MgcGF0dGVybnNcbiAqL1xuZnVuY3Rpb24gZGV0ZWN0RmFicmljYXRlZFN0YXRpc3RpY3ModGV4dDogc3RyaW5nKTogbnVtYmVyIHtcbiAgbGV0IHJpc2sgPSAwO1xuICBcbiAgZm9yIChjb25zdCBwYXR0ZXJuIG9mIEZBQlJJQ0FURURfU1RBVF9QQVRURVJOUykge1xuICAgIGlmIChwYXR0ZXJuLnRlc3QodGV4dCkpIHtcbiAgICAgIHJpc2sgKz0gMC4zO1xuICAgIH1cbiAgfVxuICBcbiAgLy8gQ2hlY2sgZm9yIHN1c3BpY2lvdXNseSBwcmVjaXNlIGxhcmdlIG51bWJlcnNcbiAgY29uc3QgbnVtYmVycyA9IHRleHQubWF0Y2goL1xcYlxcZHszLH1cXGIvZykgfHwgW107XG4gIGZvciAoY29uc3QgbnVtIG9mIG51bWJlcnMpIHtcbiAgICAvLyBOdW1iZXJzIGVuZGluZyBpbiA3LCAzLCBvciBvdGhlciBcInJhbmRvbS1sb29raW5nXCIgZGlnaXRzIGFyZSBzdXNwaWNpb3VzXG4gICAgaWYgKC9bMTM3OV0kLy50ZXN0KG51bSkgJiYgbnVtLmxlbmd0aCA+IDMpIHtcbiAgICAgIHJpc2sgKz0gMC4xO1xuICAgIH1cbiAgfVxuICBcbiAgcmV0dXJuIE1hdGgubWluKDEsIHJpc2spO1xufVxuXG4vKipcbiAqIERldGVjdCBvdmVyY29uZmlkZW50IGxhbmd1YWdlXG4gKi9cbmZ1bmN0aW9uIGRldGVjdE92ZXJjb25maWRlbmNlKHRleHQ6IHN0cmluZyk6IG51bWJlciB7XG4gIGxldCByaXNrID0gMDtcbiAgXG4gIGZvciAoY29uc3QgcGF0dGVybiBvZiBPVkVSQ09ORklERU5UX1BBVFRFUk5TKSB7XG4gICAgaWYgKHBhdHRlcm4udGVzdCh0ZXh0KSkge1xuICAgICAgcmlzayArPSAwLjI1O1xuICAgIH1cbiAgfVxuICBcbiAgLy8gQ2hlY2sgZm9yIG11bHRpcGxlIGV4Y2xhbWF0aW9uIG1hcmtzXG4gIGNvbnN0IGV4Y2xhbWF0aW9ucyA9ICh0ZXh0Lm1hdGNoKC8hL2cpIHx8IFtdKS5sZW5ndGg7XG4gIGlmIChleGNsYW1hdGlvbnMgPiAxKSB7XG4gICAgcmlzayArPSAwLjEgKiBleGNsYW1hdGlvbnM7XG4gIH1cbiAgXG4gIC8vIENoZWNrIGZvciBBTEwgQ0FQUyB3b3JkcyAoZXhjbHVkaW5nIGFjcm9ueW1zKVxuICBjb25zdCBjYXBzV29yZHMgPSB0ZXh0Lm1hdGNoKC9cXGJbQS1aXXs0LH1cXGIvZykgfHwgW107XG4gIGlmIChjYXBzV29yZHMubGVuZ3RoID4gMCkge1xuICAgIHJpc2sgKz0gMC4xICogY2Fwc1dvcmRzLmxlbmd0aDtcbiAgfVxuICBcbiAgcmV0dXJuIE1hdGgubWluKDEsIHJpc2spO1xufVxuXG4vKipcbiAqIERldGVjdCBmYWtlIGF1dGhvcml0eSBhcHBlYWxzXG4gKi9cbmZ1bmN0aW9uIGRldGVjdEZha2VBdXRob3JpdHkodGV4dDogc3RyaW5nKTogbnVtYmVyIHtcbiAgbGV0IHJpc2sgPSAwO1xuICBcbiAgZm9yIChjb25zdCBwYXR0ZXJuIG9mIEZBS0VfQVVUSE9SSVRZX1BBVFRFUk5TKSB7XG4gICAgaWYgKHBhdHRlcm4udGVzdCh0ZXh0KSkge1xuICAgICAgcmlzayArPSAwLjI7XG4gICAgfVxuICB9XG4gIFxuICAvLyBDaGVjayBmb3IgdmFndWUgZXhwZXJ0IHJlZmVyZW5jZXNcbiAgaWYgKC9cXGIoPzpleHBlcnRzfHNjaWVudGlzdHN8cmVzZWFyY2hlcnN8c3R1ZGllcylcXGIvaS50ZXN0KHRleHQpKSB7XG4gICAgLy8gV2l0aG91dCBzcGVjaWZpYyBuYW1lcyBvciBjaXRhdGlvbnNcbiAgICBpZiAoIS9cXGIoPzpEclxcLnxQcm9mXFwufFtBLVpdW2Etel0rIGV0IGFsXFwufFxcKFxcZHs0fVxcKXxcXFtcXGQrXFxdKS9pLnRlc3QodGV4dCkpIHtcbiAgICAgIHJpc2sgKz0gMC4yO1xuICAgIH1cbiAgfVxuICBcbiAgLy8gQ2hlY2sgZm9yIFwibWFueSBwZW9wbGVcIiB0eXBlIGFwcGVhbHNcbiAgaWYgKC9cXGIoPzptYW55IHBlb3BsZXxtb3N0IHBlb3BsZXxldmVyeW9uZXxub2JvZHkpXFxiL2kudGVzdCh0ZXh0KSkge1xuICAgIHJpc2sgKz0gMC4xNTtcbiAgfVxuICBcbiAgcmV0dXJuIE1hdGgubWluKDEsIHJpc2spO1xufVxuXG4vKipcbiAqIERldGVjdCB0ZW1wb3JhbCBpbmNvbnNpc3RlbmNpZXNcbiAqL1xuZnVuY3Rpb24gZGV0ZWN0VGVtcG9yYWxJc3N1ZXModGV4dDogc3RyaW5nKTogbnVtYmVyIHtcbiAgbGV0IHJpc2sgPSAwO1xuICBcbiAgLy8gRXh0cmFjdCBhbGwgeWVhcnNcbiAgY29uc3QgeWVhcnMgPSB0ZXh0Lm1hdGNoKC9cXGIoMTl8MjApXFxkezJ9XFxiL2cpIHx8IFtdO1xuICBjb25zdCB5ZWFyTnVtcyA9IHllYXJzLm1hcCh5ID0+IHBhcnNlSW50KHksIDEwKSk7XG4gIFxuICAvLyBDaGVjayBmb3IgZnV0dXJlIGRhdGVzIHByZXNlbnRlZCBhcyBmYWN0c1xuICBjb25zdCBjdXJyZW50WWVhciA9IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKTtcbiAgZm9yIChjb25zdCB5ZWFyIG9mIHllYXJOdW1zKSB7XG4gICAgaWYgKHllYXIgPiBjdXJyZW50WWVhcikge1xuICAgICAgcmlzayArPSAwLjM7XG4gICAgfVxuICB9XG4gIFxuICAvLyBDaGVjayBmb3IgaW1wb3NzaWJsZSB0aW1lbGluZXMgKHllYXIgWCBiZWZvcmUgeWVhciBZIHdoZXJlIFggPiBZKVxuICBpZiAoeWVhck51bXMubGVuZ3RoID49IDIpIHtcbiAgICBjb25zdCBzb3J0ZWQgPSBbLi4ueWVhck51bXNdLnNvcnQoKGEsIGIpID0+IGEgLSBiKTtcbiAgICAvLyBDaGVjayBpZiB0ZXh0IGltcGxpZXMgd3Jvbmcgb3JkZXJcbiAgICBpZiAoL2JlZm9yZXxwcmlvciB0b3xwcmVjZWRlZC9pLnRlc3QodGV4dCkpIHtcbiAgICAgIGNvbnN0IGZpcnN0TWVudGlvbmVkID0geWVhck51bXNbMF07XG4gICAgICBjb25zdCBzZWNvbmRNZW50aW9uZWQgPSB5ZWFyTnVtc1sxXTtcbiAgICAgIGlmIChmaXJzdE1lbnRpb25lZCA+IHNlY29uZE1lbnRpb25lZCkge1xuICAgICAgICByaXNrICs9IDAuNDtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgXG4gIHJldHVybiBNYXRoLm1pbigxLCByaXNrKTtcbn1cblxuLyoqXG4gKiBEZXRlY3QgbnVtZXJpY2FsIGNsYWltIHJpc2tzXG4gKi9cbmZ1bmN0aW9uIGRldGVjdE51bWVyaWNhbFJpc2sodGV4dDogc3RyaW5nKTogbnVtYmVyIHtcbiAgbGV0IHJpc2sgPSAwO1xuICBcbiAgLy8gQ291bnQgbnVtZXJpY2FsIGNsYWltc1xuICBjb25zdCBudW1iZXJzID0gdGV4dC5tYXRjaChOVU1FUklDQUxfQ0xBSU1fUEFUVEVSTlNbMF0pIHx8IFtdO1xuICBjb25zdCBjdXJyZW5jaWVzID0gdGV4dC5tYXRjaChOVU1FUklDQUxfQ0xBSU1fUEFUVEVSTlNbMV0pIHx8IFtdO1xuICBjb25zdCBwZXJjZW50YWdlcyA9IHRleHQubWF0Y2goTlVNRVJJQ0FMX0NMQUlNX1BBVFRFUk5TWzJdKSB8fCBbXTtcbiAgXG4gIGNvbnN0IHRvdGFsTnVtZXJpY2FsID0gbnVtYmVycy5sZW5ndGggKyBjdXJyZW5jaWVzLmxlbmd0aCArIHBlcmNlbnRhZ2VzLmxlbmd0aDtcbiAgXG4gIC8vIEhpZ2ggZGVuc2l0eSBvZiBudW1iZXJzIHdpdGhvdXQgc291cmNlcyBpcyByaXNreVxuICBjb25zdCB3b3JkcyA9IHRleHQuc3BsaXQoL1xccysvKS5sZW5ndGg7XG4gIGNvbnN0IG51bWVyaWNhbERlbnNpdHkgPSB0b3RhbE51bWVyaWNhbCAvIHdvcmRzO1xuICBcbiAgaWYgKG51bWVyaWNhbERlbnNpdHkgPiAwLjE1KSB7XG4gICAgcmlzayArPSAwLjM7XG4gIH1cbiAgXG4gIC8vIENoZWNrIGZvciByb3VuZCBudW1iZXJzIChvZnRlbiBmYWJyaWNhdGVkKVxuICBmb3IgKGNvbnN0IG51bSBvZiBudW1iZXJzKSB7XG4gICAgY29uc3QgbiA9IHBhcnNlSW50KG51bS5yZXBsYWNlKC8sL2csICcnKSwgMTApO1xuICAgIGlmIChuID4gMTAwICYmIG4gJSAxMDAgPT09IDApIHtcbiAgICAgIHJpc2sgKz0gMC4wNTtcbiAgICB9XG4gICAgaWYgKG4gPiAxMDAwICYmIG4gJSAxMDAwID09PSAwKSB7XG4gICAgICByaXNrICs9IDAuMTtcbiAgICB9XG4gIH1cbiAgXG4gIHJldHVybiBNYXRoLm1pbigxLCByaXNrKTtcbn1cblxuLyoqXG4gKiBEZXRlY3QgaGVkZ2luZyBsYW5ndWFnZSAocmVkdWNlcyByaXNrKVxuICovXG5mdW5jdGlvbiBkZXRlY3RIZWRnaW5nKHRleHQ6IHN0cmluZyk6IG51bWJlciB7XG4gIGNvbnN0IGhlZGdpbmdQYXR0ZXJucyA9IFtcbiAgICAvXFxiKD86bWF5fG1pZ2h0fGNvdWxkfHBvc3NpYmx5fHBlcmhhcHN8cHJvYmFibHkpXFxiL2ksXG4gICAgL1xcYig/OnN1Z2dlc3RzfGluZGljYXRlc3xhcHBlYXJzfHNlZW1zKVxcYi9pLFxuICAgIC9cXGIoPzphcHByb3hpbWF0ZWx5fGFib3V0fGFyb3VuZHxyb3VnaGx5fGVzdGltYXRlZClcXGIvaSxcbiAgICAvXFxiKD86aW4gbXkgb3BpbmlvbnxJIHRoaW5rfEkgYmVsaWV2ZSlcXGIvaSxcbiAgICAvXFxiKD86aXQgaXMgcG9zc2libGV8dGhlcmUgaXMgYSBjaGFuY2UpXFxiL2ksXG4gIF07XG4gIFxuICBsZXQgaGVkZ2luZ1Njb3JlID0gMDtcbiAgZm9yIChjb25zdCBwYXR0ZXJuIG9mIGhlZGdpbmdQYXR0ZXJucykge1xuICAgIGlmIChwYXR0ZXJuLnRlc3QodGV4dCkpIHtcbiAgICAgIGhlZGdpbmdTY29yZSArPSAwLjI7XG4gICAgfVxuICB9XG4gIFxuICByZXR1cm4gTWF0aC5taW4oMSwgaGVkZ2luZ1Njb3JlKTtcbn1cblxuLyoqXG4gKiBEZXRlY3Qgc3BlY2lmaWNpdHkgKGhpZ2hlciBpcyBiZXR0ZXIpXG4gKi9cbmZ1bmN0aW9uIGRldGVjdFNwZWNpZmljaXR5KHRleHQ6IHN0cmluZyk6IG51bWJlciB7XG4gIGxldCBzY29yZSA9IDAuMzsgLy8gQmFzZSBzY29yZVxuICBcbiAgLy8gUHJvcGVyIG5vdW5zIGFkZCBzcGVjaWZpY2l0eVxuICBjb25zdCBwcm9wZXJOb3VucyA9IHRleHQubWF0Y2goL1xcYltBLVpdW2Etel0rKD86XFxzK1tBLVpdW2Etel0rKSpcXGIvZykgfHwgW107XG4gIHNjb3JlICs9IE1hdGgubWluKDAuMywgcHJvcGVyTm91bnMubGVuZ3RoICogMC4xKTtcbiAgXG4gIC8vIERhdGVzIGFkZCBzcGVjaWZpY2l0eVxuICBpZiAoL1xcYig/OkphbnVhcnl8RmVicnVhcnl8TWFyY2h8QXByaWx8TWF5fEp1bmV8SnVseXxBdWd1c3R8U2VwdGVtYmVyfE9jdG9iZXJ8Tm92ZW1iZXJ8RGVjZW1iZXIpXFxzK1xcZHsxLDJ9LD9cXHMrXFxkezR9XFxiL2kudGVzdCh0ZXh0KSkge1xuICAgIHNjb3JlICs9IDAuMjtcbiAgfVxuICBcbiAgLy8gQ2l0YXRpb25zIGFkZCBzcGVjaWZpY2l0eVxuICBpZiAoL1xcKFxcZHs0fVxcKXxcXFtcXGQrXFxdfGV0IGFsXFwuL2kudGVzdCh0ZXh0KSkge1xuICAgIHNjb3JlICs9IDAuMjtcbiAgfVxuICBcbiAgLy8gVVJMcyBhZGQgc3BlY2lmaWNpdHlcbiAgaWYgKC9odHRwcz86XFwvXFwvXFxTKy9pLnRlc3QodGV4dCkpIHtcbiAgICBzY29yZSArPSAwLjE7XG4gIH1cbiAgXG4gIHJldHVybiBNYXRoLm1pbigxLCBzY29yZSk7XG59XG5cbi8qKlxuICogQ2hlY2sgZm9yIGNvbnRyYWRpY3Rpb24gc2lnbmFscyBiZXR3ZWVuIGNsYWltc1xuICovXG5leHBvcnQgZnVuY3Rpb24gY2hlY2tDb250cmFkaWN0aW9ucyhjbGFpbXM6IENsYWltW10pOiBDbGFpbVtdIHtcbiAgY29uc3QgY29udHJhZGljdGlvblBhaXJzOiBBcnJheTxbbnVtYmVyLCBudW1iZXJdPiA9IFtdO1xuICBcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBjbGFpbXMubGVuZ3RoOyBpKyspIHtcbiAgICBmb3IgKGxldCBqID0gaSArIDE7IGogPCBjbGFpbXMubGVuZ3RoOyBqKyspIHtcbiAgICAgIGlmIChkZXRlY3RDb250cmFkaWN0aW9uKGNsYWltc1tpXSwgY2xhaW1zW2pdKSkge1xuICAgICAgICBjb250cmFkaWN0aW9uUGFpcnMucHVzaChbaSwgal0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBcbiAgLy8gTWFyayBjbGFpbXMgaW52b2x2ZWQgaW4gY29udHJhZGljdGlvbnNcbiAgY29uc3QgdXBkYXRlZENsYWltcyA9IGNsYWltcy5tYXAoKGNsYWltLCBpbmRleCkgPT4ge1xuICAgIGNvbnN0IGlzSW52b2x2ZWQgPSBjb250cmFkaWN0aW9uUGFpcnMuc29tZShcbiAgICAgIChbYSwgYl0pID0+IGEgPT09IGluZGV4IHx8IGIgPT09IGluZGV4XG4gICAgKTtcbiAgICBcbiAgICBpZiAoaXNJbnZvbHZlZCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgLi4uY2xhaW0sXG4gICAgICAgIHJpc2tJbmRpY2F0b3JzOiB7XG4gICAgICAgICAgLi4uY2xhaW0ucmlza0luZGljYXRvcnMsXG4gICAgICAgICAgY29udHJhZGljdGlvblNpZ25hbDogdHJ1ZVxuICAgICAgICB9XG4gICAgICB9O1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gY2xhaW07XG4gIH0pO1xuICBcbiAgcmV0dXJuIHVwZGF0ZWRDbGFpbXM7XG59XG5cbi8qKlxuICogRGV0ZWN0IHBvdGVudGlhbCBjb250cmFkaWN0aW9uIGJldHdlZW4gdHdvIGNsYWltc1xuICovXG5mdW5jdGlvbiBkZXRlY3RDb250cmFkaWN0aW9uKGNsYWltMTogQ2xhaW0sIGNsYWltMjogQ2xhaW0pOiBib29sZWFuIHtcbiAgY29uc3QgdGV4dDEgPSBjbGFpbTEudGV4dC50b0xvd2VyQ2FzZSgpO1xuICBjb25zdCB0ZXh0MiA9IGNsYWltMi50ZXh0LnRvTG93ZXJDYXNlKCk7XG4gIFxuICAvLyBDaGVjayBmb3IgbmVnYXRpb24gcGF0dGVybnNcbiAgY29uc3QgbmVnYXRpb25QYXR0ZXJucyA9IFtcbiAgICB7IHBvc2l0aXZlOiAvXFxiaXNcXGIvLCBuZWdhdGl2ZTogL1xcYmlzIG5vdFxcYnxcXGJpc24ndFxcYi8gfSxcbiAgICB7IHBvc2l0aXZlOiAvXFxid2lsbFxcYi8sIG5lZ2F0aXZlOiAvXFxid2lsbCBub3RcXGJ8XFxid29uJ3RcXGIvIH0sXG4gICAgeyBwb3NpdGl2ZTogL1xcYmNhblxcYi8sIG5lZ2F0aXZlOiAvXFxiY2Fubm90XFxifFxcYmNhbid0XFxiLyB9LFxuICAgIHsgcG9zaXRpdmU6IC9cXGJkb2VzXFxiLywgbmVnYXRpdmU6IC9cXGJkb2VzIG5vdFxcYnxcXGJkb2Vzbid0XFxiLyB9LFxuICAgIHsgcG9zaXRpdmU6IC9cXGJoYXNcXGIvLCBuZWdhdGl2ZTogL1xcYmhhcyBub3RcXGJ8XFxiaGFzbid0XFxiLyB9LFxuICAgIHsgcG9zaXRpdmU6IC9cXGJ0cnVlXFxiLywgbmVnYXRpdmU6IC9cXGJmYWxzZVxcYi8gfSxcbiAgICB7IHBvc2l0aXZlOiAvXFxieWVzXFxiLywgbmVnYXRpdmU6IC9cXGJub1xcYi8gfSxcbiAgICB7IHBvc2l0aXZlOiAvXFxiYWx3YXlzXFxiLywgbmVnYXRpdmU6IC9cXGJuZXZlclxcYi8gfSxcbiAgICB7IHBvc2l0aXZlOiAvXFxiYWxsXFxiLywgbmVnYXRpdmU6IC9cXGJub25lXFxiLyB9XG4gIF07XG4gIFxuICBmb3IgKGNvbnN0IHBhdHRlcm4gb2YgbmVnYXRpb25QYXR0ZXJucykge1xuICAgIGNvbnN0IG1hdGNoMVBvcyA9IHBhdHRlcm4ucG9zaXRpdmUudGVzdCh0ZXh0MSk7XG4gICAgY29uc3QgbWF0Y2gxTmVnID0gcGF0dGVybi5uZWdhdGl2ZS50ZXN0KHRleHQxKTtcbiAgICBjb25zdCBtYXRjaDJQb3MgPSBwYXR0ZXJuLnBvc2l0aXZlLnRlc3QodGV4dDIpO1xuICAgIGNvbnN0IG1hdGNoMk5lZyA9IHBhdHRlcm4ubmVnYXRpdmUudGVzdCh0ZXh0Mik7XG4gICAgXG4gICAgLy8gT25lIGhhcyBwb3NpdGl2ZSwgb3RoZXIgaGFzIG5lZ2F0aXZlXG4gICAgaWYgKChtYXRjaDFQb3MgJiYgbWF0Y2gyTmVnKSB8fCAobWF0Y2gxTmVnICYmIG1hdGNoMlBvcykpIHtcbiAgICAgIC8vIENoZWNrIGlmIHRoZXkncmUgYWJvdXQgdGhlIHNhbWUgc3ViamVjdCAoc2ltcGxlIG92ZXJsYXAgY2hlY2spXG4gICAgICBjb25zdCB3b3JkczEgPSBuZXcgU2V0KHRleHQxLnNwbGl0KC9cXHMrLykuZmlsdGVyKHcgPT4gdy5sZW5ndGggPiA0KSk7XG4gICAgICBjb25zdCB3b3JkczIgPSBuZXcgU2V0KHRleHQyLnNwbGl0KC9cXHMrLykuZmlsdGVyKHcgPT4gdy5sZW5ndGggPiA0KSk7XG4gICAgICBcbiAgICAgIGNvbnN0IG92ZXJsYXAgPSBbLi4ud29yZHMxXS5maWx0ZXIodyA9PiB3b3JkczIuaGFzKHcpKTtcbiAgICAgIFxuICAgICAgaWYgKG92ZXJsYXAubGVuZ3RoID49IDIpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIFxuICByZXR1cm4gZmFsc2U7XG59XG4iXX0=