Ë
    âß²jáE  ã                  ó0  — U 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Zddl	m
Z
 ddlmZ ddlmZ ddlmZmZmZmZmZ ddlmZ dd	lmZ dd
lmZ dZded<   dZdZdZdZ  ejB                  «       Z" ejF                  «       jH                  Z%d-d„Z&d.d„Z'e
d/d„«       Z(d0d„Z)ddœ	 	 	 	 	 d1d„Z*d2d„Z+d3d„Z,d4d„Z-d5d„Z.d.d„Z/ddœ	 	 	 	 	 	 	 d6d„Z0d7d„Z1d8d„Z2d8d „Z3d8d!„Z4ddd"œ	 	 	 	 	 	 	 	 	 d9d#„Z5d$Z6d%Z7d:d&„Z8dd'dd(œ	 	 	 	 	 	 	 d;d)„Z9d8d*„Z:d<d+„Z;d=d,„Z<y)>uc  Profile-local durable audit ledger for cron execution attempts.

The ledger records what is known about each attempt; it is not a retry queue. Interrupted attempts
become ``unknown`` only after their owner process is proved gone â€” a start-time reading that fails
to match the claim-time fingerprint is not proof of death. Terminal states are immutable.
é    )ÚannotationsN)Úcontextmanager)Údatetime)ÚPath)ÚAnyÚDictÚIteratorÚListÚOptional)Úget_hermes_home)Únow)ÚCLAIM_TTL_INACTIVITY_HEADROOMzOptional[Path]ÚEXECUTIONS_FILEiè  g      >@g      ¼@)Ú	completedÚfailedÚunknownc                 óª   — ddl m}  ddlm} t        xs t        «       j                  «       dz  dz  } | |j                  «        ||ddt        ¬«      S )	Nr   )Ú_ensure_cron_dir)Úopen_dbÚcronzexecutions.dbzcron/executions.dbT)Údb_labelÚsynchronous_fullÚ
initialize)	Ú	cron.jobsr   Úhermes_cli.sqlite_utilr   r   r   ÚresolveÚparentÚ_initialize_schema)r   r   Úpaths      ú4/home/ubuntu/.hermes/hermes-agent/cron/executions.pyÚ_connectr!   (   sI   € õ +Ý.äÒVœÓ0×8Ñ8Ó:¸VÑCÀoÑU€DÙ�T—[‘[Ô!Ù�4Ð"6ÈÔZlÔmÐmó    c                óð   — ddl m} | j                  d«        || ddd«        || ddd«       | j                  d	«       | j                  d
«        || ddd«        || ddd«       | j                  d«       y )Nr   )Úadd_column_if_missingab  CREATE TABLE IF NOT EXISTS executions (
             id TEXT PRIMARY KEY,
             job_id TEXT NOT NULL,
             source TEXT NOT NULL,
             process_id TEXT NOT NULL,
             pid INTEGER NOT NULL,
             process_started_at INTEGER,
             status TEXT NOT NULL CHECK(status IN
               ('claimed','running','completed','failed','unknown')),
             handoff_pending INTEGER NOT NULL DEFAULT 0,
             handoff_started_at REAL,
             claimed_at TEXT NOT NULL,
             started_at TEXT,
             finished_at TEXT,
             error TEXT
           )Ú
executionsÚhandoff_pendingz*handoff_pending INTEGER NOT NULL DEFAULT 0Úhandoff_started_atzhandoff_started_at REALzeCREATE INDEX IF NOT EXISTS idx_executions_job_claimed ON executions(job_id, claimed_at DESC, id DESC)zhCREATE INDEX IF NOT EXISTS idx_executions_status_claimed ON executions(status, claimed_at DESC, id DESC)Údelivery_outcomezdelivery_outcome TEXTÚscheduled_instantzscheduled_instant TEXTzvCREATE INDEX IF NOT EXISTS idx_executions_occurrence ON executions(job_id, scheduled_instant) WHERE status='completed')r   r$   Úexecute)Úconnr$   s     r    r   r   4   sš   € Ý<à‡L�Lð	ôñ$ ØˆlÐ-Ø4ôñ ØˆlÐ0Ð2Kôð 	‡L�Lð	:ôð 	‡L�Lð	:ôñ ˜$ Ð.@ÐBYÔZÙ˜$ Ð.AÐC[Ô\Ø‡L�Lð	Lõr"   c               #  ó    K  — ddl m}  t        5   | t        «       «      5 }|–— d d d «       d d d «       y # 1 sw Y   ŒxY w# 1 sw Y   y xY w­w)Nr   )Útransaction)r   r-   Ú_lockr!   )r-   r+   s     r    Ú_transactionr/   `   sE   è ø€ å2ä	ñ ‘œH›JÓ'ð ¨4ØŠ
÷÷ ÷ ñ ú÷ ð üs-   ‚A�A 6¥A­	A¶?	»AÁAÁAc                ób   — | j                  d|f«      j                  «       }|�t        |«      S d S )Nú#SELECT * FROM executions WHERE id=?)r*   ÚfetchoneÚdict)r+   Úexecution_idÚrows      r    Ú_fetchr6   h   s1   € Ø
�,‰,Ð<¸|¸oÓ
N×
WÑ
WÓ
Y€CØ˜Œ4�‹9Ð1¨TÐ1r"   ©r(   c               óD   — 	 ddl m}  || |¬«       y# t        $ r Y yw xY w)zFProject durable state to monitoring without affecting ledger behavior.r   )Úemit_execution_stater7   N)Úagent.monitoring.cron_healthr9   Ú	Exception)Úrecordr(   r9   s      r    Ú_emit_execution_stater=   m   s'   € ðÝEá˜VÐ6FÖGøÜò Ùðús   ‚ “	žc                ó>   — 	 ddl m}  || «      S # t        $ r Y y w xY w)Nr   )Úget_process_start_time)Úgateway.statusr?   r;   )Úpidr?   s     r    Ú_process_start_timerB   y   s'   € ðÝ9Ù% cÓ*Ð*øÜò Ùðús   ‚ �	›c                ó®   — 	 ddl m}  || «      sy	 |€| t        j                  «       k(  S t        | «      }|€yddl m}  |||«      S # t        $ r Y yw xY w)Nr   )Ú_pid_existsFT)Ústart_time_fingerprints_match)r@   rD   r;   ÚosÚgetpidrB   rE   )rA   Ú
started_atrD   ÚcurrentrE   s        r    Ú_owner_is_liverJ   �   sk   € ðÝ.Ù˜3ÔØð  ð ÐØ”b—i‘i“kÑ!Ð!Ü! #Ó&€GØ€Øõ =Ù(¨°WÓ=Ð=øô ò Ùðús   ‚A Á	AÁAc                 ó¼   — ddl m}  ddlm} t	         | «       «      }t        j                  |«      r|dk  ryt        |t        z  t	         |«       «      t        «      S )u�  Age past which a claimed/running row with a LIVE owner is treated as wedged.

    Derived from the existing knobs, never a bare wall-clock constant:
    ``max(3 Ã— HERMES_CRON_TIMEOUT, cron script timeout, 7200)``. Returns ``None`` (never reclaim
    live owners â€” today's behaviour) when the inactivity timeout is 0/unlimited or not a finite
    positive number: with no bound to derive from, fail closed.
    r   )Ú_cron_inactivity_seconds)Ú_get_script_timeoutN)
