
    Df                     Z   d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Z	ddlm
Z ddlmZmZ 	 ddlmZ n# e$ r	 ddlmZ Y nw xY wg dZ G d d	e          ZeZd
 Z G d de          ZeZeeeegZ G d de          Z ee          Zde_         d Zd Z d Z!d Z"dDdZ#e#Z$d Z% G d d          Z&e&Z' e'ej(                  Z)de)_          G d d          Z*d Z+d Z,dEdZ-d Z. G d  d!          Z/e/Z0dFd#Z1d$ Z2d% Z3d& Z4d' Z5d( Z6d) Z7dGd+Z8dHd,Z9dEd-Z:dEd.Z;dEd/Z<d0 Z=d1 Z>d2 Z?d3 Z@d4 ZAdEd5ZB G d6 d7          ZCeCZD G d8 d9          ZEeEZFdEd:ZG G d; d<e          ZHeHZId= ZJd> ZK e)d?          ZLdEd@ZM G dA dB          ZNeOdCk    rddlPZP ePjQ                     dS dS )Iz$
General Utilities
(part of web.py)
    N)local   )	iteritems
itervalues)StringIO)1StoragestoragestorifyCountercounteritersrstripslstripsstripssafeunicodesafestr	timelimitMemoizememoize
re_compilere_submgroupuniqiterview
IterBetter
iterbettersafeiter	safewritedictreversedictfinddictfindalldictincrdictaddrequeuerestacklistgetintgetdatestrnumifydenumifycommifydateifynthstrcondCaptureStdoutcapturestdoutProfileprofiletryallThreadedDictthreadeddict
autoassignto36sendmailc                   *    e Zd ZdZd Zd Zd Zd ZdS )r   ao  
    A Storage object is like a dictionary except `obj.foo` can be used
    in addition to `obj['foo']`.

        >>> o = storage(a=1)
        >>> o.a
        1
        >>> o['a']
        1
        >>> o.a = 2
        >>> o['a']
        2
        >>> del o.a
        >>> o.a
        Traceback (most recent call last):
            ...
        AttributeError: 'a'

    c                 V    	 | |         S # t           $ r}t          |          d }~ww xY wNKeyErrorAttributeErrorselfkeyks      8/var/www/media/lib/python3.11/site-packages/web/utils.py__getattr__zStorage.__getattr__f   s>    	$9 	$ 	$ 	$ ###	$s   
 
(#(c                     || |<   d S r;    r@   rA   values      rC   __setattr__zStorage.__setattr__l   s    S			    c                 P    	 | |= d S # t           $ r}t          |          d }~ww xY wr;   r<   r?   s      rC   __delattr__zStorage.__delattr__o   s?    	$S			 	$ 	$ 	$ ###	$s    
% %c                 B    dt                               |           z   dz   S )Nz	<Storage >dict__repr__r@   s    rC   rQ   zStorage.__repr__u       T]]4000366rJ   N)__name__
__module____qualname____doc__rD   rI   rL   rQ   rF   rJ   rC   r   r   Q   sZ         ($ $ $  $ $ $7 7 7 7 7rJ   r   c                 p  	
 |                     dd          t          	durt          d          r		fd

fdt                      }|t	          |                                           z   D ]}| |         }t          |t                    r?t          |                    |          t                    rfd|D             }n|d         }t          |                    |          t                    s |          }t          |                    |          t                    rt          |t                    s|g}t          |||           t          |          D ]N\  }}|}t          ||          r||         }|dk    rt          |t                    s|f}t          |||           O|S )	a  
    Creates a `storage` object from dictionary `mapping`, raising `KeyError` if
    d doesn't have all of the keys in `requireds` and using the default
    values for keys found in `defaults`.

    For example, `storify({'a':1, 'c':3}, b=2, c=0)` will return the equivalent of
    `storage({'a':1, 'b':2, 'c':3})`.

    If a `storify` value is a list (e.g. multiple values in a form submission),
    `storify` returns the last element of the list, unless the key appears in
    `defaults` as a list. Thus:

        >>> storify({'a':[1, 2]}).a
        2
        >>> storify({'a':[1, 2]}, a=[]).a
        [1, 2]
        >>> storify({'a':1}, a=[]).a
        [1]
        >>> storify({}, a=[]).a
        []

    Similarly, if the value has a `value` attribute, `storify will return _its_
    value, unless the key appears in `defaults` as a dictionary.

        >>> storify({'a':storage(value=1)}).a
        1
        >>> storify({'a':storage(value=1)}, a={}).a
        <Storage {'value': 1}>
        >>> storify({}, a={}).a
        {}

    _unicodeF__call__c                 L    r t          | t                    r |           S | S r;   )
isinstancestr)srY   
to_unicodes    rC   	unicodifyzstorify.<locals>.unicodify   s/     	
1c** 	:a== HrJ   c                     t          | d          rt          | d          r| j        S t          | d          r | j                  S  |           S )NfilerH   )hasattrrH   )xr`   s    rC   getvaluezstorify.<locals>.getvalue   s_    1f 	 '!W"5"5 	 7NQ   	 9QW%%%9Q<<rJ   c                 &    g | ]} |          S rF   rF   ).0rd   re   s     rC   
<listcomp>zstorify.<locals>.<listcomp>   s!    444!444rJ   rF   )popr   rc   r   tuplekeysr\   listgetrP   setattrr   )mapping	requiredsdefaultsstorrA   rH   resultrY   re   r_   r`   s          @@@@rC   r
   r
   |   s   B ||J..H Ju:!>!>
               99D5000 " "eT"" 	"(,,s++T22 "4444e444b	(,,s++T22 	$HUOOEhll3''.. 	z%7N7N 	GEc5!!!!!(++ # #e4 	#YFB;;z&%88;YFc6""""KrJ   c                   B    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
S )r   a  Keeps count of how many times something is added.

    >>> c = counter()
    >>> c.add('x')
    >>> c.add('x')
    >>> c.add('x')
    >>> c.add('x')
    >>> c.add('x')
    >>> c.add('y')
    >>> c['y']
    1
    >>> c['x']
    5
    >>> c.most()
    ['x']
    c                 R    |                      |d           | |xx         dz  cc<   d S )Nr   r   
setdefault)r@   ns     rC   addzCounter.add   s/    1Q1rJ   c                 r    t          t          |                     fdt          |           D             S )z$Returns the keys with maximum count.c                 &    g | ]\  }}|k    |S rF   rF   rg   rB   vms      rC   rh   z Counter.most.<locals>.<listcomp>   "    888daarJ   )maxr   r   r@   r   s    @rC   mostzCounter.most   s8    
4  !!8888ioo8888rJ   c                 |    t          |                                           fdt          |           D             S )z$Returns the keys with minimum count.c                 &    g | ]\  }}|k    |S rF   rF   r}   s      rC   rh   z!Counter.least.<locals>.<listcomp>   r   rJ   )minr   r   r   s    @rC   leastzCounter.least   s:    !!""8888ioo8888rJ   c                 p    t          | |                   t          |                                           z  S )a  Returns what percentage a certain key is of all entries.

        >>> c = counter()
        >>> c.add('x')
        >>> c.add('x')
        >>> c.add('x')
        >>> c.add('y')
        >>> c.percent('x')
        0.75
        >>> c.percent('y')
        0.25
        )floatsumvaluesr@   rA   s     rC   percentzCounter.percent   s+     T#Y#dkkmm"4"444rJ   c                 R     t                                            fdd          S )zReturns keys sorted by value.

        >>> c = counter()
        >>> c.add('x')
        >>> c.add('x')
        >>> c.add('y')
        >>> c.sorted_keys()
        ['x', 'y']
        c                     |          S r;   rF   )rB   r@   s    rC   <lambda>z%Counter.sorted_keys.<locals>.<lambda>  s    a rJ   T)rA   reverse)sortedrl   rR   s   `rC   sorted_keyszCounter.sorted_keys   s,     diikk'8'8'8'8$GGGGrJ   c                 D      fd                                  D             S )zReturns values sorted by value.

        >>> c = counter()
        >>> c.add('x')
        >>> c.add('x')
        >>> c.add('y')
        >>> c.sorted_values()
        [2, 1]
        c                      g | ]
}|         S rF   rF   rg   rB   r@   s     rC   rh   z)Counter.sorted_values.<locals>.<listcomp>  s    444AQ444rJ   r   rR   s   `rC   sorted_valueszCounter.sorted_values  s+     5444!1!1!3!34444rJ   c                 D      fd                                  D             S )zReturns items sorted by value.

        >>> c = counter()
        >>> c.add('x')
        >>> c.add('x')
        >>> c.add('y')
        >>> c.sorted_items()
        [('x', 2), ('y', 1)]
        c                 $    g | ]}||         fS rF   rF   r   s     rC   rh   z(Counter.sorted_items.<locals>.<listcomp>  s!    999DG999rJ   r   rR   s   `rC   sorted_itemszCounter.sorted_items  s+     :999d&6&6&8&89999rJ   c                 B    dt                               |           z   dz   S )Nz	<Counter rN   rO   rR   s    rC   rQ   zCounter.__repr__  rS   rJ   N)rT   rU   rV   rW   rz   r   r   r   r   r   r   rQ   rF   rJ   rC   r   r      s         "  9 9 9
