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.

601 lines 81 kB
/** * PersonaHandler - Handles all persona-related MCP tool operations * * Provides the interface for activating, deactivating, listing, exporting, * and importing personas through MCP tools. * * Uses dependency injection for all services: * - PersonaManager for persona state and operations * - InitializationService for setup tasks * - PersonaIndicatorService for persona indicator formatting * * FIX: DMCP-SEC-006 - Security audit suppression * This handler delegates all operations to PersonaManager. * Audit logging happens in PersonaManager for CRUD operations. * @security-audit-suppress DMCP-SEC-006 */ import { SecureErrorHandler } from '../security/errorHandler.js'; import { MCPInputValidator } from '../security/InputValidator.js'; import { slugify } from '../utils/filesystem.js'; import { sanitizeMetadata } from './element-crud/helpers.js'; import { SecurityMonitor } from '../security/securityMonitor.js'; import { formatNotFoundError } from './element-crud/responseFormatter.js'; import { ElementType } from '../portfolio/PortfolioManager.js'; /** * Handles all persona-related MCP tool operations */ export class PersonaHandler { personaManager; personaExporter; personaImporter; initService; indicatorService; activePersona; constructor(personaManager, personaExporter, personaImporter, initService, indicatorService, activePersona) { this.personaManager = personaManager; this.personaExporter = personaExporter; this.personaImporter = personaImporter; this.initService = initService; this.indicatorService = indicatorService; this.activePersona = activePersona; } /** * List all available personas * Extracted from index.ts:515-557 */ async listPersonas() { const personaList = (await this.personaManager.list()).map(persona => ({ filename: persona.filename, unique_id: persona.unique_id, name: persona.metadata.name, description: persona.metadata.description, triggers: persona.metadata.triggers || [], version: persona.metadata.version || "1.0", author: persona.metadata.author || "Unknown", category: persona.metadata.category || 'general', age_rating: persona.metadata.age_rating || 'all', price: persona.metadata.price || 'free', ai_generated: persona.metadata.ai_generated || false, active: this.activePersona.get() === persona.filename, })); if (personaList.length === 0) { return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}You don't have any personas installed yet. Would you like to browse the DollhouseMCP collection on GitHub to see what's available? I can show you personas for creative writing, technical analysis, and more. Just say "yes" or use 'browse_collection'.`, }, ], }; } return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}Available Personas (${personaList.length}):\n\n` + personaList.map(p => `${p.active ? '🔹 ' : '▫️ '}**${p.name}** (${p.unique_id})\n` + ` ${p.description}\n` + ` 📁 ${p.category} | 🎭 ${p.author} | 🔖 ${p.price} | ${p.ai_generated ? '🤖 AI' : '👤 Human'}\n` + ` Age: ${p.age_rating} | Version: ${p.version}\n` + ` Triggers: ${p.triggers.join(', ') || 'None'}\n`).join('\n'), }, ], }; } /** * Activate a persona by identifier (filename or name) * Extracted from index.ts:559-592 */ async activatePersona(personaIdentifier) { const validatedIdentifier = MCPInputValidator.validatePersonaIdentifier(personaIdentifier); // FIX: DMCP-SEC-006 - Add security audit logging for persona activation SecurityMonitor.logSecurityEvent({ type: 'ELEMENT_ACTIVATED', severity: 'LOW', source: 'PersonaHandler.activatePersona', details: `Persona activation requested: ${validatedIdentifier}`, additionalData: { personaName: validatedIdentifier } }); let persona = await this.personaManager.find(p => p.filename === validatedIdentifier || p.metadata.name.toLowerCase() === validatedIdentifier.toLowerCase()); if (!persona) { // FIX: Issue #20 - Return error response instead of throwing (using standardized formatter) const response = formatNotFoundError(ElementType.PERSONA, personaIdentifier, 'list_personas'); // Add persona indicator prefix response.content[0].text = `${this.indicatorService.getPersonaIndicator()}${response.content[0].text}`; return response; } this.activePersona.set(persona.filename); return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}Persona Activated: **${persona.metadata.name}**\n\n` + `${persona.metadata.description}\n\n` + `**Instructions:**\n${persona.content}`, }, ], }; } /** * Get currently active persona details * Extracted from index.ts:594-631 */ async getActivePersona() { if (!this.activePersona.get()) { return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}No persona is currently active.`, }, ], }; } const persona = await this.personaManager.find(p => p.filename === this.activePersona.get()); if (!persona) { this.activePersona.set(null); return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}Active persona not found. Deactivated.`, }, ], }; } return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}Active Persona: **${persona.metadata.name}**\n\n` + `${persona.metadata.description}\n\n` + `File: ${persona.filename}\n` + `Version: ${persona.metadata.version || '1.0'}\n` + `Author: ${persona.metadata.author || 'Unknown'}`, }, ], }; } /** * Deactivate the currently active persona * Extracted from index.ts:633-648 */ async deactivatePersona() { const wasActive = this.activePersona.get() !== null; const indicator = this.indicatorService.getPersonaIndicator(); this.activePersona.set(null); return { content: [ { type: "text", text: wasActive ? `${indicator}✅ Persona deactivated. Back to default mode.` : "No persona was active.", }, ], }; } /** * Get detailed information about a specific persona * Extracted from index.ts:650-690 */ async getPersonaDetails(personaIdentifier) { let persona = await this.personaManager.find(p => p.filename === personaIdentifier || p.metadata.name.toLowerCase() === personaIdentifier.toLowerCase() || slugify(p.metadata.name || '') === slugify(personaIdentifier)); if (!persona) { // FIX: Issue #20 - Return error response instead of throwing (using standardized formatter) const response = formatNotFoundError(ElementType.PERSONA, personaIdentifier, 'list_personas'); // Add persona indicator prefix response.content[0].text = `${this.indicatorService.getPersonaIndicator()}${response.content[0].text}`; return response; } return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}📋 **${persona.metadata.name}** Details\n\n` + `**Description:** ${persona.metadata.description}\n` + `**File:** ${persona.filename}\n` + `**Version:** ${persona.metadata.version || '1.0'}\n` + `**Author:** ${persona.metadata.author || 'Unknown'}\n` + `**Triggers:** ${persona.metadata.triggers?.join(', ') || 'None'}\n\n` + `**Full Content:**\n\`\`\`\n${persona.content}\n\`\`\``, }, ], }; } /** * Reload personas from disk * Extracted from index.ts:692-702 */ async reloadPersonas() { await this.personaManager.reload(); const personas = await this.personaManager.list(); return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}🔄 Reloaded ${personas.length} personas`, }, ], }; } /** * Create a new persona * Extracted from index.ts:3753-4029 (277 lines - exact copy) */ async createPersona(name, description, instructions, triggers, metadata) { await this.initService.ensureInitialized(); try { if (!name || !description || !instructions) { return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}❌ **Missing Required Fields**\n\n` + `Please provide all required fields:\n` + `• **name**: Display name for the persona\n` + `• **description**: Brief description of what it does\n` + `• **instructions**: The persona's behavioral guidelines\n\n` + `**Optional:**\n` + `• **triggers**: Comma-separated keywords for activation`, }, ], }; } const sanitizedMetadata = metadata ? sanitizeMetadata(metadata) : undefined; // Use unified create() API (v2 refactor) const newPersona = await this.personaManager.create({ name, description, instructions, triggers: triggers ? triggers.split(',').map(t => t.trim()) : undefined, ...sanitizedMetadata }); // FIX: DMCP-SEC-006 - Add security audit logging for persona creation SecurityMonitor.logSecurityEvent({ type: 'ELEMENT_CREATED', severity: 'LOW', source: 'PersonaHandler.createPersona', details: `Persona created: ${newPersona.metadata.name}`, additionalData: { personaId: newPersona.unique_id } }); return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}✅ **Persona Created Successfully!**\n\n` + `🎭 **${newPersona.metadata.name}** by ${newPersona.metadata.author}\n` + `🆔 Unique ID: ${newPersona.unique_id}\n` + `📄 Saved as: ${newPersona.filename}\n` + `📊 Total personas: ${(await this.personaManager.list()).length}\n\n` + `🎯 **Ready to use:** \`activate_persona "${newPersona.metadata.name}"\`\n` + `📤 **Share it:** \`submit_collection_content "${newPersona.metadata.name}"\`\n` + `✏️ **Edit it:** \`edit_persona "${newPersona.metadata.name}" "field" "new value"\``, }, ], }; } catch (error) { const sanitized = SecureErrorHandler.sanitizeError(error); return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}❌ **Error Creating Persona**\n\n` + `${sanitized.message}\n\n` + `Please check permissions and try again.`, }, ], }; } } /** * Export a persona to base64-encoded JSON * Extracted from index.ts:4635-4670 */ async exportPersona(personaName) { try { const persona = await this.personaManager.find(p => p.filename === personaName || p.metadata.name === personaName); if (!persona) { return { content: [{ type: "text", text: `${this.indicatorService.getPersonaIndicator()}❌ Persona not found: ${personaName}` }] }; } const exportDataStr = await this.personaManager.exportElement(persona); const exportData = JSON.parse(exportDataStr); const base64 = this.personaExporter.toBase64(exportData); const result = this.personaExporter.formatExportResult(persona, base64); return { content: [{ type: "text", text: `${this.indicatorService.getPersonaIndicator()}${result}` }] }; } catch (error) { return { content: [{ type: "text", text: `${this.indicatorService.getPersonaIndicator()}❌ Export failed: ${SecureErrorHandler.sanitizeError(error).message}` }] }; } } /** * Export all personas as a bundle * Extracted from index.ts:4790-4810 */ async exportAllPersonas(includeDefaults = true) { try { const personasArray = await this.personaManager.list(); const bundle = this.personaExporter.exportBundle(personasArray, includeDefaults); const base64 = this.personaExporter.toBase64(bundle); const result = this.personaExporter.formatBundleResult(bundle, base64); return { content: [{ type: "text", text: `${this.indicatorService.getPersonaIndicator()}${result}` }] }; } catch (error) { return { content: [{ type: "text", text: `${this.indicatorService.getPersonaIndicator()}❌ Export failed: ${SecureErrorHandler.sanitizeError(error).message}` }] }; } } /** * Import a persona from file path or JSON string * Extracted from index.ts:4701-4739 */ async importPersona(source, overwrite = false) { try { if (!this.personaImporter) { return { content: [{ type: "text", text: `${this.indicatorService.getPersonaIndicator()}❌ Import functionality not available (initialization in progress)` }] }; } const importResult = await this.personaManager.importPersona(source, overwrite); if (!importResult.success) { return { content: [{ type: "text", text: `${this.indicatorService.getPersonaIndicator()}❌ Import failed: ${importResult.message}` }] }; } const importedPersona = importResult.persona; // After successful import, reload personas to update the cache await this.reloadPersonas(); return { content: [{ type: "text", text: `${this.indicatorService.getPersonaIndicator()}✅ Persona "${importedPersona.metadata.name}" imported successfully.\nTotal personas: ${(await this.personaManager.list()).length}` }] }; } catch (error) { return { content: [{ type: "text", text: `${this.indicatorService.getPersonaIndicator()}❌ Import failed: ${SecureErrorHandler.sanitizeError(error).message}` }] }; } } async editPersona(personaIdentifier, field, value) { if (!personaIdentifier || !field || !value) { return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}❌ **Missing Parameters**\n\n` + `Usage: \`edit_persona "persona_name" "field" "new_value"\`\n\n` + `**Editable fields:**\n` + `• **name** - Display name\n` + `• **description** - Brief description\n` + `• **instructions** - Main persona content\n` + `• **triggers** - Comma-separated keywords\n` + `• **version** - Version number`, }, ], }; } const persona = await this.personaManager.find(p => p.filename === personaIdentifier || p.metadata.name.toLowerCase() === personaIdentifier.toLowerCase() || slugify(p.metadata.name || '') === slugify(personaIdentifier)); if (!persona) { return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}❌ **Persona Not Found**\n\n` + `Could not find persona: "${personaIdentifier}"\n\n` + `Use \`list_personas\` to see available personas.`, }, ], }; } const fieldAliasMap = { content: 'instructions' }; const normalizedField = field.toLowerCase(); const canonicalField = fieldAliasMap[normalizedField] ?? normalizedField; const fieldDisplay = fieldAliasMap[normalizedField] ? `${canonicalField} (alias: ${field})` : field; try { const updatedPersona = await this.personaManager.editExistingPersona(persona, field, value); return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}✅ **Persona Updated Successfully!**\n\n` + `🎭 **${MCPInputValidator.sanitizeForDisplay(updatedPersona.metadata.name || '')}**\n` + `📝 **Field Updated:** ${fieldDisplay}\n` + `🔄 **New Value:** ${canonicalField === 'instructions' ? 'Content updated' : MCPInputValidator.sanitizeForDisplay(value)}\n` + `📊 **Version:** ${updatedPersona.version}\n` + `\n` + `Use \`get_persona_details "${MCPInputValidator.sanitizeForDisplay(updatedPersona.metadata.name || '')}"\` to see all changes.`, }, ], }; } catch (error) { const sanitized = SecureErrorHandler.sanitizeError(error); return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}❌ **Error Updating Persona**\n\n` + `Failed to update persona: ${sanitized.message}\n\n` + `Please check file permissions and try again.`, }, ], }; } } async validatePersona(personaIdentifier) { if (!personaIdentifier) { return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}❌ **Missing Persona Identifier**\n\n` + `Usage: \`validate_persona "persona_name"\`\n\n` + `Use \`list_personas\` to see available personas.`, }, ], }; } const persona = await this.personaManager.find(p => p.filename === personaIdentifier || p.metadata.name.toLowerCase() === personaIdentifier.toLowerCase() || slugify(p.metadata.name || '') === slugify(personaIdentifier)); if (!persona) { return { content: [ { type: "text", text: `${this.indicatorService.getPersonaIndicator()}❌ **Persona Not Found**\n\n` + `Could not find persona: "${personaIdentifier}"\n\n` + `Use \`list_personas\` to see available personas.`, }, ], }; } const indicator = this.indicatorService.getPersonaIndicator(); const validationResult = this.personaManager.validatePersona(personaIdentifier); const issues = validationResult.report.errors ?? []; const warnings = validationResult.report.warnings ?? []; const statusLine = validationResult.success ? '✅ Status: Valid' : '❌ Status: Invalid'; // Generate validation report let report = `${indicator}📋 **Validation Report: ${persona.metadata.name}**\n\n`; report += `${statusLine}\n\n`; if (issues.length === 0 && warnings.length === 0) { report += `✅ **All Checks Passed!**\n\n` + `🎭 **Persona:** ${persona.metadata.name}\n` + `📁 **Category:** ${persona.metadata.category || 'general'}\n` + `📊 **Version:** ${persona.metadata.version || '1.0'}\n` + `📝 **Content Length:** ${persona.content.length} characters\n` + `🔗 **Triggers:** ${persona.metadata.triggers?.length || 0} keywords\n\n` + `This persona meets all validation requirements and is ready for use!`; } else { if (issues.length > 0) { report += `❌ **Issues Found (${issues.length}):**\n`; issues.forEach((issue, i) => { report += ` ${i + 1}. [${issue.field}] ${issue.message}\n`; }); report += '\n'; } if (warnings.length > 0) { report += `⚠️ **Warnings (${warnings.length}):**\n`; warnings.forEach((warning, i) => { report += ` ${i + 1}. [${warning.field}] ${warning.message}\n`; }); report += '\n'; } if (issues.length > 0) { report += `**Recommendation:** Fix the issues above before using this persona.\n`; report += `Use \`edit_persona "${persona.metadata.name}" "field" "value"\` to make corrections.`; } else { report += `**Status:** Persona is functional but could be improved.\n`; report += `Address warnings above for optimal performance.`; } } return { content: [ { type: "text", text: report, }, ], }; } async deletePersona(personaIdentifier) { if (!personaIdentifier) { return { content: [{ type: "text", text: `${this.indicatorService.getPersonaIndicator()}❌ Missing persona identifier` }] }; } const persona = await this.personaManager.find(p => p.filename === personaIdentifier || p.metadata.name.toLowerCase() === personaIdentifier.toLowerCase() || slugify(p.metadata.name || '') === slugify(personaIdentifier)); if (!persona) { return { content: [{ type: "text", text: `❌ Persona '${personaIdentifier}' not found` }] }; } try { const deleteResult = await this.personaManager.deletePersona(persona.filename); if (!deleteResult.success) { return { content: [{ type: "text", text: `❌ ${deleteResult.message}` }] }; } if (this.activePersona.get() === persona.filename) { this.activePersona.set(null); } return { content: [{ type: "text", text: `✅ Successfully deleted persona '${personaIdentifier}'` }] }; } catch (error) { if (error.code === 'ENOENT') { return { content: [{ type: "text", text: `❌ Persona '${personaIdentifier}' not found` }] }; } throw error; } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVyc29uYUhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaGFuZGxlcnMvUGVyc29uYUhhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBR0gsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDakUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDbEUsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBSWpELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzdELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNqRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUMxRSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFFL0Q7O0dBRUc7QUFDSCxNQUFNLE9BQU8sY0FBYztJQUVOO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQU5uQixZQUNtQixjQUE4QixFQUM5QixlQUFnQyxFQUNoQyxlQUE0QyxFQUM1QyxXQUFrQyxFQUNsQyxnQkFBeUMsRUFDekMsYUFHaEI7UUFSZ0IsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBQzlCLG9CQUFlLEdBQWYsZUFBZSxDQUFpQjtRQUNoQyxvQkFBZSxHQUFmLGVBQWUsQ0FBNkI7UUFDNUMsZ0JBQVcsR0FBWCxXQUFXLENBQXVCO1FBQ2xDLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBeUI7UUFDekMsa0JBQWEsR0FBYixhQUFhLENBRzdCO0lBQ0EsQ0FBQztJQUVKOzs7T0FHRztJQUNILEtBQUssQ0FBQyxZQUFZO1FBQ2hCLE1BQU0sV0FBVyxHQUFHLENBQUMsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLE9B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T0FBTyxFQUFFLENBQUM7Z0JBQzFCLE9BQU87b0JBQ0wsT0FBTyxFQUFFLENBQUM7NEJBQ1IsSUFBSSxFQUFFLE1BQU07NEJBQ1osSUFBSSxFQUFFLEtBQUssWUFBWSxDQUFDLE9BQU8sRUFBRTt5QkFDbEMsQ0FBQztpQkFDSCxDQUFDO1lBQ0osQ0FBQztZQUVELElBQUksSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLEVBQUUsS0FBSyxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ2xELElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQy9CLENBQUM7WUFFRCxPQUFPO2dCQUNMLE9BQU8sRUFBRSxDQUFDO3dCQUNSLElBQUksRUFBRSxNQUFNO3dCQUNaLElBQUksRUFBRSxtQ0FBbUMsaUJBQWlCLEdBQUc7cUJBQzlELENBQUM7YUFDSCxDQUFDO1FBQ0osQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFLLEtBQStCLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUN2RCxPQUFPO29CQUNMLE9BQU8sRUFBRSxDQUFDOzRCQUNSLElBQUksRUFBRSxNQUFNOzRCQUNaLElBQUksRUFBRSxjQUFjLGlCQUFpQixhQUFhO3lCQUNuRCxDQUFDO2lCQUNILENBQUM7WUFDSixDQUFDO1lBQ0QsTUFBTSxLQUFLLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBQZXJzb25hSGFuZGxlciAtIEhhbmRsZXMgYWxsIHBlcnNvbmEtcmVsYXRlZCBNQ1AgdG9vbCBvcGVyYXRpb25zXG4gKlxuICogUHJvdmlkZXMgdGhlIGludGVyZmFjZSBmb3IgYWN0aXZhdGluZywgZGVhY3RpdmF0aW5nLCBsaXN0aW5nLCBleHBvcnRpbmcsXG4gKiBhbmQgaW1wb3J0aW5nIHBlcnNvbmFzIHRocm91Z2ggTUNQIHRvb2xzLlxuICpcbiAqIFVzZXMgZGVwZW5kZW5jeSBpbmplY3Rpb24gZm9yIGFsbCBzZXJ2aWNlczpcbiAqIC0gUGVyc29uYU1hbmFnZXIgZm9yIHBlcnNvbmEgc3RhdGUgYW5kIG9wZXJhdGlvbnNcbiAqIC0gSW5pdGlhbGl6YXRpb25TZXJ2aWNlIGZvciBzZXR1cCB0YXNrc1xuICogLSBQZXJzb25hSW5kaWNhdG9yU2VydmljZSBmb3IgcGVyc29uYSBpbmRpY2F0b3IgZm9ybWF0dGluZ1xuICpcbiAqIEZJWDogRE1DUC1TRUMtMDA2IC0gU2VjdXJpdHkgYXVkaXQgc3VwcHJlc3Npb25cbiAqIFRoaXMgaGFuZGxlciBkZWxlZ2F0ZXMgYWxsIG9wZXJhdGlvbnMgdG8gUGVyc29uYU1hbmFnZXIuXG4gKiBBdWRpdCBsb2dnaW5nIGhhcHBlbnMgaW4gUGVyc29uYU1hbmFnZXIgZm9yIENSVUQgb3BlcmF0aW9ucy5cbiAqIEBzZWN1cml0eS1hdWRpdC1zdXBwcmVzcyBETUNQLVNFQy0wMDZcbiAqL1xuXG5pbXBvcnQgeyBQZXJzb25hRXhwb3J0ZXIsIFBlcnNvbmFJbXBvcnRlciB9IGZyb20gJy4uL3BlcnNvbmEvZXhwb3J0LWltcG9ydC9pbmRleC5qcyc7XG5pbXBvcnQgeyBTZWN1cmVFcnJvckhhbmRsZXIgfSBmcm9tICcuLi9zZWN1cml