+
    6<jD
                     >   R t ^ RIt^ RIt^ RIHt RR.t]P                  P                  4       t]P                  ! R]RR7      t
R t]]
n        ]
P                  R 4       t]
P                  R	 4       t]R
8X  d%   ]
P#                  ]P$                  R,          4       R# R# )u  handler.py — single entry point for the merged Discord bot ("shallow merge").

ONE process, ONE bot, ONE token (the korean-bot token, env DISCORD_TOKEN). It loads independent
feature modules as discord.py extensions and owns the shared concerns: the bot object, login,
command-tree sync, and presence. Each feature is self-contained and only shares glicko2.py.

  Features (extensions):
    korean_bot.py  — Korean vocab quiz   (users vs words)   → korean.db
    timer_bot.py   — motivational timer   (users vs tasks)   → timer.db   (env TIMER_DB)

  Each feature exposes `async def setup(bot)` and registers its own slash commands on bot.tree.
  They share NO storage and NO rating tables — only the glicko2 engine. Adding a new feature =
  drop a new `feature.py` with a setup(), append it to EXTENSIONS, redeploy. Nothing else changes.

  Server layout (see SERVER_SETUP.md):
    /opt/korean-bot/handler.py        <- service entry (this file)
    /opt/korean-bot/korean_bot.py     <- quiz extension   (was the old standalone bot.py)
    /opt/korean-bot/timer_bot.py      <- timer extension
    /opt/korean-bot/glicko2.py        <- shared engine
    /opt/korean-bot/{korean.db,timer.db,*.json,.env,venv}
    systemd korean-bot.service ExecStart = venv/bin/python handler.py
    Rollback: point ExecStart back at the old bot.py (quiz-only) and restart.

  Env: DISCORD_TOKEN (required), plus feature envs (TIMER_DB, TIME_UNIT, …).
N)commands
korean_bot	timer_botz!kr )command_prefixintentshelp_commandc                     "   \          F/  p  \        P                  V 4      G R j  xL
  \        RV  24       K1  	  R #  L  \         d   p\        RT  RT: 24        R p?KZ  R p?ii ; i5i)Nzloaded extension: zFAILED to load extension z: )
EXTENSIONSbotload_extensionprint	Exception)extes     
handler.py_setup_hookr   $   sc     	<$$S)))&se,- ) 	<-cU"QE:;;	<s;   
A+A >A A+A  A(A#A+#A((A+c                    "   \         P                  P                  V R 7       \         P                  P                  V R 7      G Rj  xL
  \	        RV P
                   RV P                   R24       R#  L,5i)guildNzjoined guild z (z#) | guild commands synced instantly)r
   treecopy_global_tosyncr   idnamer   s   &r   on_guild_joinr   0   sW     HH%(
((--e-
$$$	M%((2ejj\1T
UV %s   AA5A3-A5c                  z  "   \         P                  P                  4       G R j  xL
  \         P                  \        P
                  ! RR7      R7      G R j  xL
  \        R \         P                  P                  4        4       4      p \        R\         P                   R\        V 4       RV  24       R #  L La5i)Nu   /quiz · /metar   )activityc              3   8   "   T F  qP                   x  K  	  R # 5i)Nr   ).0cs   & r   	<genexpr>on_ready.<locals>.<genexpr>;   s     :"9Q&&"9s   zlogged in as z | z commands synced: )r
   r   r   change_presencediscordGamesortedget_commandsr   userlen)cmdss    r   on_readyr+   7   s     
((--/


w||9I'J

KKK:#(("7"7"9::D	M#((3s4yk1CD6
JK Ks"   "B;B72B;B9A B;9B;__main__DISCORD_TOKEN)__doc__osr$   discord.extr   r	   Intentsdefaultr   Botr
   r   
setup_hookeventr   r+   __name__runenviron     r   <module>r;      s   2 
   K(

//
!
!
#ll&'M<  W W L L zGGBJJ'( r:   