
    Ⱥik                         d Z ddlZddlZddlZddlZddlZddlZddlZddlm	Z	 ddl
mZ h dZdZdZd Zd	 Zd
 Zd Zg dZddddddZd Zd Zd Zedk    r e             dS dS )u  
Boletín Oficial → CSV para importar en WordPress
Extrae avisos de un archivo .doc o .docx y genera un CSV listo para importar
con el plugin "Really Simple CSV Importer".

Uso:
    python boletin_to_csv.py BO29.doc
    python boletin_to_csv.py BO29.docx
    N)Path)Counter>	   LeyesDecretos
OrdenanzasResoluciones   Partidos PolíticosAcordada MunicipalAcuerdo LegislativoDecretos MunicipalesResoluciones MunicipaleszNhttps://boletinoficial.jujuy.gob.ar/wp-content/uploads/2016/10/PDFDownload.pngz`https://boletinoficial.jujuy.gob.ar/wp-content/uploads/2016/Boletines/{anio}/{numero}-{anio}.pdfc                 V    t                               ||           }d| dt           dS )u3   Genera el HTML del ícono PDF con link al boletín.anionumeroz<h4><strong><u><a href="z,"><img class="alignleft wp-image-2796" src="z8" alt="" width="80" height="74" /></a></u></strong></h4>)PDF_BASE_URLformatPDF_IMG_URL)r   r   urls      /E:\GuilleBO\Escritorio\py int\boletin_to_csv.pyarmar_bloque_pdfr   (   sC    


4

7
7C		 	5@	 	 	    c                      ddg} | D ]%}t           j                            |          r|c S &t          j        d          S )Nz0C:\Program Files\LibreOffice\program\soffice.exez6C:\Program Files (x86)\LibreOffice\program\soffice.exesoffice)ospathexistsshutilwhich)rutas_windowsrutas     r   encontrar_libreofficer"   4   sT    ;AM   7>>$ 	KKK	<	"""r   c           	         t                      }|sAt          d           t          d           t          d           t          j        d           t	          j                    }	 t          j        |dddd|| gd	d	
          }|j        dk    r+t          d|j	                    t          j        d           t          |           j        dz   }t          j                            t	          j                    |          }t!          j        t          j                            ||          |           |t!          j        |d	           S # t!          j        |d	           w xY w)Nz!ERROR: LibreOffice no encontrado.uG   Instalalo desde https://www.libreoffice.org y reiniciá la computadora.u6   O convertí el archivo a .docx desde Word manualmente.   z
--headlessz--convert-todocxz--outdirT)capture_outputtextr   zERROR al convertir: .docx)ignore_errors)r"   printsysexittempfilemkdtemp
subprocessrun
returncodestderrr   stemr   r   join
gettempdirr   copyrmtree)doc_pathr   tmpdirresultout_namefinals         r   convertir_doc_a_docxr=   ?   sO   #%%G 1222WXXXFGGGF2lNFJPXYd
 
 
 !!888999HQKKK>>&0X022H==BGLL22E:::fD11111fD11111s   &CE E%c                     |                                                                  }|dk    rdS |dk    rdS |dk    rdS dddd	d
dddddddddd}|                    |d          S )znDevuelve el marcador de categoria si el texto es un encabezado de seccion del boletin,
    o None si no lo es.zFE DE ERRATAS	_IGNORAR_zLEYES - DECRETOS - RESOLUCIONES_LEYES_DECRETOS_RESOLUCIONES_z#MUNICIPIOS - COMISIONES MUNICIPALES_MUNICIPIOS_r	   Licitaciones	ContratosRemateszConcursos y QuiebrasMinasu
   UsucapiónNotificacionesu	   Citación
