U
    W+d                     @   s  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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mZmZmZ ddlmZ ddlmZmZ eZddlm Z  zddl!m"Z" W n e#k
r   e$Z"Y nX dd	d
dddddddddddddddddddddd d!d"d#d$d%d&gZ%e&d'Z'e&d(Z(e&d)Z)d*d+ Z*d{d,d-Z+d|d.d/Z,d}d0d1Z-d~d4d5Z.dd6d7Z/G d8d9 d9e0Z1d:d; Z2dd@dAZ3ddBdCZ4ddDdEZ5dFZ6dGZ7dHZ8e9 Z:edIdJ Z;ddKdLZ<dMdN Z=ddOdPZ>dQdR Z?ddSdTZ@G dUdV dVeAZBG dWdX dXejCjDZEG dYdZ dZe0ZFG d[d\ d\eAZGdd]d^ZHd_d` ZIdadb ZJdcdd ZKddhdiZLdjdk ZMddmdnZNdldefdodpZOdqdr ZPdsdt ZQG dudv dveAZRdwdx ZSdydz ZTdS )z7
Some handy utility functions used by several classes.
    N)sixStringIOurllibencodebytes)contextmanager)md5sha512)json)JSONDecodeErrorZaclZcorsZdefaultObjectAcllocationloggingZ
partNumberpolicyZrequestPaymentZtorrentZ
versioningZ	versionIdversionsZwebsiteZuploadsZuploadIdzresponse-content-typezresponse-content-languagezresponse-expireszresponse-cache-controlzresponse-content-dispositionzresponse-content-encodingdeleteZ	lifecycleZtaggingrestoreZstorageClassZwebsiteConfigZcomposeZbillingZuserProjectZencryptionConfigz(.)([A-Z][a-z]+)z([a-z])([0-9]+)z([a-z0-9])([A-Z])c                 C   s,   t | dkr| S | d tj| d fS d S )N   r   )lenr   parseunquote)nv r   ./tmp/pip-unpacked-wheel-dlxw5sjy/boto/utils.py	unquote_vk   s    r   c                 C   s~  |st j }i }|D ]@}| }|| dk	r|dksB||jrt||  ||< qd|krhd|d< d|krxd|d< |j|krd|d< |rt||d< t	|
 }d|  }	|D ]6}|| }
||jr|	d||
f 7 }	q|	d|
 7 }	q|d	}|	|d
 7 }	t|dkrz|d d}dd |D }dd |D }t|d
krz|jdd d dd |D }|	d	7 }	|	d|7 }	|	S )zE
    Generates the aws canonical string for the given parameters
    N)content-md5content-typedater    r   r   z%s
z%s:%s
?r   r   &c                 S   s   g | ]}| d dqS )=r   )split.0ar   r   r   
<listcomp>   s     z$canonical_string.<locals>.<listcomp>c                 S   s    g | ]}|d  t krt|qS )r   )qsa_of_interestr   r!   r   r   r   r$      s      c                 S   s   | d S Nr   r   )xr   r   r   <lambda>       z"canonical_string.<locals>.<lambda>)keyc                 S   s   g | ]}d  |qS )r   )joinr!   r   r   r   r$      s     )botoproviderget_defaultlower
startswithZheader_prefixstrstripZdate_headersortedkeysr    r   sortr+   )methodpathheadersexpiresr-   Zinteresting_headersr*   ZlkZsorted_header_keysbufvaltZqsar   r   r   canonical_stringr   sL    



