
    ljFa                    N   U d Z ddlmZ ddlmZ ddlmZmZ ddlm	Z	 ddl
m
Z
 ddlmZmZ dd	lmZ dd
lmZmZ g d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mZmZ erddl m!Z! dZ"de#d<   dZ$de#d<    G d d          Z%d%dZ& G d de%          Z' G d de%          Z(d&d#Z)d$S )'zAnimate mobjects.    )annotations)OpenGLMobject   )configlogger)RendererTypemobject)GroupMobject)opengl_mobject)linearsmooth)	AnimationWaitAddoverride_animation)CallableIterableSequencedeepcopy)partialmethod)TYPE_CHECKINGAnySelf)Sceneg      ?floatDEFAULT_ANIMATION_RUN_TIME        DEFAULT_ANIMATION_LAG_RATIOc                      e Zd ZdZ	 dJdddK fdZeeedddddfd	 dd
dLdZe	dMd            Z
e
j        dNd             Z
dOd"ZdPd#ZdPd$ZdQd%ZdQd&ZdRd)ZdRd*ZdSd,ZdTd.ZdUd0ZdVd2ZdWd4ZdXd5ZdYd7ZdYd8ZdZd<Zd[d@Zd\dAZdMdBZd]dCZd^dDZ d_dEZ!d`dFZ"d`dGZ#e$dQ fdH            Z%eZ&e$dQdI            Z' xZ(S )ar   aD  An animation.

    Animations have a fixed time span.

    Parameters
    ----------
    mobject
        The mobject to be animated. This is not required for all types of animations.
    lag_ratio
        Defines the delay after which the animation is applied to submobjects. This lag
        is relative to the duration of the animation.

        This does not influence the total
        runtime of the animation. Instead the runtime of individual animations is
        adjusted so that the complete animation has the defined run time.

    run_time
        The duration of the animation in seconds.
    rate_func
        The function defining the animation progress based on the relative runtime (see  :mod:`~.rate_functions`) .

        For example ``rate_func(0.5)`` is the proportion of the animation that is done
        after half of the animations run time.

    reverse_rate_function
        Reverses the rate function of the animation. Setting ``reverse_rate_function``
        does not have any effect on ``remover`` or ``introducer``. These need to be
        set explicitly if an introducer-animation should be turned into a remover one
        and vice versa.
    name
        The name of the animation. This gets displayed while rendering the animation.
        Defaults to <class-name>(<Mobject-name>).
    remover
        Whether the given mobject should be removed from the scene after this animation.
    suspend_mobject_updating
        Whether updaters of the mobject should be suspended during the animation.


    .. NOTE::

        In the current implementation of this class, the specified rate function is applied
        within :meth:`.Animation.interpolate_mobject` call as part of the call to
        :meth:`.Animation.interpolate_submobject`. For subclasses of :class:`.Animation`
        that are implemented by overriding :meth:`interpolate_mobject`, the rate function
        has to be applied manually (e.g., by passing ``self.rate_func(alpha)`` instead
        of just ``alpha``).


    Examples
    --------

    .. manim:: LagRatios

        class LagRatios(Scene):
            def construct(self):
                ratios = [0, 0.1, 0.5, 1, 2]  # demonstrated lag_ratios

                # Create dot groups
                group = VGroup(*[Dot() for _ in range(4)]).arrange_submobjects()
                groups = VGroup(*[group.copy() for _ in ratios]).arrange_submobjects(buff=1)
                self.add(groups)

                # Label groups
                self.add(Text("lag_ratio = ", font_size=36).next_to(groups, UP, buff=1.5))
                for group, ratio in zip(groups, ratios):
                    self.add(Text(str(ratio), font_size=36).next_to(group, UP))

                #Animate groups with different lag_ratios
                self.play(AnimationGroup(*[
                    group.animate(lag_ratio=ratio, run_time=1.5).shift(DOWN * 2)
                    for group, ratio in zip(groups, ratios)
                ]))

                # lag_ratio also works recursively on nested submobjects:
                self.play(groups.animate(run_time=1, lag_ratio=0.1).shift(UP * 2))

    NT)use_overridereturnr   c                  t          |t                    rT|rR |j        |           }|@ ||g|R i |}t          j        d| j         dt          |          j         d           |S t                                          |           S )NzThe z# animation has been overridden for za mobjects. use_override = False can  be used as keyword argument to prevent animation overriding.)	
isinstancer   animation_override_forr   debug__name__typesuper__new__)clsr
   r#   argskwargsfuncanim	__class__s          T/home/agentuser/manim-venv/lib/python3.11/site-packages/manim/animation/animation.pyr,   zAnimation.__new__m   s     gw'' 		L 		171#66DtG5d555f55U3< U UG}}-U U U  
 wws###    Fc                    d S N )_s    r3   <lambda>zAnimation.<lambda>   s    4 r4   )
_on_finishr#   r
   Mobject | OpenGLMobject | None	lag_ratior   run_time	rate_funcCallable[[float], float]reverse_rate_functionboolnamestrremoversuspend_mobject_updating
introducerr:   Callable[[], None]r#   Nonec
                  |                      |           || _        || _        || _        || _        || _        |	| _        || _        || _        |
| _	        t          d         t          j        k    r+t                      | _        ||nt                      | _        n*t!                      | _        ||nt!                      | _        t#          | d          rt%          j        d           d S d S )NrendererCONFIG)z,CONFIG has been removed from ManimCommunity.z%Please use keyword arguments instead.)_typecheck_inputr=   r>   r@   rB   rD   rF   rE   r<   r:   r   r   OPENGLr   starting_mobjectr
   r   hasattrr   error)selfr
   r<   r=   r>   r@   rB   rD   rE   rF   r:   r#   s               r3   __init__zAnimation.__init__   s     	g&&&'3<+@" $	$ *.F% )3=*!4443@??D!".MOO LL .5YYD!/6/BGG		DL4"" 	L    	 	r4   c                    | j         S r6   )	_run_timerQ   s    r3   r=   zAnimation.run_time   s
    ~r4   valuec                `    |dk     r t          d| j        j         d| d          || _        d S )Nr   zThe run_time of z) cannot be negative. The given value was .)
