<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css"
        integrity="sha512-SzlrxWUlpfuzQ+pcUCosxcglQRNAq/DZjVsC0lE40xsADsfeQoEypE+enwcOiGjk/bSuGGKHEyjSoQ1zVisanQ=="
        crossorigin="anonymous" referrerpolicy="no-referrer" />
</head>
</html>
3
JZ=G                 @   s<  d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZ
ddl
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 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 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# 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Z)d Z*d!Z+e'rd"nd#Z,e
j-j.Z.e
j/ Z0e'rd"nd#Z,d$d% Z1d&d' Z2G d(d) d)e(j3Z4G d*d+ d+e4Z5G d,d- d-e5Z6G d.d/ d/e4Z7e8d0kr8e#e9 dS )1a)  
Tests for detecting function memory leaks (typically the ones
implemented in C). It does so by calling a function many times and
checking whether process memory usage keeps increasing between
calls or over time.
Note that this may produce false positives (especially on Windows
for some reason).
    )print_functionN)LINUX)OPENBSD)OSX)POSIX)SUNOS)WINDOWS)xrange)create_sockets)get_test_subprocess)HAS_CPU_AFFINITY)HAS_CPU_FREQ)HAS_ENVIRON)
HAS_IONICE)HAS_MEMORY_MAPS)HAS_PROC_CPU_NUM)HAS_PROC_IO_COUNTERS)
HAS_RLIMIT)HAS_SENSORS_BATTERY)HAS_SENSORS_FANS)HAS_SENSORS_TEMPERATURES)reap_children)run_test_module_by_name)safe_rmpath)skip_on_access_denied)TESTFN)TRAVIS)unittesti  i      TFc               C   s   t jto
tdS )Nz worthless on LINUX (pure python))r   skipIfr   SKIP_PYTHON_IMPL r!   r!   )/usr/lib64/python3.6/test_memory_leaks.pyskip_if_linuxF   s    
r#   c             C   st   d}i }x(t |D ]\}}d	|d	 d
 > ||< qW x8t|D ],}| || kr<t| ||  }d||f S q<W d|  S )z
    http://code.activestate.com/recipes/578019
    >>> bytes2human(10000)
    '9.8K'
    >>> bytes2human(100001221)
    '95.4M'
    KMGTPEZY   
   z%.2f%sz%sB)r$   r%   r&   r'   r(   r)   r*   r+   )	enumeratereversedfloat)nZsymbolsprefixisvaluer!   r!   r"   bytes2humanK   s    r6   c               @   sL   e Zd ZdZeZeZeZ	dd Z
dd Zdd Zedd	 Zed
d ZdS )TestMemLeakzBase framework class which calls a function many times and
    produces a failure if process memory usage keeps increasing
    between calls or over time.
    c             C   s   t j  d S )N)gccollect)selfr!   r!   r"   setUpg   s    zTestMemLeak.setUpc                s~   fdd}j ddp$j}j ddp6jj ddpHj}x"tdD ]}jf  qTW jtjg  jt	j
 d jtj g  |  j }|  j }	|	| }
|
|krzd	}tj | }x,tj |krjf  |d7 }qW ~tj  j }||	 }||	krzt|
| }td
| tjd d}|d7 }|t|
t|||f }j| dS )zTest a callable.c                 s2   x"t D ]} jf  q
W ~ tj  d S )N)r	   _callr8   r9   )x)argsfunkwargsloopsr:   r!   r"   call_many_timesl   s    z,TestMemLeak.execute.<locals>.call_many_times
tolerance_NZloops_Z
retry_for_r-   r,   r   zexta proc mem: %s)filez0+%s after %s calls, +%s after another %s calls, z+%s extra proc mem)pop	tolerancerA   	retry_forranger<   ZassertEqualr8   Zgarbage	threadingZactive_countthisprocchildren_get_memtimer9   r6   printsysstderrZfail)r:   r?   r>   r@   rB   rF   rG   r=   Zmem1Zmem2Zdiff1ZncallsZstop_atZmem3Zdiff2Zextra_proc_memmsgr!   )r>   r?   r@   rA   r:   r"   executej   sB    

