Ë
    yÌjo:  ã                   óÒ  — d Z ddlZddlZddlmZ ddlmZ ddlmZ ddl	m
Z
 ddlZddlmZmZmZmZ dZd	\  ZZeez  eez  cZZ eed
z  dz  «      Zdez  dez  dez  cZZZeez   Zdez  Zedez  z
  Zdez  Zedez  z
  Zdez  Z eez   e z   Z!eez
  e!z
  Z"dZ#d\  Z$Z%d\  Z&Z'd\  Z(Z)d\  Z*Z+dZ, ee-«      j]                  «       j^                  j^                  dz  Z0dddddœZ1dd d!g d"¢d#d$d%d&œd'd(d)g d*¢d+d,d-d&œd.d/d0g d1¢d2d3d4d&œd5œZ2 ed6¬7«      d8e3d9e4d:ejj                  fd;„«       Z6ddd<e3d=e7d:e7fd>„Z8ddd?e7d@e7d<e3d=e7d:df
dA„Z9ddd<e3dBe7d=e7d:e3fdC„Z:d<e3dBe7dDe7d:e;e3   fdE„Z<dedFe;e3   dBe7dDe7dGe3d:e;e3   f
dH„Z=dIe;e>e4e>f      d:dfdJ„Z?dKe3dLe7d:ej                  fdM„Z@dfdNe7dOe7dPe7dQe7d:df
dR„ZAdSedTe7dUe7d:e
ej                     fdV„ZBdWddXddYœdZe3d[e;e3   d\e3d]e3d^e3d_e3d`e
e7   dae3dbe
e;e      d:eCfdc„ZDy)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                 ó|   — t        j                  t        t        t        |    z  «      t        |t        z  «      «      S ©N)r	   ÚtruetypeÚstrÚ_FONTSÚ_FILESÚroundÚS)rA   rB   s     ú0/var/www/photos/backend/services/card_service.pyÚ_fontrM   Q   s,   € ä×Ñœc¤&¬6°$©<Ñ"7Ó8¼%ÀÌÁ
Ó:KÓLÐLó    ÚtextÚspacingc                 ón   — t        | j                  |«      «      |t        t        |«      dz
  d«      z  z   S )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                 ó®   — ||j                  «       d   z   }|D ]:  }| j                  ||f|||d¬«       |t        |j                  |«      «      |z   z  }Œ< y)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   s^   € à�—‘Ó" 1Ñ%Ñ%€DØò /ˆØ�	‰	�1�d�)˜R d°¸dˆ	ÔCØ	ŒS�—‘ Ó#Ó$ wÑ.Ñ.‰ñ/rN   Úmax_wc                 ó¬   — t        | ||«      |k  r|S |r.t        | |dz   |«      |kD  r|dd }|rt        | |dz   |«      |kD  rŒ|j                  «       dz   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   sd   € ä	ˆ$��gÓ %Ò'ØˆÙ
”2�d˜D 5™L¨'Ó2°UÒ:Ø�C�Rˆyˆñ ”2�d˜D 5™L¨'Ó2°UÓ:à�;‰;‹=˜5Ñ Ð rN   Ú	max_linesc                 óN  — g d}}|j                  «       D ]>  }|› d|› �j                  «       }|r#t        | |«      |kD  r|j                  |«       |}Œ=|}Œ@ |r|j                  |«       t	        |«      |kD  r|d | }|d   dz   |d<   |D �cg c]  }t        | ||«      ‘Œ c}S c c}w )NÚ ú rg   õ    â€¦)ÚsplitÚstriprX   ÚappendrV   ri   )	rW   rO   re   rj   ÚlinesÚcurÚwordÚtrialÚlns	            rL   Ú_wraprw   k   s¶   € Ø�Rˆ3€EØ—
‘
“ò ˆØ�%�q˜˜�×%Ñ%Ó'ˆÙ”2�d˜E“? UÒ*Ø�L‰L˜ÔØ‰Cà‰Cðñ Ø�‰�SÔÜ
ˆ5ƒz�IÒØ�j�yÐ!ˆØ˜"‘I Ñ&ˆˆb‰	Ø,1Ö2 bŒD��r˜5Õ!Ò2Ð2ùÒ2s   ÂB"ÚitemsÚsepc                 ó$  — g }d}|D ]5  }|r|› |› |› �n|}|r#t        | |«      |kD  r|j                  |«       |}Œ4|}Œ7 |r|j                  |«       t        |«      |kD  r|d| }|dxx   dz  cc<   |D �	cg c]  }	t        | |	|«      ‘Œ c}	S c c}	w )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˜E“? UÒ*Ø�L‰L˜ÔØ‰Cà‰Cðñ Ø�‰�SÔÜ
ˆ5ƒz�IÒØ�j�yÐ!ˆØˆb‹	�VÑ‹	Ø,1Ö2 bŒD��r˜5Õ!Ò2Ð2ùÒ2s   Á6BÚstopsc                 ó<  ‡— ||z
  }t        |«      D ]ˆ  }|t        |dz
  d«      z  }t        ||dd  «      D ]b  \  \  }	}
\  }}||k  sŒ||	k(  rdn
||	z
  ||	z
  z  Š| j                  ||z   |f||z   |dz
  fgt	        ˆfd„t        |
|«      D «       «      ¬«        Œˆ ŒŠ y )NrR   r   c              3   óL   •K  — | ]  \  }}t        |||z
  ‰z  z   «      –— Œ y ­wrE   )rJ   )Ú.0ÚaÚbÚks      €rL   ú	<genexpr>z_hgrad.<locals>.<genexpr>–   s.   øè ø€ ÒFvÑbfÐbcÐefÄuÈQÐRSÐVWÑRWÐ[\ÑQ\É_×G]ÑFvùs   ƒ!$©r^   )ÚrangerU   ÚzipÚlineÚtuple)ra   Úx0Úy0Úx1Úy1r}   ÚnÚiÚtÚp0Úc0Úp1Úc1rƒ   s                @rL   Ú_hgradr•   �   s¿   ø€ Ø
ˆR‰€AÜ�1‹Xò ˆØ”�A˜‘E˜1“ÑˆÜ"% e¨U°1°2¨YÓ"7ò 	Ñ‰HˆR�‘h�r˜2Ø�B‹wØ˜rš‘A¨¨B©°2¸±7Ñ';�Ø—	‘	˜B ™F B˜<¨"¨q©&°"°q±&Ð)9Ð:ÄÓFvÔjmÐnpÐrtÓjuÔFvÓAv�	ÔwÙñ		ñrN   ÚurlÚsize_pxc                 óÄ  — t        j                  | dd¬«      }t        |j                  «      dz   }t	        ||z  d«      }t        j                  «       }|j                  |d|t        dd¬	«       t        j                  |«      j                  d
«      }t        j                  d
||fd«      }|j                  |||j                  z
  dz  ||j                  z
  dz  f«       |S )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Ü�˜1‘˜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¸c¿j¹jÑ4HÈQÑ3NÐOÔPØ€MrN   Úradiusr¯   ÚdashÚgapc           
      ó,  — |\  }}}	}
|}||z   t         z  dz  }|t         z  dz  }t        ||z   |	|z
  |«      D ]V  }| j                  ||ft        ||z   |	|z
  «      |fg||¬«       | j                  ||
ft        ||z   |	|z
  «      |
fg||¬«       ŒX t        ||z   |
|z
  |«      D ]V  }| j                  ||f|t        ||z   |
|z
  «      fg||¬«       | j                  |	|f|	t        ||z   |
|z
  «      fg||¬«       ŒX | j	                  |||d|z  z   |d|z  z   gdd||¬«       | j	                  |	d|z  z
  ||	|d|z  z   gdd||¬«       | j	                  ||
d|z  z
  |d|z  z   |
gdd||¬«       | j	                  |	d|z  z
  |
d|z  z
  |	|
gdd||¬«       y)	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Ø�3‰Jœ!Ñ˜qÑ €DØ	”‰�Q‰€BÜ�2˜‘6˜2 ™6 4Ó(ò MˆØ	�‰��B�œ#˜a "™f b¨1¡fÓ-¨rÐ2Ð3¸$ÀeˆÔLØ	�‰��B�œ#˜a "™f b¨1¡fÓ-¨rÐ2Ð3¸$ÀeˆÕLðMô �2˜‘6˜2 ™6 4Ó(ò MˆØ	�‰��Q�˜"œc ! b¡&¨"¨q©&Ó1Ð2Ð3¸$ÀeˆÔLØ	�‰��Q�˜"œc ! b¡&¨"¨q©&Ó1Ð2Ð3¸$ÀeˆÕLðMð ‡E�Eˆ2ˆr�2˜˜A™‘:˜r A¨¡E™zÐ
*¨C°¸4Àu€EÔMØ‡E�Eˆ2��A‘‰:�r˜2˜r A¨¡E™zÐ
*¨C°¸4Àu€EÔMØ‡E�Eˆ2ˆr�A˜‘E‰z˜2  A¡™: rÐ
*¨B°¸$Àe€EÔLØ‡E�Eˆ2��A‘‰:�r˜A ™E‘z 2 rÐ
*¨A¨r¸ÀE€EÕJrN   ÚpathÚwÚhc                 ó
  — 	 t        j                  | «      5 }t        j                  |«      j	                  d«      }|j                  |dz  |dz  f«       t        j                  |||ft         j                  d¬«      }ddd«       t        j                  d||fd«      }t        j                  |«      j                  dd|dz
  |dz
  gd	t        z  d
¬«       j                  |«       |S # 1 sw Y   ŒmxY w# t        $ r Y yw xY w)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˜Óð 	Y Ü×(Ñ(¨Ó,×4Ñ4°UÓ;ˆBØ�L‰L˜!˜a™%  Q¡˜Ô(Ü—<‘<  Q¨ F´5·=±=ÈKÔXˆD÷	Yô �9‰9�S˜1˜a˜& !Ó$€DÜ‡N�N�4Ó×*Ñ*¨A¨q°!°a±%¸¸Q¹Ð+?ÈÌAÉÐTWÐ*ÔXØ‡M�M�$ÔØ€K÷	Yð 	Yûô ò Ùðús)   ‚C6 —A'C*Á>C6 Ã*C3Ã/C6 Ã6	DÄDr<   rl   )ÚlangÚyearÚbrand_colorÚphotosÚcodeÚclassesÚschool_nameÚ
portal_urlÚ	rgpd_daysrÜ   rÝ   rÞ   rß   c        	         óÚ  ‡— t         j                  |«      xs	 t         d   }	|xs t        j                  «       j                  }|j                  d«      }
|
› d| › �}t        j                  dd|
«      }t        j                  dt        t        fd«      }t        j                  |«      }t        j                  d‰xs d«      rHt        ˆfd	„d
D «       «      }t        d„ |D «       «      }t!        |ddt        t"        d|fd|fd|fg«       n-t!        |ddt        t"        dt$        fdt&        fdt&        fg«       t)        dd«      t)        dd«      }}dt*        z  }t-        |t.        dt*        z  d|d|«       t-        |t.        t1        |d|«      z   |z   dt*        z  d|t2        |«       t5        dt*        z  «      }t7        ||	d   j9                  |j;                  «       ¬«      d|› �z   t        dt.        z  z
  |«      }t-        |t.        dt*        z  ||t<        |«       t!        |dt"        t        t>        dt@        fdt2        fdt@        fg«       t)        dd«      t)        dd «      }}t>        dt*        z  z   }t-        |t.        ||	d!   |t@        t5        d"t*        z  «      «       |d#t*        z  z  }d$jC                  tD        jG                  d%„ |D «       «      «      }|r:t-        |t.        |t7        ||	d&   j9                  |¬'«      tH        «      |t&        «       |d(t*        z  z  }tK        |xs g «      d)tL         }g }|rÖd*t*        z  }tO        |«      }|dk(  rd+n|dk(  rd,nd-t*        z  }|dkD  rtH        ||dz
  z  z
  |z  nd.t*        z  }||z  ||dz
  z  z   } t.        tH        | z
  dz  z   }!|D ]5  }"tQ        tS        |"«      ||«      }#|#�|jU                  |#|!f«       |!||z   z  }!Œ7 |r.|D ]  \  }#}$|jW                  |#|$|f|#«       Œ ||d t*        z  z   z  }t)        dd/«      t)        dd0«      }&}%tY        |	d1   d«      D �]
  \  }'}(t.        d2t*        z  z   |d2t*        z  z   d2t*        z  }+}*})|j[                  |)|+z
  |*|+z
  |)|+z   |*|+z   gt&        ¬3«       t]        |'«      },|&j_                  «       \  }-}.|ja                  |)|*f|,|&dd4¬5«       tc        |%|(tH        d(t*        z  z
  d«      }/|}0|/D ],  }1t-        |t.        d6t*        z  z   |0|1|%d7«       |0d8t*        z  z  }0Œ. |te        tO        |/«      d8z  t*        z  d9t*        z  «      d*t*        z  z   z  }�Œ t        tf        z
  }2|2th        z
  d:t*        z  z
  }3|jk                  t.        |3t.        th        z   dz
  |3th        z   dz
  gd:t*        z  dtl        t*        ¬;«       |jW                  to        |tp        «      t.        d*t*        z  z   |3d*t*        z  z   f«       t)        dd0«      t)        dd0«      t)        d<d«      }6}5}4t5        d"t*        z  «      d=t*        z  d8t*        z  }9}8}7d|9z  d*t*        z  z   |8z   }:|3th        |:z
  dz  z   };t-        |tr        |;|	d>   |4tt        «       |;|9z  };|	d?   dz   }<t-        |tr        |;|<|4tt        «       t-        |tr        t1        |4|<«      z   |;t7        |5|tv        t1        |4|<«      z
  «      |5t&        «       |;|9d*t*        z  z   z  };ty        t1        |6| |7«      d(t*        z  z   tv        «      }=tr        |;tr        |=z   |;|8z   dz
  g}>|jk                  |>d@t*        z  tz        ¬A«       t}        ||>d@t*        z  t@        t5        dt*        z  «      «       |6j_                  «       \  }-}?t-        |tr        d t*        z  z   |;|8|-|?z   z
  dz  z   | |6t&        |7«       |j                  d|2t        t        gt€        ¬3«       |jƒ                  d|2ft        |2fgtl        t*        ¬B«       t)        ddC«      }@tc        |@|	dD   j9                  |¬E«      t        dt.        z  z
  d«      }A|2tf        tO        |A«      dFz  t*        z  z
  dz  z   }B|AD ]&  }1t-        |t.        B|1@tt        «       |BdFt*        z  z  }BŒ( |jk                  ddt        dz
  t        dz
  gd#t*        z  tl        t*        ¬G«       t…        j†                  «       }C|j‰                  |CdHtŠ        tŠ        fd¬I«       |Cj�                  «       S )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   óB   •K  — | ]  }t        ‰||d z    d«      –— Œ y­w)r   r   N©rS   )r€   r�   rÞ   s     €rL   r„   zrender_card.<locals>.<genexpr>×   s#   øè ø€ ÒH¸”s˜; q¨¨Q©Ð/°×4ÑHùs   ƒ)rR   r   é   c              3   ó8   K  — | ]  }t        |d z  «      –— Œ y­w)çffffffæ?Nrè   ©r€   Úcs     rL   r„   zrender_card.<locals>.<genexpr>Ø   s   è ø€ Ò2 a”S˜˜S™—\Ñ2ù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   ó&   K  — | ]	  }|sŒ|–— Œ y ­wrE   © rì   s     rL   r„   zrender_card.<locals>.<genexpr>ë   s   è ø€ Ò(A¨qºq¬Ñ(Aù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_cardrW  Ç   sG  ø€ ô
 
�‰�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ÜÓ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ð		ñ
 Ø"ò 0‘	��cØ—	‘	˜$  a ¨$Õ/ð0à��Rœ!‘V‘‰OˆAô ˜) TÓ*¬E°&¸"Ó,=ˆE€FÜ˜R ™[¨!Ó,ó 6‰ˆˆ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Šð6ô ”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Û   ÚbytesrW  rõ   rN   rL   ú<module>ri     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   