
    j                       U d Z ddlm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	Z	ddl
mZ ddlmZmZ ddlmZ ddlmZmZmZmZmZ  eej,                  j/                  dd	            Z ee      j5                         j6                  j6                  Z ee      e	j<                  vr"e	j<                  j?                  d ee             dd
l m!Z!m"Z"m#Z# eZ$de%d<   erddl&m$Z$ d Z'd Z(d Z)d Z* ejV                  e,      Z-edej\                  f   Z/d+dZ0d,dZ1d-dZ2d.dZ3	 d/	 	 	 	 	 	 	 d0dZ4ddd	 	 	 	 	 	 	 	 	 d1dZ5dd	 	 	 	 	 	 	 	 	 d2dZ6dd	 	 	 	 	 d3dZ7dd	 	 	 	 	 d4dZ8ddd	 	 	 	 	 	 	 	 	 d5d Z9dd	 	 	 	 	 	 	 	 	 d6d!Z:ddd7d"Z;dd	 	 	 	 	 	 	 	 	 	 	 d8d#Z<d9d$Z=	 	 	 	 	 	 	 	 d:d%Z>	 	 	 	 	 	 	 	 	 	 	 	 d;d&Z? G d' d(      Z@d/d<d)ZAe,d*k(  r e	j                   eA              yy)=u   utils/replacement_pr_runner.py — task-2510 5 모듈 #2.
회장 명시: contaminated PR 자동 감지 + origin/main 기준 clean branch에서
expected_files만 이식하여 replacement PR 자동 생성.
원 PR은 close/delete 없이 보존.
    )annotationsN)asdict)datetimetimezone)Path)AnyCallableOptionalTYPE_CHECKING	TypeAliasWORKSPACE_ROOTz/home/jay/workspace)ReplacementResultCriticalEscalationTypeEscalationPacketr   TaskSpec)r   c                 2    ddl m}  |j                  | i |S Nr   )merge_queue_executor)utilsr   compare_effective_diffargskwargs_mqes      L/home/jay/workspace/.worktrees/task-2644-dev1/utils/replacement_pr_runner.pyr   r   *       2&4&&777    c                 2    ddl m}  |j                  | i |S r   )r   r   detect_forbidden_pathsr   s      r   r   r   /   r   r   c                 2    ddl m}  |j                  | i |S r   )r   r   assert_no_forbidden_git_flagsr   s      r   r!   r!   4   s    2-4--t>v>>r   c                 2    ddl m}  |j                  | i |S r   )r   r   load_task_specr   s      r   r#   r#   9   s    24///r   .c                X    t        j                  | |xs t        t              dd|      S )NT)cwdcapture_outputtexttimeout)
subprocessrunstr	WORKSPACE)r   r%   r(   s      r   _default_runnerr-   A   s$    >>$C$93y>$UYcjkkr   c                "    d| v rt        d      y)uQ   args에 'cherry-pick' 토큰이 들어가면 RuntimeError(CHERRY_PICK_FORBIDDEN).zcherry-pickCHERRY_PICK_FORBIDDENN)RuntimeError)r   s    r   assert_no_cherry_pickr1   F   s    233 r   c                   dddt        |       ddg} ||      }|j                  dk7  rt        d|  d|j                        t	        j
                  |j                  xs d	      }|j                  d
d      }|j                  dd      }|j                  d      xs g D cg c]&  }|j                  d      s|j                  dd      ( }}t        j                  d|      xs t        j                  d|      }	|	r|	j                  d      nd}
||j                  dd      |j                  dd      ||
|| dS c c}w )u+  gh pr view --json headRefName,headRefOid,baseRefName,files,title.
    return {"head_ref": ..., "head_sha": ..., "base_ref": ..., "files": [...], "task_id": ..., "title": ..., "number": pr_number}
    실패 시 RuntimeError.
    task_id는 title 또는 head_ref에서 [task-NNNN] 패턴 추출.
    ghprview--jsonz.headRefName,headRefOid,baseRefName,files,titler   zFETCH_PR_METADATA_FAILED: pr= stderr={}headRefName titlefilespathztask-\d+(?:\+\d+)?unknown
