
    8i-                       d Z ddlmZ ddlZddlmc 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mZ ddlmZmZ ej&                  j)                  dd       ddlZddlmZmZ ddlmZ  ej6                         d	        Z ej6                         d
        Z ej6                         d        Zd Zd Z d Z!d Z"d Z#d Z$d Z%d Z&d Z'd Z(d Z)d Z*d Z+e,dk(  r	 ddl-Z-ddlm.c m/Z0  e-jb                  e0       ddlmZ2  e2       Z3ddiddfddid d!fdd"id#d$fd%d&d'd d!fd%d(d)ddfgZ4dZ5e4D ]o  \  Z6Z7Z8e3js                  e6      Z:e:jv                  e7k(  xr e:jx                  e8k(  Z=e=rd*nd+Z>e=re5d(z  Z5 e?d,e> d-e6d    d.e:jv                   d/e:jx                          q  e?d0e5 d1 e@e4       d2        ej                  e5 e@e4      k(  rdnd(       yy)3u  
Tests for Story 4.01 (Track B): TierRouter — Task Classification Router

Black Box tests (BB): verify the public contract from the outside.
White Box tests (WB): verify internal caching mechanics and structural guarantees.

Story: 4.01
File under test: core/routing/tier_router.py
    )annotationsN)Path)	MagicMockcallz/mnt/e/genesis-system
TierRouter	CACHE_TTL)RoutingDecisionc              #     K   | dz  }|j                  dt        |             ddl}ddlmc m}  |j                  |       ddlm}  |d      |f  |j                  |       yw)zBTierRouter with no Redis and events log redirected to a temp file.events.jsonlEVENTS_LOG_PATHr   Nr   redis_clientsetenvstr	importlibcore.routing.tier_routerroutingtier_routerreloadr   )tmp_pathmonkeypatchlog_filer   mod_TRs         6/mnt/e/genesis-system/tests/track_b/test_story_4_01.pyrouter_no_redisr   "   sc      .(H(#h-8**IS:
4
 (
**ISs   A&A(c                 .    i  G fdd      }  |        S )z<In-memory dict-backed Redis mock with get / setex interface.c                  @    e Zd Z fdZ fdZ fdZe fd       Zy)mock_redis.<locals>.FakeRedisc                &    j                  |      S N)get)selfkeystores     r   r%   z!mock_redis.<locals>.FakeRedis.get7   s    99S>!    c                    ||<   y r$    )r&   r'   ttlvaluer(   s       r   setexz#mock_redis.<locals>.FakeRedis.setex:   s    E#Jr)   c                &    j                          y r$   )clearr&   r(   s    r   flushz#mock_redis.<locals>.FakeRedis.flush=   s    KKMr)   c                    S r$   r+   r1   s    r   r(   z#mock_redis.<locals>.FakeRedis.store@   s    Lr)   N)__name__
__module____qualname__r%   r.   r2   propertyr(   )r(   s   r   	FakeRedisr"   6   s&    	"		 
	 
	r)   r8   r+   )r8   r(   s    @r   
mock_redisr9   1   s     E  ;r)   c              #     K   | dz  }|j                  dt        |             ddl}ddlmc m}  |j                  |       ddlm}  ||      ||f  |j                  |       yw)zFTierRouter with a mock Redis and events log redirected to a temp file.r   r   r   Nr   r   r   )r   r   r9   r   r   r   r   s          r   router_with_redisr;   G   se      .(H(#h-8**IS:
:
&*
<<ISs   A'A)c                   | \  }}|j                  ddd      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}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                  |      rt        j                  |      nddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }	t        t        j                  |	            d}y)uJ   BB1: type='crud_operation' key in payload → T0, model='python_function'.
redis_readzt-001typetask_idT0==z,%(py2)s
{%(py2)s = %(py0)s.tier
} == %(py5)sdecisionpy0py2py5assert %(py7)spy7Npython_functionz-%(py2)s
{%(py2)s = %(py0)s.model
} == %(py5)sz5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstancer
   )rG   py1rH   py4)routetier
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationmodelrN   r
   )
