ó
    uÕgjì!  ã                  ó$  • S r SSKJr  SSKrSSKJr  SSKJrJrJ	r	J
r
Jr  SSKJr  SSKJrJr  SrS	r\R&                  " S
5      r\R&                  " S\R*                  5      rSS jrSS jrSS jrSS jr      SS jr " S S\5      rSS jrg)uê  Read a scanned page's tables back as grids.

A scan returns a table as a table. The chunk carries an HTML grid with an id on
every cell, and the response's grounding map carries, against each of those ids,
the cell's box and its row, column and spans. Putting the two together gives a
dense grid â€” one entry per row and column â€” with a box on every cell, which is
the shape the rest of the table pipeline already works in.

A table is not always its own chunk. Where a page prints a chart and a table as
one composite, the scan returns one figure, and writes the table inside that
figure's text as markdown between a pair of markers it emits itself. The values
are complete and correctly separated there â€” on one page the scan read a bond
issuance table's four credit-rating rows exactly, while the parse ran four
ratings together into a single cell and left the next three blank.

So the markers are read and the markdown between them is taken as a table.
Nothing infers where the table is in the text; the scan labelled it.

What such a table does not carry is geometry. The composite is grounded as one
box covering the whole figure, with nothing per cell, so its cells arrive with no
boxes. That costs nothing downstream: the structure correction reads the page
image rather than the boxes, and a table with no reading to check against already
puts every cell to the agent.

