
    .cjSk                       d Z ddlmZ ddlZddlmZmZmZmZm	Z	 dZ
dZdZdZd	Zd
Zeeef         Z ej        d          Z ej        d          Z ej        d          Z ej        d          Z ej        d          Z ej        d          Z ej        d          ZdBdZdCdZ ej        d          Z ej        d          Z ej        d          Z ej        d          Z ej        d          Z dDd!Z!dEd#Z"dFd%Z#dGd'Z$dHd(Z%dId+Z&dJd.Z'dHd/Z(dKd1Z)dLd3Z*dMd5Z+dNd7Z,dOd8Z-	 dPdQd;Z.dRd=Z/dSd?Z0dTdAZ1dS )Uu  Render agent markdown into Slack Block Kit blocks.

Opt-in (``slack.extra.rich_blocks: true``) alternative to the flat mrkdwn
``text`` payload produced by :meth:`SlackAdapter.format_message`.  Block Kit
gives us real structural primitives — section headers, dividers, and true
*nested* lists via ``rich_text`` — that plain mrkdwn can only approximate.

Design constraints (why this module is deliberately conservative):

* **Markdown pipe-tables render as native ``table`` blocks** — real grid
  cells with per-column alignment and inline-formatted ``rich_text`` content.
  A table that exceeds Slack's limits (100 rows / 20 cols / 10k aggregate
  cell chars) or won't parse falls back to aligned monospace
  ``rich_text_preformatted`` so a large table never breaks the message.
* **Slack caps a message at 50 blocks** and a ``section``/text object at 3000
  characters.  :func:`render_blocks` enforces both and, if the content simply
  cannot be expressed within them, returns ``None`` so the caller falls back
  to the plain-text path.  A rich render is a nice-to-have; it must never lose
  a message.
* **Every blocks payload MUST ship a ``text`` fallback.**  Slack uses it for
  notifications, screen readers, and old clients.  This module only builds the
  ``blocks`` list; the adapter pairs it with the existing mrkdwn string.

The renderer never raises: any unexpected input degrades to ``None`` (caller
uses plain text).  It is a pure function of its input — no Slack client, no
adapter state — so it is trivially unit-testable.
    )annotationsN)AnyDictListOptionalTuple2   i     d      i'  z ^\s{0,3}([-*_])(?:\s*\1){2,}\s*$z!^\s{0,3}(#{1,6})\s+(.+?)\s*#*\s*$z^\s*(`{3,}|~{3,})(.*)$z^(\s*)(\d+)[.)]\s+(.*)$z^(\s*)[-*+]\s+(.*)$z^\s{0,3}>\s?(.*)$z1^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)+\|?\s*$linestrreturnboolc                    t          t                              |           pt                              |                     S )z=True if ``line`` is a markdown list item (bullet or ordered).)r   
