U
    f»{jÅd  ã                   @   sÎ   d dl ZddlmZ ddlmZmZ ddlmZ ddl	m
Z
 ddlmZmZmZmZ eG d	d
„ d
eeƒƒZedd„ ƒZdd„ Zdd„ Zdd„ Zdd„ ZeG dd„ deƒƒZdd„ Zdd„ Zdd„ Zdd„ ZdS )é    Né   )ÚTransformerMixin)ÚBaseEstimatorÚ_check_estimatoré   )Ú_get_check_scoring)Úparallel_func)Úarray_split_idxÚProgressBarÚverboseÚfill_docc                       sŠ   e Zd ZdZedddœdd„ƒZ‡ fdd„Zdd	„ Zd
d„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zddd„Zdd„ Zedd„ ƒZ‡  ZS )ÚSlidingEstimatora®  Search Light.

    Fit, predict and score a series of models to each subset of the dataset
    along the last dimension. Each entry in the last dimension is referred
    to as a task.

    Parameters
    ----------
    %(base_estimator)s
    %(scoring)s
    %(n_jobs)s
    %(verbose)s

    Attributes
    ----------
    estimators_ : array-like, shape (n_tasks,)
        List of fitted scikit-learn estimators (one per task).
    N)r   c                C   s,   t |ƒ t|dd ƒ| _|| _|| _|| _d S )NÚ_estimator_type)r   Úgetattrr   Úbase_estimatorÚn_jobsÚscoring)Úselfr   r   r   r   © r   úX/var/www/html/bwave/python/venv/lib/python3.8/site-packages/mne/decoding/search_light.pyÚ__init__$   s
    zSlidingEstimator.__init__c                    sB   dt t| ƒ ¡  }t| dƒr:|d d… }|dt| jƒ 7 }|d S )Nú<Úestimators_éÿÿÿÿz, fitted with %i estimatorsú>)Úsuperr   Ú__repr__ÚhasattrÚlenr   ©r   Úrepr_str©Ú	__class__r   r   r   -   s
    
zSlidingEstimator.__repr__c              	      sÐ   ˆ  |ˆ¡ ttˆj|jd dd�\}‰}tƒ ˆ_ˆ ˆ_dˆjj	f }t
|jd |d��.‰|‡ ‡‡‡‡fdd„t||dd�D ƒƒ}W 5 Q R X tj|jd td	�ˆ_d
}|D ] }	|	D ]}
|
ˆj|< |d7 }q²qªˆS )a½  Fit a series of independent estimators to the dataset.

        Parameters
        ----------
        X : array, shape (n_samples, nd_features, n_tasks)
            The training input samples. For each data slice, a clone estimator
            is fitted independently. The feature dimension can be
            multidimensional e.g.
            X.shape = (n_samples, n_features_1, n_features_2, n_tasks).
        y : array, shape (n_samples,) | (n_samples, n_targets)
            The target values.
        **fit_params : dict of string -> object
            Parameters to pass to the fit method of the estimator.

        Returns
        -------
        self : object
            Return self.
        r   F©Úmax_jobsr   z
Fitting %s©Úmesgc                 3   s,   | ]$\}}ˆˆj |ˆˆ |¡fˆ ŽV  qd S ©N)r   Úsubset)Ú.0Úpb_idxÚsplit©Ú
fit_paramsÚp_funcÚpbr   Úyr   r   Ú	<genexpr>P   s   þÿz'SlidingEstimator.fit.<locals>.<genexpr>©Úaxis)Údtyper   r   )Ú	_check_Xyr   Ú_sl_fitr   ÚshapeÚlistr   r-   r"   Ú__name__r
   r	   ÚnpÚemptyÚobject)r   ÚXr0   r-   Úparallelr   r&   Ú
