
    Y`                        S r SSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKrSSK	r	SSK
r
SSKJr  SSKJr  \R                  (       GaW  SSKrSSKr
SSKr
\
R(                  R*                  r\
R,                  R.                  r\
R(                  R0                  r\
R(                  R2                  r\
R(                  R4                  r\
R(                  R6                  r\
R(                  R8                  r\R:                  R<                  r\
R(                  R>                  r\R:                  R@                  r \
R(                  RB                  r!\
R(                  RD                  r"\
R(                  RF                  r#\
RH                  RJ                  r&\
RN                  RP                  r)OSSK*r*SSK+r+SSK,r,\,R*                  r\,R.                  r\,R0                  r\+RZ                  r\,R2                  r\,R4                  r\,R8                  r\+R\                  r\*R<                  r\*R@                  r \,RB                  r!\,RF                  r#\+R^                  r"\,RJ                  r&\
RP                  r) SSK0r0Sr1S r3\Rh                  " S5      r5\\\Rl                  4S	 jr7SS
 jr8 " S S\5      r9 " S S\:5      r; " S S\5      r< " S S\;5      r=g! \2 a    Sr1 Ncf = f)z:Tool for performing authenticated RPCs against App Engine.    N)encoding)
six_subsetTFc                      [         $ )zEReturn True if we have the SSL package and can validate certificates.)_CAN_VALIDATE_CERTS     3lib/googlecloudsdk/appengine/tools/appengine_rpc.pycan_validate_certsr
   U   s    	r   z,googlecloudsdk.appengine.tools.appengine_rpcc                     [        US5      (       a3  UR                  5       nSR                  S USS  5       5      nUS-   U-   $ [        U S5      (       a  U R                  5       nUS   < SUS	   < 3$ g
)zReturns a 'User-agent' token for the host system platform.

Args:
  os_module, sys_module, platform: Used for testing.

Returns:
  String containing the platform token for the host system.
getwindowsversion.c              3   8   #    U  H  n[        U5      v   M     g 7fN)str).0is     r	   	<genexpr>#GetPlatformToken.<locals>.<genexpr>h   s     @,?qCFF,?s   N   /unamer      unknown)hasattrr   joinr   )	os_module
sys_moduleplatformwindows_versionversion_infor   s         r	   GetPlatformTokenr!   ]   sy     Z,-- 224O88@OBQ,?@@Lc>L((y'""OOEAha))r   c                 L   SnU R                  5        H  nX#S   < SUS   < S3-  nM     SnU(       a  US-   n[        U S5      (       a  U R                  OU R                  nUc  Sn[        U S	5      (       a  U R                  OU R                  5       nUc  Sn[        U S
5      (       a  U R                  OU R                  5       nUc  Sn[        U S5      (       a  U R                  OU R                  5       nUc  SnUU R                  5       UUR                  5       UUUS.-  $ )z}Converts a urllib2.Request to a string.

Args:
  req: urllib2.Request
Returns:
  Multi-line string representing the request.
 r   z:    
z?%(method)s %(selector)s %(type)s/1.1
Host: %(host)s
%(headers)sz	
%(data)sselectortypehostdata)methodr&   r'   r(   headersr)   )header_itemsr   r&   get_selectorr'   get_typer(   get_hostr)   get_data
get_methodupper)	reqinclude_datar+   headertemplatereq_selectorreq_typereq_hostreq_datas	            r	   HttpRequestToStringr;   p   s    '  "fAYq	22G #( ,&H!(j!9!9s?O?O,L f--SXX3<<>(H f--SXX3<<>(H f--SXX3<<>(H	 nn 
 r   c                   4    \ rS rSrSrS rS r\S 5       rSr	g)ClientLoginError   zFRaised to indicate there was an error authenticating with ClientLogin.c                     [         R                  XX#US 5        XPl        UR                  S5      U l        UR                  S5      U l        g )NErrorInfo)	HTTPError__init__argsget_reasoninfo)selfurlcodemsgr+   rD   s         r	   rC   ClientLoginError.__init__   s;    t$Wd;I88G$DL DIr   c                 N    SU R                   U R                  U R                  4-  $ )Nz	%d %s: %s)rJ   rK   reasonrH   s    r	   readClientLoginError.read   s     $))TXXt{{;;;r   c                     U R                   $ r   )rF   rO   s    r	   rN   ClientLoginError.reason   s    <<r   )rF   rD   rG   N)
__name__
__module____qualname____firstlineno____doc__rC   rP   propertyrN   __static_attributes__r   r   r	   r=   r=      s#    N!<
  r   r=   c                   t    \ rS rSrSrSr   SS jrS rSS jrS r	S	 r
S
 r\S 5       rS r   SS jrSrg)AbstractRpcServer   z4Provides a common interface for a simple RPC server.pythonNc                    U(       a  SU l         OSU l         Xl        Xl        XPl        X l        X@l        SU l        Xl        Xl        Xl	        Xl
        0 U l        U(       a  X0R                  S'   U(       a  U R                  R                  U5        Xpl        [        5       U l        U R!                  5       U l        U R                  (       a,  [$        R'                  SU R                  U R                  5        O [$        R'                  SU R                  5        U R                  (       a  U R                  S:X  d0  U R                  S:X  d   U R                  R)                  S5      (       a  U R+                  5         g	g	)
aL  Creates a new HttpRpcServer.

Args:
  host: The host to send requests to.
  auth_function: A function that takes no arguments and returns an
    (email, password) tuple when called. Will be called if authentication
    is required.
  user_agent: The user-agent string to send to the server. Specify None to
    omit the user-agent header.
  source: The source to specify in authentication requests.
  host_override: The host header to send to the server (defaults to host).
  extra_headers: A dict of extra headers to append to every request. Values
    supplied here will override other default headers that are supplied.
  save_cookies: If True, save the authentication cookies to local disk.
    If False, use an in-memory cookiejar instead.  Subclasses must
    implement this functionality.  Defaults to False.
  auth_tries: The number of times to attempt auth_function before failing.
  account_type: One of GOOGLE, HOSTED_OR_GOOGLE, or None for automatic.
  debug_data: Whether debugging output should include data contents.
  secure: If the requests sent using Send should be sent over HTTPS.
  ignore_certs: If the certificate mismatches should be ignored.
  rpc_tries: The number of rpc retries upon http server error (i.e.
    Response code >= 500 and < 600) before failing.
  options: the command line options (ignored in this implementation).
httpshttpFz
User-AgentzServer: %s; Host: %sz
Server: %s	localhostz
localhost:N)schemeignore_certsr(   host_overrideauth_functionsourceauthenticated
auth_tries
debug_data	rpc_triesaccount_typeextra_headersupdatesave_cookiesMozillaCookieJar
cookie_jar
_GetOpeneropenerloggerdebug
startswith_DevAppServerAuthenticate)rH   r(   rf   
user_agentrg   re   rm   ro   ri   rl   rj   securerd   rk   optionss                  r	   rC   AbstractRpcServer.__init__   s   : dkdk$I&&KD O ON %D)3&
.$&(DO//#DKll)499d6H6HIll<+ 
		 2 2k A		[ DII$8$8$F$F
$$& %Gr   c                     [         e)zaReturns an OpenerDirector for making HTTP requests.

Returns:
  A urllib2.OpenerDirector object.
)NotImplementedErrorrO   s    r	   rr   AbstractRpcServer._GetOpener   s
     r   c                     [        XS9nU R                  (       a  UR                  SU R                  5        U R                  R	                  5        H  u  pEUR                  XE5        M     U$ )Creates a new urllib request.)r)   Host)Requestre   
add_headerrm   items)rH   rI   r)   r3   keyvalues         r	   _CreateRequest AbstractRpcServer._CreateRequest   sU    
#
!C	nnVT//0((..0
	nnS  1Jr   c                     U R                   nU(       dz  U R                  R                  S5      S   R                  S5      (       dC  U R                  (       a5  U R                  R                  S5      S   R                  S5      (       a  SnOSnUUSU R
                  US.nU R                  S[        R                  " [        R                  S	S
5      -  [        U5      S9n U R                  R                  U5      nUR                  5       n[        S UR                  S5       5       5      n[        R                  " [        R                  SS5      S:X  a  SUS   -  U R                   S'   US   $ ! ["         a  n	U	R$                  S:X  al  U	R                  5       n
[        S U
R                  S5       5       5      n['        UR)                  5       U	R$                  U	R*                  U	R,                  U5      ee Sn	A	ff = f)a[  Uses ClientLogin to authenticate the user, returning an auth token.

Args:
  email:    The user's email address
  password: The user's password

Raises:
  ClientLoginError: If there was an error authenticating with ClientLogin.
  HTTPError: If there was some other form of HTTP error.

Returns:
  The authentication token returned by ClientLogin.
:r   z.google.comHOSTED_OR_GOOGLEGOOGLEah)EmailPasswdservicerg   accountTypezhttps://%s/accounts/ClientLoginAPPENGINE_AUTH_SERVERzwww.google.comrI   r)   c              3   T   #    U  H  o(       d  M  UR                  S 5      v   M      g7f)=Nsplitr   xs     r	   r   2AbstractRpcServer._GetAuthToken.<locals>.<genexpr>0  s&      D$=q (1773<<$=s   
((r%   APPENGINE_RPC_USE_SID01zSID=%s; Path=/;SIDCookieAuthi  c              3   V   #    U  H  o(       d  M  UR                  S S5      v   M!     g7f)r   r$   Nr   r   s     r	   r   r   9  s"     L6F!_QWWS!__6Fs   
))N)rl   r(   r   endswithre   rg   r   r   GetEncodedValueosenvironurlencode_fnrs   openrP   dictrm   rB   rJ   r=   get_full_urlrK   r+   )rH   emailpasswordrl   r)   r3   responseresponse_bodyresponse_dictebodys              r	   _GetAuthTokenAbstractRpcServer._GetAuthToken	  s    $$L
))//#
q
!
*
*=
9
9  $$**3/2;;MJJ)++#D 

.%%bjj2IK[\]$  !C!!#&hmmom D$1$7$7$=D Dm		!	!"**.Es	Ks	Re 44 	8$6"" 	
3vvxLdjj6FLLs//1166155 yy-9 	9 	s   !BE1 1
G=;A=G88G=c           
         SnX!S.n[         R                  R                  SS5      nU R                  U R                  < SU R
                  < U< S[        U5      < 35      n U R                  R                  U5      nUR                  S:w  d  UR                  5       S	   U:w  aE  [        UR                  5       UR                  UR                  UR                  UR                  5      eS
U l        g! [         a  nUn SnANSnAff = f)zFetches authentication cookies for an authentication token.

Args:
  auth_token: The authentication token returned by ClientLogin.

Raises:
  HTTPError: If there was an error fetching the authentication cookies.
zhttp://localhost/)continueauthAPPCFG_LOGIN_PATHz/_ah://z/login?N.  locationT)r   r   rE   r   rc   r(   r   rs   r   rB   rJ   rG   r   rK   r+   fprh   )rH   
auth_tokencontinue_locationrD   
login_pathr3   r   r   s           r	   _GetAuthCookie AbstractRpcServer._GetAuthCookie?  s     ,)>D 3V<J


#{{DIIz+D13 4C!!#&h 	
#'88c&&((--&&5 5D  hs   $C3 3
D	=DD	c                    [        U R                  5       Hj  nU R                  5       n U R                  US   US   5      n[        R
                  " [        R                  SS5      S:X  a    g U R                  U5          g   g! [         GaO  nUR                  S:X  a  [        [        R                  -	  S4   SnA  gUR                  S	:X  a  [        [        R                  -	  S
4   SnA  gUR                  S:X  a  [        [        R                  -	  S4   SnA  gUR                  S:X  a  [        [        R                  -	  S4   SnA  gUR                  S:X  a  [        [        R                  -	  S4   SnA  gUR                  S:X  a  [        [        R                  -	  S4   SnA  gUR                  S:X  a  [        [        R                  -	  S4   SnA  ge SnAff = f)aX  Authenticates the user.

The authentication process works as follows:
 1) We get a username and password from the user
 2) We use ClientLogin to obtain an AUTH token for the user
    (see http://code.google.com/apis/accounts/AuthForInstalledApps.html).
 3) We pass the auth token to /_ah/login on the server to obtain an
    authentication cookie. If login was successful, it tries to redirect
    us to the URL we provided.

If we attempt to access the upload API without first obtaining an
authentication cookie, it returns a 401 response and directs us to
authenticate ourselves with ClientLogin.
r   r$   r   r   r   NCaptchaRequiredznPlease go to
https://www.google.com/accounts/DisplayUnlockCaptcha
and verify you are a human.  Then try again.NotVerifiedzAccount not verified.TermsNotAgreedzUser has not agreed to TOS.AccountDeletedz"The user account has been deleted.AccountDisabledz#The user account has been disabled.ServiceDisabledz3The user's access to the service has been disabled.ServiceUnavailablez.The service is not available; try again later.)rangeri   rf   r   r   r   r   r   r=   rN   printsysstderrr   )rH   unused_icredentialsr   r   s        r	   _AuthenticateAbstractRpcServer._AuthenticateY  s    $//*&&(k ''AAG
##BJJ0GMQTT
 U> *%I +   88((
#**
=> 88}$
#**
5
5
88''
#**
;
;
88''
#**
B
B
88((
#**
C
C
88((
#**
  + ,
88++
#**
N
N
9sB   ABG)G?)G.)G)G)G;)G*)GGGc                 .   U (       ar  [         R                  " U R                  5       5      R                  5       nSSR	                  [
        R                  " U5       Vs/ s H  nSU-  PM
     sn5      SS -   nOSnU < S[        U5      < SU< 3$ s  snf )zCreates cookie payload data.

Args:
  email: The user's email address.
  admin: True if the user is an admin; False otherwise.

Returns:
  String containing the cookie payload.
r   r#   z%02dN   r   )hashlibmd5lowerdigestr   r   	iterbytesbool)r   adminuser_id_digestr   user_ids        r	   _CreateDevAppServerCookieData/AbstractRpcServer._CreateDevAppServerCookieData  s     {{5;;=188:nbgg)33NC
DC!6A:C
DFFIrK Kg gUW55 Es   B
c                 r    U R                  5       nU R                  US   S5      nSU-  U R                  S'   g)z,Authenticates the user on the dev_appserver.r   Tz!dev_appserver_login="%s"; Path=/;r   N)rf   r   rm   )rH   r   r   s      r	   rw   +AbstractRpcServer._DevAppServerAuthenticate  s;    $$&K..{1~tDE$G%$ODx r   c           	         [         R                  " 5       n[         R                  " U5         SnSn US-  nU R                  < SU R                  < U< 3n	U(       a(  U	S[        [        UR                  5       5      5      -   -  n	U R                  XS9n
U
R                  SU5        U
R                  S	S
5         [        R                  SU R                  R                  5       [        XR                  S95        U R                  R!                  U
5      nUR#                  5       nUR%                  5         U[         R                  " U5        $ ! [&         Ga  n[        R                  SX}5        XpR(                  :  a  e UR*                  S:X  a   U(       a  e SnU R-                  5          SnAGO5UR*                  S:  a  UR*                  S:  a   SnAGM  UR*                  S:X  a  U(       a  e SnUR/                  5       S   n[        R                  SU5        UR1                  S5      (       a  U R-                  5          SnAO[2        R4                  " SU5      (       a@  [6        R8                  " [:        R<                  SS5      U l        U R-                  5          SnAODUR1                  SU R                  < S35      (       a  U RA                  5          SnAO
e e SnAff = fGM  ! [         R                  " U5        f = f)a  Sends an RPC and returns the response.

Args:
  request_path: The path to send the request to, eg /api/appversion/create.
  payload: The body of the request, or None to send an empty request.
  content_type: The Content-Type header to use.
  timeout: timeout in seconds; default None i.e. no timeout.
    (Note: for large requests on OS X, the timeout doesn't work right.)
  kwargs: Any keyword arguments are converted into query string parameters.

Returns:
  The response body, as a string.
r   FTr$   r   ?r   zContent-TypezX-appcfg-api-versionr   zSending %s request:
%s)r4   z"Got http error, this is try %d: %si  i  iX  Nr   r   zGot 302 redirect. Location: %sz,https://www.google.com/accounts/ServiceLoginz5https://www\.google\.com/a/[a-z0-9\.\-]+/ServiceLoginAPPENGINE_RPC_HOSTED_LOGIN_TYPEHOSTEDzhttp://z
/_ah/login)!socketgetdefaulttimeoutsetdefaulttimeoutrc   r(   r   sortedr   r   r   rt   ru   r2   r;   rj   rs   r   rP   closerB   rk   rJ   r   rG   rv   rematchr   r   r   r   rl   rw   )rH   request_pathpayloadcontent_typetimeoutkwargsold_timeouttries
auth_triedrI   r3   fr   r   locs                  r	   SendAbstractRpcServer.Send  sc   " **,K
W%?,ej
![[$))\B |F6<<>$:;;
;#!!c!8~|4 	-s3,	
,,0{{((**3__MO kks#!VVX(
'')L {+K  #	
,,;U
F ^^#vv}J  vv}#vv} J&&(:&CLL93?~~LMM  ""H#O O"*":":**?#Kd  "" DEE,,..G#	/ x {+sj   BK& :A<E K AK(K& . KK& A)K>K& AKK& 5KK& KK  K& &K>)rl   rf   ri   rh   rq   rj   rm   r(   re   rd   rs   rk   ro   rc   rg   )
NNF   NTTFr   Nr   )r#   zapplication/octet-streamN)rT   rU   rV   rW   rX   RUNTIMErC   rr   r   r   r   r   staticmethodr   rw   r   rZ   r   r   r	   r\   r\      sf    < ' EJHL8<@'D4l43l 6 6$Q (*2R,r   r\   c                   ,    \ rS rSrSrS r\rS r\rSr	g)ContentEncodingHandleri  z)Request and handle HTTP Content-Encoding.c                     UR                  SS5        UR                   H0  nUR                  5       S:X  d  M  UR                  U==   S-  ss'   M2     U$ )NzAccept-Encodinggzipz
user-agentz gzip)r   r+   r   )rH   requestr5   s      r	   http_request#ContentEncodingHandler.http_request   sL    (&1 //	<	'7* " Nr   c                 `   / nUR                   nSnU H`  nUR                  5       S:X  d  M  UnXF   R                  S5       H.  nUR                  " 5       nU(       d  M  UR	                  U5        M0       O   U(       d  U$ XE	 UnU(       a  US   R                  5       S:X  ai  [
        R                  " UR                  5       5      n[        R                  " USS9nUR                  5         U(       a  US   R                  5       S:X  a  Mi  U(       a,  SR                  U5      XE'   [        R                  S	US   5        UR                  n	[        R                   S
:  a"  [#        XUR$                  UR&                  5      nO(UR&                  n
[#        XUR$                  5      nXl        Xl        U$ )z8Handle encodings in the order that they are encountered.Nzcontent-encoding,r   r)fileobjmodez, z!Unrecognized Content-Encoding: %s)r      )r+   r   r   stripappendioBytesIOrP   r   GzipFilepopr   rt   warningrK   r   r    addinfourl_fnrI   rJ   )rH   r3   resp	encodingsr+   encoding_headerr5   r   r   rK   response_codes              r	   http_response$ContentEncodingHandler.http_response  sb   IllGO	-	- --c2H^^%(XX& 3 	  k 	 	B
	"++-7::bggi b==#.bmmo 	"++-7
 
 "&9!5gnn8)B-H
((C
6!2$))<diim21diHKr   r   N)
rT   rU   rV   rW   rX   r   https_requestr  https_responserZ   r   r   r	   r   r     s    1& --^ !.r   r   c                   X   ^  \ rS rSrSrSrU 4S jrS
U 4S jjrS rU 4S jr	S r
S	rU =r$ )HttpRpcServeriG  z<Provides a simplified RPC-style interface for HTTP requests.z~/.appcfg_cookiesc                   > [         R                  R                  [         R                  R                  [         R                  R	                  [
        5      SSSSSS5      5      U l        UR                  SS5      (       + =(       a)    [         R                  R                  U R                  5      U l	        [        [        U ]2  " U0 UD6  g )Nz..libcacertszcacerts.txtrd   F)r   pathnormpathr   dirname__file__certpathrE   existscert_file_availablesuperr  rC   )rH   rD   r   	__class__s      r	   rC   HttpRpcServer.__init__L  s    GG$$RWW\\
!4tUI& DM &,ZZ%F!F !B$&GGNN4==$A 		-'88r   c                    > [         [        U ]  X5      nU R                  (       a(  [	        5       (       a  UR                  U R                  S9  U$ )r   )ca_certs)r#  r  r   r"  r
   set_ssl_infor   )rH   rI   r)   r3   r$  s       r	   r   HttpRpcServer._CreateRequestT  s@    
t
3C
>C$6$8$8	.Jr   c                     [         R                   " 5       S-   nU R                   H7  nUR                  U R                  :X  d  M  UR	                  U5      (       a  M7    g   [
        [        R                  -	  S4  g)z4Warn if cookie is not valid for at least one minute.<   z+
Error: Machine system clock is incorrect.
N)timerq   domainr(   
is_expiredr   r   r   )rH   
min_expirecookies      r	   _CheckCookieHttpRpcServer._CheckCookie[  sW    r!J//	$))	#F,=,=j,I,I " cjjIIr   c                   > U R                   (       a$  [        5       (       d  [        R                  S5        [        [
        U ]  5         U R                  R                  bg  U R                  (       aU  [        R                  SU R                  R                  5        U R                  R                  5         U R                  5         ggg)z)Save the cookie jar after authentication.a#  ssl module not found.
Without the ssl module, the identity of the remote host cannot be verified, and
connections may NOT be secure. To fix this, please install the ssl module from
http://pypi.python.org/pypi/ssl .
To learn more, see https://developers.google.com/appengine/kb/general#rpcsslNz#Saving authentication cookies to %s)r"  r
   rt   warnr#  r  r   rq   filenamero   ru   saver1  )rH   r$  s    r	   r   HttpRpcServer._Authenticatef  s    (:(<(< kk P Q
 
-,.+0A0All8??++-
oo
	 1B+r   c                 v   [        5       nUR                  [        5       5        UR                  [        5       5        UR                  [	        5       5        UR                  [        5       5        UR                  [        5       5        UR                  [        5       5        UR                  [        5       5        U R                  (       Ga  [        R                  R                  [        R                  5      U R                  l        [        R                  R#                  U R                  R                   5      (       aM   U R                  R%                  5         SU l        [(        R+                  SU R                  R                   5        OQ [        R6                  " U R                  R                   [        R8                  S5      n[        R:                  " U5        UR                  [=        U R                  5      5        U$ ! [,        [.        [0        4 aF  n[(        R+                  SUR2                  R4                  U5        SU R                  l         SnAN|SnAff = f! [,        [.        4 aF  n[(        R+                  SUR2                  R4                  U5        SU R                  l         SnANSnAff = f)ztReturns an OpenerDirector that supports cookies and ignores redirects.

Returns:
  A urllib2.OpenerDirector object.
Tz%Loaded authentication cookies from %sz-Could not load authentication cookies; %s: %sNi  z4Could not create authentication cookies file; %s: %s)OpenerDirectoradd_handlerProxyHandlerUnknownHandlerHTTPHandlerHTTPDefaultErrorHandlerHTTPSHandlerHTTPErrorProcessorr   ro   r   r  
expanduserr  DEFAULT_COOKIE_FILE_PATHrq   r5  r!  loadrh   rt   ru   OSErrorIOError	LoadErrorr$  rT   r   O_CREATr   HTTPCookieProcessor)rH   rs   r   fds       r	   rr   HttpRpcServer._GetOpenerw  s    F
|~&
~'(
{}%
.01
|~&
)+,
-/0!#!3!3

0
0"2doo 
00	1	1		*
//


 #$

,,>//1	*wwt//UC"
((2, *4??;<M% ), 	*
,,F{{++Q0%)$//
"
"		* ! 	*
,,M{{++Q0%)$//
"
"		*s2   AH AI" I<II"J82<J33J8)rh   r"  r   r   )rT   rU   rV   rW   rX   rB  rC   r   r1  r   rr   rZ   __classcell__)r$  s   @r	   r  r  G  s+    D09J"+ +r   r  )T)>rX   r   r   r	  loggingr   r   r   r   r,  urllibgooglecloudsdk.core.utilr   "googlecloudsdk.appengine._internalr   PY3http.cookiejarra   urllib.errorurllib.requestr   BaseHandlererrorrB   r=  r>  rH  r?  r@  	cookiejarrp   r;  rF  r9  r   r<  r   
addinfourlr  parse	urlencoder   	cookielibfancy_urlliburllib2FancyHTTPSHandlerFancyProxyHandlerFancyRequestsslr   ImportErrorr
   	getLoggerrt   r   r!   r;   r=   objectr\   r   r  r   r   r	   <module>rd     si   A   	  	 	  
   - 9 >>>**+ll$$)**+"NNBB::,,,~~88^^44,,,nn&&)>>00.NN""'>>00.//,,-'',##+)##+//,#;;3311//,//!!))).)).%%'$$-!!,
 
		I	J!cCLL &*Zy &J, J,Z
G![ G!T[% [m  s   !K   K
K