§
    êÂjå1  ã                  óô  — 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m	Z	m
Z
mZ ddlmZ ddlmZmZmZmZ  eej        d¦  «        rej                             d¬	¦  «          eej        d¦  «        rej                             d¬	¦  «          ee¦  «                             ¦   «         j        j        j        Zed
z  dz  Zedz  dz  dz  Zedz  dz  dz  Zedz  dz  dz  Zedz  Zedz  dz  dz  Z g d¢Z! ej"        d¦  «        Z#e
 G d„ d¦  «        ¦   «         Z$e
 G d„ d¦  «        ¦   «         Z%d9d„Z&d:d!„Z'd;d$„Z(d<d&„Z)d=d*„Z*d>d-„Z+d?d0„Z,d@d5„Z-dAd7„Z.e/d8k    r ej0         e.¦   «         ¦  «         dS dS )Ba"  
FREEEXILE I18N HYGIENE & ANTI-REGRESSION STATIC LINTER
Validates zero unlocalized UI strings, 9-language catalog parity,
and dangling key resolution across client templates and markup.

Rules Enforced:
- Rule 1: Zero hardcoded Vietnamese diacritics in UI code (allow comments & fallback params).
- Rule 2: 100% 9-language dictionary parity for i18n and chat catalogs.
- Rule 3: Resolution of all data-i18n / data-chat-i18n template keys against master catalogs.

Usage:
    python tools/lint/check_i18n_hygiene.py [--strict] [--json-out <path>]
é    )ÚannotationsN)ÚasdictÚ	dataclassÚfield)ÚPath)ÚDictÚListÚSetÚTupleÚreconfigureúutf-8©ÚencodingÚclientÚwebappÚjsÚuiz
chat_ui.jsÚdatazchat_i18n_catalog.jszi18n_catalog.jsz
index.htmlÚ	templates)	ÚviÚenÚzhÚjaÚkoÚthÚdeÚruÚesz[\u00C0-\u1EF9]c                  óP   — e Zd ZU ded<   ded<   ded<   ded<   ded<   dZded	<   d
S )ÚLintViolationÚstrÚrule_idÚseverityÚ	file_pathÚintÚline_numberÚmessageÚ ÚsnippetN)Ú__name__Ú
__module__Ú__qualname__Ú__annotations__r)   © ó    ú6C:\Projects\FreeExile\tools\lint\check_i18n_hygiene.pyr    r    -   sS   € € € € € € à€L€L�LØ€M€M�MØ€N€N�NØÐÐÑØ€L€L�LØ€GÐÐÐÑÐÐr/   r    c                  óœ   — e Zd ZU dZded<    ee¬¦  «        Zded<    ee¬¦  «        Zded<    ee¬¦  «        Z	ded<   e
dd
„¦   «         ZdS )ÚLintSummaryr   r%   Útotal_files_scanned)Údefault_factoryúList[LintViolation]Úrule1_violationsÚrule2_violationsÚrule3_violationsÚreturnc                ó~   — t          | j        ¦  «        t          | j        ¦  «        z   t          | j        ¦  «        z   S )N)Úlenr6   r7   r8   )Úselfs    r0   Útotal_errorszLintSummary.total_errors>   s=   € õ �Ô%Ñ&Ô&Ý�$Ô'Ñ(Ô(ñ)å�$Ô'Ñ(Ô(ñ)ð	
r/   N©r9   r%   )r*   r+   r,   r3   r-   r   Úlistr6   r7   r8   Úpropertyr=   r.   r/   r0   r2   r2   7   s£   € € € € € € à ÐÐ Ð Ð Ñ Ø,1¨EÀ$Ð,GÑ,GÔ,GÐÐGÐGÐGÑGØ,1¨EÀ$Ð,GÑ,GÔ,GÐÐGÐGÐGÑGØ,1¨EÀ$Ð,GÑ,GÔ,GÐÐGÐGÐGÑGàð
ð 
ð 
ñ „Xð
ð 
ð 
r/   r2   Úcontentr!   r9   c                óz   — d
d„}t          j        d|| ¦  «        }t          j        dd|t           j        ¬	¦  «        S )zNRemoves JS single-line and multi-line comments while maintaining line indices.Úmúre.Match[str]r9   r!   c                óX   — d|                       d¦  «                             d¦  «        z  S ©Nú
r   ©ÚgroupÚcount©rC   s    r0   Ú
block_replz1strip_comments_preserve_lines.<locals>.block_replI   s%   € Ø�a—g’g˜a‘j”j×&Ò& tÑ,Ô,Ñ,Ð,r/   z/\*[\s\S]*?\*/z//.*$r(   )Úflags)rC   rD   r9   r!   )ÚreÚsubÚ	MULTILINE)rA   rL   Úcleaneds      r0   Ústrip_comments_preserve_linesrR   G   sG   € ð-ð -ð -ð -õ ŒfÐ&¨
°GÑ<Ô<€GÝŒ6�(˜B ­r¬|Ð<Ñ<Ô<Ð<r/   Útarget_filer   r5   c                óš  — g }|                       ¦   «         s|S |                      d¬¦  «        }t          |¦  «        }t          j        dd„ |¦  «        }t          j        dd|¦  «        }|                     d¦  «        }t          |d¬	¦  «        D ]¹\  }}t          j        d
|¦  «        D ]ž}|                     d¦  «        }	t           
                    |	¦  «        rmt          |                      t          ¦  «        ¦  «        }