r=   c                 C   s`   |st j }|j}|  }| D ]6}| t jjj	j
krJ|| ||< q$|| ||| < q$|S N)r,   r-   r.   metadata_prefixcopyr4   r/   Zs3r*   ZKeyZbase_user_settable_fields)r8   metadatar-   r?   Zfinal_headerskr   r   r   
merge_meta   s    
rC   c              	   C   s   |st j }|j}i }|  D ]j}| |r tj	| | }t
|trpz|d}W n tk
rn   Y nX |||t|d  < | |= q |S Nutf-8)r,   r-   r.   r?   r4   r/   r0   r   r   r   
isinstancebytesdecodeUnicodeDecodeErrorr   )r8   r-   r?   rA   hkeyr;   r   r   r   get_aws_metadata   s    

rK   T
   c                 C   s2  t d|D ]}zdtji }tj|}tj| }|j||d}| }	t|	t	j
slt|	drl|	d}	|	W   S  tjjk
r }
 z$|
 }|dkr|sW Y 
 dS W 5 d}
~
X Y n. tk
r }
 ztjd W 5 d}
~
X Y nX |d	 |kr
tjd
 ttd| tjddd q
tjd dS )a  
    Retry a url.  This is specifically used for accessing the metadata
    service on an instance.  Since this address should never be proxied
    (for security reasons), we create a ProxyHandler with a NULL
    dictionary to override any proxy settings in the environment.
    r   )timeoutrH   rE   i  r   Nz&Caught exception reading instance datar   zSleeping before retrying   Botomax_retry_delay<   z'Unable to read instance data, giving up)ranger   requestProxyHandlerbuild_openerRequestopenreadrF   r   string_typeshasattrrH   error	HTTPErrorgetcode	Exceptionr,   log	exceptiondebugtimesleepminconfigget)urlretry_on_404num_retriesrM   iZproxy_handleropenerreqrresultecoder   r   r   	retry_url   s2    

rq   c                 C   s   t | ||S r>   )LazyLoadMetadata)rg   ri   rM   r   r   r   _get_instance_metadata   s    rs   c                       sh   e Zd ZdddZdd Z fddZddd	Z fd
dZ fddZ fddZ	 fddZ
  ZS )rr   Nc           
      C   s   || _ || _i | _g | _|| _tjj| j | j| jd}|r|d}|D ]v}|	drp|dd }| j
| nF|d}|dkr||d d  }|d| d }	n| }}	|	| j|< d | |< qHd S )	Nri   rM   
/r   r   r   z/openssh-key)_url_num_retries_leaves_dicts_timeoutr,   utilsrq   r    endswithappendfind)
selfrg   ri   rM   datafieldsfieldr*   presourcer   r   r   __init__   s&    



zLazyLoadMetadata.__init__c                 C   s   | D ]}| |  qd S r>   r   r   r*   r   r   r   _materialize  s    zLazyLoadMetadata._materializec           	         s"  || krt t| |S t t| |}|d k	r4|S || jkr| j| }d }td| jD ]\}zttjj| j	t
jj|dd | j| jd}|r|d dkrt|}W  qn$|d}|dkr|d}W  qW n tk
r$ } z0tjd|jj|f  tjd|  |}W 5 d }~X Y nB tk
rd } z"tjd	d
|jj   |} W 5 d }~X Y nX tjdd|d    |d | jkrZtt d|  tjddd}t| qZtjd tjd|jj|f  ||| |< n&|| jkrt| j	| d | j| |< t t| |S )Nr   z/:)safert   {ru   zencountered '%s' exception: %szcorrupted JSON data found: %szencountered unretryablez '%s' exception, re-raisingz"Caught exception reading meta dataz for the '%s' tryr   rN   rO   rP   rQ   z#Unable to read meta data, giving uprv   ) superrr   __getitem__rz   rR   ry   r,   r}   rq   rx   r   r   quoter|   r	   loadsr   r    r
   r_   ra   	__class____name__r^   r[   rd   randomre   rf   rb   rc   r{   )	r   r*   r;   r   Zlast_exceptionrj   r   ro   Z
next_sleepr   r   r   r     s    




 
 
zLazyLoadMetadata.__getitem__c                 C   s(   z
| | W S  t k
r"   | Y S X d S r>   )KeyError)r   r*   defaultr   r   r   rf   S  s    
zLazyLoadMetadata.getc                    s   |    tt|  S r>   )r   r   rr   valuesr   r   r   r   r   Y  s    zLazyLoadMetadata.valuesc                    s   |    tt|  S r>   )r   r   rr   itemsr   r   r   r   r   ]  s    zLazyLoadMetadata.itemsc                    s   |    tt|  S r>   )r   r   rr   __str__r   r   r   r   r   a  s    zLazyLoadMetadata.__str__c                    s   |    tt|  S r>   )r   r   rr   __repr__r   r   r   r   r   e  s    zLazyLoadMetadata.__repr__)N)N)r   
__module____qualname__r   r   r   rf   r   r   r   r   __classcell__r   r   r   r   rr      s   
C
rr   c                 C   s   d| ||f S )ax  
    Builds an EC2 metadata URL for fetching information about an instance.

    Example:

        >>> _build_instance_metadata_url('http://169.254.169.254', 'latest', 'meta-data/')
        http://169.254.169.254/latest/meta-data/

    :type url: string
    :param url: URL to metadata service, e.g. 'http://169.254.169.254'

    :type version: string
    :param version: Version of the metadata to get, e.g. 'latest'

    :type path: string
    :param path: Path of the metadata to get, e.g. 'meta-data/'. If a trailing
                 slash is required it must be passed in with the path.

    :return: The full metadata URL
    z%s/%s/%sr   )rg   versionr7   r   r   r   _build_instance_metadata_urlj  s    r   latesthttp://169.254.169.254
meta-data/   c                 C   sJ   zt || |}t|||dW S  tjjk
rD   tjd| Y dS X dS )a  
    Returns the instance metadata as a nested Python dictionary.
    Simple values (e.g. local_hostname, hostname, etc.) will be
    stored as string values.  Values such as ancestor-ami-ids will
    be stored in the dict as a list of string values.  More complex
    fields such as public-keys and will be stored as nested dicts.

    If the timeout is specified, the connection to the specified url
    will time out after the specified number of seconds.

    rt   zBException caught when trying to retrieve instance metadata for: %sN)r   rs   r   r[   URLErrorr,   r_   r`   )r   rg   r   rM   ri   Zmetadata_urlr   r   r   get_instance_metadata  s    r   c           
      C   s   i }t || d}zdt|||d}|d}|D ]@}t|d | d ||d}	|	d dkrbt|	}	|r.|	||< q.|W S  tjjk
