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
JavaScript
"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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmFnZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9iYXNlbGluZS9zdG9yYWdlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7O0dBTUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQTRZSCxnREFLQztBQUtELG9EQUVDO0FBdFpELHVDQUF5QjtBQUN6QiwyQ0FBNkI7QUFDN0IsdUNBQXlCO0FBbUR6Qjs7R0FFRztBQUNILE1BQU0sY0FBYyxHQUFtQjtJQUNyQyxXQUFXLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLEVBQUUsWUFBWSxFQUFFLFVBQVUsQ0FBQztJQUM5RCxjQUFjLEVBQUUsRUFBRSxFQUFFLDZCQUE2QjtJQUNqRCxlQUFlLEVBQUUsSUFBSTtJQUNyQixhQUFhLEVBQUUsS0FBSztDQUNyQixDQUFDO0FBRUY7O0dBRUc7QUFDSCxNQUFhLGVBQWU7SUFLMUIsWUFBWSxNQUFnQztRQUMxQyxJQUFJLENBQUMsTUFBTSxHQUFHLEVBQUUsR0FBRyxjQUFjLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQztRQUMvQyxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFZLEVBQUUsZUFBZSxDQUFDLENBQUM7UUFDekUsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBWSxFQUFFLHFCQUFxQixDQUFDLENBQUM7UUFDNUUsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQ3pCLENBQUM7SUFFRDs7T0FFRztJQUNLLGVBQWU7UUFDckIsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQzVCLElBQUksQ0FBQztnQkFDSCxFQUFFLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7WUFDN0QsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsT0FBTyxDQUFDLEtBQUssQ0FBQyxzQ0FBc0MsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUMvRCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNJLFlBQVk7UUFDakIsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7WUFDdEMsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBRUQsSUFBSSxDQUFDO1lBQ0gsTUFBTSxPQUFPLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQzVELE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM3QixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsMEJBQTBCLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDakQsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ksWUFBWSxDQUFDLFFBQXlCO1FBQzNDLElBQUksQ0FBQztZQUNILEVBQUUsQ0FBQyxhQUFhLENBQ2QsSUFBSSxDQUFDLFlBQVksRUFDakIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUNqQyxPQUFPLENBQ1IsQ0FBQztRQUNKLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsT0FBTyxDQUFDLEtBQUssQ0FBQywwQkFBMEIsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNuRCxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ksY0FBYyxDQUFDLE1BVXJCO1FBQ0MsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBRW5DLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNkLHNCQUFzQjtZQUN0QixRQUFRLEdBQUc7Z0JBQ1QsT0FBTyxFQUFFLE9BQU87Z0JBQ2hCLFNBQVMsRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRTtnQkFDbkMsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFO2dCQUNuQyxXQUFXLEVBQUUsQ0FBQztnQkFDZCxPQUFPLEVBQUU7b0JBQ1AsY0FBYyxFQUFFLENBQUM7b0JBQ2pCLG9CQUFvQixFQUFFLENBQUM7b0JBQ3ZCLGdCQUFnQixFQUFFLENBQUM7b0JBQ25CLGdCQUFnQixFQUFFO3dCQUNoQixHQUFHLEVBQUUsQ0FBQzt3QkFDTixRQUFRLEVBQUUsQ0FBQzt3QkFDWCxJQUFJLEVBQUUsQ0FBQzt3QkFDUCxRQUFRLEVBQUUsQ0FBQztxQkFDWjtvQkFDRCxZQUFZLEVBQUUsRUFBRTtpQkFDakI7YUFDRixDQUFDO1FBQ0osQ0FBQztRQUVELHNCQUFzQjtRQUN0QixNQUFNLENBQUMsR0FBRyxRQUFRLENBQUMsV0FBVyxDQUFDO1FBQy9CLFFBQVEsQ0FBQyxXQUFXLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUU3Qix5REFBeUQ7UUFDekQsUUFBUSxDQUFDLE9BQU8sQ0FBQyxjQUFjO1lBQzdCLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxjQUFjLEdBQUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUVuRSxRQUFRLENBQUMsT0FBTyxDQUFDLG9CQUFvQjtZQUNuQyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsb0JBQW9CLEdBQUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUUvRSxRQUFRLENBQUMsT0FBTyxDQUFDLGdCQUFnQjtZQUMvQixDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLEdBQUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUV2RSwyQkFBMkI7UUFDM0IsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLFNBQTJELENBQUM7UUFDbkYsSUFBSSxPQUFPLElBQUksUUFBUSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ2pELFFBQVEsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUMvQyxDQUFDO1FBRUQsdUJBQXVCO1FBQ3ZCLElBQUksTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ3hCLEtBQUssTUFBTSxDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDO2dCQUNsRSxJQUFJLEtBQUssS0FBSyxTQUFTLEVBQUUsQ0FBQztvQkFDeEIsTUFBTSxZQUFZLEdBQUksUUFBUSxDQUFDLE9BQU8sQ0FBQyxZQUFvQixDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDeEUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxZQUFvQixDQUFDLE1BQU0sQ0FBQzt3QkFDNUMsQ0FBQyxZQUFZLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO2dCQUN6QyxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7UUFFRCxRQUFRLENBQUMsU0FBUyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUM7UUFFOUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM1QixPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQ7O09BRUc7SUFDSSxVQUFVLENBQUMsT0FJakI7UUFDQyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDckMsSUFBSSxDQUFDLFFBQVE7WUFBRSxPQUFPLEVBQUUsQ0FBQztRQUV6QixNQUFNLE1BQU0sR0FBa0IsRUFBRSxDQUFDO1FBQ2pDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBZSxDQUFDO1FBRTlDLHNCQUFzQjtRQUN0QixJQUFJLE9BQU8sQ0FBQyxPQUFPLEtBQUssU0FBUyxJQUFJLFFBQVEsQ0FBQyxPQUFPLENBQUMsY0FBYyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3pFLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxPQUFPLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUM7WUFDaEUsTUFBTSxZQUFZLEdBQUcsQ0FBQyxLQUFLLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsR0FBRyxHQUFHLENBQUM7WUFFckUsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxHQUFHLFNBQVMsRUFBRSxDQUFDO2dCQUN2QyxNQUFNLENBQUMsSUFBSSxDQUFDO29CQUNWLFNBQVMsRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRTtvQkFDbkMsTUFBTSxFQUFFLFNBQVM7b0JBQ2pCLFFBQVEsRUFBRSxRQUFRLENBQUMsT0FBTyxDQUFDLGNBQWM7b0JBQ3pDLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTztvQkFDeEIsS0FBSztvQkFDTCxZQUFZO29CQUNaLFFBQVEsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQztpQkFDeEQsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztRQUNILENBQUM7UUFFRCw2QkFBNkI7UUFDN0IsSUFBSSxPQUFPLENBQUMsYUFBYSxLQUFLLFNBQVMsSUFBSSxRQUFRLENBQUMsT0FBTyxDQUFDLG9CQUFvQixHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3JGLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxhQUFhLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQztZQUM1RSxNQUFNLFlBQVksR0FBRyxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLG9CQUFvQixDQUFDLEdBQUcsR0FBRyxDQUFDO1lBRTNFLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsR0FBRyxTQUFTLEVBQUUsQ0FBQztnQkFDdkMsTUFBTSxDQUFDLElBQUksQ0FBQztvQkFDVixTQUFTLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUU7b0JBQ25DLE1BQU0sRUFBRSxlQUFlO29CQUN2QixRQUFRLEVBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxvQkFBb0I7b0JBQy9DLE9BQU8sRUFBRSxPQUFPLENBQUMsYUFBYTtvQkFDOUIsS0FBSztvQkFDTCxZQUFZO29CQUNaLFFBQVEsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQztpQkFDeEQsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztRQUNILENBQUM7UUFFRCx5QkFBeUI7UUFDekIsSUFBSSxPQUFPLENBQUMsU0FBUyxLQUFLLFNBQVMsSUFBSSxRQUFRLENBQUMsT0FBTyxDQUFDLGdCQUFnQixHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzdFLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxTQUFTLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQztZQUNwRSxNQUFNLFlBQVksR0FBRyxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLEdBQUcsR0FBRyxDQUFDO1lBRXZFLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsR0FBRyxTQUFTLEVBQUUsQ0FBQztnQkFDdkMsTUFBTSxDQUFDLElBQUksQ0FBQztvQkFDVixTQUFTLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUU7b0JBQ25DLE1BQU0sRUFBRSxXQUFXO29CQUNuQixRQUFRLEVBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0I7b0JBQzNDLE9BQU8sRUFBRSxPQUFPLENBQUMsU0FBUztvQkFDMUIsS0FBSztvQkFDTCxZQUFZO29CQUNaLFFBQVEsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQztpQkFDeEQsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztRQUNILENBQUM7UUFFRCxnQkFBZ0I7UUFDaEIsSUFBSSxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3RCLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDNUIsQ0FBQztRQUVELE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUM7SUFFRDs7T0FFRztJQUNLLGdCQUFnQixDQUFDLFlBQW9CO1FBQzNDLElBQUksWUFBWSxHQUFHLEVBQUU7WUFBRSxPQUFPLE9BQU8sQ0FBQztRQUN0QyxJQUFJLFlBQVksR0FBRyxFQUFFO1lBQUUsT0FBTyxVQUFVLENBQUM7UUFDekMsT0FBTyxhQUFhLENBQUM7SUFDdkIsQ0FBQztJQUVEOztPQUVHO0lBQ0ssWUFBWSxDQUFDLE1BQXFCO1FBQ3hDLElBQUksQ0FBQztZQUNILE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUNqRSxFQUFFLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsS0FBSyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBRWxELHlCQUF5QjtZQUN6QixJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUMxQixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMseUJBQXlCLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDbEQsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLGdCQUFnQjtRQUN0QixJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDO1lBQUUsT0FBTztRQUUzQyxJQUFJLENBQUM7WUFDSCxNQUFNLE9BQU8sR0FBRyxFQUFFLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDekQsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUV4RCxJQUFJLEtBQUssQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFnQixFQUFFLENBQUM7Z0JBQ2hELE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWdCLENBQUMsQ0FBQztnQkFDM0QsRUFBRSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQ3ZFLENBQUM7UUFDSCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsK0JBQStCLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDeEQsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNJLGdCQUFnQixDQUFDLEtBQWM7UUFDcEMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQztZQUFFLE9BQU8sRUFBRSxDQUFDO1FBRTlDLElBQUksQ0FBQztZQUNILE1BQU0sT0FBTyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsQ0FBQztZQUN6RCxNQUFNLE9BQU8sR0FBRyxPQUFPO2lCQUNwQixLQUFLLENBQUMsSUFBSSxDQUFDO2lCQUNYLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztpQkFDckIsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQWdCLENBQUMsQ0FBQztZQUUxQyxJQUFJLEtBQUssRUFBRSxDQUFDO2dCQUNWLE9BQU8sT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQy9CLENBQUM7WUFFRCxPQUFPLE9BQU8sQ0FBQztRQUNqQixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsK0JBQStCLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDdEQsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ksYUFBYTtRQUNsQixJQUFJLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7WUFDckMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDbkMsQ0FBQztRQUVELElBQUksRUFBRSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztZQUNsQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNoQyxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ksYUFBYTtRQVFsQixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDckMsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRS9DLE9BQU87WUFDTCxXQUFXLEVBQUUsUUFBUSxLQUFLLElBQUk7WUFDOUIsV0FBVyxFQUFFLFFBQVEsRUFBRSxXQUFXLElBQUksQ0FBQztZQUN2QyxTQUFTLEVBQUUsUUFBUSxFQUFFLFNBQVM7WUFDOUIsU0FBUyxFQUFFLFFBQVEsRUFBRSxTQUFTO1lBQzlCLGdCQUFnQixFQUFFLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLE1BQU07WUFDaEQsWUFBWSxFQUFFLFlBQVk7U0FDM0IsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNJLFNBQVM7UUFDZCxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDdkIsQ0FBQztDQUNGO0FBOVRELDBDQThUQztBQUVEOztHQUVHO0FBQ0gsSUFBSSxjQUFjLEdBQTJCLElBQUksQ0FBQztBQUVsRDs7R0FFRztBQUNILFNBQWdCLGtCQUFrQixDQUFDLE1BQWdDO0lBQ2pFLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUNwQixjQUFjLEdBQUcsSUFBSSxlQUFlLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUNELE9BQU8sY0FBYyxDQUFDO0FBQ3hCLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLG9CQUFvQjtJQUNsQyxjQUFjLEdBQUcsSUFBSSxDQUFDO0FBQ3hCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEJhc2VsaW5lIERyaWZ0IFN0b3JhZ2UgYW5kIENhbGlicmF0aW9uXG4gKiBcbiAqIFRyYWNrcyBiYXNlbGluZSBtZXRyaWNzIGFuZCBkZXRlY3RzIGRyaWZ0IG92ZXIgdGltZVxuICogXG4gKiBAbW9kdWxlIGJhc2VsaW5lL3N0b3JhZ2VcbiAqL1xuXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0ICogYXMgb3MgZnJvbSAnb3MnO1xuXG4vKipcbiAqIEJhc2VsaW5lIG1ldHJpY3NcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCYXNlbGluZU1ldHJpY3Mge1xuICB2ZXJzaW9uOiBzdHJpbmc7XG4gIGNyZWF0ZWRBdDogc3RyaW5nO1xuICB1cGRhdGVkQXQ6IHN0cmluZztcbiAgc2FtcGxlQ291bnQ6IG51bWJlcjtcbiAgbWV0cmljczoge1xuICAgIGF2ZXJhZ2VMYXRlbmN5OiBudW1iZXI7XG4gICAgYXZlcmFnZUNvbnRlbnRMZW5ndGg6IG51bWJlcjtcbiAgICBhdmVyYWdlUmlza1Njb3JlOiBudW1iZXI7XG4gICAgcmlza0Rpc3RyaWJ1dGlvbjoge1xuICAgICAgbG93OiBudW1iZXI7XG4gICAgICBtb2RlcmF0ZTogbnVtYmVyO1xuICAgICAgaGlnaDogbnVtYmVyO1xuICAgICAgY3JpdGljYWw6IG51bWJlcjtcbiAgICB9O1xuICAgIGVuZ2luZVNjb3Jlczoge1xuICAgICAgaGFsbHVjaW5hdGlvbj86IG51bWJlcjtcbiAgICAgIGNvbnNpc3RlbmN5PzogbnVtYmVyO1xuICAgICAgY3NtNj86IG51bWJlcjtcbiAgICB9O1xuICB9O1xufVxuXG4vKipcbiAqIERyaWZ0IHJlY29yZFxuICovXG5leHBvcnQgaW50ZXJmYWNlIERyaWZ0UmVjb3JkIHtcbiAgdGltZXN0YW1wOiBzdHJpbmc7XG4gIG1ldHJpYzogc3RyaW5nO1xuICBiYXNlbGluZTogbnVtYmVyO1xuICBjdXJyZW50OiBudW1iZXI7XG4gIGRyaWZ0OiBudW1iZXI7XG4gIGRyaWZ0UGVyY2VudDogbnVtYmVyO1xuICBzZXZlcml0eTogJ21pbm9yJyB8ICdtb2RlcmF0ZScgfCAnc2lnbmlmaWNhbnQnO1xufVxuXG4vKipcbiAqIEJhc2VsaW5lIGNvbmZpZ3VyYXRpb25cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCYXNlbGluZUNvbmZpZyB7XG4gIGJhc2VsaW5lRGlyPzogc3RyaW5nO1xuICBkcmlmdFRocmVzaG9sZD86IG51bWJlcjsgLy8gcGVyY2VudGFnZVxuICBtYXhEcmlmdEhpc3Rvcnk/OiBudW1iZXI7XG4gIGF1dG9DYWxpYnJhdGU/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIERlZmF1bHQgY29uZmlndXJhdGlvblxuICovXG5jb25zdCBERUZBVUxUX0NPTkZJRzogQmFzZWxpbmVDb25maWcgPSB7XG4gIGJhc2VsaW5lRGlyOiBwYXRoLmpvaW4ob3MuaG9tZWRpcigpLCAnLmxsbXZlcmlmeScsICdiYXNlbGluZScpLFxuICBkcmlmdFRocmVzaG9sZDogMjAsIC8vIDIwJSBkcmlmdCB0cmlnZ2VycyB3YXJuaW5nXG4gIG1heERyaWZ0SGlzdG9yeTogMTAwMCxcbiAgYXV0b0NhbGlicmF0ZTogZmFsc2Vcbn07XG5cbi8qKlxuICogQmFzZWxpbmUgc3RvcmFnZSBjbGFzc1xuICovXG5leHBvcnQgY2xhc3MgQmFzZWxpbmVTdG9yYWdlIHtcbiAgcHJpdmF0ZSBjb25maWc6IEJhc2VsaW5lQ29uZmlnO1xuICBwcml2YXRlIGJhc2VsaW5lRmlsZTogc3RyaW5nO1xuICBwcml2YXRlIGRyaWZ0RmlsZTogc3RyaW5nO1xuICBcbiAgY29uc3RydWN0b3IoY29uZmlnPzogUGFydGlhbDxCYXNlbGluZUNvbmZpZz4pIHtcbiAgICB0aGlzLmNvbmZpZyA9IHsgLi4uREVGQVVMVF9DT05GSUcsIC4uLmNvbmZpZyB9O1xuICAgIHRoaXMuYmFzZWxpbmVGaWxlID0gcGF0aC5qb2luKHRoaXMuY29uZmlnLmJhc2VsaW5lRGlyISwgJ2Jhc2VsaW5lLmpzb24nKTtcbiAgICB0aGlzLmRyaWZ0RmlsZSA9IHBhdGguam9pbih0aGlzLmNvbmZpZy5iYXNlbGluZURpciEsICdkcmlmdC1oaXN0b3J5Lmpzb25sJyk7XG4gICAgdGhpcy5lbnN1cmVEaXJlY3RvcnkoKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEVuc3VyZSBiYXNlbGluZSBkaXJlY3RvcnkgZXhpc3RzXG4gICAqL1xuICBwcml2YXRlIGVuc3VyZURpcmVjdG9yeSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5jb25maWcuYmFzZWxpbmVEaXIpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGZzLm1rZGlyU3luYyh0aGlzLmNvbmZpZy5iYXNlbGluZURpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKCdGYWlsZWQgdG8gY3JlYXRlIGJhc2VsaW5lIGRpcmVjdG9yeTonLCBlcnJvcik7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogTG9hZCBiYXNlbGluZSBtZXRyaWNzXG4gICAqL1xuICBwdWJsaWMgbG9hZEJhc2VsaW5lKCk6IEJhc2VsaW5lTWV0cmljcyB8IG51bGwge1xuICAgIGlmICghZnMuZXhpc3RzU3luYyh0aGlzLmJhc2VsaW5lRmlsZSkpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBcbiAgICB0cnkge1xuICAgICAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyh0aGlzLmJhc2VsaW5lRmlsZSwgJ3V0Zi04Jyk7XG4gICAgICByZXR1cm4gSlNPTi5wYXJzZShjb250ZW50KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRmFpbGVkIHRvIGxvYWQgYmFzZWxpbmU6JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogU2F2ZSBiYXNlbGluZSBtZXRyaWNzXG4gICAqL1xuICBwdWJsaWMgc2F2ZUJhc2VsaW5lKGJhc2VsaW5lOiBCYXNlbGluZU1ldHJpY3MpOiB2b2lkIHtcbiAgICB0cnkge1xuICAgICAgZnMud3JpdGVGaWxlU3luYyhcbiAgICAgICAgdGhpcy5iYXNlbGluZUZpbGUsXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KGJhc2VsaW5lLCBudWxsLCAyKSxcbiAgICAgICAgJ3V0Zi04J1xuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRmFpbGVkIHRvIHNhdmUgYmFzZWxpbmU6JywgZXJyb3IpO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFVwZGF0ZSBiYXNlbGluZSB3aXRoIG5ldyBzYW1wbGVcbiAgICovXG4gIHB1YmxpYyB1cGRhdGVCYXNlbGluZShzYW1wbGU6IHtcbiAgICBsYXRlbmN5OiBudW1iZXI7XG4gICAgY29udGVudExlbmd0aDogbnVtYmVyO1xuICAgIHJpc2tTY29yZTogbnVtYmVyO1xuICAgIHJpc2tMZXZlbDogc3RyaW5nO1xuICAgIGVuZ2luZVNjb3Jlcz86IHtcbiAgICAgIGhhbGx1Y2luYXRpb24/OiBudW1iZXI7XG4gICAgICBjb25zaXN0ZW5jeT86IG51bWJlcjtcbiAgICAgIGNzbTY/OiBudW1iZXI7XG4gICAgfTtcbiAgfSk6IEJhc2VsaW5lTWV0cmljcyB7XG4gICAgbGV0IGJhc2VsaW5lID0gdGhpcy5sb2FkQmFzZWxpbmUoKTtcbiAgICBcbiAgICBpZiAoIWJhc2VsaW5lKSB7XG4gICAgICAvLyBDcmVhdGUgbmV3IGJhc2VsaW5lXG4gICAgICBiYXNlbGluZSA9IHtcbiAgICAgICAgdmVyc2lvbjogJzEuMC4wJyxcbiAgICAgICAgY3JlYXRlZEF0OiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICAgIHVwZGF0ZWRBdDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICBzYW1wbGVDb3VudDogMCxcbiAgICAgICAgbWV0cmljczoge1xuICAgICAgICAgIGF2ZXJhZ2VMYXRlbmN5OiAwLFxuICAgICAgICAgIGF2ZXJhZ2VDb250ZW50TGVuZ3RoOiAwLFxuICAgICAgICAgIGF2ZXJhZ2VSaXNrU2NvcmU6IDAsXG4gICAgICAgICAgcmlza0Rpc3RyaWJ1dGlvbjoge1xuICAgICAgICAgICAgbG93OiAwLFxuICAgICAgICAgICAgbW9kZXJhdGU6IDAsXG4gICAgICAgICAgICBoaWdoOiAwLFxuICAgICAgICAgICAgY3JpdGljYWw6IDBcbiAgICAgICAgICB9LFxuICAgICAgICAgIGVuZ2luZVNjb3Jlczoge31cbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9XG4gICAgXG4gICAgLy8gVXBkYXRlIHNhbXBsZSBjb3VudFxuICAgIGNvbnN0IG4gPSBiYXNlbGluZS5zYW1wbGVDb3VudDtcbiAgICBiYXNlbGluZS5zYW1wbGVDb3VudCA9IG4gKyAxO1xuICAgIFxuICAgIC8vIFVwZGF0ZSBydW5uaW5nIGF2ZXJhZ2VzIHVzaW5nIGluY3JlbWVudGFsIG1lYW4gZm9ybXVsYVxuICAgIGJhc2VsaW5lLm1ldHJpY3MuYXZlcmFnZUxhdGVuY3kgPSBcbiAgICAgIChiYXNlbGluZS5tZXRyaWNzLmF2ZXJhZ2VMYXRlbmN5ICogbiArIHNhbXBsZS5sYXRlbmN5KSAvIChuICsgMSk7XG4gICAgXG4gICAgYmFzZWxpbmUubWV0cmljcy5hdmVyYWdlQ29udGVudExlbmd0aCA9IFxuICAgICAgKGJhc2VsaW5lLm1ldHJpY3MuYXZlcmFnZUNvbnRlbnRMZW5ndGggKiBuICsgc2FtcGxlLmNvbnRlbnRMZW5ndGgpIC8gKG4gKyAxKTtcbiAgICBcbiAgICBiYXNlbGluZS5tZXRyaWNzLmF2ZXJhZ2VSaXNrU2NvcmUgPSBcbiAgICAgIChiYXNlbGluZS5tZXRyaWNzLmF2ZXJhZ2VSaXNrU2NvcmUgKiBuICsgc2FtcGxlLnJpc2tTY29yZSkgLyAobiArIDEpO1xuICAgIFxuICAgIC8vIFVwZGF0ZSByaXNrIGRpc3RyaWJ1dGlvblxuICAgIGNvbnN0IHJpc2tLZXkgPSBzYW1wbGUucmlza0xldmVsIGFzIGtleW9mIHR5cGVvZiBiYXNlbGluZS5tZXRyaWNzLnJpc2tEaXN0cmlidXRpb247XG4gICAgaWYgKHJpc2tLZXkgaW4gYmFzZWxpbmUubWV0cmljcy5yaXNrRGlzdHJpYnV0aW9uKSB7XG4gICAgICBiYXNlbGluZS5tZXRyaWNzLnJpc2tEaXN0cmlidXRpb25bcmlza0tleV0rKztcbiAgICB9XG4gICAgXG4gICAgLy8gVXBkYXRlIGVuZ2luZSBzY29yZXNcbiAgICBpZiAoc2FtcGxlLmVuZ2luZVNjb3Jlcykge1xuICAgICAgZm9yIChjb25zdCBbZW5naW5lLCBzY29yZV0gb2YgT2JqZWN0LmVudHJpZXMoc2FtcGxlLmVuZ2luZVNjb3JlcykpIHtcbiAgICAgICAgaWYgKHNjb3JlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBjb25zdCBjdXJyZW50U2NvcmUgPSAoYmFzZWxpbmUubWV0cmljcy5lbmdpbmVTY29yZXMgYXMgYW55KVtlbmdpbmVdIHx8IDA7XG4gICAgICAgICAgKGJhc2VsaW5lLm1ldHJpY3MuZW5naW5lU2NvcmVzIGFzIGFueSlbZW5naW5lXSA9IFxuICAgICAgICAgICAgKGN1cnJlbnRTY29yZSAqIG4gKyBzY29yZSkgLyAobiArIDEpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIGJhc2VsaW5lLnVwZGF0ZWRBdCA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKTtcbiAgICBcbiAgICB0aGlzLnNhdmVCYXNlbGluZShiYXNlbGluZSk7XG4gICAgcmV0dXJuIGJhc2VsaW5lO1xuICB9XG4gIFxuICAvKipcbiAgICogQ2hlY2sgZm9yIGRyaWZ0XG4gICAqL1xuICBwdWJsaWMgY2hlY2tEcmlmdChjdXJyZW50OiB7XG4gICAgbGF0ZW5jeT86IG51bWJlcjtcbiAgICBjb250ZW50TGVuZ3RoPzogbnVtYmVyO1xuICAgIHJpc2tTY29yZT86IG51bWJlcjtcbiAgfSk6IERyaWZ0UmVjb3JkW10ge1xuICAgIGNvbnN0IGJhc2VsaW5lID0gdGhpcy5sb2FkQmFzZWxpbmUoKTtcbiAgICBpZiAoIWJhc2VsaW5lKSByZXR1cm4gW107XG4gICAgXG4gICAgY29uc3QgZHJpZnRzOiBEcmlmdFJlY29yZFtdID0gW107XG4gICAgY29uc3QgdGhyZXNob2xkID0gdGhpcy5jb25maWcuZHJpZnRUaHJlc2hvbGQhO1xuICAgIFxuICAgIC8vIENoZWNrIGxhdGVuY3kgZHJpZnRcbiAgICBpZiAoY3VycmVudC5sYXRlbmN5ICE9PSB1bmRlZmluZWQgJiYgYmFzZWxpbmUubWV0cmljcy5hdmVyYWdlTGF0ZW5jeSA+IDApIHtcbiAgICAgIGNvbnN0IGRyaWZ0ID0gY3VycmVudC5sYXRlbmN5IC0gYmFzZWxpbmUubWV0cmljcy5hdmVyYWdlTGF0ZW5jeTtcbiAgICAgIGNvbnN0IGRyaWZ0UGVyY2VudCA9IChkcmlmdCAvIGJhc2VsaW5lLm1ldHJpY3MuYXZlcmFnZUxhdGVuY3kpICogMTAwO1xuICAgICAgXG4gICAgICBpZiAoTWF0aC5hYnMoZHJpZnRQZXJjZW50KSA+IHRocmVzaG9sZCkge1xuICAgICAgICBkcmlmdHMucHVzaCh7XG4gICAgICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICAgICAgbWV0cmljOiAnbGF0ZW5jeScsXG4gICAgICAgICAgYmFzZWxpbmU6IGJhc2VsaW5lLm1ldHJpY3MuYXZlcmFnZUxhdGVuY3ksXG4gICAgICAgICAgY3VycmVudDogY3VycmVudC5sYXRlbmN5LFxuICAgICAgICAgIGRyaWZ0LFxuICAgICAgICAgIGRyaWZ0UGVyY2VudCxcbiAgICAgICAgICBzZXZlcml0eTogdGhpcy5nZXREcmlmdFNldmVyaXR5KE1hdGguYWJzKGRyaWZ0UGVyY2VudCkpXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICAvLyBDaGVjayBjb250ZW50IGxlbmd0aCBkcmlmdFxuICAgIGlmIChjdXJyZW50LmNvbnRlbnRMZW5ndGggIT09IHVuZGVmaW5lZCAmJiBiYXNlbGluZS5tZXRyaWNzLmF2ZXJhZ2VDb250ZW50TGVuZ3RoID4gMCkge1xuICAgICAgY29uc3QgZHJpZnQgPSBjdXJyZW50LmNvbnRlbnRMZW5ndGggLSBiYXNlbGluZS5tZXRyaWNzLmF2ZXJhZ2VDb250ZW50TGVuZ3RoO1xuICAgICAgY29uc3QgZHJpZnRQZXJjZW50ID0gKGRyaWZ0IC8gYmFzZWxpbmUubWV0cmljcy5hdmVyYWdlQ29udGVudExlbmd0aCkgKiAxMDA7XG4gICAgICBcbiAgICAgIGlmIChNYXRoLmFicyhkcmlmdFBlcmNlbnQpID4gdGhyZXNob2xkKSB7XG4gICAgICAgIGRyaWZ0cy5wdXNoKHtcbiAgICAgICAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgICAgICBtZXRyaWM6ICdjb250ZW50TGVuZ3RoJyxcbiAgICAgICAgICBiYXNlbGluZTogYmFzZWxpbmUubWV0cmljcy5hdmVyYWdlQ29udGVudExlbmd0aCxcbiAgICAgICAgICBjdXJyZW50OiBjdXJyZW50LmNvbnRlbnRMZW5ndGgsXG4gICAgICAgICAgZHJpZnQsXG4gICAgICAgICAgZHJpZnRQZXJjZW50LFxuICAgICAgICAgIHNldmVyaXR5OiB0aGlzLmdldERyaWZ0U2V2ZXJpdHkoTWF0aC5hYnMoZHJpZnRQZXJjZW50KSlcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIENoZWNrIHJpc2sgc2NvcmUgZHJpZnRcbiAgICBpZiAoY3VycmVudC5yaXNrU2NvcmUgIT09IHVuZGVmaW5lZCAmJiBiYXNlbGluZS5tZXRyaWNzLmF2ZXJhZ2VSaXNrU2NvcmUgPiAwKSB7XG4gICAgICBjb25zdCBkcmlmdCA9IGN1cnJlbnQucmlza1Njb3JlIC0gYmFzZWxpbmUubWV0cmljcy5hdmVyYWdlUmlza1Njb3JlO1xuICAgICAgY29uc3QgZHJpZnRQZXJjZW50ID0gKGRyaWZ0IC8gYmFzZWxpbmUubWV0cmljcy5hdmVyYWdlUmlza1Njb3JlKSAqIDEwMDtcbiAgICAgIFxuICAgICAgaWYgKE1hdGguYWJzKGRyaWZ0UGVyY2VudCkgPiB0aHJlc2hvbGQpIHtcbiAgICAgICAgZHJpZnRzLnB1c2goe1xuICAgICAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICAgIG1ldHJpYzogJ3Jpc2tTY29yZScsXG4gICAgICAgICAgYmFzZWxpbmU6IGJhc2VsaW5lLm1ldHJpY3MuYXZlcmFnZVJpc2tTY29yZSxcbiAgICAgICAgICBjdXJyZW50OiBjdXJyZW50LnJpc2tTY29yZSxcbiAgICAgICAgICBkcmlmdCxcbiAgICAgICAgICBkcmlmdFBlcmNlbnQsXG4gICAgICAgICAgc2V2ZXJpdHk6IHRoaXMuZ2V0RHJpZnRTZXZlcml0eShNYXRoLmFicyhkcmlmdFBlcmNlbnQpKVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gUmVjb3JkIGRyaWZ0c1xuICAgIGlmIChkcmlmdHMubGVuZ3RoID4gMCkge1xuICAgICAgdGhpcy5yZWNvcmREcmlmdHMoZHJpZnRzKTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGRyaWZ0cztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBkcmlmdCBzZXZlcml0eVxuICAgKi9cbiAgcHJpdmF0ZSBnZXREcmlmdFNldmVyaXR5KGRyaWZ0UGVyY2VudDogbnVtYmVyKTogJ21pbm9yJyB8ICdtb2RlcmF0ZScgfCAnc2lnbmlmaWNhbnQnIHtcbiAgICBpZiAoZHJpZnRQZXJjZW50IDwgMzApIHJldHVybiAnbWlub3InO1xuICAgIGlmIChkcmlmdFBlcmNlbnQgPCA1MCkgcmV0dXJuICdtb2RlcmF0ZSc7XG4gICAgcmV0dXJuICdzaWduaWZpY2FudCc7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZWNvcmQgZHJpZnQgaGlzdG9yeVxuICAgKi9cbiAgcHJpdmF0ZSByZWNvcmREcmlmdHMoZHJpZnRzOiBEcmlmdFJlY29yZFtdKTogdm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGxpbmVzID0gZHJpZnRzLm1hcChkID0+IEpTT04uc3RyaW5naWZ5KGQpICsgJ1xcbicpLmpvaW4oJycpO1xuICAgICAgZnMuYXBwZW5kRmlsZVN5bmModGhpcy5kcmlmdEZpbGUsIGxpbmVzLCAndXRmLTgnKTtcbiAgICAgIFxuICAgICAgLy8gVHJpbSBoaXN0b3J5IGlmIG5lZWRlZFxuICAgICAgdGhpcy50cmltRHJpZnRIaXN0b3J5KCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0ZhaWxlZCB0byByZWNvcmQgZHJpZnQ6JywgZXJyb3IpO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFRyaW0gZHJpZnQgaGlzdG9yeSB0byBtYXggc2l6ZVxuICAgKi9cbiAgcHJpdmF0ZSB0cmltRHJpZnRIaXN0b3J5KCk6IHZvaWQge1xuICAgIGlmICghZnMuZXhpc3RzU3luYyh0aGlzLmRyaWZ0RmlsZSkpIHJldHVybjtcbiAgICBcbiAgICB0cnkge1xuICAgICAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyh0aGlzLmRyaWZ0RmlsZSwgJ3V0Zi04Jyk7XG4gICAgICBjb25zdCBsaW5lcyA9IGNvbnRlbnQuc3BsaXQoJ1xcbicpLmZpbHRlcihsID0+IGwudHJpbSgpKTtcbiAgICAgIFxuICAgICAgaWYgKGxpbmVzLmxlbmd0aCA+IHRoaXMuY29uZmlnLm1heERyaWZ0SGlzdG9yeSEpIHtcbiAgICAgICAgY29uc3QgdHJpbW1lZCA9IGxpbmVzLnNsaWNlKC10aGlzLmNvbmZpZy5tYXhEcmlmdEhpc3RvcnkhKTtcbiAgICAgICAgZnMud3JpdGVGaWxlU3luYyh0aGlzLmRyaWZ0RmlsZSwgdHJpbW1lZC5qb2luKCdcXG4nKSArICdcXG4nLCAndXRmLTgnKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRmFpbGVkIHRvIHRyaW0gZHJpZnQgaGlzdG9yeTonLCBlcnJvcik7XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogUmVhZCBkcmlmdCBoaXN0b3J5XG4gICAqL1xuICBwdWJsaWMgcmVhZERyaWZ0SGlzdG9yeShsaW1pdD86IG51bWJlcik6IERyaWZ0UmVjb3JkW10ge1xuICAgIGlmICghZnMuZXhpc3RzU3luYyh0aGlzLmRyaWZ0RmlsZSkpIHJldHVybiBbXTtcbiAgICBcbiAgICB0cnkge1xuICAgICAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyh0aGlzLmRyaWZ0RmlsZSwgJ3V0Zi04Jyk7XG4gICAgICBjb25zdCByZWNvcmRzID0gY29udGVudFxuICAgICAgICAuc3BsaXQoJ1xcbicpXG4gICAgICAgIC5maWx0ZXIobCA9PiBsLnRyaW0oKSlcbiAgICAgICAgLm1hcChsID0+IEpTT04ucGFyc2UobCkgYXMgRHJpZnRSZWNvcmQpO1xuICAgICAgXG4gICAgICBpZiAobGltaXQpIHtcbiAgICAgICAgcmV0dXJuIHJlY29yZHMuc2xpY2UoLWxpbWl0KTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgcmV0dXJuIHJlY29yZHM7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0ZhaWxlZCB0byByZWFkIGRyaWZ0IGhpc3Rvcnk6JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFJlc2V0IGJhc2VsaW5lXG4gICAqL1xuICBwdWJsaWMgcmVzZXRCYXNlbGluZSgpOiB2b2lkIHtcbiAgICBpZiAoZnMuZXhpc3RzU3luYyh0aGlzLmJhc2VsaW5lRmlsZSkpIHtcbiAgICAgIGZzLnVubGlua1N5bmModGhpcy5iYXNlbGluZUZpbGUpO1xuICAgIH1cbiAgICBcbiAgICBpZiAoZnMuZXhpc3RzU3luYyh0aGlzLmRyaWZ0RmlsZSkpIHtcbiAgICAgIGZzLnVubGlua1N5bmModGhpcy5kcmlmdEZpbGUpO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBiYXNlbGluZSBzdGF0aXN0aWNzXG4gICAqL1xuICBwdWJsaWMgZ2V0U3RhdGlzdGljcygpOiB7XG4gICAgaGFzQmFzZWxpbmU6IGJvb2xlYW47XG4gICAgc2FtcGxlQ291bnQ6IG51bWJlcjtcbiAgICBjcmVhdGVkQXQ/OiBzdHJpbmc7XG4gICAgdXBkYXRlZEF0Pzogc3RyaW5nO1xuICAgIGRyaWZ0UmVjb3JkQ291bnQ6IG51bWJlcjtcbiAgICByZWNlbnREcmlmdHM6IERyaWZ0UmVjb3JkW107XG4gIH0ge1xuICAgIGNvbnN0IGJhc2VsaW5lID0gdGhpcy5sb2FkQmFzZWxpbmUoKTtcbiAgICBjb25zdCBkcmlmdEhpc3RvcnkgPSB0aGlzLnJlYWREcmlmdEhpc3RvcnkoMTApO1xuICAgIFxuICAgIHJldHVybiB7XG4gICAgICBoYXNCYXNlbGluZTogYmFzZWxpbmUgIT09IG51bGwsXG4gICAgICBzYW1wbGVDb3VudDogYmFzZWxpbmU/LnNhbXBsZUNvdW50IHx8IDAsXG4gICAgICBjcmVhdGVkQXQ6IGJhc2VsaW5lPy5jcmVhdGVkQXQsXG4gICAgICB1cGRhdGVkQXQ6IGJhc2VsaW5lPy51cGRhdGVkQXQsXG4gICAgICBkcmlmdFJlY29yZENvdW50OiB0aGlzLnJlYWREcmlmdEhpc3RvcnkoKS5sZW5ndGgsXG4gICAgICByZWNlbnREcmlmdHM6IGRyaWZ0SGlzdG9yeVxuICAgIH07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDYWxpYnJhdGUgYmFzZWxpbmUgKHJlc2V0IGFuZCBzdGFydCBmcmVzaClcbiAgICovXG4gIHB1YmxpYyBjYWxpYnJhdGUoKTogdm9pZCB7XG4gICAgdGhpcy5yZXNldEJhc2VsaW5lKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBHbG9iYWwgYmFzZWxpbmUgc3RvcmFnZSBpbnN0YW5jZVxuICovXG5sZXQgZ2xvYmFsQmFzZWxpbmU6IEJhc2VsaW5lU3RvcmFnZSB8IG51bGwgPSBudWxsO1xuXG4vKipcbiAqIEdldCBnbG9iYWwgYmFzZWxpbmUgc3RvcmFnZVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0QmFzZWxpbmVTdG9yYWdlKGNvbmZpZz86IFBhcnRpYWw8QmFzZWxpbmVDb25maWc+KTogQmFzZWxpbmVTdG9yYWdlIHtcbiAgaWYgKCFnbG9iYWxCYXNlbGluZSkge1xuICAgIGdsb2JhbEJhc2VsaW5lID0gbmV3IEJhc2VsaW5lU3RvcmFnZShjb25maWcpO1xuICB9XG4gIHJldHVybiBnbG9iYWxCYXNlbGluZTtcbn1cblxuLyoqXG4gKiBSZXNldCBnbG9iYWwgYmFzZWxpbmUgc3RvcmFnZVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzZXRCYXNlbGluZVN0b3JhZ2UoKTogdm9pZCB7XG4gIGdsb2JhbEJhc2VsaW5lID0gbnVsbDtcbn1cbiJdfQ==