
    oq'j~                    D    d Z ddlmZ ddlZddlmZ  G d d          ZdS )a  Agent-construction and session-resume display methods for ``HermesCLI``.

Extracted from ``cli.py`` as part of the god-file decomposition campaign
(``~/.hermes/plans/god-file-decomposition.md``, Phase 4 step 2). This mixin holds
the agent lifecycle/setup cluster: runtime-credential resolution, per-turn agent
config, first-use agent construction, and resumed-session preload + history recap.

Behavior-neutral: every method is lifted verbatim from ``HermesCLI``. ``self.*``
calls resolve unchanged via the MRO. Neutral dependencies are imported at module
top level; ``cli.py``-internal helpers/constants are imported lazily inside each
method (``from cli import ...`` resolves at call time, when ``cli`` is fully
loaded) so this module never imports ``cli`` at import time -> no import cycle.
    )annotationsN)escapec                  B    e Zd ZdZddZddZd	d	d	d
ddZddZd Zd	S )CLIAgentSetupMixinzFAgent construction + session-resume display methods for ``HermesCLI``.returnboolc                   ddl m}m}m} ddlm}m} d}d}	  || j        | j        | j	                  }n# t          $ r}|}Y d}~nd}~ww xY w| |ddlm}	 t          ||	          rt          | j        t                    r| j        ng }
|
D ]}|                    d          pd                                                                }|                    d	          pd                                }|r|sk	  ||
          }|                    d|||            |d| d|            || _        || _        d} n# t          $ r Y w xY w|2|r ||          nd} |                                d| d           dS |                    d          }|                    d          }|                    dd          }|                    d| j                  }|                    d          }t          |                    d          pg           }|                    d          }t/          |          ot          |t0                     }|sut          |t0                    r|s^|                    dd          }t          |t0                    o|od|v}|rd}|                    d||           nt+          d           dS t          |t0                    r|st+          d           dS || j        k    p
|| j        k    }|| j        k    p || j        k    p|| j        k    p
|| j        k    }|| _        || _        || _        || _        || _        |                    d          | _         || _        || _        |                    d	          }|rTt          |t0                    r?| j         p-| j        | j        k    p| j        |                    d          k    }|r|| _        | j        sE|rC	 dd l!m"}  ||          }|r|| _        |#                    d!||           n# t          $ r Y nw xY w| $                    |          }|s|s|r| j%        d| _%        d| _&        d"S )#a  
        Ensure runtime credentials are resolved before agent use.
        Re-resolves provider credentials so key rotation and token refresh
        are picked up without restarting the CLI.
        Returns True if credentials are ready, False on auth failure.
        r   )ChatConsole_cprintlogger)resolve_runtime_providerformat_runtime_provider_errorN)	requestedexplicit_api_keyexplicit_base_url)	AuthErrorprovider model)r   zEPrimary provider auth failed (%s). Falling through to fallback: %s/%su7   ⚠️  Primary auth failed — switching to fallback: z / zProvider resolution failed.z
[bold red][/]Fapi_keybase_url
openrouterapi_modecommandargscredential_poolsourcezopenrouter.aizno-key-requireduh   No API key for custom endpoint %s (source=%s), using placeholder — local servers typically ignore authua   
⚠️  Provider resolver returned an empty API key. Set OPENROUTER_API_KEY or run: hermes setupuf   
⚠️  Provider resolver returned an empty base URL. Check your provider config or run: hermes setupname)get_default_model_for_provideru8   No model configured — defaulting to %s for provider %sT)'clir
   r   r   hermes_cli.runtime_providerr   r   requested_provider_explicit_api_key_explicit_base_url	Exceptionhermes_cli.authr   
