
    Uj                     v	   d dl mZmZmZmZmZ d dlmZ d dlm	Z	 d dl
Z
d dlZd dlZd dlmZ d dlmZ d dlmZ d dlZd dlmZ d d	lmZ d d
lmZ d dlmZ d dlmZ d dlmZ d dlm Z m!Z! d dl"m#Z#m$Z$m%Z%m&Z& d dl'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/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7 dZ8 e9d           n"# e:$ rZ;dZ8 e9de;            Y dZ;[;ndZ;[;ww xY w ed          Z<e<=                    edgdgdg            ed          Z> ed          Z?e>@                    d           e?@                    d           deAdeAfd ZBe<C                    d!          d"             ZDe<E                    d#          d$eAfd%            ZFe<E                    d&          d$eAfd'            ZGe<C                    d(          d)efd*            ZHe<E                    d+           ed,          fd)ed-ee         fd.            ZIe<C                    d/          d0             ZJe<K                    d/          d1             ZLe<E                    d2          d)ed$eAfd3            ZMe<E                    d4          d)ed$eAfd5            ZNe<C                    d6          d7eOfd8            ZPe<C                    d9          d)efd:            ZQe<E                    d;          d)efd<            ZRe<E                    d=          d)efd>            ZSe<E                    d?          d)efd@            ZTe<E                    dA          d)efdB            ZUe<E                    dC          d)efdD            ZVe<E                    dE          d)efdF            ZWe<C                    dG          dHeOd)efdI            ZXe<C                    dJ          dHeOd)efdK            ZYe<C                    dL          dHeOd)efdM            ZZe<C                    dN          dHeOd)efdO            Z[e<C                    dP          dHeOd)efdQ            Z\e<C                    dR          dHeOd)efdS            Z]e<C                    dT          d)efdU            Z^e<C                    dV          dW             Z_e<K                    dX          d7eOfdY            Z`dS )Z    )FastAPI
UploadFileFileHTTPExceptionRequest)CORSMiddleware)FileResponseN)Path)List)datetimeclassify_documentextract_document)validate_extraction)detect_exceptions)perform_rca)generate_capa)generate_full_reportget_base_url)save_sessionload_sessionupdate_sessionclear_session)run_investigation_agent)	get_user_from_tokenregister_userget_user_by_emailverify_passwordcreate_tokenr   r   r   r    )save_uploadsave_three_boomsave_exceptionssave_rcaupdate_rca_confirmation	save_capaupdate_capa_approvalsave_reportTz[DB] Database connectedFz[DB] Database not connected: zFyndo Pharma API)title*)allow_originsallow_methodsallow_headersuploadsreports)exist_okextractionsreturnc                    |                      dg           }t          d |D             d          t          d |D             d          t          d |D             d          d |D             d |D             d |D             d	 |D             d
 |D             t          d |D             i           d	}t          dt          |d                    dt          |d                    dt          |d                    dt          |d                    dt          |d                    dt	          |d                               |S )zj
    Converts nested files[] structure into flat arrays.
    GPT reads ALL files instead of just BMR.
    filesc              3   j   K   | ].}|                     d           |                     d           V  /dS )batch_idNget.0es     AC:\Users\Terasoftware\OneDrive\Desktop\faahhh\fyndo\fyndo\main.py	<genexpr>z&flatten_extractions.<locals>.<genexpr><   s?      PPaeeJ>O>OP!%%
++PPPPPP    Nc              3   j   K   | ].}|                     d           |                     d           V  /dS )product_nameNr7   r9   s     r<   r=   z&flatten_extractions.<locals>.<genexpr>=   s?      \\aeeNF[F[\aeeN33\\\\\\r>   c              3   j   K   | ].}|                     d           |                     d           V  /dS )plantNr7   r9   s     r<   r=   z&flatten_extractions.<locals>.<genexpr>>   s;      GG!gGquuW~~GGGGGGr>   c                 D    g | ]}|                     d g           D ]}|S )
parametersr7   )r:   r;   ps      r<   
<listcomp>z'flatten_extractions.<locals>.<listcomp>?   3    IIIQ|R1H1HIIAqIIIIr>   c                 D    g | ]}|                     d g           D ]}|S )lims_resultsr7   )r:   r;   ls      r<   rF   z'flatten_extractions.<locals>.<listcomp>@   s3    MMMq1553L3LMMaMMMMr>   c                 D    g | ]}|                     d g           D ]}|S )equipment_readingsr7   )r:   r;   eqs      r<   rF   z'flatten_extractions.<locals>.<listcomp>A   s5    [[[a155AUWY;Z;Z[[Rr[[[[r>   c                 D    g | ]}|                     d g           D ]}|S )maintenance_recordsr7   )r:   r;   ms      r<   rF   z'flatten_extractions.<locals>.<listcomp>B   s5    [[[a!%%@UWY:Z:Z[[Q[[[[r>   c                 D    g | ]}|                     d g           D ]}|S )
sop_limitsr7   )r:   r;   ss      r<   rF   z'flatten_extractions.<locals>.<listcomp>C   rG   r>   c              3      K   | ]B}|                     d i                                d          +|                     d           V  CdS )deviation_detailsdeviation_idNr7   r9   s     r<   r=   z&flatten_extractions.<locals>.<genexpr>E   sm       D DA)2..22>BBDQUU&'' D D D D D Dr>   )	r6   r@   rB   rD   rI   rL   rO   rR   rU   z[FLATTEN] params:rD    lims:rI    equipment:rL    maintenance:rO   z sop:rR   z deviation:rU   )r8   nextprintlenbool)r1   r4   flats      r<   flatten_extractionsr_   5   s   
 OOGR((EPPUPPPRVWW\\U\\\^bccGGuGGGNNII%IIIMMEMMM[[5[[[[[5[[[II%III!D D D D DEG
 
 D 
 Wc$|"455 W WSnAU=V=V W W4 4566W WEHNcIdEeEeW WT,'((W W59$?R:S5T5TW W X X X Kr>   /c                  
    ddiS )NstatuszFyndo API running rc   r>   r<   rootrd   O   s    )**r>   z/auth/registerpayloadc                   K   |                      dd                                          }|                      dd                                                                          }|                      dd          }|st          dd          |st          dd          |st          dd	          t	          |          d
k     rt          dd          t          |||          }d|d         |d         |d         |d         ddS )z?
    Register new user
    Body: { name, email, password }
    name emailpassword  zName is required.status_codedetailEmail is required.Password is required.   z'Password must be at least 6 characters.z?Registration successful. Please login to get your access token.id
created_atrr   rg   ri   rs   )messageuser)r8   striplowerr   r\   r   )re   rg   ri   rj   rv   s        r<   registerry   X   s1      {{62&&,,..D{{7B''--//5577E{{:r**H I4GHHHH J4HIIII M4KLLLL
8}}q _4]^^^^uh//D Ut*L']|,	
 
  r>   z/auth/loginc                   K   |                      dd                                                                          }|                      dd          }|st          dd          |st          dd          t	          |          }|st          dd	          t          ||d
                   st          dd	          t          |d         |d         |d                   }d|d         |d         |d         |d         d|ddS )za
    Login with email + password
    Body: { email, password }
    Returns: JWT access token
    ri   rh   rj   rk   ro   rl   rp   i  zInvalid email or password.password_hashrr   rg   zLogin successful.rs   rt   Bearer)ru   rv   access_token
