Ë
    +Û¯j;;  ã                  ó6  — d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
 ej                  d«      Z ej                  d«      Z ej                  d«      Z ej                  d«      Z ej                  d«      Z ej                  d	«      Zdd
„Z ej                  d«      Z ej                  d«      Zdd„Zdd„Z ej                  d«      Zdd„ZdZdZdd„Z G d„ d«      Z	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd„Zdd„Zedk(  r e  e«       «      ‚y) u‰  Import 1 YouTube Live into stream-comments unified SQLite (anonymized + dedup).

Usage:
    python scripts/import_youtube_live.py <video_url_or_id> [max_messages] [duration_sec]

defaults: max_messages=5000ã€� duration_sec=1800 (= 30 min)
0 ã‚’æ¸¡ã�™ã�¨ã��ã�® cap ã‚’ç„¡åŠ¹åŒ–ã€� ä¸¡æ–¹ 0 ã�§å®Œå…¨ç„¡åˆ¶é™� (= é…�ä¿¡çµ‚äº† or Ctrl+C å¾…ã�¡)ã€‚

LIVE å°‚ç”¨ (pytchat çµŒç”±)ã€‚ mask ã�¯ src/mask.ts ã�¨ç­‰ä¾¡ãƒ­ã‚¸ãƒƒã‚¯ (URL/MAIL/TEL)ã€‚

source-anonymized + dedup + single file:
- å‡ºåŠ›å…ˆã�¯ `data/comments.sqlite` ã�® 1 ãƒ•ã‚¡ã‚¤ãƒ«å›ºå®š (= å…¨ collect ã‚’çµ±å�ˆã€� é…�ä¿¡è·¨ã�Žã�§ dedup)
- comments table: b (TEXT PRIMARY KEY) + first_ts + count
  â†’ å�Œä¸€æœ¬æ–‡ã�¯ count++ ã�§é›†è¨ˆã€� record ã�¯é‡�è¤‡ã�—ã�ªã�„
- ã€Œå�Œä¸€æ–‡å­—ã�®ã�¿ã€� (= ã€Œã�‚ã�‚ã�‚ã€� ã€Œwwwã€� ã€Œ!!!ã€�) ã�¯ INSERT å‰�ã�« reject
- é…�ä¿¡å…ƒ (channel / stream / video / æŠ•ç¨¿è€…) ã‚’è¾¿ã‚‹æƒ…å ±ã�¯ä¸€åˆ‡ä¿�å­˜ã�—ã�ªã�„
é    )ÚannotationsNu!   (?:https?://|www\.)[^\s<>"\'ã€€]+z0[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}z)\+81[\- ]?\d{1,4}[\- ]?\d{1,4}[\- ]?\d{4}z0\d{1,4}-\d{1,4}-\d{4}z(?<!\d)0\d{9,10}(?!\d)u   [.,;:!?ã€‚ã€�ï¼�ï¼Ÿ)\]ï¼‰ã€‘]+$c                óê   — dd„}t         j                  || «      }t        j                  d|«      }t        j                  d|«      }t        j                  d|«      }t
        j                  d|«      }|S )Nc                óz   — t         j                  | j                  «       «      }d|r|j                  «       z   S dz   S )Nz[URL]Ú )ÚURL_TRAIL_REÚsearchÚgroup)ÚmÚtrails     õY   /var/www/html/é…�ä¿¡ã‚¢ãƒ¼ã‚«ã‚¤ãƒ–/videos/stream-comments/scripts/import_youtube_live.pyÚ_url_subzmask.<locals>._url_sub*   s3   € Ü×#Ñ# A§G¡G£IÓ.ˆØ©5˜%Ÿ+™+›-Ñ9Ð9°bÑ9Ð9ó    z[MAIL]z[TEL])r
   zre.Match[str]ÚreturnÚstr)ÚURL_REÚsubÚEMAIL_REÚPHONE_INTL_REÚPHONE_HYPHEN_REÚPHONE_PLAIN_RE)Úbodyr   Úss      r   Úmaskr   )   sd   € ó:ô 	�
