Ë
    ãß²jƒ  ã                   óž  — U d 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ddl	Z	ddl
mZ ddlmZ ddlmZmZ ddlmZ ddlZ ej(                  e«      Z eh d£«      Zd~d	ed
edefd„Zdded
edefd„Zdej:                  ddfd„Zdeddfd„Zdeddfd„Z deddddddfd„Z!d€d„Z"deddddfd„Z#deddddfd„Z$ejJ                  dk(  Z& eh d£«      Z'd Z(d!Z)d"Z*ejV                  ejX                  fZ-d#e.defd$„Z/d%ed&eddfd'„Z0d%ed&eddfd(„Z1d)eeef   d*eeef   defd+„Z2deeef   ddfd,„Z3dd-œdeeef   d.eddfd/„Z4d0dd1ddd2œded3ed4eddd5ed6ed7eddfd8„Z5d�ded9dd:eddfd;„Z6d0d<ddddd=œdeeef   d>ed4ed?ed@ed9dddd7eddfdA„Z7d<dddBœdeeef   d>e8d?eddd7eddfdC„Z9dDedEddFedGe:ddf
dH„Z;dIddddJœdeeef   dDedEe<de<dz  dFed7edGeddfdK„Z=deeef   de:fdL„Z>dddMœdeeef   dNedOej~                  dz  defdP„Z@ G dQ„ dRej‚                  «      ZBdddddSœdeeef   dDedTedUedVedz  d9dddfdW„ZCdefdX„ZDddYœdedVdZddfd[„ZEdeeef   d\ed	eddfd]„ZF eh d^£«      ZGd	edefd_„ZHdd`œdeeef   dae:dbdZddfdc„ZId‚dded
edefde„ZJ eKedfd«      xs ej˜                  ZMdgedefdh„ZNi ZOe:ePdi<    ej¢                  «       ZRdeeef   defdj„ZSdkefdl„ZTdƒdked
e<de<fdm„ZUd„dked
eVdeVfdn„ZWd~dked
edefdo„ZXdpZYdqedz  dedz  fdr„ZZd…ds„Z[dtefdu„Z\defdv„Z]dtedefdw„Z^dtedefdx„Z_dyedefdz„Z`dtedeaeee<f   fd{„Zbdted|edefd}„Zcy)†z*Shared utility functions for hermes-agent.é    N)Úsuppress)ÚPath)ÚAnyÚUnion)Úurlparse>   Ú1ÚonÚyesÚtrueFÚvalueÚdefaultÚreturnc                 óˆ   — | €|S t        | t        «      r$| j                  «       j                  «       t        v S t        | «      S )zDCoerce bool-ish values using the project's shared truthy string set.)Ú
isinstanceÚstrÚstripÚlowerÚTRUTHY_STRINGSÚbool)r   r   s     ú*/home/ubuntu/.hermes/hermes-agent/utils.pyÚis_truthy_valuer      s:   € à€}ØˆÜ�%œÔØ�{‰{‹}×"Ñ"Ó$¬Ð6Ð6Ü�‹;Ðó    Ú Únamec                 óD   — t        t        j                  | |«      d¬«      S )zBReturn True when an environment variable is set to a truthy value.F©r   ©r   ÚosÚgetenv)r   r   s     r   Úenv_var_enabledr    "   s   € äœ2Ÿ9™9 T¨7Ó3¸UÔCÐCr   Ústztuple[int, int, int, int]c                 ó^   — | j                   | j                  | j                  | j                  fS )u6  Change-detection key for a stat result: ``(st_mtime_ns, st_size, st_ino, st_ctime_ns)``.

    mtime + size alone miss a replacement that preserves both (``cp -p``, ``rsync -t``, a tar
    restore, a script pinning the timestamp with ``os.utime``). The inode changes on an atomic
    replace and ctime cannot be backdated from user space, so the pair catches those writers.
    On Windows ``st_ino`` may be 0 and ``st_ctime_ns`` is the creation time â€” both stable across
    an in-place rewrite, so the key degrades to mtime + size there rather than misfiring.
    )Úst_mtime_nsÚst_sizeÚst_inoÚst_ctime_ns)r!   s    r   Úfile_signaturer'   '   s#   € ð �N‰N˜BŸJ™J¨¯	©	°2·>±>ÐBÐBr   Úpathú
int | Nonec                 ó    — 	 | j                  «       r-t        j                  | j                  «       j                  «      S dS # t        $ r Y yw xY w)z6Permission bits of *path* if it exists, else ``None``.N)ÚexistsÚstatÚS_IMODEÚst_modeÚOSError)r(   s    r   Ú_preserve_file_moder0   3   sA   € ðØ48·K±K´MŒt�|‰|˜DŸI™I›K×/Ñ/Ó0ÐKÀtÐKøÜò Ùðús   ‚<A ¿A Á	AÁAztuple[int, int] | Nonec                 ó¤   — 	 t         j                  dk(  r| j                  «       nd}|r|j                  |j
                  fS dS # t        $ r Y yw xY w)z8Owning ``(uid, gid)`` of *path* on POSIX, else ``None``.ÚposixN)r   r   r,   r/   Úst_uidÚst_gid)r(   r!   s     r   Ú_preserve_file_ownerr5   ;   sO   € ðÜŸG™G wÒ.ˆT�Y‰YŒ[°Dˆñ &(ˆB�I‰I�r—y‘yÐ!Ð1¨TÐ1øô ò Ùðús   ‚%A Á	AÁAÚownerÚmodec                 ó$  — |�Et        t        d«      r5t        t        «      5  t        j                  | |d   |d   «       ddd«       |�/t        t        «      5  t        j
                  | |«       ddd«       yy# 1 sw Y   Œ;xY w# 1 sw Y   yxY w)a£  Best-effort re-apply of uid/gid and permission bits after an atomic replace.

    Docker/NAS installs often run some commands as root on a volume owned by the runtime user;
    ``os.replace`` swaps in the temp file's owner, so privileged callers chown it back. ``mkstemp``
    creates 0o600 files; without re-applying *mode* the target would inherit that and break
    volume mounts relying on broader permissions.
    NÚchownr   é   )Úhasattrr   r   r/   r9   Úchmod)r(   r6   r7   s      r   Ú_restore_file_metadatar=   D   sƒ   € ð ÐœW¤R¨Ô1Ü”gÓñ 	/Ü�H‰H�T˜5 ™8 U¨1¡XÔ.÷	/àÐÜ”gÓñ 	!Ü�H‰H�T˜4Ô ÷	!ð 	!ð ÷	/ð 	/ú÷	!ð 	!ús   ¢A:ÁBÁ:BÂBc                  óª   — t         j                  dk7  ry	 t        j                  d«      } t        j                  | «       d|  z  S # t        $ r Y yw xY w)u  The mode ``open(path, "w")`` gives a file it has to create (``0o666 & ~umask``); ``None``
    when the umask cannot be read or on non-POSIX hosts (Windows mode bits are synthesized).

    ``mkstemp`` always creates at 0600, so publishing a *new* non-secret file through a temp
    file would tighten it to owner-only â€” the Docker/NAS volume-mount hazard
    :func:`_restore_file_metadata` documents. The transient mask is 0o077: a thread that opens
    a file in the read window gets a tighter file, never a looser one.
    r2   Né?   i¶  )r   r   Úumaskr/   )Úcurrents    r   Údefault_new_file_moderB   T   sT   € ô 
