
    !jy:                        d Z ddlmZ ddlZddlmc mZ ddl	Z	e	j                  j                  dd       ddlZddlZddlZddlZddlmZ ddlZej&                  j)                  dd       ddlmZmZmZmZmZmZmZmZmZmZm Z m!Z! ejD                  d        Z#d!d	Z$d
 Z% G d d      Z& G d d      Z' G d d      Z( G d d      Z) G d d      Z* G d d      Z+ G d d      Z, G d d      Z- G d d      Z. G d d      Z/ G d d       Z0y)"a2  Tests for v3.6 Layer 2: Spawn Detector.

chair_authorization_id=CHAIR-AUTH-TASK-2704-V36-CONTROL-PLANE-P0-MVP-260528

Coverage:
- Each of 9 states reachable from fixture
- UNKNOWN forced when signals absent
- No backward state transitions
- Single-source determination forbidden (UNKNOWN when conflicting)
    )annotationsNz/home/jay/workspaceANU_V36_HARNESS_TEST_MODE1)detect_spawn_statestate_geNOT_REGISTERED
REGISTEREDFIREDSESSION_SEENWORK_STARTEDARTIFACT_SEENCALLBACK_REGISTEREDDONEUNKNOWN_STATE_ORDERc                    | dz  }|j                          | dz  }| dz  }|j                          |dz  j                          t        |      t        |      t        |      dS )z4Create temporary events dir + timers file structure.eventsztask-timers.jsonz	.cokacdirschedule_history
events_dirtimers_filecokacdir)mkdirstr)tmp_pathr   r   r   s       E/home/jay/workspace/tests/harness/test_v36_spawn_detector_contract.pytmp_envr   ,   sk     H$J//K+%HNN""))+*o;'M     c                    d|d|iii}|r||d   |   d<   t        | d      5 }t        j                  ||       d d d        y # 1 sw Y   y xY w)Ntasksstatusschedule_idw)openjsondump)pathtask_idr!   r"   datafhs         r   write_timersr+   <   sZ    g&123D0;Wg}-	dC B		$  s   AAc                l    t        | d      5 }|j                  d       d d d        | S # 1 sw Y   | S xY w)Nr#   z{})r$   write)r'   r*   s     r   
touch_filer.   D   s2    	dC B
KKs   )3c                      e Zd Zd Zd Zy)TestStateNOT_REGISTEREDc           	        t        j                  dg       5  t        j                  dd       5  t        d|d   |d   |d         }d d d        d d d        d	   }|t        k(  }|st	        j
                  d
|fd|t        f      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              nddz  }t	        j                  d|d	    d|d          dz   d|iz  }t        t	        j                  |            d x}}y # 1 sw Y   xY w# 1 sw Y   xY w)N9scripts.harness.v36.spawn_detector._list_claude_processesreturn_value7scripts.harness.v36.spawn_detector._get_anu_session_hex	task-9999r   r   r   r   state==z%(py1)s == %(py3)sr   py1py3z5Expected NOT_REGISTERED when all signals absent, got : reason
>assert %(py5)spy5)mockpatchr   r   
@pytest_ar_call_reprcompare	_saferepr@py_builtinslocals_should_repr_global_name_format_assertmsgAssertionError_format_explanationselfr   result@py_assert0@py_assert2@py_format4@py_format6s          r   test_all_signals_absentz/TestStateNOT_REGISTERED.test_all_signals_absentM   s.   ZZSbde 	Udhi +&|4 ' 6$Z0		 g 	
.0 	
 	
. 	
 	
 		  	
 	
	6	
 	
  #1 	
 	
 		 #1 	
 	
  DF7OCTTVW]^fWgVhi	
 	
 	
 	
 	
 	 	s"   ED5	E5D>	:EE