Nothing here interprets the content. Spans are honoured as geometry: a cell that
spans two columns is written once at its own position and the positions it covers
are left blank, the same way a grid extracted from a text layer arrives. What the
header block is, which cells merged, and what the title says are read later, off
the table image, by the steps that read every other table.
é    )ÚannotationsN)Ú
HTMLParser)ÚAnyÚDictÚListÚOptionalÚTuple)Úmarkdown_rows)ÚBoxÚScannedTableÚ	tableCellÚtablez#<table[^>]*\bid=[\"']([^\"']+)[\"']z<::table::>(.*?)<::/table::>c                óN  • U R                  S5      =(       d    0 n[        U5      n/ nU R                  S5      =(       d    /  HÄ  nUR                  S5      S:w  a  M  UR                  S5      nUR                  S5      =(       d    Sn[        U5      n	[        UR                  U/ 5      U	5      u  p«UR	                  [        UU
U[        Xƒ5      =(       d)    UR                  S5      =(       d    0 R                  S5      UUS	95        MÆ     UR                  [        XU5      5        U$ )
a   Every table in one page's raw response, as a dense grid with per-cell boxes.

`page` is the 1-based source page the submission came from. The response
numbers its own single page from zero, so the source page is carried in
rather than read back out of it.
Ú	groundingÚchunksÚtyper   ÚidÚmarkdownÚ Úbox©ÚpageÚcellsÚ
cell_boxesr   Úchunk_idÚjob_id)	ÚgetÚ_cells_by_chunkÚ
_cell_textÚ_dense_gridÚappendr   Ú
_table_boxÚextendÚ_composite_tables)Úresponser   r   r   Úcells_by_chunkÚtablesÚchunkr   r   Ú
text_by_idr   Úboxess               Ú5/home/mande/repo/quber/src/quber/core/figures/grid.pyÚscanned_tablesr,   7   s   € ð —‘˜[Ó)×/¨R€IÜ$ YÓ/€Nà!#€FØ—‘˜hÓ'×-¨2Ò-ˆØ�9‰9�VÓ Ó'ÙØ—9‘9˜T“?ˆØ—9‘9˜ZÓ(×.¨BˆÜ Ó)ˆ
Ü" >×#5Ñ#5°hÀÓ#CÀZÓP‰ˆØ�‰ÜØØØ Ü˜xÓ3×`¸¿	¹	À+Ó8N×8TÐRT×7YÑ7YÐZ_Ó7`Ø!Øñö		
ñ .ð$ ‡M�MÔ# H°FÓ;Ô<Ø€Mó    c                ó^  • / nU R                  S5      =(       d    /  GH  nUR                  S5      S:w  a  M  [        R                  UR                  S5      =(       d    S5       Hµ  n[        U5      nU(       d  M  [	        S U 5       5      nU Vs/ s H  oˆS/U[        U5      -
  -  -   PM     n	nUR                  [        UU	U	 V
s/ s H	  n
S/U-  PM     sn
UR                  S5      =(       d    0 R                  S	5      UR                  S
5      US95        M·     GM     U$ s  snf s  sn
f )a  The tables the scan printed inside a figure's text rather than as chunks.

The figure's own box stands as the table's box. It is the only geometry the
scan grounded for the composite, and it is drawn around the chart and the
table together, so the region is generous rather than wrong.
r   r   Úfigurer   r   c              3  ó8   #   • U  H  n[        U5      v •  M     g 7f©N)Úlen)Ú.0Úrs     r+   Ú	<genexpr>Ú$_composite_tables.<locals>.<genexpr>g   s   é € Ð-ª 1œ˜AŸ˜ªùs   ‚Nr   r   r   r   )r   Ú_FIGURE_TABLE_REÚfindallr
   Úmaxr2   r!   r   )r%   r   r   Úoutr(   r   ÚrowsÚwidthr4   r   Ú_s              r+   r$   r$   X   s  € ð !€CØ—‘˜hÓ'×-¨2Ó-ˆØ�9‰9�VÓ Ó(ÙÜ(×0Ñ0°·±¸:Ó1F×1LÈ"ÖMˆHÜ  Ó*ˆDÞÙÜÑ-©Ó-Ó-ˆEÙ:>Ó?º$°Q˜"˜ ¬¨Q«¡Ñ0Ô0¹$ˆEÐ?Ø�J‰JÜØØÙ8=Ó>º°1  ¨¤¹Ñ>ØŸ™ ;Ó/×5°2×:Ñ:¸5ÓAØ"ŸY™Y t›_Ø!ñö	ô Nñ .ð& €Jùò @ùò
  ?s   ÂD%ÃD*c                ó  • 0 nU R                  5        Hr  u  p#UR                  S5      [        :w  a  M   UR                  S5      =(       d    0 nUR                  S5      nUc  MP  UR                  U/ 5      R	                  X#45        Mt     U$ )zMThe grounding map's cell entries, grouped by the table chunk each belongs to.r   Úpositionr   )Úitemsr   Ú	CELL_TYPEÚ
setdefaultr!   )r   Úby_chunkÚcell_idÚentryr?   r   s         r+   r   r   v   s}   € à<>€HØ#Ÿ/™/Ö+‰ˆØ�9‰9�VÓ¤	Ó)ÙØ—9‘9˜ZÓ(×.¨BˆØ—<‘< 
Ó+ˆØÑÙØ×Ñ˜H bÓ)×0Ñ0°'Ð1AÖBñ ,ð €Or-   c                óÞ   • [         R                  U 5      nUc  gUR                  UR                  S5      5      =(       d    0 nUR                  S5      [        :X  a  UR                  S5      $ S$ )zEThe box around the table itself, from the id its opening tag carries.Né   r   r   )Ú_TABLE_ID_REÚsearchr   ÚgroupÚ
TABLE_TYPE)r   r   ÚmatchrE   s       r+   r"   r"   „   sY   € ä×Ñ Ó)€EØ�}ØØ�M‰M˜%Ÿ+™+ a›.Ó)×/¨R€EØ$Ÿy™y¨Ó0´JÓ>ˆ5�9‰9�UÓÐHÀDÐHr-   c                ól  • / nSnSnU  Hè  u  pVUR                  S5      =(       d    0 n[        UR                  SS5      5      n[        UR                  SS5      5      n	[        X8[        UR                  SS5      =(       d    S5      -   5      n[        XI[        UR                  SS5      =(       d    S5      -   5      nUR                  X‰UR                  US5      UR                  S	5      45        Mê     [	        U5       V
s/ s H  n
[	        U5       V
s/ s H  n
SPM     sn
PM!     nn
[	        U5       V
s/ s H  n
[	        U5       V
s/ s H  n
S
PM     sn
PM!     nn
U H:  u  p‰pÞSUs=::  a  U:  d  M  O  M  SU	s=::  a  U:  d  M(  O  M,  XÛU   U	'   XìU   U	'   M<     X¼4$ s  sn
f s  sn
f s  sn
f s  sn
f )zóOne row per row and one column per column, with a box beside every cell.

A cell that spans is written at its own row and column; the positions it
covers stay blank and carry no box of their own, so the grid never states the
same value twice.
r   r?   ÚrowÚcolÚrowspanrG   Úcolspanr   r   N)r   Úintr9   r!   Úrange)r   r)   Úplacedr;   ÚcolumnsrD   rE   r?   rN   rO   r=   Úgridr*   Útextr   s                  r+   r    r    �   s€  € ð 9;€FØ€DØ€GÛ‰ˆØ—9‘9˜ZÓ(×.¨BˆÜ�(—,‘,˜u aÓ(Ó)ˆÜ�(—,‘,˜u aÓ(Ó)ˆÜ�4œs 8§<¡<°	¸1Ó#=×#BÀÓCÑCÓDˆÜ�g¤S¨¯©°iÀÓ)C×)HÀqÓ%IÑIÓJˆØ�‰�s §¡°¸Ó!<¸e¿i¹iÈÓ>NÐOÖPñ  ô 38¸´+Ó>²+¨Qœ˜wœÓ(š�A‹R™Ô(±+€DÐ>ÜPUÐVZÔP[Ó'\ÒP[È1´u¸W´~Ó(F²~°!«±~Ô(FÑP[€EÐ'\Û%Ñˆ�$Ø��?�d�?‰?˜q CÕ1¨'×1Ñ1Ø!�‰I�c‰NØ!�#‰J�s‹Oñ  &ð ˆ;Ðùò )ùÒ>ùÚ(FùÒ'\s0   ÄF'ÄF"
Ä!F'Ä7F1Å
F,
ÅF1Æ"F'Æ,F1c                  óX   ^ • \ rS rSrSrS	U 4S jjrS
S jrSS jrSS jrS	S jr	Sr
U =r$ )Ú	_CellTexté«   zØCollects the text of every `td`/`th` carrying an id, keyed by that id.

Markup inside a cell is dropped and its text kept, so a value typeset with an
emphasis or a line break reads as the one string the page prints.
c                óJ   >• [         TU ]  SS9  0 U l        / U l        / U l        g )NT)Úconvert_charrefs)ÚsuperÚ__init__rW   Ú_openÚ_parts)ÚselfÚ	__class__s    €r+   r^   Ú_CellText.__init__²   s(   ø€ Ü‰Ñ¨$ÐÑ/Ø$&ˆŒ	Ø*,ˆŒ
Ø!#ˆ�r-   c                ó   • US;   aD  U R                  5         U R                  R                  [        U5      R	                  S5      5        g US:X  a.  U R                  (       a  U R
                  R                  S5        g g g )N©ÚtdÚthr   ÚbrÚ )Ú_flushr_   r!   Údictr   r`   )ra   ÚtagÚattrss      r+   Úhandle_starttagÚ_CellText.handle_starttag¸   sX   € Ø�,ÓØ�K‰KŒMØ�J‰J×Ñœd 5›kŸo™o¨dÓ3Õ4Ø�D‹[˜TŸZŸZØ�K‰K×Ñ˜sÕ#ð (ˆ[r-   c                ó2   • US;   a  U R                  5         g g )Nre   )rj   )ra   rl   s     r+   Úhandle_endtagÚ_CellText.handle_endtag¿   s   € Ø�,ÓØ�K‰K�Mð r-   c                ó^   • U R                   (       a  U R                  R                  U5        g g r1   )r_   r`   r!   )ra   Údatas     r+   Úhandle_dataÚ_CellText.handle_dataÃ   s    € Ø�:�:Ø�K‰K×Ñ˜tÕ$ð r-   c                óú   • U R                   (       d  g U R                   R                  5       nUbE  SR                  SR                  U R                  5      R	                  5       5      U R
                  U'   / U l        g )Nri   r   )r_   ÚpopÚjoinr`   ÚsplitrW   )ra   rD   s     r+   rj   Ú_CellText._flushÇ   sV   € Ø�z�zØØ—*‘*—.‘.Ó"ˆØÑØ!$§¡¨"¯'©'°$·+±+Ó*>×*DÑ*DÓ*FÓ!GˆD�I‰I�gÑØˆ�r-   )r_   r`   rW   )ÚreturnÚNone)rl   Ústrrm   zList[Tuple[str, Optional[str]]]r|   r}   )rl   r~   r|   r}   )rt   r~   r|   r}   )Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r^   rn   rq   ru   rj   Ú__static_attributes__Ú__classcell__)rb   s   @r+   rY   rY   «   s&   ø† ñ÷$ô$ôô%÷ò r-   rY   c                óp   • [        5       nUR                  U 5        UR                  5         UR                  $ )z:Each cell's printed text, keyed by the id its tag carries.)rY   ÚfeedÚcloserW   )r   Úparsers     r+   r   r   Ð   s(   € ä‹[€FØ
‡K�K�ÔØ
‡L�L„NØ�;‰;Ðr-   )r%   úDict[str, Any]r   rR   r   zOptional[str]r|   zList[ScannedTable])r   rŠ   r|   z+Dict[str, List[Tuple[str, Dict[str, Any]]]])r   r~   r   rŠ   r|   zOptional[Box])r   z List[Tuple[str, Dict[str, Any]]]r)   úDict[str, str]r|   z1Tuple[List[List[str]], List[List[Optional[Box]]]])r   r~   r|   r‹   )rƒ   Ú
__future__r   ÚreÚhtml.parserr   Útypingr   r   r   r   r	   Ú1quber.core.extractors.set_of_mark.merge_groundingr
   Úquber.core.figures.modelsr   r   rA   rK   ÚcompilerH   ÚDOTALLr7   r,   r$   r   r"   r    rY   r   © r-   r+   Ú<module>r•      s�   ðñõ> #ã 	Ý "ß 3Õ 3å Kß 7ð €	ð €
à�zŠzÐ@ÓA€ð —:’:Ð=¸r¿y¹yÓIÐ ôôBô<ôIðØ+ðàðð 7ôô<"�
ô "õJr-   