headRefOidbaseRefNamemainhead_refhead_shabase_refr<   task_idr;   number)r+   
returncoder0   stderrjsonloadsstdoutgetresearchgroup)	pr_numberrunnerr   resultdatarC   r;   fr<   mrF   s              r   fetch_pr_metadatarW   M   s.    $I<>DD\FA:9+XfmmM^_``::fmm+t,Dxxr*HHHWb!E)-'):)@bS1QUU6]QUU62SES
		'/]299=RT\3]Aaggaj9GHH\2.HH]F3 	 Ts   "D<9D<c                   | j                  d      rt        | d         S | j                  dd      }|sg S dddd| j                  dd	       d
| g}t        |        ||      }|j                  dk7  rg S |j                  xs dj                         D cg c]#  }|j                         s|j                         % c}S c c}w )um   gh pr view에서 받은 files 우선 사용, 비어있으면 git diff origin/main...PR_HEAD --name-only.
    r<   rD   r:   gitdiff--name-onlyzorigin/rE   rA   z...r   )rM   listr!   rH   rL   
splitlinesstrip)pr_metarR   rD   r   rS   lines         r   compute_effective_diffra   k   s     {{7GG$%%{{:r*H	6=GGKK
F4S3TTWX`Wa*bcD!$'D\FA	&,mm&9r%E%E%GXT4::<DJJLXXXs   C,Cc                    d}|r0|D cg c]%  }t        |d      r|nt        j                  |      ' }}t        | ||      }t	        | |      \  }}}t        |      xs | }	|	|||dS c c}w )u_   반환 dict: {"contaminated": bool, "forbidden_paths": [...], "extra": [...], "missing": [...]}NrO   )extra_patterns)contaminatedforbidden_pathsextramissing)hasattrrN   compiler   r   bool)
effective_filesexpected_filesextra_forbidden_patterns
extra_patsp	forbiddenequalrf   rg   rd   s
             r   detect_contaminationrr   |   s~     JLdeq71h/aRZZ]Be
e&WabI2?NSE5'	?/%iL(YQVcjkk	 fs   *A*	timestamprepo_dirc                  |2t        j                  t        j                        j	                  d      }d|  d| }g d}t        |       t        |        |||      }|j                  dk7  rt        d|j                        dd	d
|dg}t        |       t        |        |||      }|j                  dk7  rt        d| d|j                        |S )u   origin/main 기준 신규 brace `task/<task_id>-replacement-<timestamp>` 생성.
    fetch origin main으로 stale base 회피. force/rebase/cherry-pick 금지.
    %Y%m%d%H%M%Stask/-replacement-)rY   fetchoriginrA   z--quietr%   r   z!FETCH_ORIGIN_MAIN_FAILED: stderr=rY   checkout-bzorigin/mainz#CREATE_CLEAN_BRANCH_FAILED: branch=r7   )
r   nowr   utcstrftimer!   r1   rH   r0   rI   )	rF   rR   rt   ru   branch
fetch_argsfetch_resultr   rS   s	            r   create_clean_replacement_branchr      s     LL.77G	WI]9+6F ?J!*-*%*(3L!#/0C0C/FG
 	
 :tV];D!$'$Dh'FA@QWQ^Q^PabccMr   ru   c          	     @   g }|xs t        t              }| D ]  }dd| d| g}t        |       t        |        |||      }|j                  dk7  rt        d| d| d|j                        t        |      |z  }	|	j                  j                  d	d	
       |	j                  |j                  d       dd|g}
t        |
       t        |
        ||
|      }|j                  dk7  rt        d| d|j                        |j                  |        |S )u   각 파일 git show <source_head>:<path> → write → git add. cherry-pick 정적 차단.
    파일 시스템에 실제로 write하므로 호출자는 임시 작업 dir(tmp_path 등)을 repo_dir로 줘야 source 손상 방지.
    rY   show:r|   r   zGIT_SHOW_FAILED: file=z sha=r7   T)parentsexist_okzutf-8)encodingaddzGIT_ADD_FAILED: file=)r+   r,   r!   r1   rH   r0   rI   r   parentmkdir
write_textrL   append)rl   source_headrR   ru   transplantedr%   filepath	show_argssrtargetadd_argsars               r   transplant_expected_filesr      s0    !L

$c)nC" &F{m1XJ$?@	%i0i(I3'==A!7z{mS[\^\e\e[hijjcX%D48"))g65(+%h/h'H#&==A!6xjVWWH%!&" r   c                   |xs t        t              }d|  d}ddd|g}t        |       t        |        |||      }|j                  dk7  rt        d|j                        |S )	uO   git commit -m only (push 하지 않음). force 금지. 실패 시 RuntimeError.[z3] replacement: expected_files only (auto-generated)rY   commitz-mr|   r   zCOMMIT_FAILED: stderr=r+   r,   r!   r1   rH   r0   rI   )rF   rR   ru   r%   
commit_msgcargscrs          r   commit_localr      ss     
$c)nCWIPQJHdJ/E!%(% 	3	B	}}3BII=ABBIr   c                   |xs t        t              }ddd| g}t        |       t        |        |||      }|j                  dk7  rt        d|j                        |S )u@   git push origin <branch>. force 금지. 실패 시 RuntimeError.rY   pushr{   r|   r   zPUSH_FAILED: stderr=r   )r   rR   ru   r%   pargsr4   s         r   push_branchr      sd     
$c)nCFHf-E!%(% 	3	B	}}1"))?@@Ir   T)ru   r   c               B    t        | ||      }|rt        |||       |S )uL   git commit -m + (선택적) git push. force 금지. 실패 시 RuntimeError.r   )r   r   )rF   r   rR   ru   r   r   s         r   commit_and_pushr      s&     
gv	9BFFX6Ir   c                  |xs t        t              }g d}t        |       t        |        |||      }|j                  dk7  rAg d}t        |       t        |        |||      }|j                  dk7  rdg t        |      fS |j                  xs dj                         D cg c]#  }|j                         s|j                         % }	}t        |	|      \  }
}}t        |	|      }|rd||z   |fS |
||fS c c}w )u   commit 후 push 전, 로컬 git diff 기반 사전 검증.

    git show --stat HEAD 또는 git diff --name-only origin/main...HEAD 호출.
    return (valid, extra, missing).
    valid=True이면 expected_files와 일치하고 forbidden path 없음.
    )rY   rZ   r[   zorigin/main...HEADr|   r   )rY   r   z--statr[   z	--format=HEADFr:   )r+   r,   r!   r1   rH   r\   rL   r]   r^   r   r   )r   rl   rR   ru   r%   	diff_argsrS   r   r`   local_filesrq   rf   rg   rp   s                 r   precheck_local_replacement_diffr     s     
$c)nCDI!),)$I3'FAQ	%i0i(	s+!"d>222-3]]-@b,L,L,N_DRVR\R\R^4::<_K_2;OE5'&{NCIei'00%   `s   (C=>C=c                   |xs t        t              }g d}t        |        | ||      }|j                  dk7  rt	        d|j
                        |j                  xs dj                         rt	        d      y)uY   git status --porcelain 출력이 비어있지 않으면 RuntimeError(DIRTY_WORKING_TREE).)rY   statusz--porcelainr|   r   z-DIRTY_WORKING_TREE: git status failed stderr=r:   z3DIRTY_WORKING_TREE: cannot proceed with replacementN)r+   r,   r!   rH   r0   rI   rL   r^   )rR   ru   r%   r   rS   s        r   assert_clean_working_treer   )  su    