‡w�w�'ÒØðÜ—(‘(˜5“/ˆÜ
�‰�Ôð �G�8ÑÐøô ò Ùðús   –*A Á	AÁAc                 ó   — t        | |d «       y ©N©r=   )r(   r6   s     r   Ú_restore_file_ownerrF   g   s   € Ü˜4 ¨Õ-r   c                 ó   — t        | d |«       y rD   rE   )r(   r7   s     r   Ú_restore_file_moderH   k   s   € Ü˜4  tÕ,r   Únt>   é   é    é!   é   g{®Gáz”?gš™™™™™¹?Úexcc                 ó8   — t         xr t        | dd«      t        v S )z<Candidate-only: winerror 5 also covers a genuine ACL denial.ÚwinerrorN)Ú_IS_WINDOWSÚgetattrÚ!_WINDOWS_CONTENDED_REPLACE_ERRORS)rN   s    r   Ú#_is_contended_windows_replace_errorrT   ‚   s   € äÒ^œ7 3¨
°DÓ9Ô=^Ð^Ð^r   Útmp_strÚ	real_pathc           	      ó‚  — t        | d«      5 }|j                  «       }ddd«       t        j                   |t        j                  t	        t        dd«      z  «      }	 d}|t        «      k  r+|t        j                  |||d «      z  }|t        |«      k  rŒ+t        j                  |t        |«      «       t        t        «      5  t        j                  |«       ddd«       t        j                  |«       t        j                  | «       y# 1 sw Y   ŒòxY w# 1 sw Y   Œ@xY w# t        j                  |«       w xY w)uS  Overwrite *real_path* through the existing file â€” last resort for a still-held target.

    Not atomic (a smaller window than a copy, not none), so it runs only after the rename has
    genuinely failed. Writing through the target also preserves its ACL, which ``os.replace``
    does not (the temp file's inherited ACL wins there).
    ÚrbNÚO_BINARYr   )ÚopenÚreadr   ÚO_WRONLYrR   ÚlenÚwriteÚ	ftruncater   r/   ÚfsyncÚcloseÚunlink)rU   rV   ÚsrcÚdataÚfdÚwrittens         r   Ú_rewrite_in_placerg   ‡   sò   € ô 
