§
    øžyj£ ã                  óÊ  — 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	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ZddlZddlmZmZ ddlmZ ddlmZ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|d
„Z& e	j'        e(¦  «        Z)ddl*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2 ddl3m4Z4 dZ5dZ6dZ7dZ8dZ9dZ:dZ;dZ<dZ=dZ>dZ?dZ@dZAdZB eCh d£¦  «        ZDdZEdZFdZGdZHdZId ZJd!ZKd"ZLe-jM        e-jN        e-jO        e-jP        e-jQ        e-jR        e-jS        d#œZTeU V                    d$¦  «        ZW ejX        d%¦  «        ZY ejX        d&¦  «        ZZ ejX        d'¦  «        Z[ ejX        d(¦  «        Z\ ejX        d)ej]        ¦  «        Z^ ejX        d*ej_        ¦  «        Z` ejX        d+ej_        ¦  «        Zad}d/„Zbe;fd~d3„Zcdd9„Zd G d:„ d;eje        ¦  «        Zfe G d<„ d=¦  «        ¦   «         Zg G d>„ d?¦  «        Zh G d@„ dA¦  «        Zid€dE„Zjd�dK„Zk G dL„ dM¦  «        Zld‚dN„Zmd|dƒdR„Znd„d…dV„Zod†dW„Zpd‡dZ„Zqd[Zrd\esd]<   dˆd_„Ztd‰da„ZudŠd‹de„Zv G df„ dge+¦  «        ZwdŒdk„Zxd�dl„Zyd�dm„Zzd�dn„Z{dŽdp„Z|dddbdqœd�dx„Z}d�dz„Z~d�d{„ZdS )‘ua  
LINE Messaging API platform adapter for Hermes Agent.

A bundled platform plugin that runs an aiohttp webhook server, accepts LINE
webhook events (signature-verified), and relays messages to/from the agent
via the standard ``BasePlatformAdapter`` interface.

Design highlights
-----------------

**Reply token preferred, Push fallback.** LINE's reply token is single-use
and expires roughly 60 seconds after the inbound event. We try Reply first
(it's free) and fall back to the metered Push API when the token is absent,
expired, or rejected by the API.

**Slow-LLM postback button (optional).** When the LLM is still running past
``slow_response_threshold`` seconds (default 45, leaving 15s margin on the
60s reply-token TTL), we burn the original reply token to send a Template
Buttons bubble â€” the user taps it later to receive the cached answer via a
*fresh* reply token (also free). State machine: PENDING â†’ READY â†’ DELIVERED,
with ERROR for cancelled runs. Set the threshold to 0 to disable the
button and always Push-fallback instead.

**Three-allowlist gating.** Separate allowlists for users (U-prefixed),
groups (C-prefixed), and rooms (R-prefixed). ``LINE_ALLOW_ALL_USERS=true``
is a dev-only escape hatch.

**Media via public HTTPS.** LINE's Messaging API does *not* accept
binary uploads â€” images, audio, and video must be reachable HTTPS URLs.
We register registered tempfiles under ``/line/media/<token>/<filename>``
served by the same aiohttp app, with an allowed-roots traversal guard.
``LINE_PUBLIC_URL`` (e.g. ``https://my-tunnel.example.com``) overrides
the host:port construction so URLs are reachable when the bind is a
wildcard/dual-stack listener or behind a reverse proxy.

**5-message batching.** LINE accepts at most 5 message objects per
Reply/Push call; longer responses are smart-chunked at 4500 chars
(LINE per-bubble limit is 5000) and batched.

Synthesis credits
-----------------

This file is a synthesis of seven open community PRs adding LINE support
to Hermes Agent. It deliberately ports the *strongest* idea from each into
a single plugin-form module that requires zero core edits:

* PR #18153 (leepoweii)   â€” Template Buttons postback cache state machine,
  Markdown URL preservation, system-message bypass.
* PR #8398  (yuga-hashimoto) â€” media URL serving with traversal guard,
  send_voice / send_video, ``LINE_PUBLIC_URL`` env, macOS ``/tmp`` root.
* PR #16832 (jethac)      â€” config wiring style, voice/image tests.
* PR #21023 (perng)       â€” plugin-form skeleton (the only one already
  modeled on ``ADDING_A_PLATFORM.md``), replyâ†’push fallback at 50s TTL,
  loading-animation indicator, source dispatcher.
* PR #14942 (soichiyo)    â€” Cloudflare-tunnel operating model (docs only).
* PR #14988 (David-0x221Eight) â€” text-first scope discipline.
* PR #6676  (liyoungc)    â€” Push-only mode (used as the ``threshold=0``
  fallback path here).
é    )ÚannotationsN)Ú	dataclassÚfield)ÚPath)ÚAnyÚDictÚListÚOptionalÚSetÚTuple)Úquote)ÚUnscopedSecretError)Ú
get_secretc                óz   — 	 t          | |¦  «        }n$# t          $ r t          j        | ¦  «        }Y nw xY w|�|n|S )a¹  Scope-aware credential read with the default-profile startup fallback.

    Secondary profiles construct their adapters under a profile secret
    scope -- the scope is authoritative and a scoped miss returns ``default``
    (no cross-profile borrow from ``os.environ``, which may hold another
    profile's value). The DEFAULT profile's adapter constructs and sends
    *unscoped* under multiplexing, where a bare ``get_secret`` would raise
    ``UnscopedSecretError`` and crash this path; there ``os.environ`` is that
    profile's own value, so fall back to it. Same pattern as the Slack
    ``SLACK_APP_TOKEN`` read (#59739) and
    ``gateway/platforms/whatsapp_common.py::_get_wsecret``.
    )Ú_scoped_get_secretÚ_UnscopedSecretErrorÚosÚgetenv)ÚnameÚdefaultÚvals      úD/home/ragecks/.hermes/hermes-agent/plugins/platforms/line/adapter.pyÚ_get_scoped_secretr   W   sR   € ðÝ   wÑ/Ô/ˆˆøÝð ð ð ÝŒi˜‰oŒoˆˆˆðøøøà�/ˆ3ˆ3 wÐ.s   ‚ “4³4)ÚBasePlatformAdapterÚMessageEventÚMessageTypeÚ
SendResultÚcache_audio_from_bytesÚcache_document_from_bytesÚcache_image_from_bytesÚcache_video_from_bytes)ÚPlatformz(https://api.line.me/v2/bot/message/replyz'https://api.line.me/v2/bot/message/pushz-https://api.line.me/v2/bot/chat/loading/startz<https://api-data.line.me/v2/bot/message/{message_id}/contentzhttps://api.line.me/v2/bot/infoiˆ  i”  é   é2   i   iÆ!  z/line/webhookz/line/media>   ú::ú0.0.0.0Ú g     €F@uC   ðŸ¤” Still thinking. Tap below to fetch the answer when it's ready.ú
Get answeru   Already replied âœ…z&Run was interrupted before completion.i  i    i  €)ÚtextÚimageÚvideoÚaudioÚfileÚlocationÚstickerÚŠ89504e470d0a1a0a0000000d49484452000000010000000108060000001f15c4890000000d49444154789c63000100000005000100377a7ff20000000049454e44ae426082z"\[([^\]]+)\]\((https?://[^\s)]+)\)z\*\*(.+?)\*\*z#(?<!\*)\*(?!\s)(.+?)(?<!\s)\*(?!\*)z	`([^`]+)`z```[a-zA-Z0-9_+-]*\n?(.*?)```z
^#{1,6}\s+z^[\s]*[-*+]\s+r)   ÚstrÚreturnc                ó’  — | s| S d
d„}t                                || ¦  «        } t                               d| ¦  «        } t                               d„ | ¦  «        } t                               d| ¦  «        } t
                               d| ¦  «        } t                               d| ¦  «        } t                               d	| ¦  «        } | S )ul  Strip Markdown that LINE can't render, but keep URLs usable.

    LINE's text bubble has zero Markdown support â€” bold, italics, code
    fences, headings, and bullet markers all render as literal characters.
    URLs *are* auto-linked by the client, but only when they appear bare
    (not inside ``[label](url)`` syntax). This converts ``[label](url)``
    to ``label (url)`` so the URL remains tappable, then strips the rest.

    Source: PR #18153 (leepoweii) â€” adapted to keep code-block content
    visible (LINE users frequently want command snippets to land as
    plain text, not be eaten by the fence).
    Úmúre.Matchr2   r1   c                óR   — |                       d¦  «                             d¦  «        S )Né   Ú
)ÚgroupÚrstrip©r4   s    r   Ú_unfencez0strip_markdown_preserving_urls.<locals>._unfenceò   s    € Ø�wŠw�q‰zŒz× Ò  Ñ&Ô&Ð&ó    z\1c                ó^   — |                       d¦  «        › d|                       d¦  «        › d�S )Nr7   z (é   ú))r9   r;   s    r   ú<lambda>z0strip_markdown_preserving_urls.<locals>.<lambda>ú   s+   € ¨¯ª°©
¬
Ð%CÐ%C°a·g²g¸a±j´jÐ%CÐ%CÐ%C€ r=   r'   u   â€¢ )r4   r5   r2   r1   )Ú_MD_CODE_BLOCK_REÚsubÚ_MD_CODE_INLINE_REÚ_MD_LINK_REÚ_MD_BOLD_REÚ_MD_ITAL_REÚ_MD_HEADING_REÚ_MD_BULLET_RE)r)   r<   s     r   Ústrip_markdown_preserving_urlsrJ   á   sÃ   € ð ð Øˆð'ð 'ð 'ð 'å× Ò  ¨4Ñ0Ô0€Dõ ×!Ò! %¨Ñ.Ô.€Dõ �?Š?ÐCÐCÀTÑJÔJ€Dõ �?Š?˜5 $Ñ'Ô'€DÝ�?Š?˜5 $Ñ'Ô'€Dõ ×Ò˜b $Ñ'Ô'€DÝ×Ò˜V TÑ*Ô*€Dà€Kr=   Ú	max_charsÚintú	List[str]c                óh  — | sg S t          | ¦  «        |k    r| gS g }| }|�r#t          |¦  «        t          k     �r
t          |¦  «        |k    r|                     |¦  «         d}nß|                     dd|¦  «        }|t	          |dz  ¦  «        k     r|                     dd|¦  «        }|t	          |dz  ¦  «        k     r|                     dd|¦  «        }|dk    r|}|                     |d|…                              ¦   «         ¦  «         ||d…                              ¦   «         }|rt          |¦  «        t          k     �°
|rk|rF|d         }t          |¦  «        |d	z
  k    r|d|d	z
  …         }|                     ¦   «         d
z   |d<   n#|                     |d|d	z
  …         d
z   ¦  «         |S )a  Split ``text`` into LINE-sized bubbles, preferring paragraph/line breaks.

    Returns at most ``LINE_MAX_MESSAGES_PER_CALL`` chunks; longer text is
    truncated with an ellipsis on the final chunk to keep the response
    deliverable in a single Reply/Push call.
    r'   z

r   g      à?r8   Ú Néÿÿÿÿr7   õ   â€¦)ÚlenÚLINE_MAX_MESSAGES_PER_CALLÚappendÚrfindrL   r:   Úlstrip)r)   rK   ÚchunksÚ	remainingÚcutÚtails         r   Úsplit_for_liner[     sÏ  € ð ð Øˆ	Ý
ˆ4�y„y�IÒÐØˆvˆà€FØ€IØ
ñ -�˜F™œÕ&@Ò@Ñ@Ýˆy‰>Œ>˜YÒ&Ð&Ø�MŠM˜)Ñ$Ô$Ð$ØˆIØà�oŠo˜f a¨Ñ3Ô3ˆØ•�Y ‘_Ñ%Ô%Ò%Ð%Ø—/’/ $¨¨9Ñ5Ô5ˆCØ•�Y ‘_Ñ%Ô%Ò%Ð%Ø—/’/ # q¨)Ñ4Ô4ˆCØ�!Š8ˆ8ØˆCØ�Š�i   ”o×,Ò,Ñ.Ô.Ñ/Ô/Ð/Ø˜c˜d˜d”O×*Ò*Ñ,Ô,ˆ	ð ð -�˜F™œÕ&@Ò@Ñ@ð  ð >àð 	>Ø˜"”:ˆDÝ�4‰yŒy˜9 q™=Ò(Ð(Ø˜O˜i¨!™m˜OÔ,�ØŸš™œ¨Ñ.ˆF�2‰JˆJà�MŠM˜) O i°!¡m OÔ4°uÑ<Ñ=Ô=Ð=Ø€Mr=   ÚbodyÚbytesÚ	signatureÚchannel_secretÚboolc                ó‚  — |r|r| €dS 	 t          j        |                     d¦  «        | t          j        ¦  «                             ¦   «         }t          j        |¦  «                             d¦  «        }n# t          $ r Y dS w xY wt          j
        |                     ¦   «         |                     ¦   «         ¦  «        S )zïVerify a LINE webhook's ``X-Line-Signature`` header.

    LINE signs the *raw* request body with HMAC-SHA256 keyed by the
    channel secret, then base64-encodes the digest. Constant-time
    comparison defends against timing oracles.
    NFúutf-8)ÚhmacÚnewÚencodeÚhashlibÚsha256ÚdigestÚbase64Ú	b64encodeÚdecodeÚ	ExceptionÚcompare_digest)r\   r^   r_   rh   Úexpecteds        r   Úverify_line_signaturero   5  sÈ   € ð ð ˜Nð ¨d¨lØˆuðÝ”Ø×!Ò! 'Ñ*Ô*ØÝŒNñ
ô 
÷ Š&‰(Œ(ð	 	õ
 Ô# FÑ+Ô+×2Ò2°7Ñ;Ô;ˆˆøÝð ð ð Øˆuˆuðøøøõ Ô˜xŸšÑ0Ô0°)×2BÒ2BÑ2DÔ2DÑEÔEÐEs   ŠA,A7 Á7
BÂBc                  ó   — e Zd ZdZdZdZdZdS )ÚStateÚpendingÚreadyÚ	deliveredÚerrorN)Ú__name__Ú
__module__Ú__qualname__ÚPENDINGÚREADYÚ	DELIVEREDÚERROR© r=   r   rq   rq   P  s"   € € € € € Ø€GØ€EØ€IØ€E€E€Er=   rq   c                  óŽ   — e Zd ZU ded<   dZded<   dZded<    eej        ¬	¦  «        Zd
ed<    eej        ¬	¦  «        Z	d
ed<   dS )Ú_CacheEntryrq   ÚstateNr   Úpayloadr'   r1   Úchat_id)Údefault_factoryÚfloatÚ
created_atÚ
updated_at)
rv   rw   rx   Ú__annotations__r�   r‚   r   Útimer…   r†   r}   r=   r   r   r   W  s}   € € € € € € à€L€L�LØ€GÐÐÐÑØ€GÐÐÐÑØ˜¨d¬iÐ8Ñ8Ô8€JÐ8Ð8Ð8Ñ8Ø˜¨d¬iÐ8Ñ8Ô8€JÐ8Ð8Ð8Ñ8Ð8Ð8r=   r   c                  óX   — e Zd ZdZ	 	 ddd	„Zdd„Zdd„Zdd„Zdd„Zd d„Z	d!d„Z
d"d„ZdS )#ÚRequestCacheuÓ   In-memory cache for slow-LLM postback retrieval.

    PRs #18153 originally combined two TTLs â€” one for PENDING (24h) and
    a shorter one for READY/DELIVERED/ERROR (1h). We keep the same model
    here.
    é  é€Q Úttl_secondsrL   Úpending_ttl_secondsr2   ÚNonec                ó0   — i | _         || _        || _        d S ©N)Ú_entriesÚ_ttlÚ_pending_ttl)Úselfr�   rŽ   s      r   Ú__init__zRequestCache.__init__h  s    € ð
 13ˆŒØˆŒ	Ø/ˆÔÐÐr=   r‚   r1   c                óŒ   — t          t          j        ¦   «         ¦  «        }t          t          j        |¬¦  «        | j        |<   |S )N)r€   r‚   )r1   ÚuuidÚuuid4r   rq   ry   r’   )r•   r‚   Úrids      r   Úregister_pendingzRequestCache.register_pendingq  s5   € Ý•$”*‘,”,ÑÔˆÝ(­u¬}ÀgÐNÑNÔNˆŒ�cÑØˆ