$c)nC+D!$'Dc"FAJ6==J[\]]""$PQQ %r   c                  d|  d| d}d| d}dddd	d
d|d|d|g}t        |       t        |        |||      }|j                  dk7  rt        d|j                        |j
                  xs dj                         }	t        j                  d|	      }
|
st        d|	      t        |
j                  d            S )u   gh pr create. base=main, head=branch. body에 source PR 링크. return PR number.
    repo_dir은 다른 git/gh 호출과 일관되게 worktree/temp repo에 라우팅하기 위해 필요.
    r   z] replacement (auto for #)z Auto-generated replacement for #z*. Original PR preserved (no close/delete).r3   r4   createz--baserA   z--headz--titlez--bodyr|   r   z#OPEN_REPLACEMENT_PR_FAILED: stderr=r:   z/pull/(\d+)\bz)OPEN_REPLACEMENT_PR_NO_PR_NUMBER: stdout=   )r!   r1   rH   r0   rI   rL   r^   rN   rO   intrP   )rF   r   	source_prrR   ru   r;   bodyr   rS   outrV   s              r   open_replacement_prr   6  s     y1)A>E-i[8bcD$(FHfiQVX`bfgD!$'$Dh'FA@@QRSS==B
%
%
'C 			"C(AFsgNOOqwwqz?r   c                   d| d}dddt        |       d|gh d}t        fd|D              rt        d	       t               t	                |      }|j
                  d
k7  rt        d|j                        |S )u   gh pr comment <source_pr> -b "[REPLACED] by #<replacement_pr>". close/delete 호출 금지.
    args에 'close', 'delete', 'edit --state closed' 들어가면 즉시 RuntimeError.
    z[REPLACED] by #uK    — automated by replacement_pr_runner (task-2510). Original PR preserved.r3   r4   commentr~   >   delete-branchclosedeletec              3  &   K   | ]  }|v  
 y wN ).0tr   s     r   	<genexpr>z(post_replaced_comment.<locals>.<genexpr>\  s     
/19
/s   z(ORIGINAL_PR_PRESERVE_FORBIDDEN_OP: args=r   z%POST_REPLACED_COMMENT_FAILED: stderr=)r+   anyr0   r!   r1   rH   rI   )r   replacement_prrR   r   forbidden_tokensrS   r   s         @r   post_replaced_commentr   T  s     ^,,wxD$	3y>4>D;