_BULLET_REmatch_ORDERED_RE)r   s    C/home/ice/.hermes/hermes-agent/plugins/platforms/slack/block_kit.py_is_list_liner   :   s1    
  &&A+*;*;D*A*ABBB    spacesintc                P    d}| D ]}||dk    rdndz  }t          |dz  d          S )zHMap leading whitespace to a nesting level (2 spaces or 1 tab per level).r   	            )min)r   widthchs      r   _indent_levelr#   ?   sB    E ( (bDjja'uz1r   z	`([^`]+)`z7(?<!!)\[([^\]]+)\]\(([^()\s]+(?:\([^()]*\)[^()\s]*)*)\)z(?:\*\*|__)(.+?)(?:\*\*|__)z?(?<![\*_])(?:\*|_)(?![\*_\s])(.+?)(?<![\*_\s])(?:\*|_)(?![\*_])z	~~(.+?)~~textList[Dict[str, Any]]c                n    g ddfddfd
}dfddfd || i            pd| dgS )a
  Parse a run of inline markdown into rich_text section child elements.

    Produces ``text`` elements (optionally styled bold/italic/strike/code) and
    ``link`` elements.  Unmatched markup is emitted verbatim as plain text, so
    this never loses characters.
    Nsr   styleOptional[Dict[str, bool]]r   Nonec                R    | sd S d| d}|r||d<                        |           d S )Nr$   typer$   r(   )append)r'   r(   elelementss      r   	emit_textz#_inline_elements.<locals>.emit_text\   sF     	F&,a88 	 BwKr   Dict[str, bool]c                L   d}t                               |           D ]q} | ||                                         |           t          |          }d|d<    |                    d          |pd            |                                }r | |d          |           d S )Nr   Tcoder   )_INLINE_CODE_REfinditerstartdictgroupend)r'   r(   posm
code_style_walk_linksr1   s        r   walkz_inline_elements.<locals>.walkg   s     ))!,, 	 	AK#aggii-(%000eJ!%JvIaggajj*"4555%%''CCAcddGU#####r   c                   d}t                               |           D ]} | ||                                         |           d|                    d          |                    d          d}|rt	          |          |d<                       |           |                                } | |d          |           d S )Nr   linkr   r   )r-   urlr$   r(   )_LINK_REr6   r7   r9   r8   r.   r:   )r'   r(   r;   r<   link_el_walk_emphasisr0   s        r   r>   z%_inline_elements.<locals>._walk_linksr   s    ""1%% 	 	AN1S]+U333/5aggajjRSRYRYZ[R\R\&]&]G /#';; OOG$$$%%''CCqw&&&&&r   c                   | sd S t           dft          dft          dffD ]\  }}|                    |           }|r | d |                                         |           t          |          }d||<    |                    d          |            | |                                d          |            d S  | |rt          |          nd            d S )NboldstrikeitalicTr   )_BOLD_RE
_STRIKE_RE
_ITALIC_REsearchr7   r8   r9   r:   )r'   r(   rxkeyr<   inner_stylerE   r1   s         r   rE   z(_inline_elements.<locals>._walk_emphasis}   s     	F!6*Z,BZQYDZ[ 	 	GB		!A q!''))}e444"5kk#'C qwwqzz;777q{E222 		!E3T%[[[t44444r   r$   r,   N)r'   r   r(   r)   r   r*   )r'   r   r(   r2   r   r*    )r$   r?   rE   r>   r0   r1   s     @@@@r   _inline_elementsrS   S   s     &(H      	$ 	$ 	$ 	$ 	$ 	$ 	$	' 	' 	' 	' 	' 	' 	'5 5 5 5 5 5 5 	DrNNN76677r   r0   c                *    d | D             }|pdddgS )u  Make a rich_text child-element list safe for Slack.

    Slack rejects any ``rich_text_section`` / ``rich_text_preformatted`` /
    ``rich_text_quote`` whose ``elements`` list is empty or contains a ``text``
    element of zero length (``invalid_blocks``: "missing element" / "must be
    more than 0 characters"). Empty content is common — ragged table rows are
    padded with ``""``, agents emit empty code fences around empty tool output,
    blank quote lines and empty list items occur in the wild — so drop
    zero-length text elements and, if nothing remains, substitute a single
    space, which renders as blank yet stays schema-valid. Used by every
    rich_text builder so empty content can never poison the whole payload.
    c                n    g | ]2}|                     d           dk    r|                     d          0|3S r,   )get).0es     r   
<listcomp>z&_nonempty_elements.<locals>.<listcomp>   s;    
V
V
VquuV}}'>'>quuV}}'>1'>'>'>r   r$    r,   rR   )r0   elss     r   _nonempty_elementsr\      s.     W
Vh
V
V
VC1FC0011r   Optional[Block]c                    t          j        dd|                                           }|sd S t          |          t          k    r|d t          dz
           dz   }dd|ddd	S )
