o
    Mf                     @   s4  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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 ddlm Z  ddl!m"Z" ddl#m$Z$m%Z%m&Z&m'Z'm(Z( e)djZ*e+e,Z-G dd deZ.G dd de.Z/dd Z0dd Z1d_ddZ2dd Z3dd Z4d d! Z5G d"d# d#eZ6d$d% Z7ej8ej9ej:fZ;ej<e;d&ej=fej>e;d'ej?fej@ejAd(ej=fejBejAd)ej?fej@ejCejDfd*ej=fejBejCejDfd+ej?fgZEd,d- ZFd.d/ ZGejHe jIdffejJe jKe jLffejMe jNdffejOe jKe jPffejQe jKe jRffej:eGe jSffejTe jKdffej9e jUdffej8e jIdffejVe jKe jWffejXe jKe jYffejZe jKe j[ffej\e jKdffej]e jKdffej^e jKe j_ffejAe jKdffgZ`e jWe jYd0Zaejbe jKe jcffejZe jKe j[ffejde jKe jeffejVe jKd1d2 ffej^e jKe j_ffejfe jKdffejAe jKdffejMe jNdffej8e jIdffej9e jUdffej:eGe jSffejTe jKdffejQe jKe jRffejOe jKe jPffejge jKdffgZheie*eid3k re`jejke jNdff ehjejke jNdff ehe` Zld4d5 Zmd6d7 Znd8d9 Zod:d; Zpeqe jNdffere jIdffese jKdffete jUdffeue jvdffe
