UNPKG

@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
/** * 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