10c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""Module/script to byte-compile all .py files to .pyc (or .pyo) files.
20c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
30c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiWhen called as a script with arguments, this compiles the directories
40c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yigiven as arguments recursively; the -l option prevents it from
50c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yirecursing into directories.
60c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
70c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiWithout arguments, if compiles all modules on sys.path, without
80c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yirecursing into subdirectories.  (Even though it should do so for
90c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yipackages -- for now, you'll have to deal with packages separately.)
100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSee module py_compile for details of the actual byte-compilation.
120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport os
140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport sys
150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport py_compile
160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport struct
170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport imp
180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi__all__ = ["compile_dir","compile_file","compile_path"]
200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef compile_dir(dir, maxlevels=10, ddir=None,
220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                force=0, rx=None, quiet=0):
230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Byte-compile all modules in the given directory tree.
240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Arguments (only dir is required):
260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dir:       the directory to byte-compile
280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    maxlevels: maximum recursion level (default 10)
290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ddir:      the directory that will be prepended to the path to the
300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi               file as it is compiled into each byte-code file.
310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    force:     if 1, force compilation, even if timestamps are up-to-date
320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    quiet:     if 1, be quiet during compilation
330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """
340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if not quiet:
350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print 'Listing', dir, '...'
360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    try:
370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        names = os.listdir(dir)
380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    except os.error:
390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "Can't list", dir
400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        names = []
410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    names.sort()
420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    success = 1
430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    for name in names:
440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fullname = os.path.join(dir, name)
450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if sys.platform == "win32" and sys.version.find("GCC") >= 0:
460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fullname = fullname.replace('\\','/')
470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if ddir is not None:
480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            dfile = os.path.join(ddir, name)
490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            dfile = None
510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if not os.path.isdir(fullname):
520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if not compile_file(fullname, ddir, force, rx, quiet):
530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                success = 0
540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        elif maxlevels > 0 and \
550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             name != os.curdir and name != os.pardir and \
560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             os.path.isdir(fullname) and \
570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi             not os.path.islink(fullname):
580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if not compile_dir(fullname, maxlevels - 1, dfile, force, rx,
590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                               quiet):
600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                success = 0
610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return success
620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef compile_file(fullname, ddir=None, force=0, rx=None, quiet=0):
640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Byte-compile one file.
650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Arguments (only fullname is required):
670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    fullname:  the file to byte-compile
690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ddir:      if given, the directory name compiled in to the
700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi               byte-code file.
710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    force:     if 1, force compilation, even if timestamps are up-to-date
720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    quiet:     if 1, be quiet during compilation
730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """
740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    success = 1
750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    name = os.path.basename(fullname)
760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if ddir is not None:
770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dfile = os.path.join(ddir, name)
780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    else:
790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dfile = None
800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if rx is not None:
810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        mo = rx.search(fullname)
820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if mo:
830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return success
840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if os.path.isfile(fullname):
850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        head, tail = name[:-3], name[-3:]
860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if tail == '.py':
870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if not force:
880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                try:
890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    mtime = int(os.stat(fullname).st_mtime)
900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    expect = struct.pack('<4sl', imp.get_magic(), mtime)
910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    cfile = fullname + (__debug__ and 'c' or 'o')
920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    with open(cfile, 'rb') as chandle:
930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                        actual = chandle.read(8)
940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    if expect == actual:
950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                        return success
960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                except IOError:
970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    pass
980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if not quiet:
990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                print 'Compiling', fullname, '...'
1000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            try:
1010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                ok = py_compile.compile(fullname, None, dfile, True)
1020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            except py_compile.PyCompileError,err:
1030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                if quiet:
1040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    print 'Compiling', fullname, '...'
1050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                print err.msg
1060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                success = 0
1070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            except IOError, e:
1080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                print "Sorry", e
1090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                success = 0
1100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            else:
1110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                if ok == 0:
1120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    success = 0
1130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return success
1140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef compile_path(skip_curdir=1, maxlevels=0, force=0, quiet=0):
1160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Byte-compile all module on sys.path.
1170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Arguments (all optional):
1190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    skip_curdir: if true, skip current directory (default true)
1210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    maxlevels:   max recursion level (default 0)
1220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    force: as for compile_dir() (default 0)
1230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    quiet: as for compile_dir() (default 0)
1240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """
1250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    success = 1
1260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    for dir in sys.path:
1270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if (not dir or dir == os.curdir) and skip_curdir:
1280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            print 'Skipping current directory'
1290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
1300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            success = success and compile_dir(dir, maxlevels, None,
1310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                                              force, quiet=quiet)
1320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return success
1330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef expand_args(args, flist):
1350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """read names in flist and append to args"""
1360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    expanded = args[:]
1370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if flist:
1380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
1390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if flist == '-':
1400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                fd = sys.stdin
1410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            else:
1420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                fd = open(flist)
1430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            while 1:
1440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                line = fd.readline()
1450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                if not line:
1460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    break
1470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                expanded.append(line[:-1])
1480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        except IOError:
1490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            print "Error reading file list %s" % flist
1500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise
1510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return expanded
1520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef main():
1540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Script main program."""
1550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    import getopt
1560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    try:
1570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        opts, args = getopt.getopt(sys.argv[1:], 'lfqd:x:i:')
1580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    except getopt.error, msg:
1590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print msg
1600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "usage: python compileall.py [-l] [-f] [-q] [-d destdir] " \
1610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi              "[-x regexp] [-i list] [directory|file ...]"
1620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print
1630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "arguments: zero or more file and directory names to compile; " \
1640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi              "if no arguments given, "
1650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "           defaults to the equivalent of -l sys.path"
1660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print
1670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "options:"
1680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "-l: don't recurse into subdirectories"
1690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "-f: force rebuild even if timestamps are up-to-date"
1700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "-q: output only error messages"
1710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "-d destdir: directory to prepend to file paths for use in " \
1720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi              "compile-time tracebacks and in"
1730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "            runtime tracebacks in cases where the source " \
1740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi              "file is unavailable"
1750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "-x regexp: skip files matching the regular expression regexp; " \
1760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi              "the regexp is searched for"
1770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "           in the full path of each file considered for " \
1780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi              "compilation"
1790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "-i file: add all the files and directories listed in file to " \
1800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi              "the list considered for"
1810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print '         compilation; if "-", names are read from stdin'
1820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sys.exit(2)
1840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    maxlevels = 10
1850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ddir = None
1860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    force = 0
1870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    quiet = 0
1880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    rx = None
1890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    flist = None
1900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    for o, a in opts:
1910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if o == '-l': maxlevels = 0
1920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if o == '-d': ddir = a
1930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if o == '-f': force = 1
1940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if o == '-q': quiet = 1
1950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if o == '-x':
1960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            import re
1970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            rx = re.compile(a)
1980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if o == '-i': flist = a
1990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if ddir:
2000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if len(args) != 1 and not os.path.isdir(args[0]):
2010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            print "-d destdir require exactly one directory argument"
2020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            sys.exit(2)
2030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    success = 1
2040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    try:
2050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if args or flist:
2060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            try:
2070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                if flist:
2080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    args = expand_args(args, flist)
2090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            except IOError:
2100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                success = 0
2110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if success:
2120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                for arg in args:
2130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    if os.path.isdir(arg):
2140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                        if not compile_dir(arg, maxlevels, ddir,
2150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                                           force, rx, quiet):
2160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                            success = 0
2170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    else:
2180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                        if not compile_file(arg, ddir, force, rx, quiet):
2190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                            success = 0
2200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
2210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            success = compile_path()
2220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    except KeyboardInterrupt:
2230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "\n[interrupted]"
2240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        success = 0
2250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return success
2260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiif __name__ == '__main__':
2280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    exit_status = int(not main())
2290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    sys.exit(exit_status)
230