+
    G%@ipq                         ^ RI t ^ RIt^ RIt^ RIHt ^ RIHt ^ RIHtH	t	  ^ RI
t
Rt ^ RItRt ! R R4      tR#   ] d    Rt Li ; i  ] d    Rt L&i ; i)	    N)getpass)_sos)is_executableTIMEOUT_DEFAULTTFc                     a  ] tR t^ t o RtRtRtRtRtRt	Rt
RtRtRtRtRtRtRtRtRtRtRtRtRtRtRtRtRtRtRt/ R	RbR
RbRRbR. bRRbRRbRRbRRbRRbRRbRRbRRbRRbRRbRRbRRbRRbRR/CtRAR ltR t R t!]"R  4       t#R! t$R" t%R# t&R$ t'R% t(R& t)R' t*R( t+R) t,R* t-R+ t.RBR, lt/R- t0R. t1R/ t2R0 t3R1 t4R2 t5R3 t6R4 t7R5 t8R6 t9R7 t:RAR8 lt;R9 t<RCR: lt=R; t>RCR< lt?R= t@RDR> ltARER? ltBR@tCV tDR# )FUploadTargetz
This class is designed to upload files to a distribution
defined location. These files can be either sos reports,
sos collections, or other kind of files like: vmcores,
application cores, logs, etc.

z
            Upload a file (can be an sos report, a must-gather, or others) to
             a distribution defined remote location
            zGeneric UploadgenericN/zhttps://s3.amazonaws.com upload_filecase_idlow_priorityFprofiles
upload_urlupload_directoryupload_userupload_passupload_methodautoupload_no_ssl_verifyupload_protocolupload_s3_endpointupload_s3_regionupload_s3_bucketupload_s3_access_keyupload_s3_secret_keyupload_s3_object_prefixupload_targetc                `    \         P                  ! R 4      V n        Wn        W0n        W n        R# )sos_uiN)logging	getLoggerui_logparsercmdlineargs)selfr$   r&   r%   s   &&&&=/usr/lib/python3/dist-packages/sos/upload/targets/__init__.py__init__UploadTarget.__init__a   s#    ''1	    c                    R# )a3  This should be overridden by upload targets

This is called by sos upload on each target type that exists, and
is meant to return True when the upload target matches a criteria
that indicates that is the local upload target that should be used.

Only the first upload target to determine a match is selectedF r'   s   &r(   check_distributionUploadTarget.check_distributionh   s     r+   c                    V P                   # )N)upload_target_idr.   s   &r(   get_target_idUploadTarget.get_target_idr   s    $$$r+   c                r    V P                   '       d   V P                   # V P                  P                  4       # )z-Returns the upload target's name as a string.)upload_target_name__name__lower)clss   &r(   nameUploadTarget.nameu   s/     !!!)))||!!##r+   c           	         R V P                   R ,          RV P                   R,          RV P                   R ,          P                  RV P                   R ,          P                  /# )cmdlineoptspolicyr   r   )hook_commonsr   r   r.   s   &r(   get_commonsUploadTarget.get_commons|   sX    4,,];d''1t((7?? 1 1- @
 	
r+   c                    Wn         R# )z9Set common host data for the Upload targets
to reference
N)commons)r'   rC   s   &&r(   set_commonsUploadTarget.set_commons   s	     r+   c                   Wn         V P                  4       V n        V P                  R ,          pV P                  R,          pVP                  '       d   VP	                  4        VP
                  V n        VP                  V n        VP                  V n        VP                  V n	        RV n
        VP                  V n        VP                  V n        VP                  V n        VP                  V n        VP                  V n        VP                   V n        VP"                  '       g   VP$                  '       g   V P'                  4       '       d3   VP(                  R8X  g"   V P+                  4        V P-                  4        MQVP(                  R8X  dA   V P/                  4        V P1                  4        V P3                  4        V P5                  4        V P6                  P9                  R4       R# R# R# )r=   r>   r   s3N)r?   r@   rC   r   _configure_low_priorityr   r   r   r   upload_passwordupload_archive_namer   r   r   r   r   r   batchquietget_upload_urlr   prompt_for_upload_userprompt_for_upload_passwordprompt_for_upload_s3_bucketprompt_for_upload_s3_endpointprompt_for_upload_s3_access_keyprompt_for_upload_s3_secret_keyr#   info)r'   r?   cmdline_optsr>   s   &&  r(   pre_workUploadTarget.pre_work   s   ('')||M2h'$$$**,
 '11'33 , = =+77#% "."A"A , = =$0$E$E! , = ='3'K'K$$0$E$E! !!!"""""$$$44<++-//1--5002224446446KKR  # "r+   c                    V P                  4       '       gA   RV P                  4        RV P                  4        R2p\        \	        V4      4      V n        R# R# )zeShould be overridden by targets to determine if an access key needs
to be provided for upload or not
z0Please provide the upload access key for bucket  via endpoint : N)get_upload_s3_access_keyget_upload_s3_bucketget_upload_s3_endpointinput_r   r'   msgs   & r(   rR   ,UploadTarget.prompt_for_upload_s3_access_key   s^     ,,..--/0 1//12"6 
 ).afD% /r+   c                    V P                  4       '       g8   RV P                  4        RV P                  4        R2p\        V4      V n        R# R# )zdShould be overridden by targets to determine if a secret key needs
to be provided for upload or not
z0Please provide the upload secret key for bucket rY   rZ   N)get_upload_s3_secret_keyr\   r]   r   r   r`   s   & r(   rS   ,UploadTarget.prompt_for_upload_s3_secret_key   sZ     ,,..--/0 1//12"6 
 )0D% /r+   c                @   V P                   '       g   V P                  '       dF   V P                  P                  R4      '       d%   V P                  R,          V n         V P                   # \        \	        R4      4      pVP                  R4      V n         V P                   # )z`Should be overridden by targets to determine if a bucket needs to
