
    &em                       U d dl mZ d dlZd dlmZ d dlmZmZmZmZ d dl	m
Z
 d dlmZmZmZmZmZmZmZmZmZ d dlmZ d dlmZ d d	lmZ d d
lmZmZmZ d dlm Z  d dl!m"Z# d dl$m%Z& d dl'm(Z( d dl)m*Z*m+Z+ d dl,m-Z-m.Z.m/Z/m0Z0 d dl1m2Z2 d dl3m4Z4m5Z5m6Z6m7Z7 erd dl8m9Z9 eeedf         Z:de;d<   ee:ee:         f         Z<de;d<   eeed         ee         eeef         df         Z=de;d<   dZ> ej?        d          Z@d1dZAd2d$ZBd3d&ZC ed'(           G d) d*                      ZDe G d+ d,                      ZEe G d- d.                      ZF G d/ d0          ZGdS )4    )annotationsN)	dataclass)datedatetimetime	timedelta)dedent)	TYPE_CHECKINGAnyListLiteralSequenceTupleUnioncastoverload)relativedelta)	TypeAlias)current_form_id)check_callback_rulescheck_session_state_rules get_label_visibility_proto_value)StreamlitAPIException)	DateInput)	TimeInput)gather_metrics)ScriptRunContextget_script_run_ctx)
WidgetArgsWidgetCallbackWidgetKwargsregister_widget)compute_widget_id)KeyLabelVisibilitymaybe_raise_label_warningsto_key)DeltaGeneratorr   SingleDateValue	DateValue DateWidgetReturn   zB^(YYYY[/.\-]MM[/.\-]DD|DD[/.\-]MM[/.\-]YYYY|MM[/.\-]DD[/.\-]YYYY)$valueDateValue | Literal['today']returnTuple[List[date] | None, bool]c                   d}| d |fS | dk    r't          j                                                    g}nt          | t                     r|                                 g}nst          | t                    r| g}nZt          | t          t
          f          r/t          |           dvrt          d          d | D             }d}nt          d          ||fS )NFtoday)r         z_DateInput value should either be an date/datetime or a list/tuple of 0 - 2 date/datetime valuesc                d    g | ]-}t          |t                    r|                                n|.S r+   )
isinstancer   r   .0vs     Glib/python3.11/site-packages/streamlit/elements/widgets/time_widgets.py
<listcomp>z%_parse_date_value.<locals>.<listcomp>[   s3    RRRqJq($;$;BRRR    T)r   nowr   r7   listtuplelenr   )r.   range_valueparsed_datess      r;   _parse_date_valuerD   F   s     K}[   ++--.	E8	$	$ 


~	E4	 	  
w	ED%=	)	) 
5zzY&&'-  
 SRERRR#)
 
 	
 $$r=   	min_valuerC   Sequence[date] | Noner   c                B   t          | t                    r|                                 }ntt          | t                    r| }n\| K|r|d         t          j        d          z
  }n9t          j                    t          j        d          z
  }nt          d          |S )Nr   
   yearsz6DateInput min should either be a date/datetime or Noner7   r   r   r   r3   r   )rE   rC   parsed_min_dates      r;   _parse_min_daterM   e   s    
 )X&& 
#..**	It	$	$ 

#		 	S*1o0KRT0U0U0UUOO"jll]-Hr-R-R-RROO#D
 
 	
 r=   	max_valuec                B   t          | t                    r|                                 }ntt          | t                    r| }n\| K|r|d         t          j        d          z   }n9t          j                    t          j        d          z   }nt          d          |S )NrH   rI   z6DateInput max should either be a date/datetime or NonerK   )rN   rC   parsed_max_dates      r;   _parse_max_daterR   z   s    
 )X&& 
#..**	It	$	$ 

#		 	S*2.1LSU1V1V1VVOO"jll]-Hr-R-R-RROO#D
 
 	
 r=   T)frozenc                  X    e Zd ZU ded<   ded<   ded<   ded<   edd            ZddZdS )_DateInputValuesrF   r.   boolis_ranger   maxminr/   rE   r)   rN   r0   '_DateInputValues'c           	         t          |          \  }} | ||t          ||          t          ||                    S )N)r.   )rE   rC   )rN   rC   )r.   rW   rY   rX   )rD   rM   rR   )clsr.   rE   rN   parsed_valuerW   s         r;   from_raw_valuesz _DateInputValues.from_raw_values   sj     "3!?!?!?hs#)    #)  
 
 
 	
