
    ij                    T   S r SSKJr  SSKrSSKJr  SSKrSSKrSSKrSSK	r	SSK
r
SSKrSSKJr  SSKrSSKJrJrJrJr  SSKJrJrJr  SS	KJrJrJrJr  S
rSS/r\R>                  " \ 5      r! " S S\RD                  5      r#        S"S jr$S#S jr% " S S\#5      r& " S S\RN                  5      r( " S S5      r)Sr*S
r+ " S S\
RX                  5      r- " S S5      r. " S S\.5      r/      S$S jr0S%S jr1S\SS4         S&S  jjr2SS\SS4           S'S! jjr3g)(z9Discovers Chromecasts on the network using mDNS/zeroconf.    )annotationsN)Callable)UUID   )CAST_TYPE_AUDIOCAST_TYPE_GROUP
CAST_TYPES	MF_GOOGLE)get_device_infoget_multizone_statusget_ssl_context)ZEROCONF_ERRORSCastInfoHostServiceInfoMDNSServiceInfo   HKJBLc                      \ rS rSrSr\R                  SS j5       r\R                  S	S j5       r\R                  SS j5       r	Sr
g)
AbstractCastListener    z%Listener for discovering chromecasts.c                    g)zA cast has been discovered.

uuid: The cast's uuid, this is the dictionary key to find
the chromecast metadata in CastBrowser.devices.
service: First known MDNS service name or host:port
N selfuuidservices      M/home/sebas/venvs/catt/lib/python3.13/site-packages/pychromecast/discovery.pyadd_castAbstractCastListener.add_cast#           c                    g)zA cast has been removed, meaning there are no longer any known services.

uuid: The cast's uuid
service: Last valid MDNS service name or host:port
cast_info: CastInfo for the service to aid cleanup
Nr   r   r   r   	cast_infos       r   remove_cast AbstractCastListener.remove_cast,   r!   r"   c                    g)zXA cast has been updated.