r=   Ú
request_idúOptional[_CacheEntry]c                ó6   — | j                              |¦  «        S r‘   )r’   Úget)r•   rœ   s     r   rŸ   zRequestCache.getv  s   € ØŒ}× Ò  Ñ,Ô,Ð,r=   r�   r   c                óÈ   — | j                              |¦  «        }|�|j        t          j        urd S t          j        |_        ||_        t          j        ¦   «         |_        d S r‘   )	r’   rŸ   r€   rq   ry   rz   r�   rˆ   r†   )r•   rœ   r�   Úentrys       r   Ú	set_readyzRequestCache.set_readyy  óS   € Ø”×!Ò! *Ñ-Ô-ˆØˆ=˜EœK­u¬}Ð<Ð<ØˆFÝ”kˆŒØˆŒÝœ9™;œ;ˆÔÐÐr=   Úmessagec                óÈ   — | j                              |¦  «        }|�|j        t          j        urd S t          j        |_        ||_        t          j        ¦   «         |_        d S r‘   )	r’   rŸ   r€   rq   ry   r|   r�   rˆ   r†   )r•   rœ   r¤   r¡   s       r   Ú	set_errorzRequestCache.set_error�  r£   r=   c                óÒ   — | j                              |¦  «        }|�|j        t          j        t          j        hvrd S t          j        |_        t          j        ¦   «         |_        d S r‘   )	r’   rŸ   r€   rq   rz   r|   r{   rˆ   r†   )r•   rœ   r¡   s      r   Úmark_deliveredzRequestCache.mark_delivered‰  sS   € Ø”×!Ò! *Ñ-Ô-ˆØˆ=˜EœKµ´½U¼[Ð/IÐIÐIØˆFÝ”oˆŒÝœ9™;œ;ˆÔÐÐr=   úOptional[str]c                óˆ   — | j                              ¦   «         D ]'\  }}|j        t          j        u r|j        |k    r|c S Œ(d S r‘   )r’   Úitemsr€   rq   ry   r‚   )r•   r‚   rš   r¡   s       r   Úfind_pending_for_chatz"RequestCache.find_pending_for_chat�  sM   € Øœ-×-Ò-Ñ/Ô/ð 	ð 	‰JˆC�ØŒ{�eœmÐ+Ð+°´ÀÒ0HÐ0HØ�
�
�
øØˆtr=   c                óD  — t          j         ¦   «         }d}t          | j                             ¦   «         ¦  «        D ]c}| j        |         }|j        t
          j        u r!||j        z
  | j        k    r| j        |= |dz  }ŒC||j	        z
  | j
        k    r| j        |= |dz  }Œd|S )Nr   r7   )rˆ   Úlistr’   Úkeysr€   rq   ry   r…   r”   r†   r“   )r•   ÚnowÚremovedrš   r¡   s        r   ÚprunezRequestCache.prune–  sª   € ÝŒi‰kŒkˆØˆÝ˜œ×*Ò*Ñ,Ô,Ñ-Ô-ð 		!ð 		!ˆCØ”M #Ô&ˆEØŒ{�eœmÐ+Ð+Ø˜Ô)Ñ)¨DÔ,=Ò=Ð=Øœ cÐ*Ø˜q‘L�Gøà˜Ô)Ñ)¨D¬IÒ5Ð5Øœ cÐ*Ø˜q‘L�GøØˆr=   N)r‹   rŒ   )r�   rL   rŽ   rL   r2   r�   )r‚   r1   r2   r1   )rœ   r1   r2   r�   )rœ   r1   r�   r   r2   r�   )rœ   r1   r¤   r1   r2   r�   )rœ   r1   r2   r�   )r‚   r1   r2   r©   )r2   rL   )rv   rw   rx   Ú__doc__r–   r›   rŸ   r¢   r¦   r¨   r¬   r²   r}   r=   r   rŠ   rŠ   `  sË   € € € € € ðð ð  Ø#(ð0ð 0ð 0ð 0ð 0ðð ð ð ð
-ð -ð -ð -ð'ð 'ð 'ð 'ð'ð 'ð 'ð 'ð'ð 'ð 'ð 'ðð ð ð ðð ð ð ð ð r=   rŠ   c                  ó$   — e Zd ZdZddd„Zdd„ZdS )Ú_MessageDeduplicatorzFBounded LRU of LINE webhook event IDs to ignore at-least-once retries.éè  Úmax_sizerL   r2   r�   c                ó"   — i | _         || _        d S r‘   )Ú_seenÚ_max)r•   r·   s     r   r–   z_MessageDeduplicator.__init__­  s   € Ø')ˆŒ
ØˆŒ	ˆ	ˆ	r=   Úevent_idr1   r`   c                óp  ‡— |sdS || j         v rdS t          | j         ¦  «        | j        k    rmt          | j                              ¦   «         ¦  «        t          | j         ¦  «        dz  pd         Šˆfd„| j                              ¦   «         D ¦   «         | _         t          j        ¦   «         | j         |<   dS )NFTé
   r7   c                ó(   •— i | ]\  }}|‰k    ¯||“ŒS r}   r}   )Ú.0ÚkÚvÚcutoffs      €r   ú
<dictcomp>z5_MessageDeduplicator.is_duplicate.<locals>.<dictcomp>¹  s$   ø€ ÐLÐLÐL¡4 1 aÀÀVÂÀ˜!˜QÀÀÀr=   )r¹   rR   rº   ÚsortedÚvaluesr«   rˆ   )r•   r»   rÂ   s     @r   Úis_duplicatez!_MessageDeduplicator.is_duplicate±  s©   ø€ Øð 	Ø�5Ø�t”zÐ!Ð!Ø�4ÝˆtŒz‰?Œ?˜dœiÒ'Ð'å˜DœJ×-Ò-Ñ/Ô/Ñ0Ô0µ°T´Z±´ÀBÑ1FÐ1KÈ!ÔLˆFØLÐLÐLÐL¨4¬:×+;Ò+;Ñ+=Ô+=ÐLÑLÔLˆDŒJÝ#œy™{œ{ˆŒ
�8ÑØˆur=   N©r¶   )r·   rL   r2   r�   )r»   r1   r2   r`   )rv   rw   rx   r³   r–   rÆ   r}   r=   r   rµ   rµ   ª  sG   € € € € € ØPÐPðð ð ð ð ð
ð 
ð 
ð 
ð 
ð 
r=   rµ   ÚsourceúDict[str, Any]úTuple[str, str]c                óê   — | pi                       dd¦  «        }|dk    r|                       dd¦  «        dfS |dk    r|                       dd¦  «        dfS |dk    r|                       dd¦  «        d	fS d
S )uy  Return ``(chat_id, chat_type)`` from a LINE event ``source`` block.

    LINE sources are one of:
      * ``{"type": "user",  "userId":  "U..."}``  â†’ 1:1 DM
      * ``{"type": "group", "groupId": "C...", "userId": "U..."}``  â†’ group chat
      * ``{"type": "room",  "roomId":  "R...", "userId": "U..."}``  â†’ multi-user room

    Source: PR #21023 (perng), unchanged.
    Útyper'   r9   ÚgroupIdÚroomÚroomIdÚuserÚuserIdÚdm)r'   rÒ   ©rŸ   )rÈ   Úsrc_types     r   Ú_resolve_chatrÕ   Â  sŽ   € ð �˜"×!Ò! &¨"Ñ-Ô-€HØ�7ÒÐØ�zŠz˜) RÑ(Ô(¨'Ð1Ð1Ø�6ÒÐØ�zŠz˜( BÑ'Ô'¨Ð/Ð/Ø�6ÒÐØ�zŠz˜( BÑ'Ô'¨Ð-Ð-Øˆ8r=   Ú	allow_allÚuser_idsúSet[str]Ú	group_idsÚroom_idsc               óX  — |rdS | pi                       dd¦  «        }|dk    r)|                       dd¦  «        }t          |¦  «        o||v S |dk    r)|                       dd¦  «        }t          |¦  «        o||v S |dk    r)|                       d	d¦  «        }t          |¦  «        o||v S d
S )u%   Three-list gate â€” credit PR #18153.TrÌ   r'   rÐ   rÑ   r9   rÍ   rÎ   rÏ   F)rŸ   r`   )	rÈ   rÖ   r×   rÙ   rÚ   rÔ   ÚuidÚgidrš   s	            r   Ú_allowed_for_sourcerÞ   Ö  sÉ   € ð ð ØˆtØ�˜"×!Ò! &¨"Ñ-Ô-€HØ�6ÒÐØ�jŠj˜ 2Ñ&Ô&ˆÝ�C‰yŒyÐ,˜S H˜_Ð,Ø�7ÒÐØ�jŠj˜ BÑ'Ô'ˆÝ�C‰yŒyÐ-˜S IÐ-Ð-Ø�6ÒÐØ�jŠj˜ 2Ñ&Ô&ˆÝ�C‰yŒyÐ,˜S H˜_Ð,Øˆ5r=   c                  óJ   — e Zd ZdZddœdd
„Zdd„Zdd„Zddd„Zd d„Zd!d„Z	dS )"Ú_LineClientzôThin async wrapper around the LINE Messaging API.

    We use ``aiohttp`` directly to avoid a ``line-bot-sdk`` dependency
    (the SDK pulls in its own httpx pin and the ergonomic gain is small
    for the four endpoints we actually call).
    g      .@)ÚtimeoutÚchannel_access_tokenr1   rá   r„   r2   r�   c               ó<   — || _         || _        d|› �ddœ| _        d S )NúBearer zapplication/json)ÚAuthorizationúContent-Type)Ú_tokenÚ_timeoutÚ_headers)r•   râ   rá   s      r   r–   z_LineClient.__init__ú  s1   € Ø*ˆŒØˆŒà=Ð';Ð=Ð=Ø.ð
ð 
ˆŒˆˆr=   Úreply_tokenÚmessagesúList[Dict[str, Any]]c           
   ƒ  óü  K  — dd l }|                     | j        ¬¦  «        }|                     |d¬¦  «        4 ƒd {V —†}|                     t
          | j        ||dœ¬¦  «        4 ƒd {V —†	 }|j        dk    r<|                     ¦   «         ƒ d {V —†}t          d|j        › d	|d d
…         › �¦  «        ‚	 d d d ¦  «        ƒd {V —† n# 1 ƒd {V —†swxY w Y   d d d ¦  «        ƒd {V —† d S # 1 ƒd {V —†swxY w Y   d S )Nr   ©ÚtotalT©rá   Ú	trust_env)Ú
replyTokenrë   ©ÚheadersÚjsoné�  zLINE reply ú: éÈ   )
ÚaiohttpÚClientTimeoutrè   ÚClientSessionÚpostÚLINE_REPLY_URLré   Ústatusr)   ÚRuntimeError)r•   rê   rë   rù   rá   ÚsessionÚrespr\   s           r   Úreplyz_LineClient.reply  s{  è è € ØˆˆˆØ×'Ò'¨d¬mÐ'Ñ<Ô<ˆØ×(Ò(°ÀDÐ(ÑIÔIð 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	RÈWØ—|’|ÝØœØ$/¸XÐFÐFð $ñ ô ð Rð Rð Rð Rð Rð Rð Rð Rð Ø”; #Ò%Ð%Ø!%§¢¡¤Ð,Ð,Ð,Ð,Ð,Ð,�DÝ&Ð'P°T´[Ð'PÐ'PÀDÈÈ#ÈÄJÐ'PÐ'PÑQÔQÐQÐQðRð Rð Rñ Rô Rð Rð Rð Rð Rð Rð Rð Rð Rð Rð Rð Rð Rð Rð Rð Rð Rð Rð Røøøð Rð Rð Rð Rð	Rð 	Rð 	Rñ 	Rô 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	Rð 	Røøøð 	Rð 	Rð 	Rð 	Rð 	Rð 	Ró6   ¿,C+Á,ACÂ5C+Ã
C	ÃC+ÃC	ÃC+Ã+
C5Ã8C5r‚   c           
   ƒ  óü  K  — dd l }|                     | j        ¬¦  «        }|                     |d¬¦  «        4 ƒd {V —†}|                     t
          | j        ||dœ¬¦  «        4 ƒd {V —†	 }|j        dk    r<|                     ¦   «         ƒ d {V —†}t          d|j        › d	|d d