/.
//EdVLMM!$'$D\FAB6==BSTUUMr   c                ^   dddt        |       ddg} ||      }|j                  dk7  rt        d|  d|j                        t	        j
                  |j                  xs d	      }|j                  d      xs g D cg c]  }|j                  d
      s|d
    }}t        ||      S c c}w )um   gh pr view <replacement_pr> --json files → compare_effective_diff.
    return (valid, extra, missing).
    r3   r4   r5   r6   r<   r   z%VALIDATE_REPLACEMENT_DIFF_FAILED: pr=r7   r8   r=   )	r+   rH   r0   rI   rJ   rK   rL   rM   r   )r   rl   rR   r   rS   rT   rU   	effectives           r   validate_replacement_diffr   g  s     $N 3XwGDD\FAB>BRRZ[a[h[hZklmm::fmm+t,D%)XXg%6%<"Oqv6OIO!)^<< Ps   >B*B*c           
     2    t        | |||d| g dd|      S )ug   본 task에서는 EscalationPacket dataclass 인스턴스만 생성. 실제 보고는 task-2513 영역.z5replacement_pr_runner cannot continue without chair: )   회장 수동 검토 후 재개u*   원 PR 보존 + clean branch 수동 생성u   expected_files 재정의r   )rF   rQ   escalation_typereasonwhy_auto_cannot_continuesafe_optionsrecommended_optionevidence)r   rF   rQ   r   r   r   s        r   build_escalation_packetr   y  s6     '#XY_X`!a

 = r   c                  p    e Zd ZdZ	 d
ddddd	 	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 	 	 	 	 	 	 ddZd
ddZd Zd	 Zy)ReplacementPRRunneruK   contaminated PR을 받아 replacement PR을 자동 생성하는 main entry.NF)dry_runru   rm   timestamp_providerc               r    |xs t         | _        || _        || _        || _        |xs d | _        d | _        y )Nc                 f    t        j                  t        j                        j	                  d      S )Nrw   )r   r   r   r   r   r   r   r   <lambda>z.ReplacementPRRunner.__init__.<locals>.<lambda>  s    HLL.77G r   )r-   rR   r   ru   rm   _ts_providerlast_escalation_packet)selfrR   r   ru   rm   r   s         r   __init__zReplacementPRRunner.__init__  sE     / (@%. 
G 	 CG#r   c                    	 t        |||||      | _        y# t        $ r }t        j	                  d|       Y d}~yd}~ww xY w)uV   실패 경로에서 EscalationPacket을 생성하여 last_escalation_packet에 보관.r   z"build_escalation_packet failed: %sN)r   r   	Exceptionloggerwarning)r   rF   rQ   r   r   r   es          r   _record_escalationz&ReplacementPRRunner._record_escalation  sJ    		D*A# /!+D'  	DNN?CC	Ds    	A<Ac                   d | _         | j                  r| j                  ||      }n	 t        || j                        }|"t        |j                        }|j                  }n|j                  d      xs d}g }| j                  rt        |j                  d	g             }n	 t        || j                        }t!        ||| j"                        }|d   rX| j                  ||t        j$                  d|d   |d       t        |d d|||d   dt        j$                  j                        S |d   st        |d d||g dd       S | j                  r| j'                  |||||d         S 	 t)        | j                  | j*                         d }		 t1        || j                  | j3                         | j*                        }	t5        ||d   | j                  | j*                         t7        || j                  | j*                         	 t9        |	|| j                  | j*                        \  }
}}|
s	 ddd|	g}t;        |       | j	                  || j*                         | j                  ||t        j<                  d|	|||d       t        |d d||g dt        j<                  j                        S 	 t?        |	| j                  | j*                         tA        ||	|| j                  | j*                        }	 tC        ||| j                        }tE        |tF              r|n|d   }|sR| j                  ||t        j<                  d||d       t        ||d||g dt        j<                  j                        S 	 tI        ||| j                         t        ||d||g dd       S # t
        $ rh |r|j                  ndxs d}| j                  ||t        j                  dd|i       t        |d dg g g dt        j                  j                        cY S w xY w# t
        $ rU | j                  ||t        j                  d