c           	     `   t        j                  dg       5  t        j                  dd       5  t        d|d   |d   |d         }d d d        d d d        d	}d
   }|j                  } |       }||v }|st	        j
                  d|fd||f      t	        j                  |      t	        j                  |      t	        j                  |      t	        j                  |      dz  }dd|iz  }	t        t	        j                  |	            d x}x}x}x}}y # 1 sw Y   xY w# 1 sw Y   xY w)Nr2   r3   r5   r6   r   r   r   r   absentr?   in)zD%(py1)s in %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.lower
}()
})r<   py4py6py8zassert %(py10)spy10)	rB   rC   r   lowerrD   rE   rF   rK   rL   )
rN   r   rO   rP   @py_assert3@py_assert5@py_assert7rQ   @py_format9@py_format11s
             r   *test_not_registered_reason_mentions_absentzBTestStateNOT_REGISTERED.test_not_registered_reason_mentions_absentZ   s    ZZSbde 	Udhi +&|4 ' 6$Z0		 36(+3+113133x33333x3333x333+3331333333333333 	 	s"   D$D	D$D!	D$$D-N)__name__
__module____qualname__rT   rc    r   r   r0   r0   L   s    
	4r   r0   c                      e Zd Zd Zd Zy)TestStateREGISTEREDc           	     h   t        |d   ddd       t        j                  dg       5  t        dd|d   |d   |d	   
      }d d d        d   }|t        k(  }|st        j                  d|fd|t        f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                  d|d    d|d          dz   d|iz  }t        t        j                  |            d x}}y # 1 sw Y   xY w)Nr   	task-2704runningBE5161A0r!   r"   r2   r3   r   r   r"   r   r   r   r7   r8   r:   r	   r;   zExpected REGISTERED, got r>   r?   r@   rA   )r+   rB   rC   r   r	   rD   rE   rF   rG   rH   rI   rJ   rK   rL   rM   s          r   "test_timer_running_and_schedule_idz6TestStateREGISTERED.test_timer_running_and_schedule_idg   s    W]+[XbcZZSbde 	'&"<0#M2 ,F	 go*,ooo*ooooooooo*ooo*oooo0I&QX/IZZ\]cdl]m\n.ooooooo	 	s   D((D1c                   t        |d   dd       t        j                  dg       5  t        d|d   |d   |d   	      }d
d
d
       d   }t        t
        f}||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d
x}x}}y
# 1 sw Y   xY w)z-Without schedule_id, cannot reach REGISTERED.r   rk   rl   r!   r2   r3   r   r   r   Nr7   rW   z%(py1)s in %(py4)sr<   rY   assert %(py6)srZ   )r+   rB   rC   r   r   r   rD   rE   rF   rK   rL   rN   r   rO   rP   r^   rQ   @py_format5@py_format7s           r   $test_registered_requires_schedule_idz8TestStateREGISTERED.test_registered_requires_schedule_ids   s    W]+[KZZSbde 	'"<0#M2 ,	F	 g;>7";;";;;;;";;;;;;;";;;;;;;;	 	   CCN)rd   re   rf   rp   ry   rg   r   r   ri   ri   f   s    
p<r   ri   c                      e Zd Zd Zy)TestStateFIREDc           	     
   d}t        |d   dd|       t        j                  j                  |d   d      }t	        t        j                  j                  || d             t        j                  d	g 
      5  t        d||d   |d   |d         }d d d        d   }|t        k(  }|st        j                  d|fd|t        f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                  d|d    d|d          dz   d|iz  }t!        t        j"                  |            d x}}y # 1 sw Y   xY w)Nrm   r   rk   rl   rn   r   r   z.logr2   r3   r   ro   r7   r8   r:   r
   r;   zExpected FIRED, got r>   r?   r@   rA   )r+   osr'   joinr.   rB   rC   r   r
   rD   rE   rF   rG   rH   rI   rJ   rK   rL   )	rN   r   sched_idhistory_dirrO   rP   rQ   rR   rS   s	            r   test_schedule_history_presentz,TestStateFIRED.test_schedule_history_present   s&   W]+[X`aggll7:#68JK277<<z->?@ZZSbde 	'$"<0#M2 ,F	 ge%'eee%eeeeeeeee%eee%eeee+?w?PPRSYZbScRd)eeeeeee	 	s   ;E99FN)rd   re   rf   r   rg   r   r   r|   r|      s    fr   r|   c                      e Zd Zd Zy)TestStateSESSION_SEENc           
        t        |d   ddd       t        j                  ddg      5  t        j                  d	d
      5  t        dd|d   |d   |d         }d d d        d d d        d   }|t        k(  }|st        j                  d|fd|t        f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                  d|d    d|d          dz   d|iz  }t        t        j                  |            d x}}y # 1 sw Y   xY w# 1 sw Y   xY w)Nr   rk   rl   rm   rn   r2   18b3a030fdc880aer3   r5   aaaa000000000000r   r   ro   r7   r8   r:   r   r;   zExpected SESSION_SEEN, got r>   r?   r@   rA   )r+   rB   rC   r   r   rD   rE   rF   rG   rH   rI   rJ   rK   rL   rM   s          r   test_bot_session_distinct_hexz3TestStateSESSION_SEEN.test_bot_session_distinct_hex   s   W]+[XbcZZG,-
 	 I/ 
 , *&|4 ' 6$Z0	
		 gs,.sss,sssssssss,sss,ssss2MfU\oM^^`aghpaq`r0sssssss
 
		 	s#   EE	E	E	EEN)rd   re   rf   r   rg   r   r   r   r      s    tr   r   c                      e Zd Zd Zy)TestStateWORK_STARTEDc           
        t        |d   ddd       t        t        j                  j	                  |d   d             t        j                  dd	g
      5  t        j                  dd
      5  t        dd|d   |d   |d         }ddd       ddd       d   }t        |t              }|s t        j                  d|d    d|d          dz   dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t!        t        j"                  |            dx}}y# 1 sw Y   /xY w# 1 sw Y   4xY w)u  When dispatch marker exists + bot session active, state should be WORK_STARTED or higher.

        Note: a freshly-written dispatch marker file has mtime < 900s, which may trigger
        ARTIFACT_SEEN (1-signal threshold) before WORK_STARTED check. This is spec-correct
        behavior — both WORK_STARTED and ARTIFACT_SEEN indicate active work.
        We verify state is at least WORK_STARTED in the progression.
        r   rk   rl   rm   rn   r   z"task-2704.dispatched-20260528.jsonr2   r   r3   r5   r   r   ro   Nr7   z$Expected state >= WORK_STARTED, got r>   r?   z7