r   Y dS X dS )zF
    Returns the instance identity as a nested Python dictionary.
    zdynamic/instance-identity/rt   ru   rv   r   r   N)r   rq   r    r	   r   r   r[   r   )
r   rg   rM   ri   Ziidbase_urlr   r   r   r;   r   r   r   get_instance_identity  s     


r   c           
      C   sb   t || d}t|d||d}|r^|r^||}i }|D ]&}|d}	|	d  ||	d  < q6|S )Nz	user-dataF)rh   ri   rM   r   r   r   )r   rq   r    r2   )
r   seprg   rM   ri   Zud_url	user_datalZnvpairr<   r   r   r   get_instance_userdata  s    

r   z%Y-%m-%dT%H:%M:%SZz%Y-%m-%dT%H:%M:%S.%fZz%a, %d %b %Y %H:%M:%S %Zc                 c   sF   t 8 ttj}zttj| V  W 5 ttj| X W 5 Q R X dS )zE
    A context manager to set the locale in a threadsafe manner.
    N)LOCALE_LOCKlocale	setlocaleLC_ALL)nameZsavedr   r   r   r     s
    r   c                 C   s   | st  } t t| S r>   )rb   gmtimestrftimeISO8601)tsr   r   r   get_ts  s    r   c                 C   s   t d |  } z tj| t}|W W  5 Q R  S  tk
r   z$tj| t}|W  Y W  5 Q R  S  tk
r   tj| t}| Y  Y W  5 Q R  S X Y nX W 5 Q R X d S )NC)r   r2   datetimestrptimer   
ValueError
ISO8601_MSRFC1123)r   dtr   r   r   parse_ts  s    
r   c                 C   sv   |rd| |f } |  d}d }zD|dd  D ]0}|r@t||}q,ttd|dd |}q,|W S    Y d S X d S )Nz%s.%s.r   r   rw   )r    getattr
__import__r+   )module_name
class_namemodulescmr   r   r   
find_class  s    
r   c                 C   s,   d}|d7 }t j|| |||f }| S )z=
    Update your Dynamic DNS record with DNSMadeEasy.com
    z,https://www.dnsmadeeasy.com/servlet/updateipz$?username=%s&password=%s&id=%s&ip=%s)r   rS   urlopenrX   )usernamepasswordZdme_id
ip_addressZdme_urlsr   r   r   
update_dme  s    r   c                 C   s
  t jd|   |dkr t }z| drv| tdd dd\}}t j||d}|	|}|