token_type)r8   rw   rx   r   r   r   r    )re   ri   rj   rv   tokens        r<   loginr   x   s6      {{7B''--//5577E{{:r**H J4HIIII M4KLLLLU##D R4PQQQQ8T/%:;; R4PQQQQdT']DLAAE 't*L']|,	
 
 
 
 
r>   z/auth/merequestc                 .   K   t          |           }|ddS )zS
    Get current logged in user info
    Header: Authorization: Bearer <token>
    zToken valid)user_idru   )r   )r   r   s     r<   get_mer      s*       "'**G   r>   z/upload.r4   c                   K   t          |           }t          d|            t                       g }|D ]}t          |j        z  }t          |d          5 }t          j        |j        |           d d d            n# 1 swxY w Y   |	                    |j        t          j                            |          dd           t          |d d d d d d d d           t          t          j                              }t#          d|           t$          r<	 t'          ||           n)# t(          $ r}t          d|            Y d }~nd }~ww xY w||t+          |           d	d
S )Nz[UPLOAD] user_id=wbuploaded)filenamesizerb   )uploaded_filesclassificationsr1   validate
exceptionsrcacapareportchat_idr   z[DB] upload save error: z& files saved. Call /classify-all next.)r   r   ru   )r   r[   r   
UPLOAD_DIRr   openshutilcopyfileobjfileappendospathgetsizer   struuiduuid4r   
DB_ENABLEDr!   	Exceptionr\   )	r   r4   r   r   r   	file_pathfr   r;   s	            r<   upload_filesr      s     !'**G	
'g
'
'(((OOOH  .	)T"" 	-aty!,,,	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	-GOOI.. 
 
 	 	 	 	 "	 	 	 	 	 $*,,G9g&&&  2	2'22222 	2 	2 	20Q0011111111	2 (mmKKK  s*   A>>B	B	D' '
E1EEz/sessionc                     t                      } | sdddS d|                     d          t          |                     dg                     t          |                     d                    t          |                     d                    t          |                     d                    t          |                     d	                    t          |                     d
                    t          |                     d                    t          |                     d                    t          |                     d                    ddS )NemptyzNo files uploaded yet)rb   ru   activer   r   r   r1   r   r   r   r   r   )uploadclassifyextractr   r   r   r   r   )rb   r   r   steps_completed)r   r8   r\   r]   )sessions    r<   get_sessionr      s"   nnG G!.EFFF;;y))gkk*:B??@@7;;'78899W[[):;;<<GKK6677W[[4455w{{<8899E**++V,,--7;;x0011	
 	
	  r>   c                  &    t                       ddiS )Nrb   cleared)r   rc   r>   r<   delete_sessionr      s    OOOi  r>   z/rca-confirmc           	        K   t          |           }t                      }|st          dd          |                    d          }|st          dd          d|                    d          t	          j                                        d          |                    d	          |                    d
          d|d<   t          d|           t          r	 |                    d          }|rZt          ||                    d          |d         d         |                    d	          |                    d
          d           n)# t          $ r}t          d|            Y d }~nd }~ww xY wd|d         dS )Nrk   No session found.rl   r   z!No RCA found. Run /rca-all first.Tconfirmed_by%Y-%m-%d %H:%M:%Scause_idrole)	confirmedr   confirmed_atr   r   human_confirmationr   r   )r   r   r   r   z[DB] rca confirm update error: r   )rb   r   )r   r   r   r8   r   nowstrftimer   r   r%   r   r[   )r   re   r   r   r   r   r;   s          r<   rca_confirmr      s     !'**GnnG I4GHHHH
++e

C Y4WXXXXN33 //0CDDKK
++F##! !C 5#  9
	9kk),,G '$+KK$?$?$'(<$=n$M 'J 7 7#KK//	2 2     	9 	9 	97A7788888888	9 "=Q9RSSSs   A1E 
E3E..E3z/capa-approvec           	        K   t          |           }t                      }|st          dd          |                    d          }|st          dd          d|                    d          t	          j                                        d          |                    d	d
          d|d<   t          d|           t          r	 |                    d          }|rGt          ||                    d          |d         d         |                    d	d
          d           n)# t          $ r}t          d|            Y d }~nd }~ww xY wd|d         dS )Nrk   r   rl   r   z#No CAPA found. Run /capa-all first.Approvedapproved_byr   send_for_executionF)rb   r   approved_atr   plan_approvalr   r   )r   r   r   z [DB] capa approve update error: approved)rb   r   )r   r   r   r8   r   r   r   r   r   r'   r   r[   )r   re   r   r   r   r   r;   s          r<   capa_approver   !  s     !'**GnnG I4GHHHH;;vD [4YZZZZ{{=11|~~../BCC%kk*>FF	 D 64     
:		:kk),,G $W#*;;}#=#=#'#8#G*1++6JE*R*R/ /   
  	: 	: 	:8Q8899999999	: !43HIIIs   AD' '
