o
    eiF                     @   s  d dl mZ d dlm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mZ dd
lmZ ddlmZmZ ddlmZ ddlmZmZ ddlmZmZ ddlmZm Z  ddl!m"Z"m#Z# ddl$m%Z% ddl&m'Z'm(Z(m)Z)m*Z* ddl+m,Z,m-Z- ddl.m/Z/m0Z0 ddl1m2Z2 e*3e4Z5edG dd dej6Z7G dd dej6Z8G dd dej6Z9G dd dej6Z:G d d! d!ej6Z;G d"d# d#ej6Z<d$d% Z=ed&dKd'd(Z>d)ej?d*e@d+ej?fd,d-ZA	.dLd/ej6d0ej?d1ej?d2ej?d3ej?dB d4eBd5eBd6e%e' fd7d8ZCG d9d: d:ej6ZDG d;d< d<eZEe(G d=d> d>e#ZFe(G d?d@ d@eFZG		A	dMdBej?eHej? B dB dCe@dB d3ej?dB d+ej?e@B fdDdEZIG dFdG dGeFeZJG dHdI dIeeFZKg dJZLdS )N    )Callable)OptionalN)nn)
functional   )initialization)ACT2FN)CacheDynamicCache)GenerationMixin)use_kernel_forward_from_hubuse_kernel_func_from_hub)create_causal_mask) GenericForSequenceClassificationGradientCheckpointingLayer)MoeCausalLMOutputWithPastMoeModelOutputWithPast)ROPE_INIT_FUNCTIONSdynamic_rope_update)ALL_ATTENTION_FUNCTIONSPreTrainedModel)Unpack)TransformersKwargsauto_docstringcan_return_tuplelogging)maybe_autocastmerge_with_config_defaults)OutputRecordercapture_outputs   )JetMoeConfigRMSNormc                       sF   e Zd Zddeddf fddZdejdejfdd	Zd
d Z  Z	S )JetMoeRMSNormư>epsreturnNc                    s&   t    tt|| _|| _dS )z<
        JetMoeRMSNorm is equivalent to T5LayerNorm
        N)super__init__r   	Parametertorchonesweightvariance_epsilon)selfhidden_sizer%   	__class__ h/home/ubuntu/transcripts/venv/lib/python3.10/site-packages/transformers/models/jetmoe/modeling_jetmoe.pyr(   2   s   

zJetMoeRMSNorm.__init__hidden_statesc                 C   sJ   |j }|tj}|djddd}|t|| j  }| j|| S )N   T)keepdim)	dtypetor*   float32powmeanrsqrtr-   r,   )r.   r4   input_dtypevariancer2   r2   r3   forward:   s
   zJetMoeRMSNorm.forwardc                 C   s   t | jj d| j S )Nz, eps=)tupler,   shaper-   )r.   r2   r2   r3   
extra_reprA   s   zJetMoeRMSNorm.extra_repr)r$   )
__name__
__module____qualname__floatr(   r*   Tensorr@   rC   __classcell__r2   r2   r0   r3   r#   0   s    r#   c                       s~   e Zd ZU ejed< ddef fddZe			ddedB de	d de
dB d	ed
ef fddZe edd Z  ZS )JetMoeRotaryEmbeddinginv_freqNconfigc                    s   t    |j| _|j| _|| _| jjd | _| j}| jdkr$t	| j }|| j|\}| _
| jd|dd | jd| dd d S )N	rope_typedefaultrK   F)
persistentoriginal_inv_freq)r'   r(   max_position_embeddingsmax_seq_len_cachedoriginal_max_seq_lenrL   rope_parametersrM   compute_default_rope_parametersr   attention_scalingregister_bufferclone)r.   rL   devicerope_init_fnrK   r0   r2   r3   r(   H   s   


zJetMoeRotaryEmbedding.__init__rY   ztorch.deviceseq_lenr&   ztorch.Tensorc                 C   sZ   | j d }t| ddp| j| j }d}d|tjd|dtjdj|tjd|   }||fS )	a  
        Computes the inverse frequencies according to the original RoPE implementation
        Args:
            config ([`~transformers.PreTrainedConfig`]):
                The model configuration.
            device (`torch.device`):
                The device to use for initialization of the inverse frequencies.
            seq_len (`int`, *optional*):
                The current sequence length. Unused for this type of RoPE.
        Returns:
            Tuple of (`torch.Tensor`, `float`), containing the inverse frequencies for the RoPE embeddings and the
            post-processing scaling factor applied to the computed cos/sin (unused in this type of RoPE).
        