|}|| n`|r|rtj }	|	d| || tj|	}
tj|
}tj| tj| }||  |d W n"    t jd|   d}Y nX |S )	z
    Fetch a file based on the URI provided.
    If you do not pass in a file pointer a tempfile.NamedTemporaryFile,
    or None if the file could not be retrieved is returned.
    The URI can be either an HTTP url, or "s3://bucket_name/key_name"
    zFetching %sNzs3://rv   r   )Zaws_access_key_idZaws_secret_access_keyr   zProblem Retrieving file: %s)r,   r_   infotempfileNamedTemporaryFiler0   r   r    Z
connect_s3Z
get_bucketget_keyZget_contents_to_filer   rS   HTTPPasswordMgrWithDefaultRealmadd_passwordHTTPBasicAuthHandlerrU   install_openerr   writerX   seekr`   )urifiler   r   Zbucket_nameZkey_namer   Zbucketr*   ZpassmanZauthhandlerrk   r   r   r   r   
fetch_file  s4    




r   c                   @   sT   e Zd ZdddZdddZdd	 Zd
d ZeeeddZdd Z	ee	eddZ
dS )ShellCommandTFNc                 C   s0   d| _ || _t | _|| _|| _| j|d d S )Nr   )cwd)	exit_codecommandr   log_fpwait	fail_fastrun)r   r   r   r   r   r   r   r   r   $  s    zShellCommand.__init__c                 C   s   t jd| j  tj| jdtjtjtj|d| _| jr| j	 d kr|t
d | j }| j|d  | j|d  q8t j| j  | jj| _| jr| jdkrtd| j d | j | jS d S )Nz
running:%sT)shellstdinstdoutstderrr   r   r   zCommand z failed with status )r,   r_   r   r   
subprocessPopenPIPEprocessr   pollrb   rc   communicater   r   getvalue
returncoder   r   r^   )r   r   r<   r   r   r   r   ,  s,    




zShellCommand.runc                 C   s   t d S r>   )AttributeErrorr   valuer   r   r   setReadOnlyB  s    zShellCommand.setReadOnlyc                 C   s   | j S r>   )r   r   r   r   r   	getStatusE  s    zShellCommand.getStatuszThe exit code for the commandc                 C   s
   | j  S r>   )r   r   r   r   r   r   	getOutputK  s    zShellCommand.getOutputz*The STDIN and STDERR output of the command)TFN)N)r   r   r   r   r   r   r   propertystatusr   outputr   r   r   r   r   "  s   