…         › �¦  «        ‚	 d d d ¦  «        ƒd {V —† n# 1 ƒd {V —†swxY w Y   d d d ¦  «        ƒd {V —† d S # 1 ƒd {V —†swxY w Y   d S )Nr   rî   Trð   )Útorë   ró   rö   z
LINE push r÷   rø   )
rù   rú   rè   rû   rü   ÚLINE_PUSH_URLré   rþ   r)   rÿ   )r•   r‚   rë   rù   rá   r   r  r\   s           r   Úpushz_LineClient.push  s{  è è € ØˆˆˆØ×'Ò'¨d¬mÐ'Ñ<Ô<ˆØ×(Ò(°ÀDÐ(ÑIÔIð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	QÈWØ—|’|ÝØœØ#°Ð:Ð:ð $ñ ô ð Qð Qð Qð Qð Qð Qð Qð Qð Ø”; #Ò%Ð%Ø!%§¢¡¤Ð,Ð,Ð,Ð,Ð,Ð,�DÝ&Ð'O°D´KÐ'OÐ'OÀ4ÈÈÈÄ:Ð'OÐ'OÑPÔPÐPÐPðQð Qð Qñ Qô Qð Qð Qð Qð Qð Qð Qð Qð Qð Qð Qð Qð Qð Qð Qð Qð Qð Qð Qøøøð Qð Qð Qð Qð	Qð 	Qð 	Qñ 	Qô 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qøøøð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qr  é<   ÚsecondsrL   c              ƒ  óþ  K  — |r|                      d¦  «        sdS ddl}t          dt          d|dz  dz  pd¦  «        ¦  «        }	 |                     d¬¦  «        }|                     |d¬	¦  «        4 ƒd{V —†}|                     t          | j        ||d
œ¬¦  «        ƒ d{V —† ddd¦  «        ƒd{V —† dS # 1 ƒd{V —†swxY w Y   dS # t          $ r&}t                               d|¦  «         Y d}~dS d}~ww xY w)z@Loading indicator (DM only). LINE rejects this for groups/rooms.ÚUNr   r#   r  g      @rî   Trð   )ÚchatIdÚloadingSecondsró   z!LINE loading indicator failed: %s)Ú
startswithrù   ÚmaxÚminrú   rû   rü   ÚLINE_LOADING_URLré   rl   ÚloggerÚdebug)r•   r‚   r	  rù   Úclampedrá   r   Úexcs           r   Úloadingz_LineClient.loading  sá  è è € àð 	˜g×0Ò0°Ñ5Ô5ð 	ØˆFØˆˆˆå�a�˜R '¨Q¡,°!Ñ!3Ð!8°qÑ9Ô9Ñ:Ô:ˆð		CØ×+Ò+°#Ð+Ñ6Ô6ˆGØ×,Ò,°WÈÐ,ÑMÔMð ð ð ð ð ð ð ÐQXØ—l’lÝ$Ø œMØ$+¸wÐGÐGð #ñ ô ð ð ð ð ð ð ð ðð ð ñ ô ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð øøøð ð ð ð ð ð øõ ð 	Cð 	Cð 	CÝ�LŠLÐ<¸cÑBÔBÐBÐBÐBÐBÐBÐBÐBøøøøð	Cøøøs<   Á3C Á:,B9Â&C Â9
CÃC ÃCÃC Ã
C<ÃC7Ã7C<Ú
message_idr]   c              ƒ  ó,  K  — ddl }t                               |¬¦  «        }|                     d¬¦  «        }|                     |d¬¦  «        4 ƒd{V —†}|                     |dd	| j        › �i¬
¦  «        4 ƒd{V —†}|j        dk    rt          d|j        › �¦  «        ‚| 	                    ¦   «         ƒ d{V —†cddd¦  «        ƒd{V —† cddd¦  «        ƒd{V —† S # 1 ƒd{V —†swxY w Y   	 ddd¦  «        ƒd{V —† dS # 1 ƒd{V —†swxY w Y   dS )z3Download an inbound media message's binary content.r   N)r  g      >@rî   Trð   rå   rä   ©rô   rö   zLINE content )
rù   ÚLINE_CONTENT_URL_FMTÚformatrú   rû   rŸ   rç   rþ   rÿ   Úread)r•   r  rù   Úurlrá   r   r  s          r   Úfetch_contentz_LineClient.fetch_content.  sp  è è € àˆˆˆÝ"×)Ò)°ZÐ)Ñ@Ô@ˆØ×'Ò'¨dÐ'Ñ3Ô3ˆØ×(Ò(°ÀDÐ(ÑIÔIð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ÈWØ—{’{ 3°ÐBYÈDÌKÐBYÐBYÐ0Z�{Ñ[Ô[ð )ð )ð )ð )ð )ð )ð )Ð_cØ”; #Ò%Ð%Ý&Ð'D°t´{Ð'DÐ'DÑEÔEÐEØ!ŸYšY™[œ[Ð(Ð(Ð(Ð(Ð(Ð(ð)ð )ð )ð )ñ )ô )ð )ð )ð )ð )ð )ð )ð )ð	)ð 	)ð 	)ð 	)ñ 	)ô 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð)ð )ð )ð )ð )ð )ð )ð )ð )ð )øøøð )ð )ð )ð )ð )ð	)ð 	)ð 	)ñ 	)ô 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)øøøð 	)ð 	)ð 	)ð 	)ð 	)ð 	)s6   Á(DÁ=<CÂ9DÃ
C(	Ã(DÃ+C(	Ã,DÄ
DÄDr©   c              ƒ  ó`  K  — ddl }|                     d¬¦  «        }	 |                     |d¬¦  «        4 ƒd{V —†}|                     t          | j        ¬¦  «        4 ƒd{V —†}|j        dk    r%	 ddd¦  «        ƒd{V —† ddd¦  «        ƒd{V —† dS |                     ¦   «         ƒ d{V —†}|                     d	¦  «        cddd¦  «        ƒd{V —† cddd¦  «        ƒd{V —† S # 1 ƒd{V —†swxY w Y   	 ddd¦  «        ƒd{V —† dS # 1 ƒd{V —†swxY w Y   dS # t          $ r Y dS w xY w)
z?Fetch this channel's own userId so we can filter self-messages.r   Ng      $@rî   Trð   r  rö   rÑ   )	rù   rú   rû   rŸ   ÚLINE_BOT_INFO_URLré   rþ   rõ   rl   )r•   rù   rá   r   r  Údatas         r   Úget_bot_user_idz_LineClient.get_bot_user_id9  sö  è è € àˆˆˆØ×'Ò'¨dÐ'Ñ3Ô3ˆð	Ø×,Ò,°WÈÐ,ÑMÔMð .ð .ð .ð .ð .ð .ð .ÐQXØ"Ÿ;š;Õ'8À$Ä-˜;ÑPÔPð .ð .ð .ð .ð .ð .ð .ÐTXØ”{ cÒ)Ð)Ø#ð.ð .ð .ñ .ô .ð .ð .ð .ð .ð .ð .ð .ð.ð .ð .ñ .ô .ð .ð .ð .ð .ð .ð .ð .ð .ð .ð "&§¢¡¤Ð,Ð,Ð,Ð,Ð,Ð,�DØŸ8š8 HÑ-Ô-ð	.ð .ð .ð .ñ .ô .ð .ð .ð .ð .ð .ð .ð .ð.ð .ð .ð .ñ .ô .ð .ð .ð .ð .ð .ð .ð .ð .ð.ð .ð .ð .ð .ð .ð .ð .ð .ð .øøøð .ð .ð .ð .ð .ð.ð .ð .ñ .ô .ð .ð .ð .ð .ð .ð .ð .ð .ð .ð .ð .ð .ð .ð .ð .ð .ð .ð .ð .øøøð .ð .ð .ð .ð .ð .øõ ð 	ð 	ð 	Ø�4�4ð	øøøsp   žD »(DÁ#C'Á0DÂD Â.C'ÃDÃD Ã'
C1	Ã1DÃ4C1	Ã5DÃ9D Ä
DÄD ÄDÄD Ä
D-Ä,D-N)râ   r1   rá   r„   r2   r�   )rê   r1   rë   rì   r2   r�   )r‚   r1   rë   rì   r2   r�   )r  )r‚   r1   r	  rL   r2   r�   )r  r1   r2   r]   )r2   r©   )
rv   rw   rx   r³   r–   r  r  r  r  r"  r}   r=   r   rà   rà   ò  s¹   € € € € € ðð ð GKð 
ð 
ð 
ð 
ð 
ð 
ðRð Rð Rð RðQð Qð Qð QðCð Cð Cð Cð Cð$	)ð 	)ð 	)ð 	)ðð ð ð ð ð r=   rà   c                óf   — t          | ¦  «        t          k    r| dt          dz
  …         dz   } d| dœS )z;Build a LINE text message object, capped to per-bubble max.Nr7   rQ   r)   )rÌ   r)   )rR   ÚLINE_PER_BUBBLE_CHARS)r)   s    r   Ú_text_messager%  L  s=   € å
ˆ4�y„yÕ(Ò(Ð(ØÐ/Õ+¨aÑ/Ð/Ô0°5Ñ8ˆØ DÐ)Ð)Ð)r=   Úoriginal_urlÚpreview_urlr©   c                ó   — d| |p| dœS )Nr*   ©rÌ   ÚoriginalContentUrlÚpreviewImageUrlr}   )r&  r'  s     r   Ú_image_messager,  S  s   € àØ*Ø&Ð6¨,ðð ð r=   r¶   r  Úduration_msc                ó(   — d| t          |¦  «        dœS )Nr,   )rÌ   r*  Úduration)rL   )r  r-  s     r   Ú_audio_messager0  [  s"   € àØ!Ý˜Ñ$Ô$ðð ð r=   c                ó   — d| |dœS )Nr+   r)  r}   )r  r'  s     r   Ú_video_messager2  c  s   € àØ!Ø&ðð ð r=   Úbutton_labelrœ   c                óü   — t          | ¦  «        dk    r| n| dd…         dz   }t          | ¦  «        dk    r| n| dd…         dz   }d|d|d	|dd
…         pdt          j        d|dœ¦  «        |dd…         pddœgdœdœS )u<  Template Buttons message â€” the slow-LLM postback bubble.

    From PR #18153 (leepoweii). Template Buttons stay tappable from chat
    history, unlike Quick Reply chips which are dismissed the moment any
    new message arrives in the chat.

    LINE limits: ``text`` â‰¤ 160 chars, ``altText`` â‰¤ 400 chars.
    é    Né�   z...rö   i�  ÚtemplateÚbuttonsÚpostbacké   r(   Úshow_response)Úactionrœ   i,  )rÌ   Úlabelr!  ÚdisplayText)rÌ   r)   Úactions)rÌ   ÚaltTextr7  )rR   rõ   Údumps)r)   r3  rœ   Ú	truncatedÚalts        r   Úbuild_postback_button_messagerD  k  sÇ   € õ ˜D™	œ	 SÒ(Ð(��¨d°4°C°4¬j¸5Ñ.@€IÝ�d‘)”)˜sÒ"Ð"ˆ$ˆ$¨¨T¨c¨T¬
°UÑ(:€CàØàØð 'Ø)¨#¨2¨#Ô.Ð>°,Ý œJØ#2À*ÐMÐMñô ð $0°°°Ô#5Ð#E¸ðð ð	ð
ð 
ðð ð r=   )u   âš¡ Interruptingu
   â�³ Queuedu   â�© Steeredu   ðŸ’¾zTuple[str, ...]Ú_SYSTEM_BYPASS_PREFIXESÚcontentc                óL   ‡ — ‰ sdS t          ˆ fd„t          D ¦   «         ¦  «        S )NFc              3  óB   •K  — | ]}‰                      |¦  «        V — Œd S r‘   )r  )r¿   ÚprF  s     €r   ú	<genexpr>z$_is_system_bypass.<locals>.<genexpr>›  s1   øè è € ÐFÐF¨ˆw×!Ò! !Ñ$Ô$ÐFÐFÐFÐFÐFÐFr=   )ÚanyrE  )rF  s   `r   Ú_is_system_bypassrL  ˜  s4   ø€ Øð ØˆuÝÐFÐFÐFÐFÕ.EÐFÑFÔFÑFÔFÐFr=   Úvaluec                ó`   — | st          ¦   «         S d„ |                      d¦  «        D ¦   «         S )Nc                ó^   — h | ]*}|                      ¦   «         ¯|                      ¦   «         ’Œ+S r}   )Ústrip)r¿   Úxs     r   ú	<setcomp>z_csv_set.<locals>.<setcomp>¥  s-   € Ð=Ð=Ð=˜!°1·7²7±9´9Ð=ˆA�GŠG‰IŒIÐ=Ð=Ð=r=   Ú,)ÚsetÚsplit)rM  s    r   Ú_csv_setrV  ¢  s3   € Øð Ý‰uŒuˆØ=Ð=˜uŸ{š{¨3Ñ/Ô/Ð=Ñ=Ô=Ð=r=   Fr   r   c                ó‚   — t          j        | ¦  «        }|€|S |                     ¦   «                              ¦   «         dv S )N>   Ú1ÚonÚyesÚtrue)r   r   rP  Úlower)r   r   rÁ   s      r   Ú_truthy_envr]  ¨  s7   € Ý
Œ	�$‰Œ€AØ€yØˆØ�7Š7‰9Œ9�?Š?ÑÔÐ :Ð:Ð:r=   c                  ó  ‡ — e Zd ZdZˆ fd„ZddœdCd„ZdDd
„ZdEd„ZdEd„ZdFd„Z	dFd„Z
dFd„ZddœdGd„Z	 	 dHdId"„ZdJd$„ZdKd&„ZdLdMd'„ZdNd(„ZdOd)„ZdMˆ fd*„ZdPˆ fd,„Zdd-œdQd0„ZdRd2„ZdSd3„ZdEd4„Z	 	 dHdTd7„Z	 	 dUdVd<„Z	 	 dHdWd?„ZdXdB„Zˆ xZS )YÚLineAdapterz#LINE Messaging API gateway adapter.c           	     óæ  •— t          d¦  «        }t          ¦   «                              ||¬¦  «         t          |di ¦  «        pi }t	          d¦  «        p|                     dd¦  «        | _        t	          d¦  «        p|                     dd¦  «        | _        t          j	        d	¦  «        p!|                     d
t          ¦  «        pt          | _        	 t          t          j	        d¦  «        p|                     dt          ¦  «        ¦  «        | _        n## t          t           f$ r t          | _        Y nw xY w|                     dt"          ¦  «        | _        t          j	        d¦  «        p|                     dd¦  «        pd                     d¦  «        | _        t+          dt-          |                     dd¦  «        ¦  «        ¦  «        | _        t1          t          j	        dd¦  «        ¦  «        t3          |                     dg ¦  «        ¦  «        z  | _        t1          t          j	        dd¦  «        ¦  «        t3          |                     dg ¦  «        ¦  «        z  | _        t1          t          j	        dd¦  «        ¦  «        t3          |                     dg ¦  «        ¦  «        z  | _        	 t;          t          j	        d¦  «        p|                     dt<          ¦  «        ¦  «        | _        n## t          t           f$ r t<          | _        Y nw xY wt          j	        d¦  «        p|                     dt@          ¦  «        | _!        t          j	        d¦  «        p|                     dtD          ¦  «        | _#        t          j	        d ¦  «        p|                     d!tH          ¦  «        | _%        t          j	        d"¦  «        p|                     d#tL          ¦  «        | _'        d | _(        d | _)        d | _*        d | _+        i | _,        t[          ¦   «         | _.        t_          ¦   «         | _0        d | _1        d | _2        i | _3        t3          ¦   «         | _4        tj          | _6        i | _7        d S )$NÚline)ÚconfigÚplatformÚextraÚLINE_CHANNEL_ACCESS_TOKENrâ   r'   ÚLINE_CHANNEL_SECRETr_   Ú	LINE_HOSTÚhostÚ	LINE_PORTÚportÚwebhook_pathÚLINE_PUBLIC_URLÚ
public_urlú/ÚLINE_ALLOW_ALL_USERSÚallow_all_usersFÚLINE_ALLOWED_USERSÚallowed_usersÚLINE_ALLOWED_GROUPSÚallowed_groupsÚLINE_ALLOWED_ROOMSÚallowed_roomsÚLINE_SLOW_RESPONSE_THRESHOLDÚslow_response_thresholdÚLINE_PENDING_TEXTÚpending_textÚLINE_BUTTON_LABELr3  ÚLINE_DELIVERED_TEXTÚdelivered_textÚLINE_INTERRUPTED_TEXTÚinterrupted_text)8r"   Úsuperr–   Úgetattrr   rŸ   râ   r_   r   r   ÚDEFAULT_HOSTÚwebhook_hostrL   ÚDEFAULT_WEBHOOK_PORTÚwebhook_portÚ	TypeErrorÚ
ValueErrorÚDEFAULT_WEBHOOK_PATHrk  r:   Úpublic_base_urlr]  r`   rÖ   rV  rT  rr  rt  rv  r„   ÚDEFAULT_SLOW_RESPONSE_THRESHOLDrx  ÚDEFAULT_PENDING_REPLY_TEXTrz  ÚDEFAULT_BUTTON_LABELr3  ÚDEFAULT_DELIVERED_TEXTr}  ÚDEFAULT_INTERRUPTED_TEXTr  Ú_clientÚ_appÚ_runnerÚ_siteÚ_reply_tokensrŠ   Ú_cacherµ   Ú_dedupÚ_bot_user_idÚ	_lock_keyÚ_media_tokensÚ_media_temp_pathsÚMEDIA_TOKEN_TTL_SECONDSÚ
_media_ttlÚ_pending_buttons)r•   rb  Úkwargsrc  rd  Ú	__class__s        €r   r–   zLineAdapter.__init__¹  s6  ø€ Ý˜FÑ#Ô#ˆÝ‰Œ×Ò °ÐÑ:Ô:Ð:å˜ ¨Ñ,Ô,Ð2°ˆõ Ð:Ñ;Ô;ð 5Ø�yŠyÐ/°Ñ4Ô4ð 	Ô!õ
 Ð4Ñ5Ô5ð /Ø�yŠyÐ)¨2Ñ.Ô.ð 	Ôõ ŒI�kÑ"Ô"ÐU e§i¢i°½Ñ&EÔ&EÐUÍð 	Ôð	5Ý #Ý”	˜+Ñ&Ô&ÐQ¨%¯)ª)°FÕ<PÑ*QÔ*Qñ!ô !ˆDÔÐøõ �:Ð&ð 	5ð 	5ð 	5Ý 4ˆDÔÐÐð	5øøøà!ŸIšI nÕ6JÑKÔKˆÔõ
 ŒIÐ'Ñ(Ô(ð Ø�yŠy˜ rÑ*Ô*ðàß
Š&�‰+Œ+ð	 	Ôõ %Ø"¥D¨¯ªÐ3DÀeÑ)LÔ)LÑ$MÔ$Mñ
ô 
ˆŒõ &ÝŒIÐ*¨BÑ/Ô/ñ
ô 
å�—	’	˜/¨2Ñ.Ô.Ñ/Ô/ñ0ˆÔõ 'ÝŒIÐ+¨RÑ0Ô0ñ
ô 
å�—	’	Ð*¨BÑ/Ô/Ñ0Ô0ñ1ˆÔõ &ÝŒIÐ*¨BÑ/Ô/ñ
ô 
å�—	’	˜/¨2Ñ.Ô.Ñ/Ô/ñ0ˆÔð
	KÝ+0Ý”	Ð8Ñ9Ô9ð YØ—9’9Ð6Õ8WÑXÔXñ,ô ,ˆDÔ(Ð(øõ �:Ð&ð 	Kð 	Kð 	KÝ+JˆDÔ(Ð(Ð(ð	Køøøõ
 ŒIÐ)Ñ*Ô*ð EØ�yŠy˜Õ)CÑDÔDð 	Ôõ
 ŒIÐ)Ñ*Ô*ð ?Ø�yŠy˜Õ)=Ñ>Ô>ð 	Ôõ
 ŒIÐ+Ñ,Ô,ð CØ�yŠyÐ)Õ+AÑBÔBð 	Ôõ
 ŒIÐ-Ñ.Ô.ð GØ�yŠyÐ+Õ-EÑFÔFð 	Ôð /3ˆŒØˆŒ	ØˆŒØˆŒ
Ø;=ˆÔÝ"‘n”nˆŒÝ*Ñ,Ô,ˆŒØ+/ˆÔØ(,ˆŒð <>ˆÔÝ+.©5¬5ˆÔÝ1ˆŒð 13ˆÔÐÐs&   ÃAD ÄD9Ä8D9Ê8AK: Ë:LÌLF)Úis_reconnectrŸ  r`   r2   c          
   ƒ  ó†  K  — | j         r| j        s|                      ddd¬¦  «         dS 	 ddlm} t          j        | j                              ¦   «         ¦  «                             ¦   «         d d…         } |d|¦  «        s|                      d	d