estimatorsÚidxZjob_estimatorsÚestr   r,   r   Úfit4   s*       ÿý
zSlidingEstimator.fitc                 K   s   | j ||f|Ž |¡S )a,  Fit and transform a series of independent estimators to the dataset.

        Parameters
        ----------
        X : array, shape (n_samples, nd_features, n_tasks)
            The training input samples. For each task, a clone estimator
            is fitted independently. The feature dimension can be
            multidimensional, e.g.::

                X.shape = (n_samples, n_features_1, n_features_2, n_estimators)
        y : array, shape (n_samples,) | (n_samples, n_targets)
            The target values.
        **fit_params : dict of string -> object
            Parameters to pass to the fit method of the estimator.

        Returns
        -------
        y_pred : array, shape (n_samples, n_tasks) | (n_samples, n_tasks, n_targets)
            The predicted values for each estimator.
        )rB   Ú	transform)r   r=   r0   r-   r   r   r   Úfit_transform`   s    zSlidingEstimator.fit_transformc           
   	      sÔ   |   |¡ t| jˆ ƒ‰ |jd t| jƒkr2tdƒ‚tt| j	|jd dd�\}‰}d| j
jf }tj||dd�}tt| j|ƒŽ \}}t|jd |d��(‰|‡ ‡‡fdd	„t|||ƒD ƒƒ}	W 5 Q R X tj|	d
d�}	|	S )ú:Aux. function to make parallel predictions/transformation.r   ú3The number of estimators does not match X.shape[-1]Fr#   úTransforming %sr2   r%   c                 3   s(   | ] \}}}ˆ||ˆ ˆ  |¡ƒV  qd S r'   )r(   )r)   r*   rA   Úx©Úmethodr.   r/   r   r   r1   †   s   ÿz.SlidingEstimator._transform.<locals>.<genexpr>r   )r5   Ú_check_methodr   r7   r   r   Ú
ValueErrorr   Ú_sl_transformr   r"   r9   r:   Úarray_splitÚzipr	   r
   Úconcatenate)
r   r=   rJ   r>   r   r&   ÚX_splitsr@   Ú
est_splitsÚy_predr   rI   r   Ú
_transformw   s.    
   ÿ  ÿÿzSlidingEstimator._transformc                 C   s   |   |d¡S )a  Transform each data slice/task with a series of independent estimators.

        The number of tasks in X should match the number of tasks/estimators
        given at fit time.

        Parameters
        ----------
        X : array, shape (n_samples, nd_features, n_tasks)
            The input samples. For each data slice/task, the corresponding
            estimator makes a transformation of the data, e.g.
            ``[estimators[ii].transform(X[..., ii]) for ii in range(n_estimators)]``.
            The feature dimension can be multidimensional e.g.
            X.shape = (n_samples, n_features_1, n_features_2, n_tasks).

        Returns
        -------
        Xt : array, shape (n_samples, n_estimators)
            The transformed values generated by each estimator.
        rC   ©rT   ©r   r=   r   r   r   rC   �   s    zSlidingEstimator.transformc                 C   s   |   |d¡S )a+  Predict each data slice/task with a series of independent estimators.

        The number of tasks in X should match the number of tasks/estimators
        given at fit time.

        Parameters
        ----------
        X : array, shape (n_samples, nd_features, n_tasks)
            The input samples. For each data slice, the corresponding estimator
            makes the sample predictions, e.g.:
            ``[estimators[ii].predict(X[..., ii]) for ii in range(n_estimators)]``.
            The feature dimension can be multidimensional e.g.
            X.shape = (n_samples, n_features_1, n_features_2, n_tasks).

        Returns
        -------
        y_pred : array, shape (n_samples, n_estimators) | (n_samples, n_tasks, n_targets)
            Predicted values for each estimator/data slice.
        ÚpredictrU   rV   r   r   r   rW   £   s    zSlidingEstimator.predictc                 C   s   |   |d¡S )a*  Predict each data slice with a series of independent estimators.

        The number of tasks in X should match the number of tasks/estimators
        given at fit time.

        Parameters
        ----------
        X : array, shape (n_samples, nd_features, n_tasks)
            The input samples. For each data slice, the corresponding estimator
            makes the sample probabilistic predictions, e.g.:
            ``[estimators[ii].predict_proba(X[..., ii]) for ii in range(n_estimators)]``.
            The feature dimension can be multidimensional e.g.
            X.shape = (n_samples, n_features_1, n_features_2, n_tasks).

        Returns
        -------
        y_pred : array, shape (n_samples, n_tasks, n_classes)
            Predicted probabilities for each estimator/data slice/task.
        Úpredict_probarU   rV   r   r   r   rX   ¹   s    zSlidingEstimator.predict_probac                 C   s   |   |d¡S )a:  Estimate distances of each data slice to the hyperplanes.

        Parameters
        ----------
        X : array, shape (n_samples, nd_features, n_tasks)
            The input samples. For each data slice, the corresponding estimator
            outputs the distance to the hyperplane, e.g.:
            ``[estimators[ii].decision_function(X[..., ii]) for ii in range(n_estimators)]``.
            The feature dimension can be multidimensional e.g.
            X.shape = (n_samples, n_features_1, n_features_2, n_estimators).

        Returns
        -------
        y_pred : array, shape (n_samples, n_estimators, n_classes * (n_classes-1) // 2)
            Predicted distances for each estimator/data slice.

        Notes
        -----
        This requires base_estimator to have a ``decision_function`` method.
        Údecision_functionrU   rV   r   r   r   rY   Ï   s    z"SlidingEstimator.decision_functionc                 C   sB   |dk	r,t |ƒt |ƒks$t |ƒdk r,tdƒ‚|jdk r>tdƒ‚dS )z"Aux. function to check input data.Nr   z"X and y must have the same length.é   z"X must have at least 3 dimensions.)r   rL   Úndim)r   r=   r0   r   r   r   r5   æ   s
    
zSlidingEstimator._check_Xyc           	         s°   t ƒ }|  |¡ |jd t| jƒkr,tdƒ‚|| j| jƒ‰tˆˆƒ‰t	t
| j|jd d�\}‰ }tj||dd�}t | j|¡}|‡ ‡‡fdd„t||ƒD ƒƒ}tj|dd�}|S )ak  Score each estimator on each task.

        The number of tasks in X should match the number of tasks/estimators
        given at fit time, i.e. we need
        ``X.shape[-1] == len(self.estimators_)``.

        Parameters
        ----------
        X : array, shape (n_samples, nd_features, n_tasks)
            The input samples. For each data slice, the corresponding estimator
            scores the prediction, e.g.:
            ``[estimators[ii].score(X[..., ii], y) for ii in range(n_estimators)]``.
            The feature dimension can be multidimensional e.g.
            X.shape = (n_samples, n_features_1, n_features_2, n_tasks).
        y : array, shape (n_samples,) | (n_samples, n_targets)
            The target values.

        Returns
        -------
        score : array, shape (n_samples, n_estimators)
            Score for each estimator/task.
        r   rF   )r$   r2   c                 3   s    | ]\}}ˆ |ˆ|ˆƒV  qd S r'   r   )r)   rA   rH   ©r.   r   r0   r   r   r1     s   ÿz)SlidingEstimator.score.<locals>.<genexpr>r   )r   r5   r7   r   r   rL   r   r   Ú_fix_aucr   Ú	_sl_scorer   r:   rN   rO   rP   )	r   r=   r0   Úcheck_scoringr>   r   rQ   rR   Úscorer   r\   r   r`   î   s$    

  ÿÿzSlidingEstimator.scorec                 C   s0   t | jd dƒs$td| jd f ƒ‚| jd jS )Nr   Úclasses_zUclasses_ attribute available only if base_estimator has it, and estimator %s does not)r   r   ÚAttributeErrorra   )r   r   r   r   ra     s
    
