o
    Šbcsk  ã                   @   s  d Z d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mZmZ ddlmZ ddlmZmZ dd	lmZ d!dd„ZG dd„ deƒZdd„ Zdd„ Zdd„ Zdd„ Zdd„ ZG dd„ deƒZG dd„ deƒZ G dd„ deƒZ!G dd „ d e ƒZ"dS )"zÛRefactoring framework.

Used as a main program, this can refactor any number of files and/or
recursively descend down directories.  Imported as a module, this
provides infrastructure to write your own refactoring tool.
z#Guido van Rossum <guido@python.org>é    N)Úchainé   )ÚdriverÚtokenizeÚtoken)Ú	find_root)ÚpytreeÚpygram)Úbtm_matcherTc                 C   sT   t | g g dgƒ}g }t |j¡D ]\}}}| d¡r'|r"|dd… }| |¡ q|S )zEReturn a sorted list of all available fix names in the given package.Ú*Úfix_é   N)Ú
__import__ÚpkgutilÚiter_modulesÚ__path__Ú
startswithÚappend)Ú	fixer_pkgÚremove_prefixÚpkgÚ	fix_namesÚfinderÚnameÚispkg© r   ú'/usr/lib/python3.10/lib2to3/refactor.pyÚget_all_fix_names   s   

€r   c                   @   ó   e Zd ZdS )Ú
_EveryNodeN©Ú__name__Ú
__module__Ú__qualname__r   r   r   r   r   +   ó    r   c                 C   sŽ   t | tjtjfƒr| jdu rt‚| jhS t | tjƒr$| jr"t| jƒS t‚t | tj	ƒrAt
ƒ }| jD ]}|D ]	}| t|ƒ¡ q4q0|S td|  ƒ‚)zf Accepts a pytree Pattern Node and returns a set
        of the pattern types which will match first. Nz$Oh no! I don't understand pattern %s)Ú
isinstancer   ÚNodePatternÚLeafPatternÚtyper   ÚNegatedPatternÚcontentÚ_get_head_typesÚWildcardPatternÚsetÚupdateÚ	Exception)ÚpatÚrÚpÚxr   r   r   r+   /   s    


ÿr+   c              	   C   s¼   t  t¡}g }| D ];}|jr1zt|jƒ}W n ty#   | |¡ Y q	w |D ]	}||  |¡ q&q	|jdur?||j  |¡ q	| |¡ q	tt	j
j ¡ t	j
jƒD ]	}||  |¡ qPt|ƒS )z^ Accepts a list of fixers and returns a dictionary
        of head node type --> fixer list.  N)ÚcollectionsÚdefaultdictÚlistÚpatternr+   r   r   Ú_accept_typer   r	   Úpython_grammarÚsymbol2numberÚvaluesÚtokensÚextendÚdict)Ú
fixer_listÚ
head_nodesÚeveryÚfixerÚheadsÚ	node_typer   r   r   Ú_get_headnode_dictK   s(   
ÿÿ
ÿrE   c                    s   ‡ fdd„t ˆ dƒD ƒS )zN
    Return the fully qualified names for fixers in the package pkg_name.
    c                    s   g | ]}ˆ d  | ‘qS ©Ú.r   )Ú.0Úfix_name©Úpkg_namer   r   Ú
<listcomp>h   s    ÿz+get_fixers_from_package.<locals>.<listcomp>F)r   rJ   r   rJ   r   Úget_fixers_from_packaged   s   
ÿrM   c                 C   s   | S ©Nr   )Úobjr   r   r   Ú	_identityk   s   rP   c                    sj  d}t  t | ¡j¡‰ ‡ fdd„}ttjt jtj	hƒ}t
ƒ }zŠ	 |ƒ \}}||v r*q|tjkr5|r2ncd}n_|tjkr“|dkr“|ƒ \}}|tjksL|dkrMnR|ƒ \}}|tjks[|dkr\nH|ƒ \}}|tjkro|dkro|ƒ \}}|tjkr’| |¡ |ƒ \}}|tjks‡|d	krˆn
|ƒ \}}|tjkstnnq W t|ƒS W t|ƒS W t|ƒS W t|ƒS  ty´   Y t|ƒS w )
NFc                     s   t ˆ ƒ} | d | d fS )Nr   r   )Únext)Útok©Úgenr   r   Úadvancer   s   z(_detect_future_features.<locals>.advanceTÚfromÚ
__future__Úimportú(ú,)r   Úgenerate_tokensÚioÚStringIOÚreadlineÚ	frozensetr   ÚNEWLINEÚNLÚCOMMENTr-   ÚSTRINGÚNAMEÚOPÚaddÚStopIteration)ÚsourceÚhave_docstringrU   ÚignoreÚfeaturesÚtpÚvaluer   rS   r   Ú_detect_future_featureso   s\   










û€çýïòþþrn   c                   @   s   e Zd ZdZdS )Ú
FixerErrorzA fixer could not be loaded.N)r!   r"   r#   Ú__doc__r   r   r   r   ro   —   s    ro   c                   @   sê   e Zd ZddddœZdZdZd4dd„Zdd	„ Zd
d„ Zdd„ Z	dd„ Z
dd„ Zd5dd„Zd5dd„Zdd„ Zd5dd„Zdd„ Zd6dd„Zdd„ Zd d!„ Z		d7d"d#„Zd8d$d%„Zd&Zd'Zd(d)„ Zd*d+„ Zd,d-„ Zd.d/„ Zd0d1„ Zd2d3„ ZdS )9ÚRefactoringToolF)Úprint_functionÚexec_functionÚwrite_unchanged_filesÚFixr   Nc                 C   sH  || _ |pg | _| j ¡ | _|dur| j |¡ tj ¡ | _| jd r)| jj	d= n
| jd r3| jj	d= | j 
d¡| _g | _t d¡| _g | _d| _tj| jtj| jd	| _|  ¡ \| _| _g | _t ¡ | _g | _g | _t| j| jƒD ]#}|j r~| j !|¡ qr|| jv rŠ| j "|¡ qr|| jv r•| j "|¡ qrt#| jƒ| _$t#| jƒ| _%dS )
zÑInitializer.

        Args:
            fixer_names: a list of fixers to import
            options: a dict with configuration.
            explicit: a list of fixers to run even if they are explicit.
        Nrr   Úprintrs   Úexecrt   rq   F)ÚconvertÚlogger)&ÚfixersÚexplicitÚ_default_optionsÚcopyÚoptionsr.   r	   r9   ÚgrammarÚkeywordsÚgetrt   ÚerrorsÚloggingÚ	getLoggerry   Ú	fixer_logÚwroter   ÚDriverr   rx   Ú
get_fixersÚ	pre_orderÚ
post_orderÚfilesÚbmÚBottomMatcherÚBMÚbmi_pre_orderÚbmi_post_orderr   ÚBM_compatibleÚ	add_fixerr   rE   Úbmi_pre_order_headsÚbmi_post_order_heads)ÚselfÚfixer_namesr~   r{   rB   r   r   r   Ú__init__¤   sD   



þ


€zRefactoringTool.__init__c              	   C   sJ  g }g }| j D ]ˆ}t|i i dgƒ}| dd¡d }| | j¡r(|t| jƒd… }| d¡}| jd dd	„ |D ƒ¡ }zt	||ƒ}W n t
yQ   td
||f ƒd‚w || j| jƒ}	|	jrm| jdurm|| jvrm|  d|¡ q|  d|¡ |	jdkr~| |	¡ q|	jdkr‰| |	¡ qtd|	j ƒ‚t d¡}
|j|
d |j|
d ||fS )a  Inspects the options to load the requested patterns and handlers.

        Returns:
          (pre_order, post_order), where pre_order is the list of fixers that
          want a pre-order AST traversal, and post_order is the list that want
          post-order traversal.
        r   rG   r   éÿÿÿÿNÚ_Ú c                 S   s   g | ]}|  ¡ ‘qS r   )Útitle)rH   r2   r   r   r   rL   ë   s    z.RefactoringTool.get_fixers.<locals>.<listcomp>zCan't find %s.%sTzSkipping optional fixer: %szAdding transformation: %sÚpreÚpostzIllegal fixer order: %rÚ	run_order©Úkey)rz   r   Úrsplitr   ÚFILE_PREFIXÚlenÚsplitÚCLASS_PREFIXÚjoinÚgetattrÚAttributeErrorro   r~   r…   r{   Úlog_messageÚ	log_debugÚorderr   ÚoperatorÚ
