
    =!gf                        d dl Z d dlZd dlZd dlmZ d dlmZmZ d dl	Z	d dl
mZ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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$ d
dlm%Z%m&Z& d
dl'm(Z(m)Z)m*Z*  ej+        e,          Z- ej.        d          Z/d Z0d Z1 G d de          Z G d d          Z2dS )    N)OrderedDictdefaultdict)
URLPatternURLResolver)
versioning)SchemaGenerator)EndpointEnumerator)endpoint_orderingget_pk_name)get_pk_descriptionis_list_view)api_settings   )openapi)swagger_settings)SwaggerGenerationError)get_basic_type_infoget_queryset_fieldget_queryset_from_view)ReferenceResolverSwaggerDict)force_real_strget_consumesget_producesz{(?P<parameter>\w+)}c                     d | D             }t          |          }t          |          }|}t          |          D ]\  }}|||         k    r|d |         } ndd                    |          z   S )Nc                 ^    g | ]*}|                     d                               d           +S )/)stripsplit).0paths     N/var/www/html/nourish/venv/lib/python3.11/site-packages/drf_yasg/generators.py
<listcomp>zcommon_path.<locals>.<listcomp>   s0    @@@$4::c??((--@@@    r   )minmax	enumeratejoin)pathssplit_pathss1s2commonics          r"   common_pathr0      s    @@%@@@K	[		B	[		BF"  11::VFE  &!!!!r$   c                 
    | dvS )N>   listcreateupdatedestroyretrievepartial_update )actions    r"   is_custom_actionr:   (   s       r$   c                   P     e Zd Zd
 fd	Z fdZd fd	Zd ZddZd Zd	 Z	 xZ
S )r	   Nc                 h    t          t          |                               ||           || _        d S N)superr	   __init__request)selfpatternsurlconfr@   	__class__s       r"   r?   zEndpointEnumerator.__init__/   s/     $''007CCCr$   c                     |                     d          rt                              d|           |                     t	          t
          |                               |                    S )N)zEurl pattern does not end in $ ('%s') - unexpected things might happen)endswithloggerwarningunescape_pathr>   r	   get_path_from_regex)rA   
path_regexrD   s     r"   rK   z&EndpointEnumerator.get_path_from_regex3   s^    s## 	pNNbdnooo!!%(:D"A"A"U"UV`"a"abbbr$    c                 l   t          t          |                               ||          sdS t          | j        dd           }t          |j        dd           }|5t          |t          j                  r|r||	                    d          vrdS t          |j        dt                                dS dS )NFversionversioning_class:swagger_schemaT)r>   r	   should_include_endpointgetattrr@   cls
issubclassr   NamespaceVersioningr   object)	rA   r!   callbackapp_name	namespaceurl_namerO   rP   rD   s	           r"   rS   z*EndpointEnumerator.should_include_endpoint8   s    '..FFtXVV 	5$,	488"8<1CTJJ'J7GIg,h,h' 7)//#*>*>>>u8<!1688<<D5tr$   c                 J   t          |j        dd          }|t          |t          j                  rpt          | j        dd          }|rXt          |dd          }d|z  }||vr(t                              d|j        d|d|           |                    ||          }|S )	a"  If ``request.version`` is not ``None`` and `callback` uses ``URLPathVersioning``, this function replaces
        the ``version`` parameter in `path` with the actual version.

        :param str path: the templated path
        :param callback: the view callback
        :rtype: str
        rP   NrO   version_param{%s}zview z  uses URLPathVersioning but URL z has no param )	rT   rU   rV   r   URLPathVersioningr@   rH   inforeplace)rA   r!   rY   rP   rO   r^   s         r"   replace_versionz"EndpointEnumerator.replace_versionG   s     #8<1CTJJ'J7GIe,f,f'dlIt<<G < '(8/9 U U & 6 ,,KKK#+<<<}}!F G G G||M7;;r$   c           	         || j         }g }|t                      }|D ]}|t          |j                  z   }t	          |t
                    r	 |                     |          }	|j        }
|j        }| 	                    |	|
|pd|pd|          rb| 
                    |	|
          }	|	|v r|                    |	           |                     |
          D ]}|	||