Sucesorios)zPARTIDOS POLITICOSu   PARTIDOS POLÍTICOSz"LICITACIONES - CONCURSO DE PRECIOSz!CONTRATOS - CONVOCATORIAS - ACTASREMATESzCONCURSOS Y QUIEBRASzEDICTOS DE MINASzEDICTOS DE USUCAPIONu   EDICTOS DE USUCAPIÓNzEDICTOS DE NOTIFICACIONu   EDICTOS DE NOTIFICACIÓNzEDICTOS DE CITACIONu   EDICTOS DE CITACIÓNzEDICTOS SUCESORIOSN)stripupperget)r'   tMAPAs      r   es_encabezado_categoriarN   X   s     	

AO{---..111~ 0E0E/=/:/8/E/6/;0</?0@/:0;/; D  88Atr   )7z
ABRA PAMPA	ABRALAITEzAGUAS CALIENTES	ARRAYANALBARRACAS	BARRANCAS
CAIMANCITO	CALILEGUACANGREJILLOSCASPALACATUACIENEGUILLAS	COCHINOCA	CORANZULIz
EL AGUILARz	EL CARMENz	EL CONDORz	EL MORENOz
EL PIQUETEzEL TALARzFRAILE PINTADOzHIPOLITO YRIGOYEN	HUACALERA	HUMAHUACAzLA ESPERANZAzLA MENDIETAz	LA QUIACAzMINA PIRQUITAS
MONTERRICOz
PALMA SOLAPALPALAzPAMPA BLANCAPAMPICHUELAPERICOzPUESTO DEL MARQUEZzPUESTO VIEJO
PURMAMARCA	RINCONADARODEITOzROSARIO DE RIO GRANDEzSAN ANTONIOzSAN FRANCISCOz	SAN PEDROz	SANTA ANAzSANTA CLARASUSQUESTILCARAzTRES CRUCESTUMBAYAUQUIAVINALITOVOLCANYALAYAVIYUTOzS. S. DE JUJUYLGSMre   )zSAN SALVADOR DE JUJUYzLIBERTADOR GENERAL SAN MARTINzLIBERTADOR GRAL SAN MARTINzLIBERTADOR GRAL. SAN MARTINzSAN FRANCISCO DE TILCARAc                     d                     |                                           }t                                          D ]\  }}||v r|c S t	          t
          t          d          D ]
}||v r|c S dS )zRDetecta el municipio en el texto del aviso y devuelve la etiqueta correspondiente. T)keyreverse )r4   rJ   MUNICIPIO_ETIQUETA_ESPECIALitemssorted
MUNICIPIOSlen)linesbodynombreetiqueta	municipios        r   detectar_municipior}      s    88E??  ""D7==??  T>>OOO  JC>>>  	 2r   c           
        KLMNOPQ ddl m} ddlm} dd l}|                    |           5 }|                    d          }	d d d            n# 1 swxY w Y   |                    |	          }
d}d}|
                    d| d          }t          |          }i }t          |          D ]\  }}|                    d	| d
          }|D ]b}|                    d	| d          }d                    d |D                                                       }t          |          }|r|||<   c ||           Li }d}t          |          D ]5\  }}|j                            d          d         }|dk    r