attrgetterÚsort)r•   Úpre_order_fixersÚpost_order_fixersÚfix_mod_pathÚmodrI   ÚpartsÚ
class_nameÚ	fix_classrB   Úkey_funcr   r   r   rˆ   Û   s:   

ÿ



zRefactoringTool.get_fixersc                  O   s   ‚ )zCalled when an error occurs.r   )r•   ÚmsgÚargsÚkwdsr   r   r   Ú	log_error  s   zRefactoringTool.log_errorc                 G   s   |r|| }| j  |¡ dS )zHook to log a message.N)ry   Úinfo©r•   r·   r¸   r   r   r   r©     s   zRefactoringTool.log_messagec                 G   s   |r|| }| j  |¡ d S rN   )ry   Údebugr¼   r   r   r   rª     s   zRefactoringTool.log_debugc                 C   s   dS )zTCalled with the old version, new version, and filename of a
        refactored file.Nr   )r•   Úold_textÚnew_textÚfilenameÚequalr   r   r   Úprint_output  s   zRefactoringTool.print_outputc                 C   s8   |D ]}t j |¡r|  |||¡ q|  |||¡ qdS )z)Refactor a list of files and directories.N)ÚosÚpathÚisdirÚrefactor_dirÚrefactor_file)r•   ÚitemsÚwriteÚdoctests_onlyÚdir_or_filer   r   r   Úrefactor  s
   üzRefactoringTool.refactorc           
      C   sš   t jd }t  |¡D ]@\}}}|  d|¡ | ¡  | ¡  |D ]}| d¡s>t j |¡d |kr>t j ||¡}	|  	|	||¡ qdd„ |D ƒ|dd…< q
dS )zÄDescends down a directory and refactor every Python file found.

        Python files are assumed to have a .py extension.

        Files and subdirectories starting with '.' are skipped.
        ÚpyzDescending into %srG   r   c                 S   s   g | ]	}|  d ¡s|‘qS rF   )r   )rH   Údnr   r   r   rL   2  ó    z0RefactoringTool.refactor_dir.<locals>.<listcomp>N)
rÃ   ÚextsepÚwalkrª   r®   r   rÄ   Úsplitextr¦   rÇ   )
r•   Údir_namerÉ   rÊ   Úpy_extÚdirpathÚdirnamesÚ	filenamesr   Úfullnamer   r   r   rÆ      s   

€özRefactoringTool.refactor_dirc              
   C   s®   zt |dƒ}W n ty! } z|  d||¡ W Y d}~dS d}~ww zt |j¡d }W | ¡  n| ¡  w tj |d|dd}| ¡ |fW  d  ƒ S 1 sPw   Y  dS )	zG
        Do our best to decode a Python source file correctly.
        ÚrbzCan't open %s: %sN©NNr   r1   rš   ©ÚencodingÚnewline)	ÚopenÚOSErrorrº   r   Údetect_encodingr^   Úcloser\   Úread)r•   rÀ   ÚfÚerrrÜ   r   r   r   Ú_read_python_source4  s   €þ
$ÿz#RefactoringTool._read_python_sourcec                 C   sÀ   |   |¡\}}|du rdS |d7 }|r9|  d|¡ |  ||¡}| js&||kr1|  |||||¡ dS |  d|¡ dS |  ||¡}| jsG|rX|jrX| jt|ƒdd… |||d dS |  d|¡ dS )zRefactors a file.NÚ
zRefactoring doctests in %szNo doctest changes in %sr˜   )rÉ   rÜ   zNo changes in %s)rå   rª   Úrefactor_docstringrt   Úprocessed_fileÚrefactor_stringÚwas_changedÚstr)r•   rÀ   rÉ   rÊ   ÚinputrÜ   ÚoutputÚtreer   r   r   rÇ   D  s    
ÿzRefactoringTool.refactor_filec              
   C   s°   t |ƒ}d|v rtj| j_z3z| j |¡}W n# ty9 } z|  d||jj	|¡ W Y d}~W | j| j_dS d}~ww W | j| j_n| j| j_w ||_
