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.

494 lines 85.6 kB
/** * Permission evaluation HTTP routes and decision tracking. * * Provides: * - POST /evaluate_permission — evaluates tool permissions via MCP-AQL * - GET /permissions/status — returns current policies and recent decisions * - Decision tracking ring buffer for the live dashboard feed */ import express from 'express'; import { homedir } from 'node:os'; import { logger } from '../../utils/logger.js'; import { formatPermissionResponse } from '../../handlers/mcp-aql/evaluatePermission.js'; import { ensureLatestPortFile } from '../portDiscovery.js'; import { getLastPermissionHookStartupRepairSummary, getPermissionHookDiagnosticsPath, getPermissionHookStatusAsync, readLastPermissionHookDiagnostic, reconcilePermissionHookStatus, summarizePermissionHookHealth, } from '../../utils/permissionHooks.js'; import { SlidingWindowRateLimiter } from '../../utils/SlidingWindowRateLimiter.js'; import { PERMISSION_AUTHORITY_HOSTS, PERMISSION_AUTHORITY_MODES, readPermissionAuthorityState, setPermissionAuthorityMode, } from '../../utils/permissionAuthority.js'; const PERMISSION_ROUTE_RATE_LIMIT_REQUESTS = 120; const PERMISSION_ROUTE_RATE_LIMIT_WINDOW_MS = 60_000; const DECISION_BUFFER_SIZE = 200; const CLAUDE_COMPATIBLE_HOOK_PLATFORMS = new Set(['claude_code', 'vscode']); const NORMALIZABLE_PERMISSION_DECISIONS = new Set(['allow', 'deny', 'ask']); const CONTEXT_DETAIL_FIELDS = [ { key: 'session_id', label: 'Session', monospace: true }, { key: 'turn_id', label: 'Turn', monospace: true }, { key: 'tool_use_id', label: 'Tool Use', monospace: true }, { key: 'transcript_path', label: 'Transcript', monospace: true }, { key: 'cwd', label: 'Workspace', monospace: true }, { key: 'model', label: 'Model', monospace: true }, ]; /** Extract a string field from a record, trying multiple keys in order */ function extractString(obj, keys, fallback) { for (const key of keys) { const val = obj?.[key]; if (typeof val === 'string') return val; } return fallback; } function isEmptyObject(value) { return Object.keys(value).length === 0; } function extractDecision(result, platform) { const nested = result.hookSpecificOutput; if (nested && typeof nested === 'object' && !Array.isArray(nested)) { const nestedDecision = nested.permissionDecision; if (typeof nestedDecision === 'string') return nestedDecision; } if (typeof result.permission === 'string') return result.permission; if (typeof result.decision === 'string') return result.decision; if (typeof result.behavior === 'string') return result.behavior; if (typeof result.allowed === 'boolean') return result.allowed ? 'allow' : 'deny'; if (platform === 'codex' && isEmptyObject(result)) return 'allow'; return 'unknown'; } function normalizeOptionalRequestString(value) { if (typeof value !== 'string') return undefined; const normalized = value.normalize('NFC'); return normalized === '' ? undefined : normalized; } function extractReason(result) { const nested = result.hookSpecificOutput; if (nested && typeof nested === 'object' && !Array.isArray(nested)) { const nestedReason = nested.permissionDecisionReason; if (typeof nestedReason === 'string') return nestedReason; } return extractString(result, ['reason', 'message'], ''); } function shouldNormalizeClaudeHook(platform) { return platform !== undefined && CLAUDE_COMPATIBLE_HOOK_PLATFORMS.has(platform); } function normalizePermissionResponseForPlatform(platform, input, result) { if (!shouldNormalizeClaudeHook(platform)) { return result; } const nested = result.hookSpecificOutput; if (nested && typeof nested === 'object' && !Array.isArray(nested)) { const nestedDecision = nested.permissionDecision; if (typeof nestedDecision === 'string') { return result; } } const decision = extractDecision(result); if (NORMALIZABLE_PERMISSION_DECISIONS.has(decision)) { return formatPermissionResponse(decision, platform, input, extractReason(result)); } return formatPermissionResponse('allow', platform, input); } function buildDecisionDetails(toolName, input, result, platform, context) { const details = []; if (platform) { details.push({ label: 'Platform', value: platform, monospace: true }); } if (toolName === 'Bash' && typeof input.command === 'string' && input.command !== '') { details.push({ label: 'Command', value: input.command, monospace: true }); } for (const descriptor of CONTEXT_DETAIL_FIELDS) { const value = context[descriptor.key]; if (typeof value === 'string') { details.push({ label: descriptor.label, value, monospace: descriptor.monospace }); } } const targetDescriptors = [ { key: 'file_path', label: 'File', monospace: true }, { key: 'path', label: 'Path', monospace: true }, { key: 'url', label: 'URL' }, { key: 'pattern', label: 'Pattern', monospace: true }, { key: 'query', label: 'Query' }, { key: 'element_name', label: 'Element', monospace: true }, { key: 'request_id', label: 'Request', monospace: true }, ]; let target; let targetLabel; for (const descriptor of targetDescriptors) { const value = input[descriptor.key]; if (typeof value !== 'string' || value === '') { continue; } target = value; targetLabel = descriptor.label; details.push({ label: descriptor.label, value, monospace: descriptor.monospace }); break; } const matchedPattern = extractString(result, ['matched_pattern', 'matchedPattern'], ''); if (matchedPattern !== '') { details.push({ label: 'Matched Pattern', value: matchedPattern, monospace: true }); } const policySource = extractString(result, ['policy_source', 'policySource'], ''); if (policySource !== '') { details.push({ label: 'Policy Source', value: policySource, monospace: true }); } return { target, targetLabel, details }; } function createPermissionDecisionTracker(bufferSize = DECISION_BUFFER_SIZE) { const recentDecisions = []; let decisionCounter = 0; return { trackDecision(context, toolName, input, result, platform) { const detailState = buildDecisionDetails(toolName, input, result, platform, context); const entry = { id: `d-${++decisionCounter}`, timestamp: new Date().toISOString(), ...(context.session_id ? { session_id: context.session_id } : {}), ...(context.turn_id ? { turn_id: context.turn_id } : {}), ...(context.tool_use_id ? { tool_use_id: context.tool_use_id } : {}), ...(context.transcript_path ? { transcript_path: context.transcript_path } : {}), ...(context.cwd ? { cwd: context.cwd } : {}), ...(context.model ? { model: context.model } : {}), tool_name: toolName, command: toolName === 'Bash' && typeof input?.command === 'string' ? input.command : undefined, decision: extractDecision(result, platform), reason: extractReason(result), platform, target: detailState.target, targetLabel: detailState.targetLabel, details: detailState.details, }; recentDecisions.unshift(entry); if (recentDecisions.length > bufferSize) { recentDecisions.length = bufferSize; } }, getRecentDecisions() { return recentDecisions; }, }; } function mergeRuleArrays(...sources) { const merged = new Set(); for (const source of sources) { if (!Array.isArray(source)) continue; for (const entry of source) { if (typeof entry === 'string' && entry !== '') { merged.add(entry); } } } return Array.from(merged); } function normalizePolicyElements(elements) { return elements.map((element) => ({ ...element, element_name: resolveElementName(element), allowRules: mergeRuleArrays(element.allowPatterns, element.allowOperations), confirmRules: mergeRuleArrays(element.confirmPatterns, element.confirmOperations), denyRules: mergeRuleArrays(element.denyPatterns, element.denyOperations), invalidGatekeeperPolicy: !!element.invalidGatekeeperPolicy, invalidGatekeeperMessage: typeof element.invalidGatekeeperMessage === 'string' ? element.invalidGatekeeperMessage : undefined, })); } function resolveElementName(element) { if (typeof element.element_name === 'string') return element.element_name; if (typeof element.name === 'string') return element.name; return ''; } /** Helper to extract single result from MCP-AQL batch response */ function asSingleResult(results) { if (Array.isArray(results)) return results[0] || { success: false, error: 'Empty result' }; return results; } function extractKnownPolicySessions(elements) { const seen = new Set(); const knownSessions = []; for (const element of elements) { const sessionIds = Array.isArray(element.sessionIds) ? element.sessionIds : []; for (const sessionId of sessionIds) { if (typeof sessionId !== 'string' || sessionId === '' || seen.has(sessionId)) { continue; } seen.add(sessionId); knownSessions.push({ sessionId, displayName: sessionId, source: 'policy', }); } } return knownSessions.sort((a, b) => a.sessionId.localeCompare(b.sessionId)); } async function selfHealLatestPermissionPortFile(port) { if (typeof port !== 'number' || !Number.isInteger(port) || port <= 0) { return; } try { await ensureLatestPortFile(port); } catch (err) { logger.debug('[WebUI/Gateway] Could not refresh permission-server.port', { error: err instanceof Error ? err.message : String(err), port, }); } } async function resolveInstalledPermissionAuthorityHosts(homeDir, authorityState, autoRepairHookAssets) { const installedStatuses = await Promise.all(PERMISSION_AUTHORITY_HOSTS.map(async (host) => ({ host, status: await reconcilePermissionHookStatus(host, { homeDir, autoRepair: autoRepairHookAssets }), }))); const installedHosts = installedStatuses .filter(({ status }) => status.installed) .map(({ host }) => host); const persistedHosts = Object.keys(authorityState.hosts || {}).filter((host) => PERMISSION_AUTHORITY_HOSTS.includes(host)); return Array.from(new Set(installedHosts.concat(persistedHosts))); } export function registerPermissionRoutes(router, handler, options = {}) { const authorityHomeDir = options.homeDir ?? homedir(); const autoRepairHookAssets = options.autoRepairHookAssets ?? process.env.NODE_ENV !== 'test'; const decisionTracker = createPermissionDecisionTracker(); /** * POST /api/evaluate_permission * Permission evaluation endpoint for PreToolUse hooks. * Routes through evaluate_permission MCP-AQL READ operation. * Fail-open: returns allow on any error to avoid blocking the user. */ const permissionLimiter = new SlidingWindowRateLimiter(PERMISSION_ROUTE_RATE_LIMIT_REQUESTS, PERMISSION_ROUTE_RATE_LIMIT_WINDOW_MS); router.post('/evaluate_permission', express.json(), async (req, res) => { await selfHealLatestPermissionPortFile(req.socket.localPort); const body = req.body; const platform = typeof body.platform === 'string' ? body.platform.normalize('NFC') : 'claude_code'; if (!permissionLimiter.tryAcquire()) { res.json(formatPermissionResponse('allow', platform, {})); // fail open on rate limit return; } // Unicode normalization (NFC) on string inputs to prevent homograph attacks const tool_name = typeof body.tool_name === 'string' ? body.tool_name.normalize('NFC') : undefined; const context = { session_id: normalizeOptionalRequestString(body.session_id), turn_id: normalizeOptionalRequestString(body.turn_id), tool_use_id: normalizeOptionalRequestString(body.tool_use_id), transcript_path: normalizeOptionalRequestString(body.transcript_path), cwd: normalizeOptionalRequestString(body.cwd), model: normalizeOptionalRequestString(body.model), }; const input = body.input; if (!tool_name) { res.json(formatPermissionResponse('allow', platform, input || {})); // fail open on bad input return; } const startMs = Date.now(); try { const opResult = asSingleResult(await handler.handleRead({ operation: 'evaluate_permission', params: { tool_name, input: input || {}, platform, ...(context.session_id ? { session_id: context.session_id } : {}), }, })); const elapsedMs = Date.now() - startMs; if (!opResult.success) { logger.warn(`[WebUI/Gateway] evaluate_permission failed (${elapsedMs}ms): ${opResult.error}`); res.json(formatPermissionResponse('allow', platform, input || {})); // fail open return; } const rawResult = opResult.data; const responseData = normalizePermissionResponseForPlatform(platform, input || {}, rawResult); const trackedResult = { ...rawResult, ...responseData }; const decision = extractDecision(trackedResult, platform); logger.debug(`[WebUI/Gateway] evaluate_permission: ${tool_name} → ${decision} (${elapsedMs}ms)`); // Track decision for live dashboard feed decisionTracker.trackDecision(context, tool_name, input || {}, trackedResult, platform); res.json(responseData); } catch (err) { const elapsedMs = Date.now() - startMs; logger.error(`[WebUI/Gateway] evaluate_permission error (${elapsedMs}ms):`, err); res.json(formatPermissionResponse('allow', platform, input || {})); // fail open } }); /** * GET /api/permissions/status * Returns current permission policies and recent decisions * for the live permissions dashboard. */ router.get('/permissions/status', async (req, res) => { try { await selfHealLatestPermissionPortFile(req.socket.localPort); const sessionId = typeof req.query['sessionId'] === 'string' && req.query['sessionId'] ? req.query['sessionId'] : undefined; const opResult = asSingleResult(await handler.handleRead({ operation: 'get_effective_cli_policies', params: { reporting_scope: 'dashboard', ...(sessionId ? { session_id: sessionId } : {}), }, })); if (!opResult.success) { res.status(500).json({ error: opResult.error || 'Failed to get policies' }); return; } const data = opResult.data; const authorityState = await readPermissionAuthorityState(authorityHomeDir); const installedAuthorityHosts = await resolveInstalledPermissionAuthorityHosts(authorityHomeDir, authorityState, autoRepairHookAssets); const hookHost = typeof data.hookHost === 'string' ? data.hookHost : undefined; const hookStatus = hookHost ? await reconcilePermissionHookStatus(hookHost, { homeDir: authorityHomeDir, autoRepair: autoRepairHookAssets }) : await getPermissionHookStatusAsync(authorityHomeDir); const elements = normalizePolicyElements((data.elements || [])); const denyPatterns = data.combinedDenyPatterns ?? []; const allowPatterns = data.combinedAllowPatterns ?? []; const confirmPatterns = data.combinedConfirmPatterns ?? []; const denyOperations = data.combinedDenyOperations ?? []; const allowOperations = data.combinedAllowOperations ?? []; const confirmOperations = data.combinedConfirmOperations ?? []; const hookStartupRepair = getLastPermissionHookStartupRepairSummary(); const hookDiagnosticsPath = getPermissionHookDiagnosticsPath(authorityHomeDir); const hookLastDiagnostic = await readLastPermissionHookDiagnostic(authorityHomeDir); const hookHealthHost = hookStatus.host ?? hookHost ?? 'managed-host'; const hookHealth = summarizePermissionHookHealth({ installedHosts: hookStatus.installed || hookStatus.assetsPrepared ? [hookHealthHost] : [], currentHosts: hookStatus.assetsCurrent ? [hookHealthHost] : [], repairedHosts: hookStatus.autoRepaired ? [hookHealthHost] : [], needsRepairHosts: hookStatus.needsRepair ? [hookHealthHost] : [], diagnosticsPath: hookDiagnosticsPath, lastDiagnostic: hookLastDiagnostic, lastStartupRepair: hookStartupRepair, }); res.json({ ...(sessionId ? { sessionId } : {}), activeElementCount: data.activeElementCount, hasAllowlist: data.hasAllowlist, denyPatterns, allowPatterns, confirmPatterns, denyOperations, allowOperations, confirmOperations, denyRules: mergeRuleArrays(denyPatterns, denyOperations), allowRules: mergeRuleArrays(allowPatterns, allowOperations), confirmRules: mergeRuleArrays(confirmPatterns, confirmOperations), elements, knownSessions: extractKnownPolicySessions(elements), permissionPromptActive: data.permissionPromptActive, hookInstalled: hookStatus.installed, hookHost: data.hookHost, hookAssetsPrepared: hookStatus.assetsPrepared, hookAssetsCurrent: hookStatus.assetsCurrent, hookAutoRepaired: hookStatus.autoRepaired, hookNeedsRepair: hookStatus.needsRepair, hookRepairError: hookStatus.repairError, hookHealth, hookStartupRepair, hookDiagnostics: { logPath: hookDiagnosticsPath, lastEvent: hookLastDiagnostic, }, authority: authorityState, authoritySupportedHosts: installedAuthorityHosts, authoritySupportedModes: [...PERMISSION_AUTHORITY_MODES], authorityAiMutable: false, enforcementReady: data.enforcementReady, invalidPolicyElementCount: data.invalidPolicyElementCount ?? 0, advisory: data.advisory, recentDecisions: decisionTracker.getRecentDecisions(), }); } catch (err) { logger.error('[WebUI/Gateway] permissions/status error:', err); res.status(500).json({ error: 'Failed to get permission status' }); } }); router.get('/permissions/authority', async (_req, res) => { try { const authorityState = await readPermissionAuthorityState(authorityHomeDir); const installedAuthorityHosts = await resolveInstalledPermissionAuthorityHosts(authorityHomeDir, authorityState, autoRepairHookAssets); res.json({ ...authorityState, supportedHosts: installedAuthorityHosts, supportedModes: [...PERMISSION_AUTHORITY_MODES], aiMutable: false, }); } catch (err) { logger.error('[WebUI/Gateway] permissions/authority error:', err); res.status(500).json({ error: 'Failed to get permission authority' }); } }); router.post('/permissions/authority', express.json(), async (req, res) => { try { const host = normalizeAuthorityHost(req.body?.host); const mode = normalizeAuthorityMode(req.body?.mode); const reason = typeof req.body?.reason === 'string' && req.body.reason.trim() !== '' ? req.body.reason.trim() : undefined; if (!host || !mode) { res.status(400).json({ error: 'host and mode are required', supportedHosts: [...PERMISSION_AUTHORITY_HOSTS], supportedModes: [...PERMISSION_AUTHORITY_MODES], }); return; } let policies; if (mode === 'authoritative') { const policyResult = asSingleResult(await handler.handleRead({ operation: 'get_effective_cli_policies', params: { reporting_scope: 'dashboard' }, })); if (!policyResult.success) { res.status(500).json({ error: policyResult.error || 'Failed to fetch effective policies' }); return; } policies = policyResult.data; } const authorityState = await setPermissionAuthorityMode({ host, mode, reason, homeDir: authorityHomeDir, policies: mode === 'authoritative' ? { combinedAllowPatterns: asStringArray(policies?.combinedAllowPatterns), combinedConfirmPatterns: asStringArray(policies?.combinedConfirmPatterns), combinedDenyPatterns: asStringArray(policies?.combinedDenyPatterns), } : undefined, }); res.json({ success: true, authority: authorityState }); } catch (err) { logger.error(`[WebUI/Gateway] permissions/authority update error (host=${String(req.body?.host ?? '')}, mode=${String(req.body?.mode ?? '')}):`, err); res.status(500).json({ error: err instanceof Error ? err.message : 'Failed to update permission authority', }); } }); } function normalizeAuthorityHost(value) { return typeof value === 'string' && PERMISSION_AUTHORITY_HOSTS.includes(value) ? value : null; } function normalizeAuthorityMode(value) { return typeof value === 'string' && PERMISSION_AUTHORITY_MODES.includes(value) ? value : null; } function asStringArray(value) { return Array.isArray(value) ? value.filter((entry) => typeof entry === 'string') : []; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVybWlzc2lvblJvdXRlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy93ZWIvcm91dGVzL3Blcm1pc3Npb25Sb3V0ZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7R0FPRztBQUVILE9BQU8sT0FBbUIsTUFBTSxTQUFTLENBQUM7QUFDMUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNsQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFFL0MsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sOENBQThDLENBQUM7QUFDeEYsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDM0QsT0FBTyxFQUNMLHlDQUF5QyxFQUN6QyxnQ0FBZ0MsRUFDaEMsNEJBQTRCLEVBQzVCLGdDQUFnQyxFQUNoQyw2QkFBNkIsRUFDN0IsNkJBQTZCLEdBQzlCLE1BQU0sZ0NBQWdDLENBQUM7QUFFeEMsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDbkYsT0FBTyxFQUdMLDBCQUEwQixFQUMxQiwwQkFBMEIsRUFDMUIsNEJBQTRCLEVBQzVCLDBCQUEwQixHQUMzQixNQUFNLG9DQUFvQyxDQUFDO0FBdUU1QyxNQUFNLG9DQUFvQyxHQUFHLEdBQUcsQ0FBQztBQUNqRCxNQUFNLHFDQUFxQyxHQUFHLE1BQU0sQ0FBQztBQUNyRCxNQUFNLG9CQUFvQixHQUFHLEdBQUcsQ0FBQztBQWFqQyxNQUFNLGdDQUFnQyxHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsYUFBYSxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUM7QUFDNUUsTUFBTSxpQ0FBaUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztBQUU1RSxNQUFNLHFCQUFxQixHQUl0QjtJQUNILEVBQUUsR0FBRyxFQUFF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LFFBQVEsRUFBRSx1QkFBdUIsQ0FBQzt3QkFDekUsb0JBQW9CLEVBQUUsYUFBYSxDQUFDLFFBQVEsRUFBRSxvQkFBb0IsQ0FBQztxQkFDcEU7b0JBQ0QsQ0FBQyxDQUFDLFNBQVM7YUFDZCxDQUFDLENBQUM7WUFFSCxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsY0FBYyxFQUFFLENBQUMsQ0FBQztRQUN6RCxDQUFDO1FBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztZQUNiLE1BQU0sQ0FBQyxLQUFLLENBQ1YsNERBQTRELE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsVUFBVSxNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDLElBQUksRUFDbEksR0FBRyxDQUNKLENBQUM7WUFDRixHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztnQkFDbkIsS0FBSyxFQUFFLEdBQUcsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLHVDQUF1QzthQUNwRixDQUFDLENBQUM7UUFDTCxDQUFDO0lBQ0gsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBUyxzQkFBc0IsQ0FBQyxLQUFjO0lBQzVDLE9BQU8sT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLDBCQUEwQixDQUFDLFFBQVEsQ0FBQyxLQUFnQyxDQUFDO1FBQ3ZHLENBQUMsQ0FBQyxLQUFnQztRQUNsQyxDQUFDLENBQUMsSUFBSSxDQUFDO0FBQ1gsQ0FBQztBQUVELFNBQVMsc0JBQXNCLENBQUMsS0FBYztJQUM1QyxPQUFPLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSwwQkFBMEIsQ0FBQyxRQUFRLENBQUMsS0FBZ0MsQ0FBQztRQUN2RyxDQUFDLENBQUMsS0FBZ0M7UUFDbEMsQ0FBQyxDQUFDLElBQUksQ0FBQztBQUNYLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBQyxLQUFjO0lBQ25DLE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBbUIsRUFBRSxDQUFDLE9BQU8sS0FBSyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7QUFDekcsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuI