Ë
    ãß²jï@  ã                  ó:  — d Z ddlm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  ej                  d«      Zd	d	d
dddddœZ eh d£«      Zdd„ZdZd d„Zd!d„Zd"d„Zd#d„Zd$d„Zdd„Z	 	 	 	 	 	 d%d„ZdZdZeef	 	 	 	 	 	 	 d&d„Zd'd„Z	 d(	 	 	 	 	 	 	 d)d„Z y)*aC  Image format detection, normalization and region cropping for vision tools.

Everything here runs BEFORE an image is base64-embedded: a vision tool result is
baked into immutable history and re-sent every turn, so an unsupported media type
or corrupt bytes would wedge the session with a non-retryable 400 on every resume.
é    )ÚannotationsN)ÚBytesIO)ÚPath)ÚAnyÚOptional)Úget_hermes_dirztools.vision_toolsú
image/jpegú	image/pngú	image/gifú	image/bmpú
image/webpúimage/svg+xml)z.jpgz.jpegú.pngz.gifz.bmpz.webpú.svg>   r   r
   r	   r   c                ó   — | j                  d«      d   j                  «       }|j                  d«      sy|t        d«      d j	                  dd«      d   j                  «       xs d}|dk(  rd	nd
|› �}|t        v rdS |S )zÕ``image/<subtype>`` of a ``data:image/...`` URL the inline-image wire paths reject
    (``image/jpg`` counts as JPEG); None for accepted rasters and for non-data URLs (the
    provider owns remote-URL validation).ú,r   zdata:image/Nú;é   ÚunknownÚjpgr	   zimage/)Ú	partitionÚlowerÚ
startswithÚlenÚsplitÚstripÚ _ANTHROPIC_SUPPORTED_MEDIA_TYPES)ÚurlÚheaderÚsubtypeÚ
media_types       úB/home/ubuntu/.hermes/hermes-agent/tools/vision_tools_image_prep.pyÚ#unsupported_inline_image_media_typer#   #   s‹   € ð �]‰]˜3Ó Ñ"×(Ñ(Ó*€FØ×Ñ˜]Ô+ØØ”S˜Ó'Ð(Ð)×/Ñ/°°QÓ7¸Ñ:×@Ñ@ÓBÒOÀi€GØ!(¨EÒ!1‘¸À¸yÐ7I€JØÔ!AÑAˆ4ÐQÀzÐQó    ))s   ÿØÿr	   ))s   GIF87as   GIF89ar   )s   BMr   c                ó^   — t         j                  | j                  j                  «       d«      S )z7MIME type from file extension (defaults to image/jpeg).r	   )Ú_EXTENSION_MIME_TYPESÚgetÚsuffixr   )Ú
image_paths    r"   Ú_determine_mime_typer*   4   s$   € ä ×$Ñ$ Z×%6Ñ%6×%<Ñ%<Ó%>ÀÓMÐMr$   c                óš  — | dd }|j                  d«      r<	 ddlm} 	 |j	                  t        | «      «      5 }|j                  «        ddd«       yt        D ]  \  }}|j                  |«      sŒ|c S  t        |«      dk\  r|dd d	k(  r	|d
d dk(  ryt        |«      dk\  rz|dd
 dk(  rr|d
d }t        j                  |dd d«      }|dk  rdnt        |t        |«      «      }|ht        d|dz
  d«      D �	ch c]
  }	||	|	dz    ’Œ c}	z  }
|
h d£z  ry|
h d£z  ryy# t        $ r Y yw xY w# 1 sw Y   yxY w# t        $ r Y yw xY wc c}	w )u¹   Magic-byte MIME sniff (authoritative; no extension trust). ``None`` for anything without a
    recognized header â€” including SVG, which has none (the resolver sniffs ``<svg`` itself).Né@   s   ‰PNG

r   ©ÚImager
   é   é   s   RIFFé   s   WEBPr   s   ftypÚbigé   é   >   ó   av01ó   avifó   avisú
