§
    ¬	ÊjØ´  ã                  ó4  — d Z ddlmZ ddlZddlZddlZddlmZmZm	Z	m
Z
 ddlmZ ddlZddlmZmZ  G d„ d	e¦  «        Zd
ZdZ G d„ de	¦  «        Zi dd“dd“dd“dd“dd“dd“dd“dd“dd“d d!“d"d#“d$d%“d&d'“d(d)“d*d+“d,d-“d.d/“d0d1d2œ¥Zdmd8„Z ej        d9¦  «        Zd:Z ed;„ d<D ¦   «         ¦  «        Zdnd@„ZdodC„ZdpdE„Z	 dqdFdGdHœdrdL„Z dsdQ„Z!dtdS„Z"dudT„Z#dvdV„Z$ G dW„ dXe	¦  «        Z%dYddZœdwd`„Z&dxdc„Z' G dd„ dee	¦  «        Z(dydf„Z)dzdg„Z*	 d{d|dk„Z+d}dl„Z,dS )~uS  Resolve the session timezone from the egress IP (``timezone="auto"``).

Approach B: discover the egress IP with one HTTP request - routed *through the
proxy* when one is set, otherwise a direct request that sees the host's own
public IP - then map IP â†’ IANA timezone with an offline mmdb
(``daijro/geoip-all-in-one``, downloaded + cached by ``_geoip_db.py``).

Precedence (see ``resolve_session_timezone``):

    explicit IANA   â†’ unchanged   explicit always wins
    "" / "auto"     â†’ egress      ALWAYS resolve. With a proxy, from the proxy
                                  egress IP; without a proxy, from the host's
                                  own public IP. This is the default.

On failure:
    with a proxy    â†’ raise       a foreign proxy paired with the host TZ is
                                  the precise ``timezone_mismatch`` signal, so
                                  we fail loudly rather than fall back silently.
    without a proxy â†’ "" (host)   the host TZ is a safe default, so a transient
                                  lookup failure must not break the launch.
é    )ÚannotationsN)ÚAnyÚDictÚ
NamedTupleÚOptional)Úquoteé   )ÚSessionLocaleÚ_decidec                  ó,   ‡ — e Zd ZdZdddœdˆ fd„Zˆ xZS )ÚGeoTimezoneErroraW  Raised when ``timezone="auto"`` cannot resolve a valid IANA zone.

    Carries ``kind`` - one of the keys of :data:`_REMEDY` - and, for a discovery
    failure, one :class:`_Attempt` per endpoint. Read those instead of matching
    on the prose: the message is written for a person, the attributes are the
    part a caller may branch on.
    Úunknown© ©ÚkindÚattemptsÚmessageÚstrr   r   ú'tuple[_Attempt, ...]'ÚreturnÚNonec               óf   •— t          ¦   «                              |¦  «         || _        || _        d S ©N)ÚsuperÚ__init__r   r   )Úselfr   r   r   Ú	__class__s       €úCC:\Projects\Muse2API\.venv\Lib\site-packages\invisible_core/_geo.pyr   zGeoTimezoneError.__init__,   s-   ø€ å‰Œ×Ò˜Ñ!Ô!Ð!ØˆŒ	Ø ˆŒˆˆó    )r   r   r   r   r   r   r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   Ú__classcell__)r   s   @r   r   r   #   sY   ø€ € € € € ðð ð 5>Ø46ð!ð !ð !ð !ð !ð !ð !ð !ð !ð !ð !ð !r   r   )zhttps://api.ipify.orgzhttps://icanhazip.comzhttps://checkip.amazonaws.com)ú	socks5://ú	socks4://úsocks://c                  óD   — e Zd ZU dZded<   ded<   ded<   ded<   dd	„Zd
S )Ú_Attemptz/One endpoint tried, and what came back from it.r   ÚurlÚfloatÚsecondsr   Údetailr   c                óJ   — d| j         d›d| j        d›d| j        › d| j        › �S )Nz  z<32ú z5.2fzs  ú: )r*   r,   r   r-   ©r   s    r   Úlinez_Attempt.lineE   s6   € ØS�D”HÐSÐSÐS 4¤<ÐSÐSÐS¸¼ÐSÐSÀdÄkÐSÐSÐSr   N)r   r   )r    r!   r"   r#   Ú__annotations__r2   r   r   r   r)   r)   =   sZ   € € € € € € Ø9Ð9à€H€H�HØ€N€N�NØ€I€I�IØ€K€K�KðTð Tð Tð Tð Tð Tr   r)   Ú
proxy_auth)z;the proxy refused the credentials - check username/passwordzhsomething on this network demanded proxy credentials, so a transparent proxy is intercepting the requestÚproxy_rejected)ztthe proxy answered but refused to open the tunnel - check the plan, the target, or an allowlist on the provider sidezhsomething on this network refused to open the tunnel, so a transparent proxy is intercepting the requestÚsocks_missing)ú>a socks:// proxy needs PySocks - pip install 'requests[socks]'r7   Údns_failure)z9the proxy HOSTNAME does not resolve - check it for a typozzthe echo endpoint hostname does not resolve, so this host has no working DNS - not a proxy problem, there is no proxy hereÚconnect_failed)z4nothing accepted a connection at the proxy host:portzjno route to the echo endpoint from this host - the network is down or something is refusing the connectionÚread_timeout)z9the proxy accepted the connection and then never answeredz<the endpoint accepted the connection and then never answeredÚ
tls_failed)zzTLS to the endpoint failed THROUGH the proxy, which is what an intercepting proxy looks like - check the certificate chainz�TLS to the endpoint failed, which is what a captive portal or a TLS-inspecting middlebox looks like - check the certificate chainÚendpoint_http_error)úothe echo endpoint itself answered with an error, which is a third-party outage rather than a fault on this sider=   Úendpoint_not_an_ip)zqthe reply was not an IP address - something is intercepting the request (a captive portal, or a proxy error page)zuthe reply was not an IP address - something on this network is intercepting the request, most likely a captive portalÚnot_routing)zwthe reply was a PRIVATE address, so the request never left the local network - the proxy is not routing to the internetzthe reply was a PRIVATE address, so the request never left the local network - something here answered on the endpoint's behalfÚno_endpoint_tried)ú the budget expired before a single endpoint could be contacted, so nothing below was measured - raise `budget`, or find what delayed the caller before this steprA   Úgeoip_unavailable)zvthe geoip database could not be obtained, so nothing can be mapped - a download or a disk problem, NOT a proxy problemzathe geoip database could not be obtained, so nothing can be mapped - a download or a disk problemÚgeoip_unreadable)z„the geoip database is on disk but could not be opened or read - a damaged file or a path the reader cannot open, NOT a proxy problemzothe geoip database is on disk but could not be opened or read - a damaged file or a path the reader cannot openÚip_not_in_db)ú{the egress IP is absent from the geoip database, which usually means the database is stale rather than that the IP is wrongrE   Úno_timezone_for_ip)ú>the geoip database knows the IP but carries no timezone for itrG   Úno_coordinates_for_ip)ú:the geoip database knows the IP but carries no coordinatesrI   Úinvalid_timezone)úYthe geoip database returned a zone this system's tz database does not know - check tzdatarK   )úAunrecognised failure - the repr on the line above is all there isrL   )ú8the endpoints failed for DIFFERENT reasons, listed belowrM   )r   Úmixedr   r   ÚproxiedÚboolr   c                ób   — t                                | ¦  «        }|s| S |r|d         n|d         S )zùThe advice for one class, for the path the request actually took.

    Falls back to the class name rather than inventing text: a class with no
    entry is a bug in the table, and saying its name is more honest than
    guessing what it means.
    r   r	   )Ú_REMEDYÚget)r   rO   Úpairs      r   Ú_remedyrU   ¶   s9   € õ �;Š;�tÑÔ€DØð ØˆØÐ*ˆ4�Œ7ˆ7 4¨¤7Ð*r   z#Tunnel connection failed:\s*(\d{3}))ÚNameResolutionErrorzgetaddrinfo failedÚgaierrorc              #  ó>   K  — | ]}t          j        |¦  «        V — Œd S r   )Ú	ipaddressÚ