isinstance_fallback_modellistgetstriplowerwarningr   printr   callablestrdebugr   r   r   acp_commandacp_args_credential_pool_provider_sourcehermes_cli.modelsr    info_normalize_model_for_provideragent_active_agent_route_signature) selfr
   r   r   r   r   _primary_excruntimeexcr   	_fb_chain_fb_fb_provider	_fb_modelmessager   r   resolved_providerresolved_api_moderesolved_acp_commandresolved_acp_argsresolved_credential_pool_is_callable_provider_source_has_custom_basecredentials_changedrouting_changedruntime_modelshould_use_runtime_modelr    _defaultmodel_changeds                                    E/home/ubuntu/.hermes/hermes-agent/hermes_cli/cli_agent_setup_mixin.py_ensure_runtime_credentialsz.CLIAgentSetupMixin._ensure_runtime_credentials   s    	5444444444	
 	
 	
 	
 	
 	
 	
 	

 	..1!%!7"&"9  GG
  	 	 	LLLLLL	 ?|7111111,	22 !4>t?SUY4Z4ZbD00`b	$ ! !C$'GGJ$7$7$=2#D#D#F#F#L#L#N#NL!$!1!1!7R > > @ @I' !y ! !":":\"R"R"Rc(,	     vZf v vkt v vwww2>/%.
'+$ ! ! ! ! ?EQt33LAAAWtGKMM 9W 9 9 9:::5++i((;;z**#KK
LAA#KK
DMBB&{{955 V!4!4!:;;#*;;/@#A#A  !) 1 1 R*Wc:R:R6R$ 	j#.F.F 	g 	
 kk(B//G)(C88iXi/aiJi 
+Pg     D E E Eu(C(( 	 	 D E E E5%5RT]9R. 2 DM12#t'772 !DM1	 	 *)/) 8 'H 5 5   G,, 	+Zs;; 	+ J 2
dm+2
gkk&111 %
 ( +*

 z 	/ 	
LLLLLL99:KLL !)DJKKR "3      
 ::;LMM   	6? 	6m 	6I_DJ15D.ts:   6 
A AA;AE
EE51P' '
P43P4user_messager1   dictc                   ddl m} | j        | j        | j        | j        | j        t          | j        pg           t          | dd          d}| j
        || j
        |d         |d         |d         |d	         t          |d
                   fd}t          | dd          }|sd|d<   |S 	  ||d                   }n# t          $ r d}Y nw xY w||d<   |S )aL  Build the effective model/runtime config for a single user turn.

        Always uses the session's primary model/provider.  If the user has
        toggled `/fast` on and the current model supports Priority
        Processing / Anthropic fast mode, attach `request_overrides` so the
        API call is marked accordingly.
        r   )resolve_fast_mode_overridesr5   Nr   r   r   r   r   r   r   r   r   r   r   r   )r   r>   	signatureservice_tierrequest_overridesr   )r7   rX   r   r   r   r   r3   r*   r4   getattrr   tupler&   )r<   rU   rX   r>   router[   	overridess          rS   _resolve_turn_agent_configz-CLIAgentSetupMixin._resolve_turn_agent_config   s*    	BAAAAA |',"--&t-?FF
 
 Z

#
#
#	"gfo&&
 
 t^T:: 	)-E%&L	33E'NCCII 	 	 	III	%.!"s   )B; ;C
	C
N)model_overrideruntime_overrider\   rb   rc   r\   dict | Nonec               t   ddl m}m}m}m}m}m}	m}
m} | j	        dS  |
             | 
                                 |                                  |                                 sdS ddlm}  |             | j        D	 ddlm}  |            | _        n-# t$          $ r }|                    d|           Y d}~nd}~ww xY w| j        rb| j        rZ| j        sR| j                            | j                  }t1          | d	d
          dk    }|sh|r?t3          d| j         t4          j                   t3          dt4          j                   n% |	d| j         |             |	| d|            dS 	 | j                            | j                  }n# t$          $ r
 | j        }Y nw xY w|rx|| j        k    rm |                                dt;          | j                   dt;          |           d           || _        | j                            | j                  }|r|}| j                            | j                  }|r%d |D             }|| _        t?          d |D                       }d}|                     d          rd|d          d}|rEt3          d| j         | d| d|dk    rdnd dt?          |           d
t4          j                   nw |                                d  |             d!t;          | j                   d" |             d#t;          |           d$| d|dk    rdnd dt?          |           d           | !                    ||%           ne|r%t3          d&| j         d't4          j                   n> |                                d  |             d(t;          | j                   d)           	 | j        j"        #                    d*| j        f           | j        j"        $                                 n# t$          $ r Y nw xY w	 |pE| j%        | j&        | j'        | j(        | j)        tU          | j+        pg           t1          | d+d          d,}|p| j,        } |dai d-|d.|                     d.          d/|                     d/          d0|                     d0          d1|                     d1          d2|                     d3          d4|                     d5          d6|                     d6          d7| j-        d8| j.        d9| j/        d:| j0        d;| j1        d<| j1         d	t1          | d	d=          d>| j2        r| j2        ndd?| j3        pdd@| j4        dA| j5        dB|dC| j6        dD| j7        dE| j8        dF| j9        dG| j:        dH| j;        dI| j<        dJ| j        dKdLdM| j        dN| j=        dO| >                                dP| j?        dQ| j@        dR| jA        dS| jB        dT| jC        dU| jD        dV| jE        dW| jF        dX| jF        dY| jG        dZ| jH        r| jI        ndd[| jH        r| jJ        ndd\| jK        r| jL        ndd]| jK        r| jM        ndd^| jN        d_| jO        | _	        | j	        aP|	| j	        _Q        	 dd`lRmS}  || j	                   n# t$          $ r Y nw xY w||                     d0          |                     d/          |                     d1          |                     d3          t          |                     d5          pda          f| _U        | jV        r| j        r| j	        r	 | j	        W                                 | j	        jX        r?| j        Y                    | j        | jV                    |	db| jV                    d| _V        n,# t          t$          f$ r} |	dc|            Y d}~nd}~ww xY wdS # t$          $ r,} |                                dd| de           Y d}~dS d}~ww xY w)fz
        Initialize the agent on first use.
        When resuming a session, restores conversation history from SQLite.
        
        Returns:
            bool: True if successful, False otherwise
        r   )AIAgentr
   _DIM_RST_accent_hexr   _prepare_deferred_agent_startupr   NTF)wait_for_mcp_discovery)	SessionDBuF   SQLite session store not available — session will NOT be indexed: %stool_progress_modefulloffzSession not found: )filez@Use a session ID from a previous CLI run (hermes sessions list).z[1;31mSession not found: [dim]Session  was compressed into z5; resuming the descendant with your transcript.[/dim]c                D    g | ]}|                     d           dk    |S rolesession_metar+   .0ms     rS   