d¬¦  «         dS || _	        n# t          $ r
 d | _	        Y nw xY wt          | j         ¦  «        | _        	 | j                             ¦   «         ƒ d {V —†| _        n9# t          $ r,}t                                d|¦  «         d | _        Y d }~nd }~ww xY w	 ddlm} n)# t          $ r |                      ddd¬¦  «         Y dS w xY w|                     t*          ¬¦  «        | _        | j        j                             | j        | j        ¦  «         | j        j                             | j        › d�| j        ¦  «         | j        j                             t:          › d�| j        ¦  «         |                     | j        ¦  «        | _         	 | j          !                    ¦   «         ƒ d {V —† | "                    | j         | j#        | j$        tJ          j&        dk    rdnd ¬¦  «        | _'        | j'         (                    ¦   «         ƒ d {V —† nE# tR          $ r8}|                      dd| j#        pd› d| j$        › d|› �d¬¦  «         Y d }~dS d }~ww xY w|  *                    ¦   «          t            +                    d| j#        pd| j$        | j        | j,        rd| j,        › d�nd¦  «         dS )NÚconfig_missingz=LINE_CHANNEL_ACCESS_TOKEN and LINE_CHANNEL_SECRET must be setF)Ú	retryabler   )Úacquire_scoped_locké   ra  Úlock_conflictz.LINE channel already in use by another profilez LINE: get_bot_user_id failed: %s©ÚwebÚmissing_depuO   aiohttp is required for the LINE adapter â€” install with `pip install aiohttp`)Úclient_max_sizez/healthz/{token}/{filename}Údarwin)Úreuse_addressÚbind_failedzCould not bind LINE webhook on zall IPv4+IPv6 interfacesú:r÷   Tz$LINE: webhook listening on %s:%s%s%sz* (all interfaces, IPv4+IPv6)z
 (public: r@   r'   )-râ   r_   Ú_set_fatal_errorÚgateway.statusr£  rf   rg   re   Ú	hexdigestr—  ÚImportErrorrà   r�  r"  r–  rl   r  r  rù   r§  ÚApplicationÚWEBHOOK_BODY_MAX_BYTESr�  ÚrouterÚadd_postrk  Ú_handle_webhookÚadd_getÚ_handle_healthÚDEFAULT_MEDIA_PATH_PREFIXÚ_handle_mediaÚ	AppRunnerr‘  ÚsetupÚTCPSiterƒ  r…  Úsysrc  r’  ÚstartÚOSErrorÚ_mark_connectedÚinfor‰  )r•   rŸ  r£  Útok_hashr  r§  s         r   ÚconnectzLineAdapter.connect   s.  è è € ØÔ(ð 	°Ô0Cð 	Ø×!Ò!Ø ØOØð "ñ ô ð ð
 �5ð	"Ø:Ð:Ð:Ð:Ð:Ð:å”~ dÔ&?×&FÒ&FÑ&HÔ&HÑIÔI×SÒSÑUÔUÐVYÐWYÐVYÔZˆHØ&Ð& v¨xÑ8Ô8ð Ø×%Ò%Ø#ØDØ#ð &ñ ô ð ð
 �uØ%ˆDŒNˆNøÝð 	"ð 	"ð 	"Ø!ˆDŒNˆNˆNð	"øøøõ # 4Ô#<Ñ=Ô=ˆŒð	%Ø&*¤l×&BÒ&BÑ&DÔ&DÐ DÐ DÐ DÐ DÐ DÐ DˆDÔÐøÝð 	%ð 	%ð 	%Ý�LŠLÐ;¸SÑAÔAÐAØ $ˆDÔÐÐÐÐÐøøøøð	%øøøð
	Ø#Ð#Ð#Ð#Ð#Ð#Ð#øÝð 	ð 	ð 	Ø×!Ò!ØØaØð "ñ ô ð ð
 �5�5ð	øøøð —O’OÕ4J�OÑKÔKˆŒ	ØŒ	Ô×!Ò! $Ô"3°TÔ5IÑJÔJÐJàŒ	Ô× Ò  DÔ$5Ð!>Ð!>Ð!>ÀÔ@SÑTÔTÐTàŒ	Ô× Ò Ý(ÐAÐAÐAØÔñ	
ô 	
ð 	
ð
 —}’} T¤YÑ/Ô/ˆŒð	Ø”,×$Ò$Ñ&Ô&Ð&Ð&Ð&Ð&Ð&Ð&Ð&ð ŸšØ”ØÔ!ØÔ!Ý'*¤|°xÒ'?Ð'?˜e˜eÀTð	 %ñ ô ˆDŒJð ”*×"Ò"Ñ$Ô$Ð$Ð$Ð$Ð$Ð$Ð$Ð$Ð$øÝð 	ð 	ð 	Ø×!Ò!Øð.ØÔ$ÐBÐ(Bð.ð .àÔ$ð.ð .à(+ð.ð .ð ð "ñ ô ð ð �5�5�5�5�5øøøøð	øøøð 	×ÒÑÔÐÝ�ŠØ2ØÔÐ@Ð!@ØÔØÔØ48Ô4HÐPÐ0˜Ô-Ð0Ð0Ð0Ð0Èbñ	
ô 	
ð 	
ð ˆts[   ¬A/B% ÂB% Â%B9Â8B9Ã$C; Ã;
D1Ä"D,Ä,D1Ä5D< Ä<"E"Å!E"È)A=J' Ê'
K)Ê1-K$Ë$K)r�   c              ƒ  óŠ  K  — |                       ¦   «          | j        �8	 | j                             ¦   «         ƒ d {V —† n# t          $ r Y nw xY wd | _        | j        �8	 | j                             ¦   «         ƒ d {V —† n# t          $ r Y nw xY wd | _        d | _        t          | j        ¦  «        D ]'}	 t          j
        |¦  «         Œ# t          $ r Y Œ$w xY w| j                             ¦   «          | j                             ¦   «          | j        r2	 ddlm}  |d| j        ¦  «         n# t          $ r Y nw xY wd | _        d S d S )Nr   )Úrelease_scoped_lockra  )Ú_mark_disconnectedr’  Ústoprl   r‘  Úcleanupr�  r®   r™  r   ÚunlinkrÀ  Úclearr˜  r—  r¯  rÆ  )r•   ÚpathrÆ  s      r   Ú
disconnectzLineAdapter.disconnect  s¿  è è € Ø×ÒÑ!Ô!Ð!àŒ:Ð!ðØ”j—o’oÑ'Ô'Ð'Ð'Ð'Ð'Ð'Ð'Ð'Ð'øÝð ð ð Ø�ðøøøàˆDŒJØŒ<Ð#ðØ”l×*Ò*Ñ,Ô,Ð,Ð,Ð,Ð,Ð,Ð,Ð,Ð,øÝð ð ð Ø�ðøøøàˆDŒLØˆŒ	õ ˜Ô/Ñ0Ô0ð 	ð 	ˆDðÝ”	˜$‘”��øÝð ð ð Ø�ðøøøàÔ×$Ò$Ñ&Ô&Ð&ØÔ× Ò Ñ"Ô"Ð"àŒ>ð 	"ðØ>Ð>Ð>Ð>Ð>Ð>Ø#Ð# F¨D¬NÑ;Ô;Ð;Ð;øÝð ð ð Ø�ðøøøà!ˆDŒNˆNˆNð	"ð 	"sE   Ÿ? ¿
AÁAÁA> Á>
BÂ
BÂ3CÃ
CÃCÄD* Ä*
D7Ä6D7r   c              ƒ  óB   K  — ddl m} |                     dddœ¦  «        S )Nr   r¦  Úokra  )rþ   rc  )rù   r§  Újson_response)r•   Úrequestr§  s      r   r¸  zLineAdapter._handle_health¥  s4   è è € ØÐÐÐÐÐØ× Ò ¨D¸fÐ!EÐ!EÑFÔFÐFr=   c              ƒ  óv  K  — ddl m} 	 |                     ¦   «         ƒ d {V —†}nI# t          $ r<}t                               d|¦  «         |                     dd¬¦  «        cY d }~S d }~ww xY wt          |¦  «        t          k    r|                     dd¬¦  «        S |j	         
                    d	d
¦  «        }t          ||| j        ¦  «        s|                     dd¬¦  «        S 	 t          j        |                     d¦  «        ¦  «        }n3# t           t          j        f$ r |                     dd¬¦  «        cY S w xY w| 
                    dg ¦  «        pg }|D ]H}	 |                      |¦  «        ƒ d {V —† Œ# t          $ r t                               d¦  «         Y ŒEw xY w|                     dd¬¦  «        S )Nr   r¦  zLINE: read failed: %srö   zbad request©rþ   r)   i�  zpayload too largezX-Line-Signaturer'   i‘  zinvalid signaturerb   zbad jsonÚeventszLINE: dispatch_event failedrø   rÏ  )rù   r§  r  rl   r  r  ÚResponserR   r³  rô   rŸ   ro   r_   rõ   Úloadsrk   ÚUnicodeDecodeErrorÚJSONDecodeErrorÚ_dispatch_eventÚ	exception)	r•   rÑ  r§  r\   r  r^   r�   rÔ  Úevents	            r   r¶  zLineAdapter._handle_webhook©  s  è è € ØÐÐÐÐÐð	@Ø Ÿš™œÐ'Ð'Ð'Ð'Ð'Ð'ˆDˆDøÝð 	@ð 	@ð 	@Ý�LŠLÐ0°#Ñ6Ô6Ð6Ø—<’< s°�<Ñ?Ô?Ð?Ð?Ð?Ð?Ð?Ð?øøøøð	@øøøõ ˆt‰9Œ9Õ-Ò-Ð-Ø—<’< sÐ1D�<ÑEÔEÐEà”O×'Ò'Ð(:¸BÑ?Ô?ˆ	Ý$ T¨9°dÔ6IÑJÔJð 	FØ—<’< sÐ1D�<ÑEÔEÐEð	=Ý”j §¢¨WÑ!5Ô!5Ñ6Ô6ˆGˆGøÝ"¥DÔ$8Ð9ð 	=ð 	=ð 	=Ø—<’< s°�<Ñ<Ô<Ð<Ð<Ð<ð	=øøøð —’˜X rÑ*Ô*Ð0¨bˆØð 	@ð 	@ˆEð@Ø×*Ò*¨5Ñ1Ô1Ð1Ð1Ð1Ð1Ð1Ð1Ð1Ð1øÝð @ð @ð @Ý× Ò Ð!>Ñ?Ô?Ð?Ð?Ð?ð@øøøð �|Š| 3¨Tˆ|Ñ2Ô2Ð2s>   Š% ¥
A+¯1A&Á A+Á&A+Ã&'D Ä-D>Ä=D>ÅE:Å:$F!Æ F!rÛ  rÉ   c              ƒ  óè  K  — |                      d¦  «        }|                      d¦  «        pi }|                      dd¦  «        pd}|r7| j                             |¦  «        rt                               d|¦  «         d S |                      dd¦  «        }| j        r|| j        k    rd S t          || j        | j        | j	        | j
        ¬¦  «        st                               d|¦  «         d S |d	k    r|                      |¦  «        ƒ d {V —† d S |d
k    r|                      |¦  «        ƒ d {V —† d S |dv rt                               d||¦  «         d S t                               d|¦  «         d S )NrÌ   rÈ   ÚwebhookEventIdr'   z)LINE: ignoring duplicate webhook event %srÑ   )rÖ   r×   rÙ   rÚ   z&LINE: rejecting unauthorized source %sr¤   r9  >   ÚjoinÚleaveÚfollowÚunfollowz LINE: lifecycle event %s from %szLINE: ignoring event type %r)rŸ   r•  rÆ   r  r  r–  rÞ   rÖ   rr  rt  rv  rÂ  Ú_handle_message_eventÚ_handle_postback_event)r•   rÛ  Ú
event_typerÈ   Úwebhook_event_idÚsender_user_ids         r   rÙ  zLineAdapter._dispatch_eventÈ  s·  è è € Ø—Y’Y˜vÑ&Ô&ˆ
Ø—’˜8Ñ$Ô$Ð*¨ˆØ Ÿ9š9Ð%5°rÑ:Ô:Ð@¸bÐð ð 	 ¤× 8Ò 8Ð9IÑ JÔ Jð 	Ý�LŠLÐDÐFVÑWÔWÐWØˆFð  Ÿš H¨bÑ1Ô1ˆØÔð 	 °4Ô3DÒ!DÐ!DØˆFõ #ØØ”nØÔ'ØÔ)ØÔ'ð
ñ 
ô 
ð 	õ �KŠKÐ@À&ÑIÔIÐIØˆFà˜Ò"Ð"Ø×,Ò,¨UÑ3Ô3Ð3Ð3Ð3Ð3Ð3Ð3Ð3Ð3Ð3Ø˜:Ò%Ð%Ø×-Ò-¨eÑ4Ô4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4ØÐBÐBÐBÝ�KŠKÐ:¸JÈÑOÔOÐOÐOÐOå�LŠLÐ7¸ÑDÔDÐDÐDÐDr=   c           	   ƒ  óH  K  — |                      d¦  «        pi }|                      dd¦  «        }|                      dd¦  «        }|                      dd¦  «        }|                      d¦  «        pi }t          |¦  «        \  }}|                      dd¦  «        p|}	|r'|r%|t          j        ¦   «         t          z   f| j        |<   g }
g }d}|dk    r|                      dd¦  «        pd}�n|d	v r||                      |||                      d
¦  «        p|                      d¦  «        ¬¦  «        ƒ d {V —†\  }}|r*|
                     |¦  «         |                     |¦  «         d|› d�}n�|dk    r5|                      d¦  «        pg }|rdd                     |¦  «        › d�nd}nT|dk    rH|                      dd¦  «        }|                      dd¦  «        }d|› d|› d�                     ¦   «         }nd|› d�}|dk    r3| j	        r,t          j        | j	                             |¦  «        ¦  «         |                      |||	|	|¬¦  «        }t          |t                                |t           j        ¦  «        ||||