ip_network)Ú.0Úns     r   ú	<genexpr>r]   Ú   s=   è è € ð ð °!•iÔ*¨1Ñ-Ô-ð ð ð ð ð ð r   )z
10.0.0.0/8z172.16.0.0/12z192.168.0.0/16z127.0.0.0/8z169.254.0.0/16z	0.0.0.0/8z100.64.0.0/10z::1/128zfc00::/7z	fe80::/10z::/128z	fec0::/10ÚexcÚBaseExceptionú'tuple[str, str]'c                óæ  ‡— t          | ¦  «        j        › d| › �Št                               ‰¦  «        }|r+|                     d¦  «        }|dk    rdd|› d�fS dd|› d�fS t          | t          j        j        ¦  «        rd‰v rd	S t          | t          j        j	        ¦  «        r't          t          | d
d¦  «        dd¦  «        }dd|› �fS t          | t          ¦  «        r7t          | t          j        ¦  «        sddt          | ¦  «        dd…         › d�fS t          ˆfd„t          D ¦   «         ¦  «        rdS t          | t          j        j        ¦  «        rddt          | ¦  «        dd…         › d�fS t          | t          j        j        ¦  «        rdS t          | t          j        j        t          j        j        t          j        j        f¦  «        rdS dt+          | ¦  «        dd…         fS )aø  Name the failure class behind one failed attempt.

    A PURE function - no network, no clock, no state, and no notion of whether a
    proxy is in the path - which is what lets the whole classification be checked
    against known-bad inputs without a proxy. The class names the MECHANISM; the
    caller pairs it with the path to produce advice, because the caller is the
    only place that already knows the path.

    Classified on MEASURED evidence rather than on the exception type, because
    the type does not separate the cases. Measured 2026-09-02: a closed proxy
    port, a proxy hostname that does not resolve, a blackholed proxy address AND
    a 407 all arrive as `requests.exceptions.ProxyError`, while the same closed
    port behind socks5:// arrives as `ConnectTimeout` instead. What distinguishes
    them lives in the chained cause, which reaches `str(exc)`.

    ORDER IS LOAD-BEARING in three places, and each is marked below. The general
    rule: any branch testing a SUBCLASS must precede the branch testing its base,
    and `requests.exceptions` has two inheritance edges that are easy to miss -
    `SSLError` and `ProxyError` both subclass `ConnectionError`, and
    `InvalidSchema` subclasses both `RequestException` and `ValueError`.
    r0   r	   Ú407r4   zproxy answered z to CONNECTr5   ÚSOCKS)r6   zPySocks is not installedÚresponseNÚstatus_coder<   zendpoint answered HTTP r>   zreply was not an IP (éF   ú)c              3  ó    •K  — | ]}|‰v V — Œ	d S r   r   )r[   ÚtokenÚtexts     €r   r]   z_classify.<locals>.<genexpr>  s'   øè è € Ð