f}|                    |           # t          $ r t                              dd           Y w xY wt	          |t"                    r\|                     |j        ||r|d|j        n|j        |r|d|j        n|j        |          }|                    |           pt                              d                    t1          |                               t3          |t4          	          }|S )
z
        Return a list of all available API endpoints by inspecting the URL conf.

        Copied entirely from super.
        NrM   zfailed to enumerate viewT)exc_inforQ   )rB   prefixrZ   r[   ignored_endpointszunknown pattern type {}key)rB   setstrpattern
isinstancer   rK   rY   namerS   rc   addget_allowed_methodsappend	ExceptionrH   rI   r   get_api_endpointsurl_patternsrZ   r[   extendformattypesortedr
   )rA   rB   rf   rZ   r[   rg   api_endpointsrl   rL   r!   rY   r\   methodendpointnested_endpointss                  r"   rs   z$EndpointEnumerator.get_api_endpoints\   sA    }H$ #  	P  	PG#go"6"66J':.. PN33J??D&/H&|H33D(HNPRT]Tcacemnn ;#33D(CC  #444$)--d333&*&>&>x&H&H ; ;F(,fh'?H)00::::  N N NNN#=NMMMMMN G[11 
P#'#9#9$1%GOe'2B2BCCU\UeJSjG4E4EFFY`Yj&7 $: $ $  $$%566668??WNNOOOO}2CDDDs   AC1)AC11&DDc                 .    t          j        dd|          S )zzUnescape all backslash escapes from `s`.

        :param str s: string with backslash escapes
        :rtype: str
        z\\(.)z\1)resub)rA   ss     r"   unescapezEndpointEnumerator.unescape   s     vhq)))r$   c                 F   d}|rt                               |          }|s||                     |          z  }ng||                     |d|                                                   z  }||                                z  }||                                d         }||S )a  Remove backslashes escapes from all path components outside {parameters}. This is needed because
        ``simplify_regex`` does not handle this correctly.

        **NOTE:** this might destructively affect some url regex patterns that contain metacharacters (e.g. \w, \d)
        outside path parameter groups; if you are in this category, God help you

        :param str path: path possibly containing
        :return: the unescaped path
        :rtype: str
        rM   N)PATH_PARAMETER_REsearchr   startgroupend)rA   r!   
clean_pathmatchs       r"   rJ   z EndpointEnumerator.unescape_path   s     
 	&%,,T22E dmmD111
$--^ekkmm^(<===J%++--'J		%D  	& r$   )NNN)rM   rM   N)NrM   NNN)__name__
__module____qualname__r?   rK   rS   rc   rs   r   rJ   __classcell__)rD   s   @r"   r	   r	   .   s             c c c c c
       *1 1 1 1f* * *      r$   r	   c                       e Zd ZdZeZeZddddddZdd
Z	e
d             Zd Zd ZddZddZd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd	S )OpenAPISchemaGeneratorz
    This class iterates over all registered API endpoints and returns an appropriate OpenAPI 2.0 compliant schema.
    Method implementations shamelessly stolen and adapted from rest-framework ``SchemaGenerator``.
    r6   r3   r4   r7   r5   )getpostputpatchdeleterM   Nc                    t          |j        ||                    dd          ||          | _        || _        || _        g | _        g | _        t          j	        | _
        |t          j        t          j        }|rgt          j        |          }|j        dvs|j        st!          d          |j        rt$                              d|z             dS || j        _        dS dS )a  

        :param openapi.Info info: information about the API
        :param str version: API version string; if omitted, `info.default_version` will be used
        :param str url: API scheme, host and port; if ``None`` is passed and ``DEFAULT_API_URL`` is not set, the url
            will be inferred from the request made against the schema view, so you should generally not need to set
            this parameter explicitly; if the empty string is passed, no host and scheme will be emitted

            If `url` is not ``None`` or the empty string, it must be a scheme-absolute uri (i.e. starting with http://
            or https://), and any path component is ignored;

            See also: :ref:`documentation on base URL construction <custom-spec-base-url>`
        :param patterns: if given, only these patterns will be enumerated for inclusion in the API spec
        :param urlconf: if patterns is not given, use this urlconf to enumerate patterns;
            if not given, the default urlconf is used
        descriptionrM   N)httphttpsz%`url` must be an absolute HTTP(S) urlzKpath component of api base URL %s is ignored; use FORCE_SCRIPT_NAME instead)r   titler   _genra   rO   consumesproducesr   SCHEMA_COERCE_METHOD_NAMEScoerce_method_namesr   DEFAULT_API_URLurlparseschemenetlocr   r!   rH   rI   url)rA   ra   rO   r   rB   rC   