|||<   |dz  }6i }|                                D ]\  }}||v r||||         <   i Kd}t%          t'          Lj                            D ]}||v r||         }|K|<   i N	 dd l}ddlm} |                    |           5 }d|                                v rv|                    d          } |                    |           }!i }"|!                    d| d          D ]}#|#                    d| d          }$i }%|#                    d| d          D ]R}&|&                    d| d          }'|&                    d| d          }(|(|(                    d| d          |%|'<   S|%|"|$<   |!                    d| d          D ]})|)                    d| d          }*|)                    d| d          }+|+R|+                    d| d          }$|"                    |$i           }%|%                    dd          }(|(dk    rdnd N|*<   d d d            n# 1 swxY w Y   n# t.          $ r Y nw xY wi },d}-t          |          D ]3\  }}|j                            d          d         d!k    r
|-|,|<   |-dz  }-4g }.d}/t          |          D ]m\  }}|j                            d          d         }|dk    r|.                    |d|/f           |/dz  }/I|d!k    r|.                    |d!|,|         f           ng }0t          Lj                  D ](\  }1}2d"|2j        j        v r|0                    |1           )Kfd#}3Nfd$Od% QOQfd&}4g }5d}6|0D ]}7t          t%          |6|7dz                       }8Lfd'|8d d         D             MLj        |7         j                                        PPrM                    P           MPfd(MD             }9|9r|5                    M|8f           |7dz   }6t          t%          |6t'          Lj                                      }:Lfd)|:D             };|;r|5                    |;|:f           d* }<d+ }=g }>|5D ]f\  M}8 |3|8          }?Md                                         }@|?d,k    r2|?d-k    ss|?dk    ry|@                    d.          sX|@                    d/          sC|@                    d0          s.|@                    d1          s|@                    d2          sd3|@v r |<M          }?n|?d4k    r |=M          }?|?d5k    r|@                    d6          rd7}?|?                    d8          d                                         t<          v r|nd9}A|?d:v rt?          M          }B|Br|Ar|A d;|B n|B}A|?d<v rMrdd l }C|C!                    d=Md                                         |Cj"                  }D|Dr|D#                    d>                                          }Ed? |E                    d@          D             }FdAMd                                         v }G|Gr|F}Hnt'          |F          dk    r|F}Hng }H|Hr1|Ar|A d;d;                    |H           nd;                    |H          }A |4|8L|.          }IdB|z   dCz   |Iz   dDz   }J|>                    ||JdEdF|?|AdG           h|>S )HNr   Documentetreeword/document.xml<http://schemas.openxmlformats.org/wordprocessingml/2006/mainAhttp://schemas.microsoft.com/office/word/2010/wordprocessingShape{}body.//{}txbx}tro   c              3   2   K   | ]}|j         	|j         V  d S Nr'   .0rL   s     r   	<genexpr>z!extraer_avisos.<locals>.<genexpr>   s+      ??!?qv??????r   }pr$   Sin clasificarzword/numbering.xmlz}abstractNumz}abstractNumIdz}lvlz}ilvlz}numFmtz}valz}numz}numId0bulletdecimalolultblpBdrc                 @    | d         }                     |d          S )uM   Devuelve la categoría del bloque usando el último párrafo como referencia.r   r   )rK   )para_indiceslast_picat_por_paras     r   
bloque_catz"extraer_avisos.<locals>.bloque_cat  s$    r")9:::r   c                    ddl }| j                                        sdS d}| j        D ]A}|j        }|s|j        r|j        rd| d}n|j        rd| d}n|j        rd	| d
}||z  }B|                                }|sdS d| j        j        v rW|                    d| j        j                  }|r|	                    d          nd}|r
                    |d          nd}||fS |dfS )uE   Convierte un párrafo a HTML, respetando negrita y subrayado por run.r   N)NNrr   z<strong><u>z</u></strong>z<strong>z	</strong>z<u>z</u>numPrz<w:numId w:val="(\d+)"r$   r   )rer'   rI   runsbold	underline_elementxmlsearchgrouprK   )	para_re	html_textr0   rL   num_id_matchnum_id	list_typenum_format_maps	           r   para_to_htmlz$extraer_avisos.<locals>.para_to_html  sI   y   	:	9 
	 
	CA x "CM "2!222 "+q+++ "!!MMMNIIOO%%	 	:dm'''::&?ARSSL.:D\''***F<BL**64888Ii''$r   c                 P   g }| j         D ]}g }|j        D ]H}|j                                                            dd          }|                    d| d           I|                    dd                    |          z   dz              dd                    |          z   d	z   S )
z Convierte una tabla docx a HTML.
ro   z<td>z</td>z<tr>rr   z</tr>z2<table border="1" cellpadding="4" cellspacing="0">z</table>)rowscellsr'   rI   replaceappendr4   )table	rows_htmlrowr   cell	cell_texts         r   tabla_to_htmlz%extraer_avisos.<locals>.tabla_to_html5  s    	: 	@ 	@CE	 6 6 IOO--55dC@@	4I4445555Vbggenn4w>????CbggiFXFXX[eeer   c                 0   | d         }| d         }g }d}|D ]N\  }}}	|dk    r|	|k     s|	|k    r|j         |	         }
 |
          \  }}|s8|rV||k    r6|r|                    d| d           |                    d| d           |}|                    d| d	           |r|                    d| d           d}|                    d
| d           |dk    rd}d}|D ]!\  }}}|dk    r||k     r|}||k    r||} n"|W||cxk    r|k    rJn |r|                    d| d           d}|                     |j        |	                              P|r|                    d| d           d                    |          S )u<   Construye el HTML de un bloque incluyendo viñetas y tablas.r   r   Nr   z</><z<li>z</li>z<p>z</p>r   r   )
paragraphsr   tablesr4   )r   docbody_sequencefirst_pir   
html_partscurrent_list_typebody_idxtiporefr   r'   r   	prev_para	next_paraseq_body_idxseq_tiposeq_refr   r   s                     r   build_block_htmlz(extraer_avisos.<locals>.build_block_html@  sq     ?r" 
 #0 #	F #	FHdCs{{>>S7]]~c*".,t"4"4i  8(I55, I&--.G3D.G.G.GHHH"))*:i*:*:*:;;;,5)%%&8T&8&8&89999( 1"))*C/@*C*C*CDDD,0)%%&6D&6&6&67777 	 	7D " "3L(G3'(22(/II)H449J(/I!E(X-M-M-M-Mg-M-M-M-M-M( 1"))*C/@*C*C*CDDD,0)%%mmCJsO&D&DEEE 	97#4777888yy$$$r   c                     g | ]J}j         |         j                                        &j         |         j                                        KS  r   r'   rI   r   jr   s     r   
<listcomp>z"extraer_avisos.<locals>.<listcomp>y  sK    hhhAXYIZI_IeIeIgIgh"'--//hhhr   c                 J    g | ]}|r|k    rt                    d k    | S )r$   )rw   )r   lrx   sep_texts     r   r   z"extraer_avisos.<locals>.<listcomp>  s>       qQ MMc%jjAoo -oor   c                     g | ]J}j         |         j                                        &j         |         j                                        KS r   r   r   s     r   r   z"extraer_avisos.<locals>.<listcomp>  sK    iiiQ#.YZJ[J`JfJfJhJhi#.#(..00iiir   c                    | d                                          }t          |           dk    r| d                                          nd}d|v r.|                    d          rdS |                    d          rdS |                    d          rdS |                    d          rdS |                    d	          rd
|v rdS |                    d	          rdS |                    d          s|                    d          rd
|v rdS |                    d          s|                    d          rdS d|v rdS d|v sd|v rdS dS )Nr      rr   zLEGISLATURA DE JUJUYLEYr   ACUERDOr   DECRETO	MUNICIPALr   r   
RESOLUCION   RESOLUCIÓNr   r   INSTITUTO DE VIVIENDAMUNICIPALIDAD	MUNICIPIO)rJ   rw   
startswith)rx   firstthirds      r   subclasificar_leyes_decretosz4extraer_avisos.<locals>.subclasificar_leyes_decretos  s   a  $'JJNNa   !U**&& w	** -,,E"" 	7I&& 	)((I&& 	*;%+?+?))I&& 	:\** 	.e.>.>}.M.M 	.S^bgSgSg--L)) 	"U-=-=m-L-L 	"!>"e++!>e##{e';';))~r   c                    | d                                          }t          |           dk    r| d                                          nd}d                    |                                            }d|v rdS |                    d          rdS |                    d	          rd
S |                    d          s|                    d          rdS |                    d          rdS |                    d	          rd
S |                    d          rdS |                    d          s|                    d          rdS d|v rd|v rdS d|v sd|v rd	|v rd
S d|v sd|v rdS dS )Nr   r$   rr   ro   zSANCIONA CON FUERZA DE ACUERDOr
   r   r   	ORDENANZAr   r   r   r   r   zEL INTENDENTEDECRETAzSANCIONA LA ORDENANZA
PROMULGASE)rJ   rw   r4   r   )rx   r   secondry   s       r   subclasificar_municipiosz0extraer_avisos.<locals>.subclasificar_municipios  s   a  %(ZZ!^^q!!!xx$$&&+t33''Y'' 	*))[)) 	 <\** 	.f.?.?.N.N 	.--Y'' 	(''K(( 	 <I&& 	*))L)) 	.U-=-=m-L-L 	.--d""yD'8'8))"d**ld.B.B{VZGZGZ<4=D#8#8--%%r   r?   r@   r   r   r   r   r   r   rA   rF   u   INSCRIPCIÓN DE MARTILLEROz,Notificaciones, Inscripciones de Martilleros,rr   )r
   r   r   r   z, )r   r   uG   (DECRETO|RESOLUCIÓN?|RESOLUCION)(\s+\w+)?\s+N[ºo°°]?\s*\d+-([^/]+)/   c                 ^    g | ]*}|                                 |                                 +S r   )rI   )r   os     r   r   z"extraer_avisos.<locals>.<listcomp>  s-    TTT!''))T!''))TTTr   -CONJUNTAz<!-- wp:html -->
r   z
<!-- /wp:html -->publishpost
post_titlepost_contentpost_status	post_typetax_categorytax_post_tag)$r%   r   lxmlr   zipfileZipFileread
fromstringfindlist	enumeratefindallr4   rI   rN   tagsplitrt   rangerw   r   namelistrK   	Exceptionr   r   r   r'   rJ   r   CATS_CON_ETIQUETAr}   r   match
IGNORECASEr   )R	docx_pathtitulo_boletinr   r   
bloque_pdfr   r   r  zxml_rawtreeWWPSry   body_childrencat_por_childidxchildtxboxestxbxtextscontentcatpara_index_mappara_idxr   r	  cat_cambioscurrent_catzf2et2z2num_xmlnum_treeabstract_numsanan_idlvlslvlilvl_valfmtnumr   r   tabla_por_body_idxtabla_counterr   para_countersep_indicesir   r   r   blocksprevsep_iindicescontent_lineslast_indices
last_linesr   r   avisoscategoryr   r{   etiqueta_municipior   morganismos_rawparteses_conjunta
organismos	html_bodyhtml_contentr   r   rx   r   r   r   r   sR                                                                              @@@@@@@r   extraer_avisosrI     sv   NNN 
	#	# .q&&,--. . . . . . . . . . . . . . . G$$D	GA
MC99^!^^^$$DJJM M.. ) )
U-- 3 3 3 344 	) 	)DLL00Ehh??u?????EEGGG)'22C )%(c"	) (9

C
 NH$]33  %iooc""2&#::'/N8$MH K&,,.. 8 8#~%%47Kx01 L"K#cn--.. - -{""%h/K!,X N%%%%%%[[## 	Tr#r{{}}44''"677>>'22 ""**+@+@+@+@AA 0 0BFF#:#:#:#:;;ED!zz-q---88 D D#&77>>>>#:#:!hh'7A'7'7'788?-0WW]!]]]-C-CDN+/M%((#++MMMM:: T TC WW_!___55F((#:#:#:#:;;C #Q 6 6,00;;"hhsH559<	9I9Itv.+	T 	T 	T 	T 	T 	T 	T 	T 	T 	T 	T 	T 	T 	T 	T,     M$]33  %9??3#u,,+8x(QM ML$]33 R R%iooc""2&#::  (C!>???ALLE\\  (E3Eh3O!PQQQ KS^,, " "4T]&&&q!!!; ; ; ; ;
    8	f 	f 	f2% 2% 2% 2% 2% 2%h FD  uT519--..hhhh"hhh>%(-3355 	#LL"""    E     	,MM5'*+++qydC$7$78899Liiii,iiiJ 2z<0111  6& & &@ F  B Bw:g&&a   {"" 666,,,$$U++ -/4/?/?	/J/J -$$Y// - $$\22 - 7<6F6F}6U6U - ,u4433E::HH''//66H '''E,<,<=Y,Z,Z'EH#>>#..q17799=NNN44TV ooo!3E!:!:! cBJbh>>*<>>>Pb
 3333		dfklmfnftftfvfvx{  yG  H  HA m!"!1!1!3!3TT^-A-A#-F-FTTT )E!HNN,<,<< $!'JJ[[A%%!'JJ "$J mIQl(EEdii
.C.CEEEW[W`W`akWlWlH$$Wc=AA	+j84?)KNcc*(%"$$
 
 	 	 	 	 MsH   AAA+N0 
FN$N0 $N((N0 +N(,N0 0
N=<N=c            	        #$ 	 ddl m}  nC# t          $ r6 t          d           t	          j        t          j        dddddg           Y nw xY wt          t          j	                  d	k     r2t          d
           t          d           t          j
        d           t          j	        d         }|                                                    d          r2t          d| d           t          |          }t          d           nJ|                                                    d          s#t          d           t          j
        d           t          d           t          d                                          }|s#t          d           t          j
        d           t!          j        d|t           j                  }|r|                    d          nd}|r%t!          j        d|t           j                  r|dz   }t!          j        d|          }|r|                    d          nd}|s0	 ddlm} dd l}|                    |          5 }	|	                    d          }
