o
    ¾Ùøi/_  ã                   @   s4  d dl Z d dlmZ d dlmZ d dlmZmZmZm	Z	m
Z
mZmZmZmZ ddlmZ ddlmZmZmZmZmZmZ dZdZdZdZeeeeef f Zed	eeef f Zer`dd
lm Z  eefdedededefdd„Z!efdedededefdd„Z"dedededededefdd„Z#efdede$defdd„Z%efdede$defdd „Z&	d8dedededefd!d"„Z'd#ede	e fd$d%„Z(d&e	e de	e	e  fd'd(„Z)G d)d*„ d*e*ƒZ+G d+d,„ d,e+ƒZ,G d-d.„ d.e+ƒZ-G d/d0„ d0e*ƒZ.g d1¢Z/g d2¢Z0G d3d4„ d4e1ƒZ2e2d ƒZ3eG d5d	„ d	ƒƒZ4G d6d7„ d7e*ƒZ5dS )9é    N)Ú	dataclass)Ú
itemgetter)	ÚTYPE_CHECKINGÚAnyÚDictÚListÚOptionalÚSetÚTupleÚTypeÚUnioné   )Úutils)ÚT_bboxÚT_numÚT_objÚ
T_obj_iterÚ
T_obj_listÚT_pointé   ÚTableSettings)ÚPageÚedgesÚx_toleranceÚy_toleranceÚreturnc                 C   sR   g g dœ}| D ]}||d    |¡ qt |d d|¡}t |d d|¡}|| S )zs
    Given a list of edges, snap any within `tolerance` pixels of one another
    to their positional average.
    ©ÚvÚhÚorientationr   Úx0r   Útop)Úappendr   Úsnap_objects)r   r   r   Úby_orientationÚeÚ	snapped_vÚ	snapped_h© r(   ú]/home/develop/edictos_py/central_edictos/env/lib/python3.10/site-packages/pdfplumber/table.pyÚ
snap_edges   s   
	r*   r   Ú	tolerancec           	      C   s®   |dkr	d\}}n|dkrd\}}nt dƒ‚tt| t|ƒd�ƒ}|d g}|dd	… D ])}|d
 }|| || | krO|| || krNt |||| ¡|d
< q+| |¡ q+|S )z
    Given a list of edges along the same infinite line, join those that
    are within `tolerance` pixels of one another.
    r   )r    Úx1r   )r!   ÚbottomzOrientation must be 'v' or 'h'©Úkeyr   r   Néÿÿÿÿ)Ú
ValueErrorÚlistÚsortedr   r   Úresize_objectr"   )	r   r   r+   Úmin_propÚmax_propÚsorted_edgesÚjoinedr%   Úlastr(   r(   r)   Újoin_edge_group'   s   


€r:   Úsnap_x_toleranceÚsnap_y_toleranceÚjoin_x_toleranceÚjoin_y_tolerancec           	         sv   dt dtttf fdd„}|dks|dkrt| ||ƒ} t| |d�}tj||d�}‡ ‡fdd„|D ƒ}ttj	|Ž ƒ} | S )	z|
    Using the `snap_edges` and `join_edge_group` methods above,
    merge a list of edges into a more "seamless" list.
    Úedger   c                 S   s$   | d dkrd| d fS d| d fS )Nr   r   r!   r   r    r(   )r?   r(   r(   r)   Ú	get_groupP   s   zmerge_edges.<locals>.get_groupr   r.   c                 3   s4   � | ]\}}t ||d  |d  dkrˆ nˆƒV  qdS )r   r   N)r:   )Ú.0ÚkÚitems©r=   r>   r(   r)   Ú	<genexpr>[   s   € ýÿ
ÿzmerge_edges.<locals>.<genexpr>)
r   r
   Ústrr   r*   r3   Ú	itertoolsÚgroupbyr2   Úchain)	r   r;   r<   r=   r>   r@   Ú_sortedÚedge_groupsÚedge_genr(   rD   r)   Úmerge_edgesD   s   ürM   ÚwordsÚword_thresholdc           	   
      sº   t  | tdƒd¡}t‡ fdd„|ƒ}ttt j|ƒƒ}t|ƒdkr"g S tttdƒ|ƒƒ}t	ttdƒ|ƒƒ}g }|D ]"}||||d |d || dd	œ|||d
 |d
 || dd	œg7 }q8|S )zi
    Find (imaginary) horizontal lines that connect the tops
    of at least `word_threshold` words.
    r!   r   c                    ó   t | ƒˆ kS ©N©Úlen©Úx©rO   r(   r)   Ú<lambda>m   ó    z"words_to_edges_h.<locals>.<lambda>r   r    r,   r   )r    r,   r!   r-   Úwidthr   r-   )
r   Úcluster_objectsr   Úfilterr2   ÚmapÚobjects_to_rectrS   ÚminÚmax)	rN   rO   Úby_topÚlarge_clustersÚrectsÚmin_x0Úmax_x1r   Úrr(   rV   r)   Úwords_to_edges_he   s4   úúórf   c                    sF  t  | tdƒd¡}t  | tdƒd¡}dtdtfdd„}t  | |d¡}|| | }t|dd	„ d
�}t‡fdd	„|ƒ}ttt j	|ƒƒ}	g }
|	D ]‰ t
‡ fdd„|
D ƒƒ}|sY|
 ˆ ¡ qEt|
ƒdkrbg S tt j|
ƒ}tt|tdƒd
�ƒ}tttdƒ|ƒƒ}tttdƒ|ƒƒ‰tttdƒ|ƒƒ‰‡‡fdd„|D ƒ||ˆˆˆˆ ddœg S )zy
    Find (imaginary) vertical lines that connect the left, right, or
    center of at least `word_threshold` words.
    r    r   r,   Úwordr   c                 S   s   t | d | d  ƒd S )Nr    r,   é   )Úfloat)rg   r(   r(   r)   Ú
get_center›   s   z$words_to_edges_v.<locals>.get_centerc                 S   s
   t | ƒ S rQ   rR   rT   r(   r(   r)   rW   ¢   s   
 z"words_to_edges_v.<locals>.<lambda>r.   c                    rP   rQ   rR   rT   rV   r(   r)   rW   £   rX   c                 3   s   � | ]	}t  ˆ |¡V  qd S rQ   )r   Úget_bbox_overlap©rA   Úc©Úbboxr(   r)   rE   «   s   € z#words_to_edges_v.<locals>.<genexpr>r   r!   r-   c              	      s*   g | ]}|d  |d  ˆˆ ˆ ˆ ddœ‘qS )r    r   ©r    r,   r!   r-   Úheightr   r(   )rA   Úb)Ú
max_bottomÚmin_topr(   r)   Ú
<listcomp>¹   s    	ùúÿz$words_to_edges_v.<locals>.<listcomp>r   rp   )r   rZ   r   r   r   r3   r[   r2   r\   Úobjects_to_bboxÚanyr"   rS   Úbbox_to_rectr_   r^   )rN   rO   Úby_x0Úby_x1rj   Ú	by_centerÚclustersÚsorted_clustersra   ÚbboxesÚcondensed_bboxesÚoverlapÚcondensed_rectsÚsorted_rectsrd   r(   )ro   rs   rt   rO   r)   Úwords_to_edges_v�   sB   
€	÷úÿörƒ   c           	         sè   i }‡ fdd„dD ƒ\}}t |tddƒd�D ][}t |tddƒd�D ]O}|d |d | krp|d |d | krp|d |d | krp|d |d | krp|d |d f}||vr^g g dœ||< || d	  |¡ || d
  |¡ q!q|S )zi
    Given a list of edges, return the points at which they intersect
    within `tolerance` pixels.
    c                    s"   g | ]‰ t t‡ fd d„ˆƒƒ‘qS )c                    s   | d ˆ kS )Nr   r(   rT   ©Úor(   r)   rW   Ø   rX   z3edges_to_intersections.<locals>.<listcomp>.<lambda>)r2   r[   )rA   ©r   r„   r)   ru   ×   s    ÿz*edges_to_intersections.<locals>.<listcomp>r   r    r!   r.   r-   r,   r   r   )r3   r   r"   )	r   r   r   ÚintersectionsÚv_edgesÚh_edgesr   r   Úvertexr(   r†   r)   Úedges_to_intersectionsÏ   s$   

ÿ€õr‹   r‡   c                    s‚   dt dt dtf‡fdd„‰ ttˆ ¡ ƒƒ‰tˆƒ‰dtt  dtdtt	 f‡ ‡‡fdd	„‰‡‡fd
d„t
tˆƒƒD ƒ}ttd|ƒƒS )a8  
    Given a list of points (`intersections`), return all rectangular "cells"
    that those points describe.

    `intersections` should be a dictionary with (x0, top) tuples as keys,
    and a list of edge objects as values. The edge objects should correspond
    to the edges that touch the intersection.
    Úp1Úp2r   c                    s–   dt dtt fdd„}| d |d kr*|ˆ |  d ƒ |ˆ | d ƒ¡}t|ƒr*dS | d |d krI|ˆ |  d	 ƒ |ˆ | d	 ƒ¡}t|ƒrIdS d
S )Nr   r   c                 S   s   t ttj| ƒƒS rQ   )Úsetr\   r   Úobj_to_bboxr†   r(   r(   r)   Úedges_to_setõ   s   zCintersections_to_cells.<locals>.edge_connects.<locals>.edges_to_setr   r   Tr   r   F)r   r	   r   ÚintersectionrS   )rŒ   r�   r�   Úcommon)r‡   r(   r)   Úedge_connectsô   s   ÿÿz-intersections_to_cells.<locals>.edge_connectsÚpointsÚic                    sÌ   |ˆd krd S | | ‰ | |d d … }‡ fdd„|D ƒ}‡ fdd„|D ƒ}|D ];}ˆˆ |ƒs0q(|D ]0}ˆˆ |ƒs:q2|d |d f}|ˆv rbˆ||ƒrbˆ||ƒrbˆ d ˆ d |d |d f    S q2q(d S )Nr   c                    ó    g | ]}|d  ˆ d  kr|‘qS )r   r(   ©rA   rU   ©Úptr(   r)   ru     ó     zFintersections_to_cells.<locals>.find_smallest_cell.<locals>.<listcomp>c                    r–   ©r   r(   r—   r˜   r(   r)   ru     rš   r   r(   )r”   r•   ÚrestÚbelowÚrightÚbelow_ptÚright_ptÚbottom_right)r“   r‡   Ún_pointsr˜   r)   Úfind_smallest_cell
  s,   

ÿþ$€ôz2intersections_to_cells.<locals>.find_smallest_cellc                 3   s   � | ]}ˆ ˆ|ƒV  qd S rQ   r(   )rA   r•   )r£   r”   r(   r)   rE   %  s   € z)intersections_to_cells.<locals>.<genexpr>N)r   Úboolr2   r3   ÚkeysrS   r   Úintr   r   Úranger[   )r‡   Úcell_genr(   )r“   r£   r‡   r¢   r”   r)   Úintersections_to_cellsê   s   
&r©   Úcellsc                    s0  dt dtttttf fdd„}t| ƒ}tƒ ‰ g }g }t|ƒr|t|ƒ}t|ƒD ]<}||ƒ}t|ƒdkrCˆ t|ƒO ‰ | |¡ | |¡ q&t‡ fdd„|D ƒƒ}|dkrbˆ t|ƒO ‰ | |¡ | |¡ q&t|ƒ|krx| t|ƒ¡ ˆ  	¡  | 	¡  t|ƒst|ƒr‡| t|ƒ¡ t
|dd	„ d
�}	dd„ |	D ƒ}
|
S )z…
    Given a list of bounding boxes (`cells`), return a list of tables that
    hold those cells most simply (and contiguously).
    ro   r   c                 S   s(   | \}}}}||f||f||f||ffS rQ   r(   )ro   r    r!   r,   r-   r(   r(   r)   Úbbox_to_corners/  s   z(cells_to_tables.<locals>.bbox_to_cornersr   c                 3   s   � | ]}|ˆ v V  qd S rQ   r(   rl   ©Úcurrent_cornersr(   r)   rE   H  s   € z"cells_to_tables.<locals>.<genexpr>c                 S   s   t dd„ | D ƒƒS )Nc                 s   s    � | ]}|d  |d fV  qdS )r   r   Nr(   rl   r(   r(   r)   rE   a  s   € z4cells_to_tables.<locals>.<lambda>.<locals>.<genexpr>)r^   )Útr(   r(   r)   rW   a  s    z!cells_to_tables.<locals>.<lambda>r.   c                 S   s   g | ]
}t |ƒd kr|‘qS r›   rR   )rA   r®   r(   r(   r)   ru   b  ó    z#cells_to_tables.<locals>.<listcomp>)r   r
   r   r2   rŽ   rS   r"   ÚremoveÚsumÚclearr3   )rª   r«   Úremaining_cellsÚcurrent_cellsÚtablesÚinitial_cell_countÚcellÚcell_cornersÚcorner_countrJ   Úfilteredr(   r¬   r)   Úcells_to_tables)  s:   


€ær»   c                   @   s"   e Zd Zdeee  fdd„ZdS )Ú	CellGrouprª   c              	   C   sh   || _ tttdƒtd |ƒƒƒtttdƒtd |ƒƒƒtttdƒtd |ƒƒƒtttdƒtd |ƒƒƒf| _d S ©Nr   r   rh   r   )rª   r^   r\   r   r[   r_   ro   )Úselfrª   r(   r(   r)   Ú__init__g  s   
üzCellGroup.__init__N)Ú__name__Ú
__module__Ú__qualname__r   r   r   r¿   r(   r(   r(   r)   r¼   f  s    r¼   c                   @   ó   e Zd ZdS )ÚRowN©rÀ   rÁ   rÂ   r(   r(   r(   r)   rÄ   q  ó    rÄ   c                   @   rÃ   )ÚColumnNrÅ   r(   r(   r(   r)   rÇ   u  rÆ   rÇ   c                   @   s˜   e Zd Zdddee fdd„Zedefdd„ƒZd	ee	 dee	 fd
d„Z
edee	 fdd„ƒZedee	 fdd„ƒZdedeeee   fdd„ZdS )ÚTableÚpager   rª   c                 C   s   || _ || _d S rQ   )rÉ   rª   )r¾   rÉ   rª   r(   r(   r)   r¿   z  s   
zTable.__init__r   c                 C   sJ   | j }tttdƒ|ƒƒtttdƒ|ƒƒtttdƒ|ƒƒtttdƒ|ƒƒfS r½   )rª   r^   r\   r   r_   )r¾   rm   r(   r(   r)   ro   ~  s   üz
Table.bboxÚkindc           
         s¢   |t u rdnd‰ tˆ  ƒ}t| jt|ˆ ƒd�}tttttˆ ƒ| jƒƒƒƒ}t 	|t|ƒ¡}g }|D ]\}}‡ fdd„|D ƒ‰|‡fdd„|D ƒƒ}	| 
|	¡ q1|S )Nr   r   r.   c                    s   i | ]}|ˆ  |“qS r(   r(   )rA   r·   )Úaxisr(   r)   Ú
<dictcomp>˜  ó    z+Table._get_rows_or_cols.<locals>.<dictcomp>c                    s   g | ]}ˆ   |¡‘qS r(   )Úgetr—   )Úxdictr(   r)   ru   ™  rÍ   z+Table._get_rows_or_cols.<locals>.<listcomp>)rÄ   r¦   r3   rª   r   r2   rŽ   r\   rG   rH   r"   )
r¾   rÊ   ÚantiaxisrJ   ÚxsÚgroupedÚrowsÚyÚ	row_cellsÚrowr(   )rË   rÏ   r)   Ú_get_rows_or_colsˆ  s   
zTable._get_rows_or_colsc                 C   ó
   |   t¡S rQ   )r×   rÄ   ©r¾   r(   r(   r)   rÓ   �  ó   
z
Table.rowsc                 C   rØ   rQ   )r×   rÇ   rÙ   r(   r(   r)   Úcolumns¡  rÚ   zTable.columnsÚkwargsc                    sä   | j j}g }dtdtdtfdd„‰| jD ][‰g }‡‡fdd„|D ƒ}ˆjD ]D‰ ˆ d u r.d }n6‡ ‡fdd„|D ƒ}t|ƒrbd	|v rXˆ d
 ˆ d  |d< ˆ d ˆ d  |d< ˆ |d< tj	|fi |¤Ž}nd}| 
|¡ q%| 
|¡ q|S )NÚcharro   r   c                 S   sX   | d | d  d }| d | d  d }|\}}}}t ||ko*||k o*||ko*||k ƒS )Nr!   r-   rh   r    r,   )r¤   )rÝ   ro   Úv_midÚh_midr    r!   r,   r-   r(   r(   r)   Úchar_in_bboxª  s   ÿz#Table.extract.<locals>.char_in_bboxc                    s   g | ]
}ˆ |ˆj ƒr|‘qS r(   rn   ©rA   rÝ   )rà   rÖ   r(   r)   ru   ´  r¯   z!Table.extract.<locals>.<listcomp>c                    s   g | ]	}ˆ|ˆ ƒr|‘qS r(   r(   rá   )r·   rà   r(   r)   ru   º  s
    
ÿÿÚlayoutrh   r   Úlayout_widthr   r   Úlayout_heightÚlayout_bboxÚ )rÉ   Úcharsr   r   r¤   rÓ   rª   rS   r   Úextract_textr"   )r¾   rÜ   rç   Ú	table_arrÚarrÚ	row_charsÚ	cell_textÚ
cell_charsr(   )r·   rà   rÖ   r)   Úextract¥  s,   

ÿzTable.extractN)rÀ   rÁ   rÂ   r   r   r¿   Úpropertyro   r   r¼   r×   rÓ   rÛ   r   r   rF   rî   r(   r(   r(   r)   rÈ   y  s    	"rÈ   )ÚlinesÚlines_strictÚtextÚexplicit)Úsnap_tolerancer;   r<   Újoin_tolerancer=   r>   Úedge_min_lengthÚedge_min_length_prefilterÚmin_words_verticalÚmin_words_horizontalÚintersection_toleranceÚintersection_x_toleranceÚintersection_y_tolerancec                   @   rÃ   )Ú
UnsetFloatNrÅ   r(   r(   r(   r)   rý   Þ  rÆ   rý   c                   @   s6  e Zd ZU dZeed< dZeed< dZee	e
eef   ed< dZee	e
eef   ed< eZeed< eZeed< eZeed	< eZeed
< eZeed< eZeed< dZeed< dZeed< eZeed< eZeed< dZeed< eZeed< eZ eed< dZ!ee"ee#f  ed< ddd„Z$e%dee& dd fdd„ƒZ'dS )r   rð   Úvertical_strategyÚhorizontal_strategyNÚexplicit_vertical_linesÚexplicit_horizontal_linesrô   r;   r<   rõ   r=   r>   r   rö   r   r÷   rø   rù   rú   rû   rü   Útext_settingsr   c                 C   sâ   t D ]}t| |ƒp
ddk rtd|› d�ƒ‚qdD ]}t| |d ƒ}|tvr2t|› dd t¡› d�ƒ‚q| jd	u r;i | _d
D ]}|| jvrN| j dd¡| j|< q=d| jv rX| jd= dD ]\}}t| |ƒtu rnt| |t| |ƒƒ qZd	S )a¿  Clean up user-provided table settings.

        Validates that the table settings provided consists of acceptable values and
        returns a cleaned up version. The cleaned up version fills out the missing
        values with the default values in the provided settings.

        TODO: Can be further used to validate that the values are of the correct
            type. For example, raising a value error when a non-boolean input is
            provided for the key ``keep_blank_chars``.

        :param table_settings: User-provided table settings.
        :returns: A cleaned up version of the user-provided table settings.
        :raises ValueError: When an unrecognised key is provided.
        r   zTable setting 'z' cannot be negative)Ú
horizontalÚverticalÚ	_strategyz_strategy must be one of{ú,Ú}N)r   r   r+   r   ))r;   rô   )r<   rô   )r=   rõ   )r>   rõ   )rû   rú   )rü   rú   )	ÚNON_NEGATIVE_SETTINGSÚgetattrr1   ÚTABLE_STRATEGIESÚjoinr  rÎ   ÚUNSETÚsetattr)r¾   Úsettingr   ÚstrategyÚattrÚfallbackr(   r(   r)   Ú__post_init__ú  s4   ÿÿÿÿ

€
€÷zTableSettings.__post_init__Úsettingsc                 C   sŽ   |d u r| ƒ S t || ƒr|S t |tƒr@i }i }| ¡ D ]\}}|d d… dkr0|||dd … < q|||< q||d< | di |¤ŽS td|› �ƒ‚)Né   Útext_r  zCannot resolve settings: r(   )Ú
isinstanceÚdictrC   r1   )Úclsr  Úcore_settingsr  rB   r   r(   r(   r)   Úresolve-  s   


zTableSettings.resolve)r   N)(rÀ   rÁ   rÂ   rþ   rF   Ú__annotations__rÿ   r   r   r   r   r   r   r  ÚDEFAULT_SNAP_TOLERANCErô   r  r;   r<   ÚDEFAULT_JOIN_TOLERANCErõ   r=   r>   rö   r÷   ÚDEFAULT_MIN_WORDS_VERTICALrø   r¦   ÚDEFAULT_MIN_WORDS_HORIZONTALrù   rú   rû   rü   r  r   r   r  ÚclassmethodÚT_table_settingsr  r(   r(   r(   r)   r   å  s,   
 
3c                   @   s6   e Zd ZdZddddee fdd„Zdefd	d
„ZdS )ÚTableFindera0  
    Given a PDF page, find plausible table structures.

    Largely borrowed from Anssi Nurminen's master's thesis:
    http://dspace.cc.tut.fi/dpub/bitstream/handle/123456789/21520/Nurminen.pdf?sequence=3

    ... and inspired by Tabula:
    https://github.com/tabulapdf/tabula-extractor/issues/16
    NrÉ   r   r  c                    s^   |ˆ _ t |¡ˆ _ˆ  ¡ ˆ _tˆ jˆ jjˆ jjƒˆ _	t
ˆ j	ƒˆ _‡ fdd„tˆ jƒD ƒˆ _d S )Nc                    s   g | ]}t ˆ j|ƒ‘qS r(   )rÈ   rÉ   )rA   Ú
cell_grouprÙ   r(   r)   ru   V  s    ÿz(TableFinder.__init__.<locals>.<listcomp>)rÉ   r   r  r  Ú	get_edgesr   r‹   rû   rü   r‡   r©   rª   r»   rµ   )r¾   rÉ   r  r(   rÙ   r)   r¿   L  s   
ý
ÿzTableFinder.__init__r   c              
   C   s°  | j }dD ]'}t||d ƒ}|dkr,t|d| d ƒ}t|ƒdk r,td|› d|› d	�ƒ‚q|j}|j}|d
ks;|d
krG| jjdi |jpDi ¤Ž}g }|j	pMg D ]9}	t
|	tƒrit |	¡D ]}
|
d dkrg| |
¡ qZqN| |	|	| jjd | jjd | jjd | jjd  ddœ¡ qN|dkr˜tj| jjd|jd�}n#|dkr©tj| jjdd|jd�}n|d
krµt||jd�}n|dkr»g }|| }g }|jpÅg D ]9}	t
|	tƒrát |	¡D ]}
|
d dkrß| |
¡ qÒqÆ| | jjd | jjd | jjd | jjd  |	|	ddœ¡ qÆ|dk�rtj| jjd|jd�}n&|dk�r#tj| jjdd|jd�}n|d
k�r0t||jd�}n|dk�r7g }|| }t|ƒt|ƒ }t||j|j|j|jd�}tj||jd�S )N)r  r  r  ró   Ú	explicit_Ú_linesrh   zIf z"_strategy == 'explicit', explicit_zD_lines must be specified as a list/tuple of two or more floats/ints.rò   r   r   r   r   rp   rð   )Ú
min_lengthrñ   Úline)Ú	edge_typer'  rV   r   r   )r    r,   rY   r!   r-   r   )r;   r<   r=   r>   r(   )r  r	  rS   r1   rþ   rÿ   rÉ   Úextract_wordsr  r   r  r  r   Úobj_to_edgesr"   ro   Úfilter_edgesr   r÷   rƒ   rø   r  rf   rù   r2   rM   r;   r<   r=   r>   rö   )r¾   r  r   r  rð   Úv_stratÚh_stratrN   Ú
v_explicitÚdescr%   Úv_baser   Ú
h_explicitÚh_baser   r   r(   r(   r)   r$  Z  sº   ÿÿ€

€þ

úÿÿü

€þ

úÿ
ÿ
ü
ÿ
ûzTableFinder.get_edgesrQ   )	rÀ   rÁ   rÂ   Ú__doc__r   r!  r¿   r   r$  r(   r(   r(   r)   r"  A  s    
r"  )r   r   )6rG   Údataclassesr   Úoperatorr   Útypingr   r   r   r   r   r	   r
   r   r   ræ   r   Ú_typingr   r   r   r   r   r   r  r  r  r  rF   ÚT_intersectionsr!  rÉ   r   r*   r:   rM   r¦   rf   rƒ   r‹   r©   r»   Úobjectr¼   rÄ   rÇ   rÈ   r
  r  ri   rý   r  r   r"  r(   r(   r(   r)   Ú<module>   s®    , ýÿþý
üÿÿÿÿ
þÿþýüû
ú"ÿÿÿ
þ,ÿÿÿ
þ@ÿÿÿÿ
þ?=S[