
    xj>                    V   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	m
Z
 ddlmZ ddlmZ ddlmZ ddlmZ d	Zd
ZdZdZdZdZdZdZdZddZdddZ G d de          Z ed           G d d                      Z  ej!                    Z"i Z#de$d <   e
dd"            Z%ddd'Z&ed(dd)dd2Z'dd6Z(dd7Z)dd9Z*dd<Z+dd>Z,d(d(d?ddCZ-ddFZ.ddHZ/ddIddMZ0ddIddNZ1ddRZ2ddSZ3ddWZ4ddZZ5dd[Z6dd]Z7dd^Z8dd_Z9ddaZ:ddbZ;ddcZ<ddfZ=ddgZ>ddhZ?ddlZ@ddnZA	 	 	 dddqZB	 	 dddrZCddtZDddvZEdddyZFdd|ZGdd}ZHdd~ZIddZJd(dddZKdL                                ZMddZNddZOddZPddZQddZRddZSddZTddZUddZVddZWddZXddZYddZZddZ[dS )a	  Git helpers for the workspace panel.

The browser only sends session ids and workspace-relative paths.  This module
resolves the active workspace server-side, scopes paths before they become Git
pathspecs, and keeps all Git subprocess calls shell-free and bounded.
    )annotationsN)contextmanager)	dataclass)Path)Iterable)safe_resolve_ws   <   i  i   i   &HERMES_WEBUI_WORKSPACE_GIT_DESTRUCTIVE)GIT_DIRGIT_WORK_TREEGIT_CONFIG_GLOBALGIT_CONFIG_SYSTEMGIT_CONFIG_COUNTGIT_CONFIG_PARAMETERS)GIT_CONFIG_KEY_GIT_CONFIG_VALUE_zhermes-webui branch switchreturnboolc                     t          j        t          d                                                                          dv S )N >   1onyestrue)osgetenvWORKSPACE_GIT_DESTRUCTIVE_ENVstriplower     4/Users/bertmahoney/hermes-webui/api/workspace_git.py!workspace_git_destructive_enabledr$   *   s:    92B77==??EEGG L  r"   extradict[str, str] | Nonedict[str, str]c                4   t           j                                        }| r|                    |            t          D ]}|                    |d            t          |          D ]2}|                    t                    r|                    |d            3|S N)	r   environcopyupdate_GIT_ENV_SCRUB_KEYSpoplist
startswith_GIT_ENV_SCRUB_PREFIXES)r%   envkeys      r#   _clean_git_envr4   3   s    
*//

C 

5"  TCyy  >>122 	GGCJr"   c                  &     e Zd ZdZdd fdZ xZS )	GitWorkspaceErrorz User-facing Git operation error.
git_failedmessagestrcodec                X    t                                          |           || _        d S r)   )super__init__r:   )selfr8   r:   	__class__s      r#   r=   zGitWorkspaceError.__init__B   s&    !!!			r"   )r7   )r8   r9   r:   r9   )__name__
__module____qualname____doc__r=   __classcell__)r?   s   @r#   r6   r6   ?   sH        **          r"   r6   T)frozenc                  .    e Zd ZU ded<   ded<   ded<   dS )
GitContextr   	workspace	repo_rootr9   workspace_prefixN)r@   rA   rB   __annotations__r!   r"   r#   rG   rG   G   s0         OOOOOOr"   rG   zdict[str, threading.Lock]	_OP_LOCKSctxc              #    K   t          | j                  }t          5  t                              |t          j                              }d d d            n# 1 swxY w Y   |                    t                    st          dd          	 d V  |
                                 d S # |
                                 w xY w)N)timeoutz&Another Git operation is still runningoperation_in_progress)r9   rI   _LOCKS_GUARDrL   
setdefault	threadingLockacquireGIT_REMOTE_TIMEOUTr6   release)rM   r3   locks      r#   _git_mutation_lockrY   R   s      
 cm

C	 ; ;##C)9)9::; ; ; ; ; ; ; ; ; ; ; ; ; ; ;<< 2<33 c HJabbbs   -AAAB( (B>r8   r9   argslist[str] | Nonec                   | pd                                 }d                    |pg                                            }d|v rdS d|v sd|v rdS d|v rd	S d
|v sd|v rdS d|v sd|v sd|v rdS d|v sd|v sd|v rdS d|v sd|v sd|v rd|v rdS d|v sd|v sd|v rd|v rdS d|v r
d|v sd |v rd!S d"|v sd#|v rd!S d$|v sd%|v sd&|v rd'S d(|v rd)S d*S )+Nr    z	timed outrO   znot installedz no such file or directory: 'git'missing_gitznot a git repository
not_a_repozoutside the workspacezoutside the git repositorypath_outside_workspacezauthentication failedzpermission deniedzcould not read usernameauth_failedzno upstreamzno configured push destinationzhas no upstream branchno_upstreamznon-fast-forwardzfetch firstrejectedpushnon_fast_forwardconflictunmergedmergeneedszworking treecleandirtydirty_worktreezlocal changesz would be overwritten by checkoutzinvalid referenceznot a validzunknown revisioninvalid_refhookhook_failedr7   )r    join)r8   rZ   textjoineds       r#   _classify_git_errorrs   b   s   Mr  ""DXXdjb!!''))Fdy$"D"L"L}%%|$&&*F$*N*N''$&&*=*E*EIbfjIjIj} @D H HLdhlLlLl}d""D  $6V#3#3!!TZ4//GtOOSWz7d??goo$"D"L"Ld""mt&;&;?QUY?Y?Y}~~}<r"   FrO   checkr2   
ctx_or_cwdGitContext | Path	list[str]rO   intru   r2    subprocess.CompletedProcess[str]c          	     l   t          | t                    r| j        n| }t          |          }	 t	          j        dg|t          |          ddd||          }n# t          j        $ r}t          dd          |d }~wt          $ r}t          dd          |d }~wt          $ r>}t          t          |          t          t          |          |                    |d }~ww xY w|rK|j        d	k    r@|j        p|j        pd
                                }	t          |	t          |	|                    |S )NgitFT)cwdshellcapture_outputrq   rO   r2   zGit command timed outrO   z-Git is not installed or not available on PATHr^   r   zGit command failed)