r=   Nonec           	     (   | j         | j        k    r t          d| j          d| j         d          | j        rX| j        d         }| j        d         }|| j         k     s|| j        k    r*t          d| j         d| j          d| j         d	          d S d S )
NzThe `min_value`, set to z3, shouldn't be larger than the `max_value`, set to .r   rP   zThe default `value` of z% must lie between the `min_value` of z and the `max_value` of z, inclusively.)rY   rX   r   r.   )selfstart_value	end_values      r;   __post_init__z_DateInputValues.__post_init__   s    8dh'<48 < <04< < <  
 : 		*Q-K
2Idh&&I,@,@+Gdj G G;?8G G.2hG G G  		 		 -A,@r=   N)r.   r/   rE   r)   rN   r)   r0   rZ   )r0   r_   )__name__
__module____qualname____annotations__classmethodr^   re   r+   r=   r;   rU   rU      so             NNNIIIIII
 
 
 [
(     r=   rU   c                  ,    e Zd ZU ded<   ddd	ZddZdS )TimeInputSerdetime | Noner.    ui_value
str | None	widget_idr   r0   c                b    |'t          j        |d                                          n| j        S N%H:%M)r   strptimer   r.   )rb   ro   rq   s      r;   deserializezTimeInputSerde.deserialize   s5     # h0055777	
r=   r:   datetime | time | Nonec                    |d S t          |t                    r|                                }t          j        |d          S rs   )r7   r   r   strftime)rb   r:   s     r;   	serializezTimeInputSerde.serialize   s=    94a"" 	A}Q(((r=   Nrn   )ro   rp   rq   r   r0   rm   )r:   rw   r0   rp   rf   rg   rh   ri   rv   rz   r+   r=   r;   rl   rl      sO         
 
 
 
 
) ) ) ) ) )r=   rl   c                  .    e Zd ZU ded<   	 ddd
ZddZdS )DateInputSerderU   r.   rn   ro   r   rq   strr0   r,   c                   |t          d |D                       }n| j        j        }|t          |          dk    r| j        j        rdnd S | j        j        s|d         S t	          t
          t          |                    S )Nc              3  d   K   | ]+}t          j        |d                                           V  ,dS )%Y/%m/%dN)r   ru   r   r8   s     r;   	<genexpr>z-DateInputSerde.deserialize.<locals>.<genexpr>   sL       ! !<=!!Z005577! ! ! ! ! !r=   r   r+   )r@   r.   rA   rW   r   r,   )rb   ro   rq   return_values       r;   rv   zDateInputSerde.deserialize   s       ! !AI! ! !  LL  :+L3|#4#4#9#9,622$6z" 	#?"$eL&9&9:::r=   r:   	List[str]c                ~    |g S t          |t          t          f          rt          |          n|g}d |D             S )Nc                8    g | ]}t          j        |d           S r   r   ry   r8   s     r;   r<   z,DateInputSerde.serialize.<locals>.<listcomp>   s$    CCCa,,CCCr=   )r7   r?   r@   )rb   r:   to_serializes      r;   rz   zDateInputSerde.serialize   sD    9I",Qu">">GtAwwwQCCClCCCCr=   Nr{   )ro   r   rq   r   r0   r,   )r:   r,   r0   r   r|   r+   r=   r;   r~   r~      sZ         
 ; ; ; ; ;(D D D D D Dr=   r~   c                     e Zd Ze	 	 	 	 	 	 d7dd ee          dd8d            Ze	 	 	 	 	 	 d9dd ee          dd:d             Z ed!          	 	 	 	 	 	 d7dd ee          dd;d#            Z	 	 	 	 	 	 d7dd ee          dd$d<d'Z ed(          	 	 	 	 	 	 	 	 d=d*ddd+d>d2            Z		 	 	 	 	 	 	 	 d=d*dddd3d?d4Z
ed@d6            ZdS )ATimeWidgetsMixinr>   NFvisible)minutes)disabledlabel_visibilitysteplabelr   r.    time | datetime | Literal['now']key
Key | Nonehelprp   	on_changeWidgetCallback | NoneargsWidgetArgs | NonekwargsWidgetKwargs | Noner   rV   r   r%   r   Union[int, timedelta]r0   r   c                   d S Nr+   rb   r   r.   r   r   r   r   r   r   r   r   s              r;   
time_inputzTimeWidgetsMixin.time_input   	     	r=   r_   rm   c                   d S r   r+   r   s              r;   r   zTimeWidgetsMixin.time_input  r   r=   r   'time | datetime | Literal['now'] | Nonec               ^    t                      }|                     |||||||||	|
|          S )a}  Display a time input widget.

        Parameters
        ----------
        label : str
            A short label explaining to the user what this time input is for.
            The label can optionally contain Markdown and supports the following
            elements: Bold, Italics, Strikethroughs, Inline Code, Emojis, and Links.

            This also supports:

            * Emoji shortcodes, such as ``:+1:``  and ``:sunglasses:``.
              For a list of all supported codes,
              see https://share.streamlit.io/streamlit/emoji-shortcodes.

            * LaTeX expressions, by wrapping them in "$" or "$$" (the "$$"
              must be on their own lines). Supported LaTeX functions are listed
              at https://katex.org/docs/supported.html.

            * Colored text, using the syntax ``:color[text to be colored]``,
              where ``color`` needs to be replaced with any of the following
              supported colors: blue, green, orange, red, violet, gray/grey, rainbow.

            Unsupported elements are unwrapped so only their children (text contents) render.
            Display unsupported elements as literal characters by
            backslash-escaping them. E.g. ``1\. Not an ordered list``.

            For accessibility reasons, you should never set an empty label (label="")
            but hide it with label_visibility if needed. In the future, we may disallow
            empty labels by raising an exception.
        value : datetime.time/datetime.datetime, "now" or None
            The value of this widget when it first renders. This will be
            cast to str internally. If ``None``, will initialize empty and
            return ``None`` until the user selects a time. If "now" (default),
            will initialize with the current time.
        key : str or int
            An optional string or integer to use as the unique key for the widget.
            If this is omitted, a key will be generated for the widget
            based on its content. Multiple widgets of the same type may
            not share the same key.
        help : str
            An optional tooltip that gets displayed next to the input.
        on_change : callable
            An optional callback invoked when this time_input's value changes.
        args : tuple
            An optional tuple of args to pass to the callback.
        kwargs : dict
            An optional dict of kwargs to pass to the callback.
        disabled : bool
            An optional boolean, which disables the time input if set to True.
            The default is False.
        label_visibility : "visible", "hidden", or "collapsed"
            The visibility of the label. If "hidden", the label doesn't show but there
            is still empty space for it above the widget (equivalent to label="").
            If "collapsed", both the label and the space are removed. Default is
            "visible".
        step : int or timedelta
            The stepping interval in seconds. Defaults to 900, i.e. 15 minutes.
            You can also pass a datetime.timedelta object.

        Returns
        -------
        datetime.time or None
            The current value of the time input widget or ``None`` if no time has been
            selected.

        Example
        -------
        >>> import datetime
        >>> import streamlit as st
        >>>
        >>> t = st.time_input('Set an alarm for', datetime.time(8, 45))
        >>> st.write('Alarm is set for', t)

        .. output::
           https://doc-time-input.streamlit.app/
           height: 260px

        To initialize an empty time input, use ``None`` as the value:

        >>> import datetime
        >>> import streamlit as st
        >>>
        >>> t = st.time_input('Set an alarm for', value=None)
        >>> st.write('Alarm is set for', t)

        .. output::
           https://doc-time-input-empty.streamlit.app/
           height: 260px

        )r   r.   r   r   r   r   r   r   r   r   ctx)r   _time_input)rb   r   r.   r   r   r   r   r   r   r   r   r   s               r;   r   zTimeWidgetsMixin.time_input  sN    T !""-   
 
 	