d d d            n# 1 swxY w Y   |                    |
          }d}d}|                    d| d           }t7          |          d d!         D ]}|                    d"| d#          D ]h}|                    d"| d$          }d%                    d& |D                       }t!          j        d|          }|r|                    d          } ni|r nn# t<          $ r Y nw xY w|s!t          d'                                          }|rt          d(|            |rAt          d)|            t>                               ||*          }t          d+|            nt          d,           t          d           t                       |r|rtC          ||          nd}tE          t          j	        d                   j#        d-z   }t          d.           tI          |||||          #t          d/t          #           d0           tK          d1 #D                       }t          d2           tM          |'                                          D ]\  }}t          d3|d4d3|            g d5}t                       t          d6                                                                          }|d7k    r]	 tQ          t          d8                                                    $n# tR          $ r d9$Y nw xY w#$fd:tU          dt          #          $          D             }tE          t          j	        d                   j#        }tW          |d          D ]\  }}| d;| d-} tY          | d<dd=>          5 }!t[          j.        |!|?          }"|"/                                 |"0                    |           d d d            n# 1 swxY w Y   t          d@|  dAt          |           dB           t          dCt          |           dD           ntY          |d<dd=>          5 }!t[          j.        |!|?          }"|"/                                 |"0                    #           d d d            n# 1 swxY w Y   t          dE|            t          d3t          #           dF           t                       t          dG           d S )HNr   r   zInstalando python-docx...z-mpipinstallzpython-docxz-qr   z)Uso: python boletin_to_csv.py archivo.docz*     python boletin_to_csv.py archivo.docxr$   z.doczConvirtiendo z a .docx con LibreOffice...u     → Listo
