
    vj`                        d dl Z d dl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mZmZmZmZ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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+ d dl,m-Z-m.Z.m/Z/ d dl0m1Z1m2Z2 d dl3m4Z4m5Z5 d dl6m7Z7 d dl8m9Z9 ddl:m;Z; ddl<m=Z=m>Z>  e5            rd dl?Z? e4            r	 ed         Z@eeAeBeddf         ZCeeAedf         ZD e7            ZE G d de          ZF G d deF          ZGd  ZHdS )!    N)ABCabstractmethod)partial)Pool)Lock)AnyDict	GeneratorListMappingOptionalUnion)version)Model)	MsDataset)TASK_OUTPUTSModelOutputBase)TASK_INPUTScheck_input_type)Preprocessor)Config)
FrameworksInvoke	ModelFile)create_devicedevice_placementverify_device)read_configsnapshot_download)is_tf_availableis_torch_available)
get_logger)compile_model   )check_model_from_owner_group   )is_modelis_official_hub_path)ztorch.Tensorz	tf.TensorzImage.Imageznumpy.ndarrayztorch.nn.Modulec            
          e Zd ZdZd Zdee         fdZ	 	 	 	 	 	 d!ded	e	eee         f         d
e	e
ee
         f         defdZ	 	 d"dee         dee         fdZd ZdefdZde	eee         f         de	eeef         ef         fdZd ZdefdZd Zdedeeef         fdZd Zdee         deeef         fdZd Zd Zdedeeef         fdZdeeef         deeef         fdZdeeef         deeef         fd ZdS )#PipelinezPipeline base.
    c                 ~   | j         rd|d<   t          |t                    rt                              d|            t          |t                    rit          |          rZt                              d| d           t          |          r+t          j        |f| j	        dt          j        | j        d|n|S |S )NTtrust_remote_codezinitiate model from zinitiate model from location .)devicemodel_prefetched
invoked_by
device_map)r,   
isinstancestrloggerinfor(   r'   r   from_pretraineddevice_namer   PIPELINEr1   )selfmodelkwargss      i/lsinfo/ai/hellotax_ai/data_center/backend/venv/lib/python3.11/site-packages/modelscope/pipelines/base.pyinitiate_single_modelzPipeline.initiate_single_model0   s    ! 	/*.F&'eS!! 	8KK6u66777eS!! 	&:5&A&A 	KK@@@@AAA &e__85('!%!??     388 L    input_modelsc                 d    g }|D ]*}|                     |                     |                     +|S N)appendr=   )r9   r?   modelsr:   s       r<   initiate_multiple_modelsz!Pipeline.initiate_multiple_modelsB   s>    ! 	= 	=EMM$44U;;<<<<r>   NgpuTconfig_filer:   preprocessorr.   c                 `   ||dk    s
J d            || _         t          |           || _        |                    dd          | _        t          |t                    s! | j        |fi || _        | j        g| _	        n!d| _        | 
                    |          | _	        t          | j	                  dk    | _        |9t          j        |          | _        t           j                            |          }nI| j        sBt          | j        t&                    r| j        }n| j        j        }t+          |          | _        |!| j        st-          j        |          | _        n|| _        | j        s| j        r'| j	        d         r|                                 | _        nd| _        | j        t6          j        k    rt;          | j                  | _        d| _        tA                      | _!        || _"        |                    dd          | _#        |                    d	i           | _$        dS )
aH   Base class for pipeline.

        If config_file is provided, model and preprocessor will be
        instantiated from corresponding config. Otherwise, model
        and preprocessor will be constructed separately.

        Args:
            config_file(str, optional): Filepath to configuration file.
            model: (list of) Model name or model object
            preprocessor: (list of) Preprocessor object
            device (str): device str, should be either cpu, cuda, gpu, gpu:X or cuda:X
            auto_collate (bool): automatically to convert data to tensor or not.
            compile (bool, optional): Compile the model with torch 2.0, default False
            compile_options (dict, optional): The compile options if compile=True,
                default None to use the default params of 'TorchModel.compile'.
        NrE   z;`device` and `device_map` cannot be input at the same time!r,   Fr&   r   compilecompile_options)%r1   r   r7   getr,   r2   r   r=   r:   rC   rD   lenhas_multiple_modelsr   	from_filecfgospathdirnamer3   	model_dirr   r   r6   rG   _get_framework	frameworkr   torchr   r.   _model_preparer   _model_prepare_lock_auto_collate_compile_compile_options)	r9   rF   r:   rG   r.   auto_collater1   r;   rS   s	            r<   __init__zPipeline.__init__H   s   0 !U???$a???$f!!',?!G!G%&& 	?33EDDVDDDJ:,DKKDJ77>>DK#&t{#3#3a#7 "'44DH44II) 	.$*c** 1 J		 J0	"9--DH(@ , <Y G GD ,D: 	"$2 	"t{1~ 	"!0022DNN!DN>Z---'(899DK##'66 )

9e44 &

+<b A Ar>   info_strrS   c                 T    |pd}t          |          s| j        sJ |            dS dS )a%  Check trust_remote_code if the pipeline needs to import extra libs

        Args:
            info_str(str): The info showed to user if trust_remote_code is `False`.
            model_dir(`Optional[str]`): The local model directory. If is a trusted model, check remote code will pass.
        zThis pipeline requires `trust_remote_code` to be `True` because it needs to import extra libs or execute the code in the model repo, setting this to true means you trust the files in it.)rS   N)r%   r,   )r9   r^   rS   s      r<   check_trust_remote_codez Pipeline.check_trust_remote_code   sR      0/ 	 ,i@@@ 	4)33833)	4 	433r>   c                      j                             d            fd} j        s j        t          j        k    ro j        r5 j        D ]} ||            j        r fd j        D              _        n3 | j	                    j        rt           j	        fi  j         _	        d _         j                                          dS )zQ Place model on certain device for pytorch models before first inference
        iX  )timeoutc                 8   t          | t          j        j                  st	          | d          r| j        } t          | t          j        j                  sd S |                                  ddlm}  ||           r| 	                    j
                   d S d S )Nr:   r   )is_on_same_device)r2   rV   nnModulehasattrr:   evalmodelscope.utils.torch_utilsrd   tor.   )r:   rd   r9   s     r<   _prepare_singlez/Pipeline.prepare_model.<locals>._prepare_single   s    eUX_55 $'7;$ ;$ $eUX_55 JJLLLFFFFFF  '' &%%%%%& &r>   c                 4    g | ]}t          |fi j        S  )r#   r[   ).0mr9   s     r<   
<listcomp>z*Pipeline.prepare_model.<locals>.<listcomp>   s<     ' ' ' ! *!EEt/DEE' ' 'r>   TN)rX   acquirerW   rU   r   rV   rM   rC   rZ   r:   r#   r[   release)r9   rk   ro   s   `  r<   prepare_modelzPipeline.prepare_model   s'    	 (((555		& 		& 		& 		& 		& " 	'~!111+ L![ + +'****} ' ' ' '%)[' ' '
 $ODJ///} L%24: &L &L595J&L &L
"&D ((*****r>   returnc                 x   g | j         D ]n}t          |t                    r|}n|j        }t	          j        |t          j                  }t          j	        |          }
                    |j                   ot          fdD                       st                              d            d S d         S )Nc              3   0   K   | ]}|d          k    V  dS )r   Nrm   )rn   x
frameworkss     r<   	<genexpr>z*Pipeline._get_framework.<locals>.<genexpr>   s,      ::!1
1%::::::r>   z:got multiple models, but they are in different frameworks r   )rC   r2   r3   rS   ospjoinr   CONFIGURATIONr   rN   rB   rU   allr4   warning)r9   ro   rS   cfg_filerO   rx   s        @r<   rT   zPipeline._get_framework   s    
 	- 	-A!S!! (		K	x	9+BCCH"8,,Ccm,,,,::::z::::: 	NNYZYY   4!}r>   inputc                 Z   | j         s| j        r(| j        d         r| j        s|                                  |                    dd           } | j        d
i |\  }}}||d<   ||d<   ||d<   dt          |           j        v rt          |t                    r	d|i}d|d	<   t          |t                    r>|,g }|D ]&}	|                     | j        |	g|R i |           'nG | j        ||fi |}n7t          |t                    r | j        |g|R i |S  | j        |g|R i |}|S )Nr   
batch_sizepreprocess_paramsforward_paramspostprocess_paramsLLMPipelinemessagesT
is_messagerm   )r:   rM   rC   rW   rs   pop_sanitize_parameterstype__name__r2   listrB   _process_single_process_batchr   _process_iterator)
r9   r   argsr;   r   r   r   r   outputeles
             r<   __call__zPipeline.__call__   s   
 J 	%43 	%A 	%& %""$$$ ZZd33
@Y@Y A AA A=>+=&7"##1 '9#$ DJJ///Jud4K4K/'E#'F< eT"" 	B!  N NCMM"6$"6s"LT"L"L"LV"L"LMMMMN -,UJII&IIy)) 	B)4)%A$AAA&AAA *T)%A$AAA&AAFr>   c                     i i |fS )a  
        this method should sanitize the keyword args to preprocessor params,
        forward params and postprocess params on '__call__' or '_process_single' method
        considered to be a normal classmethod with default implementation / output

        Default Returns:
            Dict[str, str]:  preprocess_params = {}
            Dict[str, str]:  forward_params = {}
            Dict[str, str]:  postprocess_params = pipeline_parameters
        rm   )r9   pipeline_parameterss     r<   r   zPipeline._sanitize_parameters   s     2***r>   c              /   :   K   |D ]} | j         |g|R i |V  d S rA   )r   )r9   r   r   r;   r   s        r<   r   zPipeline._process_iterator  sK       	= 	=C&$&s<T<<<V<<<<<<	= 	=r>   c                 ,    t          || j                  S rA   )
collate_fnr.   )r9   datas     r<   _collate_fnzPipeline._collate_fn  s    $,,,r>   c                 l   |                     di           }|                     di           }|                     di           }|                     |            | j        |fi |}t          | j        | j                  5  | j        t          j        k    rVt          j                    5  | j	        r| 
                    |          } | j        |fi |}d d d            n# 1 swxY w Y   n | j        |fi |}d d d            n# 1 swxY w Y    | j        |fi |}|                     |           |S )Nr   r   r   )rK   _check_input
preprocessr   rU   r7   r   rV   no_gradrY   r   forwardpostprocess_check_output)r9   r   r   r;   r   r   r   outs           r<   r   zPipeline._process_single  s   "JJ':B??$4b99#ZZ(<bAA%   doe99'899dnd.>?? 	: 	:~!111]__ > >) 4"..s33&$,s==n==C> > > > > > > > > > > > > > >
 #dl399.99	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: ds99&8993
s6    )D)+C D C$	$D'C$	(DD
D
c                 \   i }|D ]L}|                                 D ]5\  }}|                    |g           }|                    |           |||<   6M|                                D ]E}t	          ||         d         t
          j                  rt          j        ||                   ||<   F|S )Nr   )itemsrK   rB   keysr2   rV   Tensorcat)r9   	data_list
batch_datasample_preprocessedkv
value_lists          r<   _batchzPipeline._batch"  s    
#, 	+ 	++1133 + +1'^^Ar22
!!!$$$ *
1+ "" 	9 	9A*Q-*EL99 9 %	*Q- 8 8
1r>   c                     |                     d          |                     d          }|                     d          }g }t          dt          |          |          D ]}t          ||z   t          |                    }||z
  }	 fd|||         D             }
t	           j         j                  5   j        t          j        k    rkt          j	                    5   
                    |
          } j        r                     |          }  j        |fi |}d d d            n# 1 swxY w Y   n# 
                    |
          }  j        |fi |}d d d            n# 1 swxY w Y   t          |	          D ]؊i }|                                D ]\  }}|t          |t           t"          f          rTt          |d         t          j                  r( t'          |          fd|D                       ||<   k|         ||<   w|dz            ||<     j        |fi |}                     |           |                    |           ِ|S )Nr   r   r   r   c                 ,    g | ]} j         |fi S rm   )r   )rn   ir   r9   s     r<   rp   z+Pipeline._process_batch.<locals>.<listcomp>9  s;     ! ! !<=77%677! ! !r>   c              3   2   K   | ]}|d z            V  dS )r&   Nrm   )rn   e	batch_idxs     r<   ry   z*Pipeline._process_batch.<locals>.<genexpr>O  sE       76 76() %&i	A&=$>76 76 76 76 76 76r>   r&   )rK   rangerL   minr   rU   r7   r   rV   r   r   rY   r   r   r   r2   tupler   r   r   r   r   rB   )r9   r   r   r;   r   r   output_listr   endreal_batch_sizepreprocessed_listbatched_outr   r   elementr   r   s   `              @@r<   r   zPipeline._process_batch.  su   "JJ':;;$455#ZZ(<== q#e**j11 #	( #	(Aa*nc%jj11C!AgO! ! ! ! !AFqu! ! ! "$.$2BCC 