r=   )r   r   r   r   r   ScriptRunContext | Nonec                  t          |          }t          | j        |           t          |dk    r|nd |           t	          ||	           |d }n|dk    r;t          j                                                                        dd          }nft          |t
                    r*|                                                    dd          }n't          |t                    r|}nt          d          t          d||t          |t
          t          f          r|n||||
t          | j                  |r|j        nd 	  	        }~t                      }||_        ||_        |t          j        |d          |_        t          | j                  |_        t          |
t(          t*          f          s t          d	t-          |
           d
          t          |
t*                    r|
j        }
|
dk     s|
t+          d          j        k    rt          d|
 d          |
|_        ||_        t5          |	          |j        _        |t;          |          |_        t?          |          }tA          d||||||j!        |j"        |	  	        }|j#        r*|"                    |j                  x}||_        d|_$        | j        %                    d|           |j        S )Nr>   default_valuer   r   )secondmicrosecondz9The type of value should be one of datetime, time or Noner   )user_keyr   r.   r   r   r   form_idpagert   z,`step` can only be `int` or `timedelta` but z is provided.<      )hourszG`step` must be between 60 seconds and 23 hours but is currently set to z	 seconds.r   on_change_handlerr   r   deserializer
serializerr   T)&r'   r   dgr   r&   r   r>   r   replacer7   r   r#   r   page_script_hashTimeInputProtoidr   ry   defaultr   intr   typesecondsr   r   r   r   r.   r	   r   rl   r"   rv   rz   value_changed	set_value_enqueue)rb   r   r.   r   r   r   r   r   r   r   r   r   parsed_timer   time_input_protoserdewidget_stateserialized_values                     r;   r   zTimeWidgetsMixin._time_input  s-    SkkTWi000!#(E>>%%t	
 	
 	
 	
 	#5*:;;; =KKe^^",..--//77qa7PPKKx(( 	**,,..aQ.GGKKt$$ 	KK'K   !+EHd3C!D!DO++%#DG,,),6%%$

 

 

 )++ !&"'+}[''J'J$#247#;#; $i 011 	'XtDzzXXX   dI&& 	 <D"99yr222:::'iZ^iii   !%$,!2R3
 3
)/ $*4LL!{++&'*

 

 

 % 	.$)OOL4F$G$GG T)9 &)-&'7888!!r=   