|                     t          dd|
|d|	› d�|                     ¦   «         dd…         ¬¦  «        ¦  «         ŒŸŒº|S )z[Rule 1: Scans UI JS code for unlocalized Vietnamese strings outside allowlisted structures.r   r   zeexport\s+const\s+(?:CHANNELS|RARITY_INFO|ELEMENT_NAMES|CHANNEL_I18N|RARITY_NAMES)\s*=\s*\{[\s\S]*?\};c                óX   — d|                       d¦  «                             d¦  «        z  S rF   rH   rK   s    r0   ú<lambda>z2check_rule1_hardcoded_vietnamese.<locals>.<lambda>\   s#   € �$˜Ÿš ™œ×)Ò)¨$Ñ/Ô/Ñ/€ r/   zE\bt\s*\(\s*['\"][^'\"]+['\"]\s*,\s*[^,]+,\s*['\"`][^'\"`]*['\"`]\s*\)zt_allowlisted_call()rG   é   ©Ústartz['\"`]([^'\"`]+)['\"`]zRULE-1-HARDCODED-VIÚERRORz'Hardcoded Vietnamese string detected: 'ú'Néd   )r"   r#   r$   r&   r'   r)   )ÚexistsÚ	read_textrR   rN   rO   ÚsplitÚ	enumerateÚfinditerrI   ÚVI_DIACRITICS_REGEXÚsearchr!   Úrelative_toÚPROJECT_ROOTÚappendr    Ústrip)rS   Ú
violationsÚraw_textÚstrippedÚmaskedÚlinesÚline_idxÚlineÚlit_mÚliteral_valÚrel_paths              r0   Ú check_rule1_hardcoded_vietnameserr   P   st  € à&(€JØ×ÒÑÔð ØÐà×$Ò$¨gÐ$Ñ6Ô6€HÝ,¨XÑ6Ô6€Hõ ŒVØpØ/Ð/Øñô €Fõ ŒVØPØØñô €Fð �LŠL˜ÑÔ€EÝ# E°Ð3Ñ3Ô3ð ð ‰ˆ�$Ý”[Ð!:¸DÑAÔAð 	ð 	ˆEØŸ+š+ a™.œ.ˆKÝ"×)Ò)¨+Ñ6Ô6ð Ý˜{×6Ò6µ|ÑDÔDÑEÔE�Ø×!Ò!Ý!Ø 5Ø!(Ø"*Ø$,Ø XÈ+Ð XÐ XÐ XØ $§
¢
¡¤¨T¨c¨TÔ 2ðñ ô ñ	ô 	ð 	øð		ð Ðr/   Úcatalog_pathúDict[str, Set[str]]c                óè  — |                       ¦   «         sd„ t          D ¦   «         S |                      d¬¦  «        }t          |¦  «        }i }t          D �]}t	          j        d|› d�|¦  «        }|sŒ|                     ¦   «         }d}|}|t          |¦  «        k     rG|dk    rA||         dk    r|dz  }n||         d	k    r|dz  }|dz  }|t          |¦  «        k     r|dk    °A||dz
  |…         }	t          ¦   «         }