>assert %(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
}r   r   )py0py2r=   rA   )r+   r.   r~   r'   r   rB   rC   r   r   r   rD   rJ   rG   rH   rI   rF   rK   rL   )rN   r   rO   @py_assert1@py_assert4rS   s         r   %test_dispatch_marker_plus_bot_sessionz;TestStateWORK_STARTED.test_dispatch_marker_plus_bot_session   s    	W]+[Xbc277<< 57[\]ZZG,-
 	 I/ 
 , *&|4 ' 6$Z0	
		 w 	
x6 	
6 	
  36'?2C2fXFVEWX	
 	
	6	
 	
   	
 	
 		  	
 	
 		 ( 	
 	
	6	
 	
  *6 	
 	
 		 *6 	
 	
 		 7 	
 	
 	
 	
 	

 
		 	s$   G/F6	G6G 	;GGN)rd   re   rf   r   rg   r   r   r   r      s    
r   r   c                      e Zd Zd Zy)TestStateARTIFACT_SEENc           	        t        |d   ddd       t        j                  j                  |d   d      }t	        |       t        j
                  |d        t        j                  dg 	      5  t        dd|d   |d   |d
         }d d d        d   }|t        k(  }|st        j                  d|fd|t        f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                   d|d    d|d          dz   d|iz  }t#        t        j$                  |            d x}}y # 1 sw Y   xY w)Nr   rk   rl   rm   rn   r   ztask-2704.report.jsonr2   r3   r   ro   r7   r8   r:   r   r;   zExpected ARTIFACT_SEEN, got r>   r?   r@   rA   )r+   r~   r'   r   r.   utimerB   rC   r   r   rD   rE   rF   rG   rH   rI   rJ   rK   rL   )rN   r   artifact_pathrO   rP   rQ   rR   rS   s           r   test_fresh_artifact_mtimez0TestStateARTIFACT_SEEN.test_fresh_artifact_mtime   s   W]+[XbcW\%:<ST=!