r   router_rE   @py_assert1@py_assert4@py_assert3@py_format6@py_format8@py_format5s
             r   test_bb1_crud_task_routes_to_t0rd   W   s   IFA||\gFGH== D =D    =D      8   8   =   D       >>...>.....>.......8...8...>...........h00000000:000:000000h000h0000000000000000000r)   c                V   | \  }}|j                  ddd      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}y)u?   BB2: type='email_draft' (T1 type) → T1, model='gemini-flash'.email_draftzt-002r>   T1rB   rD   rE   rF   rJ   rK   Ngemini-flashrM   rQ   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   	r   r\   r]   rE   r^   r_   r`   ra   rb   s	            r   #test_bb2_template_task_routes_to_t1rk   `   s    IFA||]wGHH== D =D    =D      8   8   =   D       >>+^+>^++++>^++++++8+++8+++>+++^+++++++r)   c                V   | \  }}|j                  ddd      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}y)uC   BB3: type='completely_unknown_xyz' → T2, model='claude-opus-4-6'.completely_unknown_xyzzt-003r>   T2rB   rD   rE   rF   rJ   rK   Nclaude-opus-4-6rM   ri   rj   s	            r   "test_bb3_unknown_task_routes_to_t2rp   h   s    IFA||%='RSH== D =D    =D      8   8   =   D       >>...>.....>.......8...8...>...........r)   c                   | \  }}ddiddiddifD ]/  }|j                  |      }|j                  }h d}||v }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d	z  }d
d|iz  }	t        t        j                  |	            dx}x}}|j                  }h d}||v }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d	z  }d
d|iz  }	t        t        j                  |	            dx}x}}|j                  }|syddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }
t        t        j                  |
            d}2 y)u[   BB4: No Redis supplied → TierRouter still classifies and returns a valid RoutingDecision.r?   health_check
faq_answernever_seen_before_type   rA   rg   rn   in)z,%(py2)s
{%(py2)s = %(py0)s.tier
} in %(py5)srE   rF   rJ   rK   N   rL   rh   ro   )z-%(py2)s
{%(py2)s = %(py0)s.model
} in %(py5)sz-assert %(py2)s
{%(py2)s = %(py0)s.rationale
}rG   rH   )rQ   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   	rationale)r   r\   r]   payloadrE   r^   r_   r`   ra   rb   @py_format3s              r   .test_bb4_no_redis_still_returns_valid_decisionr}   p   sp   IFA	 		)* "
 <<(}}2 22} 22222} 2222222x222x222}222 22222222~~W!WW~!WWWWW~!WWWWWWWxWWWxWWW~WWW!WWWWWWWW!!!!!!!!!x!!!x!!!!!!!!!!"r)   c                   | \  }}}ddd}|j                  |      }|j                  |      }|j                  }d}||u }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	t        j                  d	      d
z   d|	iz  }
t        t        j                  |
            dx}x}}|j                  }d}||u }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	t        j                  d      d
z   d|	iz  }
t        t        j                  |
            dx}x}}|j                  }|j                  }||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|j                  }|j                  }||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)uK   BB5: Same task type routed twice with Redis → second call is_cached=True.rf   zt-cached-testr>   Fisz1%(py2)s
{%(py2)s = %(py0)s.is_cached
} is %(py5)sfirstrF   zFirst call must NOT be cached
>assert %(py7)srK   NTsecondz%Second call MUST be served from cacherB   zF%(py2)s
{%(py2)s = %(py0)s.tier
} == %(py6)s
{%(py6)s = %(py4)s.tier
}rG   rH   rP   py6assert %(py8)spy8zH%(py2)s
{%(py2)s = %(py0)s.model
} == %(py6)s
{%(py6)s = %(py4)s.model
})rQ   	is_cachedrS   rT   rU   rV   rW   rX   _format_assertmsgrY   rZ   rR   r[   )r;   r\   r]   r{   r   r   r^   r_   r`   ra   rb   @py_assert5@py_format7@py_format9s                 r   9test_bb5_same_type_twice_with_redis_second_call_is_cachedr   ~   sJ   $LFAq$AGLL!E\\'"F??DeD?e#DDD?eDDDDDD5DDD5DDD?DDDeDDD%DDDDDDDDLtLt#LLLtLLLLLL6LLL6LLLLLLtLLL%LLLLLLLL;;$%**$;*$$$$;*$$$$$$6$$$6$$$;$$$$$$%$$$%$$$*$$$$$$$<<&5;;&<;&&&&<;&&&&&&6&&&6&&&<&&&&&&5&&&5&&&;&&&&&&&r)   c           	        | \  }}}d}t        j                  |j                               j                         dd }d| }|j	                  |ddd       |j
                  }||v }|st        j                  d|fd	||f      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        j                  d| dt        |j
                  j                                      dz   d|	iz  }