t	          j	        d
¦  «        }| 
                    |	¦  «        D ]A}|                     d¦  «        p|                     d¦  «        }|
                     |¦  «         ŒB|
||<   �Œ|S )zMExtracts localized key sets for all 9 locales from a JavaScript catalog file.c                ó,   — i | ]}|t          ¦   «         “ŒS r.   )Úset)Ú.0Úlocs     r0   ú
<dictcomp>z&parse_catalog_keys.<locals>.<dictcomp>|   s   € Ð4Ð4Ð4˜s�•S‘U”UÐ4Ð4Ð4r/   r   r   z\bz	\s*:\s*\{rW   r   Ú{Ú}z?(?:[{,]\s*)\s*(?:["\']([a-zA-Z0-9_]+)["\']|([a-zA-Z0-9_]+))\s*:é   )r]   ÚALL_9_LOCALESr^   rR   rN   rc   Úendr;   rw   Úcompilera   rI   Úadd)rs   Úraw_contentrA   Úresultry   rC   Ú	start_idxÚbracesÚcurrÚblockÚkeysÚ	entry_patÚentry_mÚks                 r0   Úparse_catalog_keysrŒ   y   s£  € à×ÒÑ Ô ð 5Ø4Ð4¥mÐ4Ñ4Ô4Ð4à×(Ò(°'Ð(Ñ:Ô:€KÝ+¨KÑ8Ô8€GØ"$€Fåð ñ ˆÝŒIÐ+˜CÐ+Ð+Ð+¨WÑ5Ô5ˆØð 	ØØ—E’E‘G”Gˆ	ØˆØˆØ•S˜‘\”\Ò!Ð! f¨q¢j jØ�tŒ} Ò#Ð#Ø˜!‘��Ø˜” #Ò%Ð%Ø˜!‘�Ø�A‰IˆDð •S˜‘\”\Ò!Ð! f¨q¢j jð ˜	 A™¨Ð,Ô-ˆÝ™œˆÝ”JØNñ
ô 
ˆ	ð !×)Ò)¨%Ñ0Ô0ð 	ð 	ˆGØ—’˜aÑ Ô Ð4 G§M¢M°!Ñ$4Ô$4ˆAØ�HŠH�Q‰KŒKˆKˆKØˆˆs‰‰à€Mr/   Úcatalog_namec                óz  — g }t          | ¦  «        }t          |                      t          ¦  «        ¦  «        }t          D ]L}||vst          ||         ¦  «        dk    r-|                     t          dd|d|› d|› d�¬¦  «        ¦  «         ŒM|                     dt          ¦   «         ¦  «        }d	„ t          D ¦   «         D ]ú}|                     |t          ¦   «         ¦  «        }||z
  }||z
  }	|rdt          t          |¦  «        ¦  «        d