%ZZSbde 	'&"<0#M2 ,F	 gu-/uuu-uuuuuuuuu-uuu-uuuu3OPVW^P_O``bcijrcsbt1uuuuuuu	 	s   .E,,E5N)rd   re   rf   r   rg   r   r   r   r      s    vr   r   c                      e Zd Zd Zy)TestStateCALLBACK_REGISTEREDc           	        t        |d   dd       t        t        j                  j	                  |d   d             t        j                  dg       5  t        j                  d	d
      5  t        d|d   |d   |d         }d
d
d
       d
d
d
       d   }|t        k(  }|st        j                  d|fd|t        f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                  d|d    d|d          dz   d|iz  }t!        t        j"                  |            d
x}}y
# 1 sw Y   xY w# 1 sw Y   xY w)a  CALLBACK_REGISTERED state: callback marker + done/completed signals.

        When done marker + completed timer are present, DONE is the higher state
        and fires first per spec (DONE > CALLBACK_REGISTERED in progression).
        We verify the state machine correctly reaches DONE or CALLBACK_REGISTERED.
        For pure CALLBACK_REGISTERED, use timer=completed + callback only (no .done file).
        r   rk   	completedrr   r   ztask-2704.callback-launch.jsonr2   r3   r5   Nr   r   r7   r8   r:   r   r;   zIExpected CALLBACK_REGISTERED with callback marker + completed timer, got r>   r?   r@   rA   )r+   r.   r~   r'   r   rB   rC   r   r   rD   rE   rF   rG   rH   rI   rJ   rK   rL   rM   s          r   %test_callback_marker_and_done_contextzBTestStateCALLBACK_REGISTERED.test_callback_marker_and_done_context   sc    	W]+[M277<< 57WXYZZSbde 	Udhi +&|4 ' 6$Z0		 g 	
"55 	
 	
"5 	
 	
 		  	
 	
	6	
 	
  #6 	
 	
 		 #6 	
 	
  XX^_fXgWhhjkqrzk{j|}	
 	
 	
 	
 	
 	 	s$   E>-E2E>2E;	7E>>FN)rd   re   rf   r   rg   r   r   r   r      s    
r   r   c                      e Zd Zd Zy)TestStateDONEc                   t        |d   dd       t        t        j                  j	                  |d   d             t        j                  dg       5  t        d|d   |d   |d	   
      }d d d        d   }|t        k(  }|st        j                  d|fd|t        f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                  d|d    d|d          dz   d|iz  }t!        t        j"                  |            d x}}y # 1 sw Y   xY w)Nr   rk   r   rr   r   ztask-2704.doner2   r3   r   r   r7   r8   r:   r   r;   zExpected DONE, got r>   r?   r@   rA   )r+   r.   r~   r'   r   rB   rC   r   r   rD   rE   rF   rG   rH   rI   rJ   rK   rL   rM   s          r   $test_done_marker_and_timer_completedz2TestStateDONE.test_done_marker_and_timer_completed   s    W]+[M277<< 57GHIZZSbde 	'"<0#M2 ,	F	 gc$&ccc$ccccccccc$ccc$cccc*=fWo=NbQWX`QaPb(ccccccc	 	s   EEN)rd   re   rf   r   rg   r   r   r   r      s    