2Ð
2˜Uˆ5�Dˆ=Ð
2Ð
2Ð
2Ð
2Ð
2Ð
2r   )r8   za hostname did not resolver;   zTLS failed ()r:   z,connected, then no reply before the deadline)r9   zcould not open a connectionr   én   )Útyper    Ú_TUNNEL_STATUSÚsearchÚgroupÚ
isinstanceÚrequestsÚ
exceptionsÚInvalidSchemaÚ	HTTPErrorÚgetattrÚ
ValueErrorÚRequestExceptionr   ÚanyÚ_DNS_TOKENSÚSSLErrorÚReadTimeoutÚ
ProxyErrorÚConnectTimeoutÚConnectionErrorÚrepr)r^   ÚstatusÚcoderj   s      @r   Ú	_classifyr‚   é   s!  ø€ õ, �3‰iŒiÔ Ð)Ð) CÐ)Ð)€Då×"Ò" 4Ñ(Ô(€FØð EØ�|Š|˜A‰ŒˆØ�5Š=ˆ=ØÐ!D°4Ð!DÐ!DÐ!DÐDÐDØÐ!D°4Ð!DÐ!DÐ!DÐDÐDõ �#•xÔ*Ô8Ñ9Ô9ð ;¸gÈ¸o¸oØ:Ð:å�#•xÔ*Ô4Ñ5Ô5ð GÝ•w˜s J°Ñ5Ô5°}ÀdÑKÔKˆØ$Ð&FÀÐ&FÐ&FÐFÐFå�#•zÑ"Ô"ð N­:°c½8Ô;TÑ+UÔ+Uð Nà#Ð%M½SÀ¹X¼XÀcÀrÀc¼]Ð%MÐ%MÐ%MÐMÐMå
Ð
2Ð
2Ð
2Ð
2¥kÐ
2Ñ
2Ô
2Ñ2Ô2ð ;Ø:Ð:õ �#•xÔ*Ô3Ñ4Ô4ð =ØÐ<­C°©H¬H°S°b°S¬MÐ<Ð<Ð<Ð<Ð<õ
 �#•xÔ*Ô6Ñ7Ô7ð NØMÐMå�#�Ô+Ô6Ý Ô+Ô:Ý Ô+Ô;ð=ñ >ô >ð ?ð ?Ð>à•d˜3‘i”i   ”oÐ%Ð%r   ÚproxyúOptional[Dict[str, str]]c                óª   — | sdS |                       d¦  «        pd                     ¦   «         }t          |¦  «        o|                     ¦   «         dk    S )NFÚserverÚ z	direct://)rS   ÚstriprP   Úlower)rƒ   r†   s     r   Ú_proxy_is_setrŠ   /  sO   € Øð ØˆuØ�iŠi˜Ñ!Ô!Ð' R×.Ò.Ñ0Ô0€FÝ�‰<Œ<Ð9˜FŸLšL™NœN¨kÒ9Ð9r   úDict[str, str]c                óz  — |                       d¦  «        pd                     ¦   «         }|                     ¦   «         }|                     d¦  «        s|                     d¦  «        rd}n2|                     d¦  «        rd}n|                     d¦  «        rd	}nd
}d|v r|                     dd¦  «        d         n|}d|vrt          d|›d�¦  «        ‚|                       d¦  «        pd}|                       d¦  «        pd}|r't          |d¬¦  «        › dt          |d¬¦  «        › d�}nd}|› d|› |› �}||dœS )a  Translate our proxy dict into a ``requests`` proxies mapping.

    SOCKS5 uses the ``socks5h`` scheme so DNS is resolved proxy-side (matches
    ``network.proxy.socks_remote_dns=True`` in the Firefox path). HTTP/HTTPS
    pass through unchanged. Credentials are URL-encoded.
    r†   r‡   r%   r'   Úsocks5hr&   Úsocks4zhttps://ÚhttpsÚhttpz://r	   ú:zproxy server zC has no port. An endpoint needs host:port - e.g. socks5://host:1080ÚusernameÚpassword)Úsafeú@)r�   r�   )rS   rˆ   r‰   Ú
startswithÚsplitrv   r   )	rƒ   r†   ÚlowÚschemeÚ	host_portÚuserÚpwdÚauthr*   s	            r   Ú_proxies_for_requestsrž   6  s‰  € ð �iŠi˜Ñ!Ô!Ð' R×.Ò.Ñ0Ô0€FØ
�,Š,‰.Œ.€CØ
‡~‚~�kÑ"Ô"ð  c§n¢n°ZÑ&@Ô&@ð ØˆˆØ	�Š˜Ñ	$Ô	$ð ØˆˆØ	�Š˜
Ñ	#Ô	#ð Øˆˆàˆà-2°f¨_¨_�—’˜U AÑ&Ô& qÔ)Ð)À&€IØ
�)ÐÐõ ð)˜Fð )ð )ð )ñ*ô *ð 	*ð �9Š9�ZÑ Ô Ð& B€DØ
�)Š)�JÑ
Ô
Ð
% 2€CØð Ý˜ 2Ð&Ñ&Ô&Ð?Ð?­¨s¸Ð)<Ñ)<Ô)<Ð?Ð?Ð?ˆˆàˆØÐ
)Ð
)˜Ð
)˜iÐ
)Ð
)€CØ #Ð&Ð&Ð&r   g      $@g      .@)ÚtimeoutÚbudgetrŸ   r+   r    c          
     óŒ  ‡— | rt          | ¦  «        nd}g }t          j        ¦   «         |z   }t          D �]j}|t          j        ¦   «         z
  }|dk    r �nJt          j        ¦   «         }	 t	          ||¦  «        }	t          j        |||	dz  |	dz  f¬¦  «        }
|
                     ¦   «          |
j         	                    ¦   «         }t          j        |¦  «        Šnc# t          $ rV}t          |¦  «        \  }}|                     t          |t          j        ¦   «         |z
  ||¦  «        ¦  «         Y d}~�Œd}~ww xY wt!          ˆfd„t"          D ¦   «         ¦  «        r>|                     t          |t          j        ¦   «         |z
  d|› d�¦  «        ¦  «         �Œh|c S ||t          j        ¦   «         z
  z
  }t%          |¦  «        }t%          t          ¦  «        }t'          |¦  «        }d„ |D ¦   «         }|sd	}n*t%          |¦  «        d
k    r|                     ¦   «         }nd}|rdnd}d|› dt+          ||¦  «        › �d|› d|› d|d›d|d›d�	g}|                     d„ |D ¦   «         ¦  «         ||k     r|                     d||z
  › d�¦  «         t/          d                     |¦  «        |t3          |¦  «        ¬¦  «        ‚)aë  Return the public egress IP.

    Routes the request through ``proxy`` when given (SOCKS support requires
    ``requests[socks]`` / PySocks); with ``proxy=None`` it makes a direct
    request that sees the host's own public IP. Tries each echo endpoint in
    turn; raises :class:`GeoTimezoneError` if none return a valid IP.

    ``timeout`` bounds ONE request; ``budget`` bounds the whole step. Both are
    needed, and having only the first is what made this the slowest thing in a
    launch: three endpoints tried in sequence at ten seconds each is a
    thirty-second worst case that nothing capped, and one launch in six spent
    35s here. A per-request timeout says how long to wait for a server; it
    cannot say how long the caller is willing to wait in total. The remaining
    budget is now handed to each request, so a slow first endpoint shortens the
    second rather than adding to it, and the step returns or raises within
    ``budget`` however many endpoints the list grows to.
    Nr   é   )ÚproxiesrŸ   c              3  ó    •K  — | ]}‰|v V — Œ	d S r   r   )r[   ÚnetÚparseds     €r   r]   z%discover_egress_ip.<locals>.<genexpr>—  s'   øè è € Ð6Ð6 ˆv˜ˆ}Ð6Ð6Ð6Ð6Ð6Ð6r   r?   z! is not a routable public addressc                ó   — h | ]	}|j         ’Œ