Nz[*_~`] r      …header
plain_textT)r-   r$   emojir,   )resubstriplenMAX_HEADER_TEXT)r$   cleans     r   _header_blockrj      st    F9b$''--//E  t
5zzO##+!++,u4|UUY&Z&Z[[[r   Blockc                 
    ddiS )Nr-   dividerrR   rR   r   r   _divider_blockrn      s    Ir   c                \    ddt          d|                     d          dg          dgdS )N	rich_textrich_text_preformattedr$   
r,   r-   r0   )r\   rstripr$   s    r   _preformatted_blockrv      sM      1.UYIZIZ0[0[/\]] 
  r   lines	List[str]c                    g }t          |           D ]A\  }}|r|                    ddd           |                    t          |                     Bddt	          |          dgdS )Nr$   rr   r,   rp   rich_text_quoters   )	enumerater.   extendrS   r\   )rw   section_childrenilns       r   _quote_blockr      s    -/5!! 6 62 	D##VT$B$BCCC 0 4 45555/=OP`=a=abbc  r   itemsList[Tuple[int, bool, str]]c           	         g }d}d}| D ]m\  }}}||f}||k    r"d|rdnd|g d}|                     |           |}|5|d                              dt          t          |                    d           nd	|dS )
a0  Build ONE rich_text block from consecutive list items.

    ``items`` is a list of ``(indent, ordered, text)``.  Each contiguous run
    sharing the same (indent, ordered) becomes a ``rich_text_list`` element;
    indentation changes start a new element, which is how Slack renders true
    nesting.
    Nrich_text_listorderedbullet)r-   r(   indentr0   r0   rich_text_sectionrs   rp   )r.   r\   rS   )r   r0   curcur_keyr   r   r$   rO   s           r   _list_blockr      s     &(H$(C*.G!& 
 
w'>>(&-;8 	 C OOC   G; J(6HIYZ^I_I_6`6`aa	
 	
 	
 	
  X666r   c                    dd| ddS )Nsectionmrkdwnr,   rR   ru   s    r   _section_blockr      s    $'G'GHHHr   sep_linec                   g }|                                                       d                              d          D ]}|                                 }|                    d          }|                    d          }|r|r|                    d           Z|r|                    d           r|                    d           |S )zParse a markdown separator row (``|:--|:-:|--:|``) into column aligns.

    Returns a list of ``"left"``/``"center"``/``"right"`` per column.
    |:centerrightleft)rf   split
startswithendswithr.   )r   alignscellcr   r   s         r   _parse_alignmentr      s    
 F  &&s++11#66 	" 	"JJLL||C  

3 	"E 	"MM(#### 	"MM'""""MM&!!!!Mr   rowc                    |                                                       d                              dd          }d |                    d          D             S )zSplit a markdown table row into trimmed cell strings.

    Respects backslash-escaped pipes (``\|``) so they aren't treated as
    column separators.
    r   z\| PIPE c                ^    g | ]*}|                                                     d d          +S )r   r   )rf   replace)rW   r   s     r   rY   z_split_row.<locals>.<listcomp>  s0    QQQqAGGIInc22QQQr   )rf   r   r   )r   	protecteds     r   
_split_rowr     sO     		!!#&&..unEEIQQIOOC<P<PQQQQr   Dict[str, Any]c                H    ddt          t          |                     dgdS )a  A ``rich_text`` table cell carrying inline-formatted content.

    Empty cells are common (ragged rows are padded with ``""``); Slack rejects
    a cell whose section is empty or carries a zero-length text element, so the
    elements are routed through ``_nonempty_elements``.
    rp   r   rs   )r\   rS   ru   s    r   _rich_text_cellr     s9     (6HIYZ^I_I_6`6`aa
  r   rowsc                   d | D             }|sdS t          d |D                       }t          |          t          k    s|t          k    rdS |D ]+}|                    dg|t          |          z
  z             ,t          d |D                       }|t          k    rdS t          |          }d}t          t          |t                              D ]'}|t          |          k     r||         nd}	|	dk    r|}(g }