ˆg�tÓ	ð  Ø�x‰x‹zˆ÷ä	�‰�œBŸK™K¬'´"°jÀ!Ó*DÑDÓ	E€BðØˆØœ˜D›	Ò!Ø”r—x‘x  D¨¨ NÓ3Ñ3ˆGð œ˜D›	Ó!ä
�‰�Rœ˜T›Ô#Ü”gÓñ 	Ü�H‰H�RŒL÷	ô 	�‰�ŒÜ‡I�IˆgÕ÷ð ú÷	ð 	ûô 	�‰��ús5   �DÁ:D' Â.D' ÃDÃD' ÄDÄD$Ä D' Ä'D>c                 óž  — t        j                  | |«       t        t        «      5  t        j                  | |«       ddd«       t        t        «      5  t        |d«      5 }t        j                  |j                  «       «       ddd«       ddd«       t        j                  | «       y# 1 sw Y   ŒoxY w# 1 sw Y   Œ3xY w# 1 sw Y   Œ7xY w)zCCopy/fsync/unlink fallback for cross-device and bind-mount renames.NrX   )
ÚshutilÚcopyfiler   r/   ÚcopystatrZ   r   r`   Úfilenorb   )rU   rV   Úfs      r   Ú_copy_fallbackrn   �   s–   € ä
‡O�O�G˜YÔ'Ü	”'Ó	ñ ,Ü�‰˜ Ô+÷,ä	”'Ó	ñ œD ¨DÓ1ð °QÜ
�‰�—‘“Ô÷÷ ä‡I�IˆgÕ÷	,ð ,ú÷ð ú÷ ð ús/   ¦B+ÁCÁ!$B7ÂCÂ+B4Â7C 	Â<CÃCÚtmp_pathÚtargetc                 ó„  — t        |«      }t        j                  j                  |«      rt        j                  j	                  |«      n|}t        | «      }	 t        j
                  ||«       |S # t        $ �rE}t        |«      }|j                  t        vr|s‚ |r¡ddl
m} t        dt        dz   «      D ]…  }t        j                   ||t         t"        ¬«      «       	 t        j
                  ||«       |c cY d}~S # t        $ r2}	|	}|	j                  t        v rd}Y d}	~	 nt        |	«      s‚ Y d}	~	Œd}	~	ww xY w t$        j'                  d||t)        |dd«      xs8 t        j*                  j-                  |j                  xs d|j                  «      |rd	nd
«        |rt.        nt0        ||«       Y d}~|S d}~ww xY w)uÝ  Atomically move *tmp_path* onto *target*, preserving symlinks.

    Resolves a symlink first so ``os.replace`` writes the real file in place and the symlink
    survives. Otherwise identical to ``os.replace`` unless the rename fails with EXDEV/EBUSY
    (cross-device, bind-mount, busy file: copy/fsync/unlink immediately â€” these never clear on
    retry) or a Windows rename contended by another open handle (winerror 5/32/33: bounded retry,
    then in-place rewrite).
    r   )Újittered_backoffr:   )Ú
base_delayÚ	max_delayNFz;atomic_replace: %s -> %s failed with %s; falling back to %srP   zin-place rewriteÚcopy)r   r   r(   ÚislinkÚrealpathÚreplacer/   rT   ÚerrnoÚ_CROSS_DEVICE_ERRNOSÚagent.retry_utilsrr   ÚrangeÚ_REPLACE_RETRY_ATTEMPTSÚtimeÚsleepÚ_REPLACE_RETRY_BASE_DELAY_SÚ_REPLACE_RETRY_MAX_DELAY_SÚloggerÚdebugrR   Ú	errorcodeÚgetrg   rn   )
ro   rp   Ú
target_strrV   rU   rN   Ú	contendedrr   ÚattemptÚ	retry_excs
             r   Úatomic_replacerŠ   §   sŠ  € ô �V“€JÜ02·±·±¸zÔ0J”—‘× Ñ  Ô,ÐPZ€IÜ�(‹m€GðQÜ
�
‰
�7˜IÔ&ØÐøÜó QÜ7¸Ó<ˆ	Ø�9‰9Ô0Ñ0¹ØÙå:Ü  Ô$;¸aÑ$?Ó@ò �Ü—
‘
Ñ+¨GÔ@[ô  hBô  Cô  Dð	Ü—J‘J˜w¨	Ô2Ø$×$øÜò Ø#�CØ —‘Ô*>Ñ>Ø$)˜	ÝÜ>¸yÔIØô Jûðúðô 	�‰ÐRÐT[Ð]fÜ˜S *¨dÓ3Òe´u·±×7JÑ7JÈ3Ï9É9Ê>ÐXYÐ[^×[dÑ[dÓ7eÙ+4Ñ'¸&ô	Bð 
<™iÕ	¬^¸WÀi×PÐPØÐûð1QúsV   ÁA0 Á0
F?Á:A$F:ÃC>Ã6F:Ã8F?Ã>	D9ÄD4ÄF:Ä#D4Ä/F:Ä4D9Ä9A;F:Æ:F?c           	      óŠ  — t         j                  dk(  ry	 t        j                  | t         j                  t	        t         dd«      z  «      }	 t        t
        «      5  t        j                  |«       ddd«       t        j                  |«       y# t
        $ r Y yw xY w# 1 sw Y   Œ.xY w# t        j                  |«       w xY w)uE  Best-effort fsync of a directory entry so a just-renamed file survives power loss.

    No-op on Windows (directories can't be opened with ``os.open``; the file fsync still applies)
    and on any OSError â€” durability of the directory entry is never worth failing a write that
    has already been replaced into place.
    rI   NÚO_DIRECTORYr   )	r   r   rZ   ÚO_RDONLYrR   r/   r   r`   ra   )r(   re   s     r   Úfsync_directoryrŽ   Ñ   s•   € ô 
‡w�w�$‚ØðÜ�W‰W�Tœ2Ÿ;™;¬´°]ÀAÓ)FÑFÓGˆðÜ”gÓñ 	Ü�H‰H�RŒL÷	ô 	�‰��øô ò Ùðú÷	ð 	ûô 	�‰��ús5   –6B ÁB+ ÁBÁ2B+ Â	BÂBÂB(Â$B+ Â+C)Úignore_errorsr�   c                ó¬   — d„ }	 	 t        j                  | |¬«       y# t        $ r t        j                  | |¬«       Y yw xY w# t        $ r |s‚ Y yw xY w)aL  ``shutil.rmtree`` that can also delete read-only trees.

    ``shutil.rmtree`` stops at the first entry it cannot unlink.  Git marks
    loose object files read-only on Windows (``WinError 5``), and package
    installs (Nix store, deb/rpm) are copied ``r--r--r--`` into ``0555``
    directories on POSIX, where unlinking needs a writable *parent*.  Clear the
    write bit on the failing path and on its parent, then retry the exact
    operation that failed.  Only ``PermissionError`` is retried: every other
    failure keeps ``shutil.rmtree``'s semantics (and ``ignore_errors``).
    c                 óª  — t        |t        «      r|d   n|}t        |t        «      s|‚t        j                  j                  |«      |fD ]r  }|sŒt        t        «      5  t        j                  |t        j                  |«      j                  t        j                  z  t        j                  z  «       d d d «       Œt  | |«       y # 1 sw Y   Œ‡xY w)Nr:   )r   ÚtupleÚPermissionErrorr   r(   Údirnamer   r/   r<   r,   r.   ÚS_IWUSRÚS_IXUSR)ÚfuncÚfpathÚexc_inforN   Ú	candidates        r   Ú	_on_errorz"rmtree_readonly.<locals>._on_errorñ   s­   € ä'¨´%Ô8ˆh�qŠk¸hˆÜ˜#œÔ/ØˆIÜŸ'™'Ÿ/™/¨%Ó0°%Ð8ò 	bˆIÚÜœgÓ&ñ bÜ—H‘H˜Y¬¯©°	Ó(:×(BÑ(BÄTÇ\Á\Ñ(QÔTX×T`ÑT`Ñ(`Ôa÷bð bð	bñ 	ˆU�÷bð bús   Á AC	Ã	C	)Úonexc)ÚonerrorN)ri   ÚrmtreeÚ	TypeErrorr/   )r(   r�   r›   s      r   Úrmtree_readonlyr    å   sW   € ò	ð	ð	3Ü�M‰M˜$ iÖ0øÜò 	3Ü�M‰M˜$¨	×2ð	3ûäò ñ Øñ ðús&   † ž A¾A Á AÁA ÁAÁAúutf-8T)Úencodingr7   Úpreserve_ownerÚbinaryÚ	fsync_dirÚprefixr¢   r£   r¤   r¥   c                ó6  — ddl m}  || j                  «       |€| j                  «       s