S r   ©r   ©r[   Úas     r   ú	<setcomp>z%discover_egress_ip.<locals>.<setcomp>©  s   € Ð&Ð&Ð&˜ˆQŒVÐ&Ð&Ð&r   r@   r	   rN   zthrough the proxyzdirectly (no proxy set)z!could not discover the egress IP r0   ztried z of z endpoint(s) in z.1fzs of a Úgzs budgetc              3  ó>   K  — | ]}|                      ¦   «         V — Œd S r   )r2   r©   s     r   r]   z%discover_egress_ip.<locals>.<genexpr>»  s*   è è € Ð,Ð,˜a�—’‘”Ð,Ð,Ð,Ð,Ð,Ð,r   z   NOTE: the budget ran out with z@ endpoint(s) never tried, so the redundancy never came into playú
r   )rž   ÚtimeÚ	monotonicÚ_IP_ECHO_ENDPOINTSÚminrq   rS   Úraise_for_statusrj   rˆ   rY   Ú
ip_addressÚ	Exceptionr‚   Úappendr)   rx   Ú_NOT_ROUTABLEÚlenrP   ÚpoprU   Úextendr   ÚjoinÚtuple)rƒ   rŸ   r    r£   r   Údeadliner*   Ú	remainingÚstartedÚslice_ÚrespÚipr^   r   r-   ÚspentÚtriedÚtotalrO   ÚkindsÚthroughÚlinesr¦   s                         @r   Údiscover_egress_iprÉ   \  s=  ø€ ð. /4Ð=Õ# EÑ*Ô*Ð*¸€GØ!#€HÝŒ~ÑÔ &Ñ(€HÝ!ð ,ñ ,ˆØ�tœ~Ñ/Ô/Ñ/ˆ	Ø˜Š>ˆ>Ø‰EÝ”.Ñ"Ô"ˆð	õ ˜ )Ñ,Ô,ˆFÝ”<Ø˜W¨v¸©z¸6ÀA¹:Ð.Fðñ ô ˆDð ×!Ò!Ñ#Ô#Ð#Ø”—’Ñ"Ô"ˆBÝÔ)¨"Ñ-Ô-ˆFˆFøÝð 	ð 	ð 	Ý$ S™>œ>‰LˆD�&Ø�OŠOÝ˜�dœnÑ.Ô.°Ñ8¸$ÀÑGÔGñIô Ið IàˆHˆHˆH‰Høøøøð		øøøõ Ð6Ð6Ð6Ð6­Ð6Ñ6Ô6Ñ6Ô6ð 
	ð �OŠO�HØ•T”^Ñ%Ô%¨Ñ/°ØÐ8Ð8Ð8ñ:ô :ñ ;ô ;ð ;ñ Øˆ	ˆ	ˆ	à�h¥¤Ñ!1Ô!1Ñ1Ñ2€EÝ�‰MŒM€EÝÕ"Ñ#Ô#€Eå�7‰mŒm€GØ&Ð&˜XÐ&Ñ&Ô&€EØð 
ð #ˆˆÝ	ˆU‰Œ�qŠˆØ�yŠy‰{Œ{ˆˆàˆØ%,ÐKÐ!Ð!Ð2K€Gð 	P¨GÐOÐOµw¸tÀWÑ7MÔ7MÐOÐOØW�ÐWÐW˜EÐWÐW°5ÐWÐWÐWÀVÐWÐWÐWÐWð€Eð 
‡L‚LÐ,Ð, 8Ð,Ñ,Ô,Ñ,Ô,Ð,Øˆu‚}€}ð
 	�Šð=¨u°u©}ð =ð =ð =ñ	>ô 	>ð 	>õ ˜4Ÿ9š9 UÑ+Ô+°$ÅÀxÁÄÐ
QÑ
QÔ
QÐQs   Á*A0CÃ
D;Ã%AD6Ä6D;rÂ   Ú	mmdb_pathr   ú'Optional[Dict[str, Any]]'c           
     óš  — ddl }	 |                     t          |¦  «        |j        ¬¦  «        5 }|                     | ¦  «        }ddd¦  «         n# 1 swxY w Y   nW# t
          t          t          |dt          ¦  «        f$ r.}t          d|› dt          dd¦  «        › d	|› �d¬
¦  «        |‚d}~ww xY wt          |t          ¦  «        r|ndS )uð  The ONE place that opens the database and reads a record.

    The three functions below - timezone, locale and coordinates - read the SAME
    record of the SAME IP, and before this function two of them repeated the same
    three lines. Adding the third would have made three copies of how the
    database is read, which is rule 16 broken while applying it.

    Returns ``None`` when the IP is not there: the caller decides whether that is
    fatal (the timezone, which behind a proxy must fail loudly) or not (the
    locale, which has a declared fallback).

    â›” THE MODE IS EXPLICIT, AND ``MODE_MMAP`` ON PURPOSE ([B227], 2026-09-25).
    The default picks the C extension, which on Windows opens the file with a
    path in BYTES and cannot find a name that is not ASCII. The cache lives
    under the user's profile, so every Windows user called JosÃ©, MÃ¼ller or with
    a CJK account name got ``FileNotFoundError`` on a database that exists, and
    behind a proxy that refused the launch outright. Measured on the same file:
    ``MODE_AUTO`` and ``MODE_MMAP_EXT`` fail, ``MODE_MMAP``, ``MODE_FILE`` and
    ``MODE_MEMORY`` answer. ``MODE_MMAP`` opens the file from Python and maps it
    like the extension does; the handful of lookups a launch makes do not
    notice the pure-Python reader.

    A database that is there but cannot be read is said as such
    (``geoip_unreadable``), not as the bare ``OSError``, which named a missing
    file and sent the reader looking for a download problem.
    r   N)ÚmodeÚInvalidDatabaseErrorzthe geoip database at z could not be read - rC   Fr0   r¨   )Ú	maxminddbÚopen_databaser   Ú	MODE_MMAPrS   ÚOSErrorrv   ru   r   rU   rp   Údict)rÂ   rÊ   rÏ   ÚreaderÚrecordr^   s         r   Ú_geo_recordrÖ   Ç  sC  € ð6 ÐÐÐð
