
    Œi                       d Z ddlmZ ddlZddlZddlmZ ddlmZm	Z	 ddl
mZmZmZmZmZmZmZmZmZ ddlmZmZmZmZmZmZmZmZmZmZmZm Z   edd	g
          Z! ej"        e#          Z$dFdZ%dGdZ&dHdZ'dIdZ(dJd Z)dKd#Z*dLd$Z+dMd'Z,dNd(Z-dOd*Z.e!/                    d+d,e-          dPd1            Z0e!/                    d2d3e-          dQd6            Z1e!/                    d7d8e-          dRd;            Z2e!/                    d<d=e-          dSd@            Z3e!/                    dAdBe -          dTdE            Z4dS )Uu  
Nom du fichier : milestones.py
Chemin : /var/www/html/gitlab-bridge/app/api/v1/milestones.py
Description : Endpoints API liés aux milestones GitLab compatibles OpenWebUI.
Auteur : Sylvain SCATTOLINI
Date de création / modification : 2026-04-02
Version : 1.1
    )annotationsN)Any)	APIRouterHTTPException)	_build_candidate_projects_build_issue_candidates_get_issue_by_iid_get_project_by_path_gitlab_request_normalize_text_score_text_search_best_project_search_open_issues_in_project)$MilestoneAssistantAssignIssueRequest%MilestoneAssistantAssignIssueResponseMilestoneAssistantCreateRequest MilestoneAssistantCreateResponseMilestoneAssistantListRequestMilestoneAssistantListResponseMilestoneCandidateItemMilestoneItem#MilestoneAssistantListIssuesRequest$MilestoneAssistantListIssuesResponse!MilestoneAssistantProgressRequest"MilestoneAssistantProgressResponsez/api/v1/milestones
milestones)prefixtags	milestonedict[str, Any]returnr   c                x   t          t          | d                   |                     d          t          | d                   nd t          |                     dd                    |                     d          #t          |                     dd                    nd t          |                     dd                    |                     d          "t          |                     d                    nd |                     d          "t          |                     d                    nd 	          S )
Nidiidtitle descriptionstatedue_dateweb_url)r#   r$   r%   r'   r(   r)   r*   )r   intgetstr)r   s    4/var/www/html/gitlab-bridge/app/api/v1/milestones.py_milestone_to_itemr/   2   s   y%.]]5%9%9%EC	% !!!4)--,,--=F]]==Y=Y=eC	mR88999ko)--,,--3<==3L3L3XY]]:..///^b1:y1I1I1UIMM),,---[_       
project_idr+   r(   r-   limitlist[MilestoneItem]c           	         |dk    rdn	|dk    rdnd }t          dd|  d|t          |d          dd	          }t          |t                    sg S d
 |D             S )NactiveclosedGET
/projects//milestonesd      r(   per_pagepagequery_paramsc                V    g | ]&}t          |t                    t          |          'S  )
isinstancedictr/   ).0ms     r.   
<listcomp>z,_list_project_milestones.<locals>.<listcomp>N   s0    MMMaAt9L9LMq!!MMMr0   r   minrC   list)r1   r(   r2   query_stater   s        r.   _list_project_milestonesrL   >   s    #x//(((ARARXXX\K ,Z,,, E3
 
  J j$'' 	MM:MMMMr0   r%   r'   r)   c                p   d|                                 i}|                                 r|                                 |d<   |                                 r|                                 |d<   t          dd|  d|          }t          |t                    st	          dd	
          t          |          S )Nr%   r'   r)   POSTr8   r9   payload  u>   Réponse GitLab invalide lors de la création de la milestone.status_codedetail)stripr   rC   rD   r   r/   )r1   r%   r'   r)   rP   r   s         r.   _create_project_milestonerV   Q   s     	G  5!,!2!2!4!4~~ /&nn..
,Z,,,  I i&& v4tuuuui(((r0   milestone_hint list[tuple[int, dict[str, Any]]]c           	        t          dd|  ddt          |d          dd          }t          |t                    sg S g }|D ]}t          |t                    st          |                    d	d
                    }t          ||          }t          |          t          |          v rt          |d          }|dk     r|
                    ||f           |                    dd            |d |         S )Nr7   r8   r9   r5   r:   r;   r<   r?   r%   r&   _   (   Tc                    | d         S )Nr   rB   )items    r.   <lambda>z/_search_milestones_in_project.<locals>.<lambda>   s
    47 r0   )reversekey)r   rI   rC   rJ   rD   r-   r,   r   r   maxappendsort)r1   rW   r2   r   