‰
�8˜TÓ"€AÜ�‰�X˜qÓ!€AÜ×Ñ˜' 1Ó%€AÜ×Ñ˜G QÓ'€AÜ×Ñ˜7 AÓ&€AØ€Hr   z\s+z:[_A-Za-z][_A-Za-z0-9\-]*:c                ó.   — t         j                  d| «      S )Nú )ÚYT_STICKER_REr   ©Útexts    r   Ústrip_stickerr   =   s   € Ü×Ñ˜S $Ó'Ð'r   c                óº   — t        j                  d| «      } | j                  dd«      j                  dd«      } t        j	                  d| «      j                  «       S )u½   NFKC + æ”¹è¡Œ â†’ ç©ºç™½ + é€£ç¶šç©ºç™½ collapse + ä¸¡ç«¯ trimã€‚
    dedup ã‚’å®ŸåŠ¹åŒ–ã�™ã‚‹ã�Ÿã‚� collect æ™‚ã�«é�©ç”¨ã�™ã‚‹ (= ã€Œï¼Ÿï¼Ÿï¼Ÿã€� ã�¨ã€Œ???ã€� ã‚’å�Œ row ã�«é›†ç´„)ã€‚
    ÚNFKCúr   ú
)ÚunicodedataÚ	normalizeÚreplaceÚWHITESPACE_REr   Ústripr   s    r   r%   r%   A   sO   € ô × Ñ  ¨Ó.€DØ�<‰<˜˜cÓ"×*Ñ*¨4°Ó5€DÜ×Ñ˜S $Ó'×-Ñ-Ó/Ð/r   z+(?:v=|youtu\.be/|/live/)([A-Za-z0-9_-]{11})c                óž   — t         j                  | «      }|r|j                  d«      S t        j                  d| «      r| S t        d| ›�«      ‚)Né   z[A-Za-z0-9_-]{11}z could not extract video id from )ÚVIDEO_ID_REr   r	   ÚreÚ	fullmatchÚ
ValueError)Ú	url_or_idr
   s     r   Úextract_video_idr0   O   sK   € Ü×Ñ˜9Ó%€AÙØ�w‰w�q‹zÐÜ	‡|�|Ð(¨)Ô4ØÐÜ
Ð7¸	°}ÐEÓ
FÐFr   u  
CREATE TABLE IF NOT EXISTS comments (
    b TEXT PRIMARY KEY,
    first_ts INTEGER NOT NULL,
    count INTEGER NOT NULL DEFAULT 1
);
CREATE INDEX IF NOT EXISTS idx_first_ts ON comments(first_ts);