ene jSffejwe jKe j_ffe j e jKe jPffe jxe jKe jRffg	Zyezed<rnej{Z|nd=d> Z|d?d@ Z}eyjej~ejfe}f dAdB ZdCdD ZG dEdF dFeZG dGdH dHeZG dIdJ dJeZG dKdL dLeZG dMdN dNeZG dOdP dPeZG dQdR dReZG dSdT dTeZzd dUlmZ d dVlmZmZ W n ey   d ZZdWdX ZY nw G dYdZ dZeZzd d[lmZ W n ey   G d\d] d]eZY dS w G d^d] d]eZdS )`    N)suppress)OrderedDict)Decimal)	signature)
validators)models)version)serializers)api_settings   )call_view_methodFieldInspector
NotHandledSerializerInspector   )openapi)SwaggerGenerationError)decimal_as_floatfield_value_to_representationfilter_noneget_serializer_classget_serializer_ref_namedjangorestframeworkc                   @   sT   e Zd ZdZ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 ZdS )InlineSerializerInspectorzVProvides serializer conversions using :meth:`.FieldInspector.field_to_swagger_object`.Fc                 C   s   |  |tj| jS N)probe_field_inspectorsr   Schemause_definitionsself
serializer r!   [/var/www/html/analyze/labelStudio/lib/python3.10/site-packages/drf_yasg/inspectors/field.py
get_schema%      z$InlineSerializerInspector.get_schemac                 C   s   |S )a  Add/replace parameters from the given list of automatically generated request parameters. This method
        is called only when the serializer is converted into a list of parameters for use in a form data request.

        :param serializer: serializer instance
        :param list[openapi.Parameter] parameters: generated parameters
        :return: modified parameters
        :rtype: list[openapi.Parameter]
        r!   )r   r    
parametersr!   r!   r"   add_manual_parameters(   s   	z/InlineSerializerInspector.add_manual_parametersc                    s0   t |di } fdd| D }||S )Nfieldsc              	      s:   g | ]\}}t |d dsj|tjj| dqS )	read_onlyF)namein_)getattrr   r   	Parameterr   get_parameter_name).0keyvaluer*   r   r!   r"   
<listcomp>5   s    


zDInlineSerializerInspector.get_request_parameters.<locals>.<listcomp>)r+   itemsr&   )r   r    r*   r'   r%   r!   r1   r"   get_request_parameters3   s
   
z0InlineSerializerInspector.get_request_parametersc                 C      |S r   r!   r   
field_namer!   r!   r"   get_property_nameA      z+InlineSerializerInspector.get_property_namec                 C   r5   r   r!   r6   r!   r!   r"   r-   D   r9   z,InlineSerializerInspector.get_parameter_namec                 C   s   t |S r   )r   r   r!   r!   r"   r   G   s   z1InlineSerializerInspector.get_serializer_ref_namec                 C   s   t |dd }t|dS )NMetaref_name)r+   hasattr)r   r    serializer_metar!   r!   r"   _has_ref_nameJ   s   
z'InlineSerializerInspector._has_ref_namec                    s*  j ||fi |\ t|tjtjfr/|j }t|p#i }dtj	|d|S t|tj
r|tjkrAtd|j |}|f fdd	}|rUsX| S jtj}	|	||}
|
  t|
dd }t|}|r||kr|o|}|std||f t|	|S tS )Ntyper3   z(cannot instantiate nested serializer as c                    s   t  }g }| j D ]3\}}|}dt|jpd i}t|}j| fi |}|||< |jr=t	|dds=|
| q
dtj||pFd d}t|dt|  |S )Nr(   F)use_field_titler@   
propertiesrequired_NP_serializer)r   r'   r3   r8   boolr(   r   r   rC   r+   appendr   TYPE_OBJECTsetattrr   )r    rB   rC   property_namechildprop_kwargschild_schemaresultChildSwaggerTypeSwaggerTyper   use_referencesr!   r"   make_schema_definition_   s0   

	zQInlineSerializerInspector.field_to_swagger_object.<locals>.make_schema_definitionrD   zSchema for %s would override distinct serializer %s because they implicitly share the same ref_name; explicitly set the ref_name attribute on both serializers' Meta classesr!   )_get_partial_types
isinstancer	   ListSerializer	ListFieldr   rJ   find_limitsr   
TYPE_ARRAY
Serializerr   r   __name__r   
components
with_scopeSCHEMA_DEFINITIONS
setdefault_remove_read_onlyr+   r   r>   	SchemaRefr   )r   fieldswagger_object_typerQ   kwargsrL   limitsr;   rR   definitionsactual_schemaactual_serializerthis_serializerexplicit_refsr!   rN   r"   field_to_swagger_objectN   s@   

z1InlineSerializerInspector.field_to_swagger_objectN)rZ   
__module____qualname____doc__r   r#   r&   r4   r8   r-   r   r>   rj   r!   r!   r!   r"   r      s    r   c                   @      e Zd ZdZdS )ReferencingSerializerInspectorTN)rZ   rk   rl   r   r!   r!   r!   r"   ro      s    ro   c                 C   s   t | dd}t||}||fS )a  Try to get information about a model and model field from a queryset.

    :param queryset: the queryset
    :param field_name: target field name
    :returns: the model and target field from the queryset as a 2-tuple; both elements can be ``None``
    :rtype: tuple
    modelN)r+   get_model_field)querysetr7   rp   model_fieldr!   r!   r"   get_queryset_field   s   
rt   c                 C   s6   z|dkr
| j jW S | j |W S  ty   Y dS w )zTry to get the given field from a django db model.

    :param model: the model
    :param field_name: target field name
    :return: model field or ``None``
    pkN)_metaru   	get_field	Exception)rp   r7   r!   r!   r"   rq      s   
rq   c                 C   sP   zt | dd}|dur|durt|t | ddksJ |W S  ty'   Y dS w )zTry to get the queryset of the given view

    :param view: the view instance or class
    :param serializer: if given, will check that the view's get_serializer_class return matches this serializer
    :return: queryset or ``None``
    get_querysetrr   Nr   serializer_class)r   r@   rx   )viewr    rr   r!   r!   r"   get_queryset_from_view   s   r|   c                 C   s*   | durt | tjr| S | j} | dusdS )zqGet the nearest parent ``Serializer`` instance for the given field.

    :return: ``Serializer`` or ``None``
    N)rT   r	   rY   parentra   r!   r!   r"   get_parent_serializer   s   r   c              	   C   sb   t t# z| jjW W  d    S  ty&   | jjj Y W  d    S w 1 s*w   Y  d S r   )r   rx   relrelated_modelra   remote_fieldrp   )
descriptorr!   r!   r"   get_model_from_descriptor   s   
r   c                 C   s   t t2 d|v r(|dr(|jddd\}}ttt| ||W  d   S tt| |W  d   S 1 s9w   Y  dS )zTry to find the other side of a model relationship given the name of a related field.

    :param model: one side of the relationship
    :param str source: related field name
    :return: related model or ``None``
    .r   )maxsplitN)r   rx   indexsplitget_related_modelr   r+   )rp   sourceattrr!   r!   r"   r      s   
$r   c                   @      e Zd ZdZdd ZdS )RelatedFieldInspectorz-Provides conversions for ``RelatedField``\ s.c                 K   s  | j |||fi |\}}t|tjr#| |j||}|tj|ddS t|tjs+t	S t
|dd }t|tjtjfrt
|ddrQ| j|j||fi |}	||	dS t
|dd}
|d urct||
\}}n>t|}t
|d	d }t
|d
d }|st| j|}t
|d
d }t
|ddp|j}|st|jtjr|jj}t||}t||
}t|pdtji}|di |S t|tjr|tjtjdS t	S )NT)r@   r3   unique_itemsrr   pk_field )existing_object
slug_fieldru   r:   rp   r   r@   )r@   formatr!   )rS   rT   r	   ManyRelatedFieldr   child_relationr   rX   RelatedFieldr   r+   PrimaryKeyRelatedFieldSlugRelatedFieldr   rt   r   r|   r{   r7   r}   r   rq   get_basic_type_infoTYPE_STRINGHyperlinkedRelatedField
FORMAT_URI)r   ra   rb   rQ   rc   rP   rO   rL   field_querysetrM   target_fieldrp   rs   parent_serializerr=   
this_modelview_querysetr   attrsr!   r!   r"   rj      sD   


z-RelatedFieldInspector.field_to_swagger_objectNrZ   rk   rl   rm   rj   r!   r!   r!   r"   r          r   c                 C   s   d}| j D ]}t|t jr"t|t js|t jkrq|dur  dS |}qztt|dddd}W n tyD   tjdt	|  dd Y dS w |rY|
dsQ|
drY|dd	 d
 }|S )zGiven a ``Field``, look for a ``RegexValidator`` and try to extract its pattern and return it as a string.

    :param serializers.Field regex_field: the field instance
    :return: the extracted pattern, or ``None``
    :rtype: str
    Nregexpatternz%failed to compile regex validator of T)exc_infoz\Zz\z$)r   rT   RegexValidatorURLValidatorvalidate_ipv4_addressr+   rx   loggerwarningstrendswith)regex_fieldregex_validator	validatorr   r!   r!   r"   
find_regex&  s&   
r   minimummaximum
min_length
max_length	min_items	max_itemsc                    s   i } fddt D }t tjrt s|S  jD ]4}t|ds"q|j}t|tr2t r2t	|}|D ]\}}}t||rM||vsI|||| rM|||< q4qt drc j
sc|dddk rcd|d< tt| S )zGiven a ``Field``, look for min/max value/length validators and return appropriate limit validation attributes.

    :param serializers.Field field: the field instance
    :return: the extracted limits
    :rtype: OrderedDict
    c                    s(   g | ]\}}}}t  |r|||fqS r!   )rT   )r.   r   field_classr   improvesr~   r!   r"   r2   a  s    
zfind_limits.<locals>.<listcomp>limit_valueallow_blankr   r   r   )limit_validatorsrT   r	   DecimalFieldr   r   r<   r   r   floatr   getr   sortedr3   )ra   rd   applicable_limitsr   r   validator_classr   r   r!   r~   r"   rW   Y  s,   



rW   c                 C   s   t | rtjS tjS r   )r   r   TYPE_NUMBERr   r~   r!   r!   r"   decimal_field_type~  s   r   )ipv4ipv6c                 C   s   t | jd S r   )	ip_formatr   protocolr~   r!   r!   r"   <lambda>  s    r   z3.14.0c                 C   s   | du rdS t D ]\}}t| |r'|\}}t|r|| }t|r%|| } nqdS d}|tjkr5t| }t| }td|fd|fd|fg}|| t	|}|S )a?  Given a serializer or model ``Field``, return its basic type information - ``type``, ``format``, ``pattern``,
    and any applicable min/max limit values.

    :param field: the field instance
    :return: the extracted attributes as a dictionary, or ``None`` if the field type is not known
    :rtype: OrderedDict
    Nr@   r   r   )
basic_type_inforT   callabler   r   r   rW   r   updater   )ra   r   type_formatswagger_typer   r   rd   rM   r!   r!   r"   r     s0   


r   c                   C   s   t jrtjS tjS r   )rest_framework_settingsCOERCE_DECIMAL_TO_STRINGr   r   r   r!   r!   r!   r"   decimal_return_type  r$   r   c                 C   s   t | dd p| S )N
__origin__r+   )
hint_classr!   r!   r"   get_origin_type  s   r   c                 C   s   t | }t|ot||S r   )r   inspectisclass
issubclass)r   check_classorigin_typer!   r!   r"   hint_class_issubclass  s   r   get_argsc                 C   s   t | ddS )N__args__r!   r   )tpr!   r!   r"   typing_get_args  s   r   c                 C   sL   t | }|r
|d nt}t|pdtji}tdtjfdtjdi |fgS )Nr   r@   r3   r!   )r   r   get_basic_type_info_from_hintr   r   r   rX   Items)r   argschild_classchild_type_infor!   r!   r"   inspect_collection_hint_class  s   r   c                 C   s   t | }|tju r| jS d S r   )r   typingUnionr   )r   r   r!   r!   r"   _get_union_types  s   
r   c                 C   s   t | }|r#t|dkr!td|d r!t|d }|rd|d< |S dS tD ]*\}}t| |rOt|r8||   S |\}}t|rC| }td|fd|fg  S q%dS )	a[  Given a class (eg from a SerializerMethodField's return type hint,
    return its basic type information - ``type``, ``format``, ``pattern``,
    and any applicable min/max limit values.

    :param hint_class: the class
    :return: the extracted attributes as a dictionary, or ``None`` if the field type is not known
    :rtype: OrderedDict
    r   Nr   r   Tz
x-nullabler@   r   )r   lenrT   r   hinting_type_infor   r   r   )r   union_typesrM   r   infor   r   r!   r!   r"   r     s*   	

r   c                   @   r   )SerializerMethodFieldInspectorzProvides conversion for SerializerMethodField, optionally using information from the swagger_serializer_method
    decorator.
    c                 K   sD  t |tjstS t|j|jd }|d u rtS t|dd }|re|j}|d u r+t|dd }|d u r2|j}|j	}|d u r?t|dd }t
|rS||dd}	|jd	i |	}n	||_||_	d|_| j|||ddS t|j}
t
|
syt|
dry|
jd }
t
|
rt|
t
jst|
}|d ur| j|||fi |\}}|d	i |S tS )
N_swagger_serializer	help_textlabelT)r   r   r(   )r(   r   r   r!   )rT   r	   SerializerMethodFieldr   r+   r}   method_namer   rm   r   r   r   r   r(   r   inspect_signaturereturn_annotationr<   r   r   _emptyr   rS   )r   ra   rb   rQ   rc   methodr    descriptionr   serializer_kwargsr   	type_inforP   rO   r!   r!   r"   rj   >  sL   



z6SerializerMethodFieldInspector.field_to_swagger_objectNr   r!   r!   r!   r"   r   9      r   c                   @   r   )SimpleFieldInspectorzProvides conversions for fields which can be described using just ``type``, ``format``, ``pattern``
    and min/max validators.
    c                 K   s<   t |}|d u r
tS | j|||fi |\}}|di |S )Nr!   )r   r   rS   )r   ra   rb   rQ   rc   r   rP   rO   r!   r!   r"   rj   |  s
   z,SimpleFieldInspector.field_to_swagger_objectNr   r!   r!   r!   r"   r   w  r   r   c                   @   r   )ChoiceFieldInspectorzEProvides conversions for ``ChoiceField`` and ``MultipleChoiceField``.c                 K   sr  | j |||fi |\}}t|tjrtj}g }|j D ]}	t|tjr.t	||	gd }	nt	||	}	|
|	 qt|}
t|
tjrmtt|
dd}t||jpS|jj}t|dd r^|j}|rlt|}|rl|d|}ndd |D }t|dkrttt|}|r|d|}t|tjr|tj|||d	d
}|tjkr|d tjtjfv rd|_|S |||d	}|S tS )Nr   r:   rp   
base_fieldr@   c                 S   s   h | ]}t |qS r!   r@   )r.   vr!   r!   r"   	<setcomp>  s    z?ChoiceFieldInspector.field_to_swagger_object.<locals>.<setcomp>r   )r@   enumr?   inmulti)rS   rT   r	   ChoiceFieldr   r   choiceskeysMultipleChoiceFieldr   rF   r   ModelSerializerr+   rq   r   r}   r   r   r   r   r   nextiterrX   r,   IN_FORMIN_QUERYcollection_formatr   )r   ra   rb   rQ   rc   rP   rO   	enum_typeenum_valueschoicer    rp   rs   
model_typeenum_value_typesvalues_typerM   r!   r!   r"   rj     sP   

z,ChoiceFieldInspector.field_to_swagger_objectNr   r!   r!   r!   r"   r     r   r   c                   @   r   )FileFieldInspectorz*Provides conversions for ``FileField``\ s.c           
      K   s   | j |||fi |\}}t|tjrHtd}|tjkr0|tjdd}t|dt	j
r.tj|_|S |tjkrF|tjd}	|	d tjkrD||	S |tS )NzFFileField is supported only in a formData Parameter or response SchemaT)r@   r(   use_urlr  r  )rS   rT   r	   	FileFieldr   r   r   r   r+   r   UPLOADED_FILES_USE_URLr   r   r,   	TYPE_FILEr  r   )
r   ra   rb   rQ   rc   rP   rO   errrM   paramr!   r!   r"   rj     s   

z*FileFieldInspector.field_to_swagger_objectNr   r!   r!   r!   r"   r    r   r  c                   @   r   )DictFieldInspectorz&Provides conversion for ``DictField``.c                 K   sR   | j |||fi |\}}t|tjr'|tjkr'| |j||}|tj|dS t	S )N)r@   additional_properties)
rS   rT   r	   	DictFieldr   r   r   rJ   rG   r   )r   ra   rb   rQ   rc   rP   rO   rL   r!   r!   r"   rj     s   z*DictFieldInspector.field_to_swagger_objectNr   r!   r!   r!   r"   r    r   r  c                   @   r   )HiddenFieldInspectorzHide ``HiddenField``.c                 K   s   t |tjrd S tS r   )rT   r	   HiddenFieldr   )r   ra   rb   rQ   rc   r!   r!   r"   rj     s   z,HiddenFieldInspector.field_to_swagger_objectNr   r!   r!   r!   r"   r!    r   r!  c                   @   r   )JSONFieldInspectorz&Provides conversion for ``JSONField``.c                 K   s@   | j |||fi |\}}t|tjr|tjkr|tjdS tS Nr  )rS   rT   r	   	JSONFieldr   r   rG   r   r   ra   rb   rQ   rc   rP   rO   r!   r!   r"   rj     s   z*JSONFieldInspector.field_to_swagger_objectNr   r!   r!   r!   r"   r#    r   r#  c                   @   r   )StringDefaultFieldInspectorzRFor otherwise unhandled fields, return them as plain :data:`.TYPE_STRING` objects.c                 K   s&   | j |||fi |\}}|tjdS r$  )rS   r   r   r&  r!   r!   r"   rj     s   z3StringDefaultFieldInspector.field_to_swagger_objectNr   r!   r!   r!   r"   r'    r   r'  )CamelCaseJSONParser)CamelCaseJSONRenderercamelizec                 C   s   | S r   r!   )datar!   r!   r"   r*    r9   r*  c                   @   sD   e Zd ZdZdd Zdd Zdd Zererdd	 Z	dS d
d	 Z	dS )CamelCaseJSONFilterzSConverts property names to camelCase if ``djangorestframework_camel_case`` is used.c                 C   s   t tt|diS )zHack to force ``djangorestframework_camel_case`` to camelize a plain string.

        :param str s: the string
        :return: camelized string
        :rtype: str
        r   )r  r  r*  )r   sr!   r!   r"   camelize_string  s   z#CamelCaseJSONFilter.camelize_stringc                    sX   t |di r(t fdd|j D |_t |dg r* fdd|jD |_dS dS dS )zRecursively camelize property names for the given schema using ``djangorestframework_camel_case``.
        The target schema object must be modified in-place.

        :param openapi.Schema schema: the :class:`.Schema` object
        rB   c                 3   s6    | ]\}}  | t| jp|fV  qd S r   )r.  camelize_schemar   resolve_refr[   )r.   r/   valr   r!   r"   	<genexpr>%  s
     
z6CamelCaseJSONFilter.camelize_schema.<locals>.<genexpr>rC   c                    s   g | ]}  |qS r!   )r.  )r.   pr2  r!   r"   r2   +  s    z7CamelCaseJSONFilter.camelize_schema.<locals>.<listcomp>N)r+   r   rB   r3   rC   )r   schemar!   r2  r"   r/    s   
z#CamelCaseJSONFilter.camelize_schemac                 K   s2   t |tjjr|  rt|| j}| | |S r   )rT   r   r   OR_REFis_camel_caser0  r[   r/  )r   rM   r   objrc   r5  r!   r!   r"   process_result-  s   
z"CamelCaseJSONFilter.process_resultc                 C   s,   t dd |  D pt dd |  D S )Nc                 s       | ]}t |tV  qd S r   )r   r(  )r.   parserr!   r!   r"   r3  7      z4CamelCaseJSONFilter.is_camel_case.<locals>.<genexpr>c                 s   r:  r   )r   r)  )r.   rendererr!   r!   r"   r3  8  r<  )anyget_parser_classesget_renderer_classesr2  r!   r!   r"   r7  5  s   z!CamelCaseJSONFilter.is_camel_casec                 C   s   dS )NFr!   r2  r!   r!   r"   r7  ;  r9   N)
rZ   rk   rl   rm   r.  r/  r9  r(  r)  r7  r!   r!   r!   r"   r,    s    	r,  )RecursiveFieldc                   @   rn   )RecursiveFieldInspectorbProvides conversion for RecursiveField (https://github.com/heywbj/django-rest-framework-recursive)N)rZ   rk   rl   rm   r!   r!   r!   r"   rB  B  s    rB  c                   @   r   )rB  rC  c           	      K   s   t |trQ|tjkrQ|du sJ d|j}t |jtjr|j}t|}|d us1J dt	t
| | jtj}tj||dd}t |jtjrOtjtj|d}|S tS )NTzECan not create schema for RecursiveField when use_references is Falsez.Can't create RecursiveField schema for inline )ignore_unresolvedr?   )rT   rA  r   r   proxiedr	   rU   rJ   r   r   r@   r[   r\   r]   r`   r   rX   r   )	r   ra   rb   rQ   rc   rE  r;   re   refr!   r!   r"   rj   I  s   z/RecursiveFieldInspector.field_to_swagger_objectNr   r!   r!   r!   r"   rB  F  r   r   )datetimer   loggingoperatoruuid
contextlibr   collectionsr   decimalr   r   r   pkg_resourcesr   django.corer   	django.dbr   	packagingr   rest_frameworkr	   rest_framework.settingsr
   r   baser   r   r   r   r   r   errorsr   utilsr   r   r   r   r   get_distributiondrf_version	getLoggerrZ   r   r   ro   rt   rq   r|   r   r   r   r   r   IntegerField