E1EEz/reports/download/{filename}r   c                    K   t           | z  }|                                st          dd          t          t	          |          d| dd|  i          S )N  zReport not foundrl   zapplication/pdfzContent-Dispositionzattachment; filename=)r   
media_typer   headers)REPORTS_DIRexistsr   r	   r   r   r   s     r<   download_reportr   F  sp      h&I H4FGGGG^^$&(J(J(JK	   r>   z/reports/listc                 ,   t          |           }g }t                                          D ]f}|                                rP|j        dk    rE|                    |j        t          j        	                    |          | d|j         d           gd|iS )Nz.pdfz/reports/download/)r   r   download_urlr/   )
r   r   iterdiris_filesuffixr   rg   r   r   r   )r   base_urlr/   r   s       r<   list_reportsr   S  s    G$$HG  ""  99;; 	18v- 	NNF**#+ G Gqv G G    
 wr>   z/agent-investigatec           
        K   t          |           }t                      }|st          dd          |                    dg           }|st          dd          t	          |           }t          ||           d {V }t          d|                    d                     t          d|                    d                     t          d|                    d                     t          d	|                    d	                     t          d
|                    d
                     t          r	 |                    d          }|sSt          t          j
                              }t          d|           t          ||           t          d|            |r|                    di                               d          og i i |                    di           d}t          |g i i |                    di           d           t          ||                    di                      t          ||                    di                      t!          ||                    d	i                      t#          ||                    d
i                      t          d|            n)# t$          $ r}t          d|            Y d }~nd }~ww xY w|S )Nrk   &No files uploaded. Call /upload first.rl   r   zNo files found in session.r   r   r   r   r   r   r   u'   [DB] Created upload record — chat_id=r6   r   readiness_summaryextraction_summaryr   u)   [DB] Agent all results saved — chat_id=z[DB] Agent save error: )r   r   r   r8   r   r   r   r   r   r   r   r!   r[   r"   r#   r$   r&   r(   r   )	r   r   r   r   r   resultr   three_boom_datar;   s	            r<   agent_investigater   f  s     !'**GnnG ^4\]]]][[!1266N R4PQQQQG$$H*>8DDDDDDDDF :vzz*55666<L!9!9:::5&**U++,,,66::f--...8VZZ11222   1	1kk),,G Kdjll++y'222NG<<<<IIIJJJ M (.zz*b'A'A'E'Ej'Q'Q'XVX)+*, &

:r : :	# #  '))+*, &

:r : :	* *     L")E)EFFF&**UB"7"7888'6::fb#9#9:::GVZZ"%=%=>>>K'KKLLL 	1 	1 	1/A//00000000	1 Ms   9E<J6 6
K KKz/agent/validatec                   K   t          |           }t          d|            	 t                      }|st          dd          |                    dg           }d |D             }t          dt          |           d           d	 |D             }d
 |D             }t          j        t          j        | t          j        |            d {V \  }}t          |          }t          |          }|t          |          d}	t          dt          |           d           |D ]i}
t          d|
                    d           d|
                    d           d|
                    d           d|
                    d                      jt          dt          |           d           |D ]}t          d|                    d           dt          |                    dg                      dt          |                    dg                      dt          |                    dg                      dt          |                    dg                      
           t          |	          }t          d|           t          d|	           t          d |           g d!}t          d" |D                       fd#|D             }t          fd$|D                       }t          |          |z
  }t          d% |D                       }t          |t          |          z  d&z            t          |          | d't          |           |||d(k    rd)nd*|d+}|                    d,          |                    d-          |                    d          pg |                    d          pg |                    d          pg |                    d          pg |                    d.          pg |                    d/          pi d0}t          d1           t          |           d {V }t          d2|           t          d3 |                    d4g           D                       }t          d5|            t          t          d6 |                    dg           D                                 }t          t          d7 |                    dg           D                                 }t          d8 |                    d4g           D                       }g }|D ]}|                    dd9          d d:         }|                    d          r|                    d;| d<           |                    d          r|                    d=| d<           |                    d          r|                    d>| d<           |                    d          r|                    d?| d<           t          |          }| d'| t          |                    dg                     t          |                    dg                     t          |                    dg                     t          |                    dg                     t          |                    d.g                     ||||d d@         dA
}t           rW	 |                    dB          }|rt#          |||||dC           n)# t$          $ r}t          dD|            Y d }~nd }~ww xY wd2dE||||dFS )GNz[AGENT/VALIDATE] user_id=rk   r   rl   r   c                 .    g | ]}t           |d          z  S )r   )r   r:   r   s     r<   rF   z'agent_step_validate.<locals>.<listcomp>  s!    EEE*q},EEEr>   z1[AGENT/VALIDATE] Starting classify + extract for z	 files...c                 ,    g | ]}t          |          S rc   r   r:   fps     r<   rF   z'agent_step_validate.<locals>.<listcomp>  s!    AAA'++AAAr>   c                 ,    g | ]}t          |          S rc   r   r   s     r<   rF   z'agent_step_validate.<locals>.<listcomp>  s!    ???b%b))???r>   )r4   total_filesz[AGENT/VALIDATE] Classified z filesz  -> r   z | document_type
confidencez% | verification_statusz[AGENT/VALIDATE] Extracted z
 | params:rD   rW   rI   rX   rL   rY   rO   r   r1   r^   )BMRSOPEQPLIMSMAINTDEVc              3   @   K   | ]}|                     d           V  dS )document_type_codeNr7   r:   cs     r<   r=   z&agent_step_validate.<locals>.<genexpr>  s/      KKaaee011KKKKKKr>   c                 "    i | ]}||v rd ndS )FOUNDMISSINGrc   r:   codefound_codess     r<   