-- ç²—ã�„ã‚¸ãƒ£ãƒ³ãƒ«åˆ¥ã�®å‡ºç�¾å›žæ•° (â˜…2026-09-15)ã€‚ ãƒ�ãƒ£ãƒ³ãƒ�ãƒ«å��ãƒ»é…�ä¿¡ãƒ»æŠ•ç¨¿è€…ã�¯æŒ�ã�Ÿã�šã€�
-- channels.toml ã�® genre (vtuber / news / sports ç­‰ã�®å��æ•°èªž) ã� ã�‘ã‚’ comments ã�® rowid ã�«ç´�ä»˜ã�‘ã‚‹ã€‚
-- genre å°Žå…¥å‰�ã�«é›†ã‚�ã�Ÿè¡Œã�«ã�¯å¯¾å¿œè¡Œã�Œç„¡ã�„ (= å‡ºã�©ã�“ã‚�ä¸�æ˜Ž)ã€‚
CREATE TABLE IF NOT EXISTS genres (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL UNIQUE
);
CREATE TABLE IF NOT EXISTS comment_genres (
    cid INTEGER NOT NULL,
    gid INTEGER NOT NULL,
    count INTEGER NOT NULL DEFAULT 1,
    PRIMARY KEY (cid, gid)
) WITHOUT ROWID;
)ÚvtuberÚgameÚnewsÚsportsÚmusicÚbusinessÚ	educationÚentertainmentÚproductÚhobbyÚsnsÚboardc                óX  — | j                   j                  dd¬«       t        j                  t	        | «      d¬«      }	 |j                  d«       |j                  d«       |j                  t        «       |j                  «        |j                  «        y# |j                  «        w xY w)u‡  daemon èµ·å‹•æ™‚ã�« 1 åº¦å‘¼ã�¶: journal_mode è¨­å®š + schema ä½œæˆ�ã€‚

    journal_mode ã�¯ DELETE (= classic rollback journal)ã€‚ WAL ã�¯ NTFS-FUSE (ntfs-3g) ç­‰ã�§
    mmap ã�Œä¸�å®‰å®š â†’ 'disk I/O error' ã‚’å¼•ã��èµ·ã�“ã�™ã�®ã�§é�¿ã�‘ã‚‹ã€‚ trade-off: reader ä¸¦åˆ—æ€§
    (= LIVE ä¸­ã�®å�Œæ™‚ SELECT) ã�¯å¤±ã‚�ã‚Œã‚‹ã€� ã�Ÿã� ã�— read ã�¯é›†è¨ˆæ™‚ã�® short query ã�®ã�¿æƒ³å®šã€‚
    T)ÚparentsÚexist_okç      >@)ÚtimeoutzPRAGMA journal_mode = DELETEúPRAGMA synchronous = NORMALN)