image/avif>   ó   heicó   heimó   heisó   heixó   hevcó   hevxó   mif1ó   msf1ú
image/heic)r   ÚPILr.   ÚImportErrorÚopenr   ÚverifyÚ	ExceptionÚ_MAGIC_MIME_TYPESr   ÚintÚ
from_bytesÚminÚrange)Údatar   r.   ÚimageÚmagicÚmimeÚmajorÚbox_sizeÚlimitÚiÚbrandss              r"   Ú"_detect_image_mime_type_from_bytesrU   9   s  € ð �#�2ˆY€FØ×ÑÐ-Ô.ð	Ý!ð	Ø—‘œG D›MÓ*ð ¨eØ—‘”÷àô )ò ‰ˆˆtØ×Ñ˜UÕ#ØŠKðô ˆ6ƒ{�bÒ˜V B Q˜Z¨7Ò2°v¸aÀ°|ÀwÒ7NØô ˆ6ƒ{�bÒ˜V A a˜[¨GÒ3Ø�q˜�ˆô
 —>‘> &¨¨! *¨eÓ4ˆØ ’m‘¬¨X´s¸6³{Ó)CˆØ�´U¸2¸uÀq¹yÈ!Ó5LÖM°˜F 1 Q¨¡UšOÒMÑMˆàÒ/Ò/ØØò 
ò 
ð
  ØøôK ò 	Ùð	ú÷àûÜò 	Ùð	üò* NsE   ˜D ŸD9 ¹D-Á
D9 Ã9EÄ	D*Ä)D*Ä-D6Ä2D9 Ä6D9 Ä9	EÅEc                 ó¸   — 	 ddl m}  ddlm}m}  |t         | d«      xs d«      t         | d«      xs d«      «      r|S 	 t        S # t        $ r Y t        S w xY w)u  Formats the ACTIVE main model's server can decode. The managed llama-server decodes with
    stb_image â€” no WebP â€” and an undecodable image part fails SILENTLY (the model confabulates),
    so the set is narrowed there and normalization converts those formats to PNG.r   )Ú_runtime_main_value)ÚACCEPTED_IMAGE_MIMESÚis_managed_providerÚproviderÚ Úbase_url)Úagent.auxiliary_clientrW   Ú%hermes_cli.local_runtime.capabilitiesrX   rY   ÚstrrF   r   )Ú_vrX   rY   s      r"   Ú_supported_media_typesra   j   sb   € ðÝDßcÙœs¡2 j£>Ò#7°RÓ8¼#¹bÀ»nÒ>RÐPRÓ:SÔTØ'Ð'ð Uô ,Ð+øô ò ØÜ+Ð+ðús   ‚>A Á	AÁAc                ó`   — | j                  «       xr | j                  «       j                  dkD  S )Nr   )ÚexistsÚstatÚst_size)Úpaths    r"   Ú_nonempty_filerg   x   s$   € Ø�;‰;‹=Ò4˜TŸY™Y›[×0Ñ0°1Ñ4Ð4r$   c                óN  — 	 ddl }|j                  t        | «      t        |«      ¬«       t        |«      S # t        $ r Y nw xY w	 ddlm} ddlm}  |t        | «      «      }|�(|j                  |t        |«      d¬«       t        |«      S n# t        $ r Y nw xY wddl
}ddl}dd	t        |«      t        | «      gd
t        | «      dd|› �gfD ]T  }|j                  |d   «      sŒ	 |j                  |ddd|j                  ¬«       t        |«      r yŒG# t        $ r Y ŒRw xY w y)u_   Best-effort SVG â†’ PNG via cairosvg, svglib+reportlab, rsvg-convert, inkscape (all soft deps).r   N)r   Úwrite_to)Úsvg2rlg)ÚrenderPMÚPNG)Úfmtzrsvg-convertz-oÚinkscapez--export-type=pngz--export-filename=Té   )ÚcheckÚcapture_outputÚtimeoutÚstdinF)ÚcairosvgÚsvg2pngr_   rg   rF   Úsvglib.svglibrj   Úreportlab.graphicsrk   Ú
drawToFileÚshutilÚ
subprocessÚwhichÚrunÚDEVNULL)	Úsvg_pathÚout_pathrt   rj   rk   Údrawingry   rz   Úcmds	            r"   Ú_rasterize_svg_to_pngr‚   |   s>  € ðÛØ×ÑœS ›]´S¸³]ÐÔCÜ˜hÓ'Ð'øÜò ÙðúðÝ)Ý/Ùœ#˜h›-Ó(ˆØÐØ×Ñ ¬¨X«¸EÐÔBÜ! (Ó+Ð+ð øô ò ÙðúãÛà	˜œs 8›}¬c°(«mÐ<Ø	”S˜“]Ð$7Ð;MÈhÈZÐ9XÐYð[ò 	ˆð �<‰<˜˜A™ÕðØ—‘˜s¨$¸tÈRÐWa×WiÑWi�ÔjÜ! (Ô+Ùð ,øäò Ùðúð	ð s4   ‚36 ¶	AÁAÁAB Â	BÂBÃ(+DÄ	D"Ä!D"c           	     óœ  — ddl }ddlm} ddlm} | j                  d«      \  }}}	 d|j                  «       v r|j                  |«      n ||«      j                  «       }t        dd«      }|j                  d	d	¬
«       |dt        j                  «       › �z  }	|	j                  d«      |	j                  d«      }}
	 |
