
    0FieS                    :   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mZ d dl	m
Z
 d dlmZ d dlmZ d dlZd dl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lmZ d dlm Z  d dl!m"Z" d dl#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*  ej+        e,          Z- G d de(          Z.ddZ/dS )    )annotationsN)suppress)Any)parse)IOLoop)_deprecatedformat_bytesparse_timedeltatypename)get_template)PeriodicCallback)Status)Adaptive)time)SchedulerInfo)LogLogs
LoopRunnerNoOpAwaitableSyncMethodMixinformat_dashboard_link
log_errorsc                  6   e Zd ZU dZdZdZded<   	 	 	 	 	 dAdZedBd
            Z	e	j
        dCd            Z	ed             Zed             Zej
        d             Zd Zd Zd ZdDdEdZej        fdZd Zd ZefdFdZdGd"Zd# ZdHd$ZdHd%Z ed&'          d(             Zd) Zed*             Zd+ Z d, Z!dDd-Z"d. Z#d/ Z$d0 Z%d1 Z&d2 Z'd3 Z(edId5            Z)ed6             Z*d7 Z+ed8             Z,ed9             Z-ed:             Z.d; Z/d< Z0dJd>Z1dDdKd@Z2dS )LClustera  Superclass for cluster objects

    This class contains common functionality for Dask Cluster manager classes.

    To implement this class, you must provide

    1.  A ``scheduler_comm`` attribute, which is a connection to the scheduler
        following the ``distributed.core.rpc`` API.
    2.  Implement ``scale``, which takes an integer and scales the cluster to
        that many workers, or else set ``_supports_scaling`` to False

    For that, you should get the following:

    1.  A standard ``__repr__``
    2.  A live IPython widget
    3.  Adaptive scaling
    4.  Integration with dask-labextension
    5.  A ``scheduler_info`` attribute which contains an up-to-date copy of
        ``Scheduler.identity()``, which is used for much of the above
    6.  Methods to gather logs
    TNIOLoop | None_Cluster__loopF   c                   t          ||          | _        || _        di i| _        i | _        d | _        d | _        g | _        || _        d | _	        d | _
        t          |d          | _        d | _        |(t          t          j                              d d         }|t#          t%          |                     d| _        t(          j        | _        d S )N)loopasynchronousworkerssecondsdefault   )nametype)r   _loop_runner_Cluster__asynchronousscheduler_infoperiodic_callbacks_watch_worker_status_comm_watch_worker_status_task_cluster_manager_logsquietscheduler_comm	_adaptiver
   _sync_interval_sync_cluster_info_taskstruuiduuid4r   r'   _cluster_infor   createdstatus)selfr    r   r/   r&   scheduler_sync_intervals         :lib/python3.11/site-packages/distributed/deploy/cluster.py__init__zCluster.__init__>   s     'D|LLL*("o"$)-&)-&%'"
"-#Y
 
 
 (,$<tz||$$RaR(D T$ZZ((
 
 n    returnc                >    | j         }|| j        j        x| _         }|S N)r   r(   r   )r:   r   s     r<   r   zCluster.loop_   s'    {<
 "&!2!77DK$r>   valuer   Nonec                n    t          j        dt          d           |t          d          || _        d S )Nz'setting the loop property is deprecated   )
stacklevelzexpected an IOLoop, got None)warningswarnDeprecationWarning
ValueErrorr   )r:   rB   s     r<   r   zCluster.loopj   sE    57IVW	
 	
 	
 	
 =;<<<r>   c                    	 t          | j        dd           t          j                    u S # t          $ r
 | j        cY S w xY w)Nasyncio_loop)getattrr   asyncioget_running_loopRuntimeErrorr)   r:   s    r<   called_from_running_loopz Cluster.called_from_running_loops   sW    	'	>488G<T<V<VV  	' 	' 	'&&&&	's   (+ ??c                    | j         d         S Nr&   r7   rQ   s    r<   r&   zCluster.name|   s    !&))r>   c                    || j         d<   d S rT   rU   )r:   r&   s     r<   r&   zCluster.name   s    %)6"""r>   c                  K   | j                                          d {V }d|_        |                    ddi           d {V  t	          |                                 d {V           | _        || _        t          j	        | 
                    |                    | _        | j                             dgi            d {V }| j                            |           t          j	        |                                           | _        | j                                        D ]}|                                 t(          j        | _        d S )NzCluster worker statusopsubscribe_worker_statuscluster-manager-info)keysr$   )r0   	live_commr&   writer   readr*   r,   rN   ensure_future_watch_worker_statusr-   get_metadatar7   update_sync_cluster_infor3   r+   valuesstartr   runningr9   )r:   comminfopcs       r<   _startzCluster._start   sn     (2244444444+	jj$ 9:;;;;;;;;;+$))++,=,=,=,=,=,=>>)-&)0)>%%d++*
 *
