§
    �Øj9Þ  ã                   óÀ  — d dl Z d dlZd dlZd dlmZ d dlmZmZm	Z	m
Z
 dPdej        dedej        fd„Zdej        dej        fd„Zd	„ ZdQdej        dededeeeeef                  eeeeeef                  f         f         fd„ZdRdej        dededeeeef                  fd„Zdej        dedej        fd„Zdej        defd„Zdej        defd„ZdSd„Zd„ Zdedej        fd„Zdej        dedefd„Zdej        ded eddfd!„Zded"ej        d#ej        fd$„Zd%ej        d&ej        d'ej        deee                  d(ee         dee	         fd)„Z 	 	 	 	 dTd,ej        dee
eeeef                  d-ed.ed/ed0e!d1e!d2e!dej        fd3„Z"d4ej        d5edej        fd6„Z#d4ej        dej        fd7„Z$d8„ Z%dUd;„Z&d<„ Z'	 	 	 dVd=ej        d>ee         d?ee         dz  d@edAedee         fdB„Z(dCej        dDedEedej        fdF„Z)dGej        dHedee         fdI„Z*	 	 	 dWd=ej        d>ee         d?ee         dz  d@edKedee         fdL„Z+e,dMk    r e- edNd¬O¦  «        ¦  «         dS dS )Xé    N)ÚCounter)ÚOptionalÚListÚDictÚTupleÚxÚaxisÚreturnc                 ó’   — | t          j        | |d¬¦  «        z
  }t          j        |¦  «        }|t          j        ||d¬¦  «        z  S )zò
    Numerically stable softmax along the given axis.

    Args:
        x: input array of any shape.
        axis: axis along which softmax is computed.

    Returns:
        np.ndarray of the same shape as x, summing to 1.0 along axis.
    T©r	   Úkeepdims)ÚnpÚmaxÚexpÚsum)r   r	   Ú	x_shiftedÚexp_xs       ú�/Users/tedpeters/Documents/Projects/Claude Projects/Misc Tools/notename-sheets/.venv/lib/python3.11/site-packages/pymupdf/layout/common_util.pyÚsoftmax_numpyr   	   sJ   € ð •B”F˜1 4°$Ð7Ñ7Ô7Ñ7€IÝŒF�9ÑÔ€EØ•2”6˜% d°TÐ:Ñ:Ô:Ñ:Ð:ó    c                 ó8   — ddt          j        |  ¦  «        z   z  S )z 
    Numerically stable sigmoid.

    Args:
        x: input array of any shape.

    Returns:
        np.ndarray of the same shape as x, values in (0, 1).
    g      ð?)r   r   ©r   s    r   Úsigmoid_numpyr      s   € ð �#�œ ˜r™
œ
Ñ"Ñ#Ð#r   c           
      óÂ  — | s t          j        dt           j        ¬¦  «        S t          j        | t           j        ¬¦  «        }|dd…ddgf                              ¦   «         }|dd…ddgf                              ¦   «         }|dd…ddgf                              ¦   «         |z
  }|dd…ddgf                              ¦   «         |z
  }t          j        |d¦  «        }t          j        |d¦  «        }|dd…ddgf         |z
  |z  |dd…ddgf<   |dd…ddgf         |z
  |z  |dd…ddgf<   |}|dd…df         |dd…df         z
  }|dd…df         |dd…df         z
  }|dd…df         |dd…df         z   dz  }	|dd…df         |dd…df         z   dz  }
t          j        |dd…df         |dd…df         |dd…df         |dd…df         |	|
||fd¬	¦  «        }|S )
a§  
    Normalizes bounding box coordinates (x1, y1, x2, y2) and
    calculates center coordinates and dimensions.

    Args:
        bboxes_list (list of list): A list of bounding boxes,
                                     e.g., [[x1, y1, x2, y2], ...].
                                     It is assumed that the coordinates are
                                     in the format (top-left, bottom-right).

    Returns:
        numpy.ndarray: A NumPy array where each row contains the normalized
                       (x1, y1, x2, y2), center coordinates (ctr_x, ctr_y),
                       width (box_w), and height (box_h).
                       Shape: [num_boxes, 8]
    )r   é   ©ÚdtypeNr   é   é   é   ç�íµ ÷Æ°>©r	   )r   ÚemptyÚfloat32ÚarrayÚminr   ÚmaximumÚstack)Úbboxes_listÚ	bbox_dataÚmin_xÚmin_yÚ