parsed_urls          r"   r?   zOpenAPISchemaGenerator.__init__   s    " $DJTXXmR5P5PRZ\cdd		#/#J ;+;G"2C 	$!*3//J (999AR9,-TUUU $lorrsssss #		$ 	$r$   c                     | j         j        S r=   )r   r   )rA   s    r"   r   zOpenAPISchemaGenerator.url   s    y}r$   c                 L    t           j        }|t          j        |i           }|S )a  Get the security schemes for this API. This determines what is usable in security requirements,
        and helps clients configure their authorization credentials.

        :return: the security schemes usable with this API
        :rtype: dict[str,dict] or None
        )r   SECURITY_DEFINITIONSr   	_as_odict)rA   security_definitionss     r"   get_security_definitionsz/OpenAPISchemaGenerator.get_security_definitions   s-      0D+#.#89Mr#R#R ##r$   c                 ~    t           j        }|d |D             }d |D             }t          |t                    }|S )aj  Get the base (global) security requirements of the API. This is never called if
        :meth:`.get_security_definitions` returns `None`.

        :param security_definitions: security definitions as returned by :meth:`.get_security_definitions`
        :return: the security schemes accepted by default
        :rtype: list[dict[str,list[str]]] or None
        Nc                     g | ]}|g iS r8   r8   )r    security_schemes     r"   r#   zDOpenAPISchemaGenerator.get_security_requirements.<locals>.<listcomp>   s    $g$g$gor%:$g$g$gr$   c                 8    g | ]}t          j        |i           S r8   )r   r   )r    srs     r"   r#   zDOpenAPISchemaGenerator.get_security_requirements.<locals>.<listcomp>  s%     _ _ _2!6r2!>!> _ _ _r$   rh   )r   SECURITY_REQUIREMENTSrx   r2   )rA   r   security_requirementss      r"   get_security_requirementsz0OpenAPISchemaGenerator.get_security_requirements   sW     !1 F ($g$gRf$g$g$g! _ _I^ _ _ _ &'<$ G G G$$r$   Fc                 6   |                      |          }|                     t          j        d          }t	          t
          j                  | _        t          t
          j	                  | _
        |                     ||||          \  }}|                                 }|r|                     |          }nd}| j        }	|	||                                }	t          j        d| j        || j        pd| j
        pd|||	|| j        d	t'          |          S )a  Generate a :class:`.Swagger` object representing the API schema.

        :param request: the request used for filtering accessible endpoints and finding the spec URI
        :type request: rest_framework.request.Request or None
        :param bool public: if True, all endpoints are included regardless of access through `request`

        :return: the generated Swagger specification
        :rtype: openapi.Swagger
        T)
force_initN)	ra   r)   r   r   r   security_url_prefix_versionr8   )get_endpointsreference_resolver_classr   SCHEMA_DEFINITIONSr   r   DEFAULT_PARSER_CLASSESr   r   DEFAULT_RENDERER_CLASSESr   	get_pathsr   r   r   build_absolute_uriSwaggerra   rO   dict)
rA   r@   public	endpoints
componentsr)   rf   r   r   r   s
             r"   
get_schemaz!OpenAPISchemaGenerator.get_schema  s)    &&w//	2273MZ^2__
$\%HII$\%JKKy*gvNNv#<<>> 	)$($B$BCW$X$X!!$(!h;7.,,..C 
%$-2G4RVR_Rgcg!5@Uft|
 
 @DJ?O?O
 
 	