.Ø×$Ò$¥S¨¡^¤^¸)Ô:MÐ$ÑNÔNð 	$ÐRXØ—Z’Z ‘^”^ˆFð	$ð 	$ð 	$ñ 	$ô 	$ð 	$ð 	$ð 	$ð 	$ð 	$ð 	$øøøð 	$ð 	$ð 	$ð 	$øøõ •ZÝ�IÐ5µzÑBÔBðDð .ð .ð .åð; Yð ;ð ;ÝÐ)¨5Ñ1Ô1ð;ð ;Ø58ð;ð ;à#ð%ñ %ô %ð +.ð	.øøøøð.øøøõ   ­Ñ-Ô-Ð7ˆ6ˆ6°4Ð7s:   †)A ¯AÁA ÁAÁA ÁAÁA Á&B1Â)B,Â,B1ú'tuple[float, float]'c                ó@  — t          | |¦  «        }|st          d| › d�d¬¦  «        ‚|                     d¦  «        pi }|                     d¦  «        |                     d¦  «        }}|�|€t          d	| › d
�d¬¦  «        ‚t          |¦  «        t          |¦  «        fS )u  Map ``ip`` -> (latitude, longitude) from the same record as the timezone.

    â›” It is the ONE source of the declared position: the engine no longer asks
    the hardware anything (no WiFi, no GPS, no cell) and asks Google nothing. The
    position comes out of the proxy's exit IP, exactly as the timezone and the
    language do, so the three cannot contradict one another.

    â›” THE ACCURACY DOES NOT COME FROM HERE, and that is not an oversight:
    measured 2026-08-20 on a real record, ``location`` carries ``latitude``,
    ``longitude`` and ``time_zone`` and **not** ``accuracy_radius``. Declaring it
    is a separate decision and lives in the Profile: a position derived from an
    IP with GPS-grade accuracy would be incoherent by construction.

    Raises :class:`GeoTimezoneError` - the same class as the timezone, because it
    is the same failure - when the IP is missing or the record carries no
    coordinates. **No fallback is invented**: without a declaration the engine
    refuses, which is rule 7.
    ú
egress IP ú" not present in the geoip databaserD   r¨   ÚlocationÚlatitudeÚ	longitudeNzno coordinates for egress IP ú in the geoip databaserH   )rÖ   r   rS   r+   )rÂ   rÊ   rÕ   ÚlocÚlatÚlons         r   Úip_to_coordinatesrâ   ò  sÆ   € õ& ˜˜YÑ'Ô'€FØð !ÝØ?˜Ð?Ð?Ð?Øð!ñ !ô !ð 	!ð �*Š*�ZÑ
 Ô
 Ð
& B€CØ�wŠw�zÑ"Ô" C§G¢G¨KÑ$8Ô$8ˆ€CØ
€{�c�kÝØF¨BÐFÐFÐFØ(ð*ñ *ô *ð 	*õ �‰:Œ:•u˜S‘z”zÐ!Ð!r   c           	     ó^  — t          | |¦  «        }|st          d| › d�d¬¦  «        ‚|                     d¦  «        pi                      d¦  «        }|st          d| › d�d	¬¦  «        ‚d
dlm}m} 	  ||¦  «         n/# |t          f$ r }t          d|›d| › d|› �d¬¦  «        |‚d}~ww xY w|S )a#  Map ``ip`` to its IANA timezone using the offline mmdb.

    Reads the standard MaxMind ``location.time_zone`` field and validates it
    against the system tz database. Raises :class:`GeoTimezoneError` if the IP
    is absent from the DB or the zone is missing / not a valid IANA name.
    rÙ   rÚ   rD   r¨   rÛ   Ú	time_zonezno timezone for egress IP rÞ   rF   r   )ÚZoneInfoÚZoneInfoNotFoundErrorz$geoip returned an invalid IANA zone z for r0   rJ   N)rÖ   r   rS   Úzoneinforå   ræ   rv   )rÂ   rÊ   rÕ   Útzrå   ræ   r^   s          r   Úip_to_timezoneré     s*  € õ ˜˜YÑ'Ô'€FØð !ÝØ?˜Ð?Ð?Ð?Øð!ñ !ô !ð 	!ð �*Š*�ZÑ
 Ô
 Ð
& B×	+Ò	+¨KÑ	8Ô	8€BØð 'ÝØC¨ÐCÐCÐCØ%ð'ñ 'ô 'ð 	'ð 9Ð8Ð8Ð8Ð8Ð8Ð8Ð8ð.Øˆ�‰ŒˆˆøØ!¥:Ð.ð .ð .ð .ÝØI°2ÐIÐI¸bÐIÐIÀCÐIÐIØ#ð%ñ %ô %à*-ð	.øøøøð.øøøð €Is   Á2A> Á>B*Â
B%Â%B*úOptional[str]c                ó®   — t          | |¦  «        }|r,|                     d¦  «        pi                      d¦  «        pdnd}|                     ¦   «         pdS )am  The ISO 3166 country of ``ip`` (MaxMind ``country.iso_code``), upper case,
    or None when the DB does not know the IP or the record has no code.

    Only the COUNTRY: which language a browser there reports is not a geo
    question but a Firefox one (which build people there install), and it is
    answered in one place, `_locale._COUNTRY_FIREFOX_BUILDS`.
    ÚcountryÚiso_coder‡   N)rÖ   rS   Úupper)rÂ   rÊ   rÕ   Úccs       r   Úip_to_countryrð   /  sW   € õ ˜˜YÑ'Ô'€FØBHÐ	Pˆ6�:Š:�iÑ Ô Ð& B×
+Ò
+¨JÑ
7Ô
7Ð
=¸2øÈb€BØ�8Š8‰:Œ:Ð˜Ðr   c                  ó(   — e Zd ZU dZded<   ded<   dS )Ú_Egressz²Where a session comes from: the address and its country, together,
    because the language decision needs both (the country picks the builds,
    the address picks one of them).r   rÂ   rì   N)r    r!   r"   r#   r3   r   r   r   rò   rò   <  s.   € € € € € € ð'ð 'ð €G€G�GØ€L€L�L€L€Lr   rò   T)Úmay_discoverÚdiscovery_failureÚ	egress_ipró   rô   úOptional[BaseException]úOptional[_Egress]c               ó¶  — ddl m} 	 | }|€ |rt          |¦  «        st          d¦  «        }|€/|�t	          |¦  «        j        › d|› �nd}t          ||¦  «         dS t          | |¦   «         ¦  «        }|€t          |d|› �¦  «         dS t          ||¦  «        S # t          $ r2}t          |t	          |¦  «        j        › d|› �¦  «         Y d}~dS d}~ww xY w)aE  The egress address and country, for ``locale="auto"``; None when the
    country cannot be known.

    PRIVATE, and only :func:`invisible_core._locale.decide_session_locale`
    calls it: the country is an INPUT to the decision, not a value any consumer
    may read. Until 36.x a tag took its place (the public
    `resolve_session_locale`), and every consumer that read the raw tag derived
    values the table then contradicted.

    Behind a proxy it reuses the already-discovered ``egress_ip`` (no extra
    round-trip); without a proxy it discovers the host's public IP when it was
    not handed one and ``may_discover`` allows it. On any failure it returns
    None and says so on stderr; the decision then takes en-US (never breaks
    launch - locale is cosmetic, unlike timezone which traps a foreign-proxy
    mismatch).
    r	   ©Úensure_geoip_mmdbNr0   zno egress IP was resolvedzthe geo DB has no country for )