|¬¦  «        }|                      |¦  «        ƒ d {V —† d S )Nr¤   rÌ   r'   Úidrò   rÈ   rÑ   r)   ©r*   r,   r+   r-   ÚfileNameÚ	file_name©ÚfilenameÚ[Ú]r/   Úkeywordsz
[sticker: z, z	[sticker]r.   ÚtitleÚaddressz[location: rO   z[unsupported message type: rÒ   )r‚   Ú	chat_typeÚuser_idÚ	user_nameÚ	chat_name)r)   Úmessage_typerÈ   Úraw_messager  Ú
media_urlsÚmedia_types)rŸ   rÕ   rˆ   ÚLINE_REPLY_TOKEN_TTL_SECONDSr“  Ú_download_mediarT   rÞ  rP  r�  ÚasyncioÚcreate_taskr  Úbuild_sourcer   Ú_LINE_MESSAGE_TYPESr   ÚTEXTÚhandle_message)r•   rÛ  ÚmsgÚmsg_typer  rê   rÈ   r‚   ró  rô  rù  rú  r)   Ú
local_pathÚ
media_typerð  rñ  rò  Ú
source_objÚ	event_objs                       r   râ  z!LineAdapter._handle_message_eventë  s)  è è € Ø�iŠi˜	Ñ"Ô"Ð( bˆØ—7’7˜6 2Ñ&Ô&ˆØ—W’W˜T 2Ñ&Ô&ˆ
Ø—i’i ¨bÑ1Ô1ˆØ—’˜8Ñ$Ô$Ð*¨ˆÝ*¨6Ñ2Ô2Ñˆ�Ø—*’*˜X rÑ*Ô*Ð5¨gˆð ð 	�{ð 	àÝ”	‘”Õ:Ñ:ð+ˆDÔ˜wÑ'ð !#ˆ
Ø!#ˆØˆà�vÒÐØ—7’7˜6 2Ñ&Ô&Ð,¨"ˆD‰DØÐ<Ð<Ð<Ø+/×+?Ò+?ØØØŸš Ñ,Ô,ÐD°·²¸Ñ0DÔ0Dð ,@ñ ,ô ,ð &ð &ð &ð &ð &ð &Ñ"ˆJ˜
ð
 ð /Ø×!Ò! *Ñ-Ô-Ð-Ø×"Ò" :Ñ.Ô.Ð.Ø"�x�?�?�?ˆDˆDØ˜Ò"Ð"Ø—w’w˜zÑ*Ô*Ð0¨bˆHØ:BÐSÐ6 §	¢	¨(Ñ 3Ô 3Ð6Ð6Ð6Ð6ÈˆDˆDØ˜Ò#Ð#Ø—G’G˜G RÑ(Ô(ˆEØ—g’g˜i¨Ñ,Ô,ˆGØ3 Ð3Ð3¨Ð3Ð3Ð3×9Ò9Ñ;Ô;ˆDˆDà<°Ð<Ð<Ð<ˆDð ˜ÒÐ ¤ÐÝÔ ¤× 4Ò 4°WÑ =Ô =Ñ>Ô>Ð>à×&Ò&ØØØØØð 'ñ 
ô 
ˆ
õ !ØÝ,×0Ò0°½;Ô;KÑLÔLØØØ!Ø!Ø#ð
ñ 
ô 
ˆ	ð ×!Ò! )Ñ,Ô,Ð,Ð,Ð,Ð,Ð,Ð,Ð,Ð,Ð,r=   c              ƒ  óö  K  — |                      d¦  «        pi }|                      dd¦  «        pd}|                      dd¦  «        }|                      d¦  «        pi }t          |¦  «        \  }}	 t          j        |¦  «        }n# t          t          j        f$ r Y dS w xY w|                      d¦  «        dk    rdS |                      d	d¦  «        }	|	sdS | j                              |	¦  «        }
| j        r|r|
sdS |
j        t          j
        u �rg|