r$   c                    | j                             |||          }t          |dd          }|C|                                D ].\  }}t          ||d          }|t	          |j        d|           /t	          |dd           |S )aP  Create a view instance from a view callback as registered in urlpatterns.

        :param callback: view callback registered in urlpatterns
        :param str method: HTTP method
        :param request: request to bind to the view
        :type request: rest_framework.request.Request or None
        :return: the view instance
        _swagger_auto_schemaNswagger_fake_viewT)r   create_viewrT   itemssetattr__func__)rA   rY   rz   r@   view	overrides_view_methods           r"   r   z"OpenAPISchemaGenerator.create_view&  s     y$$Xvw??H&<dCC	 &__.. U U	%dFD99*K02H)TTT)4000r$   c                     d|vr|S t          t          |          dd          }|rt          |          }nd}|                    dd|z            S )aK  Coerce {pk} path arguments into the name of the model field, where possible. This is cleaner for an
        external representation (i.e. "this is an identifier", not "this is a database primary key").

        :param str path: the path
        :param rest_framework.views.APIView view: associated view
        :rtype: str
        z{pk}modelNidr_   )rT   r   r   rb   )rA   r!   r   r   
field_names        r"   coerce_pathz"OpenAPISchemaGenerator.coerce_path;  sc     K.t44gtDD 	$U++JJJ||FFZ$7888r$   c                   	 |                      | j        j        | j        j        |          }|                                }t          t                    }i 	|D ]Z\  }}}|                     |||          }|                     ||          }||         	                    ||f           |j
        	|<   [	fd|                                D             S )a  Iterate over all the registered endpoints in the API and return a fake view with the right parameters.

        :param request: request to bind to the endpoint views
        :type request: rest_framework.request.Request or None
        :return: {path: (view_class, list[(http_method, view_instance)])
        :rtype: dict[str,(type,list[(str,rest_framework.views.APIView)])]
        )r@   c                 ,    i | ]\  }}||         |fS r8   r8   )r    r!   methodsview_clss      r"   
<dictcomp>z8OpenAPISchemaGenerator.get_endpoints.<locals>.<dictcomp>_  s(    XXXMD'x~w/XXXr$   )endpoint_enumerator_classr   rB   rC   rs   r   r2   r   r   rq   rU   r   )
rA   r@   
enumeratorr   
view_pathsr!   rz   rY   r   r   s
            @r"   r   z$OpenAPISchemaGenerator.get_endpointsM  s     33DI4F	HYcj3kk
0022	 &&
&/ 	* 	*"D&(##Hfg>>D##D$//Dt##VTN333%\HTNNXXXXZEUEUEWEWXXXXr$   c                 ,   t          |d          r|j        }n3t          |||          rd}n| j        |                                         }d |                    d                              d          D             }t          |          rmd |j        D             }t          |          dk    r;| j        |                                         }|| j
        v r| j
        |         }||gz   S |dd         |gz   S || j
        v r| j
        |         }||gz   S )	aX  Return a list of keys that should be used to group an operation within the specification. ::

          /users/                   ("users", "list"), ("users", "create")
          /users/{pk}/              ("users", "read"), ("users", "update"), ("users", "delete")
          /users/enabled/           ("users", "enabled")  # custom viewset list action
          /users/{pk}/star/         ("users", "star")     # custom viewset detail action
          /users/{pk}/groups/       ("users", "groups", "list"), ("users", "groups", "create")
          /users/{pk}/groups/{pk}/  ("users", "groups", "read"), ("users", "groups", "update")

        :param str subpath: path to the operation with any common prefix/base path removed
        :param str method: HTTP method
        :param view: the view associated with the operation
        :rtype: list[str]
        r9   r2   c                     g | ]}d |v|	S ){r8   )r    	components     r"   r#   z=OpenAPISchemaGenerator.get_operation_keys.<locals>.<listcomp>z  s-     !
 !
 !