N 
N>Z%555 E E&*kk2C&D&D- H*.*:*:;*G*GK&2dl; 'E 'E5C'E 'E	E E E E E E E E E E E E E E E #'++.?"@"@K".$,{"M"Mn"M"MK
N 
N 
N 
N 
N 
N 
N 
N 
N 
N 
N 
N 
N 
N 
N #?33 ( (	"-"3"3"5"5 F FJAw*%gt}== 	F)'!*elCC <)6g 76 76 76 76-476 76 76 *6 *6A
 *1);A%,Yy1}-D%ECF&d&sAA.@AA""3'''""3''''!($ s7   <)E,%A D1%E,1D55E,8D59'E,,E0	3E0	c                    | j         }|t          v rt          |         }t          |t                    rd }|D ]\}t          |t          t
          f          r%t          |          t          |          k    r|} nCt          |t                    r|} n]|d}|D ]
}|| dz  }t          |          |}t          |t                    rt          ||           d S t          |t
                    rGt          |t
                    s
J d            t          ||          D ]\  }}t          ||           d S t          |t                    rN|                                D ]7}t          |t                    r ||v rt          ||         ||                    8d S t          d|           t          | dd          s't                              d| d           d	| _        d S d S )
NzDinput data format for current pipeline should be one of following: 