isinstancerG   rI   r4   
subprocessrunr9   TimeoutExpiredr6   FileNotFoundErrorOSErrorrs   
returncodestderrstdoutr   )
rv   rZ   rO   ru   r2   r}   run_envresultexcr8   s
             r#   _run_gitr      sn    #-Z"D"D
T*

*CS!!GXNTNC
 
 
 $ M M M 7CCL i i i OQ^__ehh X X XC*=c#hh*M*MNNTWWX M"a''=IFMI5IPPRR)<Wd)K)KLLLMs/   +A C$*A;;C$BC$&9CC$rH   
str | PathGitContext | Nonec                   t          |                                                                           }t          |ddgd          }|j        dk    rd S t          |j                                                                                  }	 |                    |                                          }n# t          $ r Y d S w xY wt          |||dk    rdn|          S )	N	rev-parsez--show-toplevelFru   r   .r   )rH   rI   rJ   )r   
expanduserresolver   r   r   r   relative_toas_posix
ValueErrorrG   )rH   wsr   rI   prefixs        r#   resolve_git_contextr      s    	i	#	#	%	%	-	-	/	/Bb;(9:%HHHFAtV]((**++3355I	**3355   ttiPVZ]P]P]""cijjjjs   'B6 6
CCc                    | j         pdS )Nr   )rJ   )rM   s    r#   _workspace_pathspecr      s    &3&r"   workspace_relc                   	 t          | j        |pd          }n0# t          $ r#}t          t	          |          d          |d }~ww xY w	 |                    | j                                                  }n## t          $ r}t          dd          |d }~ww xY w| j        r?	 |                    | j                   n## t          $ r}t          dd          |d }~ww xY w|S )Nr   r`   z"Path is outside the Git repositoryzPath is outside the workspace)	r   rH   r   r6   r9   r   rI   r   rJ   )rM   r   targetr   repo_rels        r#   	_repo_relr      s%   M 0DEE M M MC*BCCLMi%%cm44==?? i i i DF^__ehhi
 h	hs}---- 	h 	h 	h#$CE]^^dgg	hOsD    
AAA,A8 8
BBB#B> >
CCCr   
str | Nonec                    |                     dd          }| j        s|S | j                            d          dz   }|| j        k    rdS |                    |          r|t	          |          d          S d S )N\/r   )replacerJ   rstripr0   len)rM   r   r   s      r#   _workspace_relr      s    c**H !((--3F3'''s6"" 'F&&4r"   dictc                     ddddddS )Nr   )changedstagedunstaged	untracked	conflictsr!   r!   r"   r#   _empty_statusr      s       r"   r   renamedxyr   r   c               f    |rdS | dv r| S |rdS | D ]
}|dv r|c S |                      d          pdS )N??>   AAAUDDDUUAUDUURMADRCUTr   M)r   )r   r   r   chs       r#   _status_coder      sh     t	777	 s  ??III 88C==Cr"   rq    dict[str, tuple[int, int, bool]]c                :   i }|                                  D ]}|                    dd          }t          |          dk     r,|\  }}}|dk    p|dk    }|rdnt          |pd          }	|rdnt          |pd          }
t	          ||          }|{|	|
|f||<   |S )N	      -r   0)
splitlinessplitr   ry   r   )rq   rM   statslinepartsraw_addraw_delraw_pathbinary	additions	deletionsworkspace_paths               r#   _parse_numstatr      s    .0E!! ? ?

4##u::>>%*"(C17c>8AASC%8%8	8AASC%8%8	'X66!!*Iv >nLr"   set[str]c                    t                      }|                     d          D ],}|st          ||          }||                    |           -|S )N )setr   r   add)rq   rM   pathsr   r   s        r#   _parse_path_listr      s^    eeEJJt$$ & & 	'X66%IIn%%%Lr"   )ignore_cr_at_eolcachedr   set[str] | Nonec                  g d}|r|                     d           |r|                     d           |                    dt          |           g           t          | |d          }|j        dk    rd S t          |j        |           S )N)diffz--name-only-z--ignore-cr-at-eol--cached--Fr   r   )appendextendr   r   r   r   r   rM   r   r   rZ   r   s        r#   _collect_diff_pathsr     s    (((D *()))  JKK*3//0111c4u---FAtFM3///r"   c                  ddg}|r|                     d           |r|                     d           |                    dt          |           g           t          | |d          }|j        dk    ri S t          |j        |           S )	Nr   z	--numstatr   r   r   Fr   r   )r   r   r   r   r   r   r   r   s        r#   _collect_numstatr     s     K D *()))  JKK*3//0111c4u---FA	&----r"   pathr   tuple[int, int, bool]c                   	 |                                  r"|                                 j        t          k    rdS n# t          $ r Y dS w xY w	 |                                 }n# t          $ r Y dS w xY wd|v rdS 	 |                    d          }n# t          $ r Y dS w xY wt          |	                                          p|rdndddfS )Nr   r   F    )r   r   Tutf-8   r   F)
is_filestatst_sizeDIFF_SIZE_LIMITr   
read_bytesdecodeUnicodeDecodeErrorr   r   )r   datarq   s      r#   _count_untracked_filer   $  s   ||~~ 	!4!F!F; "G   {{     {{}}z{{7##   zzt  !!74&6aaQEAAs3   6; 
A	A	A" "
A0/A0:B 
BBc                   t          |           }|ddiS t          |ddddddd	t          |          gd
          }t          |d
          }t          |d          }t          |d
d          }t          |dd          }t	          |d
          }t	          |d          }d}	d}
