@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.
119 lines • 15.7 kB
JavaScript
/**
* Tool Registry for managing MCP tool definitions and handlers
*/
import { getAuthTools } from "../server/tools/AuthTools.js";
import { getCollectionTools } from "../server/tools/CollectionTools.js";
import { getConfigToolsV2 } from "../server/tools/ConfigToolsV2.js";
import { getElementTools } from "../server/tools/ElementTools.js";
import { getEnhancedIndexTools } from "../server/tools/EnhancedIndexTools.js";
import { getBuildInfoTools } from "../server/tools/BuildInfoTools.js";
import { getPersonaExportImportTools } from "../server/tools/PersonaTools.js";
import { getPortfolioTools } from "../server/tools/PortfolioTools.js";
import { getMCPAQLTools } from "../server/tools/MCPAQLTools.js";
export class ToolRegistry {
tools = new Map();
constructor(_server) { }
/**
* Register a tool with its definition and handler
*/
register(tool, handler) {
if (handler) {
tool.handler = handler;
}
this.tools.set(tool.name, tool);
}
/**
* Register multiple tools at once
*/
registerMany(tools) {
tools.forEach(({ tool, handler }) => this.register(tool, handler));
}
registerPersonaTools(handler) {
this.registerMany(getPersonaExportImportTools(handler));
}
registerElementTools(handler) {
this.registerMany(getElementTools(handler));
}
registerCollectionTools(handler) {
this.registerMany(getCollectionTools(handler));
}
registerPortfolioTools(handler) {
this.registerMany(getPortfolioTools(handler));
}
registerAuthTools(handler) {
this.registerMany(getAuthTools(handler));
}
registerConfigTools(handler) {
this.registerMany(getConfigToolsV2(handler));
}
registerEnhancedIndexTools(handler, config) {
this.registerMany(getEnhancedIndexTools(handler, config));
}
registerBuildInfoTools(buildInfoService) {
this.registerMany(getBuildInfoTools(buildInfoService));
}
registerMCPAQLTools(handler) {
this.registerMany(getMCPAQLTools(handler));
}
/**
* Get all registered tools (for ListToolsRequest)
*/
getAllTools() {
return Array.from(this.tools.values()).map(({ handler, ...tool }) => tool);
}
/**
* Get a specific tool handler
*/
getHandler(name) {
return this.tools.get(name)?.handler;
}
/**
* Check if a tool exists
*/
has(name) {
return this.tools.has(name);
}
/**
* Get the count of registered tools
*/
getToolCount() {
return this.tools.size;
}
/**
* Estimate the token count for all registered tools.
*
* This provides an approximate token count based on the JSON representation
* of all tool definitions (name, description, inputSchema, annotations).
*
* Token estimation uses ~4 characters per token, which is appropriate for
* JSON/structured content. This matches the ratio used by tokenizers like
* cl100k_base for structured text.
*
* @returns Estimated total token count for all registered tools
*/
getToolTokenEstimate() {
const tools = this.getAllTools();
// Serialize tools to JSON for token estimation
const toolsJson = JSON.stringify(tools, null, 0);
// Use ~4 characters per token (appropriate for JSON/structured content)
// This is more accurate than word-based estimation for schema definitions
return Math.ceil(toolsJson.length / 4);
}
/**
* Get detailed token statistics for registered tools.
* Returns individual tool token estimates plus total.
*/
getToolTokenStats() {
const tools = this.getAllTools();
const toolStats = tools.map(tool => ({
name: tool.name,
tokens: Math.ceil(JSON.stringify(tool).length / 4)
}));
return {
tools: toolStats,
total: toolStats.reduce((sum, t) => sum + t.tokens, 0),
count: tools.length
};
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVG9vbFJlZ2lzdHJ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2hhbmRsZXJzL1Rvb2xSZWdpc3RyeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUtILE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUN4RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUNwRSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbEUsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFFOUUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFFdEUsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDOUUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDdEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBY2hFLE1BQU0sT0FBTyxZQUFZO0lBQ2YsS0FBSyxHQUFnQyxJQUFJLEdBQUcsRUFBRSxDQUFDO0lBQ3ZELFlBQVksT0FBZSxJQUFHLENBQUM7SUFFL0I7O09BRUc7SUFDSCxRQUFRLENBQUMsSUFBb0IsRUFBRSxPQUFxQjtRQUNsRCxJQUFJLE9BQU8sRUFBRSxDQUFDO1lBQ1osSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFDekIsQ0FBQztRQUNELElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsWUFBWSxDQUFDLEtBQTZEO1FBQ3hFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxPQUFPLEVB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QUFJLENBQUMsSUFBSTtZQUNmLE1BQU0sRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztTQUNuRCxDQUFDLENBQUMsQ0FBQztRQUVKLE9BQU87WUFDTCxLQUFLLEVBQUUsU0FBUztZQUNoQixLQUFLLEVBQUUsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztZQUN0RCxLQUFLLEVBQUUsS0FBSyxDQUFDLE1BQU07U0FDcEIsQ0FBQztJQUNKLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVG9vbCBSZWdpc3RyeSBmb3IgbWFuYWdpbmcgTUNQIHRvb2wgZGVmaW5pdGlvbnMgYW5kIGhhbmRsZXJzXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBTZXJ2ZXIgfSBmcm9tIFwiQG1vZGVsY29udGV4dHByb3RvY29sL3Nkay9zZXJ2ZXIvaW5kZXguanNcIjtcbmltcG9ydCB7IFRvb2wgfSBmcm9tIFwiQG1vZGVsY29udGV4dHByb3RvY29sL3Nkay90eXBlcy5qc1wiO1xuaW1wb3J0IHsgVG9vbERlZmluaXRpb24sIFRvb2xIYW5kbGVyIH0gZnJvbSBcIi4vdHlwZXMvVG9vbFR5cGVzLmpzXCI7XG5pbXBvcnQgeyBnZXRBdXRoVG9vbHMgfSBmcm9tIFwiLi4vc2VydmVyL3Rvb2xzL0F1dGhUb29scy5qc1wiO1xuaW1wb3J0IHsgZ2V0Q29sbGVjdGlvblRvb2xzIH0gZnJvbSBcIi4uL3NlcnZlci90b29scy9Db2xsZWN0aW9uVG9vbHMuanNcIjtcbmltcG9ydCB7IGdldENvbmZpZ1Rvb2xzVjIgfSBmcm9tIFwiLi4vc2VydmVyL3Rvb2xzL0NvbmZpZ1Rvb2xzVjIuanNcIjtcbmltcG9ydCB7IGdldEVsZW1lbnRUb29scyB9IGZyb20gXCIuLi9zZXJ2ZXIvdG9vbHMvRWxlbWVudFRvb2xzLmpzXCI7XG5pbXBvcnQgeyBnZXRFbmhhbmNlZEluZGV4VG9vbHMgfSBmcm9tIFwiLi4vc2VydmVyL3Rvb2xzL0VuaGFuY2VkSW5kZXhUb29scy5qc1wiO1xuaW1wb3J0IHR5cGUgeyBJbmRleENvbmZpZ3VyYXRpb24gfSBmcm9tIFwiLi4vcG9ydGZvbGlvL2NvbmZpZy9JbmRleENvbmZpZy5qc1wiO1xuaW1wb3J0IHsgZ2V0QnVpbGRJbmZvVG9vbHMgfSBmcm9tIFwiLi4vc2VydmVyL3Rvb2xzL0J1aWxkSW5mb1Rvb2xzLmpzXCI7XG5pbXBvcnQgdHlwZSB7IEJ1aWxkSW5mb1NlcnZpY2UgfSBmcm9tIFwiLi4vc2VydmljZXMvQnVpbGRJbmZvU2VydmljZS5qc1wiO1xuaW1wb3J0IHsgZ2V0UGVyc29uYUV4cG9ydEltcG9ydFRvb2xzIH0gZnJvbSBcIi4uL3NlcnZlci90b29scy9QZXJzb25hVG9vbHMuanNcIjtcbmltcG9ydCB7IGdldFBvcnRmb2xpb1Rvb2xzIH0gZnJvbSBcIi4uL3NlcnZlci90b29scy9Qb3J0Zm9saW9Ub29scy5qc1wiO1xuaW1wb3J0IHsgZ2V0TUNQQVFMVG9vbHMgfSBmcm9tIFwiLi4vc2VydmVyL3Rvb2xzL01DUEFRTFRvb2xzLmpzXCI7XG5pbXBvcnQgdHlwZSB7IFBlcnNvbmFIYW5kbGVyIH0gZnJvbSAnLi9QZXJzb25hSGFuZGxlci5qcyc7XG5pbXBvcnQgdHlwZSB7IEVsZW1lbnRDUlVESGFuZGxlciB9IGZyb20gJy4vRWxlbWVudENSVURIYW5kbGVyLmpzJztcbmltcG9ydCB0eXBlIHsgQ29sbGVjdGlvbkhhbmRsZXIgfSBmcm9tICcuL0NvbGxlY3Rpb25IYW5kbGVyLmpzJztcbmltcG9ydCB0eXBlIHsgUG9ydGZvbGlvSGFuZGxlciB9IGZyb20gJy4vUG9ydGZvbGlvSGFuZGxlci5qcyc7XG5pbXBvcnQgdHlwZSB7IEdpdEh1YkF1dGhIYW5kbGVyIH0gZnJvbSAnLi9HaXRIdWJBdXRoSGFuZGxlci5qcyc7XG5pbXBvcnQgdHlwZSB7IENvbmZpZ0hhbmRsZXIgfSBmcm9tICcuL0NvbmZpZ0hhbmRsZXIuanMnO1xuaW1wb3J0IHR5cGUgeyBTeW5jSGFuZGxlciB9IGZyb20gJy4vU3luY0hhbmRsZXJWMi5qcyc7XG5pbXBvcnQgdHlwZSB7IEVuaGFuY2VkSW5kZXhIYW5kbGVyIH0gZnJvbSAnLi9FbmhhbmNlZEluZGV4SGFuZGxlci5qcyc7XG5pbXBvcnQgdHlwZSB7IE1DUEFRTEhhbmRsZXIgfSBmcm9tICcuL21jcC1hcWwvTUNQQVFMSGFuZGxlci5qcyc7XG5cbi8vIFJlLWV4cG9ydCB0eXBlcyBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eVxuZXhwb3J0IHR5cGUgeyBUb29sRGVmaW5pdGlvbiwgVG9vbEhhbmRsZXIgfTtcblxuZXhwb3J0IGNsYXNzIFRvb2xSZWdpc3RyeSB7XG4gIHByaXZhdGUgdG9vbHM6IE1hcDxzdHJpbmcsIFRvb2xEZWZpbml0aW9uPiA9IG5ldyBNYXAoKTtcbiAgY29uc3RydWN0b3IoX3NlcnZlcjogU2VydmVyKSB7fVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciBhIHRvb2wgd2l0aCBpdHMgZGVmaW5pdGlvbiBhbmQgaGFuZGxlclxuICAgKi9cbiAgcmVnaXN0ZXIodG9vbDogVG9vbERlZmluaXRpb24sIGhhbmRsZXI/OiBUb29sSGFuZGxlcik6IHZvaWQge1xuICAgIGlmIChoYW5kbGVyKSB7XG4gICAgICB0b29sLmhhbmRsZXIgPSBoYW5kbGVyO1xuICAgIH1cbiAgICB0aGlzLnRvb2xzLnNldCh0b29sLm5hbWUsIHRvb2wpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVyIG11bHRpcGxlIHRvb2xzIGF0IG9uY2VcbiAgICovXG4gIHJlZ2lzdGVyTWFueSh0b29sczogQXJyYXk8eyB0b29sOiBUb29sRGVmaW5pdGlvbjsgaGFuZGxlcj86IFRvb2xIYW5kbGVyIH0+KTogdm9pZCB7XG4gICAgdG9vbHMuZm9yRWFjaCgoeyB0b29sLCBoYW5kbGVyIH0pID0+IHRoaXMucmVnaXN0ZXIodG9vbCwgaGFuZGxlcikpO1xuICB9XG5cbiAgcmVnaXN0ZXJQZXJzb25hVG9vbHMoaGFuZGxlcjogUGVyc29uYUhhbmRsZXIpOiB2b2lkIHtcbiAgICB0aGlzLnJlZ2lzdGVyTWFueShnZXRQZXJzb25hRXhwb3J0SW1wb3J0VG9vbHMoaGFuZGxlcikpO1xuICB9XG5cbiAgcmVnaXN0ZXJFbGVtZW50VG9vbHMoaGFuZGxlcjogRWxlbWVudENSVURIYW5kbGVyKTogdm9pZCB7XG4gICAgdGhpcy5yZWdpc3Rlck1hbnkoZ2V0RWxlbWVudFRvb2xzKGhhbmRsZXIpKTtcbiAgfVxuXG4gIHJlZ2lzdGVyQ29sbGVjdGlvblRvb2xzKGhhbmRsZXI6IENvbGxlY3Rpb25IYW5kbGVyKTogdm9pZCB7XG4gICAgdGhpcy5yZWdpc3Rlck1hbnkoZ2V0Q29sbGVjdGlvblRvb2xzKGhhbmRsZXIpKTtcbiAgfVxuXG4gIHJlZ2lzdGVyUG9ydGZvbGlvVG9vbHMoaGFuZGxlcjogUG9ydGZvbGlvSGFuZGxlcik6IHZvaWQge1xuICAgIHRoaXMucmVnaXN0ZXJNYW55KGdldFBvcnRmb2xpb1Rvb2xzKGhhbmRsZXIpKTtcbiAgfVxuXG4gIHJlZ2lzdGVyQXV0aFRvb2xzKGhhbmRsZXI6IEdpdEh1YkF1dGhIYW5kbGVyKTogdm9pZCB7XG4gICAgdGhpcy5yZWdpc3Rlck1hbnkoZ2V0QXV0aFRvb2xzKGhhbmRsZXIpKTtcbiAgfVxuXG4gIHJlZ2lzdGVyQ29uZmlnVG9vbHMoaGFuZGxlcjoge1xuICAgIGhhbmRsZUNvbmZpZ09wZXJhdGlvbjogQ29uZmlnSGFuZGxlclsnaGFuZGxlQ29uZmlnT3BlcmF0aW9uJ107XG4gICAgaGFuZGxlU3luY09wZXJhdGlvbjogU3luY0hhbmRsZXJbJ2hhbmRsZVN5bmNPcGVyYXRpb24nXTtcbiAgfSk6IHZvaWQge1xuICAgIHRoaXMucmVnaXN0ZXJNYW55KGdldENvbmZpZ1Rvb2xzVjIoaGFuZGxlcikpO1xuICB9XG5cbiAgcmVnaXN0ZXJFbmhhbmNlZEluZGV4VG9vbHMoaGFuZGxlcjogRW5oYW5jZWRJbmRleEhhbmRsZXIsIGNvbmZpZzogSW5kZXhDb25maWd1cmF0aW9uKTogdm9pZCB7XG4gICAgdGhpcy5yZWdpc3Rlck1hbnkoZ2V0RW5oYW5jZWRJbmRleFRvb2xzKGhhbmRsZXIsIGNvbmZpZykpO1xuICB9XG5cbiAgcmVnaXN0ZXJCdWlsZEluZm9Ub29scyhidWlsZEluZm9TZXJ2aWNlOiBCdWlsZEluZm9TZXJ2aWNlKTogdm9pZCB7XG4gICAgdGhpcy5yZWdpc3Rlck1hbnkoZ2V0QnVpbGRJbmZvVG9vbHMoYnVpbGRJbmZvU2VydmljZSkpO1xuICB9XG5cbiAgcmVnaXN0ZXJNQ1BBUUxUb29scyhoYW5kbGVyOiBNQ1BBUUxIYW5kbGVyKTogdm9pZCB7XG4gICAgdGhpcy5yZWdpc3Rlck1hbnkoZ2V0TUNQQVFMVG9vbHMoaGFuZGxlcikpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhbGwgcmVnaXN0ZXJlZCB0b29scyAoZm9yIExpc3RUb29sc1JlcXVlc3QpXG4gICAqL1xuICBnZXRBbGxUb29scygpOiBUb29sW10ge1xuICAgIHJldHVybiBBcnJheS5mcm9tKHRoaXMudG9vbHMudmFsdWVzKCkpLm1hcCgoeyBoYW5kbGVyLCAuLi50b29sIH0pID0+IHRvb2wpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhIHNwZWNpZmljIHRvb2wgaGFuZGxlclxuICAgKi9cbiAgZ2V0SGFuZGxlcihuYW1lOiBzdHJpbmcpOiBUb29sSGFuZGxlciB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMudG9vbHMuZ2V0KG5hbWUpPy5oYW5kbGVyO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIGEgdG9vbCBleGlzdHNcbiAgICovXG4gIGhhcyhuYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy50b29scy5oYXMobmFtZSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBjb3VudCBvZiByZWdpc3RlcmVkIHRvb2xzXG4gICAqL1xuICBnZXRUb29sQ291bnQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy50b29scy5zaXplO1xuICB9XG5cbiAgLyoqXG4gICAqIEVzdGltYXRlIHRoZSB0b2tlbiBjb3VudCBmb3IgYWxsIHJlZ2lzdGVyZWQgdG9vbHMuXG4gICAqXG4gICAqIFRoaXMgcHJvdmlkZXMgYW4gYXBwcm94aW1hdGUgdG9rZW4gY291bnQgYmFzZWQgb24gdGhlIEpTT04gcmVwcmVzZW50YXRpb25cbiAgICogb2YgYWxsIHRvb2wgZGVmaW5pdGlvbnMgKG5hbWUsIGRlc2NyaXB0aW9uLCBpbnB1dFNjaGVtYSwgYW5ub3RhdGlvbnMpLlxuICAgKlxuICAgKiBUb2tlbiBlc3RpbWF0aW9uIHVzZXMgfjQgY2hhcmFjdGVycyBwZXIgdG9rZW4sIHdoaWNoIGlzIGFwcHJvcHJpYXRlIGZvclxuICAgKiBKU09OL3N0cnVjdHVyZWQgY29udGVudC4gVGhpcyBtYXRjaGVzIHRoZSByYXRpbyB1c2VkIGJ5IHRva2VuaXplcnMgbGlrZVxuICAgKiBjbDEwMGtfYmFzZSBmb3Igc3RydWN0dXJlZCB0ZXh0LlxuICAgKlxuICAgKiBAcmV0dXJucyBFc3RpbWF0ZWQgdG90YWwgdG9rZW4gY291bnQgZm9yIGFsbCByZWdpc3RlcmVkIHRvb2xzXG4gICAqL1xuICBnZXRUb29sVG9rZW5Fc3RpbWF0ZSgpOiBudW1iZXIge1xuICAgIGNvbnN0IHRvb2xzID0gdGhpcy5nZXRBbGxUb29scygpO1xuXG4gICAgLy8gU2VyaWFsaXplIHRvb2xzIHRvIEpTT04gZm9yIHRva2VuIGVzdGltYXRpb25cbiAgICBjb25zdCB0b29sc0pzb24gPSBKU09OLnN0cmluZ2lmeSh0b29scywgbnVsbCwgMCk7XG5cbiAgICAvLyBVc2UgfjQgY2hhcmFjdGVycyBwZXIgdG9rZW4gKGFwcHJvcHJpYXRlIGZvciBKU09OL3N0cnVjdHVyZWQgY29udGVudClcbiAgICAvLyBUaGlzIGlzIG1vcmUgYWNjdXJhdGUgdGhhbiB3b3JkLWJhc2VkIGVzdGltYXRpb24gZm9yIHNjaGVtYSBkZWZpbml0aW9uc1xuICAgIHJldHVybiBNYXRoLmNlaWwodG9vbHNKc29uLmxlbmd0aCAvIDQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBkZXRhaWxlZCB0b2tlbiBzdGF0aXN0aWNzIGZvciByZWdpc3RlcmVkIHRvb2xzLlxuICAgKiBSZXR1cm5zIGluZGl2aWR1YWwgdG9vbCB0b2tlbiBlc3RpbWF0ZXMgcGx1cyB0b3RhbC5cbiAgICovXG4gIGdldFRvb2xUb2tlblN0YXRzKCk6IHtcbiAgICB0b29sczogQXJyYXk8eyBuYW1lOiBzdHJpbmc7IHRva2VuczogbnVtYmVyIH0+O1xuICAgIHRvdGFsOiBudW1iZXI7XG4gICAgY291bnQ6IG51bWJlcjtcbiAgfSB7XG4gICAgY29uc3QgdG9vbHMgPSB0aGlzLmdldEFsbFRvb2xzKCk7XG4gICAgY29uc3QgdG9vbFN0YXRzID0gdG9vbHMubWFwKHRvb2wgPT4gKHtcbiAgICAgIG5hbWU6IHRvb2wubmFtZSxcbiAgICAgIHRva2VuczogTWF0aC5jZWlsKEpTT04uc3RyaW5naWZ5KHRvb2wpLmxlbmd0aCAvIDQpXG4gICAgfSkpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHRvb2xzOiB0b29sU3RhdHMsXG4gICAgICB0b3RhbDogdG9vbFN0YXRzLnJlZHVjZSgoc3VtLCB0KSA9PiBzdW0gKyB0LnRva2VucywgMCksXG4gICAgICBjb3VudDogdG9vbHMubGVuZ3RoXG4gICAgfTtcbiAgfVxufVxuIl19