t        t        j                   |
            dx}}y)zKWB1: Cache key is genesis:routing:<md5_12> of task_type (not full payload).rf   N   zgenesis:routing:zt-wb1ignored)r?   r@   	extra_keyrv   )z-%(py0)s in %(py4)s
{%(py4)s = %(py2)s.store
}expected_key
fake_redisrG   rH   rP   zExpected cache key 'z(' not found in Redis store. Found keys: z
>assert %(py6)sr   )hashlibmd5encode	hexdigestrQ   r(   rS   rT   rU   rV   rW   rX   r   listkeysrY   rZ   )r;   r\   r]   r   	task_typeexpected_hashr   r`   r^   rc   r   s              r   )test_wb1_cache_key_uses_hash_of_task_typer      s\   -FAzIKK	 0 0 23==?DM%m_5L
LL)iPQ &++ <++   <+                &    &    ,    |n -J,,11345	7    r)   c           	        | \  }}dddddddddg}|D ]  }|j                  |        |j                  } |       }|st        j                  d      d	z   d
t	        j
                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}|j                         j                         j                  d      }t        |      }	t        |      }
|	|
k(  }|st        j                  d|fd|	|
f      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t        j                  |	      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t        j                  |
      dz  }t        j                  dt        |       dt        |             dz   d|iz  }t        t        j                  |            dx}	x}}
t        ||      D ]  \  }}t!        j"                  |      }|d   }d}||k(  }	|	slt        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}	}|d   }|d   }||k(  }	|	slt        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}	}|d   }|d    }||k(  }	|	slt        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}	}|d!   }h d"}||v }	|	slt        j                  d#|	fd$||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}	}|d%   }h d&}||v }	|	slt        j                  d#|	fd$||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}	}d'}||v }	|	st        j                  d#|	fd(||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndd)z  }d*d+|iz  }t        t        j                  |            dx}}	d,}||v }	|	st        j                  d#|	fd(||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndd)z  }d*d+|iz  }t        t        j                  |            dx}}	 y)-zFWB2: events.jsonl gets one entry per route() call with correct fields.rr   zevt-001r>   rf   zevt-002novel_task_typezevt-003zevents.jsonl was not createdzC
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}r   r   N
rB   )zN%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py8)s
{%(py8)s = %(py5)s(%(py6)s)
}lenlinespayloads)rG   rO   py3rI   r   r   z	Expected z log entries, got z
>assert %(py10)spy10eventrouting_decision)z%(py1)s == %(py4)s)rO   rP   zassert %(py6)sr   r@   r   r?   rR   ru   rv   )z%(py1)s in %(py4)sr[   rx   	timestamp)z%(py1)s in %(py3)s)rO   r   assert %(py5)srI   r   )rQ   existsrS   r   rU   rV   rW   rX   rY   rZ   	read_textstripsplitr   rT   zipjsonloads)r   r\   r   r   pr^   r`   rc   r   @py_assert2@py_assert7r_   r   @py_format11liner{   r   @py_assert0r   @py_format4ra   s                        r   1test_wb2_events_jsonl_written_on_every_route_callr      s   &FH  I695"y9H  Q ??<?<<<<<<<<<<8<<<8<<<?<<<<<<<<< &&(..t4Eu: X :&   :                                        &    &    '    CM?"4SZLA     UH- $g

4 W~3!33~!33333~!3333~333!33333333Y579#55#55555#5555555#55555555[!4WV_4!_4444!_444!444_4444444V}2 22} 22222} 2222}222 22222222W~W!WW~!WWWWW~!WWWW~WWW!WWWWWWWW#{e####{e###{######e###e########{e####{e###{######e###e#######$r)   c                   | dz  }|j                  dt        |             ddl}ddlmc m}  |j                  |       ddlm}m} t               }d|j                  _         ||      }|j                  ddd	       |j                  j                          |j                  j                  d   }	|	d
   }