cell_box_wÚ
cell_box_hÚboxesÚbox_wÚbox_hÚctr_xÚctr_yÚ
boxes_feats               r   Úget_boxes_transformr5   &   s`  € ð" ð 2ÝŒx˜¥b¤jÐ1Ñ1Ô1Ð1õ ”˜­B¬JÐ7Ñ7Ô7€Ið �a�a�a˜!˜Q˜�iÔ ×$Ò$Ñ&Ô&€Eà�a�a�a˜!˜Q˜�iÔ ×$Ò$Ñ&Ô&€Eð ˜1˜1˜1˜q !˜f˜9Ô%×)Ò)Ñ+Ô+¨eÑ3€Jà˜1˜1˜1˜q !˜f˜9Ô%×)Ò)Ñ+Ô+¨eÑ3€Jõ ”˜J¨Ñ-Ô-€JÝ”˜J¨Ñ-Ô-€Jð & a a a¨!¨Q¨ iÔ0°5Ñ8¸JÑF€Iˆaˆaˆa�!�Q�ˆiÑà% a a a¨!¨Q¨ iÔ0°5Ñ8¸JÑF€Iˆaˆaˆa�!�Q�ˆiÑð €Eð �!�!�!�Q�$ŒK˜%    1 œ+Ñ%€EØ�!�!�!�Q�$ŒK˜%    1 œ+Ñ%€EØ�1�1�1�a�4Œ[˜5    A œ;Ñ&¨!Ñ+€EØ�1�1�1�a�4Œ[˜5    A œ;Ñ&¨!Ñ+€Eõ ”˜5    A œ;¨¨a¨a¨a°¨d¬°U¸1¸1¸1¸a¸4´[À%ÈÈÈÈ1ÈÄ+Ø  %¨°ð7Ø=>ð@ñ @ô @€Jð Ðr   ç333333Ó?ÚbboxÚdist_thresholdÚvertical_gapc           
      ó  ‡‡&— t          | ¦  «        Š&t          j        ‰&t          ¬¦  «        }| dd…df         | dd…df         z   dz  }| dd…df         | dd…df         z   dz  }| dd…df         | dd…df         z
  }t          j        |                     ‰&¦  «                             ‰&df¦  «        j        | dd…df         ||z  z
                       ‰&¦  «                             ‰&df¦  «        k     |                     ‰&¦  «                             ‰&df¦  «        j        | dd…df         ||z  z                        ‰&¦  «                             ‰&df¦  «        k    ¦  «        }t          j        |                     ‰&¦  «                             ‰&df¦  «        j        | dd…df                              ‰&¦  «                             ‰&df¦  «        k     |                     ‰&¦  «                             ‰&df¦  «        j        | dd…df                              ‰&¦  «                             ‰&df¦  «        k    ¦  «        }| dd…df                              ‰&¦  «                             ‰&df¦  «        j        | dd…df                              ‰&¦  «                             ‰&df¦  «        z
  dz  }	| dd…df                              ‰&¦  «                             ‰&df¦  «        j        | dd…df                              ‰&¦  «                             ‰&df¦  «        z
  dz  }
| dd…df                              ‰&¦  «                             ‰&df¦  «        j        | dd…df                              ‰&¦  «                             ‰&df¦  «        z
  dz  }| dd…df                              ‰&¦  «                             ‰&df¦  «        j        | dd…df                              ‰&¦  «                             ‰&df¦  «        z
  dz  }d„ } ||	|
z   ||| dd…df                              ‰&¦  «                             ‰&df¦  «        j        | dd…df                              ‰&¦  «                             ‰&df¦  «        k    ¦  «        } ||	|
z   ||| dd…df                              ‰&¦  «                             ‰&df¦  «        j        | dd…df                              ‰&¦  «                             ‰&df¦  «        k    ¦  «        } |||z   || dd…df                              ‰&¦  «                             ‰&df¦  «        j        | dd…df                              ‰&¦  «                             ‰&df¦  «        k    ¦  «        } |||z   || dd…df                              ‰&¦  «                             ‰&df¦  «        j        | dd…df                              ‰&¦  «                             ‰&df¦  «        k    ¦  «        }t          j        |¦  «        }t          j        || dd…df                              ‰&¦  «                             ‰&df¦  «        j        | dd…df                              ‰&¦  «                             ‰&df¦  «        k    ¦  «        }t          j        ||¦  «        }t          j
        ||<   dˆ&fd
„	}i } ||d¦  «        }||d<    ||d¦  «        }||d<    ||d¦  «        }||d<    ||d¦  «        }||d<    ||d¦  «        }||d<   t          j        |¦  «        }t          j        |¦  «        }t          ‰&¦  «        D ]¤}t          j        ||         ¦  «        t          j
        k    r)t          j
        ||t          j        ||         ¦  «        f<   t          j        ||         ¦  «        t          j
        k    r)t          j
        ||t          j        ||         ¦  «        f<   Œ¥ ||d¦  «        }||d<    ||d¦  «        } | |d<   g }!|                     ¦   «         D ]}"|!                     |"¦  «         Œt!          t#          d„ |!D ¦   «         ¦  «        ¦  «        }#ˆfd„|#D ¦   «         }$t%          |$d„ ¬¦  «        }%|$|fS )aú  
    NOTE (direction-label fix): this function's internal direction names used
    to be swapped -- what was called 'left_dis_matrix' actually finds each
    box's nearest neighbor to its RIGHT, 'right_dis_matrix' actually finds
    the neighbor to its LEFT, 'up_dis_matrix' actually finds the neighbor
    BELOW, and 'down_dis_matrix' actually finds the neighbor ABOVE (verified
    empirically: e.g. for 3 boxes in a row, the matrix named "left" matched
    each box to the one on its right). All of the variable names and
    direction_edges dict keys below have been corrected to match what is
    actually computed. The underlying distance formulas and filter
    conditions are UNCHANGED from before this fix, so the final `edge_index`
    returned by this function (the only thing build_edge_index actually
    uses -- it discards direction_edges) is bit-for-bit identical to before.
    This matters for reproducibility with any model already trained on
    graphs built by the previous version of this function.

    Only the *direction_edges* dict (previously unused by any caller in this
    codebase) is affected in practice: code that starts relying on
    direction_edges['left'] meaning "genuinely left of this node" would have
    silently gotten right-neighbors before this fix.

    Open question, NOT resolved here (see down_neighbor_y_dis_matrix below):
    the y-only-distance matrix historically named 'down_y' reused what was
    then called 'up_dis_matrix's filter condition. Since that matrix's TRUE
    behavior is "find the neighbor below", down_y ends up being a
    y-distance-only variant that's largely redundant with the (corrected)
    down_neighbor_dis_matrix, just with an added x-alignment constraint and
    coarser (y-only, not x+y) ranking. Whether this was an intentional
    distinct signal or a copy-paste of the wrong direction's filter is
    unconfirmed -- flagged for future review rather than changed, since its
    actual behavior (like everything else here) is left untouched by this fix.
    r   Nr   r    r   r   éÿÿÿÿc                 ó˜  — t          j        | ¦  «        }g }t          |¦  «        D ]Q\  }}|�|                     |¦  «         Œ|                     t          j        | j        dt          ¬¦  «        ¦  «         ŒR|s"t          j        | j        dt          ¬¦  «        }nt           j                             |¦  «        }t          j
        ||<   |S )NFr   )r   ÚcopyÚ	enumerateÚappendÚfullÚshapeÚboolÚ
logical_orÚreduceÚmathÚinf)Úbase_distance_matrixÚ
conditionsÚfiltered_matrixÚall_conditionsÚiÚcondÚfilter_masks          r   Úget_filtered_distance_matrixz@get_edge_by_directional_nn.<locals>.get_filtered_distance_matrixª   sÉ   € Ýœ'Ð"6Ñ7Ô7ˆàˆÝ  Ñ,Ô,ð 	^ð 	^‰GˆAˆtØÐØ×%Ò% dÑ+Ô+Ð+Ð+à×%Ò%¥b¤gÐ.BÔ.HÈ%ÕW[Ð&\Ñ&\Ô&\Ñ]Ô]Ð]Ð]àð 	?Ýœ'Ð"6Ô"<¸eÍ4ÐPÑPÔPˆKˆKåœ-×.Ò.¨~Ñ>Ô>ˆKå'+¤xˆ˜Ñ$ØÐr   ÚUnnamedc                 ó¼   •‡‡— t          j        | d¬¦  «        }t          j        | d¬¦  «        Š|t          j        k    Šˆˆfd„t          ‰¦  «        D ¦   «         }|S )Nr   r"   c                 óh   •— g | ].}‰|         ¯
t          |¦  «        t          ‰|         ¦  «        f‘Œ/S © )Úint)Ú.0rK   Úmin_indicesÚ
valid_masks     €€r   ú
<listcomp>zKget_edge_by_directional_nn.<locals>.get_nearest_indices.<locals>.<listcomp>é   s:   ø€ Ð[Ð[Ð[°QÈZÐXYÌ]Ð[•C˜‘F”F�C ¨A¤Ñ/Ô/Ð0Ð[Ð[Ð[r   )r   r&   ÚargminrE   rF   Úrange)Údistance_matrixÚmatrix_nameÚmin_distancesÚindicesrU   rV   Úbbox_nums       @@€r   Úget_nearest_indicesz7get_edge_by_directional_nn.<locals>.get_nearest_indicesä   s`   øøø€ Ýœ˜°QÐ7Ñ7Ô7ˆÝ”i °aÐ8Ñ8Ô8ˆØ"¥d¤hÒ.ˆ
à[Ð[Ð[Ð[Ð[½%À¹/¼/Ð[Ñ[Ô[ˆØˆr   Úleft_neighbor_dis_matrixÚleftÚright_neighbor_dis_matrixÚrightÚup_neighbor_dis_matrixÚupÚdown_neighbor_dis_matrixÚdownÚdown_neighbor_y_dis_matrixÚdown_yÚsecond_down_neighbor_dis_matrixÚsecond_downÚsecond_up_neighbor_dis_matrixÚ	second_upc                 óJ   — g | ] }t          |¦  «        t          |¦  «        f‘Œ!S rR   )r&   r   )rT   Úitems     r   rW   z.get_edge_by_directional_nn.<locals>.<listcomp>  s)   € Ð>Ð>Ð>¨�c�$‰iŒi�˜T™œÐ#Ð>Ð>Ð>r   c                 óX   •— g | ]&}t          |d          |d         z
  ¦  «        ‰k     ¯$|‘Œ'S ©r   r   )Úabs)rT   ro   r8   s     €r   rW   z.get_edge_by_directional_nn.<locals>.<listcomp>  s?   ø€ ð ð ð Øµ°D¸´G¸dÀ1¼gÑ4EÑ0FÔ0FÈÒ0WÐ0WˆÐ0WÐ0WÐ0Wr   c                 ó"   — | d         | d         fS )Nr   r   rR   r   s    r   ú<lambda>z,get_edge_by_directional_nn.<locals>.<lambda>  s   € ÀAÀaÄDÈ!ÈAÌ$À<€ r   )Úkey)rO   )Úlenr   ÚeyerB   rC   ÚrepeatÚreshapeÚTr=   rE   rF   rY   r&   rX   ÚvaluesÚextendÚlistÚsetÚsorted)'r7   r8   r9   Ú
eye_matrixÚcenter_y_boxÚcenter_x_boxÚbbox_heightÚy_center_flagÚx_center_flagÚhor_x_dis_matrixÚhor_y_dis_matrixÚver_x_dis_matrixÚver_y_dis_matrixrN   rb   r`   rf   rd   rh   Ú!_down_neighbor_y_filter_conditionÚdown_neighbor_y_filter_maskr_   Údirection_edgesÚ
left_edgesÚright_edgesÚup_edgesÚ
down_edgesÚdown_y_edgesÚdown_neighbor_dis_matrix_copyÚup_neighbor_dis_matrix_copyrK   Úsecond_down_edgesÚsecond_up_edgesÚall_raw_edgesÚedgesÚori_edge_index_listÚfinal_edge_listÚfinal_edge_list_sortedr^   s'    `                                    @r   Úget_edge_by_directional_nnr›   f   s›	  øø€ õD �4‰yŒy€HÝ”˜­Ð-Ñ-Ô-€Jð ˜˜˜˜A˜”J  a a a¨ d¤Ñ+¨qÑ0€LØ˜˜˜˜A˜”J  a a a¨ d¤Ñ+¨qÑ0€LØ�q�q�q˜!�t”*˜t A A A q DœzÑ)€Kõ ”MØ×Ò˜HÑ%Ô%×-Ò-¨x¸¨nÑ=Ô=Ô?À4ÈÈÈÈ1ÈÄ:ÐP[Ð^jÑPjÑCj×BrÒBrØñCô Cß’g˜x¨˜nÑ-Ô-ò	.à×Ò˜HÑ%Ô%×-Ò-¨x¸¨nÑ=Ô=Ô?À4ÈÈÈÈ1ÈÄ:ÐP[Ð^jÑPjÑCj×BrÒBrØñCô Cß’g˜x¨˜nÑ-Ô-ò	.ñô €Mõ ”MØ×Ò˜HÑ%Ô%×-Ò-¨x¸¨nÑ=Ô=Ô?À$ÀqÀqÀqÈ!ÀtÄ*×BSÒBSÐT\ÑB]ÔB]×BeÒBeÐgoÐqsÐftÑBuÔBuÒuØ×Ò˜HÑ%Ô%×-Ò-¨x¸¨nÑ=Ô=Ô?À$ÀqÀqÀqÈ!ÀtÄ*×BSÒBSÐT\ÑB]ÔB]×BeÒBeÐgoÐqsÐftÑBuÔBuÒuñô €Mð ˜Q˜Q˜Q ˜Tœ
×)Ò)¨(Ñ3Ô3×;Ò;¸XÀr¸NÑKÔKÔMÐPTÐUVÐUVÐUVÐXYÐUYÔPZ×PaÒPaÐbjÑPkÔPk×PsÒPsØ	�2ˆñQô Qñ ØñÐà˜Q˜Q˜Q ˜Tœ
×)Ò)¨(Ñ3Ô3×;Ò;¸XÀr¸NÑKÔKÔMÐPTÐUVÐUVÐUVÐXYÐUYÔPZ×PaÒPaÐbjÑPkÔPk×PsÒPsØ	�2ˆñQô Qñ ØñÐð ˜Q˜Q˜Q ˜Tœ
×)Ò)¨(Ñ3Ô3×;Ò;¸XÀr¸NÑKÔKÔMÐPTÐUVÐUVÐUVÐXYÐUYÔPZ×PaÒPaÐbjÑPkÔPk×PsÒPsØ	�2ˆñQô Qñ ØñÐà˜Q˜Q˜Q ˜Tœ
×)Ò)¨(Ñ3Ô3×;Ò;¸XÀr¸NÑKÔKÔMÐPTÐUVÐUVÐUVÐXYÐUYÔPZ×PaÒPaÐbjÑPkÔPk×PsÒPsØ	�2ˆñQô Qñ ØñÐðð ð ð( !=Ð <ØÐ+Ñ+ØØØˆQˆQˆQ�ˆTŒ
×Ò˜(Ñ#Ô#×+Ò+¨X°r¨NÑ;Ô;Ô=ÀÀaÀaÀaÈÀdÄ×ARÒARÐS[ÑA\ÔA\×AdÒAdÐfnÐprÐesÑAtÔAtÒtñ	!ô !Ðð  <Ð;ØÐ+Ñ+ØØØˆQˆQˆQ�ˆTŒ
×Ò˜(Ñ#Ô#×+Ò+¨X°r¨NÑ;Ô;Ô=ÀÀaÀaÀaÈÀdÄ×ARÒARÐS[ÑA\ÔA\×AdÒAdÐfnÐprÐesÑAtÔAtÒtñ	 ô  Ðð  <Ð;ØÐ+Ñ+ØØˆQˆQˆQ�ˆTŒ
×Ò˜(Ñ#Ô#×+Ò+¨X°r¨NÑ;Ô;Ô=ÀÀaÀaÀaÈÀdÄ×ARÒARÐS[ÑA\ÔA\×AdÒAdÐfnÐprÐesÑAtÔAtÒtñ ô  Ðð :Ð9ØÐ+Ñ+ØØˆQˆQˆQ�ˆTŒ
×Ò˜(Ñ#Ô#×+Ò+¨X°r¨NÑ;Ô;Ô=ÀÀaÀaÀaÈÀdÄ×ARÒARÐS[ÑA\ÔA\×AdÒAdÐfnÐprÐesÑAtÔAtÒtñô Ðõ "$¤Ð)9Ñ!:Ô!:ÐÝ(*¬ØØˆQˆQˆQ�ˆTŒ
×Ò˜(Ñ#Ô#×+Ò+¨X°r¨NÑ;Ô;Ô=ÀÀaÀaÀaÈÀdÄ×ARÒARÐS[ÑA\ÔA\×AdÒAdÐfnÐprÐesÑAtÔAtÒtñ)ô )Ð%õ
 #%¤-Ð0QÐS`Ñ"aÔ"aÐÝ>B¼hÐÐ:Ñ;ðð ð ð ð ð ð €Oà$Ð$Ð%=Ð?YÑZÔZ€JØ(€O�FÑà%Ð%Ð&?ÐA\Ñ]Ô]€KØ*€O�GÑà"Ð"Ð#9Ð;SÑTÔT€HØ$€O�DÑà$Ð$Ð%=Ð?YÑZÔZ€JØ(€O�FÑà&Ð&Ð'AÐC_Ñ`Ô`€LØ ,€O�HÑõ %'¤GÐ,DÑ$EÔ$EÐ!Ý"$¤'Ð*@Ñ"AÔ"AÐõ �8‰_Œ_ð að aˆÝŒ6Ð/°Ô2Ñ3Ô3µt´xÒ?Ð?Ý\`Ô\dÐ)¨!­R¬YÐ7TÐUVÔ7WÑ-XÔ-XÐ*XÑYÝŒ6Ð-¨aÔ0Ñ1Ô1µT´XÒ=Ð=ÝX\ÔX`Ð'¨­2¬9Ð5PÐQRÔ5SÑ+TÔ+TÐ(TÑUøà+Ð+Ð,IÐKlÑmÔmÐØ%6€O�MÑ"à)Ð)Ð*EÐGfÑgÔg€OØ#2€O�KÑ ð €MØ ×'Ò'Ñ)Ô)ð $ð $ˆØ×Ò˜UÑ#Ô#Ð#Ð#õ ÝÐ>Ð>°Ð>Ñ>Ô>Ñ?Ô?ñô Ððð ð ð Ø,ðñ ô €Oõ $ OÐ9OÐ9OÐPÑPÔPÐà˜OÐ+Ð+r   çü©ñÒMbP?é'  Úcenter_limitc           	      ó–  — t          | ¦  «        }|dk     rg S | dd…df         }| dd…df         }| dd…df         }| dd…df         }||z   dz  }||z   dz  }	t          j        |dd…df         |ddd…f         z
  dz  |	dd…df         |	ddd…f         z
  dz  z   ¦  «        }
t          j        ||ft          ¬¦  «        }|||fD ]4}|t          j        |dd…df         |ddd…f         z
  ¦  «        |k    z  }Œ5t          j        ||ft          ¬¦  «        }|||	fD ]4}|t          j        |dd…df         |ddd…f         z
  ¦  «        |k    z  }Œ5|
