+
    KiXB  c                   sf   ^ RI t ^ RIt^ RIHtHtHtHt ^ RIHt ^ RI	H
t
HtHt ^ RIHt ^ RIHt ^ RIHtHtHtHtHtHtHtHtHtHt ^ RIHt ^ R	IHtH t  ^ R
I!H"t"H#t#H$t$ ]%! . RO4      t&]&]%! RR.4      ,          ]%! RR.4      ,
          t'R R lt( ! R R4      t) ! R R])4      t* ! R R])4      t+R# )i    N)AnyCallableOptionalSet)games)get_game_ids_for_categoriesget_uncategorized_game_idsnormalized_category_namesInvalidSearchTermError)get_runner_human_name)

FLAG_TEXTSTRUE_PREDICATEAndPredicateFlagPredicateFunctionPredicateMatchPredicateNotPredicateOrPredicateSearchPredicateTextPredicate)SERVICES)get_formatted_playtimeparse_playtime_parts)TokenReaderclean_tokentokenize_search-(ORANDc                sF    V ^8  d   QhR\         R\        \        ,          /#    tokensreturn)r   r   bool)formats   "2/usr/lib/python3.14/site-packages/lutris/search.py__annotate__r&   %   s"     T TK THTN T    c                 s    V P                  4       ;'       g    R pVP                  4       pV\        9   d   \        V,          # \        RV R24      h) 'z&' was found where a flag was expected.)get_cleaned_tokencasefoldr   r	   )r!   tokenZfolded   &  r%   read_flag_tokenr.   %   sL    $$&,,"E^^F&!!
 1UG+Q!R
SSr'   c                   sR  a  ] tR t^-t o ]! 4       tV 3R lR ltV 3R lR lt]V 3R lR l4       t	V 3R lR lt
V 3R	 lR
 ltV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltV 3R ltR tV tR!# )"
BaseSearchc                $   < V ^8  d   QhRS[ RR/# r    textr"   Nstrr$   __classdict__   "r%   r&   BaseSearch.__annotate__0   s     9 9S 9T 9r'   c                s     Wn         R V n        R # Nr2   	predicateselfr2      &&r%   __init__ZBaseSearch.__init__0   s    	48r'   c                    < V ^8  d   QhRS[ /# r    r"   r3   r5   r7   r%   r&   r8   4   s       r'   c                s    V P                   # r9   )r2   r=      &r%   __str__ZBaseSearch.__str__4   s    yyr'   c                r@   rA   r#   r5   r7   r%   r&   r8   8   s     4 4$ 4r'   c                sV    V P                   '       * ;'       d    V P                  '       * # r9   r:   rB   rC   r%   is_emptyZBaseSearch.is_empty7   s    99}33T^^!33r'   c                &   < V ^8  d   QhRS[ RS[/# r    	candidater"   )r    r#   r5   r7   r%   r&   r8   ;   s     6 6 6 6r'   c                s@    V P                  4       P                  V4      # r9   )get_predicateZacceptr=   rI   r>   r%   matchesZBaseSearch.matches;   s    !!#**955r'   c                rG   rH   r    r4   r5   r7   r%   r&   r8   >   s      C C r'   c                s    \        V4      # r9   r3   rK   r>   r%   get_candidate_textZBaseSearch.get_candidate_text>   s    9~r'   c                rG   )r    component_namer"   )r4   r#   r5   r7   r%   r&   r8   A   s      C D r'   c                s    WP                   9   de   R p\        V P                  \        4       FD  pVP	                  4       '       d   K  VR8X  d!   V'       d   VP                  4       V8X  d    R# TpKF  	  R# )N:TF)tagsr   r2   ISOLATED_TOKENSZisspacer+   )r=   rO   Z
prev_tokenr,      &&  r%   has_componentZBaseSearch.has_componentA   sY    YY&J(OD}}|
z7J7J7LP^7^#!&J	 E
 r'   c                r@   rA   r   r5   r7   r%   r&   r8   K   s       r'   c                s   V P                   fs   V P                  '       dV   \        V P                  \        4      p\	        V4      pV P                  V4      ;'       g    \        V n         V P                   # \        V n         V P                   # r9   )r;   r2   r   rR   r   	_parse_orr   )r=   Z
raw_tokensr!   r-   r%   rJ   ZBaseSearch.get_predicateK   sf    >>!yyy,TYYH
$Z0!%!7!I!I> ~~ "0~~r'   c                6   < V ^8  d   QhRS[ RS[S[,          /# r   r   r   r   r5   r7   r%   r&   r8   U   s      " " "0I "r'   c                s>   V P                  V4      p. pV'       dV   VP                  V4       VP                  R 4      '       d.   V P                  V4      pV'       g   MVP                  V4       KD  V'       g   R# \        V4      ^8X  d
   V^ ,          # \	        V4      # )r   N)_parse_itemsappendconsumelenr   )r=   r!   parsedZpartsZmore   &&   r%   rV   ZBaseSearch._parse_orU   s|    ""6*LL ..&&((0T"u:?8O5!!r'   c                rW   r   rX   r5   r7   r%   r&   r8   h   s      $ $; $8O3L $r'   c                s    . p V P                  V4      pV'       d   VP                  V4       K-   T'       g   R# \        T4      ^8X  d
   T^ ,          # \        T4      # )TN)_parse_itemrZ   r\   r   )r=   r!   Zbufferr]   rS   r%   rY   ZBaseSearch._parse_itemsh   sS    %%f-Ff%v;!!9F##r'   c                rW   r   rX   r5   r7   r%   r&   r8   w   s      , ,+ ,(?2K ,r'   c                sn   VP                  R 4      '       d   K  VP                  4       pV'       d   V\        9   d   R# VP                  R4      '       d+   VP	                  4        V P                  \        V4      4      # VP                  R4      '       d3   V P                  V4      ;'       g    \        pVP                  R4       V# VP                  R4      '       d%   V P                  V4      pV'       d   \        V4      # VP                  pVP	                  4        VP                  R4      '       d3   VP                  4       pW`P                  9   d    V P                  Wa4      # WQn        VP!                  V P"                  R7      pV'       d   V P                  V4      # R#   \         d     LJi ; i)r   N"r   )r   rP   Zstop_function)r[   
peek_tokenITEM_STOP_TOKENSZ
startswith	get_tokenget_text_predicater   rV   r   rY   r   Zindexr+   rQ   get_part_predicater	   get_cleaned_token_sequenceis_stop_token)r=   r!   r,   r;   ZinnerZsaved_indexnameZ
text_tokens   &&      r%   r_   ZBaseSearch._parse_itemw   sd    nnU##!!#!11C  **;u+=>>>>#v.@@.INN3>>#%%f-E#E**ll>>#>>#Dyy 224@@ #66TEWEW6X
**:66 . s   F& &F43F4c                r@   )r    r;   rU   r5   r7   r%   r&   r8      s       r'   c                st    V P                  4       p\        P                  ! V 4      p\        W!.4      Vn        V# r9   )rJ   copyr   r;   )r=   r;   Zold_predicateZ
new_searchrS   r%   with_predicateZBaseSearch.with_predicate   s3    **,YYt_
+],FG
r'   c                ,   < V ^8  d   QhRS[ RS[RS[/# r    rj   r!   r"   r4   r   r   r5   r7   r%   r&   r8      s'     M Ms MK MO Mr'   c                s     \        R V R24      h)r)   z' is not a valid search tag.r   )r=   rj   r!      &&&r%   rg   ZBaseSearch.get_part_predicate   s    $q.J%KLLr'   c                rG   r    r2   r"   r4   r   r5   r7   r%   r&   r8      s     D Ds D Dr'   c                s0    \        WP                  R R7      # )r(   tag)r   rN   r<   r>   r%   rf   ZBaseSearch.get_text_predicate   s    T#:#:CCr'   c                rG   r   )r   r#   r5   r7   r%   r&   r8      s      K D r'   c                s    VP                  ^4      pV'       g   R# V^ ,          \        9   d   R# \        V4      ^8  d7   V^,          R8X  d)   V^ ,          P                  4       V P                  9   d   R# R# )zThis function decides when to stop when reading an item;
pass this to tokens.get_cleaned_token_sequence().