ValueErrorr2   r)   rT   )rQ   rV   s     r3   r=   zAnimation.run_time   sR    199:4>#: : :16: : :   r4   Mobject | Nonec                    |t          j        d           d S t          |t          t          f          st          d          d S )NzAnimation with empty mobjectz Animation only works on Mobjects)r   r(   r&   r   r   	TypeError)rQ   r
   s     r3   rL   zAnimation._typecheck_input   sQ    ?L788888Gg}%=>> 	@>???	@ 	@r4   c                f    | j         r| j         S | j        j         dt          | j                   dS )N())rB   r2   r)   rC   r
   rU   s    r3   __str__zAnimation.__str__   s:    9 	9.)@@C,=,=@@@@r4   c                     t          |           S r6   )rC   rU   s    r3   __repr__zAnimation.__repr__   s    4yyr4   c                    |                                  | _        | j        r| j                                         |                     d           dS )zBegin the animation.

        This method is called right as an animation is being played. As much
        initialization as possible, especially any mobject copying, should live in this
        method.

        r   N)create_starting_mobjectrN   rE   r
   suspend_updatinginterpolaterU   s    r3   beginzAnimation.begin   sS     !% < < > >( 	, L))+++r4   c                    |                      d           | j        r"| j        | j                                         dS dS dS )z\Finish the animation.

        This method gets called when the animation is over.

           N)rf   rE   r
   resume_updatingrU   s    r3   finishzAnimation.finish   sT     	( 	+T\-EL((*****	+ 	+-E-Er4   scener   c                    |                      |           |                                 r|                    | j                   dS dS )a4  Clean up the :class:`~.Scene` after finishing the animation.

        This includes to :meth:`~.Scene.remove` the Animation's
        :class:`~.Mobject` if the animation is a remover.

        Parameters
        ----------
        scene
            The scene the animation should be cleaned up from.
        N)r:   
is_removerremover
   rQ   rl   s     r3   clean_up_from_scenezAnimation.clean_up_from_scene   sL     	?? 	'LL&&&&&	' 	'r4   c                    |dS |                                  r7| j        |                                vr|                    | j                   dS dS dS )a5  Setup up the :class:`~.Scene` before starting the animation.

        This includes to :meth:`~.Scene.add` the Animation's
        :class:`~.Mobject` if the animation is an introducer.

        Parameters
        ----------
        scene
            The scene the animation should be cleaned up from.
        N)is_introducerr
   get_mobject_family_membersaddrp   s     r3   _setup_scenezAnimation._setup_scene   se     =F  	$E$D$D$F$FFFIIdl#####		$ 	$FFr4   Mobject | OpenGLMobjectc                4    | j                                         S r6   )r
   copyrU   s    r3   rd   z!Animation.create_starting_mobject  s    |  """r4   !Sequence[Mobject | OpenGLMobject]c                    | j         | j        fS )zGet all mobjects involved in the animation.

        Ordering must match the ordering of arguments to interpolate_submobject

        Returns
        -------
        Sequence[Mobject]
            The sequence of mobjects.
        )r
   rN   rU   s    r3   get_all_mobjectszAnimation.get_all_mobjects  s     |T222r4   Iterable[tuple]c                    t           d         t          j        k    r(t          d |                                 D             ddiS t          d |                                 D             ddiS )NrJ   c              3  >   K   | ]}|                                 V  d S r6   )
get_family.0mobs     r3   	<genexpr>z4Animation.get_all_families_zipped.<locals>.<genexpr>  s,      FFs#..""FFFFFFr4   strictFc              3  >   K   | ]}|                                 V  d S r6   )family_members_with_pointsr   s     r3   r   z4Animation.get_all_families_zipped.<locals>.<genexpr>  s.      RR3c,,..RRRRRRr4   )r   r   rM   zipr|   rU   s    r3   get_all_families_zippedz!Animation.get_all_families_zipped  s    *!444FFd.C.C.E.EFFFOT   RR$:O:O:Q:QRRR

 
 	
r4   dtc                ^    |                                  D ]}|                    |           dS )a  
        Updates things like starting_mobject, and (for
        Transforms) target_mobject.  Note, since typically
        (always?) self.mobject will have its updating
        suspended during the animation, this will do
        nothing to self.mobject.
        N)get_all_mobjects_to_updateupdate)rQ   r   r   s      r3   update_mobjectszAnimation.update_mobjects!  s:     2244 	 	CJJrNNNN	 	r4   list[Mobject]c                h     t          t           fd                                                     S )zGet all mobjects to be updated during the animation.

        Returns
        -------
        List[Mobject]
            The list of mobjects to be updated during the animation.
        c                    | j         uS r6   r	   )mrQ   s    r3   r9   z6Animation.get_all_mobjects_to_update.<locals>.<lambda>7  s    Qdl%: r4   )listfilterr|   rU   s   `r3   r   z$Animation.get_all_mobjects_to_update,  s3     F::::D<Q<Q<S<STTUUUr4   c                     t          |           S )zzCreate a copy of the animation.

        Returns
        -------
        Animation
            A copy of ``self``
        r   rU   s    r3   ry   zAnimation.copy9  s     ~~r4   alphac                0    |                      |           dS )a
  Set the animation progress.

        This method gets called for every frame during an animation.

        Parameters
        ----------
        alpha
            The relative time to set the animation to, 0 meaning the start, 1 meaning
            the end.
        N)interpolate_mobjectrQ   r   s     r3   rf   zAnimation.interpolateF  s     	  '''''r4   c                    t          |                                           }t          |          D ]8\  }}|                     ||t	          |                    } | j        g ||R   9dS )at  Interpolates the mobject of the :class:`Animation` based on alpha value.

        Parameters
        ----------
        alpha
            A float between 0 and 1 expressing the ratio to which the animation
            is completed. For example, alpha-values of 0, 0.5, and 1 correspond
            to the animation being completed 0%, 50%, and 100%, respectively.
        N)r   r   	enumerateget_sub_alphaleninterpolate_submobject)rQ   r   familiesimobs	sub_alphas         r3   r   zAnimation.interpolate_mobjectS  s     446677 ** 	: 	:GAt**5!S]]CCI'D'99y99999	: 	:r4   
submobjectr   starting_submobjectc                    d S r6   r7   )rQ   r   r   r   s       r3   r   z Animation.interpolate_submobjectb  s	     	r4   indexintnum_submobjectsc                    | j         }|dz
  |z  dz   }||z  }||z  }| j        r|                     d||z
  z
            S |                     ||z
            S )a  Get the animation progress of any submobjects subanimation.

        Parameters
        ----------
        alpha
            The overall animation progress
        index
            The index of the subanimation.
        num_submobjects
            The total count of subanimations.

        Returns
        -------
        float
            The progress of the subanimation.
        ri   )r<   r@   r>   )rQ   r   r   r   r<   full_lengthrV   lowers           r3   r   zAnimation.get_sub_alphal  so    ( N	&*i7!;#	!% 	1>>!uu}"5666>>%%-000r4   c                    || _         | S )af  Set the run time of the animation.

        Parameters
        ----------
        run_time
            The new time the animation should take in seconds.

        .. note::

            The run_time of an animation should not be changed while it is already
            running.

        Returns
        -------
        Animation
            ``self``
        r=   )rQ   r=   s     r3   set_run_timezAnimation.set_run_time  s    $ !r4   c                    | j         S )zGet the run time of the animation.

        Returns
        -------
        float
            The time the animation takes in seconds.
        r   rU   s    r3   get_run_timezAnimation.get_run_time  s     }r4   c                    || _         | S )a7  Set the rate function of the animation.

        Parameters
        ----------
        rate_func
            The new function defining the animation progress based on the
            relative runtime (see :mod:`~.rate_functions`).

        Returns
        -------
        Animation
            ``self``
        r>   )rQ   r>   s     r3   set_rate_funczAnimation.set_rate_func  s    " #r4   c                    | j         S )zGet the rate function of the animation.

        Returns
        -------
        Callable[[float], float]
            The rate function of the animation.
        r   rU   s    r3   get_rate_funczAnimation.get_rate_func  s     ~r4   c                    || _         | S )zSet the name of the animation.

        Parameters
        ----------
        name
            The new name of the animation.

        Returns
        -------
        Animation
            ``self``
        )rB   )rQ   rB   s     r3   set_namezAnimation.set_name  s     	r4   c                    | j         S )zTest if the animation is a remover.

        Returns
        -------
        bool
            ``True`` if the animation is a remover, ``False`` otherwise.
        )rD   rU   s    r3   rn   zAnimation.is_remover  s     |r4   c                    | j         S )zTest if the animation is an introducer.

        Returns
        -------
        bool
            ``True`` if the animation is an introducer, ``False`` otherwise.
        )rF   rU   s    r3   rs   zAnimation.is_introducer  s     r4   c                R     t                      j        di | | j        | _        d S )Nr7   )r+   __init_subclass__rR   _original__init__)r-   r/   r2   s     r3   r   zAnimation.__init_subclass__  s0    !!++F+++ #r4   c                T    |rt          | j        fi || _        dS | j        | _        dS )a  Sets the default values of keyword arguments.

        If this method is called without any additional keyword
        arguments, the original default values of the initialization
        method of this class are restored.

        Parameters
        ----------

        kwargs
            Passing any keyword argument will update the default
            values of the keyword arguments of the initialization
            function of this class.

        Examples
        --------

        .. manim:: ChangeDefaultAnimation

            class ChangeDefaultAnimation(Scene):
                def construct(self):
                    Rotate.set_default(run_time=2, rate_func=rate_functions.linear)
                    Indicate.set_default(color=None)

                    S = Square(color=BLUE, fill_color=BLUE, fill_opacity=0.25)
                    self.add(S)
                    self.play(Rotate(S, PI))
                    self.play(Indicate(S))

                    Rotate.set_default()
                    Indicate.set_default()

        N)r   rR   r   )r-   r/   s     r3   set_defaultzAnimation.set_default  s8    F  	1(@@@@CLLL0CLLLr4   r6   )r$   r   )r
   r;   r<   r   r=   r   r>   r?   r@   rA   rB   rC   rD   rA   rE   rA   rF   rA   r:   rG   r#   rA   r$   rH   )r$   r   )rV   r   r$   rH   )r
   rZ   r$   rH   )r$   rC   r$   rH   rl   r   r$   rH   )r$   rw   )r$   rz   )r$   r}   r   r   r$   rH   )r$   r   )r$   r   r   r   r$   rH   )r   r   r   r   r   r   r$   r   )r   r   r   r   r   r   r$   r   )r=   r   r$   r   )r>   r?   r$   r   )r$   r?   )rB   rC   r$   r   )r$   rA   ))r)   
__module____qualname____doc__r,   r!   r   r   rR   propertyr=   setterrL   r`   rb   rg   rk   rq   rv   rd   r|   r   r   r   ry   rf   r   r   r   r   r   r   r   r   rn   rs   classmethodr   r   r   __classcell__r2   s   @r3   r   r      s)       L L` $ 	$ $ $ $ $ $ $ $, 74.4&+)- ( *8!( ( ( ( ( (T    X _   _@ @ @ @A A A A
      &+ + + +' ' ' '$ $ $ $&# # # #
3 
3 
3 
3
 
 
 
	 	 	 	V V V V   ( ( ( (: : : :   1 1 1 1<   ,      (
 
 
 
           - - - - - [-
 !%1 %1 %1 [%1 %1 %1 %1 %1r4   r   r1   HAnimation | mobject._AnimationBuilder | opengl_mobject._AnimationBuilderr$   c                   t          | t          j                  r|                                 S t          | t          j                  r|                                 S t          | t
                    r| S t          d|  d          )a  Returns either an unchanged animation, or the animation built
    from a passed animation factory.

    Examples
    --------

    ::

        >>> from manim import Square, FadeIn
        >>> s = Square()
        >>> prepare_animation(FadeIn(s))
        FadeIn(Square)

    ::

        >>> prepare_animation(s.animate.scale(2).rotate(42))
        _MethodAnimation(Square)

    ::

        >>> prepare_animation(42)
        Traceback (most recent call last):
        ...
        TypeError: Object 42 cannot be converted to an animation

    zObject z$ cannot be converted to an animation)r&   r
   _AnimationBuilderbuildr   r   r\   )r1   s    r3   prepare_animationr     s{    : $122 zz||$899 zz||$	"" 
HdHHH
I
IIr4   c                  V     e Zd ZdZdddefd fdZddZddZddZddZ	ddZ
 xZS )r   a  A "no operation" animation.

    Parameters
    ----------
    run_time
        The amount of time that should pass.
    stop_condition
        A function without positional arguments that evaluates to a boolean.
        The function is evaluated after every new frame has been rendered.
        Playing the animation stops after the return value is truthy, or
        after the specified ``run_time`` has passed.
    frozen_frame
        Controls whether or not the wait animation is static, i.e., corresponds
        to a frozen frame. If ``False`` is passed, the render loop still
        progresses through the animation as usual and (among other things)
        continues to call updater functions. If ``None`` (the default value),
        the :meth:`.Scene.play` call tries to determine whether the Wait call
        can be static or not itself via :meth:`.Scene.should_mobjects_update`.
    kwargs
        Keyword arguments to be passed to the parent class, :class:`.Animation`.
    ri   Nr=   r   stop_conditionCallable[[], bool] | Nonefrozen_framebool | Noner>   r?   c                    |r|rt          d          || _        || _        || _         t	                      j        d||d| g | j        _        d S )Nz5A static Wait animation cannot have a stop condition.)r=   r>   r6   )rY   durationr   is_static_waitr+   rR   r
   shader_wrapper_list)rQ   r=   r   r   r>   r/   r2   s         r3   rR   zWait.__init___  sp      	Vl 	VTUUU',$0PIPPPPP+-(((r4   r$   rH   c                    d S r6   r7   rU   s    r3   rg   z
Wait.beginq      r4   c                    d S r6   r7   rU   s    r3   rk   zWait.finisht  r   r4   rl   r   c                    d S r6   r7   rp   s     r3   rq   zWait.clean_up_from_scenew  r   r4   r   c                    d S r6   r7   rQ   r   s     r3   r   zWait.update_mobjectsz  r   r4   r   c                    d S r6   r7   r   s     r3   rf   zWait.interpolate}  r   r4   )r=   r   r   r   r   r   r>   r?   r   r   r   r   )r)   r   r   r   r   rR   rg   rk   rq   r   rf   r   r   s   @r3   r   r   H  s         0 48$(.4. . . . . . .$                   r4   r   c                  R     e Zd ZdZddd fdZddZddZddZddZddZ	 xZ
S )r   ak  Add Mobjects to a scene, without animating them in any other way. This
    is similar to the :meth:`.Scene.add` method, but :class:`Add` is an
    animation which can be grouped into other animations.

    Parameters
    ----------
    mobjects
        One :class:`~.Mobject` or more to add to a scene.
    run_time
        The duration of the animation after adding the ``mobjects``. Defaults
        to 0, which means this is an instant animation without extra wait time
        after adding them.
    **kwargs
        Additional arguments to pass to the parent :class:`Animation` class.

    Examples
    --------

    .. manim:: DefaultAddScene

        class DefaultAddScene(Scene):
            def construct(self):
                text_1 = Text("I was added with Add!")
                text_2 = Text("Me too!")
                text_3 = Text("And me!")
                texts = VGroup(text_1, text_2, text_3).arrange(DOWN)
                rect = SurroundingRectangle(texts, buff=0.5)

                self.play(
                    Create(rect, run_time=3.0),
                    Succession(
                        Wait(1.0),
                        # You can Add a Mobject in the middle of an animation...
                        Add(text_1),
                        Wait(1.0),
                        # ...or multiple Mobjects at once!
                        Add(text_2, text_3),
                    ),
                )
                self.wait()

    .. manim:: AddWithRunTimeScene

        class AddWithRunTimeScene(Scene):
            def construct(self):
                # A 5x5 grid of circles
                circles = VGroup(
                    *[Circle(radius=0.5) for _ in range(25)]
                ).arrange_in_grid(5, 5)

                self.play(
                    Succession(
                        # Add a run_time of 0.2 to wait for 0.2 seconds after
                        # adding the circle, instead of using Wait(0.2) after Add!
                        *[Add(circle, run_time=0.2) for circle in circles],
                        rate_func=smooth,
                    )
                )
                self.wait()
    r    r   mobjectsr   r=   r   r/   r   r$   rH   c                   t          |          dk    r|d         nt          | } t                      j        |f|dd| d S )Nri   r   T)r=   rF   )r   r   r+   rR   )rQ   r=   r   r/   r
   r2   s        r3   rR   zAdd.__init__  sS     "%X!!3!3(1++9IO8OOOOOOOr4   c                    d S r6   r7   rU   s    r3   rg   z	Add.begin  r   r4   c                    d S r6   r7   rU   s    r3   rk   z
Add.finish  r   r4   rl   r   c                    d S r6   r7   rp   s     r3   rq   zAdd.clean_up_from_scene  r   r4   r   c                    d S r6   r7   r   s     r3   r   zAdd.update_mobjects  r   r4   r   c                    d S r6   r7   r   s     r3   rf   zAdd.interpolate  r   r4   )r   r   r=   r   r/   r   r$   rH   r   r   r   r   )r)   r   r   r   rR   rg   rk   rq   r   rf   r   r   s   @r3   r   r     s        ; ;| 58P P P P P P P P                   r4   r   animation_classtype[Animation]Callable[[Callable], Callable]c                      fd}|S )a  Decorator used to mark methods as overrides for specific :class:`~.Animation` types.

    Should only be used to decorate methods of classes derived from :class:`~.Mobject`.
    ``Animation`` overrides get inherited to subclasses of the ``Mobject`` who defined
    them. They don't override subclasses of the ``Animation`` they override.

    See Also
    --------
    :meth:`~.Mobject.add_animation_override`

    Parameters
    ----------
    animation_class
        The animation to be overridden.

    Returns
    -------
    Callable[[Callable], Callable]
        The actual decorator. This marks the method as overriding an animation.

    Examples
    --------

    .. manim:: OverrideAnimationExample

        class MySquare(Square):
            @override_animation(FadeIn)
            def _fade_in_override(self, **kwargs):
                return Create(self, **kwargs)

        class OverrideAnimationExample(Scene):
            def construct(self):
                self.play(FadeIn(MySquare()))

    c                    | _         | S r6   )_override_animation)r0   r   s    r3   	decoratorz%override_animation.<locals>.decorator  s    #2 r4   r7   )r   r   s   ` r3   r   r     s%    N     r4   N)r1   r   r$   r   )r   r   r$   r   )*r   
__future__r   #manim.mobject.opengl.opengl_mobjectr    r   r   	constantsr   r
   mobject.mobjectr   r   mobject.openglr   utils.rate_functionsr   r   __all__collections.abcr   r   r   ry   r   	functoolsr   typingr   r   r   manim.scene.scener   r   __annotations__r!   r   r   r   r   r   r7   r4   r3   <module>r      s#      " " " " " " = = = = = =         $ $ $ $ $ $       , , , , , , , , + + + + + + 1 1 1 1 1 1 1 1
<
<
< 9 8 8 8 8 8 8 8 8 8       # # # # # # + + + + + + + + + + ('''''' %(  ' ' ' '%(  ( ( ( (~1 ~1 ~1 ~1 ~1 ~1 ~1 ~1B&J &J &J &JR6 6 6 6 69 6 6 6rQ Q Q Q Q) Q Q Qh+ + + + + +r4   