j                  |«       t!        |
|«      s0	 |
|fD ]'  } |t"        «      5  |j%                  «        ddd«       Œ) yd|j'                  |j)                  «       «      j+                  d«      z   |
|fD ]'  } |t"        «      5  |j%                  «        ddd«       Œ) S # t        $ r Y yw xY w# 1 sw Y   Œ¢xY w# 1 sw Y   ŒOxY w# |
|fD ]3  } |t"        «      5  |j%                  «        ddd«       Œ)# 1 sw Y   Œ2xY w w xY w)uZ  ``data:image/svg+xml[;base64],...`` â†’ ``data:image/png;base64,...`` through the same
    soft-dependency rasterizers vision_analyze uses; None when the payload does not decode or no
    rasterizer is available. Request-path callers decide the fallback (Responses backends 400 on
    SVG source, so the caller must never forward the SVG itself).r   N)Úsuppress)Úunquoter   z;base64úcache/visionÚtemp_vision_imagesT©ÚparentsÚexist_okÚinline_r   r   zdata:image/png;base64,Úascii)Úbase64Ú
contextlibr„   Úurllib.parser…   r   r   Ú	b64decodeÚencoderF   r   ÚmkdirÚuuidÚuuid4Úwith_suffixÚwrite_bytesr‚   ÚOSErrorÚunlinkÚ	b64encodeÚ
read_bytesÚdecode)r   r�   r„   r…   r   Ú_ÚpayloadÚrawÚout_dirÚstemr~   Úpng_pathrf   s                r"   Úrasterize_svg_data_urlr¢   œ   sÅ  € ó
 Ý#Ý$ØŸ™ sÓ+Ñ€FˆAˆwðØ+4¸¿¹»Ñ+Fˆf×Ñ˜wÔ'ÉGÐT[ÓL\×LcÑLcÓLeˆô ˜^Ð-AÓB€GØ‡M�M˜$¨€MÔ.Ø�wœtŸz™z›|˜nÐ-Ñ-€DØ×)Ñ)¨&Ó1°4×3CÑ3CÀFÓ3Kˆh€HðØ×Ñ˜SÔ!Ü$ X¨xÔ8Øð ˜xÐ(ò 	ˆDÙœ'Ó"ñ Ø—‘”÷ð ñ	ð (¨&×*:Ñ*:¸8×;NÑ;NÓ;PÓ*Q×*XÑ*XÐY`Ó*aÑaà˜xÐ(ò 	ˆDÙœ'Ó"ñ Ø—‘”÷ð ñ	øô ò Ùðú÷ð ú÷ ð ûð ˜xÐ(ò 	ˆDÙœ'Ó"ñ Ø—‘”÷÷ ñ úñ	úsS   §9E( Â<F Ã-E7Ä	0F ÅFÅ(	E4Å3E4Å7F 	ÆFÆGÆ#F=	Æ4	GÆ=GÇ	Gc                ó¶  — |t        «       v r| |dfS t        dd«      }|j                  dd¬«       |dt        j                  «       › d�z  }|dk(  rt        | |«      r|d	dfS y
|dv r	 ddl}|j                  «        	 ddlm} |j                  | «      5 }|j                  dvr|j                  d«      }|j!                  |d¬«       ddd«       t#        |«      r|d	dfS 	 ddd|›d�fS # t        $ r t        j                  d|«       Y ŒŽw xY w# 1 sw Y   ŒHxY w# t        $ r5}t        j%                  d||«       |dk(  rY d}~y|dk(  rY d}~yY d}~Œsd}~ww xY w)u^  Ensure an image is in a provider-supported format. Returns ``(path, mime, error)``: the input
    unchanged when supported; ``(new_png_path, "image/png", None)`` after conversion â€” a temp file
    the CALLER must clean up; ``(None, None, message)`` when impossible. SVG is rasterized; other
    Pillow-readable rasters (BMP, TIFF) re-encode to PNG.Nr†   r‡   Trˆ   Ú