t          |dz             D ]6}|t          |          k     r||         nd}	|

                    d	|	i           7d
d |D             d}|
r|
|d<   |S )u  Build a native Slack ``table`` block from markdown pipe-table rows.

    ``rows`` includes the header row (index 0) and body rows; ``sep_line`` is
    the ``|---|`` alignment row (already consumed by the caller).  Returns
    ``None`` when the table exceeds Slack's limits (100 rows / 20 cols /
    10,000 aggregate cell chars) or parses to nothing — the caller then falls
    back to the monospace preformatted rendering.
    c                T    g | ]%}|                                 t          |          &S rR   )rf   r   rW   rs     r   rY   z _table_block.<locals>.<listcomp>0  s+    777QWWYY7jmm777r   Nc              3  4   K   | ]}t          |          V  d S rQ   rg   r   s     r   	<genexpr>z_table_block.<locals>.<genexpr>3  (      ''1A''''''r   r_   c              3  >   K   | ]}|D ]}t          |          V  d S rQ   r   rW   r   r   s      r   r   z_table_block.<locals>.<genexpr>:  s5      88a88c!ff8888888r   r   r   aligntablec                &    g | ]}d  |D             S )c                ,    g | ]}t          |          S rR   )r   )rW   r   s     r   rY   z+_table_block.<locals>.<listcomp>.<listcomp>O  s     888D/$''888r   rR   )rW   r   s     r   rY   z _table_block.<locals>.<listcomp>O  s'    KKKS88C888KKKr   )r-   r   column_settings)maxrg   MAX_TABLE_ROWSMAX_TABLE_COLSr|   sumMAX_TABLE_CHARSr   ranger    r.   )r   r   parsedncolsr   total_charsr   last_non_defaultr   r   r   blocks               r   _table_blockr   '  s    87T777F t'''''''E
6{{^##u~'='=t * *	"Q())))88f88888K_$$th''F
 3un--.. ! !V__q		&F?? ,.O#a'(( 1 1V__q		&/0000 KKFKKK E  3#2 Lr   c           	        g | D ]&t                    }                    |           'sd                    |           S t          d D                       }D ]+                    dg|t                    z
  z             ,fdt          |          D             g }t                    D ]\  }d                    fdt          |          D                       }|                    |                                           |dk    rA|                    d                    fd	t          |          D                                  d                    |          S )
zERender markdown pipe-table rows as aligned monospace text (fallback).rr   c              3  4   K   | ]}t          |          V  d S rQ   r   r   s     r   r   z _render_table.<locals>.<genexpr>^  r   r   r_   c                H    g | ]t          fd D                       S )c              3  B   K   | ]}t          |                   V  d S rQ   r   r   s     r   r   z+_render_table.<locals>.<listcomp>.<genexpr>a  s-      ,,#ad)),,,,,,r   )r   )rW   r   r   s    @r   rY   z!_render_table.<locals>.<listcomp>a  s7    CCCc,,,,V,,,,,CCCr   z | c              3  Z   K   | ]%}|                              |                   V  &d S rQ   )ljust)rW   r   r   widthss     r   r   z _render_table.<locals>.<genexpr>d  s7      FFA!A$**VAY//FFFFFFr   r   z-+-c              3  .   K   | ]}d |         z  V  dS )-NrR   )rW   r   r   s     r   r   z _render_table.<locals>.<genexpr>g  s+      'N'NAfQi'N'N'N'N'N'Nr   )	r   r.   joinr   r|   rg   r   r{   rt   )	r   cellsr   	out_linesrir   r   r   r   s	         @@@r   _render_tabler   V  s    F  1e yy'''''''E * *	"Q())))CCCCeEllCCCFI6"" P PAzzFFFFFuFFFFF'''77UZZ'N'N'N'Nu'N'N'NNNOOO99Yr   markdownOptional[List[Block]]c                6   | r|                                  sdS |pd 	 g |                     dd                              d          }d}t          |          }g dfd}||k     r||         }|                                 s |             |d	z  }3t                              |          }|r |             |                    d	          }g }	|d	z  }||k     r||                                                             |          sS|		                    ||                    |d	z  }||k     r-||                                                             |          S|d	z  }	                    t          d                    |	                               7t                              |          r2 |             	                    t                                 |d	z  }t                              |          }
|
rJ |             t          |
                    d
                    }|	                    |           |d	z  }d|v r|d	z   |k     rt                               ||d	z                      r |             |}||d	z            }|g}|d
