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.

290 lines 30.5 kB
"use strict"; /** * Audit Trail System * * Compliance-ready audit logging for verification operations * * @module logging/audit */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.AuditLogger = void 0; exports.getAuditLogger = getAuditLogger; exports.setAuditLogger = setAuditLogger; const fs = __importStar(require("fs")); const path = __importStar(require("path")); const os = __importStar(require("os")); const crypto = __importStar(require("crypto")); /** * Default audit configuration */ const DEFAULT_AUDIT_CONFIG = { enabled: true, auditDir: path.join(os.homedir(), '.llmverify', 'audit'), includeContentHash: true, includeUserInfo: false, maxFileSize: 10 * 1024 * 1024, // 10MB maxFiles: 50 // Keep more audit files }; /** * Audit logger class */ class AuditLogger { constructor(config) { this.config = { ...DEFAULT_AUDIT_CONFIG, ...config }; this.ensureAuditDirectory(); } /** * Ensure audit directory exists */ ensureAuditDirectory() { if (this.config.enabled && this.config.auditDir) { try { fs.mkdirSync(this.config.auditDir, { recursive: true }); } catch (error) { console.error('Failed to create audit directory:', error); this.config.enabled = false; } } } /** * Get audit file path */ getAuditFilePath() { const date = new Date().toISOString().split('T')[0]; return path.join(this.config.auditDir, `audit-${date}.jsonl`); } /** * Generate content hash */ hashContent(content) { return crypto.createHash('sha256').update(content).digest('hex').substring(0, 16); } /** * Write audit entry */ log(entry) { if (!this.config.enabled) return; try { const fullEntry = { timestamp: new Date().toISOString(), ...entry }; const auditFile = this.getAuditFilePath(); const line = JSON.stringify(fullEntry) + '\n'; fs.appendFileSync(auditFile, line, 'utf-8'); // Rotate if needed this.rotateIfNeeded(auditFile); } catch (error) { if (process.env.NODE_ENV === 'development') { console.error('Failed to write audit entry:', error); } } } /** * Log verification operation */ logVerification(params) { this.log({ requestId: params.requestId, operation: 'verify', input: { contentLength: params.content.length, contentHash: this.config.includeContentHash ? this.hashContent(params.content) : '', hasPrompt: !!params.prompt }, output: { riskLevel: params.riskLevel, findingsCount: params.findingsCount, blocked: params.blocked }, metadata: { version: require('../../package.json').version, duration: params.duration, enginesUsed: params.enginesUsed, configTier: params.configTier }, user: this.config.includeUserInfo ? { id: params.userId, ip: params.userIp } : undefined }); } /** * Rotate audit files */ rotateIfNeeded(auditFile) { try { const stats = fs.statSync(auditFile); if (stats.size > this.config.maxFileSize) { const timestamp = Date.now(); const rotatedFile = auditFile.replace('.jsonl', `.${timestamp}.jsonl`); fs.renameSync(auditFile, rotatedFile); this.cleanupOldAudits(); } } catch (error) { // Ignore rotation errors } } /** * Clean up old audit files */ cleanupOldAudits() { if (!this.config.auditDir) return; try { const files = fs.readdirSync(this.config.auditDir) .filter(f => f.startsWith('audit-') && f.endsWith('.jsonl')) .map(f => ({ name: f, path: path.join(this.config.auditDir, f), time: fs.statSync(path.join(this.config.auditDir, f)).mtime.getTime() })) .sort((a, b) => b.time - a.time); if (files.length > this.config.maxFiles) { files.slice(this.config.maxFiles).forEach(file => { try { fs.unlinkSync(file.path); } catch (error) { // Ignore deletion errors } }); } } catch (error) { // Ignore cleanup errors } } /** * Read audit entries */ readAudit(date) { if (!this.config.auditDir) return []; const dateStr = date || new Date().toISOString().split('T')[0]; const auditFile = path.join(this.config.auditDir, `audit-${dateStr}.jsonl`); if (!fs.existsSync(auditFile)) return []; try { const content = fs.readFileSync(auditFile, 'utf-8'); return content .split('\n') .filter(line => line.trim()) .map(line => JSON.parse(line)); } catch (error) { console.error('Failed to read audit:', error); return []; } } /** * Get audit statistics */ getStats(date) { const entries = this.readAudit(date); const stats = { totalOperations: entries.length, byOperation: {}, blockedCount: 0, avgDuration: 0, riskDistribution: {} }; let totalDuration = 0; entries.forEach(entry => { // Count by operation stats.byOperation[entry.operation] = (stats.byOperation[entry.operation] || 0) + 1; // Count blocked if (entry.output.blocked) stats.blockedCount++; // Sum duration totalDuration += entry.metadata.duration; // Risk distribution const risk = entry.output.riskLevel; stats.riskDistribution[risk] = (stats.riskDistribution[risk] || 0) + 1; }); if (entries.length > 0) { stats.avgDuration = totalDuration / entries.length; } return stats; } /** * Export audit trail for compliance */ exportAuditTrail(startDate, endDate, outputPath) { const start = new Date(startDate); const end = new Date(endDate); const allEntries = []; // Collect all entries in date range for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) { const dateStr = d.toISOString().split('T')[0]; const entries = this.readAudit(dateStr); allEntries.push(...entries); } // Write to output file const report = { exportDate: new Date().toISOString(), dateRange: { start: startDate, end: endDate }, totalEntries: allEntries.length, entries: allEntries }; fs.writeFileSync(outputPath, JSON.stringify(report, null, 2), 'utf-8'); } } exports.AuditLogger = AuditLogger; /** * Global audit logger */ let globalAuditLogger = null; /** * Get global audit logger */ function getAuditLogger(config) { if (!globalAuditLogger) { globalAuditLogger = new AuditLogger(config); } return globalAuditLogger; } /** * Set global audit logger */ function setAuditLogger(logger) { globalAuditLogger = logger; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXVkaXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbG9nZ2luZy9hdWRpdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7OztHQU1HOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUErVEgsd0NBS0M7QUFLRCx3Q0FFQztBQXpVRCx1Q0FBeUI7QUFDekIsMkNBQTZCO0FBQzdCLHVDQUF5QjtBQUN6QiwrQ0FBaUM7QUEyQ2pDOztHQUVHO0FBQ0gsTUFBTSxvQkFBb0IsR0FBZ0I7SUFDeEMsT0FBTyxFQUFFLElBQUk7SUFDYixRQUFRLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLEVBQUUsWUFBWSxFQUFFLE9BQU8sQ0FBQztJQUN4RCxrQkFBa0IsRUFBRSxJQUFJO0lBQ3hCLGVBQWUsRUFBRSxLQUFLO0lBQ3RCLFdBQVcsRUFBRSxFQUFFLEdBQUcsSUFBSSxHQUFHLElBQUksRUFBRSxPQUFPO0lBQ3RDLFFBQVEsRUFBRSxFQUFFLENBQUMsd0JBQXdCO0NBQ3RDLENBQUM7QUFFRjs7R0FFRztBQUNILE1BQWEsV0FBVztJQUd0QixZQUFZLE1BQTZCO1FBQ3ZDLElBQUksQ0FBQyxNQUFNLEdBQUcsRUFBRSxHQUFHLG9CQUFvQixFQUFFLEdBQUcsTUFBTSxFQUFFLENBQUM7UUFDckQsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7SUFDOUIsQ0FBQztJQUVEOztPQUVHO0lBQ0ssb0JBQW9CO1FBQzFCLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNoRCxJQUFJLENBQUM7Z0JBQ0gsRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1lBQzFELENBQUM7WUFBQyxPQUFPLEtBQUss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RSxDQUFDO1lBQ25FLE1BQU0sT0FBTyxHQUFHLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDOUMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUN4QyxVQUFVLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxDQUFDLENBQUM7UUFDOUIsQ0FBQztRQUVELHVCQUF1QjtRQUN2QixNQUFNLE1BQU0sR0FBRztZQUNiLFVBQVUsRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRTtZQUNwQyxTQUFTLEVBQUUsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUU7WUFDN0MsWUFBWSxFQUFFLFVBQVUsQ0FBQyxNQUFNO1lBQy9CLE9BQU8sRUFBRSxVQUFVO1NBQ3BCLENBQUM7UUFFRixFQUFFLENBQUMsYUFBYSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDekUsQ0FBQztDQUNGO0FBdFBELGtDQXNQQztBQUVEOztHQUVHO0FBQ0gsSUFBSSxpQkFBaUIsR0FBdUIsSUFBSSxDQUFDO0FBRWpEOztHQUVHO0FBQ0gsU0FBZ0IsY0FBYyxDQUFDLE1BQTZCO0lBQzFELElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ3ZCLGlCQUFpQixHQUFHLElBQUksV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzlDLENBQUM7SUFDRCxPQUFPLGlCQUFpQixDQUFDO0FBQzNCLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLGNBQWMsQ0FBQyxNQUFtQjtJQUNoRCxpQkFBaUIsR0FBRyxNQUFNLENBQUM7QUFDN0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQXVkaXQgVHJhaWwgU3lzdGVtXG4gKiBcbiAqIENvbXBsaWFuY2UtcmVhZHkgYXVkaXQgbG9nZ2luZyBmb3IgdmVyaWZpY2F0aW9uIG9wZXJhdGlvbnNcbiAqIFxuICogQG1vZHVsZSBsb2dnaW5nL2F1ZGl0XG4gKi9cblxuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCAqIGFzIG9zIGZyb20gJ29zJztcbmltcG9ydCAqIGFzIGNyeXB0byBmcm9tICdjcnlwdG8nO1xuXG4vKipcbiAqIEF1ZGl0IGVudHJ5IHN0cnVjdHVyZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIEF1ZGl0RW50cnkge1xuICB0aW1lc3RhbXA6IHN0cmluZztcbiAgcmVxdWVzdElkOiBzdHJpbmc7XG4gIG9wZXJhdGlvbjogJ3ZlcmlmeScgfCAnY2xhc3NpZnknIHwgJ2NoZWNrLWlucHV0JyB8ICdjaGVjay1waWknIHwgJ3BsdWdpbi1leGVjdXRlJztcbiAgaW5wdXQ6IHtcbiAgICBjb250ZW50TGVuZ3RoOiBudW1iZXI7XG4gICAgY29udGVudEhhc2g6IHN0cmluZztcbiAgICBoYXNQcm9tcHQ6IGJvb2xlYW47XG4gIH07XG4gIG91dHB1dDoge1xuICAgIHJpc2tMZXZlbDogc3RyaW5nO1xuICAgIGZpbmRpbmdzQ291bnQ6IG51bWJlcjtcbiAgICBibG9ja2VkOiBib29sZWFuO1xuICB9O1xuICBtZXRhZGF0YToge1xuICAgIHZlcnNpb246IHN0cmluZztcbiAgICBkdXJhdGlvbjogbnVtYmVyO1xuICAgIGVuZ2luZXNVc2VkOiBzdHJpbmdbXTtcbiAgICBjb25maWdUaWVyOiBzdHJpbmc7XG4gIH07XG4gIHVzZXI/OiB7XG4gICAgaWQ/OiBzdHJpbmc7XG4gICAgaXA/OiBzdHJpbmc7XG4gIH07XG59XG5cbi8qKlxuICogQXVkaXQgY29uZmlndXJhdGlvblxuICovXG5leHBvcnQgaW50ZXJmYWNlIEF1ZGl0Q29uZmlnIHtcbiAgZW5hYmxlZDogYm9vbGVhbjtcbiAgYXVkaXREaXI/OiBzdHJpbmc7XG4gIGluY2x1ZGVDb250ZW50SGFzaD86IGJvb2xlYW47XG4gIGluY2x1ZGVVc2VySW5mbz86IGJvb2xlYW47XG4gIG1heEZpbGVTaXplPzogbnVtYmVyO1xuICBtYXhGaWxlcz86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBEZWZhdWx0IGF1ZGl0IGNvbmZpZ3VyYXRpb25cbiAqL1xuY29uc3QgREVGQVVMVF9BVURJVF9DT05GSUc6IEF1ZGl0Q29uZmlnID0ge1xuICBlbmFibGVkOiB0cnVlLFxuICBhdWRpdERpcjogcGF0aC5qb2luKG9zLmhvbWVkaXIoKSwgJy5sbG12ZXJpZnknLCAnYXVkaXQnKSxcbiAgaW5jbHVkZUNvbnRlbnRIYXNoOiB0cnVlLFxuICBpbmNsdWRlVXNlckluZm86IGZhbHNlLFxuICBtYXhGaWxlU2l6ZTogMTAgKiAxMDI0ICogMTAyNCwgLy8gMTBNQlxuICBtYXhGaWxlczogNTAgLy8gS2VlcCBtb3JlIGF1ZGl0IGZpbGVzXG59O1xuXG4vKipcbiAqIEF1ZGl0IGxvZ2dlciBjbGFzc1xuICovXG5leHBvcnQgY2xhc3MgQXVkaXRMb2dnZXIge1xuICBwcml2YXRlIGNvbmZpZzogQXVkaXRDb25maWc7XG4gIFxuICBjb25zdHJ1Y3Rvcihjb25maWc/OiBQYXJ0aWFsPEF1ZGl0Q29uZmlnPikge1xuICAgIHRoaXMuY29uZmlnID0geyAuLi5ERUZBVUxUX0FVRElUX0NPTkZJRywgLi4uY29uZmlnIH07XG4gICAgdGhpcy5lbnN1cmVBdWRpdERpcmVjdG9yeSgpO1xuICB9XG4gIFxuICAvKipcbiAgICogRW5zdXJlIGF1ZGl0IGRpcmVjdG9yeSBleGlzdHNcbiAgICovXG4gIHByaXZhdGUgZW5zdXJlQXVkaXREaXJlY3RvcnkoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuY29uZmlnLmVuYWJsZWQgJiYgdGhpcy5jb25maWcuYXVkaXREaXIpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGZzLm1rZGlyU3luYyh0aGlzLmNvbmZpZy5hdWRpdERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKCdGYWlsZWQgdG8gY3JlYXRlIGF1ZGl0IGRpcmVjdG9yeTonLCBlcnJvcik7XG4gICAgICAgIHRoaXMuY29uZmlnLmVuYWJsZWQgPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgYXVkaXQgZmlsZSBwYXRoXG4gICAqL1xuICBwcml2YXRlIGdldEF1ZGl0RmlsZVBhdGgoKTogc3RyaW5nIHtcbiAgICBjb25zdCBkYXRlID0gbmV3IERhdGUoKS50b0lTT1N0cmluZygpLnNwbGl0KCdUJylbMF07XG4gICAgcmV0dXJuIHBhdGguam9pbih0aGlzLmNvbmZpZy5hdWRpdERpciEsIGBhdWRpdC0ke2RhdGV9Lmpzb25sYCk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBjb250ZW50IGhhc2hcbiAgICovXG4gIHByaXZhdGUgaGFzaENvbnRlbnQoY29udGVudDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gY3J5cHRvLmNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShjb250ZW50KS5kaWdlc3QoJ2hleCcpLnN1YnN0cmluZygwLCAxNik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBXcml0ZSBhdWRpdCBlbnRyeVxuICAgKi9cbiAgcHVibGljIGxvZyhlbnRyeTogT21pdDxBdWRpdEVudHJ5LCAndGltZXN0YW1wJz4pOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuY29uZmlnLmVuYWJsZWQpIHJldHVybjtcbiAgICBcbiAgICB0cnkge1xuICAgICAgY29uc3QgZnVsbEVudHJ5OiBBdWRpdEVudHJ5ID0ge1xuICAgICAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgICAgLi4uZW50cnlcbiAgICAgIH07XG4gICAgICBcbiAgICAgIGNvbnN0IGF1ZGl0RmlsZSA9IHRoaXMuZ2V0QXVkaXRGaWxlUGF0aCgpO1xuICAgICAgY29uc3QgbGluZSA9IEpTT04uc3RyaW5naWZ5KGZ1bGxFbnRyeSkgKyAnXFxuJztcbiAgICAgIFxuICAgICAgZnMuYXBwZW5kRmlsZVN5bmMoYXVkaXRGaWxlLCBsaW5lLCAndXRmLTgnKTtcbiAgICAgIFxuICAgICAgLy8gUm90YXRlIGlmIG5lZWRlZFxuICAgICAgdGhpcy5yb3RhdGVJZk5lZWRlZChhdWRpdEZpbGUpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09ICdkZXZlbG9wbWVudCcpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcignRmFpbGVkIHRvIHdyaXRlIGF1ZGl0IGVudHJ5OicsIGVycm9yKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBMb2cgdmVyaWZpY2F0aW9uIG9wZXJhdGlvblxuICAgKi9cbiAgcHVibGljIGxvZ1ZlcmlmaWNhdGlvbihwYXJhbXM6IHtcbiAgICByZXF1ZXN0SWQ6IHN0cmluZztcbiAgICBjb250ZW50OiBzdHJpbmc7XG4gICAgcHJvbXB0Pzogc3RyaW5nO1xuICAgIHJpc2tMZXZlbDogc3RyaW5nO1xuICAgIGZpbmRpbmdzQ291bnQ6IG51bWJlcjtcbiAgICBibG9ja2VkOiBib29sZWFuO1xuICAgIGR1cmF0aW9uOiBudW1iZXI7XG4gICAgZW5naW5lc1VzZWQ6IHN0cmluZ1tdO1xuICAgIGNvbmZpZ1RpZXI6IHN0cmluZztcbiAgICB1c2VySWQ/OiBzdHJpbmc7XG4gICAgdXNlcklwPzogc3RyaW5nO1xuICB9KTogdm9pZCB7XG4gICAgdGhpcy5sb2coe1xuICAgICAgcmVxdWVzdElkOiBwYXJhbXMucmVxdWVzdElkLFxuICAgICAgb3BlcmF0aW9uOiAndmVyaWZ5JyxcbiAgICAgIGlucHV0OiB7XG4gICAgICAgIGNvbnRlbnRMZW5ndGg6IHBhcmFtcy5jb250ZW50Lmxlbmd0aCxcbiAgICAgICAgY29udGVudEhhc2g6IHRoaXMuY29uZmlnLmluY2x1ZGVDb250ZW50SGFzaCA/IHRoaXMuaGFzaENvbnRlbnQocGFyYW1zLmNvbnRlbnQpIDogJycsXG4gICAgICAgIGhhc1Byb21wdDogISFwYXJhbXMucHJvbXB0XG4gICAgICB9LFxuICAgICAgb3V0cHV0OiB7XG4gICAgICAgIHJpc2tMZXZlbDogcGFyYW1zLnJpc2tMZXZlbCxcbiAgICAgICAgZmluZGluZ3NDb3VudDogcGFyYW1zLmZpbmRpbmdzQ291bnQsXG4gICAgICAgIGJsb2NrZWQ6IHBhcmFtcy5ibG9ja2VkXG4gICAgICB9LFxuICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgdmVyc2lvbjogcmVxdWlyZSgnLi4vLi4vcGFja2FnZS5qc29uJykudmVyc2lvbixcbiAgICAgICAgZHVyYXRpb246IHBhcmFtcy5kdXJhdGlvbixcbiAgICAgICAgZW5naW5lc1VzZWQ6IHBhcmFtcy5lbmdpbmVzVXNlZCxcbiAgICAgICAgY29uZmlnVGllcjogcGFyYW1zLmNvbmZpZ1RpZXJcbiAgICAgIH0sXG4gICAgICB1c2VyOiB0aGlzLmNvbmZpZy5pbmNsdWRlVXNlckluZm8gPyB7XG4gICAgICAgIGlkOiBwYXJhbXMudXNlcklkLFxuICAgICAgICBpcDogcGFyYW1zLnVzZXJJcFxuICAgICAgfSA6IHVuZGVmaW5lZFxuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogUm90YXRlIGF1ZGl0IGZpbGVzXG4gICAqL1xuICBwcml2YXRlIHJvdGF0ZUlmTmVlZGVkKGF1ZGl0RmlsZTogc3RyaW5nKTogdm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHN0YXRzID0gZnMuc3RhdFN5bmMoYXVkaXRGaWxlKTtcbiAgICAgIFxuICAgICAgaWYgKHN0YXRzLnNpemUgPiB0aGlzLmNvbmZpZy5tYXhGaWxlU2l6ZSEpIHtcbiAgICAgICAgY29uc3QgdGltZXN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICAgICAgY29uc3Qgcm90YXRlZEZpbGUgPSBhdWRpdEZpbGUucmVwbGFjZSgnLmpzb25sJywgYC4ke3RpbWVzdGFtcH0uanNvbmxgKTtcbiAgICAgICAgZnMucmVuYW1lU3luYyhhdWRpdEZpbGUsIHJvdGF0ZWRGaWxlKTtcbiAgICAgICAgXG4gICAgICAgIHRoaXMuY2xlYW51cE9sZEF1ZGl0cygpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAvLyBJZ25vcmUgcm90YXRpb24gZXJyb3JzXG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogQ2xlYW4gdXAgb2xkIGF1ZGl0IGZpbGVzXG4gICAqL1xuICBwcml2YXRlIGNsZWFudXBPbGRBdWRpdHMoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmNvbmZpZy5hdWRpdERpcikgcmV0dXJuO1xuICAgIFxuICAgIHRyeSB7XG4gICAgICBjb25zdCBmaWxlcyA9IGZzLnJlYWRkaXJTeW5jKHRoaXMuY29uZmlnLmF1ZGl0RGlyKVxuICAgICAgICAuZmlsdGVyKGYgPT4gZi5zdGFydHNXaXRoKCdhdWRpdC0nKSAmJiBmLmVuZHNXaXRoKCcuanNvbmwnKSlcbiAgICAgICAgLm1hcChmID0+ICh7XG4gICAgICAgICAgbmFtZTogZixcbiAgICAgICAgICBwYXRoOiBwYXRoLmpvaW4odGhpcy5jb25maWcuYXVkaXREaXIhLCBmKSxcbiAgICAgICAgICB0aW1lOiBmcy5zdGF0U3luYyhwYXRoLmpvaW4odGhpcy5jb25maWcuYXVkaXREaXIhLCBmKSkubXRpbWUuZ2V0VGltZSgpXG4gICAgICAgIH0pKVxuICAgICAgICAuc29ydCgoYSwgYikgPT4gYi50aW1lIC0gYS50aW1lKTtcbiAgICAgIFxuICAgICAgaWYgKGZpbGVzLmxlbmd0aCA+IHRoaXMuY29uZmlnLm1heEZpbGVzISkge1xuICAgICAgICBmaWxlcy5zbGljZSh0aGlzLmNvbmZpZy5tYXhGaWxlcyEpLmZvckVhY2goZmlsZSA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGZzLnVubGlua1N5bmMoZmlsZS5wYXRoKTtcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgLy8gSWdub3JlIGRlbGV0aW9uIGVycm9yc1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIC8vIElnbm9yZSBjbGVhbnVwIGVycm9yc1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFJlYWQgYXVkaXQgZW50cmllc1xuICAgKi9cbiAgcHVibGljIHJlYWRBdWRpdChkYXRlPzogc3RyaW5nKTogQXVkaXRFbnRyeVtdIHtcbiAgICBpZiAoIXRoaXMuY29uZmlnLmF1ZGl0RGlyKSByZXR1cm4gW107XG4gICAgXG4gICAgY29uc3QgZGF0ZVN0ciA9IGRhdGUgfHwgbmV3IERhdGUoKS50b0lTT1N0cmluZygpLnNwbGl0KCdUJylbMF07XG4gICAgY29uc3QgYXVkaXRGaWxlID0gcGF0aC5qb2luKHRoaXMuY29uZmlnLmF1ZGl0RGlyLCBgYXVkaXQtJHtkYXRlU3RyfS5qc29ubGApO1xuICAgIFxuICAgIGlmICghZnMuZXhpc3RzU3luYyhhdWRpdEZpbGUpKSByZXR1cm4gW107XG4gICAgXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGNvbnRlbnQgPSBmcy5yZWFkRmlsZVN5bmMoYXVkaXRGaWxlLCAndXRmLTgnKTtcbiAgICAgIHJldHVybiBjb250ZW50XG4gICAgICAgIC5zcGxpdCgnXFxuJylcbiAgICAgICAgLmZpbHRlcihsaW5lID0+IGxpbmUudHJpbSgpKVxuICAgICAgICAubWFwKGxpbmUgPT4gSlNPTi5wYXJzZShsaW5lKSBhcyBBdWRpdEVudHJ5KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRmFpbGVkIHRvIHJlYWQgYXVkaXQ6JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBhdWRpdCBzdGF0aXN0aWNzXG4gICAqL1xuICBwdWJsaWMgZ2V0U3RhdHMoZGF0ZT86IHN0cmluZyk6IHtcbiAgICB0b3RhbE9wZXJhdGlvbnM6IG51bWJlcjtcbiAgICBieU9wZXJhdGlvbjogUmVjb3JkPHN0cmluZywgbnVtYmVyPjtcbiAgICBibG9ja2VkQ291bnQ6IG51bWJlcjtcbiAgICBhdmdEdXJhdGlvbjogbnVtYmVyO1xuICAgIHJpc2tEaXN0cmlidXRpb246IFJlY29yZDxzdHJpbmcsIG51bWJlcj47XG4gIH0ge1xuICAgIGNvbnN0IGVudHJpZXMgPSB0aGlzLnJlYWRBdWRpdChkYXRlKTtcbiAgICBcbiAgICBjb25zdCBzdGF0cyA9IHtcbiAgICAgIHRvdGFsT3BlcmF0aW9uczogZW50cmllcy5sZW5ndGgsXG4gICAgICBieU9wZXJhdGlvbjoge30gYXMgUmVjb3JkPHN0cmluZywgbnVtYmVyPixcbiAgICAgIGJsb2NrZWRDb3VudDogMCxcbiAgICAgIGF2Z0R1cmF0aW9uOiAwLFxuICAgICAgcmlza0Rpc3RyaWJ1dGlvbjoge30gYXMgUmVjb3JkPHN0cmluZywgbnVtYmVyPlxuICAgIH07XG4gICAgXG4gICAgbGV0IHRvdGFsRHVyYXRpb24gPSAwO1xuICAgIFxuICAgIGVudHJpZXMuZm9yRWFjaChlbnRyeSA9PiB7XG4gICAgICAvLyBDb3VudCBieSBvcGVyYXRpb25cbiAgICAgIHN0YXRzLmJ5T3BlcmF0aW9uW2VudHJ5Lm9wZXJhdGlvbl0gPSAoc3RhdHMuYnlPcGVyYXRpb25bZW50cnkub3BlcmF0aW9uXSB8fCAwKSArIDE7XG4gICAgICBcbiAgICAgIC8vIENvdW50IGJsb2NrZWRcbiAgICAgIGlmIChlbnRyeS5vdXRwdXQuYmxvY2tlZCkgc3RhdHMuYmxvY2tlZENvdW50Kys7XG4gICAgICBcbiAgICAgIC8vIFN1bSBkdXJhdGlvblxuICAgICAgdG90YWxEdXJhdGlvbiArPSBlbnRyeS5tZXRhZGF0YS5kdXJhdGlvbjtcbiAgICAgIFxuICAgICAgLy8gUmlzayBkaXN0cmlidXRpb25cbiAgICAgIGNvbnN0IHJpc2sgPSBlbnRyeS5vdXRwdXQucmlza0xldmVsO1xuICAgICAgc3RhdHMucmlza0Rpc3RyaWJ1dGlvbltyaXNrXSA9IChzdGF0cy5yaXNrRGlzdHJpYnV0aW9uW3Jpc2tdIHx8IDApICsgMTtcbiAgICB9KTtcbiAgICBcbiAgICBpZiAoZW50cmllcy5sZW5ndGggPiAwKSB7XG4gICAgICBzdGF0cy5hdmdEdXJhdGlvbiA9IHRvdGFsRHVyYXRpb24gLyBlbnRyaWVzLmxlbmd0aDtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHN0YXRzO1xuICB9XG4gIFxuICAvKipcbiAgICogRXhwb3J0IGF1ZGl0IHRyYWlsIGZvciBjb21wbGlhbmNlXG4gICAqL1xuICBwdWJsaWMgZXhwb3J0QXVkaXRUcmFpbChzdGFydERhdGU6IHN0cmluZywgZW5kRGF0ZTogc3RyaW5nLCBvdXRwdXRQYXRoOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBzdGFydCA9IG5ldyBEYXRlKHN0YXJ0RGF0ZSk7XG4gICAgY29uc3QgZW5kID0gbmV3IERhdGUoZW5kRGF0ZSk7XG4gICAgY29uc3QgYWxsRW50cmllczogQXVkaXRFbnRyeVtdID0gW107XG4gICAgXG4gICAgLy8gQ29sbGVjdCBhbGwgZW50cmllcyBpbiBkYXRlIHJhbmdlXG4gICAgZm9yIChsZXQgZCA9IG5ldyBEYXRlKHN0YXJ0KTsgZCA8PSBlbmQ7IGQuc2V0RGF0ZShkLmdldERhdGUoKSArIDEpKSB7XG4gICAgICBjb25zdCBkYXRlU3RyID0gZC50b0lTT1N0cmluZygpLnNwbGl0KCdUJylbMF07XG4gICAgICBjb25zdCBlbnRyaWVzID0gdGhpcy5yZWFkQXVkaXQoZGF0ZVN0cik7XG4gICAgICBhbGxFbnRyaWVzLnB1c2goLi4uZW50cmllcyk7XG4gICAgfVxuICAgIFxuICAgIC8vIFdyaXRlIHRvIG91dHB1dCBmaWxlXG4gICAgY29uc3QgcmVwb3J0ID0ge1xuICAgICAgZXhwb3J0RGF0ZTogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgZGF0ZVJhbmdlOiB7IHN0YXJ0OiBzdGFydERhdGUsIGVuZDogZW5kRGF0ZSB9LFxuICAgICAgdG90YWxFbnRyaWVzOiBhbGxFbnRyaWVzLmxlbmd0aCxcbiAgICAgIGVudHJpZXM6IGFsbEVudHJpZXNcbiAgICB9O1xuICAgIFxuICAgIGZzLndyaXRlRmlsZVN5bmMob3V0cHV0UGF0aCwgSlNPTi5zdHJpbmdpZnkocmVwb3J0LCBudWxsLCAyKSwgJ3V0Zi04Jyk7XG4gIH1cbn1cblxuLyoqXG4gKiBHbG9iYWwgYXVkaXQgbG9nZ2VyXG4gKi9cbmxldCBnbG9iYWxBdWRpdExvZ2dlcjogQXVkaXRMb2dnZXIgfCBudWxsID0gbnVsbDtcblxuLyoqXG4gKiBHZXQgZ2xvYmFsIGF1ZGl0IGxvZ2dlclxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0QXVkaXRMb2dnZXIoY29uZmlnPzogUGFydGlhbDxBdWRpdENvbmZpZz4pOiBBdWRpdExvZ2dlciB7XG4gIGlmICghZ2xvYmFsQXVkaXRMb2dnZXIpIHtcbiAgICBnbG9iYWxBdWRpdExvZ2dlciA9IG5ldyBBdWRpdExvZ2dlcihjb25maWcpO1xuICB9XG4gIHJldHVybiBnbG9iYWxBdWRpdExvZ2dlcjtcbn1cblxuLyoqXG4gKiBTZXQgZ2xvYmFsIGF1ZGl0IGxvZ2dlclxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0QXVkaXRMb2dnZXIobG9nZ2VyOiBBdWRpdExvZ2dlcik6IHZvaWQge1xuICBnbG9iYWxBdWRpdExvZ2dlciA9IGxvZ2dlcjtcbn1cbiJdfQ==