<dictcomp>z'agent_step_validate.<locals>.<dictcomp>  s)    ZZZ$+"5Dww9ZZZr>   c              3   $   K   | ]
}|v d V  dS )   Nrc   r   s     r<   r=   z&agent_step_validate.<locals>.<genexpr>  s-      DDD0CDaDDDDDDr>   c              3   N   K   | ] }|                     d d          dk     dV  !dS )r   r   K   r   Nr7   r   s     r<   r=   z&agent_step_validate.<locals>.<genexpr>  s:      MM|Q1G1G"1LM1MMMMMMr>   d   r`   r   READYPARTIAL)progress_to_next_phasefiles_uploadedrequired_types_foundrequired_files_missinglow_confidence_filesready_to_process	checklistr6   r@   rR   rU   )r6   r@   rD   rI   rL   rO   rR   rU   z)[AGENT/VALIDATE] Validating parameters...r   c              3   L   K   | ]}|                     d           dk    dV   dS )validation_status	DEVIATIONr   Nr7   r:   rs     r<   r=   z&agent_step_validate.<locals>.<genexpr>  sU       C C1122kACQ C C C C C Cr>   validation_rowsu,   [AGENT/VALIDATE] Done — deviations found: c              3   j   K   | ].}|                     d           |                     d           V  /dS )operator_idNr7   r:   rM   s     r<   r=   z&agent_step_validate.<locals>.<genexpr>   sT        "$66-  
}     r>   c              3   j   K   | ].}|                     d           |                     d           V  /dS )equipment_idNr7   r  s     r<   r=   z&agent_step_validate.<locals>.<genexpr>  sT        #%66.!!
~     r>   c              3   H   K   | ]}|                     d           dv dV  dS )r  )r  zNeeds Reviewr   Nr7   r  s     r<   r=   z&agent_step_validate.<locals>.<genexpr>  sV       Q QqEE-..2OOQ Q Q Q Q Q Qr>   rh      zChecking calibration logs for z...z Cross-referencing LIMS data for z+Awaiting equipment maintenance records for zMatching batch parameters for    )
files_processedparameters_extractedlims_results_extractedequipment_readings_extractedmaintenance_records_extractedsop_limits_extractedoperators_foundequipment_foundvalidation_issues_foundactivity_logr   r   z [DB] agent/validate save error: /agent/exceptions)step	next_stepr   r   r   r   )r   r[   r   r   r8   r\   asynciogatherlistr_   r   setsumintr   r   r   r"   r   )r   r   r   r   
file_pathsclassify_tasksextract_tasksr   r1   combinedr   r;   r^   requiredr  types_foundmissinglow_confr   	safe_flatvalidate_result
deviationsr  r  issuesr  fnamenr   r   r   s                                 @r<   agent_step_validater4    s		     !'**G	
/g
/
/000 nnG ^4\]]]][[!1266NEEnEEEJ	
\c.>Q>Q
\
\
\]]] BAjAAAN??J???M)0'&* * $ $ $ $ $ $ O[
 ?++O{##K$S5E5EFFH	
E_)=)=
E
E
EFFF @ @~aeeJ''~~AEE/,B,B~~quu\GZGZ~~`a`e`ef{`|`|~~	
@K(8(8
@
@
@AAA Z Z  YaeeJ''  Y  Y3quu\"7M7M3N3N  Y  YVYZ[Z_Z_`noqZrZrVsVs  Y  Y  AD  EF  EJ  EJ  K_  `b  Ec  Ec  Ad  Ad  Y  Y  sv  wx  w|  w|  }R  SU  wV  wV  sW  sW  Y  Y  	Z  	Z  	Z  	Z x((D $o666=(+++64    =<<HKK?KKKKKKZZZZQYZZZIDDDDHDDDDDK(mmk)GMMoMMMMMH"%{S]]'Bc&I"J"Jo..#. @ @X @ @") ('.!|BGG  HHZ((00hh|,,2006B"hh';<<B#xx(=>>D"hh|,,2!XX&9::@b	 	I 

6777/	::::::::O:/// C C 3 34Er J J C C C C CJ	
E
E
EFFF 3  (,1Er(J(J      O 3  )-2F)K)K      O  Q QO//0A2FF Q Q Q Q QF L 	M 	Mj"%%crc*55%&& 	M K K K KLLL55   	O M5 M M MNNN55&'' 	Z Xe X X XYYY55 	M K K K KLLLKA::!:: #DHH\2$>$> ? ?"%dhh~r&B&B"C"C(+DHH5I2,N,N(O(O),TXX6KR-P-P)Q)Q #DHH\2$>$> ? ?**#)$RaR(   :
	:kk),,G '6):*< /	* *     	: 	: 	:8Q8899999999	: (*.0#  s   $,\ 
\7\22\7r  c                 x
  K   t          |           }	 t                      }|st          dd          |                    d          }|sG|                    d          }|st          dd          t	          |          }t          d|           |                    d          }t          |          }|rud |                    d	g           D             }||d
<   |                    d          |d<   |                    d          |d<   t          dt          |           d           t          |           d {V }i }	|                    dg           D ]K}
t          |
                    dd                    d d         }|
                    d          }|r|r||	|<   L|                    dg           D ]}|                    d          snt          |                    dd                    d d         }|	                    |          p*|	r't          |	                                          d         nd |d<   i }|                    dg           D ]}t          |                    dd                                                                                    t          |                    dd                                                    }t          |                    dd                                                    }rd|v sd|v rd|<   |                    dg           D ]w}t          |                    dd                                                    t          fd|                                D             d           }|r||d <   |dk    rd!|d"<   x|                    d#i           }|                    d$|          }|                    d%          p|                    d           }|dk    r@|                    d&          rd|d&         d'<   |                    d(          rd|d(         d)<   t#          d* |                    dg           D                       }t#          d+ |                    dg           D                       }|                    d&          r||d&         d<   ||d&         d,<   t          d|           t$          rR	 |                    d-          }|rt'          ||           n)# t(          $ r}t          d.|            Y d }~nd }~ww xY wdd/|d0S )1Nrk   z%No session found. Call /upload first.rl   r^   r1   .No extracted data. Call /agent/validate first.r   c                 D    g | ]}|                     d           dk    |S r  r  r7   r  s     r<   rF   z)agent_step_exceptions.<locals>.<listcomp>W  sE     G G GEE"566+EG! G G Gr>   r
  validated_deviation_rowscompliance_scorealcoa_checklistz[AGENT/EXCEPTIONS] Passing z, validated deviation rows from previous steprL   	timestamprh      r  r   operatorr   rR   parameter_namecriticalityaction_if_exceededcriticalzstop immediatelyCritical	parameterc              3   2   K   | ]\  }}|v s|v |V  d S )Nrc   )r:   kvparams      r<   r=   z(agent_step_exceptions.<locals>.<genexpr>x  s:      ZZdaeZuXYzZZZZZZZr>   severityTis_critical_compliancerU   deviation_recordSeveritysummary
risk_level
batch_risklevelc              3   L   K   | ]}|                     d           dk    dV   dS )rI  rC  r   Nr7   r9   s     r<   r=   z(agent_step_exceptions.<locals>.<genexpr>  s9      ^^aeeJ>O>OS]>]^1^^^^^^r>   c              3   L   K   | ]}|                     d           dk    dV   dS )rI  Majorr   Nr7   r9   s     r<   r=   z(agent_step_exceptions.<locals>.<genexpr>  s9      XXa155;L;LPW;WXXXXXXXr>   majorr   z"[DB] agent/exceptions save error: 
/agent/rca)r  r  r   )r   r   r   r8   r_   r   dictr[   r\   r   r   r"  valuesrx   rw   rZ   itemsr$  r   r#   r   )r   r   r   r^   r1   r/  enriched_flatdeviation_rowsr   op_maprM   tsopexsop_criticalitysopr@  actionmatched	deviation
dev_recordreal_severityrB  rT  r   r;   rH  s                             @r<   agent_step_exceptionsrf  =  s     !'**G
 nnG ]4[\\\\;;vD %kk-00 	jC8hiiii";//vt$$$ kk*--O JJM oG G_%8%89JB%O%O G G G4B01,;,?,?@R,S,S()+:+>+>?P+Q+Q'(mC,?,?mmmnnn$]33333333F Fhh+R00  R(())#2#.VVM"" 	" 	F2Jjjr** ^ ^vvj!! 	^RVVK,,--crc2B#ZZ^^]F0\V]]__0E0Ea0H0HX\BzN Oxxb)) 0 0CGG,b112288::@@BB#''-4455;;==SWW126677==?? 	0jK/ 	03E3O 	0%/OE"jjr** 4 4BFF;++,,2244ZZZZo&;&;&=&=ZZZ\`aa 	4$BzN*$ 4/3+, ,b11I19==JNN:..L*..2L2LM
" 7::i   	9.8F9l+::l## 	7,6F< ) ^^fjjr::^^^^^HXX6::lB77XXXXXEzz) +(0y*%%*y'"<((( <	<kk),,G 1000 	< 	< 	<:q::;;;;;;;;	< !  s   %'T 
T3T..T3rU  c                 8  K   t          |           }	 t                      }|st          dd          |                    d          }|sG|                    d          }|st          dd          t	          |          }t          d|           |                    d          }|                    d          }|st          dd	          |                    d
g           }d |D             }d |                    dg           D             }	||||	d d         |r|                    d          nd t          d |pi                     dg           D                       |r|                    d          nd dd}
t          |
           d {V }i }|                    dg           D ]K}t          |                    dd                    d d         }|                    d          }|r|r|||<   L|                    di                               dg           }d |D             }t          d |D             d          }t          d |D             d          }t          d |D             d          }t          d |D             d          }t          d |D             d          }|                    d i                               d!g           D ]}|                    d          snt          |                    dd                    d d         }|                    |          p*|r't          |                                          d"         nd |d<   t          |                    d#          pd                              d$          r|p||d#<   |                    d%g           D ]}|                    d          snt          |                    dd                    d d         }|                    |          p*|r't          |                                          d"         nd |d<   t          |                    d&d                    }|r*|                    d$          s|                    d'          r|p||d&<   |d d(         D ]}d) |                    d%g           D             }|                    d*          |vr|                    d%g                               |pd+|                    d*d          |                    d,d          t          |                    d-d                    |                    d.d          d/           |                    d0          rd1 |||||fD             |d0         d2<   |                    d3i           }|                    d4|          }|                    d5          d6k    s|                    d7          d6k    rd6|d0         d8<   |                    d9          i |d9<   t          |          |d9         d:<   t          d;|           t          rR	 |                    d<          }|rt!          ||           n)# t"          $ r}t%          d=|            Y d }~nd }~ww xY wd;d>|d?S )@Nrk   r   rl   r^   r1   r6  r   r   z2No exceptions found. Call /agent/exceptions first.rO   c           	      \   g | ]}d t          |                    dd                                                    v sndt          |                    dd                                                    v s7dt          |                    dd                                                    v |S )overduerb   rh   driftobservationurgent)r   r8   rx   r:   rP   s     r<   rF   z"agent_step_rca.<locals>.<listcomp>  s     J J JQ Ch(;(;$<$<$B$B$D$DDJ#aeeM2&>&>"?"?"E"E"G"GGJ  3quu]B'?'?#@#@#F#F#H#HHJq J J Jr>   c                     g | ];}t          |                    d d                                                    dv 9|<S )rb   rh   )ALERTr  )r   r8   upperr9   s     r<   rF   z"agent_step_rca.<locals>.<listcomp>  s[     U U UAQUU8R00117799=SSUa U U Ur>   rL      r:  c                 D    g | ]}|                     d           dk    |S r8  r7   r  s     r<   rF   z"agent_step_rca.<locals>.<listcomp>  sE     $R $R $R!'(uu-@'A'A['P$RA $R $R $Rr>   r
  r;  )r:  deviation_countr;  )extracted_datar   key_maintenance_recordsalert_equipment_readingsvalidation_summaryr<  rh   r=  r  r4   c                 d    g | ]-}|                     d           |                     d d          .S )r   rh   r7   r   s     r<   rF   z"agent_step_rca.<locals>.<listcomp>  s7    UUU155CTCTUaeeJ++UUUr>   c              3   "   K   | ]
}d |v |V  dS )	EquipmentNrc   r   s     r<   r=   z!agent_step_rca.<locals>.<genexpr>  s,      EEQK14DEqEEEEEEr>   c              3   "   K   | ]
}d |v |V  dS )MaintenanceNrc   r   s     r<   r=   z!agent_step_rca.<locals>.<genexpr>  s,      GGQMQ4FGqGGGGGGr>   c              3   "   K   | ]
}d |v |V  dS )BatchNrc   r   s     r<   r=   z!agent_step_rca.<locals>.<genexpr>  s+      CCqglCCCCCCCr>   c              3   "   K   | ]
}d |v |V  dS )r   Nrc   r   s     r<   r=   z!agent_step_rca.<locals>.<genexpr>  s+      ??A6Q;?a??????r>   c              3   "   K   | ]
}d |v |V  dS )	DeviationNrc   r   s     r<   r=   z!agent_step_rca.<locals>.<genexpr>  s,      CC1+2BCQCCCCCCr>   cluster_contextvertical_timeliner   source_filefile_supporting_evidencer   temperature   c                 8    g | ]}|                     d           S )	referencer7   r9   s     r<   rF   z"agent_step_rca.<locals>.<listcomp>  s$    VVV1AEE+&&VVVr>   work_order_idzMaintenance_Log.csvrk  maintenance_dateperformed_by)r   r  rn   r<  r  investigation_summaryc                     g | ]}||S rc   rc   r   s     r<   rF   z"agent_step_rca.<locals>.<listcomp>  s5     G
 G
 G
VWG
G
 G
 G
r>   supporting_evidence_refsrU   rK  rL  rC  rI  rN  analysis_metadatadata_sources_countr   r   z[DB] agent/rca save error: /agent/capa)r  r  r   )r   r   r   r8   r_   r   r\   r   r   rZ   r"  rW  
startswith
setdefaultr   r   r$   r   r[   ) r   r   r   r^   r1   r/  r   maintenancekey_maintenancealert_readings	rca_inputr   r[  rM   r\  r]  
real_filesreal_filenames
equip_file
maint_fileprimary_file	lims_filedev_fileitemevr2  rP   existingrc  rd  r   r;   s                                    r<   agent_step_rcar    s     !'**G
 nnG I4GHHHH;;vD %kk-00 	jC8hiiii";//vt$$$kk*--O\**J j4hiiii ((0"55KJ J+ J J JO
U U*>!C!C U U UN  #2$22A2$6 L[ d 3 34F G G G`d" $R $R0E2/J/JK\^`/a/a $R $R $R  S  SIXb223DEEE^b	
 
 I y))))))))F Fhh+R00  R(())#2#.VVM"" 	" 	F2J]B//33GR@@JUUZUUUNEE.EEErJJJGG.GGGLLJCCNCCCRHHL?????DDICCCCCRHHH