j        pd}t          t          t          |¦  «        ¦  «        ¦  «        }d
„ |D ¦   «         dt          …         }	 | j                             ||¦  «        ƒ d{V —† | j                             |	¦  «         | j                             |d¦  «         dS # t(          $ r¶}t*                               d|¦  «         	 | j                             ||¦  «        ƒ d{V —† | j                             |	¦  «         | j                             |d¦  «         n2# t(          $ r%}t*                               d|¦  «         Y d}~nd}~ww xY wY d}~dS Y d}~dS d}~ww xY w|
j        t          j        u rµt          |
j        p| j        ¦  «        }	 | j                             |t7          |¦  «        g¦  «        ƒ d{V —† | j                             |	¦  «         | j                             |d¦  «         dS # t(          $ r&}t*                               d|¦  «         Y d}~dS d}~ww xY w|
j        t          j        u rH	 | j                             |t7          | j        ¦  «        g¦  «        ƒ d{V —† dS # t(          $ r Y dS w xY w|
j        t          j        u rH	 | j                             |t7          | j        ¦  «        g¦  «        ƒ d{V —† dS # t(          $ r Y dS w xY wdS )uD   User tapped the slow-LLM postback button â€” deliver cached payload.r9  r!  r'   rò   rÈ   Nr<  r;  rœ   c                ó,   — g | ]}t          |¦  «        ‘ŒS r}   ©r%  ©r¿   Úcs     r   ú
<listcomp>z6LineAdapter._handle_postback_event.<locals>.<listcomp>I  s    € Ð9Ð9Ð9¨Q� aÑ(Ô(Ð9Ð9Ð9r=   z6LINE: postback reply failed (%s); falling back to pushz'LINE: postback push fallback failed: %sz%LINE: postback ERROR reply failed: %s) rŸ   rÕ   rõ   rÖ  r†  rØ  r”  r�  r€   rq   rz   r�   r[   rJ   r1   rS   r  r¨   rœ  Úpoprl   r  Úwarningr  ru   r|   r  r%  r{   r}  ry   rz  )r•   rÛ  r9  r!  rê   rÈ   r‚   Ú_Úparsedrœ   r¡   r�   rW   rë   r  Úexc2r)   s                    r   rã  z"LineAdapter._handle_postback_event/  s±  è è € à—9’9˜ZÑ(Ô(Ð.¨BˆØ�|Š|˜F BÑ'Ô'Ð-¨2ˆØ—i’i ¨bÑ1Ô1ˆØ—’˜8Ñ$Ô$Ð*¨ˆÝ" 6Ñ*Ô*‰
ˆ�ð	Ý”Z Ñ%Ô%ˆFˆFøÝ�4Ô/Ð0ð 	ð 	ð 	ØˆFˆFð	øøøð �:Š:�hÑÔ ?Ò2Ð2ØˆFØ—Z’Z ¨bÑ1Ô1ˆ
Øð 	ØˆFà”—’ 
Ñ+Ô+ˆØŒ|ð 	 ;ð 	°eð 	ØˆFàŒ;�%œ+Ð%Ñ%Ø”mÐ) rˆGÝ#Õ$BÅ3ÀwÁ<Ä<Ñ$PÔ$PÑQÔQˆFØ9Ð9°&Ð9Ñ9Ô9Ð:UÕ;UÐ:UÔVˆHðRØ”l×(Ò(¨°hÑ?Ô?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ø”×*Ò*¨:Ñ6Ô6Ð6ØÔ%×)Ò)¨'°4Ñ8Ô8Ð8Ð8Ð8øÝð Rð Rð RÝ—’ÐWÐY\Ñ]Ô]Ð]ðRØœ,×+Ò+¨G°XÑ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>Ð>Ø”K×.Ò.¨zÑ:Ô:Ð:ØÔ)×-Ò-¨g°tÑ<Ô<Ð<Ð<øÝ ð Rð Rð RÝ—L’LÐ!JÈDÑQÔQÐQÐQÐQÐQÐQÐQøøøøðRøøøð =Ð<Ð<Ð<Ð<Ð<àQÐQÐQÐQÐQÐQøøøøðRøøøð Œ[�EœKÐ'Ð'Ý�u”}Ð=¨Ô(=Ñ>Ô>ˆDðMØ”l×(Ò(¨µ}ÀTÑ7JÔ7JÐ6KÑLÔLÐLÐLÐLÐLÐLÐLÐLØ”×*Ò*¨:Ñ6Ô6Ð6ØÔ%×)Ò)¨'°4Ñ8Ô8Ð8Ð8Ð8øÝð Mð Mð MÝ—’ÐFÈÑLÔLÐLÐLÐLÐLÐLÐLÐLøøøøðMøøøàŒ[�EœOÐ+Ð+ðØ”l×(Ò(¨µ}ÀTÔEXÑ7YÔ7YÐ6ZÑ[Ô[Ð[Ð[Ð[Ð[Ð[Ð[Ð[Ð[Ð[øÝð ð ð Ø��ðøøøàŒ[�EœMÐ)Ð)ðØ”l×(Ò(¨µ}ÀTÔEVÑ7WÔ7WÐ6XÑYÔYÐYÐYÐYÐYÐYÐYÐYÐYÐYøÝð ð ð Ø��ðøøøð	 *Ð)s“   Á2B ÂB!Â B!Å AF8 Æ8
I8ÇI3ÇAH5È4I3È5
I$È?IÉI3ÉI$É$I3É3I8Ê*A$L Ì
M ÌL;Ì;M Í4N Î
NÎNÎ24O( Ï(
O6Ï5O6Nrì  r  r1   r  rí  r©   úTuple[Optional[str], str]c             ƒ  óâ  K  — | j         r|sdS 	 | j                              |¦  «        ƒ d {V —†}n5# t          $ r(}t                               d|||¦  «         Y d }~dS d }~ww xY wdddddœ                     |d¦  «        }	 |dk    rt          ||¬	¦  «        d
fS |dk    r2t          j        d|› �¦  «        d         pd}t          ||¬	¦  «        |fS |dk    r2t          j        d|› �¦  «        d         pd}t          ||¬	¦  «        |fS |pd|› �}t          ||¦  «        t          j        |¦  «        d         pdfS # t          $ r'}t                               d||¦  «         Y d }~dS d }~ww xY w)N)Nr'   z+LINE: failed to fetch %s content for %s: %sz.jpgz.m4az.mp4z.binré  r*   )Úextz
image/jpegr,   r   z	audio/mp4r+   z	video/mp4Ú	line_fileúapplication/octet-streamz$LINE: failed to cache %s payload: %s)r�  r  rl   r  r  rŸ   r    Ú	mimetypesÚ
guess_typer   r!   r   )	r•   r  r  rí  r!  r  r  r  Údocument_names	            r   rü  zLineAdapter._download_mediaj  s÷  è è € ð Œ|ð 	 :ð 	Ø�8ð	Øœ×3Ò3°JÑ?Ô?Ð?Ð?Ð?Ð?Ð?Ð?ˆDˆDøÝð 	ð 	ð 	Ý�NŠNÐHÈ(ÐT^Ð`cÑdÔdÐdØ�8�8�8�8�8øøøøð	øøøð ØØØð	
ð 
÷
 Š#ˆh˜Ñ
Ô
ð 	ð	Ø˜7Ò"Ð"Ý-¨d¸Ð<Ñ<Ô<¸lÐJÐJØ˜7Ò"Ð"Ý&Ô1°-¸#°-°-Ñ@Ô@ÀÔCÐRÀ{�
Ý-¨d¸Ð<Ñ<Ô<¸jÐHÐHØ˜7Ò"Ð"Ý&Ô1°-¸#°-°-Ñ@Ô@ÀÔCÐRÀ{�
Ý-¨d¸Ð<Ñ<Ô<¸jÐHÐHØ$Ð9Ð(9°CÐ(9Ð(9ˆMå)¨$°Ñ>Ô>ÝÔ$ ]Ñ3Ô3°AÔ6ÐTÐ:Tðð øõ ð 	ð 	ð 	Ý�NŠNÐAÀ8ÈSÑQÔQÐQØ�8�8�8�8�8øøøøð	øøøs>   � 0 °
A"ºAÁA"ÂD= Â7D= Ã7D= Ä
2D= Ä=
E.ÅE)Å)E.r‚   rF  Úreply_toÚmetadataúOptional[Dict[str, Any]]r   c              ƒ  ó\  K  — | j         st          dd¬¦  «        S t          |¦  «        r|                      ||d¬¦  «        ƒ d {V —†S | j                             |¦  «        }|r,| j                             ||¦  «         t          d|¬¦  «        S |                      ||d¬¦  «        ƒ d {V —†S )NFúLINE adapter not connected©Úsuccessru   )Ú
force_pushT©r"  r  )r�  r   rL  Ú_send_text_chunksrœ  rŸ   r”  r¢   )r•   r‚   rF  r  r  Úpending_rids         r   ÚsendzLineAdapter.send”  sà   è è € ð Œ|ð 	QÝ eÐ3OÐPÑPÔPÐPõ
 ˜WÑ%Ô%ð 	TØ×/Ò/°¸ÈUÐ/ÑSÔSÐSÐSÐSÐSÐSÐSÐSð Ô+×/Ò/°Ñ8Ô8ˆØð 	DØŒK×!Ò! +¨wÑ7Ô7Ð7Ý d°{ÐCÑCÔCÐCà×+Ò+¨G°WÈÐ+ÑOÔOÐOÐOÐOÐOÐOÐOÐOr=   r#  c             ƒ  óÎ  K  — | j         st          dd¬¦  «        S t          t          |¦  «        ¦  «        }|st          dd ¬¦  «        S d„ |D ¦   «         d t          …         }|                      |¦  «        \  }}|rg|se	 | j                              ||¦  «        ƒ d {V —† t          d|¬¦  «        S # t          $ r%}t           	                    d|¦  «         Y d }~nd }~ww xY w	 | j          
                    ||¦  «        ƒ d {V —† t          dd ¬¦  «        S # t          $ rC}t                               d|¦  «         t          dt          |¦  «        ¬¦  «        cY d }~S d }~ww xY w)	NFr   r!  Tr$  c                ó,   — g | ]}t          |¦  «        ‘ŒS r}   r  r  s     r   r  z1LineAdapter._send_text_chunks.<locals>.<listcomp>º  s    € Ð5Ð5Ð5¨•M !Ñ$Ô$Ð5Ð5Ð5r=   ú5LINE: reply token rejected (%s); falling back to pushzLINE: push send failed: %s)r�  r   r[   rJ   rS   Ú_consume_reply_tokenr  rl   r  rÂ  r  ru   r1   )	r•   r‚   rF  r#  rW   rë   ÚtokenÚ
used_replyr  s	            r   r%  zLineAdapter._send_text_chunks­  sÉ  è è € ð Œ|ð 	QÝ eÐ3OÐPÑPÔPÐPåÕ >¸wÑ GÔ GÑHÔHˆØð 	=Ý d°tÐ<Ñ<Ô<Ð<Ø5Ð5¨fÐ5Ñ5Ô5Ð6QÕ7QÐ6QÔRˆà ×5Ò5°gÑ>Ô>ÑˆˆzØð 	Z˜jð 	ZðZØ”l×(Ò(¨°Ñ9Ô9Ð9Ð9Ð9Ð9Ð9Ð9Ð9Ý!¨$¸5ÐAÑAÔAÐAøÝð Zð Zð ZÝ—’ÐSÐUXÑYÔYÐYÐYÐYÐYÐYÐYøøøøðZøøøð	=Ø”,×#Ò# G¨XÑ6Ô6Ð6Ð6Ð6Ð6Ð6Ð6Ð6Ý d°tÐ<Ñ<Ô<Ð<øÝð 	=ð 	=ð 	=Ý�LŠLÐ5°sÑ;Ô;Ð;Ý eµ3°s±8´8Ð<Ñ<Ô<Ð<Ð<Ð<Ð<Ð<Ð<øøøøð	=øøøs6   Â 1B2 Â2
C!Â<CÃC!Ã%1D Ä
E$Ä!8EÅE$ÅE$úTuple[str, bool]c                óˆ   — | j                              |d¦  «        }|sdS |\  }}|rt          j        ¦   «         |k    rdS |dfS )zjConsume a stashed reply token if present and unexpired.

        Returns ``(token, used_reply)``.
        N)r'   FT)r“  r  rˆ   )r•   r‚   r¡   r,  Ú
expires_ats        r   r+  z LineAdapter._consume_reply_tokenÌ  sZ   € ð
 Ô"×&Ò& w°Ñ5Ô5ˆØð 	Ø�9Ø!ÑˆˆzØð 	�œ	™œ zÒ1Ð1Ø�9Ø�dˆ{Ðr=   c              ƒ  ód   K  — | j         r$|r$| j                              |¦  «        ƒ d{V —† dS dS dS )z5Trigger LINE's loading-animation indicator (DM only).N)r�  r  )r•   r‚   r  s      r   Úsend_typingzLineAdapter.send_typingÙ  sY   è è € àŒ<ð 	0˜Gð 	0Ø”,×&Ò& wÑ/Ô/Ð/Ð/Ð/Ð/Ð/Ð/Ð/Ð/Ð/ð	0ð 	0ð 	0ð 	0r=   c              ƒ  ó`   K  — |pddd…         }ddddœ                      |d¦  «        }|pd|dœS )	uH  Best-effort chat info derived from the chat_id prefix.

        LINE's chat-info APIs are limited and per-source-type â€” instead of
        chasing them we infer from the well-known ID prefixes:
        ``U`` = user (1:1), ``C`` = group, ``R`` = room. The agent only
        needs ``name`` + ``type`` from this method.
        r'   Nr7   rÒ   r9   Úchannel)r  ÚCÚR)r   rÌ   rÓ   )r•   r‚   Úprefixró  s       r   Úget_chat_infozLineAdapter.get_chat_infoÞ  sK   è è € ð �-˜R  ! Ô$ˆØ W°9Ð=Ð=×AÒAÀ&È$ÑOÔOˆ	Ø˜ 2¨yÐ9Ð9Ð9r=   c                ó    — t          |¦  «        S )z:Strip Markdown that LINE can't render. URLs are preserved.)rJ   )r•   rF  s     r   Úformat_messagezLineAdapter.format_messageê  s   € å-¨gÑ6Ô6Ð6r=   c              �  óV  •‡ ‡K  — ‰ j         dk    s	‰ j        r‰s% t          ¦   «         j        ‰g|¢R i |¤Žƒ d{V —† dS dˆˆ fd„}t	          j         |¦   «         ¦  «        }	  t          ¦   «         j        ‰g|¢R i |¤Žƒ d{V —† |                     ¦   «         s<|                     ¦   «          	 |ƒ d{V —† dS # t          j        t          f$ r Y dS w xY wdS # |                     ¦   «         s:|                     ¦   «          	 |ƒ d{V —† w # t          j        t          f$ r Y w w xY ww xY w)a  Override the base loop to fire the postback button at threshold.

        We intentionally keep the base implementation behind us: it's
        responsible for the typing-indicator heartbeat, while *this*
        wrapper layers in the slow-LLM postback bubble at threshold.
        r   Nr2   r�   c               “  ó¨  •K  — 	 t          j        ‰j        ¦  «        ƒ d {V —† n# t           j        $ r ‚ w xY w‰‰j        vrd S ‰‰j        v rd S ‰j                             ‰¦  «        } | ‰j        ‰<   ‰                     ‰¦  «        \  }}|s‰j         	                    ‰d ¦  «         d S t          ‰j        ‰j        | ¦  «        }	 ‰j                             ||g¦  «        ƒ d {V —† t                               d‰| ¦  «         d S # t"          $ rA}t                               d|¦  «         ‰j         	                    ‰d ¦  «         Y d }~d S d }~ww xY w)Nz8LINE: sent slow-LLM postback button for chat %s (rid=%s)z%LINE: postback button send failed: %s)rý  Úsleeprx  ÚCancelledErrorr“  rœ  r”  r›   r+  r  rD  rz  r3  r�  r  r  rÂ  rl   r  )rš   r,  Úusedr  r  r‚   r•   s        €€r   Ú_fire_postbackz0LineAdapter._keep_typing.<locals>._fire_postback  s§  øè è € ðÝ”m DÔ$@ÑAÔAÐAÐAÐAÐAÐAÐAÐAÐAøÝÔ)ð ð ð Øðøøøð ˜dÔ0Ð0Ð0Ø�Ø˜$Ô/Ð/Ð/Ø�Ø”+×.Ò.¨wÑ7Ô7ˆCØ-0ˆDÔ! 'Ñ*Ø×3Ò3°GÑ<Ô<‰KˆE�4Øð ØÔ%×)Ò)¨'°4Ñ8Ô8Ð8Ø�Ý/ØÔ! 4Ô#4°cñô ˆCð9Ø”l×(Ò(¨°°Ñ6Ô6Ð6Ð6Ð6Ð6Ð6Ð6Ð6Ý—’ÐVÐX_ÐadÑeÔeÐeÐeÐeøÝð 9ð 9ð 9Ý—’ÐFÈÑLÔLÐLØÔ%×)Ò)¨'°4Ñ8Ô8Ð8Ð8Ð8Ð8Ð8Ð8Ð8øøøøð9øøøs    …% ¥6Ã>D Ä
EÄ6EÅE©r2   r�   )
rx  r�  r€  Ú_keep_typingrý  rþ  ÚdoneÚcancelr>  rl   )r•   r‚   Úargsr�  r@  Ú	post_taskrž  s   ``    €r   rB  zLineAdapter._keep_typingò  sÄ  øøøè è € ð Ô(¨AÒ-Ð-Ø”<ð .àð .ð '•%‘'”'Ô& wÐ@°Ð@Ð@Ð@¸Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@ØˆFð	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9õ6 Ô'¨¨Ñ(8Ô(8Ñ9Ô9ˆ	ð	Ø&•%‘'”'Ô& wÐ@°Ð@Ð@Ð@¸Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@à—>’>Ñ#Ô#ð Ø× Ò Ñ"Ô"Ð"ðØ#�O�O�O�O�O�O�O�O�OøÝÔ.µ	Ð:ð ð ð Ø�D�Dðøøøð	ð ø�9—>’>Ñ#Ô#ð Ø× Ò Ñ"Ô"Ð"ðØ#�O�O�O�O�O�O�O�OøÝÔ.µ	Ð:ð ð ð Ø�Dðøøøð	øøøsB   Á##C Â/B9 Â9CÃCÃ)D(ÄDÄ
D(ÄD$Ä!D(Ä#D$Ä$D(Úsession_keyc              ƒ  óÚ   •K  — t          ¦   «                              ||¦  «        ƒ d{V —† | j                             |d¦  «        }|r"| j                             || j        ¦  «         dS dS )z?Resolve any orphan PENDING postback so the button doesn't loop.N)r€  Úinterrupt_session_activityrœ  r  r”  r¦   r  )r•   rG  r‚   rš   rž  s       €r   rI  z&LineAdapter.interrupt_session_activity'  s~   øè è € å‰gŒg×0Ò0°¸gÑFÔFÐFÐFÐFÐFÐFÐFÐFØÔ#×'Ò'¨°Ñ6Ô6ˆØð 	>ØŒK×!Ò! # tÔ'<Ñ=Ô=Ð=Ð=Ð=ð	>ð 	>r=   ©rÉ  Ú	file_pathrÉ  c               óV  — t          j         ¦   «         }t          | j                             ¦   «         ¦  «        D ]|}| j        |         \  }}||k    rd| j                             |d¦  «         || j        v r@| j                             |¦  «         	 t          j        |¦  «         Œl# t          $ r Y Œxw xY wŒ}t          t          |¦  «                             ¦   «         ¦  «        }t          j        d¦  «        }||| j        z   f| j        |<   |r| j                             |¦  «         |S )z>Register a local file for HTTPS serving; return the URL token.Né    )rˆ   r®   r˜  r¯   r  r™  Údiscardr   rÊ  rÀ  r1   r   ÚresolveÚsecretsÚtoken_urlsafer›  Úadd)r•   rK  rÉ  r°   r,  rÌ  ÚexpÚresolveds           r   Ú_register_mediazLineAdapter._register_media2  s0  € õ Œi‰kŒkˆÝ˜$Ô,×1Ò1Ñ3Ô3Ñ4Ô4ð 		ð 		ˆEØÔ*¨5Ô1‰IˆD�#Ø�SŠyˆyØÔ"×&Ò& u¨dÑ3Ô3Ð3Ø˜4Ô1Ð1Ð1ØÔ*×2Ò2°4Ñ8Ô8Ð8ðÝœ	 $™œ˜˜øÝ"ð ð ð Ø˜ðøøøøõ •t˜I‘”×.Ò.Ñ0Ô0Ñ1Ô1ˆÝÔ% bÑ)Ô)ˆØ%-¨s°T´_Ñ/DÐ$EˆÔ˜5Ñ!Øð 	1ØÔ"×&Ò& xÑ0Ô0Ð0Øˆs   ÂB&Â&
B3Â2B3r,  c                óÂ   — | j         r| j         }n/| j        }|�	|t          v rd}| j        }|dk    rd|› �}nd|› d|› �}t	          |d¬¦  «        }|› t
          › d|› d|› �S )	z=Build the public HTTPS URL for a media token. PR #8398 style.Nz	127.0.0.1i»  úhttps://r­  r'   )Úsafern  )r‰  rƒ  Ú_WILDCARD_HOSTSr…  Ú	_urlquoter¹  )r•   r,  rí  Úbaserh  rj  Ú	safe_names          r   Ú
_media_urlzLineAdapter._media_urlH  sž   € àÔð 	0ØÔ'ˆDˆDð
 Ô$ˆDØˆ|˜t¥Ð6Ð6Ø"�ØÔ$ˆDØ�sŠ{ˆ{Ø( $Ð(Ð(��à/ $Ð/Ð/¨Ð/Ð/�Ý˜h¨RÐ0Ñ0Ô0ˆ	ØÐGÕ1ÐGÐG°EÐGÐG¸IÐGÐGÐGr=   c                óB   — | j         rdS | j        du p| j        t          v S )zÄTrue when outbound media cannot work: no LINE_PUBLIC_URL and the
        bind host is a wildcard (or the dual-stack ``None`` default), i.e.
        not an address LINE's fetchers could ever reach.FN)r‰  rƒ  rY  )r•   s    r   Ú_missing_public_urlzLineAdapter._missing_public_url[  s/   € ð Ôð 	Ø�5ØÔ  DÐ(ÐP¨DÔ,=ÅÐ,PÐPr=   c              ƒ  ó¦  ‡K  — ddl m} |j        d         }| j                             |¦  «        }|s|                     dd¬¦  «        S |\  }}t          j        ¦   «         |k    r2| j                             |d¦  «         |                     dd	¬¦  «        S t          |¦  «        }| 	                    ¦   «         r| 
                    ¦   «         s|                     dd¬¦  «        S 	 dd
lm} t           |¦   «         ¦  «                             ¦   «         }	nH# t          $ r; t          j        ¦   «                              d¦  «                             ¦   «         }	Y nw xY wt          t#          j        ¦   «         ¦  «                             ¦   «         t          d¦  «                             ¦   «         |	h}
|                     ¦   «         Št'          ˆfd„|
D ¦   «         ¦  «        s2t(                               d‰¦  «         |                     dd¬¦  «        S t-          j        t1          |¦  «        ¦  «        \  }}|                     |d|pdi¬¦  «        S )a›  Serve a registered local file over HTTPS for LINE's media URLs.

        Defence-in-depth: even though ``_register_media`` is only called
        from trusted internal code, we recheck the resolved path against
        an allowed-roots set before serving. Sources allowed:
        ``tempfile.gettempdir()``, ``/tmp`` (which resolves to
        ``/private/tmp`` on macOS), and ``HERMES_HOME``. PR #8398.
        r   r¦  r,  i”  z	not foundrÓ  Niš  Úgone)Úget_hermes_homez.hermesz/tmpc              3  ó8   •K  — | ]}t          ‰|¦  «        V — Œd S r‘   )Ú_is_relative_to)r¿   ÚrrT  s     €r   rJ  z,LineAdapter._handle_media.<locals>.<genexpr>ˆ  s-   øè è € ÐGÐG°A•? 8¨QÑ/Ô/ÐGÐGÐGÐGÐGÐGr=   z1LINE: refusing to serve outside allowed roots: %si“  Ú	forbiddenræ   r  r  )rù   r§  Ú
match_infor˜  rŸ   rÕ  rˆ   r  r   ÚexistsÚis_fileÚhermes_constantsrb  rO  rl   ÚhomeÚjoinpathÚtempfileÚ
gettempdirrK  r  r  r  r  r1   ÚFileResponse)r•   rÑ  r§  r,  r¡   rK  r0  rÌ  rb  Úhermes_homeÚallowed_rootsÚcontent_typer  rT  s                @r   rº  zLineAdapter._handle_mediac  sR  øè è € ð 	 ÐÐÐÐÐàÔ" 7Ô+ˆØÔ"×&Ò& uÑ-Ô-ˆØð 	>Ø—<’< s°�<Ñ=Ô=Ð=à %Ñˆ	�:ÝŒ9‰;Œ;˜Ò#Ð#ØÔ×"Ò" 5¨$Ñ/Ô/Ð/Ø—<’< s°�<Ñ8Ô8Ð8å�I‰ŒˆØ�{Š{‰}Œ}ð 	> D§L¢L¡N¤Nð 	>Ø—<’< s°�<Ñ=Ô=Ð=ð	DØ8Ð8Ð8Ð8Ð8Ð8Ý˜˜Ñ0Ô0Ñ1Ô1×9Ò9Ñ;Ô;ˆKˆKøÝð 	Dð 	Dð 	DÝœ)™+œ+×.Ò.¨yÑ9Ô9×AÒAÑCÔCˆKˆKˆKð	Døøøõ •Ô$Ñ&Ô&Ñ'Ô'×/Ò/Ñ1Ô1Ý�‰LŒL× Ò Ñ"Ô"Øð
ˆð
 —<’<‘>”>ˆÝÐGÐGÐGÐG¸ÐGÑGÔGÑGÔGð 	>Ý�NŠNÐNÐPXÑYÔYÐYØ—<’< s°�<Ñ=Ô=Ð=å#Ô.­s°4©y¬yÑ9Ô9‰ˆ�aØ×ÒØØ# \Ð%OÐ5OÐPð  ñ 