It will stop at the end of tokens, any of our stop tokens
like AND, or at any tag, which must be a known tag followed by
a colon.TrP   F)Zpeek_tokensrd   r\   r+   rQ   )r=   r!   Zpeeked   && r%   ri   ZBaseSearch.is_stop_token   s^     ##A&!9((v;?vayC/F1I4F4F4HDII4Ur'   c                s&   < V ^8  d   QhRS[ RS[ /# rq   r3   r5   r7   r%   r&   r8      s        r'   c                s    V'       dO   R V9  dH   \        \        V\        4      4      p\        V4      pVP	                  V P
                  4      pWA8X  d   V# RV R2# )Z r`   )Zlistr   rR   r   rh   ri   )r=   r2   r!   Ztest_readerZcleanedr^   r%   quote_tokenZBaseSearch.quote_token   sT    CtO/$@AF%f-K!<<T=O=OPG4&{r'   c                s6   < V ^8  d   Qh/ S[ S[,          ;R&   # )r    rQ   )r   r4   r5   r7   r%   r&   r8   -   s     
c( r'   )r;   r2   N)__name__
__module____qualname____firstlineno__setrQ   r?   rD   ZpropertyrF   rL   rN   rT   rJ   rV   rY   r_   rl   rg   rf   ri   rv   Z__annotate_func____static_attributes____classdictcell__)r6   s   @r%   r/   r/   -   s     UD9 9  4 46 6   " "&$ $, ,\ M MD D   i  r'   r/   c                   s`  a a ] tR t^t oRt]! . R!O4      tR"V3R lV 3R llltV3R lR ltV3R lV 3R llt	V3R lR	 lt
V3R
 lR ltV3R lR ltV3R lR ltV3R lR ltV3R lR ltV3R lR ltV3R lR ltR#V3R lR lltV3R lR ltV3R lR ltV3R lR ltR tVtV ;t# )$