r   c                       s(   e Zd ZdZ fddZdd Z  ZS )AuthSMTPHandlera  
    This class extends the SMTPHandler in the standard Python logging module
    to accept a username and password on the constructor and to then use those
    credentials to authenticate with the SMTP server.  To use this, you could
    add something like this in your boto config file:

    [handler_hand07]
    class=boto.utils.AuthSMTPHandler
    level=WARN
    formatter=form07
    args=('localhost', 'username', 'password', 'from@abc', ['user1@abc', 'user2@xyz'], 'Logger Subject')
    c                    s&   t t| |||| || _|| _dS )z
        Initialize the handler.

        We have extended the constructor to accept a username/password
        for SMTP authentication.
        N)r   r   r   r   r   )r   mailhostr   r   fromaddrtoaddrssubjectr   r   r   r   `  s     zAuthSMTPHandler.__init__c              	   C   s   z~| j }|stj}t| j|}|| j| j | |}d| j	d
| j| |tj |f }|| j	| j| |  W n. ttfk
r    Y n   | | Y nX dS )z
        Emit a record.

        Format the record and send it to the specified addressees.
        It would be really nice if I could add authorization to this class
        without having to resort to cut and paste inheritance but, no.
        z-From: %s
To: %s
Subject: %s
Date: %s

%s,N)mailportsmtplib	SMTP_PORTSMTPr   loginr   r   formatr   r+   r   
getSubjectemailr}   
formatdatesendmailquitKeyboardInterrupt
SystemExithandleError)r   recordportsmtpmsgr   r   r   emitm  s(    

 zAuthSMTPHandler.emit)r   r   r   __doc__r   r  r   r   r   r   r   r   R  s   r   c                   @   sp   e Zd ZdZG dd deZdd Zdd Zdd	 Zd
d Z	dd Z
dd Zdd Zdd Zdd Zdd ZdS )LRUCacheaq  A dictionary-like object that stores only a certain number of items, and
    discards its least recently used item when full.

    >>> cache = LRUCache(3)
    >>> cache['A'] = 0
    >>> cache['B'] = 1
    >>> cache['C'] = 2
    >>> len(cache)
    3

    >>> cache['A']
    0

    Adding new items to the cache does not increase its size. Instead, the least
    recently used item is dropped:

    >>> cache['D'] = 3
    >>> len(cache)
    3
    >>> 'B' in cache
    False

    Iterating over the cache returns the keys, starting with the most recently
    used:

    >>> for key in cache:
    ...     print key
    D
    A
    C

    This code is based on the LRUCache class from Genshi which is based on
    `Myghty <http://www.myghty.org>`_'s LRUCache from ``myghtyutils.util``,
    written by Mike Bayer and released under the MIT license (Genshi uses the
    BSD License).
    c                   @   s   e Zd Zdd Zdd ZdS )zLRUCache._Itemc                 C   s   d  | _ | _|| _|| _d S r>   )previousnextr*   r   )r   r*   r   r   r   r   r     s    zLRUCache._Item.__init__c                 C   s
   t | jS r>   )reprr   r   r   r   r   r     s    zLRUCache._Item.__repr__N)r   r   r   r   r   r   r   r   r   _Item  s   r  c                 C   s   t  | _|| _d | _d | _d S r>   )dict_dictcapacityheadtail)r   r  r   r   r   r     s    zLRUCache.__init__c                 C   s
   || j kS r>   )r  r   r   r   r   __contains__  s    zLRUCache.__contains__c                 c   s   | j }|r|jV  |j}qd S r>   )r  r*   r  )r   curr   r   r   __iter__  s    zLRUCache.__iter__c                 C   s
   t | jS r>   )r   r  r   r   r   r   __len__  s    zLRUCache.__len__c                 C   s   | j | }| | |jS r>   )r  _update_itemr   )r   r*   itemr   r   r   r     s    

zLRUCache.__getitem__c                 C   sR   | j |}|d kr6| ||}|| j |< | | n||_| | |   d S r>   )r  rf   r  _insert_itemr   r  _manage_size)r   r*   r   r   r   r   r   __setitem__  s    

zLRUCache.__setitem__c                 C   s
   t | jS r>   )r  r  r   r   r   r   r     s    zLRUCache.__repr__c                 C   s:   d |_ | j|_| jd k	r"|| j_ n|| _|| _|   d S r>   )r  r  r  r  r"  )r   r   r   r   r   r!    s    

zLRUCache._insert_itemc                 C   sN   t | j| jkrJ| j| jj= | j| jkr<| jj| _d | j_q d  | _| _q d S r>   )r   r  r  r  r*   r  r  r  r   r   r   r   r"    s    

zLRUCache._manage_sizec                 C   sV   | j |krd S |j}|j|_|jd k	r0||j_n|| _d |_| j |_| | j _| _ d S r>   )r  r  r  r  )r   r   r  r   r   r   r    s    


zLRUCache._update_itemN)r   r   r   r  objectr  r   r  r  r  r   r#  r   r!  r"  r  r   r   r   r   r    s   %	
	r  c                   @   s>   e Zd ZdZeZdddZdd Zdd Zd	d
 Z	dd Z
dS )Passwordzp
    Password object that stores itself as hashed.
    Hash defaults to SHA512 if available, MD5 otherwise.
    Nc                 C   s   || _ |r|| _dS )zh
        Load the string from an initial value, this should be the
        raw hashed password.
        N)r1   hashfunc)r   r1   r&  r   r   r   r     s    zPassword.__init__c                 C   s(   t |ts|d}| | | _d S rD   )rF   rG   encoder&  	hexdigestr1   r   r   r   r   set  s    

zPassword.setc                 C   s
   t | j S r>   r1   r   r   r   r   r     s    zPassword.__str__c                 C   s<   |d krdS t |ts |d}t| | t| jkS )NFrE   )rF   rG   r'  r1   r&  r(  )r   otherr   r   r   __eq__  s
    