|k    ||z  z  }t          j        |d¬¦  «        }t          j        |¦  «        \  }}t          t          | 
                    ¦   «         | 
                    ¦   «         ¦  «        ¦  «        S )aj  
    Vectorized (broadcasting-based, matching get_edge_by_directional_nn's
    style). Previously a pure-Python O(N^2) double loop with a per-pair
    `any(...)` generator call -- the only unvectorized edge-construction
    function in this module. Not currently used by build_edge_index's
    default '4D' path (only by the experimental '4D+AL' path, not currently
    active), but fixed for consistency and to remove the latent bottleneck.

    Returns the exact same edge set, in the exact same order, as the
    previous implementation (both iterate implicitly in row-major (i, j)
    order over i < j pairs).
    r   Nr   r   r    r   ©Úk)rv   r   ÚsqrtÚzerosrB   rr   ÚtriuÚnonzeror}   ÚzipÚtolist)r7   r8   rž   r^   ÚleftsÚtopsÚrightsÚbottomsÚ	centers_xÚ	centers_yÚcenter_distÚhor_alignedÚhÚver_alignedÚvÚvalidÚi_idxÚj_idxs                     r   Úget_edge_by_alignmentr¶   "  s  € õ �4‰yŒy€HØ�!‚|€|Øˆ	à����A�ŒJ€EØ����1�Œ:€DØ�!�!�!�Q�$ŒZ€FØ�1�1�1�a�4Œj€Gà˜‘ 1Ñ$€IØ˜‘ 1Ñ$€Iõ ”'Ø	�1�1�1�d�7Ô	˜i¨¨a¨a¨a¨Ô0Ñ	0°QÑ6Ø�Q�Q�Q˜�WÔ 	¨$°°°¨'Ô 2Ñ2°qÑ
8ñ	9ñô €Kõ
 ”(˜H hÐ/µtÐ<Ñ<Ô<€KØ�V˜YÐ'ð Ið IˆØ•r”v˜a    4 œj¨1¨T°1°1°1¨W¬:Ñ5Ñ6Ô6¸.ÒHÑHˆˆå”(˜H hÐ/µtÐ<Ñ<Ô<€KØ�G˜YÐ'ð Ið IˆØ•r”v˜a    4 œj¨1¨T°1°1°1¨W¬:Ñ5Ñ6Ô6¸.ÒHÑHˆˆà˜LÒ(¨[¸;Ñ-FÑG€EÝŒG�E˜QÐÑÔ€Eå”:˜eÑ$Ô$�L€Eˆ5Ý•�E—L’L‘N”N E§L¢L¡N¤NÑ3Ô3Ñ4Ô4Ð4r   Úbboxesr¡   c                 ó®  — | j         d         dk     r t          j        dt          j        ¬¦  «        S t          j        | j         d         df¦  «        }| dd…df         | dd…df         z   dz  |dd…df<   | dd…df         | dd…df         z   dz  |dd…df<   g }t          t          |¦  «        ¦  «        D ]}}t          j        t          j        |||         z
  dz  d¬¦  «        ¦  «        }t          j	        ||<   t          j
        |¦  «        d|…         }|D ]}|                     ||g¦  «         ŒŒ~t          j        |t          j        ¬¦  «        }|S )	aÐ  
    Computes a k-nearest neighbor graph based on the center points of bounding boxes,
    returning the result as a numpy array.

    Args:
        bboxes (np.ndarray): A numpy array of shape (N, 4) where each row is a bounding box
                             in the format [x1, y1, x2, y2].
        k (int): The number of nearest neighbors for each node.

    Returns:
        np.ndarray: A numpy array of shape (E, 2) representing the directed edge_index.
    r   r   )r   r   r   Nr   r    r"   )rA   r   r#   Úint64r£   rY   rv   r¢   r   rF   Úargsortr?   r%   )	r·   r¡   Úcenter_pointsr—   rK   Ú	distancesÚnearest_indicesÚjÚ
edge_indexs	            r   Úget_edge_by_knnrÀ   P  st  € ð „|�A„˜ÒÐÝŒx˜¥b¤hÐ/Ñ/Ô/Ð/õ ”H˜fœl¨1œo¨qÐ1Ñ2Ô2€MØ! ! ! ! Q $œ<¨&°°°°A°¬,Ñ6¸!Ñ;€M�!�!�!�Q�$ÑØ! ! ! ! Q $œ<¨&°°°°A°¬,Ñ6¸!Ñ;€M�!�!�!�Q�$Ñð €Eõ •3�}Ñ%Ô%Ñ&Ô&ð 	!ð 	!ˆå”G�BœF M°MÀ!Ô4DÑ$DÈÑ#JÐQRÐSÑSÔSÑTÔTˆ	å”vˆ	�!‰åœ* YÑ/Ô/°°°Ô3ˆà ð 	!ð 	!ˆAØ�LŠL˜!˜Q˜Ñ Ô Ð Ð ð	!õ ”˜%¥r¤xÐ0Ñ0Ô0€JàÐr   r¿   c                 ó€  — t          |¦  «        dk    r t          j        dt          j        ¬¦  «        S t          j        |¦  «        }| |dd…df                  }| |dd…df                  }d}|dd…df         |dd…df         z
  }|dd…df         |dd…df         z
  }|dd…df         |dd…df         z
  }|dd…df         |dd…df         z
  }	t          j        |dd…df         |dd…df         ¦  «        }
t          j        |dd…df         |dd…df         ¦  «        }t          j        |dd…df         |dd…df         ¦  «        }t          j        |dd…df         |dd…df         ¦  «        }t          j        |
|||gd¬	¦  «        }|dd…df         |dd…df         z
  }|dd…df         |dd…df         z
  }t          j        |dk    ||¦  «        }t          j        |dk    ||¦  «        }t          j        |dk    ||¦  «        }t          j        |	dk    ||	¦  «        }t          j        |dk    ||¦  «        }t          j        |dk    ||¦  «        }g }| 	                    |dd…df         |dd…df         z
  |z  ¦  «         | 	                    |dd…df         |dd…df         z
  |z  ¦  «         | 	                    |dd…df         |dd…df         z
  |z  ¦  «         | 	                    |dd…df         |dd…df         z
  |z  ¦  «         | 	                    t          j
        ||z  ¦  «        ¦  «         | 	                    t          j
        ||z  ¦  «        ¦  «         | 	                    |dd…df         |dd…df         z
  |z  ¦  «         | 	                    |dd…df         |dd…df         z
  |z  ¦  «         | 	                    |dd…df         |dd…df         z
  |z  ¦  «         | 	                    |dd…df         |dd…df         z
  |z  ¦  «         | 	                    t          j
        ||z  ¦  «        ¦  «         | 	                    t          j
        ||z  ¦  «        ¦  «         | 	                    |dd…df         |dd…df         z
  |z  ¦  «         | 	                    |dd…df         |dd…df         z
  |z  ¦  «         | 	                    |dd…df         |dd…df         z
  |z  ¦  «         | 	                    |dd…df         |dd…df         z
  |z  ¦  «         | 	                    t          j
        ||z  ¦  «        ¦  «         | 	                    t          j
        ||z  ¦  «        ¦  «         t          j        |d¬	¦  «        }t          j        |d
dd¬¦  «        }|S )a1  
    Vectorized edge feature computation using NumPy.

    Args:
        bboxes (np.ndarray): (N, 4) array in [x_min, y_min, x_max, y_max] format.
        edge_index (list): (E, 2) list of (src_idx, dst_idx) tuples representing edges.

    Returns:
        np.ndarray: (E, 18) array of edge features.
    r   )r   é   r   Nr   r!   r   r    r"   ç        ç     jø@ç     jøÀ©ÚnanÚposinfÚneginf)rv   r   r#   r$   r%   Úminimumr'   r(   Úwherer?   ÚlogÚ
nan_to_num)r·   r¿   Úedge_index_npÚSÚOÚepsilonÚswÚshÚowÚohÚR_x1ÚR_y1ÚR_x2ÚR_y2ÚRÚrwÚrhÚsafe_swÚsafe_shÚsafe_owÚsafe_ohÚsafe_rwÚsafe_rhÚfeaturesÚ	edge_attrs                            r   Úget_edge_transform_bboxrå   y  s  € õ ˆ:�„˜!ÒÐÝŒx˜¥r¤zÐ2Ñ2Ô2Ð2õ ”H˜ZÑ(Ô(€Mð 	ˆ}˜Q˜Q˜Q ˜TÔ"Ô#€AØˆ}˜Q˜Q˜Q ˜TÔ"Ô#€Aà€Gð 
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	€BØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	€BØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	€BØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	€Bõ Œ:�a˜˜˜˜1˜”g˜q    A œwÑ'Ô'€DÝŒ:�a˜˜˜˜1˜”g˜q    A œwÑ'Ô'€DÝŒ:�a˜˜˜˜1˜”g˜q    A œwÑ'Ô'€DÝŒ:�a˜˜˜˜1˜”g˜q    A œwÑ'Ô'€DÝ
Œ�$˜˜d DÐ)°Ð2Ñ2Ô2€Aà	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	€BØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	€Bõ Œh�r˜Q’w ¨Ñ,Ô,€GÝŒh�r˜Q’w ¨Ñ,Ô,€GÝŒh�r˜Q’w ¨Ñ,Ô,€GÝŒh�r˜Q’w ¨Ñ,Ô,€GÝŒh�r˜Q’w ¨Ñ,Ô,€GÝŒh�r˜Q’w ¨Ñ,Ô,€Gà€Hð ‡O‚O�Q�q�q�q˜!�t”W˜q    A œwÑ&¨'Ñ1Ñ2Ô2Ð2Ø‡O‚O�Q�q�q�q˜!�t”W˜q    A œwÑ&¨'Ñ1Ñ2Ô2Ð2Ø‡O‚O�Q�q�q�q˜!�t”W˜q    A œwÑ&¨'Ñ1Ñ2Ô2Ð2Ø‡O‚O�Q�q�q�q˜!�t”W˜q    A œwÑ&¨'Ñ1Ñ2Ô2Ð2Ø‡O‚O•B”F˜7 WÑ,Ñ-Ô-Ñ.Ô.Ð.Ø‡O‚O•B”F˜7 WÑ,Ñ-Ô-Ñ.Ô.Ð.ð ‡O‚O�Q�q�q�q˜!�t”W˜q    A œwÑ&¨'Ñ1Ñ2Ô2Ð2Ø‡O‚O�Q�q�q�q˜!�t”W˜q    A œwÑ&¨'Ñ1Ñ2Ô2Ð2Ø‡O‚O�Q�q�q�q˜!�t”W˜q    A œwÑ&¨'Ñ1Ñ2Ô2Ð2Ø‡O‚O�Q�q�q�q˜!�t”W˜q    A œwÑ&¨'Ñ1Ñ2Ô2Ð2Ø‡O‚O•B”F˜7 WÑ,Ñ-Ô-Ñ.Ô.Ð.Ø‡O‚O•B”F˜7 WÑ,Ñ-Ô-Ñ.Ô.Ð.ð ‡O‚O�Q�q�q�q˜!�t”W˜q    A œwÑ&¨'Ñ1Ñ2Ô2Ð2Ø‡O‚O�Q�q�q�q˜!�t”W˜q    A œwÑ&¨'Ñ1Ñ2Ô2Ð2Ø‡O‚O�Q�q�q�q˜!�t”W˜q    A œwÑ&¨'Ñ1Ñ2Ô2Ð2Ø‡O‚O�Q�q�q�q˜!�t”W˜q    A œwÑ&¨'Ñ1Ñ2Ô2Ð2Ø‡O‚O•B”F˜7 WÑ,Ñ-Ô-Ñ.Ô.Ð.Ø‡O‚O•B”F˜7 WÑ,Ñ-Ô-Ñ.Ô.Ð.õ ”˜¨Ð*Ñ*Ô*€IÝ”˜i¨S¸ÀTÐJÑJÔJ€IØÐr   c                 óÀ  — t          |¦  «        dk    r t          j        dt          j        ¬¦  «        S t          j        |¦  «        }| |dd…df                  }| |dd…df                  }d}|dd…df         |dd…df         z
  }|dd…df         |dd…df         z
  }|dd…df         |dd…df         z
  }|dd…df         |dd…df         z
  }	t          j        |dd…df         |dd…df         ¦  «        }
t          j        |dd…df         |dd…df         ¦  «        }t          j        |dd…df         |dd…df         ¦  «        }t          j        |dd…df         |dd…df         ¦  «        }t          j        |
|||gd¬	¦  «        }|dd…df         |dd…df         z
  }|dd…df         |dd…df         z
  }g }|                     |dd…df         |dd…df         z
  ||z   z  ¦  «         |                     |dd…df         |dd…df         z
  ||z   z  ¦  «         |                     |dd…df         |dd…df         z
  ||z   z  ¦  «         |                     |dd…df         |dd…df         z
  |	|z   z  ¦  «         |                     t          j	        |||z   z  ¦  «        ¦  «         |                     t          j	        ||	|z   z  ¦  «        ¦  «         |                     |dd…df         |dd…df         z
  ||z   z  ¦  «         |                     |dd…df         |dd…df         z
  ||z   z  ¦  «         |                     |dd…df         |dd…df         z
  ||z   z  ¦  «         |                     |dd…df         |dd…df         z
  ||z   z  ¦  «         |                     t          j	        |||z   z  ¦  «        ¦  «         |                     t          j	        |||z   z  ¦  «        ¦  «         |                     |dd…df         |dd…df         z
  ||z   z  ¦  «         |                     |dd…df         |dd…df         z
  |	|z   z  ¦  «         |                     |dd…df         |dd…df         z
  ||z   z  ¦  «         |                     |dd…df         |dd…df         z
  ||z   z  ¦  «         |                     t          j	        |||z   z  ¦  «        ¦  «         |                     t          j	        |	||z   z  ¦  «        ¦  «         t          j
        |dd…df         |dd…df         z
  ¦  «        d