& (55()2 6 
 
 
 
 
 
 
 
 	!!$''' (/'<T=T=T=V=V'W'W$)0022 	 	BHHJJJJnr>   c                  K   d}d}d| j         z  }| j        t          j        k    r	 | j                            dg| j                                                   d {V  d}n7# t          $ r* |dz  }||k    rt          
                    dd	           Y nw xY wt          || j         d
|          }t          j        |           d {V  | j        t          j        k    d S d S )Nr      
   rZ   )r[   rB   r   zWFailed to sync cluster info multiple times - perhaps there's a connection issue? Error:T)exc_infog      ?)r2   r9   r   rf   r0   set_metadatar7   copy	Exceptionloggerwarning_exponential_backoffrN   sleep)r:   	err_countwarn_atmax_intervalintervals        r<   rc   zCluster._sync_cluster_info   sF     	D// kV^++)6601,1133 7          		   Q	
 ''NN=!% #    ,4.\ H -)))))))))/ kV^++++++s   <A$ $1BBc                  K   | j         t          j        k    rd S t          j        | _         t	          t
                    5  | j                                         d d d            n# 1 swxY w Y   | j        r| j        	                                 d {V  | j
        r| j
         d {V  | j        rW| j                                         t	          t          j                  5  | j         d {V  d d d            n# 1 swxY w Y   | j        r| j                                         d {V  | j                                        D ]}|                                 t          j        | _         d S rA   )r9   r   closedclosingr   AttributeErrorr1   stopr,   closer-   r3   cancelrN   CancelledErrorr0   	close_rpcr+   rd   )r:   ri   s     r<   _closezCluster._close   s     ;&-''Fnn%% 	" 	"N!!!	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" ) 	9066888888888) 	100000000' 	3(//111'011 3 3222222223 3 3 3 3 3 3 3 3 3 3 3 3 3 3  	2%//111111111)0022 	 	BGGIIIIms#   A%%A),A)#C==DDtimeoutfloat | Noner   c                    | j         t          j        k    r| j        rt	                      S d S 	 |                     | j        |          S # t          $ r Y d S w xY w)N)callback_timeout)r9   r   r{   r    r   syncr   rP   )r:   r   s     r<   r   zCluster.close   sj    ;&-''  '$&4	99T[79CCC 	 	 	44	s   A
 

AAc                   t          | dt          j                  t          j        k    rV	 t          |           }n-# t          $ r  dt
                              |            }Y nw xY w |d| t          |            d S d S )Nr9   zwith a broken __repr__ zunclosed cluster )source)rM   r   r{   reprrq   object__repr__ResourceWarning)r:   _warnself_rs      r<   __del__zCluster.__del__   s    46=11V]BBKd K K KJ6??43H3HJJKE.f..MMMMMM CBs   ; 'A%$A%c                $  K   	 	 |                                  d{V }n# t          $ r Y nJw xY wt                      5  |D ]\  }}|                     ||           	 ddd           n# 1 swxY w Y   r|                                 d{V  dS )z>Listen to scheduler for updates on adding and removing workersTN)r^   OSErrorr   _update_worker_statusr   )r:   rg   msgsrX   msgs        r<   r`   zCluster._watch_worker_status   s     	8!YY[[((((((     8 8# 8 8GB..r3777788 8 8 8 8 8 8 8 8 8 8 8 8 8 8	8 jjlls     
--A**A.1A.c                    |dk    rQ|                     d          }| j        d                             |           | j                            |           d S |dk    r| j        d         |= d S t          d||          )Naddr!   removez
Invalid op)popr*   rb   rJ   )r:   rX   r   r!   s       r<   r   zCluster._update_worker_status   s    ;;ggi((G	*11':::&&s+++++8^^#I.s333\2s333r>   r   type[Adaptive]kwargsc                "   t          t                    5  | j                                         ddd           n# 1 swxY w Y   t	          | d          si | _        | j                            |            || fi | j        | _        | j        S )zTurn on adaptivity

        For keyword arguments see dask.distributed.Adaptive

        Examples
        --------
        >>> cluster.adapt(minimum=0, maximum=10, interval='500ms')
        N_adaptive_options)r   r}   r1   r~   hasattrr   rb   )r:   r   r   s      r<   adaptzCluster.adapt  s     n%% 	" 	"N!!!	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	"t011 	(%'D"%%f---!$AA$*@AA~s   ;??nintc                    t                      )zScale cluster to n workers

        Parameters
        ----------
        n : int
            Target number of workers

        Examples
        --------
        >>> cluster.scale(10)  # scale cluster to ten workers
        )NotImplementedError)r:   r   s     r<   scalezCluster.scale  s     "###r>   c                    | j                             t          j                                        |f           | j        st          |           dS dS )aC  Log a message.

        Output a message to the user and also store for future retrieval.

        For use in subclasses where initialisation may take a while and it would
        be beneficial to feed back to the user.

        Examples
        --------
        >>> self._log("Submitted job X to batch scheduler")
        N)r.   appenddatetimenowr/   print)r:   logs     r<   _logzCluster._log"  sR     	"))8+<+@+@+B+BC*HIIIz 	#JJJJJ	 	r>   c                  K   t                      }|r4t          d                    d | j        D                                 |d<   |rN| j                                         d {V }t          d                    d |D                                 |d<   |rp|du rd }| j                            |           d {V }|                                D ]4\  }}t          d                    d |D                                 ||<   5|S )	N
c              3  &   K   | ]}|d          V  dS )r   N ).0lines     r<   	<genexpr>z$Cluster._get_logs.<locals>.<genexpr>7  s&      IId$q'IIIIIIr>   r   c              3      K   | ]	\  }}|V  
d S rA   r   r   levelr   s      r<   r   z$Cluster._get_logs.<locals>.<genexpr><  s&      -H-H{udd-H-H-H-H-H-Hr>   	SchedulerT)r!   c              3      K   | ]	\  }}|V  
d S rA   r   r   s      r<   r   z$Cluster._get_logs.<locals>.<genexpr>C  s&      'B'B'B'B'B'B'B'Br>   )r   r   joinr.   r0   get_logsworker_logsitems)	r:   cluster	schedulerr!   logsLdkvs	            r<   	_get_logszCluster._get_logs2  s;     vv 	!		IId.HIIIII DO  	J)2244444444A #DII-H-Ha-H-H-H$H$H I ID 	D$)55g5FFFFFFFFA		 D D1dii'B'B'B'B'BBBCCQr>   c                >    |                      | j        |||          S )ae  Return logs for the cluster, scheduler and workers

        Parameters
        ----------
        cluster : boolean
            Whether or not to collect logs for the cluster manager
        scheduler : boolean
            Whether or not to collect logs for the scheduler
        workers : boolean or Iterable[str], optional
            A list of worker addresses to select.
            Defaults to all workers if `True` or no workers if `False`

        Returns
        -------
        logs: Dict[str]
            A dictionary of logs, with one item for the scheduler and one for
            each worker
        )r   r   r!   )r   r   )r:   r   r   r!   s       r<   r   zCluster.get_logsG  s*    & yyNGy'  
 
 	
r>   r   )use_insteadc                     | j         |i |S rA   )r   )r:   argsr   s      r<   r   zCluster.logs^  s    t}d-f---r>   c                    ddl m} 	 |                                }|r|j        | k    r|S n# t          $ r Y nw xY w ||           S )zReturn client for the cluster

        If a client has already been initialized for the cluster, return that
        otherwise initialize a new client object.
        r   )Client)distributed.clientr   currentr   rJ   )r:   r   current_clients      r<   
get_clientzCluster.get_clientb  st     	.-----	#^^--N &."8D"@"@%% 	 	 	D	vd||s   ", 
99c                   	 | j         d         d         }| j                            d          d                             d          d                             d          d         }t          ||          S # t          $ r Y dS w xY w)	Nservices	dashboardz://r   /r   : )r*   scheduler_addresssplitr   KeyError)r:   porthosts      r<   dashboard_linkzCluster.dashboard_linkr  s    	5&z2;?D )//66q9??DDQGMMcRRSTUD(t444	  	 	 	22	s   A7 7
BBc                f   | j         r| j         j        rd}nd}t          | j        d                   }t	          | d          r1t          d | j                                        D                       }n't	          | d          rt          | j                  }n|}||k    r|n| d| }d| d| d	S )
Nr   Manualr!   worker_specc              3  L   K   | ]}d |vrdnt          |d                    V   dS )groupr   N)len)r   eachs     r<   r   z*Cluster._scaling_status.<locals>.<genexpr>  sP         D((c$w-.@.@     r>   z / zM
        <table>
            <tr><td style="text-align: left;">Scaling mode: zB</td></tr>
            <tr><td style="text-align: left;">Workers: z$</td></tr>
        </table>
        )	r1   periodic_callbackr   r*   r   sumr   rd   r!   )r:   moder!   	requestedworker_counts        r<   _scaling_statuszCluster._scaling_status|  s    > 	dn> 	DDDd))4554'' 	    ,3355    II T9%% 	 DL))III")Y"6"6www<V<V9<V<V=A  9E   	r>   c                |    	  j         S # t          $ r Y nw xY w	 ddlm}m}m}m}m}m}m	}m
} n# t          $ r d _         Y dS w xY w |d          }	 |                                            j        r |dd|	           |d|	          }
 |dd	|	           |dd
|	           |d|	          } | ||
g           ||g          g |d                    }d|_        |                    dd           |                    dd            fd}|                    |           t"           fd            }|
                    |           n |d          } |                                            |            } ||g          g|_        |                    dd           |                    dd           | _          fdt)          t*          j                            dd                     fd} j                            |           |S )z3Create IPython widget for display within a notebookr   )HTML	AccordionButtonHBoxIntTextLayoutTabVBoxN150px)widthWorkers)descriptionlayoutScaleMinimumMaximumAdapt500px)	min_width)r   zManual Scalingr   zAdaptive Scalingc                ^                         j        j                                 d S )N)minimummaximum)r   rB   )br   r   r:   rb   s    r<   adapt_cbz!Cluster._widget.<locals>.adapt_cb  s,    

7='-
HHHr>   c                    j         }t          t                    5  j                                         d d d            n# 1 swxY w Y                       |                         d S rA   )rB   r   r}   r1   r~   r   )r   r   requestr:   rb   s     r<   scale_cbz!Cluster._widget.<locals>.scale_cb  s    Mn-- * *N'')))* * * * * * * * * * * * * * *

1s   AA
Ar   r   Scalingc                 l                                     _                                         _        d S rA   )_repr_html_rB   r   )scale_statusr:   r9   s   r<   rb   zCluster._widget.<locals>.update  s0    ++--FL!%!5!5!7!7Lr>   z(distributed.deploy.cluster-repr-intervalmsr#   c                 j    t          dz            } | j        d<   |                                  d S )Ni  zcluster-repr)r   r+   re   )ri   cluster_repr_intervalr:   rb   s    r<   installz Cluster._widget.<locals>.install  s6    !&*?$*FGGB68D#N3HHJJJJJr>   )_cached_widgetr}   
ipywidgetsr   r   r   r   r   r   r   r   ImportErrorr  _supports_scalingselected_index	set_titleon_clickr   r   childrenr
   daskconfiggetr   add_callback)r:   r   r   r   r   r   r   r   r   r   r   r   	accordionr   r  tabr  r
  r   r   r  r  r9   rb   s   `                @@@@@@@r<   _widgetzCluster._widget  s   	&& 	 	 	D			 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	  	 	 	"&D44	 g&&&d&&(())!  	!gaYvFFFGFwv>>>EgaYvFFFGgaYvFFFGFwv>>>E!	w&''w.G)H)HIv000  I (,I$#3444#5666        NN8$$$      Z NN8$$$$RItD002233ceelI%> ? ?@a"""a###!	8 	8 	8 	8 	8 	8 	8 !0KOOFPTOUU!
 !
	 	 	 	 	 	 	
 		w'''
s    
7 AAc                    	 | j                                         }n# t          $ r d}Y nw xY wt          d                              t          |           j        | j        | j         d         | j        ||          S )NzScheduler not started yet.zcluster.html.j2r!   )r'   r&   r!   r   scheduler_info_reprcluster_status)	r*   r  r}   r   renderr'   __name__r&   r   )r:   r  r  s      r<   r  zCluster._repr_html_  s    	?"&"5"A"A"C"C 	? 	? 	?">	? -..55d$'	2. 3) 6 
 
 	
s    ++c                   ddl m} |                                 }|r{ddl}t	          |j                  t	          d          k    rG |j        d
i |pi }t          |           |d<   |                                 |d<    ||d           dS  ||fi | dS t          |           |                                 d	} ||d           dS )z%Display the cluster rich IPython reprr   )displayNz8.0.0
text/plain	text/htmlT)raw)r"  r#  r   )	IPython.displayr!  r  r  parse_version__version___repr_mimebundle_r   r  )r:   r   r!  widgetr  
mimebundles         r<   _ipython_display_zCluster._ipython_display_  s    	,+++++ 	*Z344g8N8NNN5V5????E2
+/::
<(*.*:*:*<*<
;'
------))&)))))(,T

AQAQASASTTJGJD))))))r>   c                b    | j         rt          d          |                     | j                  S )Nz<Used 'with' with asynchronous class; please use 'async with')r    	TypeErrorr   
__aenter__rQ   s    r<   	__enter__zCluster.__enter__  s8     	N   yy)))r>   c                F    |                                  }|
J |            d S rA   r   )r:   exc_type	exc_value	tracebackaws        r<   __exit__zCluster.__exit__  s"    ZZ\\zz2zzzzzr>   c              #  
   K   | S rA   r   rQ   s    r<   	__await__zCluster.__await__  s      r>   c                   K   |  d {V  | S rA   r   rQ   s    r<   r.  zCluster.__aenter__   s      






r>   c                >   K   |                                   d {V  d S rA   r1  )r:   r2  r3  r4  s       r<   	__aexit__zCluster.__aexit__$  s,      jjllr>   r4   c                ,    | j         sdS | j         j        S )Nz<Not Connected>)r0   addressrQ   s    r<   r   zCluster.scheduler_address'  s    " 	%$$"**r>   c                H    t          | dt          |           j                  S )N_name)rM   r'   r  rQ   s    r<   _cluster_class_namezCluster._cluster_class_name-  s    tWd4jj&9:::r>   c           
        d| j         | j        | j        t          | j        d                   t          d | j        d                                         D                       fz  }d | j        d                                         D             }t          |          r"|dt          t          |                    z   z  }|dz  }|S )Nz!%s(%s, %r, workers=%d, threads=%dr!   c              3  &   K   | ]}|d          V  dS )nthreadsNr   r   ws     r<   r   z#Cluster.__repr__.<locals>.<genexpr>7  s&      OO!*OOOOOOr>   c                    g | ]
}|d          S )memory_limitr   rD  s     r<   
<listcomp>z$Cluster.__repr__.<locals>.<listcomp>:  s    UUU!N#UUUr>   z	, memory=))	r@  r&   r   r   r*   r   rd   allr	   )r:   textmemorys      r<   r   zCluster.__repr__1  s    2$I"#I.//OOt':9'E'L'L'N'NOOOOO6
 
 VUT-@-K-R-R-T-TUUUv;; 	<K,s6{{";";;;Dr>   c                *    t          | j                  S rA   setr!   rQ   s    r<   planzCluster.planA      4<   r>   c                *    t          | j                  S rA   rN  rQ   s    r<   r   zCluster.requestedE  rQ  r>   c                T    d | j         d                                         D             S )Nc                    h | ]
}|d          S )r&   r   )r   r   s     r<   	<setcomp>z#Cluster.observed.<locals>.<setcomp>K  s    KKKa&	KKKr>   r!   )r*   rd   rQ   s    r<   observedzCluster.observedI  s*    KK4#6y#A#H#H#J#JKKKKr>   c                b    t          |          t          |           k    o| j        |j        k    S rA   )r'   r&   )r:   others     r<   __eq__zCluster.__eq__M  s'    E{{d4jj(DTY%*-DDr>   c                     t          |           S rA   )idrQ   s    r<   __hash__zCluster.__hash__P  s    $xxr>   r   c                   K   t          | j                                         d {V           | _        |rt	                      t          |          z   }nd }d }|r || j                  |k     r|r5t	                      |k    r#t          d || j                  ||fz            t          j        d           d {V  t          | j                                         d {V           | _        |r || j                  |k     d S d S d S d S )Nc                d    t          d | d                                         D                       S )Nc                H    g | ]}|d          t           j        j        k    | S )r9   )r   rf   r&   )r   wss     r<   rH  zFCluster._wait_for_workers.<locals>.running_workers.<locals>.<listcomp>\  s6       (|v~'::: :::r>   r!   )r   rd   )rh   s    r<   running_workersz2Cluster._wait_for_workers.<locals>.running_workersZ  s@     "9o4466    r>   z#Only %d/%d workers arrived after %sg?)	r   r0   identityr*   r   r
   TimeoutErrorrN   ru   )r:   	n_workersr   deadlinera  s        r<   _wait_for_workerszCluster._wait_for_workersS  sp     +$2E2N2N2P2P,P,P,P,P,P,PQQ 	vv 8 88HHH	 	 	  	VOOD,?@@9LL DFFX--"9&t':;;YPQ   -$$$$$$$$$"/d6I6R6R6T6T0T0T0T0T0T0T"U"UD  	VOOD,?@@9LLLL 	V 	VLL 	V 	Vr>   rd  c                    t          |t                    r|dk     rt          d| d          |                     | j        ||          S )a#  Blocking call to wait for n workers before continuing

        Parameters
        ----------
        n_workers : int
            The number of workers
        timeout : number, optional
            Time in seconds after which to raise a
            ``dask.distributed.TimeoutError``
        r   z4`n_workers` must be a positive integer. Instead got .)r   )
