
    yjPf                     0   d Z ddlZ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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 ddlmZ ej        Zej        Zej        Zej        Zd Zd Zd Zd Zd Z d Z!e!d             Z"e!d             Z#d Z$d Z%d Z&d Z'de(de(fdZ)d Z*e!d             Z+d Z,d Z-d Z.d  Z/d! Z0d" Z1d1d$e2d%e3fd&Z4d2d'Z5d( Z6d) Z7 ed* ej8                    +          d,             Z9d-Z:e:d.z  d.z  Z;e;fd/Z<d3d0Z=dS )4u^   
本文件实现了请求hub

Authors: xiangyiqing(xiangyiqing@baidu.com)
Date:    2023/07/24
    N)quote)	ErrorEnum)configlog)err_resp)gen_ISO_format_datestr)file_to_base64thread_executor)$create_sha256_file_and_encode_base64)VERSION)RequestErrorc                    t          t                    D ]}	 t          j        | |||t                    }|                                c S # t          j        j        $ r8 d                    |j	                  }|j
        }t          j        |           Y w xY wt          t          j        j        |dd         |          S )z
    request aistudio hub
    headersdatatimeout-Response body does not contain valid json: {}N  )rangeCONNECTION_RETRY_TIMESrequestsrequestCONNECTION_TIMEOUTjson
exceptionsJSONDecodeErrorformattextstatus_coder   debugr   r   INTERNAL_ERRORcode)methodurlr   r   _responseerr_msgbiz_codes           i/lsinfo/ai/hellotax_ai/data_center/backend/venv/lib/python3.11/site-packages/aistudio_sdk/requests/hub.py_request_aistudio_hubr*   %   s     )**  	'W-1;MO O OH==??""""2 	 	 	ELLX][[G+HIg	 I,1DSDM  s   1AA	BBc                     t          | d                   }|                     d           d                    t          j        dt
          j                  t
          j                  }d |                                 D             }t          j
        d|            t          j
        d|            t          j        |          }t          d	|||          }|S )
u'   
    请求AIStudio hub: 模型库
    tokenr,   {}{}STUDIO_MODEL_API_URL_PREFIXdefaultc                     i | ]\  }}||	S  r3   .0kvs      r)   
<dictcomp>z(request_aistudio_hub.<locals>.<dictcomp>C       ,,,TQAq,,,    zrequest_aistudio_hub url: zrequest_aistudio_hub body: POST)_header_fillpopr   osgetenvr   #STUDIO_MODEL_API_URL_PREFIX_DEFAULTHUB_URLitemsr   r    r   dumpsr*   kwargsr   r$   bodypayloadresps         r)   request_aistudio_hubrI   7   s     111G
JJw
--
	/9cddd C
 -,V\\^^,,,DI0300111I2D22333jG gw??DKr:   c                     t          | d                   }|                     d           d                    t          j        dt
          j                  t
          j                  }d |                                 D             }t          j
        d|            t          j
        d|            t          j        |          }t          d	|||          }|S )
u(   
    请求AIStudio hub：应用库
    r,   r-   r.   r/   r0   c                     i | ]\  }}||	S r3   r3   r4   s      r)   r8   z0request_aistudio_app_service.<locals>.<dictcomp>Y   r9   r:   z"request_aistudio_app_service url: z#request_aistudio_app_service body: r;   )r<   r=   r   r>   r?   r   r@   APP_SERVICE_URLrB   r   r    r   rC   r*   rD   s         r)   request_aistudio_app_servicerM   L   s    
 111G
JJw
--
	/9cddd C
 -,V\\^^,,,DI8388999I:D::;;;jG gw??DKr:   c                     t          | d                   }d                    t          j        dt          j                  t          j                  }|dt          | d         d	           d
z   }d}	 d}t          j	        |||t                    }|                                S # t          j        j        $ r d                    |          }|j        }Y nw xY wt          t           j        j        |dd         |          S )u3   
    请求AIStudio hub 查看repo可见权限
    r,   r-   r.   r/   r0   z?repoId=repoId safez&authorization=1GET)r   r   r   Nr   )r<   r   r>   r?   r   r@   HUB_URL_VISIBLE_CHECKr   r   r   r   r   r   r   r   r   r   r!   r"   )rE   r   r$   r#   r'   r&   r(   s          r)   request_aistudio_repo_visiblerU   b   s    111G