k                         t          j        ¦  «        }t          j
        |dd…df         |dd…df         z   dz  |dd…df         |dd…df         z   dz  z
  ¦  «        d
k                         t          j        ¦  «        }t          j
        |dd…df         |dd…df         z
  ¦  «        d
k                         t          j        ¦  «        }t          j
        |dd…df         |dd…df         z
  ¦  «        d
k                         t          j        ¦  «        }t          j
        |dd…df         |dd…df         z   dz  |dd…df         |dd…df         z   dz  z
  ¦  «        d
k                         t          j        ¦  «        }t          j
        |dd…df         |dd…df         z
  ¦  «        d
k                         t          j        ¦  «        }|                     |¦  «         |                     |¦  «         |                     |¦  «         |                     |¦  «         |                     |¦  «         |                     |¦  «         t          j        |d¬	¦  «        }t          j        |ddd¬¦  «        }|S )aP  
    Vectorized edge feature computation using NumPy,
    Args:
        bboxes (np.ndarray): (N, 4) NumPy array in [x_min, y_min, x_max, y_max] format.
        edge_index (list): (E, 2) list of tuples, where each tuple (src_idx, dst_idx)

    Returns:
        np.ndarray: (E, 24) array of edge features (18 relation + 6 alignment).
    r   )r   é   r   Nr   g»½×Ùß|Û=r   r    r"   gñhãˆµøä>rÃ   rÄ   rÅ   rÆ   )rv   r   r#   r$   r%   rÊ   r'   r(   r?   rÌ   rr   ÚastyperÍ   )r·   r¿   rÎ   rÏ   rÐ   ÚdeltarÒ   rÓ   rÔ   rÕ   rÖ   r×   rØ   rÙ   rÚ   rÛ   rÜ   rã   Úis_left_alignedÚis_center_alignedÚis_right_alignedÚis_top_alignedÚis_middle_alignedÚis_bottom_alignedrä   s                            r   Ú%get_edge_transform_bbox_add_alignmentrð   Ç  sx  € õ ˆ:�„˜!ÒÐõ Œx˜¥r¤zÐ2Ñ2Ô2Ð2õ ”H˜ZÑ(Ô(€Mð 	ˆ}˜Q˜Q˜Q ˜TÔ"Ô#€AØˆ}˜Q˜Q˜Q ˜TÔ"Ô#€Aà€Eà	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	€BØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	€BØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	€BØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	€Bõ Œ:�a˜˜˜˜1˜”g˜q    A œwÑ'Ô'€DÝŒ:�a˜˜˜˜1˜”g˜q    A œwÑ'Ô'€DÝŒ:�a˜˜˜˜1˜”g˜q    A œwÑ'Ô'€DÝŒ:�a˜˜˜˜1˜”g˜q    A œwÑ'Ô'€DÝ
Œ�$˜˜d DÐ)°Ð2Ñ2Ô2€Aà	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	€BØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	€Bð €Hð ‡O‚O�Q�q�q�q˜!�t”W˜q    A œwÑ&¨2°©:Ñ6Ñ7Ô7Ð7Ø‡O‚OØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	˜r E™zÑ*ñô ð ð ‡O‚O�Q�q�q�q˜!�t”W˜q    A œwÑ&¨2°©:Ñ6Ñ7Ô7Ð7Ø‡O‚OØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	˜r E™zÑ*ñô ð ð ‡O‚O•B”F˜2  e¡Ñ,Ñ-Ô-Ñ.Ô.Ð.Ø‡O‚O•B”F˜2  e¡Ñ,Ñ-Ô-Ñ.Ô.Ð.ð ‡O‚OØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	˜r E™zÑ*ñô ð ð ‡O‚OØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	˜r E™zÑ*ñô ð ð ‡O‚OØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	˜r E™zÑ*ñô ð ð ‡O‚OØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	˜r E™zÑ*ñô ð ð ‡O‚O•B”F˜2  e¡Ñ,Ñ-Ô-Ñ.Ô.Ð.Ø‡O‚O•B”F˜2  e¡Ñ,Ñ-Ô-Ñ.Ô.Ð.ð ‡O‚OØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	˜r E™zÑ*ñô ð ð ‡O‚OØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	˜r E™zÑ*ñô ð ð ‡O‚OØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	˜r E™zÑ*ñô ð ð ‡O‚OØ	
ˆ1ˆ1ˆ1ˆaˆ4Œ�1�Q�Q�Q˜�T”7Ñ	˜r E™zÑ*ñô ð ð ‡O‚O•B”F˜2  e¡Ñ,Ñ-Ô-Ñ.Ô.Ð.Ø‡O‚O•B”F˜2  e¡Ñ,Ñ-Ô-Ñ.Ô.Ð.õ ”v˜a    1 œg¨¨!¨!¨!¨Q¨$¬Ñ/Ñ0Ô0°DÒ8×@Ò@ÅÄÑLÔL€OÝœ  1 1 1 a 4¤¨1¨Q¨Q¨Q°¨T¬7Ñ!2°aÑ 7¸1¸Q¸Q¸QÀ¸T¼7ÀQÀqÀqÀqÈ!ÀtÄWÑ;LÐPQÑ:QÑ QÑRÔRÐVZÒZ×bÒbÕceÔcmÑnÔnÐÝœ˜q    A œw¨¨1¨1¨1¨a¨4¬Ñ0Ñ1Ô1°TÒ9×AÒAÅ"Ä*ÑMÔMÐÝ”f˜Q˜q˜q˜q !˜tœW q¨¨¨¨A¨¤wÑ.Ñ/Ô/°4Ò7×?Ò?ÅÄ
ÑKÔK€NÝœ  1 1 1 a 4¤¨1¨Q¨Q¨Q°¨T¬7Ñ!2°aÑ 7¸1¸Q¸Q¸QÀ¸T¼7ÀQÀqÀqÀqÈ!ÀtÄWÑ;LÐPQÑ:QÑ QÑRÔRÐVZÒZ×bÒbÕceÔcmÑnÔnÐÝœ  ! ! ! Q $¤¨!¨A¨A¨A¨q¨D¬'Ñ 1Ñ2Ô2°dÒ:×BÒBÅ2Ä:ÑNÔNÐà‡O‚O�OÑ$Ô$Ð$Ø‡O‚OÐ%Ñ&Ô&Ð&Ø‡O‚OÐ$Ñ%Ô%Ð%Ø‡O‚O�NÑ#Ô#Ð#Ø‡O‚OÐ%Ñ&Ô&Ð&Ø‡O‚OÐ%Ñ&Ô&Ð&õ ”˜¨Ð*Ñ*Ô*€IÝ”˜i¨S¸ÀTÐJÑJÔJ€IØÐr   Tc                 óZ  — d}g d¢}|€Ìd}| D ]_}||v r||z  }Œ|                      ¦   «         r|dz  }Œ&|                     ¦   «         r|dz  }Œ@|                     ¦   «         s|dz  }ŒZ|dz  }Œ`d}d}d}	t          |¦  «        D ]8\  }
}|
d	k    r||z  }n%||k    r|	dz  }	Œ|t	          |	¦  «        z  }||z  }d}	|}Œ9|dk    r|t	          |	¦  «        z  }|}|�rSg }|D ]ê}|                     ¦   «         r#|                     t          |¦  «        ¦  «         Œ9|dk    r|                     d
¦  «         ŒU|dk    r|                     d¦  «         Œq|dk    r|                     d¦  «         Œ�|dk    r|                     d¦  «         Œ©||v r,|                     d|                     |¦  «        z   ¦  «         ŒÙt          d|› �¦  «        ‚d„ |D ¦   «         }dg|z  }d	}|D ]K}|D ]1}t          |¦  «        dz  ||<   |dz  }|t          |¦  «        k    r nŒ2|t          |¦  «        k    r nŒL|S |S )Né(   )u   â€¢ú-Ú*ú+ú<ú>ú(ú)u   â†’u   âœ“ú#u   â–¡u   â– u   â€£u   â—¦u   â–ªú.ú:u   â€»Ú rý   ÚWÚDrÏ   ÚCr   r   é
   é   é   é   é   zInvalid pattern character: c                 ó.   — g | ]}t          |d ¦  «        ‘ŒS )Ú02o)Úformat)rT   r²   s     r   rW   z$get_text_pattern.<locals>.<listcomp>n  s"   € Ð4Ð4Ð4¨•6˜!˜UÑ#Ô#Ð4Ð4Ð4r   rÃ   r   )
ÚisspaceÚisdigitÚisalnumr>   Ústrr?   rS   ÚindexÚ	Exceptionrv   )ÚtextÚtext_patternÚreturn_vectorÚmax_lenÚsymbolsÚpatternÚcÚcompressed_patternÚprev_cÚprev_repeatÚc_idxÚvectorÚencodedÚencoded_vectorÚcur_idxÚcodes                   r   Úget_text_patternr  9  sô  € Ø€Gð Dð  Dð  D€GØÐØˆØð 
	ð 
	ˆAØ�Gˆ|ˆ|Ø˜1‘��Ø—’‘”ð Ø˜3‘��Ø—’‘”ð Ø˜3‘��Ø—Y’Y‘[”[ð Ø˜3‘��à˜3‘��àÐØˆØˆÝ! 'Ñ*Ô*ð 	ð 	‰HˆE�1Ø˜ŠzˆzØ" aÑ'Ð"Ð"à˜Q’;�;Ø 1Ñ$�KØà&­#¨kÑ*:Ô*:Ñ:Ð&Ø&¨!Ñ+Ð&Ø"#�KØˆFˆFØ�RŠ<ˆ<Ø¥# kÑ"2Ô"2Ñ2ÐØ)ˆàñ ØˆØð 	Cð 	CˆAØ�yŠy‰{Œ{ð CØ—’�c !™fœfÑ%Ô%Ð%Ð%Ø�c’�Ø—’˜bÑ!Ô!Ð!Ð!Ø�c’�Ø—’˜bÑ!Ô!Ð!Ð!Ø�c’�Ø—’˜bÑ!Ô!Ð!Ð!Ø�c’�Ø—’˜bÑ!Ô!Ð!Ð!Ø�g��Ø—’˜b 7§=¢=°Ñ#3Ô#3Ñ3Ñ4Ô4Ð4Ð4åÐ A¸aÐ AÐ AÑBÔBÐBØ4Ð4¨VÐ4Ñ4Ô4ˆØ˜ ™ˆØˆØð 	ð 	ˆDØð ð �Ý*-¨a©&¬&°1©*�˜wÑ'Ø˜1‘�Ø�c .Ñ1Ô1Ò1Ð1Ø�Eð 2à�#˜nÑ-Ô-Ò-Ð-Ø�ð .àÐàÐr   c                 óæ   — t          j        | | ft           j        ¬¦  «        }|\  }}t          t	          |¦  «        ¦  «        D ],}t          ||         ¦  «        |||                  ||         <   Œ-|S )uq  
    edge_indexì™€ edge_labelì�„ ì‚¬ìš©í•˜ì—¬ n x n ê·¼ì ‘ì�´ì›ƒ í–‰ë ¬ì�„ ë°˜í™˜í•©ë‹ˆë‹¤.

    Args:
      edge_index: ì—°ê²°ì�˜ ì�¸ë�±ìŠ¤ë¥¼ ë‚˜íƒ€ë‚´ëŠ” 2D ë¦¬ìŠ¤íŠ¸.
      edge_label: ì—°ê²° ë ˆì�´ë¸”ì�„ ë‚˜íƒ€ë‚´ëŠ” 1D ë¦¬ìŠ¤íŠ¸. 1ì�€ ì—°ê²°ì�´ ìžˆì�Œì�„, 0ì�€ ì—°ê²°ì�´ ì—†ì�Œì�„ ì�˜ë¯¸í•©ë‹ˆë‹¤.

    Returns:
      n x n ê·¼ì ‘ì�´ì›ƒ í–‰ë ¬ (numpy array).
    r   )r   r£   r¹   rY   rv   rS   )Únum_noder¿   Ú