þzSlidingEstimator.classes_)NN)N)r9   Ú
__module__Ú__qualname__Ú__doc__r   r   r   rB   rD   rT   rC   rW   rX   rY   r5   r`   Úpropertyra   Ú__classcell__r   r   r!   r   r      s"   ÿ,
-r   c           	      K   sb   ddl m} tƒ }t|jd ƒD ]<}|| ƒ}|j|d|f |f|Ž | |¡ | |d ¡ q |S )ae  Aux. function to fit SlidingEstimator in parallel.

    Fit a clone estimator to each slice of data.

    Parameters
    ----------
    %(base_estimator)s
    X : array, shape (n_samples, nd_features, n_estimators)
        The target data. The feature dimension can be multidimensional e.g.
        X.shape = (n_samples, n_features_1, n_features_2, n_estimators)
    y : array, shape (n_sample, )
        The target values.
    fit_params : dict | None
        Parameters to pass to the fit method of the estimator.

    Returns
    -------
    estimators_ : list of estimators
        The fitted estimators.
    r   )Úcloner   .r   )Zsklearn.baserh   r8   Úranger7   rB   ÚappendÚupdate)	Ú	estimatorr=   r0   r/   r-   rh   r   ÚiirA   r   r   r   r6   $  s    
r6   c           	      C   sb   t | ƒD ]T\}}t||ƒ}||d|f ƒ}|dkr<t||ƒ}||dd…|df< | |d ¡ q|S )a±  Aux. function to transform SlidingEstimator in parallel.

    Applies transform/predict/decision_function etc for each slice of data.

    Parameters
    ----------
    estimators : list of estimators
        The fitted estimators.
    X : array, shape (n_samples, nd_features, n_estimators)
        The target data. The feature dimension can be multidimensional e.g.
        X.shape = (n_samples, n_features_1, n_features_2, n_estimators)
    method : str
        The estimator method to use (e.g. 'predict', 'transform').

    Returns
    -------
    y_pred : array, shape (n_samples, n_estimators, n_classes * (n_classes-1) // 2)
        The transformations for each slice of data.
    .r   Nr   )Ú	enumerater   Ú_sl_init_predrk   )	r?   r=   rJ   r/   rm   rA   rC   Ú_y_predrS   r   r   r   rM   D  s    

rM   c                 C   s:   |j d |j d  }}t ||f| j dd…  | j¡} | S )z7Aux. function to SlidingEstimator to initialize y_pred.r   r   r   N)r7   r:   Úzerosr4   )rS   r=   Ún_sampleÚn_tasksr   r   r   ro   c  s     ro   c                 C   sB   |j d }t |¡}t| ƒD ] \}}|||d|f |ƒ||< q|S )a4  Aux. function to score SlidingEstimator in parallel.

    Predict and score each slice of data.

    Parameters
    ----------
    estimators : list, shape (n_tasks,)
        The fitted estimators.
    X : array, shape (n_samples, nd_features, n_tasks)
        The target data. The feature dimension can be multidimensional e.g.
        X.shape = (n_samples, n_features_1, n_features_2, n_tasks)
    scoring : callable, str or None
        If scoring is None (default), the predictions are internally
        generated by estimator.score(). Else, we must first get the
        predictions to pass them to ad-hoc scorer.
    y : array, shape (n_samples,) | (n_samples, n_targets)
        The target values.

    Returns
    -------
    score : array, shape (n_tasks,)
        The score for each task / slice of data.
    r   .)r7   r:   rq   rn   )r?   r   r=   r0   rs   r`   rm   rA   r   r   r   r^   j  s
    