rope_thetahead_dimNg      ?r   r5   r8   )rY   r8   )	rT   getattrr/   num_attention_headsr*   arangeint64r9   rG   )rL   rY   r[   basedimattention_factorrK   r2   r2   r3   rU   X   s   
&z5JetMoeRotaryEmbedding.compute_default_rope_parametersc           
      C   s   | j d d d d f  |jd dd|j}|d d d d d f  }t|jjtr6|jjdkr6|jjnd}t	|dd+ | |  
dd}tj||fdd	}| | j }| | j }	W d    n1 slw   Y  |j|jd
|	j|jd
fS )Nr   r6   r    mpscpuF)device_typeenabledr5   rd   r^   )rK   rG   expandrB   r9   rY   
isinstancetypestrr   	transposer*   catcosrV   sinr8   )
r.   xposition_idsinv_freq_expandedposition_ids_expandedrh   freqsembrq   rr   r2   r2   r3   r@   v   s   0&zJetMoeRotaryEmbedding.forwardN)NNN)rD   rE   rF   r*   rH   __annotations__r!   r(   staticmethodr   intrA   rG   rU   no_gradr   r@   rI   r2   r2   r0   r3   rJ   E   s&   
 

rJ   c                       s6   e Zd Zdedededdf fddZdd	 Z  ZS )
JetMoeParallelExpertsnum_experts
input_sizeoutput_sizer&   Nc                    s6   t    tt|||| _|| _|| _|| _	dS )a  
        Initialize the JetMoeParallelExperts module.
        The experts weights are stored in [num_experts, output_size, input_size] format. Such that it's compatible with
        many MoE libraries, such as [Megablock](https://github.com/databricks/megablocks) and
        [ScatterMoE](https://github.com/shawntan/scattermoe), as well as the
        [MoE kernel](https://github.com/vllm-project/vllm/blob/main/vllm/model_executor/layers/fused_moe/fused_moe.py)
        used in vllm.

        Args:
            num_experts (int):
                Number of experts.
            input_size (int):
                Size of the input.
            output_size (int):
                Size of the output.
        N)
r'   r(   r   r)   r*   emptyr,   r   r   r   )r.   r   r   r   r0   r2   r3   r(      s
   

zJetMoeParallelExperts.__init__c                 C   sP   |j |dd}g }t| jD ]}|t|| | j|  qtj|dd}|S )a  
        Forward pass of the JetMoeParallelExperts module.

        Args:
            inputs (Tensor):
                Input tensor.
            expert_size:
                Expert size information.

        Returns:
            Tensor: Output tensor.
        r   rj   )	splitranger   appendFlinearr,   r*   rp   )r.   inputsexpert_size
input_listoutput_listiresultsr2   r2   r3   r@      s   zJetMoeParallelExperts.forwardrD   rE   rF   r|   r(   r@   rI   r2   r2   r0   r3   r~      s    r~   c                       s2   e Zd Zdededef fddZdd Z  ZS )JetMoeTopKGatingr   r   top_kc                    s2   t    || _|| _|| _tj||dd| _dS )a  
        Initialize the top-k gating mechanism.

        Args:
            input_size (`int`):
                Size of the input.
            num_experts (`int`):
                Number of experts.
            top_k (`int`):
                Number of top experts to select.
        FbiasN)r'   r(   r   r   r   r   Linearlayer)r.   r   r   r   r0   r2   r3   r(      s
   