dr   r   c                      e Zd Zd Zd Zd Zy)TestStateUNKNOWNc                   t        |d   dd       t        j                  dg       5  t        d|d   |d   |d   	      }d
d
d
       d   }t        t
        f}||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d
x}x}}y
# 1 sw Y   xY w)zWTimer alone without schedule_id = UNKNOWN (cannot assert REGISTERED or NOT_REGISTERED).r   rk   rl   rr   r2   r3   r   r   r   Nr7   rW   rs   rt   ru   rZ   )r+   rB   rC   r   r   r   rD   rE   rF   rK   rL   rv   s           r   0test_unknown_when_only_timer_present_no_schedulezATestStateUNKNOWN.test_unknown_when_only_timer_present_no_schedule  s    W]+[KZZSbde 	'"<0#M2 ,F	 g;7N";;";;;;;";;;;;;;";;;;;;;;	 	rz   c                   t        t        t              }|sddt        j                         v st        j                  t               rt        j                  t               nddt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}t        t        t              }|sddt        j                         v st        j                  t               rt        j                  t               nddt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}t        t        t              }|sddt        j                         v st        j                  t               rt        j                  t               nddt        j                         v st        j                  t              rt        j                  t              ndd	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      dz  }t        t        j                  |            d}t        t        t              }| }|sd
dt        j                         v st        j                  t               rt        j                  t               ndd	t        j                         v st        j                  t              rt        j                  t              nd	dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            dx}}t        t        t              }| }|sd
dt        j                         v st        j                  t               rt        j                  t               nddt        j                         v st        j                  t              rt        j                  t              ndd	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      dz  }t        t        j                  |            dx}}y)zOnce a state is known, a re-check with fewer signals should never
        return a lower state (UNKNOWN is acceptable, lower state is not).5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}r   r   r   r   r<   r   rY   Nr   r   r	   9assert not %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}r   )r   r   r   rG   rH   rD   rI   rF   rK   rL   r   r   r	   r   )rN   r^   rw   r_   rS   s        r   test_no_backward_transitionsz-TestStateUNKNOWN.test_no_backward_transitions  s   
 l++++++++x+++x+++++++++++++++l+++l++++++++++|44444444x444x444444444444444|444|4444444444j11111111x111x111111111111111j111j1111111111J-----------8---8------J---J-------------------GZ0000000000080008000000G000G000000Z000Z0000000000r   c                b   t        |d   dd       t        j                  dg       5  t        d|d   |d   |d   	      }d
d
d
       d   t        k(  r|d   }|j
                  }d}d} |||      }| }|st        j                  d      dz   t        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }	t        t        j                  |	            d
x}x}x}x}x}}y
y
# 1 sw Y   xY w)u   Per spec: 'spawn 0 단정 금지' — we must not assert NOT_REGISTERED
        when partial signals exist (timer running but no schedule_id).r   rk   rl   rr   r2   r3   r   r   r   Nr7   signalstimer_presentFuJ   NOT_REGISTERED asserted despite timer being present — forbidden pattern!zT
>assert not %(py9)s
{%(py9)s = %(py3)s
{%(py3)s = %(py1)s.get
}(%(py5)s, %(py7)s)
})r<   r=   rA   py7py9)r+   rB   rC   r   r   getrD   rJ   rF   rK   rL   )
rN   r   rO   rP   rQ   r   @py_assert6@py_assert8@py_assert10rb   s
             r   6test_spawn_assertion_forbidden_on_insufficient_signalszGTestStateUNKNOWN.test_spawn_assertion_forbidden_on_insufficient_signals  sO    	W]+[KZZSbde 	'"<0#M2 ,	F	 '?n,i( (,, _ e ,_eD DD D   ] I )  I -  I .=  I ?D  I E       -	 	s   D%%D.N)rd   re   rf   r   r   r   rg   r   r   r   r      s    < 	1r   r   c                      e Zd Zej                  j                  deefeefee	fe	e