be provided for upload or not
s3://   NNz"Please provide the upload bucket: r
   )r   r   
startswithr^   r_   strip)r'   
user_inputs   & r(   rP   (UploadTarget.prompt_for_upload_s3_bucket   s}     $$$4??#=#=g#F#F(,(;% $$$ #1%I#JK
(2(8(8(=%$$$r+   c                    V P                   pV P                  '       g=   RV P                  4        RV R2p\        \	        V4      4      pT;'       g    TV n        V P                  # )zcShould be overridden by targets to determine if an endpoint needs
to be provided for upload or not
z.Please provide the upload endpoint for bucket z (default: z): )_upload_s3_endpointr   r\   r^   r_   )r'   default_endpointra   rl   s   &   r(   rQ   *UploadTarget.prompt_for_upload_s3_endpoint   sq      33&&&--/0./s4 
 qvJ&0&D&D4DD#&&&r+   c                    V P                  4       '       g0   RV P                  4        R2p\        \        V4      4      V n        R# R# )zSShould be overridden by targets to determine if a user needs to
be provided or not
zPlease provide upload user for rZ   N)get_upload_userrM   r^   r_   r   r`   s   & r(   rN   #UploadTarget.prompt_for_upload_user   s@     ##%%3D4G4G4I3J"MC$QsV}D &r+   c                    V P                  4       '       gH   V P                  4       V P                  8w  d'   RV P                  4        R2p\        V4      V n        R# R# R# )zbShould be overridden by targets to determine if a password needs to
be provided for upload or not
z'Please provide the upload password for rZ   N)get_upload_passwordrs   _upload_userr   rI   r`   s   & r(   rO   'UploadTarget.prompt_for_upload_password   s]     ''))t/C/C/E/3/@/@0A<**,-R1C#*3<D 	0A)r+   c                .   Wn         V P                  '       g   V P                  4       V n        V P                  '       g   \        R4      hV P	                  4       pV P
                  P                  \        RV P                  4        24      4       V! 4       # )a)  
Entry point for sos attempts to upload the generated archive to a
target or user specified location.

Currently there is support for HTTPS, SFTP, and FTP. HTTPS uploads are
preferred for target-defined defaults.

Targets that need to override uploading methods should override the
respective upload_https(), upload_sftp(), and/or upload_ftp() methods
and should NOT override this method.

:param archive: The archive filepath to use for upload
:type archive: ``str``

In order to enable this for a target, that target needs to implement
the following:

Required Class Attrs

:_upload_url:     The default location to use. Note these MUST include
                  protocol header
:_upload_user:    Default username, if any else None
:_upload_password: Default password, if any else None

The following Class Attrs may optionally be overidden by the Target

:_upload_directory:     Default FTP server directory, if any


The following methods may be overridden by ``Target`` as needed

`prompt_for_upload_user()`
    Determines if sos should prompt for a username or not.

`get_upload_user()`
    Determines if the default or a different username should be used

`get_upload_https_auth()`
    Format authentication data for HTTPS uploads

`get_upload_url_string()`
    Print a more human-friendly string than vendor URLs
zBNo upload destination provided by upload target or by --upload-urlzAttempting upload to )	rJ   r   rM   	Exception_determine_upload_typer#   rT   r_   get_upload_url_string)r'   archiveupload_funcs   && r(   upload_archiveUploadTarget.upload_archive   s    X $+ "113DO 2 3 3113%d&@&@&B%CDE	
 }r+   c                   RV P                   RV P                  RV P                  RV P                  /pV P                  R,          P
                  V9   d$   WP                  R,          P
                  ,          # RV P                  9  d   \        R4      hV P                  P                  R4      w  r#W!9  d   \        RV 24      hW,          # )	zBased on the url provided, determine what type of upload to attempt.

Note that this requires users to provide a FQDN address, such as
https://myvendor.com/api or ftp://myvendor.com instead of
myvendor.com/api or myvendor.com
ftpsftphttpsrG   r=   z://z#Must provide protocol in upload URLz&Unsupported or unrecognized protocol: )	
upload_ftpupload_sftpupload_https	upload_s3rC   r   r   rz   split)r'   protsprotr_   s   &   r(   r{   #UploadTarget._determine_upload_type3  s     4??D$$T&&$..	
 <<&66%?m4DDEE'ABB//''.DTFKLL{r+   c                    V'       g   V P                  4       pV'       g   V P                  4       p\        P                  P	                  W4      # )a0  Formats the user/password credentials using basic auth