9 9 9
5 5 5
H 
H 
H
5 
5 
5
: 
: 
:7 7 7 7 7rJ   r   c                       e Zd ZdS )_hackN)rT   rU   rV   rF   rJ   rC   r   r   (  s        DrJ   r   z
A list of iterable items (like lists, but not strings). Includes whichever
of lists, tuples, sets, and Sets are available in this version of Python.
c                 L   t          |t                    r|D ]}t          | ||          }|S | dk    r-|                    |          r|t	          |          d          S nC| dk    r.|                    |          r|d t	          |                    S nt          d          |S )NlrzDirection needs to be r or l.)r\   r   _strips
startswithlenendswith
ValueError)	directiontextremovesubrs       rC   r   r   3  s    &%    	2 	2D9dD11DDC??6"" 	'F&&	'	c		==   	(3v;;,''	( 8999KrJ   c                 $    t          d| |          S )zs
    removes the string `remove` from the right of `text`

        >>> rstrips("foobar", "bar")
        'foo'

    r   r   r   r   s     rC   r   r   D  s     3f%%%rJ   c                 $    t          d| |          S )aF  
    removes the string `remove` from the left of `text`

        >>> lstrips("foobar", "foo")
        'bar'
        >>> lstrips('http://foo.org/', ['http://', 'https://'])
        'foo.org/'
        >>> lstrips('FOOBARBAZ', ['FOO', 'BAR'])
        'BAZ'
        >>> lstrips('FOOBARBAZ', ['BAR', 'FOO'])
        'BARBAZ'

    r   r   r   s     rC   r   r   O  s     3f%%%rJ   c                 >    t          t          | |          |          S )zz
    removes the string `remove` from the both sides of `text`

        >>> strips("foobarfoo", "foo")
        'bar'

    )r   r   r   s     rC   r   r   `  s     74((&111rJ   utf-8c                 \    | rt          | d          rd | D             S t          |           S )z
    Converts any given object to utf-8 encoded string.

        >>> safestr('hello')
        'hello'
        >>> safestr(2)
        '2'
    __next__c                 ,    g | ]}t          |          S rF   r   )rg   is     rC   rh   zsafestr.<locals>.<listcomp>v  s    (((q

(((rJ   )rc   r]   )objencodings     rC   r   r   k  s<      wsJ'' ((C((((3xxrJ   c                       fd}|S )a  
    A decorator to limit a function to `timeout` seconds, raising `TimeoutError`
    if it takes longer.

        >>> import time
        >>> def meaningoflife():
        ...     time.sleep(.2)
        ...     return 42
        >>>
        >>> timelimit(.1)(meaningoflife)()
        Traceback (most recent call last):
            ...
        RuntimeError: took too long
        >>> timelimit(1)(meaningoflife)()
        42

    _Caveat:_ The function isn't stopped after `timeout` seconds but continues
    executing in a separate thread. (There seems to be no way to kill a thread.)

    inspired by <http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/473878>
    c                       fd}|S )Nc                        G  fddt           j                  } |            }|                               |                                rt	          d          |j        r|j        d         |j        S )Nc                   $    e Zd Zd Z fdZdS )3timelimit.<locals>._1.<locals>._2.<locals>.Dispatchc                     t           j                            |            d | _        d | _        |                     d           |                                  d S NT)	threadingThread__init__rt   error	setDaemonstartrR   s    rC   r   z<timelimit.<locals>._1.<locals>._2.<locals>.Dispatch.__init__  sJ    $--d333"&DK!%DJNN4(((JJLLLLLrJ   c                 d    	  i | _         d S #  t          j                    | _        Y d S xY wr;   )rt   sysexc_infor   )r@   argsfunctionkws    rC   runz7timelimit.<locals>._1.<locals>._2.<locals>.Dispatch.run  s>    4&.h&;&;&;4%(\^^



s    /N)rT   rU   rV   r   r   )r   r   r   s   rC   Dispatchr     sG        ! ! !4 4 4 4 4 4 4 4 4rJ   r   ztook too longr   )r   r   joinis_aliveRuntimeErrorr   rt   )r   r   r   cr   timeouts   ``  rC   _2z!timelimit.<locals>._1.<locals>._2  s    4 4 4 4 4 4 4 4 49+ 4 4 4 

AFF7OOOzz|| 4"?333w !gaj 8OrJ   rF   )r   r   r   s   ` rC   _1ztimelimit.<locals>._1  s)    	 	 	 	 	 	0 	rJ   rF   )r   r   s   ` rC   r   r     s#    .    6 IrJ   c                        e Zd ZdZddZd ZdS )r   a  
    'Memoizes' a function, caching its return values for each input.
    If `expires` is specified, values are recalculated after `expires` seconds.
    If `background` is specified, values are recalculated in a separate thread.

        >>> calls = 0
        >>> def howmanytimeshaveibeencalled():
        ...     global calls
        ...     calls += 1
        ...     return calls
        >>> fastcalls = memoize(howmanytimeshaveibeencalled)
        >>> howmanytimeshaveibeencalled()
        1
        >>> howmanytimeshaveibeencalled()
        2
        >>> fastcalls()
        3
        >>> fastcalls()
        3
        >>> import time
        >>> fastcalls = memoize(howmanytimeshaveibeencalled, .1, background=False)
        >>> fastcalls()
        4
        >>> fastcalls()
        4
        >>> time.sleep(.2)
        >>> fastcalls()
        5
        >>> def slowfunc():
        ...     time.sleep(.1)
        ...     return howmanytimeshaveibeencalled()
        >>> fastcalls = memoize(slowfunc, .2, background=True)
        >>> fastcalls()
        6
        >>> timelimit(.05)(fastcalls)()
        6
        >>> time.sleep(.2)
        >>> timelimit(.05)(fastcalls)()
        6
        >>> timelimit(.05)(fastcalls)()
        6
        >>> time.sleep(.2)
        >>> timelimit(.05)(fastcalls)()
        7
        >>> fastcalls = memoize(slowfunc, None, background=True)
        >>> threading.Thread(target=fastcalls).start()
        >>> time.sleep(.01)
        >>> fastcalls()
        9
    NTc                 |    || _         i | _        || _        || _        i | _        t          j                    | _        d S r;   )funccacheexpires
backgroundrunningr   Lockrunning_lock)r@   r   r   r   s       rC   r   zMemoize.__init__  s;    	
$%N,,rJ   c                 <    t                                                    f j        5   j                                      st          j                     j        <   d d d            n# 1 swxY w Y   d fd	} j        vr |d           np j        rit          j	                     j                 d         z
   j        k    r9 j
        r(t          j        |                                           n
 |              j                 d         S )	NFc                 $   j                                      |           rn	  j        i t          j                    fj        <   j                                                   d S # j                                                   w xY wd S r;   )r   acquirer   timer   release)blockr   rA   keywordsr@   s    rC   updatez Memoize.__call__.<locals>.update  s    |C ((// 00'0ty$'C('C'CTY[[&QDJsOL%--/////DL%--////	0 0s   (A, ,!BT)r   r   )targetr   )F)rk   itemsr   r   rn   r   r   r   r   r   r   r   r   )r@   r   r   r   rA   s   ``` @rC   rZ   zMemoize.__call__  ss   U8>>++,,- 	5 	5<##C(( 5$-N$4$4S!	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5	0 	0 	0 	0 	0 	0 	0 	0 	0 dj  F\ 	ty{{TZ_Q-??4<OO  ///557777z#q!!s   6A11A58A5r   rT   rU   rV   rW   r   rZ   rF   rJ   rC   r   r     sB        1 1f- - - -" " " " "rJ   r   z#