zTestMemLeak.executec                s"    fdd}j | dS )zRConvenience function which tests a callable raising
        an exception.
        c                  s   j f  d S )N)ZassertRaisesr!   )r>   excr?   r@   r:   r!   r"   call   s    z'TestMemLeak.execute_w_exc.<locals>.callN)rR   )r:   rS   r?   r>   r@   rT   r!   )r>   rS   r?   r@   r:   r"   execute_w_exc   s    zTestMemLeak.execute_w_excc               C   s$   t ststrtj jS tj jS d S )N)r   r   r   rJ   memory_full_infoZussmemory_infoZrssr!   r!   r!   r"   rL      s    
zTestMemLeak._get_memc             O   s   | || d S )Nr!   )r?   r>   r@   r!   r!   r"   r<      s    zTestMemLeak._callN)__name__
__module____qualname____doc__MEMORY_TOLERANCErF   LOOPSrA   	RETRY_FORrG   r;   rR   rU   staticmethodrL   r<   r!   r!   r!   r"   r7   ^   s   ;		r7   c               @   s  e Zd ZdZeZdd Ze dd Ze dd Z	e dd	 Z
e d
d Zeje de dd Zeje de dd Ze dd Zdd Zdd Zeje ddd Zeje ddd Zeje de dd Zejeddd  Ze d!d" Ze eed#d$d% Zeje d&d'd( Zeje de d)d* Z e d+d, Z!e eed#d-d. Z"e d/d0 Z#e eje$ dd1d2 Z%e d3d4 Z&e d5d6 Z'eje de d7d8 Z(ejeoe)d9d:d; Z*e d<d= Z+eje, dd>d? Z-eje, dd@dA Z.e dBdC Z/eje0dDeje1 de dEdF Z2eje3 dGeje4 ddHdI Z5eje3 dGeje4 ddJdK Z6e ejedLdMdN Z7eje8 ddOdP Z9eje d&dQdR Z:dSS )TTestProcessObjectLeaksz$Test leaks of Process class methods.c             C   sN   t d}x@ttjD ]2}|jdr$q||kr.q| jt| d| |d qW d S )Npidas_dictrK   cpu_affinitycpu_percentionice
is_runningkillmemory_info_exmemory_percentniceoneshotparentrlimitsend_signalsuspend	terminatewait_test_)rQ   )ra   rb   rK   rc   rd   re   rf   rg   rh   ri   rj   rk   rl   rm   rn   ro   rp   rq   )setdirpsutilProcess
startswith
assertTruehasattr)r:   skipnamer!   r!   r"   test_coverage   s       
z$TestProcessObjectLeaks.test_coveragec             C   s   | j | jj d S )N)rR   procr|   )r:   r!   r!   r"   	test_name   s    z TestProcessObjectLeaks.test_namec             C   s   | j | jj d S )N)rR   r~   Zcmdline)r:   r!   r!   r"   test_cmdline   s    z#TestProcessObjectLeaks.test_cmdlinec             C   s   | j | jj d S )N)rR   r~   Zexe)r:   r!   r!   r"   test_exe   s    zTestProcessObjectLeaks.test_exec             C   s   | j | jj d S )N)rR   r~   Zppid)r:   r!   r!   r"   	test_ppid   s    z TestProcessObjectLeaks.test_ppidz
POSIX onlyc             C   s   | j | jj d S )N)rR   r~   Zuids)r:   r!   r!   r"   	test_uids   s    z TestProcessObjectLeaks.test_uidsc             C   s   | j | jj d S )N)rR   r~   Zgids)r:   r!   r!   r"   	test_gids   s    z TestProcessObjectLeaks.test_gidsc             C   s   | j | jj d S )N)rR   r~   Zstatus)r:   r!   r!   r"   test_status   s    z"TestProcessObjectLeaks.test_statusc             C   s   | j | jj d S )N)rR   r~   rj   )r:   r!   r!   r"   test_nice_get   s    z$TestProcessObjectLeaks.test_nice_getc             C   s   t j }| j| jj| d S )N)rJ   rj   rR   r~   )r:   Znicenessr!   r!   r"   test_nice_set   s    z$TestProcessObjectLeaks.test_nice_setznot supportedc             C   s   | j | jj d S )N)rR   r~   re   )r:   r!   r!   r"   test_ionice_get   s    z&TestProcessObjectLeaks.test_ionice_getc             C   sV   t rtj }| j| jj| n4| j| jjtj tjt	j
tj dd}| jt| d S )Nr,   r   )r   rJ   re   rR   r~   rv   ZIOPRIO_CLASS_NONE	functoolspartialcextZproc_ioprio_setosgetpidrU   OSError)r:   r5   r?   r!   r!   r"   test_ionice_set   s    z&TestProcessObjectLeaks.test_ionice_setc             C   s   | j | jj d S )N)rR   r~   Zio_counters)r:   r!   r!   r"   test_io_counters  s    z'TestProcessObjectLeaks.test_io_counterszworthless on POSIXc             C   s   | j | jj d S )N)rR   r~   Zusername)r:   r!   r!   r"   test_username  s    z$TestProcessObjectLeaks.test_usernamec             C   s   | j | jj d S )N)rR   r~   Zcreate_time)r:   r!   r!   r"   test_create_time  s    z'TestProcessObjectLeaks.test_create_time)Zonly_ifc             C   s   | j | jj d S )N)rR   r~   Znum_threads)r:   r!   r!   r"   test_num_threads  s    z'TestProcessObjectLeaks.test_num_threadszWINDOWS onlyc             C   s   | j | jj d S )N)rR   r~   Znum_handles)r:   r!   r!   r"   test_num_handles  s    z'TestProcessObjectLeaks.test_num_handlesc             C   s   | j | jj d S )N)rR   r~   Znum_fds)r:   r!   r!   r"   test_num_fds  s    z#TestProcessObjectLeaks.test_num_fdsc             C   s   | j | jj d S )N)rR   r~   Znum_ctx_switches)r:   r!   r!   r"   test_num_ctx_switches!  s    z,TestProcessObjectLeaks.test_num_ctx_switchesc             C   s   | j | jj d S )N)rR   r~   Zthreads)r:   r!   r!   r"   test_threads%  s    z#TestProcessObjectLeaks.test_threadsc             C   s   | j | jj d S )N)rR   r~   	cpu_times)r:   r!   r!   r"   test_cpu_times*  s    z%TestProcessObjectLeaks.test_cpu_timesc             C   s   | j | jj d S )N)rR   r~   Zcpu_num)r:   r!   r!   r"   test_cpu_num.  s    z#TestProcessObjectLeaks.test_cpu_numc             C   s   | j | jj d S )N)rR   r~   rW   )r:   r!   r!   r"   test_memory_info3  s    z'TestProcessObjectLeaks.test_memory_infoc             C   s   | j | jj d S )N)rR   r~   rV   )r:   r!   r!   r"   test_memory_full_info7  s    z,TestProcessObjectLeaks.test_memory_full_infoc             C   s   | j | jj d S )N)rR   r~   Zterminal)r:   r!   r!   r"   test_terminal;  s    z$TestProcessObjectLeaks.test_terminalz worthless on POSIX (pure python)c             C   s   | j | jj d S )N)rR   r~   resume)r:   r!   r!   r"   test_resume@  s    z"TestProcessObjectLeaks.test_resumec             C   s   | j | jj d S )N)rR   r~   cwd)r:   r!   r!   r"   test_cwdE  s    zTestProcessObjectLeaks.test_cwdc             C   s   | j | jj d S )N)rR   r~   rc   )r:   r!   r!   r"   test_cpu_affinity_getI  s    z,TestProcessObjectLeaks.test_cpu_affinity_getc             C   s4   t j }| j| jj| ts0| jt| jjdg d S )Nr,   r   )rJ   rc   rR   r~   r   rU   
ValueError)r:   Zaffinityr!   r!   r"   test_cpu_affinity_setM  s    z,TestProcessObjectLeaks.test_cpu_affinity_setc          	   C   s0   t t ttd | j| jj W d Q R X d S )Nw)r   r   openrR   r~   Z
open_files)r:   r!   r!   r"   test_open_filesT  s    z&TestProcessObjectLeaks.test_open_filesztoo slow on OSXc             C   s   | j | jj d S )N)rR   r~   Zmemory_maps)r:   r!   r!   r"   test_memory_maps[  s    z'TestProcessObjectLeaks.test_memory_mapsz
LINUX onlyc             C   s   | j | jjtj d S )N)rR   r~   rm   rv   RLIMIT_NOFILE)r:   r!   r!   r"   test_rlimit_geta  s    z&TestProcessObjectLeaks.test_rlimit_getc             C   s6   t jtj}| j| jjtj| | jt| jjd d S )Nr,   r   )rJ   rm   rv   r   rR   r~   rU   r   )r:   limitr!   r!   r"   test_rlimit_setf  s    z&TestProcessObjectLeaks.test_rlimit_setzworthless on WINDOWSc          
   C   s2   t  " trdnd}| j| jj| W d Q R X d S )NZinetall)r
   r   rR   r~   Zconnections)r:   Zkindr!   r!   r"   test_connectionsm  s    z'TestProcessObjectLeaks.test_connectionsc             C   s   | j | jj d S )N)rR   r~   environ)r:   r!   r!   r"   test_environy  s    z#TestProcessObjectLeaks.test_environc             C   s   | j tjtj  d S )N)rR   r   	proc_infor   r   )r:   r!   r!   r"   test_proc_info}  s    z%TestProcessObjectLeaks.test_proc_infoN);rX   rY   rZ   r[   rJ   r~   r}   r#   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r!   r!   r!   r"   r`      sh   

	r`   c                   sp   e Zd ZdZe fddZe fddZdd Zerhdd	 Z	d
d Z
dd Zdd Zdd Zdd Z  ZS )TestTerminatedProcessLeakszRepeat the tests above looking for leaks occurring when dealing
    with terminated processes raising NoSuchProcess exception.
    The C functions are still invoked but will follow different code
    paths. We'll check those code paths.
    c                s:   t t| j  t }tj|j| _| jj  | jj	  d S )N)
superr   
setUpClassr   rv   rw   ra   r~   rg   rq   )clsp)	__class__r!   r"   r     s
    
z%TestTerminatedProcessLeaks.setUpClassc                s   t t| j  t  d S )N)r   r   tearDownClassr   )r   )r   r!   r"   r     s    z(TestTerminatedProcessLeaks.tearDownClassc             O   s*   y||| W n t jk
r$   Y nX d S )N)rv   ZNoSuchProcess)r:   r?   r>   r@   r!   r!   r"   r<     s    z TestTerminatedProcessLeaks._callc             C   s   | j | jj d S )N)rR   r~   rg   )r:   r!   r!   r"   	test_kill  s    z$TestTerminatedProcessLeaks.test_killc             C   s   | j | jj d S )N)rR   r~   rp   )r:   r!   r!   r"   test_terminate  s    z)TestTerminatedProcessLeaks.test_terminatec             C   s   | j | jj d S )N)rR   r~   ro   )r:   r!   r!   r"   test_suspend  s    z'TestTerminatedProcessLeaks.test_suspendc             C   s   | j | jj d S )N)rR   r~   r   )r:   r!   r!   r"   r     s    z&TestTerminatedProcessLeaks.test_resumec             C   s   | j | jj d S )N)rR   r~   rq   )r:   r!   r!   r"   	test_wait  s    z$TestTerminatedProcessLeaks.test_waitc                s    fdd} j | d S )Nc                 sD   yt j jjS  tk
r> }  z| jtjkr. W Y d d } ~ X nX d S )N)r   r   r~   ra   r   errnoZESRCH)err)r:   r!   r"   rT     s
    z7TestTerminatedProcessLeaks.test_proc_info.<locals>.call)rR   )r:   rT   r!   )r:   r"   r     s    z)TestTerminatedProcessLeaks.test_proc_info)rX   rY   rZ   r[   classmethodr   r   r<   r   r   r   r   r   r   r   __classcell__r!   r!   )r   r"   r     s   r   c               @   s  e Zd ZdZdd Ze dd Ze dd Ze dd	 Ze d
d Z	dd Z
e eje ddd Zdd Zejeddd Zejeoeddd Zejeoeddd Zdd Zejeoejjd de dd  Ze d!d" Ze d#d$ Zejed%ejeo&ej d&kd'd(d) Z d*d+ Z!eje"d,d-d. Z#e eje$ dd/d0 Z%e eje& dd1d2 Z'e eje( dd3d4 Z)e d5d6 Z*eje+d7d8d9 Z,e+rd:d; Z-d<d= Z.d>d? Z/d@dA Z0dBdC Z1dDS )ETestModuleFunctionsLeaksz&Test leaks of psutil module functions.c             C   sH   t d
}x:tjD ]0}|j sq||kr(q| jt| d| |d	 qW d S )Nversion_info__version__process_iter
wait_procsrd   cpu_times_percent	cpu_countrs   )rQ   )r   r   r   r   rd   r   r   )rt   rv   __all__islowerry   rz   )r:   r{   r|   r!   r!   r"   r}     s     z&TestModuleFunctionsLeaks.test_coveragec             C   s   | j tjdd d S )NT)logical)rR   rv   r   )r:   r!   r!   r"   test_cpu_count_logical  s    z/TestModuleFunctionsLeaks.test_cpu_count_logicalc             C   s   | j tjdd d S )NF)r   )rR   rv   r   )r:   r!   r!   r"   test_cpu_count_physical  s    z0TestModuleFunctionsLeaks.test_cpu_count_physicalc             C   s   | j tj d S )N)rR   rv   r   )r:   r!   r!   r"   r     s    z'TestModuleFunctionsLeaks.test_cpu_timesc             C   s   | j tjdd d S )NT)Zpercpu)rR   rv   r   )r:   r!   r!   r"   test_per_cpu_times  s    z+TestModuleFunctionsLeaks.test_per_cpu_timesc             C   s   | j tj d S )N)rR   rv   Z	cpu_stats)r:   r!   r!   r"   test_cpu_stats  s    z'TestModuleFunctionsLeaks.test_cpu_statsznot supportedc             C   s   | j tj d S )N)rR   rv   Zcpu_freq)r:   r!   r!   r"   test_cpu_freq  s    z&TestModuleFunctionsLeaks.test_cpu_freqc             C   s   | j tj d S )N)rR   rv   Zvirtual_memory)r:   r!   r!   r"   test_virtual_memory  s    z,TestModuleFunctionsLeaks.test_virtual_memoryz&worthless on SUNOS (uses a subprocess)c             C   s   | j tj d S )N)rR   rv   Zswap_memory)r:   r!   r!   r"   test_swap_memory  s    z)TestModuleFunctionsLeaks.test_swap_memoryz worthless on POSIX (pure python)c             C   s   | j tjtj  d S )N)rR   rv   Z
pid_existsr   r   )r:   r!   r!   r"   test_pid_exists  s    z(TestModuleFunctionsLeaks.test_pid_existsc             C   s   | j tjd d S )N.)rR   rv   Z
disk_usage)r:   r!   r!   r"   test_disk_usage  s    z(TestModuleFunctionsLeaks.test_disk_usagec             C   s   | j tj d S )N)rR   rv   Zdisk_partitions)r:   r!   r!   r"   test_disk_partitions  s    z-TestModuleFunctionsLeaks.test_disk_partitionsz/proc/diskstatsz3/proc/diskstats not available on this Linux versionc             C   s   | j tjdd d S )NF)nowrap)rR   rv   Zdisk_io_counters)r:   r!   r!   r"   test_disk_io_counters   s    z.TestModuleFunctionsLeaks.test_disk_io_countersc             C   s   | j tj d S )N)rR   rv   Zpids)r:   r!   r!   r"   	test_pids  s    z"TestModuleFunctionsLeaks.test_pidsc             C   s   | j tjdd d S )NF)r   )rR   rv   Znet_io_counters)r:   r!   r!   r"   test_net_io_counters  s    z-TestModuleFunctionsLeaks.test_net_io_countersz worthless on Linux (pure python)r   zneed root accessc          	   C   s"   t   | jtj W d Q R X d S )N)r
   rR   rv   Znet_connections)r:   r!   r!   r"   test_net_connections  s    z-TestModuleFunctionsLeaks.test_net_connectionsc             C   s   | j tjtrdnd d d S )NP   i   )rC   i @ )rR   rv   Znet_if_addrsr   )r:   r!   r!   r"   test_net_if_addrs  s    z*TestModuleFunctionsLeaks.test_net_if_addrszEPERM on travisc             C   s   | j tj d S )N)rR   rv   Znet_if_stats)r:   r!   r!   r"   test_net_if_stats  s    z*TestModuleFunctionsLeaks.test_net_if_statsc             C   s   | j tj d S )N)rR   rv   Zsensors_battery)r:   r!   r!   r"   test_sensors_battery$  s    z-TestModuleFunctionsLeaks.test_sensors_batteryc             C   s   | j tj d S )N)rR   rv   Zsensors_temperatures)r:   r!   r!   r"   test_sensors_temperatures)  s    z2TestModuleFunctionsLeaks.test_sensors_temperaturesc             C   s   | j tj d S )N)rR   rv   Zsensors_fans)r:   r!   r!   r"   test_sensors_fans.  s    z*TestModuleFunctionsLeaks.test_sensors_fansc             C   s   | j tj d S )N)rR   rv   Z	boot_time)r:   r!   r!   r"   test_boot_time5  s    z'TestModuleFunctionsLeaks.test_boot_timez(XXX produces a false positive on Windowsc             C   s   | j tj d S )N)rR   rv   Zusers)r:   r!   r!   r"   
test_users:  s    z#TestModuleFunctionsLeaks.test_usersc             C   s   | j tj d S )N)rR   r   Zwinservice_enumerate)r:   r!   r!   r"   test_win_service_iterB  s    z.TestModuleFunctionsLeaks.test_win_service_iterc             C   s   d S )Nr!   )r:   r!   r!   r"   test_win_service_getE  s    z-TestModuleFunctionsLeaks.test_win_service_getc             C   s"   t tj j }| jtj| d S )N)nextrv   win_service_iterr|   rR   r   Zwinservice_query_config)r:   r|   r!   r!   r"   test_win_service_get_configH  s    z4TestModuleFunctionsLeaks.test_win_service_get_configc             C   s"   t tj j }| jtj| d S )N)r   rv   r   r|   rR   r   Zwinservice_query_status)r:   r|   r!   r!   r"   test_win_service_get_statusL  s    z4TestModuleFunctionsLeaks.test_win_service_get_statusc             C   s"   t tj j }| jtj| d S )N)r   rv   r   r|   rR   r   Zwinservice_query_descr)r:   r|   r!   r!   r"    test_win_service_get_descriptionP  s    z9TestModuleFunctionsLeaks.test_win_service_get_descriptionN)2rX   rY   rZ   r[   r}   r#   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r   r   r   r   r   pathexistsr   r   r   r   getuidr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r!   r!   r!   r"   r     sR   

$r   __main__):r[   Z
__future__r   r   r   r8   r   rO   rI   rM   rv   Zpsutil._commonr   r   r   r   r   r   Zpsutil._compatr	   Zpsutil.testsr
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r]   r\   r^   r    Z_psplatformr   rw   rJ   r#   r6   ZTestCaser7   r`   r   r   rX   __file__r!   r!   r!   r"   <module>   sl   c B< 