r^   c                 C   s0   |dkrt | dƒsd}t | |ƒs,td| ƒ |S )z™Check that an estimator has the method attribute.

    If method == 'transform'  and estimator does not have 'transform', use
    'predict' instead.
    rC   rW   z)base_estimator does not have `%s` method.)r   rL   )rl   rJ   r   r   r   rK   ‰  s
    
rK   c                       sP   e Zd ZdZ‡ fdd„Zdd„ Zdd„ Zdd	„ Zd
d„ Zdd„ Z	dd„ Z
‡  ZS )ÚGeneralizingEstimatorzóGeneralization Light.

    Fit a search-light along the last dimension and use them to apply a
    systematic cross-tasks generalization.

    Parameters
    ----------
    %(base_estimator)s
    %(scoring)s
    %(n_jobs)s
    %(verbose)s
    c                    s:   t t| ƒ ¡ }t| dƒr6|d d… }|dt| jƒ 7 }|S )Nr   r   z, fitted with %i estimators>)r   rt   r   r   r   r   r   r!   r   r   r   ¥  s
    
zGeneralizingEstimator.__repr__c              	      sª   ˆ  |¡ tˆjˆ ƒ‰ dˆjjf }ttˆj|jd dd�\}‰}t	|jd t
ˆjƒ |d��4‰|‡ ‡‡‡fdd„t||dt
ˆjƒd�D ƒƒ}W 5 Q R X tj|d	d
�}|S )rE   rG   r   Fr#   r%   c                 3   s(   | ] \}}ˆˆj |ˆ ˆ |¡ƒV  qd S r'   ©r   r(   )r)   r*   Zx_split©rJ   r.   r/   r   r   r   r1   ´  s   ÿz3GeneralizingEstimator._transform.<locals>.<genexpr>©r3   Zn_per_splitr   r2   )r5   rK   r   r"   r9   r   Ú_gl_transformr   r7   r
   r   r   r	   r:   rP   )r   r=   rJ   r&   r>   r   rS   r   rv   r   rT   ¬  s(    
   ÿ   ÿþz GeneralizingEstimator._transformc                 C   s   |   |d¡S )aF  Transform each data slice with all possible estimators.

        Parameters
        ----------
        X : array, shape (n_samples, nd_features, n_slices)
            The input samples. For estimator the corresponding data slice is
            used to make a transformation. The feature dimension can be
            multidimensional e.g.
            X.shape = (n_samples, n_features_1, n_features_2, n_estimators).

        Returns
        -------
        Xt : array, shape (n_samples, n_estimators, n_slices)
            The transformed values generated by each estimator.
        rC   rU   rV   r   r   r   rC   ¼  s    zGeneralizingEstimator.transformc                 C   s   |   |d¡S )a�  Predict each data slice with all possible estimators.

        Parameters
        ----------
        X : array, shape (n_samples, nd_features, n_slices)
            The training input samples. For each data slice, a fitted estimator
            predicts each slice of the data independently. The feature
            dimension can be multidimensional e.g.
            X.shape = (n_samples, n_features_1, n_features_2, n_estimators).

        Returns
        -------
        y_pred : array, shape (n_samples, n_estimators, n_slices) | (n_samples, n_estimators, n_slices, n_targets)
            The predicted values for each estimator.
        rW   rU   rV   r   r   r   rW   Î  s    zGeneralizingEstimator.predictc                 C   s   |   |d¡S )aÔ  Estimate probabilistic estimates of each data slice with all possible estimators.

        Parameters
        ----------
        X : array, shape (n_samples, nd_features, n_slices)
            The training input samples. For each data slice, a fitted estimator
            predicts a slice of the data. The feature dimension can be
            multidimensional e.g.
            ``X.shape = (n_samples, n_features_1, n_features_2, n_estimators)``.

        Returns
        -------
        y_pred : array, shape (n_samples, n_estimators, n_slices, n_classes)
            The predicted values for each estimator.

        Notes
        -----
        This requires ``base_estimator`` to have a ``predict_proba`` method.
        rX   rU   rV   r   r   r   rX   à  s    z#GeneralizingEstimator.predict_probac                 C   s   |   |d¡S )a2  Estimate distances of each data slice to all hyperplanes.

        Parameters
        ----------
        X : array, shape (n_samples, nd_features, n_slices)
            The training input samples. Each estimator outputs the distance to
            its hyperplane, e.g.:
            ``[estimators[ii].decision_function(X[..., ii]) for ii in range(n_estimators)]``.
            The feature dimension can be multidimensional e.g.
            ``X.shape = (n_samples, n_features_1, n_features_2, n_estimators)``.

        Returns
        -------
        y_pred : array, shape (n_samples, n_estimators, n_slices, n_classes * (n_classes-1) // 2)
            The predicted values for each estimator.

        Notes
        -----
        This requires ``base_estimator`` to have a ``decision_function``
        method.
        rY   rU   rV   r   r   r   rY   ö  s    z'GeneralizingEstimator.decision_functionc              	      s¾   t ƒ }ˆ |¡ dˆjjf }ttˆj|jd dd�\}‰ }|ˆjˆj	ƒ‰t
ˆˆƒ‰t|jd tˆjƒ |d��6‰|‡ ‡‡‡‡fdd„t||dtˆjƒd�D ƒƒ}W 5 Q R X tj|d	d
�}|S )aö  Score each of the estimators on the tested dimensions.

        Parameters
        ----------
        X : array, shape (n_samples, nd_features, n_slices)
            The input samples. For each data slice, the corresponding estimator
            scores the prediction, e.g.:
            ``[estimators[ii].score(X[..., ii], y) for ii in range(n_slices)]``.
            The feature dimension can be multidimensional e.g.
            ``X.shape = (n_samples, n_features_1, n_features_2, n_estimators)``.
        y : array, shape (n_samples,) | (n_samples, n_targets)
            The target values.

        Returns
        -------
        score : array, shape (n_samples, n_estimators, n_slices)
            Score for each estimator / data slice couple.
        z