:param user: The username for upload
:type user: ``str``

:param password: Password for `user` to use for upload
:type password: ``str``

:returns: The user/password auth suitable for use in requests calls
:rtype: ``requests.auth.HTTPBasicAuth()``
)rs   rv   requestsauthHTTPBasicAuth)r'   userpasswords   &&&r(   get_upload_https_auth"UploadTarget.get_upload_https_authI  s;     '')D//1H}}**4::r+   c                    \         P                  ! RR4      ;'       g!    V P                  ;'       g    V P                  # )zHelper function to determine if we should use the target default
upload access key or one provided by the user

:returns: The access_key to use for upload
:rtype: ``str``
SOSUPLOADS3ACCESSKEYN)osgetenvr   _upload_s3_access_keyr.   s   &r(   r[   %UploadTarget.get_upload_s3_access_key\  >     		0$7 + +))+ +**	,r+   c                ^    V P                   '       g   V P                  4        V P                   # )zHelper function to determine if we should use the target default
upload endpoint or one provided by the user

:returns: The S3 Endpoint to use for upload
:rtype: ``str``
)r   rQ   r.   s   &r(   r]   #UploadTarget.get_upload_s3_endpointg  s(     &&&..0&&&r+   c                B    V P                   ;'       g    V P                  # )zHelper function to determine if we should use the target default
upload region or one provided by the user