z  }||k     rnd||         v rd||                                          rJ|	                    ||                    |d	z  }||k     r$d||         v r||                                          Jt#          ||          }|	                    |           n/	                    t          t%          |                               t&                              |          r |             g }||k     rVt&                              ||                   }|sn3|	                    |                    d	                     |d	z  }||k     V	                    t)          |                     t+          |          r |             g }||k     rt,                              ||                   }t.                              ||                   }|rR|	                    t1          |                    d	                    d|                    d
          f           |d	z  }nH|rQ|	                    t1          |                    d	                    d|                    d          f           |d	z  }n||                                          rU||                             d          r:|r8|d         \  }}}|||dz   ||                                          z   f|d<   |d	z  }n||                                          sk|ri|d	z   }||k     r?||                                          s%|d	z  }||k     r||                                          %||k     rt+          ||                   r|}nnn||k     	                    t3          |                     ׉	                    |           |d	z  }||k      |             sdS t                    t4          k    rdS S # t6          $ r Y dS w xY w)uc  Convert agent markdown to a Slack Block Kit ``blocks`` list.

    Args:
        markdown: The agent's response text (standard markdown).
        mrkdwn_fn: Optional callable converting a markdown paragraph to Slack
            mrkdwn for ``section`` blocks (the adapter passes
            ``format_message``).  When ``None``, the raw paragraph text is used.

    Returns:
        A list of Block Kit block dicts, or ``None`` when the content is empty,
        exceeds Slack's structural limits, or hits an unexpected shape — the
        caller then falls back to the flat ``text`` payload.  Never raises.
    Nc                    | S rQ   rR   )r'   s    r   <lambda>zrender_blocks.<locals>.<lambda>  s    ! r   z
rr   r   r   r*   c                    sd S d                                                               }                                  | sd S  |           }t          |t                    D ]$}                    t          |                     %d S )Nrr   )r   rf   clear_split_textMAX_SECTION_TEXTr.   r   )r$   renderedchunkblocksfmtparas      r   
flush_paraz!render_blocks.<locals>.flush_para  s     99T??((**DJJLLL s4yyH$X/?@@ 5 5nU3344445 5r   r   r   r   FT   )rZ   r   r   rZ   )r   r*   )rf   r   r   rg   	_FENCE_REr   r9   lstripr   r.   rv   r   _HR_RErn   
_HEADER_RErj   _TABLE_SEP_REr   r   	_QUOTE_REr   r   r   r   r#   r   
MAX_BLOCKS	Exception)r   	mrkdwn_fnrw   r~   nr   r   fencemarkerbodyhmra   
header_rowr   trowsr   qlinesqmr   bmomr   r   txtjr   r   r   s                            @@@r   render_blocksr   p  s   "  8>>++ t

$CQ   ..44T::JJ
	5 
	5 
	5 
	5 
	5 
	5 
	5 
	5 !ee8D ::<< 
Q OOD))E 