uuid: The cast's uuid
service: MDNS service name or host:port
Nr   r   s      r   update_cast AbstractCastListener.update_cast5   r!   r"   r   Nr   r   r   strreturnNoner   r   r   r,   r%   r   r-   r.   )__name__
__module____qualname____firstlineno____doc__abcabstractmethodr   r&   r)   __static_attributes__r   r"   r   r   r       sQ    /  	  	 r"   r   c                r    U H1  nU R                  U5      (       d  M  [        R                  SX 5          g   g)Nz(%s %s is blocked from host based pollingTF)
startswith_LOGGERdebug)item
block_list	item_typeblocked_prefixs       r   _is_blocked_from_host_browserr@   >   s4     %??>**MMDiV % r"   c                $    [        U [        S5      $ )NModel)r@   #HOST_BROWSER_BLOCKED_MODEL_PREFIXES)models    r   #_is_model_blocked_from_host_browserrE   H   s    (2G r"   c                  T    \ rS rSrSr   S	     S
S jjrSS jrSS jrSS jrSr	g)SimpleCastListenerN   z#Helper for backwards compatibility.Nc                (    Xl         X l        X0l        g N_add_callback_remove_callback_update_callback)r   add_callbackremove_callbackupdate_callbacks       r   __init__SimpleCastListener.__init__Q   s     * / /r"   c                J    U R                   (       a  U R                  X5        g g rJ   )rL   r   s      r   r   SimpleCastListener.add_cast[   s    t- r"   c                L    U R                   (       a  U R                  XU5        g g rJ   )rM   r$   s       r   r&   SimpleCastListener.remove_cast_   s       !!$; !r"   c                J    U R                   (       a  U R                  X5        g g rJ   )rN   r   s      r   r)   SimpleCastListener.update_castc   s      !!$0 !r"   rK   NNNrO   "Callable[[UUID, str], None] | NonerP   z,Callable[[UUID, str, CastInfo], None] | NonerQ   r\   r+   r/   )
r0   r1   r2   r3   r4   rR   r   r&   r)   r7   r   r"   r   rG   rG   N   sB    - <@HL>B	080 F0 <	0.<1r"   rG   c                  r    \ rS rSrSr          S
S jrSS jrSS jrSS jr          SS jr	Sr
g	)ZeroConfListenerh   z&Listener for ZeroConf service browser.c                4    Xl         X l        X0l        X@l        g rJ   _cast_listener_devices_host_browser_services_lock)r   cast_listenerdeviceshost_browserlocks        r   rR   ZeroConfListener.__init__k   s     ,)"r"   c                .   [         R                  SX#5        SnSn[        U5      nU R                     U R                  R                  5        HN  u  pxXhR                  ;   d  M  UnUR                  R                  U5        [        UR                  5      S:X  a  Sn  O   SSS5        U(       d  [         R                  SX#5        gU(       a  U R                  R                  WX45        gU R                  R                  WU5        g! , (       d  f       Nm= f)z0Called by zeroconf when an mDNS service is lost.zremove_service %s, %sNFr   Tzremove_service unknown %s, %s)r:   r;   r   re   rc   itemsservicesremovelenrb   r&   r)   )	r   zctype_namer%   device_removedservice_infor   info_for_uuids	            r   remove_serviceZeroConfListener.remove_servicew   s    -u;	&t,  '+}}':':'<##9#99 -I!**11,?=112a7)- (= ! MM95G++D$B++D$7! ! s   -D#<D
Dc                |    [         R                  SX#5        U R                  XX0R                  R                  5        g)z3Called by zeroconf when an mDNS service is updated.zupdate_service %s, %sN)r:   r;   _add_update_servicerb   r)   r   rp   rq   rr   s       r   update_serviceZeroConfListener.update_service   s-    -u;  D2E2E2Q2QRr"   c                |    [         R                  SX#5        U R                  XX0R                  R                  5        g)z6Called by zeroconf when an mDNS service is discovered.zadd_service %s, %sN)r:   r;   ry   rb   r   rz   s       r   add_serviceZeroConfListener.add_service   s-    *E8  D2E2E2N2NOr"   c                V  ^ SmSnUR                  S5      (       a  [        R                  SX#5        gTc(  US:  a"   UR                  X#5      mUS-  nTc  US:  a  M"  T(       d  [        R                  SX#5        gTR
                  c  [        R                  S	5        gSU4S
 jjnTR                  5       nU(       a  US   OTR                  nUc  [        R                  SX#5        gU R                  R                  U/5        U" S5      n	U" S5      =(       d    Sn
U" S5      nU(       d  [        R                  SX#5        g [        U5      n[        U5      nU R                     TR
                  S:w  a  [        n[        nO'[         R"                  " U
R%                  5       S5      u  pXR&                  ;  a+  [)        U1UU
U	UTR
                  UU5      U R&                  U'   OSU R&                  U   R*                  nUR-                  U5        [)        UUU
U	UTR
                  UU5      U R&                  U'   SSS5        U" X5        g! [         a    [        R                  ST5         GM  f = f! [         a    [        R                  SUUU
5         gf = f! , (       d  f       Ng= f)zAdd or update a service.Nr   z_sub._googlecast._tcp.local.z#_add_update_service ignoring %s, %s   z2get_info_from_service failed to resolve service %sr   z(_add_update_service failed to add %s, %sz _add_update_service port is Nonec                   > TR                   R                  U R                  S5      5      nUb  [        U[        5      (       a  U$ UR                  S5      $ )z#Retrieve value and decode to UTF-8.zutf-8)
propertiesgetencode
isinstancer,   decode)keyvaluer   s     r   	get_value7ZeroConfListener._add_update_service.<locals>.get_value   sI    &&**3::g+>?E
 }
5# 6 6<<((r"   z1_add_update_service failed to get host for %s, %sfnmdzUnknown model nameidz1_add_update_service failed to get uuid for %s, %sz?_add_update_service failed due to bad uuid for %s, %s, model %sI  NN)r   r,   r-   z
str | None)endswithr:   r;   get_service_infor   portparsed_addressesserverrd   	add_hostsr   
ValueErrorr   re   r   r
   r	   r   lowerrc   r   rm   add)r   zconftyprr   callbacktriesr   	addresseshostfriendly_name
model_nameuuid_strr   rt   	cast_typemanufacturerrm   r   s                    @r   ry   $ZeroConfListener._add_update_service   s    ==788MM?Ko%!)00; QJE o%!) MMDcP<<MM<=		) ,,.	(y|gnn<MMCS  	$$dV,!$t_<(<
T?MMCS 		>D 't,    ||t#+	(*4..$$&+'	 ==(&.!N!LL 	'd#  ==.77\*&.!LL 	'd#3 !H 	Q # 	
 H 	p  	MMQ	 	 ! s0   I
 I2 'CJ
 I/.I/2"JJ
J(ra   N)
rf   r   rg   dict[UUID, CastInfo]rh   HostBrowserri   threading.Lockr-   r.   )rp   zeroconf.Zeroconfrq   r,   rr   r,   r-   r.   )
r   r   r   r,   rr   r,   r   zCallable[[UUID, str], None]r-   r.   )r0   r1   r2   r3   r4   rR   rv   r{   r~   ry   r7   r   r"   r   r^   r^   h   s    0
#+
# &
# "	
#
 
# 

#84S
Px x x 	x
 .x 
xr"   r^   c                  "    \ rS rSrSrSS jrSrg)
HostStatusi  zStatus of known host.c                     SU l         SU l        g )Nr   F	failcount
no_pollingr   s    r   rR   HostStatus.__init__  s    r"   r   Nr-   r.   )r0   r1   r2   r3   r4   rR   r7   r   r"   r   r   r     s
     r"   r      c                     ^  \ rS rSrSr        SU 4S jjrSS jrSS jrSS jrSS jr	        SS jr
                  SS	 jr        SS
 jrSrU =r$ )r   i#  z&Repeateadly poll a set of known hosts.c                   > [         TU ]  SS9  Xl        X l        0 U l        [
        R
                  " 5       U l        X0l        SU l        S U l	        [        R                  " 5       U l        g )NT)daemonF)superrR   rb   rc   _known_hoststime_next_updatere   _start_requested_context	threadingEventstop)r   rf   rg   ri   	__class__s       r   rR   HostBrowser.__init__&  sY     	%+35 IIK" %/3OO%	r"   c                    U HA  nX R                   ;  d  M  [        R                  SU5        [        5       U R                   U'   MC     g)z%Add a list of known hosts to the set.zAddded host %sN)r   r:   r;   r   r   known_hostsr   s      r   r   HostBrowser.add_hosts6  s9    D,,,.5*4,!!$'  r"   c                    Uc  / nU R                  U5        [        U R                  R                  5       5       H;  nX!;  d  M
  [        R                  SU5        U R                  R                  U5        M=     g)zUpdate the set of known hosts.

Note: Removed hosts will no longer be polled, but services of any associated
cast devices will not be purged.
NzRemoved host %s)r   listr   keysr:   r;   popr   s      r   update_hostsHostBrowser.update_hosts=  sb     K{#**//12D&/6!!%%d+ 3r"   c                   [         R                  S5        [        5       U l         U R                  R                  5       (       d  U R                  5         U =R                  [        -  sl        U R                  R                  [        U R                  [        R                  " 5       -
  S5      5        U R                  R                  5       (       d  M  [         R                  S5        g! [         a    [         R                  S5        e f = f)zStart worker thread.zHostBrowser thread startedr   z$Unhandled exception in worker threadzHostBrowser thread doneN)r:   r;   r   r   r   is_set_poll_hostsr   HOSTLISTENER_CYCLE_TIMEwaitmaxr   	Exception	exceptionr   s    r   runHostBrowser.runM  s    23')	ii&&((  "!!%<<!		s4#4#4tyy{#BAFG ii&&(( 	/0  	DE	s   B,C* *!Dc           
        [        U R                  R                  5       5      nU GH  n/ n/ nU R                  R	                  5       (       a    g  U R                  U   nUR                  (       a  ML  [        USU R                  S9nU(       d_  U=R                  S-  sl	        UR                  [        :X  a  U R                  X#U5        [        UR                  [        S-   5      Ul	        M  UR                  (       d  [        R                  SU5        M  UR                   ["        :w  d  [%        UR&                  5      (       a  SUl        SUl	        UR)                  SUR*                  UR&                  UR                  UR                   UR,                  45        UR)                  UR                  5        UR.                  (       a  [1        X R                  S9OS nU(       a  [2        R4                  " UR6                  UR8                  5       H  nUR:                  (       a6  UR:                  U R                  ;  a  U R=                  UR:                  /5        UR>                  b  UR                  b  UR:                  U:w  a  Mv  UR)                  UR>                  UR*                  S	UR                  [@        S
45        UR)                  UR                  5        M     U R                  X#U5        GM     g ! [
         a     GM  f = f)Nr   )timeoutcontextr   zhost %s does not report UUIDTr   r   )r   zGoogle Cast GroupzGoogle Inc.)!r   r   r   r   r   KeyErrorr   r   r   r   HOSTLISTENER_MAX_FAIL_update_devicesminr   r:   r;   r   r   rE   r   appendr   r   multizone_supportedr   	itertoolschaindynamic_groupsgroupsr   r   r   r   )	r   r   r   rg   uuids
hoststatusdevice_statusmultizone_statusgroups	            r   r   HostBrowser._poll_hosts[  sx   4,,1134DBDG "Eyy!!!..t4

 $$+D"dmmTM $$)$''+@@((>'*((*?!*C(
$  %%<dC ''?:6}7O7OPP )-
% $%J NN!//!,,!&&!++!..	 LL++, !44 %T==A   &__$335E5L5LE
 zzejj8I8I&I

|4zz)UZZ-?5::QUCU NN!JJ!///!JJ+)	 LL,'*   6k    s   K44
LLc                   / nU R                      U H"  u  nnnnn	n
U R                  UUUUUUU	U
5        M$     U R                   Hs  nU R                  U   R                  R	                  5        HE  n[        U[        5      (       d  M  UR                  U:X  d  M,  X;  d  M3  U R                  XU5        MG     Mu     S S S 5        U H
  nU" 5         M     g ! , (       d  f       N= frJ   )	re   _add_host_servicerc   rm   copyr   r   r   _remove_host_service)r   r   rg   
host_uuids	callbacksr   r   r   r   r   r   r   r   s                r   r   HostBrowser._update_devices  s     /1	    &&! 	  #}}T2;;@@BG"7O<<#LLD0 211$iH  C &) !< "HJ "= ! s   A5CCC!C
C"c	           
        [        X5      n	U R                  R                  n
XPR                  ;   aU  U R                  R                  n
U R                  U   nXR
                  ;   a!  UR                  U:X  a  UR                  U:X  a  g XPR                  ;  a!  [        U	1UUUUUUU5      U R                  U'   OIU R                  U   R
                  nUR                  U	5        [        UUUUUUUU5      U R                  U'   U SU 3n[        R                  SX5        UR                  [        R                  " XU5      5        g )N:z6Host %s (%s) up, adding or updating host based service)r   rb   r   rc   r)   rm   r   r   r   r   r:   r;   r   	functoolspartial)r   r   r   r   r   r   r   r   r   rt   r   r%   rm   rr   s                 r   r   HostBrowser._add_host_service  s9    't2&&//== **66Hd+I 2 22((J6++}< }}$"*	#DMM$ }}T*33HLL&"*	#DMM$ qDd	
 	**84@Ar"   c           	     d   X R                   ;  a  g U R                   U   nUR                   GH   n[        U[        5      (       d  M  UR                  U:X  d  M-  UR                  R                  U5        UR                  nU SU 3n[        R                  SUU5        [        UR                  5      S:X  a<  UR                  [        R                  " U R                  R                  X'U5      5        O:UR                  [        R                  " U R                  R                  X'5      5          g    g )Nr   zFHost %s down or no longer handles uuid %s, removing host based servicer   )rc   rm   r   r   r   rn   r   r:   r;   ro   r   r   r   rb   r&   r)   )r   r   r   r   ru   r   r   rr   s           r   r    HostBrowser._remove_host_service  s     }}$d+$--G'?338L&&--g6||q'\
 }--.!3$$!)) //;;T $$!))$*=*=*I*I4V ) .r"   )rb   r   rc   r   r   re   r   r   )rf   r   rg   r   ri   r   r-   r.   )r   	list[str]r-   r.   )r   list[str] | Noner-   r.   r   )r   r,   rg   z*list[tuple[int, str, str, UUID, str, str]]r   z
