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.

133 lines 17.5 kB
/** * BaseActivationStrategy - Shared functionality for all activation strategies * * Provides common helper methods used by multiple strategy implementations: * - Flexible element finding (by name or filename) * - Error response formatting */ import { findElementFlexibly as findHelper } from '../element-crud/helpers.js'; import { ElementNotFoundError } from '../../utils/ErrorHandler.js'; import { getPermissionHookStatus } from '../../utils/permissionHooks.js'; import { getGatekeeperDiagnostics } from '../mcp-aql/policies/ElementPolicies.js'; /** * Base class with shared utilities for activation strategies */ export class BaseActivationStrategy { /** * Find an element by name, supporting both exact display name and filename (slug) matching * @param name - The name or filename to search for * @param elementList - List of elements to search through * @returns The found element or undefined */ async findElementFlexibly(name, elementList) { return findHelper(name, elementList); } /** * Create a standard error response * @param message - The error message * @returns MCP-formatted error response */ createErrorResponse(message) { return { content: [{ type: "text", text: message }] }; } /** * Create a standard success response * @param message - The success message * @returns MCP-formatted success response */ createSuccessResponse(message) { return { content: [{ type: "text", text: message }] }; } /** * Throw an ElementNotFoundError for missing elements. * * This replaces the previous createNotFoundResponse which returned a success * response with error text. Now we throw to ensure MCP-AQL returns success=false. * * @param name - The name of the element that wasn't found * @param type - The type of element (for error message) * @throws {ElementNotFoundError} Always throws * @see Issue #275 - Handlers return success=true for missing elements */ throwNotFoundError(name, type) { throw new ElementNotFoundError(type, name); } /** * @deprecated Use throwNotFoundError instead to ensure proper error handling. * This method returns a success response which causes MCP-AQL to return success=true. * @see Issue #275 - Handlers return success=true for missing elements */ createNotFoundResponse(name, type) { // Keep for backward compatibility but strategies should migrate to throwNotFoundError return this.createErrorResponse(`❌ ${type} '${name}' not found`); } /** * Format a fail-safe warning for elements with CLI external restrictions. * Appended to activation text so users are aware of restrictions even when * permission_prompt is not available (non-Claude-Code clients). * * @param metadata - Element metadata (may contain gatekeeper.externalRestrictions) * @returns Warning text or empty string if no restrictions * @see Issue #642 — Fail-safe enforcement for externalRestrictions */ formatRestrictionWarning(metadata) { const gatekeeper = metadata?.gatekeeper; const restrictions = gatekeeper?.externalRestrictions; if (!restrictions) return ''; const hookStatus = getPermissionHookStatus(); const parts = [hookStatus.installed ? '\n---\n**CLI Policies Loaded:**' : '\n---\n**CLI Policies Loaded (Hook Not Detected):**']; if (restrictions.description) { parts.push(`> ${restrictions.description}`); } const denyPatterns = restrictions.denyPatterns; if (denyPatterns?.length) { const shown = denyPatterns.slice(0, 5).join(', '); parts.push(`> Denied: ${shown}${denyPatterns.length > 5 ? '...' : ''}`); } const allowPatterns = restrictions.allowPatterns; if (allowPatterns?.length) { const shown = allowPatterns.slice(0, 5).join(', '); parts.push(`> Allowed only: ${shown}${allowPatterns.length > 5 ? '...' : ''}`); } const approvalPolicy = restrictions.approvalPolicy; const requireApproval = approvalPolicy?.requireApproval; if (requireApproval?.length) { parts.push(`> Requires approval for: ${requireApproval.join(', ')} risk tools`); } parts.push('> Use `get_effective_cli_policies` to see combined policy state.'); if (hookStatus.installed) { parts.push(`> Permission hook detected for ${hookStatus.host ?? 'this client'}. Enforcement depends on using that client configuration.`); } else { parts.push('> No permission hook detected. These policies are not automatically enforced unless the CLI is launched with `--permission-prompt-tool`.', '> Run `open_setup` and reinstall to wire automatic enforcement.'); } return parts.join('\n'); } formatGatekeeperValidityWarning(metadata) { const diagnostics = getGatekeeperDiagnostics(metadata); if (!diagnostics) { return ''; } return [ '\n---', '**Gatekeeper Policy Warning:**', `> ${diagnostics.message}`, '> This element can still activate and do its normal work, but its malformed gatekeeper policy is not being enforced.', '> Fix the policy structure and reactivate if you want permission rules to apply.', ].join('\n'); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQmFzZUFjdGl2YXRpb25TdHJhdGVneS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9oYW5kbGVycy9zdHJhdGVnaWVzL0Jhc2VBY3RpdmF0aW9uU3RyYXRlZ3kudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUgsT0FBTyxFQUFFLG1CQUFtQixJQUFJLFVBQVUsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQy9FLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBRW5FLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ3pFLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLHdDQUF3QyxDQUFDO0FBRWxGOztHQUVHO0FBQ0gsTUFBTSxPQUFnQixzQkFBc0I7SUFDMUM7Ozs7O09BS0c7SUFDTyxLQUFLLENBQUMsbUJBQW1CLENBQUMsSUFBWSxFQUFFLFdBQWtCO1FBQ2xFLE9BQU8sVUFBVSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsQ0FBQztJQUN2QyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNPLG1CQUFtQixDQUFDLE9BQWU7UUFDM0MsT0FBTztZQUNMLE9BQU8sRUFBRSxDQUFDO29CQUNSLElBQUksRUFBRSxNQUFNO29CQUNaLElBQUksRUFBRSxPQUFPO2lCQUNkLENBQUM7U0FDSCxDQUFDO0lBQ0osQ0FBQztJQUVEOzs7O09BSUc7SUFDTyxxQkFBcUIsQ0FBQyxPQUFlO1FBQzdDLE9BQU87WUFDTCxPQUFPLEVBQUUsQ0FBQztvQkFDUixJQUFJLEVBQUUsTUFBTTtvQkFDWixJQUFJLEVBQUUsT0FBTztpQkFDZCxDQUFDO1NBQ0gsQ0FBQztJQUNKLENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ08sa0JBQWtCLENBQUMsSUFBWSxFQUFFLElBQVk7UUFDckQsTUFBTSxJQUFJLG9CQUFvQixDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztJQUM3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QUFPO1lBQ0wsT0FBTztZQUNQLGdDQUFnQztZQUNoQyxLQUFLLFdBQVcsQ0FBQyxPQUFPLEVBQUU7WUFDMUIsc0hBQXNIO1lBQ3RILGtGQUFrRjtTQUNuRixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNmLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQmFzZUFjdGl2YXRpb25TdHJhdGVneSAtIFNoYXJlZCBmdW5jdGlvbmFsaXR5IGZvciBhbGwgYWN0aXZhdGlvbiBzdHJhdGVnaWVzXG4gKlxuICogUHJvdmlkZXMgY29tbW9uIGhlbHBlciBtZXRob2RzIHVzZWQgYnkgbXVsdGlwbGUgc3RyYXRlZ3kgaW1wbGVtZW50YXRpb25zOlxuICogLSBGbGV4aWJsZSBlbGVtZW50IGZpbmRpbmcgKGJ5IG5hbWUgb3IgZmlsZW5hbWUpXG4gKiAtIEVycm9yIHJlc3BvbnNlIGZvcm1hdHRpbmdcbiAqL1xuXG5pbXBvcnQgeyBmaW5kRWxlbWVudEZsZXhpYmx5IGFzIGZpbmRIZWxwZXIgfSBmcm9tICcuLi9lbGVtZW50LWNydWQvaGVscGVycy5qcyc7XG5pbXBvcnQgeyBFbGVtZW50Tm90Rm91bmRFcnJvciB9IGZyb20gJy4uLy4uL3V0aWxzL0Vycm9ySGFuZGxlci5qcyc7XG5pbXBvcnQgeyBNQ1BSZXNwb25zZSB9IGZyb20gJy4vRWxlbWVudEFjdGl2YXRpb25TdHJhdGVneS5qcyc7XG5pbXBvcnQgeyBnZXRQZXJtaXNzaW9uSG9va1N0YXR1cyB9IGZyb20gJy4uLy4uL3V0aWxzL3Blcm1pc3Npb25Ib29rcy5qcyc7XG5pbXBvcnQgeyBnZXRHYXRla2VlcGVyRGlhZ25vc3RpY3MgfSBmcm9tICcuLi9tY3AtYXFsL3BvbGljaWVzL0VsZW1lbnRQb2xpY2llcy5qcyc7XG5cbi8qKlxuICogQmFzZSBjbGFzcyB3aXRoIHNoYXJlZCB1dGlsaXRpZXMgZm9yIGFjdGl2YXRpb24gc3RyYXRlZ2llc1xuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgQmFzZUFjdGl2YXRpb25TdHJhdGVneSB7XG4gIC8qKlxuICAgKiBGaW5kIGFuIGVsZW1lbnQgYnkgbmFtZSwgc3VwcG9ydGluZyBib3RoIGV4YWN0IGRpc3BsYXkgbmFtZSBhbmQgZmlsZW5hbWUgKHNsdWcpIG1hdGNoaW5nXG4gICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb3IgZmlsZW5hbWUgdG8gc2VhcmNoIGZvclxuICAgKiBAcGFyYW0gZWxlbWVudExpc3QgLSBMaXN0IG9mIGVsZW1lbnRzIHRvIHNlYXJjaCB0aHJvdWdoXG4gICAqIEByZXR1cm5zIFRoZSBmb3VuZCBlbGVtZW50IG9yIHVuZGVmaW5lZFxuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGZpbmRFbGVtZW50RmxleGlibHkobmFtZTogc3RyaW5nLCBlbGVtZW50TGlzdDogYW55W10pOiBQcm9taXNlPGFueT4ge1xuICAgIHJldHVybiBmaW5kSGVscGVyKG5hbWUsIGVsZW1lbnRMaXN0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBzdGFuZGFyZCBlcnJvciByZXNwb25zZVxuICAgKiBAcGFyYW0gbWVzc2FnZSAtIFRoZSBlcnJvciBtZXNzYWdlXG4gICAqIEByZXR1cm5zIE1DUC1mb3JtYXR0ZWQgZXJyb3IgcmVzcG9uc2VcbiAgICovXG4gIHByb3RlY3RlZCBjcmVhdGVFcnJvclJlc3BvbnNlKG1lc3NhZ2U6IHN0cmluZyk6IE1DUFJlc3BvbnNlIHtcbiAgICByZXR1cm4ge1xuICAgICAgY29udGVudDogW3tcbiAgICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICAgIHRleHQ6IG1lc3NhZ2VcbiAgICAgIH1dXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBzdGFuZGFyZCBzdWNjZXNzIHJlc3BvbnNlXG4gICAqIEBwYXJhbSBtZXNzYWdlIC0gVGhlIHN1Y2Nlc3MgbWVzc2FnZVxuICAgKiBAcmV0dXJucyBNQ1AtZm9ybWF0dGVkIHN1Y2Nlc3MgcmVzcG9uc2VcbiAgICovXG4gIHByb3RlY3RlZCBjcmVhdGVTdWNjZXNzUmVzcG9uc2UobWVzc2FnZTogc3RyaW5nKTogTUNQUmVzcG9uc2Uge1xuICAgIHJldHVybiB7XG4gICAgICBjb250ZW50OiBbe1xuICAgICAgICB0eXBlOiBcInRleHRcIixcbiAgICAgICAgdGV4dDogbWVzc2FnZVxuICAgICAgfV1cbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFRocm93IGFuIEVsZW1lbnROb3RGb3VuZEVycm9yIGZvciBtaXNzaW5nIGVsZW1lbnRzLlxuICAgKlxuICAgKiBUaGlzIHJlcGxhY2VzIHRoZSBwcmV2aW91cyBjcmVhdGVOb3RGb3VuZFJlc3BvbnNlIHdoaWNoIHJldHVybmVkIGEgc3VjY2Vzc1xuICAgKiByZXNwb25zZSB3aXRoIGVycm9yIHRleHQuIE5vdyB3ZSB0aHJvdyB0byBlbnN1cmUgTUNQLUFRTCByZXR1cm5zIHN1Y2Nlc3M9ZmFsc2UuXG4gICAqXG4gICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGVsZW1lbnQgdGhhdCB3YXNuJ3QgZm91bmRcbiAgICogQHBhcmFtIHR5cGUgLSBUaGUgdHlwZSBvZiBlbGVtZW50IChmb3IgZXJyb3IgbWVzc2FnZSlcbiAgICogQHRocm93cyB7RWxlbWVudE5vdEZvdW5kRXJyb3J9IEFsd2F5cyB0aHJvd3NcbiAgICogQHNlZSBJc3N1ZSAjMjc1IC0gSGFuZGxlcnMgcmV0dXJuIHN1Y2Nlc3M9dHJ1ZSBmb3IgbWlzc2luZyBlbGVtZW50c1xuICAgKi9cbiAgcHJvdGVjdGVkIHRocm93Tm90Rm91bmRFcnJvcihuYW1lOiBzdHJpbmcsIHR5cGU6IHN0cmluZyk6IG5ldmVyIHtcbiAgICB0aHJvdyBuZXcgRWxlbWVudE5vdEZvdW5kRXJyb3IodHlwZSwgbmFtZSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlcHJlY2F0ZWQgVXNlIHRocm93Tm90Rm91bmRFcnJvciBpbnN0ZWFkIHRvIGVuc3VyZSBwcm9wZXIgZXJyb3IgaGFuZGxpbmcuXG4gICAqIFRoaXMgbWV0aG9kIHJldHVybnMgYSBzdWNjZXNzIHJlc3BvbnNlIHdoaWNoIGNhdXNlcyBNQ1AtQVFMIHRvIHJldHVybiBzdWNjZXNzPXRydWUuXG4gICAqIEBzZWUgSXNzdWUgIzI3NSAtIEhhbmRsZXJzIHJldHVybiBzdWNjZXNzPXRydWUgZm9yIG1pc3NpbmcgZWxlbWVudHNcbiAgICovXG4gIHByb3RlY3RlZCBjcmVhdGVOb3RGb3VuZFJlc3BvbnNlKG5hbWU6IHN0cmluZywgdHlwZTogc3RyaW5nKTogTUNQUmVzcG9uc2Uge1xuICAgIC8vIEtlZXAgZm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHkgYnV0IHN0cmF0ZWdpZXMgc2hvdWxkIG1pZ3JhdGUgdG8gdGhyb3dOb3RGb3VuZEVycm9yXG4gICAgcmV0dXJuIHRoaXMuY3JlYXRlRXJyb3JSZXNwb25zZShg4p2MICR7dHlwZX0gJyR7bmFtZX0nIG5vdCBmb3VuZGApO1xuICB9XG5cbiAgLyoqXG4gICAqIEZvcm1hdCBhIGZhaWwtc2FmZSB3YXJuaW5nIGZvciBlbGVtZW50cyB3aXRoIENMSSBleHRlcm5hbCByZXN0cmljdGlvbnMuXG4gICAqIEFwcGVuZGVkIHRvIGFjdGl2YXRpb24gdGV4dCBzbyB1c2VycyBhcmUgYXdhcmUgb2YgcmVzdHJpY3Rpb25zIGV2ZW4gd2hlblxuICAgKiBwZXJtaXNzaW9uX3Byb21wdCBpcyBub3QgYXZhaWxhYmxlIChub24tQ2xhdWRlLUNvZGUgY2xpZW50cykuXG4gICAqXG4gICAqIEBwYXJhbSBtZXRhZGF0YSAtIEVsZW1lbnQgbWV0YWRhdGEgKG1heSBjb250YWluIGdhdGVrZWVwZXIuZXh0ZXJuYWxSZXN0cmljdGlvbnMpXG4gICAqIEByZXR1cm5zIFdhcm5pbmcgdGV4dCBvciBlbXB0eSBzdHJpbmcgaWYgbm8gcmVzdHJpY3Rpb25zXG4gICAqIEBzZWUgSXNzdWUgIzY0MiDigJQgRmFpbC1zYWZlIGVuZm9yY2VtZW50IGZvciBleHRlcm5hbFJlc3RyaWN0aW9uc1xuICAgKi9cbiAgcHJvdGVjdGVkIGZvcm1hdFJlc3RyaWN0aW9uV2FybmluZyhtZXRhZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBzdHJpbmcge1xuICAgIGNvbnN0IGdhdGVrZWVwZXIgPSBtZXRhZGF0YT8uZ2F0ZWtlZXBlciBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZDtcbiAgICBjb25zdCByZXN0cmljdGlvbnMgPSBnYXRla2VlcGVyPy5leHRlcm5hbFJlc3RyaWN0aW9ucyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZDtcbiAgICBpZiAoIXJlc3RyaWN0aW9ucykgcmV0dXJuICcnO1xuXG4gICAgY29uc3QgaG9va1N0YXR1cyA9IGdldFBlcm1pc3Npb25Ib29rU3RhdHVzKCk7XG4gICAgY29uc3QgcGFydHM6IHN0cmluZ1tdID0gW2hvb2tTdGF0dXMuaW5zdGFsbGVkXG4gICAgICA/ICdcXG4tLS1cXG4qKkNMSSBQb2xpY2llcyBMb2FkZWQ6KionXG4gICAgICA6ICdcXG4tLS1cXG4qKkNMSSBQb2xpY2llcyBMb2FkZWQgKEhvb2sgTm90IERldGVjdGVkKToqKiddO1xuICAgIGlmIChyZXN0cmljdGlvbnMuZGVzY3JpcHRpb24pIHtcbiAgICAgIHBhcnRzLnB1c2goYD4gJHtyZXN0cmljdGlvbnMuZGVzY3JpcHRpb259YCk7XG4gICAgfVxuICAgIGNvbnN0IGRlbnlQYXR0ZXJucyA9IHJlc3RyaWN0aW9ucy5kZW55UGF0dGVybnMgYXMgc3RyaW5nW10gfCB1bmRlZmluZWQ7XG4gICAgaWYgKGRlbnlQYXR0ZXJucz8ubGVuZ3RoKSB7XG4gICAgICBjb25zdCBzaG93biA9IGRlbnlQYXR0ZXJucy5zbGljZSgwLCA1KS5qb2luKCcsICcpO1xuICAgICAgcGFydHMucHVzaChgPiBEZW5pZWQ6ICR7c2hvd259JHtkZW55UGF0dGVybnMubGVuZ3RoID4gNSA/ICcuLi4nIDogJyd9YCk7XG4gICAgfVxuICAgIGNvbnN0IGFsbG93UGF0dGVybnMgPSByZXN0cmljdGlvbnMuYWxsb3dQYXR0ZXJucyBhcyBzdHJpbmdbXSB8IHVuZGVmaW5lZDtcbiAgICBpZiAoYWxsb3dQYXR0ZXJucz8ubGVuZ3RoKSB7XG4gICAgICBjb25zdCBzaG93biA9IGFsbG93UGF0dGVybnMuc2xpY2UoMCwgNSkuam9pbignLCAnKTtcbiAgICAgIHBhcnRzLnB1c2goYD4gQWxsb3dlZCBvbmx5OiAke3Nob3dufSR7YWxsb3dQYXR0ZXJucy5sZW5ndGggPiA1ID8gJy4uLicgOiAnJ31gKTtcbiAgICB9XG4gICAgY29uc3QgYXBwcm92YWxQb2xpY3kgPSByZXN0cmljdGlvbnMuYXBwcm92YWxQb2xpY3kgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWQ7XG4gICAgY29uc3QgcmVxdWlyZUFwcHJvdmFsID0gYXBwcm92YWxQb2xpY3k/LnJlcXVpcmVBcHByb3ZhbCBhcyBzdHJpbmdbXSB8IHVuZGVmaW5lZDtcbiAgICBpZiAocmVxdWlyZUFwcHJvdmFsPy5sZW5ndGgpIHtcbiAgICAgIHBhcnRzLnB1c2goYD4gUmVxdWlyZXMgYXBwcm92YWwgZm9yOiAke3JlcXVpcmVBcHByb3ZhbC5qb2luKCcsICcpfSByaXNrIHRvb2xzYCk7XG4gICAgfVxuICAgIHBhcnRzLnB1c2goJz4gVXNlIGBnZXRfZWZmZWN0aXZlX2NsaV9wb2xpY2llc2AgdG8gc2VlIGNvbWJpbmVkIHBvbGljeSBzdGF0ZS4nKTtcbiAgICBpZiAoaG9va1N0YXR1cy5pbnN0YWxsZWQpIHtcbiAgICAgIHBhcnRzLnB1c2goYD4gUGVybWlzc2lvbiBob29rIGRldGVjdGVkIGZvciAke2hvb2tTdGF0dXMuaG9zdCA/PyAndGhpcyBjbGllbnQnfS4gRW5mb3JjZW1lbnQgZGVwZW5kcyBvbiB1c2luZyB0aGF0IGNsaWVudCBjb25maWd1cmF0aW9uLmApO1xuICAgIH0gZWxzZSB7XG4gICAgICBwYXJ0cy5wdXNoKFxuICAgICAgICAnPiBObyBwZXJtaXNzaW9uIGhvb2sgZGV0ZWN0ZWQuIFRoZXNlIHBvbGljaWVzIGFyZSBub3QgYXV0b21hdGljYWxseSBlbmZvcmNlZCB1bmxlc3MgdGhlIENMSSBpcyBsYXVuY2hlZCB3aXRoIGAtLXBlcm1pc3Npb24tcHJvbXB0LXRvb2xgLicsXG4gICAgICAgICc+IFJ1biBgb3Blbl9zZXR1cGAgYW5kIHJlaW5zdGFsbCB0byB3aXJlIGF1dG9tYXRpYyBlbmZvcmNlbWVudC4nLFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHBhcnRzLmpvaW4oJ1xcbicpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGZvcm1hdEdhdGVrZWVwZXJWYWxpZGl0eVdhcm5pbmcobWV0YWRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogc3RyaW5nIHtcbiAgICBjb25zdCBkaWFnbm9zdGljcyA9IGdldEdhdGVrZWVwZXJEaWFnbm9zdGljcyhtZXRhZGF0YSk7XG4gICAgaWYgKCFkaWFnbm9zdGljcykge1xuICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIHJldHVybiBbXG4gICAgICAnXFxuLS0tJyxcbiAgICAgICcqKkdhdGVrZWVwZXIgUG9saWN5IFdhcm5pbmc6KionLFxuICAgICAgYD4gJHtkaWFnbm9zdGljcy5tZXNzYWdlfWAsXG4gICAgICAnPiBUaGlzIGVsZW1lbnQgY2FuIHN0aWxsIGFjdGl2YXRlIGFuZCBkbyBpdHMgbm9ybWFsIHdvcmssIGJ1dCBpdHMgbWFsZm9ybWVkIGdhdGVrZWVwZXIgcG9saWN5IGlzIG5vdCBiZWluZyBlbmZvcmNlZC4nLFxuICAgICAgJz4gRml4IHRoZSBwb2xpY3kgc3RydWN0dXJlIGFuZCByZWFjdGl2YXRlIGlmIHlvdSB3YW50IHBlcm1pc3Npb24gcnVsZXMgdG8gYXBwbHkuJyxcbiAgICBdLmpvaW4oJ1xcbicpO1xuICB9XG59XG4iXX0=