edge_labelÚ
adj_matrixÚrowÚcolrK   s          r   Úget_edge_matrixr&  }  so   € õ ”˜8 XÐ.µb´hÐ?Ñ?Ô?€Jà�H€CˆÝ•3�s‘8”8‰_Œ_ð 8ð 8ˆÝ%(¨°A¬Ñ%7Ô%7ˆ
�3�q”6Ô˜3˜qœ6Ñ"Ð"àÐr   Ú	num_nodesc                 óB   — t          j        | t           j        ¬¦  «        S )zCInitialize Union-Find parent array where each node is its own root.r   )r   Úaranger¹   )r'  s    r   Ú_make_union_findr*  ‘  s   € åŒ9�Y¥b¤hÐ/Ñ/Ô/Ð/r   Úparentc                 óh   — | |         |k    r%| | |                  | |<   | |         }| |         |k    °%|S )z Find root with path compression.rR   )r+  r   s     r   Ú_findr-  –  s@   € à
�Œ)�qŠ.ˆ.Ø˜6 !œ9Ô%ˆˆq‰	Ø�1ŒIˆð �Œ)�qŠ.ˆ.ð €Hr   Úyc                 ó`   — t          | |¦  «        t          | |¦  «        }}||k    r|| |<   dS dS )z&Union two sets by linking their roots.N)r-  )r+  r   r.  ÚrxÚrys        r   Ú_unionr2  ž  s<   € å�6˜1ÑÔ�u V¨QÑ/Ô/ˆ€BØ	ˆR‚x€xØˆˆr‰
ˆ
ˆ
ð €xr   ÚrowsÚcolsc                 ó¢  — t          | ¦  «        }t          |                     ¦   «         |                     ¦   «         ¦  «        D ]\  }}t          |||¦  «         Œi }t	          j        | t          j        ¬¦  «        }t          | ¦  «        D ]3}t          ||¦  «        }	|	|vrt          |¦  «        ||	<   ||	         ||<   Œ4|t          |¦  «        fS )z½
    Find connected components via Union-Find.

    Returns:
        labels : (N,) array where labels[i] is the component id of node i
        n_components : total number of components
    r   )
r*  r¦   r§   r2  r   r#   r¹   rY   r-  rv   )
r'  r3  r4  r+  r   r.  Úroot_to_compÚlabelsrK   Úroots
             r   Úgraph_connected_componentsr9  ¤  sÖ   € õ ˜iÑ(Ô(€Få�D—K’K‘M”M 4§;¢;¡=¤=Ñ1Ô1ð ð ‰ˆˆ1Ýˆv�q˜!ÑÔÐÐð €LÝŒX�i¥r¤xÐ0Ñ0Ô0€FÝ�9ÑÔð 'ð 'ˆÝ�V˜QÑÔˆØ�|Ð#Ð#Ý!$ \Ñ!2Ô!2ˆL˜ÑØ  Ô&ˆˆq‰	ˆ	à•3�|Ñ$Ô$Ð$Ð$r   Únode_clsÚ
node_scoreÚedge_matrixÚlabel_priority_listc                 ó   — t          | ¦  «        }t          |¦  «        |k    st          |¦  «        |k    rt          d¦  «        ‚t          j        |t          j        ¬¦  «        }t          j        |d¬¦  «                             t          ¦  «        }t          j        |¦  «        \  }}	t          |||	¦  «        \  }
}|dk    r$t          |                      ¦   «         ¦  «        dz   nd}t          |t          |¦  «        dz   ¦  «        }t          j        |t          j        ¬¦  «        }t          |¦  «        D ]\  }}||k     r|||<   Œg }t          |¦  «        D �]ñ}d}|
|k    }t          j        |¦  «        d                              ¦   «         }| |         }t          j        |t          |                     ¦   «         ¦  «        dz   ¬¦  «        }|                     ¦   «         }t          j        ||k    ¦  «        d         }t          |¦  «        dk    rt          |d         ¦  «        }n3||         }|t          j        |¦  «                 }t          |¦  «        }|}t          |¦  «        dk    rg d	¢}nº||         }t'          |d
d
…df                              ¦   «         ¦  «        }t'          |d
d
…df                              ¦   «         ¦  «        } t'          |d
d
…df                              ¦   «         ¦  «        }!t'          |d
d
…df                              ¦   «         ¦  «        }"|| |!|"g}|                     ||||dœ¦  «         �Œó|S )a}  
    Drop-in replacement for the NetworkX-based implementation using pure numpy.
    No scipy dependency ? connected components are found via Union-Find.

    Optimizations over the original:
        1. O(N^2) double for loop -> np.triu + np.where (vectorized edge extraction)
        2. NetworkX connected_components -> Union-Find (no external dependency)
        3. bbox min/max -> np.min/max on masked array slice (vectorized)
        4. majority vote + priority tie-break -> np.bincount + priority lookup array
        5. tie_class reset per group (bug fix from original)

    Args / Returns: identical to the original function.
    zLbboxes and node_score must have the same length as node_cls and edge_matrix.r   r   r    r   )Ú
fill_valuer;   )Ú	minlength)rÃ   rÃ   rÃ   rÃ   Nr   r    )ÚindiciesÚgroup_classÚ
group_bboxÚ	tie_class)rv   Ú
ValueErrorr   r%   r$   r¤   rè   rB   rË   r9  rS   r   r@   rF   r>   rY   r§   ÚbincountrX   Úfloatr&   r?   )#r:  r;  r<  r·   r=  r'  Ú
bboxes_arrÚupperr3  r4  r7  Ún_componentsÚmax_clsÚlookup_sizeÚpriority_lookupÚpriorityÚcls_idÚgroupsÚcomp_idrD  Úmaskr]   Úcomp_clsÚcountsÚ	max_countÚtiedrB  Útied_prioritiesÚbestrC  Úcomp_bboxesÚx1Úy1Úx2Úy2s#                                      r   Úgroup_node_by_edger^  ½  s.  € õ( �H‘”€Iå
ˆ6�{„{�iÒÐ¥3 z¡?¤?°iÒ#?Ð#?ÝÐgÑhÔhÐhå”˜&­¬
Ð3Ñ3Ô3€Jõ
 ŒG�K 1Ð%Ñ%Ô%×,Ò,­TÑ2Ô2€EÝ”˜%‘”�J€Dˆ$õ
 6°iÀÀtÑLÔLÑ€FˆLð *3°Qª¨�c�(—,’,‘.”.Ñ!Ô! AÑ%Ð%¸A€GÝ�g�sÐ#6Ñ7Ô7¸!Ñ;Ñ<Ô<€KÝ”g˜kµb´fÐ=Ñ=Ô=€OÝ%Ð&9Ñ:Ô:ð /ð /Ñˆ�&Ø�KÒÐØ&.ˆO˜FÑ#øð
 €Få˜Ñ&Ô&ð &ñ &ˆàˆ	à˜Ò ˆÝ”(˜4‘.”. Ô#×*Ò*Ñ,Ô,ˆð ˜D”>ˆÝ”˜Xµ°X·\²\±^´^Ñ1DÔ1DÀqÑ1HÐIÑIÔIˆØ—J’J‘L”Lˆ	ÝŒx˜ )Ò+Ñ,Ô,¨QÔ/ˆåˆt‰9Œ9˜Š>ˆ>Ý˜d 1œg™,œ,ˆKˆKð .¨dÔ3ˆOØ�œ	 /Ñ2Ô2Ô3ˆDÝ˜d™)œ)ˆKØ#ˆIõ ˆw‰<Œ<˜1ÒÐØ-Ð-Ð-ˆJˆJà$ TÔ*ˆKÝ�{ 1 1 1 a 4Ô(×,Ò,Ñ.Ô.Ñ/Ô/ˆBÝ�{ 1 1 1 a 4Ô(×,Ò,Ñ.Ô.Ñ/Ô/ˆBÝ�{ 1 1 1 a 4Ô(×,Ò,Ñ.Ô.Ñ/Ô/ˆBÝ�{ 1 1 1 a 4Ô(×,Ò,Ñ.Ô.Ñ/Ô/ˆBØ˜b " bÐ)ˆJà�ŠØØ&Ø$Ø"ð	
ð 
ñ 	ô 	ð 	ñ 	ð €Mr   r   Frã   Ú
page_widthÚpage_heightÚroi_align_output_sizeÚapply_softmaxÚconcat_mean_maxÚadd_uncertaintyc                 óÚ  — | j         dk    sJ d| j        › �¦   «         ‚| j        \  }}	}
}|dk    s
J d¦   «         ‚| d         }|}|dk    s
J d¦   «         ‚|r}|                     |	d¦  «        }||                     dd¬	¦  «        z
  }t	          j        ||¬
¦  «         |                     dd¬	¦  «        dz   }||z                       |	|
|¦  «        }|}n||}|                     |	d¦  «        }||                     dd¬	¦  «        z
  }t	          j        ||¬
¦  «         |                     dd¬	¦  «        dz   }||z                       |	|
|¦  «        }|r|	dz  n|	}||rdndz   }t	          j        t          |¦  «        |ft          j	        ¬¦  «        }dt          j
        dt          dt          dt          j
        fd„}t          |¦  «        D �] \  }\  }}}}|t          |¦  «        z  }|
t          |¦  «        z  }||z  ||z  } }||z  ||z  }"}!|!|z
  }#|"| z
  }$|#|z  }%|$|z  }&g }'t          |¦  «        D ]A}(| |(dz   |&z  z   })t          |¦  «        D ]$}*||*dz   |%z  z   }+|'                     |+|)f¦  «         Œ%ŒB|'sŒ­g },g }-|'D ]K\  }.}/ |||.|/¦  «        }0|,                     |0¦  «         |r" |||.|/¦  «        }1|-                     |1¦  «         ŒLt	          j        |,d¬¦  «        }2|2                     d¬¦  «        }3|r/|2                     d¬¦  «        }4t	          j        |3|4gd¬¦  «        }5n|3}5|�rt	          j        |-d¬¦  «        }6d}7|6t	          j        |6|7z   ¦  «        z                       d¬¦  «         }8|8                     ¦   «         }9|6j        \  }:};t	          j        |6dd¬¦  «        dd…         }<t	          j        |6|<d¬¦  «        }=|=                     d¬¦  «         |=d         |=d         z
  }>|>                     ¦   «         }?t	          j        |5t	          j        |9|?gt          j	        ¬¦  «        gd¬¦  «        }5|5                     t          j	        ¦  «        ||d|5j        d         …f<   �Œ¢|S )aI  
    Extract per-bbox features with RoIAlign-like sampling and mean/max pooling,
    and uncertainty metrics. This version uses bilinear interpolation for
    more accurate feature extraction.

    Args:
        features (np.ndarray): Feature map tensor (N, C, H, W). Typically N=1.
        bboxes (List[Tuple[float, float, float, float]]): Boxes (x1, y1, x2, y2)
            defined on the same coordinate system as page_width/page_height.
        page_width (int): Width of the image used to produce 'features'.
        page_height (int): Height of the image used to produce 'features'.
        roi_align_output_size (int): The target height and width (P) for the
            sampled feature map (P x P). Default is 7.
        apply_softmax (bool): If True, apply channel-wise softmax per spatial location.
        concat_mean_max (bool): If True, output [mean; max] -> 2C dims; else only mean -> C dims.
        add_uncertainty (bool): If True, append entropy_mean and margin_mean -> +2 dims.

    Returns:
        np.ndarray: Shape (len(bboxes), C or 2C plus optional +2 for uncertainty).
    é   z features must be (N,C,H,W), got r   zOnly batch size 1 is supported.r   z1roi_align_output_size must be a positive integer.r;   Tr   )Úoutgê-�™—q=r   r   Úfeature_mapr   r.  r
   c                 ób  — | j         \  }}}t          j        |d|dz
  dz
  ¦  «        }t          j        |d|dz
  dz
  ¦  «        }t          t          j        |¦  «        ¦  «        t          t          j        |¦  «        ¦  «        }}|dz   |dz   }	}||z
  }
||z
  }t          j        |d|dz
  ¦  «        }t          j        |	d|dz
  ¦  «        }	| dd…||f         }| dd…||f         }| dd…|	|f         }| dd…|	|f         }|d|
z
  z  d|z
  z  ||
z  d|z
  z  z   |d|
z
  z  |z  z   ||
z  |z  z   }|S )zÄ
        Perform bilinear interpolation on the feature map at fractional coordinates (x, y).
        The feature map is (C, H, W). Coordinates are 0-indexed, ranging from 0 to W-1 or H-1.
        r   r   r!   N)rA   r   ÚcliprS   Úfloor)rh  r   r.  ÚC_fÚH_fÚW_fÚx0Úy0rZ  r[  ÚdxÚdyÚf00Úf10Úf01Úf11Ú
interp_vals                    r   Úbilinear_interpolatez@extract_bbox_features_by_roi_align.<locals>.bilinear_interpolate\  s{  € ð
 $Ô)‰ˆˆS�#õ ŒG�A�q˜# ™' D™.Ñ)Ô)ˆÝŒG�A�q˜# ™' D™.Ñ)Ô)ˆõ •R”X˜a‘[”[Ñ!Ô!¥3¥r¤x°¡{¤{Ñ#3Ô#3ˆBˆØ�a‘˜˜a™ˆBˆð �‰VˆØ�‰Vˆõ ŒW�R˜˜C !™GÑ$Ô$ˆÝŒW�R˜˜C !™GÑ$Ô$ˆð ˜!˜!˜!˜R ˜)Ô$ˆØ˜!˜!˜!˜R ˜)Ô$ˆØ˜!˜!˜!˜R ˜)Ô$ˆØ˜!˜!˜!˜R ˜)Ô$ˆð �q˜2‘v‘ ! b¡&Ñ)Ø�b‘˜A ™FÑ#ñ$à�q˜2‘v‘ Ñ#ñ$ð �b‘˜2‘ñð 	ð Ðr   ç      à?r"   éþÿÿÿN)ÚndimrA   ry   r   r   r   r   r£   rv   r$   ÚndarrayrG  r>   rY   r?   r(   ÚmeanÚconcatenaterÌ   ÚargpartitionÚtake_along_axisÚsortr%   rè   )@rã   r·   r_  r`  ra  rb  rc  rd  ÚNr   ÚHrþ   ÚfmapÚPÚfÚdenomÚprobsÚ	fmap_usedÚgÚdenom_gÚbase_dimÚout_dimrg  rx  rK   rZ  r[  r\  r]  Úscale_xÚscale_yÚfx1Úfy1Úfx2Úfy2Ú	roi_widthÚ