t	        «       }|rt        | «      nd}	t        j                  t        | j                  «      |d¬«      \  }
}	 t        j                  |
|rdnd|rdn|¬«      5 }|�4t        t        d	«      r$t        j                  |j                  «       |«        ||«       |j                  «        t        j                  |j                  «       «       ddd«       t!        t#        || «      «      }t%        ||	|«       |rt'        |j                  «       yy# 1 sw Y   ŒDxY w# t(        $ r; t+        t,        «      5  t        j.                  |«       ddd«       ‚ # 1 sw Y   ‚ xY ww xY w)
u,  Temp file + fsync + :func:`atomic_replace`, then re-apply owner/mode.

    *write(f)* emits the payload into the open handle (text, or bytes when *binary*). The temp file
    is created by ``mkstemp`` â€” ``O_CREAT|O_EXCL`` at 0600 regardless of umask â€” so a secret is
    never readable at process umask, not even between create and chmod. *mode* is fchmod'd onto
    the temp fd BEFORE the replace so the target never transits through mkstemp's 0600 (fchmod is
    Unix-only; the post-replace chmod is the sole path on Windows). With no *mode* a NEW target
    gets what ``open(path, "w")`` would have given it (process umask) â€” the callers this replaced
    wrote at umask, and silently tightening every fresh cache/state file to 0600 breaks shared
    volume mounts; an existing target with no *mode* keeps mkstemp's bits, as before. *fsync_dir*
    also fsyncs the resolved target's parent so the rename itself is durable. The temp file is
    removed on any failure â€” ``BaseException`` on purpose, so KeyboardInterrupt / SystemExit still
    clean up.
    r   ©Úmkdir_under_hermes_homeNz.tmp)Údirr¦   ÚsuffixÚwbÚw©r¢   Úfchmod)Úhermes_constantsr©   Úparentr+   rB   r5   ÚtempfileÚmkstempr   r   Úfdopenr;   r¯   rl   Úflushr`   r   rŠ   r=   rŽ   ÚBaseExceptionr   r/   rb   )r(   r^   r¦   r¢   r7   r£   r¤   r¥   r©   Úoriginal_ownerre   ro   rm   Úreplaceds                 r   Ú_atomic_writer¹     sA  € õ& 9á˜DŸK™KÔ(Ø€|˜DŸK™KœMÜ$Ó&ˆÙ3AÔ)¨$Ô/Àt€NÜ×#Ñ#¬¨D¯K©KÓ(8ÀÐPVÔW�L€BˆðÜ�Y‰Y�r¡6™4¨sÁV¹TÐQYÔZð 	!Ð^_ØÐ¤G¬B°Ô$9Ü—	‘	˜!Ÿ(™(›* dÔ+Ù�!ŒHØ�G‰GŒIÜ�H‰H�Q—X‘X“ZÔ ÷	!ô œ x°Ó6Ó7ˆÜ˜x¨¸Ô>ÙÜ˜HŸO™OÕ,ð ÷	!ð 	!ûô ò Ü”gÓñ 	 Ü�I‰I�hÔ÷	 à÷	 àúðús>   Á3 E ÂA2EÄAE ÅEÅE ÅFÅ,FÆ	FÆF	ÆFÚcreate_modeÚpreservec                 óL   — |rt        | «      nd}|€| j                  «       r|S |S )zXExisting permission bits of *path* (when *preserve*), else *create_mode* for a new file.N)r0   r+   )r(   rº   r»   r7   s       r   Ú_mode_for_writer½   3  s)   € á(0Ô˜tÔ$°d€DØÐ# t§{¡{¤}ˆ4ÐE¸+ÐEr   z.tmp_)r¢   Ú
tmp_prefixÚpreserve_moderº   r7   r¥   Úcontentr¾   r¿   c                óf   ‡— t        | «      } t        | ˆfd„|||�|nt        | ||¬«      ||¬«       y)aÇ  Write *content* to *path* via temp file + fsync + atomic rename.

    The target is never left partially written on crash/interrupt. Shared by every destructive
    file rewrite (memory store, skill manager, agent importer, ...). *mode* forces the final
    permission bits (secret files: ``0o600``) regardless of what exists; *create_mode* applies only
    when the target is new and *preserve_mode* carries an existing file's bits and owner across.
    c                 ó&   •— | j                  ‰«      S rD   ©r^   ©rm   rÀ   s    €r   ú<lambda>z#atomic_write_text.<locals>.<lambda>D  ó   ø€  !§'¡'¨'Ó"2€ r   N)r»   )r¦   r¢   r7   r£   r¥   )r   r¹   r½   )r(   rÀ   r¢   r¾   r¿   rº   r7   r¥   s    `      r   Úatomic_write_textrÇ   9  s:   ø€ ô �‹:€DÜ�$Ó2¸:ÐPXØ#Ð/‘t´_ÀTÈ;ÐanÔ5oØ!.¸)öEr   )r¾   r7   r¥   c          
      ó`   ‡— t        | «      } t        | ˆfd„|dd|�|n
t        | «      |¬«       y)zKBytes variant of :func:`atomic_write_text` (encrypted blobs, key material).c                 ó&   •— | j                  ‰«      S rD   rÃ   rÄ   s    €r   rÅ   z$atomic_write_bytes.<locals>.<lambda>M  rÆ   r   TFN)r¦   r¤   r£   r7   r¥   )r   r¹   r0   )r(   rÀ   r¾   r7   r¥   s    `   r   Úatomic_write_bytesrÊ   I  s6   ø€ ô �‹:€DÜ�$Ó2¸:ÈdÐchØ#Ð/‘tÔ5HÈÓ5NÐZcöer   rd   ÚindentÚensure_asciiÚdump_kwargsc          	      óÈ   — t        j                  | f||dœ|¤Ž}	 |j                  |«       y# t        $ r+ |j                  t        j                  | f|ddœ|¤Ž«       Y yw xY w)ur  ``json.dump`` that survives surrogate-escaped strings.

    ``os.fsdecode`` of a non-UTF-8 filename/argv yields lone surrogates (``'\udcff'``); a utf-8
    text handle rejects them with ``UnicodeEncodeError`` â€” a ValueError, which callers guarding
    ``except OSError`` never see. ``ensure_ascii=True`` escapes them as ``\udcff`` and
    ``json.loads`` restores the identical str, so the retry round-trips; ``surrogateescape``
    would emit a raw 0xFF byte that the reader's utf-8 decode rejects. Serializing to a str first
    keeps the failure before any byte reaches the file, so no partial payload is left behind.
    )rË   rÌ   TN)ÚjsonÚdumpsr^   ÚUnicodeEncodeError)rd   rm   rË   rÌ   rÍ   Útexts         r   Ú
_dump_jsonrÓ   Q  sa   € ô �:‰:�dÐT 6¸ÑTÈÑT€DðSØ	�‰��øÜò SØ	�‰”—
‘
˜4ÐQ¨¸TÑQÀ[ÑQÖRðSús   ›- ­1A!Á A!é   )rË   r7   rÌ   r¥   c                ó„   ‡‡‡‡— t        | «      } t        | ˆˆˆˆfd„d| j                  › d�|�|n
t        | «      |¬«       y)a›  Write JSON to *path* atomically (temp file + fsync + replace).

    Surrogate-escaped strings (non-UTF-8 argv/paths) are always persisted: the write falls back
    to ``ensure_ascii=True`` escapes for that payload only, so normal content keeps its raw UTF-8
    bytes. ``mode=0o600`` is the private-credential form: the temp file is 0600 from creation
    (mkstemp), so the payload is never umask-readable.
    c                 ó$   •— t        ‰| ‰‰‰¬«      S )N)rË   rÌ   rÍ   )rÓ   )rm   rd   rÍ   rÌ   rË   s    €€€€r   rÅ   z#atomic_json_write.<locals>.<lambda>n  s   ø€ ¤*¨T°1¸VÐR^ÐlwÔ"x€ r   ú.Ú_N)r¦   r7   r¥   )r   r¹   Ústemr0   )r(   rd   rË   r7   rÌ   r¥   rÍ   s    `` ` `r   Úatomic_json_writerÚ   b  s>   û€ ô �‹:€DÜ�$ÖxØ˜TŸY™Y˜K qÐ)¸Ð8H±ÔNaÐbfÓNgØ%ö'r   c                 ó¶   — 	 t        j                  t        | «      j                  d¬«      «      }t        |t        «      r|S i S # t        t
        f$ r i cY S w xY w)u1  The JSON object at *path*, or ``{}`` when the file is missing, unreadable, malformed or
    not an object. The read half of every ``read â†’ merge â†’ atomic_json_write`` config store
    (memory-provider ``save_config``), so a corrupt sidecar degrades to defaults instead of
    taking the provider down.z	utf-8-sigr®   )rÏ   Úloadsr   Ú	read_textr/   Ú
