
    ֞im-                        d 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ZdZe	j                  j                  ed      Ze	j                  j                  edd      Ze	j                  j                  edd      Ze	j                  j                  edd      Ze	j                  j                  ed	d
d      Ze	j                  j                  ed	d
d      Z G d d      Z G d d      Z G d d      Z G d d      ZddZddZddZy)ur  
Structural tests for the Alembic migration setup (Module 4).

All tests are offline — no database connection is opened.
Tests verify file existence, file validity, and ORM model correctness.

VERIFICATION_STAMP
Story: M4.07 — tests/infra/test_alembic.py — Alembic structural tests
Verified By: parallel-builder
Verified At: 2026-02-25
Tests: 13/13
Coverage: 100%
    Nz/mnt/e/genesis-systemzalembic.inialembiczenv.pyzscript.py.makoversionscoremodelsz	schema.pyz__init__.pyc                   0    e Zd ZdZddZddZddZddZy)TestAlembicIniz Black-box tests for alembic.ini.Nc                    t         j                  }|j                  } |t              }|st	        j
                  dt               dz   dt        j                         v st	        j                  t               rt	        j                  t               ndt	        j                  |      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}x}}y)z3BB-01a: alembic.ini must exist at the project root.	Missing: d
>assert %(py7)s
{%(py7)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.path
}.isfile
}(%(py5)s)
}osALEMBIC_INIpy0py2py4py5py7N)r   pathisfiler   
@pytest_ar_format_assertmsg@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationself@py_assert1@py_assert3@py_assert6@py_format8s        1/mnt/e/genesis-system/tests/infra/test_alembic.pytest_ini_file_existsz#TestAlembicIni.test_ini_file_exists*       wwEw~~E~k*E*EEi},EEEEEEErEEErEEEwEEE~EEEEEEkEEEkEEE*EEEEEE    c                 P   t        j                         }|j                  t              }|s{t	        j
                  d      dz   ddt        j                         v st	        j                  |      rt	        j                  |      ndiz  }t        t	        j                  |            y)z6BB-01b: alembic.ini must be parseable by ConfigParser.z'ConfigParser could not read alembic.iniz
>assert %(py0)sr   
files_readN)configparserConfigParserreadr   r   r   r   r   r   r   r   r   )r   cpr)   @py_format1s       r$   test_ini_is_valid_configparserz-TestAlembicIni.test_ini_is_valid_configparser.   sZ    &&(WW[)
DDDDDDDDDzDDDzDDDDDzr'   c           	      6   t        j                         }|j                  t               |j                  }d} ||      }|st        j                  d      dz   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }t        t        j                  |            dx}x}}|j                  }d}d} |||      }|st        j                  d      d	z   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      d
z  }t        t        j                  |            dx}x}x}}|j                  }d}d} |||      }d}||k(  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }
t        j                  d      dz   d|
iz  }t        t        j                  |            dx}x}x}x}x}	}y)zHBB-01c: alembic.ini must contain [alembic] section with script_location.r   z*[alembic] section missing from alembic.inizO
>assert %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.has_section
}(%(py4)s)
}r-   )r   r   r   py6Nscript_locationz.script_location missing from [alembic] sectionzW
>assert %(py8)s
{%(py8)s = %(py2)s
{%(py2)s = %(py0)s.has_option
}(%(py4)s, %(py6)s)
})r   r   r   r1   py8)==)zS%(py8)s
{%(py8)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s, %(py6)s)
} == %(py11)s)r   r   r   r1   r3   py11z#script_location should be 'alembic'z
>assert %(py13)spy13)r*   r+   r,   r   has_sectionr   r   r   r   r   r   r   r   
has_optionget_call_reprcompare)r   r-   r    r!   @py_assert5@py_format7@py_assert7@py_format9@py_assert10@py_assert9@py_format12@py_format14s               r$   test_ini_has_alembic_sectionz+TestAlembicIni.test_ini_has_alembic_section4   s   &&(
~~ViV~i(V(VV*VVVVVVVrVVVrVVV~VVViVVV(VVVVVV}} 	
Y 	
(9 	
}Y(9: 	
: 	
  =	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
 		 ' 	
 	
 		 ): 	
 	
 		 ; 	
 	
 	
 	
 	
 	
 vv 	
i 	
!2 	
vi!23 	
y 	
3y@ 	
 	
3y 	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
 		   	
 	
 		 "3 	
 	
 		 4 	
 	
 		 8A 	
 	
  2	
 	
 	
 	
 	
 	
r'   c                 l   t        j                         }|j                  t               dD ]  }|j                  } ||      }|st        j                  d| d      dz   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  }t        t        j                  |            dx}} y)	z?BB-01d: alembic.ini must contain all required logging sections.)loggershandlers
formattershandler_consolezMissing section [z] in alembic.inizO
>assert %(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s.has_section
}(%(py3)s)
}r-   section)r   r   py3r   N)r*   r+   r,   r   r7   r   r   r   r   r   r   r   r   )r   r-   rI   r    @py_assert4@py_format6s         r$   &test_ini_has_required_logging_sectionsz5TestAlembicIni.test_ini_has_required_logging_sections@   s    &&(
O 	ZG>>Y>'*Y*YY.?yHX,YYYYYYY2YYY2YYY>YYYYYY'YYY'YYY*YYYYYY	Zr'   returnN)__name__
__module____qualname____doc__r%   r/   rC   rM    r'   r$   r   r   '   s    *FE