date_inputr3   z
YYYY/MM/DD)formatr   r   r/   rE   r)   rN   r   r,   c
               b    t                      }|                     |||||||||	|||
|          S )u  Display a date input widget.

        Parameters
        ----------
        label : str
            A short label explaining to the user what this date input is for.
            The label can optionally contain Markdown and supports the following
            elements: Bold, Italics, Strikethroughs, Inline Code, Emojis, and Links.

            This also supports:

            * Emoji shortcodes, such as ``:+1:``  and ``:sunglasses:``.
              For a list of all supported codes,
              see https://share.streamlit.io/streamlit/emoji-shortcodes.

            * LaTeX expressions, by wrapping them in "$" or "$$" (the "$$"
              must be on their own lines). Supported LaTeX functions are listed
              at https://katex.org/docs/supported.html.

            * Colored text, using the syntax ``:color[text to be colored]``,
              where ``color`` needs to be replaced with any of the following
              supported colors: blue, green, orange, red, violet, gray/grey, rainbow.

            Unsupported elements are unwrapped so only their children (text contents) render.
            Display unsupported elements as literal characters by
            backslash-escaping them. E.g. ``1\. Not an ordered list``.

            For accessibility reasons, you should never set an empty label (label="")
            but hide it with label_visibility if needed. In the future, we may disallow
            empty labels by raising an exception.
        value : datetime.date or datetime.datetime or list/tuple of datetime.date or datetime.datetime, "today", or None
            The value of this widget when it first renders. If a list/tuple with
            0 to 2 date/datetime values is provided, the datepicker will allow
            users to provide a range. If ``None``, will initialize empty and
            return ``None`` until the user provides input. If "today" (default),
            will initialize with today as a single-date picker.
        min_value : datetime.date or datetime.datetime
            The minimum selectable date. If value is a date, defaults to value - 10 years.
            If value is the interval [start, end], defaults to start - 10 years.
        max_value : datetime.date or datetime.datetime
            The maximum selectable date. If value is a date, defaults to value + 10 years.
            If value is the interval [start, end], defaults to end + 10 years.
        key : str or int
            An optional string or integer to use as the unique key for the widget.
            If this is omitted, a key will be generated for the widget
            based on its content. Multiple widgets of the same type may
            not share the same key.
        help : str
            An optional tooltip that gets displayed next to the input.
        on_change : callable
            An optional callback invoked when this date_input's value changes.
        args : tuple
            An optional tuple of args to pass to the callback.
        kwargs : dict
            An optional dict of kwargs to pass to the callback.
        format : str
            A format string controlling how the interface should display dates.
            Supports “YYYY/MM/DD” (default), “DD/MM/YYYY”, or “MM/DD/YYYY”.
            You may also use a period (.) or hyphen (-) as separators.
        disabled : bool
            An optional boolean, which disables the date input if set to True.
            The default is False.
        label_visibility : "visible", "hidden", or "collapsed"
            The visibility of the label. If "hidden", the label doesn't show but there
            is still empty space for it above the widget (equivalent to label="").
            If "collapsed", both the label and the space are removed. Default is
            "visible".


        Returns
        -------
        datetime.date or a tuple with 0-2 dates or None
            The current value of the date input widget or ``None`` if no date has been
            selected.

        Examples
        --------
        >>> import datetime
        >>> import streamlit as st
        >>>
        >>> d = st.date_input("When's your birthday", datetime.date(2019, 7, 6))
        >>> st.write('Your birthday is:', d)

        .. output::
           https://doc-date-input.streamlit.app/
           height: 380px

        >>> import datetime
        >>> import streamlit as st
        >>>
        >>> today = datetime.datetime.now()
        >>> next_year = today.year + 1
        >>> jan_1 = datetime.date(next_year, 1, 1)
        >>> dec_31 = datetime.date(next_year, 12, 31)
        >>>
        >>> d = st.date_input(
        ...     "Select your vacation for next year",
        ...     (jan_1, datetime.date(next_year, 1, 7)),
        ...     jan_1,
        ...     dec_31,
        ...     format="MM.DD.YYYY",
        ... )
        >>> d

        .. output::
           https://doc-date-input1.streamlit.app/
           height: 380px

        To initialize an empty date input, use ``None`` as the value:

        >>> import datetime
        >>> import streamlit as st
        >>>
        >>> d = st.date_input("When's your birthday", value=None)
        >>> st.write('Your birthday is:', d)

        .. output::
           https://doc-date-input-empty.streamlit.app/
           height: 380px

        )r   r.   rE   rN   r   r   r   r   r   r   r   r   r   )r   _date_input)rb   r   r.   rE   rN   r   r   r   r   r   r   r   r   r   s                 r;   r   zTimeWidgetsMixin.date_input  sT    T !""-   
 
 	