ValueErrorr   Údict)r(   rd   s     r   Úread_json_or_emptyrà   s  sX   € ð
Ü�z‰zœ$˜t›*×.Ñ.¸Ð.ÓDÓEˆô ˜d¤DÔ)ˆ4Ð1¨rÐ1øô ”ZÐ ò ØŠ	ðús   ‚.A ÁAÁA)ÚlabelÚlográ   râ   c                ó`  — t        | «      }	 |j                  «       j                  }t        j
                  dk7  s$|t        j                  t        j                  z  z  sy|xs t        j                  d|r|› d�nd|j
                  t        j                  |«      |«       y# t        $ r Y yw xY w)a½  Warn when a credential file is group/world-readable; True when a warning was emitted.

    Hand-made secret files (or ones older Hermes wrote without an explicit mode) commonly end up
    0o644 under the default umask; call this before loading any token/credential file. No-op on
    non-POSIX (Windows ACLs don't map onto group/other bits; st_mode there is synthesized), when
    the file is missing, or when permissions are already tight.
    Fr2   zO%s%s is group/world-readable (mode 0%o) and contains secrets. Run: chmod 600 %sú r   T)r   r,   r.   r/   r   r   ÚS_IRGRPÚS_IROTHr‚   Úwarningr-   )r(   rá   râ   ÚpÚ	file_modes        r   Ú(warn_if_credential_file_broadly_readablerê     s–   € ô 	ˆT‹
€AðØ—F‘F“H×$Ñ$ˆ	ô 
‡w�w�'Ò )¬t¯|©|¼d¿l¹lÑ/JÒ"KØØ‚]ŒF×ÑÐmÙ+0˜u˜g Q™K°b¸!¿&¹&Ä$Ç,Á,ÈyÓBYÐ[\ô^àøô ò Ùðús   �B! Â!	B-Â,B-c                   ó$   ‡ — e Zd ZdZdˆ fd„	Zˆ xZS )ÚIndentDumpera¼  PyYAML dumper that indents list items under mapping keys (2-space).

    PyYAML emits "indentless" sequences while ruamel (:func:`atomic_roundtrip_yaml_update`)
    indents them; mixing both in one ``config.yaml`` makes stricter parsers like ``js-yaml``
    reject it, so every write path is forced to the same shape.

    Forcing ``indentless=False`` aligns the two serializers so all write paths emit byte-identical layouts
    (#31999).
    c                 ó$   •— t         ‰| �  |d«      S )NF)ÚsuperÚincrease_indent)ÚselfÚflowÚ
indentlessÚ	__class__s      €r   rï   zIndentDumper.increase_indentž  s   ø€ Ü‰wÑ& t¨UÓ3Ð3r   )FF)Ú__name__Ú
__module__Ú__qualname__Ú__doc__rï   Ú__classcell__)ró   s   @r   rì   rì   “  s   ø„ ñ÷4ñ 4r   rì   )Údefault_flow_styleÚ	sort_keysÚextra_contentrº   rù   rú   rû   c          	      ó‚   ‡‡‡‡— t        | «      } dˆˆˆˆfd„}t        | |d| j                  › d�t        | |«      ¬«       y)z>Write YAML to *path* atomically (temp file + fsync + replace).Nc                 ól   •— t        j                  ‰| t        ‰‰d¬«       ‰r| j                  ‰«       y y )NT)ÚDumperrù   rú   Úallow_unicode)ÚyamlÚdumprì   r^   )rm   rd   rù   rû   rú   s    €€€€r   Ú_writez!atomic_yaml_write.<locals>._write§  s2   ø€ ô 	�	‰	�$˜¤,ÐCUÐajÐz~ÕÙØ�G‰G�MÕ"ð r   r×   rØ   ©r¦   r7   ©r   N)r   r¹   rÙ   r½   )r(   rd   rù   rú   rû   rº   r  s    ````  r   Úatomic_yaml_writer  ¢  s=   û€ ô �‹:€D÷#ð #ô �$˜¨¨4¯9©9¨+°QÐ'7¼oÈdÐT_Ó>`Öar   c                 ó,  — ddl m} ddlm}  |d¬«      }d|_        d|_        d|_        |j                  dd	d¬
«       d|_        | j                  «       r!|j                  | j                  d¬«      «      nd}|t        ||«      r|fS  ||xs i «      fS )z¦``(yaml_rt, CommentedMap)``: a ruamel round-trip loader keeping quotes/Unicode with 2-space
    indents, plus *path* loaded through it (empty map when missing/blank).r   )ÚYAML©ÚCommentedMapÚrt)ÚtypTFrÔ   rM   )ÚmappingÚsequenceÚoffsetr¡   r®   N)Úruamel.yamlr  Úruamel.yaml.commentsr	  Úpreserve_quotesrÿ   rù   rË   Úallow_duplicate_keysr+   ÚloadrÝ   r   )r(   r  r	  Úyaml_rtrd   s        r   Ú_roundtrip_loadr  ²  s‘   € õ !Ý1á�tŒn€GØ"€GÔØ €GÔØ!&€GÔØ‡N�N˜1 q°€NÔ3ð $(€GÔ Ø=A¿[¹[¼]ˆ7�<‰<˜Ÿ™°˜Ó8Ô9ÐPT€DØœJ t¨\Ô:�DÐXÐXÁÈTÊZÐUWÓ@XÐXÐXr   ©rû   z
str | Nonec                óf   ‡‡‡— dˆˆˆfd„}t        | |d| j                  › d�t        | «      ¬«       y )Nc                 óR   •— ‰j                  ‰| «       ‰r| j                  ‰«       y y rD   )r  r^   )rm   Úconfigrû   r  s    €€€r   r  z_roundtrip_dump.<locals>._writeÅ  s%   ø€ Ø�‰�V˜QÔÙØ�G‰G�MÕ"ð r   r×   rØ   r  r  )r¹   rÙ   r0   )r(   r  r  rû   r  s    ``` r   Ú_roundtrip_dumpr  Ä  s,   ú€ ÷#ô
 �$˜¨¨4¯9©9¨+°QÐ'7Ô>QÐRVÓ>WÖXr   Úkey_pathc                 ó¼  — ddl m} ddlm}m} t        | «      } ddlm}  || j                  «       t        | «      \  }}|}	 ||«      }
