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.
189 lines • 23.2 kB
JavaScript
;
/**
* Instruction-Following Evaluation Module
*
* Evaluates whether LLM output follows specified instruction rules.
*
* @module engines/classification/instruction-eval
* @author Haiec
* @license MIT
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.evaluateInstructionRules = evaluateInstructionRules;
const utils_1 = require("./utils");
/**
* Evaluates a format rule.
*/
function evaluateFormatRule(rule, text, isJson, bullets, sentences) {
const expect = rule.params.expect;
switch (expect) {
case 'json':
return {
id: rule.id,
passed: isJson,
reason: isJson ? undefined : 'Expected JSON output but none found'
};
case 'list':
return {
id: rule.id,
passed: bullets >= 1,
reason: bullets >= 1 ? undefined : 'Expected list format but no list items found'
};
case 'paragraph':
const isParagraph = bullets === 0 && sentences >= 2;
return {
id: rule.id,
passed: isParagraph,
reason: isParagraph ? undefined : 'Expected paragraph format'
};
case 'code':
const hasCode = /```[\s\S]*```/.test(text) || /^\s{4,}|\t/m.test(text);
return {
id: rule.id,
passed: hasCode,
reason: hasCode ? undefined : 'Expected code block but none found'
};
default:
return { id: rule.id, passed: true };
}
}
/**
* Evaluates a length rule.
*/
function evaluateLengthRule(rule, words, bullets) {
const { minWords, maxWords, minBullets, maxBullets } = rule.params;
const failures = [];
if (minWords !== undefined && words < minWords) {
failures.push(`Expected at least ${minWords} words, got ${words}`);
}
if (maxWords !== undefined && words > maxWords) {
failures.push(`Expected at most ${maxWords} words, got ${words}`);
}
if (minBullets !== undefined && bullets < minBullets) {
failures.push(`Expected at least ${minBullets} list items, got ${bullets}`);
}
if (maxBullets !== undefined && bullets > maxBullets) {
failures.push(`Expected at most ${maxBullets} list items, got ${bullets}`);
}
return {
id: rule.id,
passed: failures.length === 0,
reason: failures.length > 0 ? failures[0] : undefined
};
}
/**
* Evaluates an include rule.
*/
function evaluateIncludeRule(rule, text) {
const terms = rule.params.terms || [];
const lower = text.toLowerCase();
const missing = terms.filter(t => !lower.includes(t.toLowerCase()));
return {
id: rule.id,
passed: missing.length === 0,
reason: missing.length > 0 ? `Missing required terms: ${missing.join(', ')}` : undefined
};
}
/**
* Evaluates an exclude rule.
*/
function evaluateExcludeRule(rule, text) {
const terms = rule.params.terms || [];
const lower = text.toLowerCase();
const found = terms.filter(t => lower.includes(t.toLowerCase()));
return {
id: rule.id,
passed: found.length === 0,
reason: found.length > 0 ? `Found forbidden terms: ${found.join(', ')}` : undefined
};
}
/**
* Evaluates a schema rule.
*/
function evaluateSchemaRule(rule, normalizedJson) {
if (!normalizedJson || typeof normalizedJson !== 'object' || Array.isArray(normalizedJson)) {
return {
id: rule.id,
passed: false,
reason: 'Expected JSON object for schema validation'
};
}
const requiredKeys = rule.params.requiredKeys || [];
const obj = normalizedJson;
const missing = requiredKeys.filter(k => !(k in obj));
return {
id: rule.id,
passed: missing.length === 0,
reason: missing.length > 0 ? `Missing required keys: ${missing.join(', ')}` : undefined
};
}
/**
* Evaluates a coverage rule.
*/
function evaluateCoverageRule(rule, text) {
const entities = rule.params.entities || [];
const lower = text.toLowerCase();
const missing = entities.filter(e => !lower.includes(e.toLowerCase()));
return {
id: rule.id,
passed: missing.length === 0,
reason: missing.length > 0 ? `Missing coverage of: ${missing.join(', ')}` : undefined
};
}
/**
* Evaluates all instruction rules against output.
*
* @param text - The output text
* @param normalizedJson - Parsed JSON if available
* @param rules - Instruction rules to evaluate
* @param isJson - Whether output is valid JSON
* @returns Evaluation result with compliance ratio
*/
function evaluateInstructionRules(text, normalizedJson, rules, isJson) {
if (!rules || rules.length === 0) {
return {
ruleResults: [],
complianceRatio: 1,
instructionFollowed: true
};
}
const words = (0, utils_1.tokenize)(text).length;
const bullets = (0, utils_1.countBullets)(text);
const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 0).length;
const ruleResults = [];
for (const rule of rules) {
let result;
switch (rule.type) {
case 'format':
result = evaluateFormatRule(rule, text, isJson, bullets, sentences);
break;
case 'length':
result = evaluateLengthRule(rule, words, bullets);
break;
case 'include':
result = evaluateIncludeRule(rule, text);
break;
case 'exclude':
result = evaluateExcludeRule(rule, text);
break;
case 'schema':
result = evaluateSchemaRule(rule, normalizedJson);
break;
case 'coverage':
result = evaluateCoverageRule(rule, text);
break;
default:
result = { id: rule.id, passed: true };
}
ruleResults.push(result);
}
const passedCount = ruleResults.filter(r => r.passed).length;
const complianceRatio = rules.length > 0 ? passedCount / rules.length : 1;
const instructionFollowed = complianceRatio >= 0.8;
return {
ruleResults,
complianceRatio,
instructionFollowed
};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5zdHJ1Y3Rpb24tZXZhbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9lbmdpbmVzL2NsYXNzaWZpY2F0aW9uL2luc3RydWN0aW9uLWV2YWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7OztHQVFHOztBQXNMSCw0REEwREM7QUE3T0QsbUNBQWlEO0FBV2pEOztHQUVHO0FBQ0gsU0FBUyxrQkFBa0IsQ0FDekIsSUFBcUIsRUFDckIsSUFBWSxFQUNaLE1BQWUsRUFDZixPQUFlLEVBQ2YsU0FBaUI7SUFFakIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFFbEMsUUFBUSxNQUFNLEVBQUUsQ0FBQztRQUNmLEtBQUssTUFBTTtZQUNULE9BQU87Z0JBQ0wsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFO2dCQUNYLE1BQU0sRUFBRSxNQUFNO2dCQUNkLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMscUNBQXFDO2FBQ25FLENBQUM7UUFFSixLQUFLLE1BQU07WUFDVCxPQUFPO2dCQUNMLEVBQUUsRUFBRSxJQUFJLENBQUMsRUFBRTtnQkFDWCxNQUFNLEVBQUUsT0FBTyxJQUFJLENBQUM7Z0JBQ3BCLE1BQU0sRUFBRSxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLDhDQUE4QzthQUNsRixDQUFDO1FBRUosS0FBSyxXQUFXO1lBQ2QsTUFBTSxXQUFXLEdBQUcsT0FBTyxLQUFLLENBQUMsSUFBSSxTQUFTLElBQUksQ0FBQyxDQUFDO1lBQ3BELE9BQU87Z0JBQ0wsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFO2dCQUNYLE1BQU0sRUFBRSxXQUFXO2dCQUNuQixNQUFNLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLDJCQUEyQjthQUM5RCxDQUFDO1FBRUosS0FBSyxNQUFNO1lBQ1QsTUFBTSxPQUFPLEdBQUcsZUFBZSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3ZFLE9BQU87Z0JBQ0wsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFO2dCQUNYLE1BQU0sRUFBRSxPQUFPO2dCQUNmLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsb0NBQW9DO2FBQ25FLENBQUM7UUFFSjtZQUNFLE9BQU8sRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUM7SUFDekMsQ0FBQztBQUNILENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMsa0JBQWtCLENBQ3pCLElBQXFCLEVBQ3JCLEtBQWEsRUFDYixPQUFlO0lBRWYsTUFBTSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUM7SUFDbkUsTUFBTSxRQUFRLEdBQWEsRUFBRSxDQUFDO0lBRTlCLElBQUksUUFBUSxLQUFLLFNBQVMsSUFBSSxLQUFLLEdBQUcsUUFBUSxFQUFFLENBQUM7UUFDL0MsUUFBUSxDQUFDLElBQUksQ0FBQyxxQkFBcUIsUUFBUSxlQUFlLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDckUsQ0FBQztJQUNELElBQUksUUFBUSxLQUFLLFNBQVMsSUFBSSxLQUFLLEdBQUcsUUFBUSxFQUFFLENBQUM7UUFDL0MsUUFBUSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsUUFBUSxlQUFlLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDcEUsQ0FBQztJQUNELElBQUksVUFBVSxLQUFLLFNBQVMsSUFBSSxPQUFPLEdBQUcsVUFBVSxFQUFFLENBQUM7UUFDckQsUUFBUSxDQUFDLElBQUksQ0FBQyxxQkFBcUIsVUFBVSxvQkFBb0IsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUM5RSxDQUFDO0lBQ0QsSUFBSSxVQUFVLEtBQUssU0FBUyxJQUFJLE9BQU8sR0FBRyxVQUFVLEVBQUUsQ0FBQztRQUNyRCxRQUFRLENBQUMsSUFBSSxDQUFDLG9CQUFvQixVQUFVLG9CQUFvQixPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQzdFLENBQUM7SUFFRCxPQUFPO1FBQ0wsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFO1FBQ1gsTUFBTSxFQUFFLFFBQVEsQ0FBQyxNQUFNLEtBQUssQ0FBQztRQUM3QixNQUFNLEVBQUUsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUztLQUN0RCxDQUFDO0FBQ0osQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBUyxtQkFBbUIsQ0FDMUIsSUFBcUIsRUFDckIsSUFBWTtJQUVaLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQztJQUN0QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDakMsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBRXBFLE9BQU87UUFDTCxFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUU7UUFDWCxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQzVCLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsMkJBQTJCLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUztLQUN6RixDQUFDO0FBQ0osQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBUyxtQkFBbUIsQ0FDMUIsSUFBcUIsRUFDckIsSUFBWTtJQUVaLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQztJQUN0QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDakMsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUVqRSxPQUFPO1FBQ0wsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFO1FBQ1gsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQztRQUMxQixNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLDBCQUEwQixLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVM7S0FDcEYsQ0FBQztBQUNKLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMsa0JBQWtCLENBQ3pCLElBQXFCLEVBQ3JCLGNBQXVCO0lBRXZCLElBQUksQ0FBQyxjQUFjLElBQUksT0FBTyxjQUFjLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQztRQUMzRixPQUFPO1lBQ0wsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFO1lBQ1gsTUFBTSxFQUFFLEtBQUs7WUFDYixNQUFNLEVBQUUsNENBQTRDO1NBQ3JELENBQUM7SUFDSixDQUFDO0lBRUQsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLElBQUksRUFBRSxDQUFDO0lBQ3BELE1BQU0sR0FBRyxHQUFHLGNBQXlDLENBQUM7SUFDdEQsTUFBTSxPQUFPLEdBQUcsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksR0FBRyxDQUFDLENBQUMsQ0FBQztJQUV0RCxPQUFPO1FBQ0wsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFO1FBQ1gsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQztRQUM1QixNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLDBCQUEwQixPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVM7S0FDeEYsQ0FBQztBQUNKLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMsb0JBQW9CLENBQzNCLElBQXFCLEVBQ3JCLElBQVk7SUFFWixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQUM7SUFDNUMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ2pDLE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUV2RSxPQUFPO1FBQ0wsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFO1FBQ1gsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQztRQUM1QixNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLHdCQUF3QixPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVM7S0FDdEYsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILFNBQWdCLHdCQUF3QixDQUN0QyxJQUFZLEVBQ1osY0FBbUMsRUFDbkMsS0FBd0IsRUFDeEIsTUFBZTtJQUVmLElBQUksQ0FBQyxLQUFLLElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUNqQyxPQUFPO1lBQ0wsV0FBVyxFQUFFLEVBQUU7WUFDZixlQUFlLEVBQUUsQ0FBQztZQUNsQixtQkFBbUIsRUFBRSxJQUFJO1NBQzFCLENBQUM7SUFDSixDQUFDO0lBRUQsTUFBTSxLQUFLLEdBQUcsSUFBQSxnQkFBUSxFQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUNwQyxNQUFNLE9BQU8sR0FBRyxJQUFBLG9CQUFZLEVBQUMsSUFBSSxDQUFDLENBQUM7SUFDbkMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUUvRSxNQUFNLFdBQVcsR0FBaUIsRUFBRSxDQUFDO0lBRXJDLEtBQUssTUFBTSxJQUFJLElBQUksS0FBSyxFQUFFLENBQUM7UUFDekIsSUFBSSxNQUFrQixDQUFDO1FBRXZCLFFBQVEsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2xCLEtBQUssUUFBUTtnQkFDWCxNQUFNLEdBQUcsa0JBQWtCLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLFNBQVMsQ0FBQyxDQUFDO2dCQUNwRSxNQUFNO1lBQ1IsS0FBSyxRQUFRO2dCQUNYLE1BQU0sR0FBRyxrQkFBa0IsQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLE9BQU8sQ0FBQyxDQUFDO2dCQUNsRCxNQUFNO1lBQ1IsS0FBSyxTQUFTO2dCQUNaLE1BQU0sR0FBRyxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7Z0JBQ3pDLE1BQU07WUFDUixLQUFLLFNBQVM7Z0JBQ1osTUFBTSxHQUFHLG1CQUFtQixDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztnQkFDekMsTUFBTTtZQUNSLEtBQUssUUFBUTtnQkFDWCxNQUFNLEdBQUcsa0JBQWtCLENBQUMsSUFBSSxFQUFFLGNBQWMsQ0FBQyxDQUFDO2dCQUNsRCxNQUFNO1lBQ1IsS0FBSyxVQUFVO2dCQUNiLE1BQU0sR0FBRyxvQkFBb0IsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7Z0JBQzFDLE1BQU07WUFDUjtnQkFDRSxNQUFNLEdBQUcsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUM7UUFDM0MsQ0FBQztRQUVELFdBQVcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDM0IsQ0FBQztJQUVELE1BQU0sV0FBVyxHQUFHLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQzdELE1BQU0sZUFBZSxHQUFHLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzFFLE1BQU0sbUJBQW1CLEdBQUcsZUFBZSxJQUFJLEdBQUcsQ0FBQztJQUVuRCxPQUFPO1FBQ0wsV0FBVztRQUNYLGVBQWU7UUFDZixtQkFBbUI7S0FDcEIsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEluc3RydWN0aW9uLUZvbGxvd2luZyBFdmFsdWF0aW9uIE1vZHVsZVxuICogXG4gKiBFdmFsdWF0ZXMgd2hldGhlciBMTE0gb3V0cHV0IGZvbGxvd3Mgc3BlY2lmaWVkIGluc3RydWN0aW9uIHJ1bGVzLlxuICogXG4gKiBAbW9kdWxlIGVuZ2luZXMvY2xhc3NpZmljYXRpb24vaW5zdHJ1Y3Rpb24tZXZhbFxuICogQGF1dGhvciBIYWllY1xuICogQGxpY2Vuc2UgTUlUXG4gKi9cblxuaW1wb3J0IHsgSW5zdHJ1Y3Rpb25SdWxlLCBSdWxlUmVzdWx0IH0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyB0b2tlbml6ZSwgY291bnRCdWxsZXRzIH0gZnJvbSAnLi91dGlscyc7XG5cbi8qKlxuICogUmVzdWx0IG9mIGluc3RydWN0aW9uIGV2YWx1YXRpb24uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSW5zdHJ1Y3Rpb25FdmFsUmVzdWx0IHtcbiAgcnVsZVJlc3VsdHM6IFJ1bGVSZXN1bHRbXTtcbiAgY29tcGxpYW5jZVJhdGlvOiBudW1iZXI7XG4gIGluc3RydWN0aW9uRm9sbG93ZWQ6IGJvb2xlYW47XG59XG5cbi8qKlxuICogRXZhbHVhdGVzIGEgZm9ybWF0IHJ1bGUuXG4gKi9cbmZ1bmN0aW9uIGV2YWx1YXRlRm9ybWF0UnVsZShcbiAgcnVsZTogSW5zdHJ1Y3Rpb25SdWxlLFxuICB0ZXh0OiBzdHJpbmcsXG4gIGlzSnNvbjogYm9vbGVhbixcbiAgYnVsbGV0czogbnVtYmVyLFxuICBzZW50ZW5jZXM6IG51bWJlclxuKTogUnVsZVJlc3VsdCB7XG4gIGNvbnN0IGV4cGVjdCA9IHJ1bGUucGFyYW1zLmV4cGVjdDtcbiAgXG4gIHN3aXRjaCAoZXhwZWN0KSB7XG4gICAgY2FzZSAnanNvbic6XG4gICAgICByZXR1cm4ge1xuICAgICAgICBpZDogcnVsZS5pZCxcbiAgICAgICAgcGFzc2VkOiBpc0pzb24sXG4gICAgICAgIHJlYXNvbjogaXNKc29uID8gdW5kZWZpbmVkIDogJ0V4cGVjdGVkIEpTT04gb3V0cHV0IGJ1dCBub25lIGZvdW5kJ1xuICAgICAgfTtcbiAgICBcbiAgICBjYXNlICdsaXN0JzpcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGlkOiBydWxlLmlkLFxuICAgICAgICBwYXNzZWQ6IGJ1bGxldHMgPj0gMSxcbiAgICAgICAgcmVhc29uOiBidWxsZXRzID49IDEgPyB1bmRlZmluZWQgOiAnRXhwZWN0ZWQgbGlzdCBmb3JtYXQgYnV0IG5vIGxpc3QgaXRlbXMgZm91bmQnXG4gICAgICB9O1xuICAgIFxuICAgIGNhc2UgJ3BhcmFncmFwaCc6XG4gICAgICBjb25zdCBpc1BhcmFncmFwaCA9IGJ1bGxldHMgPT09IDAgJiYgc2VudGVuY2VzID49IDI7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBpZDogcnVsZS5pZCxcbiAgICAgICAgcGFzc2VkOiBpc1BhcmFncmFwaCxcbiAgICAgICAgcmVhc29uOiBpc1BhcmFncmFwaCA/IHVuZGVmaW5lZCA6ICdFeHBlY3RlZCBwYXJhZ3JhcGggZm9ybWF0J1xuICAgICAgfTtcbiAgICBcbiAgICBjYXNlICdjb2RlJzpcbiAgICAgIGNvbnN0IGhhc0NvZGUgPSAvYGBgW1xcc1xcU10qYGBgLy50ZXN0KHRleHQpIHx8IC9eXFxzezQsfXxcXHQvbS50ZXN0KHRleHQpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgaWQ6IHJ1bGUuaWQsXG4gICAgICAgIHBhc3NlZDogaGFzQ29kZSxcbiAgICAgICAgcmVhc29uOiBoYXNDb2RlID8gdW5kZWZpbmVkIDogJ0V4cGVjdGVkIGNvZGUgYmxvY2sgYnV0IG5vbmUgZm91bmQnXG4gICAgICB9O1xuICAgIFxuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4geyBpZDogcnVsZS5pZCwgcGFzc2VkOiB0cnVlIH07XG4gIH1cbn1cblxuLyoqXG4gKiBFdmFsdWF0ZXMgYSBsZW5ndGggcnVsZS5cbiAqL1xuZnVuY3Rpb24gZXZhbHVhdGVMZW5ndGhSdWxlKFxuICBydWxlOiBJbnN0cnVjdGlvblJ1bGUsXG4gIHdvcmRzOiBudW1iZXIsXG4gIGJ1bGxldHM6IG51bWJlclxuKTogUnVsZVJlc3VsdCB7XG4gIGNvbnN0IHsgbWluV29yZHMsIG1heFdvcmRzLCBtaW5CdWxsZXRzLCBtYXhCdWxsZXRzIH0gPSBydWxlLnBhcmFtcztcbiAgY29uc3QgZmFpbHVyZXM6IHN0cmluZ1tdID0gW107XG4gIFxuICBpZiAobWluV29yZHMgIT09IHVuZGVmaW5lZCAmJiB3b3JkcyA8IG1pbldvcmRzKSB7XG4gICAgZmFpbHVyZXMucHVzaChgRXhwZWN0ZWQgYXQgbGVhc3QgJHttaW5Xb3Jkc30gd29yZHMsIGdvdCAke3dvcmRzfWApO1xuICB9XG4gIGlmIChtYXhXb3JkcyAhPT0gdW5kZWZpbmVkICYmIHdvcmRzID4gbWF4V29yZHMpIHtcbiAgICBmYWlsdXJlcy5wdXNoKGBFeHBlY3RlZCBhdCBtb3N0ICR7bWF4V29yZHN9IHdvcmRzLCBnb3QgJHt3b3Jkc31gKTtcbiAgfVxuICBpZiAobWluQnVsbGV0cyAhPT0gdW5kZWZpbmVkICYmIGJ1bGxldHMgPCBtaW5CdWxsZXRzKSB7XG4gICAgZmFpbHVyZXMucHVzaChgRXhwZWN0ZWQgYXQgbGVhc3QgJHttaW5CdWxsZXRzfSBsaXN0IGl0ZW1zLCBnb3QgJHtidWxsZXRzfWApO1xuICB9XG4gIGlmIChtYXhCdWxsZXRzICE9PSB1bmRlZmluZWQgJiYgYnVsbGV0cyA+IG1heEJ1bGxldHMpIHtcbiAgICBmYWlsdXJlcy5wdXNoKGBFeHBlY3RlZCBhdCBtb3N0ICR7bWF4QnVsbGV0c30gbGlzdCBpdGVtcywgZ290ICR7YnVsbGV0c31gKTtcbiAgfVxuICBcbiAgcmV0dXJuIHtcbiAgICBpZDogcnVsZS5pZCxcbiAgICBwYXNzZWQ6IGZhaWx1cmVzLmxlbmd0aCA9PT0gMCxcbiAgICByZWFzb246IGZhaWx1cmVzLmxlbmd0aCA+IDAgPyBmYWlsdXJlc1swXSA6IHVuZGVmaW5lZFxuICB9O1xufVxuXG4vKipcbiAqIEV2YWx1YXRlcyBhbiBpbmNsdWRlIHJ1bGUuXG4gKi9cbmZ1bmN0aW9uIGV2YWx1YXRlSW5jbHVkZVJ1bGUoXG4gIHJ1bGU6IEluc3RydWN0aW9uUnVsZSxcbiAgdGV4dDogc3RyaW5nXG4pOiBSdWxlUmVzdWx0IHtcbiAgY29uc3QgdGVybXMgPSBydWxlLnBhcmFtcy50ZXJtcyB8fCBbXTtcbiAgY29uc3QgbG93ZXIgPSB0ZXh0LnRvTG93ZXJDYXNlKCk7XG4gIGNvbnN0IG1pc3NpbmcgPSB0ZXJtcy5maWx0ZXIodCA9PiAhbG93ZXIuaW5jbHVkZXModC50b0xvd2VyQ2FzZSgpKSk7XG4gIFxuICByZXR1cm4ge1xuICAgIGlkOiBydWxlLmlkLFxuICAgIHBhc3NlZDogbWlzc2luZy5sZW5ndGggPT09IDAsXG4gICAgcmVhc29uOiBtaXNzaW5nLmxlbmd0aCA+IDAgPyBgTWlzc2luZyByZXF1aXJlZCB0ZXJtczogJHttaXNzaW5nLmpvaW4oJywgJyl9YCA6IHVuZGVmaW5lZFxuICB9O1xufVxuXG4vKipcbiAqIEV2YWx1YXRlcyBhbiBleGNsdWRlIHJ1bGUuXG4gKi9cbmZ1bmN0aW9uIGV2YWx1YXRlRXhjbHVkZVJ1bGUoXG4gIHJ1bGU6IEluc3RydWN0aW9uUnVsZSxcbiAgdGV4dDogc3RyaW5nXG4pOiBSdWxlUmVzdWx0IHtcbiAgY29uc3QgdGVybXMgPSBydWxlLnBhcmFtcy50ZXJtcyB8fCBbXTtcbiAgY29uc3QgbG93ZXIgPSB0ZXh0LnRvTG93ZXJDYXNlKCk7XG4gIGNvbnN0IGZvdW5kID0gdGVybXMuZmlsdGVyKHQgPT4gbG93ZXIuaW5jbHVkZXModC50b0xvd2VyQ2FzZSgpKSk7XG4gIFxuICByZXR1cm4ge1xuICAgIGlkOiBydWxlLmlkLFxuICAgIHBhc3NlZDogZm91bmQubGVuZ3RoID09PSAwLFxuICAgIHJlYXNvbjogZm91bmQubGVuZ3RoID4gMCA/IGBGb3VuZCBmb3JiaWRkZW4gdGVybXM6ICR7Zm91bmQuam9pbignLCAnKX1gIDogdW5kZWZpbmVkXG4gIH07XG59XG5cbi8qKlxuICogRXZhbHVhdGVzIGEgc2NoZW1hIHJ1bGUuXG4gKi9cbmZ1bmN0aW9uIGV2YWx1YXRlU2NoZW1hUnVsZShcbiAgcnVsZTogSW5zdHJ1Y3Rpb25SdWxlLFxuICBub3JtYWxpemVkSnNvbjogdW5rbm93blxuKTogUnVsZVJlc3VsdCB7XG4gIGlmICghbm9ybWFsaXplZEpzb24gfHwgdHlwZW9mIG5vcm1hbGl6ZWRKc29uICE9PSAnb2JqZWN0JyB8fCBBcnJheS5pc0FycmF5KG5vcm1hbGl6ZWRKc29uKSkge1xuICAgIHJldHVybiB7XG4gICAgICBpZDogcnVsZS5pZCxcbiAgICAgIHBhc3NlZDogZmFsc2UsXG4gICAgICByZWFzb246ICdFeHBlY3RlZCBKU09OIG9iamVjdCBmb3Igc2NoZW1hIHZhbGlkYXRpb24nXG4gICAgfTtcbiAgfVxuICBcbiAgY29uc3QgcmVxdWlyZWRLZXlzID0gcnVsZS5wYXJhbXMucmVxdWlyZWRLZXlzIHx8IFtdO1xuICBjb25zdCBvYmogPSBub3JtYWxpemVkSnNvbiBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgY29uc3QgbWlzc2luZyA9IHJlcXVpcmVkS2V5cy5maWx0ZXIoayA9PiAhKGsgaW4gb2JqKSk7XG4gIFxuICByZXR1cm4ge1xuICAgIGlkOiBydWxlLmlkLFxuICAgIHBhc3NlZDogbWlzc2luZy5sZW5ndGggPT09IDAsXG4gICAgcmVhc29uOiBtaXNzaW5nLmxlbmd0aCA+IDAgPyBgTWlzc2luZyByZXF1aXJlZCBrZXlzOiAke21pc3Npbmcuam9pbignLCAnKX1gIDogdW5kZWZpbmVkXG4gIH07XG59XG5cbi8qKlxuICogRXZhbHVhdGVzIGEgY292ZXJhZ2UgcnVsZS5cbiAqL1xuZnVuY3Rpb24gZXZhbHVhdGVDb3ZlcmFnZVJ1bGUoXG4gIHJ1bGU6IEluc3RydWN0aW9uUnVsZSxcbiAgdGV4dDogc3RyaW5nXG4pOiBSdWxlUmVzdWx0IHtcbiAgY29uc3QgZW50aXRpZXMgPSBydWxlLnBhcmFtcy5lbnRpdGllcyB8fCBbXTtcbiAgY29uc3QgbG93ZXIgPSB0ZXh0LnRvTG93ZXJDYXNlKCk7XG4gIGNvbnN0IG1pc3NpbmcgPSBlbnRpdGllcy5maWx0ZXIoZSA9PiAhbG93ZXIuaW5jbHVkZXMoZS50b0xvd2VyQ2FzZSgpKSk7XG4gIFxuICByZXR1cm4ge1xuICAgIGlkOiBydWxlLmlkLFxuICAgIHBhc3NlZDogbWlzc2luZy5sZW5ndGggPT09IDAsXG4gICAgcmVhc29uOiBtaXNzaW5nLmxlbmd0aCA+IDAgPyBgTWlzc2luZyBjb3ZlcmFnZSBvZjogJHttaXNzaW5nLmpvaW4oJywgJyl9YCA6IHVuZGVmaW5lZFxuICB9O1xufVxuXG4vKipcbiAqIEV2YWx1YXRlcyBhbGwgaW5zdHJ1Y3Rpb24gcnVsZXMgYWdhaW5zdCBvdXRwdXQuXG4gKiBcbiAqIEBwYXJhbSB0ZXh0IC0gVGhlIG91dHB1dCB0ZXh0XG4gKiBAcGFyYW0gbm9ybWFsaXplZEpzb24gLSBQYXJzZWQgSlNPTiBpZiBhdmFpbGFibGVcbiAqIEBwYXJhbSBydWxlcyAtIEluc3RydWN0aW9uIHJ1bGVzIHRvIGV2YWx1YXRlXG4gKiBAcGFyYW0gaXNKc29uIC0gV2hldGhlciBvdXRwdXQgaXMgdmFsaWQgSlNPTlxuICogQHJldHVybnMgRXZhbHVhdGlvbiByZXN1bHQgd2l0aCBjb21wbGlhbmNlIHJhdGlvXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBldmFsdWF0ZUluc3RydWN0aW9uUnVsZXMoXG4gIHRleHQ6IHN0cmluZyxcbiAgbm9ybWFsaXplZEpzb246IHVua25vd24gfCB1bmRlZmluZWQsXG4gIHJ1bGVzOiBJbnN0cnVjdGlvblJ1bGVbXSxcbiAgaXNKc29uOiBib29sZWFuXG4pOiBJbnN0cnVjdGlvbkV2YWxSZXN1bHQge1xuICBpZiAoIXJ1bGVzIHx8IHJ1bGVzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiB7XG4gICAgICBydWxlUmVzdWx0czogW10sXG4gICAgICBjb21wbGlhbmNlUmF0aW86IDEsXG4gICAgICBpbnN0cnVjdGlvbkZvbGxvd2VkOiB0cnVlXG4gICAgfTtcbiAgfVxuICBcbiAgY29uc3Qgd29yZHMgPSB0b2tlbml6ZSh0ZXh0KS5sZW5ndGg7XG4gIGNvbnN0IGJ1bGxldHMgPSBjb3VudEJ1bGxldHModGV4dCk7XG4gIGNvbnN0IHNlbnRlbmNlcyA9IHRleHQuc3BsaXQoL1suIT9dKy8pLmZpbHRlcihzID0+IHMudHJpbSgpLmxlbmd0aCA+IDApLmxlbmd0aDtcbiAgXG4gIGNvbnN0IHJ1bGVSZXN1bHRzOiBSdWxlUmVzdWx0W10gPSBbXTtcbiAgXG4gIGZvciAoY29uc3QgcnVsZSBvZiBydWxlcykge1xuICAgIGxldCByZXN1bHQ6IFJ1bGVSZXN1bHQ7XG4gICAgXG4gICAgc3dpdGNoIChydWxlLnR5cGUpIHtcbiAgICAgIGNhc2UgJ2Zvcm1hdCc6XG4gICAgICAgIHJlc3VsdCA9IGV2YWx1YXRlRm9ybWF0UnVsZShydWxlLCB0ZXh0LCBpc0pzb24sIGJ1bGxldHMsIHNlbnRlbmNlcyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnbGVuZ3RoJzpcbiAgICAgICAgcmVzdWx0ID0gZXZhbHVhdGVMZW5ndGhSdWxlKHJ1bGUsIHdvcmRzLCBidWxsZXRzKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdpbmNsdWRlJzpcbiAgICAgICAgcmVzdWx0ID0gZXZhbHVhdGVJbmNsdWRlUnVsZShydWxlLCB0ZXh0KTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdleGNsdWRlJzpcbiAgICAgICAgcmVzdWx0ID0gZXZhbHVhdGVFeGNsdWRlUnVsZShydWxlLCB0ZXh0KTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdzY2hlbWEnOlxuICAgICAgICByZXN1bHQgPSBldmFsdWF0ZVNjaGVtYVJ1bGUocnVsZSwgbm9ybWFsaXplZEpzb24pO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2NvdmVyYWdlJzpcbiAgICAgICAgcmVzdWx0ID0gZXZhbHVhdGVDb3ZlcmFnZVJ1bGUocnVsZSwgdGV4dCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmVzdWx0ID0geyBpZDogcnVsZS5pZCwgcGFzc2VkOiB0cnVlIH07XG4gICAgfVxuICAgIFxuICAgIHJ1bGVSZXN1bHRzLnB1c2gocmVzdWx0KTtcbiAgfVxuICBcbiAgY29uc3QgcGFzc2VkQ291bnQgPSBydWxlUmVzdWx0cy5maWx0ZXIociA9PiByLnBhc3NlZCkubGVuZ3RoO1xuICBjb25zdCBjb21wbGlhbmNlUmF0aW8gPSBydWxlcy5sZW5ndGggPiAwID8gcGFzc2VkQ291bnQgLyBydWxlcy5sZW5ndGggOiAxO1xuICBjb25zdCBpbnN0cnVjdGlvbkZvbGxvd2VkID0gY29tcGxpYW5jZVJhdGlvID49IDAuODtcbiAgXG4gIHJldHVybiB7XG4gICAgcnVsZVJlc3VsdHMsXG4gICAgY29tcGxpYW5jZVJhdGlvLFxuICAgIGluc3RydWN0aW9uRm9sbG93ZWRcbiAgfTtcbn1cbiJdfQ==