<listcomp>z2CLIAgentSetupMixin._init_agent.<locals>.<listcomp>#  s,    SSS!155==N3R3RA3R3R3R    c                D    g | ]}|                     d           dk    |S ru   userrw   rx   s     rS   r{   z2CLIAgentSetupMixin._init_agent.<locals>.<listcomp>%  s,     P P Pqf8O8O8O8O8Or|   r   title ""u   ↻ Resumed session  ( user message   s, z total messages)z[bold u   ]↻ Resumed session[/] [bold]z	[/][bold ]z[/] ()quietzSession z+ found but has no messages. Starting fresh.	]Session . found but has no messages. Starting fresh.[/]CUPDATE sessions SET ended_at = NULL, end_reason = NULL WHERE id = ?r5   rY   r   r   r   r   r   r3   r   r4   r   r   
max_tokensmax_iterationsenabled_toolsetsdisabled_toolsetsverbose_logging
quiet_modeallephemeral_system_promptprefill_messagesreasoning_configr[   r\   providers_allowedproviders_ignoredproviders_orderprovider_sortprovider_require_parametersprovider_data_collectionopenrouter_min_coding_score
session_idplatformr!   
session_dbclarify_callbackreasoning_callbackfallback_modelthinking_callbackcheckpoints_enabledcheckpoint_max_snapshotscheckpoint_max_total_size_mbcheckpoint_max_file_size_mbpass_session_idskip_context_filesskip_memorytool_progress_callbacktool_start_callbacktool_complete_callbackstream_delta_callbacktool_gen_callbacknotice_callbacknotice_clear_callback)seed_credits_at_session_start z  Session title applied: z!  Could not apply pending title: z&[bold red]Failed to initialize agent: r   )[r!   rf   r
   rg   rh   ri   r   rj   r   r:   _install_tool_callbacks_ensure_tirith_securityrT   hermes_cli.mcp_startuprk   _session_dbhermes_staterl   r&   r.   _resumedconversation_historyget_sessionr   r]   r/   sysstderrresolve_resume_session_id_escapeget_messages_as_conversationlenr+   _restore_session_cwd_connexecutecommitr   r   r   r   r3   r*   r4   r   r   	max_turnsr   r   verbosesystem_promptr   r   r[   _providers_only_providers_ignore_providers_order_provider_sort_provider_require_params_provider_data_collection_openrouter_min_coding_score_clarify_callback_current_reasoning_callbackr)   _on_thinkingr   r   r   r   r   ignore_rules_on_tool_progress_inline_diffs_enabled_on_tool_start_on_tool_completestreaming_enabled_stream_delta_on_tool_gen_start