A memoized version of re.compile.
c                       e Zd Zd Zd ZdS )_re_subm_proxyc                     d | _         d S r;   matchrR   s    rC   r   z_re_subm_proxy.__init__  s    


rJ   c                     || _         dS )N r   )r@   r   s     rC   rZ   z_re_subm_proxy.__call__  s    
rrJ   N)rT   rU   rV   r   rZ   rF   rJ   rC   r   r     s2              rJ   r   c                     t          |           }t                      }|                    |j        |           |                    ||          |j        fS )z
    Like re.sub, but returns the replacement _and_ the match object.

        >>> t, m = re_subm('g(oo+)fball', r'f\1lish', 'goooooofball')
        >>> t
        'foooooolish'
        >>> m.groups()
        ('oooooo',)
    )r   r   subrZ   r   )patreplstringcompiled_patproxys        rC   r   r     sO     c??LEU^V,,,D&))5;66rJ   c                 \      fdt          dt                               D             S )z
    Returns an iterator over a series of lists of length size from iterable.

        >>> list(group([1,2,3,4], 2))
        [[1, 2], [3, 4]]
        >>> list(group([1,2,3,4,5], 2))
        [[1, 2], [3, 4], [5]]
    c              3   2   K   | ]}||z            V  d S r;   rF   )rg   r   seqsizes     rC   	<genexpr>zgroup.<locals>.<genexpr>1  s0      @@!CAH@@@@@@rJ   r   )ranger   )r   r   s   ``rC   r   r   (  s6     A@@@@uQC$'?'?@@@@rJ   c                     |pd }t                      }g }| D ]<} ||          }||v r|                    |           |                    |           =|S )at  
    Removes duplicate elements from a list while preserving the order of the rest.

        >>> uniq([9,0,2,1,0])
        [9, 0, 2, 1]

    The value of the optional `key` parameter should be a function that
    takes a single argument and returns a key to test the uniqueness.

        >>> uniq(["Foo", "foo", "bar"], key=lambda s: s.lower())
        ['Foo', 'bar']
    c                     | S r;   rF   rd   s    rC   r   zuniq.<locals>.<lambda>A  s    A rJ   )setrz   append)r   rA   seenrt   r~   rB   s         rC   r   r   4  so     
++C55DF  CFF99aMrJ   c           	   #   n  	K   dd 	d d 	fd}t          j                     }t          |           }t          |           D ]6\  }}t          j                            d ||||          z              |V  7t          j                            d |||dz   |          z   dz              d	S )
z
    Takes an iterable `x` and returns an iterator over it
    which prints its progress to stderr as it iterates through.
    F   c                 n    dt          |           |z  dz  t          t          |                    | |fz  S )Nz%5.1f%% (%*d/%d)d   )r   r   r]   )ry   lenxs     rC   plainformatziterview.<locals>.plainformatT  s2    !eAhho%<c#d))nnaQU$VVVrJ   c                     t          t          |          | z  |z  dz             }| |z
  rdd| |z
  z  dd          z   }nd}dd|z  |dS )	Ng      ?rN    r   r   [=])intr   )r   ry   r  valspacings        rC   barsziterview.<locals>.barsW  sh    588d?d*S011#: 	SD3J/44GGG99ggg..rJ   c                     |dk    rdS ||k    rt          |           }nt          | |z  ||z
  z            }t          |d          \  }}t          |d          \  }}d|||fz  S )Nr   z--:--:--<   z%02d:%02d:%02d)r  divmod)elapsedry   r  secsminshrss         rC   etaziterview.<locals>.eta_  sx    66:99w<<DD!q122DD"%%