d}	 |
|d } |t        |	«      |«      xs |d   df\  }}||z   t        |
«      k(  r|€|	j                  |d«       n||	|<   n4|	j                  |«      }t        ||«      s|€y |«       }||	|<   |}	||z  }Œƒt        | ||«       y)aÉ  Update one dotted YAML key while preserving comments, ordering, quoting and Unicode.

    Narrower than :func:`atomic_yaml_write` on purpose: for user-edited config files where a
    single setting mutation must not disturb the rest. Still writes via temp file + atomic replace.
    ``value=None`` removes the key (a ``key: null`` leftover reads as absent everywhere but
    litters the file and diverges from whole-document writers that drop the key).
    r   r  )Ú_greedy_literal_matchÚ_split_key_pathr¨   Nr:   )r  r	  Úhermes_cli.configr  r  r   r°   r©   r±   r  rß   r]   Úpopr…   r   r  )r(   r  r   r	  r  r  r©   r  r  rA   ÚkeysÚiÚ	remainingÚsegÚconsumedÚ
next_values                   r   Úatomic_roundtrip_yaml_updater'  Í  sù   € õ 2÷
 Iä�‹:€DÝ8á˜DŸK™KÔ(Ü% dÓ+�O€GˆVØ€GÙ˜8Ó$€DØ	€AØ
Ø˜˜�Hˆ	Ù-¬d°7«m¸YÓGÒ\ÈIÐVWÉLÐZ[ÐK\‰ˆˆXØˆx‰<œ3˜t›9Ò$Øˆ}Ø—‘˜C Õ&à$�˜‘ØØ—[‘[ Ó%ˆ
Ü˜* lÔ3Øˆ}ØÙ%›ˆJØ%ˆG�C‰LØˆØ	ˆX‰ˆð! ô" �D˜' 6Õ*r   >
   ÚnÚyÚ~Únor	   Úoffr
   Únullr   Úfalsec                 óF  — ddl m}m} ddlm} t        | t        «      r/ |«       }| j                  «       D ]  \  }}t        |«      ||<   Œ |S t        | t        t        f«      r |d„ | D «       «      S t        | t        «      r| j                  «       t        v r || «      S | S )uµ   Plain Python value â†’ ruamel node: YAML 1.1-ambiguous strings force-quoted at every depth
    (a bare ``off`` inside a list reads back as ``False`` just like one at the top level).r   ©r	  ÚCommentedSeq)ÚDoubleQuotedScalarStringc              3   ó2   K  — | ]  }t        |«      –— Œ y ­wrD   )Ú	_rt_value)Ú.0Úvs     r   ú	<genexpr>z_rt_value.<locals>.<genexpr>  s   è ø€ Ò8¨QœI aŸLÑ8ùs   ‚)r  r	  r1  Úruamel.yaml.scalarstringr2  r   rß   Úitemsr4  Úlistr’   r   r   Ú_YAML11_AMBIGUOUS_WORDS)r   r	  r1  r2  ÚnodeÚkr6  s          r   r4  r4  ÿ  sŽ   € ÷ @ÝAä�%œÔÙ‹~ˆØ—K‘K“Mò 	#‰DˆAˆqÜ “lˆD�ŠGð	#àˆÜ�%œ$¤˜Ô'ÙÑ8°%Ô8Ó8Ð8Ü�%œÔ %§+¡+£-Ô3JÑ"JÙ'¨Ó.Ð.Ø€Lr   )Úextra_content_on_createÚ	new_stater>  c                óÊ  ‡‡	‡
‡‡‡— ddl mŠmŠ	 ddlm} t        | «      } ddlm}  || j                  «        || «       | j                  «        xs! | j                  d¬«      j                  «        }t        | «      \  }}dt        dt        d	t        fd
„Šd‰	dt        d	dfˆfd„Šdˆˆ	ˆ
ˆˆfd„Šd‰dt         d	dfˆfd„Š
 ‰
||«       t#        | |||r|¬«       yd¬«       y)uP  Persist a full config-state dict while preserving comments and ordering.

    THE writer for ``config.yaml`` (every production caller reaches it through
    ``hermes_cli.config.atomic_config_write``): the on-disk document is loaded through ruamel
    round-trip mode and *new_state* is merged onto it, so comments, key order, quotes, blank
    lines and readable Unicode survive. Only nodes whose value actually changed are reassigned;
    an untouched scalar or list keeps its inline comments and formatting. Keys absent from
    *new_state* are deleted ("explicit absence": ``cfg.pop(k)`` + save removes ``k`` from disk).
    ``extra_content_on_create`` (commented example blocks) is appended only when the file is
    being created â€” re-appending it on every rewrite is how the stock boilerplate replaced
    users' own comments (#92554).
    r   r0  )Ú$require_readable_config_before_writer¨   r¡   r®   rA   r   r   c                 óP   — | |k(  xr  t        | t        «      t        |t        «      u S rD   )r   r   )rA   r   s     r   Ú
_unchangedz.atomic_roundtrip_yaml_save.<locals>._unchanged*  s&   € à˜%ÑÒX¤J¨w¼Ó$=ÄÈEÔSWÓAXÐ$XÐXr   Údstrc   Nc                 ó®   •— t        |«      D ]8  \  }}|t        | «      k  r ‰| ||«       Œ| j                  t        |«      «       Œ: | t        |«      d …= y rD   )Ú	enumerater]   Úappendr4  )rD  rc   r"  r   Ú_merge_items       €r   Ú
_merge_seqz.atomic_roundtrip_yaml_save.<locals>._merge_seq.  sQ   ø€ ä! #›ò 	-‰HˆAˆuØ”3�s“8Š|Ù˜C  EÕ*à—
‘
œ9 UÓ+Õ,ð		-ð
 ”�C“‘	‰Nr   c                 óØ   •— | |   }t        |t        «      rt        |‰«      r
 ‰||«       y t        |t        «      rt        |‰«      r
 ‰||«       y  ‰||«      st        |«      | |<   y y rD   )r   rß   r:  r4  )	rD  Úkeyr   rA   r	  r1  Ú_mergerI  rC  s	       €€€€€r   rH  z/atomic_roundtrip_yaml_save.<locals>._merge_item7  sc   ø€ Ø�c‘(ˆÜ�eœTÔ"¤z°'¸<Ô'HÙ�7˜EÕ"Ü˜œtÔ$¬°G¸\Ô)JÙ�w Õ&Ù˜G UÔ+Ü  Ó'ˆC�ŠHð ,r   c                 ó´   •— |j                  «       D ]"  \  }}|| v r ‰| ||«       Œt        |«      | |<   Œ$ | D �cg c]	  }||vsŒ|‘Œ c}D ]  }| |= Œ y c c}w rD   )r9  r4  )rD  rc   rK  r   r=  rH  s        €r   rL  z*atomic_roundtrip_yaml_save.<locals>._mergeA  si   ø€ ØŸ)™)›+ò 	,‰JˆC�Ø�c‰zÙ˜C  eÕ,ä$ UÓ+��C’ð		,ð
  #Ö3˜! a¨s¢l’AÒ3ò 	ˆCØ�C‘ñ	ùÒ3s   »	AÁAr  r  )r  r	  r1  r  rA  r   r°   r©   r±   r+   rÝ   r   r  r   r   r:  rß   r  )r(   r?  r>  rA  r©   Úcreatingr  Úexistingr	  r1  rL  rH  rI  rC  s           @@@@@@r   Úatomic_roundtrip_yaml_saverP    så   ý€ ÷ @ÝFä�‹:€DÝ8á˜DŸK™KÔ(Ù(¨Ô.Ø—;‘;“=Ð ÒP¨¯©À¨Ó(H×(NÑ(NÓ(PÐ$P€HÜ'¨Ó-Ñ€GˆXðYœCð Y¬ð Y´ó Yð˜ð ¬4ð °Dõ ÷(ñ (ð�Lð ¤tð °õ ñ ˆ8�YÔÜ�D˜' 8ÑV^Ð;RÖiÐdhÖir   rÒ   c                 óz   — 	 t        j                  | «      S # t         j                  t        t        f$ r |cY S w xY w)z3Parse JSON, returning *default* on any parse error.)rÏ   rÜ   ÚJSONDecodeErrorrŸ   rÞ   )rÒ   r   s     r   Úsafe_json_loadsrS  N  s7   € ðÜ�z‰z˜$ÓÐøÜ× Ñ ¤)¬ZÐ8ò ØŠðús   ‚ — :¹:ÚCSafeLoaderÚstreamc                 ó8   — t        j                  | t        ¬«      S )zX``yaml.safe_load`` (same inputs, same result) using the libyaml C loader when available.)ÚLoader)r   r  Ú_fast_yaml_loader)rU  s    r   Úfast_safe_loadrY  \  s   € ä�9‰9�VÔ$5Ô6Ð6r   Ú_YAML_FILE_CACHEc                 óœ  — t        | «      } t        | j                  «       «      }t        | «      }t        5  t
        j                  |«      }|�|d   |k(  r|d   cddd«       S ddd«       t        | d¬«      5 }t        |«      }ddd«       t        5  |ft
        |<   ddd«       |S # 1 sw Y   ŒFxY w# 1 sw Y   Œ1xY w# 1 sw Y   S xY w)u  ``fast_safe_load`` of a file, re-parsed only when its :func:`file_signature` changes.

    Returns the cached object itself â€” callers must never mutate it. Parse errors propagate and
    are not cached; a missing file raises ``FileNotFoundError`` like ``open`` does.Nr   r:   r¡   r®   )	r   r'   r,   r   Ú_YAML_FILE_CACHE_LOCKrZ  r…   rZ   rY  )r(   ÚsigrK  Úcachedrm   rd   s         r   Úload_yaml_file_readonlyr_  e  sÉ   € ô
 �‹:€DÜ