_on_notice_on_notice_clear_active_agent_ref	_print_fnagent.credits_trackerr   r^   r;   _pending_title_ensure_db_session_session_db_createdset_session_title
ValueError)r<   rb   rc   r\   rf   r
   rg   rh   ri   r   rj   r   rk   rl   erv   _quiet_moderesolved_idresolved_metarestored	msg_count
title_partr>   effective_modelr   s                            rS   _init_agentzCLIAgentSetupMixin._init_agent   s    	xwwwwwwwwwwwwwwwwwww:!4'')))$$&&&$$&&&//11 	5AAAAAA    #l222222#,9;;   l l lgijkkkkkkkkl = M	T- M	d6O M	+77HHL "$(<fEENK 
 mAAA
SSSSZ Z    
 GSDOSTSSTTTGtkkeikklllu.".HHYY . . ."o. 	1{do==##)GDO$<$< ) ){++) ) )  
 #. $ 0 < <T_ M M  1#0L'DDT_UUH SSxSSS,4) P PH P P PQQ	
##G,, A!@|G'<!@!@!@J ;t ;
 ; ;%; ;;D>>CCr; ;x==; ; ; !Z	      KMM''u u u!(!9!9u u!,u u181D1Du u &u u <E>>CCru u VYYaUbUbu u u   )),k)JJJJ _4?___ Z    
  KMM'' B  B  B9Q9Q  B  B  B   &..Y_&    &--////   f	& < M M M+T]0b11#*41CT#J#J+ +G -:
O  2 2 2%o2I...2 !Z0002 !Z000	2
 !Z0002 $KK	2222 !V,,,2 !(,= > > >2  ??2  $~~2 "&!6!62 #'"8"82 !%2  $|++2 $+41Eu#M#M#M2  ?C>P(Z(:(:VZ!2" "&!6!>$#2$ "&!6!6%2& "..'2( #4"3)2* #'"6"6+2, #'"8"8-2. !% 5 5/20 #11122 -1,I,I324 *.)G)G526 -1,M,M728  ??92: ;2<  ++=2> "&!7!7?2@ $(#C#C#E#E#EA2D  $33E2F #'"3"3G2H %)$<$<I2J *.)F)FK2L .2-N-NM2N -1,L,LO2P !% 4 4Q2R $(#4#4S2T !--U2V (,'='=W2X <@;U$_D$7$7[_Y2Z BFA['et'='=ae[2\ =A<R&\d&8&8X\]2^ >B=S"]$"9"9Y]_2` !%a2b '+&;&;c2DJj !%
 $+DJ 
OOOOOO--dj9999     J''J''J''I&&gkk&))/R002D. " 	Et'7 	EDJ 	EEJ11333z5 3(::4?DL_``` QD<O Q QRRR.2+"I. E E EGCCCDDDDDDDDE 4 	 	 	KMM O O O OPPP55555	s   >B 
B>B99B>8F F,+F,AP 
P('P(,J	` 6[ ` 
[` [B` .A$_ ` _<$_72` 7_<<` 
`7!`22`7c                   ddl m} | j        r| j        sdS | j                            | j                  }|s5|                     d| j         d           |                     d           dS 	 | j                            | j                  }n# t          $ r
 | j        }Y nw xY w|rV|| j        k    rK|                     d| j         d| d	           || _        | j                            | j                  }|r|}| j        	                    | j                  }|rd
 |D             }|| _
        t          d |D                       }d}|                    d          rd|d          d} |            }|                     d| d| j         d| d| d|dk    rdnd dt          |           d           |                     |           n- |            }|                     d| d| j         d           dS 	 | j        j                            d| j        f           | j        j                                         n# t          $ r Y nw xY wdS )a  Load a resumed session's history from the DB early (before first chat).

        Called from run() so the conversation history is available for display
        before the user sends their first message.  Sets
        ``self.conversation_history`` and prints the one-liner status.  Returns
        True if history was loaded, False otherwise.

        The corresponding block in ``_init_agent()`` checks whether history is
        already populated and skips the DB round-trip.
        r   )ri   Fz[bold red]Session not found: r   zH[dim]Use a session ID from a previous CLI run (hermes sessions list).[/]rq   rr   z2; resuming the descendant with your transcript.[/]c                D    g | ]}|                     d           dk    |S rt   rw   rx   s     rS   r{   z?CLIAgentSetupMixin._preload_resumed_session.<locals>.<listcomp>  s,    OOOaquuV}}/N/N/N/N/Nr|   c                D    g | ]}|                     d           dk    |S r~   rw   rx   s     rS   r{   z?CLIAgentSetupMixin._preload_resumed_session.<locals>.<listcomp>  s,    LLL1AEE&MMV4K4KQ4K4K4Kr|   r   r   r   r   [u   ]↻ Resumed session [bold]z[/bold]r   r   r   r   r   z total messages)[/]r   r   r   T)r!   ri   r   r   r   r   _console_printr   r&   r   r   r   r+   r   r   r   r   )	r<   ri   rv   r   r   r   r   r   accent_colors	            rS   _preload_resumed_sessionz+CLIAgentSetupMixin._preload_resumed_session  sX    	$#####} 	D$4 	5'33DODD 	DDDD   -   5	**DDT_UUKK 	* 	* 	*/KKK	* 	-;$/99S S SS S S   *DO ,88IIM -,#@@QQ 	OO8OOOH(0D%LLLLLMMIJ(( ;:,w"7:::
