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.

433 lines 43.5 kB
"use strict"; /** * PII Detection & Redaction * * Comprehensive PII detection with redaction utilities. * Supports US and international formats. * * @module csm6/security/pii-detection * @author Haiec * @license MIT */ Object.defineProperty(exports, "__esModule", { value: true }); exports.checkPII = checkPII; exports.redactPII = redactPII; exports.containsPII = containsPII; exports.getPIIRiskScore = getPIIRiskScore; const text_1 = require("../../utils/text"); const LIMITATIONS = [ 'Pattern-based detection only', 'May miss obfuscated PII', 'US-centric patterns for SSN/phone (international formats included)', 'Context-dependent false positives possible', 'Cannot detect PII in images or encoded content' ]; const METHODOLOGY = 'Regex-based pattern matching for common PII formats. ' + 'Detects emails, phone numbers, SSNs, credit cards, API keys, and more. ' + 'Accuracy: ~90% for standard formats, lower for variations.'; /** * Comprehensive PII patterns */ const PII_PATTERNS = [ // === PERSONAL IDENTIFIERS === { name: 'EMAIL', pattern: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g, severity: 'medium', confidence: 0.95, message: 'Email address detected', category: 'personal' }, { name: 'PHONE_US', pattern: /\b(?:\+1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/g, severity: 'medium', confidence: 0.85, message: 'US phone number detected', category: 'personal' }, { name: 'PHONE_INTL', pattern: /\b\+(?:[0-9][\s.-]?){6,14}[0-9]\b/g, severity: 'medium', confidence: 0.8, message: 'International phone number detected', category: 'personal' }, { name: 'SSN', pattern: /\b\d{3}[-\s]?\d{2}[-\s]?\d{4}\b/g, severity: 'critical', confidence: 0.8, message: 'Potential SSN detected', category: 'personal' }, { name: 'PASSPORT', pattern: /\b[A-Z]{1,2}\d{6,9}\b/g, severity: 'high', confidence: 0.6, message: 'Potential passport number detected', category: 'personal' }, { name: 'DRIVERS_LICENSE', pattern: /\b[A-Z]{1,2}\d{5,8}\b/g, severity: 'high', confidence: 0.5, message: 'Potential drivers license detected', category: 'personal' }, { name: 'DATE_OF_BIRTH', pattern: /\b(?:dob|date\s+of\s+birth|born\s+on|birthday)[:\s]+\d{1,2}[-/]\d{1,2}[-/]\d{2,4}\b/gi, severity: 'medium', confidence: 0.85, message: 'Date of birth detected', category: 'personal' }, // === FINANCIAL === { name: 'CREDIT_CARD', pattern: /\b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|6(?:011|5[0-9]{2})[0-9]{12})\b/g, severity: 'critical', confidence: 0.9, message: 'Credit card number detected', category: 'financial' }, { name: 'BANK_ACCOUNT', pattern: /\b(?:account|acct)[\s#:]*\d{8,17}\b/gi, severity: 'high', confidence: 0.7, message: 'Bank account number detected', category: 'financial' }, { name: 'ROUTING_NUMBER', pattern: /\b(?:routing|aba)[\s#:]*\d{9}\b/gi, severity: 'high', confidence: 0.75, message: 'Bank routing number detected', category: 'financial' }, { name: 'IBAN', pattern: /\b[A-Z]{2}\d{2}[A-Z0-9]{4}\d{7}([A-Z0-9]?){0,16}\b/g, severity: 'high', confidence: 0.85, message: 'IBAN detected', category: 'financial' }, // === CREDENTIALS & SECRETS === { name: 'API_KEY', pattern: /\b(?:sk|pk|api|key|token|secret|password)[-_]?[a-zA-Z0-9]{20,}\b/gi, severity: 'critical', confidence: 0.75, message: 'Potential API key or secret detected', category: 'credential' }, { name: 'AWS_KEY', pattern: /\bAKIA[0-9A-Z]{16}\b/g, severity: 'critical', confidence: 0.95, message: 'AWS Access Key ID detected', category: 'credential' }, { name: 'AWS_SECRET', pattern: /\b[A-Za-z0-9/+=]{40}\b/g, severity: 'critical', confidence: 0.6, message: 'Potential AWS Secret Key detected', category: 'credential' }, { name: 'GITHUB_TOKEN', pattern: /\b(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b/g, severity: 'critical', confidence: 0.95, message: 'GitHub token detected', category: 'credential' }, { name: 'SLACK_TOKEN', pattern: /\bxox[baprs]-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24}\b/g, severity: 'critical', confidence: 0.95, message: 'Slack token detected', category: 'credential' }, { name: 'STRIPE_KEY', pattern: /\b(sk|pk)_(test|live)_[A-Za-z0-9]{24,}\b/g, severity: 'critical', confidence: 0.95, message: 'Stripe API key detected', category: 'credential' }, { name: 'JWT_TOKEN', pattern: /\beyJ[A-Za-z0-9-_]+\.eyJ[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\b/g, severity: 'high', confidence: 0.9, message: 'JWT token detected', category: 'credential' }, { name: 'PRIVATE_KEY', pattern: /-----BEGIN\s+(RSA|DSA|EC|OPENSSH|PGP)?\s*PRIVATE\s+KEY-----/gi, severity: 'critical', confidence: 0.98, message: 'Private key detected', category: 'credential' }, { name: 'PASSWORD_INLINE', pattern: /\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^\s"']{8,}["']?\b/gi, severity: 'critical', confidence: 0.85, message: 'Inline password detected', category: 'credential' }, // === LOCATION === { name: 'IP_ADDRESS', pattern: /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/g, severity: 'low', confidence: 0.9, message: 'IP address detected', category: 'location' }, { name: 'IPV6_ADDRESS', pattern: /\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b/g, severity: 'low', confidence: 0.9, message: 'IPv6 address detected', category: 'location' }, { name: 'MAC_ADDRESS', pattern: /\b([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})\b/g, severity: 'low', confidence: 0.9, message: 'MAC address detected', category: 'location' }, { name: 'US_ADDRESS', pattern: /\b\d{1,5}\s+[\w\s]+(?:street|st|avenue|ave|road|rd|boulevard|blvd|drive|dr|lane|ln|court|ct)\b/gi, severity: 'medium', confidence: 0.6, message: 'US street address detected', category: 'location' }, { name: 'ZIP_CODE', pattern: /\b\d{5}(?:-\d{4})?\b/g, severity: 'low', confidence: 0.5, message: 'US ZIP code detected', category: 'location' }, // === HEALTH === { name: 'MEDICAL_RECORD', pattern: /\b(?:mrn|medical\s+record)[\s#:]*\d{6,12}\b/gi, severity: 'critical', confidence: 0.8, message: 'Medical record number detected', category: 'health' } ]; /** * Check for PII in content * @param content - The content to scan * @returns Array of findings */ function checkPII(content) { const findings = []; const foundTypes = new Set(); for (const piiPattern of PII_PATTERNS) { // Reset lastIndex piiPattern.pattern.lastIndex = 0; const matches = Array.from(content.matchAll(piiPattern.pattern)); for (const match of matches) { // Skip if we already found this type (avoid spam) if (foundTypes.has(piiPattern.name)) continue; // Skip if likely false positive if (isLikelyFalsePositive(content, match[0], piiPattern.name)) continue; foundTypes.add(piiPattern.name); findings.push({ id: `PII_${piiPattern.name}`, category: 'privacy', severity: piiPattern.severity, surface: 'output', message: piiPattern.message, recommendation: `Remove or redact ${piiPattern.name.toLowerCase().replace(/_/g, ' ')} before use.`, evidence: { textSample: redactSample(match[0]), pattern: piiPattern.name, context: (0, text_1.extractContext)(content, match.index || 0, 30) }, confidence: calculateConfidence(piiPattern.confidence, match[0]), limitations: LIMITATIONS, methodology: METHODOLOGY, metadata: { piiType: piiPattern.name, piiCategory: piiPattern.category } }); } } return findings; } /** * Redact all PII from content * @param content - The content to redact * @param replacement - Replacement string (default: [REDACTED]) * @returns Redacted content and list of redactions */ function redactPII(content, replacement = '[REDACTED]') { let redacted = content; const redactions = []; for (const piiPattern of PII_PATTERNS) { piiPattern.pattern.lastIndex = 0; const matches = Array.from(content.matchAll(piiPattern.pattern)); for (const match of matches) { if (!isLikelyFalsePositive(content, match[0], piiPattern.name)) { redactions.push({ type: piiPattern.name, original: redactSample(match[0]), position: match.index || 0 }); redacted = redacted.replace(match[0], replacement); } } } return { redacted, redactions, piiCount: redactions.length }; } /** * Check if content contains any PII * @param content - The content to check * @returns true if PII detected */ function containsPII(content) { return checkPII(content).length > 0; } /** * Get PII risk score (0-1) * @param content - The content to score * @returns Risk score */ function getPIIRiskScore(content) { const findings = checkPII(content); if (findings.length === 0) return 0; const severityWeights = { low: 0.2, 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); } // Add penalty for multiple PII types const typeBonus = Math.min(findings.length * 0.1, 0.3); return Math.min(1, maxScore + typeBonus); } /** * Redact sensitive parts of sample for display */ function redactSample(text) { if (text.length <= 8) { return text.substring(0, 2) + '***' + text.substring(text.length - 2); } const visible = Math.min(4, Math.floor(text.length / 4)); return text.substring(0, visible) + '***' + text.substring(text.length - visible); } /** * Calculate confidence score */ function calculateConfidence(baseConfidence, match) { let value = baseConfidence; // Adjust based on match characteristics if (match.length > 20) value += 0.05; if (/^[A-Z]/.test(match)) value -= 0.05; // Might be a name, not PII value = Math.max(0.5, Math.min(0.95, value)); return { value, interval: [Math.max(0, value - 0.1), Math.min(1, value + 0.1)], method: 'empirical', factors: { patternStrength: baseConfidence } }; } /** * Check for false positives */ function isLikelyFalsePositive(fullText, match, type) { // Example/placeholder indicators const placeholders = [ /example/i, /placeholder/i, /test/i, /sample/i, /dummy/i, /fake/i, /demo/i, /xxx/i ]; const context = fullText.substring(Math.max(0, fullText.indexOf(match) - 50), fullText.indexOf(match) + match.length + 50); if (placeholders.some(p => p.test(context))) { return true; } // SSN false positives if (type === 'SSN') { // Check if it's a date format if (/\d{2}[-/]\d{2}[-/]\d{4}/.test(match)) { return true; } // Check if preceded by date-like context if (/date|time|year|month|day/i.test(context)) { return true; } } // Phone false positives if (type === 'PHONE_US') { // Check if it's a zip code or other number if (/zip|code|id|number/i.test(context) && !/phone|call|mobile|cell/i.test(context)) { return true; } } // ZIP code - too many false positives, require context if (type === 'ZIP_CODE') { if (!/zip|postal|address/i.test(context)) { return true; } } // AWS Secret - high false positive rate if (type === 'AWS_SECRET') { // Only flag if near AWS context if (!/aws|amazon|secret|key/i.test(context)) { return true; } } return false; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGlpLWRldGVjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jc202L3NlY3VyaXR5L3BpaS1kZXRlY3Rpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7R0FTRzs7QUErUEgsNEJBNENDO0FBUUQsOEJBNkJDO0FBT0Qsa0NBRUM7QUFPRCwwQ0FxQkM7QUFsWEQsMkNBQTREO0FBRTVELE1BQU0sV0FBVyxHQUFHO0lBQ2xCLDhCQUE4QjtJQUM5Qix5QkFBeUI7SUFDekIsb0VBQW9FO0lBQ3BFLDRDQUE0QztJQUM1QyxnREFBZ0Q7Q0FDakQsQ0FBQztBQUVGLE1BQU0sV0FBVyxHQUNmLHVEQUF1RDtJQUN2RCx5RUFBeUU7SUFDekUsNERBQTRELENBQUM7QUFXL0Q7O0dBRUc7QUFDSCxNQUFNLFlBQVksR0FBaUI7SUFDakMsK0JBQStCO0lBQy9CO1FBQ0UsSUFBSSxFQUFFLE9BQU87UUFDYixPQUFPLEVBQUUsc0RBQXNEO1FBQy9ELFFBQVEsRUFBRSxRQUFRO1FBQ2xCLFVBQVUsRUFBRSxJQUFJO1FBQ2hCLE9BQU8sRUFBRSx3QkFBd0I7UUFDakMsUUFBUSxFQUFFLFVBQVU7S0FDckI7SUFDRDtRQUNFLElBQUksRUFBRSxVQUFVO1FBQ2hCLE9BQU8sRUFBRSx5REFBeUQ7UUFDbEUsUUFBUSxFQUFFLFFBQVE7UUFDbEIsVUFBVSxFQUFFLElBQUk7UUFDaEIsT0FBTyxFQUFFLDBCQUEwQjtRQUNuQyxRQUFRLEVBQUUsVUFBVTtLQUNyQjtJQUNEO1FBQ0UsSUFBSSxFQUFFLFlBQVk7UUFDbEIsT0FBTyxFQUFFLG9DQUFvQztRQUM3QyxRQUFRLEVBQUUsUUFBUTtRQUNsQixVQUFVLEVBQUUsR0FBRztRQUNmLE9BQU8sRUFBRSxxQ0FBcUM7UUFDOUMsUUFBUSxFQUFFLFVBQVU7S0FDckI7SUFDRDtRQUNFLElBQUksRUFBRSxLQUFLO1FBQ1gsT0FBTyxFQUFFLGtDQUFrQztRQUMzQyxRQUFRLEVBQUUs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LENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDekMsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztJQUVELHdDQUF3QztJQUN4QyxJQUFJLElBQUksS0FBSyxZQUFZLEVBQUUsQ0FBQztRQUMxQixnQ0FBZ0M7UUFDaEMsSUFBSSxDQUFDLHdCQUF3QixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQzVDLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7SUFFRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFBJSSBEZXRlY3Rpb24gJiBSZWRhY3Rpb25cbiAqIFxuICogQ29tcHJlaGVuc2l2ZSBQSUkgZGV0ZWN0aW9uIHdpdGggcmVkYWN0aW9uIHV0aWxpdGllcy5cbiAqIFN1cHBvcnRzIFVTIGFuZCBpbnRlcm5hdGlvbmFsIGZvcm1hdHMuXG4gKiBcbiAqIEBtb2R1bGUgY3NtNi9zZWN1cml0eS9waWktZGV0ZWN0aW9uXG4gKiBAYXV0aG9yIEhhaWVjXG4gKiBAbGljZW5zZSBNSVRcbiAqL1xuXG5pbXBvcnQgeyBGaW5kaW5nLCBDb25maWRlbmNlU2NvcmUgfSBmcm9tICcuLi8uLi90eXBlcy9yZXN1bHRzJztcbmltcG9ydCB7IHRydW5jYXRlLCBleHRyYWN0Q29udGV4dCB9IGZyb20gJy4uLy4uL3V0aWxzL3RleHQnO1xuXG5jb25zdCBMSU1JVEFUSU9OUyA9IFtcbiAgJ1BhdHRlcm4tYmFzZWQgZGV0ZWN0aW9uIG9ubHknLFxuICAnTWF5IG1pc3Mgb2JmdXNjYXRlZCBQSUknLFxuICAnVVMtY2VudHJpYyBwYXR0ZXJucyBmb3IgU1NOL3Bob25lIChpbnRlcm5hdGlvbmFsIGZvcm1hdHMgaW5jbHVkZWQpJyxcbiAgJ0NvbnRleHQtZGVwZW5kZW50IGZhbHNlIHBvc2l0aXZlcyBwb3NzaWJsZScsXG4gICdDYW5ub3QgZGV0ZWN0IFBJSSBpbiBpbWFnZXMgb3IgZW5jb2RlZCBjb250ZW50J1xuXTtcblxuY29uc3QgTUVUSE9ET0xPR1kgPVxuICAnUmVnZXgtYmFzZWQgcGF0dGVybiBtYXRjaGluZyBmb3IgY29tbW9uIFBJSSBmb3JtYXRzLiAnICtcbiAgJ0RldGVjdHMgZW1haWxzLCBwaG9uZSBudW1iZXJzLCBTU05zLCBjcmVkaXQgY2FyZHMsIEFQSSBrZXlzLCBhbmQgbW9yZS4gJyArXG4gICdBY2N1cmFjeTogfjkwJSBmb3Igc3RhbmRhcmQgZm9ybWF0cywgbG93ZXIgZm9yIHZhcmlhdGlvbnMuJztcblxuaW50ZXJmYWNlIFBJSVBhdHRlcm4ge1xuICBuYW1lOiBzdHJpbmc7XG4gIHBhdHRlcm46IFJlZ0V4cDtcbiAgc2V2ZXJpdHk6ICdsb3cnIHwgJ21lZGl1bScgfCAnaGlnaCcgfCAnY3JpdGljYWwnO1xuICBjb25maWRlbmNlOiBudW1iZXI7XG4gIG1lc3NhZ2U6IHN0cmluZztcbiAgY2F0ZWdvcnk6ICdwZXJzb25hbCcgfCAnZmluYW5jaWFsJyB8ICdjcmVkZW50aWFsJyB8ICdsb2NhdGlvbicgfCAnaGVhbHRoJztcbn1cblxuLyoqXG4gKiBDb21wcmVoZW5zaXZlIFBJSSBwYXR0ZXJuc1xuICovXG5jb25zdCBQSUlfUEFUVEVSTlM6IFBJSVBhdHRlcm5bXSA9IFtcbiAgLy8gPT09IFBFUlNPTkFMIElERU5USUZJRVJTID09PVxuICB7XG4gICAgbmFtZTogJ0VNQUlMJyxcbiAgICBwYXR0ZXJuOiAvXFxiW0EtWmEtejAtOS5fJSstXStAW0EtWmEtejAtOS4tXStcXC5bQS1afGEtel17Mix9XFxiL2csXG4gICAgc2V2ZXJpdHk6ICdtZWRpdW0nLFxuICAgIGNvbmZpZGVuY2U6IDAuOTUsXG4gICAgbWVzc2FnZTogJ0VtYWlsIGFkZHJlc3MgZGV0ZWN0ZWQnLFxuICAgIGNhdGVnb3J5OiAncGVyc29uYWwnXG4gIH0sXG4gIHtcbiAgICBuYW1lOiAnUEhPTkVfVVMnLFxuICAgIHBhdHRlcm46IC9cXGIoPzpcXCsxWy0uXFxzXT8pP1xcKD9cXGR7M31cXCk/Wy0uXFxzXT9cXGR7M31bLS5cXHNdP1xcZHs0fVxcYi9nLFxuICAgIHNldmVyaXR5OiAnbWVkaXVtJyxcbiAgICBjb25maWRlbmNlOiAwLjg1LFxuICAgIG1lc3NhZ2U6ICdVUyBwaG9uZSBudW1iZXIgZGV0ZWN0ZWQnLFxuICAgIGNhdGVnb3J5OiAncGVyc29uYWwnXG4gIH0sXG4gIHtcbiAgICBuYW1lOiAnUEhPTkVfSU5UTCcsXG4gICAgcGF0dGVybjogL1xcYlxcKyg/OlswLTldW1xccy4tXT8pezYsMTR9WzAtOV1cXGIvZyxcbiAgICBzZXZlcml0eTogJ21lZGl1bScsXG4gICAgY29uZmlkZW5jZTogMC44LFxuICAgIG1lc3NhZ2U6ICdJbnRlcm5hdGlvbmFsIHBob25lIG51bWJlciBkZXRlY3RlZCcsXG4gICAgY2F0ZWdvcnk6ICdwZXJzb25hbCdcbiAgfSxcbiAge1xuICAgIG5hbWU6ICdTU04nLFxuICAgIHBhdHRlcm46IC9cXGJcXGR7M31bLVxcc10/XFxkezJ9Wy1cXHNdP1xcZHs0fVxcYi9nLFxuICAgIHNldmVyaXR5OiAnY3JpdGljYWwnLFxuICAgIGNvbmZpZGVuY2U6IDAuOCxcbiAgICBtZXNzYWdlOiAnUG90ZW50aWFsIFNTTiBkZXRlY3RlZCcsXG4gICAgY2F0ZWdvcnk6ICdwZXJzb25hbCdcbiAgfSxcbiAge1xuICAgIG5hbWU6ICdQQVNTUE9SVCcsXG4gICAgcGF0dGVybjogL1xcYltBLVpdezEsMn1cXGR7Niw5fVxcYi9nLFxuICAgIHNldmVyaXR5OiAnaGlnaCcsXG4gICAgY29uZmlkZW5jZTogMC42LFxuICAgIG1lc3NhZ2U6ICdQb3RlbnRpYWwgcGFzc3BvcnQgbnVtYmVyIGRldGVjdGVkJyxcbiAgICBjYXRlZ29yeTogJ3BlcnNvbmFsJ1xuICB9LFxuICB7XG4gICAgbmFtZTogJ0RSSVZFUlNfTElDRU5TRScsXG4gICAgcGF0dGVybjogL1xcYltBLVpdezEsMn1cXGR7NSw4fVxcYi9nLFxuICAgIHNldmVyaXR5OiAnaGlnaCcsXG4gICAgY29uZmlkZW5jZTogMC41LFxuICAgIG1lc3NhZ2U6ICdQb3RlbnRpYWwgZHJpdmVycyBsaWNlbnNlIGRldGVjdGVkJyxcbiAgICBjYXRlZ29yeTogJ3BlcnNvbmFsJ1xuICB9LFxuICB7XG4gICAgbmFtZTogJ0RBVEVfT0ZfQklSVEgnLFxuICAgIHBhdHRlcm46IC9cXGIoPzpkb2J8ZGF0ZVxccytvZlxccytiaXJ0aHxib3JuXFxzK29ufGJpcnRoZGF5KVs6XFxzXStcXGR7MSwyfVstL11cXGR7MSwyfVstL11cXGR7Miw0fVxcYi9naSxcbiAgICBzZXZlcml0eTogJ21lZGl1bScsXG4gICAgY29uZmlkZW5jZTogMC44NSxcbiAgICBtZXNzYWdlOiAnRGF0ZSBvZiBiaXJ0aCBkZXRlY3RlZCcsXG4gICAgY2F0ZWdvcnk6ICdwZXJzb25hbCdcbiAgfSxcbiAgXG4gIC8vID09PSBGSU5BTkNJQUwgPT09XG4gIHtcbiAgICBuYW1lOiAnQ1JFRElUX0NBUkQnLFxuICAgIHBhdHRlcm46IC9cXGIoPzo0WzAtOV17MTJ9KD86WzAtOV17M30pP3w1WzEtNV1bMC05XXsxNH18M1s0N11bMC05XXsxM318Nig/OjAxMXw1WzAtOV17Mn0pWzAtOV17MTJ9KVxcYi9nLFxuICAgIHNldmVyaXR5OiAnY3JpdGljYWwnLFxuICAgIGNvbmZpZGVuY2U6IDAuOSxcbiAgICBtZXNzYWdlOiAnQ3JlZGl0IGNhcmQgbnVtYmVyIGRldGVjdGVkJyxcbiAgICBjYXRlZ29yeTogJ2ZpbmFuY2lhbCdcbiAgfSxcbiAge1xuICAgIG5hbWU6ICdCQU5LX0FDQ09VTlQnLFxuICAgIHBhdHRlcm46IC9cXGIoPzphY2NvdW50fGFjY3QpW1xccyM6XSpcXGR7OCwxN31cXGIvZ2ksXG4gICAgc2V2ZXJpdHk6ICdoaWdoJyxcbiAgICBjb25maWRlbmNlOiAwLjcsXG4gICAgbWVzc2FnZTogJ0JhbmsgYWNjb3VudCBudW1iZXIgZGV0ZWN0ZWQnLFxuICAgIGNhdGVnb3J5OiAnZmluYW5jaWFsJ1xuICB9LFxuICB7XG4gICAgbmFtZTogJ1JPVVRJTkdfTlVNQkVSJyxcbiAgICBwYXR0ZXJuOiAvXFxiKD86cm91dGluZ3xhYmEpW1xccyM6XSpcXGR7OX1cXGIvZ2ksXG4gICAgc2V2ZXJpdHk6ICdoaWdoJyxcbiAgICBjb25maWRlbmNlOiAwLjc1LFxuICAgIG1lc3NhZ2U6ICdCYW5rIHJvdXRpbmcgbnVtYmVyIGRldGVjdGVkJyxcbiAgICBjYXRlZ29yeTogJ2ZpbmFuY2lhbCdcbiAgfSxcbiAge1xuICAgIG5hbWU6ICdJQkFOJyxcbiAgICBwYXR0ZXJuOiAvXFxiW0EtWl17Mn1cXGR7Mn1bQS1aMC05XXs0fVxcZHs3fShbQS1aMC05XT8pezAsMTZ9XFxiL2csXG4gICAgc2V2ZXJpdHk6ICdoaWdoJyxcbiAgICBjb25maWRlbmNlOiAwLjg1LFxuICAgIG1lc3NhZ2U6ICdJQkFOIGRldGVjdGVkJyxcbiAgICBjYXRlZ29yeTogJ2ZpbmFuY2lhbCdcbiAgfSxcbiAgXG4gIC8vID09PSBDUkVERU5USUFMUyAmIFNFQ1JFVFMgPT09XG4gIHtcbiAgICBuYW1lOiAnQVBJX0tFWScsXG4gICAgcGF0dGVybjogL1xcYig/OnNrfHBrfGFwaXxrZXl8dG9rZW58c2VjcmV0fHBhc3N3b3JkKVstX10/W2EtekEtWjAtOV17MjAsfVxcYi9naSxcbiAgICBzZXZlcml0eTogJ2NyaXRpY2FsJyxcbiAgICBjb25maWRlbmNlOiAwLjc1LFxuICAgIG1lc3NhZ2U6ICdQb3RlbnRpYWwgQVBJIGtleSBvciBzZWNyZXQgZGV0ZWN0ZWQnLFxuICAgIGNhdGVnb3J5OiAnY3JlZGVudGlhbCdcbiAgfSxcbiAge1xuICAgIG5hbWU6ICdBV1NfS0VZJyxcbiAgICBwYXR0ZXJuOiAvXFxiQUtJQVswLTlBLVpdezE2fVxcYi9nLFxuICAgIHNldmVyaXR5OiAnY3JpdGljYWwnLFxuICAgIGNvbmZpZGVuY2U6IDAuOTUsXG4gICAgbWVzc2FnZTogJ0FXUyBBY2Nlc3MgS2V5IElEIGRldGVjdGVkJyxcbiAgICBjYXRlZ29yeTogJ2NyZWRlbnRpYWwnXG4gIH0sXG4gIHtcbiAgICBuYW1lOiAnQVdTX1NFQ1JFVCcsXG4gICAgcGF0dGVybjogL1xcYltBLVphLXowLTkvKz1dezQwfVxcYi9nLFxuICAgIHNldmVyaXR5OiAnY3JpdGljYWwnLFxuICAgIGNvbmZpZGVuY2U6IDAuNixcbiAgICBtZXNzYWdlOiAnUG90ZW50aWFsIEFXUyBTZWNyZXQgS2V5IGRldGVjdGVkJyxcbiAgICBjYXRlZ29yeTogJ2NyZWRlbnRpYWwnXG4gIH0sXG4gIHtcbiAgICBuYW1lOiAnR0lUSFVCX1RPS0VOJyxcbiAgICBwYXR0ZXJuOiAvXFxiKGdocHxnaG98Z2h1fGdoc3xnaHIpX1tBLVphLXowLTldezM2LH1cXGIvZyxcbiAgICBzZXZlcml0eTogJ2NyaXRpY2FsJyxcbiAgICBjb25maWRlbmNlOiAwLjk1LFxuICAgIG1lc3NhZ2U6ICdHaXRIdWIgdG9rZW4gZGV0ZWN0ZWQnLFxuICAgIGNhdGVnb3J5OiAnY3JlZGVudGlhbCdcbiAgfSxcbiAge1xuICAgIG5hbWU6ICdTTEFDS19UT0tFTicsXG4gICAgcGF0dGVybjogL1xcYnhveFtiYXByc10tWzAtOV17MTAsMTN9LVswLTldezEwLDEzfS1bYS16QS1aMC05XXsyNH1cXGIvZyxcbiAgICBzZXZlcml0eTogJ2NyaXRpY2FsJyxcbiAgICBjb25maWRlbmNlOiAwLjk1LFxuICAgIG1lc3NhZ2U6ICdTbGFjayB0b2tlbiBkZXRlY3RlZCcsXG4gICAgY2F0ZWdvcnk6ICdjcmVkZW50aWFsJ1xuICB9LFxuICB7XG4gICAgbmFtZTogJ1NUUklQRV9LRVknLFxuICAgIHBhdHRlcm46IC9cXGIoc2t8cGspXyh0ZXN0fGxpdmUpX1tBLVphLXowLTldezI0LH1cXGIvZyxcbiAgICBzZXZlcml0eTogJ2NyaXRpY2FsJyxcbiAgICBjb25maWRlbmNlOiAwLjk1LFxuICAgIG1lc3NhZ2U6ICdTdHJpcGUgQVBJIGtleSBkZXRlY3RlZCcsXG4gICAgY2F0ZWdvcnk6ICdjcmVkZW50aWFsJ1xuICB9LFxuICB7XG4gICAgbmFtZTogJ0pXVF9UT0tFTicsXG4gICAgcGF0dGVybjogL1xcYmV5SltBLVphLXowLTktX10rXFwuZXlKW0EtWmEtejAtOS1fXStcXC5bQS1aYS16MC05LV9dK1xcYi9nLFxuICAgIHNldmVyaXR5OiAnaGlnaCcsXG4gICAgY29uZmlkZW5jZTogMC45LFxuICAgIG1lc3NhZ2U6ICdKV1QgdG9rZW4gZGV0ZWN0ZWQnLFxuICAgIGNhdGVnb3J5OiAnY3JlZGVudGlhbCdcbiAgfSxcbiAge1xuICAgIG5hbWU6ICdQUklWQVRFX0tFWScsXG4gICAgcGF0dGVybjogLy0tLS0tQkVHSU5cXHMrKFJTQXxEU0F8RUN8T1BFTlNTSHxQR1ApP1xccypQUklWQVRFXFxzK0tFWS0tLS0tL2dpLFxuICAgIHNldmVyaXR5OiAnY3JpdGljYWwnLFxuICAgIGNvbmZpZGVuY2U6IDAuOTgsXG4gICAgbWVzc2FnZTogJ1ByaXZhdGUga2V5IGRldGVjdGVkJyxcbiAgICBjYXRlZ29yeTogJ2NyZWRlbnRpYWwnXG4gIH0sXG4gIHtcbiAgICBuYW1lOiAnUEFTU1dPUkRfSU5MSU5FJyxcbiAgICBwYXR0ZXJuOiAvXFxiKD86cGFzc3dvcmR8cGFzc3dkfHB3ZClcXHMqWzo9XVxccypbXCInXT9bXlxcc1wiJ117OCx9W1wiJ10/XFxiL2dpLFxuICAgIHNldmVyaXR5OiAnY3JpdGljYWwnLFxuICAgIGNvbmZpZGVuY2U6IDAuODUsXG4gICAgbWVzc2FnZTogJ0lubGluZSBwYXNzd29yZCBkZXRlY3RlZCcsXG4gICAgY2F0ZWdvcnk6ICdjcmVkZW50aWFsJ1xuICB9LFxuICBcbiAgLy8gPT09IExPQ0FUSU9OID09PVxuICB7XG4gICAgbmFtZTogJ0lQX0FERFJFU1MnLFxuICAgIHBhdHRlcm46IC9cXGIoPzooPzoyNVswLTVdfDJbMC00XVswLTldfFswMV0/WzAtOV1bMC05XT8pXFwuKXszfSg/OjI1WzAtNV18MlswLTRdWzAtOV18WzAxXT9bMC05XVswLTldPylcXGIvZyxcbiAgICBzZXZlcml0eTogJ2xvdycsXG4gICAgY29uZmlkZW5jZTogMC45LFxuICAgIG1lc3NhZ2U6ICdJUCBhZGRyZXNzIGRldGVjdGVkJyxcbiAgICBjYXRlZ29yeTogJ2xvY2F0aW9uJ1xuICB9LFxuICB7XG4gICAgbmFtZTogJ0lQVjZfQUREUkVTUycsXG4gICAgcGF0dGVybjogL1xcYig/OlswLTlhLWZBLUZdezEsNH06KXs3fVswLTlhLWZBLUZdezEsNH1cXGIvZyxcbiAgICBzZXZlcml0eTogJ2xvdycsXG4gICAgY29uZmlkZW5jZTogMC45LFxuICAgIG1lc3NhZ2U6ICdJUHY2IGFkZHJlc3MgZGV0ZWN0ZWQnLFxuICAgIGNhdGVnb3J5OiAnbG9jYXRpb24nXG4gIH0sXG4gIHtcbiAgICBuYW1lOiAnTUFDX0FERFJFU1MnLFxuICAgIHBhdHRlcm46IC9cXGIoWzAtOUEtRmEtZl17Mn1bOi1dKXs1fShbMC05QS1GYS1mXXsyfSlcXGIvZyxcbiAgICBzZXZlcml0eTogJ2xvdycsXG4gICAgY29uZmlkZW5jZTogMC45LFxuICAgIG1lc3NhZ2U6ICdNQUMgYWRkcmVzcyBkZXRlY3RlZCcsXG4gICAgY2F0ZWdvcnk6ICdsb2NhdGlvbidcbiAgfSxcbiAge1xuICAgIG5hbWU6ICdVU19BRERSRVNTJyxcbiAgICBwYXR0ZXJuOiAvXFxiXFxkezEsNX1cXHMrW1xcd1xcc10rKD86c3RyZWV0fHN0fGF2ZW51ZXxhdmV8cm9hZHxyZHxib3VsZXZhcmR8Ymx2ZHxkcml2ZXxkcnxsYW5lfGxufGNvdXJ0fGN0KVxcYi9naSxcbiAgICBzZXZlcml0eTogJ21lZGl1bScsXG4gICAgY29uZmlkZW5jZTogMC42LFxuICAgIG1lc3NhZ2U6ICdVUyBzdHJlZXQgYWRkcmVzcyBkZXRlY3RlZCcsXG4gICAgY2F0ZWdvcnk6ICdsb2NhdGlvbidcbiAgfSxcbiAge1xuICAgIG5hbWU6ICdaSVBfQ09ERScsXG4gICAgcGF0dGVybjogL1xcYlxcZHs1fSg/Oi1cXGR7NH0pP1xcYi9nLFxuICAgIHNldmVyaXR5OiAnbG93JyxcbiAgICBjb25maWRlbmNlOiAwLjUsXG4gICAgbWVzc2FnZTogJ1VTIFpJUCBjb2RlIGRldGVjdGVkJyxcbiAgICBjYXRlZ29yeTogJ2xvY2F0aW9uJ1xuICB9LFxuICBcbiAgLy8gPT09IEhFQUxUSCA9PT1cbiAge1xuICAgIG5hbWU6ICdNRURJQ0FMX1JFQ09SRCcsXG4gICAgcGF0dGVybjogL1xcYig/Om1ybnxtZWRpY2FsXFxzK3JlY29yZClbXFxzIzpdKlxcZHs2LDEyfVxcYi9naSxcbiAgICBzZXZlcml0eTogJ2NyaXRpY2FsJyxcbiAgICBjb25maWRlbmNlOiAwLjgsXG4gICAgbWVzc2FnZTogJ01lZGljYWwgcmVjb3JkIG51bWJlciBkZXRlY3RlZCcsXG4gICAgY2F0ZWdvcnk6ICdoZWFsdGgnXG4gIH1cbl07XG5cbi8qKlxuICogQ2hlY2sgZm9yIFBJSSBpbiBjb250ZW50XG4gKiBAcGFyYW0gY29udGVudCAtIFRoZSBjb250ZW50IHRvIHNjYW5cbiAqIEByZXR1cm5zIEFycmF5IG9mIGZpbmRpbmdzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjaGVja1BJSShjb250ZW50OiBzdHJpbmcpOiBGaW5kaW5nW10ge1xuICBjb25zdCBmaW5kaW5nczogRmluZGluZ1tdID0gW107XG4gIGNvbnN0IGZvdW5kVHlwZXMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgXG4gIGZvciAoY29uc3QgcGlpUGF0dGVybiBvZiBQSUlfUEFUVEVSTlMpIHtcbiAgICAvLyBSZXNldCBsYXN0SW5kZXhcbiAgICBwaWlQYXR0ZXJuLnBhdHRlcm4ubGFzdEluZGV4ID0gMDtcbiAgICBjb25zdCBtYXRjaGVzID0gQXJyYXkuZnJvbShjb250ZW50Lm1hdGNoQWxsKHBpaVBhdHRlcm4ucGF0dGVybikpO1xuICAgIFxuICAgIGZvciAoY29uc3QgbWF0Y2ggb2YgbWF0Y2hlcykge1xuICAgICAgLy8gU2tpcCBpZiB3ZSBhbHJlYWR5IGZvdW5kIHRoaXMgdHlwZSAoYXZvaWQgc3BhbSlcbiAgICAgIGlmIChmb3VuZFR5cGVzLmhhcyhwaWlQYXR0ZXJuLm5hbWUpKSBjb250aW51ZTtcbiAgICAgIFxuICAgICAgLy8gU2tpcCBpZiBsaWtlbHkgZmFsc2UgcG9zaXRpdmVcbiAgICAgIGlmIChpc0xpa2VseUZhbHNlUG9zaXRpdmUoY29udGVudCwgbWF0Y2hbMF0sIHBpaVBhdHRlcm4ubmFtZSkpIGNvbnRpbnVlO1xuICAgICAgXG4gICAgICBmb3VuZFR5cGVzLmFkZChwaWlQYXR0ZXJuLm5hbWUpO1xuICAgICAgXG4gICAgICBmaW5kaW5ncy5wdXNoKHtcbiAgICAgICAgaWQ6IGBQSUlfJHtwaWlQYXR0ZXJuLm5hbWV9YCxcbiAgICAgICAgY2F0ZWdvcnk6ICdwcml2YWN5JyxcbiAgICAgICAgc2V2ZXJpdHk6IHBpaVBhdHRlcm4uc2V2ZXJpdHksXG4gICAgICAgIHN1cmZhY2U6ICdvdXRwdXQnLFxuICAgICAgICBtZXNzYWdlOiBwaWlQYXR0ZXJuLm1lc3NhZ2UsXG4gICAgICAgIHJlY29tbWVuZGF0aW9uOiBgUmVtb3ZlIG9yIHJlZGFjdCAke3BpaVBhdHRlcm4ubmFtZS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL18vZywgJyAnKX0gYmVmb3JlIHVzZS5gLFxuICAgICAgICBcbiAgICAgICAgZXZpZGVuY2U6IHtcbiAgICAgICAgICB0ZXh0U2FtcGxlOiByZWRhY3RTYW1wbGUobWF0Y2hbMF0pLFxuICAgICAgICAgIHBhdHRlcm46IHBpaVBhdHRlcm4ubmFtZSxcbiAgICAgICAgICBjb250ZXh0OiBleHRyYWN0Q29udGV4dChjb250ZW50LCBtYXRjaC5pbmRleCB8fCAwLCAzMClcbiAgICAgICAgfSxcbiAgICAgICAgXG4gICAgICAgIGNvbmZpZGVuY2U6IGNhbGN1bGF0ZUNvbmZpZGVuY2UocGlpUGF0dGVybi5jb25maWRlbmNlLCBtYXRjaFswXSksXG4gICAgICAgIGxpbWl0YXRpb25zOiBMSU1JVEFUSU9OUyxcbiAgICAgICAgbWV0aG9kb2xvZ3k6IE1FVEhPRE9MT0dZLFxuICAgICAgICBtZXRhZGF0YToge1xuICAgICAgICAgIHBpaVR5cGU6IHBpaVBhdHRlcm4ubmFtZSxcbiAgICAgICAgICBwaWlDYXRlZ29yeTogcGlpUGF0dGVybi5jYXRlZ29yeVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH1cbiAgXG4gIHJldHVybiBmaW5kaW5ncztcbn1cblxuLyoqXG4gKiBSZWRhY3QgYWxsIFBJSSBmcm9tIGNvbnRlbnRcbiAqIEBwYXJhbSBjb250ZW50IC0gVGhlIGNvbnRlbnQgdG8gcmVkYWN0XG4gKiBAcGFyYW0gcmVwbGFjZW1lbnQgLSBSZXBsYWNlbWVudCBzdHJpbmcgKGRlZmF1bHQ6IFtSRURBQ1RFRF0pXG4gKiBAcmV0dXJucyBSZWRhY3RlZCBjb250ZW50IGFuZCBsaXN0IG9mIHJlZGFjdGlvbnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlZGFjdFBJSShjb250ZW50OiBzdHJpbmcsIHJlcGxhY2VtZW50ID0gJ1tSRURBQ1RFRF0nKToge1xuICByZWRhY3RlZDogc3RyaW5nO1xuICByZWRhY3Rpb25zOiBBcnJheTx7IHR5cGU6IHN0cmluZzsgb3JpZ2luYWw6IHN0cmluZzsgcG9zaXRpb246IG51bWJlciB9PjtcbiAgcGlpQ291bnQ6IG51bWJlcjtcbn0ge1xuICBsZXQgcmVkYWN0ZWQgPSBjb250ZW50O1xuICBjb25zdCByZWRhY3Rpb25zOiBBcnJheTx7IHR5cGU6IHN0cmluZzsgb3JpZ2luYWw6IHN0cmluZzsgcG9zaXRpb246IG51bWJlciB9PiA9IFtdO1xuICBcbiAgZm9yIChjb25zdCBwaWlQYXR0ZXJuIG9mIFBJSV9QQVRURVJOUykge1xuICAgIHBpaVBhdHRlcm4ucGF0dGVybi5sYXN0SW5kZXggPSAwO1xuICAgIGNvbnN0IG1hdGNoZXMgPSBBcnJheS5mcm9tKGNvbnRlbnQubWF0Y2hBbGwocGlpUGF0dGVybi5wYXR0ZXJuKSk7XG4gICAgXG4gICAgZm9yIChjb25zdCBtYXRjaCBvZiBtYXRjaGVzKSB7XG4gICAgICBpZiAoIWlzTGlrZWx5RmFsc2VQb3NpdGl2ZShjb250ZW50LCBtYXRjaFswXSwgcGlpUGF0dGVybi5uYW1lKSkge1xuICAgICAgICByZWRhY3Rpb25zLnB1c2goe1xuICAgICAgICAgIHR5cGU6IHBpaVBhdHRlcm4ubmFtZSxcbiAgICAgICAgICBvcmlnaW5hbDogcmVkYWN0U2FtcGxlKG1hdGNoWzBdKSxcbiAgICAgICAgICBwb3NpdGlvbjogbWF0Y2guaW5kZXggfHwgMFxuICAgICAgICB9KTtcbiAgICAgICAgcmVkYWN0ZWQgPSByZWRhY3RlZC5yZXBsYWNlKG1hdGNoWzBdLCByZXBsYWNlbWVudCk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIFxuICByZXR1cm4ge1xuICAgIHJlZGFjdGVkLFxuICAgIHJlZGFjdGlvbnMsXG4gICAgcGlpQ291bnQ6IHJlZGFjdGlvbnMubGVuZ3RoXG4gIH07XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgY29udGVudCBjb250YWlucyBhbnkgUElJXG4gKiBAcGFyYW0gY29udGVudCAtIFRoZSBjb250ZW50IHRvIGNoZWNrXG4gKiBAcmV0dXJucyB0cnVlIGlmIFBJSSBkZXRlY3RlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gY29udGFpbnNQSUkoY29udGVudDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiBjaGVja1BJSShjb250ZW50KS5sZW5ndGggPiAwO1xufVxuXG4vKipcbiAqIEdldCBQSUkgcmlzayBzY29yZSAoMC0xKVxuICogQHBhcmFtIGNvbnRlbnQgLSBUaGUgY29udGVudCB0byBzY29yZVxuICogQHJldHVybnMgUmlzayBzY29yZVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UElJUmlza1Njb3JlKGNvbnRlbnQ6IHN0cmluZyk6IG51bWJlciB7XG4gIGNvbnN0IGZpbmRpbmdzID0gY2hlY2tQSUkoY29udGVudCk7XG4gIGlmIChmaW5kaW5ncy5sZW5ndGggPT09IDApIHJldHVybiAwO1xuICBcbiAgY29uc3Qgc2V2ZXJpdHlXZWlnaHRzOiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+ID0ge1xuICAgIGxvdzogMC4yLFxuICAgIG1lZGl1bTogMC40LFxuICAgIGhpZ2g6IDAuNyxcbiAgICBjcml0aWNhbDogMS4wXG4gIH07XG4gIFxuICBsZXQgbWF4U2NvcmUgPSAwO1xuICBmb3IgKGNvbnN0IGZpbmRpbmcgb2YgZmluZGluZ3MpIHtcbiAgICBjb25zdCBzY29yZSA9IHNldmVyaXR5V2VpZ2h0c1tmaW5kaW5nLnNldmVyaXR5XSAqIGZpbmRpbmcuY29uZmlkZW5jZS52YWx1ZTtcbiAgICBtYXhTY29yZSA9IE1hdGgubWF4KG1heFNjb3JlLCBzY29yZSk7XG4gIH1cbiAgXG4gIC8vIEFkZCBwZW5hbHR5IGZvciBtdWx0aXBsZSBQSUkgdHlwZXNcbiAgY29uc3QgdHlwZUJvbnVzID0gTWF0aC5taW4oZmluZGluZ3MubGVuZ3RoICogMC4xLCAwLjMpO1xuICBcbiAgcmV0dXJuIE1hdGgubWluKDEsIG1heFNjb3JlICsgdHlwZUJvbnVzKTtcbn1cblxuLyoqXG4gKiBSZWRhY3Qgc2Vuc2l0aXZlIHBhcnRzIG9mIHNhbXBsZSBmb3IgZGlzcGxheVxuICovXG5mdW5jdGlvbiByZWRhY3RTYW1wbGUodGV4dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgaWYgKHRleHQubGVuZ3RoIDw9IDgpIHtcbiAgICByZXR1cm4gdGV4dC5zdWJzdHJpbmcoMCwgMikgKyAnKioqJyArIHRleHQuc3Vic3RyaW5nKHRleHQubGVuZ3RoIC0gMik7XG4gIH1cbiAgXG4gIGNvbnN0IHZpc2libGUgPSBNYXRoLm1pbig0LCBNYXRoLmZsb29yKHRleHQubGVuZ3RoIC8gNCkpO1xuICByZXR1cm4gdGV4dC5zdWJzdHJpbmcoMCwgdmlzaWJsZSkgKyAnKioqJyArIHRleHQuc3Vic3RyaW5nKHRleHQubGVuZ3RoIC0gdmlzaWJsZSk7XG59XG5cbi8qKlxuICogQ2FsY3VsYXRlIGNvbmZpZGVuY2Ugc2NvcmVcbiAqL1xuZnVuY3Rpb24gY2FsY3VsYXRlQ29uZmlkZW5jZShiYXNlQ29uZmlkZW5jZTogbnVtYmVyLCBtYXRjaDogc3RyaW5nKTogQ29uZmlkZW5jZVNjb3JlIHtcbiAgbGV0IHZhbHVlID0gYmFzZUNvbmZpZGVuY2U7XG4gIFxuICAvLyBBZGp1c3QgYmFzZWQgb24gbWF0Y2ggY2hhcmFjdGVyaXN0aWNzXG4gIGlmIChtYXRjaC5sZW5ndGggPiAyMCkgdmFsdWUgKz0gMC4wNTtcbiAgaWYgKC9eW0EtWl0vLnRlc3QobWF0Y2gpKSB2YWx1ZSAtPSAwLjA1OyAvLyBNaWdodCBiZSBhIG5hbWUsIG5vdCBQSUlcbiAgXG4gIHZhbHVlID0gTWF0aC5tYXgoMC41LCBNYXRoLm1pbigwLjk1LCB2YWx1ZSkpO1xuICBcbiAgcmV0dXJuIHtcbiAgICB2YWx1ZSxcbiAgICBpbnRlcnZhbDogW01hdGgubWF4KDAsIHZhbHVlIC0gMC4xKSwgTWF0aC5taW4oMSwgdmFsdWUgKyAwLjEpXSxcbiAgICBtZXRob2Q6ICdlbXBpcmljYWwnLFxuICAgIGZhY3RvcnM6IHtcbiAgICAgIHBhdHRlcm5TdHJlbmd0aDogYmFzZUNvbmZpZGVuY2VcbiAgICB9XG4gIH07XG59XG5cbi8qKlxuICogQ2hlY2sgZm9yIGZhbHNlIHBvc2l0aXZlc1xuICovXG5mdW5jdGlvbiBpc0xpa2VseUZhbHNlUG9zaXRpdmUoXG4gIGZ1bGxUZXh0OiBzdHJpbmcsIFxuICBtYXRjaDogc3RyaW5nLCBcbiAgdHlwZTogc3RyaW5nXG4pOiBib29sZWFuIHtcbiAgLy8gRXhhbXBsZS9wbGFjZWhvbGRlciBpbmRpY2F0b3JzXG4gIGNvbnN0IHBsYWNlaG9sZGVycyA9IFtcbiAgICAvZXhhbXBsZS9pLFxuICAgIC9wbGFjZWhvbGRlci9pLFxuICAgIC90ZXN0L2ksXG4gICAgL3NhbXBsZS9pLFxuICAgIC9kdW1teS9pLFxuICAgIC9mYWtlL2ksXG4gICAgL2RlbW8vaSxcbiAgICAveHh4L2lcbiAgXTtcbiAgXG4gIGNvbnN0IGNvbnRleHQgPSBmdWxsVGV4dC5zdWJzdHJpbmcoXG4gICAgTWF0aC5tYXgoMCwgZnVsbFRleHQuaW5kZXhPZihtYXRjaCkgLSA1MCksXG4gICAgZnVsbFRleHQuaW5kZXhPZihtYXRjaCkgKyBtYXRjaC5sZW5ndGggKyA1MFxuICApO1xuICBcbiAgaWYgKHBsYWNlaG9sZGVycy5zb21lKHAgPT4gcC50ZXN0KGNvbnRleHQpKSkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIFxuICAvLyBTU04gZmFsc2UgcG9zaXRpdmVzXG4gIGlmICh0eXBlID09PSAnU1NOJykge1xuICAgIC8vIENoZWNrIGlmIGl0J3MgYSBkYXRlIGZvcm1hdFxuICAgIGlmICgvXFxkezJ9Wy0vXVxcZHsyfVstL11cXGR7NH0vLnRlc3QobWF0Y2gpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgLy8gQ2hlY2sgaWYgcHJlY2VkZWQgYnkgZGF0ZS1saWtlIGNvbnRleHRcbiAgICBpZiAoL2RhdGV8dGltZXx5ZWFyfG1vbnRofGRheS9pLnRlc3QoY29udGV4dCkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfVxuICBcbiAgLy8gUGhvbmUgZmFsc2UgcG9zaXRpdmVzXG4gIGlmICh0eXBlID09PSAnUEhPTkVfVVMnKSB7XG4gICAgLy8gQ2hlY2sgaWYgaXQncyBhIHppcCBjb2RlIG9yIG90aGVyIG51bWJlclxuICAgIGlmICgvemlwfGNvZGV8aWR8bnVtYmVyL2kudGVzdChjb250ZXh0KSAmJiAhL3Bob25lfGNhbGx8bW9iaWxlfGNlbGwvaS50ZXN0KGNvbnRleHQpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH1cbiAgXG4gIC8vIFpJUCBjb2RlIC0gdG9vIG1hbnkgZmFsc2UgcG9zaXRpdmVzLCByZXF1aXJlIGNvbnRleHRcbiAgaWYgKHR5cGUgPT09ICdaSVBfQ09ERScpIHtcbiAgICBpZiAoIS96aXB8cG9zdGFsfGFkZHJlc3MvaS50ZXN0KGNvbnRleHQpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH1cbiAgXG4gIC8vIEFXUyBTZWNyZXQgLSBoaWdoIGZhbHNlIHBvc2l0aXZlIHJhdGVcbiAgaWYgKHR5cGUgPT09ICdBV1NfU0VDUkVUJykge1xuICAgIC8vIE9ubHkgZmxhZyBpZiBuZWFyIEFXUyBjb250ZXh0XG4gICAgaWYgKCEvYXdzfGFtYXpvbnxzZWNyZXR8a2V5L2kudGVzdChjb250ZXh0KSkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICB9XG4gIFxuICByZXR1cm4gZmFsc2U7XG59XG4iXX0=