@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.
152 lines • 21.4 kB
JavaScript
/**
* Search for content in the collection
*/
import { CollectionCache } from '../cache/CollectionCache.js';
import { CollectionSeeder } from './CollectionSeeder.js';
import { logger } from '../utils/logger.js';
import { normalizeSearchTerm, validateSearchQuery } from '../utils/searchUtils.js';
export class CollectionSearch {
githubClient;
collectionCache;
searchBaseUrl = 'https://api.github.com/search/code';
constructor(githubClient, collectionCache) {
this.githubClient = githubClient;
this.collectionCache = collectionCache || new CollectionCache();
}
/**
* Search collection for content matching query
* Falls back to cached data when GitHub API is not available or not authenticated
*/
async searchCollection(query) {
// Validate search query for security
try {
validateSearchQuery(query, 1000);
}
catch (error) {
logger.warn(`Invalid search query: ${error}`);
return [];
}
try {
// First, try GitHub API search if authenticated
const searchUrl = `${this.searchBaseUrl}?q=${encodeURIComponent(query)}+repo:DollhouseMCP/collection+path:library+extension:md`;
const data = await this.githubClient.fetchFromGitHub(searchUrl, false); // Don't require auth for search
if (data.items && Array.isArray(data.items)) {
logger.debug(`Found ${data.items.length} items via GitHub API search`);
// Update cache with fresh data from API
await this.updateCacheFromGitHubItems(data.items);
return data.items;
}
return [];
}
catch (error) {
logger.debug(`GitHub API search failed, falling back to cache: ${error}`);
// Fallback to cached search
return this.searchFromCache(query);
}
}
/**
* Search cached collection items
*/
async searchFromCache(query) {
try {
// Try to load from cache first
const cachedItems = await this.collectionCache.searchCache(query);
if (cachedItems.length > 0) {
logger.debug(`Found ${cachedItems.length} items from cache`);
return this.convertCacheItemsToGitHubFormat(cachedItems);
}
// If cache is empty or no results, use seed data
const seedItems = this.searchSeedData(query);
if (seedItems.length > 0) {
logger.debug(`Found ${seedItems.length} items from seed data`);
// Save seed data to cache for future use
await this.collectionCache.saveCache(CollectionSeeder.getSeedData());
return this.convertCacheItemsToGitHubFormat(seedItems);
}
logger.debug('No items found in cache or seed data');
return [];
}
catch (error) {
logger.error(`Cache search failed: ${error}`);
// Last resort: search seed data without cache
const seedItems = this.searchSeedData(query);
logger.debug(`Fallback to seed data found ${seedItems.length} items`);
return this.convertCacheItemsToGitHubFormat(seedItems);
}
}
/**
* Search seed data for matching items with fuzzy matching
*/
searchSeedData(query) {
const seedData = CollectionSeeder.getSeedData();
const normalizedQuery = normalizeSearchTerm(query);
return seedData.filter(item => {
const normalizedName = normalizeSearchTerm(item.name);
const normalizedPath = normalizeSearchTerm(item.path);
return normalizedName.includes(normalizedQuery) ||
normalizedPath.includes(normalizedQuery);
});
}
/**
* Convert cache items to GitHub API format for consistent response structure
*/
convertCacheItemsToGitHubFormat(cacheItems) {
return cacheItems.map(item => ({
name: item.name,
path: item.path,
sha: item.sha,
url: `https://api.github.com/repos/DollhouseMCP/collection/contents/${item.path}`,
html_url: `https://github.com/DollhouseMCP/collection/blob/main/${item.path}`,
repository: {
name: 'collection',
full_name: 'DollhouseMCP/collection'
}
}));
}
/**
* Update cache with fresh data from GitHub API items
*/
async updateCacheFromGitHubItems(githubItems) {
try {
const cacheItems = githubItems.map(item => ({
name: item.name,
path: item.path,
sha: item.sha,
last_modified: new Date().toISOString()
}));
await this.collectionCache.saveCache(cacheItems);
logger.debug(`Updated cache with ${cacheItems.length} items from GitHub API`);
}
catch (error) {
logger.debug(`Failed to update cache: ${error}`);
// Don't throw - cache update failures shouldn't break functionality
}
}
/**
* Format search results
*/
formatSearchResults(items, query, personaIndicator = '') {
if (items.length === 0) {
return `${personaIndicator}🔍 No content found for query: "${query}"`;
}
const textParts = [`${personaIndicator}🔍 **Search Results for "${query}"** (${items.length} found)\n\n`];
items.forEach((item) => {
// Extract content type from path (library/personas/creative/writer.md -> personas)
const pathParts = item.path.split('/');
const contentType = pathParts[1] || 'content';
const contentIcons = {
'personas': '🎭',
'skills': '🛠️',
'agents': '🤖',
'prompts': '💬',
'templates': '📄',
'tools': '🔧',
'ensembles': '🎼'
};
const icon = contentIcons[contentType] || '📄';
textParts.push(` ${icon} **${item.name.replace('.md', '')}**\n`, ` 📂 Path: ${item.path}\n`, ` 📥 Install: \`install_content "${item.path}"\`\n`, ` 👁️ Details: \`get_collection_content "${item.path}"\`\n\n`);
});
return textParts.join('');
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29sbGVjdGlvblNlYXJjaC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb2xsZWN0aW9uL0NvbGxlY3Rpb25TZWFyY2gudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFHSCxPQUFPLEVBQUUsZUFBZSxFQUFrQixNQUFNLDZCQUE2QixDQUFDO0FBQzlFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUVuRixNQUFNLE9BQU8sZ0JBQWdCO0lBQ25CLFlBQVksQ0FBZTtJQUMzQixlQUFlLENBQWtCO0lBQ2pDLGFBQWEsR0FBRyxvQ0FBb0MsQ0FBQztJQUU3RCxZQUFZLFlBQTBCLEVBQUUsZUFBaUM7UUFDdkUsSUFBSSxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUM7UUFDakMsSUFBSSxDQUFDLGVBQWUsR0FBRyxlQUFlLElBQUksSUFBSSxlQUFlLEVBQUUsQ0FBQztJQUNsRSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLGdCQUFnQixDQUFDLEtBQWE7UUFDbEMscUNBQXFDO1FBQ3JDLElBQUksQ0FBQztZQUNILG1CQUFtQixDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNuQyxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sQ0FBQyxJQUFJLENBQUMseUJBQXlCLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDOUMsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDO1FBRUQsSUFBSSxDQUFDO1lBQ0gsZ0RBQWdEO1lBQ2hELE1BQU0sU0FBUyxHQUFHLEdBQUcsSUFBSSxDQUFDLGFBQWEsTUFBTSxrQkFBa0IsQ0FBQyxLQUFLLENBQUMseURBQXlELENBQUM7WUFDaEksTUFB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QUksQ0FBQyxJQUFJLElBQUksRUFDL0Isd0NBQXdDLElBQUksQ0FBQyxJQUFJLE9BQU8sRUFDeEQsZ0RBQWdELElBQUksQ0FBQyxJQUFJLFNBQVMsQ0FDbkUsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO1FBRUgsT0FBTyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzVCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU2VhcmNoIGZvciBjb250ZW50IGluIHRoZSBjb2xsZWN0aW9uXG4gKi9cblxuaW1wb3J0IHsgR2l0SHViQ2xpZW50IH0gZnJvbSAnLi9HaXRIdWJDbGllbnQuanMnO1xuaW1wb3J0IHsgQ29sbGVjdGlvbkNhY2hlLCBDb2xsZWN0aW9uSXRlbSB9IGZyb20gJy4uL2NhY2hlL0NvbGxlY3Rpb25DYWNoZS5qcyc7XG5pbXBvcnQgeyBDb2xsZWN0aW9uU2VlZGVyIH0gZnJvbSAnLi9Db2xsZWN0aW9uU2VlZGVyLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBub3JtYWxpemVTZWFyY2hUZXJtLCB2YWxpZGF0ZVNlYXJjaFF1ZXJ5IH0gZnJvbSAnLi4vdXRpbHMvc2VhcmNoVXRpbHMuanMnO1xuXG5leHBvcnQgY2xhc3MgQ29sbGVjdGlvblNlYXJjaCB7XG4gIHByaXZhdGUgZ2l0aHViQ2xpZW50OiBHaXRIdWJDbGllbnQ7XG4gIHByaXZhdGUgY29sbGVjdGlvbkNhY2hlOiBDb2xsZWN0aW9uQ2FjaGU7XG4gIHByaXZhdGUgc2VhcmNoQmFzZVVybCA9ICdodHRwczovL2FwaS5naXRodWIuY29tL3NlYXJjaC9jb2RlJztcbiAgXG4gIGNvbnN0cnVjdG9yKGdpdGh1YkNsaWVudDogR2l0SHViQ2xpZW50LCBjb2xsZWN0aW9uQ2FjaGU/OiBDb2xsZWN0aW9uQ2FjaGUpIHtcbiAgICB0aGlzLmdpdGh1YkNsaWVudCA9IGdpdGh1YkNsaWVudDtcbiAgICB0aGlzLmNvbGxlY3Rpb25DYWNoZSA9IGNvbGxlY3Rpb25DYWNoZSB8fCBuZXcgQ29sbGVjdGlvbkNhY2hlKCk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZWFyY2ggY29sbGVjdGlvbiBmb3IgY29udGVudCBtYXRjaGluZyBxdWVyeVxuICAgKiBGYWxscyBiYWNrIHRvIGNhY2hlZCBkYXRhIHdoZW4gR2l0SHViIEFQSSBpcyBub3QgYXZhaWxhYmxlIG9yIG5vdCBhdXRoZW50aWNhdGVkXG4gICAqL1xuICBhc3luYyBzZWFyY2hDb2xsZWN0aW9uKHF1ZXJ5OiBzdHJpbmcpOiBQcm9taXNlPGFueVtdPiB7XG4gICAgLy8gVmFsaWRhdGUgc2VhcmNoIHF1ZXJ5IGZvciBzZWN1cml0eVxuICAgIHRyeSB7XG4gICAgICB2YWxpZGF0ZVNlYXJjaFF1ZXJ5KHF1ZXJ5LCAxMDAwKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLndhcm4oYEludmFsaWQgc2VhcmNoIHF1ZXJ5OiAke2Vycm9yfWApO1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgICBcbiAgICB0cnkge1xuICAgICAgLy8gRmlyc3QsIHRyeSBHaXRIdWIgQVBJIHNlYXJjaCBpZiBhdXRoZW50aWNhdGVkXG4gICAgICBjb25zdCBzZWFyY2hVcmwgPSBgJHt0aGlzLnNlYXJjaEJhc2VVcmx9P3E9JHtlbmNvZGVVUklDb21wb25lbnQocXVlcnkpfStyZXBvOkRvbGxob3VzZU1DUC9jb2xsZWN0aW9uK3BhdGg6bGlicmFyeStleHRlbnNpb246bWRgO1xuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IHRoaXMuZ2l0aHViQ2xpZW50LmZldGNoRnJvbUdpdEh1YihzZWFyY2hVcmwsIGZhbHNlKTsgLy8gRG9uJ3QgcmVxdWlyZSBhdXRoIGZvciBzZWFyY2hcbiAgICAgIFxuICAgICAgaWYgKGRhdGEuaXRlbXMgJiYgQXJyYXkuaXNBcnJheShkYXRhLml0ZW1zKSkge1xuICAgICAgICBsb2dnZXIuZGVidWcoYEZvdW5kICR7ZGF0YS5pdGVtcy5sZW5ndGh9IGl0ZW1zIHZpYSBHaXRIdWIgQVBJIHNlYXJjaGApO1xuICAgICAgICBcbiAgICAgICAgLy8gVXBkYXRlIGNhY2hlIHdpdGggZnJlc2ggZGF0YSBmcm9tIEFQSVxuICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZUNhY2hlRnJvbUdpdEh1Ykl0ZW1zKGRhdGEuaXRlbXMpO1xuICAgICAgICBcbiAgICAgICAgcmV0dXJuIGRhdGEuaXRlbXM7XG4gICAgICB9XG4gICAgICBcbiAgICAgIHJldHVybiBbXTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmRlYnVnKGBHaXRIdWIgQVBJIHNlYXJjaCBmYWlsZWQsIGZhbGxpbmcgYmFjayB0byBjYWNoZTogJHtlcnJvcn1gKTtcbiAgICAgIFxuICAgICAgLy8gRmFsbGJhY2sgdG8gY2FjaGVkIHNlYXJjaFxuICAgICAgcmV0dXJuIHRoaXMuc2VhcmNoRnJvbUNhY2hlKHF1ZXJ5KTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZWFyY2ggY2FjaGVkIGNvbGxlY3Rpb24gaXRlbXNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgc2VhcmNoRnJvbUNhY2hlKHF1ZXJ5OiBzdHJpbmcpOiBQcm9taXNlPGFueVtdPiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFRyeSB0byBsb2FkIGZyb20gY2FjaGUgZmlyc3RcbiAgICAgIGNvbnN0IGNhY2hlZEl0ZW1zID0gYXdhaXQgdGhpcy5jb2xsZWN0aW9uQ2FjaGUuc2VhcmNoQ2FjaGUocXVlcnkpO1xuICAgICAgXG4gICAgICBpZiAoY2FjaGVkSXRlbXMubGVuZ3RoID4gMCkge1xuICAgICAgICBsb2dnZXIuZGVidWcoYEZvdW5kICR7Y2FjaGVkSXRlbXMubGVuZ3RofSBpdGVtcyBmcm9tIGNhY2hlYCk7XG4gICAgICAgIHJldHVybiB0aGlzLmNvbnZlcnRDYWNoZUl0ZW1zVG9HaXRIdWJGb3JtYXQoY2FjaGVkSXRlbXMpO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBJZiBjYWNoZSBpcyBlbXB0eSBvciBubyByZXN1bHRzLCB1c2Ugc2VlZCBkYXRhXG4gICAgICBjb25zdCBzZWVkSXRlbXMgPSB0aGlzLnNlYXJjaFNlZWREYXRhKHF1ZXJ5KTtcbiAgICAgIGlmIChzZWVkSXRlbXMubGVuZ3RoID4gMCkge1xuICAgICAgICBsb2dnZXIuZGVidWcoYEZvdW5kICR7c2VlZEl0ZW1zLmxlbmd0aH0gaXRlbXMgZnJvbSBzZWVkIGRhdGFgKTtcbiAgICAgICAgLy8gU2F2ZSBzZWVkIGRhdGEgdG8gY2FjaGUgZm9yIGZ1dHVyZSB1c2VcbiAgICAgICAgYXdhaXQgdGhpcy5jb2xsZWN0aW9uQ2FjaGUuc2F2ZUNhY2hlKENvbGxlY3Rpb25TZWVkZXIuZ2V0U2VlZERhdGEoKSk7XG4gICAgICAgIHJldHVybiB0aGlzLmNvbnZlcnRDYWNoZUl0ZW1zVG9HaXRIdWJGb3JtYXQoc2VlZEl0ZW1zKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgbG9nZ2VyLmRlYnVnKCdObyBpdGVtcyBmb3VuZCBpbiBjYWNoZSBvciBzZWVkIGRhdGEnKTtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKGBDYWNoZSBzZWFyY2ggZmFpbGVkOiAke2Vycm9yfWApO1xuICAgICAgXG4gICAgICAvLyBMYXN0IHJlc29ydDogc2VhcmNoIHNlZWQgZGF0YSB3aXRob3V0IGNhY2hlXG4gICAgICBjb25zdCBzZWVkSXRlbXMgPSB0aGlzLnNlYXJjaFNlZWREYXRhKHF1ZXJ5KTtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhgRmFsbGJhY2sgdG8gc2VlZCBkYXRhIGZvdW5kICR7c2VlZEl0ZW1zLmxlbmd0aH0gaXRlbXNgKTtcbiAgICAgIHJldHVybiB0aGlzLmNvbnZlcnRDYWNoZUl0ZW1zVG9HaXRIdWJGb3JtYXQoc2VlZEl0ZW1zKTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZWFyY2ggc2VlZCBkYXRhIGZvciBtYXRjaGluZyBpdGVtcyB3aXRoIGZ1enp5IG1hdGNoaW5nXG4gICAqL1xuICBwcml2YXRlIHNlYXJjaFNlZWREYXRhKHF1ZXJ5OiBzdHJpbmcpOiBDb2xsZWN0aW9uSXRlbVtdIHtcbiAgICBjb25zdCBzZWVkRGF0YSA9IENvbGxlY3Rpb25TZWVkZXIuZ2V0U2VlZERhdGEoKTtcbiAgICBjb25zdCBub3JtYWxpemVkUXVlcnkgPSBub3JtYWxpemVTZWFyY2hUZXJtKHF1ZXJ5KTtcbiAgICBcbiAgICByZXR1cm4gc2VlZERhdGEuZmlsdGVyKGl0ZW0gPT4ge1xuICAgICAgY29uc3Qgbm9ybWFsaXplZE5hbWUgPSBub3JtYWxpemVTZWFyY2hUZXJtKGl0ZW0ubmFtZSk7XG4gICAgICBjb25zdCBub3JtYWxpemVkUGF0aCA9IG5vcm1hbGl6ZVNlYXJjaFRlcm0oaXRlbS5wYXRoKTtcbiAgICAgIFxuICAgICAgcmV0dXJuIG5vcm1hbGl6ZWROYW1lLmluY2x1ZGVzKG5vcm1hbGl6ZWRRdWVyeSkgfHwgXG4gICAgICAgICAgICAgbm9ybWFsaXplZFBhdGguaW5jbHVkZXMobm9ybWFsaXplZFF1ZXJ5KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgXG4gIC8qKlxuICAgKiBDb252ZXJ0IGNhY2hlIGl0ZW1zIHRvIEdpdEh1YiBBUEkgZm9ybWF0IGZvciBjb25zaXN0ZW50IHJlc3BvbnNlIHN0cnVjdHVyZVxuICAgKi9cbiAgcHJpdmF0ZSBjb252ZXJ0Q2FjaGVJdGVtc1RvR2l0SHViRm9ybWF0KGNhY2hlSXRlbXM6IENvbGxlY3Rpb25JdGVtW10pOiBhbnlbXSB7XG4gICAgcmV0dXJuIGNhY2hlSXRlbXMubWFwKGl0ZW0gPT4gKHtcbiAgICAgIG5hbWU6IGl0ZW0ubmFtZSxcbiAgICAgIHBhdGg6IGl0ZW0ucGF0aCxcbiAgICAgIHNoYTogaXRlbS5zaGEsXG4gICAgICB1cmw6IGBodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL0RvbGxob3VzZU1DUC9jb2xsZWN0aW9uL2NvbnRlbnRzLyR7aXRlbS5wYXRofWAsXG4gICAgICBodG1sX3VybDogYGh0dHBzOi8vZ2l0aHViLmNvbS9Eb2xsaG91c2VNQ1AvY29sbGVjdGlvbi9ibG9iL21haW4vJHtpdGVtLnBhdGh9YCxcbiAgICAgIHJlcG9zaXRvcnk6IHtcbiAgICAgICAgbmFtZTogJ2NvbGxlY3Rpb24nLFxuICAgICAgICBmdWxsX25hbWU6ICdEb2xsaG91c2VNQ1AvY29sbGVjdGlvbidcbiAgICAgIH1cbiAgICB9KSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBVcGRhdGUgY2FjaGUgd2l0aCBmcmVzaCBkYXRhIGZyb20gR2l0SHViIEFQSSBpdGVtc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB1cGRhdGVDYWNoZUZyb21HaXRIdWJJdGVtcyhnaXRodWJJdGVtczogYW55W10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgY2FjaGVJdGVtczogQ29sbGVjdGlvbkl0ZW1bXSA9IGdpdGh1Ykl0ZW1zLm1hcChpdGVtID0+ICh7XG4gICAgICAgIG5hbWU6IGl0ZW0ubmFtZSxcbiAgICAgICAgcGF0aDogaXRlbS5wYXRoLFxuICAgICAgICBzaGE6IGl0ZW0uc2hhLFxuICAgICAgICBsYXN0X21vZGlmaWVkOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKClcbiAgICAgIH0pKTtcbiAgICAgIFxuICAgICAgYXdhaXQgdGhpcy5jb2xsZWN0aW9uQ2FjaGUuc2F2ZUNhY2hlKGNhY2hlSXRlbXMpO1xuICAgICAgbG9nZ2VyLmRlYnVnKGBVcGRhdGVkIGNhY2hlIHdpdGggJHtjYWNoZUl0ZW1zLmxlbmd0aH0gaXRlbXMgZnJvbSBHaXRIdWIgQVBJYCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhgRmFpbGVkIHRvIHVwZGF0ZSBjYWNoZTogJHtlcnJvcn1gKTtcbiAgICAgIC8vIERvbid0IHRocm93IC0gY2FjaGUgdXBkYXRlIGZhaWx1cmVzIHNob3VsZG4ndCBicmVhayBmdW5jdGlvbmFsaXR5XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogRm9ybWF0IHNlYXJjaCByZXN1bHRzXG4gICAqL1xuICBmb3JtYXRTZWFyY2hSZXN1bHRzKGl0ZW1zOiBhbnlbXSwgcXVlcnk6IHN0cmluZywgcGVyc29uYUluZGljYXRvcjogc3RyaW5nID0gJycpOiBzdHJpbmcge1xuICAgIGlmIChpdGVtcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBgJHtwZXJzb25hSW5kaWNhdG9yffCflI0gTm8gY29udGVudCBmb3VuZCBmb3IgcXVlcnk6IFwiJHtxdWVyeX1cImA7XG4gICAgfVxuICAgIFxuICAgIGNvbnN0IHRleHRQYXJ0cyA9IFtgJHtwZXJzb25hSW5kaWNhdG9yffCflI0gKipTZWFyY2ggUmVzdWx0cyBmb3IgXCIke3F1ZXJ5fVwiKiogKCR7aXRlbXMubGVuZ3RofSBmb3VuZClcXG5cXG5gXTtcbiAgICBcbiAgICBpdGVtcy5mb3JFYWNoKChpdGVtOiBhbnkpID0+IHtcbiAgICAgIC8vIEV4dHJhY3QgY29udGVudCB0eXBlIGZyb20gcGF0aCAobGlicmFyeS9wZXJzb25hcy9jcmVhdGl2ZS93cml0ZXIubWQgLT4gcGVyc29uYXMpXG4gICAgICBjb25zdCBwYXRoUGFydHMgPSBpdGVtLnBhdGguc3BsaXQoJy8nKTtcbiAgICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gcGF0aFBhcnRzWzFdIHx8ICdjb250ZW50JztcbiAgICAgIFxuICAgICAgY29uc3QgY29udGVudEljb25zOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9ID0ge1xuICAgICAgICAncGVyc29uYXMnOiAn8J+OrScsXG4gICAgICAgICdza2lsbHMnOiAn8J+boO+4jycsXG4gICAgICAgICdhZ2VudHMnOiAn8J+klicsXG4gICAgICAgICdwcm9tcHRzJzogJ/CfkqwnLFxuICAgICAgICAndGVtcGxhdGVzJzogJ/Cfk4QnLFxuICAgICAgICAndG9vbHMnOiAn8J+UpycsXG4gICAgICAgICdlbnNlbWJsZXMnOiAn8J+OvCdcbiAgICAgIH07XG4gICAgICBjb25zdCBpY29uID0gY29udGVudEljb25zW2NvbnRlbnRUeXBlXSB8fCAn8J+ThCc7XG4gICAgICBcbiAgICAgIHRleHRQYXJ0cy5wdXNoKFxuICAgICAgICBgICAgJHtpY29ufSAqKiR7aXRlbS5uYW1lLnJlcGxhY2UoJy5tZCcsICcnKX0qKlxcbmAsXG4gICAgICAgIGAgICAgICDwn5OCIFBhdGg6ICR7aXRlbS5wYXRofVxcbmAsXG4gICAgICAgIGAgICAgICDwn5OlIEluc3RhbGw6IFxcYGluc3RhbGxfY29udGVudCBcIiR7aXRlbS5wYXRofVwiXFxgXFxuYCxcbiAgICAgICAgYCAgICAgIPCfkYHvuI8gRGV0YWlsczogXFxgZ2V0X2NvbGxlY3Rpb25fY29udGVudCBcIiR7aXRlbS5wYXRofVwiXFxgXFxuXFxuYFxuICAgICAgKTtcbiAgICB9KTtcbiAgICBcbiAgICByZXR1cm4gdGV4dFBhcnRzLmpvaW4oJycpO1xuICB9XG59Il19