zinput should be a tuplezinvalid input_type definition _input_has_warnedFtask z input definition is missingT)	group_keyr   r2   r   dictr   r   r3   
ValueErrorr   zipr   getattrr4   r~   r   )	r9   r   	task_name
input_typematched_typeterr_msg	input_eler   s	            r<   r   zPipeline._check_input]  sM   N	##$Y/J *d++ .##  A!%$77 77d5kk11+,L!E 2 $As++ '(  'eG' , ,a888+$W---!-J*c** P U33333J.. 
P!%//JJ1JJJ/$'
E$:$: 3 3LAy$Q	22223 3J-- P#** B BA!%.. B1::(AaAAAB B
 !!N*!N!NOOO2E:: 	*NNJ9JJJKKK%)D"""	* 	*r>   c                    | j         }|t          vr8t          | dd          s%t                              d| d           d| _        d S t          |         }g }t          |t          t          f          r|	                                n|}|D ]7}t          |t          t          f          r||vr|
                    |           8t          |          dk    rt          d| d| d	          d S )
N_output_has_warnedFr   z output keys are missingTr   zexpected output keys are z, those z are missing)r   r   r   r4   r~   r   r2   r   r   r   rB   rL   r   )r9   r   r   output_keysmissing_keysr   s         r<   r   zPipeline._check_output  s4    N	L((4!5u== /JyJJJKKK*.'F"9- *5,0/+B!D !D O

IN 	 	' 	'A!dO455 '!5..##A&&&|q   A A A&2A A A B B B ! r>   inputsc                     | j         
J d            t          | j         t                    r
J d             | j         |fi |S )z\ Provide default implementation based on preprocess_cfg and user can reimplement it
        Nz'preprocess method should be implementedzEdefault implementation does not support using multiple preprocessors.)rG   r2   r   )r9   r   r   s      r<   r   zPipeline.preprocess  sf      ,,.W,,,d/66 	T 	TS	T 	T6 t ==+<===r>   c                 b    | j         
J d            | j        r
J d             | j         |fi |S )zU Provide default implementation using self.model and user can reimplement it
        Nz$forward method should be implementedzFdefault implementation does not support multiple models in a pipeline.)r:   rM   )r9   r   r   s      r<   r   zPipeline.forward  sM     z%%'M%%%+uu-uuu+tz&33N333r>   c                      t          d          )ac   If current pipeline support model reuse, common postprocess
            code should be write here.

        Args:
            inputs:  input data
            post_params:   post process parameters

        Return:
            dict of results:  a dict containing outputs of model, each
                output should have the standard output name.
        r   )NotImplementedError)r9   r   post_paramss      r<   r   zPipeline.postprocess  s     "-000r>   )NNNrE   TN)NN) r   
__module____qualname____doc__r=   r   
InputModelrD   r3   r   r   r]   r   r`   rs   rT   Inputr	   r   r
   r   r   r   r   r   r   r   r   r   r   r   r   rm   r>   r<   r*   r*   ,   s          $T*5E     %)>BIM$" BB BB!BBj$z*::;BB  %\43E%EFBB 	BB BB BB BBJ ;?;?4 4*23-4+3C=4 4 4 4 !+ !+ !+F    $'eE4;$67 '#DcNI$=>' ' ' 'R+ + +=u = = = =- - -U S#X    (
 
 
-DK -$(cN- - - -^(* (* (*TB B B(> >S#X > > > >4d38n 4%)#s(^4 4 4 41$sCx. 1&*38n1 1 1 1 1 1r>   r*   c                       e Zd ZdZ	 	 	 ddedeeee         f         fdZd Z	d Z
ed	             Zd
eeef         deeef         fdZed             ZdedefdZdS )DistributedPipelinea  This pipeline is used to load multi gpu models.

    What will this class do:
    1. Read the global config from the configuration.json
    2. Set the multiprocessing method to spawn
    3. Open a multiprocessing pool of the world_size to instantiate model pieces.
    4. Set the master port and ip
    5. Call _instantiate_one to instantiate one model piece,
    This method should be implemented by the derived class.
    6. After the forward method is called, do preprocess in main process and
    call _forward_one to collect results, and do post process in main process.

    NOTE: _instantiate_one and _forward_one are class methods, any derived class should implement them and
    store the model handler in the class field.
    NTr:   rG   c                 $   || _         d| _        t                      | _        || _        t
          j                            |          r|| _        nt          |          | _        t          | j                  | _        |                     | j                  | _        d | _        d| _        t!          | j                  | _        d| _        | j        j        | _        t(          j                            dd           t/          t1          | j                            }t3          | j                  | _        d|vrd|d<   d|v rt5          |d                   nt7          j        d	d
          }ddlm}m}  ||          s
 |            }tA          |          |d<   |d         t
          j!        d<   |d         t
          j!        d<   | j        "                    tG          | j$        j%        fd| j        i| j        j&        ||           g | _'        d S )NFcpuspawnT)force	master_ipz	127.0.0.1master_porti<s  iL  r   )_find_free_port_is_free_portMASTER_ADDRMASTER_PORTrS   )(rG   rW   r   rX   rY   rP   rQ   existsrS   r   r   rO   _get_world_size
world_size
model_poolr7   r   r.   rM   rU   rV   multiprocessingset_start_methodr   r   r   intrandomrandintri   r   r   r3   environmapr   	__class___instantiate_oner:   rC   )	r9   r:   rG   r\   r;   ranksr   r   r   s	            r<   r]   zDistributedPipeline.__init__  s!    )##'66 )7>>%   	6"DNN.u55DNt~....tx88 #D$455#( +..wd.CCCU4?++,,t//f$$"-F;,66 &/   <BN#U=, =, 	 	POOOOOOO}[)) 	,)/++K #K 0 0}$*;$7
=!$*=$9
=!/ . (. 	  !	" 	" 	" r>   c                     t          | d          r4| j        /	 | j                                         d S # t          $ r Y d S w xY wd S d S )Nr   )rg   r   	terminateAttributeError)r9   s    r<   __del__zDistributedPipeline.__del__  sl    4&& 	4?+F))+++++!   	 	+F+Fs   4 
AAc                 J    | j                                         }|d= |d= |d= |S )Nr   rG   rX   )__dict__copy)r9   	self_dicts     r<   __getstate__z DistributedPipeline.__getstate__  s4    M&&((	l#n%+,r>   c                     dS )a  Instantiate one model piece.

        Args:
            rank: The model rank.
            model_dir: The model_dir in the node.
            kwargs: Any extra args.

        Returns:
            None. The model handler should be kept in the class field.
        Nrm   )clsrankrS   r;   s       r<   r   z$DistributedPipeline._instantiate_one  	     	r>   r   rt   c                 x    ||d}| j                             | j        j        |g| j        z            }|d         S )N)r   r   r   )r   r   r   _forward_oner   )r9   r   r   ress       r<   r   zDistributedPipeline.forward  sK     ,
 
 o!!$."=#)(T_"<> >1vr>   c                     dS )zForward the inputs to one model piece.

        Use the model handler kept in the class field to forward.

        Args:
            inputs: The inputs after the preprocessing.

        Returns:
            The forward results.
        Nrm   )r  r   s     r<   r  z DistributedPipeline._forward_one#  r  r>   rO   c                 ^    |                     d          }||                     d          S |S )Nzmegatron.world_sizezmodel.world_size)safe_get)r9   rO   m_world_sizes      r<   r   z#DistributedPipeline._get_world_size1  s3    ||$9::<< 2333r>   )NNT)r   r   r   r   r3   r   r   r   r]   r   r   classmethodr   r	   r   r   r  r   r   r   rm   r>   r<   r   r     s        " #IM"/ //$\43E%EF/ / / /b       [d38n %)#s(^      [6 c      r>   r   c                 ,   ddl m} d }t          | t                    st          | t                    r6 t          |           fd|                                 D                       S t          | t          t          f          rdt          |           k    rt          j        g           S t          | d         t          t          f          r ||                                         S  t          |           fd| D                       S t          | t          j                  r<| j        j        t          j        u r| S t'          t          j        |                     S t          | t          j                  r|                               S t          | t*          t,          t          t          t.          t          d          f          r| S  ||           dk    r| S  ||           dk    r| S t1          d	t          |                      )
a3  Prepare the input just before the forward function.
    This method will move the tensors to the right device.
    Usually this method does not need to be overridden.

    Args:
        data: The data out of the dataloader.
        device: The device to move data to.

    Returns: The processed data.

    r   )default_collatec                     | j         j        S rA   )r   r   )objs    r<   get_class_namez"collate_fn.<locals>.get_class_nameF  s    }%%r>   c                 H    i | ]\  }}||d k    rt          |          n|S )	img_metasr   )rn   r   r   r.   s      r<   
<dictcomp>zcollate_fn.<locals>.<dictcomp>K  sH     
 
 
1 [(8(8z!V$$$a
 
 
r>   c              3   8   K   | ]}t          |          V  d S rA   r  )rn   r   r.   s     r<   ry   zcollate_fn.<locals>.<genexpr>U  s-      BBjF33BBBBBBr>   NInputFeaturesDataContainerzUnsupported data type )torch.utils.data.dataloaderr  r2   r   r   r   r   r   r   rL   rV   r   r   floatrj   npndarraydtypestr_r   
from_numpybytesr3   boolr   )r   r.   r  r  s    `  r<   r   r   8  s    <;;;;;& & & $ @D'!:!: @tDzz 
 
 
 



 
 
   	 
D5$-	(	( @D		>><###d1gU|,, 	C"?4((++F3334::BBBBTBBBBBB	D"*	%	% @:?bg%%Ke.t44f===	D%,	'	' @wwv	D5#sE4dD	E	E 	@				0	0				0	0>$t**>>???r>   )IrP   os.pathrQ   rz   r   abcr   r   	functoolsr   r   r   	threadingr   typingr   r	   r
   r   r   r   r   numpyr  	packagingr   modelscope.models.baser   modelscope.msdatasetsr   modelscope.outputsr   r   modelscope.pipeline_inputsr   r   modelscope.preprocessorsr   modelscope.utils.configr   modelscope.utils.constantr   r   r   modelscope.utils.devicer   r   r   modelscope.utils.hubr   r   modelscope.utils.import_utilsr    r!   modelscope.utils.loggerr"   ri   r#   utils.automodel_utilsr%   utilr'   r(   rV   r   r3   r   r   r   r4   r*   r   r   rm   r>   r<   <module>r5     s   
			        # # # # # # # #                         G G G G G G G G G G G G G G G G G G           ( ( ( ( ( ( + + + + + + < < < < < < < < D D D D D D D D 1 1 1 1 1 1 * * * * * * C C C C C C C C C C4 4 4 4 4 4 4 4 4 4 ? ? ? ? ? ? ? ? M M M M M M M M . . . . . . 6 6 6 6 6 6 @ @ @ @ @ @ 0 0 0 0 0 0 0 0 LLL? 		*	+c5)]OCD3001
	L1 L1 L1 L1 L1s L1 L1 L1^z z z z z( z z zz.@ .@ .@ .@ .@r>   