zJetMoeTopKGating.__init__c                 C   s   |  | }|j| jdd\}}tj|dd|}tj|d| j	g|j
|jd}|d|d}| d}| }| }	|	d\}
}|j| jdd}| }|| }|||||fS )Nr    rj   r   r8   rY   trunc)rounding_mode)r   rG   topkr   r*   softmaxtype_aszerossizer   r8   rY   scatterlongsumtolistflattensortdiv)r.   r4   logitstop_k_logitstop_k_indicestop_k_gatesr   gatesr   top_k_experts_index_sorted_expertsbatch_indexbatch_gatesr2   r2   r3   r@      s   zJetMoeTopKGating.forwardr   r2   r2   r0   r3   r      s    r   c                       s.   e Zd ZdZdef fddZdd Z  ZS )	JetMoeMoEz
    A Sparsely gated mixture of experts layer with 1-layer Feed-Forward networks as experts.

    Args:
        config:
            Configuration object with model hyperparameters.
    rL   c                    s   t    |j| _|j| _t|j | _tj	
t| j| _t|j| j| jd | _t|j| j| j| _t| j|j|jd| _d S )Nr5   r   r   r   )r'   r(   r/   r   intermediate_sizer   activation_function
activationr*   r   r)   r   r   r~   num_local_expertsinput_linearoutput_linearr   num_experts_per_tokrouterr.   rL   r0   r2   r3   r(      s   
zJetMoeMoE.__init__c                 C   s   |  \}}}|d|}| |\}}}}}	|| }
| |
|}|jddd}| |d |d  }| ||}||dddf  }tj|| | j	f|j
|jd}|d||}|||| j	}|| j }|S )a  
        Forward pass of the mixture of experts layer.

        Args:
            layer_input (Tensor):
                Input tensor.

        Returns:
            Tensor:
                Output tensor.
            Tensor:
                Router logits.
        r6   r5   rj   r   r    Nr   )r   reshaper   r   chunkr   r   r*   r   r   r8   rY   	index_addviewr   )r.   layer_inputbszlengthemb_sizer   r   r   r   router_logitsexpert_inputsr4   chunked_hidden_statesexpert_outputsr   layer_outputr2   r2   r3   r@      s   
zJetMoeMoE.forward)rD   rE   rF   __doc__r!   r(   r@   rI   r2   r2   r0   r3   r      s    r   c                       s>   e Zd ZdZdef fddZdd Zdd Zd	d
 Z  Z	S )	JetMoeMoAz
    A Sparsely gated mixture of attention layer with pairs of query- and output-projections as experts.

    Args:
        config:
            Configuration object with model hyperparameters.
    rL   c                    s   t    |j| _|j| _|j|j | _|j| _	t
jt
| j| _t| j| j| j| _t| j| j| j| _t| j| j| j	d| _d S )Nr   )r'   r(   r   r   r/   r   kv_channelsnum_key_value_headsr   r   r*   r   r)   r   r   r~   r   r   r   r   r   r0   r2   r3   r(   '  s   
zJetMoeMoA.__init__c                 C   s   |  \}}}|d|}| |\}}}}}	||||f}
|| }| ||}tj|| | j | jf|j|j	d}|
d||}|||| jd}||	|
fS )z
        Map inputs to attention experts according to routing decision and compute query projection inside each experts.
        r6   r   r   )r   r   r   r   r*   r   r   r/   r8   rY   r   r   )r.   r   r   r   r   r   r   r   r   r   	topo_infor   r   r   r   r2   r2   r3   map9  s   
zJetMoeMoA.mapc                 C   s   |  \}}}}|d|}|\}}}	}
|| }| ||
}||	dddf  }tj|| | jf|j|jd}|d||}|	||| j}|| j
 }|S )zu
        Compute output projection inside each attention experts and merge the outputs of different experts.
        r6   Nr   r   )r   r   r   r*   r   r   r8   rY   r   r   r   )r.   r   r   r   r   kr/   r   r   r   r   r   r   r   r   r2   r2   r3   reduceP  s   