||d       t        |d d|g g dt        j                  j                        cY S w xY w# t,        $ re}| j                  ||t        j                  t/        |      d|d       t        |d d||g dt        j                  j                        cY d }~S d }~ww xY w# t
        $ re}| j                  ||t        j                  t/        |      |	|d       t        |d d||g dt        j                  j                        cY d }~S d }~ww xY w# t
        $ r
 dg g }}}
Y Cw xY w# t
        $ r Y "w xY w# t
        $ re}| j                  ||t        j                  t/        |      |	|d       t        |d d||g dt        j                  j                        cY d }~S d }~ww xY w# t
        $ r d}Y w xY w# t
        $ re}| j                  ||t        j<                  t/        |      ||d       t        ||d||g dt        j<                  j                        cY d }~S d }~ww xY w) Nr>   FETCH_PR_METADATA_FAILEDrQ   r   TFr   r   original_pr_preservedrl   effective_diff_filesre   successfailure_reasonrF   r<   COMPUTE_EFFECTIVE_DIFF_FAILED)rQ   rF   )rm   re   FORBIDDEN_PATH_DETECTED)re   rF   rd   )rQ   rF   rl   rk   re   r   )
dirty_treerF   rs   rD   )r   rF   rY   r   z-dr|   PRECHECK_LOCAL_DIFF_MISMATCH)r   rf   rg   rF   r    VALIDATE_REPLACEMENT_DIFF_FAILED)r   rF   )%r   r   _dry_run_pr_metarW   rR   r   rF   r   r   9REPLACEMENT_PR_AUTO_CREATION_FAILED_FOR_CONTAMINATED_DIFFr   valuer\   rl   rM   ra   rr   rm   FORBIDDEN_PATH_INTRUSION_dry_run_replacementr   ru   r0   r+   r   r   r   r   r   r!   REPLACEMENT_PR_FAILEDr   r   r   
isinstancerj   r   )r   rQ   	task_specr_   rF   rl   rk   cr   r   precheck_validprecheck_extraprecheck_missingdel_argsr   valid_resultvalids                    r   executezReplacementPRRunner.execute  s   &*# <<++IyAG+It{{C$  !)":":;N''Gkk),9	GN<<"7;;w#;<O"8$++"N" !.[_[x[xy### 6 O O0-./@-AgV $  %#DPT-O !"3 45NNTT   $#DPT-O "T	  <<,,#W- !"3 4 -  	%dkkDMMJ$ 	4WdkkUYUfUfUhsw  tA  tA  BF%ngj6I4;;aeanano$++F$	M?^dmm@<NN,< !8T6:-h7H$--8 ### 6 L L5$+/&	 $  %#DPT-O "5KKQQ 	dmmD0&)T[[cgcpcpqN$	4^^UYU`U`aL$.|T$BLUVE ### 6 L L9,:wO $  %#NZ^-O "5KKQQ 	!)^T[[I" !VZ)	
 	
q  099,,yVY''#'$:$t$t5)95 (  )'TX#%BPR!#9#s#s#y#y	 :  ''#'$:$t$t:+4I (  )'TX#1\^!#9#s#s#y#y	 h  	### 6 p p1v(,A $  %#DPT-O "5oouu 	.  	### 6 p p1v$*w? $  %#DPT-O "5oouu 	*  	M?Db",<NN	M  4  	### 6 p p1v$*w? $  %#DPT-O "5oouu 	(  	E	(  	### 6 L L1v,:wO $  %#NZ^-O "5KKQQ 	s   N* "P +!Q? A9S0 	'U! 3.U7 6AV =.W8  X
 *A.PPAQ<;Q<?	S-AS("S-(S-0	U9AUUU!U43U47	VV	W5AW0*W50W58XX
	Y8AY3-Y83Y8c                r    |r|j                   nd}d| ddd|rt        |j                        ng |d| |dS )Nr>   rx   z-dry-runzdry-run-sha-0000000rA   z