d…         }
|                     t          dd|d|› d|› dt          |¦  «        › d|
› d�¬¦  «        ¦  «         |	rdt          t          |	¦  «        ¦  «        d
d…         }
|                     t          dd|d|› d|› dt          |	¦  «        › d|
› d�¬¦  «        ¦  «         Œû|S )zNRule 2: Enforces symmetric 1-to-1 key parity across all 9 supported languages.r   zRULE-2-DICT-PARITYrZ   rW   z: Missing locale dictionary 'r[   ©r"   r#   r$   r&   r'   r   c                ó   — g | ]
}|d k    ¯|‘ŒS )r   r.   )rx   Úls     r0   ú
<listcomp>z1check_rule2_dictionary_parity.<locals>.<listcomp>±   s   € Ð6Ð6Ð6�a¨A°ªI¨I�¨I¨I¨Ir/   Né   z
: Locale 'z
' missing z keys (e.g. ú)z' has z extra keys not in 'vi' (e.g. )rŒ   r!   rd   re   r~   r;   rf   r    Úgetrw   Úsortedr?   )rs   r�   rh   Úkeys_by_localerq   ry   Úvi_keysÚloc_keysÚmissing_in_locÚextra_in_locÚsamples              r0   Úcheck_rule2_dictionary_parityr�   �   s/  € à&(€JÝ'¨Ñ5Ô5€NÝ�<×+Ò+­LÑ9Ô9Ñ:Ô:€Hõ ð 
ð 
ˆØ�nÐ$Ð$­¨N¸3Ô,?Ñ(@Ô(@ÀAÒ(EÐ(EØ×ÒÝØ0Ø$Ø&Ø !Ø+ÐPÐPÈ#ÐPÐPÐPðñ ô ñô ð øð × Ò  ¥s¡u¤uÑ-Ô-€GØ6Ð6�=Ð6Ñ6Ô6ð ð ˆØ!×%Ò% c­3©5¬5Ñ1Ô1ˆØ  8Ñ+ˆØ 'Ñ)ˆàð 
	Ý�D Ñ0Ô0Ñ1Ô1°"°1°"Ô5ˆFØ×ÒÝØ0Ø$Ø&Ø !Ø+ÐpÐp°sÐpÐpÅcÈ.ÑFYÔFYÐpÐpÐgmÐpÐpÐpðñ ô ñô ð ð ð 
	Ý�D Ñ.Ô.Ñ/Ô/°°°Ô3ˆFØ×ÒÝØ0Ø$Ø&Ø !Ø+Ð|Ð|°sÐ|Ð|Å#ÀlÑBSÔBSÐ|Ð|ÐsyÐ|Ð|Ð|ðñ ô ñô ð øð Ðr/   Ú
target_dirÚ
index_fileúList[Tuple[str, str, int]]c                ó¸  — g }|g}|                       ¦   «         r5|                     t          |                      d¦  «        ¦  «        ¦  «         |D �]}|                      ¦   «         sŒt	          |                     t          ¦  «        ¦  «        }|                     d¬¦  «        }|                     d¦  «        }t          |d¬¦  «        D ]‹\  }}	t          j        d|	¦  «        D ]-}
|                     |
                     d¦  «        ||f¦  «         Œ.t          j        d|	¦  «        D ]-}
|                     |
                     d¦  «        ||f¦  «         Œ.ŒŒ�Œ	|S )	zOExtracts data-i18n, data-chat-i18n, and key attributes from HTML and templates.z*.jsr   r   rG   rW   rX   z3data-(?:chat-)?i18n(?:-[a-z]+)?=[\"']([^\"']+)[\"']zSdata-(?:tooltip-(?:title|desc)-key|i18n-tooltip-(?:title|desc))=[\"']([^\"']+)[\"'])r]   Úextendr–   Úglobr!   rd   re   r^   r_   r`   rN   ra   rf   rI   )rž   rŸ   Ú
referencesÚfiles_to_scanÚfpathrq   rA   rl   Úline_norn   rC   s              r0   Ú extract_template_referenced_keysr¨   Ï   sq  € à-/€JØ�L€MØ×ÒÑÔð >Ø×Ò�V J§O¢O°FÑ$;Ô$;Ñ<Ô<Ñ=Ô=Ð=àð 
Cñ 
CˆØ�|Š|‰~Œ~ð 	ØÝ�u×(Ò(­Ñ6Ô6Ñ7Ô7ˆØ—/’/¨7�/Ñ3Ô3ˆØ—’˜dÑ#Ô#ˆÝ& u°AÐ6Ñ6Ô6ð 	Cð 	C‰MˆG�TÝ”[Ð!WÐY]Ñ^Ô^ð Cð C�Ø×!Ò! 1§7¢7¨1¡:¤:¨x¸Ð"AÑBÔBÐBÐBÝ”[Ð!wÐy}Ñ~Ô~ð Cð C�Ø×!Ò! 1§7¢7¨1¡:¤:¨x¸Ð"AÑBÔBÐBÐBðCñ	Cð
 Ðr/   Úall_defined_keysúSet[str]c                ó®   — g }t          t          t          ¦  «        }|D ]5\  }}}|| vr+|                     t	          dd||d|› d�¬¦  «        ¦  «         Œ6|S )zVRule 3: Detects dangling key references in HTML and templates not present in catalogs.zRULE-3-DANGLING-KEYrZ   zReferenced i18n key 'z' not defined in any catalogr�   )r¨   ÚTEMPLATES_DIRÚ
