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.

305 lines 38.2 kB
"use strict"; /** * llmverify - Main Verification Function * * AI Output Verification with honest limitations. * Local-first, privacy-preserving, transparent. * * @module verify * @author Haiec * @license MIT */ Object.defineProperty(exports, "__esModule", { value: true }); exports.verify = verify; const uuid_1 = require("uuid"); const config_1 = require("./types/config"); const constants_1 = require("./constants"); const errors_1 = require("./errors"); const codes_1 = require("./errors/codes"); const hallucination_1 = require("./engines/hallucination"); const consistency_1 = require("./engines/consistency"); const json_validator_1 = require("./engines/json-validator"); const baseline_1 = require("./csm6/baseline"); const risk_scoring_1 = require("./engines/risk-scoring"); const config_2 = require("./config"); const logger_1 = require("./logging/logger"); const audit_1 = require("./logging/audit"); const storage_1 = require("./baseline/storage"); const registry_1 = require("./plugins/registry"); /** * Main verification function * * PRIVACY GUARANTEE: Free tier never makes network requests. * All processing is local unless explicit API key is provided. * * @param options - Verification options * @returns Complete verification result with limitations * * @example * ```typescript * const result = await verify({ * content: "The Earth is flat." * }); * * console.log(result.risk.level); // "moderate" * console.log(result.limitations); // ["Pattern-based detection only", ...] * ``` */ async function verify(options) { const startTime = Date.now(); const verificationId = (0, uuid_1.v4)(); // Initialize logging const logger = (0, logger_1.getLogger)(); const auditLogger = (0, audit_1.getAuditLogger)(); const requestId = logger.startRequest(); logger.info('Verification started', { requestId, contentLength: options.content.length, hasContext: !!options.context }); // Load config from file/env, then merge with runtime options const baseConfig = (0, config_2.loadConfig)(options.config); const config = mergeConfig(baseConfig); // CRITICAL: Validate privacy compliance validatePrivacyCompliance(config); // Validate input validateInput(options.content, config); const result = { limitations: [], notChecked: [] }; const enginesUsed = []; try { const enginePromises = []; // Hallucination detection if (config.engines.hallucination.enabled && !options.context?.skipEngines?.includes('hallucination')) { const engine = new hallucination_1.HallucinationEngine(config); enginesUsed.push('hallucination'); enginePromises.push(engine.detect(options.content).then(res => { result.hallucination = res; result.limitations?.push(...res.limitations); })); } else { result.notChecked?.push('hallucination'); } // Consistency check if (config.engines.consistency.enabled && !options.context?.skipEngines?.includes('consistency')) { const engine = new consistency_1.ConsistencyEngine(config); enginesUsed.push('consistency'); enginePromises.push(engine.check(options.content).then(res => { result.consistency = res; result.limitations?.push(...res.limitations); })); } else { result.notChecked?.push('consistency'); } // JSON validation if (config.engines.jsonValidator.enabled && options.context?.isJSON && !options.context?.skipEngines?.includes('json')) { const engine = new json_validator_1.JSONValidatorEngine(config); enginesUsed.push('json'); enginePromises.push(engine.validate(options.content, options.context?.expectedSchema).then(res => { result.json = res; result.limitations?.push(...res.limitations); })); } // CSM6 checks if (config.engines.csm6.enabled && !options.context?.skipEngines?.includes('csm6')) { const engine = new baseline_1.CSM6Baseline(config); enginesUsed.push('csm6'); enginePromises.push(engine.audit(options.content, options.content).then(res => { result.csm6 = res; result.limitations?.push(...res.limitations); })); } else { result.notChecked?.push('csm6'); } // Wait for all engines await Promise.all(enginePromises); // Execute plugins const pluginRegistry = (0, registry_1.getPluginRegistry)(); const pluginResults = await pluginRegistry.executeAll({ content: options.content, prompt: options.context?.isJSON ? 'JSON validation' : undefined, config, metadata: { requestId } }); // Add plugin findings to result if (pluginResults.length > 0) { logger.info('Plugins executed', { requestId, pluginCount: pluginResults.length }); } // Calculate overall risk const riskEngine = new risk_scoring_1.RiskScoringEngine(config); result.risk = riskEngine.calculate(result); // De-duplicate limitations result.limitations = [...new Set(result.limitations)]; } catch (error) { logger.error('Verification failed', error, { requestId, contentLength: options.content.length }); throw new errors_1.VerificationError(`Verification failed: ${error.message}`); } const endTime = Date.now(); const duration = logger.endRequest() || (endTime - startTime); // Log completion logger.info('Verification completed', { requestId, duration, riskLevel: result.risk?.level, findingsCount: result.csm6?.findings?.length || 0 }); // Audit trail auditLogger.logVerification({ requestId, content: options.content, prompt: options.context?.isJSON ? 'JSON validation' : undefined, riskLevel: result.risk?.level || 'unknown', findingsCount: result.csm6?.findings?.length || 0, blocked: result.risk?.action === 'block', duration, enginesUsed, configTier: config.tier }); // Baseline tracking and drift detection const baselineStorage = (0, storage_1.getBaselineStorage)(); baselineStorage.updateBaseline({ latency: duration, contentLength: options.content.length, riskScore: result.risk?.overall || 0, riskLevel: result.risk?.level || 'low', engineScores: { hallucination: result.hallucination?.riskScore, consistency: result.consistency?.score || 0, csm6: result.csm6?.riskScore } }); // Check for drift const drifts = baselineStorage.checkDrift({ latency: duration, contentLength: options.content.length, riskScore: result.risk?.overall || 0 }); if (drifts.length > 0) { logger.warn('Baseline drift detected', { requestId, drifts: drifts.map(d => ({ metric: d.metric, driftPercent: d.driftPercent.toFixed(2) + '%', severity: d.severity })) }); } return { ...result, risk: result.risk, meta: { verification_id: verificationId, timestamp: new Date().toISOString(), latency_ms: endTime - startTime, version: constants_1.VERSION, tier: config.tier, enginesUsed }, limitations: result.limitations, notChecked: result.notChecked }; } /** * Merge user config with defaults and tier limits */ function mergeConfig(userConfig) { const tier = userConfig?.tier || 'free'; const tierConfig = config_1.TIER_LIMITS[tier]; // Deep merge const merged = { ...config_1.DEFAULT_CONFIG, ...userConfig, tier, privacy: { ...config_1.DEFAULT_CONFIG.privacy, ...userConfig?.privacy }, engines: { ...config_1.DEFAULT_CONFIG.engines, ...userConfig?.engines, csm6: { ...config_1.DEFAULT_CONFIG.engines.csm6, ...userConfig?.engines?.csm6, checks: { ...config_1.DEFAULT_CONFIG.engines.csm6.checks, ...userConfig?.engines?.csm6?.checks } } }, performance: { ...config_1.DEFAULT_CONFIG.performance, ...tierConfig?.performance, ...userConfig?.performance }, output: { ...config_1.DEFAULT_CONFIG.output, ...userConfig?.output, includeLimitations: true // ALWAYS true } }; return merged; } /** * CRITICAL: Validate privacy compliance */ function validatePrivacyCompliance(config) { // Free tier must never allow network requests if (config.tier === 'free' && config.privacy.allowNetworkRequests) { throw new errors_1.PrivacyViolationError('Free tier cannot enable network requests. ' + 'This is a privacy violation. ' + 'Upgrade to Team tier for ML-enhanced features.'); } // Free tier must never have telemetry if (config.tier === 'free' && config.privacy.telemetryEnabled) { throw new errors_1.PrivacyViolationError('Free tier cannot enable telemetry. ' + 'This is a privacy violation.'); } } /** * Validate input with comprehensive checks */ function validateInput(content, config) { // Check for empty input if (!content || content.trim().length === 0) { throw new errors_1.ValidationError('Content cannot be empty', codes_1.ErrorCode.EMPTY_INPUT, { contentLength: content?.length || 0 }); } // Check for invalid characters if (!/^[\x00-\x7F\u0080-\uFFFF]*$/.test(content)) { throw new errors_1.ValidationError('Content contains invalid characters', codes_1.ErrorCode.INVALID_ENCODING, { contentLength: content.length }); } // Check tier limits const limits = config_1.TIER_LIMITS[config.tier]; if (content.length > (limits.performance?.maxContentLength || 100000)) { throw new errors_1.ValidationError(`Content exceeds tier limit (${limits.performance?.maxContentLength || 100000} chars). ` + `Current: ${content.length} chars. ` + `Upgrade to ${config.tier === 'free' ? 'Team' : 'Professional'} tier for higher limits.`, codes_1.ErrorCode.CONTENT_TOO_LARGE, { contentLength: content.length, maxLength: limits.performance?.maxContentLength || 100000, currentTier: config.tier, suggestedTier: config.tier === 'free' ? 'team' : 'professional' }); } // Absolute maximum safety check (prevent DoS) const ABSOLUTE_MAX = 10 * 1024 * 1024; // 10MB if (content.length > ABSOLUTE_MAX) { throw new errors_1.ValidationError(`Content exceeds absolute maximum size (${ABSOLUTE_MAX} bytes)`, codes_1.ErrorCode.CONTENT_TOO_LARGE, { contentLength: content.length, maxLength: ABSOLUTE_MAX }); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyaWZ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3ZlcmlmeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7OztHQVNHOztBQWdESCx3QkEwTUM7QUF4UEQsK0JBQW9DO0FBQ3BDLDJDQUFxRTtBQUVyRSwyQ0FBc0M7QUFDdEMscUNBQXFGO0FBQ3JGLDBDQUEyQztBQUMzQywyREFBOEQ7QUFDOUQsdURBQTBEO0FBQzFELDZEQUErRDtBQUMvRCw4Q0FBK0M7QUFDL0MseURBQTJEO0FBQzNELHFDQUFzQztBQUN0Qyw2Q0FBNkM7QUFDN0MsMkNBQWlEO0FBQ2pELGdEQUF3RDtBQUN4RCxpREFBdUQ7QUFZdkQ7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtCRztBQUNJLEtBQUssVUFBVSxNQUFNLENBQUMsT0FBc0I7SUFDakQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQzdCLE1BQU0sY0FBYyxHQUFHLElBQUEsU0FBTSxHQUFFLENBQUM7SUFFaEMscUJBQXFCO0lBQ3JCLE1BQU0sTUFBTSxHQUFHLElBQUEsa0JBQVMsR0FBRSxDQUFDO0lBQzNCLE1BQU0sV0FBVyxHQUFHLElBQUEsc0JBQWMsR0FBRSxDQUFDO0lBQ3JDLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUV4QyxNQUFNLENBQUMsSUFBSSxDQUFDLHNCQUFzQixFQUFFO1FBQ2xDLFNBQVM7UUFDVCxhQUFhLEVBQUUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNO1FBQ3JDLFVBQVUsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU87S0FDOUIsQ0FBQyxDQUFDO0lBRUgsNkRBQTZEO0lBQzdELE1BQU0sVUFBVSxHQUFHLElBQUEsbUJBQVUsRUFBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDOUMsTUFBTSxNQUFNLEdBQUcsV0FBVyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBRXZDLHdDQUF3QztJ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LEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLGNBQWMsMEJBQTBCLEVBQ3hGLGlCQUFTLENBQUMsaUJBQWlCLEVBQzNCO1lBQ0UsYUFBYSxFQUFFLE9BQU8sQ0FBQyxNQUFNO1lBQzdCLFNBQVMsRUFBRSxNQUFNLENBQUMsV0FBVyxFQUFFLGdCQUFnQixJQUFJLE1BQU07WUFDekQsV0FBVyxFQUFFLE1BQU0sQ0FBQyxJQUFJO1lBQ3hCLGFBQWEsRUFBRSxNQUFNLENBQUMsSUFBSSxLQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxjQUFjO1NBQ2hFLENBQ0YsQ0FBQztJQUNKLENBQUM7SUFFRCw4Q0FBOEM7SUFDOUMsTUFBTSxZQUFZLEdBQUcsRUFBRSxHQUFHLElBQUksR0FBRyxJQUFJLENBQUMsQ0FBQyxPQUFPO0lBQzlDLElBQUksT0FBTyxDQUFDLE1BQU0sR0FBRyxZQUFZLEVBQUUsQ0FBQztRQUNsQyxNQUFNLElBQUksd0JBQWUsQ0FDdkIsMENBQTBDLFlBQVksU0FBUyxFQUMvRCxpQkFBUyxDQUFDLGlCQUFpQixFQUMzQixFQUFFLGFBQWEsRUFBRSxPQUFPLENBQUMsTUFBTSxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsQ0FDM0QsQ0FBQztJQUNKLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBsbG12ZXJpZnkgLSBNYWluIFZlcmlmaWNhdGlvbiBGdW5jdGlvblxuICogXG4gKiBBSSBPdXRwdXQgVmVyaWZpY2F0aW9uIHdpdGggaG9uZXN0IGxpbWl0YXRpb25zLlxuICogTG9jYWwtZmlyc3QsIHByaXZhY3ktcHJlc2VydmluZywgdHJhbnNwYXJlbnQuXG4gKiBcbiAqIEBtb2R1bGUgdmVyaWZ5XG4gKiBAYXV0aG9yIEhhaWVjXG4gKiBAbGljZW5zZSBNSVRcbiAqL1xuXG5pbXBvcnQgeyB2NCBhcyB1dWlkdjQgfSBmcm9tICd1dWlkJztcbmltcG9ydCB7IENvbmZpZywgREVGQVVMVF9DT05GSUcsIFRJRVJfTElNSVRTIH0gZnJvbSAnLi90eXBlcy9jb25maWcnO1xuaW1wb3J0IHsgVmVyaWZ5UmVzdWx0IH0gZnJvbSAnLi90eXBlcy9yZXN1bHRzJztcbmltcG9ydCB7IFZFUlNJT04gfSBmcm9tICcuL2NvbnN0YW50cyc7XG5pbXBvcnQgeyBQcml2YWN5VmlvbGF0aW9uRXJyb3IsIFZhbGlkYXRpb25FcnJvciwgVmVyaWZpY2F0aW9uRXJyb3IgfSBmcm9tICcuL2Vycm9ycyc7XG5pbXBvcnQgeyBFcnJvckNvZGUgfSBmcm9tICcuL2Vycm9ycy9jb2Rlcyc7XG5pbXBvcnQgeyBIYWxsdWNpbmF0aW9uRW5naW5lIH0gZnJvbSAnLi9lbmdpbmVzL2hhbGx1Y2luYXRpb24nO1xuaW1wb3J0IHsgQ29uc2lzdGVuY3lFbmdpbmUgfSBmcm9tICcuL2VuZ2luZXMvY29uc2lzdGVuY3knO1xuaW1wb3J0IHsgSlNPTlZhbGlkYXRvckVuZ2luZSB9IGZyb20gJy4vZW5naW5lcy9qc29uLXZhbGlkYXRvcic7XG5pbXBvcnQgeyBDU002QmFzZWxpbmUgfSBmcm9tICcuL2NzbTYvYmFzZWxpbmUnO1xuaW1wb3J0IHsgUmlza1Njb3JpbmdFbmdpbmUgfSBmcm9tICcuL2VuZ2luZXMvcmlzay1zY29yaW5nJztcbmltcG9ydCB7IGxvYWRDb25maWcgfSBmcm9tICcuL2NvbmZpZyc7XG5pbXBvcnQgeyBnZXRMb2dnZXIgfSBmcm9tICcuL2xvZ2dpbmcvbG9nZ2VyJztcbmltcG9ydCB7IGdldEF1ZGl0TG9nZ2VyIH0gZnJvbSAnLi9sb2dnaW5nL2F1ZGl0JztcbmltcG9ydCB7IGdldEJhc2VsaW5lU3RvcmFnZSB9IGZyb20gJy4vYmFzZWxpbmUvc3RvcmFnZSc7XG5pbXBvcnQgeyBnZXRQbHVnaW5SZWdpc3RyeSB9IGZyb20gJy4vcGx1Z2lucy9yZWdpc3RyeSc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVmVyaWZ5T3B0aW9ucyB7XG4gIGNvbnRlbnQ6IHN0cmluZztcbiAgY29uZmlnPzogUGFydGlhbDxDb25maWc+O1xuICBjb250ZXh0Pzoge1xuICAgIGlzSlNPTj86IGJvb2xlYW47XG4gICAgZXhwZWN0ZWRTY2hlbWE/OiB1bmtub3duO1xuICAgIHNraXBFbmdpbmVzPzogc3RyaW5nW107XG4gIH07XG59XG5cbi8qKlxuICogTWFpbiB2ZXJpZmljYXRpb24gZnVuY3Rpb25cbiAqIFxuICogUFJJVkFDWSBHVUFSQU5URUU6IEZyZWUgdGllciBuZXZlciBtYWtlcyBuZXR3b3JrIHJlcXVlc3RzLlxuICogQWxsIHByb2Nlc3NpbmcgaXMgbG9jYWwgdW5sZXNzIGV4cGxpY2l0IEFQSSBrZXkgaXMgcHJvdmlkZWQuXG4gKiBcbiAqIEBwYXJhbSBvcHRpb25zIC0gVmVyaWZpY2F0aW9uIG9wdGlvbnNcbiAqIEByZXR1cm5zIENvbXBsZXRlIHZlcmlmaWNhdGlvbiByZXN1bHQgd2l0aCBsaW1pdGF0aW9uc1xuICogXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3QgcmVzdWx0ID0gYXdhaXQgdmVyaWZ5KHtcbiAqICAgY29udGVudDogXCJUaGUgRWFydGggaXMgZmxhdC5cIlxuICogfSk7XG4gKiBcbiAqIGNvbnNvbGUubG9nKHJlc3VsdC5yaXNrLmxldmVsKTsgLy8gXCJtb2RlcmF0ZVwiXG4gKiBjb25zb2xlLmxvZyhyZXN1bHQubGltaXRhdGlvbnMpOyAvLyBbXCJQYXR0ZXJuLWJhc2VkIGRldGVjdGlvbiBvbmx5XCIsIC4uLl1cbiAqIGBgYFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdmVyaWZ5KG9wdGlvbnM6IFZlcmlmeU9wdGlvbnMpOiBQcm9taXNlPFZlcmlmeVJlc3VsdD4ge1xuICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICBjb25zdCB2ZXJpZmljYXRpb25JZCA9IHV1aWR2NCgpO1xuICBcbiAgLy8gSW5pdGlhbGl6ZSBsb2dnaW5nXG4gIGNvbnN0IGxvZ2dlciA9IGdldExvZ2dlcigpO1xuICBjb25zdCBhdWRpdExvZ2dlciA9IGdldEF1ZGl0TG9nZ2VyKCk7XG4gIGNvbnN0IHJlcXVlc3RJZCA9IGxvZ2dlci5zdGFydFJlcXVlc3QoKTtcbiAgXG4gIGxvZ2dlci5pbmZvKCdWZXJpZmljYXRpb24gc3RhcnRlZCcsIHtcbiAgICByZXF1ZXN0SWQsXG4gICAgY29udGVudExlbmd0aDogb3B0aW9ucy5jb250ZW50Lmxlbmd0aCxcbiAgICBoYXNDb250ZXh0OiAhIW9wdGlvbnMuY29udGV4dFxuICB9KTtcbiAgXG4gIC8vIExvYWQgY29uZmlnIGZyb20gZmlsZS9lbnYsIHRoZW4gbWVyZ2Ugd2l0aCBydW50aW1lIG9wdGlvbnNcbiAgY29uc3QgYmFzZUNvbmZpZyA9IGxvYWRDb25maWcob3B0aW9ucy5jb25maWcpO1xuICBjb25zdCBjb25maWcgPSBtZXJnZUNvbmZpZyhiYXNlQ29uZmlnKTtcbiAgXG4gIC8vIENSSVRJQ0FMOiBWYWxpZGF0ZSBwcml2YWN5IGNvbXBsaWFuY2VcbiAgdmFsaWRhdGVQcml2YWN5Q29tcGxpYW5jZShjb25maWcpO1xuICBcbiAgLy8gVmFsaWRhdGUgaW5wdXRcbiAgdmFsaWRhdGVJbnB1dChvcHRpb25zLmNvbnRlbnQsIGNvbmZpZyk7XG4gIFxuICBjb25zdCByZXN1bHQ6IFBhcnRpYWw8VmVyaWZ5UmVzdWx0PiA9IHtcbiAgICBsaW1pdGF0aW9uczogW10sXG4gICAgbm90Q2hlY2tlZDogW11cbiAgfTtcbiAgXG4gIGNvbnN0IGVuZ2luZXNVc2VkOiBzdHJpbmdbXSA9IFtdO1xuICBcbiAgdHJ5IHtcbiAgICBjb25zdCBlbmdpbmVQcm9taXNlczogUHJvbWlzZTx2b2lkPltdID0gW107XG4gICAgXG4gICAgLy8gSGFsbHVjaW5hdGlvbiBkZXRlY3Rpb25cbiAgICBpZiAoY29uZmlnLmVuZ2luZXMuaGFsbHVjaW5hdGlvbi5lbmFibGVkICYmIFxuICAgICAgICAhb3B0aW9ucy5jb250ZXh0Py5za2lwRW5naW5lcz8uaW5jbHVkZXMoJ2hhbGx1Y2luYXRpb24nKSkge1xuICAgICAgY29uc3QgZW5naW5lID0gbmV3IEhhbGx1Y2luYXRpb25FbmdpbmUoY29uZmlnKTtcbiAgICAgIGVuZ2luZXNVc2VkLnB1c2goJ2hhbGx1Y2luYXRpb24nKTtcbiAgICAgIGVuZ2luZVByb21pc2VzLnB1c2goXG4gICAgICAgIGVuZ2luZS5kZXRlY3Qob3B0aW9ucy5jb250ZW50KS50aGVuKHJlcyA9PiB7XG4gICAgICAgICAgcmVzdWx0LmhhbGx1Y2luYXRpb24gPSByZXM7XG4gICAgICAgICAgcmVzdWx0LmxpbWl0YXRpb25zPy5wdXNoKC4uLnJlcy5saW1pdGF0aW9ucyk7XG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXN1bHQubm90Q2hlY2tlZD8ucHVzaCgnaGFsbHVjaW5hdGlvbicpO1xuICAgIH1cbiAgICBcbiAgICAvLyBDb25zaXN0ZW5jeSBjaGVja1xuICAgIGlmIChjb25maWcuZW5naW5lcy5jb25zaXN0ZW5jeS5lbmFibGVkICYmXG4gICAgICAgICFvcHRpb25zLmNvbnRleHQ/LnNraXBFbmdpbmVzPy5pbmNsdWRlcygnY29uc2lzdGVuY3knKSkge1xuICAgICAgY29uc3QgZW5naW5lID0gbmV3IENvbnNpc3RlbmN5RW5naW5lKGNvbmZpZyk7XG4gICAgICBlbmdpbmVzVXNlZC5wdXNoKCdjb25zaXN0ZW5jeScpO1xuICAgICAgZW5naW5lUHJvbWlzZXMucHVzaChcbiAgICAgICAgZW5naW5lLmNoZWNrKG9wdGlvbnMuY29udGVudCkudGhlbihyZXMgPT4ge1xuICAgICAgICAgIHJlc3VsdC5jb25zaXN0ZW5jeSA9IHJlcztcbiAgICAgICAgICByZXN1bHQubGltaXRhdGlvbnM/LnB1c2goLi4ucmVzLmxpbWl0YXRpb25zKTtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlc3VsdC5ub3RDaGVja2VkPy5wdXNoKCdjb25zaXN0ZW5jeScpO1xuICAgIH1cbiAgICBcbiAgICAvLyBKU09OIHZhbGlkYXRpb25cbiAgICBpZiAoY29uZmlnLmVuZ2luZXMuanNvblZhbGlkYXRvci5lbmFibGVkICYmXG4gICAgICAgIG9wdGlvbnMuY29udGV4dD8uaXNKU09OICYmXG4gICAgICAgICFvcHRpb25zLmNvbnRleHQ/LnNraXBFbmdpbmVzPy5pbmNsdWRlcygnanNvbicpKSB7XG4gICAgICBjb25zdCBlbmdpbmUgPSBuZXcgSlNPTlZhbGlkYXRvckVuZ2luZShjb25maWcpO1xuICAgICAgZW5naW5lc1VzZWQucHVzaCgnanNvbicpO1xuICAgICAgZW5naW5lUHJvbWlzZXMucHVzaChcbiAgICAgICAgZW5naW5lLnZhbGlkYXRlKFxuICAgICAgICAgIG9wdGlvbnMuY29udGVudCxcbiAgICAgICAgICBvcHRpb25zLmNvbnRleHQ/LmV4cGVjdGVkU2NoZW1hXG4gICAgICAgICkudGhlbihyZXMgPT4ge1xuICAgICAgICAgIHJlc3VsdC5qc29uID0gcmVzO1xuICAgICAgICAgIHJlc3VsdC5saW1pdGF0aW9ucz8ucHVzaCguLi5yZXMubGltaXRhdGlvbnMpO1xuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG4gICAgXG4gICAgLy8gQ1NNNiBjaGVja3NcbiAgICBpZiAoY29uZmlnLmVuZ2luZXMuY3NtNi5lbmFibGVkICYmXG4gICAgICAgICFvcHRpb25zLmNvbnRleHQ/LnNraXBFbmdpbmVzPy5pbmNsdWRlcygnY3NtNicpKSB7XG4gICAgICBjb25zdCBlbmdpbmUgPSBuZXcgQ1NNNkJhc2VsaW5lKGNvbmZpZyk7XG4gICAgICBlbmdpbmVzVXNlZC5wdXNoKCdjc202Jyk7XG4gICAgICBlbmdpbmVQcm9taXNlcy5wdXNoKFxuICAgICAgICBlbmdpbmUuYXVkaXQob3B0aW9ucy5jb250ZW50LCBvcHRpb25zLmNvbnRlbnQpLnRoZW4ocmVzID0+IHtcbiAgICAgICAgICByZXN1bHQuY3NtNiA9IHJlcztcbiAgICAgICAgICByZXN1bHQubGltaXRhdGlvbnM/LnB1c2goLi4ucmVzLmxpbWl0YXRpb25zKTtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlc3VsdC5ub3RDaGVja2VkPy5wdXNoKCdjc202Jyk7XG4gICAgfVxuICAgIFxuICAgIC8vIFdhaXQgZm9yIGFsbCBlbmdpbmVzXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoZW5naW5lUHJvbWlzZXMpO1xuICAgIFxuICAgIC8vIEV4ZWN1dGUgcGx1Z2luc1xuICAgIGNvbnN0IHBsdWdpblJlZ2lzdHJ5ID0gZ2V0UGx1Z2luUmVnaXN0cnkoKTtcbiAgICBjb25zdCBwbHVnaW5SZXN1bHRzID0gYXdhaXQgcGx1Z2luUmVnaXN0cnkuZXhlY3V0ZUFsbCh7XG4gICAgICBjb250ZW50OiBvcHRpb25zLmNvbnRlbnQsXG4gICAgICBwcm9tcHQ6IG9wdGlvbnMuY29udGV4dD8uaXNKU09OID8gJ0pTT04gdmFsaWRhdGlvbicgOiB1bmRlZmluZWQsXG4gICAgICBjb25maWcsXG4gICAgICBtZXRhZGF0YTogeyByZXF1ZXN0SWQgfVxuICAgIH0pO1xuICAgIFxuICAgIC8vIEFkZCBwbHVnaW4gZmluZGluZ3MgdG8gcmVzdWx0XG4gICAgaWYgKHBsdWdpblJlc3VsdHMubGVuZ3RoID4gMCkge1xuICAgICAgbG9nZ2VyLmluZm8oJ1BsdWdpbnMgZXhlY3V0ZWQnLCB7XG4gICAgICAgIHJlcXVlc3RJZCxcbiAgICAgICAgcGx1Z2luQ291bnQ6IHBsdWdpblJlc3VsdHMubGVuZ3RoXG4gICAgICB9KTtcbiAgICB9XG4gICAgXG4gICAgLy8gQ2FsY3VsYXRlIG92ZXJhbGwgcmlza1xuICAgIGNvbnN0IHJpc2tFbmdpbmUgPSBuZXcgUmlza1Njb3JpbmdFbmdpbmUoY29uZmlnKTtcbiAgICByZXN1bHQucmlzayA9IHJpc2tFbmdpbmUuY2FsY3VsYXRlKHJlc3VsdCBhcyBWZXJpZnlSZXN1bHQpO1xuICAgIFxuICAgIC8vIERlLWR1cGxpY2F0ZSBsaW1pdGF0aW9uc1xuICAgIHJlc3VsdC5saW1pdGF0aW9ucyA9IFsuLi5uZXcgU2V0KHJlc3VsdC5saW1pdGF0aW9ucyldO1xuICAgIFxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGxvZ2dlci5lcnJvcignVmVyaWZpY2F0aW9uIGZhaWxlZCcsIGVycm9yIGFzIEVycm9yLCB7XG4gICAgICByZXF1ZXN0SWQsXG4gICAgICBjb250ZW50TGVuZ3RoOiBvcHRpb25zLmNvbnRlbnQubGVuZ3RoXG4gICAgfSk7XG4gICAgdGhyb3cgbmV3IFZlcmlmaWNhdGlvbkVycm9yKGBWZXJpZmljYXRpb24gZmFpbGVkOiAkeyhlcnJvciBhcyBFcnJvcikubWVzc2FnZX1gKTtcbiAgfVxuICBcbiAgY29uc3QgZW5kVGltZSA9IERhdGUubm93KCk7XG4gIGNvbnN0IGR1cmF0aW9uID0gbG9nZ2VyLmVuZFJlcXVlc3QoKSB8fCAoZW5kVGltZSAtIHN0YXJ0VGltZSk7XG4gIFxuICAvLyBMb2cgY29tcGxldGlvblxuICBsb2dnZXIuaW5mbygnVmVyaWZpY2F0aW9uIGNvbXBsZXRlZCcsIHtcbiAgICByZXF1ZXN0SWQsXG4gICAgZHVyYXRpb24sXG4gICAgcmlza0xldmVsOiByZXN1bHQucmlzaz8ubGV2ZWwsXG4gICAgZmluZGluZ3NDb3VudDogcmVzdWx0LmNzbTY/LmZpbmRpbmdzPy5sZW5ndGggfHwgMFxuICB9KTtcbiAgXG4gIC8vIEF1ZGl0IHRyYWlsXG4gIGF1ZGl0TG9nZ2VyLmxvZ1ZlcmlmaWNhdGlvbih7XG4gICAgcmVxdWVzdElkLFxuICAgIGNvbnRlbnQ6IG9wdGlvbnMuY29udGVudCxcbiAgICBwcm9tcHQ6IG9wdGlvbnMuY29udGV4dD8uaXNKU09OID8gJ0pTT04gdmFsaWRhdGlvbicgOiB1bmRlZmluZWQsXG4gICAgcmlza0xldmVsOiByZXN1bHQucmlzaz8ubGV2ZWwgfHwgJ3Vua25vd24nLFxuICAgIGZpbmRpbmdzQ291bnQ6IHJlc3VsdC5jc202Py5maW5kaW5ncz8ubGVuZ3RoIHx8IDAsXG4gICAgYmxvY2tlZDogcmVzdWx0LnJpc2s/LmFjdGlvbiA9PT0gJ2Jsb2NrJyxcbiAgICBkdXJhdGlvbixcbiAgICBlbmdpbmVzVXNlZCxcbiAgICBjb25maWdUaWVyOiBjb25maWcudGllclxuICB9KTtcbiAgXG4gIC8vIEJhc2VsaW5lIHRyYWNraW5nIGFuZCBkcmlmdCBkZXRlY3Rpb25cbiAgY29uc3QgYmFzZWxpbmVTdG9yYWdlID0gZ2V0QmFzZWxpbmVTdG9yYWdlKCk7XG4gIGJhc2VsaW5lU3RvcmFnZS51cGRhdGVCYXNlbGluZSh7XG4gICAgbGF0ZW5jeTogZHVyYXRpb24sXG4gICAgY29udGVudExlbmd0aDogb3B0aW9ucy5jb250ZW50Lmxlbmd0aCxcbiAgICByaXNrU2NvcmU6IHJlc3VsdC5yaXNrPy5vdmVyYWxsIHx8IDAsXG4gICAgcmlza0xldmVsOiByZXN1bHQucmlzaz8ubGV2ZWwgfHwgJ2xvdycsXG4gICAgZW5naW5lU2NvcmVzOiB7XG4gICAgICBoYWxsdWNpbmF0aW9uOiByZXN1bHQuaGFsbHVjaW5hdGlvbj8ucmlza1Njb3JlLFxuICAgICAgY29uc2lzdGVuY3k6IChyZXN1bHQuY29uc2lzdGVuY3kgYXMgYW55KT8uc2NvcmUgfHwgMCxcbiAgICAgIGNzbTY6IHJlc3VsdC5jc202Py5yaXNrU2NvcmVcbiAgICB9XG4gIH0pO1xuICBcbiAgLy8gQ2hlY2sgZm9yIGRyaWZ0XG4gIGNvbnN0IGRyaWZ0cyA9IGJhc2VsaW5lU3RvcmFnZS5jaGVja0RyaWZ0KHtcbiAgICBsYXRlbmN5OiBkdXJhdGlvbixcbiAgICBjb250ZW50TGVuZ3RoOiBvcHRpb25zLmNvbnRlbnQubGVuZ3RoLFxuICAgIHJpc2tTY29yZTogcmVzdWx0LnJpc2s/Lm92ZXJhbGwgfHwgMFxuICB9KTtcbiAgXG4gIGlmIChkcmlmdHMubGVuZ3RoID4gMCkge1xuICAgIGxvZ2dlci53YXJuKCdCYXNlbGluZSBkcmlmdCBkZXRlY3RlZCcsIHtcbiAgICAgIHJlcXVlc3RJZCxcbiAgICAgIGRyaWZ0czogZHJpZnRzLm1hcChkID0+ICh7XG4gICAgICAgIG1ldHJpYzogZC5tZXRyaWMsXG4gICAgICAgIGRyaWZ0UGVyY2VudDogZC5kcmlmdFBlcmNlbnQudG9GaXhlZCgyKSArICclJyxcbiAgICAgICAgc2V2ZXJpdHk6IGQuc2V2ZXJpdHlcbiAgICAgIH0pKVxuICAgIH0pO1xuICB9XG4gIFxuICByZXR1cm4ge1xuICAgIC4uLnJlc3VsdCxcbiAgICByaXNrOiByZXN1bHQucmlzayEsXG4gICAgbWV0YToge1xuICAgICAgdmVyaWZpY2F0aW9uX2lkOiB2ZXJpZmljYXRpb25JZCxcbiAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgbGF0ZW5jeV9tczogZW5kVGltZSAtIHN0YXJ0VGltZSxcbiAgICAgIHZlcnNpb246IFZFUlNJT04sXG4gICAgICB0aWVyOiBjb25maWcudGllcixcbiAgICAgIGVuZ2luZXNVc2VkXG4gICAgfSxcbiAgICBsaW1pdGF0aW9uczogcmVzdWx0LmxpbWl0YXRpb25zISxcbiAgICBub3RDaGVja2VkOiByZXN1bHQubm90Q2hlY2tlZCFcbiAgfSBhcyBWZXJpZnlSZXN1bHQ7XG59XG5cbi8qKlxuICogTWVyZ2UgdXNlciBjb25maWcgd2l0aCBkZWZhdWx0cyBhbmQgdGllciBsaW1pdHNcbiAqL1xuZnVuY3Rpb24gbWVyZ2VDb25maWcodXNlckNvbmZpZz86IFBhcnRpYWw8Q29uZmlnPik6IENvbmZpZyB7XG4gIGNvbnN0IHRpZXIgPSB1c2VyQ29uZmlnPy50aWVyIHx8ICdmcmVlJztcbiAgY29uc3QgdGllckNvbmZpZyA9IFRJRVJfTElNSVRTW3RpZXJdO1xuICBcbiAgLy8gRGVlcCBtZXJnZVxuICBjb25zdCBtZXJnZWQ6IENvbmZpZyA9IHtcbiAgICAuLi5ERUZBVUxUX0NPTkZJRyxcbiAgICAuLi51c2VyQ29uZmlnLFxuICAgIHRpZXIsXG4gICAgcHJpdmFjeToge1xuICAgICAgLi4uREVGQVVMVF9DT05GSUcucHJpdmFjeSxcbiAgICAgIC4uLnVzZXJDb25maWc/LnByaXZhY3lcbiAgICB9LFxuICAgIGVuZ2luZXM6IHtcbiAgICAgIC4uLkRFRkFVTFRfQ09ORklHLmVuZ2luZXMsXG4gICAgICAuLi51c2VyQ29uZmlnPy5lbmdpbmVzLFxuICAgICAgY3NtNjoge1xuICAgICAgICAuLi5ERUZBVUxUX0NPTkZJRy5lbmdpbmVzLmNzbTYsXG4gICAgICAgIC4uLnVzZXJDb25maWc/LmVuZ2luZXM/LmNzbTYsXG4gICAgICAgIGNoZWNrczoge1xuICAgICAgICAgIC4uLkRFRkFVTFRfQ09ORklHLmVuZ2luZXMuY3NtNi5jaGVja3MsXG4gICAgICAgICAgLi4udXNlckNvbmZpZz8uZW5naW5lcz8uY3NtNj8uY2hlY2tzXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuICAgIHBlcmZvcm1hbmNlOiB7XG4gICAgICAuLi5ERUZBVUxUX0NPTkZJRy5wZXJmb3JtYW5jZSxcbiAgICAgIC4uLnRpZXJDb25maWc/LnBlcmZvcm1hbmNlLFxuICAgICAgLi4udXNlckNvbmZpZz8ucGVyZm9ybWFuY2VcbiAgICB9LFxuICAgIG91dHB1dDoge1xuICAgICAgLi4uREVGQVVMVF9DT05GSUcub3V0cHV0LFxuICAgICAgLi4udXNlckNvbmZpZz8ub3V0cHV0LFxuICAgICAgaW5jbHVkZUxpbWl0YXRpb25zOiB0cnVlIC8vIEFMV0FZUyB0cnVlXG4gICAgfVxuICB9O1xuICBcbiAgcmV0dXJuIG1lcmdlZDtcbn1cblxuLyoqXG4gKiBDUklUSUNBTDogVmFsaWRhdGUgcHJpdmFjeSBjb21wbGlhbmNlXG4gKi9cbmZ1bmN0aW9uIHZhbGlkYXRlUHJpdmFjeUNvbXBsaWFuY2UoY29uZmlnOiBDb25maWcpOiB2b2lkIHtcbiAgLy8gRnJlZSB0aWVyIG11c3QgbmV2ZXIgYWxsb3cgbmV0d29yayByZXF1ZXN0c1xuICBpZiAoY29uZmlnLnRpZXIgPT09ICdmcmVlJyAmJiBjb25maWcucHJpdmFjeS5hbGxvd05ldHdvcmtSZXF1ZXN0cykge1xuICAgIHRocm93IG5ldyBQcml2YWN5VmlvbGF0aW9uRXJyb3IoXG4gICAgICAnRnJlZSB0aWVyIGNhbm5vdCBlbmFibGUgbmV0d29yayByZXF1ZXN0cy4gJyArXG4gICAgICAnVGhpcyBpcyBhIHByaXZhY3kgdmlvbGF0aW9uLiAnICtcbiAgICAgICdVcGdyYWRlIHRvIFRlYW0gdGllciBmb3IgTUwtZW5oYW5jZWQgZmVhdHVyZXMuJ1xuICAgICk7XG4gIH1cbiAgXG4gIC8vIEZyZWUgdGllciBtdXN0IG5ldmVyIGhhdmUgdGVsZW1ldHJ5XG4gIGlmIChjb25maWcudGllciA9PT0gJ2ZyZWUnICYmIGNvbmZpZy5wcml2YWN5LnRlbGVtZXRyeUVuYWJsZWQpIHtcbiAgICB0aHJvdyBuZXcgUHJpdmFjeVZpb2xhdGlvbkVycm9yKFxuICAgICAgJ0ZyZWUgdGllciBjYW5ub3QgZW5hYmxlIHRlbGVtZXRyeS4gJyArXG4gICAgICAnVGhpcyBpcyBhIHByaXZhY3kgdmlvbGF0aW9uLidcbiAgICApO1xuICB9XG59XG5cbi8qKlxuICogVmFsaWRhdGUgaW5wdXQgd2l0aCBjb21wcmVoZW5zaXZlIGNoZWNrc1xuICovXG5mdW5jdGlvbiB2YWxpZGF0ZUlucHV0KGNvbnRlbnQ6IHN0cmluZywgY29uZmlnOiBDb25maWcpOiB2b2lkIHtcbiAgLy8gQ2hlY2sgZm9yIGVtcHR5IGlucHV0XG4gIGlmICghY29udGVudCB8fCBjb250ZW50LnRyaW0oKS5sZW5ndGggPT09IDApIHtcbiAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKFxuICAgICAgJ0NvbnRlbnQgY2Fubm90IGJlIGVtcHR5JyxcbiAgICAgIEVycm9yQ29kZS5FTVBUWV9JTlBVVCxcbiAgICAgIHsgY29udGVudExlbmd0aDogY29udGVudD8ubGVuZ3RoIHx8IDAgfVxuICAgICk7XG4gIH1cbiAgXG4gIC8vIENoZWNrIGZvciBpbnZhbGlkIGNoYXJhY3RlcnNcbiAgaWYgKCEvXltcXHgwMC1cXHg3RlxcdTAwODAtXFx1RkZGRl0qJC8udGVzdChjb250ZW50KSkge1xuICAgIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoXG4gICAgICAnQ29udGVudCBjb250YWlucyBpbnZhbGlkIGNoYXJhY3RlcnMnLFxuICAgICAgRXJyb3JDb2RlLklOVkFMSURfRU5DT0RJTkcsXG4gICAgICB7IGNvbnRlbnRMZW5ndGg6IGNvbnRlbnQubGVuZ3RoIH1cbiAgICApO1xuICB9XG4gIFxuICAvLyBDaGVjayB0aWVyIGxpbWl0c1xuICBjb25zdCBsaW1pdHMgPSBUSUVSX0xJTUlUU1tjb25maWcudGllcl07XG4gIGlmIChjb250ZW50Lmxlbmd0aCA+IChsaW1pdHMucGVyZm9ybWFuY2U/Lm1heENvbnRlbnRMZW5ndGggfHwgMTAwMDAwKSkge1xuICAgIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoXG4gICAgICBgQ29udGVudCBleGNlZWRzIHRpZXIgbGltaXQgKCR7bGltaXRzLnBlcmZvcm1hbmNlPy5tYXhDb250ZW50TGVuZ3RoIHx8IDEwMDAwMH0gY2hhcnMpLiBgICtcbiAgICAgIGBDdXJyZW50OiAke2NvbnRlbnQubGVuZ3RofSBjaGFycy4gYCArXG4gICAgICBgVXBncmFkZSB0byAke2NvbmZpZy50aWVyID09PSAnZnJlZScgPyAnVGVhbScgOiAnUHJvZmVzc2lvbmFsJ30gdGllciBmb3IgaGlnaGVyIGxpbWl0cy5gLFxuICAgICAgRXJyb3JDb2RlLkNPTlRFTlRfVE9PX0xBUkdFLFxuICAgICAge1xuICAgICAgICBjb250ZW50TGVuZ3RoOiBjb250ZW50Lmxlbmd0aCxcbiAgICAgICAgbWF4TGVuZ3RoOiBsaW1pdHMucGVyZm9ybWFuY2U/Lm1heENvbnRlbnRMZW5ndGggfHwgMTAwMDAwLFxuICAgICAgICBjdXJyZW50VGllcjogY29uZmlnLnRpZXIsXG4gICAgICAgIHN1Z2dlc3RlZFRpZXI6IGNvbmZpZy50aWVyID09PSAnZnJlZScgPyAndGVhbScgOiAncHJvZmVzc2lvbmFsJ1xuICAgICAgfVxuICAgICk7XG4gIH1cbiAgXG4gIC8vIEFic29sdXRlIG1heGltdW0gc2FmZXR5IGNoZWNrIChwcmV2ZW50IERvUylcbiAgY29uc3QgQUJTT0xVVEVfTUFYID0gMTAgKiAxMDI0ICogMTAyNDsgLy8gMTBNQlxuICBpZiAoY29udGVudC5sZW5ndGggPiBBQlNPTFVURV9NQVgpIHtcbiAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKFxuICAgICAgYENvbnRlbnQgZXhjZWVkcyBhYnNvbHV0ZSBtYXhpbXVtIHNpemUgKCR7QUJTT0xVVEVfTUFYfSBieXRlcylgLFxuICAgICAgRXJyb3JDb2RlLkNPTlRFTlRfVE9PX0xBUkdFLFxuICAgICAgeyBjb250ZW50TGVuZ3RoOiBjb250ZW50Lmxlbmd0aCwgbWF4TGVuZ3RoOiBBQlNPTFVURV9NQVggfVxuICAgICk7XG4gIH1cbn1cbiJdfQ==