roi_heightÚ
bin_size_xÚ
bin_size_yÚsample_pointsÚp_yÚy_centerÚp_xÚx_centerÚsampled_featuresÚsampled_probsÚsxÚsyÚinterp_featÚinterp_probÚ
patch_featÚmean_vecÚmax_vecÚpooledÚ
patch_probÚepsÚent_map_flatÚentropy_meanÚC_Únum_samplesÚidx_partÚtop_twoÚmarginsÚmargin_means@                                                                   r   Ú"extract_bbox_features_by_roi_alignr±    s0  € ð> Œ=˜AÒÐÐÐRÀ(Ä.ÐRÐRÑÔÐØ”�J€A€qˆ!ˆQØ�Š6ˆ6ˆ6Ð4‰6Œ6ˆ6Ø�AŒ;€Dð 	€AØ�Š6ˆ6ˆ6ÐF‰6Œ6ˆ6ð ð /à�LŠL˜˜BÑÔˆØ�—’˜1 t�Ñ,Ô,Ñ,ˆÝ
Œˆq�aÐÑÔÐØ—’˜1 t�Ñ,Ô,¨uÑ4ˆØ�U‘×#Ò# A q¨!Ñ,Ô,ˆØˆ	ˆ	àˆ	à�LŠL˜˜BÑÔˆØ�—’˜1 t�Ñ,Ô,Ñ,ˆÝ
Œˆq�aÐÑÔÐØ—%’%˜Q¨�%Ñ.Ô.°Ñ6ˆØ�W‘×%Ò% a¨¨AÑ.Ô.ˆð (Ð.ˆq�1‰uˆu¨Q€HØ˜Ð5˜!˜!°AÑ6€GÝ
Œ(•C˜‘K”K Ð)µ´Ð
<Ñ
<Ô
<€Cð$­"¬*ð $½ð $Å5ð $ÍRÌZð $ð $ð $ð $õN  )¨Ñ0Ô0ð O=ñ O=ÑˆÑˆB��B˜à•e˜JÑ'Ô'Ñ'ˆØ•e˜KÑ(Ô(Ñ(ˆà˜‘<  g¡ˆSˆØ˜‘<  g¡ˆSˆà˜#‘Iˆ	Ø˜3‘Yˆ
ð  ‘]ˆ
Ø !‘^ˆ
àˆÝ˜‘8”8ð 	;ð 	;ˆCØ˜c C™i¨:Ñ5Ñ5ˆHÝ˜Q‘x”xð ;ð ;�Ø #¨¡)¨zÑ!9Ñ9�Ø×$Ò$ h°Ð%9Ñ:Ô:Ð:Ð:ð;ð ð 	Øð ÐØˆà#ð 	2ð 	2‰FˆB�à.Ð.¨y¸"¸bÑAÔAˆKØ×#Ò# KÑ0Ô0Ð0ð ð 2Ø2Ð2°5¸"¸bÑAÔA�Ø×$Ò$ [Ñ1Ô1Ð1øõ ”XÐ.°QÐ7Ñ7Ô7ˆ
ð
 —?’?¨�?Ñ*Ô*ˆàð 	Ø —n’n¨!�nÑ,Ô,ˆGÝ”^ X¨wÐ$7¸aÐ@Ñ@Ô@ˆFˆFàˆFð ñ 	oÝœ -°aÐ8Ñ8Ô8ˆJð ˆCØ'­"¬&°¸cÑ1AÑ*BÔ*BÑB×GÒGÈQÐGÑOÔOÐOˆLØ'×,Ò,Ñ.Ô.ˆLð )Ô.‰OˆB�õ ” z°2¸AÐ>Ñ>Ô>¸r¸s¸sÔCˆHåÔ(¨°XÀAÐFÑFÔFˆGà�LŠL˜aˆLÑ Ô Ð ð ˜a”j 7¨1¤:Ñ-ˆGØ!Ÿ,š,™.œ.ˆKõ ”^ V­R¬X°|À[Ð6QÕY[ÔYcÐ-dÑ-dÔ-dÐ$eÐlmÐnÑnÔnˆFà#)§=¢=µ´Ñ#<Ô#<ˆˆAÐ�”˜Q”ÐÐÑ Ñ à€Jr   ÚimageÚnew_sizec                 óŽ  — | j         dd…         \  }}|\  }}t          j        |¦  «        dz   ||z  z  dz
  }t          j        |¦  «        dz   ||z  z  dz
  }t          j        |¦  «                             t
          ¦  «        }t          j        |¦  «                             t
          ¦  «        }	t          j        |dz   d|dz
  ¦  «        }
t          j        |	dz   d|dz
  ¦  «        }||z
  ddd…f         }||	z
  dd…df         }t          j        |d|dz
  ¦  «        }t          j        |	d|dz
  ¦  «        }	| j        dk    ry| |	dd…df         |ddd…f         f         }| |	dd…df         |
ddd…f         f         }| |dd…df         |ddd…f         f         }| |dd…df         |
ddd…f         f         }nl| t          j        |	|¦  «                 }| t          j        |	|
¦  «                 }| t          j        ||¦  «                 }| t          j        ||
¦  «                 }d|z
  d|z
  z  }|d|z
  z  }d|z
  |z  }||z  }| j        dk    r/|d         |z  |d         |z  z   |d         |z  z   |d         |z  z   n||z  ||z  z   ||z  z   ||z  z   }t          j        |dd¦  «                             | j	        ¦  «        S )	aS  
    Resize an image using bilinear interpolation with numpy (vectorized).
    Equivalent to cv2.resize(..., INTER_LINEAR).

    Parameters
    ----------
    image : np.ndarray
        Input image (H, W) or (H, W, C).
    new_size : tuple
        (new_width, new_height)

    Returns
    -------
    np.ndarray
        Resized image.
    Nr   ry  r   r   r    ).Néÿ   )