INDEX_HTMLrf   r    )r©   rh   Úreferenced_keysÚkey_namer¦   r§   s         r0   Úcheck_rule3_missing_keysr°   ä   s…   € à&(€JÝ6µ}ÅjÑQÔQ€Oà$3ð 
ð 
Ñ ˆ�%˜ØÐ+Ð+Ð+Ø×ÒÝØ1Ø$Ø#Ø 'ØZ°HÐZÐZÐZðñ ô ñô ð øð Ðr/   Útarget_modulesú
List[Path]c                ó”  — t          ¦   «         }t          | ¦  «        dz   |_        | D ]+}t          |¦  «        }|j                             |¦  «         Œ,t          t          d¦  «        }t          t          d¦  «        }|j	                             |¦  «         |j	                             |¦  «         t          t          ¦  «                             dt          ¦   «         ¦  «        }t          t          ¦  «                             dt          ¦   «         ¦  «        }||z  }t          |¦  «        }	|j                             |	¦  «         |S )z@Orchestrates all three rules and compiles complete lint summary.é   ÚCHAT_I18N_CATALOGÚI18N_CATALOGr   )r2   r;   r3   rr   r6   r¢   r�   ÚCHAT_CATALOG_JSÚI18N_CATALOG_JSr7   rŒ   r•   rw   r°   r8   )
r±   ÚsummaryÚmodÚv1Úv2_chatÚv2_i18nÚ	chat_keysÚ	i18n_keysÚall_definedÚv3s
             r0   Ú	run_auditrÂ   ÷   s  € å‰mŒm€GÝ"% nÑ"5Ô"5¸Ñ"9€GÔð ð ,ð ,ˆÝ-¨cÑ2Ô2ˆØÔ ×'Ò'¨Ñ+Ô+Ð+Ð+õ ,­OÐ=PÑQÔQ€GÝ+­O¸^ÑLÔL€GØÔ×#Ò# GÑ,Ô,Ð,ØÔ×#Ò# GÑ,Ô,Ð,õ #¥?Ñ3Ô3×7Ò7¸½c¹e¼eÑDÔD€IÝ"¥?Ñ3Ô3×7Ò7¸½c¹e¼eÑDÔD€IØ˜iÑ'€KÝ	! +Ñ	.Ô	.€BØÔ×#Ò# BÑ'Ô'Ð'à€Nr/   r¹   ÚstrictÚboolÚNonec                ó  — t          d¦  «         t          d¦  «         t          d¦  «         t          d| j        › �¦  «         t          dt          | j        ¦  «        › �¦  «         t          dt          | j        ¦  «        › �¦  «         t          dt          | j        ¦  «        › �¦  «         t          d¦  «         | j        | j        z   | j        z   }|r‚|D ]O}t          d|j        › d	|j        › d