candidatesr   r%   scores           r.   _search_milestones_in_projectrf   m   s'    ,Z,,,E3
 
  J j$'' 	35J . .	)T** 	IMM'2..//NE22>**oe.D.DDDrNNE2::5),----OOD&:&:O;;;fufr0   rd   list[MilestoneCandidateItem]c                Z   g }| d d         D ]\  }}|                     t          t          |d                   |                    d          t          |d                   nd t	          |                    dd                    t	          |                    dd                    |                    d          "t	          |                    d                    nd |                    d          "t	          |                    d                    nd |	                     |S )
N   r#   r$   r%   r&   r(   r)   r*   )r#   r$   r%   r(   r)   r*   re   )rb   r   r+   r,   r-   )rd   resultsre   r   s       r.   _build_milestone_candidatesrk      s   ,.G&rrN 
 
y"y''-6]]5-A-A-MC	%()))SW)--4455)--4455;D==;T;T;`Y]]:66777fj9By9Q9Q9]IMM)44555cg  
	
 
	
 
	
 
	
 Nr0   	issue_iidmilestone_idc                    t          dd|  d| d|i          }t          |t                    st          dd          |S )	NPUTr8   z/issues/rm   rO   rQ   u?   Réponse GitLab invalide lors de l'affectation de la milestone.rR   r   rC   rD   r   )r1   rl   rm   issues       r.   _assign_issue_to_milestonerr      sb    4Z4444.  E eT"" w4uvvvvLr0   c                    t          dd|  d|           }t          |t                    rd|vrt          dd          |S )Nr7   r8   z/milestones/r#   i  zMilestone introuvablerR   rp   )r1   rm   r   s      r.   _get_milestone_by_idrt      s`    ;Z;;\;; I
 i&& M$i*?*?4KLLLLr0   milestone_titlelist[dict[str, Any]]c                    |dk    rd n|}t          dd|  d||t          |d          dddd	
          }t          |t                    sg S g }|D ]}t          |t                    s|                    t          |d                   t          |d                   t          |                    dd                    t          |                    dd                    t          |                    dd                    d           |S )Nallr7   r8   /issuesr:   r;   
created_atdescr   r(   r=   r>   order_byrc   r?   r#   r$   r%   r&   r(   r*   r#   r$   r%   r(   r*   )	r   rI   rC   rJ   rD   rb   r+   r-   r,   )r1   ru   r(   r2   rK   issuesrj   rq   s           r.   _list_issues_by_milestoner      s3   5..$$eK(Z(((( E3$
 
  F fd## 	$&G 
 
%&& 	%+&&5<((UYYw3344UYYw3344uyyB7788 	
 	
 	
 	
 Nr0   c                    t          dd|  d|d t          |d          dddd	          }t          |t                    sg S d
 |D             S )Nr7   r8   ry   r:   r;   rz   r{   r|   r?   c                <    g | ]}t          |t                    |S rB   )rC   rD   )rE   rq   s     r.   rG   z1_list_all_issues_by_milestone.<locals>.<listcomp>   s'    AAAeE4)@)@AEAAAr0   rH   )r1   ru   r2   r   s       r.   _list_all_issues_by_milestoner      sx    (Z((((E3$
 
  F fd## 	AAvAAAAr0   tuple[int, int, int, int]c                &   t          | ||          }t          |          }d}d}|D ]H}t          |                    dd                                                    }|dk    r|dz  }C|dz  }I|dk    rt          ||z  dz            nd}	||||	fS )Nr   r(   r&   r6   r;   r:   )r   lenr-   r,   lowerr+   )
r1   ru   r2   r   totalopenedr6   rq   r(   progress_percents
             r.   _compute_milestone_progressr      s    *:NNFKKEFF  EIIgr**++1133HaKFFaKFF6;aiisFUNc1222Q&&"222r0   z/assistant-listzAssistant liste des milestones)summaryresponse_modelrP   r   r   c                0   	 t                               dt          j        |                                 d                     t          | j                  }| j                                        	                                }| j
        r| j                                        st          dd          t          | j                                                  }t          t          |d                   ||          }t          dd	d