ÚparentÚmkdirÚsqlite3Úconnectr   ÚexecuteÚexecutescriptÚSCHEMAÚcommitÚclose)ÚpathÚconns     r   Úinit_dbrN   y   sx   € ð 	‡K�K×Ñ˜d¨TÐÔ2Ü�?‰?œ3˜t›9¨dÔ3€DðØ�‰Ð3Ô4Ø�‰Ð2Ô3Ø×Ñœ6Ô"Ø�‰Œà�
‰
�øˆ�
‰
�ús   ¿AB ÂB)c                  ó‚   — e Zd ZU dZdZdZdZded<   dZ e	j                  «       Zedd„«       Zdd	„Zdd
„Zddd„Zdd„Zy)ÚSqliteAppenderu   data/comments.sqlite å�˜ä¸€ file ã�« append ã�™ã‚‹ writerã€‚

    æ—¢å­˜ DB ã�«å¯¾ã�—ã�¦ã�¯ INSERT OR UPDATE ã�§ mergeã€� fresh ã�ªã‚‰ schema ä½œæˆ�ã€‚

    ## ä¸¦åˆ—æ›¸ã��è¾¼ã�¿ã�®æ‰±ã�„ (â˜…2026-09-11)

    DB ã�¯ ntfs-3g (fuseblk) ä¸Šã�«ã�‚ã‚Š **WAL ã�Œä½¿ã�ˆã�ªã�„** (mmap ä¸�å®‰å®š â†’ disk I/O error)
    ã�Ÿã‚� journal_mode = DELETEã€‚ ã��ã�®çŠ¶æ…‹ã�§ channel thread ã�Œã��ã‚Œã�žã‚Œ connection ã‚’
    æŒ�ã�¤ã�¨ã€� å�„ connection ã�Œæœ€é•· `FLUSH_SECS` ç§’ transaction ã‚’é–‹ã�‘ã�Ÿã�¾ã�¾ã�«ã�ªã‚Šã€�
    thread æ•°ã�Œå¢—ã�ˆã‚‹ã�»ã�© `database is locked` ã�Œå‡ºã‚‹ (43ch ã�«å¢—ã‚„ã�—ã�Ÿæ™‚ç‚¹ã�§ç™ºç”Ÿ)ã€‚

    ã��ã�“ã�§ **process å†…ã�§ connection ã‚’ 1 æœ¬ã� ã�‘å…±æœ‰** ã�—ã€� å…¨ thread ã�Œ
    `_SHARED_LOCK` è¶Šã�—ã�«æ›¸ã��ã€‚ SQLite ã�® file lock ç«¶å�ˆã��ã�®ã‚‚ã�®ã�Œèµ·ã��ã�ªã��ã�ªã‚Šã€�
    å¾…ã�¡ã�¯ in-process ã�®çŸ­ã�„ lock ã� ã�‘ã�«ã�ªã‚‹ã€‚ `shared()` ã�§å�–å¾—ã�—ã€� `close()` ã�¯
    å�‚ç…§ã‚«ã‚¦ãƒ³ãƒˆã�Œ 0 ã�«ã�ªã�£ã�Ÿæ™‚ã� ã�‘å®Ÿéš›ã�«é–‰ã�˜ã‚‹ (= ä»– thread ã�®æ›¸ã��è¾¼ã�¿ã‚’å£Šã�•ã�ªã�„)ã€‚
    é2   g      @Nz'SqliteAppender | None'Ú_sharedr   c                óº   — | j                   5  | j                  € | |«      | _        | xj                  dz  c_        | j                  cddd«       S # 1 sw Y   yxY w)ub   å…±æœ‰ writer ã‚’å�–å¾—ã�™ã‚‹ (ç„¡ã�‘ã‚Œã�°ä½œã‚‹)ã€‚ å‘¼ã‚“ã� æ•°ã� ã�‘ `close()` ã�™ã‚‹ã�“ã�¨ã€‚Nr*   )Ú_shared_guardrR   Ú_shared_refs)ÚclsrL   s     r   ÚsharedzSqliteAppender.sharedª   sO   € ð ×Ññ 	Ø�{‰{Ð"Ù! $›i�”Ø×Ò Ñ!ÕØ—;‘;÷		÷ 	ò 	ús   �:AÁAc                óf  — || _         t        j                  t        |«      dd¬«      | _        | j                  j                  d«       | j                  j                  d«       t        j                  «       | _        d| _	        d| _
        d| _        t        j                  «       | _        i | _        y )Nr@   F)rA   Úcheck_same_threadzPRAGMA busy_timeout = 30000rB   r   )rL   rE   rF   r   rM   rG   Ú	threadingÚLockÚ_lockÚtouchedÚrejectedÚ_pendingÚtimeÚ	monotonicÚ_last_commitÚ_gids)ÚselfrL   s     r   Ú__init__zSqliteAppender.__init__³   s‚   € ØˆŒ	ô —O‘O¤C¨£I°tÈuÔUˆŒ	Ø�	‰	×ÑÐ7Ô8Ø�	‰	×ÑÐ7Ô8Ü—^‘^Ó%ˆŒ
ØˆŒØˆŒØˆŒÜ ŸN™NÓ,ˆÔØ%'ˆ�
r   c                óô   — | j                   j                  |«      }|€Z| j                  j                  d|f«       | j                  j                  d|f«      j	                  «       d   }|| j                   |<   |S )uS   genre å�� â†’ genres.id (ç„¡ã�‘ã‚Œã�°ä½œã‚‹)ã€‚ self._lock ã�®ä¸­ã�§å‘¼ã�¶ã�“ã�¨ã€‚z-INSERT OR IGNORE INTO genres(name) VALUES (?)z$SELECT id FROM genres WHERE name = ?r   )rc   ÚgetrM   rG   Úfetchone)rd   ÚgenreÚgids      r   Ú_gidzSqliteAppender._gidÂ   sl   € à�j‰j�n‰n˜UÓ#ˆØˆ;Ø�I‰I×ÑÐMÐPUÈxÔXØ—)‘)×#Ñ#Ð$JÈUÈHÓU×^Ñ^Ó`ÐabÑcˆCØ #ˆD�J‰J�uÑØˆ
r   c                ó  — t        t        |«      «      dk  r| xj                  dz  c_        y| j                  €J ‚| j                  5  | j                  j                  d||f«       |r[| j                  j                  d|f«      j                  «       d   }| j                  j                  d|| j                  |«      f«       | xj                  dz  c_        | xj                  dz  c_	        | j                  | j                  k\  s.t        j                  «       | j                  z
  | j                  k\  r:| j                  j                  «        d| _	        t        j                  «       | _        d d d «       y# 1 sw Y   yxY w)Nr*   FzhINSERT INTO comments(b, first_ts, count) VALUES (?, ?, 1) ON CONFLICT(b) DO UPDATE SET count = count + 1z&SELECT rowid FROM comments WHERE b = ?r   zrINSERT INTO comment_genres(cid, gid, count) VALUES (?, ?, 1) ON CONFLICT(cid, gid) DO UPDATE SET count = count + 1T)ÚlenÚsetr^   rM   r\   rG   rh   rk   r]   r_   ÚBATCHr`   ra   rb   Ú