d4$$	T3d"333rJ   c                      ||          dz   }||k    rd}nd}| t          j                     | z
  ||          z  }| t          |          z
  t          |          z
  ||          z  }||z  }|S )Nr	  z     z ETA )r   r   )		starttimery   r  outendWIDTHr  r  r  s	        rC   formatziterview.<locals>.formatk  s    k!T""S(99CCCss49;;*At444ttECHH$s3xx/D999s

rJ   r   
N)r   r   	enumerater   stderrwrite)
rd   r  r  r  ry   yr  r  r  r  s
         @@@@rC   r   r   M  s     
 EW W W/ / /
4 
4 
4	 	 	 	 	 	 	 	 	Iq66D!  1
y!T : ::;;;JTFF9a!eT:::TABBBBBrJ   c                   6    e Zd ZdZd ZddZd Zd Zd ZeZ	dS )	r   a  
    Returns an object that can be used as an iterator
    but can also be used via __getitem__ (although it
    cannot go backwards -- that is, you cannot request
    `iterbetter[0]` after requesting `iterbetter[1]`).

        >>> import itertools
        >>> c = iterbetter(itertools.count())
        >>> c[1]
        1
        >>> c[5]
        5
        >>> c[3]
        Traceback (most recent call last):
            ...
        IndexError: already passed 3

    It is also possible to get the first value of the iterator or None.

        >>> c = iterbetter(iter([3, 4, 5]))
        >>> print(c.first())
        3
        >>> c = iterbetter(iter([]))
        >>> print(c.first())
        None

    For boolean test, IterBetter peeps at first value in the itertor without effecting the iteration.

        >>> c = iterbetter(iter(range(5)))
        >>> bool(c)
        True
        >>> list(c)
        [0, 1, 2, 3, 4]
        >>> c = iterbetter(iter([]))
        >>> bool(c)
        False
        >>> list(c)
        []
    c                 $    |dc| _         | _        d S )Nr   )r   r   )r@   iterators     rC   r   zIterBetter.__init__  s    !1rJ   Nc                 `    	 t          t          |                     S # t          $ r |cY S w xY w)zReturns the first element of the iterator or None when there are no
        elements.

        If the optional argument default is specified, that is returned instead
        of None when there are no elements.
        )nextiterStopIteration)r@   defaults     rC   firstzIterBetter.first  s?    	T

### 	 	 	NNN	s    --c              #      K   t          | d          r	| j        V  	 	 t          | j                  V  n# t          $ r Y d S w xY w| xj        dz  c_        :)N_headr   )rc   r/  r)  r   r+  r   rR   s    rC   __iter__zIterBetter.__iter__  s}      4!! 	*	46ll""""    FFaKFF	s   5 
AAc                 h   || j         k     rt          dt          |          z             	 || j         k    r/t          | j                   | xj         dz  c_         || j         k    /| xj         dz  c_         t          | j                  S # t
          $ r t          t          |                    w xY w)Nzalready passed r   )r   
IndexErrorr]   r)  r   r+  )r@   r   s     rC   __getitem__zIterBetter.__getitem__  s    tv::.Q7888	%df**TV! df** FFaKFF<< 	% 	% 	%SVV$$$	%s   AB
 
'B1c                     t          | d          r|                                 dk    S t          | d          rdS 	 t          | j                  | _        dS # t
          $ r Y dS w xY w)N__len__r   r/  TF)rc   r5  r)  r   r/  r+  rR   s    rC   __nonzero__zIterBetter.__nonzero__  s}    4## 
	<<>>Q&&T7## 	4!$&\\
 t !   uus   A 
A%$A%r;   )
rT   rU   rV   rW   r   r-  r0  r3  r6  __bool__rF   rJ   rC   r   r   ~  sp        & &P% % %
 
 
 
	 	 	% % %   HHHrJ   r   Tc              #   P    K    fdt                      	              V  )zPMakes an iterator safe by ignoring the exceptions occurred during the iteration.c                  h    	 	             S # t           $ r   t          j                     Y nxY w1r;   )r+  	traceback	print_exc)itr)  s   rC   r)  zsafeiter.<locals>.next  sR    	&&tBxx    &#%%%%%	&s   
 0)r*  )r<  cleanupignore_errorsr)  s   `  @rC   r   r     sL      & & & & & & 
bBdffrJ   c                     t          | dz   d          5 }|                    |           ddd           n# 1 swxY w Y   t          j        |j        |            dS )zWrites the content to a temp file and then moves the temp file to
    given filename to avoid overwriting the existing file in case of errors.
    z.tmpwN)openr#  shutilmovename)filenamecontentfs      rC   r   r     s     
h	%	% 	              
K!!!!!s   6::c                 N    t          d t          |           D                       S )z|
    Returns a new dictionary with keys and values swapped.

        >>> dictreverse({1: 2, 3: 4})
        {2: 1, 4: 3}
    c                     g | ]	\  }}||f
S rF   rF   )rg   rA   rH   s      rC   rh   zdictreverse.<locals>.<listcomp>  s     EEE,3%EEErJ   )rP   r   )rp   s    rC   r   r     s)     EE)G2D2DEEEFFFrJ   c                 @    t          |           D ]\  }}||u r|c S dS )z
    Returns a key whose value in `dictionary` is `element`
    or, if none exists, None.

        >>> d = {1:2, 3:4}
        >>> dictfind(d, 4)
        3
        >>> dictfind(d, 5)
    N)r   )