Údownloadrú   rŠ   rÉ   rl   r    Ú_warn_locale_fallbackrð   rò   rµ   )	rõ   rƒ   ró   rô   rú   rÂ   Úwhyrì   r^   s	            r   Ú_egress_countryrþ   E  s0  € ð& ,Ð+Ð+Ð+Ð+Ð+ðð ˆØˆ:˜,ˆ:­}¸UÑ/CÔ/Cˆ:Ý# DÑ)Ô)ˆBØˆ:à'Ð3õ Ð,Ñ-Ô-Ô6ÐMÐMÐ:KÐMÐMÐMà3ð õ " %¨Ñ-Ô-Ð-Ø�4Ý Ð$5Ð$5Ñ$7Ô$7Ñ8Ô8ˆØˆ?Ý! %Ð)NÈ"Ð)NÐ)NÑOÔOÐOØ�4Ý�r˜7Ñ#Ô#Ð#øÝð ð ð Ý˜e­¨S©	¬	Ô(:Ð%CÐ%C¸cÐ%CÐ%CÑDÔDÐDØˆtˆtˆtˆtˆtøøøøðøøøs$   ˆAB Á-B ÂB Â
CÂ&'CÃCrý   r   c                óÐ   — ddl }t          | ¦  «        rdnd}d                     d„ |                     d¦  «        D ¦   «         ¦  «        }t	          d|› d|› �|j        ¬	¦  «         dS )
a)  Say that the locale was NOT resolved, on stderr, every time.

    This used to be two bare returns. The docstring called locale "cosmetic",
    and for a lone session it nearly is - but the timezone is resolved from the
    SAME egress IP and does not fall back, so a failure here produces a session
    whose timezone says one country and whose language says the United States.
    That pairing is a cross-field inconsistency of exactly the kind the
    timezone trap exists to prevent, and it was reaching users with no signal
    at all.

    The OUTCOME is deliberately unchanged: raising here would break launches
    that work today, on a field that is recoverable by passing `locale=`
    explicitly. What changes is that it stops being invisible - an absent
    signal must be loud, never silent.
    r   Nzbehind a proxyzwith no proxyr®   c              3  ó    K  — | ]	}d |z   V — Œ
dS )z    Nr   )r[   r2   s     r   r]   z(_warn_locale_fallback.<locals>.<genexpr>‘  s&   è è € ÐAÐA¨�v ‘}ÐAÐAÐAÐAÐAÐAr   z5invisible-core: could not resolve the session locale z¶; falling back to en-US. The timezone is still resolved from the egress IP, so this session may pair a non-US timezone with a US language - pass locale="xx-XX" to set it explicitly.
)Úfile)ÚsysrŠ   r»   r—   ÚprintÚstderr)rƒ   rý   r  Úwherer-   s        r   rü   rü   y  s™   € ð  €J€J€Jå -¨eÑ 4Ô 4ÐIÐÐ¸/€Eð �YŠYÐAÐA°·²¸4±´ÐAÑAÔAÑAÔA€FÝ	ð	Àð 	ð 	ð ð		ð 	ð
 ŒZðñ ô ð ð ð r   c                  óh   — e Zd ZU dZded<   ded<   dZded<   dZded	<   d
Zded<   dZded<   dd„Z	dS )Ú
SessionGeouÀ  Geo facts resolved once per session from a single egress round-trip.

    ``timezone`` follows the precedence in the module docstring.

    â›” ``egress_ip`` IS A FACT, NOT A DECISION: the address this session really
    leaves from, discovered once, with or without a proxy. Whether that value is
    then DECLARED to the engine as an srflx is decided by
    :meth:`srflx_to_declare`, and without a proxy the answer is no.

    Until 2026-08-26 this field was ``None`` without a proxy, and the "no" was
    expressed by that very ``None``. One field for two meanings: the effect was
    that ``prepare_session_geo`` discovered the address for the timezone, **threw
    it away**, and ``resolve_session_locale`` had to discover it again. Two
    identical requests to an external service, from the real address, before the
    browser exists - where a real user makes zero. The fact is carried now, and
    the "no" lives where the decision already lived.
    r   Útimezonerê   rõ   NzOptional[float]rÜ   rÝ   FrP   Úsrflx_suppressedzOptional['SessionLocale']Úlocaler   c                ó"   — | j         rdn| j        S )u…  The address the engine must announce as its srflx, or ``None``.

        â›” THE ONE PLACE where this question is answered. The two env builders -
        ``launch.build_launch_env`` in the core and ``_session.build_env`` in the
        wrapper - call it rather than recomputing it: they were already two
        landing points, and the same rule written twice could have drifted.
        N)r	  rõ   r1   s    r   Úsrflx_to_declarezSessionGeo.srflx_to_declareÓ  s   € ð Ô,Ð@ˆtˆt°$´.Ð@r   )r   rê   )