&;==L6L 6 6T_ 6 66 66 63<>>CCr6 6 x==6 6 6   %%l3333&;==L0L 0 04? 0 0 0   5	"**"  
 "))++++ 	 	 	D	 ts%   .B B"!B"=AI 
IIc                B   - ddl m}m}m}m}  j        sdS  j        dk    rdS |                    di           }t          |                    dd                    }t          |                    dd	                    }t          |                    d
d                    }t          |                    dd                    }	|                    dd          }
g }d}d} j        D ]}|                    dd          }|                    d          }|                    d          pg }|dk    rL|dk    rS|dk    r|dnt          |          }t          |t                    rg }|D ]}t          |t                    rC|                    d          dk    r*|                    |                    dd                     Zt          |t                    r.|                    d          dk    r|                    d           d                    |          }t          |          |k    r|d|         dz   }|                    d|f           r|dk    r
|dnt          |          } ||          }g }g }|r|                    |           |                                }t          |          |	k    r d                    |d|	                   dz   }t          |          |k    r|d|         dz   }|                    |           |rt          |          }g }|D ]^}|                    d i           }t          |t                    r|                    d!d"          nd"}||vr|                    |           _d#                    |dd$                   }t          |          d$k    r|d%z  }|d&k    rd'nd(}d)| d*| d+| d,}|                    |           |                    |           |st#          |          }|
r|s|r2|                    dd                    |          f           t          |          d&z
  }d                    |          }|sdS d} t          |          |d-z  k    rt          |          |d-z  z
  } || d         }|+|r)|| z
  }!d|!cxk    rt          |          k     r
n nd.|f||!<   dd/lm}" dd0lm}# 	 dd1lm}$  |$            }%|%                    d2d3          }&|%                    d4d5          }'|%                    d6d7          }(|%                    d8d9          })n# t2          $ r d3}&d5}'d7}(d9})Y nw xY w |#            }| r|                    d:|  d;d<=           t5          |          D ]\  }*\  }}|dk    rw|                    d>d?|' =           |                                }+|                    |+d         dz   d@=           |+d&d         D ]},|                    dA|, dd@=           n|d.k    rw|                    dBdC|) =           |                                }+|                    |+d         dz   d=           |+d&d         D ]},|                    dD|, dd=           nv|                    dBd?|) =           |                                }+|                    |+d         dz   d@=           |+d&d         D ]},|                    dD|, dd@=           |*t          |          d&z
  k     r|                    d            |"|dE|' dFdG|( dH|&I          - |- fdJ            |            5                       -           ddd           dS # 1 swxY w Y   dS )KaP  Render a compact recap of previous conversation messages.

        Uses Rich markup with dim/muted styling so the recap is visually
        distinct from the active conversation.  Caps the display at the
        last ``MAX_DISPLAY_EXCHANGES`` user/assistant exchanges and shows
        an indicator for earlier hidden messages.
        r   )