dictionaryelementrA   rH   s       rC   r    r      sB     "*--  eeJJJ  rJ   c                 f    g }t          |           D ]\  }}||u r|                    |           |S )z
    Returns the keys whose values in `dictionary` are `element`
    or, if none exists, [].

        >>> d = {1:4, 3:4}
        >>> dictfindall(d, 4)
        [1, 3]
        >>> dictfindall(d, 5)
        []
    )r   r   )rK  rL  resrA   rH   s        rC   r!   r!     sD     C!*--  eeJJsOOOJrJ   c                 ^    |                      |d           | |xx         dz  cc<   | |         S )z
    Increments `element` in `dictionary`,
    setting it to one if it doesn't exist.

        >>> d = {1:2, 3:4}
        >>> dictincr(d, 1)
        3
        >>> d[1]
        3
        >>> dictincr(d, 5)
        1
        >>> d[5]
        1
    r   r   rw   )rK  rL  s     rC   r"   r"   '  sA     '1%%%w1grJ   c                  >    i }| D ]}|                     |           |S )z
    Returns a dictionary consisting of the keys in the argument dictionaries.
    If they share a key, the value from the last argument is used.

        >>> dictadd({1: 0, 2: 0}, {2: 1, 3: 1})
        {1: 0, 2: 1, 3: 1}
    )r   )dictsrt   dcts      rC   r#   r#   ;  s2     F  cMrJ   ri   c                 \    |                      |          }|                     d|           |S )zReturns the element at index after moving it to the beginning of the queue.

    >>> x = [1, 2, 3, 4]
    >>> requeue(x)
    4
    >>> x
    [4, 1, 2, 3]
    r   )rj   insert)queueindexrd   s      rC   r$   r$   I  s.     			%A	LLAHrJ   c                 Z    |                      |          }|                     |           |S )zReturns the element at index after moving it to the top of stack.

    >>> x = [1, 2, 3, 4]
    >>> restack(x)
    1
    >>> x
    [2, 3, 4, 1]
    )rj   r   )stackrV  rd   s      rC   r%   r%   W  s)     			%A	LLOOOHrJ   c                 B    t          |           dz
  |k     r|S | |         S )z
    Returns `lst[ind]` if it exists, `default` otherwise.

        >>> listget(['a'], 0)
        'a'
        >>> listget(['a'], 1)
        >>> listget(['a'], 1, 'b')
        'b'
    r   )r   )lstindr,  s      rC   r&   r&   e  s'     3xx!|cs8OrJ   c                 T    	 t          |           S # t          t          f$ r |cY S w xY w)z
    Returns `integer` as an int or `default` if it can't.

        >>> intget('3')
        3
        >>> intget('3a')
        >>> intget('3a', 0)
        0
    )r  	TypeErrorr   )integerr,  s     rC   r'   r'   t  s<    7||z"   s    ''c                 |   dd}d}| sdS |st           j                                         }t          |          j        dk    rt           j                             |          }t          |           j        dk    r t           j                             |           } n=t          |           j        dk    r%t          j         | j        | j        | j                  } || z
  }t          |j	        |z  |j
        z   |j        dz  z             }t          |          |z  }|dk     r|d	z  }|rmt          |          d
k     r ||d          S |                     d                              dd          }| j        |j        k    s|dk     r|d| j        z  z  }|S t          |          rLt          |          dk    r ||dd          S t          |          dk    r ||dd          S  ||d          S |j        }|j	        rt          |j        dz
            }t          |          dk    r ||dd          S  ||d          S )ab  
    Converts a (UTC) datetime object to a nice string representation.

        >>> from datetime import datetime, timedelta
        >>> d = datetime(1970, 5, 1)
        >>> datestr(d, now=d)
        '0 microseconds ago'
        >>> for t, v in iteritems({
        ...   timedelta(microseconds=1): '1 microsecond ago',
        ...   timedelta(microseconds=2): '2 microseconds ago',
        ...   -timedelta(microseconds=1): '1 microsecond from now',
        ...   -timedelta(microseconds=2): '2 microseconds from now',
        ...   timedelta(microseconds=2000): '2 milliseconds ago',
        ...   timedelta(seconds=2): '2 seconds ago',
        ...   timedelta(seconds=2*60): '2 minutes ago',
        ...   timedelta(seconds=2*60*60): '2 hours ago',
        ...   timedelta(days=2): '2 days ago',
        ... }):
        ...     assert datestr(d, now=d+t) == v
        >>> datestr(datetime(1970, 1, 1), now=d)
        'January  1'
        >>> datestr(datetime(1969, 1, 1), now=d)
        'January  1, 1969'
        >>> datestr(datetime(1970, 6, 1), now=d)
        'June  1, 1970'
        >>> datestr(None)
        ''
    Nc                     |r| |z  } t          t          |                     dz   |z   }t          |           dk    r|dz  }|dz  }| dk     r|dz  }n|dz  }|S )Nr	  r   r^   r   zfrom nowago)r]   abs)ry   whatdivisorr  s       rC   agohencezdatestr.<locals>.agohence  sr     	WA#a&&kkC$&q66Q;;3JCs
q55:CC5LC
rJ   iQ r   DateTimedategư>r   ri      dayz%B %dz 0  z, %si  hourr  minutesecondg    .Ai  millisecondmicrosecondr;   )datetimeutcnowtyperT   fromtimestampyearmonthri  r  dayssecondsmicrosecondsrb  strftimereplace)	thennowre  onedaydeltadeltaseconds	deltadaysr  deltamicrosecondss	            rC   r(   r(     sr   <    F r )&&((CyyZ''--c22Dzzj(( ..t44	d		&	& DJAA$JEuzF*U]:U=ORW=WWXXLL!!V+IaR	 
y>>A8Iu--- mmG$$,,T4889  IMM6DI%%C

< 4|((8L&':::##8L(B7778L(333*z : 2S 899
$$x)=$???8%}555rJ   c                 Z    d                     d t          |           D                       S )z
    Removes all non-digit characters from `string`.

        >>> numify('800-555-1212')
        '8005551212'
        >>> numify('800.555.1212')
        '8005551212'

    r   c                 :    g | ]}|                                 |S rF   )isdigit)rg   r   s     rC   rh   znumify.<locals>.<listcomp>  s%    :::!aiikk:A:::rJ   )r   r]   )r   s    rC   r)   r)     s+     77::s6{{:::;;;rJ   c                     g }|D ]C}|dk    r&|                     | d                    | dd         } .|                     |           Dd                    |          S )z
    Formats `string` according to `pattern`, where the letter X gets replaced
    by characters from `string`.

        >>> denumify("8005551212", "(XXX) XXX-XXXX")
        '(800) 555-1212'

    Xr   r   Nr   )r   r   )r   patternr  r   s       rC   r*   r*     sg     C  88JJvay!!!ABBZFFJJqMMMM773<<rJ   c                    | dS t          |                                           } |                     d          rd}| dd                                         } nd}d| v r|                     d          \  }}n| d}}g }t	          t          |          ddd                   D ]8\  }}|r|dz  s|                    dd	           |                    d|           9d                    |          }|r|d|z   z  }||z   S )
a  
    Add commas to an integer `n`.

        >>> commify(1)
        '1'
        >>> commify(123)
        '123'
        >>> commify(-123)
        '-123'
        >>> commify(1234)
        '1,234'
        >>> commify(1234567890)
        '1,234,567,890'
        >>> commify(123.0)
        '123.0'
        >>> commify(1234.5)
        '1,234.5'
        >>> commify(1234.56789)
        '1,234.56789'
        >>> commify(' %.2f ' % -1234.5)
        '-1,234.50'
        >>> commify(None)
        >>>

    N-r   r   .ri      r   ,)r]   stripr   splitr!  rT  r   )ry   prefixdollarscentsr   r   r   r  s           rC   r+   r+     s   4 	ytAA||C abbEKKMM
axxD
A#g,,ttt,--  1 	q1u 	HHQ	A
''!**C sU{C<rJ   c                 "    t          | d          S )z3
    Formats a numified `datestring` properly.
    zXXXX-XX-XX XX:XX:XX)r*   )