r    r!   r"   r#   r3   rÜ   rÝ   r	  r
  r  r   r   r   r  r  œ  sœ   € € € € € € ðð ð$ €M€M�MØÐÐÑð !%€HÐ$Ð$Ð$Ñ$Ø!%€IÐ%Ð%Ð%Ñ%ð #ÐÐ"Ð"Ð"Ñ"ð )-€FÐ,Ð,Ð,Ñ,ðAð Að Að Að Að Ar   r  c                óè   — |sdS t          | ¦  «        sdS ddlm} |sdS 	 ddlm}  || |¬¦  «        }n# t
          $ r Y dS w xY w|                     d¦  «        du o|                     d¦  «        du S )	u.  Declare a synthetic srflx, or let the real one through?

    The criterion comes from a real detector's code, read rather than deduced:
    its configuration contains no STUN at all, only TURN, and the allocation's
    username is the same identifier its verification POST sends to the backend.
    So in an honest browser **an srflx can only come from a successful
    allocation**, and the client-side candidate and the server-side proof
    coincide by construction. It is that implication a declared candidate
    breaks.

    Da qui la regola, che ha tre rami:

    * **no proxy**: the real STUN answers with the address traffic actually
      leaves from, so the srflx is born correct and with its own allocation.
      Nothing is declared. Until 2026-08-26 this branch was not written here: the
      same outcome fell out of ``egress_ip`` being ``None`` without a proxy - the
      decision was encoded in the ABSENCE of a fact. The two are separated now,
      and this branch says out loud what used to be obtained as a side effect.
    * **UDP demonstrated and coherent** (UDP leaves from the same address as
      TCP): the real srflx will already be born with the right address. Nothing
      is declared: declaring would add a candidate with no matching allocation.
    * **everything else**: the exit IP is declared, which is the behaviour it has
      always had. Without an srflx the detector writes *"Javascript is
      manipulated"*, which accuses the browser; with one it writes *"VPN/PROXY
      detected"*, which accuses the network. The difference between those two
      sentences is this line.

    â›” AND THE PROBE CANNOT FAIL A LAUNCH. Whatever goes wrong - network, a
    timeout, a field that is not there - falls back to the cautious branch. A
    capability is only exploited once it is DEMONSTRATED.
    FTr	   )ÚUDP_GOES_THROUGH_SOCKS)Ú
capability)Úknown_tcp_exitÚudpÚudp_matches_tcp)rŠ   Ú_proxyr  Ú_capabilityr  rµ   rS   )rƒ   rõ   r  r  Úcs        r   Ú_srflx_suppressedr  Þ  sÃ   € ðB ð ØˆuÝ˜ÑÔð Øˆtð /Ð.Ð.Ð.Ð.Ð.Ø!ð ØˆuðØ+Ð+Ð+Ð+Ð+Ð+ØˆJ�u¨YÐ7Ñ7Ô7ˆˆøÝð ð ð Øˆuˆuðøøøà�5Š5�‰<Œ<˜4ÐÐD A§E¢EÐ*;Ñ$<Ô$<ÀÐ$DÐDs   ¡5 µ
AÁAc                ó²   — ddl m} 	  |¦   «         S # t          $ r:}|rd| › d�nd| › d�}t          |› t	          d|¦  «        › d|› �d¬¦  «        |‚d	}~ww xY w)
a4  The mmdb, or an error saying the DATABASE failed and not the network.

    The distinction this exists to make: acquiring the database and looking an
    address up in it are separate failures with separate remedies, and until
    2026-09-02 the acquisition sat inside the same expression as the lookup,
    under one blanket `except`. A failed download therefore reached the caller
    wearing the face of a proxy that would not answer, and the reflex it invited
    was to go and check the proxy, which was working.

    Both TIMEZONE resolvers go through here rather than keeping a copy each.
    `_coordinate` in `prepare_session_geo` still acquires the database on its own
    line, and that is deliberate: coordinates are best-effort and swallow their
    own failure, so routing them through a helper that RAISES would turn a
    tolerated gap into a refused launch.

    `proxied` selects the advice, and is passed rather than recomputed: the
    caller has already decided it with `_proxy_is_set`, and deciding it twice is
    the duplication that rule 16 names.
    r	   rù   zthe egress IP is z#, so the network path is fine, but z, but rB   r0   r¨   N)rû   rú   rµ   r   rU   )rÂ   rO   rú   r^   Úfounds        r   Ú_geoip_databaser    s´   € ð( ,Ð+Ð+Ð+Ð+Ð+ð/Ø Ð Ñ"Ô"Ð"øÝð /ð /ð /àð@ÐL RÐLÐLÐLÐLØ!?°RÐ!?Ð!?Ð!?ð 	åØÐD•gÐ1°7Ñ;Ô;ÐDÐD¸sÐDÐDØ$ð&ñ &ô &à+.ð	/øøøøð/øøøs   ˆ	 ’
Aœ5AÁAÚautor  r
  c                ó  ‡— ddl mŠ | pd                     ¦   «         }t          |¦  «        }d}d}|r*	 t	          |¦  «        }n# t
          $ r}|}Y d}~nd}~ww xY wdˆfd	„}|rZ|                     ¦   «         d
k    rB ||¦  «        \  }	}
t          |||	|
t          ||¦  «        t          |||d|¬¦  «        ¦  «        S d}	 |r|nt	          d¦  «        }|€|pt          d¦  «        ‚ ||¦  «        \  }	}
t          |t          ||¦  «        ¦  «        }n># t
          $ r1}|r‚ t          ddt          |||d|¬¦  «        ¬¦  «        cY d}~S d}~ww xY wt          |||	|