:returns: The S3 region to use for upload
:rtype: ``str``
)r   _upload_s3_regionr.   s   &r(   get_upload_s3_region!UploadTarget.get_upload_s3_regionr  s     $$>>(>(>>r+   c                   V P                   '       dq   V P                   P                  R4      '       dP   V P                   R,          P                  R^4      pV^ ,          V n        \	        V4      ^8  d   V^,          V n        V P                  '       g   V P                  4        V P                  ;'       g    V P                  # )zHelper function to determine if we should use the target default
upload bucket or one provided by the user

:returns: The S3 bucket to use for upload
:rtype: ``str``
rg   rh   r
   )r   rj   r   r   lenr   rP   _upload_s3_bucket)r'   bucket_and_prefixs   & r(   r\   !UploadTarget.get_upload_s3_bucket{  s     ???t99'BB $ 3 9 9#q A$5a$8D!$%)/@/C,$$$,,.$$>>(>(>>r+   c                B    V P                   ;'       g    V P                  # )zHelper function to determine if we should use the target default
upload object prefix or one provided by the user

:returns: The S3 object prefix to use for upload
:rtype: ``str``
)r   _upload_s3_object_prefixr.   s   &r(   get_upload_s3_object_prefix(UploadTarget.get_upload_s3_object_prefix  s     ++LLt/L/LLr+   c                    \         P                  ! RR4      ;'       g!    V P                  ;'       g    V P                  # )zHelper function to determine if we should use the target default
upload secret key or one provided by the user

:returns: The S3 secret key to use for upload
:rtype: ``str``
SOSUPLOADS3SECRETKEYN)r   r   r   _upload_s3_secret_keyr.   s   &r(   rd   %UploadTarget.get_upload_s3_secret_key  r   r+   c                ,   V P                   '       gd   V P                  '       dR   V P                  '       d@   V P                  '       d.   V P	                  4       pV P                  4       pRV RV 2V n        V P                   ;'       g    V P                  # )zHelper function to determine if we should use the target default
upload url or one provided by the user

:returns: The URL to use for upload
:rtype: ``str``
rg   r
   )r   r   r   r   r\   r   _upload_url)r'   bucketprefixs   &  r(   rM   UploadTarget.get_upload_url  sz     !!!%%%%%%..0F557F!&vhax8D22$"2"22r+   c                :    R p\         P                  ! VRV4      pV# )z([^:]+://[^:]+:)([^@]+)(@.+)z\1********\3)resub)r'   urlpatternobfuscated_urls   &&  r(   _get_obfuscated_upload_url'UploadTarget._get_obfuscated_upload_url  s    1#>r+   c                @    V P                  V P                  4       4      # )zUsed by upload targets to potentially change the string used to
report upload location from the URL to a more human-friendly string
)r   rM   r.   s   &r(   r|   "UploadTarget.get_upload_url_string  s     ..t/B/B/DEEr+   c                    \         P                  ! RR4      ;'       g!    V P                  ;'       g    V P                  # )zHelper function to determine if we should use the target default
upload user or one provided by the user

:returns: The username to use for upload
:rtype: ``str``
SOSUPLOADUSERN)r   r   r   rw   r.   s   &r(   rs   UploadTarget.get_upload_user  s=     		/40 " "  " "!!	#r+   c                    \         P                  ! RR4      ;'       g!    V P                  ;'       g    V P                  # )a/  Helper function to determine if we should use the target default
upload password or one provided by the user

A user provided password, either via option or the 'SOSUPLOADPASSWORD'
environment variable will have precendent over any target value

:returns: The password to use for upload
:rtype: ``str``
SOSUPLOADPASSWORDN)r   r   rI   _upload_passwordr.   s   &r(   rv    UploadTarget.get_upload_password  s>     		-t4 & &$$& &%%	'r+   c                   \        R4      '       g   \        R4      h ^ RIpRpT'       g   T P	                  4       pT'       g   T P                  4       pT P                  4       P                  RR4      pRT R	T 2pTP                  TR
R7      p	RRRTP                  TP                  .p
T	P                  T
^R7      pT^ 8X  d   RpMT^8X  dw   T	P                  T4       RRTP                  TP                  .pT	P                  T^
R7      ^ 8H  pT'       g-   T	P                  4        \        RT P                  4        24      hMfT^8X  d   \        RT P                  4        R24      hT^8X  d   \        RT P                  4        24      hT^8X  d   \        RT	P                   24      hT'       g-   T	P                  4        \        RT P                  4        24      hRT P                    RT'       d   T R2MR T P#                  4        2pT	P                  T4       RTP                  TP                  R.pT	P                  T^R7      pT^ 8X  d   T	P                  R4       R# T^8X  d   \        R4      hT^8X  d   \        RT	P                   24      hT^8X  d   \        R 4      h\        R!T	P                   24      h  \         d   p\        R4      ThRp?ii ; i)"a}  Attempts to upload the archive to an SFTP location.

Due to the lack of well maintained, secure, and generally widespread
python libraries for SFTP, sos will shell-out to the system's local ssh
installation in order to handle these uploads.

Do not override this method with one that uses python-paramiko, as the
upstream sos team will reject any PR that includes that dependency.
r   zSFTP is not locally supportedNzFSFTP upload requires python3-pexpect, which is not currently installedFzsftp://r   z sftp -oStrictHostKeyChecking=no @zutf-8)encodingzsftp>z	password:zConnection refusedtimeoutTzPermission deniedz#Incorrect username or password for zConnection refused by z. Incorrect port?z!Timeout hit trying to connect to z,Unexpected error trying to connect to sftp: zUnable to connect via SFTP to zput  r
   z100%zNo such file or directorybyezTimeout expired while uploadingzUnknown error during upload: z&Unable to write archive to destinationz!Unexpected response from server: )r   rz   pexpectImportErrorrs   rv   rM   replacespawnTIMEOUTEOFexpectsendlinecloser|   beforerJ   _get_sftp_upload_name)r'   r   r   user_dirr   errsftp_connectedsftp_urlsftp_cmdretsftp_expectsidxpass_expectsput_cmdput_expectsput_successs   &&&&            r(   r   UploadTarget.upload_sftp  s    V$$;<<
	@
 '')D//1H &&(00B?5dV1XJGmmHwm7  OOKK
 jjrj2!8!NAXLL"#	L !ZZbZAQFN!		 E#'#=#=#?"@!B C C " AX4#99;<<MO P PAX?#99;<> ? ?AXJ"zzl, - - IIK<#99;<> ? ?
 4++,A!)(1~r2))+,. 	
 	WOOKK'	
 jjcj:!LL!=>>!;CJJ<HII!DEE;CJJ<HIIc  	@ 6 7<?@	@s   K   KKKc                    V P                   P                  R4      R,          pV P                  '       d+   \        P                  P                  V P                  V4      pV# )zIf a specific file name pattern is required by the SFTP server,