Q"$Q!eeE!HOO$5$5$@$@$H$HeKKa)))FA !eeE!HOO$5$5$@$@$H$He Q1$))D//BBCCC ||D!! 
n..///Q !!$''B 
&rxx{{33%MM&)))Q d{{q1uqyy]-@-@q1u-N-Ny
!
 Q<#Q!eeuQxE!HNN4D4DLLq***FA !eeuQxE!HNN4D4D
 %UH55$MM%((((MM"5mE6J6J"K"KLLL t$$ 

$&!ee"q22B MM"((1++...FA !ee l622333 T"" $
57!ee#))%(33B$**5844B mBHHQKK&@&@%RS%UVVVQ mBHHQKK&@&@$QR%TUUUQq)) eAh.A.A+.N.N SX /4Ry,%+WcCi%(..BRBR6R$Sb	Q"1X^^-- %  E!eeE!HNN,<,<eFA  !eeE!HNN,<,<eq55]58%<%<5 !AA!? !ee@ k%00111 KKFAc !eef 	
 	4v;;## 4   tts   Y
Z
 .Z
 Z
 

ZZlimitc                f   t          |           |k    r| gS d| v rt          |dz
  |dz  d          n|}g }| }t          |          |k    rl|                    dd|          }|dk    r|}|                    |d|                    ||d                             d          }t          |          |k    l|r|                    |           t          |          dk    rPd| v rLg }d}|D ]C}|rd	|z   }|                    d          dz  dk    }	|	r|d
z  }|	}|                    |           D|}|S )a  Split ``text`` into <= ``limit``-char chunks on line, then hard, boundaries.

    Chunks are fence-balanced: when a split lands inside a ``` code span that
    survived into section text (the renderer normally routes fenced blocks to
    ``rich_text_preformatted``, but mrkdwn text can still carry fences), the
    fence is closed at the end of the chunk and reopened on the next so each
    section renders correctly on its own.
    z```   r   r   rr   r   NFz```
z
```)rg   r   rfindr.   r   count)
r$   r   split_limitout	remainingcutbalancedreopenr   odds
             r   r   r     sv    4yyEv38D==#eai!Q///eKCI
