ó
    ÈÌjo:  ã                   óî  • S r SSKrSSKrSSKJr  SSKJr  SSKJr  SSK	J
r
  SSKrSSKJrJrJrJr  SrS	u  rr\\-  \\-  srr\" \S
-  S-  5      rS\-  S\-  S\-  srrr\\-   rS\-  r\S\-  -
  rS\-  r\S\-  -
  rS\-  r \\-   \ -   r!\\-
  \!-
  r"Sr#Su  r$r%Su  r&r'Su  r(r)Su  r*r+Sr,\" \-5      R]                  5       R^                  R^                  S-  r0SSSSS.r1SS S!/ S"QS#S$S%S&.S'S(S)/ S*QS+S,S-S&.S.S/S0/ S1QS2S3S4S&.S5.r2\" S6S79S8\3S9\4S:\Rj                  4S; j5       r6SdS<\3S=\7S:\74S> jjr8SdS?\7S@\7S<\3S=\7S:S4
SA jjr9SdS<\3SB\7S=\7S:\34SC jjr:S<\3SB\7SD\7S:\;\3   4SE jr<SeSF\;\3   SB\7SD\7SG\3S:\;\3   4
SH jjr=SI\;\>\4\>4      S:S4SJ jr?SK\3SL\7S:\R                  4SM jr@SfSN\7SO\7SP\7SQ\7S:S4
SR jjrASS\ST\7SU\7S:\
\R                     4SV jrBSWSSXSSY.SZ\3S[\;\3   S\\3S]\3S^\3S_\3S`\
\7   Sa\3Sb\
\;\      S:\C4Sc jjrDg)guÄ  
card_service.py â€” family sheet (10x15 cm) rendered as a PNG, the single source of truth for what gets printed.

The sheet carries no name at all (the schools may not give us any): the steps to follow online, the QR
and the access code, the class(es), and the photos of the child or siblings so that the parents recognise
their own sheet at a glance.

Same technique as hec-photo-app's qr_service (read its docstring for the reasoning), one deviation:
HEC keeps a React mirror of the card and a Pillow renderer and has to keep both in sync by hand. Here the
browser never re-draws the card: the preview, the print sheet and the ZIP all show THIS PNG, so frontend and
backend cannot drift (see DECISIONS.md).

What makes the output identical on every machine:
  * Every measurement is a CSS-pixel constant multiplied by S (=3), so the file is 1200 px wide.
  * Physical size is 100 x 150 mm (10x15 cm print); the DPI is written into the PNG so it prints at 1:1.
  * Fonts are bundled (backend/fonts): the card never depends on what the server has installed.
  * Letter-spacing is applied glyph by glyph and text is placed by BASELINE (anchor "ls"). Using "b" aligns the
    glyph's bottom edge instead and lifts every descender â€” HEC printed "PhotoGraPhe" because of it.
  * The QR uses the same parameters as /api/qr.svg (error level M, no Micro QR, 4-module quiet zone, navy on
    white): the photographer shoots these cards and the organizer must be able to read them.
é    N)Údate)Ú	lru_cache)ÚPath)ÚOptional)ÚImageÚ	ImageDrawÚ	ImageFontÚImageOpsé   )i�  iX  gffffff9@éd   é>   é"   é   é   év   é   é   é   ))é
   é   éD   )é   é   é3   ))éÉ   é¢   é'   )éè   éÔ   é‹   ))éç   éâ   éÖ   )én   éu   é…   ))éô   éê   éÈ   )éû   éù   éó   )éÎ   éÓ   éÞ   ÚfontszInter-Regular.ttfzInter-SemiBold.ttfzInter-Bold.ttfzJetBrainsMono-Bold.ttf)ÚregularÚsemiboldÚboldÚmonou   {school} Â· PHOTOS SCOLAIRESu   VOS PHOTOS SONT PRÃŠTESzClasse : {c})z5Scannez le QR code, ou entrez votre code sur le site.uN   DÃ©couvrez les photos de vos enfants et crÃ©ez des photos Â« fun Â» avec l'IA.uA   Choisissez vos tirages ou fichiers numÃ©riques et payez en ligne.zScannez le QR code, ouzrendez-vous surud   AccÃ¨s privÃ© Ã  vos photos uniquement Â· Photos supprimÃ©es automatiquement aprÃ¨s {d} jours (RGPD))ÚschoolÚreadyÚklassÚstepsÚscanÚvisitÚrgpdu   {school} Â· SCHOOL PHOTOSzYOUR PHOTOS ARE READYz
Class: {c})z4Scan the QR code, or enter your code on the website.z>See your children's photos and create fun AI photos from them.z3Choose your prints or digital files and pay online.zScan the QR code, orzgo touX   Private access to your photos only Â· Photos deleted automatically after {d} days (GDPR)u   {school} Â· FOTOS ESCOLARESu   TUS FOTOS ESTÃ�N LISTASz
Clase: {c})u8   Escanea el cÃ³digo QR, o introduce tu cÃ³digo en la web.z;Mira las fotos de tus hijos y crea fotos divertidas con IA.u7   Elige tus copias o archivos digitales y paga en lÃ­nea.u   Escanea el cÃ³digo QR, ozentra enuZ   Acceso privado solo a tus fotos Â· Fotos eliminadas automÃ¡ticamente tras {d} dÃ­as (RGPD))ÚfrÚenÚesé@   )ÚmaxsizeÚkindÚcss_pxÚreturnc                 ó~   • [         R                  " [        [        [        U    -  5      [        U[        -  5      5      $ ©N)r	   ÚtruetypeÚstrÚ_FONTSÚ_FILESÚroundÚS)rA   rB   s     ÚXD:\Ingenieria\TRABAJOS ONLINE\Projects\11- Photo School\backend\services\card_service.pyÚ_fontrM   Q   s,   € ä×Òœc¤&¬6°$©<Ñ"7Ó8¼%ÀÌÁ
Ó:KÓLÐLó    ÚtextÚspacingc                 ón   • [        U R                  U5      5      U[        [        U5      S-
  S5      -  -   $ )Né   r   )ÚintÚ	getlengthÚmaxÚlen)ÚfontrO   rP   s      rL   Ú_wrX   V   s/   € Üˆt�~‰~˜dÓ#Ó$ w´´S¸³YÀ±]ÀAÓ1FÑ'FÑFÐFrN   ÚxÚtopc           	      ó¦   • X$R                  5       S   -   nU H6  nU R                  X4X„USS9  U[        UR                  U5      5      U-   -  nM8     g)z\Draw left-aligned text glyph by glyph; `top` is the top of the line box, placed by baseline.r   Úls©rW   ÚfillÚanchorN)Ú
getmetricsrO   rS   rT   )	ÚdrawrY   rZ   rO   rW   r^   rP   ÚbaseÚchs	            rL   Ú_textrd   Z   sS   € à—‘Ó" 1Ñ%Ñ%€DÛˆØ�	‰	�1�)˜R°¸dˆ	ÑCØ	ŒS�—‘ Ó#Ó$ wÑ.Ñ.Šò rN   Úmax_wc                 óÂ   • [        XU5      U::  a  U$ U(       a4  [        XS-   U5      U:”  a!  USS nU(       a  [        XS-   U5      U:”  a  M!  UR                  5       S-   $ )z_Right-truncate with an ellipsis (never cut on the left: that is how a URL starts with 'ps://').u   â€¦Néÿÿÿÿ)rX   Úrstrip)rW   rO   re   rP   s       rL   Ú_fitri   b   s^   € ä	ˆ$�gÓ %Ó'ØˆÞ
”2�d 5™L¨'Ó2°UÓ:Ø�C�Rˆyˆö ”2�d 5™L¨'Ó2°UÕ:à�;‰;‹=˜5Ñ Ð rN   Ú	max_linesc                 ól  • / SpTUR                  5        HE  nU SU 3R                  5       nU(       a$  [        X5      U:”  a  UR                  U5        UnMC  UnMG     U(       a  UR                  U5        [	        U5      U:”  a  US U nUS   S-   US'   U Vs/ s H  n[        XU5      PM     sn$ s  snf )NÚ Ú rg   õ    â€¦)ÚsplitÚstriprX   ÚappendrV   ri   )	rW   rO   re   rj   ÚlinesÚcurÚwordÚtrialÚlns	            rL   Ú_wraprw   k   s¯   € Ø�Rˆ3Ø—
‘
–ˆØ�%�q˜˜�×%Ñ%Ó'ˆÞ”2�d“? UÓ*Ø�L‰L˜ÔØŠCàŠCñ ö Ø�‰�SÔÜ
ˆ5ƒz�IÓØ�j�yÐ!ˆØ˜"‘I Ñ&ˆˆb‰	Ù,1Ó2ªE bŒD�˜5Ö!©EÑ2Ð2ùÒ2s   ÂB1ÚitemsÚsepc                 óN  • / nSnU HA  nU(       a  U U U 3OUnU(       a$  [        X5      U:”  a  UR                  U5        UnM?  UnMC     U(       a  UR                  U5        [        U5      U:”  a  USU nUS==   S-  ss'   U V	s/ s H  n	[        X	U5      PM     sn	$ s  sn	f )zFWrap whole items (one per student) so a separator never starts a line.rl   Nrg   rn   )rX   rq   rV   ri   )
rW   rx   re   rj   ry   rr   rs   Úitru   rv   s
             rL   Ú_wrap_itemsr|   |   s¦   € à€EØ
€CÛˆÞ%(�3�%˜�u˜R˜DÑ!¨bˆÞ”2�d“? UÓ*Ø�L‰L˜ÔØŠCàŠCñ ö Ø�‰�SÔÜ
ˆ5ƒz�IÓØ�j�yÐ!ˆØˆb‹	�VÑ‹	Ù,1Ó2ªE bŒD�˜5Ö!©EÑ2Ð2ùÒ2s   Â	B"Ústopsc                 ó0  ^• X1-
  n[        U5       H‚  nU[        US-
  S5      -  n[        XUSS  5       H[  u  u  pšu  p¼X‹::  d  M  X¹:X  a  SOX‰-
  X¹-
  -  mU R                  X-   U4X-   US-
  4/[	        U4S j[        X¬5       5       5      S9    M€     M„     g )NrR   r   c              3   óN   >#   • U  H  u  p[        XU-
  T-  -   5      v •  M     g 7frE   )rJ   )Ú.0ÚaÚbÚks      €rL   Ú	<genexpr>Ú_hgrad.<locals>.<genexpr>–   s-   øé € ÐFvÒjuÑbfÐbcÄuÈQÐVWÑRWÐ[\ÑQ\É_×G]ÐG]Òjuùs   ƒ"%©r^   )ÚrangerU   ÚzipÚlineÚtuple)ra   Úx0Úy0Úx1Úy1r}   ÚnÚiÚtÚp0Úc0Úp1Úc1rƒ   s                @rL   Ú_hgradr–   �   sž   ø€ Ø
‰€AÜ�1ŽXˆØ”�A˜‘E˜1“ÑˆÜ"% e°1°2¨YÖ"7Ñ‰HˆR‘h�rØ�wØ›‘A¨©°2±7Ñ';�Ø—	‘	˜B™F B˜<¨"©&°"°q±&Ð)9Ð:ÄÔFvÔjmÐnpÔjuÓFvÓAv�	ÑwÚó	 #8ò rN   ÚurlÚsize_pxc           	      ó¸  • [         R                  " U SSS9n[        UR                  5      S-   n[	        X-  S5      n[
        R                  " 5       nUR                  USU[        SSS	9  [        R                  " U5      R                  S
5      n[        R                  " S
X4S5      nUR                  XaUR                  -
  S-  XR                  -
  S-  45        U$ )NÚmF)ÚerrorÚmicroé   rR   ÚpngÚwhiter   )rA   ÚscaleÚdarkÚlightÚborderÚRGBr   )ÚsegnoÚmakerV   ÚmatrixrU   ÚioÚBytesIOÚsaveÚNAVYr   ÚopenÚconvertÚnewÚpasteÚwidthÚheight)r—   r˜   Úqrr�   r    ÚbufÚimgÚcanvass           rL   Ú	_qr_imager¶   š   s´   € Ü	�Š�C˜s¨%Ñ	0€BÜˆB�I‰I‹˜Ñ€AÜ�‘˜aÓ €EÜ
�*Š*‹,€CØ‡G�GˆC�e 5¬t¸7È1€GÑMÜ
�*Š*�S‹/×
!Ñ
! %Ó
(€CÜ�YŠY�u˜wÐ0°'Ó:€FØ
‡L�L� #§)¡)Ñ+°Ñ1°G¿j¹jÑ4HÈQÑ3NÐOÔPØ€MrN   Úradiusr°   ÚdashÚgapc           
      óÆ  • Uu  pxpšUnXV-   [         -  S-  nU[         -  S-  n[        X{-   X›-
  U5       HI  nU R                  Xè4[        Xí-   X›-
  5      U4/X4S9  U R                  Xê4[        Xí-   X›-
  5      U
4/X4S9  MK     [        X‹-   X«-
  U5       HI  nU R                  X4U[        Xý-   X«-
  5      4/X4S9  U R                  XŸ4U	[        Xý-   X«-
  5      4/X4S9  MK     U R	                  XxUSU-  -   USU-  -   /SSX4S9  U R	                  U	SU-  -
  X‰USU-  -   /SSX4S9  U R	                  XzSU-  -
  USU-  -   U
/SSX4S9  U R	                  U	SU-  -
  U
SU-  -
  Xš/SSX4S9  g)	zQDashed outline along the straight edges + solid corner arcs (CSS `1.5px dashed`).r   ©r^   r°   é´   i  ih  éZ   r   N)rK   r‡   r‰   ÚminÚarc)ÚdÚboxr·   r^   r°   r¸   r¹   r‹   rŒ   r�   rŽ   ÚrÚstepÚonrY   Úys                   rL   Ú_dashed_roundedrÆ   ¦   s¨  € à�N€BˆBØ€AØ‰Jœ!Ñ˜qÑ €DØ	”‰�Q‰€BÜ�2‘6˜2™6 4Ö(ˆØ	�‰��œ#˜a™f b¡fÓ-¨rÐ2Ð3¸$ˆÑLØ	�‰��œ#˜a™f b¡fÓ-¨rÐ2Ð3¸$ˆÓLñ )ô �2‘6˜2™6 4Ö(ˆØ	�‰��˜"œc !¡&¨"©&Ó1Ð2Ð3¸$ˆÑLØ	�‰��˜"œc !¡&¨"©&Ó1Ð2Ð3¸$ˆÓLñ )ð ‡E�Eˆ2�2˜˜A™‘:˜r A¨¡E™zÐ
*¨C°¸4€EÑMØ‡E�Eˆ2��A‘‰:�r˜r A¨¡E™zÐ
*¨C°¸4€EÑMØ‡E�Eˆ2�A˜‘E‰z˜2  A¡™: rÐ
*¨B°¸$€EÑLØ‡E�Eˆ2��A‘‰:�r˜A ™E‘z 2Ð
*¨A¨r¸€EÒJrN   ÚpathÚwÚhc                 ó  •  [         R                  " U 5       n[        R                  " U5      R	                  S5      nUR                  US-  US-  45        [        R                  " X1U4[         R                  SS9nSSS5        [         R                  " SX4S5      n[        R                  " U5      R                  SSUS-
  US-
  /S	[        -  S
S9  WR                  U5        U$ ! , (       d  f       Np= f! [         a     gf = f)z_A photo cropped to w x h (centred on the upper part: these are portraits) with rounded corners.r¤   r   )ç      à?gìQ¸…ëÑ?)ÚmethodÚ	centeringNÚLr   rR   r�   éÿ   ©r·   r^   )r   r¬   r
   Úexif_transposer­   Ú	thumbnailÚfitÚLANCZOSÚ	Exceptionr®   r   ÚDrawÚrounded_rectanglerK   Úputalpha)rÇ   rÈ   rÉ   ÚimÚtileÚmasks         rL   Ú_photo_tilerÜ   ¸   sÞ   € ðÜ�ZŠZ˜Ô Ü×(Ò(¨Ó,×4Ñ4°UÓ;ˆBØ�L‰L˜!˜a™%  Q¡˜Ô(Ü—<’< ¨ F´5·=±=ÈKÑXˆD÷ ô �9Š9�S˜1˜& !Ó$€DÜ‡N‚N�4Ó×*Ñ*¨A¨q°!°a±%¸¸Q¹Ð+?ÈÌAÉÐTWÐ*ÑXØ‡M�M�$ÔØ€K÷ Õûô ó Ùðús/   ‚C8 ˜A%C'Á=C8 Ã'
C5Ã1C8 Ã5C8 Ã8
DÄDr<   rl   )ÚlangÚyearÚbrand_colorÚphotosÚcodeÚclassesÚschool_nameÚ
portal_urlÚ	rgpd_daysrÝ   rÞ   rß   rà   c        	         ó  ^• [         R                  U5      =(       d	    [         S   n	U=(       d    [        R                  " 5       R                  nUR                  S5      n
U
 SU  3n[        R                  " SSU
5      n[        R                  " S[        [        4S5      n[        R                  " U5      n[        R                  " ST=(       d    S5      (       aI  [        U4S	 jS
 5       5      n[        S U 5       5      n[!        USS[        ["        SU4SU4SU4/5        O-[!        USS[        ["        S[$        4S[&        4S[&        4/5        [)        SS5      [)        SS5      nnS[*        -  n[-        U[.        S[*        -  SUSU5        [-        U[.        [1        USU5      -   U-   S[*        -  SU[2        U5        [5        S[*        -  5      n[7        UU	S   R9                  UR;                  5       S9SU 3-   [        S[.        -  -
  U5      n[-        U[.        S[*        -  UU[<        U5        [!        US["        [        [>        S[@        4S[2        4S[@        4/5        [)        SS5      [)        SS 5      nn[>        S[*        -  -   n[-        U[.        UU	S!   U[@        [5        S"[*        -  5      5        US#[*        -  -  nS$RC                  [D        RG                  S% U 5       5      5      nU(       a7  [-        U[.        U[7        UU	S&   R9                  US'9[H        5      U[&        5        US([*        -  -  n[K        U=(       d    / 5      S)[L         n/ nU(       aã  S*[*        -  n[O        U5      nUS:X  a  S+O	US:X  a  S,OS-[*        -  nUS:”  a  [H        UUS-
  -  -
  U-  OS.[*        -  nUU-  UUS-
  -  -   n [.        [H        U -
  S-  -   n!U H7  n"[Q        [S        U"5      UU5      n#U#b  URU                  U#U!45        U!UU-   -  n!M9     U(       a0  U H  u  n#n$URW                  U#U$U4U#5        M     UUS [*        -  -   -  n[)        SS/5      [)        SS05      n&n%[Y        U	S1   S5       GH  u  n'n([.        S2[*        -  -   US2[*        -  -   S2[*        -  n+n*n)UR[                  U)U+-
  U*U+-
  U)U+-   U*U+-   /[&        S39  []        U'5      n,U&R_                  5       u  n-n.URa                  U)U*4U,U&SS4S59  [c        U%U([H        S([*        -  -
  S5      n/Un0U/ H-  n1[-        U[.        S6[*        -  -   U0U1U%S75        U0S8[*        -  -  n0M/     U[e        [O        U/5      S8-  [*        -  S9[*        -  5      S*[*        -  -   -  nGM
     [        [f        -
  n2U2[h        -
  S:[*        -  -
  n3URk                  [.        U3[.        [h        -   S-
  U3[h        -   S-
  /S:[*        -  S[l        [*        S;9  URW                  [o        U[p        5      [.        S*[*        -  -   U3S*[*        -  -   45        [)        SS05      [)        SS05      [)        S<S5      n6n5n4[5        S"[*        -  5      S=[*        -  S8[*        -  n9n8n7SU9-  S*[*        -  -   U8-   n:U3[h        U:-
  S-  -   n;[-        U[r        U;U	S>   U4[t        5        U;U9-  n;U	S?   S-   n<[-        U[r        U;U<U4[t        5        [-        U[r        [1        U4U<5      -   U;[7        U5U[v        [1        U4U<5      -
  5      U5[&        5        U;U9S*[*        -  -   -  n;[y        [1        U6U U75      S([*        -  -   [v        5      n=[r        U;[r        U=-   U;U8-   S-
  /n>URk                  U>S@[*        -  [z        SA9  [}        UU>S@[*        -  [@        [5        S[*        -  5      5        U6R_                  5       u  n-n?[-        U[r        S [*        -  -   U;U8U-U?-   -
  S-  -   U U6[&        U75        UR                  SU2[        [        /[€        S39  URƒ                  SU24[        U24/[l        [*        SB9  [)        SSC5      n@[c        U@U	SD   R9                  USE9[        S[.        -  -
  S5      nAU2[f        [O        UA5      SF-  [*        -  -
  S-  -   nBUA H'  n1[-        U[.        WBU1W@[t        5        UBSF[*        -  -  nBM)     URk                  SS[        S-
  [        S-
  /S#[*        -  [l        [*        SG9  [„        R†                  " 5       nCUR‰                  UCSH[Š        [Š        4SSI9  UCR�                  5       $ )Jz¯One family sheet as PNG bytes. `portal_url` is the portal base (https://photos.example.com);
`photos` are original files of the child/siblings (the first MAX_PHOTOS are used).r<   Ú/z/?code=z
^https?://rl   r¤   rŸ   z^#[0-9a-fA-F]{6}$c              3   óF   >#   • U  H  n[        TXS -    S5      v •  M     g7f)r   r   N©rS   )r€   r�   rß   s     €rL   r„   Úrender_card.<locals>.<genexpr>×   s$   øé € ÐHºi¸”s˜; q¨Q©Ð/°×4Ð4ºiùs   ƒ!)rR   r   é   c              3   ó>   #   • U  H  n[        US -  5      v •  M     g7f)çffffffæ?Nré   ©r€   Úcs     rL   r„   rê   Ø   s   é € Ð2ª6 a”S˜˜S™—\�\ª6ùs   ‚r   rí   rR   r3   é   r1   g      %@r   r   ÚMEE)rÏ   rÏ   rÏ   ÚCONICg      ø?r5   )r5   rm   r   é&   rË   r2   é   r6   g      @r   õ    Â· c              3   ó6   #   • U  H  o(       d  M  Uv •  M     g 7frE   © rî   s     rL   r„   rê   ë   s   é € Ð(A²G¨q»q¯©²Gùs   ‚
�	r7   )rï   é   Nr�   r¼   é–   éx   éŒ   g      '@é   r8   é	   r†   Úmmr]   é   )é<   éB   éR   é   é   é   )r·   r^   Úoutliner°   r4   r   r9   r:   r   rÐ   r»   g      #@r;   )rÀ   é   )r·   r  r°   ÚPNG)ÚformatÚdpiÚcompress_level)GÚTEXTSÚgetr   ÚtodayrÞ   rh   ÚreÚsubr   r®   ÚCARD_WÚCARD_Hr   rÖ   ÚmatchrŠ   r–   ÚHEAD_HÚ	NAVY_DEEPr«   rM   rK   rd   ÚPAD_XrX   Ú
GOLD_LIGHTrJ   ri   r	  ÚupperÚWHITE_80ÚBODY_YÚGOLDÚjoinÚdictÚfromkeysÚ	CONTENT_WÚlistÚ
MAX_PHOTOSrV   rÜ   r   rq   r¯   Ú	enumerateÚellipserG   r`   rO   rw   rU   ÚFOOT_HÚQR_BOXr×   ÚBORDERr¶   ÚQR_INNERÚTEXT_XÚDIMÚTEXT_Wr¾   ÚCHIP_BGrÆ   Ú	rectangleÚFOOT_BGr‰   r¨   r©   rª   ÚDPIÚgetvalue)Drá   râ   rã   rä   rå   rÝ   rÞ   rß   rà   Útxrb   ÚlinkÚhostr´   rÀ   ÚaccentÚdeepÚf_logoÚf_schoolÚlogo_spÚ	school_spÚschool_lineÚf_readyÚf_classrÅ   Úcls_textÚpathsÚtilesr¹   r�   rÉ   rÈ   Úrow_wrY   rÇ   rÚ   Útx_Úf_stepÚf_numr�   rÃ   ÚcxÚcyrÂ   ÚnumÚascÚ_rr   Úlyrv   Úfoot_yÚbox_yÚf_smallÚf_hostÚf_codeÚcode_spÚchip_hÚ
line_smallÚblock_hÚtyr:   Úchip_wÚchipÚdescÚf_rgpdÚrgÚryr³   sD          `                                                            rL   Úrender_cardrY  Ç   s1  ø€ ô
 
�‰�4‹×	'œE $™K€BØ×$”4—:’:“<×$Ñ$€DØ×Ñ˜SÓ!€DØˆV�7˜4˜&Ð!€DÜ�6Š6�-  TÓ*€Dä
�)Š)�EœF¤FÐ+¨WÓ
5€CÜ�Š�sÓ€Aô 
‡x‚xÐ$ k×&7°R×8Ñ8ÜÔH¹iÓHÓHˆÜÑ2©6Ó2Ó2ˆÜˆq�!�Qœ¤¨!¨T¨°S¸&°MÀAÀvÀ;Ð(OÕPäˆq�!�Qœ¤¨!¬Y¨¸#¼t¸ÀqÌ$ÀiÐ(PÔQÜ˜V RÓ(¬%°	¸4Ó*@ˆH€FØ”!‰e€GÜ	ˆ!ŒU�Bœ‘F˜E 6¨?¸GÔDÜ	ˆ!ŒU”R˜  wÓ/Ñ/°'Ñ9¸2Ä¹6À7ÈFÔT^Ð`gÔhÜ�cœA‘g“€IÜ�x  H¡×!4Ñ!4¸K×<MÑ<MÓ<OÐ!4Ð!PÐUVÐW[ÐV\ÐS]Ñ!]Ü ¤E¡	Ñ)¨9ó6€Kä	ˆ!ŒU�Bœ‘F˜K¨´8¸YÔGÜ
ˆ1ˆa”œ¤¨1¬d¨)°c¼:Ð5FÈÌDÈ	Ð)RÔSô ˜V TÓ*¬E°*¸bÓ,AˆW€GÜ�”a‘‰€AÜ	ˆ!ŒU�A�r˜'‘{ G¬T´5¸¼q¹³>ÔBØˆŒa‰�K€AØ�{‰{œ4Ÿ=™=Ñ(A±GÓ(AÓAÓB€HÞÜˆa”˜œ4 ¨¨G©×);Ñ);¸hÐ);Ð)GÌÓSÐU\Ô^bÔcØˆŒa‰�K€Aô �—˜2Ó˜{¤
Ð+€EØ€EÞØ”!‰eˆÜ�‹JˆØ˜“F‰S q¨A£v¡°3¼!Ñ;ˆØ01°A³ŒY˜  A¡™Ñ&¨1Ò,¸3Ä¹7ˆØ�A‘˜˜q 1™u™Ñ%ˆÜ”Y Ñ&¨1Ñ,Ñ,ˆÛˆDÜœt D›z¨1¨aÓ0ˆDØÑØ—‘˜d A˜YÔ'Ø��S‘‰LŠAñ	 ö
 Û"‘	��cØ—	‘	˜$  a ¨$Ö/ñ #à��Rœ!‘V‘‰OˆAô ˜) TÓ*¬E°&¸"Ó,=ˆE€FÜ˜R ™[¨!×,‰ˆˆ4Ü˜A¤™E‘M 1 q¬1¡u¡9¨a´!©e�ˆBˆØ	�	‰	�2˜‘6˜2 ™6 2¨¡6¨2°©6Ð2¼ˆ	Ñ>Ü�!‹fˆØ×!Ñ!Ó#‰ˆˆQØ	�‰��Bˆx˜ 5¨ÀtˆÑLÜ�f˜d¤I°´Q±Ñ$6¸Ó:ˆØˆÛˆBÜ�!”U˜R¤!™V‘^ R¨¨V°\ÔBØ�"”q‘&‰LŠBñ ð 	
ŒS”�U“˜b‘¤1Ñ$ b¬1¡fÓ-°´A±Ñ5Ñ5‹ñ -ô ”f‰_€FØ”V‰O˜b¤1™fÑ$€EØ×Ñœ ¤u¬v¡~¸Ñ'9¸5Ä6¹>ÈAÑ;MÐNÐWYÔ\]ÑW]Ø$¬f¼Að ñ ?à‡I�IŒi˜œhÓ'¬%°!´a±%©-¸ÀÄQÁ¹Ð)GÔHä# I¨rÓ2´E¸*ÀbÓ4IÌ5ÐQWÐY[ÓK\�VˆV€GÜ"'¨¬a©£.°"´q±&¸"¼q¹&�ZˆV€GØ�*‰n˜q¤1™uÑ$ vÑ-€GØ	”&˜7Ñ" qÑ(Ñ	(€BÜ	ˆ!ŒV�R˜˜F™ W¬cÔ2Øˆ*Ñ€BØˆw‰K˜#Ñ€EÜ	ˆ!ŒV�R˜ ¬Ô-Ü	ˆ!ŒV”b˜ %Ó(Ñ(¨"¬d°6¸4ÄÌ"ÈWÐV[ÓJ\ÑA\Ó.]Ð_eÔgkÔlØˆ*�qœ1‘uÑ
Ñ€BÜ”�F˜D 'Ó*¨R´!©VÑ3´VÓ<€FÜ�Bœ ™¨¨f©°q©Ð9€DØ×Ñ˜ R¬!¡V´'ÐÑ:Ü�A�t˜R¤!™V¤T¬5°´q±«>Ô:Ø×!Ñ!Ó#�I€CˆÜ	ˆ!ŒV�bœ1‘f‰_˜b F¨c°D©jÑ$9¸aÑ#?Ñ?ÀÀvÌtÐU\Ô]ð ‡K�K��FœF¤FÐ+´'€KÑ:Ø‡F�FˆQ�ˆKœ& &Ð)Ð*´¼q€FÑAÜ�9˜cÓ"€FÜ	ˆv�r˜&‘z×(Ñ(¨9Ð(Ð5´vÀÄEÁ	Ñ7IÈ1Ó	M€BØ	”6œC ›G b™L¬1Ñ,Ñ,°Ñ2Ñ	2€BÛˆÜˆa”˜˜B ¬Ô,Ø
ˆb”1‰f‰Šñ ð
 ×Ñ˜˜Aœv¨™z¬6°A©:Ð6¸rÄA¹vÌvÔ]^ÐÑ_ä