ô 
ð 	
s   Ã'/D ÄAEÅEÚ
image_pathÚcaptionc              ƒ  ó0  K  — t          |¦  «        }|                     ¦   «         r|                     ¦   «         st          dd|› �¬¦  «        S |                     ¦   «         j        t          k    rt          dd¬¦  «        S | j        st          dd¬¦  «        S |                      ¦   «         rt          dd¬¦  «        S |  	                    t          |                     ¦   «         ¦  «        ¦  «        }|                      ||j        ¦  «        }|                     ¦   «                              d¦  «        st          dd|› �¬¦  «        S t!          |¦  «        g}|r"|                     t%          |¦  «        ¦  «         |                      ||¦  «        ƒ d {V —†S )	NFzimage file not found: r!  zimage exceeds 10 MB LINE limitr   z\LINE_PUBLIC_URL must be set to send images (LINE only accepts publicly reachable HTTPS URLs)rW  zLINE image URL must be HTTPS: )r   rh  ri  r   ÚstatÚst_sizeÚLINE_IMAGE_MAX_BYTESr�  r_  rU  r1   rO  r]  r   r\  r  r,  rT   r%  Ú_send_messages)	r•   r‚   rs  rt  r  rÌ  r,  r  Úmsgss	            r   Úsend_image_filezLineAdapter.send_image_file’  s   è è € õ �JÑÔˆØ�{Š{‰}Œ}ð 	Z D§L¢L¡N¤Nð 	ZÝ eÐ3XÈJÐ3XÐ3XÐYÑYÔYÐYØ�9Š9‰;Œ;ÔÕ!5Ò5Ð5Ý eÐ3SÐTÑTÔTÐTØŒ|ð 	QÝ eÐ3OÐPÑPÔPÐPØ×#Ò#Ñ%Ô%ð 	ÝØðDðñ ô ð ð ×$Ò$¥S¨¯ª©¬Ñ%8Ô%8Ñ9Ô9ˆØ�oŠo˜e T¤YÑ/Ô/ˆØ�yŠy‰{Œ{×%Ò% jÑ1Ô1ð 	[Ý eÐ3YÐTWÐ3YÐ3YÐZÑZÔZÐZÝ&4°SÑ&9Ô&9Ð%:ˆØð 	0Ø�KŠK� gÑ.Ô.Ñ/Ô/Ð/Ø×(Ò(¨°$Ñ7Ô7Ð7Ð7Ð7Ð7Ð7Ð7Ð7r=   r¶   Ú
audio_pathr-  rL   c              ƒ  óp  K  — t          |¦  «        }|                     ¦   «         r|                     ¦   «         st          dd|› �¬¦  «        S |                     ¦   «         j        t          k    rt          dd¬¦  «        S | j        st          dd¬¦  «        S |                      ¦   «         rt          dd¬¦  «        S |  	                    t          |                     ¦   «         ¦  «        ¦  «        }|                      ||j        ¦  «        }|                      |t          ||¦  «        g¦  «        ƒ d {V —†S )NFzaudio file not found: r!  zaudio exceeds 200 MB LINE limitr   z)LINE_PUBLIC_URL must be set to send audio)r   rh  ri  r   rv  rw  ÚLINE_AV_MAX_BYTESr�  r_  rU  r1   rO  r]  r   ry  r0  )r•   r‚   r|  r-  r  rÌ  r,  r  s           r   Ú
send_voicezLineAdapter.send_voice°  s<  è è € õ �JÑÔˆØ�{Š{‰}Œ}ð 	Z D§L¢L¡N¤Nð 	ZÝ eÐ3XÈJÐ3XÐ3XÐYÑYÔYÐYØ�9Š9‰;Œ;ÔÕ!2Ò2Ð2Ý eÐ3TÐUÑUÔUÐUØŒ|ð 	QÝ eÐ3OÐPÑPÔPÐPØ×#Ò#Ñ%Ô%ð 	ÝØØAðñ ô ð ð
 ×$Ò$¥S¨¯ª©¬Ñ%8Ô%8Ñ9Ô9ˆØ�oŠo˜e T¤YÑ/Ô/ˆØ×(Ò(¨µ>À#À{Ñ3SÔ3SÐ2TÑUÔUÐUÐUÐUÐUÐUÐUÐUr=   Ú
video_pathÚpreview_pathc              ƒ  óò  K  — t          |¦  «        }|                     ¦   «         r|                     ¦   «         st          dd|› �¬¦  «        S |                     ¦   «         j        t          k    rt          dd¬¦  «        S | j        st          dd¬¦  «        S |                      ¦   «         rt          dd¬¦  «        S |rwt          |¦  «                             ¦   «         rV|  	                    t          t          |¦  «                             ¦   «         ¦  «        ¦  «        }t          |¦  «        j        }n²t          j        dd¬¦  «        }	 |                     t           ¦  «         |                     ¦   «          |                     ¦   «          |  	                    |j        d	¬
¦  «        }d}n:# t&          $ r- 	 t)          j        |j        ¦  «         n# t,          $ r Y nw xY w‚ w xY w|  	                    t          |                     ¦   «         ¦  «        ¦  «        }	|                      |	|j        ¦  «        }
|                      ||¦  «        }|                      |t3          |
|¦  «        g¦  «        ƒ d {V —†S )NFzvideo file not found: r!  zvideo exceeds 200 MB LINE limitr   z)LINE_PUBLIC_URL must be set to send videoz.png)ÚsuffixÚdeleteTrJ  zpreview.png)r   rh  ri  r   rv  rw  r~  r�  r_  rU  r1   rO  r   rm  ÚNamedTemporaryFileÚwriteÚ_FALLBACK_PNG_PREVIEWÚflushÚcloserl   r   rÊ  rÀ  r]  ry  r2  )r•   r‚   r€  r�  r  rÌ  Úpreview_tokenÚpreview_filenameÚtmpÚvideo_tokenÚ	video_urlr'  s               r   Ú
send_videozLineAdapter.send_videoÈ  sz  è è € õ �JÑÔˆØ�{Š{‰}Œ}ð 	Z D§L¢L¡N¤Nð 	ZÝ eÐ3XÈJÐ3XÐ3XÐYÑYÔYÐYØ�9Š9‰;Œ;ÔÕ!2Ò2Ð2Ý eÐ3TÐUÑUÔUÐUØŒ|ð 	QÝ eÐ3OÐPÑPÔPÐPØ×#Ò#Ñ%Ô%ð 	ÝØØAðñ ô ð ð ð 	�D Ñ.Ô.×6Ò6Ñ8Ô8ð 	Ø ×0Ò0µµT¸,Ñ5GÔ5G×5OÒ5OÑ5QÔ5QÑ1RÔ1RÑSÔSˆMÝ# LÑ1Ô1Ô6ÐÐåÔ-°VÀEÐJÑJÔJˆCðØ—	’	Õ/Ñ0Ô0Ð0Ø—	’	‘”�Ø—	’	‘”�Ø $× 4Ò 4°S´XÀtÐ 4Ñ LÔ L�Ø#0Ð Ð øÝð ð ð ðÝ”I˜cœhÑ'Ô'Ð'Ð'øÝð ð ð Ø�Dðøøøàðøøøð ×*Ò*­3¨t¯|ª|©~¬~Ñ+>Ô+>Ñ?Ô?ˆØ—O’O K°´Ñ;Ô;ˆ	Ø—o’o mÐ5EÑFÔFˆØ×(Ò(¨µ>À)È[Ñ3YÔ3YÐ2ZÑ[Ô[Ð[Ð[Ð[Ð[Ð[Ð[Ð[s1   ÅA F/ Æ/
G&Æ:GÇG&Ç
G!ÇG&Ç G!Ç!G&rë   rì   c              ƒ  ó,  K  — | j         st          dd¬¦  «        S |st          dd¬¦  «        S |dt          …         }|t          d…         }|                      |¦  «        \  }}|r²	 | j                              ||¦  «        ƒ d{V —† nç# t
          $ r‚}t                               d|¦  «         	 | j                              ||¦  «        ƒ d{V —† n:# t
          $ r-}t          dt          |¦  «        ¬¦  «        cY d}~cY d}~S d}~ww xY wY d}~n`d}~ww xY w	 | j                              ||¦  «        ƒ d{V —† n5# t
          $ r(}t          dt          |¦  «        ¬¦  «        cY d}~S d}~ww xY w|r“|dt          …         }	|t          d…         }	 | j                              ||	¦  «        ƒ d{V —† nP# t
          $ rC}t           
                    d|¦  «         t          dt          |¦  «        ¬¦  «        cY d}~S d}~ww xY w|°“t          dd¬¦  «        S )	z6Send already-built message objects, batched at 5/call.Fr   r!  TNr$  r*  z)LINE: push for follow-up batch failed: %s)r�  r   rS   r+  r  rl   r  rÂ  r  r1   r  )
r•   r‚   rë   Úfirst_batchÚrestr,  r-  r  r  Úbatchs
             r   ry  zLineAdapter._send_messagesõ  sð  è è € ð Œ|ð 	QÝ eÐ3OÐPÑPÔPÐPØð 	=Ý d°tÐ<Ñ<Ô<Ð<àÐ:Õ :Ð:Ô;ˆØÕ2Ð3Ð3Ô4ˆð !×5Ò5°gÑ>Ô>ÑˆˆzØð 	AðFØ”l×(Ò(¨°Ñ<Ô<Ð<Ð<Ð<Ð<Ð<Ð<Ð<Ð<øÝð Fð Fð FÝ—’ÐSÐUXÑYÔYÐYðFØœ,×+Ò+¨G°[ÑAÔAÐAÐAÐAÐAÐAÐAÐAÐAøÝ ð Fð Fð FÝ%¨e½3¸t¹9¼9ÐEÑEÔEÐEÐEÐEÐEÐEÐEÐEÐEÐEÐEÐEøøøøðFøøøð BÐAÐAÐAÐAøøøøðFøøøðAØ”l×'Ò'¨°Ñ=Ô=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=øÝð Að Að AÝ!¨%µs¸3±x´xÐ@Ñ@Ô@Ð@Ð@Ð@Ð@Ð@Ð@øøøøðAøøøð ð 	AØÐ4Õ4Ð4Ô5ˆEØÕ2Ð3Ð3Ô4ˆDðAØ”l×'Ò'¨°Ñ7Ô7Ð7Ð7Ð7Ð7Ð7Ð7Ð7Ð7øÝð Að Að AÝ—’ÐJÈCÑPÔPÐPÝ!¨%µs¸3±x´xÐ@Ñ@Ô@Ð@Ð@Ð@Ð@Ð@Ð@øøøøðAøøøð ð 	Aõ  $°4Ð8Ñ8Ô8Ð8sŠ   Á'!B	 Â	
DÂDÂ/!CÃDÃ
DÃDÃ8DÃ9DÃ=DÄDÄDÄDÄ!D; Ä;
E-ÅE(Å"E-Å(E-Æ!F3 Æ3
H Æ=8G;Ç5H Ç;H )rŸ  r`   r2   r`   rA  )r2   r   )rÛ  rÉ   r2   r�   )r  r1   r  r1   rí  r©   r2   r  )NN)
r‚   r1   rF  r1   r  r©   r  r  r2   r   )r‚   r1   rF  r1   r#  r`   r2   r   )r‚   r1   r2   r.  r‘   )r‚   r1   r2   r�   )r‚   r1   r2   rÉ   )rF  r1   r2   r1   )rG  r1   r‚   r1   r2   r�   )rK  r1   rÉ  r`   r2   r1   )r,  r1   rí  r1   r2   r1   ©r2   r`   )
r‚   r1   rs  r1   rt  r©   r  r  r2   r   )r¶   N)
r‚   r1   r|  r1   r-  rL   r  r  r2   r   )
r‚   r1   r€  r1   r�  r©   r  r  r2   r   )r‚   r1   rë   rì   r2   r   )rv   rw   rx   r³   r–   rÄ  rÍ  r¸  r¶  rÙ  râ  rã  rü  r'  r%  r+  r2  r8  r:  rB  rI  rU  r]  r_  rº  r{  r  r�  ry  Ú__classcell__)rž  s   @r   r_  r_  ³  sÓ  ø€ € € € € Ø-Ð-ð
a3ð a3ð a3ð a3ð a3ðN 5:ð ]ð ]ð ]ð ]ð ]ð ]ð~ "ð  "ð  "ð  "ðLGð Gð Gð Gð3ð 3ð 3ð 3ð>!Eð !Eð !Eð !EðFB-ð B-ð B-ð B-ðH9ð 9ð 9ð 9ð@ #'ð$ð $ð $ð $ð $ð $ð\ #'Ø-1ðPð Pð Pð Pð Pð2=ð =ð =ð =ð>ð ð ð ð0ð 0ð 0ð 0ð 0ð

:ð 
:ð 
:ð 
:ð7ð 7ð 7ð 7ð3ð 3ð 3ð 3ð 3ð 3ðj>ð >ð >ð >ð >ð >ð BGð ð ð ð ð ð ð,Hð Hð Hð Hð&Qð Qð Qð Qð-
ð -
ð -
ð -
ðf "&Ø-1ð8ð 8ð 8ð 8ð 8ðD  Ø-1ðVð Vð Vð Vð Vð8 '+Ø-1ð+\ð +\ð +\ð +\ð +\ðZ)9ð )9ð )9ð )9ð )9ð )9ð )9ð )9r=   r_  Úchildr   Úparentc                ó>  — 	 |                       ¦   «                              |                      ¦   «         ¦  «        S # t          t          f$ rP 	 |                       ¦   «                              |                      ¦   «         ¦  «         Y dS # t          $ r Y Y dS w xY ww xY w)uv   Backport for Path.is_relative_to (Python 3.9+) â€” defensive against
    cwd-resolution differences across CI runners.TF)rO  Úis_relative_toÚAttributeErrorr‡  Úrelative_to)r–  r—  s     r   rd  rd  !  s£   € ðØ�}Š}‰Œ×-Ò-¨f¯nªnÑ.>Ô.>Ñ?Ô?Ð?øÝ�JÐ'ð ð ð ð	Ø�MŠM‰OŒO×'Ò'¨¯ªÑ(8Ô(8Ñ9Ô9Ð9Ø�4�4øÝð 	ð 	ð 	Ø�5�5�5ð	øøøð	øøøs'   ‚8; »BÁ9B	Â	