|j        › d|j	        › �¦  «         |j
        rt          d|j
        › �¦  «         ŒPt          d¦  «         t          dt          |¦  «        › d�¦  «         nt          d¦  «         t          d¦  «         t          d¦  «         dS )z>Formats and prints the human-readable audit report to console.zP================================================================================z5FREEEXILE I18N HYGIENE & ANTI-REGRESSION AUDIT REPORTz [*] Total Target Files Scanned: z3[*] Rule 1 (Zero Hardcoded VI Strings) Violations: z3[*] Rule 2 (9-Language Parity) Violations        : z3[*] Rule 3 (Missing / Dangling Keys) Violations  : zP--------------------------------------------------------------------------------u     â�Œ [z] ú:z - z     Snippet: zFAILED: Found z' internationalization hygiene error(s).uD   âœ… SUCCESS: 100% i18n hygiene compliance. All rules passed cleanly!N)Úprintr3   r;   r6   r7   r8   r"   r$   r&   r'   r)   )r¹   rÃ   Úall_vÚvs       r0   Úprint_reportrË     s¡  € å	ˆ(�O„O€OÝ	Ð
AÑBÔBÐBÝ	ˆ(�O„O€OÝ	Ð
J¨WÔ-HÐ
JÐ
JÑKÔKÐKÝ	Ð
_ÅÀGÔD\Ñ@]Ô@]Ð
_Ð
_Ñ`Ô`Ð`Ý	Ð
_ÅÀGÔD\Ñ@]Ô@]Ð
_Ð
_Ñ`Ô`Ð`Ý	Ð
_ÅÀGÔD\Ñ@]Ô@]Ð
_Ð
_Ñ`Ô`Ð`Ý	ˆ(�O„O€Oð 	Ô Ø
Ô
"ñ	#à
Ô
"ñ	#ð 
ð
 ð 	VØð 	4ð 	4ˆAÝÐT˜AœIÐTÐT¨¬ÐTÐT°q´}ÐTÐTÈÌÐTÐTÑUÔUÐUØŒyð 4ÝÐ2 q¤yÐ2Ð2Ñ3Ô3Ð3øÝˆh‰ŒˆÝÐR�s 5™zœzÐRÐRÐRÑSÔSÐSÐSåˆh‰ŒˆÝÐTÑUÔUÐUÝ	ˆ(�O„O€O€O€Or/   r%   c                 ó  — t          j        d¬¦  «        } |                      ddd¬¦  «         |                      dt          dd	¬
¦  «         |                      ddt          t          ¦  «        gd¬¦  «         |                      ¦   «         }d„ |j        D ¦   «         }t          |¦  «        }t          ||j	        ¦  «         |j
        r­t          |j
        ¦  «        }|j                             dd¬¦  «         |j        |j        d„ |j        D ¦   «         d„ |j        D ¦   «         d„ |j        D ¦   «         dœ}|                     t)          j        |dd¬¦  «        d¬¦  «         t-          d|› �¦  «         |j	        r|j        dk    rdS dS )Nz-FreeExile i18n Hygiene & Parity Static Linter)Údescriptionz--strictÚ
store_truezExit code 1 on any violation)ÚactionÚhelpz
--json-outr(   zPath to write JSON report)ÚtypeÚdefaultrÐ   z--target-filesÚ*z-Target UI JavaScript files to scan for Rule 1)ÚnargsrÒ   rÐ   c                óP   — g | ]#}t          |¦  «                             ¦   «         ‘Œ$S r.   )r   Úresolve)rx   Úps     r0   r’   zmain.<locals>.<listcomp>:  s(   € Ð<Ð<Ð< Q�t�A‰wŒw�ŠÑ Ô Ð<Ð<Ð<r/   T)ÚparentsÚexist_okc                ó,   — g | ]}t          |¦  «        ‘ŒS r.   ©r   ©rx   rÊ   s     r0   r’   zmain.<locals>.<listcomp>D  ó   € ÐBÐBÐB A•f˜Q‘i”iÐBÐBÐBr/   c                ó,   — g | ]}t          |¦  «        ‘ŒS r.   rÛ   rÜ   s     r0   r’   zmain.<locals>.<listcomp>E  rÝ   r/   c                ó,   — g | ]}t          |¦  «        ‘ŒS r.   rÛ   rÜ   s     r0   r’   zmain.<locals>.<listcomp>F  rÝ   r/   )r3   r=   Úrule1Úrule2Úrule3r}   F)ÚindentÚensure_asciir   r   z[*] JSON report written to: r   rW   )ÚargparseÚArgumentParserÚadd_argumentr!   Ú
CHAT_UI_JSÚ
parse_argsÚtarget_filesrÂ   rË   rÃ   Újson_outr   ÚparentÚmkdirr3   r=   r6   r7   r8   Ú
write_textÚjsonÚdumpsrÈ   )ÚparserÚargsÚtargetsr¹   Úout_pathÚreport_datas         r0   Úmainrö   .  s·  € ÝÔ$Ð1`ÐaÑaÔa€FØ
×Ò˜
¨<Ð>\ÐÑ]Ô]Ð]Ø
×Ò˜­3¸ÐA\ÐÑ]Ô]Ð]Ø
×ÒØØÝ•Z‘”Ð!Ø<ð	 ñ ô ð ð ×ÒÑÔ€Dà<Ð<¨$Ô*;Ð<Ñ<Ô<€GÝ˜Ñ Ô €GÝ�˜$œ+Ñ&Ô&Ð&à„}ð 9Ý˜œÑ&Ô&ˆØŒ×Ò d°TÐÑ:Ô:Ð:à#*Ô#>Ø#Ô0ØBÐB¨Ô)AÐBÑBÔBØBÐB¨Ô)AÐBÑBÔBØBÐB¨Ô)AÐBÑBÔBð
ð 
ˆð 	×Ò�DœJ {¸1È5ÐQÑQÔQÐ\cÐÑdÔdÐdÝÐ7¨XÐ7Ð7Ñ8Ô8Ð8à„{ð �wÔ+¨aÒ/Ð/ØˆqØˆ1r/   Ú__main__)rA   r!   r9   r!   )rS   r   r9   r5   )rs   r   r9   rt   )rs   r   r�   r!   r9   r5   )rž   r   rŸ   r   r9   r    )r©   rª   r9   r5   )r±   r²   r9   r2   )r¹   r2   rÃ   rÄ   r9   rÅ   r>   )1Ú__doc__Ú
__future__r   rå   rï   ÚosrN   ÚsysÚdataclassesr   r   r   Úpathlibr   Útypingr   r	   r
   r   ÚhasattrÚstdoutr   ÚstderrÚ__file__rÖ   rì   re   Ú
