home *** CD-ROM | disk | FTP | other *** search
/ com!online 2005 April / com_0405_1.iso / opensource / BTpp-0.5.4-bin.exe / $INSTDIR / BT++.exe / ftplib.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2003-04-19  |  23.6 KB  |  822 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.2)
  3.  
  4. import os
  5. import sys
  6. import string
  7.  
  8. try:
  9.     import SOCKS
  10.     socket = SOCKS
  11.     del SOCKS
  12.     from socket import getfqdn
  13.     socket.getfqdn = getfqdn
  14.     del getfqdn
  15. except ImportError:
  16.     import socket
  17.  
  18. __all__ = [
  19.     'FTP',
  20.     'Netrc']
  21. MSG_OOB = 1
  22. FTP_PORT = 21
  23.  
  24. class Error(Exception):
  25.     pass
  26.  
  27.  
  28. class error_reply(Error):
  29.     pass
  30.  
  31.  
  32. class error_temp(Error):
  33.     pass
  34.  
  35.  
  36. class error_perm(Error):
  37.     pass
  38.  
  39.  
  40. class error_proto(Error):
  41.     pass
  42.  
  43. all_errors = (Error, socket.error, IOError, EOFError)
  44. CRLF = '\r\n'
  45.  
  46. class FTP:
  47.     debugging = 0
  48.     host = ''
  49.     port = FTP_PORT
  50.     sock = None
  51.     file = None
  52.     welcome = None
  53.     passiveserver = 1
  54.     
  55.     def __init__(self, host = '', user = '', passwd = '', acct = ''):
  56.         if host:
  57.             self.connect(host)
  58.             if user:
  59.                 self.login(user, passwd, acct)
  60.             
  61.         
  62.  
  63.     
  64.     def connect(self, host = '', port = 0):
  65.         if host:
  66.             self.host = host
  67.         
  68.         if port:
  69.             self.port = port
  70.         
  71.         msg = 'getaddrinfo returns an empty list'
  72.         for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
  73.             (af, socktype, proto, canonname, sa) = res
  74.             
  75.             try:
  76.                 self.sock = socket.socket(af, socktype, proto)
  77.                 self.sock.connect(sa)
  78.             except socket.error:
  79.                 msg = None
  80.                 if self.sock:
  81.                     self.sock.close()
  82.                 
  83.                 self.sock = None
  84.                 continue
  85.  
  86.         
  87.         if not (self.sock):
  88.             raise socket.error, msg
  89.         
  90.         self.af = af
  91.         self.file = self.sock.makefile('rb')
  92.         self.welcome = self.getresp()
  93.         return self.welcome
  94.  
  95.     
  96.     def getwelcome(self):
  97.         if self.debugging:
  98.             print '*welcome*', self.sanitize(self.welcome)
  99.         
  100.         return self.welcome
  101.  
  102.     
  103.     def set_debuglevel(self, level):
  104.         self.debugging = level
  105.  
  106.     debug = set_debuglevel
  107.     
  108.     def set_pasv(self, val):
  109.         self.passiveserver = val
  110.  
  111.     
  112.     def sanitize(self, s):
  113.         if s[:5] == 'pass ' or s[:5] == 'PASS ':
  114.             i = len(s)
  115.             while i > 5 and s[i - 1] in '\r\n':
  116.                 i = i - 1
  117.             s = s[:5] + '*' * (i - 5) + s[i:]
  118.         
  119.         return `s`
  120.  
  121.     
  122.     def putline(self, line):
  123.         line = line + CRLF
  124.         if self.debugging > 1:
  125.             print '*put*', self.sanitize(line)
  126.         
  127.         self.sock.sendall(line)
  128.  
  129.     
  130.     def putcmd(self, line):
  131.         if self.debugging:
  132.             print '*cmd*', self.sanitize(line)
  133.         
  134.         self.putline(line)
  135.  
  136.     
  137.     def getline(self):
  138.         line = self.file.readline()
  139.         if self.debugging > 1:
  140.             print '*get*', self.sanitize(line)
  141.         
  142.         if not line:
  143.             raise EOFError
  144.         
  145.         if line[-2:] == CRLF:
  146.             line = line[:-2]
  147.         elif line[-1:] in CRLF:
  148.             line = line[:-1]
  149.         
  150.         return line
  151.  
  152.     
  153.     def getmultiline(self):
  154.         line = self.getline()
  155.         if line[3:4] == '-':
  156.             code = line[:3]
  157.             while 1:
  158.                 nextline = self.getline()
  159.                 line = line + '\n' + nextline
  160.                 if nextline[:3] == code and nextline[3:4] != '-':
  161.                     break
  162.                 
  163.         
  164.         return line
  165.  
  166.     
  167.     def getresp(self):
  168.         resp = self.getmultiline()
  169.         if self.debugging:
  170.             print '*resp*', self.sanitize(resp)
  171.         
  172.         self.lastresp = resp[:3]
  173.         c = resp[:1]
  174.         if c == '4':
  175.             raise error_temp, resp
  176.         
  177.         if c == '5':
  178.             raise error_perm, resp
  179.         
  180.         if c not in '123':
  181.             raise error_proto, resp
  182.         
  183.         return resp
  184.  
  185.     
  186.     def voidresp(self):
  187.         resp = self.getresp()
  188.         if resp[0] != '2':
  189.             raise error_reply, resp
  190.         
  191.         return resp
  192.  
  193.     
  194.     def abort(self):
  195.         line = 'ABOR' + CRLF
  196.         if self.debugging > 1:
  197.             print '*put urgent*', self.sanitize(line)
  198.         
  199.         self.sock.sendall(line, MSG_OOB)
  200.         resp = self.getmultiline()
  201.         if resp[:3] not in ('426', '226'):
  202.             raise error_proto, resp
  203.         
  204.  
  205.     
  206.     def sendcmd(self, cmd):
  207.         self.putcmd(cmd)
  208.         return self.getresp()
  209.  
  210.     
  211.     def voidcmd(self, cmd):
  212.         self.putcmd(cmd)
  213.         return self.voidresp()
  214.  
  215.     
  216.     def sendport(self, host, port):
  217.         hbytes = host.split('.')
  218.         pbytes = [
  219.             `port / 256`,
  220.             `port % 256`]
  221.         bytes = hbytes + pbytes
  222.         cmd = 'PORT ' + ','.join(bytes)
  223.         return self.voidcmd(cmd)
  224.  
  225.     
  226.     def sendeprt(self, host, port):
  227.         af = 0
  228.         if self.af == socket.AF_INET:
  229.             af = 1
  230.         
  231.         if self.af == socket.AF_INET6:
  232.             af = 2
  233.         
  234.         if af == 0:
  235.             raise error_proto, 'unsupported address family'
  236.         
  237.         fields = [
  238.             '',
  239.             `af`,
  240.             host,
  241.             `port`,
  242.             '']
  243.         cmd = 'EPRT ' + string.joinfields(fields, '|')
  244.         return self.voidcmd(cmd)
  245.  
  246.     
  247.     def makeport(self):
  248.         msg = 'getaddrinfo returns an empty list'
  249.         sock = None
  250.         for res in socket.getaddrinfo(None, 0, self.af, socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
  251.             (af, socktype, proto, canonname, sa) = res
  252.             
  253.             try:
  254.                 sock = socket.socket(af, socktype, proto)
  255.                 sock.bind(sa)
  256.             except socket.error:
  257.                 msg = None
  258.                 if sock:
  259.                     sock.close()
  260.                 
  261.                 sock = None
  262.                 continue
  263.  
  264.         
  265.         if not sock:
  266.             raise socket.error, msg
  267.         
  268.         sock.listen(1)
  269.         port = sock.getsockname()[1]
  270.         host = self.sock.getsockname()[0]
  271.         if self.af == socket.AF_INET:
  272.             resp = self.sendport(host, port)
  273.         else:
  274.             resp = self.sendeprt(host, port)
  275.         return sock
  276.  
  277.     
  278.     def makepasv(self):
  279.         if self.af == socket.AF_INET:
  280.             (host, port) = parse227(self.sendcmd('PASV'))
  281.         else:
  282.             (host, port) = parse229(self.sendcmd('EPSV'), self.sock.getpeername())
  283.         return (host, port)
  284.  
  285.     
  286.     def ntransfercmd(self, cmd, rest = None):
  287.         size = None
  288.         if self.passiveserver:
  289.             (host, port) = self.makepasv()
  290.             (af, socktype, proto, canon, sa) = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0]
  291.             conn = socket.socket(af, socktype, proto)
  292.             conn.connect(sa)
  293.             if rest is not None:
  294.                 self.sendcmd('REST %s' % rest)
  295.             
  296.             resp = self.sendcmd(cmd)
  297.             if resp[0] != '1':
  298.                 raise error_reply, resp
  299.             
  300.         else:
  301.             sock = self.makeport()
  302.             if rest is not None:
  303.                 self.sendcmd('REST %s' % rest)
  304.             
  305.             resp = self.sendcmd(cmd)
  306.             if resp[0] != '1':
  307.                 raise error_reply, resp
  308.             
  309.             (conn, sockaddr) = sock.accept()
  310.         if resp[:3] == '150':
  311.             size = parse150(resp)
  312.         
  313.         return (conn, size)
  314.  
  315.     
  316.     def transfercmd(self, cmd, rest = None):
  317.         return self.ntransfercmd(cmd, rest)[0]
  318.  
  319.     
  320.     def login(self, user = '', passwd = '', acct = ''):
  321.         if not user:
  322.             user = 'anonymous'
  323.         
  324.         if not passwd:
  325.             passwd = ''
  326.         
  327.         if not acct:
  328.             acct = ''
  329.         
  330.         if user == 'anonymous' and passwd in ('', '-'):
  331.             thishost = socket.getfqdn()
  332.             
  333.             try:
  334.                 if os.environ.has_key('LOGNAME'):
  335.                     realuser = os.environ['LOGNAME']
  336.                 elif os.environ.has_key('USER'):
  337.                     realuser = os.environ['USER']
  338.                 else:
  339.                     realuser = 'anonymous'
  340.             except AttributeError:
  341.                 realuser = 'anonymous'
  342.  
  343.             passwd = passwd + realuser + '@' + thishost
  344.         
  345.         resp = self.sendcmd('USER ' + user)
  346.         if resp[0] == '3':
  347.             resp = self.sendcmd('PASS ' + passwd)
  348.         
  349.         if resp[0] == '3':
  350.             resp = self.sendcmd('ACCT ' + acct)
  351.         
  352.         if resp[0] != '2':
  353.             raise error_reply, resp
  354.         
  355.         return resp
  356.  
  357.     
  358.     def retrbinary(self, cmd, callback, blocksize = 8192, rest = None):
  359.         self.voidcmd('TYPE I')
  360.         conn = self.transfercmd(cmd, rest)
  361.         while 1:
  362.             data = conn.recv(blocksize)
  363.             if not data:
  364.                 break
  365.             
  366.             callback(data)
  367.         conn.close()
  368.         return self.voidresp()
  369.  
  370.     
  371.     def retrlines(self, cmd, callback = None):
  372.         if not callback:
  373.             callback = print_line
  374.         
  375.         resp = self.sendcmd('TYPE A')
  376.         conn = self.transfercmd(cmd)
  377.         fp = conn.makefile('rb')
  378.         while 1:
  379.             line = fp.readline()
  380.             if self.debugging > 2:
  381.                 print '*retr*', `line`
  382.             
  383.             if not line:
  384.                 break
  385.             
  386.             if line[-2:] == CRLF:
  387.                 line = line[:-2]
  388.             elif line[-1:] == '\n':
  389.                 line = line[:-1]
  390.             
  391.             callback(line)
  392.         fp.close()
  393.         conn.close()
  394.         return self.voidresp()
  395.  
  396.     
  397.     def storbinary(self, cmd, fp, blocksize = 8192):
  398.         self.voidcmd('TYPE I')
  399.         conn = self.transfercmd(cmd)
  400.         while 1:
  401.             buf = fp.read(blocksize)
  402.             if not buf:
  403.                 break
  404.             
  405.             conn.sendall(buf)
  406.         conn.close()
  407.         return self.voidresp()
  408.  
  409.     
  410.     def storlines(self, cmd, fp):
  411.         self.voidcmd('TYPE A')
  412.         conn = self.transfercmd(cmd)
  413.         while 1:
  414.             buf = fp.readline()
  415.             if not buf:
  416.                 break
  417.             
  418.             if buf[-2:] != CRLF:
  419.                 if buf[-1] in CRLF:
  420.                     buf = buf[:-1]
  421.                 
  422.                 buf = buf + CRLF
  423.             
  424.             conn.sendall(buf)
  425.         conn.close()
  426.         return self.voidresp()
  427.  
  428.     
  429.     def acct(self, password):
  430.         cmd = 'ACCT ' + password
  431.         return self.voidcmd(cmd)
  432.  
  433.     
  434.     def nlst(self, *args):
  435.         cmd = 'NLST'
  436.         for arg in args:
  437.             cmd = cmd + ' ' + arg
  438.         
  439.         files = []
  440.         self.retrlines(cmd, files.append)
  441.         return files
  442.  
  443.     
  444.     def dir(self, *args):
  445.         cmd = 'LIST'
  446.         func = None
  447.         if args[-1:] and type(args[-1]) != type(''):
  448.             (args, func) = (args[:-1], args[-1])
  449.         
  450.         for arg in args:
  451.             if arg:
  452.                 cmd = cmd + ' ' + arg
  453.             
  454.         
  455.         self.retrlines(cmd, func)
  456.  
  457.     
  458.     def rename(self, fromname, toname):
  459.         resp = self.sendcmd('RNFR ' + fromname)
  460.         if resp[0] != '3':
  461.             raise error_reply, resp
  462.         
  463.         return self.voidcmd('RNTO ' + toname)
  464.  
  465.     
  466.     def delete(self, filename):
  467.         resp = self.sendcmd('DELE ' + filename)
  468.         if resp[:3] in ('250', '200'):
  469.             return resp
  470.         elif resp[:1] == '5':
  471.             raise error_perm, resp
  472.         else:
  473.             raise error_reply, resp
  474.  
  475.     
  476.     def cwd(self, dirname):
  477.         if dirname == '..':
  478.             
  479.             try:
  480.                 return self.voidcmd('CDUP')
  481.             except error_perm:
  482.                 msg = None
  483.                 if msg.args[0][:3] != '500':
  484.                     raise 
  485.                 
  486.             except:
  487.                 msg.args[0][:3] != '500'
  488.  
  489.         elif dirname == '':
  490.             dirname = '.'
  491.         
  492.         cmd = 'CWD ' + dirname
  493.         return self.voidcmd(cmd)
  494.  
  495.     
  496.     def size(self, filename):
  497.         resp = self.sendcmd('SIZE ' + filename)
  498.         if resp[:3] == '213':
  499.             s = resp[3:].strip()
  500.             
  501.             try:
  502.                 return int(s)
  503.             except (OverflowError, ValueError):
  504.                 return long(s)
  505.  
  506.         
  507.  
  508.     
  509.     def mkd(self, dirname):
  510.         resp = self.sendcmd('MKD ' + dirname)
  511.         return parse257(resp)
  512.  
  513.     
  514.     def rmd(self, dirname):
  515.         return self.voidcmd('RMD ' + dirname)
  516.  
  517.     
  518.     def pwd(self):
  519.         resp = self.sendcmd('PWD')
  520.         return parse257(resp)
  521.  
  522.     
  523.     def quit(self):
  524.         resp = self.voidcmd('QUIT')
  525.         self.close()
  526.         return resp
  527.  
  528.     
  529.     def close(self):
  530.         if self.file:
  531.             self.file.close()
  532.             self.sock.close()
  533.             self.file = self.sock = None
  534.         
  535.  
  536.  
  537. _150_re = None
  538.  
  539. def parse150(resp):
  540.     global _150_re
  541.     if resp[:3] != '150':
  542.         raise error_reply, resp
  543.     
  544.     if _150_re is None:
  545.         import re
  546.         _150_re = re.compile('150 .* \\((\\d+) bytes\\)', re.IGNORECASE)
  547.     
  548.     m = _150_re.match(resp)
  549.     if not m:
  550.         return None
  551.     
  552.     s = m.group(1)
  553.     
  554.     try:
  555.         return int(s)
  556.     except (OverflowError, ValueError):
  557.         return long(s)
  558.  
  559.  
  560. _227_re = None
  561.  
  562. def parse227(resp):
  563.     global _227_re
  564.     if resp[:3] != '227':
  565.         raise error_reply, resp
  566.     
  567.     if _227_re is None:
  568.         import re
  569.         _227_re = re.compile('(\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)')
  570.     
  571.     m = _227_re.search(resp)
  572.     if not m:
  573.         raise error_proto, resp
  574.     
  575.     numbers = m.groups()
  576.     host = '.'.join(numbers[:4])
  577.     port = (int(numbers[4]) << 8) + int(numbers[5])
  578.     return (host, port)
  579.  
  580.  
  581. def parse229(resp, peer):
  582.     if resp[:3] != '229':
  583.         raise error_reply, resp
  584.     
  585.     left = string.find(resp, '(')
  586.     if left < 0:
  587.         raise error_proto, resp
  588.     
  589.     right = string.find(resp, ')', left + 1)
  590.     if right < 0:
  591.         raise error_proto, resp
  592.     
  593.     if resp[left + 1] != resp[right - 1]:
  594.         raise error_proto, resp
  595.     
  596.     parts = string.split(resp[left + 1:right], resp[left + 1])
  597.     if len(parts) != 5:
  598.         raise error_proto, resp
  599.     
  600.     host = peer[0]
  601.     port = string.atoi(parts[3])
  602.     return (host, port)
  603.  
  604.  
  605. def parse257(resp):
  606.     if resp[:3] != '257':
  607.         raise error_reply, resp
  608.     
  609.     if resp[3:5] != ' "':
  610.         return ''
  611.     
  612.     dirname = ''
  613.     i = 5
  614.     n = len(resp)
  615.     while i < n:
  616.         c = resp[i]
  617.         i = i + 1
  618.         if c == '"':
  619.             if i >= n or resp[i] != '"':
  620.                 break
  621.             
  622.             i = i + 1
  623.         
  624.         dirname = dirname + c
  625.     return dirname
  626.  
  627.  
  628. def print_line(line):
  629.     print line
  630.  
  631.  
  632. def ftpcp(source, sourcename, target, targetname = '', type = 'I'):
  633.     if not targetname:
  634.         targetname = sourcename
  635.     
  636.     type = 'TYPE ' + type
  637.     source.voidcmd(type)
  638.     target.voidcmd(type)
  639.     (sourcehost, sourceport) = parse227(source.sendcmd('PASV'))
  640.     target.sendport(sourcehost, sourceport)
  641.     treply = target.sendcmd('STOR ' + targetname)
  642.     if treply[:3] not in ('125', '150'):
  643.         raise error_proto
  644.     
  645.     sreply = source.sendcmd('RETR ' + sourcename)
  646.     if sreply[:3] not in ('125', '150'):
  647.         raise error_proto
  648.     
  649.     source.voidresp()
  650.     target.voidresp()
  651.  
  652.  
  653. class Netrc:
  654.     __defuser = None
  655.     __defpasswd = None
  656.     __defacct = None
  657.     
  658.     def __init__(self, filename = None):
  659.         if not filename:
  660.             if os.environ.has_key('HOME'):
  661.                 filename = os.path.join(os.environ['HOME'], '.netrc')
  662.             else:
  663.                 raise IOError, 'specify file to load or set $HOME'
  664.         
  665.         self._Netrc__hosts = { }
  666.         self._Netrc__macros = { }
  667.         fp = open(filename, 'r')
  668.         in_macro = 0
  669.         while 1:
  670.             line = fp.readline()
  671.             if not line:
  672.                 break
  673.             
  674.             if in_macro and line.strip():
  675.                 macro_lines.append(line)
  676.                 continue
  677.             elif in_macro:
  678.                 self._Netrc__macros[macro_name] = tuple(macro_lines)
  679.                 in_macro = 0
  680.             
  681.             words = line.split()
  682.             host = user = passwd = acct = None
  683.             default = 0
  684.             i = 0
  685.             while i < len(words):
  686.                 w1 = words[i]
  687.                 if i + 1 < len(words):
  688.                     w2 = words[i + 1]
  689.                 else:
  690.                     w2 = None
  691.                 if w1 == 'default':
  692.                     default = 1
  693.                 elif w1 == 'machine' and w2:
  694.                     host = w2.lower()
  695.                     i = i + 1
  696.                 elif w1 == 'login' and w2:
  697.                     user = w2
  698.                     i = i + 1
  699.                 elif w1 == 'password' and w2:
  700.                     passwd = w2
  701.                     i = i + 1
  702.                 elif w1 == 'account' and w2:
  703.                     acct = w2
  704.                     i = i + 1
  705.                 elif w1 == 'macdef' and w2:
  706.                     macro_name = w2
  707.                     macro_lines = []
  708.                     in_macro = 1
  709.                     break
  710.                 
  711.                 i = i + 1
  712.             if default:
  713.                 if not user:
  714.                     pass
  715.                 self._Netrc__defuser = self._Netrc__defuser
  716.                 if not passwd:
  717.                     pass
  718.                 self._Netrc__defpasswd = self._Netrc__defpasswd
  719.                 if not acct:
  720.                     pass
  721.                 self._Netrc__defacct = self._Netrc__defacct
  722.             
  723.             if host:
  724.                 if self._Netrc__hosts.has_key(host):
  725.                     (ouser, opasswd, oacct) = self._Netrc__hosts[host]
  726.                     if not user:
  727.                         pass
  728.                     user = ouser
  729.                     if not passwd:
  730.                         pass
  731.                     passwd = opasswd
  732.                     if not acct:
  733.                         pass
  734.                     acct = oacct
  735.                 
  736.                 self._Netrc__hosts[host] = (user, passwd, acct)
  737.             
  738.         fp.close()
  739.  
  740.     
  741.     def get_hosts(self):
  742.         return self._Netrc__hosts.keys()
  743.  
  744.     
  745.     def get_account(self, host):
  746.         host = host.lower()
  747.         user = passwd = acct = None
  748.         if self._Netrc__hosts.has_key(host):
  749.             (user, passwd, acct) = self._Netrc__hosts[host]
  750.         
  751.         if not user:
  752.             pass
  753.         user = self._Netrc__defuser
  754.         if not passwd:
  755.             pass
  756.         passwd = self._Netrc__defpasswd
  757.         if not acct:
  758.             pass
  759.         acct = self._Netrc__defacct
  760.         return (user, passwd, acct)
  761.  
  762.     
  763.     def get_macros(self):
  764.         return self._Netrc__macros.keys()
  765.  
  766.     
  767.     def get_macro(self, macro):
  768.         return self._Netrc__macros[macro]
  769.  
  770.  
  771.  
  772. def test():
  773.     debugging = 0
  774.     rcfile = None
  775.     while sys.argv[1] == '-d':
  776.         debugging = debugging + 1
  777.         del sys.argv[1]
  778.     if sys.argv[1][:2] == '-r':
  779.         rcfile = sys.argv[1][2:]
  780.         del sys.argv[1]
  781.     
  782.     host = sys.argv[1]
  783.     ftp = FTP(host)
  784.     ftp.set_debuglevel(debugging)
  785.     userid = passwd = acct = ''
  786.     
  787.     try:
  788.         netrc = Netrc(rcfile)
  789.     except IOError:
  790.         if rcfile is not None:
  791.             sys.stderr.write('Could not open account file -- using anonymous login.')
  792.         
  793.     except:
  794.         rcfile is not None
  795.  
  796.     
  797.     try:
  798.         (userid, passwd, acct) = netrc.get_account(host)
  799.     except KeyError:
  800.         sys.stderr.write('No account -- using anonymous login.')
  801.  
  802.     ftp.login(userid, passwd, acct)
  803.     for file in sys.argv[2:]:
  804.         if file[:2] == '-l':
  805.             ftp.dir(file[2:])
  806.         elif file[:2] == '-d':
  807.             cmd = 'CWD'
  808.             if file[2:]:
  809.                 cmd = cmd + ' ' + file[2:]
  810.             
  811.             resp = ftp.sendcmd(cmd)
  812.         elif file == '-p':
  813.             ftp.set_pasv(not (ftp.passiveserver))
  814.         else:
  815.             ftp.retrbinary('RETR ' + file, sys.stdout.write, 1024)
  816.     
  817.     ftp.quit()
  818.  
  819. if __name__ == '__main__':
  820.     test()
  821.  
  822.