,b11556I2NN = =xx&& 	cTXXk2..//4B"(**R.."bQW5aT&--//5J5J15M5M]aDtxx&&,"--88AA 	=","<Djj.33 8 8vvm$$ 	aRVVK,,--crc2B &

2 `v3_43H3H3K3K[_B}BFF:r**++ 	8((11 	8U5E5Em5T5T 	8'7<BzN RaR  	 	VV

;PRT0U0UVVV55!!1 	3R88??&?*?UU?B77%%r22 '92!>!>?? uu^R88A A    zz)** GG
 G
$j*iRG
 G
 G
&'(BC HH0"55	]]#5yAA
>>*%%3 	Gz~~j7Q7QU_7_ 	G<FF*+L9zz%&& )&("#8;N8K8KF 455&!!! 5	5kk),,G *&))) 	5 	5 	533344444444	5 "  s   'Y- -
Z7ZZr  c                   K   t          |           }	 t                      }|st          dd          |                    d          }|s7|                    d          }|st          dd          t	          |          }|                    d          }|                    d          }|r|st          dd	          |||d
}t          |           d {V }|                    di           }	|	                    d|	          }
|
                    d          p|
                    d          }|
                    d          p|
                    d          }|r||d<   |r0||d<   |                    d          r||d         d<   d|d         d<   t          d|           t          rR	 |                    d          }|rt          ||           n)# t          $ r}t          d|            Y d }~nd }~ww xY wdd|dS )Nrk   r   rl   r^   r1   r6  r   r   z+Run /agent/exceptions and /agent/rca first.)rt  r   r   rU   rK  Deviation_IDrV   rL  rI  impact_assessmentpre_capa_riskLowresidual_riskr   r   z[DB] agent/capa save error: /agent/report)r  r  r   )r   r   r   r8   r_   r   r   r   r&   r   r[   )r   r   r   r^   r1   r   r   
capa_inputr   rc  rd  real_dev_idre  r   r;   s                  r<   agent_step_capar    s     !'**G
 nnG I4GHHHH;;vD 0kk-00 	jC8hiiii";//\**J
++e

C cS c4abbbb   J
 !,,,,,,,,F ,b11I19==J..00RJNN>4R4RKNN:..L*..2L2LM -!,~ A*z::)** 	A;HF&'8;@F&'866""" 6	6kk),,G +'6*** 	6 	6 	644455555555	6 $  s   -'G 
G;G66G;r  c                   K   t          |           }	 t                      }|st          dd          |                    d          }|s7|                    d          }|st          dd          t	          |          }|                    d          }|                    d          }|                    d	          }|r|r|st          dd
          t          |           }||||d}	t          |	|           d {V }
|                    di           }|                    d|          }|                    d          p|                    d          }|r |
                    d          r||
d         d<   i }|                    dg           D ]K}t          |                    dd                    d d         }|                    d          }|r|r|||<   L|r't          |	                                          d         nd }|r`|
                    di                               d          r7|