�*Š*‹,€CØ‡H�HˆS˜¤S¬# J¸q€HÑAØ�<‰<‹>ÐrN   )r   )rõ   )é   r   )EÚ__doc__r¨   r  Údatetimer   Ú	functoolsr   Úpathlibr   Útypingr   r¥   ÚPILr   r   r	   r
   rK   Ú
CARD_W_CSSÚ
CARD_H_CSSr  r  rJ   r.  r  ÚGOLD_Hr$  r  r  r  r%  r'  ÚCOL_GAPr(  r*  r!  r«   r  r  r  r&  r)  r+  r-  r  Ú__file__ÚresolveÚparentrH   rI   r  rG   ÚfloatÚFreeTypeFontrM   rS   rX   rd   ri   r   rw   r|   rŠ   r–   r¶   rÆ   rÜ   ÚbytesrY  r÷   rN   rL   Ú<module>rk     s°  ðñó* 
Û 	Ý Ý Ý Ý ã ß 5Ó 5à€Ø!Ñ €
ˆJØ˜a‘ ¨a¡€€ˆÙˆF�T‰M˜CÑÓ €à˜a™  Q¡¨¨Q©Ð €ˆ�Ø	�&‰€Ø
ˆQ‰€Ø�Q˜‘YÑ€	Ø	ˆq‰€Ø�E˜A‘IÑ€Ø
ˆq‰&€Ø	�‰˜'Ñ	!€Ø	�%‰˜&Ñ	 €Ø€
à+�€€iØ2Ñ €€jØ.�€ˆØ3Ñ €ˆØ€á	ˆh‹×	Ñ	Ó	!×	(Ñ	(×	/Ñ	/°'Ñ	9€Ø(Ð6JØ"Ð,Dñ
F€ð
 4Ð>WÐbpòZð ,Ð6GØyñ{ð 1Ð;RÐ]iòLð *°GØmñoð 3Ð=VÐamòPð .¸
Øoñqñ	€ñ, �2ÑðM�ð M˜Uð M y×'=Ñ'=ó Mó ðMñG�3ð G ð G¨Sõ Gñ/�3ð /˜Sð /¨ð /À#ð /Èdõ /ñ!�Sð ! ð !¨sð !¸3õ !ð3�cð 3 #ð 3°#ð 3¸$¸s¹)ô 3ñ"3˜T #™Yð 3¨sð 3¸sð 3Èð 3ÐZ^Ð_bÑZcõ 3ð&¨¨U°5¸%°<Ñ-@Ñ(Að Àdô ð	�3ð 	 ð 	¨¯©ô 	ñK Cð K°cð KÀð KÈsð KÐ[_õ Kð$�dð ˜sð  sð ¨x¸¿¹Ñ/Dô ð  -1ÈØ#%Àdòs˜ð s t¨C¡yð s¸sð sÐPSð sØðsØ&)ðsØ8@À¹ðsà ðsà/7¸¸T¹
Ñ/CðsàOTösrN   