r(   z'ERROR: El archivo debe ser .doc o .docxu   ───────────────────────────────────────────────────────uB   Título del boletín (ej: BOLETIN OFICIAL Nº 29 – 09/03/2026): u(   ERROR: El título no puede estar vacío.u   N[ºo°]?\s*(\d+)rr   zE\.?C\.?ECz\b(20\d{2})\br   r   r   r   r   r   
   r   r   r   ro   c              3   2   K   | ]}|j         	|j         V  d S r   r   r   s     r   r   zmain.<locals>.<genexpr>D  s+      "C"CaAF"C16"C"C"C"C"C"Cr   uM     No se detectó el año automáticamente. Ingresalo manualmente (ej: 2026): u     → Año detectado: u     → Número de boletín: r   u     → Link PDF: uR     ⚠ No se pudo detectar el número de boletín — el ícono PDF no se agregaráz_avisos.csvzExtrayendo avisos...u     → z avisos encontradosc              3   &   K   | ]}|d          V  dS )r   Nr   )r   as     r   r   zmain.<locals>.<genexpr>d  s'      88Aa'888888r   u   
Resumen por categoría:z  3dr   u0   ¿Dividir el CSV en lotes para importar? (s/n): su(   ¿Cuántas entradas por lote? (ej: 20):    c                 *    g | ]}||z            S r   r   )r   r7  r?  tams     r   r   zmain.<locals>.<listcomp>s  s%    EEEQ!C%EEEr   _partewz	utf-8-sig)newlineencoding)
fieldnamesu     ✓ z  (z
 entradas)u   