CLIENT_DIRrè   r·   r¸   r­   r¬   r~   r€   rb   r    r2   rR   rr   rŒ   r�   r¨   r°   rÂ   rË   rö   r*   Úexitr.   r/   r0   ú<module>r     s  ððð ð #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø 	€	€	€	Ø 	€	€	€	Ø 
€
€
€
Ø 0Ð 0Ð 0Ð 0Ð 0Ð 0Ð 0Ð 0Ð 0Ð 0Ø Ð Ð Ð Ð Ð Ø )Ð )Ð )Ð )Ð )Ð )Ð )Ð )Ð )Ð )Ð )Ð )ð €7ˆ3Œ:�}Ñ%Ô%ð -Ø„J×Ò GÐÑ,Ô,Ð,Ø
€7ˆ3Œ:�}Ñ%Ô%ð -Ø„J×Ò GÐÑ,Ô,Ð,àˆt�H‰~Œ~×%Ò%Ñ'Ô'Ô.Ô5Ô<€Ø˜HÑ$ xÑ/€
Ø˜$Ñ Ñ%¨Ñ4€
Ø˜tÑ# fÑ,Ð/EÑE€Ø˜tÑ# fÑ,Ð/@Ñ@€Ø˜,Ñ&€
Ø˜TÑ! DÑ(¨;Ñ6€àFÐFÐF€Ø �b”jÐ!3Ñ4Ô4Ð ð ðð ð ð ð ñ ô ñ „ðð ð
ð 
ð 
ð 
ð 
ñ 
ô 
ñ „ð
ð=ð =ð =ð =ð&ð &ð &ð &ðR!ð !ð !ð !ðH/ð /ð /ð /ðdð ð ð ð*ð ð ð ð&ð ð ð ð4ð ð ð ð:ð ð ð ðD ˆzÒÐØ€C„HˆTˆT‰VŒVÑÔÐÐÐð Ðr/   