|  d|¡ |  ||¡ |S )aF  Refactor a given input string.

        Args:
            data: a string holding the code to be refactored.
            name: a human-readable name for use in error/log messages.

        Returns:
            An AST corresponding to the refactored input stream; None if
            there were errors during the parse.
        rr   zCan't parse %s: %s: %sNzRefactoring %s)rn   r	   Ú!python_grammar_no_print_statementr   r   Úparse_stringr/   rº   Ú	__class__r!   Úfuture_featuresrª   Úrefactor_tree)r•   Údatar   rk   rî   rä   r   r   r   ré   [  s&   

ÿ€ûÿzRefactoringTool.refactor_stringc                 C   s’   t j ¡ }|r)|  d¡ |  |d¡}| js||kr"|  |d|¡ d S |  d¡ d S |  |d¡}| js7|rB|jrB|  t	|ƒd|¡ d S |  d¡ d S )NzRefactoring doctests in stdinz<stdin>zNo doctest changes in stdinzNo changes in stdin)
ÚsysÚstdinrâ   rª   rç   rt   rè   ré   rê   rë   )r•   rÊ   rì   rí   rî   r   r   r   Úrefactor_stdinv  s   

zRefactoringTool.refactor_stdinc           
   
   C   sÌ  t | j| jƒD ]}| ||¡ q|  | j| ¡ ¡ |  | j| ¡ ¡ | j | 	¡ ¡}t
| ¡ ƒrÓ| jjD ]˜}||v rÌ|| rÌ|| jtjjdd |jrV|| jtjjd t|| ƒD ]o}||| v rk||  |¡ zt|ƒ W n	 tyz   Y q\w |jr„||jv r„q\| |¡}|rË| ||¡}|durË| |¡ | ¡ D ]}|js¦g |_|j |¡ qž| j | 	¡ ¡}|D ]}	|	|vrÁg ||	< ||	  ||	 ¡ q·q\q4t
| ¡ ƒs0t | j| jƒD ]}| ||¡ qÚ|jS )aÏ  Refactors a parse tree (modifying the tree in place).

        For compatible patterns the bottom matcher module is
        used. Otherwise the tree is traversed node-to-node for
        matches.

        Args:
            tree: a pytree.Node instance representing the root of the tree
                  to be refactored.
            name: a human-readable name for this tree.

        Returns:
            True if the tree was modified, False otherwise.
        T)r    ÚreverserŸ   N)r   r‰   rŠ   Ú
start_treeÚtraverse_byr“   r”   rŽ   ÚrunÚleavesÚanyr;   rz   r®   r   ÚBaseÚdepthÚkeep_line_orderÚ
get_linenor6   Úremover   Ú
ValueErrorÚfixers_appliedÚmatchÚ	transformÚreplacer   r=   Úfinish_treerê   )
r•   rî   r   rB   Ú	match_setÚnodeÚresultsÚnewÚnew_matchesÚfxrr   r   r   ró   †  sP   ý

€Ñ1zRefactoringTool.refactor_treec                 C   sV   |sdS |D ]"}||j  D ]}| |¡}|r'| ||¡}|dur'| |¡ |}qqdS )a  Traverse an AST, applying a set of fixers to each node.

        This is a helper method for refactor_tree().

        Args:
            fixers: a list of fixer instances.
            traversal: a generator that yields AST nodes.

        Returns:
            None
        N)r(   r  r  r  )r•   rz   Ú	traversalr
  rB   r  r  r   r   r   rú   Õ  s   

€úÿzRefactoringTool.traverse_byc                 C   sˆ   | j  |¡ |du r|  |¡d }|du rdS ||k}|  ||||¡ |r0|  d|¡ | js0dS |r<|  ||||¡ dS |  d|¡ dS )zR
        Called when a file has been refactored and there may be changes.
        Nr   zNo changes to %szNot writing changes to %s)r‹   r   rå   rÂ   rª   rt   Ú