d}d}i }ddd}|j                            d          }d}d}|t          |          k     r||         }|dz  }|s$|                    d          rC|                    dd          }t          |          dk    r#|d         dk    r|d         dk    rdn|d         }	nt          |          dk    r|d         dk    r	|d         }
nt          |          dk    r|d         dk    r|d                                         D ]}|                    d          r4|dd          	                                rt          |dd                    }K|                    d          r3|dd          	                                rt          |dd                    }}d }d}|                    d          rd}|dd          }d
}d}nJ|                    d          rd }|dd          }d}d
}n#|                    d!          r@|                    dd"          }t          |          d#k     r|d         }|d"         }d}d}n|                    d$          rb|                    dd#          }t          |          d%k     rd|d         }|d#         }|t          |          k     r||         }|dz  }d
}d}d}nW|                    d&          r@|                    dd%          }t          |          d'k     r|d         }|d%         }d}d}nt          ||          }||rt          ||          nd }|r|d         nd(}t          |          dk    r|d         nd(}|d)v p|                    d&          }d*\  } }!}"||fD ] }#||#v r|#|         \  }$}%}&| |$z  } |!|%z  }!|"p|&}"!|rt          |j        |z            \  } }!}"|d+vo| }'|d,vo| }(|'rA|?|s=|'})||v p|d uo||v }'|)r-|'s+||v s|||v r|d-xx         dz  cc<   n|d.xx         dz  cc<   |(rA|?|s=|(}*||v p|d uo||v }(|*r-|(s+||v s|||v r|d-xx         dz  cc<   n|d.xx         dz  cc<   |r/|d |d/dddd
ddddd0||<   t          |          t          k    rd
}ni|'s
|(s|s|s|su|s$|s"|s |"s| dk    r|!dk    r|d-xx         dz  cc<   |||t          |||1          |'|(|d|| |!|"d0||<   t          |          t          k    rd
}n|t          |          k     t!          |                                d2 3          }+t%                      },|+D ]x}-|-                    d4          r|-d5         r|,d5xx         dz  cc<   |-d6         r|,d6xx         dz  cc<   |-d7         r|,d7xx         dz  cc<   |-d8         r|,d9xx         dz  cc<   yt)          d: |+D                       |,d;<   |	s-t          |g d<d          j        pd                                }	d
|	pd=|
|||,|+|i |d>t-          |                                          id?	S )@Nis_gitFstatus--porcelain=v2r   --branchz--ignored=matching--untracked-files=allr   Tr   )r   )r   r   r   r   )filemode_only	crlf_onlyr   r   z# r]   r   r   zbranch.headz
(detached)zbranch.upstreamz	branch.ab+r   z? r   z! z!!z1    	   z2 
   zu    r   >   r   r   r   r   r   r   r   r   >   r   ?>   r]   r   r  r  Ignored)r   old_pathr   r   r   r   r   ignoredrf   r   r   r   r   c                6    | d                                          S )Nr   r    )fs    r#   <lambda>zgit_status.<locals>.<lambda>  s    aioo6G6G r"   r3   r  r   r   r   rf   r   c              3  D   K   | ]}|                     d           dV  dS )r  r   Nget).0items     r#   	<genexpr>zgit_status.<locals>.<genexpr>  s3      OO$488I;N;NOAOOOOOOr"   r   r   z--shortHEADr  active)	r   branchupstreamaheadbehindtotalsfiles	truncatednoise_filtering)r   r   r   r   r   r   r   r   r0   isdigitry   r   r   rH   STATUS_FILE_LIMITr   sortedvaluesr   r  sumr   any).rH   rM   r   staged_statsunstaged_statsstaged_raw_statsunstaged_raw_statsstaged_diff_pathsunstaged_diff_pathsr  r  r  r  r!  filtered_noisetokensir"  recr   bitr  r   r   	repo_pathr   r  r   old_workspace_pathxyrf   r   r   r   sourceadbr   r   
raw_stagedraw_unstaged	file_listr   r  s.                                                 r#   
git_statusr@  7  s	   
i
(
(C
{%   #$$		
   F $C555L%c%888N'D5QQQ)#eeTTT+C===-c%@@@FHEFE'(q99N]  &&F	AI
c&kk//Qi	Q 	>>$ 	IIc1%%E5zzQ58}#<#<$Qx<77U1XUqU1X1B%B%B 8UqU1X%<%< 8>>++ . .C~~c** .s122w/@/@ . #CG,, .QRR1B1B .!$SW>>$ '	BABBIIGG^^D!! "	BABBIIGG^^D!! 	IIc1%%E5zzA~~qBaIIGG^^D!! 	IIc1%%E5zzBqBaI3v;;!!9QGIGG^^D!! 		IIc2&&E5zzBqBb	IIGG'Y77!>FP^C:::D BqEESWWq[[BqEEcCC[s~~VZG[G['2$	9f#^4 	% 	%F'' 01aQ	Q	1 	a+@Q_A_+`+`(Iy&:%8y=Z':] 	9'3G3J#'88 "$.Z3EIZ3Z   9& 9!%555&27IM]7]7]";///14////"?333q8333 	9+77#L%)<< "$.\3EI\3\   9H 9!%777&27IM_7_7_";///14////"?333q8333 	& "0#!"!% %E.! 5zz... 	 	( 	i 	8 	w 	 	X 	 	F 		QS\`aSaSa;'''1,''' #*,"2GLLL " ""!
 !
n u::***Ig c&kk//j u||~~+H+HIIII__F 
% 
%88I 	> 	"8!
 	$:!# 	%;1$
 	%;1$OO)OOOOOF9 e3 @ @ @NNNU[Y[bbdd"F

c.//1122
 
  r"   r  r  tuple[int, int]c           	     R   |sdS t          | ddd| d| gd          }|j        dk    rdS |j                                                                        }t          |          d	k    rdS 	 t          |d                   t          |d
                   fS # t          $ r Y dS w xY w)N)r   r   zrev-listz--left-rightz--countz...Fr   r   r   r   )r   r   r   r   r   r   ry   r   )rM   r  r  r   r   s        r#   _branch_ahead_behindrC    s     tcJ	fC[C[QYC[C[\dijjjFAtM!!''))E
5zzQt58}}c%(mm++   tts   .)B 
B&%B&
ref_prefix
list[dict]c           	        d}t          | dd| |gd          }g }|j                                        D ]}|                    d          g dz   d d         \  }}}}	}
}}}|r*|                    d	          s|                    d	          rZ|d
k    rd|vre||	t          |
                                          rt          |
          nd|||d}|r.t          | ||          \  }}|	                    |||d           n|	                    dddd           |
                    |           t          |d           S )Nz%(refname)%00%(refname:short)%00%(upstream:short)%00%(objectname:short)%00%(committerdate:unix)%00%(committerdate:relative)%00%(authorname)%00%(subject)zfor-each-refz	--format=Tr   r   )r   r   r   r   r   r   r   r   r  z/HEADrefs/remotesr   r   )nameshaupdatedupdated_relativeauthorsubject)r  r  r  r   c                6    | d                                          S )NrH  r  )r  s    r#   r  z_for_each_ref.<locals>.<lambda><  s    f););)=)= r"   r  )r   r   r   r   endswithr9   r$  ry   rC  r,   r   r&  )rM   rD  fmtr   refsr   	full_namerH  r  rI  rJ  rK  rL  rM  r  r  r  s                    r#   _for_each_refrS    s   	Y  cN,=,=,=zJRVWWWFD((**  JJt????