#)## ###r$   r   c                     h | ]
}|d k    |S )headr8   )r    rz   s     r"   	<setcomp>z<OpenAPISchemaGenerator.get_operation_keys.<locals>.<setcomp>  s)       !&8H8H8H8H8Hr$   r   N)hasattrr9   r   default_mappinglowerr   r   r:   
action_maplenr   )rA   subpathrz   r   r9   named_path_componentsmapped_methodss          r"   get_operation_keysz)OpenAPISchemaGenerator.get_operation_keysa  sN    4"" 	>[FF GVT22 >-fllnn=!
 !
}}S!!'',,!
 !
 !
 F## 	= %)_  N >""Q&&-fllnn=T555!5f=F,x77,SbS1VH<<T----f5F %x//r$   c                 <   g }|D ]}|                     d                              d          }g }|D ]}d|v r n|                    |           d                    |dd                   }|s dS |                    d|z   dz              t	          |          S )a  
        Given a list of all paths, return the common prefix which should be
        discounted when generating a schema structure.

        This will be the longest common string that does not include that last
        component of the URL, or the last component before a path parameter.

        For example: ::

            /api/v1/users/
            /api/v1/users/{pk}/

        The path prefix is ``/api/v1/``.

        :param list[str] paths: list of paths
        :rtype: str
        r   r   Nr   )r   r   rq   r(   r0   )rA   r)   prefixesr!   r   initial_componentsr   rf   s           r"   determine_path_prefixz,OpenAPISchemaGenerator.determine_path_prefix  s    $  	0 	0DC..s33J!#' 5 5	)##E")))4444XX0"566F  ssOOC&L3.////8$$$r$   c                 >    |p| j                             |||          S )a  Check if a given endpoint should be included in the resulting schema.

        :param str path: request path
        :param str method: http request method
        :param view: instantiated view callback
        :param bool public: if True, all endpoints are included regardless of access through `request`
        :returns: true if the view should be excluded
        :rtype: bool
        )r   has_view_permissions)rA   r!   rz   r   r   s        r"   rS   z.OpenAPISchemaGenerator.should_include_endpoint  s#     K77fdKKKr$   c                 ,    t          j        |          S )zConstruct the Swagger Paths object.

        :param OrderedDict[str,openapi.PathItem] paths: mapping of paths to :class:`.PathItem` objects
        :returns: the :class:`.Paths` object
        :rtype: openapi.Paths
        r)   )r   Paths)rA   r)   s     r"   get_paths_objectz'OpenAPISchemaGenerator.get_paths_object  s     }5))))r$   c           
         |st          j        i           dfS |                     t          |                                                    pd}d|vs
J d            t                      }t          |                                          D ]\  }\  }}	i }
|	D ]Q\  }}|                     ||||          s| 	                    ||||||          }|||
|
                                <   R|
rK|t          |          d         }|                    d          sd|z   }|                     |||
          ||<   |                     |          |fS )a+  Generate the Swagger Paths for the API from the given endpoints.

        :param dict endpoints: endpoints as returned by get_endpoints
        :param ReferenceResolver components: resolver/container for Swagger References
        :param Request request: the request made against the schema view; can be None
        :param bool public: if True, all endpoints are included regardless of access through `request`
        :returns: the :class:`.Paths` object and the longest common path prefix, as a 2-tuple
        :rtype: tuple[openapi.Paths,str]
        r   rM   r   z,base path cannot be templated in swagger 2.0Nr   )r   r   r   r2   keysr   rx   r   rS   get_operationr   r   
startswithget_path_itemr   )rA   r   r   r@   r   rf   r)   r!   r   r   
operationsrz   r   	operationpath_suffixs                  r"   r   z OpenAPISchemaGenerator.get_paths  s     	/=r***B..++D1A1A,B,BCCIr&   "P   )/	0A0A)B)B 	T 	T%D%8WJ ' ; ;33D&$OO  ..tT66:W^__	(1:Jv||~~. T #3v;;<<0"--c22 4"%"3K%)%7%7h
%S%Sk"$$U++V33r$   c           	         |                      |t          |          d         ||          }|                     ||          }t          j        }	t          |d|	          }	|                    d|	          }	|	dS  |	|||||||          }
|
                    |          }|dS d|v r,t          |j	                  t          | j	                  k    r|`	d|v r,t          |j
                  t          | j
                  k    r|`
|S )a  Get an :class:`.Operation` for the given API endpoint (path, method). This method delegates to
        :meth:`~.inspectors.ViewInspector.get_operation` of a :class:`~.inspectors.ViewInspector` determined
        according to settings and :func:`@swagger_auto_schema <.swagger_auto_schema>` overrides.

        :param view: the view associated with this endpoint
        :param str path: the path component of the operation URL
        :param str prefix: common path prefix among all endpoints
        :param str method: the http method of the operation
        :param openapi.ReferenceResolver components: referenceable components
        :param Request request: the request made against the schema view; can be None
        :rtype: openapi.Operation
        NrR   auto_schemar   r   )r   r   get_overridesr   DEFAULT_AUTO_SCHEMA_CLASSrT   r   r   rj   r   r   )rA   r   r!   rf   rz   r   r@   operation_keysr   view_inspector_clsview_inspectorr   s               r"   r   z$OpenAPISchemaGenerator.get_operation  s     00c&kkll1CVTRR&&tV44	 .G$T+;=OPP&]]=:LMM%4++D$