write_file)r•   r¿   rÀ   r¾   rÉ   rÜ   rÁ   r   r   r   rè   ì  s   zRefactoringTool.processed_filec                 C   sÈ   zt j|d|dd}W n ty% } z|  d||¡ W Y d}~dS d}~ww |) z| |¡ W n tyI } z|  d||¡ W Y d}~nd}~ww W d  ƒ n1 sTw   Y  |  d|¡ d| _dS )	zÑWrites a string to a file.

        It first shows a unified diff between the old text and the new text, and
        then rewrites the file; the latter is only done if the write option is
        set.
        Úwrš   rÛ   zCan't create %s: %sNzCan't write %s: %szWrote changes to %sT)r\   rÞ   rß   rº   rÉ   rª   r†   )r•   r¿   rÀ   r¾   rÜ   Úfprä   r   r   r   r    s$   €þ€ÿ€ý
zRefactoringTool.write_filez>>> z... c           
   	   C   s  g }d}d}d}d}|j ddD ]d}|d7 }| ¡  | j¡r?|dur-| |  ||||¡¡ |}|g}| | j¡}	|d|	… }q|dur\| || j ¡sV||| j ¡  d kr\| 	|¡ q|durk| |  ||||¡¡ d}d}| 	|¡ q|dur„| |  ||||¡¡ d 
|¡S )aË  Refactors a docstring, looking for doctests.

        This returns a modified version of the input string.  It looks
        for doctests, which start with a ">>>" prompt, and may be
        continued with "..." prompts, as long as the "..." is indented
        the same as the ">>>".

        (Unfortunately we can't use the doctest module's parser,
        since, like most parsers, it is not geared towards preserving
        the original source.)
        Nr   T©Úkeependsr   ræ   rš   )Ú
splitlinesÚlstripr   ÚPS1r=   Úrefactor_doctestÚfindÚPS2Úrstripr   r¦   )
r•   rì   rÀ   ÚresultÚblockÚblock_linenoÚindentÚlinenoÚlineÚir   r   r   rç     sB   ÿÿÿÿ
z"RefactoringTool.refactor_docstringc           
   
      s(  z	ˆ  ||ˆ ¡}W n4 ty= } z(ˆj tj¡r&|D ]}ˆ d| d¡¡ qˆ d|||j	j
|¡ |W  Y d}~S d}~ww ˆ ||¡r’t|ƒjdd}|d|d … ||d d… }	}|	dg|d  ksjJ |	ƒ‚|d  d¡sy|d  d7  < ˆ ˆj | d	¡ g}|r’|‡ ‡fd
d„|D ƒ7 }|S )zÞRefactors one doctest.

        A doctest is given as a block of lines, the first of which starts
        with ">>>" (possibly indented), while the remaining lines start
        with "..." (identically indented).

        z
Source: %sræ   z+Can't parse docstring in %s line %s: %s: %sNTr  r   r˜   r   c                    s   g | ]	}ˆ ˆj  | ‘qS r   )r  )rH   r!  ©r  r•   r   r   rL   ^  rÏ   z4RefactoringTool.refactor_doctest.<locals>.<listcomp>)Úparse_blockr/   ry   ÚisEnabledForrƒ   ÚDEBUGrª   r  rº   rñ   r!   ró   rë   r  Úendswithr  Úpop)
r•   r  r   r  rÀ   rî   rä   r!  r  Úclippedr   r#  r   r  D  s,   ÿ€ú"z RefactoringTool.refactor_doctestc                 C   sÐ   | j rd}nd}| js|  d|¡ n|  d|¡ | jD ]}|  |¡ q| jr6|  d¡ | jD ]}|  |¡ q.| jrdt| jƒdkrF|  d¡ n	|  dt| jƒ¡ | jD ]\}}}| j|g|¢R i |¤Ž qRd S d S )	NÚwerez
need to bezNo files %s modified.zFiles that %s modified:z$Warnings/messages while refactoring:r   zThere was 1 error:zThere were %d errors:)r†   r‹   r©   r…   r‚   r£   )r•   r*  ÚfileÚmessager·   r¸   r¹   r   r   r   Ú	summarizea  s(   


úzRefactoringTool.summarizec                 C   s"   | j  |  |||¡¡}tƒ |_|S )z³Parses a block into a tree.

        This is necessary to get correct line number / offset information
        in the parser diagnostics and embedded into the parse tree.
        )r   Úparse_tokensÚ	wrap_toksr_   rò   )r•   r  r   r  rî   r   r   r   r$  x  s   zRefactoringTool.parse_blockc                 c   sf    t  |  ||¡j¡}|D ]#\}}\}}\}	}
}||d 7 }|	|d 7 }	||||f|	|
f|fV  qdS )z;Wraps a tokenize stream to systematically modify start/end.r   N)r   r[   Ú	gen_linesÚ__next__)r•   r  r   r  r<   r(   rm   Úline0Úcol0Úline1Úcol1Ú	line_textr   r   r   r/  ‚  s   €øzRefactoringTool.wrap_toksc                 c   sx    || j  }|| j }|}|D ]'}| |¡r |t|ƒd… V  n|| ¡ d kr,dV  ntd||f ƒ‚|}q	 dV  q8)z–Generates lines as expected by tokenize from a list of lines.

        This strips the first len(indent + self.PS1) characters off each line.
        Nræ   zline=%r, prefix=%rTrš   )r  r  r   r£   r  ÚAssertionError)r•   r  r  Úprefix1Úprefix2Úprefixr!  r   r   r   r0    s   €


