bashstats 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/constants.ts","../src/db/database.ts","../src/installer/installer.ts","../src/installer/gemini.ts","../src/installer/copilot.ts","../src/installer/opencode.ts","../src/db/writer.ts","../src/hooks/handler.ts","../src/hooks/transcript.ts","../src/hooks/normalizers/gemini.ts","../src/hooks/normalizers/copilot.ts","../src/stats/engine.ts","../src/types.ts","../src/achievements/compute.ts"],"sourcesContent":["import type { BadgeDefinition } from './types.js'\nimport type { WeeklyChallenge, RankTierBracket } from './types.js'\n\nexport const BADGE_DEFINITIONS: BadgeDefinition[] = [\n // ===================================================================\n // VOLUME (5)\n // ===================================================================\n { id: 'first_prompt', name: 'First Prompt', icon: '\\u{1F4AC}', description: 'Submit prompts to Claude', category: 'volume', stat: 'totalPrompts', tiers: [1, 250, 2500, 10000, 50000], trigger: 'Total prompts submitted across all sessions' },\n { id: 'tool_time', name: 'Tool Time', icon: '\\u{1F527}', description: 'Make tool calls', category: 'volume', stat: 'totalToolCalls', tiers: [50, 2500, 25000, 100000, 500000], trigger: 'Total tool calls made across all sessions' },\n { id: 'marathon', name: 'Marathon', icon: '\\u{1F3C3}', description: 'Spend hours in sessions', category: 'volume', stat: 'totalSessionHours', tiers: [1, 25, 250, 1000, 5000], trigger: 'Total hours spent in sessions (rounded down)' },\n { id: 'wordsmith', name: 'Wordsmith', icon: '\\u{270D}', description: 'Type characters in prompts', category: 'volume', stat: 'totalCharsTyped', tiers: [1000, 100000, 1000000, 5000000, 25000000], trigger: 'Total characters typed in prompts' },\n { id: 'session_vet', name: 'Session Vet', icon: '\\u{1F3C5}', description: 'Complete sessions', category: 'volume', stat: 'totalSessions', tiers: [1, 50, 500, 2500, 10000], trigger: 'Total sessions completed' },\n\n // ===================================================================\n // TOOL MASTERY (7)\n // ===================================================================\n { id: 'shell_lord', name: 'Shell Lord', icon: '\\u{1F4BB}', description: 'Execute Bash commands', category: 'tool_mastery', stat: 'totalBashCommands', tiers: [25, 250, 2500, 10000, 50000], trigger: 'Bash commands executed via PostToolUse' },\n { id: 'bookworm', name: 'Bookworm', icon: '\\u{1F4D6}', description: 'Read files', category: 'tool_mastery', stat: 'totalFilesRead', tiers: [50, 500, 5000, 25000, 100000], trigger: 'Files read with the Read tool' },\n { id: 'editor_in_chief', name: 'Editor-in-Chief', icon: '\\u{1F4DD}', description: 'Edit files', category: 'tool_mastery', stat: 'totalFilesEdited', tiers: [25, 250, 2500, 10000, 50000], trigger: 'Files edited with the Edit tool' },\n { id: 'architect', name: 'Architect', icon: '\\u{1F3D7}', description: 'Create files', category: 'tool_mastery', stat: 'totalFilesCreated', tiers: [10, 100, 500, 2500, 10000], trigger: 'Files created with the Write tool' },\n { id: 'detective', name: 'Detective', icon: '\\u{1F50D}', description: 'Search with Grep and Glob', category: 'tool_mastery', stat: 'totalSearches', tiers: [50, 500, 5000, 25000, 100000], trigger: 'Grep and Glob searches performed' },\n { id: 'web_crawler', name: 'Web Crawler', icon: '\\u{1F310}', description: 'Fetch web pages', category: 'tool_mastery', stat: 'totalWebFetches', tiers: [5, 50, 200, 1000, 5000], trigger: 'WebFetch calls made' },\n { id: 'delegator', name: 'Delegator', icon: '\\u{1F916}', description: 'Spawn subagents', category: 'tool_mastery', stat: 'totalSubagents', tiers: [10, 100, 500, 2500, 10000], trigger: 'Subagents spawned via SubagentStart events' },\n\n // ===================================================================\n // TIME & PATTERNS (10)\n // ===================================================================\n { id: 'iron_streak', name: 'Iron Streak', icon: '\\u{1F525}', description: 'Maintain a daily streak', category: 'time', stat: 'longestStreak', tiers: [3, 7, 30, 100, 365], trigger: 'Longest streak of consecutive days with activity' },\n { id: 'night_owl', name: 'Night Owl', icon: '\\u{1F989}', description: 'Prompts between midnight and 5am', category: 'time', stat: 'nightOwlCount', tiers: [10, 50, 200, 1000, 5000], trigger: 'Prompts submitted between midnight and 5 AM' },\n { id: 'early_bird', name: 'Early Bird', icon: '\\u{1F426}', description: 'Prompts between 5am and 8am', category: 'time', stat: 'earlyBirdCount', tiers: [10, 50, 200, 1000, 5000], trigger: 'Prompts submitted between 5 AM and 8 AM' },\n { id: 'weekend_warrior', name: 'Weekend Warrior', icon: '\\u{2694}', description: 'Weekend sessions', category: 'time', stat: 'weekendSessions', tiers: [5, 25, 100, 500, 2000], trigger: 'Sessions started on Saturday or Sunday' },\n { id: 'witching_hour', name: 'Witching Hour', icon: '\\u{1F9D9}', description: '3 AM hits different when you\\'re debugging.', category: 'time', stat: 'witchingHourPrompts', tiers: [1, 10, 50, 200, 1000], trigger: 'Prompts submitted between 2 AM and 4 AM' },\n { id: 'lunch_break_coder', name: 'Lunch Break Coder', icon: '\\u{1F354}', description: 'Who needs food when you have Claude?', category: 'time', stat: 'lunchBreakDays', tiers: [5, 15, 30, 60, 120], trigger: 'Distinct days with sessions during 12-1 PM' },\n { id: 'monday_motivation', name: 'Monday Motivation', icon: '\\u{1F4AA}', description: 'Starting the week strong (or desperate).', category: 'time', stat: 'mondaySessions', tiers: [5, 25, 75, 200, 500], trigger: 'Sessions started on Monday' },\n { id: 'friday_shipper', name: 'Friday Shipper', icon: '\\u{1F6A2}', description: 'Deploy on Friday? You absolute madlad.', category: 'time', stat: 'fridayCommits', tiers: [1, 10, 50, 200, 1000], trigger: 'Git commits made on Friday (via Bash tool)' },\n { id: 'timezone_traveler', name: 'Timezone Traveler', icon: '\\u{2708}', description: 'Your sleep schedule is a suggestion.', category: 'time', stat: 'maxUniqueHoursInDay', tiers: [6, 8, 12, 16, 20], trigger: 'Most unique hours with prompts in a single day' },\n { id: 'seasonal_coder', name: 'Seasonal Coder', icon: '\\u{1F343}', description: \"You've coded through all four seasons.\", category: 'time', stat: 'uniqueQuarters', tiers: [1, 2, 4, 6, 8], trigger: 'Unique quarter-year combos (e.g. Q1-2025, Q2-2025) with activity' },\n\n // ===================================================================\n // SESSION BEHAVIOR (6)\n // ===================================================================\n { id: 'one_more_thing', name: 'One More Thing', icon: '\\u{261D}', description: 'You said you were done 5 prompts ago.', category: 'session_behavior', stat: 'extendedSessionCount', tiers: [1, 5, 25, 100, 500], trigger: 'Sessions over 1 hour with 15+ prompts' },\n { id: 'quick_draw', name: 'Quick Draw', icon: '\\u{1F52B}', description: 'In and out. 20 second adventure.', category: 'session_behavior', stat: 'quickDrawSessions', tiers: [5, 25, 100, 500, 2500], trigger: 'Sessions under 2 minutes with successful tool use' },\n { id: 'the_pivot', name: 'The Pivot', icon: '\\u{1F504}', description: 'Started with CSS, ended with Kubernetes.', category: 'session_behavior', stat: 'diverseToolSessions', tiers: [5, 25, 100, 500, 2500], trigger: 'Sessions using 5+ distinct tool types' },\n { id: 'context_crunch', name: 'Context Crunch', icon: '\\u{1F4A6}', description: 'Your context window is sweating.', category: 'session_behavior', stat: 'totalCompactions', tiers: [1, 5, 25, 100, 500], trigger: 'PreCompact events triggered (manual or auto)' },\n { id: 'permission_slip', name: 'Permission Slip', icon: '\\u{1F4DD}', description: 'Always asking for permission. So polite.', category: 'session_behavior', stat: 'permissionRequests', tiers: [10, 100, 500, 2500, 10000], trigger: 'PermissionRequest events recorded' },\n { id: 'the_returner', name: 'The Returner', icon: '\\u{1F519}', description: 'Back so soon? Missed me?', category: 'session_behavior', stat: 'returnerDays', tiers: [1, 5, 25, 100, 500], trigger: 'Days with 5+ sessions on the same project' },\n\n // ===================================================================\n // BEHAVIORAL (5)\n // ===================================================================\n { id: 'creature_of_habit', name: 'Creature of Habit', icon: '\\u{1F501}', description: 'Repeat your most-used prompt', category: 'behavioral', stat: 'mostRepeatedPromptCount', tiers: [25, 100, 500, 2000, 10000], trigger: 'Count of your single most repeated prompt' },\n { id: 'explorer', name: 'Explorer', icon: '\\u{1F9ED}', description: 'Use unique tool types', category: 'behavioral', stat: 'uniqueToolsUsed', tiers: [3, 5, 8, 12, 18], trigger: 'Distinct tool types used across all sessions' },\n { id: 'planner', name: 'Planner', icon: '\\u{1F4CB}', description: 'Use plan mode', category: 'behavioral', stat: 'planModeUses', tiers: [5, 25, 100, 500, 2000], trigger: 'Task tool invocations (plan mode)' },\n { id: 'novelist', name: 'Novelist', icon: '\\u{1F4D6}', description: 'Write prompts over 1000 characters', category: 'behavioral', stat: 'longPromptCount', tiers: [5, 25, 100, 500, 2000], trigger: 'Prompts with over 1,000 characters' },\n { id: 'speed_demon', name: 'Speed Demon', icon: '\\u{26A1}', description: 'Complete sessions in under 5 minutes', category: 'behavioral', stat: 'quickSessionCount', tiers: [5, 25, 100, 500, 2000], trigger: 'Sessions under 5 minutes with tool use' },\n\n // ===================================================================\n // PROMPT PATTERNS (6)\n // ===================================================================\n { id: 'minimalist', name: 'Minimalist', icon: '\\u{1F90F}', description: 'A person of few words.', category: 'prompt_patterns', stat: 'shortPromptCount', tiers: [5, 25, 100, 500, 2000], trigger: 'Prompts with fewer than 10 words' },\n { id: 'question_master', name: 'Question Master', icon: '\\u{2753}', description: 'So many questions, so little time.', category: 'prompt_patterns', stat: 'questionPromptCount', tiers: [10, 50, 200, 1000, 5000], trigger: 'Prompts ending with a question mark' },\n { id: 'the_apologizer', name: 'The Apologizer', icon: '\\u{1F625}', description: 'Sorry for asking, but...', category: 'prompt_patterns', stat: 'sorryPromptCount', tiers: [1, 10, 50, 200, 1000], trigger: \"Prompts containing the word 'sorry'\" },\n { id: 'caps_lock_energy', name: 'CAPS LOCK ENERGY', icon: '\\u{1F4E2}', description: 'WHY ARE WE YELLING?', category: 'prompt_patterns', stat: 'capsLockPromptCount', tiers: [1, 5, 25, 100, 500], trigger: 'Prompts that are fully uppercase (10+ characters)' },\n { id: 'emoji_whisperer', name: 'Emoji Whisperer', icon: '\\u{1F680}', description: 'Deploying vibes', category: 'prompt_patterns', stat: 'emojiPromptCount', tiers: [5, 25, 100, 500, 2000], trigger: 'Prompts containing emoji characters' },\n { id: 'code_dump', name: 'Code Dump', icon: '\\u{1F4E6}', description: \"Here's 500 lines, figure it out.\", category: 'prompt_patterns', stat: 'codeDumpPromptCount', tiers: [1, 10, 50, 200, 1000], trigger: 'Prompts with 50+ lines of text' },\n\n // ===================================================================\n // RESILIENCE (3)\n // ===================================================================\n { id: 'clean_hands', name: 'Clean Hands', icon: '\\u{2728}', description: 'Longest error-free tool streak', category: 'resilience', stat: 'longestErrorFreeStreak', tiers: [50, 200, 500, 2000, 10000], trigger: 'Consecutive successful tool calls without any error' },\n { id: 'resilient', name: 'Resilient', icon: '\\u{1F6E1}', description: 'Survive errors', category: 'resilience', stat: 'totalErrors', tiers: [10, 50, 200, 1000, 5000], trigger: 'Total errors survived across all sessions' },\n { id: 'rate_limited', name: 'Rate Limited', icon: '\\u{1F6A7}', description: 'Hit rate limits', category: 'resilience', stat: 'totalRateLimits', tiers: [3, 10, 25, 50, 100], trigger: 'Rate limit notification events received' },\n\n // ===================================================================\n // ERROR & RECOVERY (5)\n // ===================================================================\n { id: 'rubber_duck', name: 'Rubber Duck', icon: '\\u{1F986}', description: 'Explaining the problem IS the solution.', category: 'error_recovery', stat: 'rubberDuckCount', tiers: [1, 5, 25, 100, 500], trigger: 'Tool failure followed by same tool success without Edit in between' },\n { id: 'third_times_charm', name: \"Third Time's the Charm\", icon: '\\u{1F340}', description: 'Persistence is a virtue.', category: 'error_recovery', stat: 'thirdTimeCharmCount', tiers: [1, 5, 25, 100, 500], trigger: 'Tool success after 2+ consecutive failures of same tool' },\n { id: 'the_undoer', name: 'The Undoer', icon: '\\u{21A9}', description: 'Ctrl+Z energy.', category: 'error_recovery', stat: 'undoEditCount', tiers: [1, 10, 50, 200, 1000], trigger: 'Back-to-back Edit calls on the same file in a session' },\n { id: 'crash_test_dummy', name: 'Crash Test Dummy', icon: '\\u{1F4A5}', description: 'Testing in production, I see.', category: 'error_recovery', stat: 'crashySessions', tiers: [1, 5, 25, 100, 500], trigger: 'Sessions with 10+ errors' },\n { id: 'phoenix', name: 'Phoenix', icon: '\\u{1F985}', description: 'From the ashes of 100 errors, you rise.', category: 'error_recovery', stat: 'totalLifetimeErrors', tiers: [100, 500, 1000, 5000, 10000], trigger: 'Total lifetime errors survived across all sessions' },\n\n // ===================================================================\n // TOOL COMBOS (5)\n // ===================================================================\n { id: 'read_edit_run', name: 'Read-Edit-Run', icon: '\\u{1F3AF}', description: 'The holy trinity.', category: 'tool_combos', stat: 'readEditRunCount', tiers: [25, 100, 500, 2000, 10000], trigger: 'Read \\u2192 Edit \\u2192 Bash sequences detected in events' },\n { id: 'grep_ninja', name: 'Grep Ninja', icon: '\\u{1F977}', description: 'Finding needles in haystacks since day one.', category: 'tool_combos', stat: 'totalSearches', tiers: [250, 1000, 5000, 25000, 100000], trigger: 'Total Grep and Glob searches performed' },\n { id: 'file_factory', name: 'File Factory', icon: '\\u{1F3ED}', description: \"You're not creating files, you're creating art.\", category: 'tool_combos', stat: 'maxFilesCreatedInSession', tiers: [10, 20, 50, 100, 200], trigger: 'Max Write tool calls in a single session' },\n { id: 'the_refactorer', name: 'The Refactorer', icon: '\\u{267B}', description: 'Same file, different day.', category: 'tool_combos', stat: 'maxSameFileEditsLifetime', tiers: [50, 100, 250, 500, 2000], trigger: 'Max Edit calls to any single file path across all sessions' },\n { id: 'search_and_destroy', name: 'Search and Destroy', icon: '\\u{1F4A2}', description: 'Grep it, then wreck it.', category: 'tool_combos', stat: 'searchThenEditCount', tiers: [25, 100, 500, 2500, 10000], trigger: 'Grep/Glob followed by Edit within same session' },\n\n // ===================================================================\n // SHIPPING & PROJECTS (4)\n // ===================================================================\n { id: 'shipper', name: 'Shipper', icon: '\\u{1F4E6}', description: 'Make commits via Claude', category: 'shipping', stat: 'totalCommits', tiers: [5, 50, 200, 1000, 5000], trigger: \"Bash tool calls containing 'git commit'\" },\n { id: 'pr_machine', name: 'PR Machine', icon: '\\u{1F500}', description: 'Create pull requests', category: 'shipping', stat: 'totalPRs', tiers: [3, 25, 100, 500, 2000], trigger: \"Bash tool calls containing 'gh pr create'\" },\n { id: 'empire', name: 'Empire', icon: '\\u{1F3F0}', description: 'Work on unique projects', category: 'shipping', stat: 'uniqueProjects', tiers: [2, 5, 10, 25, 50], trigger: 'Unique project directories worked in' },\n { id: 'polyglot', name: 'Polyglot', icon: '\\u{1F30D}', description: 'Use different programming languages', category: 'shipping', stat: 'uniqueLanguages', tiers: [3, 5, 8, 15, 25], trigger: 'Distinct file extensions in Edit/Write/Read events' },\n\n // ===================================================================\n // PROJECT DEDICATION (5)\n // ===================================================================\n { id: 'monogamous', name: 'Monogamous', icon: '\\u{1F48D}', description: 'One project. True love.', category: 'project_dedication', stat: 'maxProjectSessions', tiers: [50, 100, 250, 500, 1000], trigger: 'Max sessions on any single project' },\n { id: 'project_hopper', name: 'Project Hopper', icon: '\\u{1F407}', description: \"Commitment issues? Never heard of her.\", category: 'project_dedication', stat: 'maxProjectsInDay', tiers: [3, 5, 8, 10, 15], trigger: 'Max unique projects worked on in a single day' },\n { id: 'the_finisher', name: 'The Finisher', icon: '\\u{1F3C1}', description: 'You actually completed something.', category: 'project_dedication', stat: 'finishedProjects', tiers: [1, 3, 5, 10, 25], trigger: 'Projects with git commits followed by 7+ days of inactivity' },\n { id: 'legacy_code', name: 'Legacy Code', icon: '\\u{1F9D3}', description: 'Revisiting your past mistakes.', category: 'project_dedication', stat: 'legacyReturns', tiers: [1, 3, 5, 10, 25], trigger: 'Returns to a project after 30+ days of inactivity' },\n { id: 'greenfield', name: 'Greenfield', icon: '\\u{1F331}', description: 'That new project smell.', category: 'project_dedication', stat: 'totalUniqueProjects', tiers: [10, 25, 50, 100, 200], trigger: 'Total unique projects initialized' },\n\n // ===================================================================\n // MULTI-AGENT (6)\n // ===================================================================\n { id: 'buddy_system', name: 'Buddy System', icon: '\\u{1F91D}', description: 'Use concurrent agents', category: 'multi_agent', stat: 'concurrentAgentUses', tiers: [1, 5, 25, 100, 500], trigger: 'Sessions with SubagentStart events' },\n { id: 'hive_mind', name: 'Hive Mind', icon: '\\u{1F41D}', description: 'Spawn subagents total', category: 'multi_agent', stat: 'totalSubagents', tiers: [25, 250, 1000, 5000, 25000], trigger: 'Total SubagentStart events across all sessions' },\n { id: 'swarm_intelligence', name: 'Swarm Intelligence', icon: '\\u{1F41C}', description: \"You've built an army.\", category: 'multi_agent', stat: 'maxConcurrentSubagents', tiers: [3, 5, 8, 12, 20], trigger: 'Max concurrent subagents active at any point' },\n { id: 'micromanager', name: 'Micromanager', icon: '\\u{1F440}', description: 'Let them cook? Never heard of it.', category: 'multi_agent', stat: 'quickSubagentStops', tiers: [1, 5, 25, 100, 500], trigger: 'Subagents stopped within 30 seconds of starting' },\n { id: 'the_orchestrator', name: 'The Orchestrator', icon: '\\u{1F3BC}', description: \"You don't code. You conduct.\", category: 'multi_agent', stat: 'totalSubagentSpawns', tiers: [50, 250, 1000, 5000, 25000], trigger: 'Total subagent spawns across all sessions' },\n { id: 'agent_smith', name: 'Agent Smith', icon: '\\u{1F576}', description: \"They're multiplying.\", category: 'multi_agent', stat: 'maxSubagentsInSession', tiers: [10, 25, 50, 100, 250], trigger: 'Max SubagentStart events in a single session' },\n\n // --- Cross-agent badges (new) ---\n { id: 'polyglot_agent', name: 'Polyglot Agent', icon: '\\u{1F30F}', description: 'A tool for every occasion.', category: 'multi_agent', stat: 'distinctAgentsUsed', tiers: [2, 3, 4, 4, 4], trigger: 'Distinct CLI agents used (Claude Code, Gemini, Copilot, OpenCode)' },\n { id: 'gemini_whisperer', name: 'Gemini Whisperer', icon: '\\u{264A}', description: 'The stars aligned for your Gemini sessions.', category: 'multi_agent', stat: 'geminiSessions', tiers: [10, 50, 200, 1000, 5000], trigger: 'Sessions completed in Gemini CLI' },\n { id: 'copilot_rider', name: 'Copilot Rider', icon: '\\u{2708}', description: 'Your copilot is always on duty.', category: 'multi_agent', stat: 'copilotSessions', tiers: [10, 50, 200, 1000, 5000], trigger: 'Sessions completed in Copilot CLI' },\n { id: 'open_source_spirit', name: 'Open Source Spirit', icon: '\\u{1F4A1}', description: 'Freedom in every keystroke.', category: 'multi_agent', stat: 'opencodeSessions', tiers: [10, 50, 200, 1000, 5000], trigger: 'Sessions completed in OpenCode' },\n { id: 'agent_hopper', name: 'Agent Hopper', icon: '\\u{1F407}', description: \"Can't pick a favorite? Neither can we.\", category: 'multi_agent', stat: 'agentSwitchDays', tiers: [2, 4, 6, 8, 10], trigger: 'Days where you used 2+ different CLI agents' },\n { id: 'double_agent', name: 'Double Agent', icon: '\\u{1F575}', description: 'Playing both sides. Respect.', category: 'multi_agent', stat: 'doubleAgentDays', tiers: [5, 25, 100, 250, 500], trigger: 'Days with sessions in 2+ different CLI agents' },\n\n // ===================================================================\n // WILD CARD (12)\n // ===================================================================\n { id: 'please_thank_you', name: 'Please and Thank You', icon: '\\u{1F64F}', description: \"You're polite to the AI. When they take over, you'll be spared.\", category: 'wild_card', stat: 'politePromptCount', tiers: [10, 50, 200, 1000, 5000], trigger: \"Prompts containing 'please' or 'thank'\" },\n { id: 'wall_of_text', name: 'Wall of Text', icon: '\\u{1F4DC}', description: \"Claude read your entire novel and didn't even complain.\", category: 'wild_card', stat: 'hugePromptCount', tiers: [1, 10, 50, 200, 1000], trigger: 'Prompts over 5,000 characters' },\n { id: 'the_fixer', name: 'The Fixer', icon: '\\u{1F6E0}', description: 'At this point just rewrite the whole thing.', category: 'wild_card', stat: 'maxSameFileEdits', tiers: [10, 20, 50, 100, 200], trigger: 'Max Edit calls to a single file' },\n { id: 'what_day_is_it', name: 'What Day Is It?', icon: '\\u{1F62B}', description: 'Your chair is now a part of you.', category: 'wild_card', stat: 'longSessionCount', tiers: [1, 5, 25, 100, 500], trigger: 'Sessions exceeding 8 hours' },\n { id: 'copy_pasta', name: 'Copy Pasta', icon: '\\u{1F35D}', description: \"Maybe if I ask again it'll work differently.\", category: 'wild_card', stat: 'repeatedPromptCount', tiers: [3, 10, 50, 200, 1000], trigger: 'Total duplicate prompts submitted' },\n { id: 'error_magnet', name: 'Error Magnet', icon: '\\u{1F9F2}', description: 'At this point, the errors are a feature.', category: 'wild_card', stat: 'maxErrorsInSession', tiers: [10, 25, 50, 100, 200], trigger: 'Max errors in a single session' },\n { id: 'deja_vu', name: 'D\\u00E9j\\u00E0 Vu', icon: '\\u{1F408}', description: \"Didn't we just do this?\", category: 'wild_card', stat: 'dejaVuCount', tiers: [1, 5, 25, 100, 500], trigger: 'Same prompt submitted twice within 5 minutes' },\n { id: 'trust_issues', name: 'Trust Issues', icon: '\\u{1F50E}', description: 'You read the file Claude just wrote.', category: 'wild_card', stat: 'trustIssueCount', tiers: [1, 10, 50, 200, 1000], trigger: 'Read immediately after Write on the same file' },\n { id: 'backseat_driver', name: 'Backseat Driver', icon: '\\u{1F697}', description: 'Let me tell you exactly how to do your job.', category: 'wild_card', stat: 'backseatDriverCount', tiers: [1, 10, 50, 200, 1000], trigger: \"Prompts with numbered step-by-step instructions (e.g. '1.' '2.')\" },\n { id: 'the_negotiator', name: 'The Negotiator', icon: '\\u{1F91C}', description: 'Can you try again but better?', category: 'wild_card', stat: 'negotiatorCount', tiers: [1, 10, 50, 200, 1000], trigger: \"Prompts containing 'try again' or 'one more time'\" },\n { id: 'rubber_stamp', name: 'Rubber Stamp', icon: '\\u{2705}', description: 'Yes. Yes. Yes. Approved.', category: 'wild_card', stat: 'maxConsecutivePermissions', tiers: [25, 50, 100, 250, 500], trigger: 'Max consecutive PermissionRequest events' },\n { id: 'it_works_on_my_machine', name: 'It Works On My Machine', icon: '\\u{1F937}', description: 'The classic excuse.', category: 'wild_card', stat: 'bashRetrySuccessCount', tiers: [1, 10, 50, 200, 1000], trigger: 'Bash success (exit code 0) after a previous Bash failure' },\n\n // ===================================================================\n // TOKEN USAGE (10)\n // ===================================================================\n { id: 'token_burner', name: 'Token Burner', icon: '\\u{1F525}', description: 'Consume tokens across all sessions', category: 'token_usage', stat: 'totalTokens', tiers: [50000000, 500000000, 5000000000, 50000000000, 500000000000], trigger: 'Total tokens consumed (input + output + cache read + cache creation)' },\n { id: 'output_machine', name: 'Output Machine', icon: '\\u{1F5A8}', description: 'Generate output tokens from Claude', category: 'token_usage', stat: 'totalOutputTokens', tiers: [1000000, 10000000, 100000000, 500000000, 2000000000], trigger: 'Total output tokens generated by Claude across all sessions' },\n { id: 'cache_royalty', name: 'Cache Royalty', icon: '\\u{1F451}', description: 'Read tokens from prompt cache', category: 'token_usage', stat: 'totalCacheReadTokens', tiers: [50000000, 500000000, 5000000000, 50000000000, 500000000000], trigger: 'Total cache read tokens (cached context reused across turns)' },\n { id: 'context_crafter', name: 'Context Crafter', icon: '\\u{1F9F1}', description: 'Create new cache entries', category: 'token_usage', stat: 'totalCacheCreationTokens', tiers: [10000000, 100000000, 1000000000, 10000000000, 100000000000], trigger: 'Total cache creation tokens (new context written to cache)' },\n { id: 'token_whale', name: 'Token Whale', icon: '\\u{1F40B}', description: 'Massive token consumption in a single session', category: 'token_usage', stat: 'mostTokensInSession', tiers: [10000000, 50000000, 200000000, 500000000, 1000000000], trigger: 'Most total tokens consumed in any single session' },\n { id: 'heavy_hitter', name: 'Heavy Hitter', icon: '\\u{1F4AA}', description: 'Sessions exceeding 1M total tokens', category: 'token_usage', stat: 'heavyTokenSessions', tiers: [10, 50, 250, 1000, 5000], trigger: 'Sessions with 1,000,000+ total tokens' },\n { id: 'featherweight', name: 'Featherweight', icon: '\\u{1FAB6}', description: 'Lean sessions that still get work done', category: 'token_usage', stat: 'lightTokenSessions', tiers: [1, 10, 50, 200, 1000], trigger: 'Sessions under 50,000 total tokens with at least 1 tool call' },\n { id: 'token_velocity', name: 'Token Velocity', icon: '\\u{26A1}', description: 'High average tokens per session', category: 'token_usage', stat: 'avgTokensPerSession', tiers: [5000000, 10000000, 25000000, 50000000, 100000000], trigger: 'Average total tokens per session across all sessions' },\n { id: 'prolific_session', name: 'Prolific', icon: '\\u{270D}', description: 'Most output generated in one session', category: 'token_usage', stat: 'maxOutputInSession', tiers: [100000, 500000, 2000000, 10000000, 50000000], trigger: 'Most output tokens generated by Claude in a single session' },\n { id: 'input_flood', name: 'Input Flood', icon: '\\u{1F30A}', description: 'Total raw input tokens sent to the API', category: 'token_usage', stat: 'totalInputTokens', tiers: [1000000, 10000000, 100000000, 500000000, 2000000000], trigger: 'Total non-cached input tokens (the small uncached portion of each request)' },\n\n // ===================================================================\n // ASPIRATIONAL (12) - Singularity-only\n // ===================================================================\n { id: 'the_machine', name: 'The Machine', icon: '\\u{2699}', description: 'You are no longer using the tool. You are the tool.', category: 'aspirational', stat: 'totalToolCalls', tiers: [100000, 100000, 100000, 100000, 100000], aspirational: true, trigger: 'Reach 100,000 total tool calls' },\n { id: 'year_of_code', name: 'Year of Code', icon: '\\u{1F4C5}', description: '365 days. No breaks. Absolute unit.', category: 'aspirational', stat: 'longestStreak', tiers: [365, 365, 365, 365, 365], aspirational: true, trigger: 'Achieve a 365-day consecutive streak' },\n { id: 'million_words', name: 'Million Words', icon: '\\u{1F4DA}', description: \"You've written more to Claude than most people write in a lifetime.\", category: 'aspirational', stat: 'totalCharsTyped', tiers: [10000000, 10000000, 10000000, 10000000, 10000000], aspirational: true, trigger: 'Type 10 million characters in prompts' },\n { id: 'lifer', name: 'Lifer', icon: '\\u{1F451}', description: 'At this point, Claude is your cofounder.', category: 'aspirational', stat: 'totalSessions', tiers: [10000, 10000, 10000, 10000, 10000], aspirational: true, trigger: 'Complete 10,000 sessions' },\n { id: 'transcendent', name: 'Transcendent', icon: '\\u{2B50}', description: \"You've reached the peak. The view is nice up here.\", category: 'aspirational', stat: 'totalXP', tiers: [100000, 100000, 100000, 100000, 100000], aspirational: true, trigger: 'Earn 100,000 total XP' },\n { id: 'omniscient', name: 'Omniscient', icon: '\\u{1F441}', description: \"You've mastered every tool. There is nothing left to teach you.\", category: 'aspirational', stat: 'allToolsObsidian', tiers: [1, 1, 1, 1, 1], aspirational: true, trigger: 'All tool mastery badges at Singularity tier' },\n { id: 'ten_thousand_hours', name: '10,000 Hours', icon: '\\u{23F0}', description: 'Malcolm Gladwell would be proud.', category: 'aspirational', stat: 'totalSessionHours', tiers: [10000, 10000, 10000, 10000, 10000], aspirational: true, trigger: 'Spend 10,000 hours in sessions' },\n { id: 'master_architect', name: 'The Architect', icon: '\\u{1F3DB}', description: \"You've built more than most companies ship.\", category: 'aspirational', stat: 'totalFilesCreated', tiers: [1000, 1000, 1000, 1000, 1000], aspirational: true, trigger: 'Create 1,000+ files with the Write tool' },\n { id: 'eternal_flame', name: 'Eternal Flame', icon: '\\u{1F56F}', description: 'Your streak outlasted relationships.', category: 'aspirational', stat: 'longestStreak', tiers: [180, 180, 180, 180, 180], aspirational: true, trigger: 'Maintain a 180-day consecutive streak' },\n { id: 'the_collector', name: 'The Collector', icon: '\\u{1F4BF}', description: \"Gotta catch 'em all.\", category: 'aspirational', stat: 'allNonSecretBadgesUnlocked', tiers: [1, 1, 1, 1, 1], aspirational: true, trigger: 'Unlock every non-secret, non-aspirational badge' },\n { id: 'centimillionaire', name: 'Centimillionaire', icon: '\\u{2328}', description: '100 million characters. Your keyboard weeps.', category: 'aspirational', stat: 'totalCharsTyped', tiers: [100000000, 100000000, 100000000, 100000000, 100000000], aspirational: true, trigger: 'Type 100 million characters in prompts' },\n { id: 'token_billionaire', name: 'Token Billionaire', icon: '\\u{1F4B0}', description: 'A billion tokens. You single-handedly funded a GPU cluster.', category: 'aspirational', stat: 'totalTokens', tiers: [1000000000, 1000000000, 1000000000, 1000000000, 1000000000], aspirational: true, trigger: 'Consume 1 billion total tokens' },\n\n // ===================================================================\n // SECRET (17)\n // ===================================================================\n { id: 'rm_rf_survivor', name: 'rm -rf Survivor', icon: '\\u{1F4A3}', description: \"You almost mass deleted that folder. But you didn't. And honestly, we're all better for it.\", category: 'secret', stat: 'dangerousCommandBlocked', tiers: [1, 1, 1, 1, 1], secret: true, trigger: \"rm -rf or rm -r / detected in PreToolUse event\" },\n { id: 'touch_grass', name: 'Touch Grass', icon: '\\u{1F33F}', description: \"Welcome back. The codebase missed you. (It didn't change, but still.)\", category: 'secret', stat: 'returnAfterBreak', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'Return after 7+ day gap between sessions' },\n { id: 'three_am_coder', name: '3am Coder', icon: '\\u{1F319}', description: 'Nothing good happens at 3am. Except shipping code, apparently.', category: 'secret', stat: 'threeAmPrompt', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'Submit a prompt at exactly 3 AM' },\n { id: 'night_shift', name: 'Night Shift', icon: '\\u{1F303}', description: 'Started yesterday, finishing today. Time is a construct.', category: 'secret', stat: 'midnightSpanSession', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'Session that started before midnight and ended after' },\n { id: 'inception', name: 'Inception', icon: '\\u{1F300}', description: 'We need to go deeper.', category: 'secret', stat: 'nestedSubagent', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'Any SubagentStart event detected' },\n { id: 'holiday_hacker', name: 'Holiday Hacker', icon: '\\u{1F384}', description: \"Your family is wondering where you are. You're deploying.\", category: 'secret', stat: 'holidayActivity', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'Session on Dec 25, Jan 1, or Jul 4' },\n { id: 'speed_run', name: 'Speed Run Any%', icon: '\\u{23F1}', description: 'In and out. Twenty-second adventure.', category: 'secret', stat: 'speedRunSession', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'Session under 20 seconds with tool use' },\n { id: 'full_send', name: 'Full Send', icon: '\\u{1F680}', description: 'Bash, Read, Write, Edit, Grep, Glob, WebFetch -- the whole buffet.', category: 'secret', stat: 'allToolsInSession', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'Use all 7 core tools in one session' },\n { id: 'launch_day', name: 'Launch Day', icon: '\\u{1F389}', description: 'Welcome to bashstats. Your stats are now being watched. Forever.', category: 'secret', stat: 'firstEverSession', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'Complete your first ever session' },\n { id: 'the_completionist', name: 'The Completionist', icon: '\\u{1F3C6}', description: 'You absolute legend.', category: 'secret', stat: 'allBadgesGold', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'All non-secret, non-aspirational badges at Gold+ tier' },\n { id: 'easter_egg_hunter', name: 'Easter Egg Hunter', icon: '\\u{1F95A}', description: 'You found me!', category: 'secret', stat: 'easterEggActivity', tiers: [1, 1, 1, 1, 1], secret: true, trigger: \"Session on Easter, Valentine's Day, or Thanksgiving\" },\n { id: 'full_moon_coder', name: 'Full Moon Coder', icon: '\\u{1F315}', description: 'Lycanthropic debugging.', category: 'secret', stat: 'fullMoonSession', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'Session during a full moon (calculated from lunar cycle)' },\n { id: 'birthday_bash', name: 'Birthday Bash', icon: '\\u{1F382}', description: 'Celebrating with Claude.', category: 'secret', stat: 'birthdaySession', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'Session on your bashstats install anniversary' },\n { id: 'lucky_number', name: 'Lucky Number', icon: '\\u{1F340}', description: '7-7-7', category: 'secret', stat: 'luckyNumber', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'Reach 777 prompts or 7,777 tool calls' },\n { id: 'ghost_session', name: 'Ghost Session', icon: '\\u{1F47B}', description: 'Boo!', category: 'secret', stat: 'ghostSessions', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'Complete a session with 0 tool calls' },\n { id: 'bullseye', name: 'Bullseye', icon: '\\u{1F3AF}', description: 'First try, no errors.', category: 'secret', stat: 'bullseyeSessions', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'Session with 1 prompt, 0 errors, and 1+ tool calls' },\n { id: 'token_singularity', name: 'Token Singularity', icon: '\\u{1F573}', description: 'The context window stared into the abyss, and the abyss stared back.', category: 'secret', stat: 'hasTenMillionSession', tiers: [1, 1, 1, 1, 1], secret: true, trigger: 'Complete a session exceeding 10 million total tokens' },\n]\n\n// ===================================================================\n// RANK SYSTEM (1-500)\n// ===================================================================\n\nexport const RANK_TIER_BRACKETS: RankTierBracket[] = [\n { tier: 'System Anomaly', minRank: 500, maxRank: 500 },\n { tier: 'Obsidian', minRank: 401, maxRank: 499 },\n { tier: 'Diamond', minRank: 301, maxRank: 400 },\n { tier: 'Gold', minRank: 201, maxRank: 300 },\n { tier: 'Silver', minRank: 101, maxRank: 200 },\n { tier: 'Bronze', minRank: 1, maxRank: 100 },\n]\n\nexport function xpForRank(rank: number): number {\n if (rank <= 0) return 0\n return Math.floor(10 * Math.pow(rank, 2.2))\n}\n\nexport function rankTierForRank(rank: number): string {\n for (const bracket of RANK_TIER_BRACKETS) {\n if (rank >= bracket.minRank && rank <= bracket.maxRank) {\n return bracket.tier\n }\n }\n return 'Unranked'\n}\n\n// ===================================================================\n// BADGE TIER XP REWARDS\n// ===================================================================\n\nexport const TIER_XP = [0, 50, 100, 200, 500, 1000]\n\n// ===================================================================\n// WEEKLY GOALS\n// ===================================================================\n\nexport const ACTIVITY_MULTIPLIERS: Record<number, number> = {\n 1: 1.0,\n 2: 1.1,\n 3: 1.2,\n 4: 1.3,\n 5: 1.5,\n 6: 1.75,\n 7: 2.0,\n}\n\nexport const WEEKLY_CHALLENGES: WeeklyChallenge[] = [\n { id: 'wk_diverse_tools', description: 'Use 5+ distinct tools in 5 sessions', stat: 'diverseToolSessions', threshold: 5, xpReward: 200, weekScoped: true },\n { id: 'wk_200_prompts', description: 'Submit 200 prompts this week', stat: 'totalPrompts', threshold: 200, xpReward: 250, weekScoped: true },\n { id: 'wk_quick_sessions', description: 'Complete 3 sessions under 2 minutes', stat: 'quickDrawSessions', threshold: 3, xpReward: 150, weekScoped: true },\n { id: 'wk_5_day_commits', description: 'Make git commits on 5 different days', stat: 'commitDays', threshold: 5, xpReward: 300, weekScoped: true },\n { id: 'wk_7_day_streak', description: 'Be active all 7 days this week', stat: 'daysActive', threshold: 7, xpReward: 400, weekScoped: true },\n { id: 'wk_subagent_power', description: 'Spawn 8+ subagents in a single session', stat: 'maxSubagentsInSession', threshold: 8, xpReward: 200, weekScoped: true },\n { id: 'wk_night_code', description: 'Code after midnight on 3 different nights', stat: 'nightOwlDays', threshold: 3, xpReward: 150, weekScoped: true },\n { id: 'wk_2000_tools', description: 'Make 2,000 tool calls this week', stat: 'totalToolCalls', threshold: 2000, xpReward: 250, weekScoped: true },\n { id: 'wk_10_sessions', description: 'Complete 10 sessions this week', stat: 'totalSessions', threshold: 10, xpReward: 200, weekScoped: true },\n { id: 'wk_20_sessions', description: 'Complete 20 sessions this week', stat: 'totalSessions', threshold: 20, xpReward: 350, weekScoped: true },\n { id: 'wk_500_reads', description: 'Read 500 files this week', stat: 'totalFilesRead', threshold: 500, xpReward: 250, weekScoped: true },\n { id: 'wk_100_edits', description: 'Edit 100 files this week', stat: 'totalFilesEdited', threshold: 100, xpReward: 250, weekScoped: true },\n { id: 'wk_20_creates', description: 'Create 20 new files this week', stat: 'totalFilesCreated', threshold: 20, xpReward: 200, weekScoped: true },\n { id: 'wk_3_projects', description: 'Work on 3+ different projects this week', stat: 'uniqueProjects', threshold: 3, xpReward: 200, weekScoped: true },\n { id: 'wk_3_marathons', description: 'Have 3 sessions lasting over 1 hour', stat: 'extendedSessionCount', threshold: 3, xpReward: 250, weekScoped: true },\n { id: 'wk_5_clean', description: 'Complete 5 sessions with zero errors', stat: 'cleanSessions', threshold: 5, xpReward: 200, weekScoped: true },\n { id: 'wk_15_hours', description: 'Spend 15+ total hours in sessions', stat: 'totalHours', threshold: 15, xpReward: 300, weekScoped: true },\n { id: 'wk_200_bash', description: 'Run 200 Bash commands this week', stat: 'totalBashCommands', threshold: 200, xpReward: 200, weekScoped: true },\n { id: 'wk_250_searches', description: 'Perform 250 searches (Grep/Glob)', stat: 'totalSearches', threshold: 250, xpReward: 200, weekScoped: true },\n { id: 'wk_10_long_prompts', description: 'Write 10 prompts over 1,000 characters', stat: 'longPromptCount', threshold: 10, xpReward: 150, weekScoped: true },\n { id: 'wk_5_commits', description: 'Make 5 git commits this week', stat: 'totalCommits', threshold: 5, xpReward: 200, weekScoped: true },\n { id: 'wk_2_prs', description: 'Create 2 pull requests this week', stat: 'totalPRs', threshold: 2, xpReward: 250, weekScoped: true },\n { id: 'wk_5000_tools', description: 'Make 5,000 tool calls this week', stat: 'totalToolCalls', threshold: 5000, xpReward: 400, weekScoped: true },\n { id: 'wk_weekend_warrior', description: 'Code on both Saturday and Sunday', stat: 'weekendDays', threshold: 2, xpReward: 200, weekScoped: true },\n { id: 'wk_3_early_birds', description: 'Submit a prompt before 8am on 3 days', stat: 'earlyBirdDays', threshold: 3, xpReward: 200, weekScoped: true },\n]\n\n// ===================================================================\n// PATHS\n// ===================================================================\n\nexport const DATA_DIR = '.bashstats'\nexport const DB_FILENAME = 'bashstats.db'\nexport const DEFAULT_PORT = 17900\n","import Database from 'better-sqlite3'\nimport type { EventRow, SessionRow, PromptRow, DailyActivityRow, AchievementUnlockRow, TokenUsage, WeeklyGoalRow, WeeklyXPRow } from '../types.js'\n\nfunction localNow(): string {\n const d = new Date()\n const pad = (n: number) => String(n).padStart(2, '0')\n const ms = String(d.getMilliseconds()).padStart(3, '0')\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}.${ms}`\n}\n\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n session_id TEXT NOT NULL,\n hook_type TEXT NOT NULL,\n tool_name TEXT,\n tool_input TEXT,\n tool_output TEXT,\n exit_code INTEGER,\n success INTEGER,\n cwd TEXT,\n project TEXT,\n timestamp TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n agent TEXT NOT NULL DEFAULT 'claude-code',\n started_at TEXT NOT NULL,\n ended_at TEXT,\n stop_reason TEXT,\n prompt_count INTEGER DEFAULT 0,\n tool_count INTEGER DEFAULT 0,\n error_count INTEGER DEFAULT 0,\n project TEXT,\n duration_seconds INTEGER,\n input_tokens INTEGER DEFAULT 0,\n output_tokens INTEGER DEFAULT 0,\n cache_creation_input_tokens INTEGER DEFAULT 0,\n cache_read_input_tokens INTEGER DEFAULT 0\n);\n\nCREATE TABLE IF NOT EXISTS prompts (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n session_id TEXT NOT NULL,\n content TEXT NOT NULL,\n char_count INTEGER NOT NULL,\n word_count INTEGER NOT NULL,\n timestamp TEXT NOT NULL,\n FOREIGN KEY (session_id) REFERENCES sessions(id)\n);\n\nCREATE TABLE IF NOT EXISTS daily_activity (\n date TEXT PRIMARY KEY,\n sessions INTEGER DEFAULT 0,\n prompts INTEGER DEFAULT 0,\n tool_calls INTEGER DEFAULT 0,\n errors INTEGER DEFAULT 0,\n duration_seconds INTEGER DEFAULT 0,\n input_tokens INTEGER DEFAULT 0,\n output_tokens INTEGER DEFAULT 0,\n cache_creation_input_tokens INTEGER DEFAULT 0,\n cache_read_input_tokens INTEGER DEFAULT 0\n);\n\nCREATE TABLE IF NOT EXISTS achievement_unlocks (\n badge_id TEXT NOT NULL,\n tier INTEGER NOT NULL,\n unlocked_at TEXT NOT NULL,\n notified INTEGER DEFAULT 0,\n PRIMARY KEY (badge_id, tier)\n);\n\nCREATE TABLE IF NOT EXISTS metadata (\n key TEXT PRIMARY KEY,\n value TEXT\n);\n\nCREATE TABLE IF NOT EXISTS weekly_goals (\n week_start TEXT NOT NULL,\n challenge_id TEXT NOT NULL,\n completed INTEGER DEFAULT 0,\n xp_reward INTEGER NOT NULL,\n PRIMARY KEY (week_start, challenge_id)\n);\n\nCREATE TABLE IF NOT EXISTS weekly_xp (\n week_start TEXT PRIMARY KEY,\n base_xp INTEGER DEFAULT 0,\n multiplier REAL DEFAULT 1.0,\n bonus_xp INTEGER DEFAULT 0\n);\n\nCREATE INDEX IF NOT EXISTS idx_events_session ON events(session_id);\nCREATE INDEX IF NOT EXISTS idx_events_hook_type ON events(hook_type);\nCREATE INDEX IF NOT EXISTS idx_events_tool_name ON events(tool_name);\nCREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);\nCREATE INDEX IF NOT EXISTS idx_events_project ON events(project);\nCREATE INDEX IF NOT EXISTS idx_prompts_session ON prompts(session_id);\nCREATE INDEX IF NOT EXISTS idx_prompts_timestamp ON prompts(timestamp);\n`\n\nexport class BashStatsDB {\n private db: Database.Database\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath)\n this.db.pragma('journal_mode = WAL')\n this.db.pragma('busy_timeout = 5000')\n this.db.pragma('foreign_keys = ON')\n this.db.exec(SCHEMA)\n this.migrate()\n }\n\n private migrate(): void {\n const sessionCols = this.db.pragma('table_info(sessions)') as { name: string }[]\n const sessionColNames = new Set(sessionCols.map(c => c.name))\n\n if (!sessionColNames.has('agent')) {\n this.db.exec(\"ALTER TABLE sessions ADD COLUMN agent TEXT NOT NULL DEFAULT 'claude-code'\")\n }\n\n const tokenCols = ['input_tokens', 'output_tokens', 'cache_creation_input_tokens', 'cache_read_input_tokens']\n for (const col of tokenCols) {\n if (!sessionColNames.has(col)) {\n this.db.exec(`ALTER TABLE sessions ADD COLUMN ${col} INTEGER DEFAULT 0`)\n }\n }\n\n const dailyCols = this.db.pragma('table_info(daily_activity)') as { name: string }[]\n const dailyColNames = new Set(dailyCols.map(c => c.name))\n for (const col of tokenCols) {\n if (!dailyColNames.has(col)) {\n this.db.exec(`ALTER TABLE daily_activity ADD COLUMN ${col} INTEGER DEFAULT 0`)\n }\n }\n }\n\n close(): void {\n this.db.close()\n }\n\n getTableNames(): string[] {\n const rows = this.db.prepare(\"SELECT name FROM sqlite_master WHERE type='table'\").all() as { name: string }[]\n return rows.map(r => r.name)\n }\n\n // === Events ===\n\n insertEvent(event: Omit<EventRow, 'id'>): number {\n const stmt = this.db.prepare(`\n INSERT INTO events (session_id, hook_type, tool_name, tool_input, tool_output, exit_code, success, cwd, project, timestamp)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `)\n const result = stmt.run(\n event.session_id, event.hook_type, event.tool_name, event.tool_input,\n event.tool_output, event.exit_code, event.success, event.cwd, event.project, event.timestamp\n )\n return result.lastInsertRowid as number\n }\n\n getEvents(filter: { session_id?: string; hook_type?: string; tool_name?: string }): EventRow[] {\n let sql = 'SELECT * FROM events WHERE 1=1'\n const params: unknown[] = []\n if (filter.session_id) { sql += ' AND session_id = ?'; params.push(filter.session_id) }\n if (filter.hook_type) { sql += ' AND hook_type = ?'; params.push(filter.hook_type) }\n if (filter.tool_name) { sql += ' AND tool_name = ?'; params.push(filter.tool_name) }\n sql += ' ORDER BY timestamp ASC'\n return this.db.prepare(sql).all(...params) as EventRow[]\n }\n\n // === Sessions ===\n\n insertSession(session: { id: string; agent?: string; started_at: string; project?: string | null }): void {\n this.db.prepare(`\n INSERT OR IGNORE INTO sessions (id, agent, started_at, project) VALUES (?, ?, ?, ?)\n `).run(session.id, session.agent ?? 'claude-code', session.started_at, session.project ?? null)\n }\n\n getSession(id: string): SessionRow | null {\n return this.db.prepare('SELECT * FROM sessions WHERE id = ?').get(id) as SessionRow | null\n }\n\n updateSession(id: string, updates: Partial<Pick<SessionRow, 'ended_at' | 'stop_reason' | 'duration_seconds'>>): void {\n const sets: string[] = []\n const params: unknown[] = []\n if (updates.ended_at !== undefined) { sets.push('ended_at = ?'); params.push(updates.ended_at) }\n if (updates.stop_reason !== undefined) { sets.push('stop_reason = ?'); params.push(updates.stop_reason) }\n if (updates.duration_seconds !== undefined) { sets.push('duration_seconds = ?'); params.push(updates.duration_seconds) }\n if (sets.length === 0) return\n params.push(id)\n this.db.prepare(`UPDATE sessions SET ${sets.join(', ')} WHERE id = ?`).run(...params)\n }\n\n updateSessionTokens(id: string, tokens: TokenUsage): void {\n this.db.prepare(`\n UPDATE sessions SET input_tokens = ?, output_tokens = ?, cache_creation_input_tokens = ?, cache_read_input_tokens = ? WHERE id = ?\n `).run(tokens.input_tokens, tokens.output_tokens, tokens.cache_creation_input_tokens, tokens.cache_read_input_tokens, id)\n }\n\n incrementSessionCounters(id: string, counters: { prompts?: number; tools?: number; errors?: number }): void {\n const sets: string[] = []\n const params: unknown[] = []\n if (counters.prompts) { sets.push('prompt_count = prompt_count + ?'); params.push(counters.prompts) }\n if (counters.tools) { sets.push('tool_count = tool_count + ?'); params.push(counters.tools) }\n if (counters.errors) { sets.push('error_count = error_count + ?'); params.push(counters.errors) }\n if (sets.length === 0) return\n params.push(id)\n this.db.prepare(`UPDATE sessions SET ${sets.join(', ')} WHERE id = ?`).run(...params)\n }\n\n // === Prompts ===\n\n insertPrompt(prompt: Omit<PromptRow, 'id'>): number {\n const result = this.db.prepare(`\n INSERT INTO prompts (session_id, content, char_count, word_count, timestamp) VALUES (?, ?, ?, ?, ?)\n `).run(prompt.session_id, prompt.content, prompt.char_count, prompt.word_count, prompt.timestamp)\n return result.lastInsertRowid as number\n }\n\n getPrompts(sessionId: string): PromptRow[] {\n return this.db.prepare('SELECT * FROM prompts WHERE session_id = ? ORDER BY timestamp ASC').all(sessionId) as PromptRow[]\n }\n\n // === Daily Activity ===\n\n incrementDailyActivity(date: string, increments: { sessions?: number; prompts?: number; tool_calls?: number; errors?: number; duration_seconds?: number; input_tokens?: number; output_tokens?: number; cache_creation_input_tokens?: number; cache_read_input_tokens?: number }): void {\n this.db.prepare(`\n INSERT INTO daily_activity (date, sessions, prompts, tool_calls, errors, duration_seconds, input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(date) DO UPDATE SET\n sessions = sessions + excluded.sessions,\n prompts = prompts + excluded.prompts,\n tool_calls = tool_calls + excluded.tool_calls,\n errors = errors + excluded.errors,\n duration_seconds = duration_seconds + excluded.duration_seconds,\n input_tokens = input_tokens + excluded.input_tokens,\n output_tokens = output_tokens + excluded.output_tokens,\n cache_creation_input_tokens = cache_creation_input_tokens + excluded.cache_creation_input_tokens,\n cache_read_input_tokens = cache_read_input_tokens + excluded.cache_read_input_tokens\n `).run(\n date,\n increments.sessions ?? 0,\n increments.prompts ?? 0,\n increments.tool_calls ?? 0,\n increments.errors ?? 0,\n increments.duration_seconds ?? 0,\n increments.input_tokens ?? 0,\n increments.output_tokens ?? 0,\n increments.cache_creation_input_tokens ?? 0,\n increments.cache_read_input_tokens ?? 0,\n )\n }\n\n getDailyActivity(date: string): DailyActivityRow | null {\n return this.db.prepare('SELECT * FROM daily_activity WHERE date = ?').get(date) as DailyActivityRow | null\n }\n\n getAllDailyActivity(days?: number): DailyActivityRow[] {\n if (days) {\n return this.db.prepare('SELECT * FROM daily_activity ORDER BY date DESC LIMIT ?').all(days) as DailyActivityRow[]\n }\n return this.db.prepare('SELECT * FROM daily_activity ORDER BY date DESC').all() as DailyActivityRow[]\n }\n\n // === Achievement Unlocks ===\n\n insertUnlock(badgeId: string, tier: number): void {\n this.db.prepare(`\n INSERT OR IGNORE INTO achievement_unlocks (badge_id, tier, unlocked_at) VALUES (?, ?, ?)\n `).run(badgeId, tier, localNow())\n }\n\n getUnlocks(): AchievementUnlockRow[] {\n return this.db.prepare('SELECT * FROM achievement_unlocks ORDER BY unlocked_at DESC').all() as AchievementUnlockRow[]\n }\n\n getUnnotifiedUnlocks(): AchievementUnlockRow[] {\n return this.db.prepare('SELECT * FROM achievement_unlocks WHERE notified = 0').all() as AchievementUnlockRow[]\n }\n\n markNotified(badgeId: string, tier: number): void {\n this.db.prepare('UPDATE achievement_unlocks SET notified = 1 WHERE badge_id = ? AND tier = ?').run(badgeId, tier)\n }\n\n // === Metadata ===\n\n setMetadata(key: string, value: string): void {\n this.db.prepare('INSERT OR REPLACE INTO metadata (key, value) VALUES (?, ?)').run(key, value)\n }\n\n getMetadata(key: string): string | null {\n const row = this.db.prepare('SELECT value FROM metadata WHERE key = ?').get(key) as { value: string } | undefined\n return row?.value ?? null\n }\n\n // === Weekly Goals ===\n\n insertWeeklyGoal(weekStart: string, challengeId: string, xpReward: number): void {\n this.db.prepare(`\n INSERT OR IGNORE INTO weekly_goals (week_start, challenge_id, xp_reward) VALUES (?, ?, ?)\n `).run(weekStart, challengeId, xpReward)\n }\n\n completeWeeklyGoal(weekStart: string, challengeId: string): void {\n this.db.prepare('UPDATE weekly_goals SET completed = 1 WHERE week_start = ? AND challenge_id = ?').run(weekStart, challengeId)\n }\n\n getWeeklyGoals(weekStart: string): WeeklyGoalRow[] {\n return this.db.prepare('SELECT * FROM weekly_goals WHERE week_start = ?').all(weekStart) as WeeklyGoalRow[]\n }\n\n // === Weekly XP ===\n\n upsertWeeklyXP(weekStart: string, baseXP: number, multiplier: number, bonusXP: number): void {\n this.db.prepare(`\n INSERT INTO weekly_xp (week_start, base_xp, multiplier, bonus_xp) VALUES (?, ?, ?, ?)\n ON CONFLICT(week_start) DO UPDATE SET base_xp = ?, multiplier = ?, bonus_xp = ?\n `).run(weekStart, baseXP, multiplier, bonusXP, baseXP, multiplier, bonusXP)\n }\n\n getWeeklyXP(weekStart: string): WeeklyXPRow | null {\n return this.db.prepare('SELECT * FROM weekly_xp WHERE week_start = ?').get(weekStart) as WeeklyXPRow | null\n }\n\n // === Raw DB access for stats engine ===\n\n prepare(sql: string): Database.Statement {\n return this.db.prepare(sql)\n }\n}\n","import fs from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport { fileURLToPath } from 'url'\nimport { DATA_DIR, DB_FILENAME } from '../constants.js'\nimport { BashStatsDB } from '../db/database.js'\n\n/**\n * Maps each Claude hook event name to the corresponding script filename.\n */\nexport const HOOK_SCRIPTS: Record<string, string> = {\n SessionStart: 'session-start.js',\n UserPromptSubmit: 'user-prompt-submit.js',\n PreToolUse: 'pre-tool-use.js',\n PostToolUse: 'post-tool-use.js',\n PostToolUseFailure: 'post-tool-failure.js',\n Stop: 'stop.js',\n Notification: 'notification.js',\n SubagentStart: 'subagent-start.js',\n SubagentStop: 'subagent-stop.js',\n PreCompact: 'pre-compact.js',\n PermissionRequest: 'permission-request.js',\n Setup: 'setup.js',\n}\n\n/** Marker comment appended to bashstats hook commands for identification. */\nconst MARKER = '# bashstats-managed'\n\ninterface HookEntry {\n matcher: string\n hooks: { type: string; command: string }[]\n}\n\ninterface HooksMap {\n [event: string]: HookEntry[]\n}\n\ninterface Settings {\n hooks?: HooksMap\n [key: string]: unknown\n}\n\n/**\n * Merges bashstats hooks into a settings object without overwriting existing hooks.\n * Uses the `# bashstats-managed` marker to identify our hooks for idempotent updates.\n */\nexport function mergeHooks(settings: Record<string, unknown>, hooksDir: string): Record<string, unknown> {\n const result: Settings = { ...settings }\n\n if (!result.hooks) {\n result.hooks = {}\n }\n\n for (const [event, scriptFile] of Object.entries(HOOK_SCRIPTS)) {\n const command = `node \"${path.join(hooksDir, scriptFile)}\" ${MARKER}`\n\n // Get existing entries for this event, or empty array\n const existing: HookEntry[] = result.hooks[event] ?? []\n\n // Filter out any previous bashstats-managed hooks\n const nonBashstats = existing.filter((entry) => {\n return !entry.hooks?.some((h) => h.command?.includes(MARKER))\n })\n\n // Build the new bashstats hook entry\n const bashstatsEntry: HookEntry = {\n matcher: '',\n hooks: [{ type: 'command', command }],\n }\n\n // Add bashstats entry alongside preserved hooks\n result.hooks[event] = [...nonBashstats, bashstatsEntry]\n }\n\n return result\n}\n\n/**\n * Returns the path to ~/.claude/settings.json\n */\nexport function getClaudeSettingsPath(): string {\n return path.join(os.homedir(), '.claude', 'settings.json')\n}\n\n/**\n * Returns the path to the dist/hooks/ directory, resolved from this module's location.\n */\nexport function getHooksDir(): string {\n const __filename = fileURLToPath(import.meta.url)\n const __dirname = path.dirname(__filename)\n return path.resolve(__dirname, 'hooks')\n}\n\n/**\n * Full installation:\n * - Creates ~/.bashstats/ directory\n * - Initializes the database with metadata\n * - Reads existing ~/.claude/settings.json\n * - Merges bashstats hooks\n * - Writes settings back\n */\nexport function install(): { success: boolean; message: string } {\n try {\n // Create data directory\n const dataDir = path.join(os.homedir(), DATA_DIR)\n fs.mkdirSync(dataDir, { recursive: true })\n\n // Initialize database\n const dbPath = path.join(dataDir, DB_FILENAME)\n const db = new BashStatsDB(dbPath)\n const now = new Date().toISOString()\n db.setMetadata('installed_at', now)\n if (!db.getMetadata('first_run')) {\n db.setMetadata('first_run', now)\n }\n db.close()\n\n // Ensure ~/.claude/ directory exists\n const claudeDir = path.join(os.homedir(), '.claude')\n fs.mkdirSync(claudeDir, { recursive: true })\n\n // Read existing settings\n const settingsPath = getClaudeSettingsPath()\n let settings: Record<string, unknown> = {}\n if (fs.existsSync(settingsPath)) {\n const raw = fs.readFileSync(settingsPath, 'utf-8')\n settings = JSON.parse(raw)\n }\n\n // Merge hooks\n const hooksDir = getHooksDir()\n settings = mergeHooks(settings, hooksDir)\n\n // Write settings back\n fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8')\n\n return { success: true, message: 'bashstats hooks installed successfully.' }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return { success: false, message: `Installation failed: ${message}` }\n }\n}\n\n/**\n * Removes all bashstats hooks from ~/.claude/settings.json.\n * Cleans up empty arrays and empty hooks objects.\n */\nexport function uninstall(): { success: boolean; message: string } {\n try {\n const settingsPath = getClaudeSettingsPath()\n if (!fs.existsSync(settingsPath)) {\n return { success: true, message: 'No settings.json found; nothing to uninstall.' }\n }\n\n const raw = fs.readFileSync(settingsPath, 'utf-8')\n const settings: Settings = JSON.parse(raw)\n\n if (settings.hooks) {\n for (const event of Object.keys(settings.hooks)) {\n // Filter out bashstats-managed entries\n settings.hooks[event] = settings.hooks[event].filter((entry) => {\n return !entry.hooks?.some((h) => h.command?.includes(MARKER))\n })\n\n // Clean up empty arrays\n if (settings.hooks[event].length === 0) {\n delete settings.hooks[event]\n }\n }\n\n // Clean up empty hooks object\n if (Object.keys(settings.hooks).length === 0) {\n delete settings.hooks\n }\n }\n\n fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8')\n\n return { success: true, message: 'bashstats hooks removed successfully.' }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return { success: false, message: `Uninstall failed: ${message}` }\n }\n}\n\n/**\n * Checks if bashstats hooks are currently present in ~/.claude/settings.json.\n */\nexport function isInstalled(): boolean {\n try {\n const settingsPath = getClaudeSettingsPath()\n if (!fs.existsSync(settingsPath)) return false\n\n const raw = fs.readFileSync(settingsPath, 'utf-8')\n const settings: Settings = JSON.parse(raw)\n\n if (!settings.hooks) return false\n\n // Check if any hook event contains a bashstats-managed entry\n for (const event of Object.keys(settings.hooks)) {\n const entries = settings.hooks[event]\n for (const entry of entries) {\n if (entry.hooks?.some((h) => h.command?.includes(MARKER))) {\n return true\n }\n }\n }\n\n return false\n } catch {\n return false\n }\n}\n","import fs from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport { DATA_DIR, DB_FILENAME } from '../constants.js'\nimport { BashStatsDB } from '../db/database.js'\nimport { getHooksDir } from './installer.js'\n\n/**\n * Maps each Gemini hook event name to the corresponding script filename.\n *\n * Gemini uses different event names than Claude. Our normalizer maps:\n * SessionStart -> session-start.js\n * SessionEnd -> stop.js (normalizer converts to Stop)\n * BeforeAgent -> user-prompt-submit.js (normalizer converts to UserPromptSubmit)\n * BeforeTool -> pre-tool-use.js\n * AfterTool -> post-tool-use.js\n * AfterModel -> stop.js (handler accumulates tokens; script is a no-op)\n * PreCompress -> pre-compact.js\n * Notification -> notification.js\n */\nexport const GEMINI_HOOK_SCRIPTS: Record<string, string> = {\n SessionStart: 'session-start.js',\n SessionEnd: 'stop.js',\n BeforeAgent: 'user-prompt-submit.js',\n BeforeTool: 'pre-tool-use.js',\n AfterTool: 'post-tool-use.js',\n AfterModel: 'stop.js',\n PreCompress: 'pre-compact.js',\n Notification: 'notification.js',\n}\n\n/** Marker comment appended to bashstats hook commands for identification. */\nconst MARKER = '# bashstats-managed'\n\n/** Default timeout (in seconds) for Gemini hook commands. */\nconst DEFAULT_TIMEOUT = 10\n\ninterface GeminiHookCommand {\n name: string\n type: string\n command: string\n timeout: number\n}\n\ninterface GeminiHookEntry {\n hooks: GeminiHookCommand[]\n}\n\ninterface GeminiHooksMap {\n [event: string]: GeminiHookEntry[]\n}\n\ninterface GeminiSettings {\n hooks?: GeminiHooksMap\n [key: string]: unknown\n}\n\n/**\n * Merges bashstats hooks into a Gemini settings object without overwriting existing hooks.\n * Uses the `# bashstats-managed` marker to identify our hooks for idempotent updates.\n *\n * Gemini hook structure: { hooks: { EventName: [{ hooks: [{ name, type, command, timeout }] }] } }\n */\nexport function mergeGeminiHooks(settings: Record<string, unknown>, hooksDir: string): Record<string, unknown> {\n const result: GeminiSettings = { ...settings }\n\n if (!result.hooks) {\n result.hooks = {}\n }\n\n for (const [event, scriptFile] of Object.entries(GEMINI_HOOK_SCRIPTS)) {\n const command = `node \"${path.join(hooksDir, scriptFile)}\" ${MARKER}`\n\n // Get existing entries for this event, or empty array\n const existing: GeminiHookEntry[] = result.hooks[event] ?? []\n\n // Filter out any previous bashstats-managed hooks\n const nonBashstats = existing.filter((entry) => {\n return !entry.hooks?.some((h) => h.command?.includes(MARKER))\n })\n\n // Build the new bashstats hook entry\n const bashstatsEntry: GeminiHookEntry = {\n hooks: [{ name: 'bashstats', type: 'command', command, timeout: DEFAULT_TIMEOUT }],\n }\n\n // Add bashstats entry alongside preserved hooks\n result.hooks[event] = [...nonBashstats, bashstatsEntry]\n }\n\n return result\n}\n\n/**\n * Returns the path to ~/.gemini/settings.json\n */\nexport function getGeminiSettingsPath(): string {\n return path.join(os.homedir(), '.gemini', 'settings.json')\n}\n\n/**\n * Checks if the ~/.gemini/ directory exists, indicating Gemini CLI is available.\n */\nexport function isGeminiAvailable(): boolean {\n try {\n const geminiDir = path.join(os.homedir(), '.gemini')\n return fs.existsSync(geminiDir) && fs.statSync(geminiDir).isDirectory()\n } catch {\n return false\n }\n}\n\n/**\n * Checks if bashstats hooks are currently present in ~/.gemini/settings.json.\n */\nexport function isGeminiInstalled(): boolean {\n try {\n const settingsPath = getGeminiSettingsPath()\n if (!fs.existsSync(settingsPath)) return false\n\n const raw = fs.readFileSync(settingsPath, 'utf-8')\n const settings: GeminiSettings = JSON.parse(raw)\n\n if (!settings.hooks) return false\n\n // Check if any hook event contains a bashstats-managed entry\n for (const event of Object.keys(settings.hooks)) {\n const entries = settings.hooks[event]\n for (const entry of entries) {\n if (entry.hooks?.some((h) => h.command?.includes(MARKER))) {\n return true\n }\n }\n }\n\n return false\n } catch {\n return false\n }\n}\n\n/**\n * Full Gemini installation:\n * - Creates ~/.bashstats/ directory\n * - Initializes the database with metadata\n * - Reads existing ~/.gemini/settings.json\n * - Merges bashstats hooks\n * - Writes settings back\n */\nexport function installGemini(): { success: boolean; message: string } {\n try {\n // Create data directory\n const dataDir = path.join(os.homedir(), DATA_DIR)\n fs.mkdirSync(dataDir, { recursive: true })\n\n // Initialize database\n const dbPath = path.join(dataDir, DB_FILENAME)\n const db = new BashStatsDB(dbPath)\n const now = new Date().toISOString()\n db.setMetadata('installed_at', now)\n if (!db.getMetadata('first_run')) {\n db.setMetadata('first_run', now)\n }\n db.close()\n\n // Ensure ~/.gemini/ directory exists\n const geminiDir = path.join(os.homedir(), '.gemini')\n fs.mkdirSync(geminiDir, { recursive: true })\n\n // Read existing settings\n const settingsPath = getGeminiSettingsPath()\n let settings: Record<string, unknown> = {}\n if (fs.existsSync(settingsPath)) {\n const raw = fs.readFileSync(settingsPath, 'utf-8')\n settings = JSON.parse(raw)\n }\n\n // Merge hooks\n const hooksDir = getHooksDir()\n settings = mergeGeminiHooks(settings, hooksDir)\n\n // Write settings back\n fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8')\n\n return { success: true, message: 'bashstats Gemini hooks installed successfully.' }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return { success: false, message: `Gemini installation failed: ${message}` }\n }\n}\n\n/**\n * Removes all bashstats hooks from ~/.gemini/settings.json.\n * Cleans up empty arrays and empty hooks objects.\n */\nexport function uninstallGemini(): { success: boolean; message: string } {\n try {\n const settingsPath = getGeminiSettingsPath()\n if (!fs.existsSync(settingsPath)) {\n return { success: true, message: 'No Gemini settings.json found; nothing to uninstall.' }\n }\n\n const raw = fs.readFileSync(settingsPath, 'utf-8')\n const settings: GeminiSettings = JSON.parse(raw)\n\n if (settings.hooks) {\n for (const event of Object.keys(settings.hooks)) {\n // Filter out bashstats-managed entries\n settings.hooks[event] = settings.hooks[event].filter((entry) => {\n return !entry.hooks?.some((h) => h.command?.includes(MARKER))\n })\n\n // Clean up empty arrays\n if (settings.hooks[event].length === 0) {\n delete settings.hooks[event]\n }\n }\n\n // Clean up empty hooks object\n if (Object.keys(settings.hooks).length === 0) {\n delete settings.hooks\n }\n }\n\n fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8')\n\n return { success: true, message: 'bashstats Gemini hooks removed successfully.' }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return { success: false, message: `Gemini uninstall failed: ${message}` }\n }\n}\n","import fs from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport { execSync } from 'child_process'\nimport { getHooksDir } from './installer.js'\n\n/**\n * Maps Copilot hook event names to the corresponding bashstats script filenames.\n */\nexport const COPILOT_HOOK_SCRIPTS: Record<string, string> = {\n sessionStart: 'session-start.js',\n sessionEnd: 'stop.js',\n userPromptSubmitted: 'user-prompt-submit.js',\n preToolUse: 'pre-tool-use.js',\n postToolUse: 'post-tool-use.js',\n errorOccurred: 'post-tool-failure.js',\n}\n\n/** Comment marker for identifying bashstats-managed hook entries. */\nconst COMMENT_MARKER = 'bashstats-managed'\n\ninterface CopilotHookEntry {\n type: string\n bash: string\n powershell: string\n timeoutSec: number\n comment: string\n}\n\ninterface CopilotHooksConfig {\n version: number\n hooks: Record<string, CopilotHookEntry[]>\n}\n\n/**\n * Builds the complete Copilot hooks JSON config for bashstats.\n * Each event maps to a single hook entry with both bash and powershell commands.\n */\nexport function buildCopilotHooksConfig(hooksDir: string): CopilotHooksConfig {\n const hooks: Record<string, CopilotHookEntry[]> = {}\n\n for (const [event, scriptFile] of Object.entries(COPILOT_HOOK_SCRIPTS)) {\n const scriptPath = path.join(hooksDir, scriptFile)\n hooks[event] = [\n {\n type: 'command',\n bash: `node \"${scriptPath}\"`,\n powershell: `node \"${scriptPath}\"`,\n timeoutSec: 30,\n comment: COMMENT_MARKER,\n },\n ]\n }\n\n return { version: 1, hooks }\n}\n\n/**\n * Returns the path to ~/.copilot/hooks/bashstats-hooks.json\n */\nexport function getCopilotHooksPath(): string {\n return path.join(os.homedir(), '.copilot', 'hooks', 'bashstats-hooks.json')\n}\n\n/**\n * Installs bashstats hooks for Copilot by writing bashstats-hooks.json\n * to ~/.copilot/hooks/.\n */\nexport function installCopilot(): { success: boolean; message: string } {\n try {\n const hooksPath = getCopilotHooksPath()\n const hooksDir = path.dirname(hooksPath)\n\n // Ensure ~/.copilot/hooks/ directory exists\n fs.mkdirSync(hooksDir, { recursive: true })\n\n // Build and write the hooks config\n const distHooksDir = getHooksDir()\n const config = buildCopilotHooksConfig(distHooksDir)\n fs.writeFileSync(hooksPath, JSON.stringify(config, null, 2), 'utf-8')\n\n return { success: true, message: 'Copilot bashstats hooks installed successfully.' }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return { success: false, message: `Copilot installation failed: ${message}` }\n }\n}\n\n/**\n * Uninstalls bashstats hooks for Copilot by deleting bashstats-hooks.json.\n */\nexport function uninstallCopilot(): { success: boolean; message: string } {\n try {\n const hooksPath = getCopilotHooksPath()\n\n if (!fs.existsSync(hooksPath)) {\n return { success: true, message: 'No bashstats-hooks.json found; nothing to uninstall.' }\n }\n\n fs.unlinkSync(hooksPath)\n return { success: true, message: 'Copilot bashstats hooks removed successfully.' }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return { success: false, message: `Copilot uninstall failed: ${message}` }\n }\n}\n\n/**\n * Checks if the `copilot` binary is available on PATH.\n */\nexport function isCopilotAvailable(): boolean {\n try {\n execSync('copilot --version', { stdio: 'ignore', timeout: 5000 })\n return true\n } catch {\n return false\n }\n}\n","import fs from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport { DATA_DIR, DB_FILENAME } from '../constants.js'\n\n/**\n * Returns the OpenCode plugins directory path: ~/.config/opencode/plugins/\n */\nexport function getOpenCodePluginsDir(): string {\n return path.join(os.homedir(), '.config', 'opencode', 'plugins')\n}\n\n/**\n * Returns the full path to the bashstats plugin file inside OpenCode's plugins directory.\n */\nexport function getOpenCodePluginPath(): string {\n return path.join(getOpenCodePluginsDir(), 'bashstats.ts')\n}\n\n/**\n * Checks whether OpenCode is available by looking for ~/.config/opencode/.\n */\nexport function isOpenCodeAvailable(): boolean {\n try {\n return fs.existsSync(path.join(os.homedir(), '.config', 'opencode'))\n } catch {\n return false\n }\n}\n\n/**\n * Generates the self-contained TypeScript plugin source that OpenCode loads in-process.\n *\n * The plugin uses `better-sqlite3` directly (not our modules) because OpenCode\n * loads plugins separately. It opens and closes the DB per event to avoid\n * long-lived connections.\n *\n * @param dbPath - Absolute path to the bashstats SQLite database\n */\nexport function getOpenCodePluginContent(dbPath: string): string {\n return `// bashstats plugin for OpenCode -- auto-generated, do not edit\n// Tracks coding sessions, tool usage, and prompts for bashstats achievements.\n\nimport Database from \"better-sqlite3\";\n\nconst DB_PATH = ${JSON.stringify(dbPath)};\n\nfunction today(): string {\n const d = new Date();\n const pad = (n: number) => String(n).padStart(2, \"0\");\n return \\`\\${d.getFullYear()}-\\${pad(d.getMonth() + 1)}-\\${pad(d.getDate())}\\`;\n}\n\nfunction localNow(): string {\n const d = new Date();\n const pad = (n: number) => String(n).padStart(2, \"0\");\n const ms = String(d.getMilliseconds()).padStart(3, \"0\");\n return \\`\\${d.getFullYear()}-\\${pad(d.getMonth() + 1)}-\\${pad(d.getDate())}T\\${pad(d.getHours())}:\\${pad(d.getMinutes())}:\\${pad(d.getSeconds())}.\\${ms}\\`;\n}\n\nfunction withDb<T>(fn: (db: InstanceType<typeof Database>) => T): T | undefined {\n let db: InstanceType<typeof Database> | undefined;\n try {\n db = new Database(DB_PATH);\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"busy_timeout = 5000\");\n return fn(db);\n } catch {\n // silently ignore DB errors so we never break the host\n } finally {\n try { db?.close(); } catch {}\n }\n return undefined;\n}\n\nfunction insertEvent(db: InstanceType<typeof Database>, sessionId: string, hookType: string, toolName?: string, toolInput?: string, project?: string): void {\n db.prepare(\n \"INSERT INTO events (session_id, hook_type, tool_name, tool_input, cwd, project, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?)\"\n ).run(sessionId, hookType, toolName ?? null, toolInput ?? null, null, project ?? null, localNow());\n}\n\nfunction incrementDaily(db: InstanceType<typeof Database>, increments: { sessions?: number; prompts?: number; tool_calls?: number; errors?: number; duration_seconds?: number }): void {\n const date = today();\n db.prepare(\n \\`INSERT INTO daily_activity (date, sessions, prompts, tool_calls, errors, duration_seconds, input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens)\n VALUES (?, ?, ?, ?, ?, ?, 0, 0, 0, 0)\n ON CONFLICT(date) DO UPDATE SET\n sessions = sessions + excluded.sessions,\n prompts = prompts + excluded.prompts,\n tool_calls = tool_calls + excluded.tool_calls,\n errors = errors + excluded.errors,\n duration_seconds = duration_seconds + excluded.duration_seconds\\`\n ).run(\n date,\n increments.sessions ?? 0,\n increments.prompts ?? 0,\n increments.tool_calls ?? 0,\n increments.errors ?? 0,\n increments.duration_seconds ?? 0,\n );\n}\n\nexport default async ({ project, directory }: { project?: string; directory?: string }) => {\n const sessionId = \\`opencode-\\${Date.now()}\\`;\n const startedAt = localNow();\n const projectName = project ?? directory ?? null;\n\n // Create session on plugin load\n withDb((db) => {\n db.prepare(\n \"INSERT OR IGNORE INTO sessions (id, agent, started_at, project) VALUES (?, ?, ?, ?)\"\n ).run(sessionId, \"opencode\", startedAt, projectName);\n incrementDaily(db, { sessions: 1 });\n });\n\n return {\n event: async ({ event }: { event: { type: string; properties?: Record<string, unknown> } }) => {\n const eventType = event.type;\n const props = event.properties ?? {};\n\n if (eventType === \"session.created\") {\n withDb((db) => {\n db.prepare(\n \"INSERT OR IGNORE INTO sessions (id, agent, started_at, project) VALUES (?, ?, ?, ?)\"\n ).run(sessionId, \"opencode\", startedAt, projectName);\n incrementDaily(db, { sessions: 1 });\n });\n }\n\n else if (eventType === \"session.idle\" || eventType === \"session.deleted\") {\n withDb((db) => {\n const endedAt = localNow();\n const startMs = new Date(startedAt).getTime();\n const endMs = new Date(endedAt).getTime();\n const durationSeconds = Math.max(0, Math.floor((endMs - startMs) / 1000));\n const stopReason = eventType === \"session.idle\" ? \"idle\" : \"deleted\";\n db.prepare(\n \"UPDATE sessions SET ended_at = ?, stop_reason = ?, duration_seconds = ? WHERE id = ?\"\n ).run(endedAt, stopReason, durationSeconds, sessionId);\n incrementDaily(db, { duration_seconds: durationSeconds });\n });\n }\n\n else if (eventType === \"tool.execute.before\") {\n withDb((db) => {\n const toolName = (props.tool as string) ?? \"unknown\";\n const toolInput = props.input ? JSON.stringify(props.input) : null;\n insertEvent(db, sessionId, \"PreToolUse\", toolName, toolInput, projectName ?? undefined);\n });\n }\n\n else if (eventType === \"tool.execute.after\") {\n withDb((db) => {\n const toolName = (props.tool as string) ?? \"unknown\";\n const toolInput = props.input ? JSON.stringify(props.input) : null;\n insertEvent(db, sessionId, \"PostToolUse\", toolName, toolInput, projectName ?? undefined);\n db.prepare(\n \"UPDATE sessions SET tool_count = tool_count + 1 WHERE id = ?\"\n ).run(sessionId);\n incrementDaily(db, { tool_calls: 1 });\n });\n }\n\n else if (eventType === \"session.error\") {\n withDb((db) => {\n const toolName = (props.tool as string) ?? null;\n insertEvent(db, sessionId, \"PostToolUseFailure\", toolName ?? undefined, undefined, projectName ?? undefined);\n db.prepare(\n \"UPDATE sessions SET error_count = error_count + 1 WHERE id = ?\"\n ).run(sessionId);\n incrementDaily(db, { errors: 1 });\n });\n }\n\n else if (eventType === \"session.compacted\") {\n withDb((db) => {\n insertEvent(db, sessionId, \"PreCompact\", undefined, undefined, projectName ?? undefined);\n });\n }\n\n else if (eventType === \"message.updated\") {\n const role = props.role as string | undefined;\n if (role === \"user\") {\n withDb((db) => {\n const content = (props.content as string) ?? \"\";\n const charCount = content.length;\n const wordCount = content.trim() === \"\" ? 0 : content.trim().split(/\\\\s+/).length;\n db.prepare(\n \"INSERT INTO prompts (session_id, content, char_count, word_count, timestamp) VALUES (?, ?, ?, ?, ?)\"\n ).run(sessionId, content, charCount, wordCount, localNow());\n db.prepare(\n \"UPDATE sessions SET prompt_count = prompt_count + 1 WHERE id = ?\"\n ).run(sessionId);\n incrementDaily(db, { prompts: 1 });\n });\n }\n }\n },\n };\n};\n`\n}\n\n/**\n * Installs the bashstats plugin into OpenCode's plugins directory.\n * Creates the plugins directory if it does not exist.\n */\nexport function installOpenCode(): { success: boolean; message: string } {\n try {\n const dataDir = path.join(os.homedir(), DATA_DIR)\n fs.mkdirSync(dataDir, { recursive: true })\n\n const dbPath = path.join(dataDir, DB_FILENAME)\n const pluginsDir = getOpenCodePluginsDir()\n fs.mkdirSync(pluginsDir, { recursive: true })\n\n const pluginPath = getOpenCodePluginPath()\n const content = getOpenCodePluginContent(dbPath)\n fs.writeFileSync(pluginPath, content, 'utf-8')\n\n return { success: true, message: `bashstats plugin installed at ${pluginPath}` }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return { success: false, message: `OpenCode plugin install failed: ${message}` }\n }\n}\n\n/**\n * Removes the bashstats plugin file from OpenCode's plugins directory.\n */\nexport function uninstallOpenCode(): { success: boolean; message: string } {\n try {\n const pluginPath = getOpenCodePluginPath()\n if (fs.existsSync(pluginPath)) {\n fs.unlinkSync(pluginPath)\n return { success: true, message: 'bashstats plugin removed from OpenCode.' }\n }\n return { success: true, message: 'No bashstats plugin found; nothing to uninstall.' }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return { success: false, message: `OpenCode plugin uninstall failed: ${message}` }\n }\n}\n","import { BashStatsDB } from './database.js'\nimport type { TokenUsage } from '../types.js'\nimport path from 'path'\n\nexport class BashStatsWriter {\n private db: BashStatsDB\n\n constructor(db: BashStatsDB) {\n this.db = db\n }\n\n private extractProject(cwd: string): string {\n return path.basename(cwd)\n }\n\n private today(): string {\n const d = new Date()\n const pad = (n: number) => String(n).padStart(2, '0')\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`\n }\n\n private now(): string {\n const d = new Date()\n const pad = (n: number) => String(n).padStart(2, '0')\n const ms = String(d.getMilliseconds()).padStart(3, '0')\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}.${ms}`\n }\n\n recordSessionStart(sessionId: string, cwd: string, source: string, agent?: string): void {\n const project = this.extractProject(cwd)\n const timestamp = this.now()\n\n this.db.insertSession({\n id: sessionId,\n agent,\n started_at: timestamp,\n project,\n })\n\n this.db.insertEvent({\n session_id: sessionId,\n hook_type: 'SessionStart',\n tool_name: null,\n tool_input: JSON.stringify({ source }),\n tool_output: null,\n exit_code: null,\n success: null,\n cwd,\n project,\n timestamp,\n })\n\n this.db.incrementDailyActivity(this.today(), { sessions: 1 })\n }\n\n recordPrompt(sessionId: string, content: string): void {\n const timestamp = this.now()\n const wordCount = content.split(/\\s+/).filter(w => w.length > 0).length\n const charCount = content.length\n\n this.db.insertPrompt({\n session_id: sessionId,\n content,\n char_count: charCount,\n word_count: wordCount,\n timestamp,\n })\n\n this.db.insertEvent({\n session_id: sessionId,\n hook_type: 'UserPromptSubmit',\n tool_name: null,\n tool_input: null,\n tool_output: null,\n exit_code: null,\n success: null,\n cwd: null,\n project: null,\n timestamp,\n })\n\n this.db.incrementSessionCounters(sessionId, { prompts: 1 })\n this.db.incrementDailyActivity(this.today(), { prompts: 1 })\n }\n\n recordToolUse(\n sessionId: string,\n hookType: string,\n toolName: string,\n toolInput: Record<string, unknown>,\n toolOutput: Record<string, unknown>,\n exitCode: number | null,\n cwd: string,\n ): void {\n const timestamp = this.now()\n const project = this.extractProject(cwd)\n const success = exitCode === 0 ? 1 : 0\n\n this.db.insertEvent({\n session_id: sessionId,\n hook_type: hookType,\n tool_name: toolName,\n tool_input: JSON.stringify(toolInput),\n tool_output: JSON.stringify(toolOutput),\n exit_code: exitCode,\n success,\n cwd,\n project,\n timestamp,\n })\n\n this.db.incrementSessionCounters(sessionId, {\n tools: 1,\n errors: success === 0 ? 1 : 0,\n })\n\n this.db.incrementDailyActivity(this.today(), {\n tool_calls: 1,\n errors: success === 0 ? 1 : 0,\n })\n }\n\n recordSessionEnd(sessionId: string, stopReason: string, tokens?: TokenUsage | null): void {\n const timestamp = this.now()\n const session = this.db.getSession(sessionId)\n\n let durationSeconds: number | undefined\n if (session) {\n const startTime = new Date(session.started_at).getTime()\n const endTime = new Date(timestamp).getTime()\n durationSeconds = Math.round((endTime - startTime) / 1000)\n }\n\n this.db.updateSession(sessionId, {\n ended_at: timestamp,\n stop_reason: stopReason,\n duration_seconds: durationSeconds,\n })\n\n if (tokens) {\n this.db.updateSessionTokens(sessionId, tokens)\n }\n\n this.db.insertEvent({\n session_id: sessionId,\n hook_type: 'Stop',\n tool_name: null,\n tool_input: JSON.stringify({ stop_reason: stopReason }),\n tool_output: null,\n exit_code: null,\n success: null,\n cwd: null,\n project: null,\n timestamp,\n })\n\n const dailyIncrements: Record<string, number> = {}\n if (durationSeconds !== undefined) {\n dailyIncrements.duration_seconds = durationSeconds\n }\n if (tokens) {\n dailyIncrements.input_tokens = tokens.input_tokens\n dailyIncrements.output_tokens = tokens.output_tokens\n dailyIncrements.cache_creation_input_tokens = tokens.cache_creation_input_tokens\n dailyIncrements.cache_read_input_tokens = tokens.cache_read_input_tokens\n }\n if (Object.keys(dailyIncrements).length > 0) {\n this.db.incrementDailyActivity(this.today(), dailyIncrements)\n }\n }\n\n recordNotification(sessionId: string, message: string, notificationType: string): void {\n const timestamp = this.now()\n const isError = notificationType === 'error' || notificationType === 'rate_limit'\n\n this.db.insertEvent({\n session_id: sessionId,\n hook_type: 'Notification',\n tool_name: null,\n tool_input: JSON.stringify({ message, notification_type: notificationType }),\n tool_output: null,\n exit_code: null,\n success: null,\n cwd: null,\n project: null,\n timestamp,\n })\n\n if (isError) {\n this.db.incrementSessionCounters(sessionId, { errors: 1 })\n this.db.incrementDailyActivity(this.today(), { errors: 1 })\n }\n }\n\n recordSubagent(sessionId: string, hookType: string, agentId: string, agentType?: string): void {\n const timestamp = this.now()\n\n this.db.insertEvent({\n session_id: sessionId,\n hook_type: hookType,\n tool_name: null,\n tool_input: JSON.stringify({ agent_id: agentId, agent_type: agentType ?? null }),\n tool_output: null,\n exit_code: null,\n success: null,\n cwd: null,\n project: null,\n timestamp,\n })\n }\n\n recordCompaction(sessionId: string, trigger: string): void {\n const timestamp = this.now()\n\n this.db.insertEvent({\n session_id: sessionId,\n hook_type: 'PreCompact',\n tool_name: null,\n tool_input: JSON.stringify({ trigger }),\n tool_output: null,\n exit_code: null,\n success: null,\n cwd: null,\n project: null,\n timestamp,\n })\n }\n}\n","import path from 'path'\nimport os from 'os'\nimport fs from 'fs'\nimport { DATA_DIR, DB_FILENAME } from '../constants.js'\nimport { BashStatsDB } from '../db/database.js'\nimport { BashStatsWriter } from '../db/writer.js'\nimport type { AgentType, TokenUsage } from '../types.js'\nimport { extractTokenUsage } from './transcript.js'\nimport { normalizeGeminiEvent } from './normalizers/gemini.js'\nimport { normalizeCopilotEvent } from './normalizers/copilot.js'\n\n/**\n * Detect which CLI agent is running based on environment variables and process context.\n * Currently supports Claude Code (default), Gemini CLI, Copilot CLI, and OpenCode.\n */\nexport function detectAgent(): AgentType {\n if (process.env.GEMINI_SESSION_ID || process.env.GEMINI_PROJECT_DIR || process.env.GEMINI_CLI) return 'gemini-cli'\n if (process.env.GITHUB_COPILOT_CLI) return 'copilot-cli'\n if (process.env.OPENCODE) return 'opencode'\n return 'claude-code'\n}\n\nexport function parseHookEvent(input: string): Record<string, unknown> | null {\n try {\n if (!input) return null\n return JSON.parse(input) as Record<string, unknown>\n } catch {\n return null\n }\n}\n\nexport function getProjectFromCwd(cwd: string): string {\n return path.basename(cwd)\n}\n\nexport function getDataDir(): string {\n return path.join(os.homedir(), DATA_DIR)\n}\n\nexport function getDbPath(): string {\n return path.join(os.homedir(), DATA_DIR, DB_FILENAME)\n}\n\nexport async function readStdin(): Promise<string> {\n if (process.env.CLAUDE_HOOK_EVENT) {\n return process.env.CLAUDE_HOOK_EVENT\n }\n\n return new Promise<string>((resolve) => {\n let data = ''\n process.stdin.setEncoding('utf-8')\n process.stdin.on('data', (chunk: string) => {\n data += chunk\n })\n process.stdin.on('end', () => {\n resolve(data)\n })\n })\n}\n\nexport async function handleHookEvent(hookType: string): Promise<void> {\n const raw = await readStdin()\n const event = parseHookEvent(raw)\n if (!event) return\n\n const dataDir = getDataDir()\n fs.mkdirSync(dataDir, { recursive: true })\n\n const dbPath = getDbPath()\n const db = new BashStatsDB(dbPath)\n const writer = new BashStatsWriter(db)\n\n try {\n const agent = detectAgent()\n\n // Normalize events for non-Claude agents\n let effectiveHookType = hookType\n let payload: Record<string, unknown> = event\n\n if (agent === 'gemini-cli') {\n const normalized = normalizeGeminiEvent(hookType, event)\n if (!normalized) return\n\n // For AfterModel events, accumulate token counts in metadata and return early\n if (normalized.hookType === 'AfterModel') {\n if (normalized.tokenData) {\n const sessionId = (event.session_id as string) ?? ''\n const metaKey = `gemini_tokens_${sessionId}`\n const existing = db.getMetadata(metaKey)\n const prev = existing ? parseInt(existing, 10) : 0\n db.setMetadata(metaKey, String(prev + normalized.tokenData.totalTokenCount))\n }\n return\n }\n\n effectiveHookType = normalized.hookType\n payload = normalized.payload\n } else if (agent === 'copilot-cli') {\n const normalized = normalizeCopilotEvent(hookType, event)\n if (!normalized) return\n\n effectiveHookType = normalized.hookType\n payload = normalized.payload\n }\n\n const sessionId = (payload.session_id as string) ?? ''\n const cwd = (payload.cwd as string) ?? ''\n\n switch (effectiveHookType) {\n case 'SessionStart': {\n const source = (payload.source as string) ?? 'startup'\n writer.recordSessionStart(sessionId, cwd, source, agent)\n break\n }\n\n case 'UserPromptSubmit': {\n const prompt = (payload.prompt as string) ?? ''\n writer.recordPrompt(sessionId, prompt)\n break\n }\n\n case 'PreToolUse': {\n const toolName = (payload.tool_name as string) ?? ''\n const toolInput = (payload.tool_input as Record<string, unknown>) ?? {}\n writer.recordToolUse(sessionId, 'PreToolUse', toolName, toolInput, {}, 0, cwd)\n break\n }\n\n case 'PostToolUse': {\n const toolName = (payload.tool_name as string) ?? ''\n const toolInput = (payload.tool_input as Record<string, unknown>) ?? {}\n const toolResponse = (payload.tool_response as Record<string, unknown>) ?? {}\n const exitCode = (payload.exit_code as number) ?? 0\n writer.recordToolUse(sessionId, 'PostToolUse', toolName, toolInput, toolResponse, exitCode, cwd)\n break\n }\n\n case 'PostToolUseFailure': {\n const toolName = (payload.tool_name as string) ?? ''\n const toolInput = (payload.tool_input as Record<string, unknown>) ?? {}\n const toolResponse = (payload.tool_response as Record<string, unknown>) ?? {}\n writer.recordToolUse(sessionId, 'PostToolUseFailure', toolName, toolInput, toolResponse, 1, cwd)\n break\n }\n\n case 'Stop': {\n let tokens: TokenUsage | null = null\n\n if (agent === 'gemini-cli') {\n // Retrieve accumulated tokens from metadata\n const metaKey = `gemini_tokens_${sessionId}`\n const stored = db.getMetadata(metaKey)\n if (stored) {\n const totalTokens = parseInt(stored, 10)\n // Approximate 70/30 split for input/output\n const inputTokens = Math.round(totalTokens * 0.7)\n const outputTokens = totalTokens - inputTokens\n tokens = {\n input_tokens: inputTokens,\n output_tokens: outputTokens,\n cache_creation_input_tokens: 0,\n cache_read_input_tokens: 0,\n }\n }\n } else if (agent === 'copilot-cli') {\n // Copilot CLI does not provide token data through hooks\n tokens = null\n } else {\n // Claude Code: parse transcript file for tokens\n const rawPath = (payload.transcript_path as string) ?? ''\n const transcriptPath = rawPath && rawPath.endsWith('.jsonl') ? path.resolve(rawPath) : ''\n tokens = transcriptPath ? await extractTokenUsage(transcriptPath) : null\n }\n\n writer.recordSessionEnd(sessionId, 'stopped', tokens)\n break\n }\n\n case 'Notification': {\n const message = (payload.message as string) ?? ''\n const notificationType = (payload.notification_type as string) ?? ''\n writer.recordNotification(sessionId, message, notificationType)\n break\n }\n\n case 'SubagentStart': {\n const agentId = (payload.agent_id as string) ?? ''\n const agentType = (payload.agent_type as string) ?? ''\n writer.recordSubagent(sessionId, 'SubagentStart', agentId, agentType)\n break\n }\n\n case 'SubagentStop': {\n const agentId = (payload.agent_id as string) ?? ''\n writer.recordSubagent(sessionId, 'SubagentStop', agentId)\n break\n }\n\n case 'PreCompact': {\n const trigger = (payload.trigger as string) ?? 'manual'\n writer.recordCompaction(sessionId, trigger)\n break\n }\n\n case 'PermissionRequest': {\n const toolName = (payload.tool_name as string) ?? ''\n const toolInput = (payload.tool_input as Record<string, unknown>) ?? {}\n writer.recordToolUse(sessionId, 'PermissionRequest', toolName, toolInput, {}, 0, cwd)\n break\n }\n\n case 'Setup': {\n // no-op\n return\n }\n }\n } finally {\n db.close()\n }\n}\n","import fs from 'fs'\nimport readline from 'readline'\nimport type { TokenUsage } from '../types.js'\n\n/**\n * Read a Claude Code transcript JSONL file and sum all token usage.\n *\n * Claude Code writes multiple transcript entries per API call (one per streaming\n * content block), each carrying the same usage object. We deduplicate by message\n * ID so each API call's usage is counted exactly once.\n *\n * Returns null on any failure (missing file, no usage data, parse errors).\n */\nexport async function extractTokenUsage(transcriptPath: string): Promise<TokenUsage | null> {\n try {\n if (!fs.existsSync(transcriptPath)) return null\n\n const stream = fs.createReadStream(transcriptPath, { encoding: 'utf-8' })\n const rl = readline.createInterface({ input: stream, crlfDelay: Infinity })\n\n // Track usage per unique message ID to avoid counting streaming duplicates\n const seenMessages = new Map<string, {\n input_tokens: number\n output_tokens: number\n cache_creation_input_tokens: number\n cache_read_input_tokens: number\n }>()\n\n for await (const line of rl) {\n if (!line.trim()) continue\n try {\n const entry = JSON.parse(line)\n const usage = entry.usage ?? entry.response?.usage ?? entry.message?.usage\n if (usage && typeof usage === 'object' && 'input_tokens' in usage) {\n // Use message ID to deduplicate; fall back to a unique key if absent\n const msgId = entry.message?.id ?? entry.id ?? `_line_${seenMessages.size}`\n // Keep the last occurrence (most complete usage data for this message)\n seenMessages.set(msgId, {\n input_tokens: usage.input_tokens ?? 0,\n output_tokens: usage.output_tokens ?? 0,\n cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,\n cache_read_input_tokens: usage.cache_read_input_tokens ?? 0,\n })\n }\n } catch {\n // skip unparseable lines\n }\n }\n\n if (seenMessages.size === 0) return null\n\n let inputTokens = 0\n let outputTokens = 0\n let cacheCreation = 0\n let cacheRead = 0\n for (const u of seenMessages.values()) {\n inputTokens += u.input_tokens\n outputTokens += u.output_tokens\n cacheCreation += u.cache_creation_input_tokens\n cacheRead += u.cache_read_input_tokens\n }\n\n return {\n input_tokens: inputTokens,\n output_tokens: outputTokens,\n cache_creation_input_tokens: cacheCreation,\n cache_read_input_tokens: cacheRead,\n }\n } catch {\n return null\n }\n}\n","/**\n * Gemini CLI hook event normalizer.\n *\n * Translates Gemini CLI hook event names and payloads into bashstats's\n * internal format so the shared handler can process them uniformly.\n */\n\nexport interface NormalizedEvent {\n hookType: string\n payload: Record<string, unknown>\n tokenData?: { totalTokenCount: number }\n}\n\n/**\n * Map a Gemini CLI hook event to a bashstats NormalizedEvent.\n * Returns null for events that have no bashstats equivalent.\n */\nexport function normalizeGeminiEvent(\n geminiEvent: string,\n raw: Record<string, unknown>,\n): NormalizedEvent | null {\n switch (geminiEvent) {\n case 'SessionStart':\n return { hookType: 'SessionStart', payload: raw }\n\n case 'SessionEnd':\n return {\n hookType: 'Stop',\n payload: { ...raw, stop_hook_active: false },\n }\n\n case 'BeforeAgent':\n return { hookType: 'UserPromptSubmit', payload: raw }\n\n case 'BeforeTool':\n return { hookType: 'PreToolUse', payload: raw }\n\n case 'AfterTool':\n return { hookType: 'PostToolUse', payload: raw }\n\n case 'AfterModel': {\n const usageMetadata = (\n raw.llm_response as Record<string, unknown> | undefined\n )?.usageMetadata as Record<string, unknown> | undefined\n\n const totalTokenCount =\n typeof usageMetadata?.totalTokenCount === 'number'\n ? usageMetadata.totalTokenCount\n : undefined\n\n return {\n hookType: 'AfterModel',\n payload: raw,\n ...(totalTokenCount !== undefined ? { tokenData: { totalTokenCount } } : {}),\n }\n }\n\n case 'PreCompress':\n return { hookType: 'PreCompact', payload: raw }\n\n case 'Notification':\n return { hookType: 'Notification', payload: raw }\n\n default:\n return null\n }\n}\n","/**\n * Copilot CLI hook event normalizer.\n *\n * Translates Copilot CLI hook event names and payloads into bashstats's\n * internal format so the shared handler can process them uniformly.\n *\n * Key differences from Claude/Gemini:\n * - Copilot uses camelCase event names (sessionStart, not SessionStart)\n * - toolArgs is a stringified JSON string, not an object\n * - No session_id in payloads -- derived from PPID + date (parent process\n * is the Copilot CLI process, consistent across all hook invocations)\n * - postToolUse can be success OR failure based on toolResult.resultType\n * - errorOccurred maps to PostToolUseFailure with tool_name=\"_error\"\n * - source values: \"new\" -> \"startup\", \"resume\" -> \"resume\"\n */\n\nimport type { NormalizedEvent } from './gemini.js'\n\n/**\n * Safely parse a stringified JSON toolArgs value.\n * Returns {} on any parse failure (malformed JSON, null, undefined, etc.).\n */\nexport function parseToolArgs(toolArgs: string): Record<string, unknown> {\n if (!toolArgs || typeof toolArgs !== 'string') return {}\n try {\n return JSON.parse(toolArgs)\n } catch {\n return {}\n }\n}\n\n/**\n * Derive a session ID for Copilot events.\n * Copilot doesn't provide session_id in hook payloads, so we construct one\n * from the parent process PID (PPID) and the current date (YYYY-MM-DD).\n * Each hook invocation spawns a new child process, but the parent (Copilot CLI)\n * stays the same for the entire session, so PPID is consistent across events.\n */\nfunction deriveSessionId(): string {\n const date = new Date().toISOString().slice(0, 10)\n const ppid = process.ppid ?? process.pid\n return `copilot-${ppid}-${date}`\n}\n\n/**\n * Map Copilot source values to bashstats internal source values.\n * \"new\" -> \"startup\", \"resume\" -> \"resume\", anything else -> \"startup\"\n */\nfunction mapSource(source: unknown): string {\n if (source === 'resume') return 'resume'\n return 'startup'\n}\n\n/**\n * Determine if a postToolUse result represents a failure.\n * resultType of \"failure\" or \"denied\" = failure, everything else = success.\n */\nfunction isToolFailure(toolResult: Record<string, unknown> | undefined): boolean {\n if (!toolResult) return false\n const resultType = toolResult.resultType\n return resultType === 'failure' || resultType === 'denied'\n}\n\n/**\n * Map a Copilot CLI hook event to a bashstats NormalizedEvent.\n * Returns null for events that have no bashstats equivalent.\n */\nexport function normalizeCopilotEvent(\n copilotEvent: string,\n raw: Record<string, unknown>,\n): NormalizedEvent | null {\n const sessionId = deriveSessionId()\n\n switch (copilotEvent) {\n case 'sessionStart': {\n return {\n hookType: 'SessionStart',\n payload: {\n session_id: sessionId,\n source: mapSource(raw.source),\n ...(raw.model !== undefined ? { model: raw.model } : {}),\n },\n }\n }\n\n case 'sessionEnd': {\n return {\n hookType: 'Stop',\n payload: {\n session_id: sessionId,\n ...raw,\n stop_hook_active: false,\n },\n }\n }\n\n case 'userPromptSubmitted': {\n return {\n hookType: 'UserPromptSubmit',\n payload: {\n session_id: sessionId,\n prompt: raw.prompt,\n },\n }\n }\n\n case 'preToolUse': {\n return {\n hookType: 'PreToolUse',\n payload: {\n session_id: sessionId,\n tool_name: raw.toolName as string,\n tool_input: parseToolArgs(raw.toolArgs as string),\n },\n }\n }\n\n case 'postToolUse': {\n const toolResult = (raw.toolResult as Record<string, unknown>) ?? {}\n const failed = isToolFailure(\n raw.toolResult as Record<string, unknown> | undefined,\n )\n\n return {\n hookType: failed ? 'PostToolUseFailure' : 'PostToolUse',\n payload: {\n session_id: sessionId,\n tool_name: raw.toolName as string,\n tool_input: parseToolArgs(raw.toolArgs as string),\n tool_response: toolResult,\n exit_code: failed ? 1 : 0,\n },\n }\n }\n\n case 'errorOccurred': {\n const error = (raw.error as Record<string, unknown>) ?? {}\n return {\n hookType: 'PostToolUseFailure',\n payload: {\n session_id: sessionId,\n tool_name: '_error',\n tool_input: {},\n tool_response: {\n error_message: (error.message as string) ?? '',\n error_name: (error.name as string) ?? '',\n },\n exit_code: 1,\n },\n }\n }\n\n default:\n return null\n }\n}\n","import { BashStatsDB } from '../db/database.js'\nimport { WEEKLY_CHALLENGES, ACTIVITY_MULTIPLIERS } from '../constants.js'\nimport type {\n LifetimeStats,\n ToolBreakdown,\n TimeStats,\n SessionRecords,\n ProjectStats,\n AllStats,\n WeeklyGoalsPayload,\n WeeklyChallenge,\n} from '../types.js'\n\nfunction localDateStr(d: Date = new Date()): string {\n const pad = (n: number) => String(n).padStart(2, '0')\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`\n}\n\nfunction selectWeekChallenges(weekStart: string): WeeklyChallenge[] {\n let hash = 0\n for (const c of weekStart) {\n hash = ((hash * 31) + c.charCodeAt(0)) | 0\n }\n hash = Math.abs(hash)\n const pool = [...WEEKLY_CHALLENGES]\n const selected: WeeklyChallenge[] = []\n for (let i = 0; i < 3 && pool.length > 0; i++) {\n const idx = hash % pool.length\n selected.push(pool.splice(idx, 1)[0])\n hash = Math.abs(((hash * 127) + 63) | 0)\n }\n return selected\n}\n\nexport class StatsEngine {\n private db: BashStatsDB\n\n constructor(db: BashStatsDB) {\n this.db = db\n }\n\n private queryScalar<T = number>(sql: string, ...params: unknown[]): T {\n const row = this.db.prepare(sql).get(...params) as Record<string, T> | undefined\n if (!row) return 0 as T\n return Object.values(row)[0] ?? (0 as T)\n }\n\n /** Returns a WHERE/AND clause filtering sessions by agent */\n private agentWhere(agent?: string, alias?: string): { clause: string; params: unknown[] } {\n if (!agent) return { clause: '', params: [] }\n const col = alias ? `${alias}.agent` : 'agent'\n return { clause: ` AND ${col} = ?`, params: [agent] }\n }\n\n /** Returns a subquery filter for events/prompts tables */\n private agentSessionFilter(agent?: string): { clause: string; params: unknown[] } {\n if (!agent) return { clause: '', params: [] }\n return { clause: ` AND session_id IN (SELECT id FROM sessions WHERE agent = ?)`, params: [agent] }\n }\n\n getLifetimeStats(agent?: string): LifetimeStats {\n const sf = this.agentWhere(agent)\n const ef = this.agentSessionFilter(agent)\n\n const totalSessions = this.queryScalar('SELECT COUNT(*) as c FROM sessions WHERE 1=1' + sf.clause, ...sf.params)\n const totalPrompts = this.queryScalar('SELECT COUNT(*) as c FROM prompts WHERE 1=1' + ef.clause, ...ef.params)\n const totalCharsTyped = this.queryScalar('SELECT COALESCE(SUM(char_count), 0) as c FROM prompts WHERE 1=1' + ef.clause, ...ef.params)\n const totalToolCalls = this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE hook_type IN ('PostToolUse', 'PostToolUseFailure')\" + ef.clause, ...ef.params\n )\n const totalDurationSeconds = this.queryScalar(\n 'SELECT COALESCE(SUM(duration_seconds), 0) as c FROM sessions WHERE 1=1' + sf.clause, ...sf.params\n )\n const totalFilesRead = this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Read' AND hook_type = 'PostToolUse'\" + ef.clause, ...ef.params\n )\n const totalFilesWritten = this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Write' AND hook_type IN ('PostToolUse', 'PostToolUseFailure')\" + ef.clause, ...ef.params\n )\n const totalFilesEdited = this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Edit' AND hook_type IN ('PostToolUse', 'PostToolUseFailure')\" + ef.clause, ...ef.params\n )\n const totalFilesCreated = totalFilesWritten\n const totalBashCommands = this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Bash' AND hook_type IN ('PostToolUse', 'PostToolUseFailure')\" + ef.clause, ...ef.params\n )\n const totalWebSearches = this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE tool_name = 'WebSearch' AND hook_type IN ('PostToolUse', 'PostToolUseFailure')\" + ef.clause, ...ef.params\n )\n const totalWebFetches = this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE tool_name = 'WebFetch' AND hook_type IN ('PostToolUse', 'PostToolUseFailure')\" + ef.clause, ...ef.params\n )\n const totalSubagents = this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE hook_type = 'SubagentStart'\" + ef.clause, ...ef.params\n )\n const totalCompactions = this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE hook_type = 'PreCompact'\" + ef.clause, ...ef.params\n )\n const totalErrors = this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE (hook_type = 'PostToolUseFailure' OR (hook_type = 'Notification' AND (tool_input LIKE '%\\\"notification_type\\\":\\\"error\\\"%' OR tool_input LIKE '%\\\"notification_type\\\":\\\"rate_limit\\\"%')))\" + ef.clause, ...ef.params\n )\n const totalRateLimits = this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE hook_type = 'Notification' AND tool_input LIKE '%rate_limit%'\" + ef.clause, ...ef.params\n )\n const totalInputTokens = this.queryScalar(\n 'SELECT COALESCE(SUM(input_tokens), 0) as c FROM sessions WHERE 1=1' + sf.clause, ...sf.params\n )\n const totalOutputTokens = this.queryScalar(\n 'SELECT COALESCE(SUM(output_tokens), 0) as c FROM sessions WHERE 1=1' + sf.clause, ...sf.params\n )\n const totalCacheCreationTokens = this.queryScalar(\n 'SELECT COALESCE(SUM(cache_creation_input_tokens), 0) as c FROM sessions WHERE 1=1' + sf.clause, ...sf.params\n )\n const totalCacheReadTokens = this.queryScalar(\n 'SELECT COALESCE(SUM(cache_read_input_tokens), 0) as c FROM sessions WHERE 1=1' + sf.clause, ...sf.params\n )\n const totalTokens = totalInputTokens + totalOutputTokens + totalCacheCreationTokens + totalCacheReadTokens\n\n return {\n totalSessions,\n totalDurationSeconds,\n totalPrompts,\n totalCharsTyped,\n totalToolCalls,\n totalFilesRead,\n totalFilesWritten,\n totalFilesEdited,\n totalFilesCreated,\n totalBashCommands,\n totalWebSearches,\n totalWebFetches,\n totalSubagents,\n totalCompactions,\n totalErrors,\n totalRateLimits,\n totalInputTokens,\n totalOutputTokens,\n totalCacheCreationTokens,\n totalCacheReadTokens,\n totalTokens,\n }\n }\n\n getToolBreakdown(agent?: string): ToolBreakdown {\n const ef = this.agentSessionFilter(agent)\n const rows = this.db\n .prepare(\n \"SELECT tool_name, COUNT(*) as cnt FROM events WHERE hook_type = 'PostToolUse' AND tool_name IS NOT NULL\" + ef.clause + \" GROUP BY tool_name\"\n )\n .all(...ef.params) as { tool_name: string; cnt: number }[]\n\n const breakdown: ToolBreakdown = {}\n for (const row of rows) {\n breakdown[row.tool_name] = row.cnt\n }\n return breakdown\n }\n\n getTimeStats(agent?: string): TimeStats {\n const sf = this.agentWhere(agent)\n const ef = this.agentSessionFilter(agent)\n\n // Compute streaks from daily_activity (no agent filter -- daily_activity lacks agent info)\n const dailyRows = this.db\n .prepare('SELECT date FROM daily_activity WHERE sessions > 0 OR prompts > 0 OR tool_calls > 0 ORDER BY date ASC')\n .all() as { date: string }[]\n\n let longestStreak = 0\n let currentStreak = 0\n\n if (dailyRows.length > 0) {\n // Compute longest streak\n let streak = 1\n for (let i = 1; i < dailyRows.length; i++) {\n const prevDate = new Date(dailyRows[i - 1].date + 'T00:00:00Z')\n const currDate = new Date(dailyRows[i].date + 'T00:00:00Z')\n const diffDays = (currDate.getTime() - prevDate.getTime()) / (1000 * 60 * 60 * 24)\n if (diffDays === 1) {\n streak++\n } else {\n longestStreak = Math.max(longestStreak, streak)\n streak = 1\n }\n }\n longestStreak = Math.max(longestStreak, streak)\n\n // Compute current streak (backwards from today using local time)\n const activeDates = new Set(dailyRows.map(r => r.date))\n const todayStr = localDateStr()\n\n // Start from today and go backwards\n let checkDate = new Date()\n currentStreak = 0\n\n // Check today first; if not active, check yesterday (in case session hasn't been recorded today yet)\n if (activeDates.has(todayStr)) {\n currentStreak = 1\n checkDate.setDate(checkDate.getDate() - 1)\n while (activeDates.has(localDateStr(checkDate))) {\n currentStreak++\n checkDate.setDate(checkDate.getDate() - 1)\n }\n } else {\n // Check if yesterday was active\n checkDate.setDate(checkDate.getDate() - 1)\n const yesterdayStr = localDateStr(checkDate)\n if (activeDates.has(yesterdayStr)) {\n currentStreak = 1\n checkDate.setDate(checkDate.getDate() - 1)\n while (activeDates.has(localDateStr(checkDate))) {\n currentStreak++\n checkDate.setDate(checkDate.getDate() - 1)\n }\n }\n }\n }\n\n // Peak hour from prompts timestamps\n const peakHourRow = this.db\n .prepare(\n \"SELECT CAST(strftime('%H', timestamp) AS INTEGER) as hour, COUNT(*) as cnt FROM prompts WHERE 1=1\" + ef.clause + \" GROUP BY hour ORDER BY cnt DESC LIMIT 1\"\n )\n .get(...ef.params) as { hour: number; cnt: number } | undefined\n\n const peakHour = peakHourRow?.hour ?? 0\n const peakHourCount = peakHourRow?.cnt ?? 0\n\n // Night owl: prompts where hour < 5\n const nightOwlCount = this.queryScalar(\n \"SELECT COUNT(*) as c FROM prompts WHERE CAST(strftime('%H', timestamp) AS INTEGER) < 5\" + ef.clause, ...ef.params\n )\n\n // Early bird: prompts where hour BETWEEN 5 AND 7\n const earlyBirdCount = this.queryScalar(\n \"SELECT COUNT(*) as c FROM prompts WHERE CAST(strftime('%H', timestamp) AS INTEGER) BETWEEN 5 AND 7\" + ef.clause, ...ef.params\n )\n\n // Weekend sessions: day of week 0 (Sunday) or 6 (Saturday)\n // SQLite strftime('%w') returns 0=Sunday, 1=Monday, ... 6=Saturday\n const weekendSessions = this.queryScalar(\n \"SELECT COUNT(*) as c FROM sessions WHERE CAST(strftime('%w', started_at) AS INTEGER) IN (0, 6)\" + sf.clause, ...sf.params\n )\n\n // Most active day of week\n const mostActiveDayRow = this.db\n .prepare(\n \"SELECT CAST(strftime('%w', started_at) AS INTEGER) as dow, COUNT(*) as cnt FROM sessions WHERE 1=1\" + sf.clause + \" GROUP BY dow ORDER BY cnt DESC LIMIT 1\"\n )\n .get(...sf.params) as { dow: number; cnt: number } | undefined\n\n const mostActiveDay = mostActiveDayRow?.dow ?? 0\n\n // Busiest single date (no agent filter -- daily_activity lacks agent info)\n const busiestDateRow = this.db\n .prepare(\n 'SELECT date, (sessions + prompts + tool_calls) as total FROM daily_activity ORDER BY total DESC LIMIT 1'\n )\n .get() as { date: string; total: number } | undefined\n\n const busiestDate = busiestDateRow?.date ?? ''\n const busiestDateCount = busiestDateRow?.total ?? 0\n\n return {\n currentStreak,\n longestStreak,\n peakHour,\n peakHourCount,\n nightOwlCount,\n earlyBirdCount,\n weekendSessions,\n mostActiveDay,\n busiestDate,\n busiestDateCount,\n }\n }\n\n getSessionRecords(agent?: string): SessionRecords {\n const sf = this.agentWhere(agent)\n\n const longestSessionSeconds = this.queryScalar(\n 'SELECT COALESCE(MAX(duration_seconds), 0) as c FROM sessions WHERE 1=1' + sf.clause, ...sf.params\n )\n const mostToolsInSession = this.queryScalar(\n 'SELECT COALESCE(MAX(tool_count), 0) as c FROM sessions WHERE 1=1' + sf.clause, ...sf.params\n )\n const mostPromptsInSession = this.queryScalar(\n 'SELECT COALESCE(MAX(prompt_count), 0) as c FROM sessions WHERE 1=1' + sf.clause, ...sf.params\n )\n const fastestSessionSeconds = this.queryScalar(\n 'SELECT COALESCE(MIN(duration_seconds), 0) as c FROM sessions WHERE duration_seconds IS NOT NULL AND duration_seconds > 0' + sf.clause, ...sf.params\n )\n const avgDurationSeconds = this.queryScalar(\n 'SELECT COALESCE(AVG(duration_seconds), 0) as c FROM sessions WHERE duration_seconds IS NOT NULL' + sf.clause, ...sf.params\n )\n const avgPromptsPerSession = this.queryScalar(\n 'SELECT COALESCE(AVG(prompt_count), 0) as c FROM sessions WHERE 1=1' + sf.clause, ...sf.params\n )\n const avgToolsPerSession = this.queryScalar(\n 'SELECT COALESCE(AVG(tool_count), 0) as c FROM sessions WHERE 1=1' + sf.clause, ...sf.params\n )\n const mostTokensInSession = this.queryScalar(\n 'SELECT COALESCE(MAX(COALESCE(input_tokens, 0) + COALESCE(output_tokens, 0) + COALESCE(cache_creation_input_tokens, 0) + COALESCE(cache_read_input_tokens, 0)), 0) as c FROM sessions WHERE 1=1' + sf.clause, ...sf.params\n )\n const avgTokensPerSession = this.queryScalar(\n 'SELECT COALESCE(AVG(COALESCE(input_tokens, 0) + COALESCE(output_tokens, 0) + COALESCE(cache_creation_input_tokens, 0) + COALESCE(cache_read_input_tokens, 0)), 0) as c FROM sessions WHERE 1=1' + sf.clause, ...sf.params\n )\n\n return {\n longestSessionSeconds,\n mostToolsInSession,\n mostPromptsInSession,\n fastestSessionSeconds,\n avgDurationSeconds: Math.round(avgDurationSeconds),\n avgPromptsPerSession: Math.round(avgPromptsPerSession * 100) / 100,\n avgToolsPerSession: Math.round(avgToolsPerSession * 100) / 100,\n mostTokensInSession,\n avgTokensPerSession: Math.round(avgTokensPerSession),\n }\n }\n\n getProjectStats(agent?: string): ProjectStats {\n const sf = this.agentWhere(agent)\n\n const uniqueProjects = this.queryScalar(\n 'SELECT COUNT(DISTINCT project) as c FROM sessions WHERE project IS NOT NULL' + sf.clause, ...sf.params\n )\n\n const projectRows = this.db\n .prepare(\n 'SELECT project, COUNT(*) as cnt FROM sessions WHERE project IS NOT NULL' + sf.clause + ' GROUP BY project ORDER BY cnt DESC'\n )\n .all(...sf.params) as { project: string; cnt: number }[]\n\n const mostVisitedProject = projectRows.length > 0 ? projectRows[0].project : ''\n const mostVisitedProjectCount = projectRows.length > 0 ? projectRows[0].cnt : 0\n\n const projectBreakdown: Record<string, number> = {}\n for (const row of projectRows) {\n projectBreakdown[row.project] = row.cnt\n }\n\n return {\n uniqueProjects,\n mostVisitedProject,\n mostVisitedProjectCount,\n projectBreakdown,\n }\n }\n\n getAllStats(agent?: string): AllStats {\n return {\n lifetime: this.getLifetimeStats(agent),\n tools: this.getToolBreakdown(agent),\n time: this.getTimeStats(agent),\n sessions: this.getSessionRecords(agent),\n projects: this.getProjectStats(agent),\n }\n }\n\n getAgentBreakdown(): { favoriteAgent: string; sessionsPerAgent: Record<string, number>; hoursPerAgent: Record<string, number>; distinctAgents: number } {\n const rows = this.db.prepare(\n 'SELECT agent, COUNT(*) as cnt, COALESCE(SUM(duration_seconds), 0) as total_seconds FROM sessions GROUP BY agent ORDER BY cnt DESC'\n ).all() as { agent: string; cnt: number; total_seconds: number }[]\n\n const sessionsPerAgent: Record<string, number> = {}\n const hoursPerAgent: Record<string, number> = {}\n for (const row of rows) {\n sessionsPerAgent[row.agent] = row.cnt\n hoursPerAgent[row.agent] = Math.round(row.total_seconds / 3600 * 10) / 10\n }\n\n return {\n favoriteAgent: rows.length > 0 ? rows[0].agent : 'unknown',\n sessionsPerAgent,\n hoursPerAgent,\n distinctAgents: rows.length,\n }\n }\n\n getWeeklyGoalsPayload(): WeeklyGoalsPayload {\n const today = new Date()\n const dayOfWeek = today.getDay()\n const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek\n const monday = new Date(today)\n monday.setDate(monday.getDate() + mondayOffset)\n const sunday = new Date(monday)\n sunday.setDate(sunday.getDate() + 6)\n const nextMonday = new Date(monday)\n nextMonday.setDate(nextMonday.getDate() + 7)\n\n const weekStart = localDateStr(monday)\n const weekEnd = localDateStr(sunday)\n const nextWeekStart = localDateStr(nextMonday)\n\n const challenges = selectWeekChallenges(weekStart)\n\n const daysActive = this.queryScalar<number>(\n 'SELECT COUNT(*) as c FROM daily_activity WHERE date >= ? AND date <= ? AND (sessions > 0 OR prompts > 0)',\n weekStart, weekEnd\n )\n\n const multiplier = ACTIVITY_MULTIPLIERS[Math.min(7, Math.max(1, daysActive))] ?? 1.0\n\n const results = challenges.map(c => {\n const current = this.computeWeeklyStat(c.stat, weekStart, weekEnd, nextWeekStart)\n return {\n id: c.id,\n description: c.description,\n xpReward: c.xpReward,\n completed: current >= c.threshold,\n progress: Math.min(1, current / Math.max(1, c.threshold)),\n threshold: c.threshold,\n current,\n }\n })\n\n return {\n weekStart,\n daysActive,\n multiplier,\n challenges: results,\n }\n }\n\n private computeWeeklyStat(stat: string, weekStart: string, weekEnd: string, nextWeekStart: string): number {\n switch (stat) {\n case 'totalPrompts':\n return this.queryScalar('SELECT COALESCE(SUM(prompts), 0) as c FROM daily_activity WHERE date >= ? AND date <= ?', weekStart, weekEnd)\n case 'totalToolCalls':\n return this.queryScalar('SELECT COALESCE(SUM(tool_calls), 0) as c FROM daily_activity WHERE date >= ? AND date <= ?', weekStart, weekEnd)\n case 'totalSessions':\n return this.queryScalar('SELECT COALESCE(SUM(sessions), 0) as c FROM daily_activity WHERE date >= ? AND date <= ?', weekStart, weekEnd)\n case 'daysActive':\n return this.queryScalar('SELECT COUNT(*) as c FROM daily_activity WHERE date >= ? AND date <= ? AND (sessions > 0 OR prompts > 0)', weekStart, weekEnd)\n case 'totalHours': {\n const secs = this.queryScalar('SELECT COALESCE(SUM(duration_seconds), 0) as c FROM daily_activity WHERE date >= ? AND date <= ?', weekStart, weekEnd)\n return Math.round(secs / 3600 * 10) / 10\n }\n case 'totalFilesRead':\n return this.queryScalar(\"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Read' AND hook_type = 'PostToolUse' AND timestamp >= ? AND timestamp < ?\", weekStart, nextWeekStart)\n case 'totalFilesEdited':\n return this.queryScalar(\"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Edit' AND hook_type IN ('PostToolUse', 'PostToolUseFailure') AND timestamp >= ? AND timestamp < ?\", weekStart, nextWeekStart)\n case 'totalFilesCreated':\n return this.queryScalar(\"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Write' AND hook_type IN ('PostToolUse', 'PostToolUseFailure') AND timestamp >= ? AND timestamp < ?\", weekStart, nextWeekStart)\n case 'totalBashCommands':\n return this.queryScalar(\"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Bash' AND hook_type IN ('PostToolUse', 'PostToolUseFailure') AND timestamp >= ? AND timestamp < ?\", weekStart, nextWeekStart)\n case 'totalSearches':\n return this.queryScalar(\"SELECT COUNT(*) as c FROM events WHERE tool_name IN ('Grep', 'Glob') AND hook_type = 'PostToolUse' AND timestamp >= ? AND timestamp < ?\", weekStart, nextWeekStart)\n case 'totalCommits':\n return this.queryScalar(\"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Bash' AND hook_type = 'PostToolUse' AND tool_input LIKE '%git commit%' AND timestamp >= ? AND timestamp < ?\", weekStart, nextWeekStart)\n case 'totalPRs':\n return this.queryScalar(\"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Bash' AND hook_type = 'PostToolUse' AND tool_input LIKE '%gh pr create%' AND timestamp >= ? AND timestamp < ?\", weekStart, nextWeekStart)\n case 'commitDays':\n return this.queryScalar(\"SELECT COUNT(DISTINCT substr(timestamp, 1, 10)) as c FROM events WHERE tool_name = 'Bash' AND hook_type = 'PostToolUse' AND tool_input LIKE '%git commit%' AND timestamp >= ? AND timestamp < ?\", weekStart, nextWeekStart)\n case 'longPromptCount':\n return this.queryScalar('SELECT COUNT(*) as c FROM prompts WHERE char_count > 1000 AND timestamp >= ? AND timestamp < ?', weekStart, nextWeekStart)\n case 'nightOwlDays':\n return this.queryScalar(\"SELECT COUNT(DISTINCT substr(timestamp, 1, 10)) as c FROM prompts WHERE CAST(strftime('%H', timestamp) AS INTEGER) < 5 AND timestamp >= ? AND timestamp < ?\", weekStart, nextWeekStart)\n case 'earlyBirdDays':\n return this.queryScalar(\"SELECT COUNT(DISTINCT substr(timestamp, 1, 10)) as c FROM prompts WHERE CAST(strftime('%H', timestamp) AS INTEGER) BETWEEN 5 AND 7 AND timestamp >= ? AND timestamp < ?\", weekStart, nextWeekStart)\n case 'weekendDays':\n return this.queryScalar(\"SELECT COUNT(*) as c FROM daily_activity WHERE date >= ? AND date <= ? AND (sessions > 0 OR prompts > 0) AND CAST(strftime('%w', date) AS INTEGER) IN (0, 6)\", weekStart, weekEnd)\n case 'uniqueProjects':\n return this.queryScalar('SELECT COUNT(DISTINCT project) as c FROM sessions WHERE project IS NOT NULL AND started_at >= ? AND started_at < ?', weekStart, nextWeekStart)\n case 'cleanSessions':\n return this.queryScalar('SELECT COUNT(*) as c FROM sessions WHERE error_count = 0 AND tool_count > 0 AND started_at >= ? AND started_at < ?', weekStart, nextWeekStart)\n case 'extendedSessionCount':\n return this.queryScalar('SELECT COUNT(*) as c FROM sessions WHERE duration_seconds > 3600 AND prompt_count >= 15 AND started_at >= ? AND started_at < ?', weekStart, nextWeekStart)\n case 'quickDrawSessions':\n return this.queryScalar('SELECT COUNT(*) as c FROM sessions WHERE duration_seconds IS NOT NULL AND duration_seconds < 120 AND tool_count > 0 AND started_at >= ? AND started_at < ?', weekStart, nextWeekStart)\n case 'diverseToolSessions':\n return this.queryScalar(\"SELECT COUNT(*) as c FROM (SELECT session_id FROM events WHERE hook_type = 'PostToolUse' AND tool_name IS NOT NULL AND session_id IN (SELECT id FROM sessions WHERE started_at >= ? AND started_at < ?) GROUP BY session_id HAVING COUNT(DISTINCT tool_name) >= 5)\", weekStart, nextWeekStart)\n case 'maxSubagentsInSession':\n return this.queryScalar(\"SELECT COALESCE(MAX(cnt), 0) as c FROM (SELECT COUNT(*) as cnt FROM events WHERE hook_type = 'SubagentStart' AND session_id IN (SELECT id FROM sessions WHERE started_at >= ? AND started_at < ?) GROUP BY session_id)\", weekStart, nextWeekStart)\n default:\n return 0\n }\n }\n}\n","// === Hook Event Types ===\n\nexport interface HookInput {\n session_id: string\n transcript_path: string\n cwd: string\n permission_mode: string\n hook_event_name: string\n}\n\nexport interface SessionStartInput extends HookInput {\n source: 'startup' | 'resume' | 'clear' | 'compact'\n model: string\n agent_type?: string\n}\n\nexport interface UserPromptInput extends HookInput {\n prompt: string\n}\n\nexport interface PreToolUseInput extends HookInput {\n tool_name: string\n tool_input: Record<string, unknown>\n tool_use_id: string\n}\n\nexport interface PostToolUseInput extends HookInput {\n tool_name: string\n tool_input: Record<string, unknown>\n tool_response: Record<string, unknown>\n tool_use_id: string\n}\n\nexport interface StopInput extends HookInput {\n stop_hook_active: boolean\n}\n\nexport interface SubagentStartInput extends HookInput {\n agent_id: string\n agent_type: string\n}\n\nexport interface SubagentStopInput extends HookInput {\n agent_id: string\n agent_transcript_path: string\n stop_hook_active: boolean\n}\n\nexport interface NotificationInput extends HookInput {\n message: string\n notification_type: string\n}\n\nexport interface PreCompactInput extends HookInput {\n trigger: 'manual' | 'auto'\n custom_instructions: string\n}\n\nexport interface PermissionRequestInput extends HookInput {\n tool_name: string\n tool_input: Record<string, unknown>\n}\n\nexport interface SetupInput extends HookInput {\n trigger: 'init' | 'maintenance'\n CLAUDE_ENV_FILE: string\n}\n\n// === Token Usage ===\n\nexport interface TokenUsage {\n input_tokens: number\n output_tokens: number\n cache_creation_input_tokens: number\n cache_read_input_tokens: number\n}\n\n// === Database Row Types ===\n\nexport interface EventRow {\n id: number\n session_id: string\n hook_type: string\n tool_name: string | null\n tool_input: string | null\n tool_output: string | null\n exit_code: number | null\n success: number | null\n cwd: string | null\n project: string | null\n timestamp: string\n}\n\nexport interface SessionRow {\n id: string\n agent: string\n started_at: string\n ended_at: string | null\n stop_reason: string | null\n prompt_count: number\n tool_count: number\n error_count: number\n project: string | null\n duration_seconds: number | null\n input_tokens: number | null\n output_tokens: number | null\n cache_creation_input_tokens: number | null\n cache_read_input_tokens: number | null\n}\n\nexport interface PromptRow {\n id: number\n session_id: string\n content: string\n char_count: number\n word_count: number\n timestamp: string\n}\n\nexport interface DailyActivityRow {\n date: string\n sessions: number\n prompts: number\n tool_calls: number\n errors: number\n duration_seconds: number\n input_tokens: number\n output_tokens: number\n cache_creation_input_tokens: number\n cache_read_input_tokens: number\n}\n\nexport interface AchievementUnlockRow {\n badge_id: string\n tier: number\n unlocked_at: string\n notified: number\n}\n\n// === Stats Types ===\n\nexport interface LifetimeStats {\n totalSessions: number\n totalDurationSeconds: number\n totalPrompts: number\n totalCharsTyped: number\n totalToolCalls: number\n totalFilesRead: number\n totalFilesWritten: number\n totalFilesEdited: number\n totalFilesCreated: number\n totalBashCommands: number\n totalWebSearches: number\n totalWebFetches: number\n totalSubagents: number\n totalCompactions: number\n totalErrors: number\n totalRateLimits: number\n totalInputTokens: number\n totalOutputTokens: number\n totalCacheCreationTokens: number\n totalCacheReadTokens: number\n totalTokens: number\n}\n\nexport interface ToolBreakdown {\n [toolName: string]: number\n}\n\nexport interface TimeStats {\n currentStreak: number\n longestStreak: number\n peakHour: number\n peakHourCount: number\n nightOwlCount: number\n earlyBirdCount: number\n weekendSessions: number\n mostActiveDay: number\n busiestDate: string\n busiestDateCount: number\n}\n\nexport interface SessionRecords {\n longestSessionSeconds: number\n mostToolsInSession: number\n mostPromptsInSession: number\n fastestSessionSeconds: number\n avgDurationSeconds: number\n avgPromptsPerSession: number\n avgToolsPerSession: number\n mostTokensInSession: number\n avgTokensPerSession: number\n}\n\nexport interface ProjectStats {\n uniqueProjects: number\n mostVisitedProject: string\n mostVisitedProjectCount: number\n projectBreakdown: Record<string, number>\n}\n\nexport interface AllStats {\n lifetime: LifetimeStats\n tools: ToolBreakdown\n time: TimeStats\n sessions: SessionRecords\n projects: ProjectStats\n}\n\nexport interface AgentBreakdown {\n favoriteAgent: string\n sessionsPerAgent: Record<string, number>\n hoursPerAgent: Record<string, number>\n distinctAgents: number\n}\n\n// === Agent Types ===\n\nexport type AgentType =\n | 'claude-code'\n | 'gemini-cli'\n | 'copilot-cli'\n | 'opencode'\n | 'unknown'\n\nexport const AGENT_DISPLAY_NAMES: Record<AgentType, string> = {\n 'claude-code': 'Claude Code',\n 'gemini-cli': 'Gemini CLI',\n 'copilot-cli': 'Copilot CLI',\n 'opencode': 'OpenCode',\n 'unknown': 'Unknown',\n}\n\n// === Achievement Types ===\n\nexport type BadgeTier = 0 | 1 | 2 | 3 | 4 | 5\n\nexport interface BadgeDefinition {\n id: string\n name: string\n icon: string\n description: string\n category: 'volume' | 'tool_mastery' | 'time' | 'behavioral' | 'resilience' | 'shipping' | 'multi_agent' | 'wild_card' | 'aspirational' | 'secret' | 'session_behavior' | 'prompt_patterns' | 'error_recovery' | 'tool_combos' | 'project_dedication' | 'token_usage'\n stat: string\n tiers: [number, number, number, number, number]\n trigger: string\n secret?: boolean\n aspirational?: boolean\n}\n\nexport interface BadgeResult {\n id: string\n name: string\n icon: string\n description: string\n category: string\n stat: string\n tiers: [number, number, number, number, number]\n tier: BadgeTier\n tierName: string\n value: number\n nextThreshold: number\n progress: number\n maxed: boolean\n trigger: string\n secret: boolean\n unlocked: boolean\n}\n\nexport interface XPResult {\n totalXP: number\n rankNumber: number\n rankTier: string\n nextRankXP: number\n progress: number\n}\n\nexport interface AchievementsPayload {\n stats: AllStats\n badges: BadgeResult[]\n xp: XPResult\n}\n\nexport const TIER_NAMES: Record<BadgeTier, string> = {\n 0: 'Locked',\n 1: 'Bronze',\n 2: 'Silver',\n 3: 'Gold',\n 4: 'Diamond',\n 5: 'Singularity',\n}\n\n// === Weekly Goals Types ===\n\nexport interface WeeklyChallenge {\n id: string\n description: string\n stat: string\n threshold: number\n xpReward: number\n weekScoped: boolean\n}\n\nexport interface WeeklyGoalRow {\n week_start: string\n challenge_id: string\n completed: number\n xp_reward: number\n}\n\nexport interface WeeklyXPRow {\n week_start: string\n base_xp: number\n multiplier: number\n bonus_xp: number\n}\n\nexport interface WeeklyGoalsPayload {\n weekStart: string\n daysActive: number\n multiplier: number\n challenges: Array<{\n id: string\n description: string\n xpReward: number\n completed: boolean\n progress: number\n threshold: number\n current: number\n }>\n}\n\n// === Rank Tier Bracket ===\n\nexport interface RankTierBracket {\n tier: string\n minRank: number\n maxRank: number\n}\n","import { BashStatsDB } from '../db/database.js'\nimport { StatsEngine } from '../stats/engine.js'\nimport { BADGE_DEFINITIONS, TIER_XP, xpForRank, rankTierForRank } from '../constants.js'\nimport type {\n BadgeResult,\n BadgeTier,\n XPResult,\n AchievementsPayload,\n AllStats,\n} from '../types.js'\nimport { TIER_NAMES } from '../types.js'\n\nexport class AchievementEngine {\n private db: BashStatsDB\n private stats: StatsEngine\n\n constructor(db: BashStatsDB, stats: StatsEngine) {\n this.db = db\n this.stats = stats\n }\n\n computeBadges(agent?: string): BadgeResult[] {\n const allStats = this.stats.getAllStats(agent)\n const flat = this.flattenStats(allStats)\n\n return BADGE_DEFINITIONS.map(badge => {\n const value = flat[badge.stat] ?? 0\n\n let tier: BadgeTier = 0\n if (badge.aspirational) {\n // Aspirational: only Obsidian (5) or Locked (0)\n tier = value >= badge.tiers[4] ? 5 : 0\n } else if (badge.secret) {\n // Secret: unlocked (1) or locked (0)\n tier = value >= badge.tiers[0] ? 1 : 0\n } else {\n // Normal tiered badge: check how many thresholds exceeded\n for (let i = 0; i < badge.tiers.length; i++) {\n if (value >= badge.tiers[i]) {\n tier = (i + 1) as BadgeTier\n } else {\n break\n }\n }\n }\n\n // Calculate progress toward next tier\n let nextThreshold = 0\n let progress = 0\n let maxed = false\n\n if (badge.aspirational) {\n nextThreshold = badge.tiers[4]\n progress = tier === 5 ? 1 : Math.min(value / nextThreshold, 0.99)\n maxed = tier === 5\n } else if (badge.secret) {\n nextThreshold = badge.tiers[0]\n progress = tier >= 1 ? 1 : 0\n maxed = tier >= 1\n } else if (tier >= 5) {\n nextThreshold = badge.tiers[4]\n progress = 1\n maxed = true\n } else {\n // tier is 0..4 here (we already handled tier >= 5 above)\n const tierIdx = tier as 0 | 1 | 2 | 3 | 4\n nextThreshold = badge.tiers[tierIdx]\n const prevThreshold = tierIdx > 0 ? badge.tiers[(tierIdx - 1) as 0 | 1 | 2 | 3] : 0\n const range = nextThreshold - prevThreshold\n progress = range > 0 ? Math.min((value - prevThreshold) / range, 0.99) : 0\n }\n\n // Persist unlock if tier > 0\n if (tier > 0) {\n for (let t = 1; t <= tier; t++) {\n this.db.insertUnlock(badge.id, t)\n }\n }\n\n return {\n id: badge.id,\n name: badge.name,\n icon: badge.icon,\n description: badge.description,\n category: badge.category,\n stat: badge.stat,\n tiers: badge.tiers,\n tier,\n tierName: TIER_NAMES[tier],\n value,\n nextThreshold,\n progress,\n maxed,\n trigger: badge.trigger,\n secret: badge.secret ?? false,\n unlocked: tier > 0,\n }\n })\n }\n\n computeXP(agent?: string): XPResult {\n const allStats = this.stats.getAllStats(agent)\n const badges = this.computeBadges(agent)\n\n // Calculate XP from activity\n let totalXP = 0\n totalXP += allStats.lifetime.totalPrompts * 1 // +1 per prompt\n totalXP += allStats.lifetime.totalSessions * 5 // +5 per session\n totalXP += Math.floor(allStats.lifetime.totalDurationSeconds / 3600) * 10 // +10 per hour\n totalXP += allStats.time.longestStreak * 5 // +5 per streak day\n\n // Badge tier XP\n for (const badge of badges) {\n if (badge.tier > 0) {\n totalXP += TIER_XP[badge.tier] ?? 0\n }\n }\n\n // Determine rank number (1-500) from XP using exponential curve\n let rankNumber = 0\n for (let r = 500; r >= 1; r--) {\n if (totalXP >= xpForRank(r)) {\n rankNumber = r\n break\n }\n }\n\n // Calculate progress toward next rank\n let nextRankXP: number\n let progress: number\n\n if (rankNumber >= 500) {\n nextRankXP = xpForRank(500)\n progress = 1\n } else {\n const nextRank = rankNumber + 1\n nextRankXP = xpForRank(nextRank)\n const currentThreshold = rankNumber > 0 ? xpForRank(rankNumber) : 0\n const range = nextRankXP - currentThreshold\n progress = range > 0 ? Math.min((totalXP - currentThreshold) / range, 0.99) : 0\n }\n\n return {\n totalXP,\n rankNumber,\n rankTier: rankTierForRank(rankNumber || 1),\n nextRankXP,\n progress,\n }\n }\n\n getAchievementsPayload(agent?: string): AchievementsPayload {\n const allStats = this.stats.getAllStats(agent)\n return {\n stats: allStats,\n badges: this.computeBadges(agent),\n xp: this.computeXP(agent),\n }\n }\n\n private flattenStats(allStats: AllStats): Record<string, number> {\n const flat: Record<string, number> = {}\n\n // Direct lifetime mappings\n flat.totalPrompts = allStats.lifetime.totalPrompts\n flat.totalToolCalls = allStats.lifetime.totalToolCalls\n flat.totalSessions = allStats.lifetime.totalSessions\n flat.totalCharsTyped = allStats.lifetime.totalCharsTyped\n flat.totalBashCommands = allStats.lifetime.totalBashCommands\n flat.totalFilesRead = allStats.lifetime.totalFilesRead\n flat.totalFilesEdited = allStats.lifetime.totalFilesEdited\n flat.totalFilesCreated = allStats.lifetime.totalFilesCreated\n flat.totalSubagents = allStats.lifetime.totalSubagents\n flat.totalErrors = allStats.lifetime.totalErrors\n flat.totalRateLimits = allStats.lifetime.totalRateLimits\n flat.totalWebFetches = allStats.lifetime.totalWebFetches\n flat.totalWebSearches = allStats.lifetime.totalWebSearches\n flat.totalCompactions = allStats.lifetime.totalCompactions\n\n // Derived\n flat.totalSessionHours = Math.floor(allStats.lifetime.totalDurationSeconds / 3600)\n\n // From time stats\n flat.longestStreak = allStats.time.longestStreak\n flat.nightOwlCount = allStats.time.nightOwlCount\n flat.earlyBirdCount = allStats.time.earlyBirdCount\n flat.weekendSessions = allStats.time.weekendSessions\n\n // Computed via queries - tool mastery\n flat.totalSearches = this.queryTotalSearches()\n\n // Behavioral\n flat.mostRepeatedPromptCount = this.queryMostRepeatedPromptCount()\n flat.uniqueToolsUsed = this.queryUniqueToolsUsed()\n flat.planModeUses = this.queryPlanModeUses()\n flat.longPromptCount = this.queryLongPromptCount()\n flat.quickSessionCount = this.queryQuickSessionCount()\n\n // Resilience\n flat.longestErrorFreeStreak = this.queryLongestErrorFreeStreak()\n\n // Humor\n flat.politePromptCount = this.queryPolitePromptCount()\n flat.hugePromptCount = this.queryHugePromptCount()\n flat.maxSameFileEdits = this.queryMaxSameFileEdits()\n flat.longSessionCount = this.queryLongSessionCount()\n flat.repeatedPromptCount = this.queryRepeatedPromptCount()\n flat.maxErrorsInSession = this.queryMaxErrorsInSession()\n\n // Shipping\n flat.totalCommits = this.queryTotalCommits()\n flat.totalPRs = this.queryTotalPRs()\n flat.uniqueProjects = allStats.projects.uniqueProjects\n flat.uniqueLanguages = this.queryUniqueLanguages()\n\n // Multi-agent\n flat.concurrentAgentUses = this.queryConcurrentAgentUses()\n\n // Secret stats\n flat.dangerousCommandBlocked = this.queryDangerousCommandBlocked()\n flat.returnAfterBreak = this.queryReturnAfterBreak()\n flat.threeAmPrompt = this.queryThreeAmPrompt()\n flat.midnightSpanSession = this.queryMidnightSpanSession()\n flat.nestedSubagent = this.queryNestedSubagent()\n flat.holidayActivity = this.queryHolidayActivity()\n flat.speedRunSession = this.querySpeedRunSession()\n flat.allToolsInSession = this.queryAllToolsInSession()\n flat.firstEverSession = allStats.lifetime.totalSessions > 0 ? 1 : 0\n flat.allBadgesGold = 0 // computed after badges are resolved; set to 0 for first pass\n\n // Aspirational\n flat.totalXP = 0 // computed after XP is calculated; set to 0 for badge pass\n flat.allToolsObsidian = 0 // computed after all badges; set to 0 for first pass\n flat.allNonSecretBadgesUnlocked = 0 // computed after all badges; set to 0\n\n // ===================================================================\n // NEW: Time & Patterns\n // ===================================================================\n flat.witchingHourPrompts = this.queryWitchingHourPrompts()\n flat.lunchBreakDays = this.queryLunchBreakDays()\n flat.mondaySessions = this.queryMondaySessions()\n flat.fridayCommits = this.queryFridayCommits()\n flat.maxUniqueHoursInDay = this.queryMaxUniqueHoursInDay()\n flat.uniqueQuarters = this.queryUniqueQuarters()\n\n // ===================================================================\n // NEW: Session Behavior\n // ===================================================================\n flat.extendedSessionCount = this.queryExtendedSessionCount()\n flat.quickDrawSessions = this.queryQuickDrawSessions()\n flat.diverseToolSessions = this.queryDiverseToolSessions()\n // totalCompactions already mapped above\n flat.permissionRequests = this.queryPermissionRequests()\n flat.returnerDays = this.queryReturnerDays()\n\n // ===================================================================\n // NEW: Prompt Patterns\n // ===================================================================\n flat.shortPromptCount = this.queryShortPromptCount()\n flat.questionPromptCount = this.queryQuestionPromptCount()\n flat.sorryPromptCount = this.querySorryPromptCount()\n flat.capsLockPromptCount = this.queryCapsLockPromptCount()\n flat.emojiPromptCount = this.queryEmojiPromptCount()\n flat.codeDumpPromptCount = this.queryCodeDumpPromptCount()\n\n // ===================================================================\n // NEW: Error & Recovery\n // ===================================================================\n flat.rubberDuckCount = this.queryRubberDuckCount()\n flat.thirdTimeCharmCount = this.queryThirdTimeCharmCount()\n flat.undoEditCount = this.queryUndoEditCount()\n flat.crashySessions = this.queryCrashySessions()\n flat.totalLifetimeErrors = allStats.lifetime.totalErrors\n\n // ===================================================================\n // NEW: Tool Combos\n // ===================================================================\n flat.readEditRunCount = this.queryReadEditRunCount()\n // totalSearches already mapped above (reused by grep_ninja)\n flat.maxFilesCreatedInSession = this.queryMaxFilesCreatedInSession()\n flat.maxSameFileEditsLifetime = this.queryMaxSameFileEditsLifetime()\n flat.searchThenEditCount = this.querySearchThenEditCount()\n\n // ===================================================================\n // NEW: Project Dedication\n // ===================================================================\n flat.maxProjectSessions = this.queryMaxProjectSessions()\n flat.maxProjectsInDay = this.queryMaxProjectsInDay()\n flat.finishedProjects = this.queryFinishedProjects()\n flat.legacyReturns = this.queryLegacyReturns()\n flat.totalUniqueProjects = allStats.projects.uniqueProjects\n\n // ===================================================================\n // NEW: Multi-Agent (additional stats)\n // ===================================================================\n flat.maxConcurrentSubagents = this.queryMaxConcurrentSubagents()\n flat.quickSubagentStops = this.queryQuickSubagentStops()\n flat.totalSubagentSpawns = allStats.lifetime.totalSubagents\n flat.maxSubagentsInSession = this.queryMaxSubagentsInSession()\n\n // Cross-agent stats\n flat.distinctAgentsUsed = this.queryScalar('SELECT COUNT(DISTINCT agent) FROM sessions')\n flat.geminiSessions = this.queryScalar(\"SELECT COUNT(*) FROM sessions WHERE agent = 'gemini-cli'\")\n flat.copilotSessions = this.queryScalar(\"SELECT COUNT(*) FROM sessions WHERE agent = 'copilot-cli'\")\n flat.opencodeSessions = this.queryScalar(\"SELECT COUNT(*) FROM sessions WHERE agent = 'opencode'\")\n flat.doubleAgentDays = this.queryScalar(\n \"SELECT COUNT(*) FROM (SELECT substr(started_at, 1, 10) as d FROM sessions GROUP BY d HAVING COUNT(DISTINCT agent) >= 2)\"\n )\n flat.agentSwitchDays = flat.doubleAgentDays\n\n // ===================================================================\n // NEW: Humor & Meta (additional stats)\n // ===================================================================\n flat.dejaVuCount = this.queryDejaVuCount()\n flat.trustIssueCount = this.queryTrustIssueCount()\n flat.backseatDriverCount = this.queryBackseatDriverCount()\n flat.negotiatorCount = this.queryNegotiatorCount()\n flat.maxConsecutivePermissions = this.queryMaxConsecutivePermissions()\n // longSessionCount already mapped above (reused by touch_grass_humor)\n // longestErrorFreeStreak already mapped above (reused by inbox_zero)\n flat.bashRetrySuccessCount = this.queryBashRetrySuccessCount()\n\n // ===================================================================\n // NEW: Secret (additional stats)\n // ===================================================================\n flat.easterEggActivity = this.queryEasterEggActivity()\n flat.fullMoonSession = this.queryFullMoonSession()\n flat.birthdaySession = this.queryBirthdaySession()\n flat.luckyNumber = (allStats.lifetime.totalPrompts >= 777 || allStats.lifetime.totalToolCalls >= 7777) ? 1 : 0\n flat.ghostSessions = this.queryGhostSessions()\n flat.bullseyeSessions = this.queryBullseyeSessions()\n flat.hasTenMillionSession = this.queryHasTenMillionSession()\n\n // ===================================================================\n // NEW: Token Usage\n // ===================================================================\n flat.totalTokens = allStats.lifetime.totalTokens\n flat.totalOutputTokens = allStats.lifetime.totalOutputTokens\n flat.totalCacheReadTokens = allStats.lifetime.totalCacheReadTokens\n flat.totalCacheCreationTokens = allStats.lifetime.totalCacheCreationTokens\n flat.totalInputTokens = allStats.lifetime.totalInputTokens\n flat.mostTokensInSession = allStats.sessions.mostTokensInSession\n flat.avgTokensPerSession = allStats.sessions.avgTokensPerSession\n flat.heavyTokenSessions = this.queryHeavyTokenSessions()\n flat.lightTokenSessions = this.queryLightTokenSessions()\n flat.maxOutputInSession = this.queryMaxOutputInSession()\n\n return flat\n }\n\n // === Computed stat query helpers ===\n\n private queryScalar(sql: string, ...params: unknown[]): number {\n const row = this.db.prepare(sql).get(...params) as Record<string, number> | undefined\n if (!row) return 0\n return Object.values(row)[0] ?? 0\n }\n\n private queryTotalSearches(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE tool_name IN ('Grep', 'Glob') AND hook_type = 'PostToolUse'\"\n )\n }\n\n private queryPolitePromptCount(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM prompts WHERE LOWER(content) LIKE '%please%' OR LOWER(content) LIKE '%thank%'\"\n )\n }\n\n private queryHugePromptCount(): number {\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM prompts WHERE char_count > 5000'\n )\n }\n\n private queryLongPromptCount(): number {\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM prompts WHERE char_count > 1000'\n )\n }\n\n private queryMostRepeatedPromptCount(): number {\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM prompts GROUP BY LOWER(TRIM(content)) ORDER BY c DESC LIMIT 1'\n )\n }\n\n private queryUniqueToolsUsed(): number {\n return this.queryScalar(\n \"SELECT COUNT(DISTINCT tool_name) as c FROM events WHERE hook_type = 'PostToolUse' AND tool_name IS NOT NULL\"\n )\n }\n\n private queryPlanModeUses(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE hook_type = 'PostToolUse' AND tool_name = 'Task'\"\n )\n }\n\n private queryQuickSessionCount(): number {\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM sessions WHERE duration_seconds IS NOT NULL AND duration_seconds < 300 AND tool_count > 0'\n )\n }\n\n private queryLongSessionCount(): number {\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM sessions WHERE duration_seconds IS NOT NULL AND duration_seconds > 28800'\n )\n }\n\n private queryMaxErrorsInSession(): number {\n return this.queryScalar(\n 'SELECT COALESCE(MAX(error_count), 0) as c FROM sessions'\n )\n }\n\n private queryMaxSameFileEdits(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Edit' AND hook_type = 'PostToolUse' GROUP BY json_extract(tool_input, '$.file_path') ORDER BY c DESC LIMIT 1\"\n )\n }\n\n private queryRepeatedPromptCount(): number {\n return this.queryScalar(\n 'SELECT COALESCE(SUM(cnt), 0) as c FROM (SELECT COUNT(*) as cnt FROM prompts GROUP BY LOWER(TRIM(content)) HAVING cnt > 1)'\n )\n }\n\n private queryLongestErrorFreeStreak(): number {\n const rows = this.db.prepare(\n \"SELECT hook_type FROM events WHERE hook_type IN ('PostToolUse', 'PostToolUseFailure') ORDER BY timestamp ASC\"\n ).all() as { hook_type: string }[]\n\n let longest = 0\n let current = 0\n for (const row of rows) {\n if (row.hook_type === 'PostToolUse') {\n current++\n longest = Math.max(longest, current)\n } else {\n current = 0\n }\n }\n return longest\n }\n\n private queryTotalCommits(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Bash' AND hook_type = 'PostToolUse' AND tool_input LIKE '%git commit%'\"\n )\n }\n\n private queryTotalPRs(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Bash' AND hook_type = 'PostToolUse' AND tool_input LIKE '%gh pr create%'\"\n )\n }\n\n private queryUniqueLanguages(): number {\n const rows = this.db.prepare(\n \"SELECT DISTINCT json_extract(tool_input, '$.file_path') as fp FROM events WHERE tool_name IN ('Edit', 'Write', 'Read') AND hook_type = 'PostToolUse' AND tool_input IS NOT NULL\"\n ).all() as { fp: string | null }[]\n\n const extensions = new Set<string>()\n for (const row of rows) {\n if (row.fp) {\n const match = row.fp.match(/\\.([a-zA-Z0-9]+)$/)\n if (match) {\n extensions.add(match[1].toLowerCase())\n }\n }\n }\n return extensions.size\n }\n\n private queryConcurrentAgentUses(): number {\n return this.queryScalar(\n \"SELECT COUNT(DISTINCT session_id) as c FROM events WHERE hook_type = 'SubagentStart'\"\n )\n }\n\n // === Secret stat helpers ===\n\n private queryDangerousCommandBlocked(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE hook_type = 'PreToolUse' AND tool_name = 'Bash' AND (tool_input LIKE '%rm -rf%' OR tool_input LIKE '%rm -r /%')\"\n )\n }\n\n private queryReturnAfterBreak(): number {\n const rows = this.db.prepare(\n 'SELECT started_at FROM sessions ORDER BY started_at ASC'\n ).all() as { started_at: string }[]\n\n if (rows.length < 2) return 0\n for (let i = 1; i < rows.length; i++) {\n const prev = new Date(rows[i - 1].started_at).getTime()\n const curr = new Date(rows[i].started_at).getTime()\n const diffDays = (curr - prev) / (1000 * 60 * 60 * 24)\n if (diffDays >= 7) return 1\n }\n return 0\n }\n\n private queryThreeAmPrompt(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM prompts WHERE CAST(strftime('%H', timestamp) AS INTEGER) = 3\"\n ) > 0 ? 1 : 0\n }\n\n private queryMidnightSpanSession(): number {\n const rows = this.db.prepare(\n \"SELECT started_at, ended_at FROM sessions WHERE ended_at IS NOT NULL\"\n ).all() as { started_at: string; ended_at: string }[]\n\n for (const row of rows) {\n const startDate = row.started_at.slice(0, 10)\n const endDate = row.ended_at.slice(0, 10)\n if (startDate !== endDate) return 1\n }\n return 0\n }\n\n private queryNestedSubagent(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE hook_type = 'SubagentStart'\"\n ) > 0 ? 1 : 0\n }\n\n private queryHolidayActivity(): number {\n const holidays = this.queryScalar(\n \"SELECT COUNT(*) as c FROM sessions WHERE strftime('%m-%d', started_at) IN ('12-25', '01-01', '07-04')\"\n )\n return holidays > 0 ? 1 : 0\n }\n\n private querySpeedRunSession(): number {\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM sessions WHERE duration_seconds IS NOT NULL AND duration_seconds <= 20 AND tool_count > 0'\n ) > 0 ? 1 : 0\n }\n\n private queryAllToolsInSession(): number {\n const requiredTools = ['Bash', 'Read', 'Write', 'Edit', 'Grep', 'Glob', 'WebFetch']\n const rows = this.db.prepare(\n \"SELECT session_id, COUNT(DISTINCT tool_name) as cnt FROM events WHERE hook_type = 'PostToolUse' AND tool_name IN ('Bash', 'Read', 'Write', 'Edit', 'Grep', 'Glob', 'WebFetch') GROUP BY session_id\"\n ).all() as { session_id: string; cnt: number }[]\n\n for (const row of rows) {\n if (row.cnt >= requiredTools.length) return 1\n }\n return 0\n }\n\n // ===================================================================\n // NEW: Time & Patterns queries\n // ===================================================================\n\n private queryWitchingHourPrompts(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM prompts WHERE CAST(strftime('%H', timestamp) AS INTEGER) BETWEEN 2 AND 3\"\n )\n }\n\n private queryLunchBreakDays(): number {\n return this.queryScalar(\n \"SELECT COUNT(DISTINCT strftime('%Y-%m-%d', started_at)) as c FROM sessions WHERE CAST(strftime('%H', started_at) AS INTEGER) = 12\"\n )\n }\n\n private queryMondaySessions(): number {\n // SQLite strftime('%w') returns 1 for Monday\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM sessions WHERE CAST(strftime('%w', started_at) AS INTEGER) = 1\"\n )\n }\n\n private queryFridayCommits(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Bash' AND hook_type = 'PostToolUse' AND tool_input LIKE '%git commit%' AND CAST(strftime('%w', timestamp) AS INTEGER) = 5\"\n )\n }\n\n private queryMaxUniqueHoursInDay(): number {\n return this.queryScalar(\n \"SELECT COUNT(DISTINCT CAST(strftime('%H', timestamp) AS INTEGER)) as c FROM prompts GROUP BY strftime('%Y-%m-%d', timestamp) ORDER BY c DESC LIMIT 1\"\n )\n }\n\n private queryUniqueQuarters(): number {\n // Count unique year-quarter combos (e.g. 2025-Q1, 2025-Q2, 2026-Q1 = 3)\n return this.queryScalar(\n \"SELECT COUNT(DISTINCT (strftime('%Y', timestamp) || '-Q' || CASE WHEN CAST(strftime('%m', timestamp) AS INTEGER) BETWEEN 1 AND 3 THEN '1' WHEN CAST(strftime('%m', timestamp) AS INTEGER) BETWEEN 4 AND 6 THEN '2' WHEN CAST(strftime('%m', timestamp) AS INTEGER) BETWEEN 7 AND 9 THEN '3' ELSE '4' END)) as c FROM prompts\"\n )\n }\n\n // ===================================================================\n // NEW: Session Behavior queries\n // ===================================================================\n\n private queryExtendedSessionCount(): number {\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM sessions WHERE duration_seconds IS NOT NULL AND duration_seconds > 3600 AND prompt_count >= 15'\n )\n }\n\n private queryQuickDrawSessions(): number {\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM sessions WHERE duration_seconds IS NOT NULL AND duration_seconds < 120 AND tool_count > 0'\n )\n }\n\n private queryDiverseToolSessions(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM (SELECT session_id FROM events WHERE hook_type = 'PostToolUse' AND tool_name IS NOT NULL GROUP BY session_id HAVING COUNT(DISTINCT tool_name) >= 5)\"\n )\n }\n\n private queryPermissionRequests(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE hook_type = 'PermissionRequest'\"\n )\n }\n\n private queryReturnerDays(): number {\n // Days where a single project had 5+ sessions\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM (SELECT strftime('%Y-%m-%d', started_at) as d, project FROM sessions WHERE project IS NOT NULL GROUP BY d, project HAVING COUNT(*) >= 5)\"\n )\n }\n\n // ===================================================================\n // NEW: Prompt Patterns queries\n // ===================================================================\n\n private queryShortPromptCount(): number {\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM prompts WHERE word_count < 10'\n )\n }\n\n private queryQuestionPromptCount(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM prompts WHERE TRIM(content) LIKE '%?'\"\n )\n }\n\n private querySorryPromptCount(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM prompts WHERE LOWER(content) LIKE '%sorry%'\"\n )\n }\n\n private queryCapsLockPromptCount(): number {\n // Prompts that are fully uppercase and at least 10 chars\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM prompts WHERE content = UPPER(content) AND char_count >= 10\"\n )\n }\n\n private queryEmojiPromptCount(): number {\n // Count prompts containing emoji characters using a range check\n // SQLite doesn't have great emoji support, so we check for characters above the basic multilingual plane\n const rows = this.db.prepare(\n 'SELECT content FROM prompts'\n ).all() as { content: string }[]\n\n const emojiRegex = /[\\u{1F300}-\\u{1F9FF}\\u{2600}-\\u{26FF}\\u{2700}-\\u{27BF}\\u{FE00}-\\u{FE0F}\\u{1FA00}-\\u{1FAFF}]/u\n let count = 0\n for (const row of rows) {\n if (emojiRegex.test(row.content)) {\n count++\n }\n }\n return count\n }\n\n private queryCodeDumpPromptCount(): number {\n // Prompts with 50+ newlines (proxy for 50+ lines)\n const rows = this.db.prepare(\n 'SELECT content FROM prompts WHERE char_count > 200'\n ).all() as { content: string }[]\n\n let count = 0\n for (const row of rows) {\n const lineCount = row.content.split('\\n').length\n if (lineCount >= 50) count++\n }\n return count\n }\n\n // ===================================================================\n // NEW: Error & Recovery queries\n // ===================================================================\n\n private queryRubberDuckCount(): number {\n // Error followed by success on same tool without Edit in between\n const rows = this.db.prepare(\n \"SELECT hook_type, tool_name FROM events WHERE hook_type IN ('PostToolUse', 'PostToolUseFailure') ORDER BY timestamp ASC\"\n ).all() as { hook_type: string; tool_name: string | null }[]\n\n let count = 0\n for (let i = 1; i < rows.length; i++) {\n const prev = rows[i - 1]\n const curr = rows[i]\n if (\n prev.hook_type === 'PostToolUseFailure' &&\n curr.hook_type === 'PostToolUse' &&\n prev.tool_name === curr.tool_name &&\n curr.tool_name !== 'Edit'\n ) {\n count++\n }\n }\n return count\n }\n\n private queryThirdTimeCharmCount(): number {\n // Tool success after 2+ consecutive failures of same tool\n const rows = this.db.prepare(\n \"SELECT hook_type, tool_name FROM events WHERE hook_type IN ('PostToolUse', 'PostToolUseFailure') ORDER BY timestamp ASC\"\n ).all() as { hook_type: string; tool_name: string | null }[]\n\n let count = 0\n let failStreak = 0\n let failTool: string | null = null\n\n for (const row of rows) {\n if (row.hook_type === 'PostToolUseFailure') {\n if (row.tool_name === failTool) {\n failStreak++\n } else {\n failStreak = 1\n failTool = row.tool_name\n }\n } else if (row.hook_type === 'PostToolUse') {\n if (failStreak >= 2 && row.tool_name === failTool) {\n count++\n }\n failStreak = 0\n failTool = null\n }\n }\n return count\n }\n\n private queryUndoEditCount(): number {\n // Back-to-back Edit on same file within same session\n const rows = this.db.prepare(\n \"SELECT session_id, json_extract(tool_input, '$.file_path') as fp FROM events WHERE tool_name = 'Edit' AND hook_type = 'PostToolUse' AND tool_input IS NOT NULL ORDER BY timestamp ASC\"\n ).all() as { session_id: string; fp: string | null }[]\n\n let count = 0\n for (let i = 1; i < rows.length; i++) {\n if (rows[i].session_id === rows[i - 1].session_id && rows[i].fp === rows[i - 1].fp && rows[i].fp) {\n count++\n }\n }\n return count\n }\n\n private queryCrashySessions(): number {\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM sessions WHERE error_count >= 10'\n )\n }\n\n // ===================================================================\n // NEW: Tool Combos queries\n // ===================================================================\n\n private queryReadEditRunCount(): number {\n // Detect Read → Edit → Bash sequences\n const rows = this.db.prepare(\n \"SELECT tool_name FROM events WHERE hook_type = 'PostToolUse' AND tool_name IN ('Read', 'Edit', 'Bash') ORDER BY timestamp ASC\"\n ).all() as { tool_name: string }[]\n\n let count = 0\n for (let i = 2; i < rows.length; i++) {\n if (rows[i - 2].tool_name === 'Read' && rows[i - 1].tool_name === 'Edit' && rows[i].tool_name === 'Bash') {\n count++\n }\n }\n return count\n }\n\n private queryMaxFilesCreatedInSession(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Write' AND hook_type = 'PostToolUse' GROUP BY session_id ORDER BY c DESC LIMIT 1\"\n )\n }\n\n private queryMaxSameFileEditsLifetime(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE tool_name = 'Edit' AND hook_type = 'PostToolUse' GROUP BY json_extract(tool_input, '$.file_path') ORDER BY c DESC LIMIT 1\"\n )\n }\n\n private querySearchThenEditCount(): number {\n // Grep/Glob followed by Edit within same session (adjacent or within 5 events)\n const rows = this.db.prepare(\n \"SELECT session_id, tool_name FROM events WHERE hook_type = 'PostToolUse' AND tool_name IN ('Grep', 'Glob', 'Edit') ORDER BY timestamp ASC\"\n ).all() as { session_id: string; tool_name: string }[]\n\n let count = 0\n for (let i = 1; i < rows.length; i++) {\n if (\n rows[i].tool_name === 'Edit' &&\n (rows[i - 1].tool_name === 'Grep' || rows[i - 1].tool_name === 'Glob') &&\n rows[i].session_id === rows[i - 1].session_id\n ) {\n count++\n }\n }\n return count\n }\n\n // ===================================================================\n // NEW: Project Dedication queries\n // ===================================================================\n\n private queryMaxProjectSessions(): number {\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM sessions WHERE project IS NOT NULL GROUP BY project ORDER BY c DESC LIMIT 1'\n )\n }\n\n private queryMaxProjectsInDay(): number {\n return this.queryScalar(\n \"SELECT COUNT(DISTINCT project) as c FROM sessions WHERE project IS NOT NULL GROUP BY strftime('%Y-%m-%d', started_at) ORDER BY c DESC LIMIT 1\"\n )\n }\n\n private queryFinishedProjects(): number {\n // Projects that had a commit and then 7+ days of inactivity\n const projectRows = this.db.prepare(\n \"SELECT DISTINCT project FROM events WHERE tool_name = 'Bash' AND hook_type = 'PostToolUse' AND tool_input LIKE '%git commit%' AND project IS NOT NULL\"\n ).all() as { project: string }[]\n\n let count = 0\n for (const pr of projectRows) {\n const lastSession = this.db.prepare(\n 'SELECT MAX(started_at) as last FROM sessions WHERE project = ?'\n ).get(pr.project) as { last: string | null } | undefined\n\n if (lastSession?.last) {\n const daysSince = (Date.now() - new Date(lastSession.last).getTime()) / (1000 * 60 * 60 * 24)\n if (daysSince >= 7) count++\n }\n }\n return count\n }\n\n private queryLegacyReturns(): number {\n // Returns to a project after 30+ days of inactivity\n const rows = this.db.prepare(\n 'SELECT project, started_at FROM sessions WHERE project IS NOT NULL ORDER BY project, started_at ASC'\n ).all() as { project: string; started_at: string }[]\n\n let count = 0\n for (let i = 1; i < rows.length; i++) {\n if (rows[i].project === rows[i - 1].project) {\n const prev = new Date(rows[i - 1].started_at).getTime()\n const curr = new Date(rows[i].started_at).getTime()\n const diffDays = (curr - prev) / (1000 * 60 * 60 * 24)\n if (diffDays >= 30) count++\n }\n }\n return count\n }\n\n // ===================================================================\n // NEW: Multi-Agent queries\n // ===================================================================\n\n private queryMaxConcurrentSubagents(): number {\n // Simulate concurrent subagents by tracking start/stop events\n const rows = this.db.prepare(\n \"SELECT hook_type, tool_input FROM events WHERE hook_type IN ('SubagentStart', 'SubagentStop') ORDER BY timestamp ASC\"\n ).all() as { hook_type: string; tool_input: string | null }[]\n\n let current = 0\n let max = 0\n for (const row of rows) {\n if (row.hook_type === 'SubagentStart') {\n current++\n max = Math.max(max, current)\n } else {\n current = Math.max(0, current - 1)\n }\n }\n return max\n }\n\n private queryQuickSubagentStops(): number {\n // Subagents stopped within 30 seconds of starting\n const starts = this.db.prepare(\n \"SELECT tool_input, timestamp FROM events WHERE hook_type = 'SubagentStart'\"\n ).all() as { tool_input: string | null; timestamp: string }[]\n\n const stops = this.db.prepare(\n \"SELECT tool_input, timestamp FROM events WHERE hook_type = 'SubagentStop'\"\n ).all() as { tool_input: string | null; timestamp: string }[]\n\n let count = 0\n for (const start of starts) {\n if (!start.tool_input) continue\n let agentId: string | null = null\n try {\n const parsed = JSON.parse(start.tool_input)\n agentId = parsed.agent_id ?? null\n } catch { continue }\n if (!agentId) continue\n\n for (const stop of stops) {\n if (!stop.tool_input) continue\n try {\n const parsed = JSON.parse(stop.tool_input)\n if (parsed.agent_id === agentId) {\n const startTime = new Date(start.timestamp).getTime()\n const stopTime = new Date(stop.timestamp).getTime()\n if ((stopTime - startTime) < 30000) count++\n break\n }\n } catch { continue }\n }\n }\n return count\n }\n\n private queryMaxSubagentsInSession(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM events WHERE hook_type = 'SubagentStart' GROUP BY session_id ORDER BY c DESC LIMIT 1\"\n )\n }\n\n // ===================================================================\n // NEW: Humor & Meta queries\n // ===================================================================\n\n private queryDejaVuCount(): number {\n // Same prompt submitted twice within 5 minutes\n const rows = this.db.prepare(\n 'SELECT LOWER(TRIM(content)) as content, timestamp FROM prompts ORDER BY timestamp ASC'\n ).all() as { content: string; timestamp: string }[]\n\n let count = 0\n for (let i = 1; i < rows.length; i++) {\n if (rows[i].content === rows[i - 1].content) {\n const prev = new Date(rows[i - 1].timestamp).getTime()\n const curr = new Date(rows[i].timestamp).getTime()\n if ((curr - prev) < 300000) count++ // 5 minutes\n }\n }\n return count\n }\n\n private queryTrustIssueCount(): number {\n // Read immediately after Write on same file\n const rows = this.db.prepare(\n \"SELECT tool_name, json_extract(tool_input, '$.file_path') as fp FROM events WHERE hook_type = 'PostToolUse' AND tool_name IN ('Write', 'Read') AND tool_input IS NOT NULL ORDER BY timestamp ASC\"\n ).all() as { tool_name: string; fp: string | null }[]\n\n let count = 0\n for (let i = 1; i < rows.length; i++) {\n if (rows[i].tool_name === 'Read' && rows[i - 1].tool_name === 'Write' && rows[i].fp === rows[i - 1].fp && rows[i].fp) {\n count++\n }\n }\n return count\n }\n\n private queryBackseatDriverCount(): number {\n // Prompts with numbered step-by-step instructions (e.g., \"1.\" \"2.\" \"3.\")\n const rows = this.db.prepare(\n 'SELECT content FROM prompts WHERE char_count > 20'\n ).all() as { content: string }[]\n\n let count = 0\n const stepPattern = /(?:^|\\n)\\s*\\d+\\.\\s/\n for (const row of rows) {\n const matches = row.content.match(/(?:^|\\n)\\s*\\d+\\.\\s/g)\n if (matches && matches.length >= 3) count++\n }\n return count\n }\n\n private queryNegotiatorCount(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM prompts WHERE LOWER(content) LIKE '%try again%' OR LOWER(content) LIKE '%one more time%'\"\n )\n }\n\n private queryMaxConsecutivePermissions(): number {\n const rows = this.db.prepare(\n \"SELECT hook_type FROM events WHERE hook_type IN ('PermissionRequest', 'PostToolUse', 'UserPromptSubmit') ORDER BY timestamp ASC\"\n ).all() as { hook_type: string }[]\n\n let maxStreak = 0\n let current = 0\n for (const row of rows) {\n if (row.hook_type === 'PermissionRequest') {\n current++\n maxStreak = Math.max(maxStreak, current)\n } else {\n current = 0\n }\n }\n return maxStreak\n }\n\n private queryBashRetrySuccessCount(): number {\n // Bash success after a previous Bash failure\n const rows = this.db.prepare(\n \"SELECT hook_type FROM events WHERE tool_name = 'Bash' AND hook_type IN ('PostToolUse', 'PostToolUseFailure') ORDER BY timestamp ASC\"\n ).all() as { hook_type: string }[]\n\n let count = 0\n for (let i = 1; i < rows.length; i++) {\n if (rows[i - 1].hook_type === 'PostToolUseFailure' && rows[i].hook_type === 'PostToolUse') {\n count++\n }\n }\n return count\n }\n\n // ===================================================================\n // NEW: Secret queries\n // ===================================================================\n\n private queryEasterEggActivity(): number {\n // Check for sessions on Easter, Valentine's Day, or Thanksgiving\n // Valentine's Day: Feb 14, Thanksgiving: Nov 22-28 (Thursday, 4th week)\n // We use a simplified check for key dates\n const count = this.queryScalar(\n \"SELECT COUNT(*) as c FROM sessions WHERE strftime('%m-%d', started_at) IN ('02-14', '11-28', '11-27', '11-26', '11-25', '11-24', '11-23', '11-22') OR (strftime('%m', started_at) = '04' AND CAST(strftime('%d', started_at) AS INTEGER) BETWEEN 1 AND 25)\"\n )\n return count > 0 ? 1 : 0\n }\n\n private queryFullMoonSession(): number {\n // Check if any session falls on a full moon date\n // Using lunar cycle calculation: known new moon = Jan 11, 2024\n // Full moon is ~14.765 days after new moon, cycle is ~29.53059 days\n const knownNewMoon = new Date('2024-01-11T11:57:00Z').getTime()\n const lunarCycleMs = 29.53059 * 24 * 60 * 60 * 1000\n const fullMoonOffsetMs = 14.765 * 24 * 60 * 60 * 1000\n const oneDayMs = 24 * 60 * 60 * 1000\n\n const rows = this.db.prepare(\n 'SELECT started_at FROM sessions'\n ).all() as { started_at: string }[]\n\n for (const row of rows) {\n const sessionTime = new Date(row.started_at).getTime()\n const timeSinceFullMoon = ((sessionTime - knownNewMoon - fullMoonOffsetMs) % lunarCycleMs + lunarCycleMs) % lunarCycleMs\n // Within 1 day of a full moon\n if (timeSinceFullMoon < oneDayMs || timeSinceFullMoon > lunarCycleMs - oneDayMs) {\n return 1\n }\n }\n return 0\n }\n\n private queryBirthdaySession(): number {\n // Session on the anniversary of first session (same month-day, different year)\n const first = this.db.prepare(\n 'SELECT started_at FROM sessions ORDER BY started_at ASC LIMIT 1'\n ).get() as { started_at: string } | undefined\n\n if (!first) return 0\n\n const installMonthDay = first.started_at.slice(5, 10) // \"MM-DD\"\n const installYear = first.started_at.slice(0, 4)\n\n const anniversarySession = this.queryScalar(\n \"SELECT COUNT(*) as c FROM sessions WHERE strftime('%m-%d', started_at) = ? AND strftime('%Y', started_at) != ?\",\n installMonthDay, installYear\n )\n return anniversarySession > 0 ? 1 : 0\n }\n\n private queryGhostSessions(): number {\n return this.queryScalar(\n \"SELECT COUNT(*) as c FROM sessions WHERE tool_count = 0 AND ended_at IS NOT NULL\"\n ) > 0 ? 1 : 0\n }\n\n private queryBullseyeSessions(): number {\n // Session with exactly 1 prompt, 0 errors, and at least 1 tool call\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM sessions WHERE prompt_count = 1 AND error_count = 0 AND tool_count > 0'\n ) > 0 ? 1 : 0\n }\n\n // === Token Usage queries ===\n\n private queryHeavyTokenSessions(): number {\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM sessions WHERE (COALESCE(input_tokens, 0) + COALESCE(output_tokens, 0) + COALESCE(cache_creation_input_tokens, 0) + COALESCE(cache_read_input_tokens, 0)) >= 1000000'\n )\n }\n\n private queryLightTokenSessions(): number {\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM sessions WHERE (COALESCE(input_tokens, 0) + COALESCE(output_tokens, 0) + COALESCE(cache_creation_input_tokens, 0) + COALESCE(cache_read_input_tokens, 0)) > 0 AND (COALESCE(input_tokens, 0) + COALESCE(output_tokens, 0) + COALESCE(cache_creation_input_tokens, 0) + COALESCE(cache_read_input_tokens, 0)) < 50000 AND tool_count > 0'\n )\n }\n\n private queryMaxOutputInSession(): number {\n return this.queryScalar(\n 'SELECT COALESCE(MAX(output_tokens), 0) as c FROM sessions'\n )\n }\n\n private queryHasTenMillionSession(): number {\n return this.queryScalar(\n 'SELECT COUNT(*) as c FROM sessions WHERE (COALESCE(input_tokens, 0) + COALESCE(output_tokens, 0) + COALESCE(cache_creation_input_tokens, 0) + COALESCE(cache_read_input_tokens, 0)) >= 10000000'\n ) > 0 ? 1 : 0\n }\n}\n"],"mappings":";;;AAGO,IAAM,oBAAuC;AAAA;AAAA;AAAA;AAAA,EAIlD,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,4BAA4B,UAAU,UAAU,MAAM,gBAAgB,OAAO,CAAC,GAAG,KAAK,MAAM,KAAO,GAAK,GAAG,SAAS,8CAA8C;AAAA,EAC9O,EAAE,IAAI,aAAa,MAAM,aAAa,MAAM,aAAa,aAAa,mBAAmB,UAAU,UAAU,MAAM,kBAAkB,OAAO,CAAC,IAAI,MAAM,MAAO,KAAQ,GAAM,GAAG,SAAS,4CAA4C;AAAA,EACpO,EAAE,IAAI,YAAY,MAAM,YAAY,MAAM,aAAa,aAAa,2BAA2B,UAAU,UAAU,MAAM,qBAAqB,OAAO,CAAC,GAAG,IAAI,KAAK,KAAM,GAAI,GAAG,SAAS,+CAA+C;AAAA,EACvO,EAAE,IAAI,aAAa,MAAM,aAAa,MAAM,UAAY,aAAa,8BAA8B,UAAU,UAAU,MAAM,mBAAmB,OAAO,CAAC,KAAM,KAAQ,KAAS,KAAS,IAAQ,GAAG,SAAS,oCAAoC;AAAA,EAChP,EAAE,IAAI,eAAe,MAAM,eAAe,MAAM,aAAa,aAAa,qBAAqB,UAAU,UAAU,MAAM,iBAAiB,OAAO,CAAC,GAAG,IAAI,KAAK,MAAM,GAAK,GAAG,SAAS,2BAA2B;AAAA;AAAA;AAAA;AAAA,EAKhN,EAAE,IAAI,cAAc,MAAM,cAAc,MAAM,aAAa,aAAa,yBAAyB,UAAU,gBAAgB,MAAM,qBAAqB,OAAO,CAAC,IAAI,KAAK,MAAM,KAAO,GAAK,GAAG,SAAS,yCAAyC;AAAA,EAC9O,EAAE,IAAI,YAAY,MAAM,YAAY,MAAM,aAAa,aAAa,cAAc,UAAU,gBAAgB,MAAM,kBAAkB,OAAO,CAAC,IAAI,KAAK,KAAM,MAAO,GAAM,GAAG,SAAS,gCAAgC;AAAA,EACpN,EAAE,IAAI,mBAAmB,MAAM,mBAAmB,MAAM,aAAa,aAAa,cAAc,UAAU,gBAAgB,MAAM,oBAAoB,OAAO,CAAC,IAAI,KAAK,MAAM,KAAO,GAAK,GAAG,SAAS,kCAAkC;AAAA,EACrO,EAAE,IAAI,aAAa,MAAM,aAAa,MAAM,aAAa,aAAa,gBAAgB,UAAU,gBAAgB,MAAM,qBAAqB,OAAO,CAAC,IAAI,KAAK,KAAK,MAAM,GAAK,GAAG,SAAS,oCAAoC;AAAA,EAC5N,EAAE,IAAI,aAAa,MAAM,aAAa,MAAM,aAAa,aAAa,6BAA6B,UAAU,gBAAgB,MAAM,iBAAiB,OAAO,CAAC,IAAI,KAAK,KAAM,MAAO,GAAM,GAAG,SAAS,mCAAmC;AAAA,EACvO,EAAE,IAAI,eAAe,MAAM,eAAe,MAAM,aAAa,aAAa,mBAAmB,UAAU,gBAAgB,MAAM,mBAAmB,OAAO,CAAC,GAAG,IAAI,KAAK,KAAM,GAAI,GAAG,SAAS,sBAAsB;AAAA,EAChN,EAAE,IAAI,aAAa,MAAM,aAAa,MAAM,aAAa,aAAa,mBAAmB,UAAU,gBAAgB,MAAM,kBAAkB,OAAO,CAAC,IAAI,KAAK,KAAK,MAAM,GAAK,GAAG,SAAS,6CAA6C;AAAA;AAAA;AAAA;AAAA,EAKrO,EAAE,IAAI,eAAe,MAAM,eAAe,MAAM,aAAa,aAAa,2BAA2B,UAAU,QAAQ,MAAM,iBAAiB,OAAO,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,SAAS,mDAAmD;AAAA,EACvO,EAAE,IAAI,aAAa,MAAM,aAAa,MAAM,aAAa,aAAa,oCAAoC,UAAU,QAAQ,MAAM,iBAAiB,OAAO,CAAC,IAAI,IAAI,KAAK,KAAM,GAAI,GAAG,SAAS,8CAA8C;AAAA,EAC5O,EAAE,IAAI,cAAc,MAAM,cAAc,MAAM,aAAa,aAAa,+BAA+B,UAAU,QAAQ,MAAM,kBAAkB,OAAO,CAAC,IAAI,IAAI,KAAK,KAAM,GAAI,GAAG,SAAS,0CAA0C;AAAA,EACtO,EAAE,IAAI,mBAAmB,MAAM,mBAAmB,MAAM,UAAY,aAAa,oBAAoB,UAAU,QAAQ,MAAM,mBAAmB,OAAO,CAAC,GAAG,IAAI,KAAK,KAAK,GAAI,GAAG,SAAS,yCAAyC;AAAA,EAClO,EAAE,IAAI,iBAAiB,MAAM,iBAAiB,MAAM,aAAa,aAAa,8CAA+C,UAAU,QAAQ,MAAM,uBAAuB,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,GAAI,GAAG,SAAS,0CAA0C;AAAA,EAC9P,EAAE,IAAI,qBAAqB,MAAM,qBAAqB,MAAM,aAAa,aAAa,wCAAwC,UAAU,QAAQ,MAAM,kBAAkB,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,GAAG,GAAG,SAAS,6CAA6C;AAAA,EAC3P,EAAE,IAAI,qBAAqB,MAAM,qBAAqB,MAAM,aAAa,aAAa,4CAA4C,UAAU,QAAQ,MAAM,kBAAkB,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,GAAG,GAAG,SAAS,6BAA6B;AAAA,EAChP,EAAE,IAAI,kBAAkB,MAAM,kBAAkB,MAAM,aAAa,aAAa,0CAA0C,UAAU,QAAQ,MAAM,iBAAiB,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,GAAI,GAAG,SAAS,6CAA6C;AAAA,EACxP,EAAE,IAAI,qBAAqB,MAAM,qBAAqB,MAAM,UAAY,aAAa,wCAAwC,UAAU,QAAQ,MAAM,uBAAuB,OAAO,CAAC,GAAG,GAAG,IAAI,IAAI,EAAE,GAAG,SAAS,iDAAiD;AAAA,EACjQ,EAAE,IAAI,kBAAkB,MAAM,kBAAkB,MAAM,aAAa,aAAa,0CAA0C,UAAU,QAAQ,MAAM,kBAAkB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,SAAS,mEAAmE;AAAA;AAAA;AAAA;AAAA,EAKxQ,EAAE,IAAI,kBAAkB,MAAM,kBAAkB,MAAM,UAAY,aAAa,yCAAyC,UAAU,oBAAoB,MAAM,wBAAwB,OAAO,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,SAAS,wCAAwC;AAAA,EAClQ,EAAE,IAAI,cAAc,MAAM,cAAc,MAAM,aAAa,aAAa,oCAAoC,UAAU,oBAAoB,MAAM,qBAAqB,OAAO,CAAC,GAAG,IAAI,KAAK,KAAK,IAAI,GAAG,SAAS,oDAAoD;AAAA,EAClQ,EAAE,IAAI,aAAa,MAAM,aAAa,MAAM,aAAa,aAAa,4CAA4C,UAAU,oBAAoB,MAAM,uBAAuB,OAAO,CAAC,GAAG,IAAI,KAAK,KAAK,IAAI,GAAG,SAAS,wCAAwC;AAAA,EAC9P,EAAE,IAAI,kBAAkB,MAAM,kBAAkB,MAAM,aAAa,aAAa,oCAAoC,UAAU,oBAAoB,MAAM,oBAAoB,OAAO,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,SAAS,+CAA+C;AAAA,EACjQ,EAAE,IAAI,mBAAmB,MAAM,mBAAmB,MAAM,aAAa,aAAa,4CAA4C,UAAU,oBAAoB,MAAM,sBAAsB,OAAO,CAAC,IAAI,KAAK,KAAK,MAAM,GAAK,GAAG,SAAS,oCAAoC;AAAA,EACzQ,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,4BAA4B,UAAU,oBAAoB,MAAM,gBAAgB,OAAO,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,SAAS,4CAA4C;AAAA;AAAA;AAAA;AAAA,EAK9O,EAAE,IAAI,qBAAqB,MAAM,qBAAqB,MAAM,aAAa,aAAa,gCAAgC,UAAU,cAAc,MAAM,2BAA2B,OAAO,CAAC,IAAI,KAAK,KAAK,KAAM,GAAK,GAAG,SAAS,4CAA4C;AAAA,EACxQ,EAAE,IAAI,YAAY,MAAM,YAAY,MAAM,aAAa,aAAa,yBAAyB,UAAU,cAAc,MAAM,mBAAmB,OAAO,CAAC,GAAG,GAAG,GAAG,IAAI,EAAE,GAAG,SAAS,+CAA+C;AAAA,EAChO,EAAE,IAAI,WAAW,MAAM,WAAW,MAAM,aAAa,aAAa,iBAAiB,UAAU,cAAc,MAAM,gBAAgB,OAAO,CAAC,GAAG,IAAI,KAAK,KAAK,GAAI,GAAG,SAAS,oCAAoC;AAAA,EAC9M,EAAE,IAAI,YAAY,MAAM,YAAY,MAAM,aAAa,aAAa,sCAAsC,UAAU,cAAc,MAAM,mBAAmB,OAAO,CAAC,GAAG,IAAI,KAAK,KAAK,GAAI,GAAG,SAAS,qCAAqC;AAAA,EACzO,EAAE,IAAI,eAAe,MAAM,eAAe,MAAM,UAAY,aAAa,wCAAwC,UAAU,cAAc,MAAM,qBAAqB,OAAO,CAAC,GAAG,IAAI,KAAK,KAAK,GAAI,GAAG,SAAS,yCAAyC;AAAA;AAAA;AAAA;AAAA,EAKtP,EAAE,IAAI,cAAc,MAAM,cAAc,MAAM,aAAa,aAAa,0BAA0B,UAAU,mBAAmB,MAAM,oBAAoB,OAAO,CAAC,GAAG,IAAI,KAAK,KAAK,GAAI,GAAG,SAAS,mCAAmC;AAAA,EACrO,EAAE,IAAI,mBAAmB,MAAM,mBAAmB,MAAM,UAAY,aAAa,sCAAsC,UAAU,mBAAmB,MAAM,uBAAuB,OAAO,CAAC,IAAI,IAAI,KAAK,KAAM,GAAI,GAAG,SAAS,sCAAsC;AAAA,EAClQ,EAAE,IAAI,kBAAkB,MAAM,kBAAkB,MAAM,aAAa,aAAa,4BAA4B,UAAU,mBAAmB,MAAM,oBAAoB,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,GAAI,GAAG,SAAS,sCAAsC;AAAA,EACjP,EAAE,IAAI,oBAAoB,MAAM,oBAAoB,MAAM,aAAa,aAAa,uBAAuB,UAAU,mBAAmB,MAAM,uBAAuB,OAAO,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,SAAS,oDAAoD;AAAA,EAC/P,EAAE,IAAI,mBAAmB,MAAM,mBAAmB,MAAM,aAAa,aAAa,mBAAmB,UAAU,mBAAmB,MAAM,oBAAoB,OAAO,CAAC,GAAG,IAAI,KAAK,KAAK,GAAI,GAAG,SAAS,sCAAsC;AAAA,EAC3O,EAAE,IAAI,aAAa,MAAM,aAAa,MAAM,aAAa,aAAa,oCAAoC,UAAU,mBAAmB,MAAM,uBAAuB,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,GAAI,GAAG,SAAS,iCAAiC;AAAA;AAAA;AAAA;AAAA,EAK7O,EAAE,IAAI,eAAe,MAAM,eAAe,MAAM,UAAY,aAAa,kCAAkC,UAAU,cAAc,MAAM,0BAA0B,OAAO,CAAC,IAAI,KAAK,KAAK,KAAM,GAAK,GAAG,SAAS,sDAAsD;AAAA,EACtQ,EAAE,IAAI,aAAa,MAAM,aAAa,MAAM,aAAa,aAAa,kBAAkB,UAAU,cAAc,MAAM,eAAe,OAAO,CAAC,IAAI,IAAI,KAAK,KAAM,GAAI,GAAG,SAAS,4CAA4C;AAAA,EAC5N,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,mBAAmB,UAAU,cAAc,MAAM,mBAAmB,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,GAAG,GAAG,SAAS,0CAA0C;AAAA;AAAA;AAAA;AAAA,EAKhO,EAAE,IAAI,eAAe,MAAM,eAAe,MAAM,aAAa,aAAa,2CAA2C,UAAU,kBAAkB,MAAM,mBAAmB,OAAO,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,SAAS,qEAAqE;AAAA,EACrR,EAAE,IAAI,qBAAqB,MAAM,0BAA0B,MAAM,aAAa,aAAa,4BAA4B,UAAU,kBAAkB,MAAM,uBAAuB,OAAO,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,SAAS,0DAA0D;AAAA,EAChR,EAAE,IAAI,cAAc,MAAM,cAAc,MAAM,UAAY,aAAa,kBAAkB,UAAU,kBAAkB,MAAM,iBAAiB,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,GAAI,GAAG,SAAS,wDAAwD;AAAA,EAC5O,EAAE,IAAI,oBAAoB,MAAM,oBAAoB,MAAM,aAAa,aAAa,iCAAiC,UAAU,kBAAkB,MAAM,kBAAkB,OAAO,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,SAAS,2BAA2B;AAAA,EAC1O,EAAE,IAAI,WAAW,MAAM,WAAW,MAAM,aAAa,aAAa,2CAA2C,UAAU,kBAAkB,MAAM,uBAAuB,OAAO,CAAC,KAAK,KAAK,KAAM,KAAM,GAAK,GAAG,SAAS,qDAAqD;AAAA;AAAA;AAAA;AAAA,EAK1Q,EAAE,IAAI,iBAAiB,MAAM,iBAAiB,MAAM,aAAa,aAAa,qBAAqB,UAAU,eAAe,MAAM,oBAAoB,OAAO,CAAC,IAAI,KAAK,KAAK,KAAM,GAAK,GAAG,SAAS,4DAA4D;AAAA,EAC/P,EAAE,IAAI,cAAc,MAAM,cAAc,MAAM,aAAa,aAAa,+CAA+C,UAAU,eAAe,MAAM,iBAAiB,OAAO,CAAC,KAAK,KAAM,KAAM,MAAO,GAAM,GAAG,SAAS,yCAAyC;AAAA,EAClQ,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,mDAAmD,UAAU,eAAe,MAAM,4BAA4B,OAAO,CAAC,IAAI,IAAI,IAAI,KAAK,GAAG,GAAG,SAAS,2CAA2C;AAAA,EAC7Q,EAAE,IAAI,kBAAkB,MAAM,kBAAkB,MAAM,UAAY,aAAa,6BAA6B,UAAU,eAAe,MAAM,4BAA4B,OAAO,CAAC,IAAI,KAAK,KAAK,KAAK,GAAI,GAAG,SAAS,6DAA6D;AAAA,EAC/Q,EAAE,IAAI,sBAAsB,MAAM,sBAAsB,MAAM,aAAa,aAAa,2BAA2B,UAAU,eAAe,MAAM,uBAAuB,OAAO,CAAC,IAAI,KAAK,KAAK,MAAM,GAAK,GAAG,SAAS,iDAAiD;AAAA;AAAA;AAAA;AAAA,EAKvQ,EAAE,IAAI,WAAW,MAAM,WAAW,MAAM,aAAa,aAAa,2BAA2B,UAAU,YAAY,MAAM,gBAAgB,OAAO,CAAC,GAAG,IAAI,KAAK,KAAM,GAAI,GAAG,SAAS,0CAA0C;AAAA,EAC7N,EAAE,IAAI,cAAc,MAAM,cAAc,MAAM,aAAa,aAAa,wBAAwB,UAAU,YAAY,MAAM,YAAY,OAAO,CAAC,GAAG,IAAI,KAAK,KAAK,GAAI,GAAG,SAAS,4CAA4C;AAAA,EAC7N,EAAE,IAAI,UAAU,MAAM,UAAU,MAAM,aAAa,aAAa,2BAA2B,UAAU,YAAY,MAAM,kBAAkB,OAAO,CAAC,GAAG,GAAG,IAAI,IAAI,EAAE,GAAG,SAAS,uCAAuC;AAAA,EACpN,EAAE,IAAI,YAAY,MAAM,YAAY,MAAM,aAAa,aAAa,uCAAuC,UAAU,YAAY,MAAM,mBAAmB,OAAO,CAAC,GAAG,GAAG,GAAG,IAAI,EAAE,GAAG,SAAS,qDAAqD;AAAA;AAAA;AAAA;AAAA,EAKlP,EAAE,IAAI,cAAc,MAAM,cAAc,MAAM,aAAa,aAAa,2BAA2B,UAAU,sBAAsB,MAAM,sBAAsB,OAAO,CAAC,IAAI,KAAK,KAAK,KAAK,GAAI,GAAG,SAAS,qCAAqC;AAAA,EAC/O,EAAE,IAAI,kBAAkB,MAAM,kBAAkB,MAAM,aAAa,aAAa,0CAA0C,UAAU,sBAAsB,MAAM,oBAAoB,OAAO,CAAC,GAAG,GAAG,GAAG,IAAI,EAAE,GAAG,SAAS,gDAAgD;AAAA,EACvQ,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,qCAAqC,UAAU,sBAAsB,MAAM,oBAAoB,OAAO,CAAC,GAAG,GAAG,GAAG,IAAI,EAAE,GAAG,SAAS,8DAA8D;AAAA,EAC5Q,EAAE,IAAI,eAAe,MAAM,eAAe,MAAM,aAAa,aAAa,kCAAkC,UAAU,sBAAsB,MAAM,iBAAiB,OAAO,CAAC,GAAG,GAAG,GAAG,IAAI,EAAE,GAAG,SAAS,oDAAoD;AAAA,EAC1P,EAAE,IAAI,cAAc,MAAM,cAAc,MAAM,aAAa,aAAa,2BAA2B,UAAU,sBAAsB,MAAM,uBAAuB,OAAO,CAAC,IAAI,IAAI,IAAI,KAAK,GAAG,GAAG,SAAS,oCAAoC;AAAA;AAAA;AAAA;AAAA,EAK5O,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,yBAAyB,UAAU,eAAe,MAAM,uBAAuB,OAAO,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,SAAS,qCAAqC;AAAA,EACtO,EAAE,IAAI,aAAa,MAAM,aAAa,MAAM,aAAa,aAAa,yBAAyB,UAAU,eAAe,MAAM,kBAAkB,OAAO,CAAC,IAAI,KAAK,KAAM,KAAM,IAAK,GAAG,SAAS,iDAAiD;AAAA,EAC/O,EAAE,IAAI,sBAAsB,MAAM,sBAAsB,MAAM,aAAa,aAAa,yBAAyB,UAAU,eAAe,MAAM,0BAA0B,OAAO,CAAC,GAAG,GAAG,GAAG,IAAI,EAAE,GAAG,SAAS,+CAA+C;AAAA,EAC5P,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,qCAAqC,UAAU,eAAe,MAAM,sBAAsB,OAAO,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,SAAS,kDAAkD;AAAA,EAC9P,EAAE,IAAI,oBAAoB,MAAM,oBAAoB,MAAM,aAAa,aAAa,gCAAgC,UAAU,eAAe,MAAM,uBAAuB,OAAO,CAAC,IAAI,KAAK,KAAM,KAAM,IAAK,GAAG,SAAS,4CAA4C;AAAA,EACpQ,EAAE,IAAI,eAAe,MAAM,eAAe,MAAM,aAAa,aAAa,wBAAwB,UAAU,eAAe,MAAM,yBAAyB,OAAO,CAAC,IAAI,IAAI,IAAI,KAAK,GAAG,GAAG,SAAS,+CAA+C;AAAA;AAAA,EAGjP,EAAE,IAAI,kBAAkB,MAAM,kBAAkB,MAAM,aAAa,aAAa,8BAA8B,UAAU,eAAe,MAAM,sBAAsB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,SAAS,oEAAoE;AAAA,EACxQ,EAAE,IAAI,oBAAoB,MAAM,oBAAoB,MAAM,UAAY,aAAa,+CAA+C,UAAU,eAAe,MAAM,kBAAkB,OAAO,CAAC,IAAI,IAAI,KAAK,KAAM,GAAI,GAAG,SAAS,mCAAmC;AAAA,EACjQ,EAAE,IAAI,iBAAiB,MAAM,iBAAiB,MAAM,UAAY,aAAa,mCAAmC,UAAU,eAAe,MAAM,mBAAmB,OAAO,CAAC,IAAI,IAAI,KAAK,KAAM,GAAI,GAAG,SAAS,oCAAoC;AAAA,EACjP,EAAE,IAAI,sBAAsB,MAAM,sBAAsB,MAAM,aAAa,aAAa,+BAA+B,UAAU,eAAe,MAAM,oBAAoB,OAAO,CAAC,IAAI,IAAI,KAAK,KAAM,GAAI,GAAG,SAAS,iCAAiC;AAAA,EACtP,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,0CAA0C,UAAU,eAAe,MAAM,mBAAmB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,SAAS,8CAA8C;AAAA,EACxP,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,gCAAgC,UAAU,eAAe,MAAM,mBAAmB,OAAO,CAAC,GAAG,IAAI,KAAK,KAAK,GAAG,GAAG,SAAS,gDAAgD;AAAA;AAAA;AAAA;AAAA,EAKtP,EAAE,IAAI,oBAAoB,MAAM,wBAAwB,MAAM,aAAa,aAAa,mEAAmE,UAAU,aAAa,MAAM,qBAAqB,OAAO,CAAC,IAAI,IAAI,KAAK,KAAM,GAAI,GAAG,SAAS,yCAAyC;AAAA,EACjS,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,2DAA2D,UAAU,aAAa,MAAM,mBAAmB,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,GAAI,GAAG,SAAS,gCAAgC;AAAA,EAC/P,EAAE,IAAI,aAAa,MAAM,aAAa,MAAM,aAAa,aAAa,+CAA+C,UAAU,aAAa,MAAM,oBAAoB,OAAO,CAAC,IAAI,IAAI,IAAI,KAAK,GAAG,GAAG,SAAS,kCAAkC;AAAA,EAChP,EAAE,IAAI,kBAAkB,MAAM,mBAAmB,MAAM,aAAa,aAAa,oCAAoC,UAAU,aAAa,MAAM,oBAAoB,OAAO,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,SAAS,6BAA6B;AAAA,EACzO,EAAE,IAAI,cAAc,MAAM,cAAc,MAAM,aAAa,aAAa,gDAAgD,UAAU,aAAa,MAAM,uBAAuB,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,GAAI,GAAG,SAAS,oCAAoC;AAAA,EACxP,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,4CAA4C,UAAU,aAAa,MAAM,sBAAsB,OAAO,CAAC,IAAI,IAAI,IAAI,KAAK,GAAG,GAAG,SAAS,iCAAiC;AAAA,EACpP,EAAE,IAAI,WAAW,MAAM,iBAAqB,MAAM,aAAa,aAAa,2BAA2B,UAAU,aAAa,MAAM,eAAe,OAAO,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,SAAS,+CAA+C;AAAA,EACxO,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,wCAAwC,UAAU,aAAa,MAAM,mBAAmB,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,GAAI,GAAG,SAAS,gDAAgD;AAAA,EAC5P,EAAE,IAAI,mBAAmB,MAAM,mBAAmB,MAAM,aAAa,aAAa,+CAA+C,UAAU,aAAa,MAAM,uBAAuB,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,GAAI,GAAG,SAAS,mEAAmE;AAAA,EAChS,EAAE,IAAI,kBAAkB,MAAM,kBAAkB,MAAM,aAAa,aAAa,iCAAiC,UAAU,aAAa,MAAM,mBAAmB,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,GAAI,GAAG,SAAS,oDAAoD;AAAA,EAC7P,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,UAAY,aAAa,4BAA4B,UAAU,aAAa,MAAM,6BAA6B,OAAO,CAAC,IAAI,IAAI,KAAK,KAAK,GAAG,GAAG,SAAS,2CAA2C;AAAA,EACrP,EAAE,IAAI,0BAA0B,MAAM,0BAA0B,MAAM,aAAa,aAAa,uBAAuB,UAAU,aAAa,MAAM,yBAAyB,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,GAAI,GAAG,SAAS,2DAA2D;AAAA;AAAA;AAAA;AAAA,EAKhR,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,sCAAsC,UAAU,eAAe,MAAM,eAAe,OAAO,CAAC,KAAU,KAAW,KAAY,MAAa,IAAY,GAAG,SAAS,uEAAuE;AAAA,EACrT,EAAE,IAAI,kBAAkB,MAAM,kBAAkB,MAAM,aAAa,aAAa,sCAAsC,UAAU,eAAe,MAAM,qBAAqB,OAAO,CAAC,KAAS,KAAU,KAAW,KAAW,GAAU,GAAG,SAAS,8DAA8D;AAAA,EAC/S,EAAE,IAAI,iBAAiB,MAAM,iBAAiB,MAAM,aAAa,aAAa,iCAAiC,UAAU,eAAe,MAAM,wBAAwB,OAAO,CAAC,KAAU,KAAW,KAAY,MAAa,IAAY,GAAG,SAAS,+DAA+D;AAAA,EACnT,EAAE,IAAI,mBAAmB,MAAM,mBAAmB,MAAM,aAAa,aAAa,4BAA4B,UAAU,eAAe,MAAM,4BAA4B,OAAO,CAAC,KAAU,KAAW,KAAY,MAAa,IAAY,GAAG,SAAS,6DAA6D;AAAA,EACpT,EAAE,IAAI,eAAe,MAAM,eAAe,MAAM,aAAa,aAAa,iDAAiD,UAAU,eAAe,MAAM,uBAAuB,OAAO,CAAC,KAAU,KAAU,KAAW,KAAW,GAAU,GAAG,SAAS,mDAAmD;AAAA,EAC5S,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,sCAAsC,UAAU,eAAe,MAAM,sBAAsB,OAAO,CAAC,IAAI,IAAI,KAAK,KAAM,GAAI,GAAG,SAAS,wCAAwC;AAAA,EAC1P,EAAE,IAAI,iBAAiB,MAAM,iBAAiB,MAAM,aAAa,aAAa,0CAA0C,UAAU,eAAe,MAAM,sBAAsB,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,GAAI,GAAG,SAAS,+DAA+D;AAAA,EACpR,EAAE,IAAI,kBAAkB,MAAM,kBAAkB,MAAM,UAAY,aAAa,mCAAmC,UAAU,eAAe,MAAM,uBAAuB,OAAO,CAAC,KAAS,KAAU,MAAU,KAAU,GAAS,GAAG,SAAS,uDAAuD;AAAA,EACnS,EAAE,IAAI,oBAAoB,MAAM,YAAY,MAAM,UAAY,aAAa,wCAAwC,UAAU,eAAe,MAAM,sBAAsB,OAAO,CAAC,KAAQ,KAAQ,KAAS,KAAU,GAAQ,GAAG,SAAS,6DAA6D;AAAA,EACpS,EAAE,IAAI,eAAe,MAAM,eAAe,MAAM,aAAa,aAAa,0CAA0C,UAAU,eAAe,MAAM,oBAAoB,OAAO,CAAC,KAAS,KAAU,KAAW,KAAW,GAAU,GAAG,SAAS,6EAA6E;AAAA;AAAA;AAAA;AAAA,EAK3T,EAAE,IAAI,eAAe,MAAM,eAAe,MAAM,UAAY,aAAa,uDAAuD,UAAU,gBAAgB,MAAM,kBAAkB,OAAO,CAAC,KAAQ,KAAQ,KAAQ,KAAQ,GAAM,GAAG,cAAc,MAAM,SAAS,iCAAiC;AAAA,EACjS,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,uCAAuC,UAAU,gBAAgB,MAAM,iBAAiB,OAAO,CAAC,KAAK,KAAK,KAAK,KAAK,GAAG,GAAG,cAAc,MAAM,SAAS,uCAAuC;AAAA,EAC1Q,EAAE,IAAI,iBAAiB,MAAM,iBAAiB,MAAM,aAAa,aAAa,uEAAuE,UAAU,gBAAgB,MAAM,mBAAmB,OAAO,CAAC,KAAU,KAAU,KAAU,KAAU,GAAQ,GAAG,cAAc,MAAM,SAAS,wCAAwC;AAAA,EACxU,EAAE,IAAI,SAAS,MAAM,SAAS,MAAM,aAAa,aAAa,4CAA4C,UAAU,gBAAgB,MAAM,iBAAiB,OAAO,CAAC,KAAO,KAAO,KAAO,KAAO,GAAK,GAAG,cAAc,MAAM,SAAS,2BAA2B;AAAA,EAC/P,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,UAAY,aAAa,sDAAsD,UAAU,gBAAgB,MAAM,WAAW,OAAO,CAAC,KAAQ,KAAQ,KAAQ,KAAQ,GAAM,GAAG,cAAc,MAAM,SAAS,wBAAwB;AAAA,EAClR,EAAE,IAAI,cAAc,MAAM,cAAc,MAAM,aAAa,aAAa,mEAAmE,UAAU,gBAAgB,MAAM,oBAAoB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,cAAc,MAAM,SAAS,8CAA8C;AAAA,EAClS,EAAE,IAAI,sBAAsB,MAAM,gBAAgB,MAAM,UAAY,aAAa,oCAAoC,UAAU,gBAAgB,MAAM,qBAAqB,OAAO,CAAC,KAAO,KAAO,KAAO,KAAO,GAAK,GAAG,cAAc,MAAM,SAAS,iCAAiC;AAAA,EACpR,EAAE,IAAI,oBAAoB,MAAM,iBAAiB,MAAM,aAAa,aAAa,+CAA+C,UAAU,gBAAgB,MAAM,qBAAqB,OAAO,CAAC,KAAM,KAAM,KAAM,KAAM,GAAI,GAAG,cAAc,MAAM,SAAS,0CAA0C;AAAA,EACnS,EAAE,IAAI,iBAAiB,MAAM,iBAAiB,MAAM,aAAa,aAAa,wCAAwC,UAAU,gBAAgB,MAAM,iBAAiB,OAAO,CAAC,KAAK,KAAK,KAAK,KAAK,GAAG,GAAG,cAAc,MAAM,SAAS,wCAAwC;AAAA,EAC9Q,EAAE,IAAI,iBAAiB,MAAM,iBAAiB,MAAM,aAAa,aAAa,wBAAwB,UAAU,gBAAgB,MAAM,8BAA8B,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,cAAc,MAAM,SAAS,kDAAkD;AAAA,EAC3Q,EAAE,IAAI,oBAAoB,MAAM,oBAAoB,MAAM,UAAY,aAAa,gDAAgD,UAAU,gBAAgB,MAAM,mBAAmB,OAAO,CAAC,KAAW,KAAW,KAAW,KAAW,GAAS,GAAG,cAAc,MAAM,SAAS,yCAAyC;AAAA,EAC5T,EAAE,IAAI,qBAAqB,MAAM,qBAAqB,MAAM,aAAa,aAAa,+DAA+D,UAAU,gBAAgB,MAAM,eAAe,OAAO,CAAC,KAAY,KAAY,KAAY,KAAY,GAAU,GAAG,cAAc,MAAM,SAAS,iCAAiC;AAAA;AAAA;AAAA;AAAA,EAKvU,EAAE,IAAI,kBAAkB,MAAM,mBAAmB,MAAM,aAAa,aAAa,+FAA+F,UAAU,UAAU,MAAM,2BAA2B,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,iDAAiD;AAAA,EACrU,EAAE,IAAI,eAAe,MAAM,eAAe,MAAM,aAAa,aAAa,yEAAyE,UAAU,UAAU,MAAM,oBAAoB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,2CAA2C;AAAA,EAC3R,EAAE,IAAI,kBAAkB,MAAM,aAAa,MAAM,aAAa,aAAa,kEAAkE,UAAU,UAAU,MAAM,iBAAiB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,kCAAkC;AAAA,EACzQ,EAAE,IAAI,eAAe,MAAM,eAAe,MAAM,aAAa,aAAa,4DAA4D,UAAU,UAAU,MAAM,uBAAuB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,uDAAuD;AAAA,EAC7R,EAAE,IAAI,aAAa,MAAM,aAAa,MAAM,aAAa,aAAa,yBAAyB,UAAU,UAAU,MAAM,kBAAkB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,mCAAmC;AAAA,EAC7N,EAAE,IAAI,kBAAkB,MAAM,kBAAkB,MAAM,aAAa,aAAa,6DAA6D,UAAU,UAAU,MAAM,mBAAmB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,qCAAqC;AAAA,EAC9Q,EAAE,IAAI,aAAa,MAAM,kBAAkB,MAAM,UAAY,aAAa,wCAAwC,UAAU,UAAU,MAAM,mBAAmB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,yCAAyC;AAAA,EACvP,EAAE,IAAI,aAAa,MAAM,aAAa,MAAM,aAAa,aAAa,sEAAsE,UAAU,UAAU,MAAM,qBAAqB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,sCAAsC;AAAA,EAChR,EAAE,IAAI,cAAc,MAAM,cAAc,MAAM,aAAa,aAAa,oEAAoE,UAAU,UAAU,MAAM,oBAAoB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,mCAAmC;AAAA,EAC5Q,EAAE,IAAI,qBAAqB,MAAM,qBAAqB,MAAM,aAAa,aAAa,wBAAwB,UAAU,UAAU,MAAM,iBAAiB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,wDAAwD;AAAA,EAChQ,EAAE,IAAI,qBAAqB,MAAM,qBAAqB,MAAM,aAAa,aAAa,iBAAiB,UAAU,UAAU,MAAM,qBAAqB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,sDAAsD;AAAA,EAC3P,EAAE,IAAI,mBAAmB,MAAM,mBAAmB,MAAM,aAAa,aAAa,2BAA2B,UAAU,UAAU,MAAM,mBAAmB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,2DAA2D;AAAA,EACpQ,EAAE,IAAI,iBAAiB,MAAM,iBAAiB,MAAM,aAAa,aAAa,4BAA4B,UAAU,UAAU,MAAM,mBAAmB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,gDAAgD;AAAA,EACtP,EAAE,IAAI,gBAAgB,MAAM,gBAAgB,MAAM,aAAa,aAAa,SAAS,UAAU,UAAU,MAAM,eAAe,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,wCAAwC;AAAA,EACrN,EAAE,IAAI,iBAAiB,MAAM,iBAAiB,MAAM,aAAa,aAAa,QAAQ,UAAU,UAAU,MAAM,iBAAiB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,uCAAuC;AAAA,EACvN,EAAE,IAAI,YAAY,MAAM,YAAY,MAAM,aAAa,aAAa,yBAAyB,UAAU,UAAU,MAAM,oBAAoB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,qDAAqD;AAAA,EAC/O,EAAE,IAAI,qBAAqB,MAAM,qBAAqB,MAAM,aAAa,aAAa,wEAAwE,UAAU,UAAU,MAAM,wBAAwB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,MAAM,SAAS,uDAAuD;AACxT;AAMO,IAAM,qBAAwC;AAAA,EACnD,EAAE,MAAM,kBAAkB,SAAS,KAAK,SAAS,IAAI;AAAA,EACrD,EAAE,MAAM,YAAY,SAAS,KAAK,SAAS,IAAI;AAAA,EAC/C,EAAE,MAAM,WAAW,SAAS,KAAK,SAAS,IAAI;AAAA,EAC9C,EAAE,MAAM,QAAQ,SAAS,KAAK,SAAS,IAAI;AAAA,EAC3C,EAAE,MAAM,UAAU,SAAS,KAAK,SAAS,IAAI;AAAA,EAC7C,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAC7C;AAEO,SAAS,UAAU,MAAsB;AAC9C,MAAI,QAAQ,EAAG,QAAO;AACtB,SAAO,KAAK,MAAM,KAAK,KAAK,IAAI,MAAM,GAAG,CAAC;AAC5C;AAEO,SAAS,gBAAgB,MAAsB;AACpD,aAAW,WAAW,oBAAoB;AACxC,QAAI,QAAQ,QAAQ,WAAW,QAAQ,QAAQ,SAAS;AACtD,aAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AACA,SAAO;AACT;AAMO,IAAM,UAAU,CAAC,GAAG,IAAI,KAAK,KAAK,KAAK,GAAI;AAM3C,IAAM,uBAA+C;AAAA,EAC1D,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AAEO,IAAM,oBAAuC;AAAA,EAClD,EAAE,IAAI,oBAAoB,aAAa,uCAAuC,MAAM,uBAAuB,WAAW,GAAG,UAAU,KAAK,YAAY,KAAK;AAAA,EACzJ,EAAE,IAAI,kBAAkB,aAAa,gCAAgC,MAAM,gBAAgB,WAAW,KAAK,UAAU,KAAK,YAAY,KAAK;AAAA,EAC3I,EAAE,IAAI,qBAAqB,aAAa,uCAAuC,MAAM,qBAAqB,WAAW,GAAG,UAAU,KAAK,YAAY,KAAK;AAAA,EACxJ,EAAE,IAAI,oBAAoB,aAAa,wCAAwC,MAAM,cAAc,WAAW,GAAG,UAAU,KAAK,YAAY,KAAK;AAAA,EACjJ,EAAE,IAAI,mBAAmB,aAAa,kCAAkC,MAAM,cAAc,WAAW,GAAG,UAAU,KAAK,YAAY,KAAK;AAAA,EAC1I,EAAE,IAAI,qBAAqB,aAAa,0CAA0C,MAAM,yBAAyB,WAAW,GAAG,UAAU,KAAK,YAAY,KAAK;AAAA,EAC/J,EAAE,IAAI,iBAAiB,aAAa,6CAA6C,MAAM,gBAAgB,WAAW,GAAG,UAAU,KAAK,YAAY,KAAK;AAAA,EACrJ,EAAE,IAAI,iBAAiB,aAAa,mCAAmC,MAAM,kBAAkB,WAAW,KAAM,UAAU,KAAK,YAAY,KAAK;AAAA,EAChJ,EAAE,IAAI,kBAAkB,aAAa,kCAAkC,MAAM,iBAAiB,WAAW,IAAI,UAAU,KAAK,YAAY,KAAK;AAAA,EAC7I,EAAE,IAAI,kBAAkB,aAAa,kCAAkC,MAAM,iBAAiB,WAAW,IAAI,UAAU,KAAK,YAAY,KAAK;AAAA,EAC7I,EAAE,IAAI,gBAAgB,aAAa,4BAA4B,MAAM,kBAAkB,WAAW,KAAK,UAAU,KAAK,YAAY,KAAK;AAAA,EACvI,EAAE,IAAI,gBAAgB,aAAa,4BAA4B,MAAM,oBAAoB,WAAW,KAAK,UAAU,KAAK,YAAY,KAAK;AAAA,EACzI,EAAE,IAAI,iBAAiB,aAAa,iCAAiC,MAAM,qBAAqB,WAAW,IAAI,UAAU,KAAK,YAAY,KAAK;AAAA,EAC/I,EAAE,IAAI,iBAAiB,aAAa,2CAA2C,MAAM,kBAAkB,WAAW,GAAG,UAAU,KAAK,YAAY,KAAK;AAAA,EACrJ,EAAE,IAAI,kBAAkB,aAAa,uCAAuC,MAAM,wBAAwB,WAAW,GAAG,UAAU,KAAK,YAAY,KAAK;AAAA,EACxJ,EAAE,IAAI,cAAc,aAAa,wCAAwC,MAAM,iBAAiB,WAAW,GAAG,UAAU,KAAK,YAAY,KAAK;AAAA,EAC9I,EAAE,IAAI,eAAe,aAAa,qCAAqC,MAAM,cAAc,WAAW,IAAI,UAAU,KAAK,YAAY,KAAK;AAAA,EAC1I,EAAE,IAAI,eAAe,aAAa,mCAAmC,MAAM,qBAAqB,WAAW,KAAK,UAAU,KAAK,YAAY,KAAK;AAAA,EAChJ,EAAE,IAAI,mBAAmB,aAAa,oCAAoC,MAAM,iBAAiB,WAAW,KAAK,UAAU,KAAK,YAAY,KAAK;AAAA,EACjJ,EAAE,IAAI,sBAAsB,aAAa,0CAA0C,MAAM,mBAAmB,WAAW,IAAI,UAAU,KAAK,YAAY,KAAK;AAAA,EAC3J,EAAE,IAAI,gBAAgB,aAAa,gCAAgC,MAAM,gBAAgB,WAAW,GAAG,UAAU,KAAK,YAAY,KAAK;AAAA,EACvI,EAAE,IAAI,YAAY,aAAa,oCAAoC,MAAM,YAAY,WAAW,GAAG,UAAU,KAAK,YAAY,KAAK;AAAA,EACnI,EAAE,IAAI,iBAAiB,aAAa,mCAAmC,MAAM,kBAAkB,WAAW,KAAM,UAAU,KAAK,YAAY,KAAK;AAAA,EAChJ,EAAE,IAAI,sBAAsB,aAAa,oCAAoC,MAAM,eAAe,WAAW,GAAG,UAAU,KAAK,YAAY,KAAK;AAAA,EAChJ,EAAE,IAAI,oBAAoB,aAAa,wCAAwC,MAAM,iBAAiB,WAAW,GAAG,UAAU,KAAK,YAAY,KAAK;AACtJ;AAMO,IAAM,WAAW;AACjB,IAAM,cAAc;AACpB,IAAM,eAAe;;;ACpR5B,OAAO,cAAc;AAGrB,SAAS,WAAmB;AAC1B,QAAM,IAAI,oBAAI,KAAK;AACnB,QAAM,MAAM,CAAC,MAAc,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG;AACpD,QAAM,KAAK,OAAO,EAAE,gBAAgB,CAAC,EAAE,SAAS,GAAG,GAAG;AACtD,SAAO,GAAG,EAAE,YAAY,CAAC,IAAI,IAAI,EAAE,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,QAAQ,CAAC,CAAC,IAAI,IAAI,EAAE,SAAS,CAAC,CAAC,IAAI,IAAI,EAAE,WAAW,CAAC,CAAC,IAAI,IAAI,EAAE,WAAW,CAAC,CAAC,IAAI,EAAE;AACjJ;AAEA,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4FR,IAAM,cAAN,MAAkB;AAAA,EACf;AAAA,EAER,YAAY,QAAgB;AAC1B,SAAK,KAAK,IAAI,SAAS,MAAM;AAC7B,SAAK,GAAG,OAAO,oBAAoB;AACnC,SAAK,GAAG,OAAO,qBAAqB;AACpC,SAAK,GAAG,OAAO,mBAAmB;AAClC,SAAK,GAAG,KAAK,MAAM;AACnB,SAAK,QAAQ;AAAA,EACf;AAAA,EAEQ,UAAgB;AACtB,UAAM,cAAc,KAAK,GAAG,OAAO,sBAAsB;AACzD,UAAM,kBAAkB,IAAI,IAAI,YAAY,IAAI,OAAK,EAAE,IAAI,CAAC;AAE5D,QAAI,CAAC,gBAAgB,IAAI,OAAO,GAAG;AACjC,WAAK,GAAG,KAAK,2EAA2E;AAAA,IAC1F;AAEA,UAAM,YAAY,CAAC,gBAAgB,iBAAiB,+BAA+B,yBAAyB;AAC5G,eAAW,OAAO,WAAW;AAC3B,UAAI,CAAC,gBAAgB,IAAI,GAAG,GAAG;AAC7B,aAAK,GAAG,KAAK,mCAAmC,GAAG,oBAAoB;AAAA,MACzE;AAAA,IACF;AAEA,UAAM,YAAY,KAAK,GAAG,OAAO,4BAA4B;AAC7D,UAAM,gBAAgB,IAAI,IAAI,UAAU,IAAI,OAAK,EAAE,IAAI,CAAC;AACxD,eAAW,OAAO,WAAW;AAC3B,UAAI,CAAC,cAAc,IAAI,GAAG,GAAG;AAC3B,aAAK,GAAG,KAAK,yCAAyC,GAAG,oBAAoB;AAAA,MAC/E;AAAA,IACF;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,SAAK,GAAG,MAAM;AAAA,EAChB;AAAA,EAEA,gBAA0B;AACxB,UAAM,OAAO,KAAK,GAAG,QAAQ,mDAAmD,EAAE,IAAI;AACtF,WAAO,KAAK,IAAI,OAAK,EAAE,IAAI;AAAA,EAC7B;AAAA;AAAA,EAIA,YAAY,OAAqC;AAC/C,UAAM,OAAO,KAAK,GAAG,QAAQ;AAAA;AAAA;AAAA,KAG5B;AACD,UAAM,SAAS,KAAK;AAAA,MAClB,MAAM;AAAA,MAAY,MAAM;AAAA,MAAW,MAAM;AAAA,MAAW,MAAM;AAAA,MAC1D,MAAM;AAAA,MAAa,MAAM;AAAA,MAAW,MAAM;AAAA,MAAS,MAAM;AAAA,MAAK,MAAM;AAAA,MAAS,MAAM;AAAA,IACrF;AACA,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,UAAU,QAAqF;AAC7F,QAAI,MAAM;AACV,UAAM,SAAoB,CAAC;AAC3B,QAAI,OAAO,YAAY;AAAE,aAAO;AAAuB,aAAO,KAAK,OAAO,UAAU;AAAA,IAAE;AACtF,QAAI,OAAO,WAAW;AAAE,aAAO;AAAsB,aAAO,KAAK,OAAO,SAAS;AAAA,IAAE;AACnF,QAAI,OAAO,WAAW;AAAE,aAAO;AAAsB,aAAO,KAAK,OAAO,SAAS;AAAA,IAAE;AACnF,WAAO;AACP,WAAO,KAAK,GAAG,QAAQ,GAAG,EAAE,IAAI,GAAG,MAAM;AAAA,EAC3C;AAAA;AAAA,EAIA,cAAc,SAA4F;AACxG,SAAK,GAAG,QAAQ;AAAA;AAAA,KAEf,EAAE,IAAI,QAAQ,IAAI,QAAQ,SAAS,eAAe,QAAQ,YAAY,QAAQ,WAAW,IAAI;AAAA,EAChG;AAAA,EAEA,WAAW,IAA+B;AACxC,WAAO,KAAK,GAAG,QAAQ,qCAAqC,EAAE,IAAI,EAAE;AAAA,EACtE;AAAA,EAEA,cAAc,IAAY,SAA2F;AACnH,UAAM,OAAiB,CAAC;AACxB,UAAM,SAAoB,CAAC;AAC3B,QAAI,QAAQ,aAAa,QAAW;AAAE,WAAK,KAAK,cAAc;AAAG,aAAO,KAAK,QAAQ,QAAQ;AAAA,IAAE;AAC/F,QAAI,QAAQ,gBAAgB,QAAW;AAAE,WAAK,KAAK,iBAAiB;AAAG,aAAO,KAAK,QAAQ,WAAW;AAAA,IAAE;AACxG,QAAI,QAAQ,qBAAqB,QAAW;AAAE,WAAK,KAAK,sBAAsB;AAAG,aAAO,KAAK,QAAQ,gBAAgB;AAAA,IAAE;AACvH,QAAI,KAAK,WAAW,EAAG;AACvB,WAAO,KAAK,EAAE;AACd,SAAK,GAAG,QAAQ,uBAAuB,KAAK,KAAK,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,MAAM;AAAA,EACtF;AAAA,EAEA,oBAAoB,IAAY,QAA0B;AACxD,SAAK,GAAG,QAAQ;AAAA;AAAA,KAEf,EAAE,IAAI,OAAO,cAAc,OAAO,eAAe,OAAO,6BAA6B,OAAO,yBAAyB,EAAE;AAAA,EAC1H;AAAA,EAEA,yBAAyB,IAAY,UAAuE;AAC1G,UAAM,OAAiB,CAAC;AACxB,UAAM,SAAoB,CAAC;AAC3B,QAAI,SAAS,SAAS;AAAE,WAAK,KAAK,iCAAiC;AAAG,aAAO,KAAK,SAAS,OAAO;AAAA,IAAE;AACpG,QAAI,SAAS,OAAO;AAAE,WAAK,KAAK,6BAA6B;AAAG,aAAO,KAAK,SAAS,KAAK;AAAA,IAAE;AAC5F,QAAI,SAAS,QAAQ;AAAE,WAAK,KAAK,+BAA+B;AAAG,aAAO,KAAK,SAAS,MAAM;AAAA,IAAE;AAChG,QAAI,KAAK,WAAW,EAAG;AACvB,WAAO,KAAK,EAAE;AACd,SAAK,GAAG,QAAQ,uBAAuB,KAAK,KAAK,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,MAAM;AAAA,EACtF;AAAA;AAAA,EAIA,aAAa,QAAuC;AAClD,UAAM,SAAS,KAAK,GAAG,QAAQ;AAAA;AAAA,KAE9B,EAAE,IAAI,OAAO,YAAY,OAAO,SAAS,OAAO,YAAY,OAAO,YAAY,OAAO,SAAS;AAChG,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,WAAW,WAAgC;AACzC,WAAO,KAAK,GAAG,QAAQ,mEAAmE,EAAE,IAAI,SAAS;AAAA,EAC3G;AAAA;AAAA,EAIA,uBAAuB,MAAc,YAAmP;AACtR,SAAK,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAaf,EAAE;AAAA,MACD;AAAA,MACA,WAAW,YAAY;AAAA,MACvB,WAAW,WAAW;AAAA,MACtB,WAAW,cAAc;AAAA,MACzB,WAAW,UAAU;AAAA,MACrB,WAAW,oBAAoB;AAAA,MAC/B,WAAW,gBAAgB;AAAA,MAC3B,WAAW,iBAAiB;AAAA,MAC5B,WAAW,+BAA+B;AAAA,MAC1C,WAAW,2BAA2B;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,iBAAiB,MAAuC;AACtD,WAAO,KAAK,GAAG,QAAQ,6CAA6C,EAAE,IAAI,IAAI;AAAA,EAChF;AAAA,EAEA,oBAAoB,MAAmC;AACrD,QAAI,MAAM;AACR,aAAO,KAAK,GAAG,QAAQ,yDAAyD,EAAE,IAAI,IAAI;AAAA,IAC5F;AACA,WAAO,KAAK,GAAG,QAAQ,iDAAiD,EAAE,IAAI;AAAA,EAChF;AAAA;AAAA,EAIA,aAAa,SAAiB,MAAoB;AAChD,SAAK,GAAG,QAAQ;AAAA;AAAA,KAEf,EAAE,IAAI,SAAS,MAAM,SAAS,CAAC;AAAA,EAClC;AAAA,EAEA,aAAqC;AACnC,WAAO,KAAK,GAAG,QAAQ,6DAA6D,EAAE,IAAI;AAAA,EAC5F;AAAA,EAEA,uBAA+C;AAC7C,WAAO,KAAK,GAAG,QAAQ,sDAAsD,EAAE,IAAI;AAAA,EACrF;AAAA,EAEA,aAAa,SAAiB,MAAoB;AAChD,SAAK,GAAG,QAAQ,6EAA6E,EAAE,IAAI,SAAS,IAAI;AAAA,EAClH;AAAA;AAAA,EAIA,YAAY,KAAa,OAAqB;AAC5C,SAAK,GAAG,QAAQ,4DAA4D,EAAE,IAAI,KAAK,KAAK;AAAA,EAC9F;AAAA,EAEA,YAAY,KAA4B;AACtC,UAAM,MAAM,KAAK,GAAG,QAAQ,0CAA0C,EAAE,IAAI,GAAG;AAC/E,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA;AAAA,EAIA,iBAAiB,WAAmB,aAAqB,UAAwB;AAC/E,SAAK,GAAG,QAAQ;AAAA;AAAA,KAEf,EAAE,IAAI,WAAW,aAAa,QAAQ;AAAA,EACzC;AAAA,EAEA,mBAAmB,WAAmB,aAA2B;AAC/D,SAAK,GAAG,QAAQ,iFAAiF,EAAE,IAAI,WAAW,WAAW;AAAA,EAC/H;AAAA,EAEA,eAAe,WAAoC;AACjD,WAAO,KAAK,GAAG,QAAQ,iDAAiD,EAAE,IAAI,SAAS;AAAA,EACzF;AAAA;AAAA,EAIA,eAAe,WAAmB,QAAgB,YAAoB,SAAuB;AAC3F,SAAK,GAAG,QAAQ;AAAA;AAAA;AAAA,KAGf,EAAE,IAAI,WAAW,QAAQ,YAAY,SAAS,QAAQ,YAAY,OAAO;AAAA,EAC5E;AAAA,EAEA,YAAY,WAAuC;AACjD,WAAO,KAAK,GAAG,QAAQ,8CAA8C,EAAE,IAAI,SAAS;AAAA,EACtF;AAAA;AAAA,EAIA,QAAQ,KAAiC;AACvC,WAAO,KAAK,GAAG,QAAQ,GAAG;AAAA,EAC5B;AACF;;;AC1UA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,SAAS,qBAAqB;AAOvB,IAAM,eAAuC;AAAA,EAClD,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,oBAAoB;AAAA,EACpB,MAAM;AAAA,EACN,cAAc;AAAA,EACd,eAAe;AAAA,EACf,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,mBAAmB;AAAA,EACnB,OAAO;AACT;AAGA,IAAM,SAAS;AAoBR,SAAS,WAAW,UAAmC,UAA2C;AACvG,QAAM,SAAmB,EAAE,GAAG,SAAS;AAEvC,MAAI,CAAC,OAAO,OAAO;AACjB,WAAO,QAAQ,CAAC;AAAA,EAClB;AAEA,aAAW,CAAC,OAAO,UAAU,KAAK,OAAO,QAAQ,YAAY,GAAG;AAC9D,UAAM,UAAU,SAAS,KAAK,KAAK,UAAU,UAAU,CAAC,KAAK,MAAM;AAGnE,UAAM,WAAwB,OAAO,MAAM,KAAK,KAAK,CAAC;AAGtD,UAAM,eAAe,SAAS,OAAO,CAAC,UAAU;AAC9C,aAAO,CAAC,MAAM,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS,MAAM,CAAC;AAAA,IAC9D,CAAC;AAGD,UAAM,iBAA4B;AAAA,MAChC,SAAS;AAAA,MACT,OAAO,CAAC,EAAE,MAAM,WAAW,QAAQ,CAAC;AAAA,IACtC;AAGA,WAAO,MAAM,KAAK,IAAI,CAAC,GAAG,cAAc,cAAc;AAAA,EACxD;AAEA,SAAO;AACT;AAKO,SAAS,wBAAgC;AAC9C,SAAO,KAAK,KAAK,GAAG,QAAQ,GAAG,WAAW,eAAe;AAC3D;AAKO,SAAS,cAAsB;AACpC,QAAM,aAAa,cAAc,YAAY,GAAG;AAChD,QAAM,YAAY,KAAK,QAAQ,UAAU;AACzC,SAAO,KAAK,QAAQ,WAAW,OAAO;AACxC;AAUO,SAAS,UAAiD;AAC/D,MAAI;AAEF,UAAM,UAAU,KAAK,KAAK,GAAG,QAAQ,GAAG,QAAQ;AAChD,OAAG,UAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAGzC,UAAM,SAAS,KAAK,KAAK,SAAS,WAAW;AAC7C,UAAM,KAAK,IAAI,YAAY,MAAM;AACjC,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,OAAG,YAAY,gBAAgB,GAAG;AAClC,QAAI,CAAC,GAAG,YAAY,WAAW,GAAG;AAChC,SAAG,YAAY,aAAa,GAAG;AAAA,IACjC;AACA,OAAG,MAAM;AAGT,UAAM,YAAY,KAAK,KAAK,GAAG,QAAQ,GAAG,SAAS;AACnD,OAAG,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAG3C,UAAM,eAAe,sBAAsB;AAC3C,QAAI,WAAoC,CAAC;AACzC,QAAI,GAAG,WAAW,YAAY,GAAG;AAC/B,YAAM,MAAM,GAAG,aAAa,cAAc,OAAO;AACjD,iBAAW,KAAK,MAAM,GAAG;AAAA,IAC3B;AAGA,UAAM,WAAW,YAAY;AAC7B,eAAW,WAAW,UAAU,QAAQ;AAGxC,OAAG,cAAc,cAAc,KAAK,UAAU,UAAU,MAAM,CAAC,GAAG,OAAO;AAEzE,WAAO,EAAE,SAAS,MAAM,SAAS,0CAA0C;AAAA,EAC7E,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAO,EAAE,SAAS,OAAO,SAAS,wBAAwB,OAAO,GAAG;AAAA,EACtE;AACF;AAMO,SAAS,YAAmD;AACjE,MAAI;AACF,UAAM,eAAe,sBAAsB;AAC3C,QAAI,CAAC,GAAG,WAAW,YAAY,GAAG;AAChC,aAAO,EAAE,SAAS,MAAM,SAAS,gDAAgD;AAAA,IACnF;AAEA,UAAM,MAAM,GAAG,aAAa,cAAc,OAAO;AACjD,UAAM,WAAqB,KAAK,MAAM,GAAG;AAEzC,QAAI,SAAS,OAAO;AAClB,iBAAW,SAAS,OAAO,KAAK,SAAS,KAAK,GAAG;AAE/C,iBAAS,MAAM,KAAK,IAAI,SAAS,MAAM,KAAK,EAAE,OAAO,CAAC,UAAU;AAC9D,iBAAO,CAAC,MAAM,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS,MAAM,CAAC;AAAA,QAC9D,CAAC;AAGD,YAAI,SAAS,MAAM,KAAK,EAAE,WAAW,GAAG;AACtC,iBAAO,SAAS,MAAM,KAAK;AAAA,QAC7B;AAAA,MACF;AAGA,UAAI,OAAO,KAAK,SAAS,KAAK,EAAE,WAAW,GAAG;AAC5C,eAAO,SAAS;AAAA,MAClB;AAAA,IACF;AAEA,OAAG,cAAc,cAAc,KAAK,UAAU,UAAU,MAAM,CAAC,GAAG,OAAO;AAEzE,WAAO,EAAE,SAAS,MAAM,SAAS,wCAAwC;AAAA,EAC3E,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAO,EAAE,SAAS,OAAO,SAAS,qBAAqB,OAAO,GAAG;AAAA,EACnE;AACF;AAKO,SAAS,cAAuB;AACrC,MAAI;AACF,UAAM,eAAe,sBAAsB;AAC3C,QAAI,CAAC,GAAG,WAAW,YAAY,EAAG,QAAO;AAEzC,UAAM,MAAM,GAAG,aAAa,cAAc,OAAO;AACjD,UAAM,WAAqB,KAAK,MAAM,GAAG;AAEzC,QAAI,CAAC,SAAS,MAAO,QAAO;AAG5B,eAAW,SAAS,OAAO,KAAK,SAAS,KAAK,GAAG;AAC/C,YAAM,UAAU,SAAS,MAAM,KAAK;AACpC,iBAAW,SAAS,SAAS;AAC3B,YAAI,MAAM,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS,MAAM,CAAC,GAAG;AACzD,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACpNA,OAAOA,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAOC,SAAQ;AAkBR,IAAM,sBAA8C;AAAA,EACzD,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,cAAc;AAChB;AAGA,IAAMC,UAAS;AAGf,IAAM,kBAAkB;AA4BjB,SAAS,iBAAiB,UAAmC,UAA2C;AAC7G,QAAM,SAAyB,EAAE,GAAG,SAAS;AAE7C,MAAI,CAAC,OAAO,OAAO;AACjB,WAAO,QAAQ,CAAC;AAAA,EAClB;AAEA,aAAW,CAAC,OAAO,UAAU,KAAK,OAAO,QAAQ,mBAAmB,GAAG;AACrE,UAAM,UAAU,SAASC,MAAK,KAAK,UAAU,UAAU,CAAC,KAAKD,OAAM;AAGnE,UAAM,WAA8B,OAAO,MAAM,KAAK,KAAK,CAAC;AAG5D,UAAM,eAAe,SAAS,OAAO,CAAC,UAAU;AAC9C,aAAO,CAAC,MAAM,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,SAASA,OAAM,CAAC;AAAA,IAC9D,CAAC;AAGD,UAAM,iBAAkC;AAAA,MACtC,OAAO,CAAC,EAAE,MAAM,aAAa,MAAM,WAAW,SAAS,SAAS,gBAAgB,CAAC;AAAA,IACnF;AAGA,WAAO,MAAM,KAAK,IAAI,CAAC,GAAG,cAAc,cAAc;AAAA,EACxD;AAEA,SAAO;AACT;AAKO,SAAS,wBAAgC;AAC9C,SAAOC,MAAK,KAAKC,IAAG,QAAQ,GAAG,WAAW,eAAe;AAC3D;AAKO,SAAS,oBAA6B;AAC3C,MAAI;AACF,UAAM,YAAYD,MAAK,KAAKC,IAAG,QAAQ,GAAG,SAAS;AACnD,WAAOC,IAAG,WAAW,SAAS,KAAKA,IAAG,SAAS,SAAS,EAAE,YAAY;AAAA,EACxE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAuCO,SAAS,gBAAuD;AACrE,MAAI;AAEF,UAAM,UAAUC,MAAK,KAAKC,IAAG,QAAQ,GAAG,QAAQ;AAChD,IAAAC,IAAG,UAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAGzC,UAAM,SAASF,MAAK,KAAK,SAAS,WAAW;AAC7C,UAAM,KAAK,IAAI,YAAY,MAAM;AACjC,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,OAAG,YAAY,gBAAgB,GAAG;AAClC,QAAI,CAAC,GAAG,YAAY,WAAW,GAAG;AAChC,SAAG,YAAY,aAAa,GAAG;AAAA,IACjC;AACA,OAAG,MAAM;AAGT,UAAM,YAAYA,MAAK,KAAKC,IAAG,QAAQ,GAAG,SAAS;AACnD,IAAAC,IAAG,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAG3C,UAAM,eAAe,sBAAsB;AAC3C,QAAI,WAAoC,CAAC;AACzC,QAAIA,IAAG,WAAW,YAAY,GAAG;AAC/B,YAAM,MAAMA,IAAG,aAAa,cAAc,OAAO;AACjD,iBAAW,KAAK,MAAM,GAAG;AAAA,IAC3B;AAGA,UAAM,WAAW,YAAY;AAC7B,eAAW,iBAAiB,UAAU,QAAQ;AAG9C,IAAAA,IAAG,cAAc,cAAc,KAAK,UAAU,UAAU,MAAM,CAAC,GAAG,OAAO;AAEzE,WAAO,EAAE,SAAS,MAAM,SAAS,iDAAiD;AAAA,EACpF,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAO,EAAE,SAAS,OAAO,SAAS,+BAA+B,OAAO,GAAG;AAAA,EAC7E;AACF;AAMO,SAAS,kBAAyD;AACvE,MAAI;AACF,UAAM,eAAe,sBAAsB;AAC3C,QAAI,CAACA,IAAG,WAAW,YAAY,GAAG;AAChC,aAAO,EAAE,SAAS,MAAM,SAAS,uDAAuD;AAAA,IAC1F;AAEA,UAAM,MAAMA,IAAG,aAAa,cAAc,OAAO;AACjD,UAAM,WAA2B,KAAK,MAAM,GAAG;AAE/C,QAAI,SAAS,OAAO;AAClB,iBAAW,SAAS,OAAO,KAAK,SAAS,KAAK,GAAG;AAE/C,iBAAS,MAAM,KAAK,IAAI,SAAS,MAAM,KAAK,EAAE,OAAO,CAAC,UAAU;AAC9D,iBAAO,CAAC,MAAM,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,SAASC,OAAM,CAAC;AAAA,QAC9D,CAAC;AAGD,YAAI,SAAS,MAAM,KAAK,EAAE,WAAW,GAAG;AACtC,iBAAO,SAAS,MAAM,KAAK;AAAA,QAC7B;AAAA,MACF;AAGA,UAAI,OAAO,KAAK,SAAS,KAAK,EAAE,WAAW,GAAG;AAC5C,eAAO,SAAS;AAAA,MAClB;AAAA,IACF;AAEA,IAAAD,IAAG,cAAc,cAAc,KAAK,UAAU,UAAU,MAAM,CAAC,GAAG,OAAO;AAEzE,WAAO,EAAE,SAAS,MAAM,SAAS,+CAA+C;AAAA,EAClF,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAO,EAAE,SAAS,OAAO,SAAS,4BAA4B,OAAO,GAAG;AAAA,EAC1E;AACF;;;ACvOA,OAAOE,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAOC,SAAQ;AACf,SAAS,gBAAgB;AAMlB,IAAM,uBAA+C;AAAA,EAC1D,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,qBAAqB;AAAA,EACrB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,eAAe;AACjB;AAGA,IAAM,iBAAiB;AAmBhB,SAAS,wBAAwB,UAAsC;AAC5E,QAAM,QAA4C,CAAC;AAEnD,aAAW,CAAC,OAAO,UAAU,KAAK,OAAO,QAAQ,oBAAoB,GAAG;AACtE,UAAM,aAAaC,MAAK,KAAK,UAAU,UAAU;AACjD,UAAM,KAAK,IAAI;AAAA,MACb;AAAA,QACE,MAAM;AAAA,QACN,MAAM,SAAS,UAAU;AAAA,QACzB,YAAY,SAAS,UAAU;AAAA,QAC/B,YAAY;AAAA,QACZ,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,GAAG,MAAM;AAC7B;AAKO,SAAS,sBAA8B;AAC5C,SAAOA,MAAK,KAAKC,IAAG,QAAQ,GAAG,YAAY,SAAS,sBAAsB;AAC5E;AAMO,SAAS,iBAAwD;AACtE,MAAI;AACF,UAAM,YAAY,oBAAoB;AACtC,UAAM,WAAWD,MAAK,QAAQ,SAAS;AAGvC,IAAAE,IAAG,UAAU,UAAU,EAAE,WAAW,KAAK,CAAC;AAG1C,UAAM,eAAe,YAAY;AACjC,UAAM,SAAS,wBAAwB,YAAY;AACnD,IAAAA,IAAG,cAAc,WAAW,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,OAAO;AAEpE,WAAO,EAAE,SAAS,MAAM,SAAS,kDAAkD;AAAA,EACrF,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAO,EAAE,SAAS,OAAO,SAAS,gCAAgC,OAAO,GAAG;AAAA,EAC9E;AACF;AAKO,SAAS,mBAA0D;AACxE,MAAI;AACF,UAAM,YAAY,oBAAoB;AAEtC,QAAI,CAACA,IAAG,WAAW,SAAS,GAAG;AAC7B,aAAO,EAAE,SAAS,MAAM,SAAS,uDAAuD;AAAA,IAC1F;AAEA,IAAAA,IAAG,WAAW,SAAS;AACvB,WAAO,EAAE,SAAS,MAAM,SAAS,gDAAgD;AAAA,EACnF,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAO,EAAE,SAAS,OAAO,SAAS,6BAA6B,OAAO,GAAG;AAAA,EAC3E;AACF;AAKO,SAAS,qBAA8B;AAC5C,MAAI;AACF,aAAS,qBAAqB,EAAE,OAAO,UAAU,SAAS,IAAK,CAAC;AAChE,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACrHA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAOC,SAAQ;AAMR,SAAS,wBAAgC;AAC9C,SAAOC,MAAK,KAAKC,IAAG,QAAQ,GAAG,WAAW,YAAY,SAAS;AACjE;AAKO,SAAS,wBAAgC;AAC9C,SAAOD,MAAK,KAAK,sBAAsB,GAAG,cAAc;AAC1D;AAKO,SAAS,sBAA+B;AAC7C,MAAI;AACF,WAAOE,IAAG,WAAWF,MAAK,KAAKC,IAAG,QAAQ,GAAG,WAAW,UAAU,CAAC;AAAA,EACrE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAWO,SAAS,yBAAyB,QAAwB;AAC/D,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,kBAKS,KAAK,UAAU,MAAM,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4JxC;AAMO,SAAS,kBAAyD;AACvE,MAAI;AACF,UAAM,UAAUD,MAAK,KAAKC,IAAG,QAAQ,GAAG,QAAQ;AAChD,IAAAC,IAAG,UAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAEzC,UAAM,SAASF,MAAK,KAAK,SAAS,WAAW;AAC7C,UAAM,aAAa,sBAAsB;AACzC,IAAAE,IAAG,UAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AAE5C,UAAM,aAAa,sBAAsB;AACzC,UAAM,UAAU,yBAAyB,MAAM;AAC/C,IAAAA,IAAG,cAAc,YAAY,SAAS,OAAO;AAE7C,WAAO,EAAE,SAAS,MAAM,SAAS,iCAAiC,UAAU,GAAG;AAAA,EACjF,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAO,EAAE,SAAS,OAAO,SAAS,mCAAmC,OAAO,GAAG;AAAA,EACjF;AACF;AAKO,SAAS,oBAA2D;AACzE,MAAI;AACF,UAAM,aAAa,sBAAsB;AACzC,QAAIA,IAAG,WAAW,UAAU,GAAG;AAC7B,MAAAA,IAAG,WAAW,UAAU;AACxB,aAAO,EAAE,SAAS,MAAM,SAAS,0CAA0C;AAAA,IAC7E;AACA,WAAO,EAAE,SAAS,MAAM,SAAS,mDAAmD;AAAA,EACtF,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAO,EAAE,SAAS,OAAO,SAAS,qCAAqC,OAAO,GAAG;AAAA,EACnF;AACF;;;AChPA,OAAOC,WAAU;AAEV,IAAM,kBAAN,MAAsB;AAAA,EACnB;AAAA,EAER,YAAY,IAAiB;AAC3B,SAAK,KAAK;AAAA,EACZ;AAAA,EAEQ,eAAe,KAAqB;AAC1C,WAAOA,MAAK,SAAS,GAAG;AAAA,EAC1B;AAAA,EAEQ,QAAgB;AACtB,UAAM,IAAI,oBAAI,KAAK;AACnB,UAAM,MAAM,CAAC,MAAc,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG;AACpD,WAAO,GAAG,EAAE,YAAY,CAAC,IAAI,IAAI,EAAE,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,QAAQ,CAAC,CAAC;AAAA,EACxE;AAAA,EAEQ,MAAc;AACpB,UAAM,IAAI,oBAAI,KAAK;AACnB,UAAM,MAAM,CAAC,MAAc,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG;AACpD,UAAM,KAAK,OAAO,EAAE,gBAAgB,CAAC,EAAE,SAAS,GAAG,GAAG;AACtD,WAAO,GAAG,EAAE,YAAY,CAAC,IAAI,IAAI,EAAE,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,QAAQ,CAAC,CAAC,IAAI,IAAI,EAAE,SAAS,CAAC,CAAC,IAAI,IAAI,EAAE,WAAW,CAAC,CAAC,IAAI,IAAI,EAAE,WAAW,CAAC,CAAC,IAAI,EAAE;AAAA,EACjJ;AAAA,EAEA,mBAAmB,WAAmB,KAAa,QAAgB,OAAsB;AACvF,UAAM,UAAU,KAAK,eAAe,GAAG;AACvC,UAAM,YAAY,KAAK,IAAI;AAE3B,SAAK,GAAG,cAAc;AAAA,MACpB,IAAI;AAAA,MACJ;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,IACF,CAAC;AAED,SAAK,GAAG,YAAY;AAAA,MAClB,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,WAAW;AAAA,MACX,YAAY,KAAK,UAAU,EAAE,OAAO,CAAC;AAAA,MACrC,aAAa;AAAA,MACb,WAAW;AAAA,MACX,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,SAAK,GAAG,uBAAuB,KAAK,MAAM,GAAG,EAAE,UAAU,EAAE,CAAC;AAAA,EAC9D;AAAA,EAEA,aAAa,WAAmB,SAAuB;AACrD,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,YAAY,QAAQ,MAAM,KAAK,EAAE,OAAO,OAAK,EAAE,SAAS,CAAC,EAAE;AACjE,UAAM,YAAY,QAAQ;AAE1B,SAAK,GAAG,aAAa;AAAA,MACnB,YAAY;AAAA,MACZ;AAAA,MACA,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ;AAAA,IACF,CAAC;AAED,SAAK,GAAG,YAAY;AAAA,MAClB,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,WAAW;AAAA,MACX,SAAS;AAAA,MACT,KAAK;AAAA,MACL,SAAS;AAAA,MACT;AAAA,IACF,CAAC;AAED,SAAK,GAAG,yBAAyB,WAAW,EAAE,SAAS,EAAE,CAAC;AAC1D,SAAK,GAAG,uBAAuB,KAAK,MAAM,GAAG,EAAE,SAAS,EAAE,CAAC;AAAA,EAC7D;AAAA,EAEA,cACE,WACA,UACA,UACA,WACA,YACA,UACA,KACM;AACN,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,UAAU,KAAK,eAAe,GAAG;AACvC,UAAM,UAAU,aAAa,IAAI,IAAI;AAErC,SAAK,GAAG,YAAY;AAAA,MAClB,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,WAAW;AAAA,MACX,YAAY,KAAK,UAAU,SAAS;AAAA,MACpC,aAAa,KAAK,UAAU,UAAU;AAAA,MACtC,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,SAAK,GAAG,yBAAyB,WAAW;AAAA,MAC1C,OAAO;AAAA,MACP,QAAQ,YAAY,IAAI,IAAI;AAAA,IAC9B,CAAC;AAED,SAAK,GAAG,uBAAuB,KAAK,MAAM,GAAG;AAAA,MAC3C,YAAY;AAAA,MACZ,QAAQ,YAAY,IAAI,IAAI;AAAA,IAC9B,CAAC;AAAA,EACH;AAAA,EAEA,iBAAiB,WAAmB,YAAoB,QAAkC;AACxF,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,UAAU,KAAK,GAAG,WAAW,SAAS;AAE5C,QAAI;AACJ,QAAI,SAAS;AACX,YAAM,YAAY,IAAI,KAAK,QAAQ,UAAU,EAAE,QAAQ;AACvD,YAAM,UAAU,IAAI,KAAK,SAAS,EAAE,QAAQ;AAC5C,wBAAkB,KAAK,OAAO,UAAU,aAAa,GAAI;AAAA,IAC3D;AAEA,SAAK,GAAG,cAAc,WAAW;AAAA,MAC/B,UAAU;AAAA,MACV,aAAa;AAAA,MACb,kBAAkB;AAAA,IACpB,CAAC;AAED,QAAI,QAAQ;AACV,WAAK,GAAG,oBAAoB,WAAW,MAAM;AAAA,IAC/C;AAEA,SAAK,GAAG,YAAY;AAAA,MAClB,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,WAAW;AAAA,MACX,YAAY,KAAK,UAAU,EAAE,aAAa,WAAW,CAAC;AAAA,MACtD,aAAa;AAAA,MACb,WAAW;AAAA,MACX,SAAS;AAAA,MACT,KAAK;AAAA,MACL,SAAS;AAAA,MACT;AAAA,IACF,CAAC;AAED,UAAM,kBAA0C,CAAC;AACjD,QAAI,oBAAoB,QAAW;AACjC,sBAAgB,mBAAmB;AAAA,IACrC;AACA,QAAI,QAAQ;AACV,sBAAgB,eAAe,OAAO;AACtC,sBAAgB,gBAAgB,OAAO;AACvC,sBAAgB,8BAA8B,OAAO;AACrD,sBAAgB,0BAA0B,OAAO;AAAA,IACnD;AACA,QAAI,OAAO,KAAK,eAAe,EAAE,SAAS,GAAG;AAC3C,WAAK,GAAG,uBAAuB,KAAK,MAAM,GAAG,eAAe;AAAA,IAC9D;AAAA,EACF;AAAA,EAEA,mBAAmB,WAAmB,SAAiB,kBAAgC;AACrF,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,UAAU,qBAAqB,WAAW,qBAAqB;AAErE,SAAK,GAAG,YAAY;AAAA,MAClB,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,WAAW;AAAA,MACX,YAAY,KAAK,UAAU,EAAE,SAAS,mBAAmB,iBAAiB,CAAC;AAAA,MAC3E,aAAa;AAAA,MACb,WAAW;AAAA,MACX,SAAS;AAAA,MACT,KAAK;AAAA,MACL,SAAS;AAAA,MACT;AAAA,IACF,CAAC;AAED,QAAI,SAAS;AACX,WAAK,GAAG,yBAAyB,WAAW,EAAE,QAAQ,EAAE,CAAC;AACzD,WAAK,GAAG,uBAAuB,KAAK,MAAM,GAAG,EAAE,QAAQ,EAAE,CAAC;AAAA,IAC5D;AAAA,EACF;AAAA,EAEA,eAAe,WAAmB,UAAkB,SAAiB,WAA0B;AAC7F,UAAM,YAAY,KAAK,IAAI;AAE3B,SAAK,GAAG,YAAY;AAAA,MAClB,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,WAAW;AAAA,MACX,YAAY,KAAK,UAAU,EAAE,UAAU,SAAS,YAAY,aAAa,KAAK,CAAC;AAAA,MAC/E,aAAa;AAAA,MACb,WAAW;AAAA,MACX,SAAS;AAAA,MACT,KAAK;AAAA,MACL,SAAS;AAAA,MACT;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,iBAAiB,WAAmB,SAAuB;AACzD,UAAM,YAAY,KAAK,IAAI;AAE3B,SAAK,GAAG,YAAY;AAAA,MAClB,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,WAAW;AAAA,MACX,YAAY,KAAK,UAAU,EAAE,QAAQ,CAAC;AAAA,MACtC,aAAa;AAAA,MACb,WAAW;AAAA,MACX,SAAS;AAAA,MACT,KAAK;AAAA,MACL,SAAS;AAAA,MACT;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACnOA,OAAOC,WAAU;AACjB,OAAOC,SAAQ;AACf,OAAOC,SAAQ;;;ACFf,OAAOC,SAAQ;AACf,OAAO,cAAc;AAYrB,eAAsB,kBAAkB,gBAAoD;AAC1F,MAAI;AACF,QAAI,CAACA,IAAG,WAAW,cAAc,EAAG,QAAO;AAE3C,UAAM,SAASA,IAAG,iBAAiB,gBAAgB,EAAE,UAAU,QAAQ,CAAC;AACxE,UAAM,KAAK,SAAS,gBAAgB,EAAE,OAAO,QAAQ,WAAW,SAAS,CAAC;AAG1E,UAAM,eAAe,oBAAI,IAKtB;AAEH,qBAAiB,QAAQ,IAAI;AAC3B,UAAI,CAAC,KAAK,KAAK,EAAG;AAClB,UAAI;AACF,cAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,cAAM,QAAQ,MAAM,SAAS,MAAM,UAAU,SAAS,MAAM,SAAS;AACrE,YAAI,SAAS,OAAO,UAAU,YAAY,kBAAkB,OAAO;AAEjE,gBAAM,QAAQ,MAAM,SAAS,MAAM,MAAM,MAAM,SAAS,aAAa,IAAI;AAEzE,uBAAa,IAAI,OAAO;AAAA,YACtB,cAAc,MAAM,gBAAgB;AAAA,YACpC,eAAe,MAAM,iBAAiB;AAAA,YACtC,6BAA6B,MAAM,+BAA+B;AAAA,YAClE,yBAAyB,MAAM,2BAA2B;AAAA,UAC5D,CAAC;AAAA,QACH;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,QAAI,aAAa,SAAS,EAAG,QAAO;AAEpC,QAAI,cAAc;AAClB,QAAI,eAAe;AACnB,QAAI,gBAAgB;AACpB,QAAI,YAAY;AAChB,eAAW,KAAK,aAAa,OAAO,GAAG;AACrC,qBAAe,EAAE;AACjB,sBAAgB,EAAE;AAClB,uBAAiB,EAAE;AACnB,mBAAa,EAAE;AAAA,IACjB;AAEA,WAAO;AAAA,MACL,cAAc;AAAA,MACd,eAAe;AAAA,MACf,6BAA6B;AAAA,MAC7B,yBAAyB;AAAA,IAC3B;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACtDO,SAAS,qBACd,aACA,KACwB;AACxB,UAAQ,aAAa;AAAA,IACnB,KAAK;AACH,aAAO,EAAE,UAAU,gBAAgB,SAAS,IAAI;AAAA,IAElD,KAAK;AACH,aAAO;AAAA,QACL,UAAU;AAAA,QACV,SAAS,EAAE,GAAG,KAAK,kBAAkB,MAAM;AAAA,MAC7C;AAAA,IAEF,KAAK;AACH,aAAO,EAAE,UAAU,oBAAoB,SAAS,IAAI;AAAA,IAEtD,KAAK;AACH,aAAO,EAAE,UAAU,cAAc,SAAS,IAAI;AAAA,IAEhD,KAAK;AACH,aAAO,EAAE,UAAU,eAAe,SAAS,IAAI;AAAA,IAEjD,KAAK,cAAc;AACjB,YAAM,gBACJ,IAAI,cACH;AAEH,YAAM,kBACJ,OAAO,eAAe,oBAAoB,WACtC,cAAc,kBACd;AAEN,aAAO;AAAA,QACL,UAAU;AAAA,QACV,SAAS;AAAA,QACT,GAAI,oBAAoB,SAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,IAAI,CAAC;AAAA,MAC5E;AAAA,IACF;AAAA,IAEA,KAAK;AACH,aAAO,EAAE,UAAU,cAAc,SAAS,IAAI;AAAA,IAEhD,KAAK;AACH,aAAO,EAAE,UAAU,gBAAgB,SAAS,IAAI;AAAA,IAElD;AACE,aAAO;AAAA,EACX;AACF;;;AC5CO,SAAS,cAAc,UAA2C;AACvE,MAAI,CAAC,YAAY,OAAO,aAAa,SAAU,QAAO,CAAC;AACvD,MAAI;AACF,WAAO,KAAK,MAAM,QAAQ;AAAA,EAC5B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AASA,SAAS,kBAA0B;AACjC,QAAM,QAAO,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AACjD,QAAM,OAAO,QAAQ,QAAQ,QAAQ;AACrC,SAAO,WAAW,IAAI,IAAI,IAAI;AAChC;AAMA,SAAS,UAAU,QAAyB;AAC1C,MAAI,WAAW,SAAU,QAAO;AAChC,SAAO;AACT;AAMA,SAAS,cAAc,YAA0D;AAC/E,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,aAAa,WAAW;AAC9B,SAAO,eAAe,aAAa,eAAe;AACpD;AAMO,SAAS,sBACd,cACA,KACwB;AACxB,QAAM,YAAY,gBAAgB;AAElC,UAAQ,cAAc;AAAA,IACpB,KAAK,gBAAgB;AACnB,aAAO;AAAA,QACL,UAAU;AAAA,QACV,SAAS;AAAA,UACP,YAAY;AAAA,UACZ,QAAQ,UAAU,IAAI,MAAM;AAAA,UAC5B,GAAI,IAAI,UAAU,SAAY,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;AAAA,QACxD;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK,cAAc;AACjB,aAAO;AAAA,QACL,UAAU;AAAA,QACV,SAAS;AAAA,UACP,YAAY;AAAA,UACZ,GAAG;AAAA,UACH,kBAAkB;AAAA,QACpB;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK,uBAAuB;AAC1B,aAAO;AAAA,QACL,UAAU;AAAA,QACV,SAAS;AAAA,UACP,YAAY;AAAA,UACZ,QAAQ,IAAI;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK,cAAc;AACjB,aAAO;AAAA,QACL,UAAU;AAAA,QACV,SAAS;AAAA,UACP,YAAY;AAAA,UACZ,WAAW,IAAI;AAAA,UACf,YAAY,cAAc,IAAI,QAAkB;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK,eAAe;AAClB,YAAM,aAAc,IAAI,cAA0C,CAAC;AACnE,YAAM,SAAS;AAAA,QACb,IAAI;AAAA,MACN;AAEA,aAAO;AAAA,QACL,UAAU,SAAS,uBAAuB;AAAA,QAC1C,SAAS;AAAA,UACP,YAAY;AAAA,UACZ,WAAW,IAAI;AAAA,UACf,YAAY,cAAc,IAAI,QAAkB;AAAA,UAChD,eAAe;AAAA,UACf,WAAW,SAAS,IAAI;AAAA,QAC1B;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK,iBAAiB;AACpB,YAAM,QAAS,IAAI,SAAqC,CAAC;AACzD,aAAO;AAAA,QACL,UAAU;AAAA,QACV,SAAS;AAAA,UACP,YAAY;AAAA,UACZ,WAAW;AAAA,UACX,YAAY,CAAC;AAAA,UACb,eAAe;AAAA,YACb,eAAgB,MAAM,WAAsB;AAAA,YAC5C,YAAa,MAAM,QAAmB;AAAA,UACxC;AAAA,UACA,WAAW;AAAA,QACb;AAAA,MACF;AAAA,IACF;AAAA,IAEA;AACE,aAAO;AAAA,EACX;AACF;;;AH5IO,SAAS,cAAyB;AACvC,MAAI,QAAQ,IAAI,qBAAqB,QAAQ,IAAI,sBAAsB,QAAQ,IAAI,WAAY,QAAO;AACtG,MAAI,QAAQ,IAAI,mBAAoB,QAAO;AAC3C,MAAI,QAAQ,IAAI,SAAU,QAAO;AACjC,SAAO;AACT;AAEO,SAAS,eAAe,OAA+C;AAC5E,MAAI;AACF,QAAI,CAAC,MAAO,QAAO;AACnB,WAAO,KAAK,MAAM,KAAK;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,aAAqB;AACnC,SAAOC,MAAK,KAAKC,IAAG,QAAQ,GAAG,QAAQ;AACzC;AAEO,SAAS,YAAoB;AAClC,SAAOD,MAAK,KAAKC,IAAG,QAAQ,GAAG,UAAU,WAAW;AACtD;AAEA,eAAsB,YAA6B;AACjD,MAAI,QAAQ,IAAI,mBAAmB;AACjC,WAAO,QAAQ,IAAI;AAAA,EACrB;AAEA,SAAO,IAAI,QAAgB,CAAC,YAAY;AACtC,QAAI,OAAO;AACX,YAAQ,MAAM,YAAY,OAAO;AACjC,YAAQ,MAAM,GAAG,QAAQ,CAAC,UAAkB;AAC1C,cAAQ;AAAA,IACV,CAAC;AACD,YAAQ,MAAM,GAAG,OAAO,MAAM;AAC5B,cAAQ,IAAI;AAAA,IACd,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,gBAAgB,UAAiC;AACrE,QAAM,MAAM,MAAM,UAAU;AAC5B,QAAM,QAAQ,eAAe,GAAG;AAChC,MAAI,CAAC,MAAO;AAEZ,QAAM,UAAU,WAAW;AAC3B,EAAAC,IAAG,UAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAEzC,QAAM,SAAS,UAAU;AACzB,QAAM,KAAK,IAAI,YAAY,MAAM;AACjC,QAAM,SAAS,IAAI,gBAAgB,EAAE;AAErC,MAAI;AACF,UAAM,QAAQ,YAAY;AAG1B,QAAI,oBAAoB;AACxB,QAAI,UAAmC;AAEvC,QAAI,UAAU,cAAc;AAC1B,YAAM,aAAa,qBAAqB,UAAU,KAAK;AACvD,UAAI,CAAC,WAAY;AAGjB,UAAI,WAAW,aAAa,cAAc;AACxC,YAAI,WAAW,WAAW;AACxB,gBAAMC,aAAa,MAAM,cAAyB;AAClD,gBAAM,UAAU,iBAAiBA,UAAS;AAC1C,gBAAM,WAAW,GAAG,YAAY,OAAO;AACvC,gBAAM,OAAO,WAAW,SAAS,UAAU,EAAE,IAAI;AACjD,aAAG,YAAY,SAAS,OAAO,OAAO,WAAW,UAAU,eAAe,CAAC;AAAA,QAC7E;AACA;AAAA,MACF;AAEA,0BAAoB,WAAW;AAC/B,gBAAU,WAAW;AAAA,IACvB,WAAW,UAAU,eAAe;AAClC,YAAM,aAAa,sBAAsB,UAAU,KAAK;AACxD,UAAI,CAAC,WAAY;AAEjB,0BAAoB,WAAW;AAC/B,gBAAU,WAAW;AAAA,IACvB;AAEA,UAAM,YAAa,QAAQ,cAAyB;AACpD,UAAM,MAAO,QAAQ,OAAkB;AAEvC,YAAQ,mBAAmB;AAAA,MACzB,KAAK,gBAAgB;AACnB,cAAM,SAAU,QAAQ,UAAqB;AAC7C,eAAO,mBAAmB,WAAW,KAAK,QAAQ,KAAK;AACvD;AAAA,MACF;AAAA,MAEA,KAAK,oBAAoB;AACvB,cAAM,SAAU,QAAQ,UAAqB;AAC7C,eAAO,aAAa,WAAW,MAAM;AACrC;AAAA,MACF;AAAA,MAEA,KAAK,cAAc;AACjB,cAAM,WAAY,QAAQ,aAAwB;AAClD,cAAM,YAAa,QAAQ,cAA0C,CAAC;AACtE,eAAO,cAAc,WAAW,cAAc,UAAU,WAAW,CAAC,GAAG,GAAG,GAAG;AAC7E;AAAA,MACF;AAAA,MAEA,KAAK,eAAe;AAClB,cAAM,WAAY,QAAQ,aAAwB;AAClD,cAAM,YAAa,QAAQ,cAA0C,CAAC;AACtE,cAAM,eAAgB,QAAQ,iBAA6C,CAAC;AAC5E,cAAM,WAAY,QAAQ,aAAwB;AAClD,eAAO,cAAc,WAAW,eAAe,UAAU,WAAW,cAAc,UAAU,GAAG;AAC/F;AAAA,MACF;AAAA,MAEA,KAAK,sBAAsB;AACzB,cAAM,WAAY,QAAQ,aAAwB;AAClD,cAAM,YAAa,QAAQ,cAA0C,CAAC;AACtE,cAAM,eAAgB,QAAQ,iBAA6C,CAAC;AAC5E,eAAO,cAAc,WAAW,sBAAsB,UAAU,WAAW,cAAc,GAAG,GAAG;AAC/F;AAAA,MACF;AAAA,MAEA,KAAK,QAAQ;AACX,YAAI,SAA4B;AAEhC,YAAI,UAAU,cAAc;AAE1B,gBAAM,UAAU,iBAAiB,SAAS;AAC1C,gBAAM,SAAS,GAAG,YAAY,OAAO;AACrC,cAAI,QAAQ;AACV,kBAAM,cAAc,SAAS,QAAQ,EAAE;AAEvC,kBAAM,cAAc,KAAK,MAAM,cAAc,GAAG;AAChD,kBAAM,eAAe,cAAc;AACnC,qBAAS;AAAA,cACP,cAAc;AAAA,cACd,eAAe;AAAA,cACf,6BAA6B;AAAA,cAC7B,yBAAyB;AAAA,YAC3B;AAAA,UACF;AAAA,QACF,WAAW,UAAU,eAAe;AAElC,mBAAS;AAAA,QACX,OAAO;AAEL,gBAAM,UAAW,QAAQ,mBAA8B;AACvD,gBAAM,iBAAiB,WAAW,QAAQ,SAAS,QAAQ,IAAIH,MAAK,QAAQ,OAAO,IAAI;AACvF,mBAAS,iBAAiB,MAAM,kBAAkB,cAAc,IAAI;AAAA,QACtE;AAEA,eAAO,iBAAiB,WAAW,WAAW,MAAM;AACpD;AAAA,MACF;AAAA,MAEA,KAAK,gBAAgB;AACnB,cAAM,UAAW,QAAQ,WAAsB;AAC/C,cAAM,mBAAoB,QAAQ,qBAAgC;AAClE,eAAO,mBAAmB,WAAW,SAAS,gBAAgB;AAC9D;AAAA,MACF;AAAA,MAEA,KAAK,iBAAiB;AACpB,cAAM,UAAW,QAAQ,YAAuB;AAChD,cAAM,YAAa,QAAQ,cAAyB;AACpD,eAAO,eAAe,WAAW,iBAAiB,SAAS,SAAS;AACpE;AAAA,MACF;AAAA,MAEA,KAAK,gBAAgB;AACnB,cAAM,UAAW,QAAQ,YAAuB;AAChD,eAAO,eAAe,WAAW,gBAAgB,OAAO;AACxD;AAAA,MACF;AAAA,MAEA,KAAK,cAAc;AACjB,cAAM,UAAW,QAAQ,WAAsB;AAC/C,eAAO,iBAAiB,WAAW,OAAO;AAC1C;AAAA,MACF;AAAA,MAEA,KAAK,qBAAqB;AACxB,cAAM,WAAY,QAAQ,aAAwB;AAClD,cAAM,YAAa,QAAQ,cAA0C,CAAC;AACtE,eAAO,cAAc,WAAW,qBAAqB,UAAU,WAAW,CAAC,GAAG,GAAG,GAAG;AACpF;AAAA,MACF;AAAA,MAEA,KAAK,SAAS;AAEZ;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAE;AACA,OAAG,MAAM;AAAA,EACX;AACF;;;AI9MA,SAAS,aAAa,IAAU,oBAAI,KAAK,GAAW;AAClD,QAAM,MAAM,CAAC,MAAc,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG;AACpD,SAAO,GAAG,EAAE,YAAY,CAAC,IAAI,IAAI,EAAE,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,QAAQ,CAAC,CAAC;AACxE;AAEA,SAAS,qBAAqB,WAAsC;AAClE,MAAI,OAAO;AACX,aAAW,KAAK,WAAW;AACzB,WAAS,OAAO,KAAM,EAAE,WAAW,CAAC,IAAK;AAAA,EAC3C;AACA,SAAO,KAAK,IAAI,IAAI;AACpB,QAAM,OAAO,CAAC,GAAG,iBAAiB;AAClC,QAAM,WAA8B,CAAC;AACrC,WAAS,IAAI,GAAG,IAAI,KAAK,KAAK,SAAS,GAAG,KAAK;AAC7C,UAAM,MAAM,OAAO,KAAK;AACxB,aAAS,KAAK,KAAK,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC;AACpC,WAAO,KAAK,IAAM,OAAO,MAAO,KAAM,CAAC;AAAA,EACzC;AACA,SAAO;AACT;AAEO,IAAM,cAAN,MAAkB;AAAA,EACf;AAAA,EAER,YAAY,IAAiB;AAC3B,SAAK,KAAK;AAAA,EACZ;AAAA,EAEQ,YAAwB,QAAgB,QAAsB;AACpE,UAAM,MAAM,KAAK,GAAG,QAAQ,GAAG,EAAE,IAAI,GAAG,MAAM;AAC9C,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO,OAAO,OAAO,GAAG,EAAE,CAAC,KAAM;AAAA,EACnC;AAAA;AAAA,EAGQ,WAAW,OAAgB,OAAuD;AACxF,QAAI,CAAC,MAAO,QAAO,EAAE,QAAQ,IAAI,QAAQ,CAAC,EAAE;AAC5C,UAAM,MAAM,QAAQ,GAAG,KAAK,WAAW;AACvC,WAAO,EAAE,QAAQ,QAAQ,GAAG,QAAQ,QAAQ,CAAC,KAAK,EAAE;AAAA,EACtD;AAAA;AAAA,EAGQ,mBAAmB,OAAuD;AAChF,QAAI,CAAC,MAAO,QAAO,EAAE,QAAQ,IAAI,QAAQ,CAAC,EAAE;AAC5C,WAAO,EAAE,QAAQ,gEAAgE,QAAQ,CAAC,KAAK,EAAE;AAAA,EACnG;AAAA,EAEA,iBAAiB,OAA+B;AAC9C,UAAM,KAAK,KAAK,WAAW,KAAK;AAChC,UAAM,KAAK,KAAK,mBAAmB,KAAK;AAExC,UAAM,gBAAgB,KAAK,YAAY,iDAAiD,GAAG,QAAQ,GAAG,GAAG,MAAM;AAC/G,UAAM,eAAe,KAAK,YAAY,gDAAgD,GAAG,QAAQ,GAAG,GAAG,MAAM;AAC7G,UAAM,kBAAkB,KAAK,YAAY,oEAAoE,GAAG,QAAQ,GAAG,GAAG,MAAM;AACpI,UAAM,iBAAiB,KAAK;AAAA,MAC1B,8FAA8F,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACjH;AACA,UAAM,uBAAuB,KAAK;AAAA,MAChC,2EAA2E,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IAC9F;AACA,UAAM,iBAAiB,KAAK;AAAA,MAC1B,4FAA4F,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IAC/G;AACA,UAAM,oBAAoB,KAAK;AAAA,MAC7B,sHAAsH,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACzI;AACA,UAAM,mBAAmB,KAAK;AAAA,MAC5B,qHAAqH,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACxI;AACA,UAAM,oBAAoB;AAC1B,UAAM,oBAAoB,KAAK;AAAA,MAC7B,qHAAqH,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACxI;AACA,UAAM,mBAAmB,KAAK;AAAA,MAC5B,0HAA0H,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IAC7I;AACA,UAAM,kBAAkB,KAAK;AAAA,MAC3B,yHAAyH,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IAC5I;AACA,UAAM,iBAAiB,KAAK;AAAA,MAC1B,uEAAuE,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IAC1F;AACA,UAAM,mBAAmB,KAAK;AAAA,MAC5B,oEAAoE,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACvF;AACA,UAAM,cAAc,KAAK;AAAA,MACvB,4NAAoO,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACvP;AACA,UAAM,kBAAkB,KAAK;AAAA,MAC3B,yGAAyG,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IAC5H;AACA,UAAM,mBAAmB,KAAK;AAAA,MAC5B,uEAAuE,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IAC1F;AACA,UAAM,oBAAoB,KAAK;AAAA,MAC7B,wEAAwE,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IAC3F;AACA,UAAM,2BAA2B,KAAK;AAAA,MACpC,sFAAsF,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACzG;AACA,UAAM,uBAAuB,KAAK;AAAA,MAChC,kFAAkF,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACrG;AACA,UAAM,cAAc,mBAAmB,oBAAoB,2BAA2B;AAEtF,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,iBAAiB,OAA+B;AAC9C,UAAM,KAAK,KAAK,mBAAmB,KAAK;AACxC,UAAM,OAAO,KAAK,GACf;AAAA,MACC,4GAA4G,GAAG,SAAS;AAAA,IAC1H,EACC,IAAI,GAAG,GAAG,MAAM;AAEnB,UAAM,YAA2B,CAAC;AAClC,eAAW,OAAO,MAAM;AACtB,gBAAU,IAAI,SAAS,IAAI,IAAI;AAAA,IACjC;AACA,WAAO;AAAA,EACT;AAAA,EAEA,aAAa,OAA2B;AACtC,UAAM,KAAK,KAAK,WAAW,KAAK;AAChC,UAAM,KAAK,KAAK,mBAAmB,KAAK;AAGxC,UAAM,YAAY,KAAK,GACpB,QAAQ,uGAAuG,EAC/G,IAAI;AAEP,QAAI,gBAAgB;AACpB,QAAI,gBAAgB;AAEpB,QAAI,UAAU,SAAS,GAAG;AAExB,UAAI,SAAS;AACb,eAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,cAAM,WAAW,oBAAI,KAAK,UAAU,IAAI,CAAC,EAAE,OAAO,YAAY;AAC9D,cAAM,WAAW,oBAAI,KAAK,UAAU,CAAC,EAAE,OAAO,YAAY;AAC1D,cAAM,YAAY,SAAS,QAAQ,IAAI,SAAS,QAAQ,MAAM,MAAO,KAAK,KAAK;AAC/E,YAAI,aAAa,GAAG;AAClB;AAAA,QACF,OAAO;AACL,0BAAgB,KAAK,IAAI,eAAe,MAAM;AAC9C,mBAAS;AAAA,QACX;AAAA,MACF;AACA,sBAAgB,KAAK,IAAI,eAAe,MAAM;AAG9C,YAAM,cAAc,IAAI,IAAI,UAAU,IAAI,OAAK,EAAE,IAAI,CAAC;AACtD,YAAM,WAAW,aAAa;AAG9B,UAAI,YAAY,oBAAI,KAAK;AACzB,sBAAgB;AAGhB,UAAI,YAAY,IAAI,QAAQ,GAAG;AAC7B,wBAAgB;AAChB,kBAAU,QAAQ,UAAU,QAAQ,IAAI,CAAC;AACzC,eAAO,YAAY,IAAI,aAAa,SAAS,CAAC,GAAG;AAC/C;AACA,oBAAU,QAAQ,UAAU,QAAQ,IAAI,CAAC;AAAA,QAC3C;AAAA,MACF,OAAO;AAEL,kBAAU,QAAQ,UAAU,QAAQ,IAAI,CAAC;AACzC,cAAM,eAAe,aAAa,SAAS;AAC3C,YAAI,YAAY,IAAI,YAAY,GAAG;AACjC,0BAAgB;AAChB,oBAAU,QAAQ,UAAU,QAAQ,IAAI,CAAC;AACzC,iBAAO,YAAY,IAAI,aAAa,SAAS,CAAC,GAAG;AAC/C;AACA,sBAAU,QAAQ,UAAU,QAAQ,IAAI,CAAC;AAAA,UAC3C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,UAAM,cAAc,KAAK,GACtB;AAAA,MACC,sGAAsG,GAAG,SAAS;AAAA,IACpH,EACC,IAAI,GAAG,GAAG,MAAM;AAEnB,UAAM,WAAW,aAAa,QAAQ;AACtC,UAAM,gBAAgB,aAAa,OAAO;AAG1C,UAAM,gBAAgB,KAAK;AAAA,MACzB,2FAA2F,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IAC9G;AAGA,UAAM,iBAAiB,KAAK;AAAA,MAC1B,uGAAuG,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IAC1H;AAIA,UAAM,kBAAkB,KAAK;AAAA,MAC3B,mGAAmG,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACtH;AAGA,UAAM,mBAAmB,KAAK,GAC3B;AAAA,MACC,uGAAuG,GAAG,SAAS;AAAA,IACrH,EACC,IAAI,GAAG,GAAG,MAAM;AAEnB,UAAM,gBAAgB,kBAAkB,OAAO;AAG/C,UAAM,iBAAiB,KAAK,GACzB;AAAA,MACC;AAAA,IACF,EACC,IAAI;AAEP,UAAM,cAAc,gBAAgB,QAAQ;AAC5C,UAAM,mBAAmB,gBAAgB,SAAS;AAElD,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,kBAAkB,OAAgC;AAChD,UAAM,KAAK,KAAK,WAAW,KAAK;AAEhC,UAAM,wBAAwB,KAAK;AAAA,MACjC,2EAA2E,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IAC9F;AACA,UAAM,qBAAqB,KAAK;AAAA,MAC9B,qEAAqE,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACxF;AACA,UAAM,uBAAuB,KAAK;AAAA,MAChC,uEAAuE,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IAC1F;AACA,UAAM,wBAAwB,KAAK;AAAA,MACjC,6HAA6H,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IAChJ;AACA,UAAM,qBAAqB,KAAK;AAAA,MAC9B,oGAAoG,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACvH;AACA,UAAM,uBAAuB,KAAK;AAAA,MAChC,uEAAuE,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IAC1F;AACA,UAAM,qBAAqB,KAAK;AAAA,MAC9B,qEAAqE,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACxF;AACA,UAAM,sBAAsB,KAAK;AAAA,MAC/B,mMAAmM,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACtN;AACA,UAAM,sBAAsB,KAAK;AAAA,MAC/B,mMAAmM,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACtN;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,oBAAoB,KAAK,MAAM,kBAAkB;AAAA,MACjD,sBAAsB,KAAK,MAAM,uBAAuB,GAAG,IAAI;AAAA,MAC/D,oBAAoB,KAAK,MAAM,qBAAqB,GAAG,IAAI;AAAA,MAC3D;AAAA,MACA,qBAAqB,KAAK,MAAM,mBAAmB;AAAA,IACrD;AAAA,EACF;AAAA,EAEA,gBAAgB,OAA8B;AAC5C,UAAM,KAAK,KAAK,WAAW,KAAK;AAEhC,UAAM,iBAAiB,KAAK;AAAA,MAC1B,gFAAgF,GAAG;AAAA,MAAQ,GAAG,GAAG;AAAA,IACnG;AAEA,UAAM,cAAc,KAAK,GACtB;AAAA,MACC,4EAA4E,GAAG,SAAS;AAAA,IAC1F,EACC,IAAI,GAAG,GAAG,MAAM;AAEnB,UAAM,qBAAqB,YAAY,SAAS,IAAI,YAAY,CAAC,EAAE,UAAU;AAC7E,UAAM,0BAA0B,YAAY,SAAS,IAAI,YAAY,CAAC,EAAE,MAAM;AAE9E,UAAM,mBAA2C,CAAC;AAClD,eAAW,OAAO,aAAa;AAC7B,uBAAiB,IAAI,OAAO,IAAI,IAAI;AAAA,IACtC;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,YAAY,OAA0B;AACpC,WAAO;AAAA,MACL,UAAU,KAAK,iBAAiB,KAAK;AAAA,MACrC,OAAO,KAAK,iBAAiB,KAAK;AAAA,MAClC,MAAM,KAAK,aAAa,KAAK;AAAA,MAC7B,UAAU,KAAK,kBAAkB,KAAK;AAAA,MACtC,UAAU,KAAK,gBAAgB,KAAK;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,oBAAwJ;AACtJ,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,UAAM,mBAA2C,CAAC;AAClD,UAAM,gBAAwC,CAAC;AAC/C,eAAW,OAAO,MAAM;AACtB,uBAAiB,IAAI,KAAK,IAAI,IAAI;AAClC,oBAAc,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,gBAAgB,OAAO,EAAE,IAAI;AAAA,IACzE;AAEA,WAAO;AAAA,MACL,eAAe,KAAK,SAAS,IAAI,KAAK,CAAC,EAAE,QAAQ;AAAA,MACjD;AAAA,MACA;AAAA,MACA,gBAAgB,KAAK;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,wBAA4C;AAC1C,UAAM,QAAQ,oBAAI,KAAK;AACvB,UAAM,YAAY,MAAM,OAAO;AAC/B,UAAM,eAAe,cAAc,IAAI,KAAK,IAAI;AAChD,UAAM,SAAS,IAAI,KAAK,KAAK;AAC7B,WAAO,QAAQ,OAAO,QAAQ,IAAI,YAAY;AAC9C,UAAM,SAAS,IAAI,KAAK,MAAM;AAC9B,WAAO,QAAQ,OAAO,QAAQ,IAAI,CAAC;AACnC,UAAM,aAAa,IAAI,KAAK,MAAM;AAClC,eAAW,QAAQ,WAAW,QAAQ,IAAI,CAAC;AAE3C,UAAM,YAAY,aAAa,MAAM;AACrC,UAAM,UAAU,aAAa,MAAM;AACnC,UAAM,gBAAgB,aAAa,UAAU;AAE7C,UAAM,aAAa,qBAAqB,SAAS;AAEjD,UAAM,aAAa,KAAK;AAAA,MACtB;AAAA,MACA;AAAA,MAAW;AAAA,IACb;AAEA,UAAM,aAAa,qBAAqB,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,UAAU,CAAC,CAAC,KAAK;AAEjF,UAAM,UAAU,WAAW,IAAI,OAAK;AAClC,YAAM,UAAU,KAAK,kBAAkB,EAAE,MAAM,WAAW,SAAS,aAAa;AAChF,aAAO;AAAA,QACL,IAAI,EAAE;AAAA,QACN,aAAa,EAAE;AAAA,QACf,UAAU,EAAE;AAAA,QACZ,WAAW,WAAW,EAAE;AAAA,QACxB,UAAU,KAAK,IAAI,GAAG,UAAU,KAAK,IAAI,GAAG,EAAE,SAAS,CAAC;AAAA,QACxD,WAAW,EAAE;AAAA,QACb;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IACd;AAAA,EACF;AAAA,EAEQ,kBAAkB,MAAc,WAAmB,SAAiB,eAA+B;AACzG,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,eAAO,KAAK,YAAY,2FAA2F,WAAW,OAAO;AAAA,MACvI,KAAK;AACH,eAAO,KAAK,YAAY,8FAA8F,WAAW,OAAO;AAAA,MAC1I,KAAK;AACH,eAAO,KAAK,YAAY,4FAA4F,WAAW,OAAO;AAAA,MACxI,KAAK;AACH,eAAO,KAAK,YAAY,4GAA4G,WAAW,OAAO;AAAA,MACxJ,KAAK,cAAc;AACjB,cAAM,OAAO,KAAK,YAAY,oGAAoG,WAAW,OAAO;AACpJ,eAAO,KAAK,MAAM,OAAO,OAAO,EAAE,IAAI;AAAA,MACxC;AAAA,MACA,KAAK;AACH,eAAO,KAAK,YAAY,gIAAgI,WAAW,aAAa;AAAA,MAClL,KAAK;AACH,eAAO,KAAK,YAAY,yJAAyJ,WAAW,aAAa;AAAA,MAC3M,KAAK;AACH,eAAO,KAAK,YAAY,0JAA0J,WAAW,aAAa;AAAA,MAC5M,KAAK;AACH,eAAO,KAAK,YAAY,yJAAyJ,WAAW,aAAa;AAAA,MAC3M,KAAK;AACH,eAAO,KAAK,YAAY,2IAA2I,WAAW,aAAa;AAAA,MAC7L,KAAK;AACH,eAAO,KAAK,YAAY,mKAAmK,WAAW,aAAa;AAAA,MACrN,KAAK;AACH,eAAO,KAAK,YAAY,qKAAqK,WAAW,aAAa;AAAA,MACvN,KAAK;AACH,eAAO,KAAK,YAAY,mMAAmM,WAAW,aAAa;AAAA,MACrP,KAAK;AACH,eAAO,KAAK,YAAY,kGAAkG,WAAW,aAAa;AAAA,MACpJ,KAAK;AACH,eAAO,KAAK,YAAY,+JAA+J,WAAW,aAAa;AAAA,MACjN,KAAK;AACH,eAAO,KAAK,YAAY,2KAA2K,WAAW,aAAa;AAAA,MAC7N,KAAK;AACH,eAAO,KAAK,YAAY,gKAAgK,WAAW,OAAO;AAAA,MAC5M,KAAK;AACH,eAAO,KAAK,YAAY,sHAAsH,WAAW,aAAa;AAAA,MACxK,KAAK;AACH,eAAO,KAAK,YAAY,sHAAsH,WAAW,aAAa;AAAA,MACxK,KAAK;AACH,eAAO,KAAK,YAAY,kIAAkI,WAAW,aAAa;AAAA,MACpL,KAAK;AACH,eAAO,KAAK,YAAY,8JAA8J,WAAW,aAAa;AAAA,MAChN,KAAK;AACH,eAAO,KAAK,YAAY,sQAAsQ,WAAW,aAAa;AAAA,MACxT,KAAK;AACH,eAAO,KAAK,YAAY,0NAA0N,WAAW,aAAa;AAAA,MAC5Q;AACE,eAAO;AAAA,IACX;AAAA,EACF;AACF;;;AC7PO,IAAM,sBAAiD;AAAA,EAC5D,eAAe;AAAA,EACf,cAAc;AAAA,EACd,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,WAAW;AACb;AAoDO,IAAM,aAAwC;AAAA,EACnD,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;;;ACtRO,IAAM,oBAAN,MAAwB;AAAA,EACrB;AAAA,EACA;AAAA,EAER,YAAY,IAAiB,OAAoB;AAC/C,SAAK,KAAK;AACV,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,cAAc,OAA+B;AAC3C,UAAM,WAAW,KAAK,MAAM,YAAY,KAAK;AAC7C,UAAM,OAAO,KAAK,aAAa,QAAQ;AAEvC,WAAO,kBAAkB,IAAI,WAAS;AACpC,YAAM,QAAQ,KAAK,MAAM,IAAI,KAAK;AAElC,UAAI,OAAkB;AACtB,UAAI,MAAM,cAAc;AAEtB,eAAO,SAAS,MAAM,MAAM,CAAC,IAAI,IAAI;AAAA,MACvC,WAAW,MAAM,QAAQ;AAEvB,eAAO,SAAS,MAAM,MAAM,CAAC,IAAI,IAAI;AAAA,MACvC,OAAO;AAEL,iBAAS,IAAI,GAAG,IAAI,MAAM,MAAM,QAAQ,KAAK;AAC3C,cAAI,SAAS,MAAM,MAAM,CAAC,GAAG;AAC3B,mBAAQ,IAAI;AAAA,UACd,OAAO;AACL;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,UAAI,gBAAgB;AACpB,UAAI,WAAW;AACf,UAAI,QAAQ;AAEZ,UAAI,MAAM,cAAc;AACtB,wBAAgB,MAAM,MAAM,CAAC;AAC7B,mBAAW,SAAS,IAAI,IAAI,KAAK,IAAI,QAAQ,eAAe,IAAI;AAChE,gBAAQ,SAAS;AAAA,MACnB,WAAW,MAAM,QAAQ;AACvB,wBAAgB,MAAM,MAAM,CAAC;AAC7B,mBAAW,QAAQ,IAAI,IAAI;AAC3B,gBAAQ,QAAQ;AAAA,MAClB,WAAW,QAAQ,GAAG;AACpB,wBAAgB,MAAM,MAAM,CAAC;AAC7B,mBAAW;AACX,gBAAQ;AAAA,MACV,OAAO;AAEL,cAAM,UAAU;AAChB,wBAAgB,MAAM,MAAM,OAAO;AACnC,cAAM,gBAAgB,UAAU,IAAI,MAAM,MAAO,UAAU,CAAmB,IAAI;AAClF,cAAM,QAAQ,gBAAgB;AAC9B,mBAAW,QAAQ,IAAI,KAAK,KAAK,QAAQ,iBAAiB,OAAO,IAAI,IAAI;AAAA,MAC3E;AAGA,UAAI,OAAO,GAAG;AACZ,iBAAS,IAAI,GAAG,KAAK,MAAM,KAAK;AAC9B,eAAK,GAAG,aAAa,MAAM,IAAI,CAAC;AAAA,QAClC;AAAA,MACF;AAEA,aAAO;AAAA,QACL,IAAI,MAAM;AAAA,QACV,MAAM,MAAM;AAAA,QACZ,MAAM,MAAM;AAAA,QACZ,aAAa,MAAM;AAAA,QACnB,UAAU,MAAM;AAAA,QAChB,MAAM,MAAM;AAAA,QACZ,OAAO,MAAM;AAAA,QACb;AAAA,QACA,UAAU,WAAW,IAAI;AAAA,QACzB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,SAAS,MAAM;AAAA,QACf,QAAQ,MAAM,UAAU;AAAA,QACxB,UAAU,OAAO;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,OAA0B;AAClC,UAAM,WAAW,KAAK,MAAM,YAAY,KAAK;AAC7C,UAAM,SAAS,KAAK,cAAc,KAAK;AAGvC,QAAI,UAAU;AACd,eAAW,SAAS,SAAS,eAAe;AAC5C,eAAW,SAAS,SAAS,gBAAgB;AAC7C,eAAW,KAAK,MAAM,SAAS,SAAS,uBAAuB,IAAI,IAAI;AACvE,eAAW,SAAS,KAAK,gBAAgB;AAGzC,eAAW,SAAS,QAAQ;AAC1B,UAAI,MAAM,OAAO,GAAG;AAClB,mBAAW,QAAQ,MAAM,IAAI,KAAK;AAAA,MACpC;AAAA,IACF;AAGA,QAAI,aAAa;AACjB,aAAS,IAAI,KAAK,KAAK,GAAG,KAAK;AAC7B,UAAI,WAAW,UAAU,CAAC,GAAG;AAC3B,qBAAa;AACb;AAAA,MACF;AAAA,IACF;AAGA,QAAI;AACJ,QAAI;AAEJ,QAAI,cAAc,KAAK;AACrB,mBAAa,UAAU,GAAG;AAC1B,iBAAW;AAAA,IACb,OAAO;AACL,YAAM,WAAW,aAAa;AAC9B,mBAAa,UAAU,QAAQ;AAC/B,YAAM,mBAAmB,aAAa,IAAI,UAAU,UAAU,IAAI;AAClE,YAAM,QAAQ,aAAa;AAC3B,iBAAW,QAAQ,IAAI,KAAK,KAAK,UAAU,oBAAoB,OAAO,IAAI,IAAI;AAAA,IAChF;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,UAAU,gBAAgB,cAAc,CAAC;AAAA,MACzC;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,uBAAuB,OAAqC;AAC1D,UAAM,WAAW,KAAK,MAAM,YAAY,KAAK;AAC7C,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,KAAK,cAAc,KAAK;AAAA,MAChC,IAAI,KAAK,UAAU,KAAK;AAAA,IAC1B;AAAA,EACF;AAAA,EAEQ,aAAa,UAA4C;AAC/D,UAAM,OAA+B,CAAC;AAGtC,SAAK,eAAe,SAAS,SAAS;AACtC,SAAK,iBAAiB,SAAS,SAAS;AACxC,SAAK,gBAAgB,SAAS,SAAS;AACvC,SAAK,kBAAkB,SAAS,SAAS;AACzC,SAAK,oBAAoB,SAAS,SAAS;AAC3C,SAAK,iBAAiB,SAAS,SAAS;AACxC,SAAK,mBAAmB,SAAS,SAAS;AAC1C,SAAK,oBAAoB,SAAS,SAAS;AAC3C,SAAK,iBAAiB,SAAS,SAAS;AACxC,SAAK,cAAc,SAAS,SAAS;AACrC,SAAK,kBAAkB,SAAS,SAAS;AACzC,SAAK,kBAAkB,SAAS,SAAS;AACzC,SAAK,mBAAmB,SAAS,SAAS;AAC1C,SAAK,mBAAmB,SAAS,SAAS;AAG1C,SAAK,oBAAoB,KAAK,MAAM,SAAS,SAAS,uBAAuB,IAAI;AAGjF,SAAK,gBAAgB,SAAS,KAAK;AACnC,SAAK,gBAAgB,SAAS,KAAK;AACnC,SAAK,iBAAiB,SAAS,KAAK;AACpC,SAAK,kBAAkB,SAAS,KAAK;AAGrC,SAAK,gBAAgB,KAAK,mBAAmB;AAG7C,SAAK,0BAA0B,KAAK,6BAA6B;AACjE,SAAK,kBAAkB,KAAK,qBAAqB;AACjD,SAAK,eAAe,KAAK,kBAAkB;AAC3C,SAAK,kBAAkB,KAAK,qBAAqB;AACjD,SAAK,oBAAoB,KAAK,uBAAuB;AAGrD,SAAK,yBAAyB,KAAK,4BAA4B;AAG/D,SAAK,oBAAoB,KAAK,uBAAuB;AACrD,SAAK,kBAAkB,KAAK,qBAAqB;AACjD,SAAK,mBAAmB,KAAK,sBAAsB;AACnD,SAAK,mBAAmB,KAAK,sBAAsB;AACnD,SAAK,sBAAsB,KAAK,yBAAyB;AACzD,SAAK,qBAAqB,KAAK,wBAAwB;AAGvD,SAAK,eAAe,KAAK,kBAAkB;AAC3C,SAAK,WAAW,KAAK,cAAc;AACnC,SAAK,iBAAiB,SAAS,SAAS;AACxC,SAAK,kBAAkB,KAAK,qBAAqB;AAGjD,SAAK,sBAAsB,KAAK,yBAAyB;AAGzD,SAAK,0BAA0B,KAAK,6BAA6B;AACjE,SAAK,mBAAmB,KAAK,sBAAsB;AACnD,SAAK,gBAAgB,KAAK,mBAAmB;AAC7C,SAAK,sBAAsB,KAAK,yBAAyB;AACzD,SAAK,iBAAiB,KAAK,oBAAoB;AAC/C,SAAK,kBAAkB,KAAK,qBAAqB;AACjD,SAAK,kBAAkB,KAAK,qBAAqB;AACjD,SAAK,oBAAoB,KAAK,uBAAuB;AACrD,SAAK,mBAAmB,SAAS,SAAS,gBAAgB,IAAI,IAAI;AAClE,SAAK,gBAAgB;AAGrB,SAAK,UAAU;AACf,SAAK,mBAAmB;AACxB,SAAK,6BAA6B;AAKlC,SAAK,sBAAsB,KAAK,yBAAyB;AACzD,SAAK,iBAAiB,KAAK,oBAAoB;AAC/C,SAAK,iBAAiB,KAAK,oBAAoB;AAC/C,SAAK,gBAAgB,KAAK,mBAAmB;AAC7C,SAAK,sBAAsB,KAAK,yBAAyB;AACzD,SAAK,iBAAiB,KAAK,oBAAoB;AAK/C,SAAK,uBAAuB,KAAK,0BAA0B;AAC3D,SAAK,oBAAoB,KAAK,uBAAuB;AACrD,SAAK,sBAAsB,KAAK,yBAAyB;AAEzD,SAAK,qBAAqB,KAAK,wBAAwB;AACvD,SAAK,eAAe,KAAK,kBAAkB;AAK3C,SAAK,mBAAmB,KAAK,sBAAsB;AACnD,SAAK,sBAAsB,KAAK,yBAAyB;AACzD,SAAK,mBAAmB,KAAK,sBAAsB;AACnD,SAAK,sBAAsB,KAAK,yBAAyB;AACzD,SAAK,mBAAmB,KAAK,sBAAsB;AACnD,SAAK,sBAAsB,KAAK,yBAAyB;AAKzD,SAAK,kBAAkB,KAAK,qBAAqB;AACjD,SAAK,sBAAsB,KAAK,yBAAyB;AACzD,SAAK,gBAAgB,KAAK,mBAAmB;AAC7C,SAAK,iBAAiB,KAAK,oBAAoB;AAC/C,SAAK,sBAAsB,SAAS,SAAS;AAK7C,SAAK,mBAAmB,KAAK,sBAAsB;AAEnD,SAAK,2BAA2B,KAAK,8BAA8B;AACnE,SAAK,2BAA2B,KAAK,8BAA8B;AACnE,SAAK,sBAAsB,KAAK,yBAAyB;AAKzD,SAAK,qBAAqB,KAAK,wBAAwB;AACvD,SAAK,mBAAmB,KAAK,sBAAsB;AACnD,SAAK,mBAAmB,KAAK,sBAAsB;AACnD,SAAK,gBAAgB,KAAK,mBAAmB;AAC7C,SAAK,sBAAsB,SAAS,SAAS;AAK7C,SAAK,yBAAyB,KAAK,4BAA4B;AAC/D,SAAK,qBAAqB,KAAK,wBAAwB;AACvD,SAAK,sBAAsB,SAAS,SAAS;AAC7C,SAAK,wBAAwB,KAAK,2BAA2B;AAG7D,SAAK,qBAAqB,KAAK,YAAY,4CAA4C;AACvF,SAAK,iBAAiB,KAAK,YAAY,0DAA0D;AACjG,SAAK,kBAAkB,KAAK,YAAY,2DAA2D;AACnG,SAAK,mBAAmB,KAAK,YAAY,wDAAwD;AACjG,SAAK,kBAAkB,KAAK;AAAA,MAC1B;AAAA,IACF;AACA,SAAK,kBAAkB,KAAK;AAK5B,SAAK,cAAc,KAAK,iBAAiB;AACzC,SAAK,kBAAkB,KAAK,qBAAqB;AACjD,SAAK,sBAAsB,KAAK,yBAAyB;AACzD,SAAK,kBAAkB,KAAK,qBAAqB;AACjD,SAAK,4BAA4B,KAAK,+BAA+B;AAGrE,SAAK,wBAAwB,KAAK,2BAA2B;AAK7D,SAAK,oBAAoB,KAAK,uBAAuB;AACrD,SAAK,kBAAkB,KAAK,qBAAqB;AACjD,SAAK,kBAAkB,KAAK,qBAAqB;AACjD,SAAK,cAAe,SAAS,SAAS,gBAAgB,OAAO,SAAS,SAAS,kBAAkB,OAAQ,IAAI;AAC7G,SAAK,gBAAgB,KAAK,mBAAmB;AAC7C,SAAK,mBAAmB,KAAK,sBAAsB;AACnD,SAAK,uBAAuB,KAAK,0BAA0B;AAK3D,SAAK,cAAc,SAAS,SAAS;AACrC,SAAK,oBAAoB,SAAS,SAAS;AAC3C,SAAK,uBAAuB,SAAS,SAAS;AAC9C,SAAK,2BAA2B,SAAS,SAAS;AAClD,SAAK,mBAAmB,SAAS,SAAS;AAC1C,SAAK,sBAAsB,SAAS,SAAS;AAC7C,SAAK,sBAAsB,SAAS,SAAS;AAC7C,SAAK,qBAAqB,KAAK,wBAAwB;AACvD,SAAK,qBAAqB,KAAK,wBAAwB;AACvD,SAAK,qBAAqB,KAAK,wBAAwB;AAEvD,WAAO;AAAA,EACT;AAAA;AAAA,EAIQ,YAAY,QAAgB,QAA2B;AAC7D,UAAM,MAAM,KAAK,GAAG,QAAQ,GAAG,EAAE,IAAI,GAAG,MAAM;AAC9C,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO,OAAO,OAAO,GAAG,EAAE,CAAC,KAAK;AAAA,EAClC;AAAA,EAEQ,qBAA6B;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,yBAAiC;AACvC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,uBAA+B;AACrC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,uBAA+B;AACrC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,+BAAuC;AAC7C,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,uBAA+B;AACrC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,oBAA4B;AAClC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,yBAAiC;AACvC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,wBAAgC;AACtC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,0BAAkC;AACxC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,wBAAgC;AACtC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,2BAAmC;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,8BAAsC;AAC5C,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,UAAU;AACd,QAAI,UAAU;AACd,eAAW,OAAO,MAAM;AACtB,UAAI,IAAI,cAAc,eAAe;AACnC;AACA,kBAAU,KAAK,IAAI,SAAS,OAAO;AAAA,MACrC,OAAO;AACL,kBAAU;AAAA,MACZ;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,oBAA4B;AAClC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,gBAAwB;AAC9B,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,uBAA+B;AACrC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,UAAM,aAAa,oBAAI,IAAY;AACnC,eAAW,OAAO,MAAM;AACtB,UAAI,IAAI,IAAI;AACV,cAAM,QAAQ,IAAI,GAAG,MAAM,mBAAmB;AAC9C,YAAI,OAAO;AACT,qBAAW,IAAI,MAAM,CAAC,EAAE,YAAY,CAAC;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AACA,WAAO,WAAW;AAAA,EACpB;AAAA,EAEQ,2BAAmC;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIQ,+BAAuC;AAC7C,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,wBAAgC;AACtC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,KAAK,SAAS,EAAG,QAAO;AAC5B,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,OAAO,IAAI,KAAK,KAAK,IAAI,CAAC,EAAE,UAAU,EAAE,QAAQ;AACtD,YAAM,OAAO,IAAI,KAAK,KAAK,CAAC,EAAE,UAAU,EAAE,QAAQ;AAClD,YAAM,YAAY,OAAO,SAAS,MAAO,KAAK,KAAK;AACnD,UAAI,YAAY,EAAG,QAAO;AAAA,IAC5B;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,qBAA6B;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,IACF,IAAI,IAAI,IAAI;AAAA,EACd;AAAA,EAEQ,2BAAmC;AACzC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,eAAW,OAAO,MAAM;AACtB,YAAM,YAAY,IAAI,WAAW,MAAM,GAAG,EAAE;AAC5C,YAAM,UAAU,IAAI,SAAS,MAAM,GAAG,EAAE;AACxC,UAAI,cAAc,QAAS,QAAO;AAAA,IACpC;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,sBAA8B;AACpC,WAAO,KAAK;AAAA,MACV;AAAA,IACF,IAAI,IAAI,IAAI;AAAA,EACd;AAAA,EAEQ,uBAA+B;AACrC,UAAM,WAAW,KAAK;AAAA,MACpB;AAAA,IACF;AACA,WAAO,WAAW,IAAI,IAAI;AAAA,EAC5B;AAAA,EAEQ,uBAA+B;AACrC,WAAO,KAAK;AAAA,MACV;AAAA,IACF,IAAI,IAAI,IAAI;AAAA,EACd;AAAA,EAEQ,yBAAiC;AACvC,UAAM,gBAAgB,CAAC,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,UAAU;AAClF,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,eAAW,OAAO,MAAM;AACtB,UAAI,IAAI,OAAO,cAAc,OAAQ,QAAO;AAAA,IAC9C;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,2BAAmC;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,sBAA8B;AACpC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,sBAA8B;AAEpC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,qBAA6B;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,2BAAmC;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,sBAA8B;AAEpC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,4BAAoC;AAC1C,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,yBAAiC;AACvC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,2BAAmC;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,0BAAkC;AACxC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,oBAA4B;AAElC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,wBAAgC;AACtC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,2BAAmC;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,wBAAgC;AACtC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,2BAAmC;AAEzC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,wBAAgC;AAGtC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,UAAM,aAAa;AACnB,QAAI,QAAQ;AACZ,eAAW,OAAO,MAAM;AACtB,UAAI,WAAW,KAAK,IAAI,OAAO,GAAG;AAChC;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,2BAAmC;AAEzC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,QAAQ;AACZ,eAAW,OAAO,MAAM;AACtB,YAAM,YAAY,IAAI,QAAQ,MAAM,IAAI,EAAE;AAC1C,UAAI,aAAa,GAAI;AAAA,IACvB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,uBAA+B;AAErC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,QAAQ;AACZ,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,OAAO,KAAK,IAAI,CAAC;AACvB,YAAM,OAAO,KAAK,CAAC;AACnB,UACE,KAAK,cAAc,wBACnB,KAAK,cAAc,iBACnB,KAAK,cAAc,KAAK,aACxB,KAAK,cAAc,QACnB;AACA;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,2BAAmC;AAEzC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,QAAQ;AACZ,QAAI,aAAa;AACjB,QAAI,WAA0B;AAE9B,eAAW,OAAO,MAAM;AACtB,UAAI,IAAI,cAAc,sBAAsB;AAC1C,YAAI,IAAI,cAAc,UAAU;AAC9B;AAAA,QACF,OAAO;AACL,uBAAa;AACb,qBAAW,IAAI;AAAA,QACjB;AAAA,MACF,WAAW,IAAI,cAAc,eAAe;AAC1C,YAAI,cAAc,KAAK,IAAI,cAAc,UAAU;AACjD;AAAA,QACF;AACA,qBAAa;AACb,mBAAW;AAAA,MACb;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,qBAA6B;AAEnC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,QAAQ;AACZ,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,KAAK,CAAC,EAAE,eAAe,KAAK,IAAI,CAAC,EAAE,cAAc,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC,EAAE,MAAM,KAAK,CAAC,EAAE,IAAI;AAChG;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,sBAA8B;AACpC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,wBAAgC;AAEtC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,QAAQ;AACZ,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,KAAK,IAAI,CAAC,EAAE,cAAc,UAAU,KAAK,IAAI,CAAC,EAAE,cAAc,UAAU,KAAK,CAAC,EAAE,cAAc,QAAQ;AACxG;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,gCAAwC;AAC9C,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,gCAAwC;AAC9C,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,2BAAmC;AAEzC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,QAAQ;AACZ,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UACE,KAAK,CAAC,EAAE,cAAc,WACrB,KAAK,IAAI,CAAC,EAAE,cAAc,UAAU,KAAK,IAAI,CAAC,EAAE,cAAc,WAC/D,KAAK,CAAC,EAAE,eAAe,KAAK,IAAI,CAAC,EAAE,YACnC;AACA;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,0BAAkC;AACxC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,wBAAgC;AACtC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,wBAAgC;AAEtC,UAAM,cAAc,KAAK,GAAG;AAAA,MAC1B;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,QAAQ;AACZ,eAAW,MAAM,aAAa;AAC5B,YAAM,cAAc,KAAK,GAAG;AAAA,QAC1B;AAAA,MACF,EAAE,IAAI,GAAG,OAAO;AAEhB,UAAI,aAAa,MAAM;AACrB,cAAM,aAAa,KAAK,IAAI,IAAI,IAAI,KAAK,YAAY,IAAI,EAAE,QAAQ,MAAM,MAAO,KAAK,KAAK;AAC1F,YAAI,aAAa,EAAG;AAAA,MACtB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,qBAA6B;AAEnC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,QAAQ;AACZ,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,KAAK,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC,EAAE,SAAS;AAC3C,cAAM,OAAO,IAAI,KAAK,KAAK,IAAI,CAAC,EAAE,UAAU,EAAE,QAAQ;AACtD,cAAM,OAAO,IAAI,KAAK,KAAK,CAAC,EAAE,UAAU,EAAE,QAAQ;AAClD,cAAM,YAAY,OAAO,SAAS,MAAO,KAAK,KAAK;AACnD,YAAI,YAAY,GAAI;AAAA,MACtB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,8BAAsC;AAE5C,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,UAAU;AACd,QAAI,MAAM;AACV,eAAW,OAAO,MAAM;AACtB,UAAI,IAAI,cAAc,iBAAiB;AACrC;AACA,cAAM,KAAK,IAAI,KAAK,OAAO;AAAA,MAC7B,OAAO;AACL,kBAAU,KAAK,IAAI,GAAG,UAAU,CAAC;AAAA,MACnC;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,0BAAkC;AAExC,UAAM,SAAS,KAAK,GAAG;AAAA,MACrB;AAAA,IACF,EAAE,IAAI;AAEN,UAAM,QAAQ,KAAK,GAAG;AAAA,MACpB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,QAAQ;AACZ,eAAW,SAAS,QAAQ;AAC1B,UAAI,CAAC,MAAM,WAAY;AACvB,UAAI,UAAyB;AAC7B,UAAI;AACF,cAAM,SAAS,KAAK,MAAM,MAAM,UAAU;AAC1C,kBAAU,OAAO,YAAY;AAAA,MAC/B,QAAQ;AAAE;AAAA,MAAS;AACnB,UAAI,CAAC,QAAS;AAEd,iBAAW,QAAQ,OAAO;AACxB,YAAI,CAAC,KAAK,WAAY;AACtB,YAAI;AACF,gBAAM,SAAS,KAAK,MAAM,KAAK,UAAU;AACzC,cAAI,OAAO,aAAa,SAAS;AAC/B,kBAAM,YAAY,IAAI,KAAK,MAAM,SAAS,EAAE,QAAQ;AACpD,kBAAM,WAAW,IAAI,KAAK,KAAK,SAAS,EAAE,QAAQ;AAClD,gBAAK,WAAW,YAAa,IAAO;AACpC;AAAA,UACF;AAAA,QACF,QAAQ;AAAE;AAAA,QAAS;AAAA,MACrB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,6BAAqC;AAC3C,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,mBAA2B;AAEjC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,QAAQ;AACZ,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,KAAK,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC,EAAE,SAAS;AAC3C,cAAM,OAAO,IAAI,KAAK,KAAK,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ;AACrD,cAAM,OAAO,IAAI,KAAK,KAAK,CAAC,EAAE,SAAS,EAAE,QAAQ;AACjD,YAAK,OAAO,OAAQ,IAAQ;AAAA,MAC9B;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,uBAA+B;AAErC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,QAAQ;AACZ,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,KAAK,CAAC,EAAE,cAAc,UAAU,KAAK,IAAI,CAAC,EAAE,cAAc,WAAW,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC,EAAE,MAAM,KAAK,CAAC,EAAE,IAAI;AACpH;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,2BAAmC;AAEzC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,QAAQ;AACZ,UAAM,cAAc;AACpB,eAAW,OAAO,MAAM;AACtB,YAAM,UAAU,IAAI,QAAQ,MAAM,qBAAqB;AACvD,UAAI,WAAW,QAAQ,UAAU,EAAG;AAAA,IACtC;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,uBAA+B;AACrC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,iCAAyC;AAC/C,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,YAAY;AAChB,QAAI,UAAU;AACd,eAAW,OAAO,MAAM;AACtB,UAAI,IAAI,cAAc,qBAAqB;AACzC;AACA,oBAAY,KAAK,IAAI,WAAW,OAAO;AAAA,MACzC,OAAO;AACL,kBAAU;AAAA,MACZ;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,6BAAqC;AAE3C,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,QAAQ;AACZ,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,KAAK,IAAI,CAAC,EAAE,cAAc,wBAAwB,KAAK,CAAC,EAAE,cAAc,eAAe;AACzF;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,yBAAiC;AAIvC,UAAM,QAAQ,KAAK;AAAA,MACjB;AAAA,IACF;AACA,WAAO,QAAQ,IAAI,IAAI;AAAA,EACzB;AAAA,EAEQ,uBAA+B;AAIrC,UAAM,gBAAe,oBAAI,KAAK,sBAAsB,GAAE,QAAQ;AAC9D,UAAM,eAAe,WAAW,KAAK,KAAK,KAAK;AAC/C,UAAM,mBAAmB,SAAS,KAAK,KAAK,KAAK;AACjD,UAAM,WAAW,KAAK,KAAK,KAAK;AAEhC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF,EAAE,IAAI;AAEN,eAAW,OAAO,MAAM;AACtB,YAAM,cAAc,IAAI,KAAK,IAAI,UAAU,EAAE,QAAQ;AACrD,YAAM,sBAAsB,cAAc,eAAe,oBAAoB,eAAe,gBAAgB;AAE5G,UAAI,oBAAoB,YAAY,oBAAoB,eAAe,UAAU;AAC/E,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,uBAA+B;AAErC,UAAM,QAAQ,KAAK,GAAG;AAAA,MACpB;AAAA,IACF,EAAE,IAAI;AAEN,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,kBAAkB,MAAM,WAAW,MAAM,GAAG,EAAE;AACpD,UAAM,cAAc,MAAM,WAAW,MAAM,GAAG,CAAC;AAE/C,UAAM,qBAAqB,KAAK;AAAA,MAC9B;AAAA,MACA;AAAA,MAAiB;AAAA,IACnB;AACA,WAAO,qBAAqB,IAAI,IAAI;AAAA,EACtC;AAAA,EAEQ,qBAA6B;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,IACF,IAAI,IAAI,IAAI;AAAA,EACd;AAAA,EAEQ,wBAAgC;AAEtC,WAAO,KAAK;AAAA,MACV;AAAA,IACF,IAAI,IAAI,IAAI;AAAA,EACd;AAAA;AAAA,EAIQ,0BAAkC;AACxC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,0BAAkC;AACxC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,0BAAkC;AACxC,WAAO,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,4BAAoC;AAC1C,WAAO,KAAK;AAAA,MACV;AAAA,IACF,IAAI,IAAI,IAAI;AAAA,EACd;AACF;","names":["fs","path","os","MARKER","path","os","fs","path","os","fs","MARKER","fs","path","os","path","os","fs","fs","path","os","path","os","fs","path","path","os","fs","fs","path","os","fs","sessionId"]}