zPassword.__eq__c                 C   s   | j rt| j S dS d S r&   )r1   r   r   r   r   r   r    s    
zPassword.__len__)NN)r   r   r   r  _hashfnr&  r   r)  r   r,  r  r   r   r   r   r%     s   
	r%  c                 C   s  |pg }|r"dt jdd| f } |s6t jddd }|rĐzlt jddd}tjj }||d< ||d	< ||d
< tjjdd|d< | |d< |r|	tjj
| |rtjjdd}|| tj| |	| |D ]}|	| qt jddd}	t jddr*t|	tt jdd}
n
t|	}
t jddr\|
  |
  |
  t jddd}t jddd}|r|
|| |
|||  |
  W n   t jd Y nX d S )Nz[%s] %sZInstancezinstance-idZNotificationZsmtp_toZ	smtp_fromr,   FromzReply-ToToT)	localtimeDateSubjecttexthtml	smtp_host	localhostZ	smtp_portZsmtp_tls	smtp_userr   	smtp_passznotify failed)r,   re   	get_valuer  mime	multipartMIMEMultipartr}   r  attachr3  MIMETextbaseMIMEBaseset_payloadencodersencode_base64r   r   intZgetboolehlostarttlsr  r  	as_stringr  r_   r`   )r   bodyZ	html_bodyZ	to_stringattachmentsZappend_instance_idZfrom_stringr  partr5  serverr7  r8  r   r   r   notify&  sd      

 
rL  c                 C   sD   t jst| tr| S t| t js*t | } t| t jr@| d} | S rD   )r   PY2rF   rG   rY   	text_typer'  r   r   r   r   get_utf8_value^  s    

rP  c                 C   s(   t | ts$t | trt| } n| g} | S r>   )rF   listtuplerO  r   r   r   mklistk  s
    


rS  c                 C   s(   t d| }td|}td| S )a~  Convert camel case to a "pythonic" name.

    Examples::

        pythonize_name('CamelCase') -> 'camel_case'
        pythonize_name('already_pythonized') -> 'already_pythonized'
        pythonize_name('HTTPRequest') -> 'http_request'
        pythonize_name('HTTPStatus200Ok') -> 'http_status_200_ok'
        pythonize_name('UPPER') -> 'upper'
        pythonize_name('') -> ''

    z\1_\2)_first_cap_regexsub_number_cap_regex_end_cap_regexr/   )r   s1s2r   r   r   pythonize_namet  s    rZ  F
text/plain:c                 C   s   t jj }| D ]~\}}t||}|dd\}}	|dkrNt jjj||	d}
n&t jj	||	}
|

| t j|
 |
jdd|d ||
 q| }|rt }tjd|d	}z|| W 5 |  X | }|S )
a  Description:
    :param content: A list of tuples of name-content pairs. This is used
    instead of a dict to ensure that scripts run in order
    :type list of tuples:

    :param compress: Use gzip to compress the scripts, defaults to no compression
    :type bool:

    :param deftype: The type that should be assumed if nothing else can be figured out
    :type str:

    :param delimiter: mime delimiter
    :type str:

    :return: Final mime multipart
    :rtype: str:
    rv   r   r3  )_subtypezContent-Disposition
attachment)filenamewb)modefileobj)r  r:  r;  r<  guess_mime_typer    r3  r>  r?  r@  rA  rB  rC  
add_headerr=  rG  r   gzipGzipFilecloser   r   )contentcompressdeftype	delimiterwrapperr   conZdefinite_typemaintypesubtypeZmime_conZrcontentr:   gzr   r   r   write_mime_multipart  s(    


rq  c                 C   s>   ddddddd}|}|  D ]\}}| |r|} q:q|S )zDescription: Guess the mime type of a block of text
    :param content: content we're finding the type of
    :type str:

    :param deftype: Default mime type
    :type str:

    :rtype: <type>:
    :return: <description>
    ztext/x-include-urlztext/x-shellscriptztext/cloud-configztext/upstart-jobztext/part-handlerztext/cloud-boothook)z#includez#!z#cloud-configz#upstart-jobz#part-handlerz#cloud-boothook)r   r0   )rh  rj  Zstarts_with_mappingsZrtypeZpossible_typemimetyper   r   r   rc    s    
rc      c                 C   s   t | ||tdS )a  
    Compute MD5 hash on passed file and return results in a tuple of values.

    :type fp: file
    :param fp: File pointer to the file to MD5 hash.  The file pointer
               will be reset to its current location before the
               method returns.

    :type buf_size: integer
    :param buf_size: Number of bytes per read request.

    :type size: int
    :param size: (optional) The Maximum number of bytes to read from
                 the file pointer (fp). This is useful when uploading
                 a file in multiple parts where the file is being
                 split inplace into different parts. Less bytes may
                 be available.

    :rtype: tuple
    :return: A tuple containing the hex digest version of the MD5 hash
             as the first element, the base64 encoded version of the
             plain digest as the second element and the data size as
             the third element.
    )hash_algorithm)compute_hashr   )fpbuf_sizesizer   r   r   compute_md5  s    ry  c           
      C   s   | }|   }|r&||k r&| |}n
| |}|rt|tsH|d}|| |rl|t|8 }|dkrlq|r||k r| |}q0| |}q0| }t|	 
d}|d dkr|dd }|   | }	| | |||	fS )NrE   r   rw   ru   )tellrX   rF   rG   r'  updater   r(  r   digestrH   r   )
rv  rw  rx  rt  Zhash_objsposr   
hex_digestZbase64_digest	data_sizer   r   r   ru    s.    




ru  c                    s    fdd|D S )z
    Takes a specific header name and a dict of headers {"name": "value"}.
    Returns a list of matching header names, case-insensitive.

    c                    s    g | ]}|     kr|qS r   )r/   r"   hr   r   r   r$     s      z)find_matching_headers.<locals>.<listcomp>r   )r   r8   r   r  r   find_matching_headers  s    r  c                    s"   t |  }d fdd|D S )z
    Takes a specific header name and a dict of headers {"name": "value"}.
    Returns a string of all header values, comma-separated, that match the
    input header name, case-insensitive.

    r   c                 3   s&   | ]} | d k	rt  | V  qd S r>   r*  r  r8   r   r   	<genexpr>  s    z(merge_headers_by_name.<locals>.<genexpr>)r  r+   )r   r8   Zmatching_headersr   r  r   merge_headers_by_name  s    
r  c                   @   s   e Zd ZdZdddZdS )RequestHookz
    This can be extended and supplied to the connection object
    to gain access to request and response object after the request completes.
    One use for this would be to implement some specific request logging.
    Fc                 C   s   d S r>   r   )r   rS   responser[   r   r   r   handle_request_data#  s    zRequestHook.handle_request_dataN)F)r   r   r   r  r  r   r   r   r   r    s   r  c                 C   s:   | rt | tsdS | dr dS t| ddkr6dS dS )zQ
    Detect (naively) if the hostname is an IPV6 host.
    Return a boolean.
    F[Tr\  rN   )rF   r1   r0   r   r    hostnamer   r   r   host_is_ipv6'  s    
r  c                 C   s:   |   } t| r&| ddd  dS | ddd S dS )z
    Given a hostname that may have a port name, ensure that the port is trimmed
    returning only the host, including hostnames that are IPV6 and may include
    brackets.
    z]:r   r   z[]r\  N)r2   r  r    r  r   r   r   
parse_host>  s    r  )NN)N)N)TrL   N)N)r   r   r   Nr   )r   r   Nr   )r   Nr   Nr   )N)N)NNN)NNNNT)Fr[  r\  )rs  N)Ur  r   rb   logging.handlersr   r,   Zboto.providerr   r   r   r   reZemail.mime.multipartr  Zemail.mime.baseZemail.mime.textemail.utilsemail.encodersre  	threadingr   Zboto.compatr   r   r   r   
contextlibr   hashlibr   r   r-  r	   Zboto.compat.jsonr
   ImportErrorr   r%   compilerT  rV  rW  r   r=   rC   rK   rq   rs   r  rr   r   r   r   r   r   r   r   Lockr   r   r   r   r   r   r   r$  r   handlersSMTPHandlerr   r  r%  rL  rP  rS  rZ  rq  rc  ry  ru  r  r  r  r  r  r   r   r   r   <module>&   s   

             


  
:


#
v      
    
      





#07w&    
8	
-
	