BÂBÂBÂBc                 óx   — t          d¦  «        sdS t          d¦  «        sdS 	 ddl} n# t          $ r Y dS w xY wdS )z8Plugin gate: require credentials AND aiohttp at runtime.re  Frf  r   NT)r   rù   r±  )rù   s    r   Úcheck_requirementsr�  2  se   € åÐ9Ñ:Ô:ð ØˆuÝÐ3Ñ4Ô4ð ØˆuðØˆˆˆˆøÝð ð ð Øˆuˆuðøøøàˆ4s   ¤) ©
7¶7c                óô   — t          | di ¦  «        pi }t          t          d¦  «        p|                     d¦  «        ¦  «        }t          t          d¦  «        p|                     d¦  «        ¦  «        }|o|S )Nrd  re  râ   rf  r_   )r�  r`   r   rŸ   )rb  rd  Ú	has_tokenÚ
has_secrets       r   Úvalidate_configr¡  ?  s�   € Ý�F˜G RÑ(Ô(Ð.¨B€EÝÝÐ6Ñ7Ô7Ð\¸5¿9º9ÐE[Ñ;\Ô;\ñô €Iõ ÝÐ0Ñ1Ô1ÐP°U·Y²YÐ?OÑ5PÔ5Pñô €Jð Ð#˜Ð#r=   c                ó    — t          | ¦  «        S )zESurface in ``hermes status`` even before the adapter is instantiated.)r¡  )rb  s    r   Úis_connectedr£  J  s   € å˜6Ñ"Ô"Ð"r=   r  c                 óÔ  — t          d¦  «        rt          d¦  «        sdS i } t          j        d¦  «        r4	 t          t          j        d         ¦  «        | d<   n# t
          $ r Y nw xY wt          j        d¦  «        rt          j        d         | d<   t          j        d¦  «        rt          j        d         | d	<   t          j        d
¦  «        rt          j        d
         | d<   | pi S )zóAuto-seed PlatformConfig.extra from env-only setups.

    Lets ``hermes status`` reflect a LINE configuration that lives entirely
    in ``.env`` without a ``platforms.line`` block in ``config.yaml``.
    Mirrors the IRC plugin's pattern.
    re  rf  Nri  rj  rg  rh  rl  rm  ÚLINE_HOME_CHANNELÚhome_channel)r   r   r   rL   Úenvironr‡  )Úseededs    r   Ú_env_enablementr©  O  sø   € õ Ð:Ñ;Ô;ð Õ@RÐShÑ@iÔ@ið ØˆtØ€FÝ	„y�ÑÔð ð	Ý ¥¤¨KÔ!8Ñ9Ô9ˆF�6‰NˆNøÝð 	ð 	ð 	ØˆDð	øøøå	„y�ÑÔð 1Ýœ KÔ0ˆˆv‰Ý	„yÐ"Ñ#Ô#ð =Ý!œzÐ*;Ô<ˆˆ|ÑÝ	„yÐ$Ñ%Ô%ð AÝ!#¤Ð,?Ô!@ˆˆ~ÑØˆ<�RÐs   ¸"A Á
A(Á'A()Ú	thread_idÚmedia_filesÚforce_documentr‚   r¤   rª  r«  úOptional[List[str]]r¬  c             ƒ  ó8  K  — t          | di ¦  «        pi }t          d¦  «        p|                     dd¦  «        }|r|sddiS t          |pd¦  «        }t	          |¦  «        pdg}	d„ |	D ¦   «         dt
          …         }
|rB|
                     t          d	t          |¦  «        › d
�¦  «        ¦  «         |
dt
          …         }
t          |¦  «        }	 | 
                    ||
¦  «        ƒ d{V —† dddœS # t          $ r}dt          |¦  «        icY d}~S d}~ww xY w)u‚  Out-of-process push delivery for cron jobs running detached from the gateway.

    Without this hook ``deliver=line`` cron jobs fail with ``no live adapter``
    when cron runs as its own process. We always Push (reply tokens require
    an inbound webhook event we don't have in this path).

    ``thread_id`` is accepted for signature parity but ignored â€” LINE has
    no native thread primitive on the channel-side API. ``media_files``
    likewise: cron-side media delivery requires a publicly-reachable URL,
    which the standalone path can't construct without binding the webhook
    server, so we send a text reference instead.
    rd  re  râ   r'   ru   z.LINE standalone send: missing token or chat_idc                ó,   — g | ]}t          |¦  «        ‘ŒS r}   r  r  s     r   r  z$_standalone_send.<locals>.<listcomp>†  s    € Ð1Ð1Ð1 Q•˜aÑ Ô Ð1Ð1Ð1r=   Nrî  z4 attachment(s) generated; not deliverable from cron]Tr$  )r�  r   rŸ   rJ   r[   rS   rT   r%  rR   rà   r  rl   r1   )Úpconfigr‚   r¤   rª  r«  r¬  rd  r,  ÚplainrW   rë   Úclientr  s                r   Ú_standalone_sendr³  g  su  è è € õ* �G˜W bÑ)Ô)Ð/¨R€EåÐ6Ñ7Ô7ð 	1Ø�9Š9Ð+¨RÑ0Ô0ð 
ð ð K˜ð KØÐIÐJÐJå*¨7¨=°bÑ9Ô9€EÝ˜EÑ"Ô"Ð* r d€FØ1Ð1¨&Ð1Ñ1Ô1Ð2MÕ3MÐ2MÔN€HØð 9à�Š�Ð&p­#¨kÑ*:Ô*:Ð&pÐ&pÐ&pÑqÔqÑrÔrÐrØÐ7Õ7Ð7Ô8ˆå˜ÑÔ€Fð#Ø�kŠk˜' 8Ñ,Ô,Ð,Ð,Ð,Ð,Ð,Ð,Ð,Ø¨tÐ4Ð4Ð4øÝð #ð #ð #Ø�˜S™œÐ"Ð"Ð"Ð"Ð"Ð"Ð"øøøøð#øøøs   Ã C4 Ã4
DÃ>DÄDÄDr�   c                 ó¨  ‡‡— t          ¦   «          t          d¦  «         t          d¦  «         t          d¦  «         t          d¦  «         t          ¦   «          	 ddlmŠmŠ n # t          $ r t          d¦  «         Y dS w xY wd	d
œdˆˆfd„}  | ddd¬
¦  «          | ddd¬
¦  «          | dd¦  «          | dd¦  «         t          d¦  «         dS )zÓMinimal stdin wizard for ``hermes setup line``.

    Mirrors the irc/teams style: prompts for the two required vars, plus
    one optional public URL. Writes to ``~/.hermes/.env`` via ``hermes_cli.config``.
    zLINE Messaging API setupz------------------------zFCreate a Messaging API channel at https://developers.line.biz/console/zthen copy the values below.r   )Úget_env_valueÚsave_env_valuezKhermes_cli.config not available; set LINE_* vars manually in ~/.hermes/.envNF)ÚsecretÚvarr1   Úpromptr·  r`   r2   r�   c               ó:  •— t          ‰¦  «        r ‰| ¦  «        nd }|rdnd}	 |rddlm}  ||› |› d�¦  «        }n&t          |› |› d�¦  «                             ¦   «         }n&# t
          t          f$ r t          ¦   «          Y d S w xY w|r ‰| |¦  «         d S d S )Nz [keep current]r'   r   )Úmasked_secret_promptr÷   )ÚcallableÚhermes_cli.secret_promptr»  ÚinputrP  ÚEOFErrorÚKeyboardInterruptÚprint)	r¸  r¹  r·  Úexistingrƒ  r»  rM  Ú_get_envÚ_set_envs	          €€r   Ú_promptz"interactive_setup.<locals>._prompt§  sõ   ø€ Ý$,¨XÑ$6Ô$6Ð@�8�8˜C‘=”=�=¸DˆØ&.Ð6Ð"Ð"°Bˆð	Øð =ØIÐIÐIÐIÐIÐIØ,Ð,°Ð-B¸Ð-BÐ-BÐ-BÑCÔC��å Ð3¨Ð3Ð3Ð3Ñ4Ô4×:Ò:Ñ<Ô<�øøÝÕ+Ð,ð 	ð 	ð 	Ý‰GŒGˆGØˆFˆFð	øøøð ð 	!ØˆH�S˜%Ñ Ô Ð Ð Ð ð	!ð 	!s   ¥?A% Á%BÂBre  zChannel access tokenTrf  zChannel secretrl  zDPublic HTTPS base URL (optional, e.g. https://my-tunnel.example.com)rq  z.Allowed user IDs (comma-separated; blank=skip)ziDone. Set the webhook URL in the LINE console to <your-public-url>/line/webhook and enable 'Use webhook'.)r¸  r1   r¹  r1   r·  r`   r2   r�   )rÁ  Úhermes_cli.configrµ  r¶  r±  )rÅ  rÃ  rÄ  s    @@r   Úinteractive_setuprÇ  ”  sZ  øø€ õ 
�G„G€GÝ	Ð
$Ñ%Ô%Ð%Ý	Ð
$Ñ%Ô%Ð%Ý	Ð
RÑSÔSÐSÝ	Ð
'Ñ(Ô(Ð(Ý	�G„G€GðØ[Ð[Ð[Ð[Ð[Ð[Ð[Ð[Ð[øÝð ð ð ÝÐ[Ñ\Ô\Ð\Øˆˆðøøøð :?ð !ð !ð !ð !ð !ð !ð !ð !ð !ð €GÐ'Ð)?ÈÐMÑMÔMÐMØ€GÐ!Ð#3¸DÐAÑAÔAÐAØ€GÐÐeÑfÔfÐfØ€GÐ Ð"RÑSÔSÐSÝ	ð Eñ Fô Fð Fð Fð Fs   ÁA% Á%BÂBc                ó¢   — |                       ddd„ t          t          t          ddgdt          t
          dt          dd	t          d
ddd¬¦  «         dS )uE   Plugin entry point â€” called by the Hermes plugin system at startup.ra  ÚLINEc                ó    — t          | ¦  «        S r‘   )r_  )Úcfgs    r   rA   zregister.<locals>.<lambda>Ã  s   € ¥K°Ñ$4Ô$4€ r=   re  rf  zpip install aiohttpr¥  rq  ro  u   ðŸ’šFTuè  You are chatting via LINE Messaging API. LINE does NOT render Markdown â€” text bubbles show ** and # literally. Bare URLs are auto-linked, but \[label\](url) syntax is not. Each text bubble is capped at 5000 characters and at most 5 bubbles are sent per reply, so keep responses concise. Image/audio/video sending requires LINE_PUBLIC_URL configured to a publicly reachable HTTPS host. Slow responses surface a 'Get answer' button the user taps to fetch the reply via a fresh free token.)r   r=  Úadapter_factoryÚcheck_fnr¡  r£  Úrequired_envÚinstall_hintÚsetup_fnÚenv_enablement_fnÚcron_deliver_env_varÚstandalone_sender_fnÚallowed_users_envÚallow_all_envÚmax_message_lengthÚemojiÚpii_safeÚallow_update_commandÚplatform_hintN)Úregister_platformr�  r¡  r£  rÇ  r©  r³  ÚLINE_SAFE_BUBBLE_CHARS)Úctxs    r   ÚregisterrÞ  ¾  sm   € à×ÒØØØ4Ð4Ý#Ý'Ý!Ø1Ð3HÐIØ*Ý"Ý)Ø0Ý-Ø.Ø,å1ØØØ!ð9ð+ ñ ô ð ð ð r=   r‘   )r)   r1   r2   r1   )r)   r1   rK   rL   r2   rM   )r\   r]   r^   r1   r_   r1   r2   r`   )rÈ   rÉ   r2   rÊ   )rÈ   rÉ   rÖ   r`   r×   rØ   rÙ   rØ   rÚ   rØ   r2   r`   )r)   r1   r2   rÉ   )r&  r1   r'  r©   r2   rÉ   rÇ   )r  r1   r-  rL   r2   rÉ   )r  r1   r'  r1   r2   rÉ   )r)   r1   r3  r1   rœ   r1   r2   rÉ   )rF  r1   r2   r`   )rM  r1   r2   rØ   )F)r   r1   r   r`   r2   r`   )r–  r   r—  r   r2   r`   r”  )r2   r  )r‚   r1   r¤   r1   rª  r©   r«  r­  r¬  r`   r2   rÉ   rA  )€r³   Ú
__future__r   rý  ri   Úenumrf   rc   rõ   Úloggingr  r   ÚrerP  r¾  rm  rˆ   r˜   Údataclassesr   r   Úpathlibr   Útypingr   r   r	   r
   r   r   Úurllib.parser   rZ  Úagent.secret_scoper   r   r   r   r   Ú	getLoggerrv   r  Úgateway.platforms.baser   r   r   r   r   r   r    r!   Úgateway.configr"   rý   r  r  r  r   r$  rÜ  rS   rû  r³  r„  rˆ  r¹  r‚  Ú	frozensetrY  rŠ  r‹  rŒ  r�  rŽ  rš  rx  r~  r  ÚPHOTOÚVIDEOÚVOICEÚDOCUMENTÚLOCATIONÚSTICKERr   r]   Úfromhexr‡  ÚcompilerE   rF   rG   rD   ÚDOTALLrB   Ú	MULTILINErH   rI   rJ   r[   ro   ÚEnumrq   r   rŠ   rµ   rÕ   rÞ   rà   r%  r,  r0  r2  rD  rE  r‡   rL  rV  r]  r_  rd  r�  r¡  r£  r©  r³  rÇ  rÞ  r}   r=   r   ú<module>r÷     s”  ðð:ð :ð :ðx #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø €€€Ø €€€Ø €€€Ø €€€Ø €€€Ø Ð Ð Ð Ø 	€	€	€	Ø 	€	€	€	Ø €€€Ø 
€
€
€
Ø €€€Ø €€€Ø €€€Ø (Ð (Ð (Ð (Ð (Ð (Ð (Ð (Ø Ð Ð Ð Ð Ð Ø 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ø +Ð +Ð +Ð +Ð +Ð +à JÐ JÐ JÐ JÐ JÐ JØ ?Ð ?Ð ?Ð ?Ð ?Ð ?ð/ð /ð /ð /ð( 
ˆÔ	˜8Ñ	$Ô	$€ð	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð $Ð #Ð #Ð #Ð #Ð #ð <€Ø9€ØBÐ ØUÐ Ø5Ð ð Ð ØÐ ØÐ Ø!Ð ð #Ð ØÐ Ø&Ð Ø)Ð ð$ €ð
 �)Ð1Ð1Ð1Ñ2Ô2€ð #'Ð àIð ð $Ð Ø.Ð ØCÐ ð Ð Ø'Ð Ø%Ð ð ÔØÔØÔØÔØÔ ØÔ$ØÔ"ðð Ð ð Ÿšðñô Ð ð ˆbŒjÐ>Ñ?Ô?€ØˆbŒjÐ)Ñ*Ô*€ØˆbŒjÐ?Ñ@Ô@€Ø�R”Z Ñ-Ô-Ð Ø�B”JÐ?ÀÄÑKÔKÐ Ø�”˜M¨2¬<Ñ8Ô8€Ø�”
Ð,¨b¬lÑ;Ô;€ð#ð #ð #ð #ðL 0Fð 'ð 'ð 'ð 'ð 'ð\Fð Fð Fð Fð6ð ð ð ð ˆDŒIñ ô ð ð ð9ð 9ð 9ð 9ð 9ñ 9ô 9ñ „ð9ðCð Cð Cð Cð Cñ Cô Cð CðTð ð ð ð ñ ô ð ð0ð ð ð ð(ð ð ð ð8Sð Sð Sð Sð Sñ Sô Sð Sðt*ð *ð *ð *ðð ð ð ð ðð ð ð ð ðð ð ð ðð ð ð ðJ,Ð ð ð ð ñ ðGð Gð Gð Gð>ð >ð >ð >ð;ð ;ð ;ð ;ð ;ðk9ð k9ð k9ð k9ð k9Ð%ñ k9ô k9ð k9ð\
ð 
ð 
ð 
ð"
ð 
ð 
ð 
ð$ð $ð $ð $ð#ð #ð #ð #ð
ð ð ð ð:  $Ø'+Ø ð*#ð *#ð *#ð *#ð *#ð *#ðZ'Fð 'Fð 'Fð 'FðT ð  ð  ð  ð  ð  r=   