Úcron.schedulerrL   Úcron.scheduler_scriptrM   ÚfloatÚmathÚisfiniteÚmaxr   Ú$LIVE_OWNER_STALE_CLAIM_FLOOR_SECONDS)rL   rM   Ú
inactivitys      r    Ú_live_owner_stale_after_secondsrV   “   sR   € õ 8Ý9äÑ/Ó1Ó2€JÜ�=‰=˜Ô$¨
°aªØÜØÔ2Ñ2ÜÑ!Ó#Ó$Ü,óð r"   c                ó^   — t        «       t        j                  | «      z
  j                  «       S )zZSeconds since ``claimed_at`` (NOT NULL, always the aware ISO string from hermes_time.now).)Ú_hermes_nowr   ÚfromisoformatÚtotal_seconds)Ú
claimed_ats    r    Ú_claim_age_secondsr\   ¨   s#   € ä‹MœH×2Ñ2°:Ó>Ñ>×MÑMÓOÐOr"   c           	     óX   — | j                  dt        dt        t        «      «      f«       y )NzéDELETE FROM executions WHERE id IN (
             SELECT id FROM executions
             WHERE status IN ('completed','failed','unknown')
             ORDER BY finished_at DESC, claimed_at DESC, id DESC LIMIT -1 OFFSET ?
           )r   )r*   rS   ÚintÚMAX_TERMINAL_EXECUTIONS)r+   s    r    Ú_prune_unlockedr`   ­   s(   € Ø‡L�Lð	ô
 
ˆQ”Ô+Ó,Ó	-Ð/õr"   ©r)   c               ó�  — ddl m} t        «       j                  «       }t	        j
                  «       j                  }t        j                  «       }t        «       5 }|j                  d|t        | «      t        |«      t        |t        |«      | ||«      f«       t        ||«      }ddd«       t        «       |S # 1 sw Y   ŒxY w)z<Persist a claimed attempt before executor/provider dispatch.r   ra   zÐINSERT INTO executions
               (id, job_id, source, process_id, pid, process_started_at,
                status, claimed_at, scheduled_instant)
               VALUES (?, ?, ?, ?, ?, ?, 'claimed', ?, ?)N)Úcron.occurrencesr)   rX   Ú	isoformatÚuuidÚuuid4ÚhexrF   rG   r/   r*   ÚstrÚ_PROCESS_IDrB   r6   r=   )	Újob_idÚsourcer)   Úcanonical_instantr   r4   rA   r+   r<   s	            r    Úcreate_executionrm   ¸   s¬   € õ Hä
‹-×
!Ñ
!Ó
#€CÜ—:‘:“<×#Ñ#€LÜ
�)‰)‹+€CÜ	‹ð 	,˜4Ø�‰ð=ð œ3˜v›;¬¨F«´[À#Ü  Ó% sÑ,=Ð>OÓ,PðRô	
ô ˜˜lÓ+ˆ÷	,ô ˜&Ô!Ø€M÷	,ð 	,ús   ÁAB<Â<Cc           	     óè   — ddl m} t        «       5 }|j                  d ||«      | t        t        j                  «       f«      }|j                  dk7  rt        d«      ‚	 ddd«       y# 1 sw Y   yxY w)zGBind the store-claimed snapshot before a provider hands it to a worker.r   ra   zzUPDATE executions SET scheduled_instant=? WHERE id=? AND status='claimed' AND handoff_pending=0 AND process_id=? AND pid=?é   z2Cron occurrence could not be bound before dispatchN)	rc   r)   r/   r*   ri   rF   rG   ÚrowcountÚRuntimeError)r4   Úinstantr)   r+   Úcurs        r    Úset_execution_occurrencert   Ï   sn   € å2ä	‹ð U˜4Ø�l‰lð?á˜wÓ'¨´{ÄBÇIÁIÃKÐPó
ˆð
 �<‰<˜1ÒÜÐSÓTÐTð ÷U÷ Uñ Uús   ‘AA(Á(A1c           	     ó   — t        «       5 }|j                  dt        j                  «       | t        t	        j
                  «       f«      }|j                  dk7  r
	 ddd«       yt        || «      }ddd«       t        «       |S # 1 sw Y   ŒxY w)zDFence restart recovery while an external worker is adopting a claim.z§UPDATE executions
               SET handoff_pending=1, handoff_started_at=?
               WHERE id=? AND status='claimed'
                 AND process_id=? AND pid=?ro   N)	r/   r*   Útimeri   rF   rG   rp   r6   r=   )r4   r+   rs   r<   s       r    Úmark_execution_handoff_pendingrw   Ý   sƒ   € ä	‹ð 
,˜4Ø�l‰lð/ô �Y‰Y‹[˜,¬´R·Y±Y³[ÐAó
ˆð �<‰<˜1ÒØ÷
,ð 
,ô ˜˜lÓ+ˆ÷
,ô ˜&Ô!Ø€M÷
,ð 
,ús   ‹ABÁ#BÂBc           	     óH  — t        j                  «       }t        |«      }t        «       j	                  «       }t        «       5 }|j                  dt        |||| f«      }|j                  dk7  r
	 ddd«       yt        || «      }ddd«       t        «       |S # 1 sw Y   ŒxY w)u  Atomically transfer and start an attempt in its worker process.

    The dispatching gateway creates the row before spawning a restart-safe
    worker.  Adoption is the single ``claimed`` â†’ ``running`` gate: only the
    winner may acknowledge ownership or run side effects.
    a  UPDATE executions
               SET process_id=?, pid=?, process_started_at=?,
                   status='running', started_at=?, handoff_pending=0,
                   handoff_started_at=NULL
               WHERE id=? AND status='claimed' AND handoff_pending=1ro   N)rF   rG   rB   rX   rd   r/   r*   ri   rp   r6   r=   )r4   rA   Úprocess_started_atr   r+   rs   r<   s          r    Úadopt_claimed_executionrz   î   s£   € ô �)‰)‹+€CÜ,¨SÓ1ÐÜ
‹-×
!Ñ
!Ó
#€CÜ	‹ð ,˜4Ø�l‰lðHô
 ˜#Ð1°3¸ÐEó
ˆð �<‰<˜1ÒØ÷,ð ,ô ˜˜lÓ+ˆ÷,ô ˜&Ô!Ø€M÷,ð ,ús   Á,BÁ7BÂB!c           	     ó,  — t        «       j                  «       }t        «       5 }|j                  d|| t        t        j                  «       f«      }|j                  dk7  r
	 ddd«       yt        || «      }ddd«       t        «       |S # 1 sw Y   ŒxY w)z7Transition one claimed attempt to running exactly once.zóUPDATE executions
               SET status='running', started_at=?, handoff_pending=0,
                   handoff_started_at=NULL
               WHERE id=? AND status='claimed' AND handoff_pending=0
                 AND process_id=? AND pid=?ro   N)
rX   rd   r/   r*   ri   rF   rG   rp   r6   r=   )r4   r   r+   rs   r<   s        r    Úmark_execution_runningr|     s�   € ä
‹-×
!Ñ
!Ó
#€CÜ	‹ð ,˜4Ø�l‰lð/ð
 �,¤¬R¯Y©Y«[Ð9ó
ˆð �<‰<˜1ÒØ÷,ð ,ô ˜˜lÓ+ˆ÷,ô ˜&Ô!Ø€M÷,ð ,ús   £=B
Á)B
Â
B)Úerrorr(   c               ó~  — t        «       j                  «       }|rdnd}|rdn|rt        |«      nd}t        «       5 }|j	                  d||||| t
        t        j                  «       f«      }|j                  dk7  r
	 ddd«       yt        |«       t        || «      }	ddd«       t        	|¬«       |	S # 1 sw Y   ŒxY w)zDWrite a terminal result once; terminal attempts cannot be rewritten.r   r   Nzunknown failurea  UPDATE executions
               SET status=?, finished_at=?, error=?, handoff_pending=0,
                   handoff_started_at=NULL, delivery_outcome=?
               WHERE id=? AND status IN ('claimed','running')
                 AND process_id=? AND pid=?ro   r7   )rX   rd   rh   r/   r*   ri   rF   rG   rp   r`   r6   r=   )