--
	/9cddd$ C M5!1;;;MMM
MCF(#FC,>@ @ @}}. ( ( (AHHRR'( I,1DSDM  s   62B) )0CCc                 Z   t          t                    D ]}t          j                    }|                    | |||t
                    }|                                 |j        dvrt          j	        d|j
         d|j                    t          j        d| d|            |j        dk    rdnd	}t          | d
k    rt          j        j        nt          j        j        |j                                        dd         |z   |j                  c S |                                c S dS )z
    request gitea
    r         z
response:  z'potential network problem while request:  u   [仓库或分支不存在]rP   rS   Nr   r(   )r   r   r   Sessionr   r   closer   r   r    r   infor   r   GITEA_DOWNLOAD_FILE_FAILEDr"   GITEA_UPLOAD_FILE_FAILEDcontentdecoder   )r#   r$   r   r   r%   sessionr&   	extra_msgs           r)   _request_gitearg   }   sI    )** # #"$$??63dTf?ggz11II8=II83GIIJJJHOsOOXOOPPP8@8LPS8S8S44Y[I"eOO &@EE1:1S1X$,3355dsd;iG%-%9; ; ; ; ; ;
 ==??"""# #r:   c                       fd}|S )z
    time cost decorator
    c                      t          j                     } | i |}t          j                     }||z
  }t          j         d|dd           |S )Nz done, time cost: .2fs)timeprint__name__)argsrE   
start_timeresultend_timeelapsed_timefuncs         r)   wrapperz!timing_decorator.<locals>.wrapper   s`    Y[[
t&v&&9;;*,EE,EEEEFFFr:   r3   )rt   ru   s   ` r)   timing_decoratorrv      s#         Nr:   c                 0   t          j                    }|                    | |||dt                    }|                                 |j        dvr3t          t          j        j	        |j
        dd         |j                  S |                                S )z
    _upload proc
    T)r   r   streamr   rW   Nr   r]   )r   r^   r   CONNECTION_TIMEOUT_UPLOADr_   r   r   r   rb   r"   rc   r   )r#   r$   r   r   re   r&   s         r)   _uploadrz      s    
   GvsG$&*4M  O OHMMOOO:--	:? (#.!)!57 7 7 	7 }}r:   c                    t          j        d| d|t                    }|j        dk    ri }n|j        dk    ru	 |                                d         }n3# t           j        j        $ r |j                                        }Y nw xY wt          t          j        j        ||j                  }n-t          t          j        j        d|j         |j                  }t          |j                            dd	                    }d
}t#          j        |dddd          }t%          |d          5 }	|                    |          D ]9}
|                    t+          |
                     |	                    |
           :	 ddd           n# 1 swxY w Y   |                                 |d	k    r|j        |k    rt3          d           |S )z
    Params
        :url: http url
        :download_path: download path
        :headers: headers
    Returns
        file
    rS   T)rx   r   r   rX   r\   messagez Download failed, response code: zcontent-lengthr   i  2   iBzDownloading file)totalncolsunit
unit_scaledescwbNzERROR, something went wrong)r   r   CONNECTION_TIMEOUT_DOWNLOADr   r   r   r   rc   rd   r   r   FILE_NOT_FOUNDr"   ra   intr   gettqdmopeniter_contentupdatelenwriter_   nrm   )r$   download_pathr   r&   retr|   
total_size
block_sizeprogress_barfiler   s              r)   	_downloadr      s,    s4(CE E EH s""			$	$	0mmooi0GG"2 	0 	0 	0&--//GGG	0 y/4 ,. . y;@Q8;OQQ ,. . X%))*:A>>??JJ9:Rdt"46 6 6L 
mT	"	" d))*55 	 	DD		***JJt	              
 Q<>Z77+,,,Js$   A -BB-AF

FFc                 H    t          |          }t          | ||          }|S )u*   
    请求AIStudio gitea文件下载
    r-   )r<   r   )r$   r   r,   r   ress        r)   request_aistudio_git_downloadr      s*     '''G
C
0
0CJr:   c           
      ,   |  dt          |d           dt          |d           dt          |d           }|dk    r|dt          |d           z  }t          |          }t          d	||d          }t          j        d
| d|            |S )u   
    请求AIStudio gitea 文件info
    GET /api/v1/repos/{owner}/{repo}/contents/{filepath} 返回的文件的数据、大小、编码等metadata信息+文件内容，或者文件夹中的文件列表
    /api/v1/repos/rP   rQ   /
/contents/master?ref=r-   rS   z...result of GET /contents/: )r   r<   rg   r   r    )		call_host	user_name	repo_name	file_pathrevisionr,   r$   r   r   s	            r)   request_aistudio_git_file_infor      s      J JeIB&?&?&? J J	yr	"	"	"J J.3IB.G.G.GJ JC81uXB///111'''G
Wb
1
1CI>I>>>>???Jr:   c           
         t          |          }|  dt          |d           dt          |d           dt          |d           }dd|igi}t          j        |          }	t	          d|||		          }
t          j        d
| d|
            d|
v r|
}ngd|
vs|
d         rd|
d         d         vr5t          t          j	        j
        t          |
          dd                   }nd|
d         d         d         i}|S )u1   
    请求AIStudio gitea 确认文件类型
    r-   r   rP   rQ   /preupload/filespathr;   r   ...result of POST /preupload: r   
error_codelfsr   Nr   is_lfs)r<   r   r   rC   rg   r   r    r   r   GITEA_FAILEDr"   str)r   r   r   r   path_in_repor,   r   r$   paramsrG   rq   r   s               r)   request_aistudio_git_file_typer      sL   
 '''G
u
uyr222
u
uU925N5N5N
u
u[`aipr[s[s[s
u
uC 	L
 F j  GFCw???FI>s>>f>>???v			fWo	fWoVWFX9X9Xy-2FDSD)+ + fWoa(/
 Jr:   c           
      8   t          |          }|  dt          |d           dt          |d           dt          |d           }dd |D             i}t          j        |          }	t	          d	|||	
          }
t          j        d| d|
            d|
v rt          d          d|
vst          |
d         t                    st          d          i }|
d         D ]4}|
                    d          }|
                    dd          }|r|||<   5|S )u   
        批量请求 AIStudio gitea 确认多个文件是否为 LFS 类型

        :param path_list: List[str]，每个元素是 repo 内的相对路径
        :return: Dict[str, bool]，key 是路径，value 是是否为 LFS
        r-   r   rP   rQ   r   r   r   c                     g | ]}d |iS )r   r3   )r5   r   s     r)   
<listcomp>z3request_aistudio_git_files_type.<locals>.<listcomp>)  s    ???T64.???r:   r;   r   r   r   r   z-preupload fail, there is error_code in resultz#preupload fail, wrong result formatr   r   F)r<   r   r   rC   rg   r   r    
ValueError
isinstancelistr   )r   r   r   r   path_in_repo_listr,   r   r$   r   rG   rq   lfs_map	file_infor   r   s                  r)   request_aistudio_git_files_typer     s{    '''G k kIB'''k k*/	*C*C*Ck kPUV^egPhPhPhk kC 	??->???F j  GFCw???FI>s>>f>>???vIJJJ			j$&G&G	?@@@GG_ # #	}}V$$ue,, 	#"GDMNr:   upload_sectionreturnc           	      ~   |                      di           }|r|                     d          r|                     d          |                     d          |                     d          |                     d          |                     d          |                     d          |                     d          d	S i S )
u  
    解析sts_token

    "upload": {
        "href": "https://some-download.com",
        "header": {
            "Key": "value"
        },
        "sts_token": {
            "bosHost":""
            "bucketName": "",
            "key":"",
            "accessKeyId":"",
            "secretAccessKey":"",
            "sessionToken":"",
            "createTime":"",
            "expiration":""
            }
        "expires_at": "2016-11-10T15:29:07Z"
    }
    	sts_tokenaccessKeyIdbosHost
bucketNamekeysecretAccessKeysessionToken
expiration)bos_hostbucket_namer   access_key_idsecret_access_keysession_tokenr   )r   )r   r   s     r)   _parse_sts_tokenr   >  s    , "";33I 	
Y]]=11 	
!i00$==66==''&]]=99!*/@!A!A&]]>::#--55
 
 	
 Ir:   c                    ddd}t          ||          }|  dt          |d           dt          |d           d}	d	||d
gddgdd| idd}t          j        |          }
t	          d|	||
          }t          j        d|            d|v r|}nd|vs|d         s5t          t          j	        j
        t          |          dd                   }nt|d         d         }d|v rd	|d         v rdndd|v r|d         d	         d         ndd|v rt          |d         d	                   ni d|v r|d         d         d         ndd}|S )uL   
    请求AIStudio gitea 申请上传LFS文件.
    只支持单文件
    z+application/vnd.git-lfs+json; charset=utf-8application/vnd.git-lfs+jsonContent-TypeAcceptr   r,   r   rP   rQ   z.git/info/lfs/objects/batchuploadoidsizezlfs-standalone-filebasicnamezrefs/heads/sha256)	operationobjects	transfersref	hash_algor;   z...result of POST /batch: r   r   Nr   r   actionsTFhrefverify)r   upload_hrefr   verify_href)r<   r   r   rC   rg   r   r    r   r   r   r"   r   r   )r   r   r   r   	file_sizer   r,   r   r   r$   rG   rq   r   tmps                 r)   "request_aistudio_git_upload_accessr   c  s    F0 F &666G
k
kyr222
k
kU925N5N5N
k
k
kC  ! 
 "7
 ,(,,
  F" j  GFC'::FI3633444v	&	 	 y(9	 y-2FDSD)+ + Y" (3..8s9~3M3MddSX?HC?O?O3y>(3F;;UWGPTWGWGW)#i.*BCCC]_?HC?O?O3y>(3F;;UW	
 
 Jr:   c           	          t          |d          5 }t          j        d| ||t          d          }ddd           n# 1 swxY w Y   d|j        d         iS )   
    上传LFS文件到bos
    rbPUTT)r   r   r   rx   NzContent-Md5)r   r   r   ry   r   )r$   path_or_fileobjr   r   r&   s        r)   _lfs_uploadr     s    
 
ot	$	$ T#E3d,EdT T TT T T T T T T T T T T T T T T 8+M:;;s    =AAc                 N    ddi}t          |d          }t          | ||          S )r   r   zapplication/octet-streamrP   r   )r<   r   )r$   r   r   r   s       r)   request_bos_uploadr     s3     89F&333GsOW555r:   c                 h    d| v r| d         t           j        j        k    rdS | rd| vrdS | d         }|S )u   
    解析info_res
    r   rP   sha)r   SUCCESSr"   )info_resold_shas     r)   get_exist_file_old_shar     sN     xH\$:i>O>T$T$Tr h..r5/r:   c	           
         t          | |||||          }	t          |	          }
|
dk    rd}nd}t          |          }|  dt          |d           dt          |d           dt          |d           }||t	          ||          d	t                      t                      d
|d}|dk    r|
|d<   t          j        |          }t          ||||          }|S )C   
    请求AIStudio gitea 上传LFS指针文件（到仓库）
    rP   r;   r   r-   r   rQ   r   r   Tauthor	committer)branch
new_branchrc   
lfsPointerdatesr|   r   )	r   r   r<   r   r   r   r   rC   rg   )r   r   r   r   commit_messager   r   r   r,   r   r   r#   r   r$   r   rG   r   s                    r)   #request_aistudio_git_upload_pointerr    s8    .iI|.6? ?H$X..G"}} '''G M MeIB&?&?&? M M	yr	"	"	"M M.3Lr.J.J.JM MC 7	JJ,../11
 
 "
 
F uj  G
gw
7
7CJr:   c           
         t          | |||||          }t          |          }	|	dk    rd}
nd}
t          |          }|  dt          |d           dt          |d           dt          |d           }||t	          ||          d	d
}|
dk    r|	|d<   t          j        |          }t          |
|||          }|S )r   rP   r;   r   r-   r   rQ   r   r   T)r   r   rc   r   r   )r   r   r<   r   r   r   rC   rg   )r   r   r   r   r   r   r   r,   r   r   r#   r   r$   r   rG   r   s                   r)   !request_single_git_upload_pointerr    s    .iI|.6? ?H$X..G"}} '''G M MeIB&?&?&? M M	yr	"	"	"M M.3Lr.J.J.JM MC 7	JJ	
 
F uj  G
gw
7
7CJr:   c           
         t          | |||||          }t          |          }	|	dk    rd}
nd}
|  dt          |d           dt          |d           dt          |d           }t          |          }t	          |          }|||d	t                      t                      d
|d}|
dk    r|	|d<   t          j        |          }t          |
|||          }|S )@   
    请求AIStudio gitea 上传普通文件（到仓库）
    rP   r;   r   r   rQ   r   r   r-   Fr   )r   r   rc   r   r   r|   r   )	r   r   r   r<   r	   r   r   rC   rz   )r   r   r   r   r  r   r   r,   r   r   r#   r$   r   base64_datar   rG   r   s                    r)   "request_aistudio_git_upload_commonr    s;    .iI|.6? ?H$X..G"}}  M MeIB&?&?&? M M	yr	"	"	"M M.3Lr.J.J.JM MC'''G 11K ,../11
 
 "
 
F uj  G
&#w
0
0CJr:   c           
         t          | |||||          }t          |          }|dk    rd}	nd}	|  dt          |d           dt          |d           dt          |d           }
t          |          }t	          |          }|d	d
}|	dk    r||d<   t          j        |          }t          |	|
||          }|S )r  rP   r;   r   r   rQ   r   r   r-   F)rc   r   r   )r   r   r   r<   r	   r   rC   rz   )r   r   r   r   r   r   r,   r   r   r#   r$   r   r  r   rG   r   s                   r)    request_single_git_upload_commonr
  0  s    .iI|.6? ?H$X..G"}}  M MeIB&?&?&? M M	yr	"	"	"M M.3Lr.J.J.JM MC'''G 11K
 	
 
F uj  G
&#w
0
0CJr:   rP   r   r   c           	      V   ddd}||d}t          ||          }t          j        d| ||t          j        |                    }t          j        d|j                    |j        dvr+t          t          j        j        |j        |j        	          S |                                S )
zp
    param
        call_host: verify url
        oid: sha256, without sha256prefix
        size: file size

    r   r   r   r-   r;   )r   r   r   z...result of POST /verify: rW   r]   )r<   r   r   r   rC   r   r    r   r   r   r   rb   r"   )r   r   r   r,   r   r   headerr   s           r)    request_aistudio_verify_lfs_filer  X  s     70 G
  F '///F

69f6PTPZ[aPbPb
c
c
cCI6CH66777
j((	:?!$2 2 2 	2 xxzzr:   c                     |rd| }ndt          j        dd           }d|t          t                    d}| r|                    |            |S )u   
    填充header
    ztoken AISTUDIO_ACCESS_TOKENrP   r0   zapplication/json)r   AuthorizationzSDK-Version)r>   r?   r   r   r   )r   r,   authr   s       r)   r<   r<   s  su      IH	"92FFFHH*7|| G
  vNr:   c                    t          j        dt          j                  }| d|  d| d| }t	          |          }t          j        ||          }|j        dk    r)d	|                                                    d
          fS dS )uH   检查目标文件是否存在，返回 (exists: bool, sha: str or None)STUDIO_GIT_HOSTr0   r   r   r   r-   )r   rX   Tr   )FN)	r>   r?   r   STUDIO_GIT_HOST_DEFAULTr<   r   r   r   r   )repo_idr   r   r,   hostr$   r   rH   s           r)   file_exists_and_shar    s    9&0NOOOD
I
I
I
ID
I
Ix
I
IC'''G<W---D3TYY[[__U++++;r:   c                     d|  d| dS )u.   构造 LFS pointer 文件内容（纯文本）z6version https://git-lfs.github.com/spec/v1
oid sha256:z
size 
r3   )r   r   s     r)   get_lfs_pointer_contentr    s+    11 1(,1 1 1 1r:   F)disable_tqdmmax_workersc                 <   | \  }}}}	 t          ||||          \  }}	n/# t          $ r"}
t          j        | d           Y d}
~
dS d}
~
ww xY w|r2t          j                            |          }t          |p||          }nt          |d          5 }|	                                }ddd           n# 1 swxY w Y   	 t          j        |          }|                    d          }n!# t          $ r t          d| d          w xY w||||rdndd	}|	r|	|d
<   |S )z
    prepare body data
    z request git error,skipNr   zutf-8u   ❌ Non-UTF8 content in z-. Consider LFS or base64 with encoding field.r   create)r   r   rc   r   r   )r  	Exceptionr   errorr>   r   getsizer   r   readbase64	b64encoderd   UnicodeDecodeErrorr   )qr  r   r,   r   
local_pathr   sha256_inputexistsr   er   content_b64fcontent_bytescontent_strentrys                    r)   prepare_entryr0    s   
 ./*D*fl)'8T5II   	T222333ttttt  swz**:<;W<Y]^^*d## 	%qFFHHM	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	%	s *=99K%,,W55KK! 	s 	s 	sq
qqqrrr	s !'5XXX	 E  eLs2    
AAAB33B7:B7?)C) )DrX      c                    g }g }d}d}| D ]}|                     dd          }||k    rt          d|dz  dz  dd          ||z   |k    s4|dz   t          t          j                             dd	                    k    r|                    |           |g}|}d}|                    |           ||z  }|dz  }|r|                    |           |S )
u   
    将 files 拆分为多个分组，每组最大总大小不超过 max_bytes,每组个数不超过1k
    要求每个 file 是一个 dict，包含 'size' 字段（单位字节）。
    r   r   u!   单个文件超过最大限制：r1  rj   MB   MAX_COMMIT_FILE_COUNT500)r   r   r   r>   environappend)r   	max_byteschunkscurrent_chunkcurrent_sizecurrent_countr   r   s           r)   split_files_by_sizer>    s   
 FMLM  HHVQ''	y  `TAQTXAX````aaa9$y00MA4EBJNN#:EBBCC5D 5DMM-(((!FM$LMM  &&&I%LQMM %m$$$Mr:   c                    |ddd}||}t          j        d           t          j        dt          j                                t          ||||          }d |D             }t          |          }	t          |	          d	k    rt          j        d
           t          j        dt          j
                  }
t          |          }|
 d| d}t          |	d	          D ]\  }}t          |	          d	k    r|n| d| dt          |	           d}|||||d}t          j        |||          }|j        dz  dk    r(t!          |j                   t!          d| d           |D ]/}|D ]*\  }}}}|d         |k    r|                     |df           +0t!          d| d|j                    t!          |j                   dS )z
    commit
    NzAuto Commitzauto@example.com)r   emailzcalculate fileszcpu:)r  r   r,   c                     g | ]}||S )Nr3   )r5   items     r)   r   z commit_files.<locals>.<listcomp>  s    888dt'7T'7'7'7r:   r4  z'files will be commited in multi batchesr  r0   r-   r   z	/contents)startz (part r   ))r   r|   r   r   r   )r   r   d      u   ✅ Commit part z successful!r   zcommit failu   ❌ Commit part z	 failed: )r   r`   r    r>   	cpu_countr0  r>  r   r?   r   r  r<   	enumerater   postr   rm   r8  r   )log_listr  r   r  
file_quadsr,   r   r   r   file_chunksr  r   r$   ichunkcommit_message_currentchunk_payloadrH   r/  r   r'  r   r(  s                          r)   commit_filesrQ    sZ    ~'2DEE	HI%R\^^%%&&&*gPUVVVE88e888E%e,,K
;!:;;;9&0NOOOD'''G
3
3
3
3
3Ck333  536{3C3Cq3H3H"BB1BBs;/?/?BBB 	 -"
 
 }S'FFFs"a''$"###4Q4445555 E E>H E E:D*flV},, ](CDDDE CQCC1ACCDDD$)- r:   )rP   )NrP   )NN)>__doc__r#  r>   rl   r   r   r   urllib.parser   aistudio_sdk.constant.err_coder   aistudio_sdkr   r   aistudio_sdk.utils.utilr   r   r	   r
   r   aistudio_sdk.constant.versionr   aistudio_sdk.errorsr   r   r   r   ry   r*   rI   rM   rU   rg   rv   rz   r   r   r   r   r   dictr   r   r   r   r   r  r  r  r
  r   r   r  r<   r  r  rG  r0  MAX_PAYLOAD_MBMAX_PAYLOAD_BYTESr>  rQ  r3   r:   r)   <module>r\     ss     				           4 4 4 4 4 4 $ $ $ $ $ $ $ $ , , , , , , : : : : : : C C C C C C C C H H H H H H 1 1 1 1 1 1 , , , , , ,6 . $@ "<   $  *  ,  6# # #*     " + + +\    $  >! ! !F!T !d ! ! ! !J1 1 1h < < <6 6 6
 
 
$ $ $N$ $ $N' ' 'T& & &P S     6   $  1 1 1 e@@@    A@ D "T)D0  *;    @) ) ) ) ) )r:   