converted_r   r   r
   )NNu8  This is an SVG, which vision models cannot read directly, and no SVG rasterizer is installed (tried cairosvg, svglib, rsvg-convert, inkscape). Convert the SVG to PNG first â€” e.g. open it in a browser and screenshot it, or install a rasterizer (`pip install cairosvg`) â€” then re-run vision_analyze on the PNG.)rA   r8   r   z1pillow-heif unavailable; relying on Pillow for %sr-   )ÚRGBÚRGBAÚLr¦   rl   ©Úformatz'Failed to normalize %s image to PNG: %srA   )NNzìThis is a HEIC/HEIF image (common for iPhone photos), which vision models cannot read directly, and no HEIF decoder is available. Install one (`pip install pillow-heif`) and re-run vision_analyze, or convert the image to PNG/JPEG first.r8   )NNu  This is an AVIF image, which vision models cannot read directly, and no AV1 decoder is available. Upgrade Pillow (>= 11.3 bundles AVIF support) or install a pillow-heif build with an AV1 codec, then re-run vision_analyze â€” or convert the image to PNG/JPEG first.zImage format z– is not supported by the vision API and could not be converted to PNG (install Pillow for raster conversion). Convert it to PNG or JPEG and try again.)ra   r   r’   r“   r”   r‚   Úpillow_heifÚregister_heif_openerrF   ÚloggerÚdebugrB   r.   rD   ÚmodeÚconvertÚsaverg   Úwarning)r)   Údetected_mimerŸ   r   rª   Ú	_PILImageÚ_imgÚ_excs           r"   Ú_normalize_to_supported_imager¶   ¸   s˜  € ð Ô.Ó0Ñ0Ø˜=¨$Ð.Ð.Ü˜^Ð-AÓB€GØ‡M�M˜$¨€MÔ.Ø˜:¤d§j¡j£l ^°4Ð8Ñ8€HØ˜Ò'Ü  ¨XÔ6Ø˜[¨$Ð.Ð.ðSð Ð4Ñ4ð	]ÛØ×,Ñ,Ô.ð,Ý*Ø�^‰^˜JÓ'ð 	.¨4Ø�y‰yÐ 4Ñ4Ø—|‘| FÓ+�Ø�I‰I�h uˆIÔ-÷	.ô ˜(Ô#Ø˜[¨$Ð.Ð.ð $ð$ �Ø
˜Ð(ð )@ð 	AðBð Bøô5 ò 	]Ü�L‰LÐLÈmÖ\ð	]ú÷	.ð 	.ûô ò ,Ü�‰Ð@À-ÐQUÔVà˜LÒ(ôKð
 ˜LÒ(ô,ô )ûð,úsH   Á(C) Á=D Â3DÃD Ã)DÄ
DÄDÄD Ä	EÄ#EÅEÅEéd   i áõc           	     ó8  — 	 ddl m}m} 	 |j	                  | «      5 }|j                  «        ddd«       |j	                  | «      5 }d}t        |j                  |«      d¬«      D ]h  \  }}||kD  rd|› d|› d�c cddd«       S ||j                  |j                  z  z   }	|	|kD  rd	|	› d
|› d|› d�c cddd«       S |j                  «        |	}Œj 	 ddd«       y# t        $ r Y yw xY w# 1 sw Y   Œ½xY w# 1 sw Y   yxY w# t        $ r}
d|
› �cY d}
~
S d}
~
ww xY w)a  Return an error unless Pillow can fully decode every frame. Header sniffing and ``Image.open``
    only inspect containers: a timed-out download can look like a valid PNG with a truncated pixel
    stream. Without Pillow the image passes unvalidated rather than rejecting everything.r   )r.   ÚImageSequenceNr   )Ústartz+Image validation rejected animation: frame z exceeds the maximum z validated frames.zOImage validation rejected animation: aggregate decoded pixel count would reach z
 at frame z, exceeding the maximum ú.z"Image could not be fully decoded: )rB   r.   r¹   rC   rD   rE   Ú	enumerateÚIteratorÚwidthÚheightÚloadrF   )r)   Ú