|d          t          |d                   t!          |                    dd                    t!          |                    dd                    d|g           S t%          | j        | j                  }|st          ddd| j         dd g g           S t+          |          dk    rC|d         d         |d         d         dz
  k    r"t          dddd g t-          |                    S |d         d         }t          t          |d                   ||          }t          dd	d
|d          t          |d                   t!          |                    dd                    t!          |                    dd                    d|t-          |d d                             S # t          $ r  t.          $ r?}t                               dt!          |                     t          dd          |d }~ww xY w)Nu8   Payload reçu sur /api/v1/milestones/assistant-list : %sFensure_ascii  BLe champ resolved_project_path est obligatoire quand confirm=true.rR   r#   Tresolvedu   Milestones récupérées pour path_with_namespacenamer&   r#   r   r   )successstatusmessageprojectr   candidate_projects	not_found-   Je ne trouve pas de projet correspondant à ''.r;   r   
   clarification_neededO   J’ai trouvé plusieurs projets possibles. Merci de préciser lequel utiliser.z5Erreur inattendue dans assistant_list_milestones : %s  uB   Erreur interne lors de la récupération assistée des milestones.)loggerinfojsondumps
model_dumpr+   r2   r(   rU   r   confirmresolved_project_pathr   r
   rL   r   r-   r,   r   project_hint	root_hintr   r   	Exception	exception)rP   
safe_limit
safe_stater   r   rd   excs          r.   assistant_list_milestonesr     se   GCFJw))++%@@@	
 	
 	

 ''
]((**0022
? 	06688 B#  =A  B  B  B  B*7+H+N+N+P+PQQG1#gdm2D2DjR\]]J1!YAV9WYYgdm,,FB 7 788+.w{{;PRT/U/U+V+V 
 &#%    *'*>@QRR
 	1"`H\```#%    z??Q:a=#3z!}Q7G"7L#L#L1-i#<Z#H#H    Q-"-c'$-.@.@*jYY
-UW=R5SUU'$-((GKK3344'*7;;7Lb+Q+Q'R'R 
 "8BQBHH
 
 
 	
     C C CPRUVYRZRZ[[[4xyyy  @C  	CCs,   E1K 49K .AK B=K L:LLz/assistant-createu    Assistant création de milestoner   r   c                   	 t                               dt          j        |                                 d                     | j        r| j                                        st          dd          t          | j                                                  }t          t          |d                   | j        | j        | j                  }t          dd	d
|j         t          |d                   t!          |                    dd                    t!          |                    dd                    d|g           S t%          | j        | j                  }|st          ddd| j         dd d g           S t+          |          dk    rC|d         d         |d         d         dz
  k    r"t          dddd d t-          |                    S |d         d         }t          t          |d                   | j        | j        | j                  }t          dd	d
|j         t          |d                   t!          |                    dd                    t!          |                    dd                    d|t-          |d d                             S # t          $ r  t.          $ r?}t                               dt!          |                     t          dd          |d }~ww xY w)Nu:   Payload reçu sur /api/v1/milestones/assistant-create : %sFr   r   r   rR   r#   Tcreatedu   Milestone créée : r   r&   r   r   )r   r   r   r   r   r   r   r   r   r;   r   r   r   r   z6Erreur inattendue dans assistant_create_milestone : %sr   u;   Erreur interne lors de la création assistée de milestone.)r   r   r   r   r   r   r   rU   r   r
   rV   r+   r%   r'   r)   r   r-   r,   r   r   r   r   r   r   r   )rP   r   r   rd   r   s        r.   assistant_create_milestoner   ]  sO   N|HJw))++%@@@	
 	
 	

 ? 	06688 B#  =A  B  B  B  B*7+H+N+N+P+PQQG1GDM""# 	 I 4 @y@@gdm,,FB 7 788+.w{{;PRT/U/U+V+V 
 $#%    *'*>@QRR
 	3"`H\```#%    z??Q:a=#3z!}Q7G"7L#L#L3-i#<Z#H#H    Q-"-M	
 
	 0<9?<<'$-((GKK3344'*7;;7Lb+Q+Q'R'R 
  8BQBHH
 
 
 	
     | | |QSVWZS[S[\\\4qrrrx{{|s,   EJ! 9J! >AJ! CJ! !K45:K//K4z/assistant-assign-issueu2   Assistant affectation d'une issue à une milestoner   r   c                   	 t                               dt          j        |                                 d                     t          | j                  }| j        r$| j        	                                st          dd          | j        dk    rt          dd          | j        dk    rt          dd	          t          | j        	                                          }t          t          |d
                   t          | j                  t          | j                            }|                    d          pi }t!          ddd|                    dd           t          |d
                   t#          |                    dd                    t#          |                    dd                    dt          |d
                   t          |d                   t#          |                    dd                    t#          |                    dd                    t#          |                    dd                    dt%          |t&                    r|rt)          |          nd g g g 	  	        S t+          | j        | j                  }|st!          dddd d d g g g 	  	        S t1          |          dk    rF|d         d         |d         d         dz
  k    r%t!          dddd d d t3          |          g g 	  	        S |d         d         }t          |d
                   }t5          || j        |          }|sgt!          ddd | j         d!|t#          |                    dd                    t#          |                    dd                    dd d g g g 	  	        S t1          |          dk    r|d         d         |d         d         dz
  k    rkt!          dd"d#|t#          |                    dd                    t#          |                    dd                    dd d g t9          |          g 	  	        S t;          || j        |          }|sgt!          dd$d%| j         d!|t#          |                    dd                    t#          |                    dd                    dd d g g g 	  	        S t1          |          dk    r|d         d         |d         d         dz
  k    rkt!          dd&d'|t#          |                    dd                    t#          |                    dd                    dd d g g t?          |          	  	        S t          |d         d         d                   }	t          |d         d         d
                   }