datestrings    rC   r,   r,   :  s     J 5666rJ   c                 j    | dk    sJ | dz  dv rd| z  S dddd                     | d	z  d          | z  S )
a)  
    Formats an ordinal.
    Doesn't handle negative numbers.

        >>> nthstr(1)
        '1st'
        >>> nthstr(0)
        '0th'
        >>> [nthstr(x) for x in [2, 3, 4, 5, 10, 11, 12, 13, 14, 15]]
        ['2nd', '3rd', '4th', '5th', '10th', '11th', '12th', '13th', '14th', '15th']
        >>> [nthstr(x) for x in [91, 92, 93, 94, 99, 100, 101, 102]]
        ['91st', '92nd', '93rd', '94th', '99th', '100th', '101st', '102nd']
        >>> [nthstr(x) for x in [111, 112, 113, 114, 115]]
        ['111th', '112th', '113th', '114th', '115th']

    r   r  )         z%sthz%sstz%sndz%srd)r      r  
   )rn   )ry   s    rC   r-   r-   A  sS    $ 66663w,z&V,,00R@@1DDrJ   c                     | r|S |S )z
    Function replacement for if-else to use in expressions.

        >>> x = 2
        >>> cond(x % 2 == 0, "even", "odd")
        'even'
        >>> cond(x % 2 == 0, "even", "odd") + '_row'
        'even_row'
    rF   )	predicateconsequencealternatives      rC   r.   r.   Y  s      rJ   c                       e Zd ZdZd Zd ZdS )r/   z
    Captures everything `func` prints to stdout and returns it instead.

        >>> def idiot():
        ...     print("foo")
        >>> capturestdout(idiot)()
        'foo\n'

    **WARNING:** Not threadsafe!
    c                     || _         d S r;   r   r@   r   s     rC   r   zCaptureStdout.__init__u      			rJ   c                     t                      }t          j        }|t          _        	  | j        |i | |t          _        n# |t          _        w xY w|                                S r;   )r   r   stdoutr   re   )r@   r   r   r  	oldstdouts        rC   rZ   zCaptureStdout.__call__x  s_    jjJ	
	#DIt(x((("CJJCJ""""||~~s   A ANr   rF   rJ   rC   r/   r/   i  s<        	 	      rJ   r/   c                       e Zd ZdZd Zd ZdS )r1   a	  
    Profiles `func` and returns a tuple containing its output
    and a string with human-readable profiling information.

        >>> import time
        >>> out, inf = profile(time.sleep)(.001)
        >>> out
        >>> inf[:10].strip()
        'took 0.0'
    c                     || _         d S r;   r  r  s     rC   r   zProfile.__init__  r  rJ   c                    dd l }dd l}dd l}dd l}|                                \  }} |j        |           |                                }t          j                    }	 |j        | j	        g|R  }
t          j                    |	z
  }	t                      }|                    ||          }|                                 |                    dd           |                    d           |                                 dt!          |	          z   dz   }||                                z  }	  |j        |           n# t&          $ r Y nw xY w|
|fS )Nr   )streamr   calls(   z

took z	 seconds
)cProfilepstatsostempfilemkstempcloser1   r   runcallr   r   Stats
strip_dirs
sort_statsprint_statsprint_callersr]   re   r   IOError)r@   r   r  r  r  r  rG  rE  profstimert   r  statsrd   s                 rC   rZ   zProfile.__call__  sj   			&&((8!!	di/$///	e#jjT#..)))"#e**$|3	S\\^^	BIh 	 	 	D	 qys   -D> >
E
ENr   rF   rJ   rC   r1   r1     s<        	 	      rJ   r1   c           
         |                                  } i }t          |           D ]\  }}t          |d          s|r|                    |          s.t	          |dz   d           	  |            }t          ||           t	          |           m#  t	          d           t          |d           t	          dd                    t          j                    	                    d                    z              Y xY wt	          d	           t	          d
           t          |          D ]&\  }}t	          dt          |          dz   |           'dS )aZ  
    Tries a series of functions and prints their results.
    `context` is a dictionary mapping names to values;
    the value will only be tried if it's callable.

        >>> tryall(dict(j=lambda: True))
        j: True
        ----------------------------------------
        results:
           True: 1

    For example, you might have a file `test/stuff.py`
    with a series of functions testing various things in it.
    At the bottom, have a line:

        if __name__ == "__main__": tryall(globals())

    Then you can run `python test/stuff.py` and get the results of
    all the tests.
    rZ   :r	  )r  ERRORz   z
   r   z(----------------------------------------zresults:rj  N)copyr   rc   r   printr"   r   r:  
format_excr  r]   )contextr  resultsrA   rH   r   s         rC   r3   r3     si   * llnnGG!'** L Leuj)) 	 	#..00 	cCiS!!!!	LAWa   !HHHH	L'NNNWg&&&%',,y';'='='C'CD'I'IJJJKKKKK	(OOO	*!'** . .egs3xx#~u----. .s   ))BA*C?c                       e Zd ZdZ e            Zd Zd Zd Zd Z	 e
e	          Z	d Zd Zd Zd	 ZeZd
 Zd ZddZd Zd Zd Zd ZeZd Zd Zd Zd ZddZd Zd ZeZdS )r4   a#  
    Thread local storage.

        >>> d = ThreadedDict()
        >>> d.x = 1
        >>> d.x
        1
        >>> import threading
        >>> def f(): d.x = 2
        ...
        >>> t = threading.Thread(target=f)
        >>> t.start()
        >>> t.join()
        >>> d.x
        1
    c                 D    t           j                            |            d S r;   )r4   