d         d         }dD ]}|
                    |d|           }||
d         d<   dd l}|                    dg           }t          d |D             d           }|r&|                    dd          }t          |                    dd                    }|                    d |          }|rd!|                    d"           d#nd }t          |                    d$i                               d%d                    }|                    d&||j                  }|r|                    d"           d'nd }|
                    di                               d(          r|
d         d(         }t          |                    d)d                    } d*D ]}!| 
                    |!|          } |r|                    d+||           } |r]|                    d,d-| |           } t          |                    d.d                    }"d/D ]}!|"
                    |!|          }"|"|d.<   | |d)<   |
                    di                               d0          r0d/D ]-}!|
d         d0         
                    |!|          |
d         d0<   .|                    d1i           }#|#                    d2d          }$|$r|
                    d          rd3D ]}%|
d                             |%          }&t#          |&t$                    rN|&                                D ]8\  }'}(t#          |(t                    rd4|(v r|                    d5|$|(          |&|'<   9t#          |&t                    r$d4|&v r |                    d5|$|&          |
d         |%<   |
                    di                               d6          r-|
d         d6         D ]})|)                    d7          d8v rd9|)d7<   |
                    d:          r)|
d:         D ] }*|*                    d7          d;k    rd<|*d7<   !t)          d=|
           t*          rR	 |                    d>          }+|+rt-          |+|
           n)# t.          $ r},t1          d?|,            Y d },~,nd },~,ww xY wd=d |