isinstancer   rJ   r   rf  )r:   rd  r   s      r<   wait_for_workerszCluster.wait_for_workersm  s[     )S)) 	Y]]SySSS   yy/GyLLLr>   )FNFNr   )r?   r   )rB   r   r?   rC   rA   )r   r   r?   r   )r   r   r   r   r?   r   )r   r   r?   rC   )TTT)r?   r4   )r   N)rd  r   r   r   r?   rC   )3r  
__module____qualname____doc__r  r   __annotations__r=   propertyr   setterrR   r&   rj   rc   r   r   rG   rH   r   r`   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r+  r/  r6  r8  r.  r;  r   r@  r   rP  r   rV  rY  r\  rf  rj  r   r>   r<   r   r   $   s         ,  F      !% % % %B    X 
[   [ ' ' X' * * X* 
[* * [*% % %, *  *  *D$ $ $6
 
 
 
 
 %M N N N N  4 4 4 08     "$ $ $ $      *
 
 
 
. [Z(((. . )(.    5 5 X5  0S S Sj
 
 
 
* * *0* * *         + + + X+
 ; ; X;    ! ! X! ! ! X! L L XLE E E  V V V V4M M M M M M Mr>   r   attemptr   
multiplierfloatexponential_baserx   r?   c                Z    	 ||| z  z  }n# t           $ r |cY S w xY wt          ||          S )z0Calculate the duration of an exponential backoff)OverflowErrormin)rq  rr  rt  rx   ry   s        r<   rt   rt     sR     0' 99    |X&&&s    )
rq  r   rr  rs  rt  rs  rx   rs  r?   rs  )0
__future__r   rN   r   loggingr5   rG   
contextlibr   typingr   packaging.versionr   r&  tornado.ioloopr   dask.configr  
dask.utilsr   r	   r
   r   dask.widgetsr   distributed.compatibilityr   distributed.corer   distributed.deploy.adaptiver   distributed.metricsr   distributed.objectsr   distributed.utilsr   r   r   r   r   r   r   	getLoggerr  rr   r   rt   r   r>   r<   <module>r     s   " " " " " "                  4 4 4 4 4 4 ! ! ! ! ! !     K K K K K K K K K K K K % % % % % % 6 6 6 6 6 6 # # # # # # 0 0 0 0 0 0 $ $ $ $ $ $ - - - - - -                  
	8	$	$X	M X	M X	M X	M X	Mo X	M X	M X	Mv	' 	' 	' 	' 	' 	'r>   