GU^`noo"00@@	4""s9+='>'>#dmBTBT'T'T"""s9+='>'>#dmBTBT'T'T"r$   c                 T    |                      ||          }t          j        dd|i|S )a  Get a :class:`.PathItem` object that describes the parameters and operations related to a single path in the
        API.

        :param str path: the path
        :param type view_cls: the view that was bound to this path in urlpatterns
        :param dict[str,openapi.Operation] operations: operations defined on this path, keyed by lowercase HTTP method
        :rtype: openapi.PathItem
        
parametersr8   )get_path_parametersr   PathItem)rA   r!   r   r   path_parameterss        r"   r   z$OpenAPISchemaGenerator.get_path_item  s5     224BBII?IjIIIr$   c                     |                                 }t          |d|          }t          ||d          }t          |di           }||v r||         }t          j        |          S )a"  Get overrides specified for a given operation.

        :param view: the view associated with the operation
        :param str method: HTTP method
        :return: a dictionary containing any overrides set by :func:`@swagger_auto_schema <.swagger_auto_schema>`
        :rtype: dict
        r9   Nr   )r   rT   copydeepcopy)rA   r   rz   r9   action_methodr   s         r"   r  z$OpenAPISchemaGenerator.get_overrides"  sj     x00fd33M+A2FF	Y!&)I}Y'''r$   c           	      f   g }t          |          }t          j        |          D ]	}t          ||          \  }}t	          |          pdt
          j        i}t          |dd          |k    r>|d         t
          j        k    r(t          |d|                    dd                    |d<   |rt          |dd          r|j	        }	n&|r"t          |dd          rt          ||          }	nd}	t          j        d|t          |	          d	t
          j        d
|}
|                    |
           |S )a  Return a list of Parameter instances corresponding to any templated path variables.

        :param str path: templated request path
        :param type view_cls: the view class associated with the path
        :return: path parameters
        :rtype: list[openapi.Parameter]
        rw   lookup_fieldNlookup_value_regexrl   	help_textFprimary_keyT)rn   r   requiredin_r8   )r   uritemplate	variablesr   r   r   TYPE_STRINGrT   r   r  r   	Parameterr   IN_PATHrq   )rA   r!   r   r	  querysetvariabler   model_fieldattrsr   fields              r"   r
  z*OpenAPISchemaGenerator.get_path_parameters3  s_    
)(33#-d33 	% 	%H!3Hh!G!GE;'44UAT8UEx66(BBuV}X_XkGkGk#*85I599U^`dKeKe#f#fi  #w{KGG #)3 #mU!K!K #0DD"% *;77O	 
  E e$$$$r$   )rM   NNN)NFr=   )r   r   r   __doc__r	   r   r   r   r   r?   propertyr   r   r   r   r   r   r   r   r   rS   r   r   r   r   r  r
  r8   r$   r"   r   r      sr         !30 ! O"$ "$ "$ "$H   X$ $ $% % % 
 
 
 
@   *9 9 9$Y Y Y(10 10 10f %  %  %D
L 
L 
L* * *#4 #4 #4J$ $ $L
J 
J 
J( ( ("! ! ! ! !r$   r   )3r  loggingr~   urllib.parseparser   collectionsr   r   r  django.urlsr   r   rest_frameworkr   rest_framework.schemas.openapir   !rest_framework.schemas.generatorsr	   _EndpointEnumeratorr
   r   rest_framework.schemas.utilsr   r   rest_framework.settingsr   rM   r   app_settingsr   errorsr   inspectors.fieldr   r   r   r   r   utilsr   r   r   	getLoggerr   rH   compiler   r0   r:   r   r8   r$   r"   <module>r5     s#     				       0 0 0 0 0 0 0 0     / / / / / / / / % % % % % % : : : : : : W W W W W W L L L L L L L L I I I I I I I I 0 0 0 0 0 0       * * * * * * * * * * * * ] ] ] ] ] ] ] ] ] ] 3 3 3 3 3 3 3 3 = = = = = = = = = =		8	$	$BJ677 	" 	" 	"      ,   Dd d d d d d d d d dr$   