|
                    d@          |
                    dA          dBdCS )DNrk   r   rl   r^   r1   r6  r   r   r   z#Run all previous agent steps first.)rt  r   r   r   rU   rK  rL  rI  report_metadatarL   r<  rh   r=  r  r   sectionsdeviation_description)zoperator ID was not recordedz The operator ID was not recordedzoperator not recordedzoperator ID: rO   c              3   d   K   | ]+}d t          |                    dd                    v '|V  ,dS )0401r  rh   N)r   r8   rm  s     r<   r=   z$agent_step_report.<locals>.<genexpr>  sC      bbA#aeeO]_F`F`BaBa8ababbbbbbr>   r  zWO-2024-0401rk  z[+](\d+\.?\d+|\d+)+r   u   °CEquipment_DetailsCalibration_Statusz(\d+)\s*days?\s*past\s*duez daysroot_cause_analysisprobable_cause)WO-2024-0456WO-2024-045zWO-2024-046u   [+]\d+\.?\d*°Czoverdue by \d+ dayszoverdue by 
conclusion)r  r  capa_summaryLinked_RecordsOOS_Reference)r  r  executive_summaryr  OOSz0OOS[-\s]?\d{4}[-\s]?\d{4}|OOS[-\s]?\d{4}|OOS-\d+regulatory_compliancerb   )zNon-CompliantfailzUnder Reviewcompliance_checklistr  warnr   r   z[DB] agent/report save error: r   pdf_filename	completed)r  r  r   r   r  rb   )r   r   r   r8   r_   r   r   r   r"  rW  replacererZ   searchgroup
IGNORECASEsub
isinstancerV  rX  r   r   r(   r   r[   )-r   r   r   r^   r1   r   r   r   r   report_inputr   rc  rd  re  r[  rM   r\  r]  first_opdescphraser  rO   	breakdownwo_idobsdrift_match
real_drift
cal_statusoverdue_matchreal_overduerca_secprobablewrong_wor  linkedreal_oossection_keysecrF  rG  regr  r   r;   s-                                                r<   agent_step_reportr  Z  s     !'**G
 nnG I4GHHHH;;vD 0kk-00 	jC8hiiii";//\**J
++e

C;;vD [S [ [4YZZZZG$$H 	 L (h????????F ,b11I19==JNN:..L*..2L2LM >$566 >0= !*- Fhh+R00  R(())#2#.VVM"" 	" 	F2J+1;tFMMOO$$Q''tH ;FJJz2..223JKK ;j!"9:s 	D 	DF<<(B(B(BCCDD6:z23 III((#8"==bb!4bbbdhiiI qo~>>)--r2233ii 5s;;6AK2**1--2222t
(;R@@DDEY[]^^__
		"?R][[;HR---a007777d::j"%%))*?@@ 	1Z()>?G7;;'7<<==HJ = =#++He<< L66"4j(KK 366"8:V:V:VX`aa \2!>!>??
 ? E EH!+!3!3He!D!DJJ(2%(0G$%::j"%%)).99 	q; q q5;J5G5W5_5_`hjo5p5pz">22 ^^,b11Fzz/2..H }FJJz** }j 	} 	}K$((55C#t$$ }IIKK j jDAq!!S)) jeqj j!#([]egh!i!iAj C%% }%3, }24&&9lnvx{2|2|z";/ zz*b!!%%&=>> /*%&=> 	/ 	/Cwwx  $== / .Hzz()) (12 	( 	(Dxx!!V+ (!'X8V$$$ 8	8kk),,G -GV,,, 	8 	8 	8616677777777	8 

>22

>22  s   5'Z 
['Z>>[z/agent/validate/{chat_id}r   c                 `  K   t          |          }t          st          dd          	 dd l}dd l}dd l}|                     |j        d                    }|                                }|	                    d| f           |
                                }|                                 |                                 |st          dd          | d	d
|d         |d         |d         |d         dS # t          $ r  t          $ r#}	t          dt          |	                    d }	~	ww xY w)N  Database not connected.rl   r   DATABASE_URLzjSELECT validate, classifications, readiness_summary, extraction_summary FROM three_boom WHERE chat_id = %sr   z(No validate data found for this chat_id.r   r  r   r     )r   r  r  r   r   r   r     )r   r   r   psycopg2jsonr   connectgetenvcursorexecutefetchonecloser   r   )
r   r   r   r  r  r   conncurrowr;   s
             r<   get_agent_validater    sl     !'**G O4MNNNN<!!!!!!!!!!!!		. 9 9::kkmmxJ	
 	
 	
 llnn		

 	dC8bcccc,A"1v!$Q"%a&
 
 	
     < < <CFF;;;;<s   C
C6 6D-
D((D-z/agent/exceptions/{chat_id}c                 ,  K   t          |          }t          st          dd          	 dd l}dd l}|                     |j        d                    }|                                }|                    d| f           |	                                }|
                                 |
                                 |st          dd          | d	|d         d
S # t          $ r  t          $ r#}t          dt          |                    d }~ww xY w)Nr  r  rl   r   r  2SELECT response FROM exceptions WHERE chat_id = %sr   z*No exceptions data found for this chat_id.r   )r   r  r   r  r   r   r   r  r   r  r  r  r  r  r  r   r   	r   r   r   r  r   r  r  r  r;   s	            r<   get_agent_exceptionsr    s5     !'**G O4MNNNN<		. 9 9::kkmmH7*UUUllnn		

 	fC8deeee"LAOOO    < < <CFF;;;;<   B0C D0DDz/agent/rca/{chat_id}c                 ,  K   t          |          }t          st          dd          	 dd l}dd l}|                     |j        d                    }|                                }|                    d| f           |	                                }|
                                 |
                                 |st          dd          | d	|d         d
S # t          $ r  t          $ r#}t          dt          |                    d }~ww xY w)Nr  r  rl   r   r  +SELECT response FROM rca WHERE chat_id = %sr   z#No RCA data found for this chat_id.r   )r   r  r   r  r  r  s	            r<   get_agent_rcar    s5     !'**G O4MNNNN<		. 9 9::kkmmAG:NNNllnn		

 	_C8]^^^^"E#a&AAA    < < <CFF;;;;<r  z/agent/capa/{chat_id}c                 ,  K   t          |          }t          st          dd          	 dd l}dd l}|                     |j        d                    }|                                }|                    d| f           |	                                }|
                                 |
                                 |st          dd          | d	|d         d
