UNPKG

llmverify

Version:

AI Output Verification Toolkit — Local-first LLM safety, hallucination detection, PII redaction, prompt injection defense, and runtime monitoring. Zero telemetry. OWASP LLM Top 10 aligned.

359 lines 43.7 kB
"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==