GameSearchz[A search for games, which applies to the games database dictionaries, not the Game objects.c                r0   r1   r3   r5   r7   r%   r&   GameSearch.__annotate__   s      S 4 r'   c                s2   < W n         \        SV `	  V4       R # r9   )servicesuperr?   )r=   r2   r   	__class__s   &&&r%   r?   ZGameSearch.__init__   s    r'   c                rG   rH   rM   r5   r7   r%   r&   r      s     ! !C !C !r'   c                s    VR ,          # )rj    rK   r>   r%   rN   ZGameSearch.get_candidate_text   s      r'   c                rm   rn   ro   r5   r7   r%   r&   r      s"     $8 $8s $8K $8O $8r'   c                s  < VR 8X  d,   VP                  4       ;'       g    RpV P                  V4      # VR9   d,   VP                  4       ;'       g    RpV P                  V4      # VR8X  d,   VP                  4       ;'       g    RpV P                  V4      # VR8X  d,   VP                  4       ;'       g    RpV P	                  V4      # VR8X  d   V P                  V4      # VR8X  d   V P                  V4      # VR8X  d8   VP                  V P                  R7      ;'       g    RpV P                  V4      # \        V4      pV P                  W4      p	V	'       d   V	# \        S
V `5  W4      # )	categoryr(   runnerplatformplaytime
lastplayed	directoryrb   )sourcer   )r*   get_category_predicateget_service_predicateget_runner_predicateget_platform_predicateget_playtime_predicateget_lastplayed_predicaterh   ri   get_directory_predicater.   get_flag_predicater   rg   )r=   rj   r!   r   service_namerunner_namer   r   flagZflag_predicater   s   &&&       r%   rg   ZGameSearch.get_part_predicate   sb   ://177RH..x88((!335;;L--l;;8 224::K,,[99://177RH..x88:..v66<0088;99HZHZ9[aa_aI//	:: v&00<!!w)$77r'   c                sL   < V ^8  d   QhRS[ RS[S[,          RS[S[,          /# )r    rj   r   r"   )r4   r   r#   r   r5   r7   r%   r&   r     s+      s (4. XoE^ r'   c                s    VR 8X  d   V P                  V4      # VR8X  d   V P                  RRVR7      # VR8X  d   V P                  RRVR7      # VR8X  d   V P                  V4      # R# )	installedhiddenz.hidden)in_categoryfavoritecategorizedN)get_installed_predicateget_category_flag_predicateget_categorized_predicate)r=   rj   r   rp   r%   r   ZGameSearch.get_flag_predicate  sy    ;//55833IxUY3ZZ:33J
X\3]]= 11$77r'   c                rG   r   r   r   r5   r7   r%   r&   r     s     V V[ V_ Vr'   c                s.    R  pV P                  W!RR7      # )c                 $    V P                  R 4      # )r   getdb_gamerC   r%   get_game_playtimeZ<GameSearch.get_playtime_predicate.<locals>.get_game_playtime  s    ;;z**r'   r   rs   )get_duration_predicate)r=   r!   r   ru   r%   r   Z!GameSearch.get_playtime_predicate  s     	+ **+<**UUr'   c                rG   r   r   r5   r7   r%   r&   r   !  s     	g 	g{ 	g 	gr'   c                s`   a \         P                   ! 4       oV3R  lpV P                  W!RR7      # )c                 sZ   < V P                  R 4      pV'       d   SV,
          R,          # R# )r   Ni  r   )r   r   now   & r%    get_game_lastplayed_duration_agoZMGameSearch.get_lastplayed_predicate.<locals>.get_game_lastplayed_duration_ago$  s'     \2Jj(W55r'   r   rs   )timer   )r=   r!   r   r      && @r%   r   Z#GameSearch.get_lastplayed_predicate!  s-    iik	 **+KYe*ffr'   c                s2   < V ^8  d   QhRS[ RS[RS[RS[/# )r    value_functionr!   rt   r"   )r   r   r4   r   r5   r7   r%   r&   r   ,  s+     )0 )0X )0{ )0Y\ )0ap )0r'   c                sV  aa	a
aaa V	V3R  loV	V3R loV
V3R loVP                  4       pVR8X  d   SpVP                  4        MZVR8X  d   SpVP                  4        M@VR8X  d   VV3R lpVP                  4        M!VR8X  d   VV3R lpVP                  4        MSpVP                  V P                  R	7      pV'       g   \	        R
4      h \        V4      o
S
P                  4       o	T RT \        S	4       2p\        YX4      #   \         d   p\	        RT R24      ThRp?ii ; i)c                 s2   < S! V 4      pT;'       d    VS8  # r9   r   r   game_playtimedurationr      & r%   match_greater_playtimeZAGameSearch.get_duration_predicate.<locals>.match_greater_playtime-       *73M ==]X%==r'   c                 s2   < S! V 4      pT;'       d    VS8  # r9   r   r   r   r%   match_lesser_playtimeZ@GameSearch.get_duration_predicate.<locals>.match_lesser_playtime1  r   r'   c                 sJ   < S! V 4      pT;'       d    SP                  V4      # r9   )rL   )r   r   duration_partsr   r   r%   match_playtimeZ9GameSearch.get_duration_predicate.<locals>.match_playtime5  s&    *73M JJ^%;%;M%JJr'   ><>=c                  ,   < S! V !  ;'       g    S! V !  # r9   r   )ar   r      *r%   <lambda>3GameSearch.get_duration_predicate.<locals>.<lambda>A  s    !7!;!Q!Q~q?Q!Qr'   <=c                  r   r9   r   )r   r   r   r   r%   r   r   D  s    !6!:!P!Pna>P!Pr'   rb   z A blank is not a valid duration.r)   z' is not a valid playtime.NrP   )
rc   re   rh   ri   r	   r   Zget_total_hoursZ
ValueErrorr   r   )r=   r   r!   rt   ZoperatorZmatcherZduration_textZexr2   r   r   r   r   r   s   &f&&     @@@@@r%   r   Z!GameSearch.get_duration_predicate,  s&   	>	>	K $$&s?,G_+GQGPG$G 99HZHZ9[()KLL	`1-@N%557H az"8"B!CD //	  	`(1]O;U)VW]__	`s   D D(D##D(c                rG   )r    r   r"   rr   r5   r7   r%   r&   r   W  s     W W W Wr'   c                     \        VR  RR7      # )c                 r   )r   r   )ZcrC   r%   r   Z4GameSearch.get_directory_predicate.<locals>.<lambda>X  s    !%%2Dr'   r   rs   )r   )r=   r   r>   r%   r   Z"GameSearch.get_directory_predicateW  s    Y(D+VVr'   c                6   < V ^8  d   QhRS[ S[,          RS[/# r    r   r"   r   r#   r   r5   r7   r%   r&   r   Z  s#     	e 	e$ 	eO 	er'   c                sl   a  S P                   '       d   V 3R  lp\        WRR7      # \        VR RR7      # )c                 s   < V P                  R 4      p\        T;'       d.    V\        P                  ! SP                  P
                  4      9   4      # )appid)r   r#   r   Zget_service_gamesr   id)r   r   r=   r   r%   is_installedZ8GameSearch.get_installed_predicate.<locals>.is_installed]  s<    G,EWWeu/F/Ft||/W&WXXr'   r   rs   c                 s&    \        V R ,          4      # r   rE   r   rC   r%   r   Z4GameSearch.get_installed_predicate.<locals>.<lambda>c  s    W[=Q8Rr'   )r   r   )r=   r   r   s   f& r%   r   Z"GameSearch.get_installed_predicateZ  s2    <<<Y !kJJY(RXcddr'   c                r   )r    r   r"   r   r5   r7   r%   r&   r   e  s#     M MXd^ M Mr'   c                s>   a \        4       oV3R  lp\        WRR7      # )c                 s   < V R ,          S9  # r   r   )r   uncategorized_idss   &r%   is_categorizedZ<GameSearch.get_categorized_predicate.<locals>.is_categorizedh  s    4=(999r'   r   rs   )r   r   )r=   r   r   r   r   r%   r   Z$GameSearch.get_categorized_predicatee  s     68	: [mLLr'   c                rG   )r    r   r"   rr   r5   r7   r%   r&   r   m  s     	Y 	Ys 	Y 	Yr'   c                s   a \        VR R7      p\        \        V4      4      oV3R lpRV P                  V4       2p\	        W4RVR7      # )TZsubname_allowedc                     < V R ,          pVS9   # r   r   r   Zgame_idcategory_game_idsr   r%   match_categoryZ9GameSearch.get_category_predicate.<locals>.match_categoryq      dmG///r'   z	category:r   r2   rt   Zvalue)r   r{   r   rv   r   )r=   r   namesr   r2   r   s   &&   @r%   r   Z!GameSearch.get_category_predicatem  sN    )(DI ;E BC	0 4++H567nZxXXr'   c                sB   < V ^8  d   QhRS[ RS[ RS[S[,          RS[/# )r    r   rt   r   r"   )r4   r   r#   r   r5   r7   r%   r&   r   x  s7     C CC Cc CPXY]P^ Cjw Cr'   c                sl   a \        VR R7      p\        \        V4      4      oV3R lp\        W5VR7      # )Tr   c                 r   r   r   r   r   r%   is_in_categoryZ>GameSearch.get_category_flag_predicate.<locals>.is_in_category|  r   r'   rs   )r   r{   r   r   )r=   r   rt   r   r   r   r   s   &&&&  @r%   r   Z&GameSearch.get_category_flag_predicatex  s4    )(DI ;E BC	0 [cBBr'   c                rG   )r    r   r"   rr   r5   r7   r%   r&   r     s     Z Z# Z/ Zr'   c                sl   a SP                  4       oR S 2pSR8X  d   R pMV3R lp\        W2RSR7      # )zsource:nonec                 2    V P                  R 4      pV'       * # r   r   )r   game_service   & r%   match_service7GameSearch.get_service_predicate.<locals>.match_service  s    &{{95'''r'   c                 s   < V P                  R 4      pV'       g   R# VP                  4       S8X  d   R# \        P                   ! V4      pT;'       d    SVP                  P                  4       9   # )r   FT)r   r+   r   rj   )r   r   r   r   s   &  r%   r   r     sY    &{{95# ((*l:",,|4JJ<7<<3H3H3J#JJr'   r   r   )r+   r   )r=   r   r2   r   s   &f  r%   r   Z GameSearch.get_service_predicate  sA    #,,.'6!(
	K mHLYYr'   c                rG   )r    r   r"   rr   r5   r7   r%   r&   r     s     X X X Xr'   c                s   aa SP                  4       oR V P                  S4       2pSR8X  d   R pMVV3R lp\        W2RSR7      # )zrunner:r   c                 r   r   r   )r   game_runnerr   r%   match_runner5GameSearch.get_runner_predicate.<locals>.match_runner  s    %kk(3&&r'   c                 s   < V P                  R 4      pV'       g   R# VP                  4       S8X  d   R# \        V4      pSVP                  4       9   # )r   FT)r   r+   r
   )r   r   Zrunner_human_namefolded_runner_namer   s   &  r%   r   r     sL    %kk(3" '')-??$9+$F!"&7&@&@&BBBr'   r   r   r+   rv   r   )r=   r   r2   r   r   s   &f  @r%   r   ZGameSearch.get_runner_predicate  sN    (113))+678''

C l8;WWr'   c                rG   )r    r   r"   rr   r5   r7   r%   r&   r     s     Y Ys Y Yr'   c                s   a a VP                  4       oR S P                  V4       2pSR8X  d   R pMVV 3R lp\        W2RVR7      # )z	platform:r   c                 r   )r   r   )r   game_platformr   r%   match_platform9GameSearch.get_platform_predicate.<locals>.match_platform  s     'J 7(((r'   c                 sP  < V P                  R 4      pV'       d   SVP                  4       9   # SP                  '       d]   SP                  P                  V 4       Uu. uF  q"P                  4       NK  	  ppV Uu. uF  pSV9   g   K  VNK  	  pp\	        V4      # R# u upi u upi )r   F)r   r+   r   Zget_game_platformsZany)r   r   ZpZ	platformsrL   folded_platformr=   s   &    r%   r   r     s     'J 7 *m.D.D.FFF<<<7;||7V7VW^7_ `7_!7_I `*3L)Q!7Kqq)GLw<' !aLs   B;	B#	B#r   r   r   )r=   r   r2   r   r   s   f&  @r%   r   Z!GameSearch.get_platform_predicate  sL    "++-4++H567f$)
 nZxXXr'   r   )r   r   r   r   r   r   r   r   r   r   r   r   r9   )T)rw   rx   ry   rz   __doc__r{   rQ   r?   rN   rg   r   r   r   r   r   r   r   r   r   r   r   r   r|   r}   __classcell__r   r6      @@r%   r~   r~      s     e	
D" ! !$8 $8L V V	g 	g)0 )0VW W	e 	eM M	Y 	YC CZ Z0X X2Y Y Yr'   r~   c                   sx   a a ] tR tRt oRt]! R.4      tV3R lR ltV3R lV 3R lltV3R lR	 lt	R
t
VtV ;t# )RunnerSearchi  z:A search for runners, which applies to the runner objects.r   c                rG   rH   rM   r5   r7   r%   r&   RunnerSearch.__annotate__  s     < <C <C <r'   c                s8    VP                    R VP                   2# )Z
)rj   ZdescriptionrK   r>   r%   rN   ZRunnerSearch.get_candidate_text  s    ..!I$9$9#:;;r'   c                rm   rn   ro   r5   r7   r%   r&   r     s"     	8 	8s 	8K 	8O 	8r'   c                s|   < VR 8X  d'   \        V4      pVf   \        # V P                  V4      # \        SV `  W4      # r   )r.   r   r   r   rg   )r=   rj   r!   r   r   s   &&& r%   rg   ZRunnerSearch.get_part_predicate  sA    ;"6*D|%%//55w)$77r'   c                rG   r   )r#   r   r5   r7   r%   r&   r     s     _ _ _/ _r'   c                r   )c                 s"    V P                  4       # r9   )r   r   rC   r%   r   Z6RunnerSearch.get_installed_predicate.<locals>.<lambda>  s    v7J7J7Lr'   r   rs   )r   )r=   r   r>   r%   r   Z$RunnerSearch.get_installed_predicate  s    Y(LR]^^r'   r   )rw   rx   ry   rz   r   r{   rQ   rN   rg   r   r|   r}   r   r   r   r%   r   r     s:     D}D< <	8 	8_ _ _r'   r   )rP   r   r   ra   r   r   r   r   ),rk   r   Ztypingr    r   r   r   Zlutris.databaser   Zlutris.database.categoriesr   r   r   Zlutris.exceptionsr	   Zlutris.runnersr
   Zlutris.search_predicater   r   r   r   r   r   r   r   r   r   Zlutris.servicesr   Zlutris.util.stringsr   r   Zlutris.util.tokenizationr   r   r   r{   rR   rd   r.   r/   r~   r   r   r'   r%   <module>r      s      / / ! 
 5 0   % L  @A#c4-&88Cc
OK T[ [|}Y }Y@_: _r'   