S # t          $ r  t          $ r#}t          dt          |                    d }~ww xY w)Nr  r  rl   r   r  ,SELECT response FROM capa WHERE chat_id = %sr   z$No CAPA data found for this chat_id.r   )r   r  r   r  r  r  s	            r<   get_agent_capar  0  s5     !'**G O4MNNNN<		. 9 9::kkmmBWJOOOllnn		

 	`C8^____"FCFCCC    < < <CFF;;;;<r  z/agent/report/{chat_id}c                 H  K   t          |          }t          st          dd          	 dd l}dd l}|                     |j        d                    }|                                }|                    d| f           |	                                }|
                                 |
                                 |st          dd          | d	|d         |d
         |d         dS # t          $ r  t          $ r#}t          dt          |                    d }~ww xY w)Nr  r  rl   r   r  KSELECT response, pdf_filename, download_url FROM reports WHERE chat_id = %sr   z!No report found for this chat_id.r   r   r  )r   r  r   r  r   r  r  r  s	            r<   get_agent_reportr  F  sO     !'**G O4MNNNN<		. 9 9::kkmmadkcmnnnllnn		

 	]C8[\\\\!fFF
 
 	
     < < <CFF;;;;<s   B>C* *D!>DD!z/agent/all/{chat_id}c           	      N  K   t          |          }t          st          dd          	 ddl}ddl}|                     |j        d                    }|                                }|                    d| f           |	                                }|r|d         nd}|                    d| f           |	                                }|r|d         nd}	|                    d	| f           |	                                }|r|d         nd}
|                    d
| f           |	                                }|r|d         nd}|                    d| f           |	                                }|r|d         nd}|r|d         nd}|r|d         nd}|
                                 |
                                 t          ||	|
||g          st          dd          | ||	|
||||dS # t          $ r  t          $ r#}t          dt          |                    d}~ww xY w)zj
    Get all steps for a chat_id in one call
    Returns: validate + exceptions + rca + capa + report
    r  r  rl   r   Nr  z2SELECT validate FROM three_boom WHERE chat_id = %sr  r  r   r  r   r  r   zNo data found for this chat_id.)r   r   r   r   r   r   r  r   r  )r   r   r   r  r   r  r  r  r  r  r  anyr   r   )r   r   r   r  r   r  r  r  r   r   r   r   r   r  r   r;   s                   r<   get_agent_allr  b  s{      "'**G O4MNNNN3<		. 9 9::kkmm 	H7*UUUllnn *3q66d 	H7*UUUllnn",SVV
 	AG:NNNllnn%c!ff 	BWJOOOllnn&s1vv$ 	adkcmnnnllnn(QD!$.s1vv$!$.s1vv$		

Hj#tV<== 	[C8YZZZZ  $((	
 	
 		
     < < <CFF;;;;<s   GG- -H$HH$z/investigationsc                   K   t          |           }t          st          dd          	 ddl}ddl}|                     |j        d                    }|                                }|                    d           |	                                }|
                                 |
                                 t          |          d |D             d	S # t          $ r#}t          d
t          |                    d}~ww xY w)z\
    Get list of all investigations
    Returns: chat_id, batch_id, created_at for each
    r  r  rl   r   Nr  an  
            SELECT u.chat_id, u.batch_id, u.total_files, u.created_at,
                   e.risk_level, e.total_exceptions,
                   r.pdf_filename, r.download_url
            FROM uploads u
            LEFT JOIN exceptions e ON e.chat_id = u.chat_id
            LEFT JOIN reports r ON r.chat_id = u.chat_id
            ORDER BY u.created_at DESC
        c                     g | ]J}|d          |d         |d         t          |d                   |d         |d         |d         |d         dKS )	r   r   r  r     rq  rq      )r   r6   r   rs   rN  total_exceptionsr  r   )r   )r:   r  s     r<   rF   z*get_all_investigations.<locals>.<listcomp>  so          #1v #A#&q6"%c!f++"%a&(+A$'F$'F	 	  r>   )totalinvestigationsr  )r   r   r   r  r   r  r  r  r  fetchallr  r\   r   r   )r   r   r  r   r  r  rowsr;   s           r<   get_all_investigationsr    s/      "'**G O4MNNNN!<		. 9 9::kkmm  	 	 	 ||~~		

YY     
 
 	
   < < <CFF;;;;<s   B+C 
D!C??Dz/filesc                     g } t                                           D ]h}|                                rR|                     |j        t
          j                            |          |j        	                                d           id| iS )N)r   r   	extensionr4   )
r   r   r   r   rg   r   r   r   r   rx   )r4   r   s     r<   
list_filesr    s    E!!  99;; 	LLF**X^^--    
 Ur>   z/files/{filename}c                     t           | z  }|                                st          dd          t          j        |           d| iS )Nr   zFile not foundrl   deleted)r   r   r   r   remover   s     r<   delete_filer    sP    X%I F4DEEEEIix  r>   )afastapir   r   r   r   r   fastapi.middleware.corsr   fastapi.responsesr	   r   r   r   pathlibr
   typingr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   agentr   authr   r   r   r   r    databaser!   r"   r#   r$   r%   r&   r'   r(   r   r[   r   r;   appadd_middlewarer   r   mkdirrV  r_   r8   rd   postry   r   r   r   r   deleter   r   r   r   r   r   r   r4  rf  r  r  r  r  r  r  r  r  r  r  r  r  rc   r>   r<   <module>r&     s	   E E E E E E E E E E E E E E 2 2 2 2 2 2 * * * * * * 				                      & & & & & & $ $ $ $ $ $ ( ( ( ( ( ( ( ( ( ( ( (             5 5 5 5 5 5 5 5 M M M M M M M M M M M M ) ) ) ) ) ) g  g  g  g  g  g  g  g  g  g  g  g  g  g  g  g  g  g  g  g  g  g
/                   
 J	E
#$$$$ / / /J	E
-!
-
-......../ g&'''   %%%	     T)__
d9oo 
  $       4       T d    4 + + + 
D    > -         F 	' 	 	 	 	0 )CG499 * * *Z0@ * * * *X   * J! ! !
 .Tw T T T T TD /J J$ J J J JH 	'((	C 	 	 	 )(	 
 ' 
  
  
  
 $ 
7W 7 7 7  7D 
Pw P P P Pf 
_ _ _ _ _D ,x' x x x xv -:7 : : : :z /W    P 	$%%<c <G < < < &%<@ 	&''< <g < < < ('<* 	  < <w < < < ! <* 	 !!<# < < < < "!<* 	"##<C <' < < < $#<6 	  ;< ;<w ;< ;< ;< ! ;<| 	)<' )< )< )< )<` 	 	 	   !# ! ! ! ! ! ! !s   !B4 4C9CC