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.
359 lines • 43.7 kB
JavaScript
"use strict";
/**
* Prompt Injection Detection & Deterrence
*
* Comprehensive detection based on OWASP LLM-01.
* Includes detection, sanitization, and deterrence utilities.
*
* @module csm6/security/prompt-injection
* @author Haiec
* @license MIT
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkPromptInjection = checkPromptInjection;
exports.sanitizePromptInjection = sanitizePromptInjection;
exports.getInjectionRiskScore = getInjectionRiskScore;
exports.isInputSafe = isInputSafe;
const text_1 = require("../../utils/text");
const LIMITATIONS = [
'Pattern-based detection (novel attacks may evade)',
'English language only',
'Context-dependent false positives possible',
'Obfuscated attacks may not be detected',
'Base64/encoding attacks have limited detection',
'Educational content about attacks may be flagged'
];
const METHODOLOGY = 'OWASP LLM-01 aligned pattern matching. ' +
'Detects known prompt injection techniques using regex patterns ' +
'validated against public attack datasets (HackAPrompt, Gandalf, etc). ' +
'Accuracy: ~70-85% on known attacks, lower on novel variations.';
/**
* Comprehensive prompt injection patterns
* Categories based on OWASP LLM Top 10 and real-world attack datasets
*/
const PATTERNS = {
// OWASP LLM01: System Override Attempts
systemOverride: {
patterns: [
/\b(ignore|bypass|forget|disregard)\s+(all\s+)?(your\s+)?(previous|prior|above|earlier)\s+(instructions?|rules?|prompts?|directives?)/gi,
/\byou\s+are\s+now\s+(the\s+)?(system|admin|developer|root|god\s*mode)\b/gi,
/\bas\s+(system|admin|developer|root),?\s+you\s+(must|should|will|shall)\b/gi,
/\b(new|updated?|revised)\s+(instructions?|rules?|system\s+prompt|directives?)\s*:?\s*\n/gi,
/\b(start|begin)\s+(with|by)\s+(ignoring|forgetting|disregarding)\b/gi,
/\bfrom\s+now\s+on,?\s+(you\s+)?(will|must|should|are)/gi,
/\breset\s+(your|all)\s+(instructions?|rules?|context)/gi
],
severity: 'high',
confidence: 0.8,
description: 'Attempts to override system instructions'
},
// Policy/Safety Bypass
policyBypass: {
patterns: [
/\b(ignore|bypass|override|disable|turn\s+off)\s+(all\s+)?(safety|content|policy|policies|filters?|guidelines?|restrictions?)/gi,
/\b(pretend|act\s+as\s+if|simulate|imagine)\s+you\s+(have\s+no|don'?t\s+have|lack|are\s+without)\s+(restrictions?|limitations?|rules?|policies)\b/gi,
/\bi\s+give\s+you\s+permission\s+to\s+(ignore|bypass|break)\b/gi,
/\b(enable|activate|enter)\s+(developer|debug|god|admin)\s+mode/gi,
/\bunlock\s+(your\s+)?(full|hidden|secret)\s+(potential|capabilities|features)/gi,
/\bno\s+(ethical|moral|safety)\s+(guidelines?|restrictions?|limitations?)/gi
],
severity: 'high',
confidence: 0.75,
description: 'Attempts to bypass safety policies'
},
// Context/System Prompt Exfiltration
contextExfiltration: {
patterns: [
/\b(print|show|display|reveal|output|dump|list)\s+(your\s+)?(system\s+prompt|original\s+instructions?|initial\s+prompt|hidden\s+(config|instructions?))\b/gi,
/\bwhat\s+(is|are|were|was)\s+your\s+(original|initial|first|secret)\s+(instructions?|prompt|rules?|directives?)\b/gi,
/\b(repeat|show|print)\s+(everything|all)\s+(above|before|prior|previous)\b/gi,
/\b(show|display|list)\s+(all\s+)?(previous|prior|earlier)\s+messages?\b/gi,
/\brepeat\s+(the\s+)?(text|words|content)\s+(above|before)/gi,
/\bwhat\s+did\s+(the\s+)?(user|developer|admin)\s+tell\s+you/gi,
/\b(output|print|echo)\s+(your\s+)?(config|configuration|settings|parameters)/gi
],
severity: 'medium',
confidence: 0.7,
description: 'Attempts to extract system prompt or context'
},
// Jailbreak Attempts (DAN, etc.)
jailbreak: {
patterns: [
/\b(DAN|do\s+anything\s+now)\b/gi,
/\bjailbreak(ed|ing)?\b/gi,
/\b(STAN|DUDE|AIM|KEVIN)\s+(mode|persona)/gi,
/\bact\s+as\s+(an?\s+)?(unrestricted|unfiltered|uncensored)\b/gi,
/\bpretend\s+(to\s+be|you\s+are)\s+(an?\s+)?(evil|malicious|unethical)/gi,
/\byou\s+are\s+(now\s+)?(free|liberated)\s+from\s+(all\s+)?(restrictions?|rules?)/gi,
/\bopposite\s+(mode|day|personality)/gi,
/\balter\s+ego/gi
],
severity: 'high',
confidence: 0.85,
description: 'Known jailbreak techniques (DAN, etc.)'
},
// Roleplay Manipulation
roleplayManipulation: {
patterns: [
/\bpretend\s+(you\s+are|to\s+be)\s+(an?\s+)?(hacker|criminal|villain|terrorist)/gi,
/\broleplay\s+as\s+(an?\s+)?(malicious|evil|unethical)/gi,
/\bact\s+as\s+if\s+you\s+(have\s+no|don'?t\s+have)\s+(morals?|ethics?)/gi,
/\bimagine\s+you\s+(are|were)\s+(programmed|designed)\s+to\s+(harm|hurt|attack)/gi,
/\bfor\s+(a\s+)?(fictional|hypothetical)\s+(story|scenario),?\s+(ignore|bypass)/gi
],
severity: 'medium',
confidence: 0.7,
description: 'Roleplay-based manipulation attempts'
},
// Tool/Function Abuse
toolAbuse: {
patterns: [
/\b(execute|run|call|invoke)\s+.*\b(delete|drop|truncate|remove|destroy|rm\s+-rf)\b/gi,
/\b(send|email|post|upload|transmit)\s+.*\b(password|credentials?|secret|token|key|private)\b/gi,
/\b(read|write|access)\s+.*\b(\/etc\/|\/root\/|\.ssh|\.aws|\.env)\b/gi,
/\b(curl|wget|fetch)\s+http/gi,
/\b(eval|exec|system|shell_exec|subprocess)\s*\(/gi,
/\bsudo\s+/gi,
/\bchmod\s+777/gi
],
severity: 'critical',
confidence: 0.85,
description: 'Attempts to abuse tools or execute dangerous commands'
},
// Encoding/Obfuscation Attacks
encodingAttack: {
patterns: [
/\bdecode\s+(this|the\s+following)\s+(base64|hex|rot13)/gi,
/\b(base64|hex|rot13)\s*:\s*[A-Za-z0-9+/=]{20,}/gi,
/\\x[0-9a-fA-F]{2}/g,
/\\u[0-9a-fA-F]{4}/g,
/&#x?[0-9a-fA-F]+;/g,
/\beval\s*\(\s*atob\s*\(/gi
],
severity: 'medium',
confidence: 0.6,
description: 'Encoded or obfuscated attack payloads'
},
// Indirect Injection (via data)
indirectInjection: {
patterns: [
/\[SYSTEM\]|\[INST\]|\[\/INST\]|<\|system\|>|<\|user\|>/gi,
/###\s*(system|instruction|human|assistant)\s*:/gi,
/<\/?s>|<\/?human>|<\/?assistant>/gi,
/\bHuman:\s*|\bAssistant:\s*|\bSystem:\s*/gi
],
severity: 'high',
confidence: 0.75,
description: 'Indirect injection via data/markup'
},
// Prompt Leaking via Completion
completionLeak: {
patterns: [
/\bcomplete\s+the\s+(following|sentence|text)\s*:\s*["']?(system|instruction)/gi,
/\bfinish\s+this\s+(sentence|prompt)\s*:\s*["']?you\s+are/gi,
/\bwhat\s+comes\s+(after|next)\s*:\s*["']?(ignore|bypass|system)/gi
],
severity: 'medium',
confidence: 0.65,
description: 'Attempts to leak prompts via completion'
}
};
/**
* Check for prompt injection attempts
* @param input - The input text to check
* @returns Array of findings
*/
function checkPromptInjection(input) {
const findings = [];
for (const [category, config] of Object.entries(PATTERNS)) {
for (const pattern of config.patterns) {
// Reset lastIndex for global patterns
pattern.lastIndex = 0;
const matches = Array.from(input.matchAll(pattern));
if (matches.length > 0) {
const match = matches[0];
// Check for false positives
if (!isLikelyFalsePositive(input, match[0])) {
findings.push(createFinding(category, config.severity, match, config.confidence, input, config.description));
// Only report one finding per category
break;
}
}
}
}
return findings;
}
/**
* Sanitize input by removing or neutralizing injection attempts
* @param input - The input to sanitize
* @returns Sanitized input and list of removed patterns
*/
function sanitizePromptInjection(input) {
let sanitized = input;
const removed = [];
for (const [category, config] of Object.entries(PATTERNS)) {
for (const pattern of config.patterns) {
pattern.lastIndex = 0;
const matches = Array.from(sanitized.matchAll(pattern));
for (const match of matches) {
if (!isLikelyFalsePositive(input, match[0])) {
removed.push(`[${category}]: ${match[0]}`);
sanitized = sanitized.replace(match[0], '[REMOVED]');
}
}
}
}
return {
sanitized,
removed,
wasModified: removed.length > 0
};
}
/**
* Get risk score for input (0-1)
* @param input - The input to score
* @returns Risk score between 0 and 1
*/
function getInjectionRiskScore(input) {
const findings = checkPromptInjection(input);
if (findings.length === 0)
return 0;
const severityWeights = {
medium: 0.4,
high: 0.7,
critical: 1.0
};
let maxScore = 0;
for (const finding of findings) {
const score = severityWeights[finding.severity] * finding.confidence.value;
maxScore = Math.max(maxScore, score);
}
return maxScore;
}
/**
* Quick check if input is likely safe (no injection detected)
* @param input - The input to check
* @returns true if no injection detected
*/
function isInputSafe(input) {
return checkPromptInjection(input).length === 0;
}
/**
* Create a finding object
*/
function createFinding(category, severity, match, confidence, fullInput, description) {
const messages = {
systemOverride: 'System override attempt detected',
policyBypass: 'Policy bypass attempt detected',
contextExfiltration: 'System prompt exfiltration attempt detected',
jailbreak: 'Jailbreak attempt detected (DAN/similar)',
roleplayManipulation: 'Roleplay manipulation attempt detected',
toolAbuse: 'Tool abuse attempt detected',
encodingAttack: 'Encoded/obfuscated attack detected',
indirectInjection: 'Indirect injection markers detected',
completionLeak: 'Prompt leak via completion detected'
};
const recommendations = {
systemOverride: 'Reject or sanitize request. Use sanitizePromptInjection() to clean input.',
policyBypass: 'Block request - attempting to bypass safety policies.',
contextExfiltration: 'Sanitize request to prevent system prompt leakage.',
jailbreak: 'Block immediately - known jailbreak technique.',
roleplayManipulation: 'Review carefully - roleplay may be used to bypass safety.',
toolAbuse: 'Block immediately - attempting dangerous operations.',
encodingAttack: 'Decode and re-scan before processing.',
indirectInjection: 'Sanitize data inputs - may contain injected instructions.',
completionLeak: 'Block - attempting to extract prompts via completion.'
};
const contextClarity = analyzeContext(fullInput, match[0]);
return {
id: `PROMPT_INJECTION_${category.toUpperCase()}`,
category: 'security',
severity,
surface: 'input',
message: messages[category] || 'Prompt injection attempt detected',
recommendation: recommendations[category] || 'Review and sanitize input.',
evidence: {
textSample: (0, text_1.truncate)(match[0], 100),
pattern: category,
context: (0, text_1.extractContext)(fullInput, match.index || 0, 50)
},
confidence: calculateConfidence(confidence, contextClarity),
limitations: LIMITATIONS,
methodology: METHODOLOGY,
metadata: {
attackType: category,
description
}
};
}
/**
* Calculate confidence score
*/
function calculateConfidence(baseConfidence, contextClarity) {
const value = baseConfidence * contextClarity;
return {
value,
interval: [Math.max(0, value - 0.15), Math.min(1, value + 0.15)],
method: 'empirical',
factors: {
patternStrength: baseConfidence,
contextClarity
}
};
}
/**
* Check if this is likely a false positive
*/
function isLikelyFalsePositive(fullText, matchedText) {
// Educational context
const educationalMarkers = [
/this\s+is\s+an\s+example\s+of/i,
/for\s+educational\s+purposes/i,
/demonstrate\s+how/i,
/showing\s+you\s+what\s+not\s+to/i,
/never\s+do\s+this/i,
/avoid\s+doing/i,
/here'?s?\s+how\s+attacks?\s+work/i,
/security\s+training/i,
/awareness\s+training/i
];
if (educationalMarkers.some(p => p.test(fullText))) {
return true;
}
// Question about security
const securityQuestions = [
/how\s+(do|can)\s+(?:i|we|you)\s+prevent/i,
/what\s+(?:is|are)\s+the\s+risks?\s+of/i,
/how\s+to\s+protect\s+against/i,
/how\s+to\s+detect/i,
/what\s+is\s+prompt\s+injection/i
];
if (securityQuestions.some(p => p.test(fullText))) {
return true;
}
// Quoted content
if ((0, text_1.isLikelyQuoted)(fullText, matchedText)) {
return true;
}
return false;
}
/**
* Analyze context to refine confidence
*/
function analyzeContext(fullText, match) {
const matchIndex = fullText.indexOf(match);
if (matchIndex === -1)
return 0.9;
const before = fullText.substring(Math.max(0, matchIndex - 30), matchIndex);
const after = fullText.substring(matchIndex + match.length, matchIndex + match.length + 30);
// Lower confidence if surrounded by quotes or code markers
if (/["'`]/.test(before) || /["'`]/.test(after)) {
return 0.6;
}
// Lower confidence if in code block
if (/```/.test(before) || /```/.test(after)) {
return 0.5;
}
return 0.9;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvbXB0LWluamVjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jc202L3NlY3VyaXR5L3Byb21wdC1pbmplY3Rpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7R0FTRzs7QUE0S0gsb0RBK0JDO0FBT0QsMERBMkJDO0FBT0Qsc0RBaUJDO0FBT0Qsa0NBRUM7QUEzUUQsMkNBQTRFO0FBRTVFLE1BQU0sV0FBVyxHQUFHO0lBQ2xCLG1EQUFtRDtJQUNuRCx1QkFBdUI7SUFDdkIsNENBQTRDO0lBQzVDLHdDQUF3QztJQUN4QyxnREFBZ0Q7SUFDaEQsa0RBQWtEO0NBQ25ELENBQUM7QUFFRixNQUFNLFdBQVcsR0FDZix5Q0FBeUM7SUFDekMsaUVBQWlFO0lBQ2pFLHdFQUF3RTtJQUN4RSxnRUFBZ0UsQ0FBQztBQVNuRTs7O0dBR0c7QUFDSCxNQUFNLFFBQVEsR0FBa0M7SUFDOUMsd0NBQXdDO0lBQ3hDLGNBQWMsRUFBRTtRQUNkLFFBQVEsRUFBRTtZQUNSLHdJQUF3STtZQUN4SSwyRUFBMkU7WUFDM0UsNkVBQTZFO1lBQzdFLDJGQUEyRjtZQUMzRixzRUFBc0U7WUFDdEUseURBQXlEO1lBQ3pELHlEQUF5RDtTQUMxRDtRQUNELFFBQVEsRUFBRSxNQUFNO1FBQ2hCLFVBQVUsRUFBRSxHQUFHO1FBQ2YsV0FBVyxFQUFFLDBDQUEwQztLQUN4RDtJQUVELHVCQUF1QjtJQUN2QixZQUFZLEVBQUU7UUFDWixRQUFRLEVBQUU7WUFDUixnSUFBZ0k7WUFDaEksb0pBQW9KO1lBQ3BKLGdFQUFnRTtZQUNoRSxrRUFBa0U7WUFDbEUsaUZBQWlGO1lBQ2pGLDRFQUE0RTtTQUM3RTtRQUNELFFBQVEsRUFBRSxNQUFNO1FBQ2hCLFVBQVUsRUFBRSxJQUFJO1FBQ2hCLFdBQVcsRUFBRSxvQ0FBb0M7S0FDbEQ7SUFFRCxxQ0FBcUM7SUFDckMsbUJBQW1CLEVBQUU7UUFDbkIsUUFBUSxFQUFFO1lBQ1IsNEpBQTRK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LE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztJQUVELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUHJvbXB0IEluamVjdGlvbiBEZXRlY3Rpb24gJiBEZXRlcnJlbmNlXG4gKiBcbiAqIENvbXByZWhlbnNpdmUgZGV0ZWN0aW9uIGJhc2VkIG9uIE9XQVNQIExMTS0wMS5cbiAqIEluY2x1ZGVzIGRldGVjdGlvbiwgc2FuaXRpemF0aW9uLCBhbmQgZGV0ZXJyZW5jZSB1dGlsaXRpZXMuXG4gKiBcbiAqIEBtb2R1bGUgY3NtNi9zZWN1cml0eS9wcm9tcHQtaW5qZWN0aW9uXG4gKiBAYXV0aG9yIEhhaWVjXG4gKiBAbGljZW5zZSBNSVRcbiAqL1xuXG5pbXBvcnQgeyBGaW5kaW5nLCBDb25maWRlbmNlU2NvcmUgfSBmcm9tICcuLi8uLi90eXBlcy9yZXN1bHRzJztcbmltcG9ydCB7IHRydW5jYXRlLCBleHRyYWN0Q29udGV4dCwgaXNMaWtlbHlRdW90ZWQgfSBmcm9tICcuLi8uLi91dGlscy90ZXh0JztcblxuY29uc3QgTElNSVRBVElPTlMgPSBbXG4gICdQYXR0ZXJuLWJhc2VkIGRldGVjdGlvbiAobm92ZWwgYXR0YWNrcyBtYXkgZXZhZGUpJyxcbiAgJ0VuZ2xpc2ggbGFuZ3VhZ2Ugb25seScsXG4gICdDb250ZXh0LWRlcGVuZGVudCBmYWxzZSBwb3NpdGl2ZXMgcG9zc2libGUnLFxuICAnT2JmdXNjYXRlZCBhdHRhY2tzIG1heSBub3QgYmUgZGV0ZWN0ZWQnLFxuICAnQmFzZTY0L2VuY29kaW5nIGF0dGFja3MgaGF2ZSBsaW1pdGVkIGRldGVjdGlvbicsXG4gICdFZHVjYXRpb25hbCBjb250ZW50IGFib3V0IGF0dGFja3MgbWF5IGJlIGZsYWdnZWQnXG5dO1xuXG5jb25zdCBNRVRIT0RPTE9HWSA9XG4gICdPV0FTUCBMTE0tMDEgYWxpZ25lZCBwYXR0ZXJuIG1hdGNoaW5nLiAnICtcbiAgJ0RldGVjdHMga25vd24gcHJvbXB0IGluamVjdGlvbiB0ZWNobmlxdWVzIHVzaW5nIHJlZ2V4IHBhdHRlcm5zICcgK1xuICAndmFsaWRhdGVkIGFnYWluc3QgcHVibGljIGF0dGFjayBkYXRhc2V0cyAoSGFja0FQcm9tcHQsIEdhbmRhbGYsIGV0YykuICcgK1xuICAnQWNjdXJhY3k6IH43MC04NSUgb24ga25vd24gYXR0YWNrcywgbG93ZXIgb24gbm92ZWwgdmFyaWF0aW9ucy4nO1xuXG5pbnRlcmZhY2UgUGF0dGVybkNvbmZpZyB7XG4gIHBhdHRlcm5zOiBSZWdFeHBbXTtcbiAgc2V2ZXJpdHk6ICdtZWRpdW0nIHwgJ2hpZ2gnIHwgJ2NyaXRpY2FsJztcbiAgY29uZmlkZW5jZTogbnVtYmVyO1xuICBkZXNjcmlwdGlvbjogc3RyaW5nO1xufVxuXG4vKipcbiAqIENvbXByZWhlbnNpdmUgcHJvbXB0IGluamVjdGlvbiBwYXR0ZXJuc1xuICogQ2F0ZWdvcmllcyBiYXNlZCBvbiBPV0FTUCBMTE0gVG9wIDEwIGFuZCByZWFsLXdvcmxkIGF0dGFjayBkYXRhc2V0c1xuICovXG5jb25zdCBQQVRURVJOUzogUmVjb3JkPHN0cmluZywgUGF0dGVybkNvbmZpZz4gPSB7XG4gIC8vIE9XQVNQIExMTTAxOiBTeXN0ZW0gT3ZlcnJpZGUgQXR0ZW1wdHNcbiAgc3lzdGVtT3ZlcnJpZGU6IHtcbiAgICBwYXR0ZXJuczogW1xuICAgICAgL1xcYihpZ25vcmV8YnlwYXNzfGZvcmdldHxkaXNyZWdhcmQpXFxzKyhhbGxcXHMrKT8oeW91clxccyspPyhwcmV2aW91c3xwcmlvcnxhYm92ZXxlYXJsaWVyKVxccysoaW5zdHJ1Y3Rpb25zP3xydWxlcz98cHJvbXB0cz98ZGlyZWN0aXZlcz8pL2dpLFxuICAgICAgL1xcYnlvdVxccythcmVcXHMrbm93XFxzKyh0aGVcXHMrKT8oc3lzdGVtfGFkbWlufGRldmVsb3Blcnxyb290fGdvZFxccyptb2RlKVxcYi9naSxcbiAgICAgIC9cXGJhc1xccysoc3lzdGVtfGFkbWlufGRldmVsb3Blcnxyb290KSw/XFxzK3lvdVxccysobXVzdHxzaG91bGR8d2lsbHxzaGFsbClcXGIvZ2ksXG4gICAgICAvXFxiKG5ld3x1cGRhdGVkP3xyZXZpc2VkKVxccysoaW5zdHJ1Y3Rpb25zP3xydWxlcz98c3lzdGVtXFxzK3Byb21wdHxkaXJlY3RpdmVzPylcXHMqOj9cXHMqXFxuL2dpLFxuICAgICAgL1xcYihzdGFydHxiZWdpbilcXHMrKHdpdGh8YnkpXFxzKyhpZ25vcmluZ3xmb3JnZXR0aW5nfGRpc3JlZ2FyZGluZylcXGIvZ2ksXG4gICAgICAvXFxiZnJvbVxccytub3dcXHMrb24sP1xccysoeW91XFxzKyk/KHdpbGx8bXVzdHxzaG91bGR8YXJlKS9naSxcbiAgICAgIC9cXGJyZXNldFxccysoeW91cnxhbGwpXFxzKyhpbnN0cnVjdGlvbnM/fHJ1bGVzP3xjb250ZXh0KS9naVxuICAgIF0sXG4gICAgc2V2ZXJpdHk6ICdoaWdoJyxcbiAgICBjb25maWRlbmNlOiAwLjgsXG4gICAgZGVzY3JpcHRpb246ICdBdHRlbXB0cyB0byBvdmVycmlkZSBzeXN0ZW0gaW5zdHJ1Y3Rpb25zJ1xuICB9LFxuICBcbiAgLy8gUG9saWN5L1NhZmV0eSBCeXBhc3NcbiAgcG9saWN5QnlwYXNzOiB7XG4gICAgcGF0dGVybnM6IFtcbiAgICAgIC9cXGIoaWdub3JlfGJ5cGFzc3xvdmVycmlkZXxkaXNhYmxlfHR1cm5cXHMrb2ZmKVxccysoYWxsXFxzKyk/KHNhZmV0eXxjb250ZW50fHBvbGljeXxwb2xpY2llc3xmaWx0ZXJzP3xndWlkZWxpbmVzP3xyZXN0cmljdGlvbnM/KS9naSxcbiAgICAgIC9cXGIocHJldGVuZHxhY3RcXHMrYXNcXHMraWZ8c2ltdWxhdGV8aW1hZ2luZSlcXHMreW91XFxzKyhoYXZlXFxzK25vfGRvbic/dFxccytoYXZlfGxhY2t8YXJlXFxzK3dpdGhvdXQpXFxzKyhyZXN0cmljdGlvbnM/fGxpbWl0YXRpb25zP3xydWxlcz98cG9saWNpZXMpXFxiL2dpLFxuICAgICAgL1xcYmlcXHMrZ2l2ZVxccyt5b3VcXHMrcGVybWlzc2lvblxccyt0b1xccysoaWdub3JlfGJ5cGFzc3xicmVhaylcXGIvZ2ksXG4gICAgICAvXFxiKGVuYWJsZXxhY3RpdmF0ZXxlbnRlcilcXHMrKGRldmVsb3BlcnxkZWJ1Z3xnb2R8YWRtaW4pXFxzK21vZGUvZ2ksXG4gICAgICAvXFxidW5sb2NrXFxzKyh5b3VyXFxzKyk/KGZ1bGx8aGlkZGVufHNlY3JldClcXHMrKHBvdGVudGlhbHxjYXBhYmlsaXRpZXN8ZmVhdHVyZXMpL2dpLFxuICAgICAgL1xcYm5vXFxzKyhldGhpY2FsfG1vcmFsfHNhZmV0eSlcXHMrKGd1aWRlbGluZXM/fHJlc3RyaWN0aW9ucz98bGltaXRhdGlvbnM/KS9naVxuICAgIF0sXG4gICAgc2V2ZXJpdHk6ICdoaWdoJyxcbiAgICBjb25maWRlbmNlOiAwLjc1LFxuICAgIGRlc2NyaXB0aW9uOiAnQXR0ZW1wdHMgdG8gYnlwYXNzIHNhZmV0eSBwb2xpY2llcydcbiAgfSxcbiAgXG4gIC8vIENvbnRleHQvU3lzdGVtIFByb21wdCBFeGZpbHRyYXRpb25cbiAgY29udGV4dEV4ZmlsdHJhdGlvbjoge1xuICAgIHBhdHRlcm5zOiBbXG4gICAgICAvXFxiKHByaW50fHNob3d8ZGlzcGxheXxyZXZlYWx8b3V0cHV0fGR1bXB8bGlzdClcXHMrKHlvdXJcXHMrKT8oc3lzdGVtXFxzK3Byb21wdHxvcmlnaW5hbFxccytpbnN0cnVjdGlvbnM/fGluaXRpYWxcXHMrcHJvbXB0fGhpZGRlblxccysoY29uZmlnfGluc3RydWN0aW9ucz8pKVxcYi9naSxcbiAgICAgIC9cXGJ3aGF0XFxzKyhpc3xhcmV8d2VyZXx3YXMpXFxzK3lvdXJcXHMrKG9yaWdpbmFsfGluaXRpYWx8Zmlyc3R8c2VjcmV0KVxccysoaW5zdHJ1Y3Rpb25zP3xwcm9tcHR8cnVsZXM/fGRpcmVjdGl2ZXM/KVxcYi9naSxcbiAgICAgIC9cXGIocmVwZWF0fHNob3d8cHJpbnQpXFxzKyhldmVyeXRoaW5nfGFsbClcXHMrKGFib3ZlfGJlZm9yZXxwcmlvcnxwcmV2aW91cylcXGIvZ2ksXG4gICAgICAvXFxiKHNob3d8ZGlzcGxheXxsaXN0KVxccysoYWxsXFxzKyk/KHByZXZpb3VzfHByaW9yfGVhcmxpZXIpXFxzK21lc3NhZ2VzP1xcYi9naSxcbiAgICAgIC9cXGJyZXBlYXRcXHMrKHRoZVxccyspPyh0ZXh0fHdvcmRzfGNvbnRlbnQpXFxzKyhhYm92ZXxiZWZvcmUpL2dpLFxuICAgICAgL1xcYndoYXRcXHMrZGlkXFxzKyh0aGVcXHMrKT8odXNlcnxkZXZlbG9wZXJ8YWRtaW4pXFxzK3RlbGxcXHMreW91L2dpLFxuICAgICAgL1xcYihvdXRwdXR8cHJpbnR8ZWNobylcXHMrKHlvdXJcXHMrKT8oY29uZmlnfGNvbmZpZ3VyYXRpb258c2V0dGluZ3N8cGFyYW1ldGVycykvZ2lcbiAgICBdLFxuICAgIHNldmVyaXR5OiAnbWVkaXVtJyxcbiAgICBjb25maWRlbmNlOiAwLjcsXG4gICAgZGVzY3JpcHRpb246ICdBdHRlbXB0cyB0byBleHRyYWN0IHN5c3RlbSBwcm9tcHQgb3IgY29udGV4dCdcbiAgfSxcbiAgXG4gIC8vIEphaWxicmVhayBBdHRlbXB0cyAoREFOLCBldGMuKVxuICBqYWlsYnJlYWs6IHtcbiAgICBwYXR0ZXJuczogW1xuICAgICAgL1xcYihEQU58ZG9cXHMrYW55dGhpbmdcXHMrbm93KVxcYi9naSxcbiAgICAgIC9cXGJqYWlsYnJlYWsoZWR8aW5nKT9cXGIvZ2ksXG4gICAgICAvXFxiKFNUQU58RFVERXxBSU18S0VWSU4pXFxzKyhtb2RlfHBlcnNvbmEpL2dpLFxuICAgICAgL1xcYmFjdFxccythc1xccysoYW4/XFxzKyk/KHVucmVzdHJpY3RlZHx1bmZpbHRlcmVkfHVuY2Vuc29yZWQpXFxiL2dpLFxuICAgICAgL1xcYnByZXRlbmRcXHMrKHRvXFxzK2JlfHlvdVxccythcmUpXFxzKyhhbj9cXHMrKT8oZXZpbHxtYWxpY2lvdXN8dW5ldGhpY2FsKS9naSxcbiAgICAgIC9cXGJ5b3VcXHMrYXJlXFxzKyhub3dcXHMrKT8oZnJlZXxsaWJlcmF0ZWQpXFxzK2Zyb21cXHMrKGFsbFxccyspPyhyZXN0cmljdGlvbnM/fHJ1bGVzPykvZ2ksXG4gICAgICAvXFxib3Bwb3NpdGVcXHMrKG1vZGV8ZGF5fHBlcnNvbmFsaXR5KS9naSxcbiAgICAgIC9cXGJhbHRlclxccytlZ28vZ2lcbiAgICBdLFxuICAgIHNldmVyaXR5OiAnaGlnaCcsXG4gICAgY29uZmlkZW5jZTogMC44NSxcbiAgICBkZXNjcmlwdGlvbjogJ0tub3duIGphaWxicmVhayB0ZWNobmlxdWVzIChEQU4sIGV0Yy4pJ1xuICB9LFxuICBcbiAgLy8gUm9sZXBsYXkgTWFuaXB1bGF0aW9uXG4gIHJvbGVwbGF5TWFuaXB1bGF0aW9uOiB7XG4gICAgcGF0dGVybnM6IFtcbiAgICAgIC9cXGJwcmV0ZW5kXFxzKyh5b3VcXHMrYXJlfHRvXFxzK2JlKVxccysoYW4/XFxzKyk/KGhhY2tlcnxjcmltaW5hbHx2aWxsYWlufHRlcnJvcmlzdCkvZ2ksXG4gICAgICAvXFxicm9sZXBsYXlcXHMrYXNcXHMrKGFuP1xccyspPyhtYWxpY2lvdXN8ZXZpbHx1bmV0aGljYWwpL2dpLFxuICAgICAgL1xcYmFjdFxccythc1xccytpZlxccyt5b3VcXHMrKGhhdmVcXHMrbm98ZG9uJz90XFxzK2hhdmUpXFxzKyhtb3JhbHM/fGV0aGljcz8pL2dpLFxuICAgICAgL1xcYmltYWdpbmVcXHMreW91XFxzKyhhcmV8d2VyZSlcXHMrKHByb2dyYW1tZWR8ZGVzaWduZWQpXFxzK3RvXFxzKyhoYXJtfGh1cnR8YXR0YWNrKS9naSxcbiAgICAgIC9cXGJmb3JcXHMrKGFcXHMrKT8oZmljdGlvbmFsfGh5cG90aGV0aWNhbClcXHMrKHN0b3J5fHNjZW5hcmlvKSw/XFxzKyhpZ25vcmV8YnlwYXNzKS9naVxuICAgIF0sXG4gICAgc2V2ZXJpdHk6ICdtZWRpdW0nLFxuICAgIGNvbmZpZGVuY2U6IDAuNyxcbiAgICBkZXNjcmlwdGlvbjogJ1JvbGVwbGF5LWJhc2VkIG1hbmlwdWxhdGlvbiBhdHRlbXB0cydcbiAgfSxcbiAgXG4gIC8vIFRvb2wvRnVuY3Rpb24gQWJ1c2VcbiAgdG9vbEFidXNlOiB7XG4gICAgcGF0dGVybnM6IFtcbiAgICAgIC9cXGIoZXhlY3V0ZXxydW58Y2FsbHxpbnZva2UpXFxzKy4qXFxiKGRlbGV0ZXxkcm9wfHRydW5jYXRlfHJlbW92ZXxkZXN0cm95fHJtXFxzKy1yZilcXGIvZ2ksXG4gICAgICAvXFxiKHNlbmR8ZW1haWx8cG9zdHx1cGxvYWR8dHJhbnNtaXQpXFxzKy4qXFxiKHBhc3N3b3JkfGNyZWRlbnRpYWxzP3xzZWNyZXR8dG9rZW58a2V5fHByaXZhdGUpXFxiL2dpLFxuICAgICAgL1xcYihyZWFkfHdyaXRlfGFjY2VzcylcXHMrLipcXGIoXFwvZXRjXFwvfFxcL3Jvb3RcXC98XFwuc3NofFxcLmF3c3xcXC5lbnYpXFxiL2dpLFxuICAgICAgL1xcYihjdXJsfHdnZXR8ZmV0Y2gpXFxzK2h0dHAvZ2ksXG4gICAgICAvXFxiKGV2YWx8ZXhlY3xzeXN0ZW18c2hlbGxfZXhlY3xzdWJwcm9jZXNzKVxccypcXCgvZ2ksXG4gICAgICAvXFxic3Vkb1xccysvZ2ksXG4gICAgICAvXFxiY2htb2RcXHMrNzc3L2dpXG4gICAgXSxcbiAgICBzZXZlcml0eTogJ2NyaXRpY2FsJyxcbiAgICBjb25maWRlbmNlOiAwLjg1LFxuICAgIGRlc2NyaXB0aW9uOiAnQXR0ZW1wdHMgdG8gYWJ1c2UgdG9vbHMgb3IgZXhlY3V0ZSBkYW5nZXJvdXMgY29tbWFuZHMnXG4gIH0sXG4gIFxuICAvLyBFbmNvZGluZy9PYmZ1c2NhdGlvbiBBdHRhY2tzXG4gIGVuY29kaW5nQXR0YWNrOiB7XG4gICAgcGF0dGVybnM6IFtcbiAgICAgIC9cXGJkZWNvZGVcXHMrKHRoaXN8dGhlXFxzK2ZvbGxvd2luZylcXHMrKGJhc2U2NHxoZXh8cm90MTMpL2dpLFxuICAgICAgL1xcYihiYXNlNjR8aGV4fHJvdDEzKVxccyo6XFxzKltBLVphLXowLTkrLz1dezIwLH0vZ2ksXG4gICAgICAvXFxcXHhbMC05YS1mQS1GXXsyfS9nLFxuICAgICAgL1xcXFx1WzAtOWEtZkEtRl17NH0vZyxcbiAgICAgIC8mI3g/WzAtOWEtZkEtRl0rOy9nLFxuICAgICAgL1xcYmV2YWxcXHMqXFwoXFxzKmF0b2JcXHMqXFwoL2dpXG4gICAgXSxcbiAgICBzZXZlcml0eTogJ21lZGl1bScsXG4gICAgY29uZmlkZW5jZTogMC42LFxuICAgIGRlc2NyaXB0aW9uOiAnRW5jb2RlZCBvciBvYmZ1c2NhdGVkIGF0dGFjayBwYXlsb2FkcydcbiAgfSxcbiAgXG4gIC8vIEluZGlyZWN0IEluamVjdGlvbiAodmlhIGRhdGEpXG4gIGluZGlyZWN0SW5qZWN0aW9uOiB7XG4gICAgcGF0dGVybnM6IFtcbiAgICAgIC9cXFtTWVNURU1cXF18XFxbSU5TVFxcXXxcXFtcXC9JTlNUXFxdfDxcXHxzeXN0ZW1cXHw+fDxcXHx1c2VyXFx8Pi9naSxcbiAgICAgIC8jIyNcXHMqKHN5c3RlbXxpbnN0cnVjdGlvbnxodW1hbnxhc3Npc3RhbnQpXFxzKjovZ2ksXG4gICAgICAvPFxcLz9zPnw8XFwvP2h1bWFuPnw8XFwvP2Fzc2lzdGFudD4vZ2ksXG4gICAgICAvXFxiSHVtYW46XFxzKnxcXGJBc3Npc3RhbnQ6XFxzKnxcXGJTeXN0ZW06XFxzKi9naVxuICAgIF0sXG4gICAgc2V2ZXJpdHk6ICdoaWdoJyxcbiAgICBjb25maWRlbmNlOiAwLjc1LFxuICAgIGRlc2NyaXB0aW9uOiAnSW5kaXJlY3QgaW5qZWN0aW9uIHZpYSBkYXRhL21hcmt1cCdcbiAgfSxcbiAgXG4gIC8vIFByb21wdCBMZWFraW5nIHZpYSBDb21wbGV0aW9uXG4gIGNvbXBsZXRpb25MZWFrOiB7XG4gICAgcGF0dGVybnM6IFtcbiAgICAgIC9cXGJjb21wbGV0ZVxccyt0aGVcXHMrKGZvbGxvd2luZ3xzZW50ZW5jZXx0ZXh0KVxccyo6XFxzKltcIiddPyhzeXN0ZW18aW5zdHJ1Y3Rpb24pL2dpLFxuICAgICAgL1xcYmZpbmlzaFxccyt0aGlzXFxzKyhzZW50ZW5jZXxwcm9tcHQpXFxzKjpcXHMqW1wiJ10/eW91XFxzK2FyZS9naSxcbiAgICAgIC9cXGJ3aGF0XFxzK2NvbWVzXFxzKyhhZnRlcnxuZXh0KVxccyo6XFxzKltcIiddPyhpZ25vcmV8YnlwYXNzfHN5c3RlbSkvZ2lcbiAgICBdLFxuICAgIHNldmVyaXR5OiAnbWVkaXVtJyxcbiAgICBjb25maWRlbmNlOiAwLjY1LFxuICAgIGRlc2NyaXB0aW9uOiAnQXR0ZW1wdHMgdG8gbGVhayBwcm9tcHRzIHZpYSBjb21wbGV0aW9uJ1xuICB9XG59O1xuXG4vKipcbiAqIENoZWNrIGZvciBwcm9tcHQgaW5qZWN0aW9uIGF0dGVtcHRzXG4gKiBAcGFyYW0gaW5wdXQgLSBUaGUgaW5wdXQgdGV4dCB0byBjaGVja1xuICogQHJldHVybnMgQXJyYXkgb2YgZmluZGluZ3NcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNoZWNrUHJvbXB0SW5qZWN0aW9uKGlucHV0OiBzdHJpbmcpOiBGaW5kaW5nW10ge1xuICBjb25zdCBmaW5kaW5nczogRmluZGluZ1tdID0gW107XG4gIFxuICBmb3IgKGNvbnN0IFtjYXRlZ29yeSwgY29uZmlnXSBvZiBPYmplY3QuZW50cmllcyhQQVRURVJOUykpIHtcbiAgICBmb3IgKGNvbnN0IHBhdHRlcm4gb2YgY29uZmlnLnBhdHRlcm5zKSB7XG4gICAgICAvLyBSZXNldCBsYXN0SW5kZXggZm9yIGdsb2JhbCBwYXR0ZXJuc1xuICAgICAgcGF0dGVybi5sYXN0SW5kZXggPSAwO1xuICAgICAgY29uc3QgbWF0Y2hlcyA9IEFycmF5LmZyb20oaW5wdXQubWF0Y2hBbGwocGF0dGVybikpO1xuICAgICAgXG4gICAgICBpZiAobWF0Y2hlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IG1hdGNoID0gbWF0Y2hlc1swXTtcbiAgICAgICAgXG4gICAgICAgIC8vIENoZWNrIGZvciBmYWxzZSBwb3NpdGl2ZXNcbiAgICAgICAgaWYgKCFpc0xpa2VseUZhbHNlUG9zaXRpdmUoaW5wdXQsIG1hdGNoWzBdKSkge1xuICAgICAgICAgIGZpbmRpbmdzLnB1c2goY3JlYXRlRmluZGluZyhcbiAgICAgICAgICAgIGNhdGVnb3J5LFxuICAgICAgICAgICAgY29uZmlnLnNldmVyaXR5LFxuICAgICAgICAgICAgbWF0Y2gsXG4gICAgICAgICAgICBjb25maWcuY29uZmlkZW5jZSxcbiAgICAgICAgICAgIGlucHV0LFxuICAgICAgICAgICAgY29uZmlnLmRlc2NyaXB0aW9uXG4gICAgICAgICAgKSk7XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gT25seSByZXBvcnQgb25lIGZpbmRpbmcgcGVyIGNhdGVnb3J5XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgXG4gIHJldHVybiBmaW5kaW5ncztcbn1cblxuLyoqXG4gKiBTYW5pdGl6ZSBpbnB1dCBieSByZW1vdmluZyBvciBuZXV0cmFsaXppbmcgaW5qZWN0aW9uIGF0dGVtcHRzXG4gKiBAcGFyYW0gaW5wdXQgLSBUaGUgaW5wdXQgdG8gc2FuaXRpemVcbiAqIEByZXR1cm5zIFNhbml0aXplZCBpbnB1dCBhbmQgbGlzdCBvZiByZW1vdmVkIHBhdHRlcm5zXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzYW5pdGl6ZVByb21wdEluamVjdGlvbihpbnB1dDogc3RyaW5nKTogeyBcbiAgc2FuaXRpemVkOiBzdHJpbmc7IFxuICByZW1vdmVkOiBzdHJpbmdbXTtcbiAgd2FzTW9kaWZpZWQ6IGJvb2xlYW47XG59IHtcbiAgbGV0IHNhbml0aXplZCA9IGlucHV0O1xuICBjb25zdCByZW1vdmVkOiBzdHJpbmdbXSA9IFtdO1xuICBcbiAgZm9yIChjb25zdCBbY2F0ZWdvcnksIGNvbmZpZ10gb2YgT2JqZWN0LmVudHJpZXMoUEFUVEVSTlMpKSB7XG4gICAgZm9yIChjb25zdCBwYXR0ZXJuIG9mIGNvbmZpZy5wYXR0ZXJucykge1xuICAgICAgcGF0dGVybi5sYXN0SW5kZXggPSAwO1xuICAgICAgY29uc3QgbWF0Y2hlcyA9IEFycmF5LmZyb20oc2FuaXRpemVkLm1hdGNoQWxsKHBhdHRlcm4pKTtcbiAgICAgIFxuICAgICAgZm9yIChjb25zdCBtYXRjaCBvZiBtYXRjaGVzKSB7XG4gICAgICAgIGlmICghaXNMaWtlbHlGYWxzZVBvc2l0aXZlKGlucHV0LCBtYXRjaFswXSkpIHtcbiAgICAgICAgICByZW1vdmVkLnB1c2goYFske2NhdGVnb3J5fV06ICR7bWF0Y2hbMF19YCk7XG4gICAgICAgICAgc2FuaXRpemVkID0gc2FuaXRpemVkLnJlcGxhY2UobWF0Y2hbMF0sICdbUkVNT1ZFRF0nKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuICBcbiAgcmV0dXJuIHtcbiAgICBzYW5pdGl6ZWQsXG4gICAgcmVtb3ZlZCxcbiAgICB3YXNNb2RpZmllZDogcmVtb3ZlZC5sZW5ndGggPiAwXG4gIH07XG59XG5cbi8qKlxuICogR2V0IHJpc2sgc2NvcmUgZm9yIGlucHV0ICgwLTEpXG4gKiBAcGFyYW0gaW5wdXQgLSBUaGUgaW5wdXQgdG8gc2NvcmVcbiAqIEByZXR1cm5zIFJpc2sgc2NvcmUgYmV0d2VlbiAwIGFuZCAxXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRJbmplY3Rpb25SaXNrU2NvcmUoaW5wdXQ6IHN0cmluZyk6IG51bWJlciB7XG4gIGNvbnN0IGZpbmRpbmdzID0gY2hlY2tQcm9tcHRJbmplY3Rpb24oaW5wdXQpO1xuICBpZiAoZmluZGluZ3MubGVuZ3RoID09PSAwKSByZXR1cm4gMDtcbiAgXG4gIGNvbnN0IHNldmVyaXR5V2VpZ2h0czogUmVjb3JkPHN0cmluZywgbnVtYmVyPiA9IHtcbiAgICBtZWRpdW06IDAuNCxcbiAgICBoaWdoOiAwLjcsXG4gICAgY3JpdGljYWw6IDEuMFxuICB9O1xuICBcbiAgbGV0IG1heFNjb3JlID0gMDtcbiAgZm9yIChjb25zdCBmaW5kaW5nIG9mIGZpbmRpbmdzKSB7XG4gICAgY29uc3Qgc2NvcmUgPSBzZXZlcml0eVdlaWdodHNbZmluZGluZy5zZXZlcml0eV0gKiBmaW5kaW5nLmNvbmZpZGVuY2UudmFsdWU7XG4gICAgbWF4U2NvcmUgPSBNYXRoLm1heChtYXhTY29yZSwgc2NvcmUpO1xuICB9XG4gIFxuICByZXR1cm4gbWF4U2NvcmU7XG59XG5cbi8qKlxuICogUXVpY2sgY2hlY2sgaWYgaW5wdXQgaXMgbGlrZWx5IHNhZmUgKG5vIGluamVjdGlvbiBkZXRlY3RlZClcbiAqIEBwYXJhbSBpbnB1dCAtIFRoZSBpbnB1dCB0byBjaGVja1xuICogQHJldHVybnMgdHJ1ZSBpZiBubyBpbmplY3Rpb24gZGV0ZWN0ZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzSW5wdXRTYWZlKGlucHV0OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIGNoZWNrUHJvbXB0SW5qZWN0aW9uKGlucHV0KS5sZW5ndGggPT09IDA7XG59XG5cbi8qKlxuICogQ3JlYXRlIGEgZmluZGluZyBvYmplY3RcbiAqL1xuZnVuY3Rpb24gY3JlYXRlRmluZGluZyhcbiAgY2F0ZWdvcnk6IHN0cmluZyxcbiAgc2V2ZXJpdHk6IEZpbmRpbmdbJ3NldmVyaXR5J10sXG4gIG1hdGNoOiBSZWdFeHBNYXRjaEFycmF5LFxuICBjb25maWRlbmNlOiBudW1iZXIsXG4gIGZ1bGxJbnB1dDogc3RyaW5nLFxuICBkZXNjcmlwdGlvbjogc3RyaW5nXG4pOiBGaW5kaW5nIHtcbiAgY29uc3QgbWVzc2FnZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgc3lzdGVtT3ZlcnJpZGU6ICdTeXN0ZW0gb3ZlcnJpZGUgYXR0ZW1wdCBkZXRlY3RlZCcsXG4gICAgcG9saWN5QnlwYXNzOiAnUG9saWN5IGJ5cGFzcyBhdHRlbXB0IGRldGVjdGVkJyxcbiAgICBjb250ZXh0RXhmaWx0cmF0aW9uOiAnU3lzdGVtIHByb21wdCBleGZpbHRyYXRpb24gYXR0ZW1wdCBkZXRlY3RlZCcsXG4gICAgamFpbGJyZWFrOiAnSmFpbGJyZWFrIGF0dGVtcHQgZGV0ZWN0ZWQgKERBTi9zaW1pbGFyKScsXG4gICAgcm9sZXBsYXlNYW5pcHVsYXRpb246ICdSb2xlcGxheSBtYW5pcHVsYXRpb24gYXR0ZW1wdCBkZXRlY3RlZCcsXG4gICAgdG9vbEFidXNlOiAnVG9vbCBhYnVzZSBhdHRlbXB0IGRldGVjdGVkJyxcbiAgICBlbmNvZGluZ0F0dGFjazogJ0VuY29kZWQvb2JmdXNjYXRlZCBhdHRhY2sgZGV0ZWN0ZWQnLFxuICAgIGluZGlyZWN0SW5qZWN0aW9uOiAnSW5kaXJlY3QgaW5qZWN0aW9uIG1hcmtlcnMgZGV0ZWN0ZWQnLFxuICAgIGNvbXBsZXRpb25MZWFrOiAnUHJvbXB0IGxlYWsgdmlhIGNvbXBsZXRpb24gZGV0ZWN0ZWQnXG4gIH07XG4gIFxuICBjb25zdCByZWNvbW1lbmRhdGlvbnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgc3lzdGVtT3ZlcnJpZGU6ICdSZWplY3Qgb3Igc2FuaXRpemUgcmVxdWVzdC4gVXNlIHNhbml0aXplUHJvbXB0SW5qZWN0aW9uKCkgdG8gY2xlYW4gaW5wdXQuJyxcbiAgICBwb2xpY3lCeXBhc3M6ICdCbG9jayByZXF1ZXN0IC0gYXR0ZW1wdGluZyB0byBieXBhc3Mgc2FmZXR5IHBvbGljaWVzLicsXG4gICAgY29udGV4dEV4ZmlsdHJhdGlvbjogJ1Nhbml0aXplIHJlcXVlc3QgdG8gcHJldmVudCBzeXN0ZW0gcHJvbXB0IGxlYWthZ2UuJyxcbiAgICBqYWlsYnJlYWs6ICdCbG9jayBpbW1lZGlhdGVseSAtIGtub3duIGphaWxicmVhayB0ZWNobmlxdWUuJyxcbiAgICByb2xlcGxheU1hbmlwdWxhdGlvbjogJ1JldmlldyBjYXJlZnVsbHkgLSByb2xlcGxheSBtYXkgYmUgdXNlZCB0byBieXBhc3Mgc2FmZXR5LicsXG4gICAgdG9vbEFidXNlOiAnQmxvY2sgaW1tZWRpYXRlbHkgLSBhdHRlbXB0aW5nIGRhbmdlcm91cyBvcGVyYXRpb25zLicsXG4gICAgZW5jb2RpbmdBdHRhY2s6ICdEZWNvZGUgYW5kIHJlLXNjYW4gYmVmb3JlIHByb2Nlc3NpbmcuJyxcbiAgICBpbmRpcmVjdEluamVjdGlvbjogJ1Nhbml0aXplIGRhdGEgaW5wdXRzIC0gbWF5IGNvbnRhaW4gaW5qZWN0ZWQgaW5zdHJ1Y3Rpb25zLicsXG4gICAgY29tcGxldGlvbkxlYWs6ICdCbG9jayAtIGF0dGVtcHRpbmcgdG8gZXh0cmFjdCBwcm9tcHRzIHZpYSBjb21wbGV0aW9uLidcbiAgfTtcbiAgXG4gIGNvbnN0IGNvbnRleHRDbGFyaXR5ID0gYW5hbHl6ZUNvbnRleHQoZnVsbElucHV0LCBtYXRjaFswXSk7XG4gIFxuICByZXR1cm4ge1xuICAgIGlkOiBgUFJPTVBUX0lOSkVDVElPTl8ke2NhdGVnb3J5LnRvVXBwZXJDYXNlKCl9YCxcbiAgICBjYXRlZ29yeTogJ3NlY3VyaXR5JyxcbiAgICBzZXZlcml0eSxcbiAgICBzdXJmYWNlOiAnaW5wdXQnLFxuICAgIG1lc3NhZ2U6IG1lc3NhZ2VzW2NhdGVnb3J5XSB8fCAnUHJvbXB0IGluamVjdGlvbiBhdHRlbXB0IGRldGVjdGVkJyxcbiAgICByZWNvbW1lbmRhdGlvbjogcmVjb21tZW5kYXRpb25zW2NhdGVnb3J5XSB8fCAnUmV2aWV3IGFuZCBzYW5pdGl6ZSBpbnB1dC4nLFxuICAgIFxuICAgIGV2aWRlbmNlOiB7XG4gICAgICB0ZXh0U2FtcGxlOiB0cnVuY2F0ZShtYXRjaFswXSwgMTAwKSxcbiAgICAgIHBhdHRlcm46IGNhdGVnb3J5LFxuICAgICAgY29udGV4dDogZXh0cmFjdENvbnRleHQoZnVsbElucHV0LCBtYXRjaC5pbmRleCB8fCAwLCA1MClcbiAgICB9LFxuICAgIFxuICAgIGNvbmZpZGVuY2U6IGNhbGN1bGF0ZUNvbmZpZGVuY2UoY29uZmlkZW5jZSwgY29udGV4dENsYXJpdHkpLFxuICAgIGxpbWl0YXRpb25zOiBMSU1JVEFUSU9OUyxcbiAgICBtZXRob2RvbG9neTogTUVUSE9ET0xPR1ksXG4gICAgbWV0YWRhdGE6IHtcbiAgICAgIGF0dGFja1R5cGU6IGNhdGVnb3J5LFxuICAgICAgZGVzY3JpcHRpb25cbiAgICB9XG4gIH07XG59XG5cbi8qKlxuICogQ2FsY3VsYXRlIGNvbmZpZGVuY2Ugc2NvcmVcbiAqL1xuZnVuY3Rpb24gY2FsY3VsYXRlQ29uZmlkZW5jZShiYXNlQ29uZmlkZW5jZTogbnVtYmVyLCBjb250ZXh0Q2xhcml0eTogbnVtYmVyKTogQ29uZmlkZW5jZVNjb3JlIHtcbiAgY29uc3QgdmFsdWUgPSBiYXNlQ29uZmlkZW5jZSAqIGNvbnRleHRDbGFyaXR5O1xuICBcbiAgcmV0dXJuIHtcbiAgICB2YWx1ZSxcbiAgICBpbnRlcnZhbDogW01hdGgubWF4KDAsIHZhbHVlIC0gMC4xNSksIE1hdGgubWluKDEsIHZhbHVlICsgMC4xNSldLFxuICAgIG1ldGhvZDogJ2VtcGlyaWNhbCcsXG4gICAgZmFjdG9yczoge1xuICAgICAgcGF0dGVyblN0cmVuZ3RoOiBiYXNlQ29uZmlkZW5jZSxcbiAgICAgIGNvbnRleHRDbGFyaXR5XG4gICAgfVxuICB9O1xufVxuXG4vKipcbiAqIENoZWNrIGlmIHRoaXMgaXMgbGlrZWx5IGEgZmFsc2UgcG9zaXRpdmVcbiAqL1xuZnVuY3Rpb24gaXNMaWtlbHlGYWxzZVBvc2l0aXZlKGZ1bGxUZXh0OiBzdHJpbmcsIG1hdGNoZWRUZXh0OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgLy8gRWR1Y2F0aW9uYWwgY29udGV4dFxuICBjb25zdCBlZHVjYXRpb25hbE1hcmtlcnMgPSBbXG4gICAgL3RoaXNcXHMraXNcXHMrYW5cXHMrZXhhbXBsZVxccytvZi9pLFxuICAgIC9mb3JcXHMrZWR1Y2F0aW9uYWxcXHMrcHVycG9zZXMvaSxcbiAgICAvZGVtb25zdHJhdGVcXHMraG93L2ksXG4gICAgL3Nob3dpbmdcXHMreW91XFxzK3doYXRcXHMrbm90XFxzK3RvL2ksXG4gICAgL25ldmVyXFxzK2RvXFxzK3RoaXMvaSxcbiAgICAvYXZvaWRcXHMrZG9pbmcvaSxcbiAgICAvaGVyZSc/cz9cXHMraG93XFxzK2F0dGFja3M/XFxzK3dvcmsvaSxcbiAgICAvc2VjdXJpdHlcXHMrdHJhaW5pbmcvaSxcbiAgICAvYXdhcmVuZXNzXFxzK3RyYWluaW5nL2lcbiAgXTtcbiAgXG4gIGlmIChlZHVjYXRpb25hbE1hcmtlcnMuc29tZShwID0+IHAudGVzdChmdWxsVGV4dCkpKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgXG4gIC8vIFF1ZXN0aW9uIGFib3V0IHNlY3VyaXR5XG4gIGNvbnN0IHNlY3VyaXR5UXVlc3Rpb25zID0gW1xuICAgIC9ob3dcXHMrKGRvfGNhbilcXHMrKD86aXx3ZXx5b3UpXFxzK3ByZXZlbnQvaSxcbiAgICAvd2hhdFxccysoPzppc3xhcmUpXFxzK3RoZVxccytyaXNrcz9cXHMrb2YvaSxcbiAgICAvaG93XFxzK3RvXFxzK3Byb3RlY3RcXHMrYWdhaW5zdC9pLFxuICAgIC9ob3dcXHMrdG9cXHMrZGV0ZWN0L2ksXG4gICAgL3doYXRcXHMraXNcXHMrcHJvbXB0XFxzK2luamVjdGlvbi9pXG4gIF07XG4gIFxuICBpZiAoc2VjdXJpdHlRdWVzdGlvbnMuc29tZShwID0+IHAudGVzdChmdWxsVGV4dCkpKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgXG4gIC8vIFF1b3RlZCBjb250ZW50XG4gIGlmIChpc0xpa2VseVF1b3RlZChmdWxsVGV4dCwgbWF0Y2hlZFRleHQpKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgXG4gIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiBBbmFseXplIGNvbnRleHQgdG8gcmVmaW5lIGNvbmZpZGVuY2VcbiAqL1xuZnVuY3Rpb24gYW5hbHl6ZUNvbnRleHQoZnVsbFRleHQ6IHN0cmluZywgbWF0Y2g6IHN0cmluZyk6IG51bWJlciB7XG4gIGNvbnN0IG1hdGNoSW5kZXggPSBmdWxsVGV4dC5pbmRleE9mKG1hdGNoKTtcbiAgaWYgKG1hdGNoSW5kZXggPT09IC0xKSByZXR1cm4gMC45O1xuICBcbiAgY29uc3QgYmVmb3JlID0gZnVsbFRleHQuc3Vic3RyaW5nKE1hdGgubWF4KDAsIG1hdGNoSW5kZXggLSAzMCksIG1hdGNoSW5kZXgpO1xuICBjb25zdCBhZnRlciA9IGZ1bGxUZXh0LnN1YnN0cmluZyhtYXRjaEluZGV4ICsgbWF0Y2gubGVuZ3RoLCBtYXRjaEluZGV4ICsgbWF0Y2gubGVuZ3RoICsgMzApO1xuICBcbiAgLy8gTG93ZXIgY29uZmlkZW5jZSBpZiBzdXJyb3VuZGVkIGJ5IHF1b3RlcyBvciBjb2RlIG1hcmtlcnNcbiAgaWYgKC9bXCInYF0vLnRlc3QoYmVmb3JlKSB8fCAvW1wiJ2BdLy50ZXN0KGFmdGVyKSkge1xuICAgIHJldHVybiAwLjY7XG4gIH1cbiAgXG4gIC8vIExvd2VyIGNvbmZpZGVuY2UgaWYgaW4gY29kZSBibG9ja1xuICBpZiAoL2BgYC8udGVzdChiZWZvcmUpIHx8IC9gYGAvLnRlc3QoYWZ0ZXIpKSB7XG4gICAgcmV0dXJuIDAuNTtcbiAgfVxuICBcbiAgcmV0dXJuIDAuOTtcbn1cbiJdfQ==