r4   Úsuccessr}   r(   r   ÚstatusÚdetailr+   rs   r<   s
             r    Úfinish_executionr‚     s¼   € ô
 ‹-×
!Ñ
!Ó
#€CÙ#‰[¨€FÙ‰T±¤3 u¤:Ð<M€FÜ	‹ð ,˜4Ø�l‰lð/ð
 �S˜&Ð"2°LÄ+ÌrÏyÉyË{Ð[ó
ˆð �<‰<˜1ÒØ÷,ð ,ô 	˜ÔÜ˜˜lÓ+ˆ÷,ô ˜&Ð3CÕDØ€M÷,ð ,ús   ¼A B3ÂB3Â3B<z}Scheduler restarted after this execution's owner exited before a durable terminal state; whether side effects ran is unknown.z®Owner process is still alive but the claim outlived the derived stale bound; treated as wedged (#115692). The process was not terminated; whether side effects ran is unknown.c                 óø  — t        «       j                  «       } d}g }d}d}t        «       5 }|j                  d«      j	                  «       }|D ]÷  }|d   t
        k(  rŒt        }t        t        |d   «      |d   «      r(|st        «       }d}|�t        |d	   «      |k  rŒSt        }|d
   }	|d   r*|	�(t        j                  «       t        |	«      z
  t        k  rŒ�|j                  d| ||d   |d   |d   |d   |d   |d
   f«      }