FloatFieldr   numeric_fieldsMinValueValidator__gt__MaxValueValidator__lt__MinLengthValidator	CharFieldMaxLengthValidatorrV   rU   r   rW   r   	AutoFieldTYPE_INTEGERBinaryFieldr   FORMAT_BINARYBooleanFieldTYPE_BOOLEANDateTimeFieldFORMAT_DATETIME	DateFieldFORMAT_DATEFORMAT_DECIMALDurationFieldr   IPAddressFieldFORMAT_IPV4GenericIPAddressFieldFORMAT_IPV6	SlugFieldFORMAT_SLUG	TextField	TimeField	UUIDFieldFORMAT_UUIDmodel_field_to_basic_typer   
EmailFieldFORMAT_EMAILURLFieldr   
RegexField
ModelFieldserializer_field_to_basic_typeparserF   NullBooleanFieldr   r   r   r   r   rE   intr   r   dictrG   UUIDdater   r<   r   r   r   SequenceAbstractSetr   r   r   r   r   r  r  r!  r#  r'  %djangorestframework_camel_case.parserr(  %djangorestframework_camel_case.renderr)  r*  ImportErrorr,  rest_framework_recursive.fieldsrA  rB  r!   r!   r!   r"   <module>   s    
t
:#%&'>9
	-