t          ||¦  «        t          |||d¬¦  «        ¦  «        S )aÁ  Resolve the session timezone, egress IP AND language in ONE round-trip.

    The egress IP is discovered once and reused for the timezone mapping (when
    ``timezone`` is ``""``/``"auto"``), the WebRTC public-IP override and the
    language. Timezone precedence is identical to
    :func:`resolve_session_timezone`; the egress IP is best-effort for the
    WebRTC side (a discovery failure that the timezone path doesn't need won't
    break the launch - but if the timezone path *does* need it behind a proxy,
    that path still fails loudly).

    ``locale`` is what the caller asked for, a tag or "auto", and the returned
    ``SessionGeo.locale`` is the decision (`decide_session_locale`). It is
    decided HERE so that a consumer makes one call and gets the three facts
    that must agree with one another, instead of repeating an
    ``if locale == "auto"`` branch of its own: until 36.x every consumer did,
    five copies across four packages.
    r	   rù   r‡   NrÂ   ú'Optional[str]'r   ú)'tuple[Optional[float], Optional[float]]'c                ó`   •— | sdS 	 t          |  ‰¦   «         ¦  «        S # t          $ r Y dS w xY w)a­  Coordinates are BEST-EFFORT, the zone is not, and the gap is meant.

        A wrong timezone behind a proxy is the `tz_mismatch` trap and has to fail
        the launch. A MISSING position, on the other hand, is not a
        contradiction: it is a browser nobody has asked where it is yet, and the
        engine refuses it cleanly. Failing a launch over that would be more
        brittle without being more faithful.
        )NN)râ   rµ   )rÂ   rú   s    €r   Ú_coordinatez(prepare_session_geo.<locals>._coordinate]  sS   ø€ ð ð 	Ø�:ð	Ý$ RÐ):Ð):Ñ)<Ô)<Ñ=Ô=Ð=øÝð 	ð 	ð 	Ø�:�:ð	øøøs   ‡ Ÿ
-¬-r  T)rõ   rƒ   ró   rô   zegress IP discovery failedF)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è   Ú	proxy_setrõ   Ú
egress_errr^   r  rà   rá   rÂ   Úzonerú   s                @r   Úprepare_session_geor#  9  sO  ø€ ð( ,Ð+Ð+Ð+Ð+Ð+à
ˆ.�b×	Ò	Ñ	!Ô	!€BÝ˜eÑ$Ô$€Ið  $€IØ&*€JØð ð	Ý*¨5Ñ1Ô1ˆIˆIøÝð 	ð 	ð 	ØˆJˆJˆJˆJˆJˆJøøøøð	øøøðð ð ð ð ð ð  
ð Tˆb�hŠh‰jŒj˜FÒ"Ð"Ø�;˜yÑ)Ô)‰ˆˆSõ ˜"˜i¨¨cÝ+¨E°9Ñ=Ô=Ý! &°IÀUØ/3ÀzðSñ Sô SñTô Tð 	Tð €Bð$Ø#ÐAˆYˆYÕ);¸DÑ)AÔ)AˆØˆ:ØÐNÕ 0Ð1MÑ NÔ NÐNØ�;˜r‘?”?‰ˆˆSÝ˜b¥/°"°iÑ"@Ô"@ÑAÔAˆˆøÝð $ð $ð $Øð 	Øõ ˜"˜d­7Ø˜b¨¸EØ!ð,#ñ ,#ô ,#ð $ñ $ô $ð 	$ð 	$ð 	$ð 	$ð 	$ð 	$øøøøð$øøøõ �d˜B  SÕ*;¸EÀ2Ñ*FÔ*FÝ˜f°¸%ÈeÐTÑTÔTñVô Vð Vs6   ´A Á
AÁAÁAÃAD Ä
EÄ&EÅEÅEc                ó  — | pd                      ¦   «         }|r|                     ¦   «         dk    r|S t          |¦  «        }	 t          |r|nd¦  «        }t	          |t          ||¦  «        ¦  «        S # t          $ r |r‚ Y dS w xY w)aô  Map the user's ``timezone`` setting to a concrete IANA zone (or ``""``).

    Timezone-only path (no WebRTC side effects): an explicit IANA zone wins and
    triggers NO network call; ``""``/``"auto"`` resolve from the egress IP. The
    launch path uses :func:`prepare_session_geo` instead (which additionally
    returns the egress IP for WebRTC); this standalone resolver is kept for
    third-party integrations that only want the zone. See the module docstring
    for the precedence table.
    r‡   r  N)rˆ   r‰   rŠ   rÉ   ré   r  rµ   )r  rƒ   rè   r   rÂ   s        r   Úresolve_session_timezoner%  Ž  s§   € ð ˆ.�b×	Ò	Ñ	!Ô	!€BØ	ð ˆb�hŠh‰jŒj˜FÒ"Ð"Øˆ	å˜eÑ$Ô$€IðÝ¨Ð <  ¸Ñ=Ô=ˆÝ˜b¥/°"°iÑ"@Ô"@ÑAÔAÐAøÝð ð ð Øð 	ØØˆrˆrðøøøs   Á0A4 Á4BÂB)r   r   rO   rP   r   r   )r^   r_   r   r`   )rƒ   r„   r   rP   )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ó   rP   rô   rö   r   r÷   )rƒ   r„   rý   r   r   r   )rƒ   r„   rõ   rê   r   rP   )rÂ   r   rO   rP   r   r   )r  )r  r   rƒ   r„   r
  rê   r   r  )r  r   rƒ   r„   r   r   )-r#   Ú
__future__r   rY   Úrer¯   Útypingr   r   r   r   Úurllib.parser   rq   Ú_localer
   r   ÚRuntimeErrorr   r±   Ú_SOCKS_SCHEMESr)   rR   rU   Úcompilerm   ry   r¼   r·   r‚   rŠ   rž   rÉ   rÖ   râ   ré   rð   rò   rþ   rü   r  r  r  r#  r%  r   r   r   ú<module>r.     s—  ððð ð* #Ð "Ð "Ð "Ð "Ð "à Ð Ð Ð Ø 	€	€	€	Ø €€€Ø 2Ð 2Ð 2Ð 2Ð 2Ð 2Ð 2Ð 2Ð 2Ð 2Ð 2Ð 2Ø Ð Ð Ð Ð Ð à €€€à +Ð +Ð +Ð +Ð +Ð +Ð +Ð +ð!ð !ð !ð !ð !�|ñ !ô !ð !ð"Ð ð 8€ð	Tð 	Tð 	Tð 	Tð 	Tˆzñ 	Tô 	Tð 	Tð>Wàð -ðWð ð -ðWð ð JðWð ð =ðWð$ ð 0ð%Wð, ð Hð-Wð2 ð Mð3Wð< ð 3ð=WðF ð BðGWðP ð FðQWðZ ð #ð[Wðn ð &ðoWðx ð 9ðyWðB ð >ðCWðL ð JðMWðR ð FðSWðX ð ðYWðbMðDðiWð Wð W€ðt
+ð 
+ð 
+ð 
+ð" �”ÐBÑCÔC€ð H€ð �ð ð ð 8ð ñ ô ñ ô €ðC&ð C&ð C&ð C&ðL:ð :ð :ð :ð#'ð #'ð #'ð #'ðN '+ðhRð Øð	hRð hRð hRð hRð hRð hRðV(8ð (8ð (8ð (8ðV"ð "ð "ð "ðBð ð ð ð8
ð 
ð 
ð 
ðð ð ð ð ˆjñ ô ð ð -1ØAEð1ð 1ð 1ð 1ð 1ð 1ðh ð  ð  ð  ðF?Að ?Að ?Að ?Að ?A�ñ ?Aô ?Að ?AðD8Eð 8Eð 8Eð 8Eðv/ð /ð /ð /ðB MSðRVð RVð RVð RVð RVðjð ð ð ð ð r   