||
j                  z  }|
j                  sŒÕt!        ||d   «      }|€Œç|j#                  |«       Œù |rt%        |«       ddd«       |D ]  }t'        |«       Œ |S # 1 sw Y   ŒxY w)zÏMark abandoned attempts unknown without scheduling retries: rows whose owner is provably
    dead, plus rows whose live owner holds a claim older than the derived stale bound (the
    process is not killed).r   NFzÑSELECT id, status, process_id, pid, process_started_at,
                      handoff_pending, handoff_started_at, claimed_at
               FROM executions
               WHERE status IN ('claimed','running')Ú
process_idrA   ry   Tr[   r'   r&   a6  UPDATE executions
                   SET status='unknown', finished_at=?, error=?,
                       handoff_pending=0, handoff_started_at=NULL
                   WHERE id=? AND status=? AND process_id=? AND pid=?
                     AND handoff_pending=?
                     AND handoff_started_at IS ?Úidr€   )rX   rd   r/   r*   Úfetchallri   Ú_OWNER_GONE_REASONrJ   r^   rV   r\   Ú_OWNER_WEDGED_REASONrv   rP   ÚHANDOFF_ADOPTION_GRACE_SECONDSrp   r6   Úappendr`   r=   )r   ÚchangedÚ	recoveredÚstale_afterÚstale_after_resolvedr+   Úrowsr5   Úreasonr'   rs   r<   s               r    Úrecover_interrupted_executionsr‘   ?  sÉ  € ô ‹-×
!Ñ
!Ó
#€CØ€GØ&(€Ið $(€KØ ÐÜ	‹ð 2"˜4Ø�|‰|ð8ó
÷
 ‰(‹*ð 	ð ò )	-ˆCØ�<Ñ ¤KÒ/ØÜ'ˆFÜœc # e¡*›o¨sÐ3GÑ/HÔIñ ,Ü"AÓ"C�KØ+/Ð(ØÐ&Ô*<¸SÀÑ=NÓ*OÐS^Ò*^ØÜ-�Ø!$Ð%9Ñ!:ÐàÐ%Ò&Ø&Ð2Ü—I‘I“K¤%Ð(:Ó";Ñ;Ü0ò1ð Ø—,‘,ð4ð �f˜c $™i¨¨X©¸¸LÑ8IÈ3ÈuÉ:ØÐ&Ñ'¨Ð-AÑ)BðDó	ˆCð �s—|‘|Ñ#ˆGØ�|‹|Ü  c¨$¡iÓ0�ØÑ%Ø×$Ñ$ VÕ,ðS)	-ñT Ü˜DÔ!÷e2"ðf ò &ˆÜ˜fÕ%ð&à€N÷k2"ð 2"ús   «C6E0Ä"E0Ä4 E0Å0E9é2   )rj   ÚlimitÚbefore_claimed_atc           
     ó  — g }g }| �+|j                  d«       |j                  t        | «      «       |�+|j                  d«       |j                  t        |«      «       |rddj                  |«      z   nd}|j                  t        dt	        t        |«      d«      «      «       t        «       5 }|j                  d	|z   d
z   |«      j                  «       }ddd«       D �cg c]  }t        |«      ‘Œ c}S # 1 sw Y   Œ"xY wc c}w )zFReturn indexed, newest-first execution history with cursor pagination.Nzjob_id=?zclaimed_at < ?z WHERE z AND Ú ro   iô  zSELECT * FROM executionsz* ORDER BY claimed_at DESC, id DESC LIMIT ?)
rŠ   rh   ÚjoinrS   Úminr^   r/   r*   r†   r3   )	rj   r“   r”   ÚclausesÚparamsÚwherer+   r�   r5   s	            r    Úlist_executionsrœ   ‚  sî   € ð €GØ€FØÐØ�‰�zÔ"Ø�‰”c˜&“kÔ"ØÐ$Ø�‰Ð'Ô(Ø�‰”cÐ+Ó,Ô-Ù18ˆI˜Ÿ™ WÓ-Ò-¸b€EØ
‡M�M”#�aœœS ›Z¨Ó-Ó.Ô/Ü	‹ð ˜4Ø�|‰|Ø&¨Ñ.Ø:ñ;àó
÷ ‰(‹*ð	 	÷ð "&Ö&˜#ŒD��IÒ&Ð&÷ð üò 's   Â/'C7Ã"DÃ7D c                ó²   — t        «       5 }|j                  dt        | «      f«      j                  «       }ddd«       �t	        |«      S dS # 1 sw Y   ŒxY w)zBReturn one exact execution attempt, or ``None`` when it is absent.r1   N)r/   r*   rh   r2   r3   )r4   r+   r5   s      r    Úget_executionrž   ™  s[   € ä	‹ð ˜4Ø�l‰lØ1Ü�ÓÐ ó
÷ ‰(‹*ð 	÷ð
 ˜Œ4�‹9Ð1¨TÐ1÷ð ús   ‹+AÁAc                ó.   — t        | d¬«      }|r|d   S d S )Nro   )rj   r“   r   )rœ   )rj   r�   s     r    Úlatest_executionr    £  s   € Ü &°Ô2€DÙˆ4�‰7Ð$ Ð$r"   c                ój  — t         j                  | «      D �cg c]  }|sŒt        |«      ‘Œ }}|si S dj                  d„ |D «       «      }t	        «       5 }|j                  d|› d�|«      j                  «       }ddd«       D �ci c]  }|d   t        |«      “Œ c}S c c}w # 1 sw Y   Œ+xY wc c}w )z9Load latest execution for many jobs in one indexed query.ú,c              3  ó    K  — | ]  }d –— Œ y­w)ú?N© )Ú.0Ú_s     r    ú	<genexpr>z$latest_executions.<locals>.<genexpr>­  s   è ø€ Ò/ AœCÑ/ùs   ‚z@SELECT e.* FROM executions e
                WHERE e.job_id IN (z¿)
                  AND e.id=(SELECT e2.id FROM executions e2
                            WHERE e2.job_id=e.job_id
                            ORDER BY e2.claimed_at DESC, e2.id DESC LIMIT 1)Nrj   )r3   Úfromkeysrh   r—   r/   r*   r†   )Újob_idsrj   ÚcleanÚplaceholdersr+   r�   r5   s          r    Úlatest_executionsr­   ¨  s»   € ä'+§}¡}°WÓ'=ÖH˜VÂŒS��[ÐH€EÐHÙØˆ	Ø—8‘8Ñ/¨Ô/Ó/€LÜ	‹ð ˜4Ø�|‰|ð$Ø$0 >ð 2MðPð
 ó
÷ ‰(‹*ð 	÷ð 15Ö5¨ˆC�‰Mœ4 ›9Ñ$Ò5Ð5ùò I÷ð üò 6s   ˜B BÁ%B$ÂB0Â$B-)Úreturnúsqlite3.Connection)r+   r¯   r®   ÚNone)r®   zIterator[sqlite3.Connection])r+   r¯   r4   rh   r®   úOptional[Dict[str, Any]])r<   r±   r(   úOptional[str]r®   r°   )rA   r^   r®   úOptional[int])rA   r^   rH   r³   r®   Úbool)r®   zOptional[float])r[   rh   r®   rP   )rj   rh   rk   rh   r)   r²   r®   zDict[str, Any])r4   rh   rr   r²   r®   r°   )r4   rh   r®   r±   )
r4   rh   r   r´   r}   r²   r(   r²   r®   r±   )r®   r^   )rj   r²   r“   r^   r”   r²   r®   zList[Dict[str, Any]])rj   rh   r®   r±   )rª   z	List[str]r®   zDict[str, Dict[str, Any]])=Ú__doc__Ú
__future__r   rQ   rF   Úsqlite3Ú	threadingrv   re   Ú
contextlibr   r   Úpathlibr   Útypingr   r   r	   r
   r   Úhermes_constantsr   Úhermes_timer   rX   Úcron.constantsr   r   Ú__annotations__r_   r‰   rT   Ú_TERMINAL_STATESÚRLockr.   rf   rg   ri   r!   r   r/   r6   r=   rB   rJ   rV   r\   r`   rm   rt   rw   rz   r|   r‚   r‡   rˆ   r‘   rœ   rž   r    r­   r¥   r"   r    ú<module>rÂ      s´  ðòõ #ã Û 	Û Û Û Û Ý %Ý Ý ß 6Õ 6å ,Ý *Ý 8ð
 #'€�Ó &ØÐ Ø!%Ð à'-Ð $Ø5Ð Øˆ	�‰Ó€Øˆd�j‰j‹l×Ñ€ó
	nó)ðX òó ðó2ð LPñ	Ø$ð	Ø;Hð	à	ó	óó>ó$ó*Pó
ð EIñØðØðØ4Aðàóó.Uóó"ó4ð( AEØ&*ñØðØ#'ðØ0=ðà#ðð óð4;ð ð
ð ó@ðH  $°"ÐY]ñ'Øð'Ø,/ð'ØIVð'àó'ó.2ó%ô
6r"   