zJetMoeMoA.reducec                 C   s   t d)Nz-This module doesn't support call and forward.)NotImplementedError)r.   r   r2   r2   r3   r@   f  s   zJetMoeMoA.forward)
rD   rE   rF   r   r!   r(   r   r   r@   rI   r2   r2   r0   r3   r     s    r   c                 C   sH   | dd| j d d f }| d| j d d df }tj| |fddS )z*Rotates half the hidden dims of the input..Nr6   r5   rj   )rB   r*   rp   )rs   x1x2r2   r2   r3   rotate_halfj  s   r   rotary_pos_embc                 C   sD   | |}| |}| | t| |  }|| t||  }||fS )a  Applies Rotary Position Embedding to the query and key tensors.

    Args:
        q (`torch.Tensor`): The query tensor.
        k (`torch.Tensor`): The key tensor.
        cos (`torch.Tensor`): The cosine part of the rotary embedding.
        sin (`torch.Tensor`): The sine part of the rotary embedding.
        unsqueeze_dim (`int`, *optional*, defaults to 1):
            The 'unsqueeze_dim' argument specifies the dimension along which to unsqueeze cos[position_ids] and
            sin[position_ids] so that they can be properly broadcasted to the dimensions of q and k. For example, note
            that cos[position_ids] and sin[position_ids] have the shape [batch_size, seq_len, head_dim]. Then, if q and
            k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes
            cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have
            the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2.
    Returns:
        `tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding.
    )	unsqueezer   )qr   rq   rr   unsqueeze_dimq_embedk_embedr2   r2   r3   apply_rotary_pos_embq  s
   

r   r4   n_repr&   c                 C   s^   | j \}}}}|dkr| S | dddddddddf |||||} | ||| ||S )z
    This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch,
    num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
    r    N)rB   rk   r   )r4   r   batchr   slenr]   r2   r2   r3   	repeat_kv  s
   0r           modulequerykeyvalueattention_maskscalingdropoutkwargsc                 K   s   t || j}t || j}	t||dd| }
|d ur |
| }
tjj|
dtjd	|j
}
tjj|
|| jd}
t|
|	}|dd }||
fS )Nr5   r   r6   )rd   r8   )ptrainingr    )r   num_key_value_groupsr*   matmulro   r   r   r   r:   r9   r8   r   r   
contiguous)r   r   r   r   r   r   r   r   
key_statesvalue_statesattn_weightsattn_outputr2   r2   r3   eager_attention_forward  s   
r   c                       s   e Zd ZdZddededB f fddZ				ddejdejdB d	ej	dB d
e
dB dej	dB deejejdB eej dB f fddZ  ZS )JetMoeAttentionzH
    Multi-headed attention from 'Attention Is All You Need' paper.
    NrL   	layer_idxc                    s   t    || _|| _d| _|du rtd| jj d d| _	|j
| _|j| _|j|j | _|j| _|j| _|j| _| jd | _t|| _tjj|j| jd dd	| _dS )
z
        Initialize the JetMoeAttention module.

        Args:
            config:
                Configuration object with model hyperparameters.
            layer_idx:
                Index of the layer in the model.
        TNzInstantiating z without passing a `layer_idx` is not recommended and will lead to errors during the forward call if caching is used. Please make sure to provide a `layer_idx` when creating this class.r    g      r5   Fr   )r'   r(   rL   r   	is_causalloggerwarning_oncer1   rD   r   r   r   attention_dropoutr   r   kv_projection_sizer`   	num_headsr]   r   r   expertsr*   r   r   r/   kv_projr.   rL   r   r0   r2   r3   r(     s$   


 zJetMoeAttention.__init__r4   r   position_embeddingspast_key_valuescache_positionr&   c                 K   sp  |j d d }g |d| jR }| j|\}	}
}| |jddd\}}|	|dd}	||dd}||dd}|\}}t|	|||\}	}|d urc|||d}|	||| j
|\}}t| jjt}|d| jdd}|d| jdd}|| |	|||f| jsdn| j| jd|\}}|jg || jdR  }| j||}|jg |dR  }|||
fS )Nr6   r5   rj   r    )rr   rq   r   r   )r   r   )rB   r]   r   r   r   r   r   ro   r   updater   r   get_interfacerL   _attn_implementationr   repeatr   r   r   r   r   )r.   r4   r   r   r   r   r   input_shapehidden_shapequery_statesr   r   r   r   rq   rr   cache_kwargsattention_interfacer   r   r2   r2   r3   r@     sB   	

zJetMoeAttention.forwardry   )NNNN)rD   rE   rF   r   r!   r|   r(   r*   rH   
LongTensorr	   rA   r@   rI   r2   r2   r0   r3   r     s(    $r   c                       s   e Zd ZddededB f fddZ						ddejdejdB d	ejdB d
e	dB de
dB dejdB deejejf dB dee dejfddZ  ZS )JetMoeDecoderLayerNrL   r   c                    sD   t    |j| _t|| _t|j| _t|j| _t||| _	d S ry   )
r'   r(   r/   r   mlpr#   input_layernormpost_attention_layernormr   self_attentionr   r0   r2   r3   r(     s   