override this method in the relevant Upload Target. Otherwise the
archive's name on disk will be used

:returns:       Filename as it will exist on the SFTP server
:rtype:         ``str``
r
   )rJ   r   r   r   pathjoin)r'   fnames   & r(   r   "UploadTarget._get_sftp_upload_name:  sJ     ((..s3B7   GGLL!6!6>Er+   c                x    \         P                  ! V P                  4       VV P                  4       V\        R7      # )zIf upload_https() needs to use requests.put(), use this method.

Targets should override this method instead of the base upload_https()

:param archive:     The open archive file object
)datar   verifyr   )r   putrM   r   r   )r'   r}   r   s   &&&r(   _upload_https_putUploadTarget._upload_https_putG  s5     ||D//1!%!;!;!=#)?D 	Dr+   c                    / # )zJDefine any needed headers to be passed with the POST request here
        r-   r.   s   &r(   _get_upload_headers UploadTarget._get_upload_headersR  s	     	r+   c                    RVP                   P                  R4      R,          VV P                  4       3/p\        P                  ! V P                  4       VV P                  4       V\        R7      # )zIf upload_https() needs to use requests.post(), use this method.

Targets should override this method instead of the base upload_https()

:param archive:     The open archive file object
filer
   )filesr   r   r   r   )r:   r   r   r   postrM   r   r   )r'   r}   r   r   s   &&& r(   _upload_https_postUploadTarget._upload_https_postW  sj     W\\'',R0'--/1
 }}T002%"&"<"<">$*OE 	Er+   c                z   \         '       g   \        R4      h\        V P                  R4      ;_uu_ 4       pV P                  R,          P
                  R8X  d   V P                  pMV P                  R,          P
                  pV P                  R,          P                  RJ pVR8X  d   V P                  W4      pMV P                  W4      pVP                  R9  dB   VP                  R8X  d   \        R4      h\        R	VP                   R
VP                   24      h RRR4       R#   + '       g   i     R# ; i)zAttempts to upload the archive to an HTTPS location.

:returns: ``True`` if upload is successful
:rtype: ``bool``

:raises: ``Exception`` if upload was unsuccessful
z7Unable to upload due to missing python requests libraryrbr=   r   Fr   i  z/Authentication failed: invalid user credentialszPOST request returned rZ   NT)      )REQUESTS_LOADEDrz   openrJ   rC   r   _upload_methodr   r   r   status_codereason)r'   arcmethodr   rs   &    r(   r   UploadTarget.upload_httpsf  s     & ' ' $**D11S||M*88FB,,m4BB\\-0EENF**37++C8}}J.==C'#I   "8r#$88*!. / /# 2111s   C)D))D:	c                ^   ^ RI p^ RIpV'       g   V P                  4       pVf   \        R4      hVP	                  RR4      pV'       g   V P                  4       pV'       g   V P                  4       pV'       g!   V P                  ;'       g    V P                  p VP                  WV^R7      pV'       g   \        R4      hVP                  V4       \!        T P"                  R4      ;_uu_ 4       p
TP%                  RT P"                  P                  R4      R,           2T
4       RRR4       TP'                  4        R#   TP                   d   p\        RT 24      ThRp?iTP                   d   p\        RT 24      ThRp?iTP                   d   p\        T4      P                  4       ^ ,          p	T	R	8X  d   \        R
T R24      ThT	R8X  d   \        RT R24      ThT	R8X  d   \        RT 24      Th\        R\        T4       24      ThRp?ii ; i  + '       g   i     L; i)a  Attempts to upload the archive to either the target defined or user
provided FTP location.

:param url: The URL to upload to
:type url: ``str``

:param directory: The directory on the FTP server to write to
:type directory: ``str`` or ``None``