ÿzRefactoringTool.gen_linesrÚ   )FF)F)NFNrN   )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/  r0  r   r   r   r   rq   ›   sB    þ
7(

	

O
ÿ
+
rq   c                   @   r   )ÚMultiprocessingUnsupportedNr    r   r   r   r   r;  ¤  r$   r;  c                       sF   e Zd Z‡ fdd„Z		d‡ fdd„	Z‡ fdd„Z‡ fd	d
„Z‡  ZS )ÚMultiprocessRefactoringToolc                    s&   t t| ƒj|i |¤Ž d | _d | _d S rN   )Úsuperr<  r—   ÚqueueÚoutput_lock©r•   r¸   Úkwargs©rñ   r   r   r—   ª  s   
z$MultiprocessRefactoringTool.__init__Fr   c              
      s2  |dkrt tˆƒ |||¡S zdd l‰ W n	 ty   t‚w ˆjd ur'tdƒ‚ˆ  ¡ ˆ_ˆ  	¡ ˆ_
‡ ‡fdd„t|ƒD ƒ}z8|D ]}| ¡  q@t tˆƒ |||¡ W ˆj ¡  t|ƒD ]}ˆj d ¡ q[|D ]
}| ¡ rp| ¡  qfd ˆ_d S ˆj ¡  t|ƒD ]}ˆj d ¡ q|D ]
}| ¡ r”| ¡  qŠd ˆ_w )Nr   r   z already doing multiple processesc                    s   g | ]	}ˆ j ˆjd ‘qS ))Útarget)ÚProcessÚ_child)rH   r"  ©Úmultiprocessingr•   r   r   rL   ¼  s    ÿz8MultiprocessRefactoringTool.refactor.<locals>.<listcomp>)r=  r<  rÌ   rG  ÚImportErrorr;  r>  ÚRuntimeErrorÚJoinableQueueÚLockr?  ÚrangeÚstartr¦   ÚputÚis_alive)r•   rÈ   rÉ   rÊ   Únum_processesÚ	processesr2   r"  rB  rF  r   rÌ   ¯  sL   
ÿÿ


ÿ
ÿ
€

ú€z$MultiprocessRefactoringTool.refactorc                    sf   | j  ¡ }|d ur1|\}}ztt| ƒj|i |¤Ž W | j  ¡  n| j  ¡  w | j  ¡ }|d us	d S d S rN   )r>  r   r=  r<  rÇ   Ú	task_done)r•   Útaskr¸   rA  rB  r   r   rE  Ì  s   

ÿÿ
ùz"MultiprocessRefactoringTool._childc                    s4   | j d ur| j  ||f¡ d S tt| ƒj|i |¤ŽS rN   )r>  rN  r=  r<  rÇ   r@  rB  r   r   rÇ   ×  s   

ÿÿz)MultiprocessRefactoringTool.refactor_file)FFr   )r!   r"   r#   r—   rÌ   rE  rÇ   Ú__classcell__r   r   rB  r   r<  ¨  s    ÿr<  )T)#rp   Ú
__author__r\   rÃ   r   rõ   rƒ   r¬   r4   Ú	itertoolsr   Úpgen2r   r   r   Ú
fixer_utilr   rš   r   r	   r
   rŒ   r   r/   r   r+   rE   rM   rP   rn   ro   Úobjectrq   r;  r<  r   r   r   r   Ú<module>   s:   
(    