Zr'   r   c                   0    e Zd ZdZddZddZddZddZy)TestAlembicEnvPyz#Black-box tests for alembic/env.py.Nc                    t         j                  }|j                  } |t              }|st	        j
                  dt               dz   dt        j                         v st	        j                  t               rt	        j                  t               ndt	        j                  |      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}x}}y)z"BB-02a: alembic/env.py must exist.r
   r   r   ALEMBIC_ENVr   N)r   r   r   rX   r   r   r   r   r   r   r   r   r   s        r$   test_env_py_existsz#TestAlembicEnvPy.test_env_py_existsO   r&   r'   c                     t        t        d      5 }|j                         }ddd       	 t        t        d       y# 1 sw Y   xY w# t        $ r"}t        j                  d|        Y d}~yd}~ww xY w)z:BB-02b: alembic/env.py must compile without syntax errors.rNexecz!alembic/env.py has syntax error: )openrX   r,   compileSyntaxErrorpytestfail)r   fhsourceexcs       r$   test_env_py_compilesz%TestAlembicEnvPy.test_env_py_compilesS   sj    +s# 	rWWYF		CFK0		 	
  	CKK;C5ABB	Cs    =A	 A		A4A//A4c                    t        t        d      5 }|j                         }ddd       d}|v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y# 1 sw Y   xY w)z>BB-02c: env.py must reference the Elestio PostgreSQL hostname.r[   Nz(postgresql-genesis-u50607.vm.elestio.appinz%(py1)s in %(py3)scontentpy1rJ   z1env.py must reference the Elestio PostgreSQL host
>assert %(py5)sr   r]   rX   r,   r   r:   r   r   r   r   r   r   r   r   rb   rj   @py_assert0@py_assert2@py_format4rL   s          r$   #test_env_py_references_elestio_hostz4TestAlembicEnvPy.test_env_py_references_elestio_host]   s    +s# 	 rggiG	 9 	
9WD 	
 	
9W 	
 	
 		 : 	
 	
	6	
 	
  >E 	
 	
 		 >E 	
 	
  @	
 	
 	
 	
 	
	  	    C&&C/c                    t        t        d      5 }|j                         }ddd       d}|v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y# 1 sw Y   xY w)z@BB-02d: env.py must read credentials from environment variables.r[   Nzos.environ.getrg   ri   rj   rk   uB   env.py must use os.environ.get for credentials — never hard-coderm   r   rn   ro   s          r$   test_env_py_uses_env_varsz*TestAlembicEnvPy.test_env_py_uses_env_varse   s    +s# 	 rggiG	  	
7* 	
 	
7 	
 	
 		   	
 	
	6	
 	
  $+ 	
 	
 		 $+ 	
 	
  Q	
 	
 	
 	
 	
	  	 rt   rN   )rP   rQ   rR   rS   rY   re   rs   rv   rT   r'   r$   rV   rV   L   s    -FC

