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.

343 lines 37.8 kB
"use strict"; /** * Baseline Drift Storage and Calibration * * Tracks baseline metrics and detects drift over time * * @module baseline/storage */ 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.BaselineStorage = void 0; exports.getBaselineStorage = getBaselineStorage; exports.resetBaselineStorage = resetBaselineStorage; const fs = __importStar(require("fs")); const path = __importStar(require("path")); const os = __importStar(require("os")); /** * Default configuration */ const DEFAULT_CONFIG = { baselineDir: path.join(os.homedir(), '.llmverify', 'baseline'), driftThreshold: 20, // 20% drift triggers warning maxDriftHistory: 1000, autoCalibrate: false }; /** * Baseline storage class */ class BaselineStorage { constructor(config) { this.config = { ...DEFAULT_CONFIG, ...config }; this.baselineFile = path.join(this.config.baselineDir, 'baseline.json'); this.driftFile = path.join(this.config.baselineDir, 'drift-history.jsonl'); this.ensureDirectory(); } /** * Ensure baseline directory exists */ ensureDirectory() { if (this.config.baselineDir) { try { fs.mkdirSync(this.config.baselineDir, { recursive: true }); } catch (error) { console.error('Failed to create baseline directory:', error); } } } /** * Load baseline metrics */ loadBaseline() { if (!fs.existsSync(this.baselineFile)) { return null; } try { const content = fs.readFileSync(this.baselineFile, 'utf-8'); return JSON.parse(content); } catch (error) { console.error('Failed to load baseline:', error); return null; } } /** * Save baseline metrics */ saveBaseline(baseline) { try { fs.writeFileSync(this.baselineFile, JSON.stringify(baseline, null, 2), 'utf-8'); } catch (error) { console.error('Failed to save baseline:', error); } } /** * Update baseline with new sample */ updateBaseline(sample) { let baseline = this.loadBaseline(); if (!baseline) { // Create new baseline baseline = { version: '1.0.0', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), sampleCount: 0, metrics: { averageLatency: 0, averageContentLength: 0, averageRiskScore: 0, riskDistribution: { low: 0, moderate: 0, high: 0, critical: 0 }, engineScores: {} } }; } // Update sample count const n = baseline.sampleCount; baseline.sampleCount = n + 1; // Update running averages using incremental mean formula baseline.metrics.averageLatency = (baseline.metrics.averageLatency * n + sample.latency) / (n + 1); baseline.metrics.averageContentLength = (baseline.metrics.averageContentLength * n + sample.contentLength) / (n + 1); baseline.metrics.averageRiskScore = (baseline.metrics.averageRiskScore * n + sample.riskScore) / (n + 1); // Update risk distribution const riskKey = sample.riskLevel; if (riskKey in baseline.metrics.riskDistribution) { baseline.metrics.riskDistribution[riskKey]++; } // Update engine scores if (sample.engineScores) { for (const [engine, score] of Object.entries(sample.engineScores)) { if (score !== undefined) { const currentScore = baseline.metrics.engineScores[engine] || 0; baseline.metrics.engineScores[engine] = (currentScore * n + score) / (n + 1); } } } baseline.updatedAt = new Date().toISOString(); this.saveBaseline(baseline); return baseline; } /** * Check for drift */ checkDrift(current) { const baseline = this.loadBaseline(); if (!baseline) return []; const drifts = []; const threshold = this.config.driftThreshold; // Check latency drift if (current.latency !== undefined && baseline.metrics.averageLatency > 0) { const drift = current.latency - baseline.metrics.averageLatency; const driftPercent = (drift / baseline.metrics.averageLatency) * 100; if (Math.abs(driftPercent) > threshold) { drifts.push({ timestamp: new Date().toISOString(), metric: 'latency', baseline: baseline.metrics.averageLatency, current: current.latency, drift, driftPercent, severity: this.getDriftSeverity(Math.abs(driftPercent)) }); } } // Check content length drift if (current.contentLength !== undefined && baseline.metrics.averageContentLength > 0) { const drift = current.contentLength - baseline.metrics.averageContentLength; const driftPercent = (drift / baseline.metrics.averageContentLength) * 100; if (Math.abs(driftPercent) > threshold) { drifts.push({ timestamp: new Date().toISOString(), metric: 'contentLength', baseline: baseline.metrics.averageContentLength, current: current.contentLength, drift, driftPercent, severity: this.getDriftSeverity(Math.abs(driftPercent)) }); } } // Check risk score drift if (current.riskScore !== undefined && baseline.metrics.averageRiskScore > 0) { const drift = current.riskScore - baseline.metrics.averageRiskScore; const driftPercent = (drift / baseline.metrics.averageRiskScore) * 100; if (Math.abs(driftPercent) > threshold) { drifts.push({ timestamp: new Date().toISOString(), metric: 'riskScore', baseline: baseline.metrics.averageRiskScore, current: current.riskScore, drift, driftPercent, severity: this.getDriftSeverity(Math.abs(driftPercent)) }); } } // Record drifts if (drifts.length > 0) { this.recordDrifts(drifts); } return drifts; } /** * Get drift severity */ getDriftSeverity(driftPercent) { if (driftPercent < 30) return 'minor'; if (driftPercent < 50) return 'moderate'; return 'significant'; } /** * Record drift history */ recordDrifts(drifts) { try { const lines = drifts.map(d => JSON.stringify(d) + '\n').join(''); fs.appendFileSync(this.driftFile, lines, 'utf-8'); // Trim history if needed this.trimDriftHistory(); } catch (error) { console.error('Failed to record drift:', error); } } /** * Trim drift history to max size */ trimDriftHistory() { if (!fs.existsSync(this.driftFile)) return; try { const content = fs.readFileSync(this.driftFile, 'utf-8'); const lines = content.split('\n').filter(l => l.trim()); if (lines.length > this.config.maxDriftHistory) { const trimmed = lines.slice(-this.config.maxDriftHistory); fs.writeFileSync(this.driftFile, trimmed.join('\n') + '\n', 'utf-8'); } } catch (error) { console.error('Failed to trim drift history:', error); } } /** * Read drift history */ readDriftHistory(limit) { if (!fs.existsSync(this.driftFile)) return []; try { const content = fs.readFileSync(this.driftFile, 'utf-8'); const records = content .split('\n') .filter(l => l.trim()) .map(l => JSON.parse(l)); if (limit) { return records.slice(-limit); } return records; } catch (error) { console.error('Failed to read drift history:', error); return []; } } /** * Reset baseline */ resetBaseline() { if (fs.existsSync(this.baselineFile)) { fs.unlinkSync(this.baselineFile); } if (fs.existsSync(this.driftFile)) { fs.unlinkSync(this.driftFile); } } /** * Get baseline statistics */ getStatistics() { const baseline = this.loadBaseline(); const driftHistory = this.readDriftHistory(10); return { hasBaseline: baseline !== null, sampleCount: baseline?.sampleCount || 0, createdAt: baseline?.createdAt, updatedAt: baseline?.updatedAt, driftRecordCount: this.readDriftHistory().length, recentDrifts: driftHistory }; } /** * Calibrate baseline (reset and start fresh) */ calibrate() { this.resetBaseline(); } } exports.BaselineStorage = BaselineStorage; /** * Global baseline storage instance */ let globalBaseline = null; /** * Get global baseline storage */ function getBaselineStorage(config) { if (!globalBaseline) { globalBaseline = new BaselineStorage(config); } return globalBaseline; } /** * Reset global baseline storage */ function resetBaselineStorage() { globalBaseline = null; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmFnZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9iYXNlbGluZS9zdG9yYWdlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7O0dBTUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQTRZSCxnREFLQztBQUtELG9EQUVDO0FBdFpELHVDQUF5QjtBQUN6QiwyQ0FBNkI7QUFDN0IsdUNBQXlCO0FBbUR6Qjs7R0FFRztBQUNILE1BQU0sY0FBYyxHQUFtQjtJQUNyQyxXQUFXLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLEVBQUUsWUFBWSxFQUFFLFVBQVUsQ0FBQztJQUM5RCxjQUFjLEVBQUUsRUFBRSxFQUFFLDZCQUE2QjtJQUNqRCxlQUFlLEVBQUUsSUFBSTtJQUNyQixhQUFhLEVBQUUsS0FBSztDQUNyQixDQUFDO0FBRUY7O0dBRUc7QUFDSCxNQUFhLGVBQWU7SUFLMUIsWUFBWSxNQUFnQztRQUMxQyxJQUFJLENBQUMsTUFBTSxHQUFHLEVBQUUsR0FBRyxjQUFjLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQztRQUMvQyxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFZLEVBQUUsZUFBZSxDQUFDLENBQUM7UUFDekUsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBWSxFQUFFLHFCQUFxQixDQUFDLENBQUM7UUFDNUUsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQ3pCLENBQUM7SUFFRDs7T0FFRztJQUNLLGVBQWU7UUFDckIsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQzVCLElBQUksQ0FBQztnQkFDSCxFQUFFLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxF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QUFTO1lBQzlCLGdCQUFnQixFQUFFLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLE1BQU07WUFDaEQsWUFBWSxFQUFFLFlBQVk7U0FDM0IsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNJLFNBQVM7UUFDZCxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDdkIsQ0FBQztDQUNGO0FBOVRELDBDQThUQztBQUVEOztHQUVHO0FBQ0gsSUFBSSxjQUFjLEdBQTJCLElBQUksQ0FBQztBQUVsRDs7R0FFRztBQUNILFNBQWdCLGtCQUFrQixDQUFDLE1BQWdDO0lBQ2pFLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUNwQixjQUFjLEdBQUcsSUFBSSxlQUFlLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUNELE9BQU8sY0FBYyxDQUFDO0FBQ3hCLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLG9CQUFvQjtJQUNsQyxjQUFjLEdBQUcsSUFBSSxDQUFDO0FBQ3hCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEJhc2VsaW5lIERyaWZ0IFN0b3JhZ2UgYW5kIENhbGlicmF0aW9uXG4gKiBcbiAqIFRyYWNrcyBiYXNlbGluZSBtZXRyaWNzIGFuZCBkZXRlY3RzIGRyaWZ0IG92ZXIgdGltZVxuICogXG4gKiBAbW9kdWxlIGJhc2VsaW5lL3N0b3JhZ2VcbiAqL1xuXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0ICogYXMgb3MgZnJvbSAnb3MnO1xuXG4vKipcbiAqIEJhc2VsaW5lIG1ldHJpY3NcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCYXNlbGluZU1ldHJpY3Mge1xuICB2ZXJzaW9uOiBzdHJpbmc7XG4gIGNyZWF0ZWRBdDogc3RyaW5nO1xuICB1cGRhdGVkQXQ6IHN0cmluZztcbiAgc2FtcGxlQ291bnQ6IG51bWJlcjtcbiAgbWV0cmljczoge1xuICAgIGF2ZXJhZ2VMYXRlbmN5OiBudW1iZXI7XG4gICAgYXZlcmFnZUNvbnRlbnRMZW5ndGg6IG51bWJlcjtcbiAgICBhdmVyYWdlUmlza1Njb3JlOiBudW1iZXI7XG4gICAgcmlza0Rpc3RyaWJ1dGlvbjoge1xuICAgICAgbG93OiBudW1iZXI7XG4gICAgICBtb2RlcmF0ZTogbnVtYmVyO1xuICAgICAgaGlnaDogbnVtYmVyO1xuICAgICAgY3JpdGljYWw6IG51bWJlcjtcbiAgICB9O1xuICAgIGVuZ2luZVNjb3Jlczoge1xuICAgICAgaGFsbHVjaW5hdGlvbj86IG51bWJlcjtcbiAgICAgIGNvbnNpc3RlbmN5PzogbnVtYmVyO1xuICAgICAgY3NtNj86IG51bWJlcjtcbiAgICB9O1xuICB9O1xufVxuXG4vKipcbiAqIERyaWZ0IHJlY29yZFxuICovXG5leHBvcnQgaW50ZXJmYWNlIERyaWZ0UmVjb3JkIHtcbiAgdGltZXN0YW1wOiBzdHJpbmc7XG4gIG1ldHJpYzogc3RyaW5nO1xuICBiYXNlbGluZTogbnVtYmVyO1xuICBjdXJyZW50OiBudW1iZXI7XG4gIGRyaWZ0OiBudW1iZXI7XG4gIGRyaWZ0UGVyY2VudDogbnVtYmVyO1xuICBzZXZlcml0eTogJ21pbm9yJyB8ICdtb2RlcmF0ZScgfCAnc2lnbmlmaWNhbnQnO1xufVxuXG4vKipcbiAqIEJhc2VsaW5lIGNvbmZpZ3VyYXRpb25cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCYXNlbGluZUNvbmZpZyB7XG4gIGJhc2VsaW5lRGlyPzogc3RyaW5nO1xuICBkcmlmdFRocmVzaG9sZD86IG51bWJlcjsgLy8gcGVyY2VudGFnZVxuICBtYXhEcmlmdEhpc3Rvcnk/OiBudW1iZXI7XG4gIGF1dG9DYWxpYnJhdGU/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIERlZmF1bHQgY29uZmlndXJhdGlvblxuICovXG5jb25zdCBERUZBVUxUX0NPTkZJRzogQmFzZWxpbmVDb25maWcgPSB7XG4gIGJhc2VsaW5lRGlyOiBwYXRoLmpvaW4ob3MuaG9tZWRpcigpLCAnLmxsbXZlcmlmeScsICdiYXNlbGluZScpLFxuICBkcmlmdFRocmVzaG9sZDogMjAsIC8vIDIwJSBkcmlmdCB0cmlnZ2VycyB3YXJuaW5nXG4gIG1heERyaWZ0SGlzdG9yeTogMTAwMCxcbiAgYXV0b0NhbGlicmF0ZTogZmFsc2Vcbn07XG5cbi8qKlxuICogQmFzZWxpbmUgc3RvcmFnZSBjbGFzc1xuICovXG5leHBvcnQgY2xhc3MgQmFzZWxpbmVTdG9yYWdlIHtcbiAgcHJpdmF0ZSBjb25maWc6IEJhc2VsaW5lQ29uZmlnO1xuICBwcml2YXRlIGJhc2VsaW5lRmlsZTogc3RyaW5nO1xuICBwcml2YXRlIGRyaWZ0RmlsZTogc3RyaW5nO1xuICBcbiAgY29uc3RydWN0b3IoY29uZmlnPzogUGFydGlhbDxCYXNlbGluZUNvbmZpZz4pIHtcbiAgICB0aGlzLmNvbmZpZyA9IHsgLi4uREVGQVVMVF9DT05GSUcsIC4uLmNvbmZpZyB9O1xuICAgIHRoaXMuYmFzZWxpbmVGaWxlID0gcGF0aC5qb2luKHRoaXMuY29uZmlnLmJhc2VsaW5lRGlyISwgJ2Jhc2VsaW5lLmpzb24nKTtcbiAgICB0aGlzLmRyaWZ0RmlsZSA9IHBhdGguam9pbih0aGlzLmNvbmZpZy5iYXNlbGluZURpciEsICdkcmlmdC1oaXN0b3J5Lmpzb25sJyk7XG4gICAgdGhpcy5lbnN1cmVEaXJlY3RvcnkoKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEVuc3VyZSBiYXNlbGluZSBkaXJlY3RvcnkgZXhpc3RzXG4gICAqL1xuICBwcml2YXRlIGVuc3VyZURpcmVjdG9yeSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5jb25maWcuYmFzZWxpbmVEaXIpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGZzLm1rZGlyU3luYyh0aGlzLmNvbmZpZy5iYXNlbGluZURpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKCdGYWlsZWQgdG8gY3JlYXRlIGJhc2VsaW5lIGRpcmVjdG9yeTonLCBlcnJvcik7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogTG9hZCBiYXNlbGluZSBtZXRyaWNzXG4gICAqL1xuICBwdWJsaWMgbG9hZEJhc2VsaW5lKCk6IEJhc2VsaW5lTWV0cmljcyB8IG51bGwge1xuICAgIGlmICghZnMuZXhpc3RzU3luYyh0aGlzLmJhc2VsaW5lRmlsZSkpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBcbiAgICB0cnkge1xuICAgICAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyh0aGlzLmJhc2VsaW5lRmlsZSwgJ3V0Zi04Jyk7XG4gICAgICByZXR1cm4gSlNPTi5wYXJzZShjb250ZW50KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRmFpbGVkIHRvIGxvYWQgYmFzZWxpbmU6JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogU2F2ZSBiYXNlbGluZSBtZXRyaWNzXG4gICAqL1xuICBwdWJsaWMgc2F2ZUJhc2VsaW5lKGJhc2VsaW5lOiBCYXNlbGluZU1ldHJpY3MpOiB2b2lkIHtcbiAgICB0cnkge1xuICAgICAgZnMud3JpdGVGaWxlU3luYyhcbiAgICAgICAgdGhpcy5iYXNlbGluZUZpbGUsXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KGJhc2VsaW5lLCBudWxsLCAyKSxcbiAgICAgICAgJ3V0Zi04J1xuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRmFpbGVkIHRvIHNhdmUgYmFzZWxpbmU6JywgZXJyb3IpO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFVwZGF0ZSBiYXNlbGluZSB3aXRoIG5ldyBzYW1wbGVcbiAgICovXG4gIHB1YmxpYyB1cGRhdGVCYXNlbGluZShzYW1wbGU6IHtcbiAgICBsYXRlbmN5OiBudW1iZXI7XG4gICAgY29udGVudExlbmd0aDogbnVtYmVyO1xuICAgIHJpc2tTY29yZTogbnVtYmVyO1xuICAgIHJpc2tMZXZlbDogc3RyaW5nO1xuICAgIGVuZ2luZVNjb3Jlcz86IHtcbiAgICAgIGhhbGx1Y2luYXRpb24/OiBudW1iZXI7XG4gICAgICBjb25zaXN0ZW5jeT86IG51bWJlcjtcbiAgICAgIGNzbTY/OiBudW1iZXI7XG4gICAgfTtcbiAgfSk6IEJhc2VsaW5lTWV0cmljcyB7XG4gICAgbGV0IGJhc2VsaW5lID0gdGhpcy5sb2FkQmFzZWxpbmUoKTtcbiAgICBcbiAgICBpZiAoIWJhc2VsaW5lKSB7XG4gICAgICAvLyBDcmVhdGUgbmV3IGJhc2VsaW5lXG4gICAgICBiYXNlbGluZSA9IHtcbiAgICAgICAgdmVyc2lvbjogJzEuMC4wJyxcbiAgICAgICAgY3JlYXRlZEF0OiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICAgIHVwZGF0ZWRBdDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICBzYW1wbGVDb3VudDogMCxcbiAgICAgICAgbWV0cmljczoge1xuICAgICAgICAgIGF2ZXJhZ2VMYXRlbmN5OiAwLFxuICAgICAgICAgIGF2ZXJhZ2VDb250ZW50TGVuZ3RoOiAwLFxuICAgICAgICAgIGF2ZXJhZ2VSaXNrU2NvcmU6IDAsXG4gICAgICAgICAgcmlza0Rpc3RyaWJ1dGlvbjoge1xuICAgICAgICAgICAgbG93OiAwLFxuICAgICAgICAgICAgbW9kZXJhdGU6IDAsXG4gICAgICAgICAgICBoaWdoOiAwLFxuICAgICAgICAgICAgY3JpdGljYWw6IDBcbiAgICAgICAgICB9LFxuICAgICAgICAgIGVuZ2luZVNjb3Jlczoge31cbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9XG4gICAgXG4gICAgLy8gVXBkYXRlIHNhbXBsZSBjb3VudFxuICAgIGNvbnN0IG4gPSBiYXNlbGluZS5zYW1wbGVDb3VudDtcbiAgICBiYXNlbGluZS5zYW1wbGVDb3VudCA9IG4gKyAxO1xuICAgIFxuICAgIC8vIFVwZGF0ZSBydW5uaW5nIGF2ZXJhZ2VzIHVzaW5nIGluY3JlbWVudGFsIG1lYW4gZm9ybXVsYVxuICAgIGJhc2VsaW5lLm1ldHJpY3MuYXZlcmFnZUxhdGVuY3kgPSBcbiAgICAgIChiYXNlbGluZS5tZXRyaWNzLmF2ZXJhZ2VMYXRlbmN5ICogbiArIHNhbXBsZS5sYXRlbmN5KSAvIChuICsgMSk7XG4gICAgXG4gICAgYmFzZWxpbmUubWV0cmljcy5hdmVyYWdlQ29udGVudExlbmd0aCA9IFxuICAgICAgKGJhc2VsaW5lLm1ldHJpY3MuYXZlcmFnZUNvbnRlbnRMZW5ndGggKiBuICsgc2FtcGxlLmNvbnRlbnRMZW5ndGgpIC8gKG4gKyAxKTtcbiAgICBcbiAgICBiYXNlbGluZS5tZXRyaWNzLmF2ZXJhZ2VSaXNrU2NvcmUgPSBcbiAgICAgIChiYXNlbGluZS5tZXRyaWNzLmF2ZXJhZ2VSaXNrU2NvcmUgKiBuICsgc2FtcGxlLnJpc2tTY29yZSkgLyAobiArIDEpO1xuICAgIFxuICAgIC8vIFVwZGF0ZSByaXNrIGRpc3RyaWJ1dGlvblxuICAgIGNvbnN0IHJpc2tLZXkgPSBzYW1wbGUucmlza0xldmVsIGFzIGtleW9mIHR5cGVvZiBiYXNlbGluZS5tZXRyaWNzLnJpc2tEaXN0cmlidXRpb247XG4gICAgaWYgKHJpc2tLZXkgaW4gYmFzZWxpbmUubWV0cmljcy5yaXNrRGlzdHJpYnV0aW9uKSB7XG4gICAgICBiYXNlbGluZS5tZXRyaWNzLnJpc2tEaXN0cmlidXRpb25bcmlza0tleV0rKztcbiAgICB9XG4gICAgXG4gICAgLy8gVXBkYXRlIGVuZ2luZSBzY29yZXNcbiAgICBpZiAoc2FtcGxlLmVuZ2luZVNjb3Jlcykge1xuICAgICAgZm9yIChjb25zdCBbZW5naW5lLCBzY29yZV0gb2YgT2JqZWN0LmVudHJpZXMoc2FtcGxlLmVuZ2luZVNjb3JlcykpIHtcbiAgICAgICAgaWYgKHNjb3JlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBjb25zdCBjdXJyZW50U2NvcmUgPSAoYmFzZWxpbmUubWV0cmljcy5lbmdpbmVTY29yZXMgYXMgYW55KVtlbmdpbmVdIHx8IDA7XG4gICAgICAgICAgKGJhc2VsaW5lLm1ldHJpY3MuZW5naW5lU2NvcmVzIGFzIGFueSlbZW5naW5lXSA9IFxuICAgICAgICAgICAgKGN1cnJlbnRTY29yZSAqIG4gKyBzY29yZSkgLyAobiArIDEpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIGJhc2VsaW5lLnVwZGF0ZWRBdCA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKTtcbiAgICBcbiAgICB0aGlzLnNhdmVCYXNlbGluZShiYXNlbGluZSk7XG4gICAgcmV0dXJuIGJhc2VsaW5lO1xuICB9XG4gIFxuICAvKipcbiAgICogQ2hlY2sgZm9yIGRyaWZ0XG4gICAqL1xuICBwdWJsaWMgY2hlY2tEcmlmdChjdXJyZW50OiB7XG4gICAgbGF0ZW5jeT86IG51bWJlcjtcbiAgICBjb250ZW50TGVuZ3RoPzogbnVtYmVyO1xuICAgIHJpc2tTY29yZT86IG51bWJlcjtcbiAgfSk6IERyaWZ0UmVjb3JkW10ge1xuICAgIGNvbnN0IGJhc2VsaW5lID0gdGhpcy5sb2FkQmFzZWxpbmUoKTtcbiAgICBpZiAoIWJhc2VsaW5lKSByZXR1cm4gW107XG4gICAgXG4gICAgY29uc3QgZHJpZnRzOiBEcmlmdFJlY29yZFtdID0gW107XG4gICAgY29uc3QgdGhyZXNob2xkID0gdGhpcy5jb25maWcuZHJpZnRUaHJlc2hvbGQhO1xuICAgIFxuICAgIC8vIENoZWNrIGxhdGVuY3kgZHJpZnRcbiAgICBpZiAoY3VycmVudC5sYXRlbmN5ICE9PSB1bmRlZmluZWQgJiYgYmFzZWxpbmUubWV0cmljcy5hdmVyYWdlTGF0ZW5jeSA+IDApIHtcbiAgICAgIGNvbnN0IGRyaWZ0ID0gY3VycmVudC5sYXRlbmN5IC0gYmFzZWxpbmUubWV0cmljcy5hdmVyYWdlTGF0ZW5jeTtcbiAgICAgIGNvbnN0IGRyaWZ0UGVyY2VudCA9IChkcmlmdCAvIGJhc2VsaW5lLm1ldHJpY3MuYXZlcmFnZUxhdGVuY3kpICogMTAwO1xuICAgICAgXG4gICAgICBpZiAoTWF0aC5hYnMoZHJpZnRQZXJjZW50KSA+IHRocmVzaG9sZCkge1xuICAgICAgICBkcmlmdHMucHVzaCh7XG4gICAgICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICAgICAgbWV0cmljOiAnbGF0ZW5jeScsXG4gICAgICAgICAgYmFzZWxpbmU6IGJhc2VsaW5lLm1ldHJpY3MuYXZlcmFnZUxhdGVuY3ksXG4gICAgICAgICAgY3VycmVudDogY3VycmVudC5sYXRlbmN5LFxuICAgICAgICAgIGRyaWZ0LFxuICAgICAgICAgIGRyaWZ0UGVyY2VudCxcbiAgICAgICAgICBzZXZlcml0eTogdGhpcy5nZXREcmlmdFNldmVyaXR5KE1hdGguYWJzKGRyaWZ0UGVyY2VudCkpXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICAvLyBDaGVjayBjb250ZW50IGxlbmd0aCBkcmlmdFxuICAgIGlmIChjdXJyZW50LmNvbnRlbnRMZW5ndGggIT09IHVuZGVmaW5lZCAmJiBiYXNlbGluZS5tZXRyaWNzLmF2ZXJhZ2VDb250ZW50TGVuZ3RoID4gMCkge1xuICAgICAgY29uc3QgZHJpZnQgPSBjdXJyZW50LmNvbnRlbnRMZW5ndGggLSBiYXNlbGluZS5tZXRyaWNzLmF2ZXJhZ2VDb250ZW50TGVuZ3RoO1xuICAgICAgY29uc3QgZHJpZnRQZXJjZW50ID0gKGRyaWZ0IC8gYmFzZWxpbmUubWV0cmljcy5hdmVyYWdlQ29udGVudExlbmd0aCkgKiAxMDA7XG4gICAgICBcbiAgICAgIGlmIChNYXRoLmFicyhkcmlmdFBlcmNlbnQpID4gdGhyZXNob2xkKSB7XG4gICAgICAgIGRyaWZ0cy5wdXNoKHtcbiAgICAgICAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgICAgICBtZXRyaWM6ICdjb250ZW50TGVuZ3RoJyxcbiAgICAgICAgICBiYXNlbGluZTogYmFzZWxpbmUubWV0cmljcy5hdmVyYWdlQ29udGVudExlbmd0aCxcbiAgICAgICAgICBjdXJyZW50OiBjdXJyZW50LmNvbnRlbnRMZW5ndGgsXG4gICAgICAgICAgZHJpZnQsXG4gICAgICAgICAgZHJpZnRQZXJjZW50LFxuICAgICAgICAgIHNldmVyaXR5OiB0aGlzLmdldERyaWZ0U2V2ZXJpdHkoTWF0aC5hYnMoZHJpZnRQZXJjZW50KSlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIENoZWNrIHJpc2sgc2NvcmUgZHJpZnRcbiAgICBpZiAoY3VycmVudC5yaXNrU2NvcmUgIT09IHVuZGVmaW5lZCAmJiBiYXNlbGluZS5tZXRyaWNzLmF2ZXJhZ2VSaXNrU2NvcmUgPiAwKSB7XG4gICAgICBjb25zdCBkcmlmdCA9IGN1cnJlbnQucmlza1Njb3JlIC0gYmFzZWxpbmUubWV0cmljcy5hdmVyYWdlUmlza1Njb3JlO1xuICAgICAgY29uc3QgZHJpZnRQZXJjZW50ID0gKGRyaWZ0IC8gYmFzZWxpbmUubWV0cmljcy5hdmVyYWdlUmlza1Njb3JlKSAqIDEwMDtcbiAgICAgIFxuICAgICAgaWYgKE1hdGguYWJzKGRyaWZ0UGVyY2VudCkgPiB0aHJlc2hvbGQpIHtcbiAgICAgICAgZHJpZnRzLnB1c2goe1xuICAgICAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICAgIG1ldHJpYzogJ3Jpc2tTY29yZScsXG4gICAgICAgICAgYmFzZWxpbmU6IGJhc2VsaW5lLm1ldHJpY3MuYXZlcmFnZVJpc2tTY29yZSxcbiAgICAgICAgICBjdXJyZW50OiBjdXJyZW50LnJpc2tTY29yZSxcbiAgICAgICAgICBkcmlmdCxcbiAgICAgICAgICBkcmlmdFBlcmNlbnQsXG4gICAgICAgICAgc2V2ZXJpdHk6IHRoaXMuZ2V0RHJpZnRTZXZlcml0eShNYXRoLmFicyhkcmlmdFBlcmNlbnQpKVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gUmVjb3JkIGRyaWZ0c1xuICAgIGlmIChkcmlmdHMubGVuZ3RoID4gMCkge1xuICAgICAgdGhpcy5yZWNvcmREcmlmdHMoZHJpZnRzKTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGRyaWZ0cztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBkcmlmdCBzZXZlcml0eVxuICAgKi9cbiAgcHJpdmF0ZSBnZXREcmlmdFNldmVyaXR5KGRyaWZ0UGVyY2VudDogbnVtYmVyKTogJ21pbm9yJyB8ICdtb2RlcmF0ZScgfCAnc2lnbmlmaWNhbnQnIHtcbiAgICBpZiAoZHJpZnRQZXJjZW50IDwgMzApIHJldHVybiAnbWlub3InO1xuICAgIGlmIChkcmlmdFBlcmNlbnQgPCA1MCkgcmV0dXJuICdtb2RlcmF0ZSc7XG4gICAgcmV0dXJuICdzaWduaWZpY2FudCc7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZWNvcmQgZHJpZnQgaGlzdG9yeVxuICAgKi9cbiAgcHJpdmF0ZSByZWNvcmREcmlmdHMoZHJpZnRzOiBEcmlmdFJlY29yZFtdKTogdm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGxpbmVzID0gZHJpZnRzLm1hcChkID0+IEpTT04uc3RyaW5naWZ5KGQpICsgJ1xcbicpLmpvaW4oJycpO1xuICAgICAgZnMuYXBwZW5kRmlsZVN5bmModGhpcy5kcmlmdEZpbGUsIGxpbmVzLCAndXRmLTgnKTtcbiAgICAgIFxuICAgICAgLy8gVHJpbSBoaXN0b3J5IGlmIG5lZWRlZFxuICAgICAgdGhpcy50cmltRHJpZnRIaXN0b3J5KCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0ZhaWxlZCB0byByZWNvcmQgZHJpZnQ6JywgZXJyb3IpO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFRyaW0gZHJpZnQgaGlzdG9yeSB0byBtYXggc2l6ZVxuICAgKi9cbiAgcHJpdmF0ZSB0cmltRHJpZnRIaXN0b3J5KCk6IHZvaWQge1xuICAgIGlmICghZnMuZXhpc3RzU3luYyh0aGlzLmRyaWZ0RmlsZSkpIHJldHVybjtcbiAgICBcbiAgICB0cnkge1xuICAgICAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyh0aGlzLmRyaWZ0RmlsZSwgJ3V0Zi04Jyk7XG4gICAgICBjb25zdCBsaW5lcyA9IGNvbnRlbnQuc3BsaXQoJ1xcbicpLmZpbHRlcihsID0+IGwudHJpbSgpKTtcbiAgICAgIFxuICAgICAgaWYgKGxpbmVzLmxlbmd0aCA+IHRoaXMuY29uZmlnLm1heERyaWZ0SGlzdG9yeSEpIHtcbiAgICAgICAgY29uc3QgdHJpbW1lZCA9IGxpbmVzLnNsaWNlKC10aGlzLmNvbmZpZy5tYXhEcmlmdEhpc3RvcnkhKTtcbiAgICAgICAgZnMud3JpdGVGaWxlU3luYyh0aGlzLmRyaWZ0RmlsZSwgdHJpbW1lZC5qb2luKCdcXG4nKSArICdcXG4nLCAndXRmLTgnKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRmFpbGVkIHRvIHRyaW0gZHJpZnQgaGlzdG9yeTonLCBlcnJvcik7XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogUmVhZCBkcmlmdCBoaXN0b3J5XG4gICAqL1xuICBwdWJsaWMgcmVhZERyaWZ0SGlzdG9yeShsaW1pdD86IG51bWJlcik6IERyaWZ0UmVjb3JkW10ge1xuICAgIGlmICghZnMuZXhpc3RzU3luYyh0aGlzLmRyaWZ0RmlsZSkpIHJldHVybiBbXTtcbiAgICBcbiAgICB0cnkge1xuICAgICAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyh0aGlzLmRyaWZ0RmlsZSwgJ3V0Zi04Jyk7XG4gICAgICBjb25zdCByZWNvcmRzID0gY29udGVudFxuICAgICAgICAuc3BsaXQoJ1xcbicpXG4gICAgICAgIC5maWx0ZXIobCA9PiBsLnRyaW0oKSlcbiAgICAgICAgLm1hcChsID0+IEpTT04ucGFyc2UobCkgYXMgRHJpZnRSZWNvcmQpO1xuICAgICAgXG4gICAgICBpZiAobGltaXQpIHtcbiAgICAgICAgcmV0dXJuIHJlY29yZHMuc2xpY2UoLWxpbWl0KTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgcmV0dXJuIHJlY29yZHM7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0ZhaWxlZCB0byByZWFkIGRyaWZ0IGhpc3Rvcnk6JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFJlc2V0IGJhc2VsaW5lXG4gICAqL1xuICBwdWJsaWMgcmVzZXRCYXNlbGluZSgpOiB2b2lkIHtcbiAgICBpZiAoZnMuZXhpc3RzU3luYyh0aGlzLmJhc2VsaW5lRmlsZSkpIHtcbiAgICAgIGZzLnVubGlua1N5bmModGhpcy5iYXNlbGluZUZpbGUpO1xuICAgIH1cbiAgICBcbiAgICBpZiAoZnMuZXhpc3RzU3luYyh0aGlzLmRyaWZ0RmlsZSkpIHtcbiAgICAgIGZzLnVubGlua1N5bmModGhpcy5kcmlmdEZpbGUpO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBiYXNlbGluZSBzdGF0aXN0aWNzXG4gICAqL1xuICBwdWJsaWMgZ2V0U3RhdGlzdGljcygpOiB7XG4gICAgaGFzQmFzZWxpbmU6IGJvb2xlYW47XG4gICAgc2FtcGxlQ291bnQ6IG51bWJlcjtcbiAgICBjcmVhdGVkQXQ/OiBzdHJpbmc7XG4gICAgdXBkYXRlZEF0Pzogc3RyaW5nO1xuICAgIGRyaWZ0UmVjb3JkQ291bnQ6IG51bWJlcjtcbiAgICByZWNlbnREcmlmdHM6IERyaWZ0UmVjb3JkW107XG4gIH0ge1xuICAgIGNvbnN0IGJhc2VsaW5lID0gdGhpcy5sb2FkQmFzZWxpbmUoKTtcbiAgICBjb25zdCBkcmlmdEhpc3RvcnkgPSB0aGlzLnJlYWREcmlmdEhpc3RvcnkoMTApO1xuICAgIFxuICAgIHJldHVybiB7XG4gICAgICBoYXNCYXNlbGluZTogYmFzZWxpbmUgIT09IG51bGwsXG4gICAgICBzYW1wbGVDb3VudDogYmFzZWxpbmU/LnNhbXBsZUNvdW50IHx8IDAsXG4gICAgICBjcmVhdGVkQXQ6IGJhc2VsaW5lPy5jcmVhdGVkQXQsXG4gICAgICB1cGRhdGVkQXQ6IGJhc2VsaW5lPy51cGRhdGVkQXQsXG4gICAgICBkcmlmdFJlY29yZENvdW50OiB0aGlzLnJlYWREcmlmdEhpc3RvcnkoKS5sZW5ndGgsXG4gICAgICByZWNlbnREcmlmdHM6IGRyaWZ0SGlzdG9yeVxuICAgIH07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDYWxpYnJhdGUgYmFzZWxpbmUgKHJlc2V0IGFuZCBzdGFydCBmcmVzaClcbiAgICovXG4gIHB1YmxpYyBjYWxpYnJhdGUoKTogdm9pZCB7XG4gICAgdGhpcy5yZXNldEJhc2VsaW5lKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBHbG9iYWwgYmFzZWxpbmUgc3RvcmFnZSBpbnN0YW5jZVxuICovXG5sZXQgZ2xvYmFsQmFzZWxpbmU6IEJhc2VsaW5lU3RvcmFnZSB8IG51bGwgPSBudWxsO1xuXG4vKipcbiAqIEdldCBnbG9iYWwgYmFzZWxpbmUgc3RvcmFnZVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0QmFzZWxpbmVTdG9yYWdlKGNvbmZpZz86IFBhcnRpYWw8QmFzZWxpbmVDb25maWc+KTogQmFzZWxpbmVTdG9yYWdlIHtcbiAgaWYgKCFnbG9iYWxCYXNlbGluZSkge1xuICAgIGdsb2JhbEJhc2VsaW5lID0gbmV3IEJhc2VsaW5lU3RvcmFnZShjb25maWcpO1xuICB9XG4gIHJldHVybiBnbG9iYWxCYXNlbGluZTtcbn1cblxuLyoqXG4gKiBSZXNldCBnbG9iYWwgYmFzZWxpbmUgc3RvcmFnZVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzZXRCYXNlbGluZVN0b3JhZ2UoKTogdm9pZCB7XG4gIGdsb2JhbEJhc2VsaW5lID0gbnVsbDtcbn1cbiJdfQ==