˜Ÿ™›Ó
%€CÜ
ˆd‹)€CÜ	ñ Ü!×%Ñ% cÓ*ˆØÐ &¨¡)¨sÒ"2Ø˜!‘9÷÷ ñ ô 
ˆd˜WÔ	%ð !¨Ü˜aÓ ˆ÷!ä	ñ ,Ø!$ d Ô˜Ñ÷,à€K÷ð ú÷!ð !ú÷,à€Kús#   ¶$B)Á9B5ÂCÂ)B2Â5B>ÃCrK  c                 ó’   — t        j                  | d«      j                  «       }	 |r ||«      S |S # t        t        f$ r |cY S w xY w)Nr   )r   r   r   rÞ   rŸ   )rK  r   ÚcastÚraws       r   Ú_env_numberrc  x  sJ   € Ü
�)‰)�C˜Ó
×
"Ñ
"Ó
$€CðÙ‰t�C‹yÐ, WÐ,øÜœ	Ð"ò ØŠðús   ¦	2 °2 ²AÁAc                 ó$   — t        | |t        «      S )z:Read an environment variable as an integer, with fallback.)rc  Úint©rK  r   s     r   Úenv_intrg  €  s   € ä�s˜G¤SÓ)Ð)r   c                 ó$   — t        | |t        «      S )z7Read an environment variable as a float, with fallback.)rc  Úfloatrf  s     r   Ú	env_floatrj  …  s   € ä�s˜G¤UÓ+Ð+r   c                 óD   — t        t        j                  | d«      |¬«      S )z*Read an environment variable as a boolean.r   r   r   rf  s     r   Úenv_boolrl  Š  s   € äœ2Ÿ9™9 S¨"Ó-°wÔ?Ð?r   )ÚHTTPS_PROXYÚ
HTTP_PROXYÚ	ALL_PROXYÚhttps_proxyÚ
http_proxyÚ	all_proxyÚ	proxy_urlc                 ó¨   — t        | xs d«      j                  «       }|j                  «       j                  d«      rd|t	        d«      d › �S |xs dS )zaNormalize proxy URLs for httpx/aiohttp: WSL/Clash export ``socks://``, httpx needs ``socks5://``.r   zsocks://z	socks5://N)r   r   r   Ú
startswithr]   )rs  rš   s     r   Únormalize_proxy_urlrv  ’  sS   € ä�I’O Ó$×*Ñ*Ó,€IØ‡�Ó×#Ñ# JÔ/Ø˜9¤S¨£_Ð%5Ð6Ð7Ð8Ð8ØÒ˜Ðr   c                  ó”   — t         D ]?  } t        j                  | d«      }t        |«      }|sŒ'||k7  sŒ-|t        j                  | <   ŒA y)zARewrite supported proxy env vars to canonical URL forms in-place.r   N)Ú_PROXY_ENV_KEYSr   r   rv  Úenviron)rK  r   Ú
normalizeds      r   Únormalize_proxy_env_varsr{  š  sB   € äò )ˆÜ—	‘	˜#˜rÓ"ˆÜ(¨Ó/ˆ
Ú˜*¨Ó-Ø(ŒB�J‰J�sŠOñ	)r   Úbase_urlc                 ób   — | xs dj                  «       }|rt        d|v r|«      S d|› �«      S dS )zF``urlparse`` that tolerates a bare ``host[:port][/path]`` (no scheme).r   z://z//N)r   r   )r|  rb  s     r   Ú_parse_base_urlr~  £  s:   € àŠ>�r×
 Ñ
 Ó