r'   rV   c                      e Zd ZdZ ej
                  d      dej                  fd       ZddZ	dej                  ddfd	Z
dej                  ddfd
Zdej                  ddfdZdej                  ddfdZdej                  ddfdZy)TestSchemaModelsz*Black-box tests for ORM model definitions.class)scoperO   c                 H   t         t        j                  vr$t        j                  j                  dt                t	        t        j
                  j                               D ]*  }|j                  d      s|dk(  st        j
                  |= , t        j                  d      S )z<Import core.models.schema without triggering DB connections.r   zcore.modelszcore.models.schema)
GENESIS_ROOTsysr   insertlistmoduleskeys
startswith	importlibimport_module)r   keys     r$   schema_modulezTestSchemaModels.schema_moduleu   sv     sxx'HHOOA|,((*+ 	%C~~m,}0DKK$	% &&';<<r'   Nc                    t         j                  }|j                  } |t              }|st	        j
                  dt               dz   dt        j                         v st	        j                  t               rt	        j                  t               ndt	        j                  |      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}x}}y)z)BB-03a: core/models/schema.py must exist.r
   r   r   	SCHEMA_PYr   N)r   r   r   r   r   r   r   r   r   r   r   r   r   s        r$   test_schema_file_existsz(TestSchemaModels.test_schema_file_exists   s    wwAw~~A~i(A(AAIi[*AAAAAAArAAArAAAwAAA~AAAAAAiAAAiAAA(AAAAAAr'   r   c                    ddl m} d}t        ||      }|st        j                  d      dz   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                  |      t        j                  |      dz  }t        t        j                  |            d	x}}|j                  }t        ||      }|s-t        j                  d
      dz   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                  |      rt        j                  |      ndt        j                  |      dz  }t        t        j                  |            d	x}}y	)zDBB-03b: schema.py must export a SQLAlchemy DeclarativeBase subclass.r   )DeclarativeBaseBasezschema.py must define Basez7