t          ||	|
          }|                    d          pi }t!          ddd|                    dd           |t#          |                    dd                    t#          |                    dd                    dt          |d
                   t          |d                   t#          |                    dd                    t#          |                    dd                    t#          |                    dd                    dt%          |t&                    r|rt)          |          nd g g g 	  	        S # t          $ r  t@          $ r?}t           !                    d(t#          |                     t          d)d*          |d }~ww xY w)+Nu@   Payload reçu sur /api/v1/milestones/assistant-assign-issue : %sFr   r   r   rR   r   z?Le champ resolved_issue_iid est obligatoire quand confirm=true.BLe champ resolved_milestone_id est obligatoire quand confirm=true.r#   r   Tassignedu"   Issue affectée à la milestone : r%   r&   r   r   r   r$   r(   r*   r~   )	r   r   r   r   rq   r   r   candidate_issuescandidate_milestonesproject_not_found)Je ne trouve pas le projet correspondant.r;   r   project_clarification_neededr   issue_not_foundu3   Je ne trouve pas d'issue ouverte correspondant à 'r   issue_clarification_neededuP   J’ai trouvé plusieurs issues possibles. Merci de préciser laquelle utiliser.milestone_not_found0   Je ne trouve pas de milestone correspondant à 'milestone_clarification_neededT   J’ai trouvé plusieurs milestones possibles. Merci de préciser laquelle utiliser.z?Erreur inattendue dans assistant_assign_issue_to_milestone : %sr   uH   Erreur interne lors de l'affectation assistée d'issue à une milestone.)"r   r   r   r   r   r+   r2   r   r   rU   r   resolved_issue_iidresolved_milestone_idr
   rr   r,   r   r-   rC   rD   r/   r   r   r   r   r   r   
issue_hintr   rf   rW   rk   r   r   )rP   r   r   updated_issuemilestone_datard   r1   issue_candidatesmilestone_candidatesrl   rm   r   s               r.   #assistant_assign_issue_to_milestoner     s)   tINJw))++%@@@	
 	
 	

 ''
? %	06688 B#  =A  B  B  B  B)Q..#<}~~~~,11#  =A  B  B  B  B*7+H+N+N+P+PQQG6GDM""G.//G122 M +..{;;ArN8!]]=N=NwXZ=[=[]]gdm,,FB 7 788+.w{{;PRT/U/U+V+V  mD122}U344 !2!27B!?!?@@ !2!27B!?!?@@"=#4#4Y#C#CDD  AK>[_@`@`}es},^<<<y}#%!#%''   , *'*>@QRR
 	8*C#%!#%'
 
 
 
 z??Q:a=#3z!}Q7G"7L#L#L85i#<Z#H#H!#%'
 
 
 
 Q-"''