FLUSH_SECSrJ   )rd   Útsr   ri   Úcids        r   ÚwritezSqliteAppender.writeË   s?  € ÜŒs�4‹y‹>˜QÒØ�MŠM˜QÑ�MØØ�y‰yÐ$Ð$Ð$ð �Z‰Zñ 	5Ø�I‰I×ÑðAà�r�
ôñ
 Ø—i‘i×'Ñ'Ð(PÐSWÐRYÓZ×cÑcÓeÐfgÑh�Ø—	‘	×!Ñ!ðLà˜$Ÿ)™) EÓ*Ð+ôð
 �LŠL˜AÑ�LØ�MŠM˜QÑ�Mà—‘ §¡Ò+Ü—N‘NÓ$ t×'8Ñ'8Ñ8¸T¿_¹_ÒLà—	‘	× Ñ Ô"Ø !�”Ü$(§N¡NÓ$4�Ô!÷+	5ð, ÷-	5ð, ús   ÁD'E8Å8Fc                óÌ  — t        | «      }|j                  5  |j                  | u }|r|xj                  dz  c_        | xs |j                  dk  }| j                  5  | j
                  dkD  r!| j                  j                  «        d| _        |r| j                  j                  «        ddd«       |r|rd|_        d|_        ddd«       y# 1 sw Y   Œ$xY w# 1 sw Y   yxY w)uj   flush ã�™ã‚‹ã€‚ å…±æœ‰ writer ã�®å ´å�ˆã€� æœ€å¾Œã�®å�‚ç…§ã�Œé–‰ã�˜ã�Ÿæ™‚ã� ã�‘ connection ã‚’é–‰ã�˜ã‚‹ã€‚r*   r   N)	ÚtyperT   rR   rU   r\   r_   rM   rJ   rK   )rd   rV   Ú	is_sharedÚlasts       r   rK   zSqliteAppender.closeê   sÍ   € ä�4‹jˆØ×Ññ 	%ØŸ™ tÐ+ˆIÙØ× Ò  AÑ%Õ Ø!�MÒ; c×&6Ñ&6¸!Ñ&;ˆDØ—‘ñ &Ø—=‘= 1Ò$Ø—I‘I×$Ñ$Ô&Ø$%�D”MÙØ—I‘I—O‘OÔ%÷&ñ ™TØ"�”Ø#$�Ô ÷	%ð 	%÷
&ð &ú÷	%ð 	%ús%   ˜ACÁACÂ+CÃC	ÃCÃC#)rL   úpathlib.Pathr   z'SqliteAppender'©rL   rx   r   ÚNone)ri   r   r   Úint)N)rq   r{   r   r   ri   ú
str | Noner   Úbool)r   rz   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__ro   rp   rR   Ú__annotations__rU   rZ   r[   rT   ÚclassmethodrW   re   rk   rs   rK   © r   r   rP   rP   ‹   sY   … ñð, €EØ€Jð (,€GÐ$Ó+Ø€LØ"�I—N‘NÓ$€Màòó ðó(óôô>%r   rP   c                óÚ  — t        | «      }t        j                  |d¬«      }|dz  }	t        j	                  |	«      }
d}|dk  }|dk  }|rdnt        j
                  «       |z   }d}|rd|› d�nd	}t        |› d