>assert %(py5)s
{%(py5)s = %(py0)s(%(py1)s, %(py3)s)
}hasattrr   )r   rl   rJ   r   Nz2Base must be a SQLAlchemy DeclarativeBase subclasszQ
>assert %(py6)s
{%(py6)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.Base
}, %(py4)s)
}
issubclassr   )r   rl   rJ   r   r1   )sqlalchemy.ormr   r   r   r   r   r   r   r   r   r   r   r   )r   r   r   rq   rK   rL   r;   r<   s           r$   test_base_is_definedz%TestSchemaModels.test_base_is_defined   s   2&,Kw}f-K-KK/KKKKKKKwKKKwKKKKKK}KKK}KKKfKKK-KKKKKK',, 	
z,o> 	
> 	
  A	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
  ( 	
 	
 		 ( 	
 	
 		 - 	
 	
	6	
 	
  /> 	
 	
 		 /> 	
 	
 		 ? 	
 	
 	
 	
 	
r'   c                    t        |j                  j                  j                  j	                               }t        |      }d}||k\  }|st        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                  |      t        j                  |      dz  }t        j                  dt        |       d|       d	z   d
|iz  }t        t        j                  |            dx}x}}y)zABB-03c: Base.metadata must contain at least 3 mapped table names.   )>=)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} >= %(py6)slentables)r   rl   rJ   r1   z"Expected at least 3 tables, found z: z
>assert %(py8)sr3   N)r   r   metadatar   r   r   r   r:   r   r   r   r   r   r   r   )r   r   r   rq   r;   rK   r<   r>   s           r$   test_minimum_three_modelsz*TestSchemaModels.test_minimum_three_models   s2   m((1188==?@6{ 	
a 	
{a 	
 	
 	
{a 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
 		   	
 	
  1VRxH	
 	
 	
 	
 	
 	
r'   c                    t        |j                  j                  j                  j	                               }h d}||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)z<BB-03d: Required tables must be registered in Base.metadata.>   	epoch_logknowledge_entitiesroyal_conversationszMissing tables in metadata: 
>assert not %(py0)sr   missingN)setr   r   r   r   r   r   r   r   r   r   r   r   )r   r   r   requiredr   r    @py_format2s          r$   !test_expected_table_names_presentz2TestSchemaModels.test_expected_table_names_present   s     ]''0077<<>?MV#{D{DD:7)DDDDDDD7DDD7DDDDDDr'   c                    |j                   j                  j                  d   }|j                  D ch c]  }|j                   }}h d}||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c c}w )z<BB-03e: RoyalConversation must have all 13 required columns.r   >   outcomeended_at	key_facts
started_ataction_itemsparticipantscaller_numberdecisions_madetranscript_rawconversation_idkinan_directivesenriched_entitiesz#RoyalConversation missing columns: r   r   r   N)r   r   r   columnsnamer   r   r   r   r   r   r   r   )	r   r   tableccolumn_namesrequired_columnsr   r    r   s	            r$   (test_royal_conversation_required_columnsz9TestSchemaModels.test_royal_conversation_required_columns   s     ""++223HI(-6166
 #\1{ 	
{ 	
  2';	
 	
	6	
 	
   	
 	
 		  	
 	
 	
 	
 	
! 7s   Cc                    |j                   j                  j                  d   }|j                  D ch c]  }|j                   }}d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d      dz   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  }t        j                  d      dz   d	|iz  }t        t        j                  |            d
x}}y
c c}w )zFBB-03f: EpochLog must have 'status' column (epoch lifecycle tracking).r   statusrg   ri   r   rk   z"EpochLog must have 'status' columnrm   r   Nepoch_idz$EpochLog must have 'epoch_id' column)r   r   r   r   r   r   r:   r   r   r   r   r   r   r   )	r   r   r   r   r   rp   rq   rr   rL   s	            r$    test_epoch_log_has_status_columnz1TestSchemaModels.test_epoch_log_has_status_column   s
    ""++22;?(-6166Mx<'MMMx<MMMxMMMMMM<MMM<MMMM)MMMMMMMQz\)QQQz\QQQzQQQQQQ\QQQ\QQQQ+QQQQQQQ 7s   F>rN   )rP   rQ   rR   rS   r`   fixturetypes
ModuleTyper   r   r   r   r   r   r   rT   r'   r$   rx   rx   r   s    4V^^'"=u// = #=B
%2B2B 
t 

u7G7G 
D 
E"--E	E
"--
	
2R"--R	Rr'   rx   c                   4    e Zd ZdZeeeegZddZ	ddZ
ddZy)TestNoSqliteRule7z
    Rule 7 compliance: SQLite is FORBIDDEN in Genesis.

    Scans all newly created Alembic and models files for SQLite usage.
    Nc                 H   | j                   D ]  }t        j                  j                  |      s$t	        |d      5 }|j                         }ddd       d}|v}|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d|       d	z   d
|iz  }t        t        j                  |            dx}}	 y# 1 sw Y   xY w)zDWB-01a: 'import sqlite3' must not appear in any Alembic/models file.r[   Nzimport sqlite3not inz%(py1)s not in %(py3)srj   rk   z,Rule 7 VIOLATION: 'import sqlite3' found in rm   r   SCANNED_FILESr   r   r   r]   r,   r   r:   r   r   r   r   r   r   r   r   r   rb   rj   rp   rq   rr   rL   s           r$   !test_no_sqlite_import_in_any_filez3TestNoSqliteRule7.test_no_sqlite_import_in_any_file   s    && 	D77>>$'dC $B'')$# #72  #7  I $  v   ,3  I ,3    ?tfE    	$ $   DD!	c                 H   | j                   D ]  }t        j                  j                  |      s$t	        |d      5 }|j                         }ddd       d}|v}|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d|       d	z   d
|iz  }t        t        j                  |            dx}}	 y# 1 sw Y   xY w)zEWB-01b: 'sqlite3.connect' must not appear in any Alembic/models file.r[   Nzsqlite3.connectr   r   rj   rk   z-Rule 7 VIOLATION: 'sqlite3.connect' found in rm   r   r   r   s           r$   #test_no_sqlite3_connect_in_any_filez5TestNoSqliteRule7.test_no_sqlite3_connect_in_any_file   s    && 	D77>>$'dC $B'')$$ $G3  $G  I %  v   -4  I -4    @vF    	$ $r   c                 r   | j                   D ]  }t        j                  j                  |      s$t	        |d      5 }|j                         }ddd       g }d}|v}|}|rd}||v}	|	}|sqt        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  }|j                  |       |rt        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  }|j                  |       t        j                  |d      i z  }t        j                  d|       dz   d|iz  }t        t        j                   |            dx}x}x}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  }t        j                  d|       dz   d|iz  }
t        t        j                   |
            dx}} y# 1 sw Y   `xY w)zFWB-01c: '.db' file references must not appear in Alembic/models files.r[   Nz.db'z.db"r   )z%(py3)s not in %(py5)srj   )rJ   r   z%(py7)sr   )z%(py10)s not in %(py12)s)py10py12z%(py14)spy14r   z0Rule 7 VIOLATION: '.db' file reference found in z
