@dollhousemcp/mcp-server
Version:
DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.
354 lines • 59.1 kB
JavaScript
/**
* TemplateManager - Refactored to extend BaseElementManager, keeping
* template-specific validation, import/export logic, and analytics helpers.
*/
import * as path from 'path';
import { ElementType } from '../../portfolio/types.js';
import { toSingularLabel } from '../../utils/elementTypeNormalization.js';
import { SecurityMonitor } from '../../security/securityMonitor.js';
import { sanitizeInput } from '../../security/InputValidator.js';
import { UnicodeValidator } from '../../security/validators/unicodeValidator.js';
import { logger } from '../../utils/logger.js';
import { BaseElementManager } from '../base/BaseElementManager.js';
import { Template } from './Template.js';
import { sanitizeGatekeeperPolicy } from '../../handlers/mcp-aql/policies/ElementPolicies.js';
import { SECURITY_LIMITS } from '../../security/constants.js';
export class TemplateManager extends BaseElementManager {
metadataService;
triggerValidationService;
validationService;
serializationService;
constructor(portfolioManager, fileLockManager, fileOperationsService, validationRegistry, serializationService, metadataService, fileWatchService, memoryBudget, backupService) {
super(ElementType.TEMPLATE, portfolioManager, fileLockManager, { fileWatchService, memoryBudget, backupService }, fileOperationsService, validationRegistry);
this.metadataService = metadataService;
this.triggerValidationService = validationRegistry.getTriggerValidationService();
this.validationService = validationRegistry.getValidationService();
this.serializationService = serializationService;
}
getElementLabel() {
return 'template';
}
async load(filePath) {
const template = await super.load(filePath);
SecurityMonitor.logSecurityEvent({
type: 'TEMPLATE_LOADED',
severity: 'LOW',
source: 'TemplateManager.load',
details: `Template loaded: ${template.metadata.name} from ${path.basename(filePath)}`
});
return template;
}
async save(template, filePath) {
// Auto-derive variables from content (#1896): ensures every {{placeholder}}
// has a matching schema entry so render() never silently returns unfilled text.
// Existing entries are never overwritten — user-set descriptions, types, and
// required flags survive. New entries default to type: 'string', required: false.
if (template.content) {
template.metadata.variables = Template.deriveVariablesFromContent(template.content, template.metadata.variables ?? []);
}
await super.save(template, filePath);
SecurityMonitor.logSecurityEvent({
type: 'TEMPLATE_SAVED',
severity: 'LOW',
source: 'TemplateManager.save',
details: `Template saved: ${template.metadata.name} to ${path.basename(filePath)}`
});
logger.info(`Template saved: ${template.metadata.name}`);
}
async delete(filePath) {
await super.delete(filePath);
SecurityMonitor.logSecurityEvent({
type: 'TEMPLATE_DELETED',
severity: 'MEDIUM',
source: 'TemplateManager.delete',
details: `Template deleted: ${path.basename(filePath)}`
});
logger.info(`Template deleted: ${path.basename(filePath)}`);
}
async create(data) {
// Use specialized validator for input validation
const validationResult = await this.validator.validateCreate({
name: data.name,
description: data.description,
content: data.content
});
if (!validationResult.isValid) {
throw new Error(`Validation failed: ${validationResult.errors.join(', ')}`);
}
// Log warnings if any
if (validationResult.warnings && validationResult.warnings.length > 0) {
logger.warn(`Template creation warnings: ${validationResult.warnings.join(', ')}`);
}
// Get sanitized name for file operations (validator already validated)
const nameInput = data.name || 'new-template';
const nameResult = this.validationService.validateAndSanitizeInput(nameInput, {
maxLength: SECURITY_LIMITS.MAX_NAME_LENGTH,
allowSpaces: true
});
const sanitizedName = nameResult.sanitizedValue;
// Use inherited getElementFilename() for consistent filename normalization
const filename = this.getElementFilename(sanitizedName);
// FIX: Issue #20 - Check for duplicate before creating
const existingTemplates = await this.list();
const duplicate = existingTemplates.find(t => t.metadata.name.toLowerCase() === sanitizedName.toLowerCase());
if (duplicate) {
throw new Error(`A template named "${sanitizedName}" already exists`);
}
const template = new Template({
...data.metadata,
name: sanitizedName,
description: data.description || ''
}, data.content || '', this.metadataService);
// Set instructions (rendering directives) if provided
if (data.instructions) {
template.instructions = data.instructions;
}
await this.save(template, filename);
// Note: No reload() here — save() caches the element correctly.
// See Issue #491 for why PersonaManager's reload-after-create was removed.
SecurityMonitor.logSecurityEvent({
type: 'ELEMENT_CREATED',
severity: 'LOW',
source: 'TemplateManager.create',
details: `Template created: ${template.metadata.name}`
});
return template;
}
async importElement(data, format = 'markdown') {
try {
let metadata;
let content = '';
switch (format) {
case 'json': {
const jsonData = this.serializationService.parseJson(data, {
source: 'TemplateManager.importElement'
});
metadata = await this.sanitizeMetadata(jsonData.metadata || {});
content = jsonData.content || '';
break;
}
case 'yaml': {
const parsed = this.serializationService.parseFrontmatter(data, {
maxYamlSize: 64 * 1024,
validateContent: true,
source: 'TemplateManager.importElement'
});
metadata = await this.sanitizeMetadata(parsed.data.metadata || parsed.data);
content = parsed.content || '';
break;
}
case 'markdown': {
const mdParsed = this.serializationService.parseFrontmatter(data, {
maxYamlSize: 64 * 1024,
validateContent: true,
source: 'TemplateManager.importElement'
});
metadata = await this.sanitizeMetadata(mdParsed.data);
content = mdParsed.content;
break;
}
default:
throw new Error(`Unsupported import format: ${format}`);
}
const template = new Template(metadata, content, this.metadataService);
const validation = template.validate();
if (!validation.valid) {
throw new Error(`Invalid template: ${validation.errors?.map(e => e.message).join(', ')}`);
}
return template;
}
catch (error) {
logger.error(`Failed to import template: ${error}`);
throw error;
}
}
async exportElement(template, format = 'markdown') {
try {
switch (format) {
case 'json':
return template.serializeToJSON ? template.serializeToJSON() : template.serialize();
case 'yaml': {
const yamlData = {
metadata: template.metadata,
content: template.content,
id: template.id,
version: template.version
};
return this.serializationService.dumpYaml(yamlData, {
schema: 'json', // Fix #914: standardize on JSON schema across all managers
noRefs: true,
sortKeys: true,
skipInvalid: true
});
}
case 'markdown': {
return this.serializationService.createFrontmatter(template.metadata, template.content, {
method: 'manual',
schema: 'json', // Fix #914: standardize on JSON schema across all managers
cleanMetadata: true,
cleaningStrategy: 'remove-both' // Fix #913: standardize across all managers
});
}
default:
throw new Error(`Unsupported export format: ${format}`);
}
}
catch (error) {
logger.error(`Failed to export template: ${error}`);
throw error;
}
}
async findByCategory(category) {
const sanitizedCategory = sanitizeInput(category, 50);
const templates = await this.list();
return templates.filter(t => t.metadata.category === sanitizedCategory);
}
async findByTag(tag) {
const sanitizedTag = sanitizeInput(tag, 50);
const templates = await this.list();
return templates.filter(t => t.metadata.tags?.includes(sanitizedTag));
}
async getMostUsed(limit = 10) {
const MIN_LIMIT = 1;
const MAX_LIMIT = 100;
const validatedLimit = Math.max(MIN_LIMIT, Math.min(MAX_LIMIT, Math.floor(limit)));
if (limit !== validatedLimit) {
logger.warn(`getMostUsed: limit ${limit} adjusted to ${validatedLimit} (valid range: ${MIN_LIMIT}-${MAX_LIMIT})`);
}
const templates = await this.list();
return templates
.sort((a, b) => (b.metadata.usage_count || 0) - (a.metadata.usage_count || 0))
.slice(0, validatedLimit);
}
getFileExtension() {
return '.md';
}
async parseMetadata(data) {
const sanitized = await this.sanitizeMetadata(data);
// Use Template constructor to ensure required fields are populated
const tempTemplate = new Template(sanitized, '', this.metadataService);
return tempTemplate.metadata;
}
createElement(metadata, bodyContent) {
// Fix #912: Prefer explicit format_version marker, fall back to instructions-presence check
const metadataInstructions = metadata.instructions;
delete metadata.format_version; // Strip marker from runtime metadata
const template = new Template(metadata, bodyContent, this.metadataService);
if (metadataInstructions) {
template.instructions = metadataInstructions;
delete metadata.instructions;
}
return template;
}
buildDefaultBody(template) {
const name = (template.metadata.name ?? '').trim();
const description = (template.metadata.description ?? '').trim();
const lines = [];
if (name) {
lines.push(`# ${name}`);
lines.push('');
}
if (description) {
lines.push(description);
lines.push('');
}
// Section format: <template> for Handlebars content, <style>/<script> for raw passthrough.
// Auto-detection (issue #705): section mode activates when body has a <template> root element.
lines.push('<template>');
lines.push('<!-- HTML content with {{variable}} substitution -->');
lines.push('</template>');
lines.push('');
lines.push('<style>');
lines.push('/* CSS styles (}} is safe here — not Handlebars processed) */');
lines.push('</style>');
lines.push('');
lines.push('<script>');
lines.push('// JavaScript (}} is safe here — not Handlebars processed)');
lines.push('</script>');
return lines.join('\n');
}
async serializeElement(template) {
// v2.0 format: add instructions to YAML frontmatter if present
const metadata = { ...template.metadata };
// Issue #755: Serialize type as singular and persist unique_id
metadata.type = toSingularLabel(ElementType.TEMPLATE);
metadata.unique_id = template.id;
// Fix #912: Explicit format marker
metadata.format_version = 'v2';
if (template.instructions) {
metadata.instructions = template.instructions;
}
return this.serializationService.createFrontmatter(metadata, template.content || this.buildDefaultBody(template), {
method: 'manual',
schema: 'json', // Fix #914: standardize on JSON schema across all managers
cleanMetadata: true,
cleaningStrategy: 'remove-both', // Fix #913: standardize across all managers
sortKeys: true,
lineWidth: 80,
skipInvalid: true
});
}
async sanitizeMetadata(data) {
const metadata = {};
if (data.name) {
metadata.name = sanitizeInput(UnicodeValidator.normalize(data.name).normalizedContent, 100);
}
if (data.description) {
metadata.description = sanitizeInput(UnicodeValidator.normalize(data.description).normalizedContent, 500);
}
if (data.category) {
// SECURITY FIX: Use ValidationService for category validation
const categoryResult = this.validationService.validateCategory(data.category);
if (categoryResult.isValid && categoryResult.sanitizedValue) {
metadata.category = categoryResult.sanitizedValue;
}
}
if (data.output_format) {
metadata.output_format = sanitizeInput(data.output_format, 20);
}
if (Array.isArray(data.tags)) {
metadata.tags = data.tags.map((tag) => sanitizeInput(String(tag), 50));
}
if (Array.isArray(data.includes)) {
metadata.includes = data.includes.map((inc) => sanitizeInput(String(inc), 200));
}
if (data.triggers && Array.isArray(data.triggers)) {
const validationResult = this.triggerValidationService.validateTriggers(data.triggers, ElementType.TEMPLATE, metadata.name || 'unknown');
metadata.triggers = validationResult.validTriggers;
}
if (typeof data.usage_count === 'number') {
metadata.usage_count = Math.max(0, Math.floor(data.usage_count));
}
if (data.last_used) {
metadata.last_used = sanitizeInput(String(data.last_used), 50);
}
if (Array.isArray(data.variables)) {
metadata.variables = data.variables.map((v) => ({
name: sanitizeInput(v.name || '', 50),
type: sanitizeInput(v.type || 'string', 20),
description: v.description ? sanitizeInput(v.description, SECURITY_LIMITS.MAX_DOCUMENTATION_FIELD_LENGTH) : undefined,
required: Boolean(v.required),
default: v.default,
validation: v.validation ? sanitizeInput(v.validation, 200) : undefined,
options: Array.isArray(v.options) ? v.options.map((o) => sanitizeInput(String(o), 100)) : undefined,
format: v.format ? sanitizeInput(v.format, 50) : undefined
}));
}
if (Array.isArray(data.examples)) {
metadata.examples = data.examples.map((ex) => ({
title: sanitizeInput(ex.title || '', 100),
description: ex.description ? sanitizeInput(ex.description, SECURITY_LIMITS.MAX_DOCUMENTATION_FIELD_LENGTH) : undefined,
variables: ex.variables || {},
output: ex.output ? sanitizeInput(ex.output, 5000) : undefined
}));
}
metadata.author = data.author ? sanitizeInput(data.author, 100) : undefined;
metadata.version = data.version ? sanitizeInput(data.version, 20) : undefined;
// Issue #524 — Gatekeeper policy (all element types)
metadata.gatekeeper = sanitizeGatekeeperPolicy(data.gatekeeper, metadata.name || 'unknown', 'template', metadata);
metadata.name = metadata.name ?? 'Untitled Template';
metadata.description = metadata.description ?? '';
return metadata;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVGVtcGxhdGVNYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2VsZW1lbnRzL3RlbXBsYXRlcy9UZW1wbGF0ZU1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBRUgsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFFN0IsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQztBQUMxRSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDcEUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLCtDQUErQyxDQUFDO0FBRWpGLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNuRSxPQUFPLEVBQUUsUUFBUSxFQUFvQixNQUFNLGVBQWUsQ0FBQztBQVMzRCxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxvREFBb0QsQ0FBQztBQUM5RixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFOUQsTUFBTSxPQUFPLGVBQWdCLFNBQVEsa0JBQTRCO0lBV3JEO0lBVkYsd0JBQXdCLENBQTJCO0lBQ25ELGlCQUFpQixDQUFvQjtJQUNyQyxvQkFBb0IsQ0FBdUI7SUFFbkQsWUFDRSxnQkFBa0MsRUFDbEMsZUFBZ0MsRUFDaEMscUJBQTRDLEVBQzVDLGtCQUFzQyxFQUN0QyxvQkFBMEMsRUFDbEMsZUFBZ0MsRUFDeEMsZ0JBQW1DLEVBQ25DLFlBQTJFLEVBQzNFLGFBQXVFO1FBRXZFLEtBQUssQ0FBQyxXQUFXLENBQUMsUUFBUSxFQUFFLGdCQUFnQixFQUFFLGVBQWUsRUFBRSxF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QyxNQUFNLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFDNUUsUUFBUSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO1FBRTlFLHFEQUFxRDtRQUNyRCxRQUFRLENBQUMsVUFBVSxHQUFHLHdCQUF3QixDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsUUFBUSxDQUFDLElBQUksSUFBSSxTQUFTLEVBQUUsVUFBVSxFQUFFLFFBQW1DLENBQUMsQ0FBQztRQUU3SSxRQUFRLENBQUMsSUFBSSxHQUFHLFFBQVEsQ0FBQyxJQUFJLElBQUksbUJBQW1CLENBQUM7UUFDckQsUUFBUSxDQUFDLFdBQVcsR0FBRyxRQUFRLENBQUMsV0FBVyxJQUFJLEVBQUUsQ0FBQztRQUVsRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRlbXBsYXRlTWFuYWdlciAtIFJlZmFjdG9yZWQgdG8gZXh0ZW5kIEJhc2VFbGVtZW50TWFuYWdlciwga2VlcGluZ1xuICogdGVtcGxhdGUtc3BlY2lmaWMgdmFsaWRhdGlvbiwgaW1wb3J0L2V4cG9ydCBsb2dpYywgYW5kIGFuYWx5dGljcyBoZWxwZXJzLlxuICovXG5cbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5cbmltcG9ydCB7IEVsZW1lbnRUeXBlIH0gZnJvbSAnLi4vLi4vcG9ydGZvbGlvL3R5cGVzLmpzJztcbmltcG9ydCB7IHRvU2luZ3VsYXJMYWJlbCB9IGZyb20gJy4uLy4uL3V0aWxzL2VsZW1lbnRUeXBlTm9ybWFsaXphdGlvbi5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi8uLi9zZWN1cml0eS9zZWN1cml0eU1vbml0b3IuanMnO1xuaW1wb3J0IHsgc2FuaXRpemVJbnB1dCB9IGZyb20gJy4uLy4uL3NlY3VyaXR5L0lucHV0VmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IFVuaWNvZGVWYWxpZGF0b3IgfSBmcm9tICcuLi8uLi9zZWN1cml0eS92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuaW1wb3J0IHsgRmlsZUxvY2tNYW5hZ2VyIH0gZnJvbSAnLi4vLi4vc2VjdXJpdHkvZmlsZUxvY2tNYW5hZ2VyLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uLy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBCYXNlRWxlbWVudE1hbmFnZXIgfSBmcm9tICcuLi9iYXNlL0Jhc2VFbGVtZW50TWFuYWdlci5qcyc7XG5pbXBvcnQgeyBUZW1wbGF0ZSwgVGVtcGxhdGVNZXRhZGF0YSB9IGZyb20gJy4vVGVtcGxhdGUuanMnO1xuaW1wb3J0IHsgUG9ydGZvbGlvTWFuYWdlciB9IGZyb20gJy4uLy4uL3BvcnRmb2xpby9Qb3J0Zm9saW9NYW5hZ2VyLmpzJztcbmltcG9ydCB7IFZhbGlkYXRpb25SZWdpc3RyeSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL3ZhbGlkYXRpb24vVmFsaWRhdGlvblJlZ2lzdHJ5LmpzJztcbmltcG9ydCB7IFRyaWdnZXJWYWxpZGF0aW9uU2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL3ZhbGlkYXRpb24vVHJpZ2dlclZhbGlkYXRpb25TZXJ2aWNlLmpzJztcbmltcG9ydCB7IFZhbGlkYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi4vLi4vc2VydmljZXMvdmFsaWRhdGlvbi9WYWxpZGF0aW9uU2VydmljZS5qcyc7XG5pbXBvcnQgeyBTZXJpYWxpemF0aW9uU2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL1NlcmlhbGl6YXRpb25TZXJ2aWNlLmpzJztcbmltcG9ydCB7IE1ldGFkYXRhU2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL01ldGFkYXRhU2VydmljZS5qcyc7XG5pbXBvcnQgeyBGaWxlT3BlcmF0aW9uc1NlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9GaWxlT3BlcmF0aW9uc1NlcnZpY2UuanMnO1xuaW1wb3J0IHsgRmlsZVdhdGNoU2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL0ZpbGVXYXRjaFNlcnZpY2UuanMnO1xuaW1wb3J0IHsgc2FuaXRpemVHYXRla2VlcGVyUG9saWN5IH0gZnJvbSAnLi4vLi4vaGFuZGxlcnMvbWNwLWFxbC9wb2xpY2llcy9FbGVtZW50UG9saWNpZXMuanMnO1xuaW1wb3J0IHsgU0VDVVJJVFlfTElNSVRTIH0gZnJvbSAnLi4vLi4vc2VjdXJpdHkvY29uc3RhbnRzLmpzJztcblxuZXhwb3J0IGNsYXNzIFRlbXBsYXRlTWFuYWdlciBleHRlbmRzIEJhc2VFbGVtZW50TWFuYWdlcjxUZW1wbGF0ZT4ge1xuICBwcml2YXRlIHRyaWdnZXJWYWxpZGF0aW9uU2VydmljZTogVHJpZ2dlclZhbGlkYXRpb25TZXJ2aWNlO1xuICBwcml2YXRlIHZhbGlkYXRpb25TZXJ2aWNlOiBWYWxpZGF0aW9uU2VydmljZTtcbiAgcHJpdmF0ZSBzZXJpYWxpemF0aW9uU2VydmljZTogU2VyaWFsaXphdGlvblNlcnZpY2U7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcG9ydGZvbGlvTWFuYWdlcjogUG9ydGZvbGlvTWFuYWdlcixcbiAgICBmaWxlTG9ja01hbmFnZXI6IEZpbGVMb2NrTWFuYWdlcixcbiAgICBmaWxlT3BlcmF0aW9uc1NlcnZpY2U6IEZpbGVPcGVyYXRpb25zU2VydmljZSxcbiAgICB2YWxpZGF0aW9uUmVnaXN0cnk6IFZhbGlkYXRpb25SZWdpc3RyeSxcbiAgICBzZXJpYWxpemF0aW9uU2VydmljZTogU2VyaWFsaXphdGlvblNlcnZpY2UsXG4gICAgcHJpdmF0ZSBtZXRhZGF0YVNlcnZpY2U6IE1ldGFkYXRhU2VydmljZSxcbiAgICBmaWxlV2F0Y2hTZXJ2aWNlPzogRmlsZVdhdGNoU2VydmljZSxcbiAgICBtZW1vcnlCdWRnZXQ/OiBpbXBvcnQoJy4uLy4uL2NhY2hlL0NhY2hlTWVtb3J5QnVkZ2V0LmpzJykuQ2FjaGVNZW1vcnlCdWRnZXQsXG4gICAgYmFja3VwU2VydmljZT86IGltcG9ydCgnLi4vLi4vc2VydmljZXMvQmFja3VwU2VydmljZS5qcycpLkJhY2t1cFNlcnZpY2VcbiAgKSB7XG4gICAgc3VwZXIoRWxlbWVudFR5cGUuVEVNUExBVEUsIHBvcnRmb2xpb01hbmFnZXIsIGZpbGVMb2NrTWFuYWdlciwgeyBmaWxlV2F0Y2hTZXJ2aWNlLCBtZW1vcnlCdWRnZXQsIGJhY2t1cFNlcnZpY2UgfSwgZmlsZU9wZXJhdGlvbnNTZXJ2aWNlLCB2YWxpZGF0aW9uUmVnaXN0cnkpO1xuICAgIHRoaXMudHJpZ2dlclZhbGlkYXRpb25TZXJ2aWNlID0gdmFsaWRhdGlvblJlZ2lzdHJ5LmdldFRyaWdnZXJWYWxpZGF0aW9uU2VydmljZSgpO1xuICAgIHRoaXMudmFsaWRhdGlvblNlcnZpY2UgPSB2YWxpZGF0aW9uUmVnaXN0cnkuZ2V0VmFsaWRhdGlvblNlcnZpY2UoKTtcbiAgICB0aGlzLnNlcmlhbGl6YXRpb25TZXJ2aWNlID0gc2VyaWFsaXphdGlvblNlcnZpY2U7XG4gIH1cblxuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgZ2V0RWxlbWVudExhYmVsKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuICd0ZW1wbGF0ZSc7XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyBsb2FkKGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPFRlbXBsYXRlPiB7XG4gICAgY29uc3QgdGVtcGxhdGUgPSBhd2FpdCBzdXBlci5sb2FkKGZpbGVQYXRoKTtcblxuICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgIHR5cGU6ICdURU1QTEFURV9MT0FERUQnLFxuICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgc291cmNlOiAnVGVtcGxhdGVNYW5hZ2VyLmxvYWQnLFxuICAgICAgZGV0YWlsczogYFRlbXBsYXRlIGxvYWRlZDogJHt0ZW1wbGF0ZS5tZXRhZGF0YS5uYW1lfSBmcm9tICR7cGF0aC5iYXNlbmFtZShmaWxlUGF0aCl9YFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHRlbXBsYXRlO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgc2F2ZSh0ZW1wbGF0ZTogVGVtcGxhdGUsIGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyBBdXRvLWRlcml2ZSB2YXJpYWJsZXMgZnJvbSBjb250ZW50ICgjMTg5Nik6IGVuc3VyZXMgZXZlcnkge3twbGFjZWhvbGRlcn19XG4gICAgLy8gaGFzIGEgbWF0Y2hpbmcgc2NoZW1hIGVudHJ5IHNvIHJlbmRlcigpIG5ldmVyIHNpbGVudGx5IHJldHVybnMgdW5maWxsZWQgdGV4dC5cbiAgICAvLyBFeGlzdGluZyBlbnRyaWVzIGFyZSBuZXZlciBvdmVyd3JpdHRlbiDigJQgdXNlci1zZXQgZGVzY3JpcHRpb25zLCB0eXBlcywgYW5kXG4gICAgLy8gcmVxdWlyZWQgZmxhZ3Mgc3Vydml2ZS4gTmV3IGVudHJpZXMgZGVmYXVsdCB0byB0eXBlOiAnc3RyaW5nJywgcmVxdWlyZWQ6IGZhbHNlLlxuICAgIGlmICh0ZW1wbGF0ZS5jb250ZW50KSB7XG4gICAgICB0ZW1wbGF0ZS5tZXRhZGF0YS52YXJpYWJsZXMgPSBUZW1wbGF0ZS5kZXJpdmVWYXJpYWJsZXNGcm9tQ29udGVudChcbiAgICAgICAgdGVtcGxhdGUuY29udGVudCxcbiAgICAgICAgdGVtcGxhdGUubWV0YWRhdGEudmFyaWFibGVzID8/IFtdXG4gICAgICApO1xuICAgIH1cblxuICAgIGF3YWl0IHN1cGVyLnNhdmUodGVtcGxhdGUsIGZpbGVQYXRoKTtcblxuICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgIHR5cGU6ICdURU1QTEFURV9TQVZFRCcsXG4gICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICBzb3VyY2U6ICdUZW1wbGF0ZU1hbmFnZXIuc2F2ZScsXG4gICAgICBkZXRhaWxzOiBgVGVtcGxhdGUgc2F2ZWQ6ICR7dGVtcGxhdGUubWV0YWRhdGEubmFtZX0gdG8gJHtwYXRoLmJhc2VuYW1lKGZpbGVQYXRoKX1gXG4gICAgfSk7XG5cbiAgICBsb2dnZXIuaW5mbyhgVGVtcGxhdGUgc2F2ZWQ6ICR7dGVtcGxhdGUubWV0YWRhdGEubmFtZX1gKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIGRlbGV0ZShmaWxlUGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgc3VwZXIuZGVsZXRlKGZpbGVQYXRoKTtcblxuICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgIHR5cGU6ICdURU1QTEFURV9ERUxFVEVEJyxcbiAgICAgIHNldmVyaXR5OiAnTUVESVVNJyxcbiAgICAgIHNvdXJjZTogJ1RlbXBsYXRlTWFuYWdlci5kZWxldGUnLFxuICAgICAgZGV0YWlsczogYFRlbXBsYXRlIGRlbGV0ZWQ6ICR7cGF0aC5iYXNlbmFtZShmaWxlUGF0aCl9YFxuICAgIH0pO1xuXG4gICAgbG9nZ2VyLmluZm8oYFRlbXBsYXRlIGRlbGV0ZWQ6ICR7cGF0aC5iYXNlbmFtZShmaWxlUGF0aCl9YCk7XG4gIH1cblxuICBhc3luYyBjcmVhdGUoZGF0YToge1xuICAgIG5hbWU6IHN0cmluZztcbiAgICBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICAgIGNvbnRlbnQ/OiBzdHJpbmc7XG4gICAgaW5zdHJ1Y3Rpb25zPzogc3RyaW5nO1xuICAgIG1ldGFkYXRhPzogUGFydGlhbDxUZW1wbGF0ZU1ldGFkYXRhPjtcbiAgfSk6IFByb21pc2U8VGVtcGxhdGU+IHtcbiAgICAvLyBVc2Ugc3BlY2lhbGl6ZWQgdmFsaWRhdG9yIGZvciBpbnB1dCB2YWxpZGF0aW9uXG4gICAgY29uc3QgdmFsaWRhdGlvblJlc3VsdCA9IGF3YWl0IHRoaXMudmFsaWRhdG9yLnZhbGlkYXRlQ3JlYXRlKHtcbiAgICAgIG5hbWU6IGRhdGEubmFtZSxcbiAgICAgIGRlc2NyaXB0aW9uOiBkYXRhLmRlc2NyaXB0aW9uLFxuICAgICAgY29udGVudDogZGF0YS5jb250ZW50XG4gICAgfSk7XG5cbiAgICBpZiAoIXZhbGlkYXRpb25SZXN1bHQuaXNWYWxpZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBWYWxpZGF0aW9uIGZhaWxlZDogJHt2YWxpZGF0aW9uUmVzdWx0LmVycm9ycy5qb2luKCcsICcpfWApO1xuICAgIH1cblxuICAgIC8vIExvZyB3YXJuaW5ncyBpZiBhbnlcbiAgICBpZiAodmFsaWRhdGlvblJlc3VsdC53YXJuaW5ncyAmJiB2YWxpZGF0aW9uUmVzdWx0Lndhcm5pbmdzLmxlbmd0aCA+IDApIHtcbiAgICAgIGxvZ2dlci53YXJuKGBUZW1wbGF0ZSBjcmVhdGlvbiB3YXJuaW5nczogJHt2YWxpZGF0aW9uUmVzdWx0Lndhcm5pbmdzLmpvaW4oJywgJyl9YCk7XG4gICAgfVxuXG4gICAgLy8gR2V0IHNhbml0aXplZCBuYW1lIGZvciBmaWxlIG9wZXJhdGlvbnMgKHZhbGlkYXRvciBhbHJlYWR5IHZhbGlkYXRlZClcbiAgICBjb25zdCBuYW1lSW5wdXQgPSBkYXRhLm5hbWUgfHwgJ25ldy10ZW1wbGF0ZSc7XG4gICAgY29uc3QgbmFtZVJlc3VsdCA9IHRoaXMudmFsaWRhdGlvblNlcnZpY2UudmFsaWRhdGVBbmRTYW5pdGl6ZUlucHV0KG5hbWVJbnB1dCwge1xuICAgICAgbWF4TGVuZ3RoOiBTRUNVUklUWV9MSU1JVFMuTUFYX05BTUVfTEVOR1RILFxuICAgICAgYWxsb3dTcGFjZXM6IHRydWVcbiAgICB9KTtcbiAgICBjb25zdCBzYW5pdGl6ZWROYW1lID0gbmFtZVJlc3VsdC5zYW5pdGl6ZWRWYWx1ZSE7XG5cbiAgICAvLyBVc2UgaW5oZXJpdGVkIGdldEVsZW1lbnRGaWxlbmFtZSgpIGZvciBjb25zaXN0ZW50IGZpbGVuYW1lIG5vcm1hbGl6YXRpb25cbiAgICBjb25zdCBmaWxlbmFtZSA9IHRoaXMuZ2V0RWxlbWVudEZpbGVuYW1lKHNhbml0aXplZE5hbWUpO1xuXG4gICAgLy8gRklYOiBJc3N1ZSAjMjAgLSBDaGVjayBmb3IgZHVwbGljYXRlIGJlZm9yZSBjcmVhdGluZ1xuICAgIGNvbnN0IGV4aXN0aW5nVGVtcGxhdGVzID0gYXdhaXQgdGhpcy5saXN0KCk7XG4gICAgY29uc3QgZHVwbGljYXRlID0gZXhpc3RpbmdUZW1wbGF0ZXMuZmluZCh0ID0+XG4gICAgICB0Lm1ldGFkYXRhLm5hbWUudG9Mb3dlckNhc2UoKSA9PT0gc2FuaXRpemVkTmFtZS50b0xvd2VyQ2FzZSgpXG4gICAgKTtcblxuICAgIGlmIChkdXBsaWNhdGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQSB0ZW1wbGF0ZSBuYW1lZCBcIiR7c2FuaXRpemVkTmFtZX1cIiBhbHJlYWR5IGV4aXN0c2ApO1xuICAgIH1cblxuICAgIGNvbnN0IHRlbXBsYXRlID0gbmV3IFRlbXBsYXRlKFxuICAgICAge1xuICAgICAgICAuLi5kYXRhLm1ldGFkYXRhLFxuICAgICAgICBuYW1lOiBzYW5pdGl6ZWROYW1lLFxuICAgICAgICBkZXNjcmlwdGlvbjogZGF0YS5kZXNjcmlwdGlvbiB8fCAnJ1xuICAgICAgfSxcbiAgICAgIGRhdGEuY29udGVudCB8fCAnJyxcbiAgICAgIHRoaXMubWV0YWRhdGFTZXJ2aWNlXG4gICAgKTtcbiAgICAvLyBTZXQgaW5zdHJ1Y3Rpb25zIChyZW5kZXJpbmcgZGlyZWN0aXZlcykgaWYgcHJvdmlkZWRcbiAgICBpZiAoZGF0YS5pbnN0cnVjdGlvbnMpIHtcbiAgICAgIHRlbXBsYXRlLmluc3RydWN0aW9ucyA9IGRhdGEuaW5zdHJ1Y3Rpb25zO1xuICAgIH1cblxuICAgIGF3YWl0IHRoaXMuc2F2ZSh0ZW1wbGF0ZSwgZmlsZW5hbWUpO1xuICAgIC8vIE5vdGU6IE5vIHJlbG9hZCgpIGhlcmUg4oCUIHNhdmUoKSBjYWNoZXMgdGhlIGVsZW1lbnQgY29ycmVjdGx5LlxuICAgIC8vIFNlZSBJc3N1ZSAjNDkxIGZvciB3aHkgUGVyc29uYU1hbmFnZXIncyByZWxvYWQtYWZ0ZXItY3JlYXRlIHdhcyByZW1vdmVkLlxuXG4gICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgdHlwZTogJ0VMRU1FTlRfQ1JFQVRFRCcsXG4gICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICBzb3VyY2U6ICdUZW1wbGF0ZU1hbmFnZXIuY3JlYXRlJyxcbiAgICAgIGRldGFpbHM6IGBUZW1wbGF0ZSBjcmVhdGVkOiAke3RlbXBsYXRlLm1ldGFkYXRhLm5hbWV9YFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHRlbXBsYXRlO1xuICB9XG5cbiAgYXN5bmMgaW1wb3J0RWxlbWVudChkYXRhOiBzdHJpbmcsIGZvcm1hdDogJ2pzb24nIHwgJ3lhbWwnIHwgJ21hcmtkb3duJyA9ICdtYXJrZG93bicpOiBQcm9taXNlPFRlbXBsYXRlPiB7XG4gICAgdHJ5IHtcbiAgICAgIGxldCBtZXRhZGF0YTogUGFydGlhbDxUZW1wbGF0ZU1ldGFkYXRhPjtcbiAgICAgIGxldCBjb250ZW50ID0gJyc7XG5cbiAgICAgIHN3aXRjaCAoZm9ybWF0KSB7XG4gICAgICAgIGNhc2UgJ2pzb24nOiB7XG4gICAgICAgICAgY29uc3QganNvbkRhdGEgPSB0aGlzLnNlcmlhbGl6YXRpb25TZXJ2aWNlLnBhcnNlSnNvbihkYXRhLCB7XG4gICAgICAgICAgICBzb3VyY2U6ICdUZW1wbGF0ZU1hbmFnZXIuaW1wb3J0RWxlbWVudCdcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBtZXRhZGF0YSA9IGF3YWl0IHRoaXMuc2FuaXRpemVNZXRhZGF0YShqc29uRGF0YS5tZXRhZGF0YSB8fCB7fSk7XG4gICAgICAgICAgY29udGVudCA9IGpzb25EYXRhLmNvbnRlbnQgfHwgJyc7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICBjYXNlICd5YW1sJzoge1xuICAgICAgICAgIGNvbnN0IHBhcnNlZCA9IHRoaXMuc2VyaWFsaXphdGlvblNlcnZpY2UucGFyc2VGcm9udG1hdHRlcihkYXRhLCB7XG4gICAgICAgICAgICBtYXhZYW1sU2l6ZTogNjQgKiAxMDI0LFxuICAgICAgICAgICAgdmFsaWRhdGVDb250ZW50OiB0cnVlLFxuICAgICAgICAgICAgc291cmNlOiAnVGVtcGxhdGVNYW5hZ2VyLmltcG9ydEVsZW1lbnQnXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBtZXRhZGF0YSA9IGF3YWl0IHRoaXMuc2FuaXRpemVNZXRhZGF0YShwYXJzZWQuZGF0YS5tZXRhZGF0YSB8fCBwYXJzZWQuZGF0YSk7XG4gICAgICAgICAgY29udGVudCA9IHBhcnNlZC5jb250ZW50IHx8ICcnO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgY2FzZSAnbWFya2Rvd24nOiB7XG4gICAgICAgICAgY29uc3QgbWRQYXJzZWQgPSB0aGlzLnNlcmlhbGl6YXRpb25TZXJ2aWNlLnBhcnNlRnJvbnRtYXR0ZXIoZGF0YSwge1xuICAgICAgICAgICAgbWF4WWFtbFNpemU6IDY0ICogMTAyNCxcbiAgICAgICAgICAgIHZhbGlkYXRlQ29udGVudDogdHJ1ZSxcbiAgICAgICAgICAgIHNvdXJjZTogJ1RlbXBsYXRlTWFuYWdlci5pbXBvcnRFbGVtZW50J1xuICAgICAgICAgIH0pO1xuICAgICAgICAgIG1ldGFkYXRhID0gYXdhaXQgdGhpcy5zYW5pdGl6ZU1ldGFkYXRhKG1kUGFyc2VkLmRhdGEpO1xuICAgICAgICAgIGNvbnRlbnQgPSBtZFBhcnNlZC5jb250ZW50O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIGltcG9ydCBmb3JtYXQ6ICR7Zm9ybWF0fWApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB0ZW1wbGF0ZSA9IG5ldyBUZW1wbGF0ZShtZXRhZGF0YSwgY29udGVudCwgdGhpcy5tZXRhZGF0YVNlcnZpY2UpO1xuICAgICAgY29uc3QgdmFsaWRhdGlvbiA9IHRlbXBsYXRlLnZhbGlkYXRlKCk7XG4gICAgICBpZiAoIXZhbGlkYXRpb24udmFsaWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHRlbXBsYXRlOiAke3ZhbGlkYXRpb24uZXJyb3JzPy5tYXAoZSA9PiBlLm1lc3NhZ2UpLmpvaW4oJywgJyl9YCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0ZW1wbGF0ZTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKGBGYWlsZWQgdG8gaW1wb3J0IHRlbXBsYXRlOiAke2Vycm9yfWApO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgZXhwb3J0RWxlbWVudCh0ZW1wbGF0ZTogVGVtcGxhdGUsIGZvcm1hdDogJ2pzb24nIHwgJ3lhbWwnIHwgJ21hcmtkb3duJyA9ICdtYXJrZG93bicpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRyeSB7XG4gICAgICBzd2l0Y2ggKGZvcm1hdCkge1xuICAgICAgICBjYXNlICdqc29uJzpcbiAgICAgICAgICByZXR1cm4gKHRlbXBsYXRlIGFzIGFueSkuc2VyaWFsaXplVG9KU09OID8gKHRlbXBsYXRlIGFzIGFueSkuc2VyaWFsaXplVG9KU09OKCkgOiB0ZW1wbGF0ZS5zZXJpYWxpemUoKTtcblxuICAgICAgICBjYXNlICd5YW1sJzoge1xuICAgICAgICAgIGNvbnN0IHlhbWxEYXRhID0ge1xuICAgICAgICAgICAgbWV0YWRhdGE6IHRlbXBsYXRlLm1ldGFkYXRhLFxuICAgICAgICAgICAgY29udGVudDogdGVtcGxhdGUuY29udGVudCxcbiAgICAgICAgICAgIGlkOiB0ZW1wbGF0ZS5pZCxcbiAgICAgICAgICAgIHZlcnNpb246IHRlbXBsYXRlLnZlcnNpb25cbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgcmV0dXJuIHRoaXMuc2VyaWFsaXphdGlvblNlcnZpY2UuZHVtcFlhbWwoeWFtbERhdGEsIHtcbiAgICAgICAgICAgIHNjaGVtYTogJ2pzb24nLCAgLy8gRml4ICM5MTQ6IHN0YW5kYXJkaXplIG9uIEpTT04gc2NoZW1hIGFjcm9zcyBhbGwgbWFuYWdlcnNcbiAgICAgICAgICAgIG5vUmVmczogdHJ1ZSxcbiAgICAgICAgICAgIHNvcnRLZXlzOiB0cnVlLFxuICAgICAgICAgICAgc2tpcEludmFsaWQ6IHRydWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNhc2UgJ21hcmtkb3duJzoge1xuICAgICAgICAgIHJldHVybiB0aGlzLnNlcmlhbGl6YXRpb25TZXJ2aWNlLmNyZWF0ZUZyb250bWF0dGVyKFxuICAgICAgICAgICAgdGVtcGxhdGUubWV0YWRhdGEsXG4gICAgICAgICAgICB0ZW1wbGF0ZS5jb250ZW50LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBtZXRob2Q6ICdtYW51YWwnLFxuICAgICAgICAgICAgICBzY2hlbWE6ICdqc29uJywgIC8vIEZpeCAjOTE0OiBzdGFuZGFyZGl6ZSBvbiBKU09OIHNjaGVtYSBhY3Jvc3MgYWxsIG1hbmFnZXJzXG4gICAgICAgICAgICAgIGNsZWFuTWV0YWRhdGE6IHRydWUsXG4gICAgICAgICAgICAgIGNsZWFuaW5nU3RyYXRlZ3k6ICdyZW1vdmUtYm90aCcgIC8vIEZpeCAjOTEzOiBzdGFuZGFyZGl6ZSBhY3Jvc3MgYWxsIG1hbmFnZXJzXG4gICAgICAgICAgICB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBleHBvcnQgZm9ybWF0OiAke2Zvcm1hdH1gKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKGBGYWlsZWQgdG8gZXhwb3J0IHRlbXBsYXRlOiAke2Vycm9yfWApO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgZmluZEJ5Q2F0ZWdvcnkoY2F0ZWdvcnk6IHN0cmluZyk6IFByb21pc2U8VGVtcGxhdGVbXT4ge1xuICAgIGNvbnN0IHNhbml0aXplZENhdGVnb3J5ID0gc2FuaXRpemVJbnB1dChjYXRlZ29yeSwgNTApO1xuICAgIGNvbnN0IHRlbXBsYXRlcyA9IGF3YWl0IHRoaXMubGlzdCgpO1xuICAgIHJldHVybiB0ZW1wbGF0ZXMuZmlsdGVyKHQgPT4gdC5tZXRhZGF0YS5jYXRlZ29yeSA9PT0gc2FuaXRpemVkQ2F0ZWdvcnkpO1xuICB9XG5cbiAgYXN5bmMgZmluZEJ5VGFnKHRhZzogc3RyaW5nKTogUHJvbWlzZTxUZW1wbGF0ZVtdPiB7XG4gICAgY29uc3Qgc2FuaXRpemVkVGFnID0gc2FuaXRpemVJbnB1dCh0YWcsIDUwKTtcbiAgICBjb25zdCB0ZW1wbGF0ZXMgPSBhd2FpdCB0aGlzLmxpc3QoKTtcbiAgICByZXR1cm4gdGVtcGxhdGVzLmZpbHRlcih0ID0+IHQubWV0YWRhdGEudGFncz8uaW5jbHVkZXMoc2FuaXRpemVkVGFnKSk7XG4gIH1cblxuICBhc3luYyBnZXRNb3N0VXNlZChsaW1pdDogbnVtYmVyID0gMTApOiBQcm9taXNlPFRlbXBsYXRlW10+IHtcbiAgICBjb25zdCBNSU5fTElNSVQgPSAxO1xuICAgIGNvbnN0IE1BWF9MSU1JVCA9IDEwMDtcbiAgICBjb25zdCB2YWxpZGF0ZWRMaW1