|
|k(  }|st!        j"                  d|fd|
|f      dt%        j&                         v st!        j(                  |
      rt!        j*                  |
      nddt%        j&                         v st!        j(                  |      rt!        j*                  |      nddz  }t!        j,                  d| d|
       dz   d|iz  }t/        t!        j0                  |            d}d}||k(  }|st!        j"                  d|fd||f      dt%        j&                         v st!        j(                  |      rt!        j*                  |      ndt!        j*                  |      dz  }t!        j,                  d      dz   d|iz  }t/        t!        j0                  |            dx}} |j                  |       y)zBWB3: Redis.setex is called with CACHE_TTL=300 as the TTL argument.r   r   r   Nr   r   rf   zt-ttlr>      rB   )z%(py0)s == %(py2)sttl_arg_TTLry   zExpected TTL=z, got z
>assert %(py4)srP   ,  z%(py0)s == %(py3)srG   r   zCACHE_TTL constant must be 300z
>assert %(py5)srI   )r   r   r   r   r   r   r   r   r	   r   r%   return_valuerQ   r.   assert_called_once	call_argsrS   rT   rU   rV   rW   rX   r   rY   rZ   )r   r   r   r   r   r   r   r9   r\   argsr   r^   r|   rc   r   r   ra   s                    r   "test_wb3_cache_ttl_used_with_setexr      s   .(H(#h-8**ISMJ"&JNNj)F
LL-G<= '')%%a(D1gGd?AAA7dAAAAAA7AAA7AAAAAAdAAAdAAAAmD6yAAAAAAA843;888438888884888488838888888888ISr)   c                   | dz  }|j                  dt        |             ddl}ddlmc m}  |j                  |       ddlm} t               }t        d      |j                  _         ||      }|j                  dd	d
      }|j                  }	d}
|	|
k(  }|st        j                  d|fd|	|
f      dt!        j"                         v st        j$                  |      rt        j&                  |      ndt        j&                  |	      t        j&                  |
      dz  }dd|iz  }t)        t        j*                  |            dx}	x}}
|j,                  }	d}
|	|
k(  }|st        j                  d|fd|	|
f      dt!        j"                         v st        j$                  |      rt        j&                  |      ndt        j&                  |	      t        j&                  |
      dz  }dd|iz  }t)        t        j*                  |            dx}	x}}