✓ u8    archivos generados — importalos de a uno en WordPressu   
✓ CSV generado: z+ entradas listas para importar en WordPressu7   Próximo paso: Herramientas → Import CSV en WordPress)1r%   r   ImportErrorr*   r/   r0   r+   
executablerw   argvr,   lowerendswithr=   inputrI   r   r   r  r   r   r   r  r  r  r  r  r  r  r4   r  r   r   r   r   r3   rI  r   ru   rt   int
ValueErrorr  r  opencsv
DictWriterwriteheader	writerows)%r   archivotitulo	match_numr   
match_anior   r   zfr  r  r  r  r  ry   r  r  r  txtrB  pdf_urlr  salidaresumenr!  ncamposresplotesr3   r  lotenombre_lotefwriterr?  rV  s%                                      @@r   mainrz    s   V!!!!!!! V V V)***eYtTUUUUUV 38}}q9::::;;;hqkG}}'' BgBBBCCC&w//]]__%%g.. 7888	*WXX^^``F 8999 	.FFI#,4Y__Q"F ")K?? $ +V44J",4:A"D 	""""""    G$$ 6&&!4556 6 6 6 6 6 6 6 6 6 6 6 6 6 6##G,,DPAUC99^!^^^,,DdCRC 	 	!MM*=#*=*=*=>>  D LL88E(("C"C5"C"C"CCCC	"2C88A  wwqzz  E 	 	 	D	  ndeekkmm /-t--... d4F44555%%4%??***++++bccc	*	GGG39JdJ!&$///J#(1+#m3F	
 !!!GVT6:FFF	
33v;;
3
3
34448888888G	
%&&&)) " "Q 1   3  !!!!gggF 
GGGCDDJJLLRRTTDs{{	eFGGMMOOPPCC 	 	 	CCC	EEEEE%3v;;*D*DEEECHQK  %"5!,, 	B 	BIC!99999Kk3[III 'Qf===""$$$  &&&' ' ' ' ' ' ' ' ' ' ' ' ' ' ' @;@@3t99@@@AAAA[s5zz[[[\\\\&#rK@@@ 	%A^A&999F   V$$$	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	-V--...K3v;;KKKLLL	GGG	
CDDDDDs~    =A
A9M I:.M :I>>M I>CM 
M%$M%?.U. .U=<U=?A YY	Y	.A [::[>[>__main__)__doc__r+   r   re  r   r   r-   r/   pathlibr   collectionsr   r  r   r   r   r"   r=   rN   rv   rs   r}   rI  rz  __name__r   r   r   <module>r     s^    


 				 



 				                  
 
 
  _q	 	 	# # #2 2 22  @  
" .%+"(#) )    n n nbvE vE vEr zDFFFFF r   