zJetMoeDecoderLayer.__init__Fr4   r   rt   r   	use_cacher   r   r   r&   c              
   K   s`   |}	|  |}| jd|||||||d|\}}
}
|	| }|}	| |}| |}|	| }|S )N)r4   r   rt   r   r  r   r   r2   )r
  r  r  r	  )r.   r4   r   rt   r   r  r   r   r   residualr   r2   r2   r3   r@     s&   



zJetMoeDecoderLayer.forwardry   )NNNFNN)rD   rE   rF   r!   r|   r(   r*   rH   r  r	   boolrA   r   r   r@   rI   r2   r2   r0   r3   r    s6    	
r  c                       s~   e Zd ZU eed< dZdZdgZdgZdZ	dZ
dZdZdZeeddeed	dgeeed
ddZe  fddZ  ZS )JetMoePreTrainedModelrL   modelFr  r   Tr5   )index   r    )r   r4   
attentionsc                    sR   t  | t|trtj|jd| jjd dS t|t	t
B r't|j dS dS )zInitialize the weights.r   )r<   stdN)r'   _init_weightsrl   r~   initnormal_r,   rL   initializer_ranger   r   zeros_r   )r.   r   r0   r2   r3   r  H  s   
z#JetMoePreTrainedModel._init_weights)rD   rE   rF   r!   rz   base_model_prefixsupports_gradient_checkpointing_no_split_modules_skip_keys_device_placement_supports_flash_attn_supports_sdpa_supports_flex_attn_can_compile_fullgraph_supports_attention_backendr   r   r   r  _can_record_outputsr*   r}   r  rI   r2   r2   r0   r3   r  6  s"   
 
r  c                       s   e Zd Zdef fddZeee							ddej	dB dej
dB dej	dB dedB d	ejdB d
edB dej	dB dee defddZ  ZS )JetMoeModelrL   c                    s   t     j| _ j| _t j j| j| _t	 fddt
 jD | _t j jd| _t d| _d| _ j| _|   d S )Nc                    s   g | ]}t  |qS r2   )r  ).0r   rL   r2   r3   
<listcomp>[      z(JetMoeModel.__init__.<locals>.<listcomp>)r%   r'  F)r'   r(   pad_token_idpadding_idx
vocab_sizer   	Embeddingr/   embed_tokens
ModuleListr   num_hidden_layerslayersr#   rms_norm_epsnormrJ   
rotary_embgradient_checkpointingr   	post_initr   r0   r'  r3   r(   T  s   zJetMoeModel.__init__N	input_idsr   rt   r   inputs_embedsr  r   r   r&   c              
   K   s   |d u |d uA rt d|r|d u rt| jd}|d u r!| |}|d u r=|d ur-| nd}	tj|	|	|jd  |jd}|d u rF|	d}t
| j|||||d}
|}| ||}| jd | jj D ]}||f||
||||d|}qb| |}t||dS )	Nz:You must specify exactly one of input_ids or inputs_embedsr'  r   r    )rY   )rL   r8  r   r   r   rt   )r   r   r   r  r   rt   )last_hidden_stater   )
ValueErrorr
   rL   r.  get_seq_lengthr*   ra   rB   rY   r   r   r4  r1  r0  r3  r   )r.   r7  r   rt   r   r8  r  r   r   past_seen_tokenscausal_maskr4   r   decoder_layerr2   r2   r3   r@   e  sR   

	
zJetMoeModel.forward)NNNNNNN)rD   rE   rF   r!   r(   r   r   r   r*   r  rH   r	   FloatTensorr  r   r   r   r@   rI   r2   r2   r0   r3   r%  R  s>    	
r%  r5   gate_logitsr   c                    s  | du s	t | tsdS t | tr#| d j tj fdd| D dd}tjjj|dd}tj||dd\}}tjj	||}|du rStj
| dd}	tj
|dd}
ng|j\}}|jd ||  }|dddddddf |||||fd|| }tj| | ddtj|dd }	|ddddddf ||||fd| }tj|| ddtj|dd }
t|	|
d }|| S )a  
    Computes auxiliary load balancing loss as in Switch Transformer - implemented in Pytorch.

    See Switch Transformer (https://huggingface.co/papers/2101.03961) for more details. This function implements the loss
    function presented in equations (4) - (6) of the paper. It aims at penalizing cases where the routing between
    experts is too unbalanced.

    Args:
        gate_logits:
            Logits from the `gate`, should be a tuple of model.config.num_hidden_layers tensors of
            shape [batch_size X sequence_length, num_experts].
        num_experts:
            Number of experts
        top_k:
            The number of experts to route per-token, can be also interpreted as the `top-k` routing
            parameter.
        attention_mask (`torch.Tensor`, *optional*):
            The attention_mask used in forward function
            shape [batch_size X sequence_length] if not None.

    Returns:
        The auxiliary loss.
    Nr   c                    s   g | ]}|  qS r2   )r9   )r&  
layer_gatecompute_devicer2   r3   r(    r)  z,load_balancing_loss_func.<locals>.<listcomp>rj   r6   )rl   rA   rY   r*   rp   r   r   r   r   one_hotr<   rG   rB   rk   r   r9   r   r   )r@  r   r   r   concatenated_gate_logitsrouting_weightsr   selected_expertsexpert_masktokens_per_expertrouter_prob_per_expert
batch_sizesequence_lengthr0  expert_attention_mask router_per_expert_attention_maskoverall_lossr2   rB  r3   load_balancing_loss_func  s>   



rP  c                       s   e Zd ZddiZ fddZee										ddejdB d	ej	dB d
ejdB de
dB dejdB dejdB dedB dejdB deej	B dedB defddZ  ZS )JetMoeForCausalLMzlm_head.weightzmodel.embed_tokens.weightc                    s`   t  | t|| _|j| _|j| _tj|j|jdd| _	|j
| _
|j| _|j| _|   d S )NFr   )r'   r(   r%  r  r,  aux_loss_coefr   r   r/   lm_headtie_word_embeddingsr   r   r   r6  r   r0   r2   r3   r(     s   
zJetMoeForCausalLM.__init__Nr   Fr7  r   rt   r   r8  labelsr  r   logits_to_keepoutput_router_logitsr&   c                 K   s   | j d||||||||
d|}|j}t|	trt|	 d n|	}| |d d |d d f }d }|d urC| j||fd| jji|}d }|
r`t	|j
| j| j|}|d ur`|| j||j 7 }t||||j|j|j|j
dS )N)r7  r   rt   r   r8  r  r   rW  r,  )lossaux_lossr   r   r4   r  r   r2   )r  r9  rl   r|   slicerS  loss_functionrL   r,  rP  r   r   r   rR  r9   rY   r   r   r4   r  )r.   r7  r   rt   r   r8  rU  r  r   rV  rW  r   outputsr4   slice_indicesr   rX  rY  r2   r2   r3   r@     sX   	zJetMoeForCausalLM.forward)
NNNNNNNNr   F)rD   rE   rF   _tied_weights_keysr(   r   r   r*   r  rH   r	   r?  r  r|   r   r@   rI   r2   r2   r0   r3   rQ    sL    	
rQ  c                   @   s   e Zd ZdS )JetMoeForSequenceClassificationN)rD   rE   rF   r2   r2   r2   r3   r_  H  s    r_  )rQ  r%  r  r_  )r    )r   )Nr5   N)Mcollections.abcr   typingr   r*   r   torch.nnr   r    r   r  activationsr   cache_utilsr	   r
   
generationr   integrationsr   r   masking_utilsr   modeling_layersr   r   modeling_outputsr   r   modeling_rope_utilsr   r   modeling_utilsr   r   processing_utilsr   utilsr   r   r   r   utils.genericr   r   utils.output_capturingr   r   configuration_jetmoer!   
get_loggerrD   r   Moduler#   rJ   r~   r   r   r   r   r   rH   r|   r   rG   r   r   r  r  r%  rA   rP  rQ  r_  __all__r2   r2   r2   r3   <module>   s   
A-1:L
[+U
RP