r=   )r   r   r   r   c
               R   t          |          }t          | j        |           t          |dk    r|nd |           t	          ||           dd |          } |          }|dk    s|d }n6t          |t          t          f          r |          }nfd|D             }t          d	||||||||
t          | j                  |r|j
        nd 
          }t          t                              |
                    st          d|
 d          t                              |||          }~~~t#                      }||_        |j        |_        ||_        t+          |          |j        _        |
|_        ||_        |j        g |j        d d <   nd |j        D             |j        d d <   t          j        |j        d          |_        t          j        |j        d          |_        t          | j                  |_        |t?          |          |_         tC          |          }tE          d	|||||	|j#        |j$        |	  	        }|j%        r+|$                    |j                  |j        d d <   d|_&        | j        '                    d	|           |j        S )Nr3   r   r:   "SingleDateValue | Literal['today']r0   rp   c                    t          | t                    r't          j        |                                 d          S t          | t                    rt          j        | d          S d S )Nr   )r7   r   r   ry   )r:   s    r;   parse_date_deterministicz>TimeWidgetsMixin._date_input.<locals>.parse_date_deterministic  sY     !X&& 4}QVVXXz:::At$$ 4}Q
3334r=   c                L    g | ] } t          t          |                    !S r+   )r   r)   )r9   r:   r   s     r;   r<   z0TimeWidgetsMixin._date_input.<locals>.<listcomp>  s/    XXXQ..tOQ/G/GHHXXXr=   r   )
r   r   r.   rE   rN   r   r   r   r   r   zThe provided format (`z`) is not valid. DateInput format should be one of `YYYY/MM/DD`, `DD/MM/YYYY`, or `MM/DD/YYYY` and can also use a period (.) or hyphen (-) as separators.)r.   rE   rN   c                8    g | ]}t          j        |d           S r   r   r8   s     r;   r<   z0TimeWidgetsMixin._date_input.<locals>.<listcomp>  s1     + + +12a,,+ + +r=   r   r   T)r:   r   r0   rp   )(r'   r   r   r   r&   r7   r   r   r#   r   r   rV   ALLOWED_DATE_FORMATSmatchr   rU   r^   DateInputProtor   rW   r   r   r   r.   r   r   r   ry   rY   rX   r   r	   r   r~   r"   rv   rz   r   r   r   )rb   r   r.   rE   rN   r   r   r   r   r   r   r   r   r   rL   rQ   parsedr   parsed_valuesdate_input_protor   r   r   s                         @r;   r   zTimeWidgetsMixin._date_input  sS   " SkkTWi000!#(G#3#3%%3	
 	
 	
 	
 	#5*:;;;	 	 	 	 329==229== Gu}FF$/00 	Y--e44FFXXXXRWXXXF %%#DG,,),6%%$
 
 
 (..v6677 	'M M M M   )88 9 
 

 9i)++ $1$:!$,!2R3
 3
)/ #)!&& +-$QQQ''+ +6C6I+ + +$QQQ'  $}]->
KK#}]->
KK#247#;#; $*4LL!}--&'*

 

 

 % 	.(-8J(K(K"111%)-&'7888!!r=   'DeltaGenerator'c                "    t          d|           S )zGet our DeltaGenerator.r(   )r   )rb   s    r;   r   zTimeWidgetsMixin.dg   s     $d+++r=   )r>   NNNNN)r   r   r.   r   r   r   r   rp   r   r   r   r   r   r   r   rV   r   r%   r   r   r0   r   )NNNNNN)r   r   r.   r_   r   r   r   rp   r   r   r   r   r   r   r   rV   r   r%   r   r   r0   rm   )r   r   r.   r   r   r   r   rp   r   r   r   r   r   r   r   rV   r   r%   r   r   r0   rm   )r   r   r.   r   r   r   r   rp   r   r   r   r   r   r   r   rV   r   r%   r   r   r   r   r0   rm   )r3   NNNNNNN)r   r   r.   r/   rE   r)   rN   r)   r   r   r   rp   r   r   r   r   r   r   r   r   r   rV   r   r%   r0   r,   )r   r   r.   r/   rE   r)   rN   r)   r   r   r   rp   r   r   r   r   r   r   r   r   r   rV   r   r%   r   r   r0   r,   )r0   r   )rf   rg   rh   r   r   DEFAULT_STEP_MINUTESr   r   r   r   r   propertyr   r+   r=   r;   r   r      sn        38+/"&&* ,5&/i8L&M&M&M     X   +/"&&* ,5&/i8L&M&M&M     X  ^L!! :?+/"&&*v
 ,5&/i8L&M&M&Mv
 v
 v
 v
 v
 "!v