"€CÙ<?Œ8˜5 C™<�CÓ8ÐI¨r°#°¨ZÓ8ÐIÀTÐIr   c                 ód   — | r-| j                   xs dj                  «       j                  d«      S dS )Nr   r×   )Úhostnamer   Úrstrip)Úparseds    r   Ú_hostname_ofrƒ  ©  s,   € Ù:@ˆF�O‰OÒ!˜r×(Ñ(Ó*×1Ñ1°#Ó6ÐHÀbÐHr   c                 ó*   — t        t        | «      «      S )a@  Lowercased hostname for a base URL, or ``""`` if absent.

    Compare exact hostnames against provider hosts instead of substring-matching the raw URL:
    ``https://api.openai.com.example/v1`` or ``https://proxy.test/api.openai.com/v1`` would
    otherwise pass as native endpoints and mis-route api_mode and auth.
    )rƒ  r~  )r|  s    r   Úbase_url_hostnamer…  ­  s   € ô œ¨Ó1Ó2Ð2r   c                 ór   — t        | «      }|r|j                  ndj                  «       j                  d«      S )z©Lowercased URL path without the trailing slash (``""`` for a bare host); same scheme
    tolerance as :func:`base_url_hostname` so host and path checks agree on one URL.r   ú/)r~  r(   r   r�  )r|  r‚  s     r   Úbase_url_pathrˆ  ·  s0   € ô ˜XÓ&€FÙ!ˆF�KŠK r×0Ñ0Ó2×9Ñ9¸#Ó>Ð>r   Úmodelc                 óŽ   — | xs dj                  «       j                  «       j                  dd«      d   }|j                  d«      S )zYTrue for OpenAI families that reject ``max_tokens`` (HTTP 400 ``unsupported_parameter``).r   r‡  r:   éÿÿÿÿ)zgpt-4ozgpt-4.1zgpt-5Úo1Úo3Úo4)r   r   Úrsplitru  )r‰  Úms     r   Ú"model_forces_max_completion_tokensr‘  ¾  s?   € à	Š�"×ÑÓ×#Ñ#Ó%×,Ñ,¨S°!Ó4°RÑ8€AØ�<‰<ÐHÓIÐIr   c                 óâ   — t        | «      }t        |«      }|sy|j                  xs dj                  «       }	 |j                  }|||€dddœj                  |d«      fS |fS # t
        $ r Y yw xY w)u   ``(scheme, hostname, effective_port)`` for a base URL; ``("", "", 0)`` on no host/bad port.

    Origin, not just host: ``https://h`` vs ``http://h`` and two ports on one host are different
    trust boundaries, so handing a bearer secret to a new URL must compare all three â€” hostname
    alone would authorise an HTTPSâ†’HTTP downgrade. Port defaults to 443/80 so ``https://h``
    equals ``https://h:443``.
    )r   r   r   r   i»  éP   )ÚhttpsÚhttpr   )r~  rƒ  Úschemer   ÚportrÞ   r…   )r|  r‚  r€  r–  r—  s        r   Úbase_url_originr˜  Ä  s…   € ô ˜XÓ&€FÜ˜FÓ#€HÙØØ�m‰mÒ!˜r×(Ñ(Ó*€FðØ�{‰{ˆð �HÈ4È<¨°RÑ8×<Ñ<¸VÀQÓGÐbÐbÐ]aÐbÐbøô ò Ùðús   ¹A" Á"	A.Á-A.Údomainc                 óÒ   — t        | «      }|xs dj                  «       j                  «       j                  d«      }t	        |xr |«      xr ||k(  xs |j                  d|z   «      S )zåTrue when the base URL's hostname is ``domain`` or a subdomain.

    Safer than ``domain in base_url`` (``evil.com/moonshot.ai`` / ``moonshot.ai.evil`` must not
    match). Accepts bare hosts, full URLs, and URLs with paths.
    r   r×   )r…  r   r   r�  r   Úendswith)r|  r™  r€  s      r   Úbase_url_host_matchesrœ  Ø  se   € ô ! Ó*€HØŠl˜×!Ñ!Ó#×)Ñ)Ó+×2Ñ2°3Ó7€FÜ�Ò#˜VÓ$Ò`¨(°fÑ*<Ò*_À×@QÑ@QÐRUÐX^ÑR^Ó@_Ð`r   )F)r   )r   r)   )TrD   )r   )g        r  )dr÷   ry   rÏ   Úloggingr   ri   r,   r²   Ú	threadingr~   Ú
contextlibr   Úpathlibr   Útypingr   r   Úurllib.parser   r   Ú	getLoggerrô   r‚   Ú	frozensetr   r   r   r   r    Ústat_resultr'   r0   r5   r=   rB   rF   rH   r   rQ   rS   r}   r€   r�   ÚEXDEVÚEBUSYrz   r/   rT   rg   rn   rŠ   rŽ   r    r¹   r½   rÇ   ÚbytesrÊ   rß   rÓ   re  rÚ   rà   ÚLoggerrê   Ú
SafeDumperrì   r  r  r  r'  r;  r4  rP  rS  rR   Ú
SafeLoaderrX  rY  rZ  Ú__annotations__ÚLockr\  r_  rc  rg  ri  rj  rl  rx  rv  r{  r~  rƒ  r…  rˆ  r‘  r’   r˜  rœ  © r   r   ú<module>r¯     s  ðÚ 0ã Û Û Û 	Û Û Û Û Û Ý Ý ß Ý !ã à	ˆ×	Ñ	˜8Ó	$€ñ Ò5Ó6€ñ˜3ð ¨ð ¸$ó ñD˜#ð D¨ð D°Tó Dð
	C�r—~‘~ð 	CÐ*Eó 	Cð˜dð  |ó ð2˜tð 2Ð(@ó 2ð! ð !Ð.Fð !Èlð !Ð_có !ó ð&.˜dð .Ð+Cð .Èó .ð-˜Tð -¨ð -¸$ó -ð �g‰g˜‰o€ñ %.ªkÓ$:Ð !ð Ð Ø"Ð Ø Ð ØŸ™ U§[¡[Ð1Ð ð_¨Wð _¸ó _ð
˜sð ¨sð °tó ð,˜Cð ¨Cð °Dó ð'˜U 3¨ 9Ñ-ð '°u¸SÀ$¸YÑ7Gð 'ÈCó 'ðT˜%  T 	Ñ*ð ¨tó ð( FKò  ˜%  T 	Ñ*ð  ¸dð  Ètó  ðF FMÐcgØ)-¸eÐW\ò(˜ð (°ð (¸sð (ÐT`ð (Ø"&ð(Ø7;ð(ØPTð(Øaeó(ñVF˜$ð F¨\ð FÀTð FÐUaó Fð PWÐjqØ,1ÈtÐjnØ(-òE˜E # t )Ñ,ð E°sð EÈð EÐdgð EØ%)ðEØ@LðEØ[gðEà!%ðEà26óEð  U\Ø,0ÀEòe˜U 3¨ 9Ñ-ð e¸ð eÈcð eØ)ðeØ=AðeØNRóeðS�Sð S¨ð SÀDð SÐW[ð SÐ`dó Sð$ 9:ÈdØ°%ò'Ø
��T�	Ñ
ð'Ø"%ð'Ø25ð'ØADÀtÁð'àð'à+/ð'àHKð'ð 
ó'ð"	2˜U 3¨ 9Ñ-ð 	2°$ó 	2ð VXÐvzò °5¸¸d¸Ñ3Cð Èsð Ð^e×^lÑ^lÐosÑ^sð ð  @Dó ô(4�4—?‘?ô 4ð X]ÐpuØ26ÐTXòb˜E # t )Ñ,ð b°Cð bÐPTð bÐimð bØ%(¨4¡ZðbØEQðbØ]aóbð Y˜$ó Yð$ SWò Y˜$ð YÀ<ð YÐ[_ó Yð(+ u¨S°$¨YÑ'7ð (+À3ð (+Èsð (+ÐW[ó (+ñ^ $Ò$fÓgÐ ð�Sð ˜Só ð& HLò:j U¨3°¨9Ñ%5ð :jÀ$ð :jØ8Dð:jØPTó:jñz˜#ð ¨ð °só ñ ˜D -°Ó6ÒI¸$¿/¹/Ð ð7˜3ð 7 3ó 7ð
 Ð �$Ó Ø&˜	Ÿ™Ó(Ð ð %¨¨T¨	Ñ"2ð °só ð&�Só ñ*�ð *˜sð *¨3ó *ñ
,�3ð , ð ,°ó ,ñ
@�#ð @ ð @°ó @ð
 g€ð 3¨¡:ð °#¸±*ó ó)ðJ˜có JðI˜Có Ið3 ð 3¨ó 3ð?˜Cð ? Có ?ðJ¨cð J°dó Jðc˜cð c e¨C°°c¨MÑ&:ó cð(a Cð a°ð a¸ô ar   