list[UUID]r-   r.   )r   r,   r   intr   r,   r   r,   r   r   r   list[Callable[[], None]]r   r,   r   r,   r-   r.   )r   r,   r   r   r   r   r-   r.   )r0   r1   r2   r3   r4   rR   r   r   r   r   r   r   r   r7   __classcell__r   s   @r   r   r   #  s   0&+& && 	&
 
& 7, 1X7t(( <( 	(
 
(T7B7B 7B 	7B
 7B 7B ,7B 7B 7B 
7Br  ,	
 
 r"   r   c                  j    \ rS rSrSr  S
       SS jjr\SS j5       rSS jrSS jr	SS jr
S	rg)CastBrowseri9  ab  Discover Chromecasts on the network.

When a Chromecast is found, cast_listener.add_cast is called
When a Chromecast is updated, cast_listener.update_cast is called
When a Chromecast is lost, the cast_listener.remove_cast is called

A shared zeroconf instance can be passed as zeroconf_instance. If no
instance is passed, a new instance will be created.
Nc                   Xl         X l        S U l        0 U l        U R                  U l        [
        R                  " 5       U l        [        U R                   U R                  U R                  5      U l	        [        U R                   U R                  U R                  U R                  5      U l        U(       a  U R                  R                  U5        g g rJ   )rb   rp   _zc_browserrg   rm   r   Lockre   r   rh   r^   zeroconf_listenerr   )r   rf   zeroconf_instancer   s       r   rR   CastBrowser.__init__D  s     ,#;?-/'nn.'t/B/B
 "2t/@/@$BUBU"
 ''4 r"   c                ,    [        U R                  5      $ )z"Number of discovered cast devices.)ro   rg   r   s    r   countCastBrowser.countY  s     4<<  r"   c                4    U R                   (       a  gXl         g)zSet zeroconf_instance.N)rp   )r   r  s     r   set_zeroconf_instance!CastBrowser.set_zeroconf_instance^  s    77#r"   c                    U R                   (       a1  [        R                  " U R                   SU R                  5      U l        U R
                  R                  5         g)a{  
This method will start discovering chromecasts on separate threads. When
a chromecast is discovered, callback will be called with the
discovered chromecast's zeroconf name. This is the dictionary key to find
the chromecast metadata in CastBrowser.devices.

A shared zeroconf instance can be passed as zeroconf_instance. If no
instance is passed, a new instance will be created.
z_googlecast._tcp.local.N)rp   zeroconfServiceBrowserr  r   rh   startr   s    r   start_discoveryCastBrowser.start_discoveryd  sE     77'66)&& D
 	!r"   c                @   U R                   (       a?   U R                   R                  5         U R                   R                  R	                  5         U R
                  R                  R                  5         U R
                  R                  5         g! [         a     Nof = f)z&Stop the chromecast discovery threads.N)	r   cancelRuntimeErrorrp   closerh   r   setjoinr   s    r   stop_discoveryCastBrowser.stop_discoveryw  sz      '') %%'""$    s   B 
BB)rb   re   r   rg   rh   rm   rp   r  r   )rf   r   r  zeroconf.Zeroconf | Noner   r   r-   r.   )r-   r   )r  r   r-   r.   r   )r0   r1   r2   r3   r4   rR   propertyr  r	  r  r  r7   r   r"   r   r   r   9  s]     7;(,	5+5 45 &	5
 