Scoring %sr   Fr#   r%   c              	   3   s*   | ]"\}}ˆ ˆj ˆ|ˆˆ |¡ƒV  qd S r'   ru   )r)   r*   rH   ©r.   r/   r   r   r0   r   r   r1   +  s   þÿz.GeneralizingEstimator.score.<locals>.<genexpr>rw   r   r2   )r   r5   r"   r9   r   Ú	_gl_scorer   r7   r   r   r]   r
   r   r   r	   r:   rP   )r   r=   r0   r_   r&   r>   r   r`   r   ry   r   r`     s,    
   ÿ
  þþzGeneralizingEstimator.score)r9   rc   rd   re   r   rT   rC   rW   rX   rY   r`   rg   r   r   r!   r   rt   –  s   rt   c              
   C   s  |j d |j d  }}t| ƒD ]ð\}}| tjd|jd td|jd ƒf ¡}| tj|| |j dd… f ¡}t||ƒ}	|	|ƒ}
|
jdkr¦t |
|||
j d g¡}
n,tj|||
j dd… f  	t
¡}t |
|¡}
|dkrêt|
|t| ƒƒ}|
|dd…|df< | |d | ¡ q|S )a  Transform the dataset.

    This will apply each estimator to all slices of the data.

    Parameters
    ----------
    X : array, shape (n_samples, nd_features, n_slices)
        The training input samples. For each data slice, a clone estimator
        is fitted independently. The feature dimension can be multidimensional
        e.g. X.shape = (n_samples, n_features_1, n_features_2, n_estimators)

    Returns
    -------
    Xt : array, shape (n_samples, n_slices)
        The transformed values generated by each estimator.
    r   r   r   r   N.)r7   rn   Z	transposer:   Zr_r[   ri   Zreshaper   ZastypeÚintÚ_gl_init_predr   rk   )r?   r=   rJ   r/   rr   Ún_iterrm   rA   ZX_stackrC   rp   r7   rS   r   r   r   rx   5  s    ("

 rx   c                 C   sV   |j d |j d  }}| jdkr>t |||| j d f| j¡} nt |||f| j¡} | S )z<Aux. function to GeneralizingEstimator to initialize y_pred.r   r   rZ   )r7   r[   r:   rq   r4   )rS   r=   Zn_trainrr   r}   r   r   r   r|   [  s    
ÿr|   c                 C   sœ   t | ƒ|jd g}t|jd ƒD ]v}t| ƒD ]h\}}|||d|f |ƒ}	|dkrl|dkrlt|	ƒ}
t ||
¡}|	|||df< | |t | ƒ | d ¡ q,q |S )a4  Score GeneralizingEstimator in parallel.

    Predict and score each slice of data.

    Parameters
    ----------
    estimators : list of estimators
        The fitted estimators.
    scoring : callable, string or None
        If scoring is None (default), the predictions are internally
        generated by estimator.score(). Else, we must first get the
        predictions to pass them to ad-hoc scorer.
    X : array, shape (n_samples, nd_features, n_slices)
        The target data. The feature dimension can be multidimensional e.g.
        X.shape = (n_samples, n_features_1, n_features_2, n_estimators)
    y : array, shape (n_samples,) | (n_samples, n_targets)
        The target values.

    Returns
    -------
    score : array, shape (n_estimators, n_slices)
        The score for each slice of data.
    r   .r   r   )r   r7   ri   rn   Útyper:   rq   rk   )r?   r   r=   r0   r/   Zscore_shapeZjjrm   rA   Z_scorer4   r`   r   r   r   rz   f  s    rz   c                 C   s‚   ddl m} | d k	r~t| dd ƒ}t| di ƒ}t|ddƒdkr~| dd	¡d	kr~t |¡d
ksjtt|ƒƒdkrrtdƒ‚|ƒ  	|¡}|S )Nr   )ÚLabelEncoderZ_score_funcÚ_kwargsr9   Ú Zroc_auc_scoreZmulti_classÚraiser   r   z<roc_auc scoring can only be computed for two-class problems.)
Zsklearn.preprocessingr   r   Úgetr:   r[   r   ÚsetrL   rD   )r   r0   r   Z
score_funcÚkwargsr   r   r   r]   �  s    ÿr]   )Únumpyr:   Zmixinr   Úbaser   r   Úfixesr   r>   r   Úutilsr	   r
   r   r   r   r6   rM   ro   r^   rK   rt   rx   r|   rz   r]   r   r   r   r   Ú<module>   s,     
 &'