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.
214 lines • 20.1 kB
JavaScript
;
/**
* JSON Detection and Repair Module
*
* Detects JSON in text and attempts to repair malformed JSON.
*
* @module engines/classification/json-repair
* @author Haiec
* @license MIT
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.detectAndRepairJson = detectAndRepairJson;
/**
* Extracts JSON candidate from text.
*/
function extractJsonCandidate(text) {
// Try to find JSON in code blocks first
const codeBlockMatch = text.match(/```(?:json)?\s*([\s\S]*?)```/);
if (codeBlockMatch) {
const content = codeBlockMatch[1].trim();
if (content.startsWith('{') || content.startsWith('[')) {
return content;
}
}
// Look for JSON-like patterns
const jsonPatterns = [
/(\{[\s\S]*\})/, // Object
/(\[[\s\S]*\])/ // Array
];
for (const pattern of jsonPatterns) {
const match = text.match(pattern);
if (match) {
return match[1];
}
}
return null;
}
/**
* Attempts to parse JSON, returns null if invalid.
*/
function tryParse(json) {
try {
return JSON.parse(json);
}
catch {
return null;
}
}
/**
* Repair step: Remove trailing commas.
*/
function removeTrailingCommas(json) {
// Remove trailing commas before } or ]
return json.replace(/,(\s*[}\]])/g, '$1');
}
/**
* Repair step: Add missing quotes to keys.
*/
function quoteUnquotedKeys(json) {
// Match unquoted keys followed by :
return json.replace(/([{,]\s*)([a-zA-Z_][a-zA-Z0-9_]*)(\s*:)/g, '$1"$2"$3');
}
/**
* Repair step: Replace single quotes with double quotes.
*/
function replaceSingleQuotes(json) {
// Simple replacement - may not handle all edge cases
let result = '';
let inString = false;
let stringChar = '';
for (let i = 0; i < json.length; i++) {
const char = json[i];
const prevChar = i > 0 ? json[i - 1] : '';
if (!inString) {
if (char === '"' || char === "'") {
inString = true;
stringChar = char;
result += '"';
}
else {
result += char;
}
}
else {
if (char === stringChar && prevChar !== '\\') {
inString = false;
result += '"';
}
else if (char === '"' && stringChar === "'") {
result += '\\"';
}
else {
result += char;
}
}
}
return result;
}
/**
* Repair step: Escape unescaped newlines in strings.
*/
function escapeNewlines(json) {
// This is a simplified version - proper implementation would need state tracking
return json.replace(/(?<!\\)\n/g, '\\n');
}
/**
* Repair step: Close unclosed braces and brackets.
*/
function closeBrackets(json) {
let braceCount = 0;
let bracketCount = 0;
for (const char of json) {
if (char === '{')
braceCount++;
else if (char === '}')
braceCount--;
else if (char === '[')
bracketCount++;
else if (char === ']')
bracketCount--;
}
let result = json;
while (bracketCount > 0) {
result += ']';
bracketCount--;
}
while (braceCount > 0) {
result += '}';
braceCount--;
}
return result;
}
/**
* Repair step: Remove JavaScript-style comments.
*/
function removeComments(json) {
// Remove single-line comments
let result = json.replace(/\/\/[^\n]*/g, '');
// Remove multi-line comments
result = result.replace(/\/\*[\s\S]*?\*\//g, '');
return result;
}
/** Default maximum repair steps */
const DEFAULT_MAX_REPAIR_STEPS = 6;
/**
* Detects and repairs JSON in text.
*
* @param text - The text to analyze
* @param maxRepairSteps - Maximum repair steps to attempt (default: 6)
* @returns JSON detection result with repair information
*/
function detectAndRepairJson(text, maxRepairSteps = DEFAULT_MAX_REPAIR_STEPS) {
const candidate = extractJsonCandidate(text);
const repairSteps = [];
if (!candidate) {
return {
isJson: false,
candidate: null,
repairSteps: [],
repairSucceeded: false
};
}
// Try parsing as-is first
let parsed = tryParse(candidate);
if (parsed !== null) {
return {
isJson: true,
normalizedJson: parsed,
candidate,
repairSteps: [],
repairSucceeded: true
};
}
// Apply repair steps in order (limited by maxRepairSteps)
const repairs = [
{ name: 'remove_comments', fn: removeComments },
{ name: 'remove_trailing_commas', fn: removeTrailingCommas },
{ name: 'quote_unquoted_keys', fn: quoteUnquotedKeys },
{ name: 'replace_single_quotes', fn: replaceSingleQuotes },
{ name: 'escape_newlines', fn: escapeNewlines },
{ name: 'close_brackets', fn: closeBrackets }
].slice(0, maxRepairSteps);
let current = candidate;
for (const repair of repairs) {
const before = current;
current = repair.fn(current);
const applied = current !== before;
repairSteps.push({
step: repair.name,
applied
});
// Try parsing after each step
if (applied) {
parsed = tryParse(current);
if (parsed !== null) {
return {
isJson: true,
normalizedJson: parsed,
candidate,
repairSteps,
repairSucceeded: true
};
}
}
}
// All repairs failed
return {
isJson: false,
candidate,
repairSteps,
repairSucceeded: false
};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoianNvbi1yZXBhaXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZW5naW5lcy9jbGFzc2lmaWNhdGlvbi9qc29uLXJlcGFpci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7O0dBUUc7O0FBbUtILGtEQXdFQztBQTVORDs7R0FFRztBQUNILFNBQVMsb0JBQW9CLENBQUMsSUFBWTtJQUN4Qyx3Q0FBd0M7SUFDeEMsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO0lBQ2xFLElBQUksY0FBYyxFQUFFLENBQUM7UUFDbkIsTUFBTSxPQUFPLEdBQUcsY0FBYyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3pDLElBQUksT0FBTyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsSUFBSSxPQUFPLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDdkQsT0FBTyxPQUFPLENBQUM7UUFDakIsQ0FBQztJQUNILENBQUM7SUFFRCw4QkFBOEI7SUFDOUIsTUFBTSxZQUFZLEdBQUc7UUFDbkIsZUFBZSxFQUFHLFNBQVM7UUFDM0IsZUFBZSxDQUFHLFFBQVE7S0FDM0IsQ0FBQztJQUVGLEtBQUssTUFBTSxPQUFPLElBQUksWUFBWSxFQUFFLENBQUM7UUFDbkMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNsQyxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1YsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbEIsQ0FBQztJQUNILENBQUM7SUFFRCxPQUFPLElBQUksQ0FBQztBQUNkLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMsUUFBUSxDQUFDLElBQVk7SUFDNUIsSUFBSSxDQUFDO1FBQ0gsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzFCLENBQUM7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Q0FBQztZQUNKLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELHFCQUFxQjtJQUNyQixPQUFPO1FBQ0wsTUFBTSxFQUFFLEtBQUs7UUFDYixTQUFTO1FBQ1QsV0FBVztRQUNYLGVBQWUsRUFBRSxLQUFLO0tBQ3ZCLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBKU09OIERldGVjdGlvbiBhbmQgUmVwYWlyIE1vZHVsZVxuICogXG4gKiBEZXRlY3RzIEpTT04gaW4gdGV4dCBhbmQgYXR0ZW1wdHMgdG8gcmVwYWlyIG1hbGZvcm1lZCBKU09OLlxuICogXG4gKiBAbW9kdWxlIGVuZ2luZXMvY2xhc3NpZmljYXRpb24vanNvbi1yZXBhaXJcbiAqIEBhdXRob3IgSGFpZWNcbiAqIEBsaWNlbnNlIE1JVFxuICovXG5cbmltcG9ydCB7IEpzb25SZXBhaXJTdGVwIH0gZnJvbSAnLi90eXBlcyc7XG5cbi8qKlxuICogUmVzdWx0IG9mIEpTT04gZGV0ZWN0aW9uIGFuZCByZXBhaXIuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSnNvbkRldGVjdGlvblJlc3VsdCB7XG4gIGlzSnNvbjogYm9vbGVhbjtcbiAgbm9ybWFsaXplZEpzb24/OiB1bmtub3duO1xuICBjYW5kaWRhdGU6IHN0cmluZyB8IG51bGw7XG4gIHJlcGFpclN0ZXBzOiBKc29uUmVwYWlyU3RlcFtdO1xuICByZXBhaXJTdWNjZWVkZWQ6IGJvb2xlYW47XG59XG5cbi8qKlxuICogRXh0cmFjdHMgSlNPTiBjYW5kaWRhdGUgZnJvbSB0ZXh0LlxuICovXG5mdW5jdGlvbiBleHRyYWN0SnNvbkNhbmRpZGF0ZSh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcgfCBudWxsIHtcbiAgLy8gVHJ5IHRvIGZpbmQgSlNPTiBpbiBjb2RlIGJsb2NrcyBmaXJzdFxuICBjb25zdCBjb2RlQmxvY2tNYXRjaCA9IHRleHQubWF0Y2goL2BgYCg/Ompzb24pP1xccyooW1xcc1xcU10qPylgYGAvKTtcbiAgaWYgKGNvZGVCbG9ja01hdGNoKSB7XG4gICAgY29uc3QgY29udGVudCA9IGNvZGVCbG9ja01hdGNoWzFdLnRyaW0oKTtcbiAgICBpZiAoY29udGVudC5zdGFydHNXaXRoKCd7JykgfHwgY29udGVudC5zdGFydHNXaXRoKCdbJykpIHtcbiAgICAgIHJldHVybiBjb250ZW50O1xuICAgIH1cbiAgfVxuICBcbiAgLy8gTG9vayBmb3IgSlNPTi1saWtlIHBhdHRlcm5zXG4gIGNvbnN0IGpzb25QYXR0ZXJucyA9IFtcbiAgICAvKFxce1tcXHNcXFNdKlxcfSkvLCAgLy8gT2JqZWN0XG4gICAgLyhcXFtbXFxzXFxTXSpcXF0pLyAgIC8vIEFycmF5XG4gIF07XG4gIFxuICBmb3IgKGNvbnN0IHBhdHRlcm4gb2YganNvblBhdHRlcm5zKSB7XG4gICAgY29uc3QgbWF0Y2ggPSB0ZXh0Lm1hdGNoKHBhdHRlcm4pO1xuICAgIGlmIChtYXRjaCkge1xuICAgICAgcmV0dXJuIG1hdGNoWzFdO1xuICAgIH1cbiAgfVxuICBcbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogQXR0ZW1wdHMgdG8gcGFyc2UgSlNPTiwgcmV0dXJucyBudWxsIGlmIGludmFsaWQuXG4gKi9cbmZ1bmN0aW9uIHRyeVBhcnNlKGpzb246IHN0cmluZyk6IHVua25vd24gfCBudWxsIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gSlNPTi5wYXJzZShqc29uKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXBhaXIgc3RlcDogUmVtb3ZlIHRyYWlsaW5nIGNvbW1hcy5cbiAqL1xuZnVuY3Rpb24gcmVtb3ZlVHJhaWxpbmdDb21tYXMoanNvbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgLy8gUmVtb3ZlIHRyYWlsaW5nIGNvbW1hcyBiZWZvcmUgfSBvciBdXG4gIHJldHVybiBqc29uLnJlcGxhY2UoLywoXFxzKlt9XFxdXSkvZywgJyQxJyk7XG59XG5cbi8qKlxuICogUmVwYWlyIHN0ZXA6IEFkZCBtaXNzaW5nIHF1b3RlcyB0byBrZXlzLlxuICovXG5mdW5jdGlvbiBxdW90ZVVucXVvdGVkS2V5cyhqc29uOiBzdHJpbmcpOiBzdHJpbmcge1xuICAvLyBNYXRjaCB1bnF1b3RlZCBrZXlzIGZvbGxvd2VkIGJ5IDpcbiAgcmV0dXJuIGpzb24ucmVwbGFjZSgvKFt7LF1cXHMqKShbYS16QS1aX11bYS16QS1aMC05X10qKShcXHMqOikvZywgJyQxXCIkMlwiJDMnKTtcbn1cblxuLyoqXG4gKiBSZXBhaXIgc3RlcDogUmVwbGFjZSBzaW5nbGUgcXVvdGVzIHdpdGggZG91YmxlIHF1b3Rlcy5cbiAqL1xuZnVuY3Rpb24gcmVwbGFjZVNpbmdsZVF1b3Rlcyhqc29uOiBzdHJpbmcpOiBzdHJpbmcge1xuICAvLyBTaW1wbGUgcmVwbGFjZW1lbnQgLSBtYXkgbm90IGhhbmRsZSBhbGwgZWRnZSBjYXNlc1xuICBsZXQgcmVzdWx0ID0gJyc7XG4gIGxldCBpblN0cmluZyA9IGZhbHNlO1xuICBsZXQgc3RyaW5nQ2hhciA9ICcnO1xuICBcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBqc29uLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3QgY2hhciA9IGpzb25baV07XG4gICAgY29uc3QgcHJldkNoYXIgPSBpID4gMCA/IGpzb25baSAtIDFdIDogJyc7XG4gICAgXG4gICAgaWYgKCFpblN0cmluZykge1xuICAgICAgaWYgKGNoYXIgPT09ICdcIicgfHwgY2hhciA9PT0gXCInXCIpIHtcbiAgICAgICAgaW5TdHJpbmcgPSB0cnVlO1xuICAgICAgICBzdHJpbmdDaGFyID0gY2hhcjtcbiAgICAgICAgcmVzdWx0ICs9ICdcIic7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXN1bHQgKz0gY2hhcjtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKGNoYXIgPT09IHN0cmluZ0NoYXIgJiYgcHJldkNoYXIgIT09ICdcXFxcJykge1xuICAgICAgICBpblN0cmluZyA9IGZhbHNlO1xuICAgICAgICByZXN1bHQgKz0gJ1wiJztcbiAgICAgIH0gZWxzZSBpZiAoY2hhciA9PT0gJ1wiJyAmJiBzdHJpbmdDaGFyID09PSBcIidcIikge1xuICAgICAgICByZXN1bHQgKz0gJ1xcXFxcIic7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXN1bHQgKz0gY2hhcjtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgXG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogUmVwYWlyIHN0ZXA6IEVzY2FwZSB1bmVzY2FwZWQgbmV3bGluZXMgaW4gc3RyaW5ncy5cbiAqL1xuZnVuY3Rpb24gZXNjYXBlTmV3bGluZXMoanNvbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgLy8gVGhpcyBpcyBhIHNpbXBsaWZpZWQgdmVyc2lvbiAtIHByb3BlciBpbXBsZW1lbnRhdGlvbiB3b3VsZCBuZWVkIHN0YXRlIHRyYWNraW5nXG4gIHJldHVybiBqc29uLnJlcGxhY2UoLyg/PCFcXFxcKVxcbi9nLCAnXFxcXG4nKTtcbn1cblxuLyoqXG4gKiBSZXBhaXIgc3RlcDogQ2xvc2UgdW5jbG9zZWQgYnJhY2VzIGFuZCBicmFja2V0cy5cbiAqL1xuZnVuY3Rpb24gY2xvc2VCcmFja2V0cyhqc29uOiBzdHJpbmcpOiBzdHJpbmcge1xuICBsZXQgYnJhY2VDb3VudCA9IDA7XG4gIGxldCBicmFja2V0Q291bnQgPSAwO1xuICBcbiAgZm9yIChjb25zdCBjaGFyIG9mIGpzb24pIHtcbiAgICBpZiAoY2hhciA9PT0gJ3snKSBicmFjZUNvdW50Kys7XG4gICAgZWxzZSBpZiAoY2hhciA9PT0gJ30nKSBicmFjZUNvdW50LS07XG4gICAgZWxzZSBpZiAoY2hhciA9PT0gJ1snKSBicmFja2V0Q291bnQrKztcbiAgICBlbHNlIGlmIChjaGFyID09PSAnXScpIGJyYWNrZXRDb3VudC0tO1xuICB9XG4gIFxuICBsZXQgcmVzdWx0ID0ganNvbjtcbiAgd2hpbGUgKGJyYWNrZXRDb3VudCA+IDApIHtcbiAgICByZXN1bHQgKz0gJ10nO1xuICAgIGJyYWNrZXRDb3VudC0tO1xuICB9XG4gIHdoaWxlIChicmFjZUNvdW50ID4gMCkge1xuICAgIHJlc3VsdCArPSAnfSc7XG4gICAgYnJhY2VDb3VudC0tO1xuICB9XG4gIFxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKipcbiAqIFJlcGFpciBzdGVwOiBSZW1vdmUgSmF2YVNjcmlwdC1zdHlsZSBjb21tZW50cy5cbiAqL1xuZnVuY3Rpb24gcmVtb3ZlQ29tbWVudHMoanNvbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgLy8gUmVtb3ZlIHNpbmdsZS1saW5lIGNvbW1lbnRzXG4gIGxldCByZXN1bHQgPSBqc29uLnJlcGxhY2UoL1xcL1xcL1teXFxuXSovZywgJycpO1xuICAvLyBSZW1vdmUgbXVsdGktbGluZSBjb21tZW50c1xuICByZXN1bHQgPSByZXN1bHQucmVwbGFjZSgvXFwvXFwqW1xcc1xcU10qP1xcKlxcLy9nLCAnJyk7XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKiBEZWZhdWx0IG1heGltdW0gcmVwYWlyIHN0ZXBzICovXG5jb25zdCBERUZBVUxUX01BWF9SRVBBSVJfU1RFUFMgPSA2O1xuXG4vKipcbiAqIERldGVjdHMgYW5kIHJlcGFpcnMgSlNPTiBpbiB0ZXh0LlxuICogXG4gKiBAcGFyYW0gdGV4dCAtIFRoZSB0ZXh0IHRvIGFuYWx5emVcbiAqIEBwYXJhbSBtYXhSZXBhaXJTdGVwcyAtIE1heGltdW0gcmVwYWlyIHN0ZXBzIHRvIGF0dGVtcHQgKGRlZmF1bHQ6IDYpXG4gKiBAcmV0dXJucyBKU09OIGRldGVjdGlvbiByZXN1bHQgd2l0aCByZXBhaXIgaW5mb3JtYXRpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRldGVjdEFuZFJlcGFpckpzb24oXG4gIHRleHQ6IHN0cmluZyxcbiAgbWF4UmVwYWlyU3RlcHM6IG51bWJlciA9IERFRkFVTFRfTUFYX1JFUEFJUl9TVEVQU1xuKTogSnNvbkRldGVjdGlvblJlc3VsdCB7XG4gIGNvbnN0IGNhbmRpZGF0ZSA9IGV4dHJhY3RKc29uQ2FuZGlkYXRlKHRleHQpO1xuICBjb25zdCByZXBhaXJTdGVwczogSnNvblJlcGFpclN0ZXBbXSA9IFtdO1xuICBcbiAgaWYgKCFjYW5kaWRhdGUpIHtcbiAgICByZXR1cm4ge1xuICAgICAgaXNKc29uOiBmYWxzZSxcbiAgICAgIGNhbmRpZGF0ZTogbnVsbCxcbiAgICAgIHJlcGFpclN0ZXBzOiBbXSxcbiAgICAgIHJlcGFpclN1Y2NlZWRlZDogZmFsc2VcbiAgICB9O1xuICB9XG4gIFxuICAvLyBUcnkgcGFyc2luZyBhcy1pcyBmaXJzdFxuICBsZXQgcGFyc2VkID0gdHJ5UGFyc2UoY2FuZGlkYXRlKTtcbiAgaWYgKHBhcnNlZCAhPT0gbnVsbCkge1xuICAgIHJldHVybiB7XG4gICAgICBpc0pzb246IHRydWUsXG4gICAgICBub3JtYWxpemVkSnNvbjogcGFyc2VkLFxuICAgICAgY2FuZGlkYXRlLFxuICAgICAgcmVwYWlyU3RlcHM6IFtdLFxuICAgICAgcmVwYWlyU3VjY2VlZGVkOiB0cnVlXG4gICAgfTtcbiAgfVxuICBcbiAgLy8gQXBwbHkgcmVwYWlyIHN0ZXBzIGluIG9yZGVyIChsaW1pdGVkIGJ5IG1heFJlcGFpclN0ZXBzKVxuICBjb25zdCByZXBhaXJzOiBBcnJheTx7IG5hbWU6IHN0cmluZzsgZm46IChzOiBzdHJpbmcpID0+IHN0cmluZyB9PiA9IFtcbiAgICB7IG5hbWU6ICdyZW1vdmVfY29tbWVudHMnLCBmbjogcmVtb3ZlQ29tbWVudHMgfSxcbiAgICB7IG5hbWU6ICdyZW1vdmVfdHJhaWxpbmdfY29tbWFzJywgZm46IHJlbW92ZVRyYWlsaW5nQ29tbWFzIH0sXG4gICAgeyBuYW1lOiAncXVvdGVfdW5xdW90ZWRfa2V5cycsIGZuOiBxdW90ZVVucXVvdGVkS2V5cyB9LFxuICAgIHsgbmFtZTogJ3JlcGxhY2Vfc2luZ2xlX3F1b3RlcycsIGZuOiByZXBsYWNlU2luZ2xlUXVvdGVzIH0sXG4gICAgeyBuYW1lOiAnZXNjYXBlX25ld2xpbmVzJywgZm46IGVzY2FwZU5ld2xpbmVzIH0sXG4gICAgeyBuYW1lOiAnY2xvc2VfYnJhY2tldHMnLCBmbjogY2xvc2VCcmFja2V0cyB9XG4gIF0uc2xpY2UoMCwgbWF4UmVwYWlyU3RlcHMpO1xuICBcbiAgbGV0IGN1cnJlbnQgPSBjYW5kaWRhdGU7XG4gIFxuICBmb3IgKGNvbnN0IHJlcGFpciBvZiByZXBhaXJzKSB7XG4gICAgY29uc3QgYmVmb3JlID0gY3VycmVudDtcbiAgICBjdXJyZW50ID0gcmVwYWlyLmZuKGN1cnJlbnQpO1xuICAgIGNvbnN0IGFwcGxpZWQgPSBjdXJyZW50ICE9PSBiZWZvcmU7XG4gICAgXG4gICAgcmVwYWlyU3RlcHMucHVzaCh7XG4gICAgICBzdGVwOiByZXBhaXIubmFtZSxcbiAgICAgIGFwcGxpZWRcbiAgICB9KTtcbiAgICBcbiAgICAvLyBUcnkgcGFyc2luZyBhZnRlciBlYWNoIHN0ZXBcbiAgICBpZiAoYXBwbGllZCkge1xuICAgICAgcGFyc2VkID0gdHJ5UGFyc2UoY3VycmVudCk7XG4gICAgICBpZiAocGFyc2VkICE9PSBudWxsKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgaXNKc29uOiB0cnVlLFxuICAgICAgICAgIG5vcm1hbGl6ZWRKc29uOiBwYXJzZWQsXG4gICAgICAgICAgY2FuZGlkYXRlLFxuICAgICAgICAgIHJlcGFpclN0ZXBzLFxuICAgICAgICAgIHJlcGFpclN1Y2NlZWRlZDogdHJ1ZVxuICAgICAgICB9O1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBcbiAgLy8gQWxsIHJlcGFpcnMgZmFpbGVkXG4gIHJldHVybiB7XG4gICAgaXNKc29uOiBmYWxzZSxcbiAgICBjYW5kaWRhdGUsXG4gICAgcmVwYWlyU3RlcHMsXG4gICAgcmVwYWlyU3VjY2VlZGVkOiBmYWxzZVxuICB9O1xufVxuIl19