[DRY-RUN] rB   )rF   r\   rl   )r   rQ   r   rF   s       r   r   z$ReplacementPRRunner._dry_run_pr_meta  sO    '0)##iy1-7@T)223b!'+
 	
r   c          
         | j                         }d| d| }t        j                  d||       t        |d d|||dd       S )Nrx   ry   z>[DRY-RUN] Would create branch=%r and replacement PR for PR #%dTr   )r   r   infor   )r   rQ   rF   rl   rk   re   rt   simulated_branchs           r   r   z(ReplacementPRRunner._dry_run_replacement  sW    %%'	"7)=DTVfhqr D)+	
 	
r   r   )
rR   zOptional[RunnerType]r   rj   ru   Optional[str]rm   Optional[list]r   zOptional[Callable[[], str]])rF   r+   rQ   r   r   r   r   r+   r   dictreturnNone)rQ   r   r   zOptional[TaskSpec]r
  r   )	__name__
__module____qualname____doc__r   r   r  r   r   r   r   r   r   r     s    U (,G "&37:>G$G 	G
  G #1G 8G$DD D 0	D
 D D 
D(f
P

	
r   r   c                   t        j                  d      }|j                  dt        d       |j                  dd       |j                  d	t        d 
       |j                  |       }t        |j                        }d }|j                  rt        t        |j                              }|j                  |j                  |      }t        t        j                  t!        |      t        dd             |j"                  rIt        t        j                  dt!        |j"                        it              t$        j&                         |j(                  rdS dS )Nz#task-2510 replacement_pr_runner CLI)descriptionz--prT)typerequiredz	--dry-run
store_true)actionz--task-file)r  default)r   )r   F   )r  ensure_asciiindentescalation_packet)r  )filer   )argparseArgumentParseradd_argumentr   r+   
parse_argsr   r   	task_filer#   r   r  r4   printrJ   dumpsr   r   sysrI   r   )argvparserr   rR   specrS   s         r   rA   rA     s   $$1VWF
S48
L9
C>T"D 6FD~~d4>>23^^DGGt^4F	$**VF^SuQ
OP$$djj-vf6S6S/TU_bcjmjtjtu1%A%r   __main__)N<   )r   	list[str]r
  r  )rQ   r   rR   
RunnerTyper
  r	  )r_   r	  rR   r*  r
  r)  r   )rk   r)  rl   r)  rm   r  r
  r	  )
rF   r+   rR   r*  rt   r  ru   r  r
  r+   )
rl   r)  r   r+   rR   r*  ru   r  r
  r)  )rF   r+   rR   r*  ru   r  )r   r+   rR   r*  ru   r  )
rF   r+   r   r+   rR   r*  ru   r  r   rj   )
r   r+   rl   r)  rR   r*  ru   r  r
  !tuple[bool, list[str], list[str]])rR   r*  ru   r  r
  r  )rF   r+   r   r+   r   r   rR   r*  ru   r  r
  r   )r   r   r   r   rR   r*  )r   r   rl   r)  rR   r*  r
  r+  )rF   r+   rQ   r   r   r   r   r+   r   r	  r
  r   )r$  zOptional[list[str]]r
  r   )Cr  
__future__r   r  rJ   loggingosrN   r)   r#  dataclassesr   r   r   pathlibr   typingr   r	   r
   r   r   environrM   r,   __file__resolver   _HEREr+   r=   insertutils.automation_contractsr   r   r   r   __annotations__utils.merge_queue_executorr   r   r!   r#   	getLoggerr  r   CompletedProcessr*  r-   r1   rW   ra   rr   r   r   r   r   r   r   r   r   r   r   r   r   rA   exitr   r   r   <module>r=     sR  
 #    	 	  
  '  D D 02GHI	 	X ''..u:SXXHHOOAs5z"  ) 38
8
?
0 
		8	$c:6667
l
4<Y( 04lll -l 
	l(  $" 	
  	N # 
  J #	 	. #	 	. # 
  * #!!!!!! !!
 !! '!!J PT 	R& #  	  	<&=== = '	=$ , 	
  2f
 f
T	&" zCHHTV r   