i..;
&
&oodA{33!88C

9TcT?###cddO**400	 i..;
&
&  

9
3xx!||  	# 	#E (%++e$$q(A-C ! FOOE""""Jr   text_objc                    |                      d          pd}t          |          |k    r| S t          |           }|d|dz
                                           dz   |d<   |S )zAReturn ``text_obj`` with its ``text`` clamped to ``limit`` chars.r$   r_   Nr   r`   )rV   rg   r8   rt   )r  r   r   clampeds       r   _clamp_text_objr	  E  se    
,,v


$"C
3xx58nnG+EAI+&--//%7GFONr   r   c                @   | sdS 	 g }| D ]}t          |t                    r|                    d          s.|d         }|dk    r|                    d          }t          |                    d                    p!t          |                    d                    }t          |t                    r[|                    d          pd                                s|st          |t                    }||urt          |          }||d<   n|s	n|dk    r|                    d          }t          |t                    r)|                    d          pd                                sft          |t                    }||urt          |          }||d<   nF|d	k    rc|                    d
          pg }|sd |D             }t          d t          ||          D                       rt          |          }||d
<   n|dv r|                    d
          sn|dk    r|                    d          s7|                    d          }	t          |	t                    rzt          d |	D                       rad |	D             }
|
r&|
d         s|
                                 |
r|
d         t          |          }|
r|
|d<   n|                    dd           |                    |           |sdS |dt                   S # t          $ r Y dS w xY w)um  Clamp an outbound ``blocks`` payload to Slack's hard limits.

    Defensive boundary applied wherever the adapter attaches ``blocks`` to
    ``chat.postMessage`` / ``chat.update``.  One oversized or malformed block
    fails the WHOLE call with ``invalid_blocks`` — approval cards then never
    update and messages silently drop — so instead of trusting every builder,
    the payload is normalized just before the API call:

    * ``section`` / ``context`` text objects are truncated to the 3000-char
      cap with an ellipsis (Slack HTML-escapes ``< > &`` on storage, so text
      echoed back through interaction payloads can exceed the limit that the
      send path originally budgeted for — see #53693 / #62054).
    * ``header`` text is truncated to its 150-char cap.
    * Empty blocks (no text / no elements / no rows) are dropped — Slack
      rejects zero-length text objects and empty element lists.
    * ``table.column_settings`` entries must all be objects; ``null`` entries
      (emitted by older renderers, per the "use null to skip" misreading of
      the schema) are replaced with ``{}`` and default trailing entries are
      trimmed (#56615).
    * The payload is capped at Slack's 50-block maximum.

    Returns the sanitized list, or ``None`` when nothing valid remains — the
    caller then sends the plain ``text`` fallback alone.  Never raises.
    Nr-   r   r$   fields	accessoryr_   ra   contextr0   c                    g | ]E}t          |t                    r,|                    d           dv rt          |t                    n|FS )r-   )r   rb   )
isinstancer8   rV   r	  r   )rW   r/   s     r   rY   z#sanitize_blocks.<locals>.<listcomp>  se         ""d++02vBZ0Z0Z $B(8999  r   c              3  $   K   | ]\  }}||uV  d S rQ   rR   )rW   r   rX   s      r   r   z"sanitize_blocks.<locals>.<genexpr>  s*      IIdaqzIIIIIIr   )rp   actionscontext_actionsr   r   r   c              3  B   K   | ]}t          |t                     V  d S rQ   r  r8   rW   css     r   r   z"sanitize_blocks.<locals>.<genexpr>  s@       6 613
2t,,,6 6 6 6 6 6r   c                @    g | ]}t          |t                    r|ni S rR   r  r  s     r   rY   z#sanitize_blocks.<locals>.<listcomp>  s+    SSSB:b$#7#7?RRRSSSr   r   )r  r8   rV   r   rf   r	  r   rh   anyziplistpopr.   r   r   )r   r   r   btyper  has_bodyr  r0   clamped_elssettingsfixeds              r   sanitize_blocksr!  O  s   2  tF =	 =	EeT** %))F2C2C &ME	!! 99V,,		( 3 344TUYY{=S=S8T8Th-- $LL006B==?? ! ! -h8HIIGh.. $U(/f!  ("" 99V,,!(D11 (,,v:N:N:TRT9[9[9]9] )(ODD(** KKE$+E&M)## 99Z006B   '	   IIc+x.H.HIIIII 4 KKE(3E*%EEEyy,,  '!!yy((  99%677h-- 
;# 6 67?6 6 6 3 3 
; TS(SSSE $b	 $		   $b	 $ KKE ;38/00		"3T:::JJu 	4;J;   tts   K8L  L 
LL)r   r   r   r   )r   r   r   r   )r$   r   r   r%   )r0   r%   r   r%   )r$   r   r   r]   )r   rk   )r$   r   r   rk   )rw   rx   r   rk   )r   r   r   rk   )r   r   r   rx   )r   r   r   rx   )r$   r   r   r   )r   rx   r   r   r   r]   )r   rx   r   r   rQ   )r   r   r   r   )r$   r   r   r   r   rx   )r  r   r   r   r   r   )r   r   r   r   )2__doc__
__future__r   rd   typingr   r   r   r   r   r   r   rh   r   r   r   r   rk   compiler   r   r   r   r   r   r   r   r#   r5   rC   rJ   rL   rK   rS   r\   rj   rn   rv   r   r   r   r   r   r   r   r   r   r   r	  r!  rR   r   r   <module>r&     s   8 # " " " " " 				 3 3 3 3 3 3 3 3 3 3 3 3 3 3 
 S#X 
7	8	8RZ<==
BJ011	bj344RZ.//
BJ+,,	
OPPC C C C
    "*\**2:PQQ2:455RZZ[[
RZ%%
:8 :8 :8 :8D2 2 2 2"
\ 
\ 
\ 
\   
 
 
 
	 	 	 	7 7 7 7BI I I I   &R R R R   , , , ,^       8 g g g g gT# # # #V   a a a a a ar   