_instancesrz   rR   s    rC   r   zThreadedDict.__init__  s    ##D)))))rJ   c                 D    t           j                            |            d S r;   )r4   r  r   rR   s    rC   __del__zThreadedDict.__del__  s    &&t,,,,,rJ   c                      t          |           S r;   )idrR   s    rC   __hash__zThreadedDict.__hash__   s    $xxrJ   c                  f    t          t          j                  D ]} |                                  dS )z"Clears all ThreadedDict instances.N)rm   r4   r  clear)ts    rC   	clear_allzThreadedDict.clear_all  s5    l-.. 	 	AGGIIII	 	rJ   c                     | j         |         S r;   __dict__r   s     rC   r3  zThreadedDict.__getitem__  s    }S!!rJ   c                     || j         |<   d S r;   r  rG   s      rC   __setitem__zThreadedDict.__setitem__  s    "crJ   c                     | j         |= d S r;   r  r   s     rC   __delitem__zThreadedDict.__delitem__  s    M#rJ   c                     || j         v S r;   r  r   s     rC   __contains__zThreadedDict.__contains__  s    dm##rJ   c                 8    | j                                          d S r;   )r  r  rR   s    rC   r  zThreadedDict.clear  s    rJ   c                 4    | j                                         S r;   )r  r  rR   s    rC   r  zThreadedDict.copy      }!!###rJ   Nc                 8    | j                             ||          S r;   )r  rn   r@   rA   r,  s      rC   rn   zThreadedDict.get!  s    }  g...rJ   c                 4    | j                                         S r;   )r  r   rR   s    rC   r   zThreadedDict.items$  s    }""$$$rJ   c                 *    t          | j                  S r;   )r   r  rR   s    rC   r   zThreadedDict.iteritems'  s    '''rJ   c                 4    | j                                         S r;   )r  rl   rR   s    rC   rl   zThreadedDict.keys*  r  rJ   c                 ~    	 t          | j                  S # t          $ r | j                                        cY S w xY wr;   )iterkeysr  	NameErrorrl   rR   s    rC   r  zThreadedDict.iterkeys-  sL    	(DM*** 	( 	( 	(=%%'''''	(s    #<<c                 4    | j                                         S r;   )r  r   rR   s    rC   r   zThreadedDict.values5  s    }##%%%rJ   c                 *    t          | j                  S r;   )r   r  rR   s    rC   r   zThreadedDict.itervalues8  s    $-(((rJ   c                 (     | j         j        |g|R  S r;   )r  rj   )r@   rA   r   s      rC   rj   zThreadedDict.pop;  s     t} ,t,,,,rJ   c                 4    | j                                         S r;   )r  popitemrR   s    rC   r  zThreadedDict.popitem>  s    }$$&&&rJ   c                 8    | j                             ||          S r;   )r  rx   r  s      rC   rx   zThreadedDict.setdefaultA  s    }''W555rJ   c                 *     | j         j        |i | d S r;   )r  r   )r@   r   kwargss      rC   r   zThreadedDict.updateD  s"    d-f-----rJ   c                     d| j         z  S )Nz<ThreadedDict %r>r  rR   s    rC   rQ   zThreadedDict.__repr__G  s    "T]22rJ   r;   ) rT   rU   rV   rW   r   r  r   r  r  r  staticmethodr3  r  r  r  has_keyr  r  rn   r   r   rl   r  r*  r   r   rj   r  rx   r   rQ   __str__rF   rJ   rC   r4   r4     s        " J* * *- - -    
 Y''I
" " "# # #  $ $ $ G  $ $ $/ / / /% % %( ( ($ $ $( ( ( D& & &) ) )- - -' ' '6 6 6 6. . .3 3 3 GGGrJ   r4   c                 `    t          |          D ]\  }}|dk    rt          | ||           dS )a:  
    Automatically assigns local variables to `self`.

        >>> self = storage()
        >>> autoassign(self, dict(a=1, b=2))
        >>> self.a
        1
        >>> self.b
        2

    Generally used in `__init__` methods, as in:

        def __init__(self, foo, bar, baz=1): autoassign(self, locals())
    r@   N)r   ro   )r@   localsrA   rH   s       rC   r6   r6   P  sJ     "&)) " "e&==c5!!!!" "rJ   c                     | dk     rt          d          d}g }| dk    r5t          | d          \  } }|                    d||                    | dk    5d                    |          pdS )ax  
    Converts an integer to base 36 (a useful scheme for human-sayable IDs).

        >>> to36(35)
        'z'
        >>> to36(119292)
        '2k1o'
        >>> int(to36(939387374), 36)
        939387374
        >>> to36(0)
        '0'
        >>> to36(-393)
        Traceback (most recent call last):
            ...
        ValueError: must supply a positive integer

    r   zmust supply a positive integer$0123456789abcdefghijklmnopqrstuvwxyz$   r   0)r   r  rT  r   )qletters	convertedr   s       rC   r7   r7   e  s~    $ 	1uu9:::4GI
