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
JavaScript
;
/**
* 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==