1"VR	431A67  	y))'22 	dmmG6L6L 	''CtOO'*7||';';'='=Ds7|||1 0
 
  	C0dHEEME6KKXPPQQQQKKR!qAABBBD$==>>>>r"   c                   t          |           }|t          dd          t          |ddgd          j                                        }t          |           }t          |g dd          j                                        }t          |           }t          |d          }t          |d	          }d|p|pd
|||||                    dd          |                    dd          |                    dd          d	S )N!Workspace is not a Git repositoryr_   r  --show-currentTr   r  z
refs/headsrG  r  r  r   r  r   r  )	r   currentdetachedheadlocalremoter  r  r  )	r   r6   r   r   r   r   r@  rS  r  )rH   rM   	head_namerX  head_shar   rZ  r[  s           r#   git_branchesr^  ?  s   
i
(
(C
{ C\RRRx)9:$GGGNTTVVI	??"H===TJJJQWWYYH	""F#|,,E3//F22FJJz2..GQ''**Xq))
 
 
r"   refc                    t          |pd                                          }|st          dd          t          | ddd| gd           |S )	Nr   zBranch name is requiredrm   show-ref--verifyrefs/heads/Tr   r9   r   r6   r   rM   r_  s     r#   _validate_local_branchrf  V  sa    
ciR..


 
 C J 9=IIIS:z+>+>+>?tLLLLJr"   c                    t          |pd                                          }|st          dd          t          | ddd| gd           |S )	Nr   zRemote branch name is requiredrm   ra  rb  zrefs/remotes/Tr   rd  re  s     r#   _validate_remote_branchrh  ^  sa    
ciR..


 
 C Q @-PPPS:z+@3+@+@ANNNNJr"   c                    t          |pd                                          pd}t          | dd| dgd          }|j        dk    rt	          dd	          |S )
Nr  r   rb  z	^{commit}Fr   r   zInvalid checkout referencerm   )r9   r   r   r   r6   )rM   r_  r   s      r#   _validate_checkout_startrj  f  sm    
cmV


"
"
$
$
.CcK5H5H5HIQVWWWFA <mLLLJr"   rH  c                6   t          |pd                                          }|st          dd          t          | dd|gd          }|j        dk    rt          d	d          t          | d
dd| gd          }|j        dk    rt          dd          |S )Nr   zNew branch name is requiredrm   zcheck-ref-formatr  Fr   r   zInvalid branch namera  rb  rc  z,A local branch with that name already exists)r9   r   r6   r   r   )rM   rH  r   existss       r#   _validate_new_branch_namerm  n  s    tzr??  ""D N =}MMMc.
DAOOOFA 5}EEEcJ
4H$4H4HIQVWWWFA NP]^^^Kr"   c                v    t          | g dd          }t          |j                                                  S )N)r   r   r  Tr   )r   r   r   r   )rM   r   s     r#   _dirty_worktreero  {  s:    cPPPX\]]]F##%%&&&r"   c                    t          | ddgd          j                                        }|r|S t          | g dd          j                                        pdS )Nr  rV  Fr   r  Tr  )r   r   r   rM   r  s     r#   _current_checkout_labelrr    si    cH&67uEEELRRTTF C999FFFMSSUU_Y__r"   rM  tuple[str, str] | Nonec                T   t          | pd                                          } |                     d          rd| vrd S | dd                              dd          \  }}|                                }|                                }|r|                    t                    sd S ||fS )Nr   zOn z: r   r   )r9   r   r0   r   "_HERMES_BRANCH_SWITCH_STASH_PREFIX)rM  r  r8   s      r#   _stash_subject_partsrv    s    '-R  &&((Ge$$ G(;(;tabbk''a00OFG\\^^FmmooG ++,NOO t7?r"   c                :   t          | g dd          }|j        dk    rg S g }|j                                        D ]]}	 |                    dd          \  }}n# t
          $ r Y )w xY wt          |          }|s?|\  }}|                    |||d           ^|S )N)stashr/   z--format=%gd%x00%gsFr   r   r   r   )r_  r  r8   )r   r   r   r   r   r   rv  r   )	rM   r   stashesr   r_  rM  r   r  r8   s	            r#   _hermes_branch_switch_stashesrz    s    cCCC5QQQFA	G((** 	K 	K	::dA..LC 	 	 	H	$W-- 	sfIIJJJJNs    A
A'&A'c           	     (   t          |           ri S t          |           D ]p}|                    d          |k    rt          | ddd|d         gd          }|j        dk    rd	|ic S d
|j        p|j        pd                                |dc S i S )Nr  rx  r.   --indexr_  Fr   r   restored_stashTzGit stash restore failed)restore_failedrestore_errorrestore_stash)ro  rz  r  r   r   r   r   r   )rM   r  r  r   s       r#   #_restore_branch_switch_stash_lockedr    s    s 	-c22 

 

88H''#	4;GuUUU!!$d++++"$mZv}Z@Zaacc!
 
 	
 	
 	

 Ir"   mode
new_branchNonec                   |dk    rt          | |           d S |dv r0t          | |p|           t          | |r
|r||k    r|nd           d S |dk    rt          | |          }t	          |p|                    dd          d                                                   }t          | dd	d
| gd          }|j        dk    rt          | |           d S |dv rt          | |           d S t          dd          )NrZ  >   newcreater  r[  r   r   ra  rb  rc  Fr   r   >   detachrX  Unsupported checkout moderm   )
rf  rm  rj  rh  r9   r   r   r   r   r6   )rM   r_  r  r  
remote_refbranch_namerl  s          r#   !_validate_checkout_request_lockedr    s8    wsC(((   !#z'8S999 j&cS&cSJEVEVcc]cdddx,S#66
*D
(8(8a(@(@(DEEKKMM#
J8Sk8S8ST\abbb!!%c;777%%% c***
7
G
GGr"   trackc                F   |dk    r$t          | |          }t          | d|gd          S |dv rDt          | |p|          }t          | |r
|r||k    r|nd          }t          | dd||gd          S |dk    rt	          | |          }	t          |p|	                    d	d
          d                                                   }
t          | ddd|
 gd          }|j        dk    r.t          | d|
gd          }|rt          | dd|	|
gd           |S t          | |
          }dd|g}|r|	                    d           |	                    |	           t          | |d          S |dv r%t          | |          }t          | dd|gd          S t          dd          )NrZ  switchTr   >   r  r  r  z-cr[  r   r   r  ra  rb  rc  Fr   r  z--set-upstream-toz--track>   r  rX  z--detachr  rm   )rf  r   rm  rj  rh  r9   r   r   r   r   r6   )rM   rH   r_  r  r  r  r   r  	start_refr  r  rl  r   rZ   s                 r#   _perform_checkout_lockedr    s	    w'S11h/t<<<<   *3