rA   r   r)  rk  rè   rS   rj  r{  Úix_r   )r²  r³  r°   ÚwÚnew_wÚnew_hr   r.  ro  rp  rZ  r[  rq  rr  ÚIaÚIbÚIcÚIdÚwaÚwbÚwcÚwdrg  s                          r   Úresize_imagerÂ  Ö  sû  € ð" Œ;�r˜�rŒ?�D€A€qØ�L€Eˆ5õ 
Œ�5Ñ	Ô	˜CÑ	 A¨¡IÑ.°Ñ4€AÝ	Œ�5Ñ	Ô	˜CÑ	 A¨¡IÑ.°Ñ4€Aå	Œ�!‰Œ×	Ò	�CÑ	 Ô	 €BÝ	Œ�!‰Œ×	Ò	�CÑ	 Ô	 €BÝ	Œ��a‘˜˜A ™EÑ	"Ô	"€BÝ	Œ��a‘˜˜A ™EÑ	"Ô	"€Bà
ˆb‰&�$˜˜˜�'Ô	€BØ
ˆb‰&�!�!�!�T�'Ô	€Bõ 
Œ��Q˜˜A™Ñ	Ô	€BÝ	Œ��Q˜˜A™Ñ	Ô	€Bà„z�Q‚€à�2�a�a�a˜�g”;  4¨¨¨ 7¤Ð+Ô,ˆØ�2�a�a�a˜�g”;  4¨¨¨ 7¤Ð+Ô,ˆØ�2�a�a�a˜�g”;  4¨¨¨ 7¤Ð+Ô,ˆØ�2�a�a�a˜�g”;  4¨¨¨ 7¤Ð+Ô,ˆˆà•2”6˜"˜b‘>”>Ô"ˆØ•2”6˜"˜b‘>”>Ô"ˆØ•2”6˜"˜b‘>”>Ô"ˆØ•2”6˜"˜b‘>”>Ô"ˆð ˆb‰&�Q˜‘VÑ	€BØ	ˆq�2‰v‰€BØ
ˆb‰&�B‰€BØ	ˆb‰€Bð 8=´zÀQ²°ð ˆiŒ=˜2Ñ  9¤°Ñ 2Ñ2ØˆiŒ=˜2ÑñØ " 9¤°Ñ 2ñ3ð 3à	ˆb‰�2˜‘7Ñ	˜R "™WÑ	$ r¨B¡wÑ	.ð õ Œ7�3˜˜3ÑÔ×&Ò& u¤{Ñ3Ô3Ð3r   c                 óè  — | j         dk    s| j        d         dk    rt          d¦  «        ‚| dd…dd…df                              t          j        ¦  «        }| dd…dd…df                              t          j        ¦  «        }| dd…dd…df                              t          j        ¦  «        }d|z  d|z  z   d	|z  z   }t	          j        |dd
¦  «                             t          j        ¦  «        S )a0  
    Convert a BGR image to grayscale using numpy only.
    Equivalent to cv2.cvtColor(image, cv2.COLOR_BGR2GRAY).

    Parameters
    ----------
    image : np.ndarray
        Input image in BGR format, shape (H, W, 3).

    Returns
    -------
    np.ndarray
        Grayscale image, shape (H, W).
    r    r   z/Input must be a BGR image with shape (H, W, 3).Nr   r   gÉv¾Ÿ/½?gbX9´Èâ?g‰A`åÐ"Ó?rµ  )r{  rA   rE  rè   r   r$   rj  Úuint8)r²  ÚBÚGrÚ   Úgrays        r   Úto_grayrÈ    sè   € ð „z�Q‚€˜%œ+ aœ.¨AÒ-Ð-ÝÐJÑKÔKÐKð 	ˆaˆaˆa����AˆgŒ×Ò�bœjÑ)Ô)€AØˆaˆaˆa����AˆgŒ×Ò�bœjÑ)Ô)€AØˆaˆaˆa����AˆgŒ×Ò�bœjÑ)Ô)€Að �1‰9�u˜q‘yÑ  5¨1¡9Ñ,€Dõ Œ7�4˜˜CÑ Ô ×'Ò'­¬Ñ1Ô1Ð1r   c                 óî  — t          | d         |d         ¦  «        }t          | d         |d         ¦  «        }t          | d         |d         ¦  «        }t          | d         |d         ¦  «        }t          d||z
  ¦  «        }t          d||z
  ¦  «        }||z  }| d         | d         z
  | d         | d         z
  z  }	|d         |d         z
  |d         |d         z
  z  }
|	|
z   |z
  }|dk    r||z  ndS )Nr   r   r   r    )r   r&   )Úbox1Úbox2Úxi1Úyi1Úxi2Úyi2Úinter_widthÚinter_heightÚ
inter_areaÚ	box1_areaÚ	box2_areaÚ
union_areas               r   Úcompute_iourÖ  1  sý   € å
ˆd�1Œg�t˜A”wÑ
Ô
€CÝ
ˆd�1Œg�t˜A”wÑ
Ô
€CÝ
ˆd�1Œg�t˜A”wÑ
Ô
€CÝ
ˆd�1Œg�t˜A”wÑ
Ô
€CÝ�a˜˜s™Ñ#Ô#€KÝ�q˜# ™)Ñ$Ô$€LØ˜|Ñ+€Jà�a”˜4 œ7Ñ" t¨A¤w°°a´Ñ'8Ñ9€IØ�a”˜4 œ7Ñ" t¨A¤w°°a´Ñ'8Ñ9€IØ˜YÑ&¨Ñ3€Jà&0°1¢n nˆ:˜
Ñ"Ð"¸!Ð;r   r   r  c           	      ó  — ddl }|dvrt          d¦  «        ‚|                     | ||j        ¬¦  «        \  }}}}g }t	          d|¦  «        D ]¸}t          |||j        f         ¦  «        }	|	|k     rŒ%t          |||j        f         ¦  «        }
t          |||j        f         ¦  «        }t          |||j	        f         ¦  «        }t          |||j
        f         ¦  «        }|                     |||
||z   |
|z   f|	dœ¦  «         Œ¹|S )ag  
    Find connected components in a binary mask and return their bounding boxes.

    Replaces the previous two-step pipeline:
        segmentation_connected_components()  (Python BFS)
        _get_bboxes_from_labeled_image()     (np.argwhere per label)

    Both steps are now handled by cv2.connectedComponentsWithStats in a single
    C++ call, which is ~100x faster than the Python BFS and eliminates the
    O(N * num_labels) argwhere scans.

    Args:
        binary_mask (np.ndarray): 2D uint8 array with 0 (background) and 1 (foreground).
        connectivity (int): 4 or 8.
        min_area_threshold (int): Components smaller than this pixel count are ignored.

    Returns:
        list[dict]: Each dict has keys 'label', 'bbox' (min_row, min_col, max_row, max_col),
                    and 'area'. Same schema as the old _get_bboxes_from_labeled_image().
    r   N)rf  r   zconnectivity must be 4 or 8.)ÚconnectivityÚltyper   )Úlabelr7   Úarea)Úcv2rE  ÚconnectedComponentsWithStatsÚCV_32SrY   rS   ÚCC_STAT_AREAÚCC_STAT_LEFTÚCC_STAT_TOPÚCC_STAT_WIDTHÚCC_STAT_HEIGHTr?   )Úbinary_maskrØ  Úmin_area_thresholdrÜ  Ú
num_labelsÚ_ÚstatsÚregionsÚlabel_idrÛ  r   r.  ÚwidthÚheights                 r   Ú!_find_connected_component_regionsrí  A  sK  € ð* €J€J€Jà˜6Ð!Ð!ÝÐ7Ñ8Ô8Ð8à!×>Ò>Ø ,°c´jð ?ñ ô Ñ€J��5˜!ð €GÝ˜!˜ZÑ(Ô(ð ð ˆÝ�5˜ 3Ô#3Ð3Ô4Ñ5Ô5ˆØÐ$Ò$Ð$Øå�U˜8 SÔ%5Ð5Ô6Ñ7Ô7ˆÝ�U˜8 S¤_Ð4Ô5Ñ6Ô6ˆÝ�U˜8 SÔ%6Ð6Ô7Ñ8Ô8ˆÝ�U˜8 SÔ%7Ð7Ô8Ñ9Ô9ˆð 	�ŠØØ˜˜1˜v™: q¨5¡yÐ1Øð
ð 
ñ 	ô 	ð 	ð 	ð
 €Nr   c                 óÌ   — ddl }|dk    r| S |dz  dk    rt          d¦  «        ‚|                     |j        ||f¦  «        }|                     | |j        ||j        d¬¦  «        S )as  
    Performs binary opening (erosion followed by dilation) on a 2D binary image
    using a square kernel of ones.

    Args:
        binary_image (np.ndarray): A 2D uint8 array (H, W) with 0s and 1s.
        kernel_size (int): Side length of the square kernel. Must be an odd number.

    Returns:
        np.ndarray: The opened binary image (same dtype as input).
    r   Nr   r   z?Kernel size for morphological operations must be an odd number.)Ú
borderTypeÚborderValue)rÜ  rE  ÚgetStructuringElementÚ
MORPH_RECTÚmorphologyExÚ
MORPH_OPENÚBORDER_CONSTANT)Úbinary_imageÚkernel_sizerÜ  Úkernels       r   Ú_binary_opening_numpyrù  u  s„   € ð €J€J€Jà�aÒÐØÐØ�Q�˜!ÒÐÝÐZÑ[Ô[Ð[à×&Ò&ØŒ˜ kÐ2ñô €Fð ×Ò˜L¨#¬.¸&ÈSÔM`ÐnoÐÑpÔpÐpr   Ú
seg_logitsÚclass_namesÚtarget_classÚmin_component_areaÚmorphology_kernel_sizec           
      ó”  ‡— t          |¦  «        }| j        d         |k    sJ d| j        d         › d|› d�¦   «         ‚| d         }|€"t          j        d|t          j        ¬¦  «        }nEd„ t          |¦  «        D ¦   «         Št          j        ˆfd	„|D ¦   «         t          j        ¬¦  «        }t          j        |d¬
¦  «        }g }	|D ]þ}
||
k                         t          j	        ¦  «        }|dk    rt          ||¦  «        }t          |d|¬¦  «        }||
         }|D ]¦}|d         \  }}}}|||…||…f         }t          j        ||
k    ¦  «        }|j        r
||j        z  nd}|	                     t          |¦  «        t          |¦  «        t          |¦  «        t          |¦  «        g|t!          |¦  «        dœ¦  «         Œ§Œÿ|	S )a/  
    Extract bounding boxes only for the classes you care about.

    Args:
        seg_logits (np.ndarray):
            Per-class segmentation logits, shape (1, len(class_names), H, W).
            The caller must slice out exactly the class channels before
            calling this function; no implicit channel slicing happens here.
            Detection uses argmax, which is invariant to whether the values
            are raw logits or post-softmax probabilities, so either can be
            passed in.
        class_names (list[str]):
            Ordered list of class names (index i corresponds to channel i).
        target_class (list[str] | None):
            If given, only these classes are processed.  None means process
            every class except background (class-id 0).
        min_component_area (int):
            Connected components smaller than this many pixels are ignored.
        morphology_kernel_size (int):
            Size of the square morphological opening kernel (must be odd).
            0 or 1 disables opening.

    Returns:
        list[dict]:
            [{'bbox': [x1, y1, x2, y2], 'class': <name>, 'score': <float>}, ...]
            (x1,y1) is top-left, (x2,y2) is bottom-right in image coordinates.
            score = (# pixels of predicted class inside bbox) / (bbox area).
    r   úseg_logits channel count (ú) must equal len(class_names) (úO); caller must pass only the class-logit channels, not a larger feature tensor.r   Nr   c                 ó   — i | ]\  }}||“Œ	S rR   rR   ©rT   ÚidxÚnames      r   ú
<dictcomp>z4extract_bboxes_from_segmentation.<locals>.<dictcomp>¿  ó   € ÐHÐHÐH¡I C¨�d˜CÐHÐHÐHr   c                 ó(   •— g | ]}|‰v ¯‰|         ‘ŒS rR   rR   ©rT   ÚnÚ
name_to_ids     €r   rW   z4extract_bboxes_from_segmentation.<locals>.<listcomp>À  s"   ø€ ÐVÐVÐV°ÀaÈ:ÀoÀo˜z¨!œ}ÀoÀoÀor   r"   r   )rØ  rå  r7   rÃ   ©r7   ÚclassÚscore)rv   rA   r   r)  Úintpr>   r%   Úargmaxrè   rÄ  rù  rí  Úcount_nonzeroÚsizer?   rS   rG  )rú  rû  rü  rý  rþ  Ú	n_classesÚseg_mapsÚ
active_idsÚ	class_mapÚresultÚclass_idrR  ré  Úcls_nameÚregÚmin_rowÚmin_colÚmax_rowÚmax_colÚroiÚpix_clsr  r  s                         @r   Ú extract_bboxes_from_segmentationr"  �  s,  ø€ õF �KÑ Ô €IØÔ˜AÔ )Ò+Ð+Ð+ð	> ZÔ%5°aÔ%8ð 	>ð 	>Ø&ð	>ð 	>ð 	>ñ ,Ô+Ð+ð
 ˜!Œ}€Hð ÐÝ”Y˜q )µ2´7Ð;Ñ;Ô;ˆ
ˆ
àHÐHµ¸;Ñ1GÔ1GÐHÑHÔHˆ
Ý”XÐVÐVÐVÐV°lÐVÑVÔVÝ$&¤Gð-ñ -ô -ˆ
õ ”	˜(¨Ð+Ñ+Ô+€Ià€Fàð ð ˆà˜XÒ%×-Ò-­b¬hÑ7Ô7ˆð " AÒ%Ð%Ý(¨Ð/EÑFÔFˆDõ 4ØØØ1ð
ñ 
ô 
ˆð ˜xÔ(ˆàð 	ð 	ˆCØ14°V´Ñ.ˆG�W˜g wð ˜G G˜O¨W°W¨_Ð<Ô=ˆCÝÔ& s¨h¢Ñ7Ô7ˆGØ*-¬(Ð;�G˜cœhÑ&Ð&¸ˆEà�MŠMÝ˜W™œ¥s¨7¡|¤|µS¸±\´\Å3ÀwÁ<Ä<ÐPØ!Ý˜u™œðð ñ ô ð ð ð	ð €Mr   r  Útarget_hÚtarget_wc                 ó(  — | j         \  }}t          j        |¦  «        |z  |z                       t          j        ¦  «        }t          j        |¦  «        |z  |z                       t          j        ¦  «        }| t          j        ||¦  «                 S )am  
    Resize a 2-D integer label map using nearest-neighbor interpolation.
    Pure numpy; no scipy/cv2 dependency.

    Args:
        class_map (np.ndarray): (H, W) integer array of class IDs.
        target_h (int): Output height.
        target_w (int): Output width.

    Returns:
        np.ndarray: (target_h, target_w) integer array, same dtype as input.
    )rA   r   r)  rè   r  r¶  )r  r#  r$  Úsrc_hÚsrc_wÚrow_idxÚcol_idxs          r   Ú_resize_class_map_nearestr*  ê  sz   € ð ”?�L€Eˆ5õ Œy˜Ñ"Ô" UÑ*¨XÑ5×=Ò=½b¼gÑFÔF€GÝŒy˜Ñ"Ô" UÑ*¨XÑ5×=Ò=½b¼gÑFÔF€Gà•R”V˜G WÑ-Ô-Ô.Ð.r   rä  Úmin_areac                 ó  — | j         \  }}t          j        ||ft          ¬¦  «        }g }t          j        | ¦  «        \  }}g d¢}t          |                     ¦   «         |                     ¦   «         ¦  «        D �]\  }	}