:param user: The user to authenticate with
:type user: ``str``

:param password: The password to use for `user`
:type password: ``str``

:returns: ``True`` if upload is successful
:rtype: ``bool``

:raises: ``Exception`` if upload in unsuccessful
NzPno FTP server specified by upload target, use --upload-url to specify a locationzftp://r   r   z3connection failed, did you set a user and password?z timeout hit while connecting to zunable to connect to 503zcould not login as ''530zinvalid password for user '550z"could not set upload directory to z#error trying to establish session: r   zSTOR r
   Tr   )ftplibsocketrM   rz   r   rs   rv   r   _upload_directoryFTPcwdr   gaierror
error_permstrr   r   rJ   
storbinaryquit)r'   r   	directoryr   r   r  r  sessionr   errno_arcfiles   &&&&&      r(   r   UploadTarget.upload_ftp  s   * 	%%'C; E F F kk(B''')D//1H--GG1G1GI	jjHbjAG !, - -KK	"" $**D11X0066s;B?@A8 2 	+ ~~ 	O>seDE3N 	D3C59:C   
	HNN$Q'E~"6tfA >?SH~"=dV1 EFCO~ D#,+!/ 0589A#c(LM
	 21sI   8E 16HHE!!H4H5FHHA<HHH,	c                0   \         '       g   \        R4      hV'       g   V P                  4       pV'       g   V P                  4       pV'       g    V P	                  4       P                  R4      pV'       ge   V P                  4       pVR8w  d!   VP                  R4      '       d
   VR,          pVR8w  d'   VP                  R4      '       g   V'       d   V R2MRpV'       g   V P                  4       pV'       g   V P                  4       p\        P                  ! RVVVVR7      p W@P                  P                  R4      R
,          ,           pVP                  V P                  W84       R#   \         d   p	\        R\!        T	4       24      T	hR	p	?	ii ; i)a5  Attempts to upload the archive to an S3 bucket.

:param endpoint: The S3 endpoint to upload to
:type endpoint: str

:param region: The S3 region to upload to
:type region: str

:param bucket: The name of the S3 bucket to upload to
:type bucket: str

:param prefix: The prefix for the S3 object/key
:type prefix: str

:param access_key: The access key for the S3 bucket
:type access_key: str

:param secret_key: The secret key for the S3 bucket
:type secret_key: str

:returns: True if upload is successful
:rtype: bool

:raises: Exception if upload is unsuccessful
z4Unable to upload due to missing python boto3 libraryr
   r   :   NNrG   )endpoint_urlregion_nameaws_access_key_idaws_secret_access_keyTzFailed to upload to S3: Nr   )BOTO3_LOADEDrz   r]   r   r\   rk   r   rj   endswithr[   rd   boto3clientrJ   r   r   r  )
r'   endpointregionr   r   
access_key
secret_key	s3_clientkeyes
   &&&&&&&   r(   r   UploadTarget.upload_s3  sY   6 | & ' ' 224H..0F..066s;F557F| 1 1# 6 6|FOOC$8$8)/F81R668J668JLLH-33=7AC	
	H3399#>rBBC!!$":":"(/ 	H6s1vh?@aG	Hs   'AE- -F8FF)r   r&   r%   rC   r?   r$   r#   rJ   r   rI   r   r   r   r   r   r   r   r   )NNN)NN)T)NNNN)NNNNNN)Er7   
__module____qualname____firstlineno____doc__descr6   r2   _upload_filer   r  rw   r   r   ro   r   r   r   r   r   r   r   rI   r   r   r   r   r   r   r   arg_defaultsr)   r/   r3   classmethodr:   r@   rD   rV   rR   rS   rP   rQ   rN   rO   r   r{   r   r[   r]   r   r\   r   rd   rM   r   r|   rs   rv   r   r   r   r   r   r   r   r   __static_attributes____classdictcell__)__classdict__s   @r(   r   r       sF    D * LKLN4  !JKO"Mr2 	 	B	
 	d 	D 	t 	t 	 	 	6 	d 	D 	D 	  	!" 	"4#$ 	%L*% $ $
(!T6
5
%'-06p,;&	,	'?? M	,3"
F	#'dJL	D
E>DL?H ?Hr+   r   )r   r   r!   r   sosr   r_   sos.utilitiesr   r   r   r   r   r"  r   r   r-   r+   r(   <module>r9     sl    
 	    8OL
jH jH  O  Ls    ; A
 	AA
	AA