v :?+/"&&*^" ,5&/i8L&M&M&M'+^" ^" ^" ^" ^" ^"@ ^L!! /6%)%)+/"&&*X
 #,5X
 X
 X
 X
 X
 "!X
z /6%)%)+/"&&*v" #,5'+v" v" v" v" v" v"p , , , X, , ,r=   r   )r.   r/   r0   r1   )rE   r)   rC   rF   r0   r   )rN   r)   rC   rF   r0   r   )H
__future__r   redataclassesr   r   r   r   r   textwrapr	   typingr
   r   r   r   r   r   r   r   r   dateutilr   typing_extensionsr   streamlit.elements.formr   streamlit.elements.utilsr   r   r   streamlit.errorsr   streamlit.proto.DateInput_pb2r   r   streamlit.proto.TimeInput_pb2r   r   streamlit.runtime.metrics_utilr   streamlit.runtime.scriptrunnerr   r   streamlit.runtime.stater   r    r!   r"   streamlit.runtime.state.commonr#   streamlit.type_utilr$   r%   r&   r'   streamlit.delta_generatorr(   r)   ri   r*   r,   r   compiler   rD   rM   rR   rU   rl   r~   r   r+   r=   r;   <module>r      s   # " " " " " " 				 ! ! ! ! ! ! 4 4 4 4 4 4 4 4 4 4 4 4      
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 # " " " " " ' ' ' ' ' ' 3 3 3 3 3 3         
 3 2 2 2 2 2 E E E E E E E E E E E E 9 9 9 9 9 9 O O O O O O O O            = < < < < < X X X X X X X X X X X X 9888888"44#78 8 8 8 8_h.GGH	 H H H H#%)U4[%d
"3T9       !rzI  
% % % %>   *   * $+ + + + + + + +\ ) ) ) ) ) ) ) )$ D D D D D D D D>R, R, R, R, R, R, R, R, R, R,r=   