0AcBB,S*2o2oQTXbQbQb##iopp	hfi@MMMMx,S#66
*D
(8(8a(@(@(DEEKKMM#
J8Sk8S8ST\abbb!!cHk#:$GGGF ex)<j+V^cddddM*3<<$' 	#KK	"""JT....%%%)#s33h
F;4HHHH
7
G
GGr"   block
dirty_modec           	        t          |           }|t          dd          t          |pd                                                                          }t          |pd                                                                          }|dk    rt          dd          t          |          5  t          ||||           t          |          rt          dd          t          || ||||          }d d d            n# 1 swxY w Y   t          |           }t          |           }	dt          |          |	                    d	          ||	d
S )NrU  r_   rZ  r  z6Only dirty_mode=block is supported for branch checkoutrl   zACheckout blocked because the Git worktree has uncommitted changesTrW  )okr8   current_branchr   branches)r   r6   r9   r   r    rY   r  ro  r  r@  r^  _remote_messager  )
rH   r_  r  r  r  r  rM   r   r   r  s
             r#   git_checkoutr    s    i
(
(C
{ C\RRRtw%%''--//DZ*7++113399;;JW XZjkkk	C	 	  X X)#sD*EEE3 	#S    *#y#tZQVWWX X X X X X X X X X X X X X X 	""FI&&H"6**",,y11  s   1ADD
Dc                ,   t          |           }|t          dd          t          |pd                                                                          }t          |p|pd                                          pd}t
           d|                                 }i }t          |          5  t          ||||           d}	t          |          r*t          |ddd	d
|gd          }
t          |
          }d|v}		 t          || ||||          }n%# t          $ r |	rt          |g dd            w xY wt          |          }t          ||          }d d d            n# 1 swxY w Y   t          |           }t!          |           }dt          |          |	r|nd|	|                    d          t%          |                    d                    |                    dd          |                    d          |                    d          ||dS )NrU  r_   rZ  r  z to Frx  rd   -u-mTr   zNo local changes to save)rx  r.   r|  z	stash@{0}r   r}  r~  r  r  rW  )r  r8   
stash_namestashedr}  r~  r  r  r  r   r  )r   r6   r9   r   r    ru  rY   r  ro  r   r  r  	Exceptionrr  r  r@  r^  r  r   )rH   r_  r  r  r  rM   target_labelr  restoredr  stash_result
stash_textr   r  r   r  s                   r#   git_stash_and_checkoutr    s    i
(
(C
{ C\RRRtw%%''--//Dz2S2F3399;;EvL6JJLJJPPRRJH	C	 	  L L)#sD*EEE3 	C#C'64z)RZ^___L(66J0
BG	-c9c4UZ[[FF 	 	 	 UFFFeTTTT	 1556sNKKL L L L L L L L L L L L L L L 	""FI&&H"6**$+3jj",,'788x||,<==>>!or::!o66",,y11  s+   -AE!<DE!"D33"E!!E%(E%	diff_textc                    dx}}|                                  D ]b}|                    d          s|                    d          r-|                    d          r|dz  }H|                    d          r|dz  }c||fS )Nr   z+++z---r  r   r   )r   r0   )r  r   r   r   s       r#   _diff_statsr  D  s    I	$$&&  ??5!! 	T__U%;%; 	??3 	NII__S!! 	NIir"   labelc           	     `   	 |                                  st          d          |                                 j        t          k    rddddddS n/# t
          $ r"}t          t          |                    |d }~ww xY w	 |                                 }n/# t
          $ r"}t          t          |                    |d }~ww xY wd|v rddddddS 	 |                    d          }n# t          $ r ddddddcY S w xY w|
                                }t          t          j        g |d	d
| d                    }d                    |          |rdndz   }t          |                    dd                    t          k    }|r|d t                   }t#          |          \  }	}
d|||	|
dS )NzPath is not a fileFTr   r   )r   	too_larger   r   r   r   r   z	/dev/nullzb/)fromfiletofilelineterm
r   errors)r   r6   r   r   r   r   r9   r   r   r   r   r/   difflibunified_diffrp   r   encoder  )r   r  r   r   rq   lines
diff_linesr   r  r   r   s              r#   _synthetic_untracked_diffr  P  s   3||~~ 	:#$899999;;00!   1  3 3 3C))s233   3 3 3C))s23}}UBQ]^___`{{7## ` ` `UBQ]^_____`OOER\%\\\^___ J 99Z  J$>DDB?DDKK	K::;;oMI &$_$%&t,,Iy  sB   AA 
A<A77A< B 
CB<<CC' 'C<;C<r   kindc                   t          |           }|t          d          |dvrt          d          t          ||          }t          ||          p|t	          |           }t          fd|                    dg           D             d           }|dk    r6|r4|                    d          rt          |j        z            }|d|S g d	}|d
k    r|	                    d           |
                    d|g           t          ||d          }	|	j        }
d|
v pd|
v }t          |
                    dd                    t          k    }|r|
d t                   }
t!          |
          \  }}||||||rdn|
