@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.
177 lines • 24.5 kB
JavaScript
/**
* Extracts metadata from pure YAML memory files for lightweight indexing.
*
* Memory files differ from other elements: they are pure YAML (not markdown
* with frontmatter). Metadata lives under a top-level `metadata` key or
* directly as top-level keys. This extractor reads raw YAML and returns
* the subset of fields needed for ElementIndexEntry without constructing
* a full Memory object.
*/
import { SecureYamlParser } from '../security/secureYamlParser.js';
import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
import { logger } from '../utils/logger.js';
export class MemoryMetadataExtractor {
/** Align with SecureYamlParser default raw YAML limit (64KB). */
static MAX_YAML_SIZE = 64 * 1024;
/**
* Extract index-relevant metadata from raw YAML memory content.
*
* @param rawContent - Full YAML file content
* @param relativePath - Path relative to the memories element directory
* @returns Partial ElementIndexEntry with extracted fields
*/
static extractMetadata(rawContent, relativePath) {
if (!rawContent || typeof rawContent !== 'string' || rawContent.trim().length === 0) {
return MemoryMetadataExtractor.defaultEntry(relativePath);
}
const primaryParse = MemoryMetadataExtractor.tryParseYamlObject(rawContent);
let yamlData = primaryParse.data;
if (!yamlData) {
// Multi-document streams (frontmatter + content) fail single-doc parsing.
// Extract just the frontmatter block and retry parsing safely.
const fmContent = MemoryMetadataExtractor.extractFrontmatter(rawContent);
if (!fmContent) {
if (primaryParse.errorMessage) {
logger.debug('MemoryMetadataExtractor: failed to parse YAML, returning default metadata', {
relativePath,
stage: 'primary',
error: primaryParse.errorMessage,
});
}
return MemoryMetadataExtractor.defaultEntry(relativePath);
}
const fallbackParse = MemoryMetadataExtractor.tryParseYamlObject(fmContent);
yamlData = fallbackParse.data;
if (!yamlData) {
logger.debug('MemoryMetadataExtractor: failed to parse YAML (primary + frontmatter fallback), returning default metadata', {
relativePath,
primaryError: primaryParse.errorMessage,
fallbackError: fallbackParse.errorMessage,
});
return MemoryMetadataExtractor.defaultEntry(relativePath);
}
}
// Memory files store metadata under a top-level `metadata` key or directly as top-level keys
const metadataSource = (yamlData.metadata && typeof yamlData.metadata === 'object' && !Array.isArray(yamlData.metadata)
? yamlData.metadata
: yamlData);
const normalizedName = typeof metadataSource.name === 'string'
? MemoryMetadataExtractor.normalizeText(metadataSource.name)
: '';
const name = normalizedName.length > 0
? normalizedName
: 'unnamed';
const description = typeof metadataSource.description === 'string'
? MemoryMetadataExtractor.normalizeText(metadataSource.description)
: '';
const normalizedVersion = typeof metadataSource.version === 'string'
? MemoryMetadataExtractor.normalizeText(metadataSource.version)
: '';
const version = normalizedVersion.length > 0
? normalizedVersion
: '1.0.0';
const author = typeof metadataSource.author === 'string'
? MemoryMetadataExtractor.normalizeText(metadataSource.author)
: '';
const tags = Array.isArray(metadataSource.tags) && metadataSource.tags.every((t) => typeof t === 'string')
? metadataSource.tags
.map(tag => MemoryMetadataExtractor.normalizeText(tag))
.filter(tag => tag.length > 0)
: [];
const autoLoad = typeof metadataSource.autoLoad === 'boolean'
? metadataSource.autoLoad
: undefined;
const priority = typeof metadataSource.priority === 'number'
? metadataSource.priority
: undefined;
const normalizedMemoryType = typeof metadataSource.memoryType === 'string'
? MemoryMetadataExtractor.normalizeText(metadataSource.memoryType)
: '';
const memoryType = normalizedMemoryType.length > 0
? normalizedMemoryType
: MemoryMetadataExtractor.inferMemoryType(relativePath);
// totalEntries: prefer stats.totalEntries, fall back to entries array length
let totalEntries;
const stats = yamlData.stats;
if (stats && typeof stats === 'object' && typeof stats.totalEntries === 'number') {
totalEntries = stats.totalEntries;
}
else if (Array.isArray(yamlData.entries)) {
totalEntries = yamlData.entries.length;
}
const entry = {
filePath: relativePath,
name,
description,
version,
author,
tags,
memoryType,
};
if (autoLoad !== undefined)
entry.autoLoad = autoLoad;
if (priority !== undefined)
entry.priority = priority;
if (totalEntries !== undefined)
entry.totalEntries = totalEntries;
return entry;
}
/**
* Infer the memory type from the file's relative path.
*
* @param relativePath - Path relative to the memories directory
* @returns 'system' | 'adapter' | 'user'
*/
static inferMemoryType(relativePath) {
// Normalize separators to forward slash for consistent matching
const normalized = relativePath.replace(/\\/g, '/');
if (normalized.startsWith('system/'))
return 'system';
if (normalized.startsWith('adapters/'))
return 'adapter';
return 'user';
}
/**
* Extract YAML content between --- frontmatter markers.
* Returns null if no valid frontmatter block found.
*/
static extractFrontmatter(rawContent) {
const trimmed = rawContent.trim();
if (!trimmed.startsWith('---'))
return null;
const endIndex = trimmed.indexOf('\n---', 3);
if (endIndex === -1)
return null;
return trimmed.substring(3, endIndex).trim();
}
/**
* Parse raw YAML using the centralized secure parser.
* Returns parse diagnostics so callers can fail closed while preserving error context.
*/
static tryParseYamlObject(content) {
try {
return { data: SecureYamlParser.parseRawYaml(content, MemoryMetadataExtractor.MAX_YAML_SIZE) };
}
catch (error) {
return {
errorMessage: error instanceof Error ? error.message : String(error),
};
}
}
/** Return a minimal default entry for empty/corrupt content. */
static defaultEntry(relativePath) {
return {
filePath: relativePath,
name: 'unnamed',
description: '',
version: '1.0.0',
author: '',
tags: [],
memoryType: MemoryMetadataExtractor.inferMemoryType(relativePath),
};
}
static normalizeText(value) {
return UnicodeValidator.normalize(value).normalizedContent;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RvcmFnZS9NZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7R0FRRztBQUVILE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ25FLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBRTlFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUU1QyxNQUFNLE9BQU8sdUJBQXVCO0lBQ2xDLGlFQUFpRTtJQUN6RCxNQUFNLENBQVUsYUFBYSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7SUFFbEQ7Ozs7OztPQU1HO0lBQ0gsTUFBTSxDQUFDLGVBQWUsQ0FBQyxVQUFrQixFQUFFLFlBQW9CO1FBQzdELElBQUksQ0FBQyxVQUFVLElBQUksT0FBTyxVQUFVLEtBQUssUUFBUSxJQUFJLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDcEYsT0FBTyx1QkFBdUIsQ0FBQyxZQUFZLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDNUQsQ0FBQztRQUVELE1BQU0sWUFBWSxHQUFHLHVCQUF1QixDQUFDLGtCQUFrQixDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQzVFLElBQUksUUFBUSxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUM7UUFDakMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ2QsMEVBQTBFO1lBQzFFLCtEQUErRDtZQUMvRCxNQUFNLFNBQVMsR0FBRyx1QkFBdUIsQ0FBQyxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUN6RSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7Z0JBQ2YsSUFBSSxZQUFZLENBQUMsWUFBWSxFQUFFLENBQUM7b0JBQzlCLE1BQU0sQ0FBQyxLQUFL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RSxJQUFJLEVBQUUsZ0JBQWdCLENBQUMsWUFBWSxDQUFDLE9BQU8sRUFBRSx1QkFBdUIsQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDO1FBQ2pHLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsT0FBTztnQkFDTCxZQUFZLEVBQUUsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQzthQUNyRSxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFRCxnRUFBZ0U7SUFDeEQsTUFBTSxDQUFDLFlBQVksQ0FBQyxZQUFvQjtRQUM5QyxPQUFPO1lBQ0wsUUFBUSxFQUFFLFlBQVk7WUFDdEIsSUFBSSxFQUFFLFNBQVM7WUFDZixXQUFXLEVBQUUsRUFBRTtZQUNmLE9BQU8sRUFBRSxPQUFPO1lBQ2hCLE1BQU0sRUFBRSxFQUFFO1lBQ1YsSUFBSSxFQUFFLEVBQUU7WUFDUixVQUFVLEVBQUUsdUJBQXVCLENBQUMsZUFBZSxDQUFDLFlBQVksQ0FBQztTQUNsRSxDQUFDO0lBQ0osQ0FBQztJQUVPLE1BQU0sQ0FBQyxhQUFhLENBQUMsS0FBYTtRQUN4QyxPQUFPLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQztJQUM3RCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBFeHRyYWN0cyBtZXRhZGF0YSBmcm9tIHB1cmUgWUFNTCBtZW1vcnkgZmlsZXMgZm9yIGxpZ2h0d2VpZ2h0IGluZGV4aW5nLlxuICpcbiAqIE1lbW9yeSBmaWxlcyBkaWZmZXIgZnJvbSBvdGhlciBlbGVtZW50czogdGhleSBhcmUgcHVyZSBZQU1MIChub3QgbWFya2Rvd25cbiAqIHdpdGggZnJvbnRtYXR0ZXIpLiBNZXRhZGF0YSBsaXZlcyB1bmRlciBhIHRvcC1sZXZlbCBgbWV0YWRhdGFgIGtleSBvclxuICogZGlyZWN0bHkgYXMgdG9wLWxldmVsIGtleXMuIFRoaXMgZXh0cmFjdG9yIHJlYWRzIHJhdyBZQU1MIGFuZCByZXR1cm5zXG4gKiB0aGUgc3Vic2V0IG9mIGZpZWxkcyBuZWVkZWQgZm9yIEVsZW1lbnRJbmRleEVudHJ5IHdpdGhvdXQgY29uc3RydWN0aW5nXG4gKiBhIGZ1bGwgTWVtb3J5IG9iamVjdC5cbiAqL1xuXG5pbXBvcnQgeyBTZWN1cmVZYW1sUGFyc2VyIH0gZnJvbSAnLi4vc2VjdXJpdHkvc2VjdXJlWWFtbFBhcnNlci5qcyc7XG5pbXBvcnQgeyBVbmljb2RlVmFsaWRhdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvdmFsaWRhdG9ycy91bmljb2RlVmFsaWRhdG9yLmpzJztcbmltcG9ydCB0eXBlIHsgRWxlbWVudEluZGV4RW50cnkgfSBmcm9tICcuL3R5cGVzLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5cbmV4cG9ydCBjbGFzcyBNZW1vcnlNZXRhZGF0YUV4dHJhY3RvciB7XG4gIC8qKiBBbGlnbiB3aXRoIFNlY3VyZVlhbWxQYXJzZXIgZGVmYXVsdCByYXcgWUFNTCBsaW1pdCAoNjRLQikuICovXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IE1BWF9ZQU1MX1NJWkUgPSA2NCAqIDEwMjQ7XG5cbiAgLyoqXG4gICAqIEV4dHJhY3QgaW5kZXgtcmVsZXZhbnQgbWV0YWRhdGEgZnJvbSByYXcgWUFNTCBtZW1vcnkgY29udGVudC5cbiAgICpcbiAgICogQHBhcmFtIHJhd0NvbnRlbnQgLSBGdWxsIFlBTUwgZmlsZSBjb250ZW50XG4gICAqIEBwYXJhbSByZWxhdGl2ZVBhdGggLSBQYXRoIHJlbGF0aXZlIHRvIHRoZSBtZW1vcmllcyBlbGVtZW50IGRpcmVjdG9yeVxuICAgKiBAcmV0dXJucyBQYXJ0aWFsIEVsZW1lbnRJbmRleEVudHJ5IHdpdGggZXh0cmFjdGVkIGZpZWxkc1xuICAgKi9cbiAgc3RhdGljIGV4dHJhY3RNZXRhZGF0YShyYXdDb250ZW50OiBzdHJpbmcsIHJlbGF0aXZlUGF0aDogc3RyaW5nKTogUGFydGlhbDxFbGVtZW50SW5kZXhFbnRyeT4ge1xuICAgIGlmICghcmF3Q29udGVudCB8fCB0eXBlb2YgcmF3Q29udGVudCAhPT0gJ3N0cmluZycgfHwgcmF3Q29udGVudC50cmltKCkubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3IuZGVmYXVsdEVudHJ5KHJlbGF0aXZlUGF0aCk7XG4gICAgfVxuXG4gICAgY29uc3QgcHJpbWFyeVBhcnNlID0gTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3IudHJ5UGFyc2VZYW1sT2JqZWN0KHJhd0NvbnRlbnQpO1xuICAgIGxldCB5YW1sRGF0YSA9IHByaW1hcnlQYXJzZS5kYXRhO1xuICAgIGlmICgheWFtbERhdGEpIHtcbiAgICAgIC8vIE11bHRpLWRvY3VtZW50IHN0cmVhbXMgKGZyb250bWF0dGVyICsgY29udGVudCkgZmFpbCBzaW5nbGUtZG9jIHBhcnNpbmcuXG4gICAgICAvLyBFeHRyYWN0IGp1c3QgdGhlIGZyb250bWF0dGVyIGJsb2NrIGFuZCByZXRyeSBwYXJzaW5nIHNhZmVseS5cbiAgICAgIGNvbnN0IGZtQ29udGVudCA9IE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLmV4dHJhY3RGcm9udG1hdHRlcihyYXdDb250ZW50KTtcbiAgICAgIGlmICghZm1Db250ZW50KSB7XG4gICAgICAgIGlmIChwcmltYXJ5UGFyc2UuZXJyb3JNZXNzYWdlKSB7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKCdNZW1vcnlNZXRhZGF0YUV4dHJhY3RvcjogZmFpbGVkIHRvIHBhcnNlIFlBTUwsIHJldHVybmluZyBkZWZhdWx0IG1ldGFkYXRhJywge1xuICAgICAgICAgICAgcmVsYXRpdmVQYXRoLFxuICAgICAgICAgICAgc3RhZ2U6ICdwcmltYXJ5JyxcbiAgICAgICAgICAgIGVycm9yOiBwcmltYXJ5UGFyc2UuZXJyb3JNZXNzYWdlLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5kZWZhdWx0RW50cnkocmVsYXRpdmVQYXRoKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGZhbGxiYWNrUGFyc2UgPSBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci50cnlQYXJzZVlhbWxPYmplY3QoZm1Db250ZW50KTtcbiAgICAgIHlhbWxEYXRhID0gZmFsbGJhY2tQYXJzZS5kYXRhO1xuICAgICAgaWYgKCF5YW1sRGF0YSkge1xuICAgICAgICBsb2dnZXIuZGVidWcoJ01lbW9yeU1ldGFkYXRhRXh0cmFjdG9yOiBmYWlsZWQgdG8gcGFyc2UgWUFNTCAocHJpbWFyeSArIGZyb250bWF0dGVyIGZhbGxiYWNrKSwgcmV0dXJuaW5nIGRlZmF1bHQgbWV0YWRhdGEnLCB7XG4gICAgICAgICAgcmVsYXRpdmVQYXRoLFxuICAgICAgICAgIHByaW1hcnlFcnJvcjogcHJpbWFyeVBhcnNlLmVycm9yTWVzc2FnZSxcbiAgICAgICAgICBmYWxsYmFja0Vycm9yOiBmYWxsYmFja1BhcnNlLmVycm9yTWVzc2FnZSxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5kZWZhdWx0RW50cnkocmVsYXRpdmVQYXRoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBNZW1vcnkgZmlsZXMgc3RvcmUgbWV0YWRhdGEgdW5kZXIgYSB0b3AtbGV2ZWwgYG1ldGFkYXRhYCBrZXkgb3IgZGlyZWN0bHkgYXMgdG9wLWxldmVsIGtleXNcbiAgICBjb25zdCBtZXRhZGF0YVNvdXJjZSA9IChcbiAgICAgIHlhbWxEYXRhLm1ldGFkYXRhICYmIHR5cGVvZiB5YW1sRGF0YS5tZXRhZGF0YSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkoeWFtbERhdGEubWV0YWRhdGEpXG4gICAgICAgID8geWFtbERhdGEubWV0YWRhdGFcbiAgICAgICAgOiB5YW1sRGF0YVxuICAgICkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG5cbiAgICBjb25zdCBub3JtYWxpemVkTmFtZSA9IHR5cGVvZiBtZXRhZGF0YVNvdXJjZS5uYW1lID09PSAnc3RyaW5nJ1xuICAgICAgPyBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5ub3JtYWxpemVUZXh0KG1ldGFkYXRhU291cmNlLm5hbWUpXG4gICAgICA6ICcnO1xuICAgIGNvbnN0IG5hbWUgPSBub3JtYWxpemVkTmFtZS5sZW5ndGggPiAwXG4gICAgICA/IG5vcm1hbGl6ZWROYW1lXG4gICAgICA6ICd1bm5hbWVkJztcblxuICAgIGNvbnN0IGRlc2NyaXB0aW9uID0gdHlwZW9mIG1ldGFkYXRhU291cmNlLmRlc2NyaXB0aW9uID09PSAnc3RyaW5nJ1xuICAgICAgPyBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5ub3JtYWxpemVUZXh0KG1ldGFkYXRhU291cmNlLmRlc2NyaXB0aW9uKVxuICAgICAgOiAnJztcblxuICAgIGNvbnN0IG5vcm1hbGl6ZWRWZXJzaW9uID0gdHlwZW9mIG1ldGFkYXRhU291cmNlLnZlcnNpb24gPT09ICdzdHJpbmcnXG4gICAgICA/IE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLm5vcm1hbGl6ZVRleHQobWV0YWRhdGFTb3VyY2UudmVyc2lvbilcbiAgICAgIDogJyc7XG4gICAgY29uc3QgdmVyc2lvbiA9IG5vcm1hbGl6ZWRWZXJzaW9uLmxlbmd0aCA+IDBcbiAgICAgID8gbm9ybWFsaXplZFZlcnNpb25cbiAgICAgIDogJzEuMC4wJztcblxuICAgIGNvbnN0IGF1dGhvciA9IHR5cGVvZiBtZXRhZGF0YVNvdXJjZS5hdXRob3IgPT09ICdzdHJpbmcnXG4gICAgICA/IE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLm5vcm1hbGl6ZVRleHQobWV0YWRhdGFTb3VyY2UuYXV0aG9yKVxuICAgICAgOiAnJztcblxuICAgIGNvbnN0IHRhZ3MgPSBBcnJheS5pc0FycmF5KG1ldGFkYXRhU291cmNlLnRhZ3MpICYmIG1ldGFkYXRhU291cmNlLnRhZ3MuZXZlcnkoKHQ6IHVua25vd24pID0+IHR5cGVvZiB0ID09PSAnc3RyaW5nJylcbiAgICAgID8gKG1ldGFkYXRhU291cmNlLnRhZ3MgYXMgc3RyaW5nW10pXG4gICAgICAgIC5tYXAodGFnID0+IE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLm5vcm1hbGl6ZVRleHQodGFnKSlcbiAgICAgICAgLmZpbHRlcih0YWcgPT4gdGFnLmxlbmd0aCA+IDApXG4gICAgICA6IFtdO1xuXG4gICAgY29uc3QgYXV0b0xvYWQgPSB0eXBlb2YgbWV0YWRhdGFTb3VyY2UuYXV0b0xvYWQgPT09ICdib29sZWFuJ1xuICAgICAgPyBtZXRhZGF0YVNvdXJjZS5hdXRvTG9hZFxuICAgICAgOiB1bmRlZmluZWQ7XG5cbiAgICBjb25zdCBwcmlvcml0eSA9IHR5cGVvZiBtZXRhZGF0YVNvdXJjZS5wcmlvcml0eSA9PT0gJ251bWJlcidcbiAgICAgID8gbWV0YWRhdGFTb3VyY2UucHJpb3JpdHlcbiAgICAgIDogdW5kZWZpbmVkO1xuXG4gICAgY29uc3Qgbm9ybWFsaXplZE1lbW9yeVR5cGUgPSB0eXBlb2YgbWV0YWRhdGFTb3VyY2UubWVtb3J5VHlwZSA9PT0gJ3N0cmluZydcbiAgICAgID8gTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3Iubm9ybWFsaXplVGV4dChtZXRhZGF0YVNvdXJjZS5tZW1vcnlUeXBlKVxuICAgICAgOiAnJztcbiAgICBjb25zdCBtZW1vcnlUeXBlID0gbm9ybWFsaXplZE1lbW9yeVR5cGUubGVuZ3RoID4gMFxuICAgICAgPyBub3JtYWxpemVkTWVtb3J5VHlwZVxuICAgICAgOiBNZW1vcnlNZXRhZGF0YUV4dHJhY3Rvci5pbmZlck1lbW9yeVR5cGUocmVsYXRpdmVQYXRoKTtcblxuICAgIC8vIHRvdGFsRW50cmllczogcHJlZmVyIHN0YXRzLnRvdGFsRW50cmllcywgZmFsbCBiYWNrIHRvIGVudHJpZXMgYXJyYXkgbGVuZ3RoXG4gICAgbGV0IHRvdGFsRW50cmllczogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICAgIGNvbnN0IHN0YXRzID0geWFtbERhdGEuc3RhdHMgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWQ7XG4gICAgaWYgKHN0YXRzICYmIHR5cGVvZiBzdGF0cyA9PT0gJ29iamVjdCcgJiYgdHlwZW9mIHN0YXRzLnRvdGFsRW50cmllcyA9PT0gJ251bWJlcicpIHtcbiAgICAgIHRvdGFsRW50cmllcyA9IHN0YXRzLnRvdGFsRW50cmllcztcbiAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoeWFtbERhdGEuZW50cmllcykpIHtcbiAgICAgIHRvdGFsRW50cmllcyA9IHlhbWxEYXRhLmVudHJpZXMubGVuZ3RoO1xuICAgIH1cblxuICAgIGNvbnN0IGVudHJ5OiBQYXJ0aWFsPEVsZW1lbnRJbmRleEVudHJ5PiA9IHtcbiAgICAgIGZpbGVQYXRoOiByZWxhdGl2ZVBhdGgsXG4gICAgICBuYW1lLFxuICAgICAgZGVzY3JpcHRpb24sXG4gICAgICB2ZXJzaW9uLFxuICAgICAgYXV0aG9yLFxuICAgICAgdGFncyxcbiAgICAgIG1lbW9yeVR5cGUsXG4gICAgfTtcblxuICAgIGlmIChhdXRvTG9hZCAhPT0gdW5kZWZpbmVkKSBlbnRyeS5hdXRvTG9hZCA9IGF1dG9Mb2FkO1xuICAgIGlmIChwcmlvcml0eSAhPT0gdW5kZWZpbmVkKSBlbnRyeS5wcmlvcml0eSA9IHByaW9yaXR5O1xuICAgIGlmICh0b3RhbEVudHJpZXMgIT09IHVuZGVmaW5lZCkgZW50cnkudG90YWxFbnRyaWVzID0gdG90YWxFbnRyaWVzO1xuXG4gICAgcmV0dXJuIGVudHJ5O1xuICB9XG5cbiAgLyoqXG4gICAqIEluZmVyIHRoZSBtZW1vcnkgdHlwZSBmcm9tIHRoZSBmaWxlJ3MgcmVsYXRpdmUgcGF0aC5cbiAgICpcbiAgICogQHBhcmFtIHJlbGF0aXZlUGF0aCAtIFBhdGggcmVsYXRpdmUgdG8gdGhlIG1lbW9yaWVzIGRpcmVjdG9yeVxuICAgKiBAcmV0dXJucyAnc3lzdGVtJyB8ICdhZGFwdGVyJyB8ICd1c2VyJ1xuICAgKi9cbiAgc3RhdGljIGluZmVyTWVtb3J5VHlwZShyZWxhdGl2ZVBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgLy8gTm9ybWFsaXplIHNlcGFyYXRvcnMgdG8gZm9yd2FyZCBzbGFzaCBmb3IgY29uc2lzdGVudCBtYXRjaGluZ1xuICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSByZWxhdGl2ZVBhdGgucmVwbGFjZSgvXFxcXC9nLCAnLycpO1xuXG4gICAgaWYgKG5vcm1hbGl6ZWQuc3RhcnRzV2l0aCgnc3lzdGVtLycpKSByZXR1cm4gJ3N5c3RlbSc7XG4gICAgaWYgKG5vcm1hbGl6ZWQuc3RhcnRzV2l0aCgnYWRhcHRlcnMvJykpIHJldHVybiAnYWRhcHRlcic7XG4gICAgcmV0dXJuICd1c2VyJztcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRyYWN0IFlBTUwgY29udGVudCBiZXR3ZWVuIC0tLSBmcm9udG1hdHRlciBtYXJrZXJzLlxuICAgKiBSZXR1cm5zIG51bGwgaWYgbm8gdmFsaWQgZnJvbnRtYXR0ZXIgYmxvY2sgZm91bmQuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBleHRyYWN0RnJvbnRtYXR0ZXIocmF3Q29udGVudDogc3RyaW5nKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgY29uc3QgdHJpbW1lZCA9IHJhd0NvbnRlbnQudHJpbSgpO1xuICAgIGlmICghdHJpbW1lZC5zdGFydHNXaXRoKCctLS0nKSkgcmV0dXJuIG51bGw7XG5cbiAgICBjb25zdCBlbmRJbmRleCA9IHRyaW1tZWQuaW5kZXhPZignXFxuLS0tJywgMyk7XG4gICAgaWYgKGVuZEluZGV4ID09PSAtMSkgcmV0dXJuIG51bGw7XG5cbiAgICByZXR1cm4gdHJpbW1lZC5zdWJzdHJpbmcoMywgZW5kSW5kZXgpLnRyaW0oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQYXJzZSByYXcgWUFNTCB1c2luZyB0aGUgY2VudHJhbGl6ZWQgc2VjdXJlIHBhcnNlci5cbiAgICogUmV0dXJucyBwYXJzZSBkaWFnbm9zdGljcyBzbyBjYWxsZXJzIGNhbiBmYWlsIGNsb3NlZCB3aGlsZSBwcmVzZXJ2aW5nIGVycm9yIGNvbnRleHQuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyB0cnlQYXJzZVlhbWxPYmplY3QoY29udGVudDogc3RyaW5nKTogeyBkYXRhPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47IGVycm9yTWVzc2FnZT86IHN0cmluZyB9IHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHsgZGF0YTogU2VjdXJlWWFtbFBhcnNlci5wYXJzZVJhd1lhbWwoY29udGVudCwgTWVtb3J5TWV0YWRhdGFFeHRyYWN0b3IuTUFYX1lBTUxfU0laRSkgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvciksXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIC8qKiBSZXR1cm4gYSBtaW5pbWFsIGRlZmF1bHQgZW50cnkgZm9yIGVtcHR5L2NvcnJ1cHQgY29udGVudC4gKi9cbiAgcHJpdmF0ZSBzdGF0aWMgZGVmYXVsdEVudHJ5KHJlbGF0aXZlUGF0aDogc3RyaW5nKTogUGFydGlhbDxFbGVtZW50SW5kZXhFbnRyeT4ge1xuICAgIHJldHVybiB7XG4gICAgICBmaWxlUGF0aDogcmVsYXRpdmVQYXRoLFxuICAgICAgbmFtZTogJ3VubmFtZWQnLFxuICAgICAgZGVzY3JpcHRpb246ICcnLFxuICAgICAgdmVyc2lvbjogJzEuMC4wJyxcbiAgICAgIGF1dGhvcjogJycsXG4gICAgICB0YWdzOiBbXSxcbiAgICAgIG1lbW9yeVR5cGU6IE1lbW9yeU1ldGFkYXRhRXh0cmFjdG9yLmluZmVyTWVtb3J5VHlwZShyZWxhdGl2ZVBhdGgpLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBub3JtYWxpemVUZXh0KHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZSh2YWx1ZSkubm9ybWFsaXplZENvbnRlbnQ7XG4gIH1cbn1cbiJdfQ==