|j.                  }	d}
|	|
u }|st        j                  d|fd|	|
f      dt!        j"                         v st        j$                  |      rt        j&                  |      ndt        j&                  |	      t        j&                  |
      dz  }dd|iz  }t)        t        j*                  |            dx}	x}}
 |j                  |       y)uQ   WB4: Redis.get raising an exception → TierRouter still classifies successfully.r   r   r   Nr   zRedis is downr   rr   zt-redis-failr>   rA   rB   rD   rE   rF   rJ   rK   rL   rM   Fr   r   )r   r   r   r   r   r   r   r   r   ConnectionErrorr%   side_effectrQ   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r   )r   r   r   r   r   r   exploding_redisr\   rE   r^   r_   r`   ra   rb   s                 r   5test_wb4_redis_read_failure_falls_through_to_classifyr      s   .(H(#h-8**IS:kO&5o&FO#o.F||^OPH == D =D    =D      8   8   =   D       >>...>.....>.......8...8...>...........&&&&&&&&&&&&8&&&8&&&&&&&&&&&&&ISr)   c                ^   | \  }}}ddd}|j                  |      }|j                  |      }|j                  }|j                  }||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }	d	d
|	iz  }
t        t        j                  |
            dx}x}}|j                  }|j                  }||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }	d	d
|	iz  }
t        t        j                  |
            dx}x}}|j                  }|j                  }||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }	d	d
|	iz  }
t        t        j                  |
            dx}x}}|j                  }d}||u }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)zOWB5: Cached RoutingDecision has same tier and model as original classification.rs   zcache-integrityr>   rB   r   r   r   r   r   r   Nr   )zP%(py2)s
{%(py2)s = %(py0)s.rationale
} == %(py6)s
{%(py6)s = %(py4)s.rationale
}Tr   r   rF   rJ   rK   )rQ   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   rz   r   )r;   r\   r]   r{   r   r   r^   r   r`   r   r   r_   ra   rb   s                 r   /test_wb5_cached_result_preserves_tier_and_modelr      s[   $LFAq#0ABGLL!E\\'"F;;$%**$;*$$$$;*$$$$$$6$$$6$$$;$$$$$$%$$$%$$$*$$$$$$$<<&5;;&<;&&&&<;&&&&&&6&&&6&&&<&&&&&&5&&&5&&&;&&&&&&&.u...........6...6.........u...u..........#t#t####t######6###6######t#######r)   c                   | \  }}ddi}t        d      D ]  }|j                  |      }|j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d	      d
z   d|iz  }	t        t        j                  |	            dx}x}} y)zDWB6: Without Redis, is_cached is never True even for repeated calls.r?   rf      Fr   r   rE   rF   z4is_cached must be False when Redis is not configuredr   rK   N)rangerQ   r   rS   rT   rU   rV   rW   rX   r   rY   rZ   )
r   r\   r]   r{   rE   r^   r_   r`   ra   rb   s
             r   +test_wb6_no_redis_is_cached_is_always_falser      s    IFA}%G1X c<<(!!bUb!U*bbb!Ubbbbbbxbbbxbbb!bbbUbbb,bbbbbbbbcr)   c                    ddl m}  | t        u }|st        j                  d|fd| t        f      dt	        j
                         v st        j                  |       rt        j                  |       nddt	        j
                         v st        j                  t              rt        j                  t              nddz  }dd	|iz  }t        t        j                  |            d
}y
)z2TierRouter is exported from core.routing.__init__.r   r   r   )z%(py0)s is %(py2)sTRr   ry   zassert %(py4)srP   N)
core.routingr   rS   rT   rU   rV   rW   rX   rY   rZ   )r   r^   r|   rc   s       r   (test_tier_router_importable_from_packager     sm    -222r)   c                 p   d} t         | k(  }|st        j                  d|fdt         | f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       dz  }dd|iz  }t        t        j                  |            dx}} y)	z"CACHE_TTL constant must equal 300.r   rB   r   r	   r   r   rI   N)	r	   rS   rT   rU   rV   rW   rX   rY   rZ   )r   r^   r   ra   s       r   test_cache_ttl_constant_valuer     s[    9999r)   __main__r   r?   r=   rA   rL   rf   rg   rh   	novel_xyzrn   ro   xt)r?   templater   )r?   crud_operationPASSFAILz  [z] u
    → tier=z, model=r   /z smoke tests passed)B__doc__
__future__r   builtinsrU   _pytest.assertion.rewrite	assertionrewriterS   r   r   ossystempfilepathlibr   unittest.mockr   r   pathinsertpytestr   r   r	   core.routing.tier_classifierr
   fixturer   r9   r;   rd   rk   rp   r}   r   r   r   r   r   r   r   r   r   r4   r   r   r   _modr   r   r\   casespassedr{   exp_tier	exp_modelrQ   drR   r[   okstatusprintr   exitr+   r)   r   <module>r      s0   #     	 
   ) * +  : 8    * 	 	1,/"'""$<40$c z8++IT: UF
,	T3DE
-	 T>B
+	T3DE3	'T>B	+T3DEE F(- T$9LL!VVx8AGGy$86aKFF82gfo.j	RST 
BvhaE
|#6
78CHH&CJ&QA.7 r)   