dS )NrU  >   r   r   zkind must be staged or unstagedc              3  N   K   | ]}|                     d           k    |V   dS )r   Nr  )r  r  r   s     r#   r  zgit_diff.<locals>.<genexpr>  s7      \\QQUU6]]m=[=[q=[=[=[=[\\r"   r!  r   r   )r   r  )r   --no-ext-diff--unified=3r   r   r   Tr   zBinary files zGIT binary patchr   r   r  r   )r   r  r   r  r   r   r   )r   r6   r   r   r@  nextr  r  rH   r   r   r   r   r   r  r   r  )rH   r   r  rM   r   r   
file_statepayloadrZ   r   r   r   r  r   r   r   s                  @r#   git_diffr  z  s   
i
(
(C
{ CDDD))) ABBBd##H"3119TM	""F\\\\&**Wb"9"9\\\^bccJzjZ^^K-H-H+CMM,I=YY%t??w??333DxJKKx !!!c4t,,,F=D$B(:d(BFDKK	K::;;oMI &$_$%&t,,Iy&$  r"   r   Iterable[str]c                    g }| D ]@}t          |pd                                          }|r||vr|                    |           A|st          d          |S )Nr   zAt least one path is required)r9   r   r   r6   )r   cleanedr   values       r#   _clean_pathsr    ss    G " "DJB%%'' 	"U'))NN5!!! A ?@@@Nr"   c                :      fdt          |          D             S )Nc                0    g | ]}t          |          S r!   r   r  r   rM   s     r#   
<listcomp>z_pathspecs.<locals>.<listcomp>  s#    AAATIc4  AAAr"   )r  )rM   r   s   ` r#   
_pathspecsr    s%    AAAA\%-@-@AAAAr"   c           	         t          |           }|t          dd          t          |          5  t          |ddgt	          ||          d           d d d            n# 1 swxY w Y   t          |           S )NrU  r_   r   r   Tr   )r   r6   rY   r   r  r@  )rH   r   rM   s      r#   	git_stager    s    
i
(
(C
{ C\RRR	C	 	  J Jud<ZU%;%;<DIIIIJ J J J J J J J J J J J J J Ji   s   %A""A&)A&c                B   t          |           }|t          dd          t          ||          }t          |          5  t	          |dddg|d          }|j        dk    rt	          |d	d
dg|d           d d d            n# 1 swxY w Y   t          |           S )NrU  r_   restorez--stagedr   Fr   r   resetr  T)r   r6   r  rY   r   r   r@  )rH   r   rM   specsr   s        r#   git_unstager    s   
i
(
(C
{ C\RRRsE""E	C	 	  G G#	:tDeDERRR!!S7FD959FFFFG G G G G G G G G G G G G G G i   s   :BBB)delete_untrackedr  c          	     r   t          |           }|t          dd          t          |          5  t          |           }d |                    dg           D             }t          |          D ] }t          ||          }t          ||          p|}|                    |          p*|                    |                    d          dz             }	|	r%|	                    d          rt          dd          |	r||	                    d          rg|st          d	          t          |j
        |          }
|
                                rt          j        |
           n|
                    d
           
t          |ddd|gd
           "	 d d d            n# 1 swxY w Y   t          |           S )NrU  r_   c                     i | ]}|d          |S r   r!   r  r  s     r#   
<dictcomp>zgit_discard.<locals>.<dictcomp>  s    AAAA1V9aAAAr"   r!  r   rf   z4Conflicted files cannot be discarded from this panelr   z-Untracked files require delete_untracked=trueT
missing_okr  z
--worktreer   r   )r   r6   rY   r@  r  r  r   r   r   r   rH   is_dirshutilrmtreeunlinkr   )rH   r   r  rM   r   by_pathr   r   r   stater   s              r#   git_discardr    s   
i
(
(C
{ C\RRR	C	 	  Q QI&&AAGR)@)@AAA '' 	Q 	QD d++H*399ATMKK..^'++m>R>RSV>W>WZ]>]2^2^E l:.. l'(^`jkkk ;// ' ]+,[\\\(FF==?? 3M&))))MMTM222S9lD(C4PPPPP	QQ Q Q Q Q Q Q Q Q Q Q Q Q Q Q& i   s   E!FF#&F#a-  When writing commit messages, PR titles, or PR descriptions:

- Inspect the staged diff before suggesting a commit message.
- Do not use vague subjects like "update", "improve", "refine", "misc changes", "fix stuff", or "various changes".
- For large commits, write a concise subject plus a short body with 2-5 bullets summarizing the main areas changed.
- The subject should describe the actual user-facing result or bug fixed, not just broad implementation activity.
- Keep wording short, clear, and natural.
- Never mention AI, Cursor, Zed, agents, or similar tooling in commits, branch names, PR titles, or PR descriptions.
- Never add your own thoughts or questions into the commit message, the commit message is definitive in nature.

Return only the commit message text. Do not wrap it in Markdown fences.
tuple[str, bool]c                   t          | dddddt          |           gd          }|j        pd}|                    d	d
          }t	          |          t
          k    r|dfS |d t
                                       d	d
          dfS )Nr   r   r  r  r   Tr   r   r   r   r  F)r   r   r   r  r   COMMIT_MESSAGE_DIFF_LIMITr   )rM   r   r   encodeds       r#   _staged_diff_textr    s    $$	
   F =BDkk')k44G
7||000U{---.55gi5PPRVVVr"   r  tuple[dict[str, str], str]c                   t          j        d          \  }}t          j        |           t	          |                              d           d|i}	 t          | g dd|          }|j        d	k    rt          | d
dgd|           nt          | d
dgd|           t          | dddg|d|           ||fS # t          $ r% t	          |                              d            w xY w)Nzhermes-webui-git-index-)r   Tr  GIT_INDEX_FILE)r   rb  r  Fru   r2   r   z	read-treer  z--emptyr   z-Ar   )	tempfilemkstempr   closer   r  r   r   r  )rM   r  fd
index_pathr2   rY  s         r#   _selected_temp_index_envr    s%   %-FGGGNB
HRLLLt,,,Z
(C
>>>eQTUUU?aS;/tEEEEES;	2$CHHHHudD1513GGGGJ   Z4000s   A&B< </C+'tuple[list[str], list[str], list[dict]]c                6    t          |          } fd|D             } fdt          ||          D             }t           j                  }d |                    dg           D             }g }g }t          ||          D ]\  }	}
|                    |	          }|s|                    d          rt          dd          |                    d          s*|                    d          s|                    d	          rb|                    |           |
|                    d
          rt           |d
                   ndfD ]}|r||vr|                    |           t          |          t          |          k    rt          d          |||fS )Nc                0    g | ]}t          |          S r!   r  r  s     r#   r  z#_selected_files.<locals>.<listcomp>  s#    BBByd++BBBr"   c                :    g | ]\  }}t          |          p|S r!   )r   )r  specr   rM   s      r#   r  z#_selected_files.<locals>.<listcomp>  s,    kkkZT4~c4008Dkkkr"   c                     i | ]}|d          |S r  r!   r  s     r#   r  z#_selected_files.<locals>.<dictcomp>  s    ===qy!===r"   r!  rf   z2Resolve conflicts before committing selected filesr   r   r   r  r   *Selected paths have no committable changes)	r  zipr@  rH   r  r6   r   r   r   )rM   r   	requestedrequested_specsworkspace_pathsr   r  r  selectedr   r   r  r  s   `            r#   _selected_filesr    s   U##IBBBB	BBBOkkkk3`iKjKjkkkO&&F==VZZ%<%<===GEHo?? 
' 
'hD!! 	99Z   	f#$XZdeee99X 	'%))J"7"7 	'599[;Q;Q 	'OOE"""!		R\H]H]#e9S%
2C#D#D#Dcef ' ' 'D--LL&&&
8}}O,,,, LMMM/8++r"   c                   t          | |          \  }}	 t          | dddddg|d|          }|j        pd}|                    d	d
          }t	          |          t
          k    r'|dft          |                              d           S |d t
                                       d	d
          dft          |                              d           S # t          |                              d           w xY w)Nr   r   r  r  r   Tr  r   r   r   r  Fr  )	r  r   r   r  r   r  r   r  r   )rM   r  r2   r  r   r   r  s          r#   _selected_diff_textr  )  s   .sE::OC1Z-NN	
 
 
 }"++gi+88w<<444; 	Z40000 111299')9TTVZZZ40000Z40000s   AC %C %C<c           
     f   t          |           }|t          dd          t          ||          \  }}}t          ||          \  }}|                                st          d          t          |           }g }	|d d         D ]}
|
                    d          rdn1d|
                    d          pd d	|
                    d
          pd }|	                    d|
                    d          pd d|
                    d           d| d           t          |          dk    r)|	                    dt          |          dz
   d           d|                    d          pd dt          |           dd	                    |	          z   |rdndz   dz   |z   dz   }t          |||dS )NrU  r_   zNo selected diff is availableP   r   r  r   r    -r   - r   r   r]   r    ()- ... z more selected file(s)zAWrite a commit message for the selected Git diff below.

Branch: r  r  z
Selected files ():
r  ?

Diff was truncated for size; summarize only what is visible.
z
Selected diff:
```diff

```system_promptuser_promptr"  r   )r   r6   r  r  r   r@  r  r   r   rp   COMMIT_MESSAGE_SYSTEM_PROMPT)rH   r   rM   r  _workspace_pathsselected_filesr   r"  r   
file_linesr  r   r  s                r#   selected_commit_message_promptr  ;  s-   
i
(
(C
{ C\RRR.=c5.I.I+E^)#u55OD)::<< A ?@@@	""FJss# Y Y xx!!PHHOTXXk**/aOO488K3H3H3MAOO 	
 	Wtxx118SWW488F;K;KWWuWWWXXXX
>RS3~#6#6#;SSSTTT	5::h''16	5 	5~..	5 	5 	5 ))J

	  PP	
 (		( 
	 	  6"	  r"   c           
        t          |           }|t          d          t          |           }t          |                    d          pi                     d          pd          dk    rt          d          t          |          \  }}|                                st          d          d |                    dg           D             }g }|d d	         D ]}|                    d
          rd
n1d|                    d          pd d|                    d          pd }|                    d|                    d          pd d|                    d           d| d           t          |          d	k    r)|                    dt          |          d	z
   d           d|                    d          pd dt          |           dd	                    |          z   |rdndz   dz   |z   d z   }	t          |	||d!S )"NrU  r   r   r   z0Stage changes before generating a commit messagezNo staged diff is availablec                <    g | ]}|                     d           |S )r   r  r  s     r#   r  z0staged_commit_message_prompt.<locals>.<listcomp>n  s'    JJJ!!%%//JAJJJr"   r!  r  r   r  r   r  r   r  r   r   r]   r   r  r  r  z more staged file(s)z?Write a commit message for the staged Git diff below.

Branch: r  r  z
Staged files (r  r  r  z
Staged diff:
```diff
r	  r
  )r   r6   r@  ry   r  r  r   r   r   rp   r  )
rH   rM   r   r   r"  staged_filesr  r  r   r  s
             r#   staged_commit_message_promptr  d  sx   
i
(
(C
{ CDDD	""F
FJJx  &B++H55:;;q@@ RSSS',,OD)::<< ? =>>>JJvzz'266JJJLJSbS! Y Y xx!!PHHOTXXk**/aOO488K3H3H3MAOO 	
 	Wtxx118SWW488F;K;KWWuWWWXXXX
<2O3|#4#4r#9OOOPPP	1::h''16	1 	1\**	1 	1 	1 ))J

	  PP	
 &		& 
	 	  6"	  r"   c                n   t          | pd                                          }|                    d          r|                                }|r%|d                             d          r
|dd          }|r(|d                                         dk    r
|d d         }d                    |                                          }|                    d          r|                    d          s*|                    d          r1|                    d          r|dd                                         }|S )	Nr   z```r   r   r  r  "')r9   r   r0   r   rp   rO  )r8   rq   r  s      r#   clean_generated_commit_messager    s)   w}"##%%Du (!! 	U1X((// 	!""IE 	U2Y__&&%//#2#JEyy%%'' "s!3!3 ""!%s!3!3" AbDz!!Kr"   c                   t          |pd                                          }|st          d          t          |           }|t          dd          t	          |          5  t          |dd|gdd	           d d d            n# 1 swxY w Y   t          |g d
d          j                                        }d|t          |           dS )Nr   Commit message is requiredrU  r_   commitr  r  TrO   ru   r  r   )r  r  r   )r9   r   r6   r   rY   r   r   r@  )rH   r8   msgrM   rI  s        r#   
git_commitr    s-   
gm


"
"
$
$C > <===
i
(
(C
{ C\RRR	C	 	  E Exs+RtDDDDE E E E E E E E E E E E E E E
3888
E
E
E
L
R
R
T
TC#I1F1FGGGs   %BBBc                &   t          |pd                                          }|st          d          t          |           }|t          dd          t	          |          5  t          ||          \  }}}t          ||          \  }}		 t          |ddddg|d	|
          }
|
j        dk    rt          d          t          |dd|gdd|           t          |ddddg|d           t          |	          
                    d           n(# t          |	          
                    d           w xY w	 d d d            n# 1 swxY w Y   t          |g dd          j                                        }d||t          |           dS )Nr   r  rU  r_   r   r   z--quietr   Fr  r   r  r  r  r  Trt   r  z-qr  r   r  r  )r  r  r   r   )r9   r   r6   r   rY   r  r  r   r   r   r  r   r@  )rH   r8   r   r  rM   r  r  _selected_files_listr2   r  quietrI  s               r#   git_commit_selectedr#    s   
gm


"
"
$
$C > <===
i
(
(C
{ C\RRR	C	 	  
5 
57FsE7R7R4 423>>Z	5S6:y$"O"OW\befffE1$$'(TUUUS8T3/4SQQQQS7D&$??tLLLL##t#4444D##t#44444
5 
5 
5 
5 
5 
5 
5 
5 
5 
5 
5 
5 
5 
5 
5 3888
E
E
E
L
R
R
T
TC#:V_K`K`aaas+   %(E	A"D0$E	%D99E		EEc                ~    t          | ddgd          j                                        }|st          d          |S )Nr  rV  Tr   z Cannot push from a detached HEAD)r   r   r   r6   rq  s     r#   _branch_namer%    sH    cH&67tDDDKQQSSF D BCCCMr"   r   c                F    | j         p| j        pd                                S )Nr   )r   r   r   )r   s    r#   r  r    s"    M0V]0b77999r"   c                   t          |           }|t          dd          t          |          5  t          |ddgt          d          }d d d            n# 1 swxY w Y   dt          |          t          |           dS )NrU  r_   fetchz--pruneTr  r  r8   r   r   r6   rY   r   rV   r  r@  rH   rM   r   s      r#   	git_fetchr,    s    
i
(
(C
{ C\RRR	C	 	  ] ]#3=OW[\\\] ] ] ] ] ] ] ] ] ] ] ] ] ] ]?6#:#:jQZF[F[\\\   AAAc                   t          |           }|t          dd          t          |          5  t          |ddgt          d          }d d d            n# 1 swxY w Y   dt          |          t          |           dS )NrU  r_   pullz	--ff-onlyTr  r)  r*  r+  s      r#   git_pullr0    s    
i
(
(C
{ C\RRR	C	 	  ^ ^#4>PX\]]]^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^?6#:#:jQZF[F[\\\r-  c                   t          |           }|t          dd          t          |          5  t          |           }dg}|                    d          set          |          }t          |dgd          j                                        }d|vrt          d	d
          |	                    dd|g           t          ||t          d          }d d d            n# 1 swxY w Y   dt          |          t          |           dS )NrU  r_   rd   r  r[  Tr   originz1No upstream branch or origin remote is configuredrb   r  r  r)  )r   r6   rY   r@  r  r%  r   r   r   r   rV   r  )rH   rM   r   rZ   r  remotesr   s          r#   git_pushr4    sc   
i
(
(C
{ C\RRR	C	 	  	M 	MI&&xzz*%% 	2!#&&FsXJd;;;BHHJJGw&&'([]jkkkKKx0111#t-?tLLL	M 	M 	M 	M 	M 	M 	M 	M 	M 	M 	M 	M 	M 	M 	M ?6#:#:jQZF[F[\\\s   B%C""C&)C&)r   r   r)   )r%   r&   r   r'   )rM   rG   )r8   r9   rZ   r[   r   r9   )rv   rw   rZ   rx   rO   ry   ru   r   r2   r&   r   rz   )rH   r   r   r   )rM   rG   r   r9   )rM   rG   r   r9   r   r9   )rM   rG   r   r9   r   r   )r   r   )r   r9   r   r   r   r   r   r9   )rq   r9   rM   rG   r   r   )rq   r9   rM   rG   r   r   )rM   rG   r   r   r   r   r   r   )rM   rG   r   r   r   r   r   r   )r   r   r   r   )rH   r   r   r   )rM   rG   r  r9   r  r9   r   rA  )rM   rG   rD  r9   r   rE  )rM   rG   r_  r9   r   r9   )rM   rG   rH  r9   r   r9   )rM   rG   r   r   )rM  r9   r   rs  )rM   rG   r   rE  )rM   rG   r  r9   r   r   )
rM   rG   r_  r9   r  r9   r  r   r   r  )rM   rG   rH   r   r_  r9   r  r9   r  r   r  r   r   rz   )NFr  )rH   r   r_  r9   r  r9   r  r   r  r   r  r9   r   r   )NF)rH   r   r_  r9   r  r9   r  r   r  r   r   r   )r  r9   r   rA  )r   r   r  r9   r   r   )r   )rH   r   r   r9   r  r9   r   r   )r   r  r   rx   )rM   rG   r   r  r   rx   )rH   r   r   r  r   r   )rH   r   r   r  r  r   r   r   )rM   rG   r   r  )rM   rG   r  rx   r   r  )rM   rG   r   r  r   r  )rM   rG   r  rx   r   r  )r8   r9   r   r9   )rH   r   r8   r9   r   r   )rH   r   r8   r9   r   r  r   r   )r   rz   r   r9   )\rC   
__future__r   r  r   r  r   r  rS   
contextlibr   dataclassesr   pathlibr   typingr   api.workspacer   GIT_TIMEOUTrV   r%  r   r  r   r-   r1   ru  r$   r4   RuntimeErrorr6   rG   rT   rQ   rL   rK   rY   rs   r   r   r   r   r   r   r   r   r   r   r   r   r@  rC  rS  r^  rf  rh  rj  rm  ro  rr  rv  rz  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,  r0  r4  r!   r"   r#   <module>r=     s     # " " " " "  				           % % % % % % ! ! ! ! ! !             ) ) ) ) ) )   %  H   C %A "   	 	 	 	 	        $        y~')	 ) ) ) )        L !%     @
k 
k 
k 
k' ' ' '   "	 	 	 	    05e 
  
  
  
  
  
    "    TX 
0 
0 
0 
0 
0 
0" "	. . . . . .$B B B B&V V V Vr   ? ? ? ?@   .         
 
 
 
' ' ' '
` ` ` `	 	 	 	   $   "H H H H4!H !H !H !HP "    L "+ + + + +\	  	  	  	 ' ' ' 'T" " " " "J   B B B B! ! ! !	! 	! 	! 	! Z_ ! ! ! ! ! !4  
EGG W W W W(   $, , , ,01 1 1 1$& & & &R( ( ( (V    
H 
H 
H 
Hb b b b,   : : : :] ] ] ]] ] ] ]] ] ] ] ] ]r"   