q&&a}}1GAJ''' q&& 779$$rJ   z(?<!\()(http://(\S+))c                 X   |                     dg           }t          | ||||fi |}|D ]j}t          |t                    r7|                    |d         |d         |                    d                     Ot          |d          rit          j        	                    t          |dd                    }	t          |dd          }
|                    |	|                                |
           t          |t                    rpt          |d	          }|                                }|                                 t          j        	                    |          }	|                    |	|d           Mt          d
t!          |          z            |                                 dS )a  
    Sends the email message `message` with mail and envelope headers
    for from `from_address_` to `to_address` with `subject`.
    Additional email headers can be specified with the dictionary
    `headers.

    Optionally cc, bcc and attachments can be specified as keyword arguments.
    Attachments must be an iterable and each attachment can be either a
    filename or a file object or a dictionary with filename, content and
    optionally content_type keys.

    If `web.config.smtp_server` is set, it will send the message
    to that SMTP server. Otherwise it will look for
    `/usr/sbin/sendmail`, the typical location for the sendmail-style
    binary. To use sendmail from a different path, set `web.config.sendmail_path`.
    attachmentsrE  rF  content_typereadrD  r   NrbzInvalid attachment: %s)rj   _EmailMessager\   rP   attachrn   rc   r  pathbasenamegetattrr  r]   rA  r  r   reprsend)from_address
to_addresssubjectmessageheadersr   r  mailarE  r  rG  rF  s                rC   r8   r8     s   " &&++Kz7GWSSPRSSD A Aa 	AKK*q|QUU>5J5JKKKKQ 	Aw''62(>(>??H"1nd;;LKK!&&((L99993 	AQAffhhGGGIIIw''**HKK'400005Q?@@@IIKKKKKrJ   c                   N    e Zd ZddZd ZddZd Zd Zd Zd Z	d	 Z
d
 Zd ZdS )r  Nc                 4   d }t          |          }t          |          }t          |          } ||          } ||                    dg                     } ||                    dg                     }	||z   |	z   }
dd lj                            |          d         | _        fd|
D             | _        t          |d                    |          |d|pi           | _	        |rd                    |          | j	        d	<   | 
                                | _        | j                            d
d           | j                            dd           | j                            dd           | j                            |d           d| _        d S )Nc                 d    t          | t                    st          |           gS d | D             S )Nc                 ,    g | ]}t          |          S rF   r   )rg   r  s     rC   rh   z;_EmailMessage.__init__.<locals>.listify.<locals>.<listcomp>  s    ...q

...rJ   )r\   rm   r   r   s    rC   listifyz'_EmailMessage.__init__.<locals>.listify  s6    a&& /

|#..A....rJ   ccbccr   r   c                 P    g | ]"}j                             |          d          #S )r   )utils	parseaddr)rg   r   emails     rC   rh   z*_EmailMessage.__init__.<locals>.<listcomp>  s.    KKK15;0033A6KKKrJ   z, )FromToSubjectCczContent-Transfer-Encoding7bitContent-DispositioninlinezMIME-Versionz1.0r   F)r   rn   email.utilsr  r  r  
recipientsr#   r   r	  new_messager  
add_headerset_payload	multipart)r@   r  r  r  r  r	  r   r  r  r  r  r  s              @rC   r   z_EmailMessage.__init__  s   	/ 	/ 	/ '""'""|,,WZ((
WRVVD"%%&&gbffUB''(("_s*
!K11,??BKKKK
KKK!:)>)>7SSMr
 

  	/!%2DL'')) ;VDDD 5x@@@666  '222rJ   c                 "    ddl m}  |            S )Nr   )Message)email.messager%  )r@   r%  s     rC   r   z_EmailMessage.new_message  s     ))))))wyyrJ   c                 ^   | j         sR|                                 }|                    dd           |                    | j                   || _        d| _         dd l}	 ddlm} n#  ddlm} Y nxY w|p|	                    |          d         pd}|                                 }|
                    |           |                    d|           |                    dd	|
           |                    d          s|                    |           | j                            |           d S )NzContent-Typezmultipart/mixedTr   )encoders)Encoderszapplication/octet-streamr  
attachment)rE  ztext/)r#  r   r!  r  r  	mimetypesr  r(  r)  
guess_typer"  r   encode_base64)r@   rE  rF  r  msgr+  r(  s          rC   r  z_EmailMessage.attach  s`   ~ 	"""$$CNN>+<===JJt|$$$DL!DN	3&&&&&&&	322222222  *##H--a0*) 	      ~|444,lXNNN&&w// 	(""3'''C     s   A& &A0c                     t          | j                  D ]S\  }}|                                dk    r| j                            |           8| j                            ||           Ti | _        d S )Nzcontent-type)r   r	  lowerr  set_typer!  )r@   rB   r~   s      rC   prepare_messagez_EmailMessage.prepare_message  sq    dl++ 	. 	.DAqwwyyN**%%a((((''1----rJ   c                    |                                   | j                                        }	 ddlm} n,# t
          $ r t          t                                }Y nw xY w|j                            d          r| 	                    |           d S |j                            d          dk    r| 
                    |           d S |                     |           d S )Nr   webapiconfigsmtp_serveremail_engineaws)r2  r  	as_stringr   r5  ImportErrorr   r7  rn   send_with_smtpsend_with_awsdefault_email_sender)r@   message_textr5  s      rC   r  z_EmailMessage.send  s    |--//	/        	/ 	/ 	/GII...FFF	/ =]++ 	4-----]~..%77|,,,,,%%l33333s   6 &AAc                 P   	 ddl m} n,# t          $ r t          t                                }Y nw xY wdd l}|j                            |j                            d          |j                            d                    }|	                    || j
        | j                   d S )Nr   r4  r6  r   aws_access_key_idaws_secret_access_key)rB  rC  )r   r5  r<  r   boto.sessesSESConnectionr7  rn   send_raw_emailr  r  )r@   r@  r5  botor   s        rC   r>  z_EmailMessage.send_with_aws  s    	/        	/ 	/ 	/GII...FFF	/ 	H""$m//0CDD"(-"3"34K"L"L # 
 
 	
t'8$/JJJJJ   	 &22c                 (   	 ddl m} n,# t          $ r t          t                                }Y nw xY w|j                            d          }|j                            dd          }|j                            d          }|j                            d          }|j                            d	d           }|j                            d
d          }dd l}	|	                    ||          }
|r|
                    |           |r<|
	                                 |

                                 |
	                                 |r|r|
                    ||           |
                    | j        | j        |           |
                                 d S )Nr   r4  r6  r8  	smtp_portr   smtp_usernamesmtp_passwordsmtp_debuglevelsmtp_starttlsF)r   r5  r<  r   r7  rn   smtplibSMTPset_debuglevelehlostarttlsloginr8   r  r  quit)r@   r@  r5  serverportusernamepassworddebug_levelrT  rP  
smtpservers              rC   r=  z_EmailMessage.send_with_smtp  s   	/        	/ 	/ 	/GII...FFF	/ ""=11}  a00=$$_55=$$_55m''(94@@=$$_e<<\\&$//
 	3%%k222 	OO!!!OO 	1 	1Xx000D-tMMMrI  c                 V   	 ddl m} n,# t          $ r t          t                                }Y nw xY w|j                            dd          }| j                            d          r
J d            | j        D ]!}|                    d          r
J d            "|d| j        g| j        z   }t          j
        |t          j        	          }|j                            |                    d
                     |j                                         |                                 d S )Nr   r4  r6  sendmail_pathz/usr/sbin/sendmailr  securityz-f)stdinr   )r   r5  r<  r   r7  rn   r  r   r  
subprocessPopenPIPEr`  r#  encoder  wait)r@   r@  r5  r8   r   cmdps          rC   r?  z"_EmailMessage.default_email_sender;  s1   	/        	/ 	/ 	/GII...FFF	/ =$$_6JKK$//44@@j@@@ 	5 	5A||C((44*4444t01DOCS
888	l))'22333		rI  c                     dS )Nz<EmailMessage>rF   rR   s    rC   rQ   z_EmailMessage.__repr__O  s    rJ   c                 4    | j                                         S r;   )r  r;  rR   s    rC   r  z_EmailMessage.__str__R  s    |%%'''rJ   r;   )rT   rU   rV   r   r   r  r2  r  r>  r=  r?  rQ   r  rF   rJ   rC   r  r    s        " " " "H  
! ! ! !>  4 4 4 K K K  >  (     ( ( ( ( (rJ   r  __main__)r   r;   r   )ri   )r   )RrW   rp  r  rerB  ra  r   r   r   r:  r   threadlocal
py3helpersr   r   r   r<  io__all__rP   r   r	   r
   r   r   rm   rk   r   	frozensetr   r   r   r   r   r   r   r   r   r   r   compiler   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/   r0   r1   r2   r3   r4   r5   r6   r7   r_urlr8   r  rT   doctesttestmodrF   rJ   rC   <module>ru     s   
  				 				      



          * * * * * *       
!!!!!!!   2 2 2j%7 %7 %7 %7 %7d %7 %7 %7P M M M`T7 T7 T7 T7 T7g T7 T7 T7n 	uc9%	 	 	 	 	E 	 	 	 	e  "& & && & &"2 2 2   " 2 2 2jP" P" P" P" P" P" P" P"f WRZ  

 
       7 7 7 	A 	A 	A   2.C .C .Cb^ ^ ^ ^ ^ ^ ^ ^B 
   "" " "G G G    $  (               ^6 ^6 ^6 ^6B
< 
< 
<  &2 2 2j7 7 7E E E0           4 . . . . . . . .b ). ). ). ).Xd d d d d; d d dN " " "*% % %: 	
+,,$ $ $ $Ng( g( g( g( g( g( g( g(T zNNNGO s   = A
A