|	j                  › d|rdn|› d|rdn|› d�› d|j                  «       › �	«       	 |j                  «       �rh|s||k  �r`|�|j                  «       rd}�nJ|�t        j
                  «       |k\  rd}�n-t        |j                  «       j                  «       «      }|s:t        d«      D ]+  }|�|j                  «       r nt        j                  d«       Œ- Œ¯|D ]Â  }|j                  xs d	j!                  «       }|sŒ$t#        t%        t'        |«      «      «      }|sŒD|
j)                  t+        |j,                  «      ||«       |dz  }|dz  dk(  r*t        |› d|› d|
j.                  › d|
j0                  › �«       |s	||k\  rd} n|€Œ¯|j                  «       sŒÀd} n �Œx	 |j5                  «        |
j7                  «        |	j9                  «       r|	j;                  «       j<                  dz  nd}t        |› d|› d|› d|
j.                  › d|
j0                  › d|d ›d!�«       y# t2        $ r d}t        d|› d�«       Y Œžw xY w# |j5                  «        |
j7                  «        w xY w)"uŸ  LIVE chat collectã€‚ stop_event ã�Œ set ã�•ã‚Œã�Ÿã‚‰æ¬¡ã�® chunk ã�§é›¢è„±ã€‚

    ä¸¦åˆ—åˆ©ç”¨æ™‚: å�„ thread ã�Œç‹¬è‡ªã�® pytchat session ã‚’æŒ�ã�¤ã�Œã€� **SQLite writer ã�¯
    process å†…ã�§ 1 connection ã‚’å…±æœ‰** ã�™ã‚‹ (`SqliteAppender.shared`)ã€‚ ntfs-3g ä¸Šã�§ã�¯
    WAL ã�Œä½¿ã�ˆã�šã€� connection ã‚’åˆ†ã�‘ã‚‹ã�¨ thread æ•°ã�«æ¯”ä¾‹ã�—ã�¦
    `database is locked` ã�Œå‡ºã‚‹ã�Ÿã‚� (â˜…2026-09-11)ã€‚
    F)Úvideo_idÚinterruptablezcomments.sqliter   NÚ
live_endedú[z] r   z[start] db=z max=u   âˆžz dur=r   z
 is_alive=ÚstoppedÚduration_capé   r*   éd   z  seen=z	 touched=z
 rejected=Úmessage_capÚinterruptedr#   z[interrupted] flushing...i   z[done] reason=z seen=z	 db_size=z.1fÚKiB)r0   ÚpytchatÚcreaterP   rW   r`   ÚprintÚnameÚis_aliveÚis_setÚlistrg   Ú
