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.
224 lines (215 loc) • 23.4 kB
JavaScript
;
/**
* Badge Generator and Verification
*
* Generate "Built with llmverify" badges for verified applications
*
* @module badge/generator
*/
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.generateBadgeSignature = generateBadgeSignature;
exports.verifyBadgeSignature = verifyBadgeSignature;
exports.generateBadgeMarkdown = generateBadgeMarkdown;
exports.generateBadgeHTML = generateBadgeHTML;
exports.extractBadgeVerification = extractBadgeVerification;
exports.generateBadgeForProject = generateBadgeForProject;
exports.saveBadgeToFile = saveBadgeToFile;
const crypto = __importStar(require("crypto"));
const fs = __importStar(require("fs"));
/**
* Generate badge verification signature
*/
function generateBadgeSignature(config) {
const data = `${config.projectName}:${config.verifiedDate}:${config.version}`;
return crypto.createHash('sha256').update(data).digest('hex').substring(0, 16);
}
/**
* Verify badge signature
*/
function verifyBadgeSignature(projectName, verifiedDate, version, signature) {
const expectedSignature = generateBadgeSignature({
projectName,
verifiedDate,
version
});
return signature === expectedSignature;
}
/**
* Generate badge markdown
*/
function generateBadgeMarkdown(config) {
const signature = generateBadgeSignature(config);
const badgeUrl = config.projectUrl
? `https://img.shields.io/badge/Built_with-llmverify-blue?logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8cGF0aCBkPSJNMTIgMkw0IDZWMTJDNCAyMC41IDEyIDIyIDEyIDIyQzEyIDIyIDIwIDIwLjUgMjAgMTJWNkwxMiAyWiIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KICA8cGF0aCBkPSJNOSAxMkwxMSAxNEwxNSAxMCIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPC9zdmc+`
: 'https://img.shields.io/badge/Built_with-llmverify-blue';
const linkUrl = config.projectUrl || 'https://github.com/subodhkc/llmverify-npm';
return `[](${linkUrl})
<!-- llmverify badge verification -->
<!-- project: ${config.projectName} -->
<!-- verified: ${config.verifiedDate} -->
<!-- version: ${config.version} -->
<!-- signature: ${signature} -->`;
}
/**
* Generate badge HTML
*/
function generateBadgeHTML(config) {
const signature = generateBadgeSignature(config);
const linkUrl = config.projectUrl || 'https://github.com/subodhkc/llmverify-npm';
return `<a href="${linkUrl}" target="_blank" rel="noopener noreferrer">
<img src="https://img.shields.io/badge/Built_with-llmverify-blue" alt="Built with llmverify" />
</a>
<!-- llmverify badge verification -->
<!-- project: ${config.projectName} -->
<!-- verified: ${config.verifiedDate} -->
<!-- version: ${config.version} -->
<!-- signature: ${signature} -->`;
}
/**
* Extract badge verification from markdown/HTML
*/
function extractBadgeVerification(content) {
const projectMatch = content.match(/<!-- project: (.+?) -->/);
const verifiedMatch = content.match(/<!-- verified: (.+?) -->/);
const versionMatch = content.match(/<!-- version: (.+?) -->/);
const signatureMatch = content.match(/<!-- signature: (.+?) -->/);
if (!projectMatch || !verifiedMatch || !versionMatch || !signatureMatch) {
return null;
}
const projectName = projectMatch[1];
const verifiedDate = verifiedMatch[1];
const version = versionMatch[1];
const signature = signatureMatch[1];
const valid = verifyBadgeSignature(projectName, verifiedDate, version, signature);
return {
projectName,
verifiedDate,
version,
signature,
valid
};
}
/**
* Validate badge generation request
*/
function validateBadgeRequest(projectName, projectUrl) {
// Validate project name
if (!projectName || projectName.trim().length === 0) {
throw new Error('Project name is required');
}
if (projectName.length > 100) {
throw new Error('Project name must be less than 100 characters');
}
// Prevent malicious names
const maliciousPatterns = [
/<script/i,
/javascript:/i,
/on\w+=/i,
/<iframe/i,
/eval\(/i
];
if (maliciousPatterns.some(pattern => pattern.test(projectName))) {
throw new Error('Project name contains invalid characters');
}
// Validate URL if provided
if (projectUrl) {
try {
const url = new URL(projectUrl);
if (!['http:', 'https:'].includes(url.protocol)) {
throw new Error('URL must use http or https protocol');
}
}
catch (error) {
if (error.message === 'URL must use http or https protocol') {
throw error;
}
throw new Error('Invalid project URL');
}
}
// Rate limiting check (simple in-memory)
// Only enforce in production, not in tests
if (process.env.NODE_ENV !== 'test') {
const now = Date.now();
const key = `badge:${projectName}`;
if (typeof global !== 'undefined') {
const cache = global.__badgeCache || {};
const lastGenerated = cache[key];
if (lastGenerated && now - lastGenerated < 60000) {
throw new Error('Badge generation rate limit exceeded. Please wait 1 minute.');
}
cache[key] = now;
global.__badgeCache = cache;
}
}
}
/**
* CLI helper to generate badge
*/
function generateBadgeForProject(projectName, projectUrl, version) {
// Validate request
validateBadgeRequest(projectName, projectUrl);
const config = {
projectName: projectName.trim(),
projectUrl,
verifiedDate: new Date().toISOString().split('T')[0],
version: version || require('../../package.json').version
};
const signature = generateBadgeSignature(config);
const markdown = generateBadgeMarkdown(config);
const html = generateBadgeHTML(config);
return { markdown, html, signature };
}
/**
* Save badge to file
*/
function saveBadgeToFile(outputPath, projectName, projectUrl) {
const { markdown, html } = generateBadgeForProject(projectName, projectUrl);
const content = `# llmverify Badge
## Markdown
\`\`\`markdown
${markdown}
\`\`\`
## HTML
\`\`\`html
${html}
\`\`\`
## Usage
Copy the markdown or HTML code above and paste it into your README.md or website.
The badge verifies that your project uses llmverify for AI output verification.
`;
fs.writeFileSync(outputPath, content, 'utf-8');
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2JhZGdlL2dlbmVyYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7OztHQU1HOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQThCSCx3REFHQztBQUtELG9EQVlDO0FBS0Qsc0RBZ0JDO0FBS0QsOENBYUM7QUFLRCw0REF3QkM7QUFrRUQsMERBb0JDO0FBS0QsMENBNkJDO0FBNU9ELCtDQUFpQztBQUNqQyx1Q0FBeUI7QUF3QnpCOztHQUVHO0FBQ0gsU0FBZ0Isc0JBQXNCLENBQUMsTUFBbUI7SUFDeEQsTUFBTSxJQUFJLEdBQUcsR0FBRyxNQUFNLENBQUMsV0FBVyxJQUFJLE1BQU0sQ0FBQyxZQUFZLElBQUksTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQzlFLE9BQU8sTUFBTSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFDakYsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0Isb0JBQW9CLENBQ2xDLFdBQW1CLEVBQ25CLFlBQW9CLEVBQ3BCLE9BQWUsRUFDZixTQUFpQjtJQUVqQixNQUFNLGlCQUFpQixHQUFHLHNCQUFzQixDQUFDO1FBQy9DLFdBQVc7UUFDWCxZQUFZO1FBQ1osT0FBTztLQUNSLENBQUMsQ0FBQztJQUNILE9BQU8sU0FBUyxLQUFLLGlCQUFpQixDQUFDO0FBQ3pDLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLHFCQUFxQixDQUFDLE1BQW1CO0lBQ3ZELE1BQU0sU0FBUyxHQUFHLHNCQUFzQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBRWpELE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxVQUFVO1FBQ2hDLENBQUMsQ0FBQyxna0JBQWdrQjtR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QWdCLHVCQUF1QixDQUNyQyxXQUFtQixFQUNuQixVQUFtQixFQUNuQixPQUFnQjtJQUVoQixtQkFBbUI7SUFDbkIsb0JBQW9CLENBQUMsV0FBVyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBRTlDLE1BQU0sTUFBTSxHQUFnQjtRQUMxQixXQUFXLEVBQUUsV0FBVyxDQUFDLElBQUksRUFBRTtRQUMvQixVQUFVO1FBQ1YsWUFBWSxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNwRCxPQUFPLEVBQUUsT0FBTyxJQUFJLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLE9BQU87S0FDMUQsQ0FBQztJQUVGLE1BQU0sU0FBUyxHQUFHLHNCQUFzQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2pELE1BQU0sUUFBUSxHQUFHLHFCQUFxQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQy9DLE1BQU0sSUFBSSxHQUFHLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBRXZDLE9BQU8sRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxDQUFDO0FBQ3ZDLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLGVBQWUsQ0FDN0IsVUFBa0IsRUFDbEIsV0FBbUIsRUFDbkIsVUFBbUI7SUFFbkIsTUFBTSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsR0FBRyx1QkFBdUIsQ0FBQyxXQUFXLEVBQUUsVUFBVSxDQUFDLENBQUM7SUFFNUUsTUFBTSxPQUFPLEdBQUc7Ozs7O0VBS2hCLFFBQVE7Ozs7OztFQU1SLElBQUk7Ozs7Ozs7O0NBUUwsQ0FBQztJQUVBLEVBQUUsQ0FBQyxhQUFhLENBQUMsVUFBVSxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztBQUNqRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBCYWRnZSBHZW5lcmF0b3IgYW5kIFZlcmlmaWNhdGlvblxuICogXG4gKiBHZW5lcmF0ZSBcIkJ1aWx0IHdpdGggbGxtdmVyaWZ5XCIgYmFkZ2VzIGZvciB2ZXJpZmllZCBhcHBsaWNhdGlvbnNcbiAqIFxuICogQG1vZHVsZSBiYWRnZS9nZW5lcmF0b3JcbiAqL1xuXG5pbXBvcnQgKiBhcyBjcnlwdG8gZnJvbSAnY3J5cHRvJztcbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5cbi8qKlxuICogQmFkZ2UgY29uZmlndXJhdGlvblxuICovXG5leHBvcnQgaW50ZXJmYWNlIEJhZGdlQ29uZmlnIHtcbiAgcHJvamVjdE5hbWU6IHN0cmluZztcbiAgcHJvamVjdFVybD86IHN0cmluZztcbiAgdmVyaWZpZWREYXRlOiBzdHJpbmc7XG4gIHZlcnNpb246IHN0cmluZztcbn1cblxuLyoqXG4gKiBCYWRnZSB2ZXJpZmljYXRpb24gZGF0YVxuICovXG5leHBvcnQgaW50ZXJmYWNlIEJhZGdlVmVyaWZpY2F0aW9uIHtcbiAgcHJvamVjdE5hbWU6IHN0cmluZztcbiAgdmVyaWZpZWREYXRlOiBzdHJpbmc7XG4gIHZlcnNpb246IHN0cmluZztcbiAgc2lnbmF0dXJlOiBzdHJpbmc7XG4gIHZhbGlkOiBib29sZWFuO1xufVxuXG4vKipcbiAqIEdlbmVyYXRlIGJhZGdlIHZlcmlmaWNhdGlvbiBzaWduYXR1cmVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlQmFkZ2VTaWduYXR1cmUoY29uZmlnOiBCYWRnZUNvbmZpZyk6IHN0cmluZyB7XG4gIGNvbnN0IGRhdGEgPSBgJHtjb25maWcucHJvamVjdE5hbWV9OiR7Y29uZmlnLnZlcmlmaWVkRGF0ZX06JHtjb25maWcudmVyc2lvbn1gO1xuICByZXR1cm4gY3J5cHRvLmNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShkYXRhKS5kaWdlc3QoJ2hleCcpLnN1YnN0cmluZygwLCAxNik7XG59XG5cbi8qKlxuICogVmVyaWZ5IGJhZGdlIHNpZ25hdHVyZVxuICovXG5leHBvcnQgZnVuY3Rpb24gdmVyaWZ5QmFkZ2VTaWduYXR1cmUoXG4gIHByb2plY3ROYW1lOiBzdHJpbmcsXG4gIHZlcmlmaWVkRGF0ZTogc3RyaW5nLFxuICB2ZXJzaW9uOiBzdHJpbmcsXG4gIHNpZ25hdHVyZTogc3RyaW5nXG4pOiBib29sZWFuIHtcbiAgY29uc3QgZXhwZWN0ZWRTaWduYXR1cmUgPSBnZW5lcmF0ZUJhZGdlU2lnbmF0dXJlKHtcbiAgICBwcm9qZWN0TmFtZSxcbiAgICB2ZXJpZmllZERhdGUsXG4gICAgdmVyc2lvblxuICB9KTtcbiAgcmV0dXJuIHNpZ25hdHVyZSA9PT0gZXhwZWN0ZWRTaWduYXR1cmU7XG59XG5cbi8qKlxuICogR2VuZXJhdGUgYmFkZ2UgbWFya2Rvd25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlQmFkZ2VNYXJrZG93bihjb25maWc6IEJhZGdlQ29uZmlnKTogc3RyaW5nIHtcbiAgY29uc3Qgc2lnbmF0dXJlID0gZ2VuZXJhdGVCYWRnZVNpZ25hdHVyZShjb25maWcpO1xuICBcbiAgY29uc3QgYmFkZ2VVcmwgPSBjb25maWcucHJvamVjdFVybCBcbiAgICA/IGBodHRwczovL2ltZy5zaGllbGRzLmlvL2JhZGdlL0J1aWx0X3dpdGgtbGxtdmVyaWZ5LWJsdWU/bG9nbz1kYXRhOmltYWdlL3N2Zyt4bWw7YmFzZTY0LFBITjJaeUIzYVdSMGFEMGlNalFpSUdobGFXZG9kRDBpTWpRaUlIWnBaWGRDYjNnOUlqQWdNQ0F5TkNBeU5DSWdabWxzYkQwaWJtOXVaU0lnZUcxc2JuTTlJbWgwZEhBNkx5OTNkM2N1ZHpNdWIzSm5Mekl3TURBdmMzWm5JajRLSUNBOGNHRjBhQ0JrUFNKTk1USWdNa3cwSURaV01USkROQ0F5TUM0MUlERXlJREl5SURFeUlESXlRekV5SURJeUlESXdJREl3TGpVZ01qQWdNVEpXTmt3eE1pQXlXaUlnYzNSeWIydGxQU0ozYUdsMFpTSWdjM1J5YjJ0bExYZHBaSFJvUFNJeUlpQnpkSEp2YTJVdGJHbHVaV05oY0QwaWNtOTFibVFpSUhOMGNtOXJaUzFzYVc1bGFtOXBiajBpY205MWJtUWlMejRLSUNBOGNHRjBhQ0JrUFNKTk9TQXhNa3d4TVNBeE5Fd3hOU0F4TUNJZ2MzUnliMnRsUFNKM2FHbDBaU0lnYzNSeWIydGxMWGRwWkhSb1BTSXlJaUJ6ZEhKdmEyVXRiR2x1WldOaGNEMGljbTkxYm1RaUlITjBjbTlyWlMxc2FXNWxhbTlwYmowaWNtOTFibVFpTHo0S1BDOXpkbWMrYFxuICAgIDogJ2h0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2UvQnVpbHRfd2l0aC1sbG12ZXJpZnktYmx1ZSc7XG4gIFxuICBjb25zdCBsaW5rVXJsID0gY29uZmlnLnByb2plY3RVcmwgfHwgJ2h0dHBzOi8vZ2l0aHViLmNvbS9zdWJvZGhrYy9sbG12ZXJpZnktbnBtJztcbiAgXG4gIHJldHVybiBgWyFbQnVpbHQgd2l0aCBsbG12ZXJpZnldKCR7YmFkZ2VVcmx9KV0oJHtsaW5rVXJsfSlcblxuPCEtLSBsbG12ZXJpZnkgYmFkZ2UgdmVyaWZpY2F0aW9uIC0tPlxuPCEtLSBwcm9qZWN0OiAke2NvbmZpZy5wcm9qZWN0TmFtZX0gLS0+XG48IS0tIHZlcmlmaWVkOiAke2NvbmZpZy52ZXJpZmllZERhdGV9IC0tPlxuPCEtLSB2ZXJzaW9uOiAke2NvbmZpZy52ZXJzaW9ufSAtLT5cbjwhLS0gc2lnbmF0dXJlOiAke3NpZ25hdHVyZX0gLS0+YDtcbn1cblxuLyoqXG4gKiBHZW5lcmF0ZSBiYWRnZSBIVE1MXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZUJhZGdlSFRNTChjb25maWc6IEJhZGdlQ29uZmlnKTogc3RyaW5nIHtcbiAgY29uc3Qgc2lnbmF0dXJlID0gZ2VuZXJhdGVCYWRnZVNpZ25hdHVyZShjb25maWcpO1xuICBjb25zdCBsaW5rVXJsID0gY29uZmlnLnByb2plY3RVcmwgfHwgJ2h0dHBzOi8vZ2l0aHViLmNvbS9zdWJvZGhrYy9sbG12ZXJpZnktbnBtJztcbiAgXG4gIHJldHVybiBgPGEgaHJlZj1cIiR7bGlua1VybH1cIiB0YXJnZXQ9XCJfYmxhbmtcIiByZWw9XCJub29wZW5lciBub3JlZmVycmVyXCI+XG4gIDxpbWcgc3JjPVwiaHR0cHM6Ly9pbWcuc2hpZWxkcy5pby9iYWRnZS9CdWlsdF93aXRoLWxsbXZlcmlmeS1ibHVlXCIgYWx0PVwiQnVpbHQgd2l0aCBsbG12ZXJpZnlcIiAvPlxuPC9hPlxuXG48IS0tIGxsbXZlcmlmeSBiYWRnZSB2ZXJpZmljYXRpb24gLS0+XG48IS0tIHByb2plY3Q6ICR7Y29uZmlnLnByb2plY3ROYW1lfSAtLT5cbjwhLS0gdmVyaWZpZWQ6ICR7Y29uZmlnLnZlcmlmaWVkRGF0ZX0gLS0+XG48IS0tIHZlcnNpb246ICR7Y29uZmlnLnZlcnNpb259IC0tPlxuPCEtLSBzaWduYXR1cmU6ICR7c2lnbmF0dXJlfSAtLT5gO1xufVxuXG4vKipcbiAqIEV4dHJhY3QgYmFkZ2UgdmVyaWZpY2F0aW9uIGZyb20gbWFya2Rvd24vSFRNTFxuICovXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdEJhZGdlVmVyaWZpY2F0aW9uKGNvbnRlbnQ6IHN0cmluZyk6IEJhZGdlVmVyaWZpY2F0aW9uIHwgbnVsbCB7XG4gIGNvbnN0IHByb2plY3RNYXRjaCA9IGNvbnRlbnQubWF0Y2goLzwhLS0gcHJvamVjdDogKC4rPykgLS0+Lyk7XG4gIGNvbnN0IHZlcmlmaWVkTWF0Y2ggPSBjb250ZW50Lm1hdGNoKC88IS0tIHZlcmlmaWVkOiAoLis/KSAtLT4vKTtcbiAgY29uc3QgdmVyc2lvbk1hdGNoID0gY29udGVudC5tYXRjaCgvPCEtLSB2ZXJzaW9uOiAoLis/KSAtLT4vKTtcbiAgY29uc3Qgc2lnbmF0dXJlTWF0Y2ggPSBjb250ZW50Lm1hdGNoKC88IS0tIHNpZ25hdHVyZTogKC4rPykgLS0+Lyk7XG4gIFxuICBpZiAoIXByb2plY3RNYXRjaCB8fCAhdmVyaWZpZWRNYXRjaCB8fCAhdmVyc2lvbk1hdGNoIHx8ICFzaWduYXR1cmVNYXRjaCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIFxuICBjb25zdCBwcm9qZWN0TmFtZSA9IHByb2plY3RNYXRjaFsxXTtcbiAgY29uc3QgdmVyaWZpZWREYXRlID0gdmVyaWZpZWRNYXRjaFsxXTtcbiAgY29uc3QgdmVyc2lvbiA9IHZlcnNpb25NYXRjaFsxXTtcbiAgY29uc3Qgc2lnbmF0dXJlID0gc2lnbmF0dXJlTWF0Y2hbMV07XG4gIFxuICBjb25zdCB2YWxpZCA9IHZlcmlmeUJhZGdlU2lnbmF0dXJlKHByb2plY3ROYW1lLCB2ZXJpZmllZERhdGUsIHZlcnNpb24sIHNpZ25hdHVyZSk7XG4gIFxuICByZXR1cm4ge1xuICAgIHByb2plY3ROYW1lLFxuICAgIHZlcmlmaWVkRGF0ZSxcbiAgICB2ZXJzaW9uLFxuICAgIHNpZ25hdHVyZSxcbiAgICB2YWxpZFxuICB9O1xufVxuXG4vKipcbiAqIFZhbGlkYXRlIGJhZGdlIGdlbmVyYXRpb24gcmVxdWVzdFxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZUJhZGdlUmVxdWVzdChwcm9qZWN0TmFtZTogc3RyaW5nLCBwcm9qZWN0VXJsPzogc3RyaW5nKTogdm9pZCB7XG4gIC8vIFZhbGlkYXRlIHByb2plY3QgbmFtZVxuICBpZiAoIXByb2plY3ROYW1lIHx8IHByb2plY3ROYW1lLnRyaW0oKS5sZW5ndGggPT09IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1Byb2plY3QgbmFtZSBpcyByZXF1aXJlZCcpO1xuICB9XG4gIFxuICBpZiAocHJvamVjdE5hbWUubGVuZ3RoID4gMTAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdQcm9qZWN0IG5hbWUgbXVzdCBiZSBsZXNzIHRoYW4gMTAwIGNoYXJhY3RlcnMnKTtcbiAgfVxuICBcbiAgLy8gUHJldmVudCBtYWxpY2lvdXMgbmFtZXNcbiAgY29uc3QgbWFsaWNpb3VzUGF0dGVybnMgPSBbXG4gICAgLzxzY3JpcHQvaSxcbiAgICAvamF2YXNjcmlwdDovaSxcbiAgICAvb25cXHcrPS9pLFxuICAgIC88aWZyYW1lL2ksXG4gICAgL2V2YWxcXCgvaVxuICBdO1xuICBcbiAgaWYgKG1hbGljaW91c1BhdHRlcm5zLnNvbWUocGF0dGVybiA9PiBwYXR0ZXJuLnRlc3QocHJvamVjdE5hbWUpKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignUHJvamVjdCBuYW1lIGNvbnRhaW5zIGludmFsaWQgY2hhcmFjdGVycycpO1xuICB9XG4gIFxuICAvLyBWYWxpZGF0ZSBVUkwgaWYgcHJvdmlkZWRcbiAgaWYgKHByb2plY3RVcmwpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgdXJsID0gbmV3IFVSTChwcm9qZWN0VXJsKTtcbiAgICAgIGlmICghWydodHRwOicsICdodHRwczonXS5pbmNsdWRlcyh1cmwucHJvdG9jb2wpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVVJMIG11c3QgdXNlIGh0dHAgb3IgaHR0cHMgcHJvdG9jb2wnKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICBpZiAoZXJyb3IubWVzc2FnZSA9PT0gJ1VSTCBtdXN0IHVzZSBodHRwIG9yIGh0dHBzIHByb3RvY29sJykge1xuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgIH1cbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBwcm9qZWN0IFVSTCcpO1xuICAgIH1cbiAgfVxuICBcbiAgLy8gUmF0ZSBsaW1pdGluZyBjaGVjayAoc2ltcGxlIGluLW1lbW9yeSlcbiAgLy8gT25seSBlbmZvcmNlIGluIHByb2R1Y3Rpb24sIG5vdCBpbiB0ZXN0c1xuICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICd0ZXN0Jykge1xuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gICAgY29uc3Qga2V5ID0gYGJhZGdlOiR7cHJvamVjdE5hbWV9YDtcbiAgICBcbiAgICBpZiAodHlwZW9mIGdsb2JhbCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIGNvbnN0IGNhY2hlID0gKGdsb2JhbCBhcyBhbnkpLl9fYmFkZ2VDYWNoZSB8fCB7fTtcbiAgICAgIGNvbnN0IGxhc3RHZW5lcmF0ZWQgPSBjYWNoZVtrZXldO1xuICAgICAgXG4gICAgICBpZiAobGFzdEdlbmVyYXRlZCAmJiBub3cgLSBsYXN0R2VuZXJhdGVkIDwgNjAwMDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdCYWRnZSBnZW5lcmF0aW9uIHJhdGUgbGltaXQgZXhjZWVkZWQuIFBsZWFzZSB3YWl0IDEgbWludXRlLicpO1xuICAgICAgfVxuICAgICAgXG4gICAgICBjYWNoZVtrZXldID0gbm93O1xuICAgICAgKGdsb2JhbCBhcyBhbnkpLl9fYmFkZ2VDYWNoZSA9IGNhY2hlO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIENMSSBoZWxwZXIgdG8gZ2VuZXJhdGUgYmFkZ2VcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlQmFkZ2VGb3JQcm9qZWN0KFxuICBwcm9qZWN0TmFtZTogc3RyaW5nLFxuICBwcm9qZWN0VXJsPzogc3RyaW5nLFxuICB2ZXJzaW9uPzogc3RyaW5nXG4pOiB7IG1hcmtkb3duOiBzdHJpbmc7IGh0bWw6IHN0cmluZzsgc2lnbmF0dXJlOiBzdHJpbmcgfSB7XG4gIC8vIFZhbGlkYXRlIHJlcXVlc3RcbiAgdmFsaWRhdGVCYWRnZVJlcXVlc3QocHJvamVjdE5hbWUsIHByb2plY3RVcmwpO1xuICBcbiAgY29uc3QgY29uZmlnOiBCYWRnZUNvbmZpZyA9IHtcbiAgICBwcm9qZWN0TmFtZTogcHJvamVjdE5hbWUudHJpbSgpLFxuICAgIHByb2plY3RVcmwsXG4gICAgdmVyaWZpZWREYXRlOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkuc3BsaXQoJ1QnKVswXSxcbiAgICB2ZXJzaW9uOiB2ZXJzaW9uIHx8IHJlcXVpcmUoJy4uLy4uL3BhY2thZ2UuanNvbicpLnZlcnNpb25cbiAgfTtcbiAgXG4gIGNvbnN0IHNpZ25hdHVyZSA9IGdlbmVyYXRlQmFkZ2VTaWduYXR1cmUoY29uZmlnKTtcbiAgY29uc3QgbWFya2Rvd24gPSBnZW5lcmF0ZUJhZGdlTWFya2Rvd24oY29uZmlnKTtcbiAgY29uc3QgaHRtbCA9IGdlbmVyYXRlQmFkZ2VIVE1MKGNvbmZpZyk7XG4gIFxuICByZXR1cm4geyBtYXJrZG93biwgaHRtbCwgc2lnbmF0dXJlIH07XG59XG5cbi8qKlxuICogU2F2ZSBiYWRnZSB0byBmaWxlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzYXZlQmFkZ2VUb0ZpbGUoXG4gIG91dHB1dFBhdGg6IHN0cmluZyxcbiAgcHJvamVjdE5hbWU6IHN0cmluZyxcbiAgcHJvamVjdFVybD86IHN0cmluZ1xuKTogdm9pZCB7XG4gIGNvbnN0IHsgbWFya2Rvd24sIGh0bWwgfSA9IGdlbmVyYXRlQmFkZ2VGb3JQcm9qZWN0KHByb2plY3ROYW1lLCBwcm9qZWN0VXJsKTtcbiAgXG4gIGNvbnN0IGNvbnRlbnQgPSBgIyBsbG12ZXJpZnkgQmFkZ2VcblxuIyMgTWFya2Rvd25cblxuXFxgXFxgXFxgbWFya2Rvd25cbiR7bWFya2Rvd259XG5cXGBcXGBcXGBcblxuIyMgSFRNTFxuXG5cXGBcXGBcXGBodG1sXG4ke2h0bWx9XG5cXGBcXGBcXGBcblxuIyMgVXNhZ2VcblxuQ29weSB0aGUgbWFya2Rvd24gb3IgSFRNTCBjb2RlIGFib3ZlIGFuZCBwYXN0ZSBpdCBpbnRvIHlvdXIgUkVBRE1FLm1kIG9yIHdlYnNpdGUuXG5cblRoZSBiYWRnZSB2ZXJpZmllcyB0aGF0IHlvdXIgcHJvamVjdCB1c2VzIGxsbXZlcmlmeSBmb3IgQUkgb3V0cHV0IHZlcmlmaWNhdGlvbi5cbmA7XG4gIFxuICBmcy53cml0ZUZpbGVTeW5jKG91dHB1dFBhdGgsIGNvbnRlbnQsICd1dGYtOCcpO1xufVxuIl19