9*gFXZdee 	8(dgN`ddd$FB 7 788+.w{{;PRT/U/U+V+V 
 #%!#%'       1$$)9!)<Q)?CSTUCVWXCY\^C^)^)^83j$FB 7 788+.w{{;PRT/U/U+V+V 
 #%!89I!J!J%'      =ZI_akll# 	8,e7Kaeee$FB 7 788+.w{{;PRT/U/U+V+V 
 #%!#%'     #$$q((-A!-DQ-GK_`aKbcdKehjKj-j-j87n$FB 7 788+.w{{;PRT/U/U+V+V 
 #%!#%@AU%V%V     (+A.u566	/215d;<<2:y,WW&**;77=24Y9J9J7TV9W9WYY GKK3344'*7;;7Lb+Q+Q'R'R  --..=/00]..w;;<<]..w;;<<}00B??@@  =G~W[<\<\yaoy(888uy!!#'
 
 
 	
,     I I IZ\_`c\d\deee4~  FI  	IIsH   J \ 3\ 7A\ B!\ 2B\ A>\ B\ /F\ ]:]]z/assistant-list-issuesz*Assistant liste des issues d'une milestoner   r   c                   	 t                               dt          j        |                                 d                     t          | j                  }| j                                        	                                }| j
        r.| j                                        st          dd          | j        dk    rt          dd          t          | j                                                  }t          |d	                   }t          |t          | j                            }t!          |          }t#          ||j        ||          }t'          d
dd|j         |t)          |                    dd                    t)          |                    dd                    d||g g           S t-          | j        | j                  }|st'          d
ddd d g g g           S t3          |          dk    rE|d         d         |d         d         dz
  k    r$t'          d
ddd d g t5          |          g           S |d         d         }t          |d	                   }t7          || j        |          }	|	sft'          d
dd| j         d|t)          |                    dd                    t)          |                    dd                    dd g g g           S t3          |	          dk    r|	d         d         |	d         d         dz
  k    rjt'          d
dd|t)          |                    dd                    t)          |                    dd                    dd g g t;          |	                    S |	d         d         }t!          |          }t#          ||j        ||          }t'          d
dd|j         |t)          |                    dd                    t)          |                    dd                    d||g g           S # t          $ r  t<          $ r?}
t                               dt)          |
                     t          dd          |
d }
~
ww xY w) Nu?   Payload reçu sur /api/v1/milestones/assistant-list-issues : %sFr   r   r   rR   r   r   r#   Tr   u'   Issues récupérées pour la milestone r   r&   r   r   )r   r   r   r   r   r   r   r   r   r   r;   r   r   r   r   r   r   r   r   z>Erreur inattendue dans assistant_list_issues_by_milestone : %sr   uK   Erreur interne lors de la récupération assistée des issues de milestone.) r   r   r   r   r   r+   r2   r(   rU   r   r   r   r   r   r
   rt   r/   r   r%   r   r-   r,   r   r   r   r   r   rf   rW   rk   r   r   )rP   r   r   r   r1   r   milestone_itemr   rd   r   r   s              r.   "assistant_list_issues_by_milestoner   t  s   EMJw))++%@@@	
 	
 	

 ''
]((**0022
? !	06688 # #_   
 ,11# #_   
 +7+H+N+N+P+PQQGWT]++J,ZW=Z9[9[\\I/	::N.z>;OQ[]ghhF7!X.BVXX$FB 7 788+.w{{;PRT/U/U+V+V 
 )#%%'    *'*>@QRR
 
	7*C#%%'	 	 	 	 z??Q:a=#3z!}Q7G"7L#L#L75i#<Z#H#H%'	 	 	 	 Q-"''
<ZI_akll# 	7,e7Kaeee$FB 7 788+.w{{;PRT/U/U+V+V 
 #%%'    #$$q((-A!-DQ-GK_`aKbcdKehjKj-j-j77n$FB 7 788+.w{{;PRT/U/U+V+V 
 #%%@AU%V%V    )+A.	+I66*:~7KZYcdd3Tn>RTT GKK3344'*7;;7Lb+Q+Q'R'R 
 %!!#
 
 
 	
       Y[^_b[c[cddd`
 
 
 	s:   F5P 82P +AP B P $BP BP Q./:Q))Q.z/assistant-progressz%Assistant progression d'une milestoner   r   c                   	 t                               dt          j        |                                 d                     t          | j                  }| j        r5| j        	                                st          dd          | j        dk    rt          dd          t          | j        	                                          }t          |d	                   }t          |t          | j                            }t          |          }t          ||j        |          \  }}}}	t#          d
dd|j         |t%          |                    dd                    t%          |                    dd                    d|||||	g g           S t)          | j        | j                  }
|
st#          d
ddd d ddddg g           S t/          |
          dk    rH|
d         d         |
d         d         dz
  k    r't#          d
ddd d ddddt1          |
          g           S |
d         d         }t          |d	                   }t3          || j        |          }|sit#          d
dd| j         d|t%          |                    dd                    t%          |                    dd                    dd ddddg g           S t/          |          dk    r|d         d         |d         d         dz
  k    rmt#          d
dd|t%          |                    dd                    t%          |                    dd                    dd ddddg t7          |                    S |d         d         }t          |          }t          ||j        |          \  }}}}	t#          d
dd|j         |t%          |                    dd                    t%          |                    dd                    d|||||	g g           S # t          $ r  t8          $ r?}t                               dt%          |                     t          dd          |d }~ww xY w) Nu<   Payload reçu sur /api/v1/milestones/assistant-progress : %sFr   r   r   rR   r   r   r#   Tr   u(   Progression calculée pour la milestone r   r&   r   r   )r   r   r   r   r   r   r   r6   r   r   r   r   r   r;   r   r   r   r   r   r   r   r   z;Erreur inattendue dans assistant_progress_by_milestone : %sr   uC   Erreur interne lors du calcul assisté de progression de milestone.)r   r   r   r   r   r+   r2   r   r   rU   r   r   r
   rt   r/   r   r%   r   r-   r,   r   r   r   r   r   rf   rW   rk   r   r   )rP   r   r   r1   r   r   r   r   r6   r   rd   r   r   s                r.   assistant_progress_by_milestoner     sJ   `JJw))++%@@@	
 	
 	

 ''
? )	06688 # #_   
 ,11# #_   
 +7+H+N+N+P+PQQGWT]++J,ZW=Z9[9[\\I/	::N6Q$7 73E66#3 6!Y>CWYY$FB 7 788+.w{{;PRT/U/U+V+V 
 )!1#%%'   $ *'*>@QRR
 	5*C!"#%%'    z??Q:a=#3z!}Q7G"7L#L#L55i!"#<Z#H#H%'    Q-"''
<ZI_akll# 	5,e7Kaeee$FB 7 788+.w{{;PRT/U/U+V+V 
 !"#%%'   $ #$$q((-A!-DQ-GK_`aKbcdKehjKj-j-j57n$FB 7 788+.w{{;PRT/U/U+V+V 
 !"#%%@AU%V%V   $ )+A.	+I662M 3
 3
/vv/ 2U~?SUU GKK3344'*7;;7Lb+Q+Q'R'R 
 %-!!#
 
 
 	
$       VX[\_X`X`aaaX
 
 
 	s:   FP
 5P
 
AP
 %B#P
 	B P
 *BP
 
Q:QQ)r   r    r!   r   )r1   r+   r(   r-   r2   r+   r!   r3   )
r1   r+   r%   r-   r'   r-   r)   r-   r!   r   )r1   r+   rW   r-   r2   r+   r!   rX   )rd   rX   r!   rg   )r1   r+   rl   r+   rm   r+   r!   r    )r1   r+   rm   r+   r!   r    )
r1   r+   ru   r-   r(   r-   r2   r+   r!   rv   )r1   r+   ru   r-   r2   r+   r!   rv   )r1   r+   ru   r-   r2   r+   r!   r   )rP   r   r!   r   )rP   r   r!   r   )rP   r   r!   r   )rP   r   r!   r   )rP   r   r!   r   )5__doc__
__future__r   r   loggingtypingr   fastapir   r   app.api.v1.issuesr   r   r	   r
   r   r   r   r   r   app.schemas.milestonesr   r   r   r   r   r   r   r   r   r   r   r   router	getLogger__name__r   r/   rL   rV   rf   rk   rr   rt   r   r   r   postr   r   r   r   r   rB   r0   r.   <module>r      s    # " " " " "         , , , , , , , ,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                            
.l^	D	D	D		8	$	$	 	 	 	N N N N&) ) ) )8       F   &
 
 
 
	 	 	 	# # # #JB B B B(3 3 3 3, ,1   
JC JC JC 
JCZ .3   
Q| Q| Q| 
Q|h @8   
wI wI wI 
wIr 87   
H H H 
HT 35   
c c c 
c c cr0   