sync_itemsÚrangeÚsleepÚmessager(   r%   r   r   rs   r{   Ú	timestampr]   r^   ÚKeyboardInterruptÚ	terminaterK   ÚexistsÚstatÚst_size)r/   Úmax_messagesÚduration_secÚout_dirÚ
stop_eventÚlog_tagri   r†   ÚchatÚdb_pathÚwriterÚcountÚunlimited_msgsÚunlimited_durÚdeadlineÚstop_reasonÚprefixÚitemsÚ_ÚcÚrawr   Úsize_kibs                          r   Úcollectrµ   ÿ   s  € ô    	Ó*€Hô �>‰> 8¸5ÔA€DàÐ)Ñ)€Gä×"Ñ" 7Ó+€Fà€EØ! QÑ&€NØ  AÑ%€MÙ$‰t¬$¯)©)«+¸Ñ*D€HØ€Ká 'ˆq��	˜‰_¨R€FÜ	Øˆ(�+˜gŸl™l˜^ð ,Ù&‰u¨LÐ9ð :Ù%‰u¨l¨^¸1Ð+=Ð>ð ?Ø—M‘M“OÐ$ð	&ôð-Ø�m‰m�o¡>°U¸\Ó5IØÐ%¨*×*;Ñ*;Ô*=Ø'�ÙØÐ#¬¯	©	«°xÒ(?Ø,�ÙÜ˜Ÿ™›×.Ñ.Ó0Ó1ˆEÙä˜q›ò "�AØ!Ð-°*×2CÑ2CÔ2EÙÜ—J‘J˜q•Mð"ð Øò �Ø—y‘y’ B×-Ñ-Ó/�ÙØä ¤¬t°C«yÓ!9Ó:�ÙØØ—‘œS §¡Ó-¨t°UÔ;Ø˜‘
�Ø˜3‘; !Ò#ÜØ!˜( '¨%¨°	¸&¿.¹.Ð9Ið J$Ø$*§O¡OÐ#4ð6ôñ &¨%°<Ò*?Ø"/�KÙØÑ)¨j×.?Ñ.?Õ.AØ"+�KÙð)ñ, Øð
 	�‰ÔØ�‰Œà07·±Ô0@ˆw�|‰|‹~×%Ñ%¨Ò,Àa€HÜ	Øˆ(�.  ¨V°E°7ð ;Ø—>‘>Ð" *¨V¯_©_Ð,=ð >Ø˜C�. ð	%õøô ò 6Ø#ˆÜ��6�(Ð3Ð4Ö5ð6ûð 	�‰ÔØ�‰�ús1   Â-EJ( ÈJ( ÈJ( Ê(KËK ËKËK Ë"K*c                 ó  — t        t        j                  «      dk  rt        t        «       yt        j                  d   } t        t        j                  «      dkD  rt        t        j                  d   «      nd}t        t        j                  «      dkD  rt        t        j                  d   «      nd}t        j                  t        «      j                  «       j                  j                  }|dz  }t        | |||«       y)NrŒ   r*   iˆ  é   i  Údatar   )rm   ÚsysÚargvr“   r�   r{   ÚpathlibÚPathÚ__file__ÚresolverC   rµ   )Úurlr¢   r£   Úherer¤   s        r   ÚmainrÁ   \  s¬   € Ü
Œ3�8‰8ƒ}�qÒÜŒgŒØÜ
�(‰(�1‰+€CÜ'*¬3¯8©8£}°qÒ'8”3”s—x‘x ‘{Ô#¸d€LÜ'*¬3¯8©8£}°qÒ'8”3”s—x‘x ‘{Ô#¸d€Lä�<‰<œÓ!×)Ñ)Ó+×2Ñ2×9Ñ9€DØ�V‰m€GÜˆC�˜|¨WÔ5Ør   Ú__main__)r   r   r   r   )r   r   r   r   )r/   r   r   r   ry   )Nr   N)r/   r   r¢   r{   r£   r{   r¤   rx   r¥   zthreading.Event | Noner¦   r   ri   r|   r   rz   )r   r{   )!r�   Ú
__future__r   r»   r,   rE   r¹   rZ   r`   r$   r‘   Úcompiler   r   r   r   r   r   r   r'   r   r   r%   r+   r0   rI   ÚGENRESrN   rP   rµ   rÁ   r~   Ú
SystemExitr„   r   r   ú<module>rÇ      sƒ  ðñõ$ #ã Û 	Û Û 
Û Û Û ã ð 
ˆ�‰Ð8Ó	9€Øˆ2�:‰:ÐIÓJ€Ø�—
‘
ÐGÓH€Ø�"—*‘*Ð6Ó7€Ø�—‘Ð5Ó6€Øˆr�z‰zÐ<Ó=€ó	ð �—
‘
˜6Ó"€ð
 �—
‘
Ð8Ó9€ó(ó0ð ˆb�j‰jÐGÓH€óGð
€ð0
€ó÷$o%ñ o%ðr *.ØØðZØðZàðZð ðZð ð	Zð
 'ðZð ðZð ðZð 
óZózð ˆzÒÙ
‘T“VÓ
Ðð r   