fe
efeefeefg      d        Zd Zy)TestStateGezhigher,lowerc                ^   t        ||      }|sddt        j                         v st        j                  t               rt        j
                  t               nddt        j                         v st        j                  |      rt        j
                  |      nddt        j                         v st        j                  |      rt        j
                  |      ndt        j
                  |      dz  }t        t        j                  |            d }t        ||      }| }|sddt        j                         v st        j                  t               rt        j
                  t               nddt        j                         v st        j                  |      rt        j
                  |      nddt        j                         v st        j                  |      rt        j
                  |      ndt        j
                  |      dz  }t        t        j                  |            d x}}y )Nr   r   higherr]   r   r   )r   rG   rH   rD   rI   rF   rK   rL   )rN   r   r]   r^   rw   r_   rS   s          r   test_state_ge_higher_vs_lowerz)TestStateGe.test_state_ge_higher_vs_lower1  s    &&&&&&&&x&&&x&&&&&&&&&&&&&&&&&&&&&&&&&&&&E6***********8***8******E***E******6***6**********r   c                *   t        t        t              }| }|sddt        j                         v st        j                  t               rt        j                  t               nddt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d x}}t        t        t              }| }|sddt        j                         v st        j                  t               rt        j                  t               nddt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d x}}t        t        t              }| }|sddt        j                         v st        j                  t               rt        j                  t               nddt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d x}}y )Nr   r   r   r   r   r   )r   r   r   rG   rH   rD   rI   rF   rK   rL   r   )rN   r^   r_   rS   s       r   test_unknown_is_incomparablez(TestStateGe.test_unknown_is_incomparable>  s   G^4444444444484448444444G444G444444^444^4444444444NG4444444444484448444444N444N444444G444G4444444444GT***********8***8******G***G******T***T**********r   N)rd   re   rf   pytestmarkparametrizer   r   r   r   r   r
   r	   r   r   r   rg   r   r   r   r   0  sh    [[^	"#	m,	%	|$	u	
	^$. +++r   r   c                      e Zd ZdZd Zy)TestAllStatesReachablezAVerify all 9 states can be reached from appropriate fixture data.c                d   t         j                  j                  t         j                  j                  t              d      }t        |      5 }t        j                  |      }d d d        ddlm	}m
} t        |      |hz  }t        j                               }||z
  }| }	|	s~t        j                  d|       dz   ddt        j                          v st        j"                  |      rt        j$                  |      ndiz  }
t'        t        j(                  |
            d }	y # 1 sw Y   xY w)Nzfixtures/v36_spawn_states.jsonr   )r   r   z%Missing fixture coverage for states: z
>assert not %(py0)sr   missing)r~   r'   r   dirname__file__r$   r%   load"scripts.harness.v36.spawn_detectorr   r   setkeysrD   rJ   rG   rH   rI   rF   rK   rL   )rN   fixture_pathr*   fixturesr   r   
all_statesfixture_statesr   r   @py_format2s              r   'test_all_9_states_have_fixture_coveragez>TestAllStatesReachable.test_all_9_states_have_fixture_coverageG  s    ww||GGOOH%,
 , 	%2yy}H	%L&'2
X]]_-~-{M{MMCG9MMMMMMM7MMM7MMMMMM	% 	%s   D&&D/N)rd   re   rf   __doc__r   rg   r   r   r   r   D  s    KNr   r   )rl   N)1r   
__future__r   builtinsrG   _pytest.assertion.rewrite	assertionrewriterD   sysr'   insertr%   r~   tempfiletimeunittest.mockrB   r   environ
setdefaultr   r   r   r   r	   r
   r   r   r   r   r   r   r   fixturer   r+   r.   r0   ri   r|   r   r   r   r   r   r   r   r   rg   r   r   <module>r      s   	 #   
 ( )  	     

  13 7   $  4 44< <6f f"t t*
 
>v v&
 
2d d- -`+ +(N Nr   