max_framesÚ
max_pixelsr³   Ú_PILImageSequencerM   Úvalidated_pixelsÚframe_numberÚframeÚnext_validated_pixelsÚexcs              r"   Ú _validate_raster_image_decodablerÉ   ü   sW  € ðßNð:Ø�^‰^˜JÓ'ð 	¨5Ø�L‰LŒN÷	à�^‰^˜JÓ'ð 	9¨5Ø ÐÜ'0Ð1B×1KÑ1KÈEÓ1RÐZ[Ô'\ò 9Ñ#�˜eØ *Ò,ð!Ø!- Ð.CØ%˜,Ð&8ð:ñ;÷		9ñ 	9ð )9¸5¿;¹;ÈÏÉÑ;UÑ(UÐ%Ø(¨:Ò5ð3Ø3HÐ2IÈØ'˜.Ð(@Ø%˜, að)ñ*÷	9ñ 	9ð —
‘
”Ø#8Ñ ñ9÷	9ð& øô1 ò Ùðú÷	ð 	ú÷	9ð& ûô ò :Ø3°C°5Ð9Õ9ûð:úsz   ‚C ‹D œC)­D Á4C5Á:	D Â.C5Â2	D Â<C5ÃD Ã	C&Ã%C&Ã)C2Ã.D Ã5C>Ã:D Ã>D Ä	DÄ
DÄDÄDc                ó¬   — 	 ddl m} |j                  | «      5 }t        |j                  «      |kD  cddd«       S # 1 sw Y   yxY w# t
        $ r Y yw xY w)uã   True if the longest side exceeds ``max_dimension`` px (Anthropic's 8000px per-side cap is
    independent of bytes). False without Pillow or on unreadable files â€” a missing soft
    dependency must never break the embed path.r   r-   NF)rB   r.   rD   ÚmaxÚsizerF   )r)   Úmax_dimensionr³   r´   s       r"   Ú_image_exceeds_dimensionrÎ      sN   € ðÝ*Ø�^‰^˜JÓ'ð 	2¨4Ü�t—y‘y“> MÑ1÷	2÷ 	2ò 	2ûäò Ùðús+   ‚A ™;±	A »AÁ A ÁA Á	AÁAc                óX  — 	 ddl m} t        |t        t
        f«      r t        |«      dk(  rt        d„ |D «       «      sy	 |j                  | «      5 }|j                  \  }}d„ |D «       \  }}}	}
d„ t        |||	|
f||fd	z  «      D «       \  }}}}||k  s||k  r'd
d
d|› d|› d|	› d|
› d|› d|› d|› d|› d�fcd
d
d
«       S |j                  ||||f«      }|�|j                  ||||z
  ||z
  ¬«       | j                  | j                  › dt        j                   «       j"                  d
d › d�«      }|j$                  dvr|j'                  d«      }|j)                  |d¬«       |dd
fcd
d
d
«       S # t        $ r Y yw xY w# 1 sw Y   y
xY w# t*        $ r}d
d
d|› �fcY d
}~S d
}~ww xY w)u¤  Crop to ``region`` = [x1, y1, x2, y2] (original-image pixels), BEFORE downscaling so the crop
    gets the full resolution budget. Coordinates clamp to the image bounds; a zero-area/inverted
    region is rejected with an error naming the real dimensions. Returns ``(cropped_temp_path,
    mime, None)`` â€” caller owns cleanup â€” or ``(None, None, error)``.
    Ported from QwenLM/qwen-code zoom-image.ts (Apache-2.0).r   r-   )NNz[region cropping requires Pillow (`pip install Pillow`); retry without the region parameter.r0   c              3  ón   K  — | ]-  }t        |t        t        f«      xr t        |t        «       –— Œ/ y ­w©N)Ú