||	|
f         rŒ|	|
fg}d||	|
f<   |	x}}|
x}}d}d}|t          |¦  «        k     r¬||         \  }}|dz  }|dz  }||k     r|}||k    r|}||k     r|}||k    r|}|D ]a\  }}||z   ||z   }}d|cxk    r|k     rEn Œd|cxk    r|k     r5n Œ/|||f         s(| ||f         rd|||f<   |                     ||f¦  «         Œb|t          |¦  «        k     °¬||k    r"|                     |||dz   |dz   f|dœ¦  «         �Œ|S )a¾  
    BFS-based connected-component labeling on a 2-D binary uint8 mask.
    8-connectivity.  Pure numpy + Python; no cv2/scipy.

    Args:
        binary_mask (np.ndarray): (H, W) uint8 array, 0 = background, 1 = foreground.
        min_area (int): Components with fewer pixels than this are discarded.

    Returns:
        list[dict]: Each entry has 'bbox' (min_row, min_col, max_row, max_col)
                    and 'area' (pixel count).
    r   ))r;   r;   )r;   r   )r;   r   )r   r;   )r   r   )r   r;   rq   )r   r   Tr   r   )r7   rÛ  )	rA   r   r£   rB   r¥   r¦   r§   rv   r?   )rä  r+  r°   r·  Úvisitedré  Úfg_rowsÚfg_colsÚoffsetsÚstart_rÚstart_cÚqueueÚmin_rÚmax_rÚmin_cÚmax_crÛ  ÚheadÚrr  ÚdrÚdcÚnrÚncs                           r   Ú _find_connected_components_numpyr>     s1  € ð Ô�D€A€qÝŒh˜˜1�v¥TÐ*Ñ*Ô*€GØ€Gõ ”z +Ñ.Ô.Ñ€GˆWð(ð (ð (€Gõ   §¢Ñ 0Ô 0°'·.².Ñ2BÔ2BÑCÔCð  ñ  Ñˆ�Ø�7˜GÐ#Ô$ð 	Øð ˜7Ð#Ð$ˆØ$(ˆ�˜Ð Ñ!ØÐˆ�ØÐˆ�ØˆàˆØ•S˜‘Z”ZÒÐØ˜”;‰DˆAˆqØ�A‰IˆDØ�A‰IˆDà�5Šyˆy !˜%Ø�5Šyˆy !˜%Ø�5Šyˆy !˜%Ø�5Šyˆy !˜%à!ð +ð +‘��BØ˜R™  R¡�B�Ø˜�;�;’;�;˜Q’;�;�;�;�; 1¨ ; ;¢; ;¨Q¢; ; ; ; ;°w¸rÀ2¸v´ ;È;ÐWYÐ[]ÐW]ÔK^ ;Ø&*�G˜B ˜F‘OØ—L’L " b Ñ*Ô*Ð*øð •S˜‘Z”ZÒÐð  �8ÒÐØ�NŠNØ  u¨q¡y°%¸!±)Ð<Øðð ñ ô ð ùð
 €Nr   éd   Údownscale_sizec                 óî  ‡$— t          |¦  «        }| j        d         |k    sJ d| j        d         › d|› d�¦   «         ‚| d         }|j        d         |j        d         }}t          j        |d¬¦  «        }	|t	          ||¦  «        z  }
t	          dt          t          ||
z  ¦  «        ¦  «        ¦  «        }t	          dt          t          ||
z  ¦  «        ¦  «        ¦  «        }t          |	||¦  «        }||z  ||z  z  }t	          dt          t          j        ||z  ¦  «        ¦  «        ¦  «        }||z  }||z  }|€"t          j	        d|t          j
        ¬	¦  «        }nEd
„ t          |¦  «        D ¦   «         Š$t          j        ˆ$fd„|D ¦   «         t          j
        ¬	¦  «        }g }|D �]K}||k                         t          j        ¦  «        }t          ||¬¦  «        }||         }|D �]}|d         \  }}}}t          ||z  ¦  «        }t          ||z  ¦  «        }t!          |t          t          j        ||z  ¦  «        ¦  «        ¦  «        }t!          |t          t          j        ||z  ¦  «        ¦  «        ¦  «        } |	||…|| …f         }!t          t          j        |!|k    ¦  «        ¦  «        }"|!j        r
|"|!j        z  nd}#|                     ||| |g|t)          |#¦  «        dœ¦  «         �Œ
�ŒM|S )aß  
    Numpy-only equivalent of extract_bboxes_from_segmentation().

    To compensate for the slower Python BFS, detection is performed on a
    downscaled class map (longest side capped at `downscale_size`), and the
    resulting bounding boxes are scaled back to original resolution.
    Morphological opening is omitted; callers should apply post-processing if
    needed.

    Args:
        seg_logits (np.ndarray):
            Per-class segmentation logits, shape (1, len(class_names), H, W).
            The caller must slice out exactly the class channels before
            calling this function; no implicit channel slicing happens here.
            Detection uses argmax, which is invariant to whether the values
            are raw logits or post-softmax probabilities, so either can be
            passed in.
        class_names (list[str]):
            Ordered list of class names (index i corresponds to channel i).
        target_class (list[str] | None):
            Classes to process.  None processes all non-background classes
            (class-id >= 1).
        min_component_area (int):
            Minimum component size in *original* pixels.  Scaled
            proportionally before BFS so that the threshold is consistent
            regardless of downscale_size.
        downscale_size (int):
            The downscaled map's longest dimension.  Smaller values are
            faster but may merge or lose small regions.

    Returns:
        list[dict]:
            [{'bbox': [x1, y1, x2, y2], 'class': <name>, 'score': <float>}]
            (x1, y1) = top-left, (x2, y2) = bottom-right in original image
            coordinates.  score = fraction of bbox pixels predicted as this
            class in the *original* class map.
    r   r   r  r  r   r   r"   Nr   c                 ó   — i | ]\  }}||“Œ	S rR   rR   r  s      r   r  z:extract_bboxes_from_segmentation_numpy.<locals>.<dictcomp>ˆ  r  r   c                 ó(   •— g | ]}|‰v ¯‰|         ‘ŒS rR   rR   r
  s     €r   rW   z:extract_bboxes_from_segmentation_numpy.<locals>.<listcomp>Š  s"   ø€ ÐDÐDÐD˜q°A¸°O°OˆZ˜Œ]°O°O°Or   )r+  r7   rÃ   r  )rv   rA   r   r  r   rS   Úroundr*  Úceilr)  r  r>   r%   rè   rÄ  r>  r&   r  r  r?   rG  )%rú  rû  rü  rý  r@  r  r  Úorig_hÚorig_wÚclass_map_fullÚscaleÚds_hÚds_wÚclass_map_dsÚ
area_scaleÚmin_area_dsÚscale_rÚscale_cr  r  r  Úmask_dsré  r  r  Úds_min_rÚds_min_cÚds_max_rÚds_max_cÚ
orig_min_rÚ
orig_min_cÚ
orig_max_rÚ
orig_max_cr   r!  r  r  s%                                       @r   Ú&extract_bboxes_from_segmentation_numpyrZ  >  s9  ø€ õX �KÑ Ô €IØÔ˜AÔ )Ò+Ð+Ð+ð	> ZÔ%5°aÔ%8ð 	>ð 	>Ø&ð	>ð 	>ð 	>ñ ,Ô+Ð+ð
 ˜!Œ}€HØ”^ AÔ&¨¬°qÔ(9ˆF€Fõ ”Y˜x¨aÐ0Ñ0Ô0€Nð �S ¨Ñ0Ô0Ñ0€EÝˆq•#•e˜F U™NÑ+Ô+Ñ,Ô,Ñ-Ô-€DÝˆq•#•e˜F U™NÑ+Ô+Ñ,Ô,Ñ-Ô-€DÝ,¨^¸TÀ4ÑHÔH€Lð ˜‘+ &¨6¡/Ñ2€JÝ�a��RœWÐ%7¸*Ñ%DÑEÔEÑFÔFÑGÔG€Kð �t‰m€GØ�t‰m€Gð ÐÝ”Y˜q )µ2´7Ð;Ñ;Ô;ˆ
ˆ
àHÐHµ¸;Ñ1GÔ1GÐHÑHÔHˆ
Ý”XØDÐDÐDÐD LÐDÑDÔDÝ”'ð
ñ 
ô 
ˆ
ð
 €Fàð ñ ˆØ 8Ò+×3Ò3µB´HÑ=Ô=ˆå2°7À[ÐQÑQÔQˆà˜xÔ(ˆàð 	ñ 	ˆCØ58¸´[Ñ2ˆH�h ¨(õ ˜X¨Ñ/Ñ0Ô0ˆJÝ˜X¨Ñ/Ñ0Ô0ˆJÝ˜V¥S­¬°¸GÑ1CÑ)DÔ)DÑ%EÔ%EÑFÔFˆJÝ˜V¥S­¬°¸GÑ1CÑ)DÔ)DÑ%EÔ%EÑFÔFˆJð ! ¨JÐ!6¸
À:Ð8MÐ!MÔNˆCÝ�"Ô*¨3°(ª?Ñ;Ô;Ñ<Ô<ˆGØ*-¬(Ð;�G˜cœhÑ&Ð&¸ˆEà�MŠMØ# Z°¸ZÐHØ!Ý˜u™œðð ñ ô ð ñ ñ	ð( €Mr   Ú__main__z(A) This is... A)r  )r   )r6   )rœ   r�   )NT)r   FTF)r   r  )Nr  r   )Nr  r?  ).ÚosrE   Únumpyr   Úcollectionsr   Útypingr   r   r   r   r|  rS   r   r   r5   rG  Útupler}   Údictr  r›   r¶   rÀ   rå   rð   r  r&  r*  r-  r2  r9  r^  rB   r±  rÂ  rÈ  rÖ  rí  rù  r"  r*  r>  rZ  Ú__name__ÚprintrR   r   r   ú<module>rd     s  ðØ 	€	€	€	Ø €€€Ø Ð Ð Ð à Ð Ð Ð Ð Ð Ø .Ð .Ð .Ð .Ð .Ð .Ð .Ð .Ð .Ð .Ð .Ð .ð;ð ;�R”Zð ; sð ;°2´:ð ;ð ;ð ;ð ;ð 
$�R”Zð 
$ B¤Jð 
$ð 
$ð 
$ð 
$ð=ð =ð =ð@x,ð x, R¤Zð x,Àð x,ÐTYð x,ÐdiØˆˆs�CˆxŒÔ˜4  T¨%°°S°¬/Ô%:Ð :Ô;Ð;ôe=ð x,ð x,ð x,ð x,ðx+5ð +5 ¤
ð +5¸Eð +5ÐY^ð +5ÐkoÐpuÐvyÐ{~Ðv~Ôpô  lAð +5ð +5ð +5ð +5ð\'˜BœJð '¨3ð '°2´:ð 'ð 'ð 'ð 'ðRL B¤Jð L¸Dð Lð Lð Lð Lð\p°"´*ð pÈ$ð pð pð pð pðdBð Bð Bð BðHð ð ð(0 ð 0¨¬
ð 0ð 0ð 0ð 0ð
�"”*ð  ð ¨ð ð ð ð ð�2”:ð  #ð ¨#ð °$ð ð ð ð ð%¨#ð %°R´Zð %ÀrÄzð %ð %ð %ð %ð2\Ø”*ð\à”Jð\ð ”Zð\ð �T˜%”[Ô!ð	\ð
 " #œYð\ð 
ˆ$„Zð\ð \ð \ð \ðH &'Ø#Ø $Ø %ðxð xØ”*ðxà�U˜5 %¨°Ð5Ô6Ô7ðxð ðxð ð	xð
  #ðxð ðxð ðxð ðxð „Zðxð xð xð xðt:4˜œ
ð :4¨eð :4¸¼
ð :4ð :4ð :4ð :4ðz2�2”:ð 2 "¤*ð 2ð 2ð 2ð 2ð<<ð <ð <ð 1ð 1ð 1ð 1ðhqð qð qð< &*Ø Ø"#ðWð WØ”
ðWà�c”ðWð �s”)˜dÑ"ðWð ð	Wð
  ðWð 
ˆ$„ZðWð Wð Wð Wðt/¨¬ð /¸sð /Ècð /ÐVXÔV`ð /ð /ð /ð /ð,;°"´*ð ;Èð ;ÐPTÐUYÔPZð ;ð ;ð ;ð ;ðB *.Ø"$Ø!ðmð mØ”Jðmà˜#”Yðmð ˜3”i $Ñ&ðmð  ð	mð
 ðmð 
ˆ$„Zðmð mð mð mð` ˆzÒÐØ	€EÐ
Ð
Ð-¸TÐ
BÑ
BÔ
BÑCÔCÐCÐCÐCð Ðr   