CLI_CONFIG_record_output_history_entry_strip_reasoning_tags_suspend_output_historyNminimaldisplayresume_exchanges
   resume_max_user_charsi,  resume_max_assistant_chars   resume_max_assistant_lines   resume_skip_tool_onlyTru   r   content
tool_callssystemtoolr   typetext	image_urlz[image] z...	assistant
z ...functionr   unknownr      z, ...r   callcallsr   z tool z: r      assistant_last)Panel)Text)get_active_skinbanner_textz#FFF8DCsession_labelz#DAA520session_borderz#8B8682ui_okz#8FBC8Fz  ... z earlier messages ...

z
dim italic)styleu     ● You: z	dim bold dimz	         u     ◆ Hermes: zbold z            z[dim z]Previous Conversation[/]zdim )r   r   )r   border_stylepaddingr  c                 .                                    S )N)"_render_resume_history_panel_lines)panelr<   s   rS   <lambda>z=CLIAgentSetupMixin._display_resumed_history.<locals>.<lambda>  s    T-T-TUZ-[-[ r|   )r!   r   r   r   r   r   resume_displayr+   intr1   r(   r*   rV   appendjoinr   
splitlinesr   
rich.panelr  	rich.textr  hermes_cli.skin_enginer  	get_colorr&   	enumerater   ).r<   r   r   r   r   _dispMAX_DISPLAY_EXCHANGESMAX_USER_LENMAX_ASST_LENMAX_ASST_LINESSKIP_TOOL_ONLYentries_last_asst_idx_last_asst_fullmsgru   r  r  r
  partspart
full_partslinestc_countnamestcfnr   	names_strnoun
tc_summaryhas_textskippedadj_idxr  r  r  _skin_history_text_c_session_label_c_session_border_c_assistant_label_ci	msg_linesmlr#  s.   `                                            @rS   _display_resumed_historyz+CLIAgentSetupMixin._display_resumed_history  s`	    	qppppppppppp( 	F )++F y"-- #EII.@"$E$E F F599%<cBBCC599%A3GGHHUYY'CQGGHH#:DAA , ?	7 ?	7C7762&&Dggi((G..4"Jxv~~v~~$_rr#g,,gt,, +E ' 4 4%dD11 4dhhv6F6F&6P6P!LL&")=)=>>>>'d33 48H8HK8W8W!LL33388E??Dt99|++.6D~....$$$_rr#g,,,,T22
 '%%d+++ OO--E5zzN22#yy)?@@6I4yy<//#M\M2U:LL&&& 2":HE( / /VVJ33<Fr4<P<P_rvvfi888V_u,,!LL... $		%) 4 4I5zzA~~!W,	%-]]66D!IX!I!IT!I!IY!I!I!IJLL,,,%%j111 ::! ( z SXXe__=>>>!$W!1"%((:"6"6 	F w<</!333'll%:Q%>>Gghh'G %/%$w.GG****c'll*****$4o#F  	%$$$$$""""""	+>>>>>>#O%%E#oomYGGO$	JJ %0@) L L!&)!D!D 	+ 	+ 	+'O( )!*		+  	LL;;;;"    
  )11 	! 	!OA|dv~~]2P>N2P2PQQQ OO--	Yq\D0>>>#ABB- B BBLL!3R!3!3!35LAAAAB)))-5Q=O5Q5QRRR OO--	Yq\D0;;;#ABB- B BBLL!6!6!6!6bLAAAAB -5UAS5U5UVVV OO--	Yq\D0>>>#ABB- E EBLL!6!6!6!6eLDDDD3w<<!###R   E*EEE3 133!
 
 
 	%$%[%[%[%[%[\\\$$&& 	' 	'&&&	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	's%   $A(U U"!U"1^^^)r   r   )rU   r1   r   rV   )rb   r1   rc   rV   r\   rd   r   r   )	__name__
__module____qualname____doc__rT   ra   r   r   rO  r   r|   rS   r   r      s        PPS S S Sj* * * *X 48RVy} X X X X X XtM M M M^f' f' f' f' f'r|   r   )rS  
__future__r   r   rich.markupr   r   r   r   r|   rS   <module>rV     sz     # " " " " " 



 ) ) ) ) ) )S
' S
' S
' S
' S
' S
' S
' S
' S
' S
'r|   