isinstancerH   ÚfloatÚbool©Ú.0Úvs     r"   ú	<genexpr>z%_crop_image_region.<locals>.<genexpr>;  s.   è ø€ Ò\ÐPQ”J˜q¤3¬ ,Ó/ÒK¼
À1ÄdÓ8KÐ4KÓKÑ\ùs   ‚35)NNzdInvalid region: expected [x1, y1, x2, y2] as four numbers (pixel coordinates in the original image).c              3  ó2   K  — | ]  }t        |«      –— Œ y ­wrÑ   )rH   rÕ   s     r"   rØ   z%_crop_image_region.<locals>.<genexpr>B  s   è ø€ Ò5¨œc !ŸfÑ5ùs   ‚c              3  óN   K  — | ]  \  }}t        d t        ||«      «      –— Œ y­w)r   N)rË   rJ   )rÖ   r×   Úbs      r"   rØ   z%_crop_image_region.<locals>.<genexpr>C  s!   è ø€ Ò!k¹¸¸1¤# a¬¨Q°«×"3Ñ!kùs   ‚#%é   NzInvalid region [z, zG]: crops to zero area after clamping to the image bounds. The image is Úxu+    px â€” pick x1<x2 and y1<y2 inside [0, 0, z].)rÝ   Úyr¾   r¿   Ú_region_r1   r   )r¥   r¦   r§   ÚLAÚPr¥   rl   r¨   r
   zFailed to crop region: )rB   r.   rC   rÒ   ÚlistÚtupler   ÚallrD   rÌ   ÚzipÚcropÚupdateÚ	with_namer    r“   r”   Úhexr®   r¯   r°   rF   )r)   ÚregionÚ
offset_outr.   Úimgr¾   r¿   Úx1Úy1Úx2Úy2Úcx1Úcy1Úcx2Úcy2Úcroppedr   rÈ   s                     r"   Ú_crop_image_regionrö   ,  s   € ð3Ýô
 �v¤¤e˜}Ô-´#°f³+ÀÒ2BÜÑ\ÐU[Ô\Ô\ð:ð;Ø�Z‰Z˜
Ó#ð 	/ sØŸH™H‰MˆE�6Ù5¨fÔ5‰NˆB��B˜Ù!kÄÀRÈÈRÐQSÐDTÐW\Ð^dÐVeÐhiÑViÓ@jÔ!kÑˆC��c˜3Ø�cŠz˜S CšZØ˜TØ& r d¨"¨R¨D°°2°$°b¸¸ð =Mà�g˜Q˜v˜hð 'Ø#˜W B v h¨bð2ð3÷	/ñ 	/ð —h‘h  S¨#¨sÐ3Ó4ˆGØÐ%Ø×!Ñ! C¨3°c¸C±iÈÈcÉ	Ð!ÔRØ!×+Ñ+¨z¯©Ð.?¸xÌÏ
É
Ë×HXÑHXÐY[ÐZ[ÐH\ÐG]Ð]aÐ,bÓcˆHØ�|‰|Ð#BÑBØ!Ÿ/™/¨%Ó0�Ø�L‰L˜¨%ˆLÔ0Ø˜[¨$Ð.÷#	/ñ 	/øô ò 3ñ3ð3ú÷	/ð 	/ûô$ ò ;Ø�TÐ4°S°EÐ:Ð:Õ:ûð;ús[   ‚E3 Á F ÁA&FÂ7	F ÃB(FÅ)	F Å3	E?Å>E?ÆFÆF ÆF Æ	F)ÆF$ÆF)Æ$F))r   r_   ÚreturnúOptional[str])r)   r   r÷   r_   )rL   Úbytesr÷   rø   )r÷   Ú	frozenset)rf   r   r÷   rÔ   )r~   r   r   r   r÷   rÔ   )r)   r   r²   r_   r÷   ú3tuple[Optional[Path], Optional[str], Optional[str]])r)   r   rÁ   rH   rÂ   rH   r÷   rø   )r)   r   rÍ   rH   r÷   rÔ   rÑ   )r)   r   rê   r   rë   zOptional[dict]r÷   rû   )!Ú__doc__Ú
__future__r   Úloggingr“   Úior   Úpathlibr   Útypingr   r   Úhermes_constantsr   Ú	getLoggerr¬   r&   rú   r   r#   rG   r*   rU   ra   rg   r‚   r¢   r¶   Ú!_VISION_MAX_VALIDATED_FRAME_COUNTÚ&_VISION_MAX_VALIDATED_AGGREGATE_PIXELSrÉ   rÎ   rö   © r$   r"   ú<module>r     s%  ðñõ #ã Û Ý Ý ß  å +à	ˆ×	Ñ	Ð/Ó	0€ð ØØØØØØñÐ ñ $-Ò-cÓ#dÐ  ó	RðÐ ó
Nó
.ób,ó5óó@ð8;BØð;BØ%(ð;BØ-`ó;Bð@ %(Ð !Ø)4Ð &ð
 8Ø<ð!Øð!àð!ð ð!ð BOó!óH	ð AEð';Øð';Ø!ð';Ø/=ð';à8ô';r$   