>assert %(py17)spy17z:memory:r   rk   z-Rule 7 VIOLATION: SQLite ':memory:' found in rm   r   )r   r   r   r   r]   r,   r   r:   r   r   r   r   append_format_boolopr   r   r   )r   r   rb   rj   r    rq   rK   rp   r@   @py_assert11rL   r#   @py_format13@py_format15@py_format16@py_format18rr   s                    r$   #test_no_dot_db_extension_referencesz5TestNoSqliteRule7.test_no_dot_db_extension_references   s_    && 	D77>>$'dC $B'')$6 6( V V7-B   6  I   v   ")  I ")   v V7  I .4  v   <C  I <C   v    C4&I       :W,  :W  I   v   &-  I &-    @vF    	$ $s   J,,J6	rN   )rP   rQ   rR   rS   r   rX   r   MODELS_INITr   r   r   r   rT   r'   r$   r   r      s+     		M		r'   r   c                     t         j                  } | j                  } |t              }|st	        j
                  dt               dz   dt        j                         v st	        j                  t               rt	        j                  t               ndt	        j                  |       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} x}}y)zHBB-05: alembic/versions/ directory must exist (holds migration scripts).z%alembic/versions/ directory missing: zc
>assert %(py7)s
{%(py7)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.path
}.isdir
}(%(py5)s)
}r   ALEMBIC_VERSIONS_DIRr   N)r   r   isdirr   r   r   r   r   r   r   r   r   r    r!   r"   r#   s       r$   test_versions_directory_existsr      s   77 7== =-. .   00D/EF                       .    .    /      r'   c                     t         j                  } | j                  } |t              }|st	        j
                  dt               dz   dt        j                         v st	        j                  t               rt	        j                  t               ndt	        j                  |       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} x}}y)z*BB-06a: alembic/script.py.mako must exist.r
   r   r   ALEMBIC_MAKOr   N)r   r   r   r   r   r   r   r   r   r   r   r   r   s       r$   test_mako_template_existsr     s    77C7>>C>,'C'CC9\N)CCCCCCC2CCC2CCC7CCC>CCCCCC,CCC,CCC'CCCCCCr'   c                     t        t        d      5 } | j                         }ddd       d}|v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   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  }t        j                  d      d	z   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  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y# 1 sw Y   <xY w)zFBB-06b: mako template must define upgrade() and downgrade() functions.r[   Nzdef upgrade()rg   ri   rj   rk   z(mako template missing upgrade() functionrm   r   zdef downgrade()z*mako template missing downgrade() functionz	revision:z/mako template missing revision identifier block)r]   r   r,   r   r:   r   r   r   r   r   r   r   )rb   rj   rp   rq   rr   rL   s         r$   (test_mako_template_has_upgrade_downgrader     s`   	lC	  B'')Q?g%QQQ?gQQQ?QQQQQQgQQQgQQQQ'QQQQQQQU'UUUUUUUUUUUUUUUUUUU)UUUUUUUT;'!TTT;'TTT;TTTTTT'TTT'TTTT#TTTTTTT	 s   II&rN   )rS   builtinsr   _pytest.assertion.rewrite	assertionrewriter   r*   r   r   r}   r   r`   r|   r   joinr   rX   r   r   r   r   r   rV   rx   r   r   r   r   rT   r'   r$   <module>r      s        	 
   'ggll<7ggll<H=ww||L)5EFww||L)ZH GGLLvxE	ggll<=IZ ZJ
 
LKR KRd2 2rD
Ur'   