5* ! !$"&
!r"   r   c                  D   ^  \ rS rSrSr   S     SU 4S jjjrSrU =r$ )CastListeneri  zbBackwards compatible helper class.

Deprecated as of February 2021, will be removed in June 2024.
c                f   > [         R                  S5        [        XU5      n[        TU ]  U5        g )Nz^CastListener is deprecated and will be removed in June 2024, update to use CastBrowser instead)r:   inforG   r   rR   )r   rO   rP   rQ   listenerr   s        r   rR   CastListener.__init__  s/     	l	
 &l_U"r"   r   rZ   r[   )r0   r1   r2   r3   r4   rR   r7   r   r   s   @r   r  r    s;     <@HL>B	
#8
# F
# <	
# 
#r"   r  c                r    [         R                  S5        U R                  U5        U R                  5         U $ )zmStart discovering chromecasts on the network.

Deprecated as of February 2021, will be removed in June 2024.
zjstart_discovery is deprecated and will be removed in June 2024, call CastBrowser.start_discovery() instead)r:   r  r	  r  )cast_browserr  s     r   r  r    s6     LLt &&'89  "r"   c                N    [         R                  S5        U R                  5         g)zfStop the chromecast discovery threads.

Deprecated as of February 2021, will be removed in June 2024.
zhstop_discovery is deprecated and will be removed in June 2024, call CastBrowser.stop_discovery() insteadN)r:   r  r  )r"  s    r   r  r    s!    
 LLr !r"   c                b  ^ ^^ [         R                  S5        SUUU 4S jjn[        R                  " 5       mU=(       d    [        R
                  " 5       n[        [        U5      XS5      mTR                  5         TR                  U5        [        TR                  R                  5       5      T4$ )a  
Discover chromecasts on the network.

Deprecated as of February 2021, will be removed in June 2024.


Returns a tuple of:
  A list of chromecast devices, or an empty list if no chromecasts were found.
  A service browser to keep the Chromecast mDNS data updated. When updates
  are (no longer) needed, call browser.stop_discovery().

:param zeroconf_instance: An existing zeroconf instance.
zgdiscover_chromecasts is deprecated and will be removed in June 2024, update to use CastBrowser instead.c                P   > Tb"  TR                   T:  a  TR                  5         ggg)z1Called when a new chromecast has been discovered.N)r  r  )_uuid_servicebrowserdiscover_completemax_devicess     r   rO   *discover_chromecasts.<locals>.add_callback  s)    "w}}'C!!# (D"r"   )r&  r   r'  r,   r-   r.   )r:   r  r   r   r  Zeroconfr   rG   r  r   r   rg   values)r*  r   r  r   rO   r   r(  r)  s   `     @@r   discover_chromecastsr.    s    ( LLq$ $
 ")4!2!2!4E,\:EOG 7#'')*G44r"   c                0  ^ ^^^^	 0 mSUUU	U U4S jjn[         R                  " 5       m	U=(       d    [        R                  " 5       n[	        [        U5      Xd5      mTR                  5         T	R                  U5        [        TR                  5       5      T4$ )a  
Searches the network for chromecast devices matching a list of friendly
names or a list of UUIDs.

Returns a tuple of:
  A list of chromecast devices matching the criteria,
  or an empty list if no matching chromecasts were found.
  A service browser to keep the Chromecast mDNS data updated. When updates
  are (no longer) needed, call browser.stop_discovery().

:param friendly_names: A list of wanted friendly names
:param uuids: A list of wanted uuids
:param discovery_timeout: A floating point number specifying the time to wait
                           devices matching the criteria have been found.
:param zeroconf_instance: An existing zeroconf instance.
c                h  > [         R                  SX5        TR                  U    nUR                  nT(       a)  U T;   a#  TR                  U    TU '   TR	                  U 5        T(       a)  UT;   a#  TR                  U    TU '   TR	                  U5        T(       d  T(       d  TR                  5         g g g )NzGot cast %s, %s)r:   r;   rg   r   rn   r  )	r   r   r%   r   r(  cc_listr)  friendly_namesr   s	       r   rO   1discover_listed_chromecasts.<locals>.add_callback  s    '7OOD)	!//TU]#OOD1GDMLLm~=#OOD1GDM!!-0e!!# ',~r"   r+   )
r   r   r  r,  r   rG   r  r   r   r-  )
r2  r   discovery_timeoutr  r   rO   r   r(  r1  r)  s
   ``     @@@r   discover_listed_chromecastsr5    s|    0 %'G$ $ ")4!2!2!4E,\:EOG ,-!"G,,r"   )r<   r,   r=   r   r>   r,   r-   bool)rD   r,   r-   r6  )r"  r   r  r   r-   r   )r"  r   r-   r.   )
r*  z
int | Noner   floatr  r  r   r   r-   "tuple[list[CastInfo], CastBrowser])r2  r   r   zlist[UUID] | Noner4  r7  r  r  r   r   r-   r8  )4r4   
__future__r   r5   collections.abcr   r   r   loggingsslr   r   r   r   r  constr   r   r	   r
   dialr   r   r   modelsr   r   r   r   DISCOVER_TIMEOUTrC   	getLoggerr0   r:   ABCr   r@   rE   rG   ServiceListenerr^   r   r   r   Threadr   r   r  r  r  r.  r5  r   r"   r   <module>rE     s   ? " 
 $    
     J J H H O O  		' #
 

H
%377 <
$14	1- 14lx// l^      S)"" SlH! H!V#; #&2C" #%26$(	%5%5%5 0%5 "	%5
 (%5R (,#/26$(/-$/-/- /- 0	/-
 "/- (/-r"   