KanonConductor

changeset 12:427a87821423 centos5-support

refactoring for CentOS5.x support.
author chris
date Wed, 09 Mar 2011 18:15:30 +0900
parents 6524a9f7a133
children d48ffe357575
files kanon-setup pkglist.rhel pkglist.rhel6 resource/virtualenv.py
diffstat 4 files changed, 1722 insertions(+), 54 deletions(-) [+]
line diff
     1.1 --- a/kanon-setup	Mon Mar 07 23:58:42 2011 +0900
     1.2 +++ b/kanon-setup	Wed Mar 09 18:15:30 2011 +0900
     1.3 @@ -9,8 +9,14 @@
     1.4      APACHE_USER=www-data
     1.5  elif [ -f /etc/redhat-release ]
     1.6  then
     1.7 -    OS='rhel'
     1.8      APACHE_USER=apache
     1.9 +    CHK=`egrep "CentOS release 5|Red Hat Enterprise Linux .* 5" /etc/redhat-release`
    1.10 +    if [ "$CHK" != '' ]
    1.11 +    then
    1.12 +        OS='rhel5'    
    1.13 +    else
    1.14 +        OS='rhel6'
    1.15 +    fi
    1.16  else
    1.17      echo "サポートされていないOSです。"
    1.18      echo "現在サポートされいているOSは、"
    1.19 @@ -49,14 +55,19 @@
    1.20  fi
    1.21  
    1.22  ### install ubuntu package 
    1.23 -if [ "$OS" = 'debian' ]
    1.24 -then
    1.25 -    apt-get update
    1.26 -    apt-get -y install `cat pkglist.debian`
    1.27 -elif [ "$OS" = 'rhel' ]
    1.28 -then
    1.29 -    yum -y install `cat pkglist.rhel`
    1.30 -fi
    1.31 +case $OS in
    1.32 +    debian)
    1.33 +        apt-get update 
    1.34 +        apt-get -y install `cat pkglist.debian` 
    1.35 +        ;;
    1.36 +    rhel6)
    1.37 +        yum -y install `cat pkglist.rhel6`
    1.38 +        ;;
    1.39 +    rhel5)
    1.40 +        ;;
    1.41 +    *)
    1.42 +        ;;    
    1.43 +esac
    1.44  
    1.45  ### install files
    1.46  cp -fr opt/* /opt
    1.47 @@ -64,8 +75,8 @@
    1.48  
    1.49  
    1.50  ### setup configuration
    1.51 -export PYTHONPATH=/opt/kanon/lib/python2.6:/opt/kanon/lib/python2.6/site-packages
    1.52 -cp resource/dot.pydistutils.cfg ~/.pydistutils.cfg
    1.53 +python resource/virtualenv.py /opt/kanon
    1.54 +source /opt/kanon/bin/activate
    1.55  
    1.56  ## setup sitecustomize for python
    1.57  if [ -f /etc/python2.6/sitecustomize.py ]
    1.58 @@ -78,18 +89,18 @@
    1.59  fi
    1.60  
    1.61  ### install python components
    1.62 -easy_install --prefix $KANON_OPT http://svn.edgewall.org/repos/genshi/tags/0.6.0/
    1.63 -easy_install --prefix $KANON_OPT http://ftp.edgewall.com/pub/babel/Babel-0.9.5.zip
    1.64 -easy_install --prefix $KANON_OPT http://www.i-act.co.jp/project/products/downloads/Trac-0.12.2.ja1.zip
    1.65 -easy_install --prefix $KANON_OPT xlrd
    1.66 -easy_install --prefix $KANON_OPT https://github.com/hvr/trac-git-plugin/zipball/v0.12.0.5
    1.67 +easy_install http://svn.edgewall.org/repos/genshi/tags/0.6.0/
    1.68 +easy_install http://ftp.edgewall.com/pub/babel/Babel-0.9.5.zip
    1.69 +easy_install http://www.i-act.co.jp/project/products/downloads/Trac-0.12.2.ja1.zip
    1.70 +easy_install xlrd
    1.71 +easy_install https://github.com/hvr/trac-git-plugin/zipball/v0.12.0.5
    1.72  # bzr co lp:trac-bzr /tmp/trac-bzr-install
    1.73  #easy_install --prefix /opt/kanon /tmp/trac-bzr-install
    1.74  #rm -fr /tmp/trac-bzr-install
    1.75  
    1.76  
    1.77  ### install trac plugins
    1.78 -easy_install --prefix $KANON_OPT http://svn.edgewall.com/repos/trac/plugins/0.12/mercurial-plugin 
    1.79 +easy_install http://svn.edgewall.com/repos/trac/plugins/0.12/mercurial-plugin 
    1.80  
    1.81  #resource/pluginsディレクトリのプラグインをインストール
    1.82  pushd .
    1.83 @@ -117,32 +128,38 @@
    1.84  
    1.85  
    1.86  ### setup apache and restart
    1.87 -if [ "$OS" = 'debian' ]
    1.88 -then
    1.89 -    cp resource/trac_hook.py /usr/lib/python2.6/dist-packages/bzrlib/plugins
    1.90 -    if [ ! -f /etc/apache2/sites-available/kanon ]
    1.91 -    then
    1.92 -        cp resource/httpd.conf /etc/apache2/sites-available/kanon
    1.93 -    fi
    1.94 -    a2enmod expires
    1.95 -    a2enmod auth_digest
    1.96 -    a2enmod dav_fs
    1.97 -    a2ensite kanon
    1.98 -    service apache2 stop
    1.99 -    service apache2 start
   1.100 -elif [ "$OS" = 'rhel' ]
   1.101 -then
   1.102 -    mkdir -p /usr/lib/python2.6/site-packages/bzrlib/plugin
   1.103 -    cp resource/trac_hook.py /usr/lib/python2.6/site-packages/bzrlib/plugin
   1.104 -    if [ ! -f /etc/httpd/conf.d/kanon.conf ]
   1.105 -    then
   1.106 -        cp resource/httpd.conf /etc/httpd/conf.d/kanon.conf
   1.107 -    fi
   1.108 -    echo 0 > /selinux/enforce
   1.109 -    echo "SELinuxが無効化されました"
   1.110 -    service httpd stop
   1.111 -    service httpd start
   1.112 -fi
   1.113 +case $OS in
   1.114 +    debian)
   1.115 +        cp resource/trac_hook.py /usr/lib/python2.6/dist-packages/bzrlib/plugins
   1.116 +        if [ ! -f /etc/apache2/sites-available/kanon ]
   1.117 +        then
   1.118 +            cp resource/httpd.conf /etc/apache2/sites-available/kanon
   1.119 +        fi
   1.120 +        a2enmod expires
   1.121 +        a2enmod auth_digest
   1.122 +        a2enmod dav_fs
   1.123 +        a2ensite kanon
   1.124 +        service apache2 stop
   1.125 +        service apache2 start
   1.126 +        ;;
   1.127 +    rhel6)
   1.128 +        mkdir -p /usr/lib/python2.6/site-packages/bzrlib/plugin
   1.129 +        cp resource/trac_hook.py /usr/lib/python2.6/site-packages/bzrlib/plugin
   1.130 +        if [ ! -f /etc/httpd/conf.d/kanon.conf ]
   1.131 +        then
   1.132 +            cp resource/httpd.conf /etc/httpd/conf.d/kanon.conf
   1.133 +        fi
   1.134 +        echo 0 > /selinux/enforce
   1.135 +        echo "SELinuxが無効化されました"
   1.136 +        service httpd stop
   1.137 +        service httpd start
   1.138 +        ;;
   1.139 +    rhel5)
   1.140 +        ;;
   1.141 +    *)
   1.142 +        ;;    
   1.143 +esac
   1.144 +
   1.145  
   1.146  # データディレクトリが存在しない場合作成
   1.147  if [ ! -d "$KANON_VAR/trac" ]
     2.1 --- a/pkglist.rhel	Mon Mar 07 23:58:42 2011 +0900
     2.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 @@ -1,11 +0,0 @@
     2.4 -httpd
     2.5 -python-setuptools
     2.6 -python-pygments
     2.7 -sqlite
     2.8 -mod_dav_svn
     2.9 -mod_wsgi
    2.10 -subversion
    2.11 -mercurial
    2.12 -bzr
    2.13 -gcc
    2.14 -git
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/pkglist.rhel6	Wed Mar 09 18:15:30 2011 +0900
     3.3 @@ -0,0 +1,11 @@
     3.4 +httpd
     3.5 +python-setuptools
     3.6 +python-pygments
     3.7 +sqlite
     3.8 +mod_dav_svn
     3.9 +mod_wsgi
    3.10 +subversion
    3.11 +mercurial
    3.12 +bzr
    3.13 +gcc
    3.14 +git
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/resource/virtualenv.py	Wed Mar 09 18:15:30 2011 +0900
     4.3 @@ -0,0 +1,1651 @@
     4.4 +#!/usr/bin/env python
     4.5 +"""Create a "virtual" Python installation
     4.6 +"""
     4.7 +
     4.8 +virtualenv_version = "1.5.1"
     4.9 +
    4.10 +import sys
    4.11 +import os
    4.12 +import optparse
    4.13 +import re
    4.14 +import shutil
    4.15 +import logging
    4.16 +import tempfile
    4.17 +import distutils.sysconfig
    4.18 +try:
    4.19 +    import subprocess
    4.20 +except ImportError, e:
    4.21 +    if sys.version_info <= (2, 3):
    4.22 +        print 'ERROR: %s' % e
    4.23 +        print 'ERROR: this script requires Python 2.4 or greater; or at least the subprocess module.'
    4.24 +        print 'If you copy subprocess.py from a newer version of Python this script will probably work'
    4.25 +        sys.exit(101)
    4.26 +    else:
    4.27 +        raise
    4.28 +try:
    4.29 +    set
    4.30 +except NameError:
    4.31 +    from sets import Set as set
    4.32 +
    4.33 +join = os.path.join
    4.34 +py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
    4.35 +
    4.36 +is_jython = sys.platform.startswith('java')
    4.37 +is_pypy = hasattr(sys, 'pypy_version_info')
    4.38 +
    4.39 +if is_pypy:
    4.40 +    expected_exe = 'pypy-c'
    4.41 +elif is_jython:
    4.42 +    expected_exe = 'jython'
    4.43 +else:
    4.44 +    expected_exe = 'python'
    4.45 +
    4.46 +
    4.47 +REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath',
    4.48 +                    'fnmatch', 'locale', 'encodings', 'codecs',
    4.49 +                    'stat', 'UserDict', 'readline', 'copy_reg', 'types',
    4.50 +                    're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile',
    4.51 +                    'zlib']
    4.52 +
    4.53 +REQUIRED_FILES = ['lib-dynload', 'config']
    4.54 +
    4.55 +if sys.version_info[:2] >= (2, 6):
    4.56 +    REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc'])
    4.57 +if sys.version_info[:2] >= (2, 7):
    4.58 +    REQUIRED_MODULES.extend(['_weakrefset'])
    4.59 +if sys.version_info[:2] <= (2, 3):
    4.60 +    REQUIRED_MODULES.extend(['sets', '__future__'])
    4.61 +if is_pypy:
    4.62 +    # these are needed to correctly display the exceptions that may happen
    4.63 +    # during the bootstrap
    4.64 +    REQUIRED_MODULES.extend(['traceback', 'linecache'])
    4.65 +
    4.66 +class Logger(object):
    4.67 +
    4.68 +    """
    4.69 +    Logging object for use in command-line script.  Allows ranges of
    4.70 +    levels, to avoid some redundancy of displayed information.
    4.71 +    """
    4.72 +
    4.73 +    DEBUG = logging.DEBUG
    4.74 +    INFO = logging.INFO
    4.75 +    NOTIFY = (logging.INFO+logging.WARN)/2
    4.76 +    WARN = WARNING = logging.WARN
    4.77 +    ERROR = logging.ERROR
    4.78 +    FATAL = logging.FATAL
    4.79 +
    4.80 +    LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
    4.81 +
    4.82 +    def __init__(self, consumers):
    4.83 +        self.consumers = consumers
    4.84 +        self.indent = 0
    4.85 +        self.in_progress = None
    4.86 +        self.in_progress_hanging = False
    4.87 +
    4.88 +    def debug(self, msg, *args, **kw):
    4.89 +        self.log(self.DEBUG, msg, *args, **kw)
    4.90 +    def info(self, msg, *args, **kw):
    4.91 +        self.log(self.INFO, msg, *args, **kw)
    4.92 +    def notify(self, msg, *args, **kw):
    4.93 +        self.log(self.NOTIFY, msg, *args, **kw)
    4.94 +    def warn(self, msg, *args, **kw):
    4.95 +        self.log(self.WARN, msg, *args, **kw)
    4.96 +    def error(self, msg, *args, **kw):
    4.97 +        self.log(self.WARN, msg, *args, **kw)
    4.98 +    def fatal(self, msg, *args, **kw):
    4.99 +        self.log(self.FATAL, msg, *args, **kw)
   4.100 +    def log(self, level, msg, *args, **kw):
   4.101 +        if args:
   4.102 +            if kw:
   4.103 +                raise TypeError(
   4.104 +                    "You may give positional or keyword arguments, not both")
   4.105 +        args = args or kw
   4.106 +        rendered = None
   4.107 +        for consumer_level, consumer in self.consumers:
   4.108 +            if self.level_matches(level, consumer_level):
   4.109 +                if (self.in_progress_hanging
   4.110 +                    and consumer in (sys.stdout, sys.stderr)):
   4.111 +                    self.in_progress_hanging = False
   4.112 +                    sys.stdout.write('\n')
   4.113 +                    sys.stdout.flush()
   4.114 +                if rendered is None:
   4.115 +                    if args:
   4.116 +                        rendered = msg % args
   4.117 +                    else:
   4.118 +                        rendered = msg
   4.119 +                    rendered = ' '*self.indent + rendered
   4.120 +                if hasattr(consumer, 'write'):
   4.121 +                    consumer.write(rendered+'\n')
   4.122 +                else:
   4.123 +                    consumer(rendered)
   4.124 +
   4.125 +    def start_progress(self, msg):
   4.126 +        assert not self.in_progress, (
   4.127 +            "Tried to start_progress(%r) while in_progress %r"
   4.128 +            % (msg, self.in_progress))
   4.129 +        if self.level_matches(self.NOTIFY, self._stdout_level()):
   4.130 +            sys.stdout.write(msg)
   4.131 +            sys.stdout.flush()
   4.132 +            self.in_progress_hanging = True
   4.133 +        else:
   4.134 +            self.in_progress_hanging = False
   4.135 +        self.in_progress = msg
   4.136 +
   4.137 +    def end_progress(self, msg='done.'):
   4.138 +        assert self.in_progress, (
   4.139 +            "Tried to end_progress without start_progress")
   4.140 +        if self.stdout_level_matches(self.NOTIFY):
   4.141 +            if not self.in_progress_hanging:
   4.142 +                # Some message has been printed out since start_progress
   4.143 +                sys.stdout.write('...' + self.in_progress + msg + '\n')
   4.144 +                sys.stdout.flush()
   4.145 +            else:
   4.146 +                sys.stdout.write(msg + '\n')
   4.147 +                sys.stdout.flush()
   4.148 +        self.in_progress = None
   4.149 +        self.in_progress_hanging = False
   4.150 +
   4.151 +    def show_progress(self):
   4.152 +        """If we are in a progress scope, and no log messages have been
   4.153 +        shown, write out another '.'"""
   4.154 +        if self.in_progress_hanging:
   4.155 +            sys.stdout.write('.')
   4.156 +            sys.stdout.flush()
   4.157 +
   4.158 +    def stdout_level_matches(self, level):
   4.159 +        """Returns true if a message at this level will go to stdout"""
   4.160 +        return self.level_matches(level, self._stdout_level())
   4.161 +
   4.162 +    def _stdout_level(self):
   4.163 +        """Returns the level that stdout runs at"""
   4.164 +        for level, consumer in self.consumers:
   4.165 +            if consumer is sys.stdout:
   4.166 +                return level
   4.167 +        return self.FATAL
   4.168 +
   4.169 +    def level_matches(self, level, consumer_level):
   4.170 +        """
   4.171 +        >>> l = Logger()
   4.172 +        >>> l.level_matches(3, 4)
   4.173 +        False
   4.174 +        >>> l.level_matches(3, 2)
   4.175 +        True
   4.176 +        >>> l.level_matches(slice(None, 3), 3)
   4.177 +        False
   4.178 +        >>> l.level_matches(slice(None, 3), 2)
   4.179 +        True
   4.180 +        >>> l.level_matches(slice(1, 3), 1)
   4.181 +        True
   4.182 +        >>> l.level_matches(slice(2, 3), 1)
   4.183 +        False
   4.184 +        """
   4.185 +        if isinstance(level, slice):
   4.186 +            start, stop = level.start, level.stop
   4.187 +            if start is not None and start > consumer_level:
   4.188 +                return False
   4.189 +            if stop is not None or stop <= consumer_level:
   4.190 +                return False
   4.191 +            return True
   4.192 +        else:
   4.193 +            return level >= consumer_level
   4.194 +
   4.195 +    #@classmethod
   4.196 +    def level_for_integer(cls, level):
   4.197 +        levels = cls.LEVELS
   4.198 +        if level < 0:
   4.199 +            return levels[0]
   4.200 +        if level >= len(levels):
   4.201 +            return levels[-1]
   4.202 +        return levels[level]
   4.203 +
   4.204 +    level_for_integer = classmethod(level_for_integer)
   4.205 +
   4.206 +def mkdir(path):
   4.207 +    if not os.path.exists(path):
   4.208 +        logger.info('Creating %s', path)
   4.209 +        os.makedirs(path)
   4.210 +    else:
   4.211 +        logger.info('Directory %s already exists', path)
   4.212 +
   4.213 +def copyfile(src, dest, symlink=True):
   4.214 +    if not os.path.exists(src):
   4.215 +        # Some bad symlink in the src
   4.216 +        logger.warn('Cannot find file %s (bad symlink)', src)
   4.217 +        return
   4.218 +    if os.path.exists(dest):
   4.219 +        logger.debug('File %s already exists', dest)
   4.220 +        return
   4.221 +    if not os.path.exists(os.path.dirname(dest)):
   4.222 +        logger.info('Creating parent directories for %s' % os.path.dirname(dest))
   4.223 +        os.makedirs(os.path.dirname(dest))
   4.224 +    if symlink and hasattr(os, 'symlink'):
   4.225 +        logger.info('Symlinking %s', dest)
   4.226 +        os.symlink(os.path.abspath(src), dest)
   4.227 +    else:
   4.228 +        logger.info('Copying to %s', dest)
   4.229 +        if os.path.isdir(src):
   4.230 +            shutil.copytree(src, dest, True)
   4.231 +        else:
   4.232 +            shutil.copy2(src, dest)
   4.233 +
   4.234 +def writefile(dest, content, overwrite=True):
   4.235 +    if not os.path.exists(dest):
   4.236 +        logger.info('Writing %s', dest)
   4.237 +        f = open(dest, 'wb')
   4.238 +        f.write(content)
   4.239 +        f.close()
   4.240 +        return
   4.241 +    else:
   4.242 +        f = open(dest, 'rb')
   4.243 +        c = f.read()
   4.244 +        f.close()
   4.245 +        if c != content:
   4.246 +            if not overwrite:
   4.247 +                logger.notify('File %s exists with different content; not overwriting', dest)
   4.248 +                return
   4.249 +            logger.notify('Overwriting %s with new content', dest)
   4.250 +            f = open(dest, 'wb')
   4.251 +            f.write(content)
   4.252 +            f.close()
   4.253 +        else:
   4.254 +            logger.info('Content %s already in place', dest)
   4.255 +
   4.256 +def rmtree(dir):
   4.257 +    if os.path.exists(dir):
   4.258 +        logger.notify('Deleting tree %s', dir)
   4.259 +        shutil.rmtree(dir)
   4.260 +    else:
   4.261 +        logger.info('Do not need to delete %s; already gone', dir)
   4.262 +
   4.263 +def make_exe(fn):
   4.264 +    if hasattr(os, 'chmod'):
   4.265 +        oldmode = os.stat(fn).st_mode & 07777
   4.266 +        newmode = (oldmode | 0555) & 07777
   4.267 +        os.chmod(fn, newmode)
   4.268 +        logger.info('Changed mode of %s to %s', fn, oct(newmode))
   4.269 +
   4.270 +def _find_file(filename, dirs):
   4.271 +    for dir in dirs:
   4.272 +        if os.path.exists(join(dir, filename)):
   4.273 +            return join(dir, filename)
   4.274 +    return filename
   4.275 +
   4.276 +def _install_req(py_executable, unzip=False, distribute=False):
   4.277 +    if not distribute:
   4.278 +        setup_fn = 'setuptools-0.6c11-py%s.egg' % sys.version[:3]
   4.279 +        project_name = 'setuptools'
   4.280 +        bootstrap_script = EZ_SETUP_PY
   4.281 +        source = None
   4.282 +    else:
   4.283 +        setup_fn = None
   4.284 +        source = 'distribute-0.6.14.tar.gz'
   4.285 +        project_name = 'distribute'
   4.286 +        bootstrap_script = DISTRIBUTE_SETUP_PY
   4.287 +        try:
   4.288 +            # check if the global Python has distribute installed or plain
   4.289 +            # setuptools
   4.290 +            import pkg_resources
   4.291 +            if not hasattr(pkg_resources, '_distribute'):
   4.292 +                location = os.path.dirname(pkg_resources.__file__)
   4.293 +                logger.notify("A globally installed setuptools was found (in %s)" % location)
   4.294 +                logger.notify("Use the --no-site-packages option to use distribute in "
   4.295 +                              "the virtualenv.")
   4.296 +        except ImportError:
   4.297 +            pass
   4.298 +
   4.299 +    search_dirs = file_search_dirs()
   4.300 +
   4.301 +    if setup_fn is not None:
   4.302 +        setup_fn = _find_file(setup_fn, search_dirs)
   4.303 +
   4.304 +    if source is not None:
   4.305 +        source = _find_file(source, search_dirs)
   4.306 +
   4.307 +    if is_jython and os._name == 'nt':
   4.308 +        # Jython's .bat sys.executable can't handle a command line
   4.309 +        # argument with newlines
   4.310 +        fd, ez_setup = tempfile.mkstemp('.py')
   4.311 +        os.write(fd, bootstrap_script)
   4.312 +        os.close(fd)
   4.313 +        cmd = [py_executable, ez_setup]
   4.314 +    else:
   4.315 +        cmd = [py_executable, '-c', bootstrap_script]
   4.316 +    if unzip:
   4.317 +        cmd.append('--always-unzip')
   4.318 +    env = {}
   4.319 +    remove_from_env = []
   4.320 +    if logger.stdout_level_matches(logger.DEBUG):
   4.321 +        cmd.append('-v')
   4.322 +
   4.323 +    old_chdir = os.getcwd()
   4.324 +    if setup_fn is not None and os.path.exists(setup_fn):
   4.325 +        logger.info('Using existing %s egg: %s' % (project_name, setup_fn))
   4.326 +        cmd.append(setup_fn)
   4.327 +        if os.environ.get('PYTHONPATH'):
   4.328 +            env['PYTHONPATH'] = setup_fn + os.path.pathsep + os.environ['PYTHONPATH']
   4.329 +        else:
   4.330 +            env['PYTHONPATH'] = setup_fn
   4.331 +    else:
   4.332 +        # the source is found, let's chdir
   4.333 +        if source is not None and os.path.exists(source):
   4.334 +            os.chdir(os.path.dirname(source))
   4.335 +            # in this case, we want to be sure that PYTHONPATH is unset (not
   4.336 +            # just empty, really unset), else CPython tries to import the
   4.337 +            # site.py that it's in virtualenv_support
   4.338 +            remove_from_env.append('PYTHONPATH')
   4.339 +        else:
   4.340 +            logger.info('No %s egg found; downloading' % project_name)
   4.341 +        cmd.extend(['--always-copy', '-U', project_name])
   4.342 +    logger.start_progress('Installing %s...' % project_name)
   4.343 +    logger.indent += 2
   4.344 +    cwd = None
   4.345 +    if project_name == 'distribute':
   4.346 +        env['DONT_PATCH_SETUPTOOLS'] = 'true'
   4.347 +
   4.348 +    def _filter_ez_setup(line):
   4.349 +        return filter_ez_setup(line, project_name)
   4.350 +
   4.351 +    if not os.access(os.getcwd(), os.W_OK):
   4.352 +        cwd = tempfile.mkdtemp()
   4.353 +        if source is not None and os.path.exists(source):
   4.354 +            # the current working dir is hostile, let's copy the
   4.355 +            # tarball to a temp dir
   4.356 +            target = os.path.join(cwd, os.path.split(source)[-1])
   4.357 +            shutil.copy(source, target)
   4.358 +    try:
   4.359 +        call_subprocess(cmd, show_stdout=False,
   4.360 +                        filter_stdout=_filter_ez_setup,
   4.361 +                        extra_env=env,
   4.362 +                        remove_from_env=remove_from_env,
   4.363 +                        cwd=cwd)
   4.364 +    finally:
   4.365 +        logger.indent -= 2
   4.366 +        logger.end_progress()
   4.367 +        if os.getcwd() != old_chdir:
   4.368 +            os.chdir(old_chdir)
   4.369 +        if is_jython and os._name == 'nt':
   4.370 +            os.remove(ez_setup)
   4.371 +
   4.372 +def file_search_dirs():
   4.373 +    here = os.path.dirname(os.path.abspath(__file__))
   4.374 +    dirs = ['.', here,
   4.375 +            join(here, 'virtualenv_support')]
   4.376 +    if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv':
   4.377 +        # Probably some boot script; just in case virtualenv is installed...
   4.378 +        try:
   4.379 +            import virtualenv
   4.380 +        except ImportError:
   4.381 +            pass
   4.382 +        else:
   4.383 +            dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support'))
   4.384 +    return [d for d in dirs if os.path.isdir(d)]
   4.385 +
   4.386 +def install_setuptools(py_executable, unzip=False):
   4.387 +    _install_req(py_executable, unzip)
   4.388 +
   4.389 +def install_distribute(py_executable, unzip=False):
   4.390 +    _install_req(py_executable, unzip, distribute=True)
   4.391 +
   4.392 +_pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I)
   4.393 +def install_pip(py_executable):
   4.394 +    filenames = []
   4.395 +    for dir in file_search_dirs():
   4.396 +        filenames.extend([join(dir, fn) for fn in os.listdir(dir)
   4.397 +                          if _pip_re.search(fn)])
   4.398 +    filenames = [(os.path.basename(filename).lower(), i, filename) for i, filename in enumerate(filenames)]
   4.399 +    filenames.sort()
   4.400 +    filenames = [filename for basename, i, filename in filenames]
   4.401 +    if not filenames:
   4.402 +        filename = 'pip'
   4.403 +    else:
   4.404 +        filename = filenames[-1]
   4.405 +    easy_install_script = 'easy_install'
   4.406 +    if sys.platform == 'win32':
   4.407 +        easy_install_script = 'easy_install-script.py'
   4.408 +    cmd = [py_executable, join(os.path.dirname(py_executable), easy_install_script), filename]
   4.409 +    if filename == 'pip':
   4.410 +        logger.info('Installing pip from network...')
   4.411 +    else:
   4.412 +        logger.info('Installing %s' % os.path.basename(filename))
   4.413 +    logger.indent += 2
   4.414 +    def _filter_setup(line):
   4.415 +        return filter_ez_setup(line, 'pip')
   4.416 +    try:
   4.417 +        call_subprocess(cmd, show_stdout=False,
   4.418 +                        filter_stdout=_filter_setup)
   4.419 +    finally:
   4.420 +        logger.indent -= 2
   4.421 +
   4.422 +def filter_ez_setup(line, project_name='setuptools'):
   4.423 +    if not line.strip():
   4.424 +        return Logger.DEBUG
   4.425 +    if project_name == 'distribute':
   4.426 +        for prefix in ('Extracting', 'Now working', 'Installing', 'Before',
   4.427 +                       'Scanning', 'Setuptools', 'Egg', 'Already',
   4.428 +                       'running', 'writing', 'reading', 'installing',
   4.429 +                       'creating', 'copying', 'byte-compiling', 'removing',
   4.430 +                       'Processing'):
   4.431 +            if line.startswith(prefix):
   4.432 +                return Logger.DEBUG
   4.433 +        return Logger.DEBUG
   4.434 +    for prefix in ['Reading ', 'Best match', 'Processing setuptools',
   4.435 +                   'Copying setuptools', 'Adding setuptools',
   4.436 +                   'Installing ', 'Installed ']:
   4.437 +        if line.startswith(prefix):
   4.438 +            return Logger.DEBUG
   4.439 +    return Logger.INFO
   4.440 +
   4.441 +def main():
   4.442 +    parser = optparse.OptionParser(
   4.443 +        version=virtualenv_version,
   4.444 +        usage="%prog [OPTIONS] DEST_DIR")
   4.445 +
   4.446 +    parser.add_option(
   4.447 +        '-v', '--verbose',
   4.448 +        action='count',
   4.449 +        dest='verbose',
   4.450 +        default=0,
   4.451 +        help="Increase verbosity")
   4.452 +
   4.453 +    parser.add_option(
   4.454 +        '-q', '--quiet',
   4.455 +        action='count',
   4.456 +        dest='quiet',
   4.457 +        default=0,
   4.458 +        help='Decrease verbosity')
   4.459 +
   4.460 +    parser.add_option(
   4.461 +        '-p', '--python',
   4.462 +        dest='python',
   4.463 +        metavar='PYTHON_EXE',
   4.464 +        help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 '
   4.465 +        'interpreter to create the new environment.  The default is the interpreter that '
   4.466 +        'virtualenv was installed with (%s)' % sys.executable)
   4.467 +
   4.468 +    parser.add_option(
   4.469 +        '--clear',
   4.470 +        dest='clear',
   4.471 +        action='store_true',
   4.472 +        help="Clear out the non-root install and start from scratch")
   4.473 +
   4.474 +    parser.add_option(
   4.475 +        '--no-site-packages',
   4.476 +        dest='no_site_packages',
   4.477 +        action='store_true',
   4.478 +        help="Don't give access to the global site-packages dir to the "
   4.479 +             "virtual environment")
   4.480 +
   4.481 +    parser.add_option(
   4.482 +        '--unzip-setuptools',
   4.483 +        dest='unzip_setuptools',
   4.484 +        action='store_true',
   4.485 +        help="Unzip Setuptools or Distribute when installing it")
   4.486 +
   4.487 +    parser.add_option(
   4.488 +        '--relocatable',
   4.489 +        dest='relocatable',
   4.490 +        action='store_true',
   4.491 +        help='Make an EXISTING virtualenv environment relocatable.  '
   4.492 +        'This fixes up scripts and makes all .pth files relative')
   4.493 +
   4.494 +    parser.add_option(
   4.495 +        '--distribute',
   4.496 +        dest='use_distribute',
   4.497 +        action='store_true',
   4.498 +        help='Use Distribute instead of Setuptools. Set environ variable '
   4.499 +        'VIRTUALENV_USE_DISTRIBUTE to make it the default ')
   4.500 +
   4.501 +    parser.add_option(
   4.502 +        '--prompt=',
   4.503 +        dest='prompt',
   4.504 +        help='Provides an alternative prompt prefix for this environment')
   4.505 +
   4.506 +    if 'extend_parser' in globals():
   4.507 +        extend_parser(parser)
   4.508 +
   4.509 +    options, args = parser.parse_args()
   4.510 +
   4.511 +    global logger
   4.512 +
   4.513 +    if 'adjust_options' in globals():
   4.514 +        adjust_options(options, args)
   4.515 +
   4.516 +    verbosity = options.verbose - options.quiet
   4.517 +    logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
   4.518 +
   4.519 +    if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
   4.520 +        env = os.environ.copy()
   4.521 +        interpreter = resolve_interpreter(options.python)
   4.522 +        if interpreter == sys.executable:
   4.523 +            logger.warn('Already using interpreter %s' % interpreter)
   4.524 +        else:
   4.525 +            logger.notify('Running virtualenv with interpreter %s' % interpreter)
   4.526 +            env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true'
   4.527 +            file = __file__
   4.528 +            if file.endswith('.pyc'):
   4.529 +                file = file[:-1]
   4.530 +            popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env)
   4.531 +            raise SystemExit(popen.wait())
   4.532 +
   4.533 +    if not args:
   4.534 +        print 'You must provide a DEST_DIR'
   4.535 +        parser.print_help()
   4.536 +        sys.exit(2)
   4.537 +    if len(args) > 1:
   4.538 +        print 'There must be only one argument: DEST_DIR (you gave %s)' % (
   4.539 +            ' '.join(args))
   4.540 +        parser.print_help()
   4.541 +        sys.exit(2)
   4.542 +
   4.543 +    home_dir = args[0]
   4.544 +
   4.545 +    if os.environ.get('WORKING_ENV'):
   4.546 +        logger.fatal('ERROR: you cannot run virtualenv while in a workingenv')
   4.547 +        logger.fatal('Please deactivate your workingenv, then re-run this script')
   4.548 +        sys.exit(3)
   4.549 +
   4.550 +    if 'PYTHONHOME' in os.environ:
   4.551 +        logger.warn('PYTHONHOME is set.  You *must* activate the virtualenv before using it')
   4.552 +        del os.environ['PYTHONHOME']
   4.553 +
   4.554 +    if options.relocatable:
   4.555 +        make_environment_relocatable(home_dir)
   4.556 +        return
   4.557 +
   4.558 +    create_environment(home_dir, site_packages=not options.no_site_packages, clear=options.clear,
   4.559 +                       unzip_setuptools=options.unzip_setuptools,
   4.560 +                       use_distribute=options.use_distribute,
   4.561 +                       prompt=options.prompt)
   4.562 +    if 'after_install' in globals():
   4.563 +        after_install(options, home_dir)
   4.564 +
   4.565 +def call_subprocess(cmd, show_stdout=True,
   4.566 +                    filter_stdout=None, cwd=None,
   4.567 +                    raise_on_returncode=True, extra_env=None,
   4.568 +                    remove_from_env=None):
   4.569 +    cmd_parts = []
   4.570 +    for part in cmd:
   4.571 +        if len(part) > 40:
   4.572 +            part = part[:30]+"..."+part[-5:]
   4.573 +        if ' ' in part or '\n' in part or '"' in part or "'" in part:
   4.574 +            part = '"%s"' % part.replace('"', '\\"')
   4.575 +        cmd_parts.append(part)
   4.576 +    cmd_desc = ' '.join(cmd_parts)
   4.577 +    if show_stdout:
   4.578 +        stdout = None
   4.579 +    else:
   4.580 +        stdout = subprocess.PIPE
   4.581 +    logger.debug("Running command %s" % cmd_desc)
   4.582 +    if extra_env or remove_from_env:
   4.583 +        env = os.environ.copy()
   4.584 +        if extra_env:
   4.585 +            env.update(extra_env)
   4.586 +        if remove_from_env:
   4.587 +            for varname in remove_from_env:
   4.588 +                env.pop(varname, None)
   4.589 +    else:
   4.590 +        env = None
   4.591 +    try:
   4.592 +        proc = subprocess.Popen(
   4.593 +            cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
   4.594 +            cwd=cwd, env=env)
   4.595 +    except Exception, e:
   4.596 +        logger.fatal(
   4.597 +            "Error %s while executing command %s" % (e, cmd_desc))
   4.598 +        raise
   4.599 +    all_output = []
   4.600 +    if stdout is not None:
   4.601 +        stdout = proc.stdout
   4.602 +        while 1:
   4.603 +            line = stdout.readline()
   4.604 +            if not line:
   4.605 +                break
   4.606 +            line = line.rstrip()
   4.607 +            all_output.append(line)
   4.608 +            if filter_stdout:
   4.609 +                level = filter_stdout(line)
   4.610 +                if isinstance(level, tuple):
   4.611 +                    level, line = level
   4.612 +                logger.log(level, line)
   4.613 +                if not logger.stdout_level_matches(level):
   4.614 +                    logger.show_progress()
   4.615 +            else:
   4.616 +                logger.info(line)
   4.617 +    else:
   4.618 +        proc.communicate()
   4.619 +    proc.wait()
   4.620 +    if proc.returncode:
   4.621 +        if raise_on_returncode:
   4.622 +            if all_output:
   4.623 +                logger.notify('Complete output from command %s:' % cmd_desc)
   4.624 +                logger.notify('\n'.join(all_output) + '\n----------------------------------------')
   4.625 +            raise OSError(
   4.626 +                "Command %s failed with error code %s"
   4.627 +                % (cmd_desc, proc.returncode))
   4.628 +        else:
   4.629 +            logger.warn(
   4.630 +                "Command %s had error code %s"
   4.631 +                % (cmd_desc, proc.returncode))
   4.632 +
   4.633 +
   4.634 +def create_environment(home_dir, site_packages=True, clear=False,
   4.635 +                       unzip_setuptools=False, use_distribute=False,
   4.636 +                       prompt=None):
   4.637 +    """
   4.638 +    Creates a new environment in ``home_dir``.
   4.639 +
   4.640 +    If ``site_packages`` is true (the default) then the global
   4.641 +    ``site-packages/`` directory will be on the path.
   4.642 +
   4.643 +    If ``clear`` is true (default False) then the environment will
   4.644 +    first be cleared.
   4.645 +    """
   4.646 +    home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
   4.647 +
   4.648 +    py_executable = os.path.abspath(install_python(
   4.649 +        home_dir, lib_dir, inc_dir, bin_dir,
   4.650 +        site_packages=site_packages, clear=clear))
   4.651 +
   4.652 +    install_distutils(home_dir)
   4.653 +
   4.654 +    if use_distribute or os.environ.get('VIRTUALENV_USE_DISTRIBUTE'):
   4.655 +        install_distribute(py_executable, unzip=unzip_setuptools)
   4.656 +    else:
   4.657 +        install_setuptools(py_executable, unzip=unzip_setuptools)
   4.658 +
   4.659 +    install_pip(py_executable)
   4.660 +
   4.661 +    install_activate(home_dir, bin_dir, prompt)
   4.662 +
   4.663 +def path_locations(home_dir):
   4.664 +    """Return the path locations for the environment (where libraries are,
   4.665 +    where scripts go, etc)"""
   4.666 +    # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its
   4.667 +    # prefix arg is broken: http://bugs.python.org/issue3386
   4.668 +    if sys.platform == 'win32':
   4.669 +        # Windows has lots of problems with executables with spaces in
   4.670 +        # the name; this function will remove them (using the ~1
   4.671 +        # format):
   4.672 +        mkdir(home_dir)
   4.673 +        if ' ' in home_dir:
   4.674 +            try:
   4.675 +                import win32api
   4.676 +            except ImportError:
   4.677 +                print 'Error: the path "%s" has a space in it' % home_dir
   4.678 +                print 'To handle these kinds of paths, the win32api module must be installed:'
   4.679 +                print '  http://sourceforge.net/projects/pywin32/'
   4.680 +                sys.exit(3)
   4.681 +            home_dir = win32api.GetShortPathName(home_dir)
   4.682 +        lib_dir = join(home_dir, 'Lib')
   4.683 +        inc_dir = join(home_dir, 'Include')
   4.684 +        bin_dir = join(home_dir, 'Scripts')
   4.685 +    elif is_jython:
   4.686 +        lib_dir = join(home_dir, 'Lib')
   4.687 +        inc_dir = join(home_dir, 'Include')
   4.688 +        bin_dir = join(home_dir, 'bin')
   4.689 +    elif is_pypy:
   4.690 +        lib_dir = home_dir
   4.691 +        inc_dir = join(home_dir, 'include')
   4.692 +        bin_dir = join(home_dir, 'bin')
   4.693 +    else:
   4.694 +        lib_dir = join(home_dir, 'lib', py_version)
   4.695 +        inc_dir = join(home_dir, 'include', py_version)
   4.696 +        bin_dir = join(home_dir, 'bin')
   4.697 +    return home_dir, lib_dir, inc_dir, bin_dir
   4.698 +
   4.699 +
   4.700 +def change_prefix(filename, dst_prefix):
   4.701 +    prefixes = [sys.prefix]
   4.702 +    if hasattr(sys, 'real_prefix'):
   4.703 +        prefixes.append(sys.real_prefix)
   4.704 +    prefixes = map(os.path.abspath, prefixes)
   4.705 +    filename = os.path.abspath(filename)
   4.706 +    for src_prefix in prefixes:
   4.707 +        if filename.startswith(src_prefix):
   4.708 +            _, relpath = filename.split(src_prefix, 1)
   4.709 +            assert relpath[0] == os.sep
   4.710 +            relpath = relpath[1:]
   4.711 +            return join(dst_prefix, relpath)
   4.712 +    assert False, "Filename %s does not start with any of these prefixes: %s" % \
   4.713 +        (filename, prefixes)
   4.714 +
   4.715 +def copy_required_modules(dst_prefix):
   4.716 +    import imp
   4.717 +    for modname in REQUIRED_MODULES:
   4.718 +        if modname in sys.builtin_module_names:
   4.719 +            logger.info("Ignoring built-in bootstrap module: %s" % modname)
   4.720 +            continue
   4.721 +        try:
   4.722 +            f, filename, _ = imp.find_module(modname)
   4.723 +        except ImportError:
   4.724 +            logger.info("Cannot import bootstrap module: %s" % modname)
   4.725 +        else:
   4.726 +            if f is not None:
   4.727 +                f.close()
   4.728 +            dst_filename = change_prefix(filename, dst_prefix)
   4.729 +            copyfile(filename, dst_filename)
   4.730 +            if filename.endswith('.pyc'):
   4.731 +                pyfile = filename[:-1]
   4.732 +                if os.path.exists(pyfile):
   4.733 +                    copyfile(pyfile, dst_filename[:-1])
   4.734 +
   4.735 +
   4.736 +def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
   4.737 +    """Install just the base environment, no distutils patches etc"""
   4.738 +    if sys.executable.startswith(bin_dir):
   4.739 +        print 'Please use the *system* python to run this script'
   4.740 +        return
   4.741 +
   4.742 +    if clear:
   4.743 +        rmtree(lib_dir)
   4.744 +        ## FIXME: why not delete it?
   4.745 +        ## Maybe it should delete everything with #!/path/to/venv/python in it
   4.746 +        logger.notify('Not deleting %s', bin_dir)
   4.747 +
   4.748 +    if hasattr(sys, 'real_prefix'):
   4.749 +        logger.notify('Using real prefix %r' % sys.real_prefix)
   4.750 +        prefix = sys.real_prefix
   4.751 +    else:
   4.752 +        prefix = sys.prefix
   4.753 +    mkdir(lib_dir)
   4.754 +    fix_lib64(lib_dir)
   4.755 +    stdlib_dirs = [os.path.dirname(os.__file__)]
   4.756 +    if sys.platform == 'win32':
   4.757 +        stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs'))
   4.758 +    elif sys.platform == 'darwin':
   4.759 +        stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages'))
   4.760 +    if hasattr(os, 'symlink'):
   4.761 +        logger.info('Symlinking Python bootstrap modules')
   4.762 +    else:
   4.763 +        logger.info('Copying Python bootstrap modules')
   4.764 +    logger.indent += 2
   4.765 +    try:
   4.766 +        # copy required files...
   4.767 +        for stdlib_dir in stdlib_dirs:
   4.768 +            if not os.path.isdir(stdlib_dir):
   4.769 +                continue
   4.770 +            for fn in os.listdir(stdlib_dir):
   4.771 +                if fn != 'site-packages' and os.path.splitext(fn)[0] in REQUIRED_FILES:
   4.772 +                    copyfile(join(stdlib_dir, fn), join(lib_dir, fn))
   4.773 +        # ...and modules
   4.774 +        copy_required_modules(home_dir)
   4.775 +    finally:
   4.776 +        logger.indent -= 2
   4.777 +    mkdir(join(lib_dir, 'site-packages'))
   4.778 +    import site
   4.779 +    site_filename = site.__file__
   4.780 +    if site_filename.endswith('.pyc'):
   4.781 +        site_filename = site_filename[:-1]
   4.782 +    elif site_filename.endswith('$py.class'):
   4.783 +        site_filename = site_filename.replace('$py.class', '.py')
   4.784 +    site_filename_dst = change_prefix(site_filename, home_dir)
   4.785 +    site_dir = os.path.dirname(site_filename_dst)
   4.786 +    writefile(site_filename_dst, SITE_PY)
   4.787 +    writefile(join(site_dir, 'orig-prefix.txt'), prefix)
   4.788 +    site_packages_filename = join(site_dir, 'no-global-site-packages.txt')
   4.789 +    if not site_packages:
   4.790 +        writefile(site_packages_filename, '')
   4.791 +    else:
   4.792 +        if os.path.exists(site_packages_filename):
   4.793 +            logger.info('Deleting %s' % site_packages_filename)
   4.794 +            os.unlink(site_packages_filename)
   4.795 +
   4.796 +    if is_pypy:
   4.797 +        stdinc_dir = join(prefix, 'include')
   4.798 +    else:
   4.799 +        stdinc_dir = join(prefix, 'include', py_version)
   4.800 +    if os.path.exists(stdinc_dir):
   4.801 +        copyfile(stdinc_dir, inc_dir)
   4.802 +    else:
   4.803 +        logger.debug('No include dir %s' % stdinc_dir)
   4.804 +
   4.805 +    if sys.exec_prefix != prefix:
   4.806 +        if sys.platform == 'win32':
   4.807 +            exec_dir = join(sys.exec_prefix, 'lib')
   4.808 +        elif is_jython:
   4.809 +            exec_dir = join(sys.exec_prefix, 'Lib')
   4.810 +        else:
   4.811 +            exec_dir = join(sys.exec_prefix, 'lib', py_version)
   4.812 +        for fn in os.listdir(exec_dir):
   4.813 +            copyfile(join(exec_dir, fn), join(lib_dir, fn))
   4.814 +
   4.815 +    if is_jython:
   4.816 +        # Jython has either jython-dev.jar and javalib/ dir, or just
   4.817 +        # jython.jar
   4.818 +        for name in 'jython-dev.jar', 'javalib', 'jython.jar':
   4.819 +            src = join(prefix, name)
   4.820 +            if os.path.exists(src):
   4.821 +                copyfile(src, join(home_dir, name))
   4.822 +        # XXX: registry should always exist after Jython 2.5rc1
   4.823 +        src = join(prefix, 'registry')
   4.824 +        if os.path.exists(src):
   4.825 +            copyfile(src, join(home_dir, 'registry'), symlink=False)
   4.826 +        copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'),
   4.827 +                 symlink=False)
   4.828 +
   4.829 +    mkdir(bin_dir)
   4.830 +    py_executable = join(bin_dir, os.path.basename(sys.executable))
   4.831 +    if 'Python.framework' in prefix:
   4.832 +        if re.search(r'/Python(?:-32|-64)*$', py_executable):
   4.833 +            # The name of the python executable is not quite what
   4.834 +            # we want, rename it.
   4.835 +            py_executable = os.path.join(
   4.836 +                    os.path.dirname(py_executable), 'python')
   4.837 +
   4.838 +    logger.notify('New %s executable in %s', expected_exe, py_executable)
   4.839 +    if sys.executable != py_executable:
   4.840 +        ## FIXME: could I just hard link?
   4.841 +        executable = sys.executable
   4.842 +        if sys.platform == 'cygwin' and os.path.exists(executable + '.exe'):
   4.843 +            # Cygwin misreports sys.executable sometimes
   4.844 +            executable += '.exe'
   4.845 +            py_executable += '.exe'
   4.846 +            logger.info('Executable actually exists in %s' % executable)
   4.847 +        shutil.copyfile(executable, py_executable)
   4.848 +        make_exe(py_executable)
   4.849 +        if sys.platform == 'win32' or sys.platform == 'cygwin':
   4.850 +            pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe')
   4.851 +            if os.path.exists(pythonw):
   4.852 +                logger.info('Also created pythonw.exe')
   4.853 +                shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe'))
   4.854 +        if is_pypy:
   4.855 +            # make a symlink python --> pypy-c
   4.856 +            python_executable = os.path.join(os.path.dirname(py_executable), 'python')
   4.857 +            logger.info('Also created executable %s' % python_executable)
   4.858 +            copyfile(py_executable, python_executable)
   4.859 +
   4.860 +    if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:
   4.861 +        secondary_exe = os.path.join(os.path.dirname(py_executable),
   4.862 +                                     expected_exe)
   4.863 +        py_executable_ext = os.path.splitext(py_executable)[1]
   4.864 +        if py_executable_ext == '.exe':
   4.865 +            # python2.4 gives an extension of '.4' :P
   4.866 +            secondary_exe += py_executable_ext
   4.867 +        if os.path.exists(secondary_exe):
   4.868 +            logger.warn('Not overwriting existing %s script %s (you must use %s)'
   4.869 +                        % (expected_exe, secondary_exe, py_executable))
   4.870 +        else:
   4.871 +            logger.notify('Also creating executable in %s' % secondary_exe)
   4.872 +            shutil.copyfile(sys.executable, secondary_exe)
   4.873 +            make_exe(secondary_exe)
   4.874 +
   4.875 +    if 'Python.framework' in prefix:
   4.876 +        logger.debug('MacOSX Python framework detected')
   4.877 +
   4.878 +        # Make sure we use the the embedded interpreter inside
   4.879 +        # the framework, even if sys.executable points to
   4.880 +        # the stub executable in ${sys.prefix}/bin
   4.881 +        # See http://groups.google.com/group/python-virtualenv/
   4.882 +        #                              browse_thread/thread/17cab2f85da75951
   4.883 +        original_python = os.path.join(
   4.884 +            prefix, 'Resources/Python.app/Contents/MacOS/Python')
   4.885 +        shutil.copy(original_python, py_executable)
   4.886 +
   4.887 +        # Copy the framework's dylib into the virtual
   4.888 +        # environment
   4.889 +        virtual_lib = os.path.join(home_dir, '.Python')
   4.890 +
   4.891 +        if os.path.exists(virtual_lib):
   4.892 +            os.unlink(virtual_lib)
   4.893 +        copyfile(
   4.894 +            os.path.join(prefix, 'Python'),
   4.895 +            virtual_lib)
   4.896 +
   4.897 +        # And then change the install_name of the copied python executable
   4.898 +        try:
   4.899 +            call_subprocess(
   4.900 +                ["install_name_tool", "-change",
   4.901 +                 os.path.join(prefix, 'Python'),
   4.902 +                 '@executable_path/../.Python',
   4.903 +                 py_executable])
   4.904 +        except:
   4.905 +            logger.fatal(
   4.906 +                "Could not call install_name_tool -- you must have Apple's development tools installed")
   4.907 +            raise
   4.908 +
   4.909 +        # Some tools depend on pythonX.Y being present
   4.910 +        py_executable_version = '%s.%s' % (
   4.911 +            sys.version_info[0], sys.version_info[1])
   4.912 +        if not py_executable.endswith(py_executable_version):
   4.913 +            # symlinking pythonX.Y > python
   4.914 +            pth = py_executable + '%s.%s' % (
   4.915 +                    sys.version_info[0], sys.version_info[1])
   4.916 +            if os.path.exists(pth):
   4.917 +                os.unlink(pth)
   4.918 +            os.symlink('python', pth)
   4.919 +        else:
   4.920 +            # reverse symlinking python -> pythonX.Y (with --python)
   4.921 +            pth = join(bin_dir, 'python')
   4.922 +            if os.path.exists(pth):
   4.923 +                os.unlink(pth)
   4.924 +            os.symlink(os.path.basename(py_executable), pth)
   4.925 +
   4.926 +    if sys.platform == 'win32' and ' ' in py_executable:
   4.927 +        # There's a bug with subprocess on Windows when using a first
   4.928 +        # argument that has a space in it.  Instead we have to quote
   4.929 +        # the value:
   4.930 +        py_executable = '"%s"' % py_executable
   4.931 +    cmd = [py_executable, '-c', 'import sys; print sys.prefix']
   4.932 +    logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
   4.933 +    proc = subprocess.Popen(cmd,
   4.934 +                            stdout=subprocess.PIPE)
   4.935 +    proc_stdout, proc_stderr = proc.communicate()
   4.936 +    proc_stdout = os.path.normcase(os.path.abspath(proc_stdout.strip()))
   4.937 +    if proc_stdout != os.path.normcase(os.path.abspath(home_dir)):
   4.938 +        logger.fatal(
   4.939 +            'ERROR: The executable %s is not functioning' % py_executable)
   4.940 +        logger.fatal(
   4.941 +            'ERROR: It thinks sys.prefix is %r (should be %r)'
   4.942 +            % (proc_stdout, os.path.normcase(os.path.abspath(home_dir))))
   4.943 +        logger.fatal(
   4.944 +            'ERROR: virtualenv is not compatible with this system or executable')
   4.945 +        if sys.platform == 'win32':
   4.946 +            logger.fatal(
   4.947 +                'Note: some Windows users have reported this error when they installed Python for "Only this user".  The problem may be resolvable if you install Python "For all users".  (See https://bugs.launchpad.net/virtualenv/+bug/352844)')
   4.948 +        sys.exit(100)
   4.949 +    else:
   4.950 +        logger.info('Got sys.prefix result: %r' % proc_stdout)
   4.951 +
   4.952 +    pydistutils = os.path.expanduser('~/.pydistutils.cfg')
   4.953 +    if os.path.exists(pydistutils):
   4.954 +        logger.notify('Please make sure you remove any previous custom paths from '
   4.955 +                      'your %s file.' % pydistutils)
   4.956 +    ## FIXME: really this should be calculated earlier
   4.957 +    return py_executable
   4.958 +
   4.959 +def install_activate(home_dir, bin_dir, prompt=None):
   4.960 +    if sys.platform == 'win32' or is_jython and os._name == 'nt':
   4.961 +        files = {'activate.bat': ACTIVATE_BAT,
   4.962 +                 'deactivate.bat': DEACTIVATE_BAT}
   4.963 +        if os.environ.get('OS') == 'Windows_NT' and os.environ.get('OSTYPE') == 'cygwin':
   4.964 +            files['activate'] = ACTIVATE_SH
   4.965 +    else:
   4.966 +        files = {'activate': ACTIVATE_SH}
   4.967 +
   4.968 +        # suppling activate.fish in addition to, not instead of, the
   4.969 +        # bash script support.
   4.970 +        files['activate.fish'] = ACTIVATE_FISH
   4.971 +
   4.972 +        # same for csh/tcsh support...
   4.973 +        files['activate.csh'] = ACTIVATE_CSH
   4.974 +
   4.975 +
   4.976 +
   4.977 +    files['activate_this.py'] = ACTIVATE_THIS
   4.978 +    vname = os.path.basename(os.path.abspath(home_dir))
   4.979 +    for name, content in files.items():
   4.980 +        content = content.replace('__VIRTUAL_PROMPT__', prompt or '')
   4.981 +        content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname)
   4.982 +        content = content.replace('__VIRTUAL_ENV__', os.path.abspath(home_dir))
   4.983 +        content = content.replace('__VIRTUAL_NAME__', vname)
   4.984 +        content = content.replace('__BIN_NAME__', os.path.basename(bin_dir))
   4.985 +        writefile(os.path.join(bin_dir, name), content)
   4.986 +
   4.987 +def install_distutils(home_dir):
   4.988 +    distutils_path = change_prefix(distutils.__path__[0], home_dir)
   4.989 +    mkdir(distutils_path)
   4.990 +    ## FIXME: maybe this prefix setting should only be put in place if
   4.991 +    ## there's a local distutils.cfg with a prefix setting?
   4.992 +    home_dir = os.path.abspath(home_dir)
   4.993 +    ## FIXME: this is breaking things, removing for now:
   4.994 +    #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir
   4.995 +    writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT)
   4.996 +    writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False)
   4.997 +
   4.998 +def fix_lib64(lib_dir):
   4.999 +    """
  4.1000 +    Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y
  4.1001 +    instead of lib/pythonX.Y.  If this is such a platform we'll just create a
  4.1002 +    symlink so lib64 points to lib
  4.1003 +    """
  4.1004 +    if [p for p in distutils.sysconfig.get_config_vars().values()
  4.1005 +        if isinstance(p, basestring) and 'lib64' in p]:
  4.1006 +        logger.debug('This system uses lib64; symlinking lib64 to lib')
  4.1007 +        assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], (
  4.1008 +            "Unexpected python lib dir: %r" % lib_dir)
  4.1009 +        lib_parent = os.path.dirname(lib_dir)
  4.1010 +        assert os.path.basename(lib_parent) == 'lib', (
  4.1011 +            "Unexpected parent dir: %r" % lib_parent)
  4.1012 +        copyfile(lib_parent, os.path.join(os.path.dirname(lib_parent), 'lib64'))
  4.1013 +
  4.1014 +def resolve_interpreter(exe):
  4.1015 +    """
  4.1016 +    If the executable given isn't an absolute path, search $PATH for the interpreter
  4.1017 +    """
  4.1018 +    if os.path.abspath(exe) != exe:
  4.1019 +        paths = os.environ.get('PATH', '').split(os.pathsep)
  4.1020 +        for path in paths:
  4.1021 +            if os.path.exists(os.path.join(path, exe)):
  4.1022 +                exe = os.path.join(path, exe)
  4.1023 +                break
  4.1024 +    if not os.path.exists(exe):
  4.1025 +        logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))
  4.1026 +        sys.exit(3)
  4.1027 +    return exe
  4.1028 +
  4.1029 +############################################################
  4.1030 +## Relocating the environment:
  4.1031 +
  4.1032 +def make_environment_relocatable(home_dir):
  4.1033 +    """
  4.1034 +    Makes the already-existing environment use relative paths, and takes out
  4.1035 +    the #!-based environment selection in scripts.
  4.1036 +    """
  4.1037 +    home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
  4.1038 +    activate_this = os.path.join(bin_dir, 'activate_this.py')
  4.1039 +    if not os.path.exists(activate_this):
  4.1040 +        logger.fatal(
  4.1041 +            'The environment doesn\'t have a file %s -- please re-run virtualenv '
  4.1042 +            'on this environment to update it' % activate_this)
  4.1043 +    fixup_scripts(home_dir)
  4.1044 +    fixup_pth_and_egg_link(home_dir)
  4.1045 +    ## FIXME: need to fix up distutils.cfg
  4.1046 +
  4.1047 +OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],
  4.1048 +                  'activate', 'activate.bat', 'activate_this.py']
  4.1049 +
  4.1050 +def fixup_scripts(home_dir):
  4.1051 +    # This is what we expect at the top of scripts:
  4.1052 +    shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir))
  4.1053 +    # This is what we'll put:
  4.1054 +    new_shebang = '#!/usr/bin/env python%s' % sys.version[:3]
  4.1055 +    activate = "import os; activate_this=os.path.join(os.path.dirname(__file__), 'activate_this.py'); execfile(activate_this, dict(__file__=activate_this)); del os, activate_this"
  4.1056 +    if sys.platform == 'win32':
  4.1057 +        bin_suffix = 'Scripts'
  4.1058 +    else:
  4.1059 +        bin_suffix = 'bin'
  4.1060 +    bin_dir = os.path.join(home_dir, bin_suffix)
  4.1061 +    home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
  4.1062 +    for filename in os.listdir(bin_dir):
  4.1063 +        filename = os.path.join(bin_dir, filename)
  4.1064 +        if not os.path.isfile(filename):
  4.1065 +            # ignore subdirs, e.g. .svn ones.
  4.1066 +            continue
  4.1067 +        f = open(filename, 'rb')
  4.1068 +        lines = f.readlines()
  4.1069 +        f.close()
  4.1070 +        if not lines:
  4.1071 +            logger.warn('Script %s is an empty file' % filename)
  4.1072 +            continue
  4.1073 +        if not lines[0].strip().startswith(shebang):
  4.1074 +            if os.path.basename(filename) in OK_ABS_SCRIPTS:
  4.1075 +                logger.debug('Cannot make script %s relative' % filename)
  4.1076 +            elif lines[0].strip() == new_shebang:
  4.1077 +                logger.info('Script %s has already been made relative' % filename)
  4.1078 +            else:
  4.1079 +                logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)'
  4.1080 +                            % (filename, shebang))
  4.1081 +            continue
  4.1082 +        logger.notify('Making script %s relative' % filename)
  4.1083 +        lines = [new_shebang+'\n', activate+'\n'] + lines[1:]
  4.1084 +        f = open(filename, 'wb')
  4.1085 +        f.writelines(lines)
  4.1086 +        f.close()
  4.1087 +
  4.1088 +def fixup_pth_and_egg_link(home_dir, sys_path=None):
  4.1089 +    """Makes .pth and .egg-link files use relative paths"""
  4.1090 +    home_dir = os.path.normcase(os.path.abspath(home_dir))
  4.1091 +    if sys_path is None:
  4.1092 +        sys_path = sys.path
  4.1093 +    for path in sys_path:
  4.1094 +        if not path:
  4.1095 +            path = '.'
  4.1096 +        if not os.path.isdir(path):
  4.1097 +            continue
  4.1098 +        path = os.path.normcase(os.path.abspath(path))
  4.1099 +        if not path.startswith(home_dir):
  4.1100 +            logger.debug('Skipping system (non-environment) directory %s' % path)
  4.1101 +            continue
  4.1102 +        for filename in os.listdir(path):
  4.1103 +            filename = os.path.join(path, filename)
  4.1104 +            if filename.endswith('.pth'):
  4.1105 +                if not os.access(filename, os.W_OK):
  4.1106 +                    logger.warn('Cannot write .pth file %s, skipping' % filename)
  4.1107 +                else:
  4.1108 +                    fixup_pth_file(filename)
  4.1109 +            if filename.endswith('.egg-link'):
  4.1110 +                if not os.access(filename, os.W_OK):
  4.1111 +                    logger.warn('Cannot write .egg-link file %s, skipping' % filename)
  4.1112 +                else:
  4.1113 +                    fixup_egg_link(filename)
  4.1114 +
  4.1115 +def fixup_pth_file(filename):
  4.1116 +    lines = []
  4.1117 +    prev_lines = []
  4.1118 +    f = open(filename)
  4.1119 +    prev_lines = f.readlines()
  4.1120 +    f.close()
  4.1121 +    for line in prev_lines:
  4.1122 +        line = line.strip()
  4.1123 +        if (not line or line.startswith('#') or line.startswith('import ')
  4.1124 +            or os.path.abspath(line) != line):
  4.1125 +            lines.append(line)
  4.1126 +        else:
  4.1127 +            new_value = make_relative_path(filename, line)
  4.1128 +            if line != new_value:
  4.1129 +                logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename))
  4.1130 +            lines.append(new_value)
  4.1131 +    if lines == prev_lines:
  4.1132 +        logger.info('No changes to .pth file %s' % filename)
  4.1133 +        return
  4.1134 +    logger.notify('Making paths in .pth file %s relative' % filename)
  4.1135 +    f = open(filename, 'w')
  4.1136 +    f.write('\n'.join(lines) + '\n')
  4.1137 +    f.close()
  4.1138 +
  4.1139 +def fixup_egg_link(filename):
  4.1140 +    f = open(filename)
  4.1141 +    link = f.read().strip()
  4.1142 +    f.close()
  4.1143 +    if os.path.abspath(link) != link:
  4.1144 +        logger.debug('Link in %s already relative' % filename)
  4.1145 +        return
  4.1146 +    new_link = make_relative_path(filename, link)
  4.1147 +    logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link))
  4.1148 +    f = open(filename, 'w')
  4.1149 +    f.write(new_link)
  4.1150 +    f.close()
  4.1151 +
  4.1152 +def make_relative_path(source, dest, dest_is_directory=True):
  4.1153 +    """
  4.1154 +    Make a filename relative, where the filename is dest, and it is
  4.1155 +    being referred to from the filename source.
  4.1156 +
  4.1157 +        >>> make_relative_path('/usr/share/something/a-file.pth',
  4.1158 +        ...                    '/usr/share/another-place/src/Directory')
  4.1159 +        '../another-place/src/Directory'
  4.1160 +        >>> make_relative_path('/usr/share/something/a-file.pth',
  4.1161 +        ...                    '/home/user/src/Directory')
  4.1162 +        '../../../home/user/src/Directory'
  4.1163 +        >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')
  4.1164 +        './'
  4.1165 +    """
  4.1166 +    source = os.path.dirname(source)
  4.1167 +    if not dest_is_directory:
  4.1168 +        dest_filename = os.path.basename(dest)
  4.1169 +        dest = os.path.dirname(dest)
  4.1170 +    dest = os.path.normpath(os.path.abspath(dest))
  4.1171 +    source = os.path.normpath(os.path.abspath(source))
  4.1172 +    dest_parts = dest.strip(os.path.sep).split(os.path.sep)
  4.1173 +    source_parts = source.strip(os.path.sep).split(os.path.sep)
  4.1174 +    while dest_parts and source_parts and dest_parts[0] == source_parts[0]:
  4.1175 +        dest_parts.pop(0)
  4.1176 +        source_parts.pop(0)
  4.1177 +    full_parts = ['..']*len(source_parts) + dest_parts
  4.1178 +    if not dest_is_directory:
  4.1179 +        full_parts.append(dest_filename)
  4.1180 +    if not full_parts:
  4.1181 +        # Special case for the current directory (otherwise it'd be '')
  4.1182 +        return './'
  4.1183 +    return os.path.sep.join(full_parts)
  4.1184 +
  4.1185 +
  4.1186 +
  4.1187 +############################################################
  4.1188 +## Bootstrap script creation:
  4.1189 +
  4.1190 +def create_bootstrap_script(extra_text, python_version=''):
  4.1191 +    """
  4.1192 +    Creates a bootstrap script, which is like this script but with
  4.1193 +    extend_parser, adjust_options, and after_install hooks.
  4.1194 +
  4.1195 +    This returns a string that (written to disk of course) can be used
  4.1196 +    as a bootstrap script with your own customizations.  The script
  4.1197 +    will be the standard virtualenv.py script, with your extra text
  4.1198 +    added (your extra text should be Python code).
  4.1199 +
  4.1200 +    If you include these functions, they will be called:
  4.1201 +
  4.1202 +    ``extend_parser(optparse_parser)``:
  4.1203 +        You can add or remove options from the parser here.
  4.1204 +
  4.1205 +    ``adjust_options(options, args)``:
  4.1206 +        You can change options here, or change the args (if you accept
  4.1207 +        different kinds of arguments, be sure you modify ``args`` so it is
  4.1208 +        only ``[DEST_DIR]``).
  4.1209 +
  4.1210 +    ``after_install(options, home_dir)``:
  4.1211 +
  4.1212 +        After everything is installed, this function is called.  This
  4.1213 +        is probably the function you are most likely to use.  An
  4.1214 +        example would be::
  4.1215 +
  4.1216 +            def after_install(options, home_dir):
  4.1217 +                subprocess.call([join(home_dir, 'bin', 'easy_install'),
  4.1218 +                                 'MyPackage'])
  4.1219 +                subprocess.call([join(home_dir, 'bin', 'my-package-script'),
  4.1220 +                                 'setup', home_dir])
  4.1221 +
  4.1222 +        This example immediately installs a package, and runs a setup
  4.1223 +        script from that package.
  4.1224 +
  4.1225 +    If you provide something like ``python_version='2.4'`` then the
  4.1226 +    script will start with ``#!/usr/bin/env python2.4`` instead of
  4.1227 +    ``#!/usr/bin/env python``.  You can use this when the script must
  4.1228 +    be run with a particular Python version.
  4.1229 +    """
  4.1230 +    filename = __file__
  4.1231 +    if filename.endswith('.pyc'):
  4.1232 +        filename = filename[:-1]
  4.1233 +    f = open(filename, 'rb')
  4.1234 +    content = f.read()
  4.1235 +    f.close()
  4.1236 +    py_exe = 'python%s' % python_version
  4.1237 +    content = (('#!/usr/bin/env %s\n' % py_exe)
  4.1238 +               + '## WARNING: This file is generated\n'
  4.1239 +               + content)
  4.1240 +    return content.replace('##EXT' 'END##', extra_text)
  4.1241 +
  4.1242 +##EXTEND##
  4.1243 +
  4.1244 +##file site.py
  4.1245 +SITE_PY = """
  4.1246 +eJzVPP1z2zaWv/OvQOXJUEplOh/dzo5T98ZJnNZ7buJt0mluXY+WkiCJNUWyBGlZe3P3t9/7AECA
  4.1247 +pGS77f5wmkwskcDDw8P7xgMGg8FpUchsLtb5vE6lUDIuZytRxNVKiUVeimqVlPPDIi6rLTyd3cRL
  4.1248 +qUSVC7VVEbaKguDpH/wET8WnVaIMCvAtrqt8HVfJLE7TrUjWRV5Wci7mdZlkS5FkSZXEafIvaJFn
  4.1249 +kXj6xzEIzjMBM08TWYpbWSqAq0S+EJfbapVnYlgXOOfn0V/il6OxULMyKSpoUGqcgSKruAoyKeeA
  4.1250 +JrSsFZAyqeShKuQsWSQz23CT1+lcFGk8k+Kf/+SpUdMwDFS+lpuVLKXIABmAKQFWgXjA16QUs3wu
  4.1251 +IyFey1mMA/DzhlgBQxvjmikkY5aLNM+WMKdMzqRScbkVw2ldESBCWcxzwCkBDKokTYNNXt6oESwp
  4.1252 +rccGHomY2cOfDLMHzBPH73IO4PghC37KkrsxwwbuQXDVitmmlIvkTsQIFn7KOzmb6GfDZCHmyWIB
  4.1253 +NMiqETYJGAEl0mR6VNByfKNX6NsjwspyZQxjSESZG/NL6hEF55WIUwVsWxdII0WYv5XTJM6AGtkt
  4.1254 +DAcQgaRB3zjzRFV2HJqdyAFAietYgZSslRiu4yQDZv0hnhHaPyfZPN+oEVEAVkuJX2tVufMf9hAA
  4.1255 +WjsEGAe4WGY16yxNbmS6HQECnwD7Uqo6rVAg5kkpZ1VeJlIRAEBtK+QdID0WcSk1CZkzjdyOif5E
  4.1256 +kyTDhUUBQ4HHl0iSRbKsS5IwsUiAc4Er3n34Ubw9e31++l7zmAHGMrtcA84AhRbawQkGEEe1Ko/S
  4.1257 +HAQ6Ci7wj4jncxSyJY4PeDUNju5d6WAIcy+idh9nwYHsenH1MDDHCpQJjRVQv/+GLmO1Avr8zz3r
  4.1258 +HQSnu6hCE+dvm1UOMpnFaylWMfMXckbwjYbzbVRUq1fADQrhVEAqhYuDCCYID0ji0myYZ1IUwGJp
  4.1259 +kslRABSaUlt/FYEV3ufZIa11ixMAQhlk8NJ5NqIRMwkT7cJ6hfrCNN7SzHSTwK7zOi9JcQD/ZzPS
  4.1260 +RWmc3RCOihiKv03lMskyRAh5IQgPQhpY3STAifNIXFAr0gumkQhZe3FLFIkaeAmZDnhS3sXrIpVj
  4.1261 +Fl/UrfvVCA0mK2HWOmWOg5YVqVdatWaqvbz3Ivrc4jpCs1qVEoDXU0/oFnk+FlPQ2YRNEa9ZvKpN
  4.1262 +TpwT9MgTdUKeoJbQF78DRU+VqtfSvkReAc1CDBUs8jTNN0Cy4yAQ4gAbGaPsMye8hXfwP8DF/1NZ
  4.1263 +zVZB4IxkAWtQiPwuUAgETILMNFdrJDxu06zcVjJJxpoiL+eypKEeRuwjRvyBjXGuwfu80kaNp4ur
  4.1264 +nK+TClXSVJvMhC1eFlasH1/xvGEaYLkV0cw0bei0xumlxSqeSuOSTOUCJUEv0iu77DBm0DMm2eJK
  4.1265 +rNnKwDsgi0zYgvQrFlQ6i0qSEwAwWPjiLCnqlBopZDARw0DrguCvYzTpuXaWgL3ZLAeokNh8z8D+
  4.1266 +AG7/AjHarBKgzwwggIZBLQXLN02qEh2ERh8FvtE3/Xl84NTzhbZNPOQiTlJt5eMsOKeHZ2VJ4juT
  4.1267 +BfYaa2IomGFWoWu3zICOKOaDwSAIjDu0VeZrbr9NJtM6QXs3mQRVuT0G7hAo5AFDF+9hojQcv1mU
  4.1268 ++RpfW/Q+gj4AvYw9ggNxSYpCso/rMdMrpICrlQvTFM2vw5ECVUlw+ePZu/PPZx/FibhqtNK4rZKu
  4.1269 +YcyzLAbOJKUOfNEatlFH0BJ1V4LqS7wDC03rCiaJepMEyriqgf0A9U9lTa9hGjPvZXD2/vT1xdnk
  4.1270 +p49nP04+nn86AwTBVMjggKaMFq4Gn09FwN/AWHMVaRMZdHrQg9enH+2DYJKoSbEttvAAbB1wYTmE
  4.1271 ++Y5FiA8n2oxOkmyRhyNq/Cv70SesGbTTdHX81bU4ORHhr/FtHAbguDRNeRF/IB7+tC0kdK3gzzBX
  4.1272 +oyCYywXw+41EqRg+JWd0xB2AiNAy18bx1zzJzHt67Q1BQjukHoDDZDJLY6Ww8WQSAmmpQ88HOkTs
  4.1273 +0SKrD6FjsXW7jjQq+CklLEWGXcb4Xw+K8ZT6IRqMotvFNAIZWc9iJbkVTR/6TSaoKCaToR4QJIh4
  4.1274 +HLwclv1QmCaoKMoEnEniFVQcU5Wn+BPho+iRyGA8g6oJF0nHK9FtnNZSDZ1JARGHwxYZUbslijgI
  4.1275 +/IIhmL9m6UajNjUNz0AzIF+ag+oqW5TDzwE4GaAjTOSE0RUHPEwzxPRv7N4TDuDnhahjlWpBYZUk
  4.1276 +Ls8uxctnLw7Rh4BAb26p4zVHs5hktbQPF7BaS1k5CHOvcEzCMHLpskDlhk+P98NcR3Zluqyw0Etc
  4.1277 +ynV+K+eALTKws8riR3oD4TDMYxbDKoIyJSPMSs84azEGfzx7kBY02EC9NUEx62+W/oAjcJkpUB0c
  4.1278 +zRKpdajN9qco89sELfx0q1+CgQL1hmbKeBOBs3Aek6EdAg0BrmeGlNrIEBRYWbOXSHgjSFTx80YV
  4.1279 +RgTuAnXrNX29yfJNNuHw8wTV5HBkWRcFSzMvNmiW4EC8A8MBSOYQTTVEYyjgZwuUrUNAHqYP0wXK
  4.1280 +kkMPgMC6KoqRHFgmvqIpcqiGwyKM0StBwltKNNK3ZgiKbwwxHEj0NrIPjJZASDA5q+CsatBMhrJm
  4.1281 +msHADkl8rruIOO7zAbSoGIGhG2po3MjQ7+oYlLO4cJWS0w9t6OfPn5lt1IqSGojYFCeNdntB5i0q
  4.1282 +tmAKE9AJxg3iFAmxwQY8SgBTK82a4vCjyAt2gWA9L7Vsg+WGkKqqiuOjo81mE+mQPi+XR2px9Je/
  4.1283 +fv31X5+xTpzPiX9gOo606PxWdETv0I2MvjEW6Fuzci1+TDKfGwnWUJIrRP4f4vddncxzcXw4svoT
  4.1284 +ubgxrPi/cT5AgUzMoExloO2gweiJOnwSvVQD8UQM3bbDEXsS2qRaK+ZbXehR5WC7wdOY5XVWhY4i
  4.1285 +VeJLsG4QFs/ltF6GdnDPRpofMFWU06HlgcPn14iBzxmGr4wpnqCWILZAi++Q/kdmm5j8Ga0hkLxo
  4.1286 +ojoh67Zfixnizh8u79Y7dITGzDBRyB0oEX6TBwugbdyVHPxoZxTtnuOMmo9nCIylDwzzaldwiIJD
  4.1287 +uOBajF2pc7gafVSQpg2rZlAwrmoEBQ1u3ZSprcGRjQwRJHo3JsLmhdUtgE6tdJ0Jys0qQAt3nI61
  4.1288 +a7OC4wkhD5yI5/REglN73Hn3jJe2TlPKorR41KMKA/YWGu10Dnw5NADGYlD+NOCWelnOP7QWhdeg
  4.1289 +B1jOiRdksEWHmfCN6wMODgY97NSx+rt6M437QOAiUfuHASeMT3iAUoEwFUOfcXdxuKUtJ5taCO82
  4.1290 +OMRTZpVIotUO2Wrrjl6Z2muXFkmGqtdZo2iW5uAUW6VIfNS8930FClzwcZ8t0wKoydCQw2l0Qs6e
  4.1291 +J3+hbocpq2WNwb2b+0CM1oki44ZkWsF/4FVQToESQEBLgmbBPFTI/In9CSJn56u/7GAPS2hkCLfp
  4.1292 +Li+kYzA0HPP+QCAZdQYEhCADEnZlkTxH1gYpcJizQJ5sw2u5U7gJRqRAzBwDQloGcKeXXnyDTyLc
  4.1293 +dSABRch3lZKF+FIMYPnakvow1f2ncqnJGgydBuQp6HTDiZuKcNIQJ620hM/QfkKC9ieKHDh4Ch6P
  4.1294 +m1x32dwwrc2SgK/u622LFChkSpwMRi6q14YwbgL3ixOnRUMsM4hhKG8gbxvFjDQK7HJr0LDgBoy3
  4.1295 +5u2x9GM3YYF9h2GuXsj1HYR/YZmoWa5CjG87qQv3o7miSxuL7UUyHcAfbwEGo2sPkkx1+gKTLL9j
  4.1296 +kNCDHvZB9yaLWZF5XG6SLCQFpul34i9NBw9LSs/GHX2kaOoIJopZxqN3JQgIbTcegTihJoCgXIZK
  4.1297 +e/1dsHunOLBwufvA85qvjl9ed4k73pXgsZ/+pTq7q8pY4WqlvGgsFLhaXfuNShcmF2dbvWGoN5Qx
  4.1298 +SihzBUGk+PDxs0BCcC51E28fN/WG4RGbe+fkfQzqoNfuJVdrdsQugAhqRWSUo/DxHPlwZB87uT0T
  4.1299 +ewSQRzHMnkUxkDSf/B44+xYKxjicbzNMo7VVBn7g9ddfTXoSoy6SX381uGeUFjH6xH7Y8gTtyLSR
  4.1300 +L3qnbbqUMk7J13A6UVIxa3jHtilGrNAp/NNMdt3jdOLHvDcmo4Hfad6JG83ngOgBUXY+/RViVaXT
  4.1301 +W7dxklJOHtA4PEQ9Z8Jszhz04+NB2o8ypqTAY3k27o2E1NUzWJiQ4/pRdzraLzo1qd+eeNR8ilh1
  4.1302 +UTnQW+jNDpC3Le7u/u2W/V5L/W/SWY8E5M1m0EPAB87B7E7+/58JKyuGppXVqKX1ldyv5w2wB6jD
  4.1303 +HW7OHjekOzRvZi2MM8Fyp8RTFNCnYkNb0pTKw40JgDJnP6MHDi6j3th8U5clb0+SnBeyPMT9urHA
  4.1304 +ahzjaVCRTxfM0XtZISa22YxSo07tRt6nOkOd7LQzCRs/tV9kV7lJkcjsNimhL2iVYfj9hx/Owi4D
  4.1305 +6GGwUz84dx0NlzzcTiHcRzBtqIkTPqYPU+gxXX6/VLVdZZ+gZsvYJCA12bqE7eQdTdzavwb3ZCC8
  4.1306 +/UHeh8WIcLaSs5uJpL1lZFPs6uRg3+BrxMRuOfs1PipeUKESzGSW1kgrdvSwwmxRZzNKx1cS7Lku
  4.1307 +B8XyENox5nTTIo2XYkid55jq0NxI2ZDbuNTeTlHmWIAo6mR+tEzmQv5WxymGkXKxAFxwr0S/inh4
  4.1308 +yniIt7zpzYVpSs7qMqm2QIJY5XqrifbHnYbTLU906CHJuwpMQNwxPxYfcdr4ngk3N+QywaifYMdJ
  4.1309 +YpyHHcxeIHIXPYf3WT7BUSdUxzlmpLrbwPQ4aI+QA4ABAIX5D0Y6U+S/kfTK3c+iNXeJilrSI6Ub
  4.1310 +2ebkcSCU4Qgja/5NP31GdHlrB5bL3Vgu92O5bGO57MVy6WO53I+lKxK4sDZJYiShL1HSzqL3FmS4
  4.1311 +OQ4e5iyerbgd1vdhHR9AFIUJ6IxMcZmrl0nh7SQCQmrb2d+kh02BRcKFg2XOKVcNErkf90x08GgK
  4.1312 +lJ3OVK6hO/NUjM+2q8jE73sURVQONKXuLG/zuIojTy6WaT4FsbXojhsAY9GuN+HcXHY7mXI2sWWp
  4.1313 +Bpf/9en7D++xOYIamN106oaLiIYFpzJ8GpdL1ZWmJtgogB2ppV/3Qd00wIMHZnJ4lAP+7y0VFCDj
  4.1314 +iA1tiOeiAA+Ayn5sM7c4Jgxbz3UVjX7OTM57GydikFWDZlI7iHR6efn29NPpgFJMg/8duAJjaOtL
  4.1315 +h4uPaWEbdP03t7mlOPYBoda5lMb4uXPyaN1wxP021oBtub3PrlsPXjzEYPeGpf4s/62UgiUBQkU6
  4.1316 +2fgYQj04+PlDYUKHPoYRO9Vh7k4OOyv2nSN7joviiH5fmrs9gL+3hjHGBAigXaihiQyaYKql9K15
  4.1317 +3UNRB+gDfb0/HIK1Q692JONT1E6ixwF0KGub7Xb/vH0BNnpKVq/Pvjt/f3H++vL00/eOC4iu3IeP
  4.1318 +Ry/E2Q+fBZUjoAFjnyjGnfgKC1/AsLiHWcQ8h381pjfmdcVJSej19uJC7wys8TgD1reizYngOVfN
  4.1319 +WGico+Gsp32oy10Qo1QHSM65EaoOoXMlGC+t+cyCynUNLB1HmaKzWuvQS58HMueGaBs1AumDxi4p
  4.1320 +GARXNMErqlSuTFRY8o6TPkvTg5S20bYOIaUcVGd32tlvMdl8LzFHneFJ01kr+qvQxTW8jlSRJhDJ
  4.1321 +vQqtLOluWI3RMI5+aDdUGa8+Deh0h5F1Q571TizQar0KeW66/6hhtN9qwLBhsLcw70xSNQLV6GIt
  4.1322 +lQixEe8chPIOvtql12ugYMFwY6nCRTRMl8DsYwiuxSqBAAJ4cgXWF+MEgNBaCT8BfexkB2SOxQDh
  4.1323 +m/X88O+hJojf+pdfeppXZXr4D1FAFCS4ciXsIabb+C0EPpGMxNmHd6OQkaNKUPH3GkvAwSGhLJ8j
  4.1324 +7VQuwzu2k6GS6UKXM/j6AF9oP4Fet7qXsih1937XOEQJeKKG5DU8UYZ+IVYXWdhjnMqoBRqr2y1m
  4.1325 +eErM3fY2nwPxcSXTVBdEn7+9OAPfEQvuUYJ4n+cMhuN8CW7Z6lovPsXWAoUbuvC6RDYu0YWlTf15
  4.1326 +5DXrzcyiyFFvrw7ArhNlP7u9OqnOMk6Ui/YQp82wnJLzCLkZlsOsLHN3txnS2W1GdEfJYcaYXJZU
  4.1327 +NelzBnA0PY05MIKICYv6TbKZ9y6TrDJlcmkyA20KihfU6hhEBUmMJ9eI//KM0715qcyBF3hYbMtk
  4.1328 +uaowpQ6dIyq2x+Y/nH6+OH9P1esvXja+dw+LjikeGHPpwgnWpWHOA764tWbIW5NJH+fqVwgDdRD8
  4.1329 +ab/imogTHqDTj9OL+Kf9ik8cnTjxIM8A1FRdtIUEwwCnW5/0NBLBuNpoGD9u3VmDmQ+GMpJ4wEGX
  4.1330 +F7jz6/KjbdkyKJT9MS8fsVexKDQNh6azWwfV/ug5LgrcXJkP+xvB2z4JM58pdL3pvNlVceV+OrKI
  4.1331 +hx8Bo25rfwxTk9RpqqfjMNsubqHgVlvaXzInY+q0m2UoykDEodt55DJZvyrWzZkDvdrdDjDxjUbX
  4.1332 +SGKvQh/8kg20n+FhYondiVZMRzo7QaYA8xlSHxGpwZNCuwAKhEpOh47kjkdPX3hzdGzC/XPUugss
  4.1333 +5PegCHUBKB0syEvgRPjyG7uP/IrQQlV6LELHX8lkltvqJPxsVuhbPvfn2CsDlMpEsSvjbCmHDGts
  4.1334 +YH7pE3tHIpa0rccxV0mrWkJzN3iodzsYvCsW/bsnBrMWH3Ta3chtWxv51MEGvccPfAhlvAHtXtTV
  4.1335 +kNdq52YBNtdbsMMQkyS/hTvodQ96Ghb6Xb/17OHgh4ll3Etrr1pHW0L7QvuVsxICpkrRZoljhY2H
  4.1336 +6BrmxgaeNFZ4YJ/qihH7u+e8kFPl6sJlFFyo3gwHukEr1B/wyRU+uZdQZXRzsEK/m8tbmebgFkHE
  4.1337 +hYXvv9rC91FkUx29NUF/BoKX28ttP3r0pkHu2BTno+OkCljIKJPVEWLUm5C5B7kGH1z2X3TQEGc3
  4.1338 +5Me++fl8LN68/xH+fy0/QOSD59fG4h+AiXiTlxAB8hlKOtyOpf0Vh3Z5rfCQG0GjzQS+BwBdqkuP
  4.1339 +2rhxoc8c+IcNrBYTWGdZrvnyCUCR50jnihsbbirp4bc56tN1Fo0j17c0A/0SybD7AAQeGjjSLaNV
  4.1340 +tU5RnTupjGZNrwYX52/O3n88i6o75Hbzc+CkOvwqHZyR3sgtcdNqLOyTWY1Prh2/9nuZFj1urY4M
  4.1341 +zWEKjAxFCMFDYaNBvtsgthFAXGJ4L4rtPJ9F2BJ4n89vVRvwc0dOEHivHfaMIMIajvRWV+Ns42Og
  4.1342 +hvilrZcG0JD66DlRT0IonuJBIn4cDfot5VhQ/hn+PL3ZzN30tT4RQhNsY9rMeuh3t6pxxXTW8Fxm
  4.1343 +ItRO7EqYc4JpEqv1dOaeH/uQCX07BSg92o+Qi7hOKyEzEGEKxumaAND97pEvlhPmFrY4dA6K0inp
  4.1344 +Jt4qpyImVmKAow7opDNunFBmD2LlH+IbthB4Fk3UfKgVoBOiFOHkTldVz1Ysxxy0EAF7CgQ2Sfby
  4.1345 +RdghMg/KkeyscTVhnujYMUZLWen584Ph6Op5Y+wpezzzDnzOCrCDLqccgA4tnj59OhD/cb9/wqhE
  4.1346 +aZ7fgOMEsPvCVnFBr3d4FnpydrW6vrd5EwFLzlbyCh5cU5bbPq8zSiHu6UoLIu1fAyPEtQktP5r2
  4.1347 +LUvNybWSN4S5BW8saRPyU5bQHTSYApKocvVVPpgeMgJFLAm6IYzVLElCTifAemzzGs9qYTpQ84u8
  4.1348 +A45PEMwY3+JOFgfDK/QBqbDSco9F50QMCPCACp14NDrsSqeVAM/J5VajOTnPkqo5Z/DM3eTUh7or
  4.1349 +e7WM5isRb1AyzDxaxHCO/Xms2vjA+V4W9WKKfHblJgZbs+TX9+EOrA2Sli8WBlN4aBZplstyZowq
  4.1350 +rlgySyoHjGmHcLgz3ahDBigKelAagIYnwzC3Em3ffmHXxcX0A+33HpqRdJlPZW8p4iROnLWq3aKo
  4.1351 +GZ/SRZaQlm/NlxGM8p7Sz9of8MYSX+jkJxaZe5cpuMfd6kxfksB1Fs3NCQCHLuaxCtKyo6cjnNug
  4.1352 +LHxmWh1uNHcqODXxGEQTbrdJWdVxOtEH+SfouU3sBrjG0x6T2nsA0Pos4Pbn4BAf6pJu8B1MNQzS
  4.1353 +EysyTcn+iVjoJELkHj3yT+kUOfp6Lzw9jqnpZ3wRgKPBseWX5vDKQ1S+OULROX3gYjmm2qNw1K6o
  4.1354 +7LTCfQ5TIm+d7HYc8KghW7B8h31WbPFOHpjWk3lE/0LfkaPLFHBj6tGDp8mUBgv7Co/v76srATH+
  4.1355 +W4OgLBI5P3yiEDvG+Y9C1VAMddxA4REzDOnuCQL5ZWsnzykv5NrfXds3HaBff7UPrKuCewufac/E
  4.1356 +V8v6aJtbidxs2uDnwHrEK3C6UW/MzWFkrZb43CbqEDaI9qy5qVdpH5mB1w+f8p4JP2BHNMTBNHe4
  4.1357 +8rqPVha/faRqGgW/i0q6Vz+t0AnGUtFVzG9QmdXFsQ0V+TBfRmn2oVtAhJ/qpre0Psa7j4jRq5tw
  4.1358 +3/S5/7656xaBnbnZP+vM3T9C49JA993NL300YAddE+JBVbkWo8mfI7pjvbXbn6LSn4W9hZEzVcSD
  4.1359 +GrWxZsl1PHO/Y4HBIV/i6B6HClyQZtVbc+qcD2uzc5eTu9zMm6n43J6QpB3yuWYvNud0pc+Ea64m
  4.1360 +crlUkxhvhJqQD0j1AR3jbryKd3QbkIzV1jgDeOcCgDCsoiu53GJNWHXwM/lmSt5edw7XCxqaitCc
  4.1361 +qjaVzDm2154HgIs4pqf+JnPEZWmDVGI2RtVlUYKzNtD3F/K+b1+pXAPUxJfrWN0Y1E2Psb7ODofg
  4.1362 +YgNzhIozCewAetQBQvDJCudmF67znEzsO+CXZ81R0WRsGUJm9VqWcdXckuDvLyXiW2cEOjiHC+xE
  4.1363 +kI3YtTjFRSyx/OEghTGc/f6ldo4832/P+dCRVWkPZyvqoZMTjzl66ki54ebkzt6S5N7OMadrMSle
  4.1364 +5Ns1hG3WcJ+9GQKWwlz5Q4pQh3T8Vl9DwvfTcc4Jq+ocPgK5d4+t+NWNVmexw2DRcJ65iqF77wSe
  4.1365 +fCRD23edVIcLuhdH+czQjO/rDcssnd2EHY0tFU+4Ra/iaUYbNYEOFiLdE+j4xaaPDHQ8+A8MdPTl
  4.1366 +X2BNND5aH/SWn94TEbGacG/SahgB+kyASLhh0rqHydjDoVvMCeFKcjewl1GyznROiBgzgRzZvWKF
  4.1367 +QPCNWcqtfPNutDHj9kUivnTR4+8uPrw+vSBaTC5P3/zn6Xe0zY9ZvZbNenAkmOWHTO1Dr6zQjQr1
  4.1368 +1mzf4A22PVfTcW28htB539nW6oHQfw6ib0Hbisx9vatDp5682wkQ3z/tFtRdKrsXcsf50rXL7oZs
  4.1369 +q/4v0E+5WMv8cvbWzCOTU2ZxaBLG5n2T49My2kmB7Fo4p2yqq060U6ovM9uRnhnZ4j1aAUztIX/Z
  4.1370 +zJ6pxLb5I3ZU2leEU8UhnmIxNwGAFM6kcyEV3UXFoCr/LvISlF2MOxTsMI7tvZ7UjrOYyl5Yi7sU
  4.1371 +MxkZgnjHSAbd+bnCPpfpDioEASs8fd0SI2L0n877272yJ0pcHdKBtUNUNtf2F66ZdnJ/TnBHrLL3
  4.1372 +liiz5Y27AdB4UafuLpft0+lAzh8lTfOFUyENmu8I6NyIpwL2Rp+JFeJ0K0KIEvVWDhZdER31nUMO
  4.1373 +8mg3HewNrZ6Jw13HmdzjPEI8391w3joxpHu84B7qnh6qNodGHAuMdT+7zimJbwkyZ90FXVTiOR+4
  4.1374 +26Ovx4Svt1fPj23KFvkdX7vXYCDtB45hv2pOBuy9GsvpTbxSjqn+A4uNRm3w1wOHNRdid4DTqXPe
  4.1375 +EQSZ7TiGNPDe99dGmB7enb2DNqKW745hQmL4RI1oUk5luMbdPhl1JtuorC4MLnK/H0ZH+wEohNLv
  4.1376 +m+CHb2MB9fxMx4PTmu4TtA4nHg115IEKHXxe4B7G62uwa3eno2kP6k4l//agADdo855ebxBr9hq4
  4.1377 +lZfo2G0L2jNveGCH7edDfv39nz+gf7ckxnZ/sc+htq1e9h4sYScWi6hw87pFIfM4AusCCnNIahrr
  4.1378 +b42E4+H9howONzVTQ65Ah4/qsvCuUAosyImdaMtvjUHwf71Zz9M=
  4.1379 +""".decode("base64").decode("zlib")
  4.1380 +
  4.1381 +##file ez_setup.py
  4.1382 +EZ_SETUP_PY = """
  4.1383 +eJzNWmuP28YV/a5fwShYSIJlLt8PGXKRJi5gIEiDPAoU9lY7zxVrilRJyhu1yH/vmeFDJLVU2iIf
  4.1384 +ysDZXXJ45z7PuXekL784nqt9ns3m8/kf87wqq4IcjVJUp2OV52lpJFlZkTQlVYJFs/fSOOcn45lk
  4.1385 +lVHlxqkUw7XqaWEcCftEnsSirB+ax/Pa+PuprLCApScujGqflDOZpEK9Uu0hhByEwZNCsCovzsZz
  4.1386 +Uu2NpFobJOMG4Vy/oDZUa6v8aOSy3qmVv9nMZgYuWeQHQ/xzp+8byeGYF5XScnfRUq8b3lquriwr
  4.1387 +xD9OUMcgRnkULJEJMz6LooQT1N6XV9fqd6zi+XOW5oTPDklR5MXayAvtHZIZJK1EkZFKdIsulq71
  4.1388 +pgyreG6UuUHPRnk6HtNzkj3NlLHkeCzyY5Go1/OjCoL2w+Pj2ILHR3M2+0m5SfuV6Y2VRGEUJ/xe
  4.1389 +KlNYkRy1eU1UtZbHp4LwfhxNlQyzxnnluZx98+5PX/387U+7v7z74cf3f/7O2BpzywyYbc+7Rz//
  4.1390 +8K3yq3q0r6rj5v7+eD4mZp1cZl483TdJUd7flff4r9vtfm7cqV3Mxr8fNu7DbHbg/o6TikDgv3TE
  4.1391 +Fpc3XmNzar8+nh3TNcXT02JjLKLIcRiRsWU7vsUjL6JxHNBQOj4LRMDIYn1DitdKoWFMIuJZrvB8
  4.1392 +y5GURr4QrrRjzw5dn9EJKc5QFz/ww9CPeUQCHknmeVZokZhboRM6PI5vS+l08WAAibgdxNyhIghs
  4.1393 +SVyHBMJ3hCcjZ8oid6gLpa7NLMlCN45J4PphHIc+IzyWPrECO7oppdPFjUjEcJcHgnHHcbxQ2mEs
  4.1394 +Q06CIJaETUjxhroEjuX5xPEE94QtKAtDKSw3JsQTgQyFf1PKxS+MOsSOfOgRccKkpA63oY/lUpfa
  4.1395 +zHtZChvlC3WlQ33fjXmAuIYy9AgPY9uBIBJb0YRFbJwvsIcLDk8GIXe4I6WwPcuK3cCTDvEmIs1s
  4.1396 +a6gMgzscQn3uEsvxA88PEB9mu5FlkdCKrdtiOm38kONFxCimkRWGDvNj4rsk8lyX+JxPeqYW47di
  4.1397 +uPACwiL4Mg5ZFPt+6AhfRD7SUdCIhbfFBJ02kUAlESGtAA5ymAg824M0B0bC4RPRBqgMfeNQIghq
  4.1398 +2HY53kcZOZEIKfGpT6ARF7fFXCLFAzeWMbUgzGOe48Wh5XpcMEcwizmTkbKHvgk8FnvSpTIkIbLQ
  4.1399 +FSxyhUUdhDv0YurcFtP5hkoSO7ZlUY4wcdQEJAnOXQQ+8KwomBAzwhlpWYFHZUCIQ0NuQS141kNi
  4.1400 +W5EdMmcqUCOcCezAjh0hmOtLLxSImh0wHhDbgVQnnJIywhlpRwAogC+XSBXi+DGLIUXaPKRhJCfQ
  4.1401 +io1wRliCh14QOSyOIyppCE9HFrLXQsxDeyrY7jBIhAppB5JzGOb7vu1Fns1C4BePozjwp6SM0Ipa
  4.1402 +NLZdmzBCXceCM4BzofQ85gMoQlvelNJZhCSR2DPgnqTSRUVRGXsBs+AqoJ6YShhvaFGk0BrA7zqM
  4.1403 +05iFDmXSA3w5gXQiIqfQyh9aJEQseWRBHRQkMla6ApjuhwAMHtnBVKT9oUVEAqu4BKvYoWULAeeG
  4.1404 +ICefMhAeCaZQxh/FKOKuDAAIHmOERKHtIXG4G1LGuMt9PiElGFqEgonA8pFtB2CiKPJCByLAmL4X
  4.1405 +o7SngDMYsRvzAyL9kMK/6B5QDYEFQzzPRYH5ZAobgqFF1JERCX0HZA/YpS5I2kKoufAlWgnfnZAS
  4.1406 +juDOQoxkTDhzSWD7wrdtH2WIliICBE7mSzhiAhLJ2PfAAhxYbkkahEza0kEY8MiZqoBwaJEHjiXA
  4.1407 +W4mWAQXouZ5t25KLyLXxL5zSJRp1Q5bqhZwYHok5+EOlIAA8ci3VWFm3pXQWMUrcCNiAnsOLXGap
  4.1408 +nEW2wdkMzDJJA9HQIjt07BAgh0DHnNm+5ccW8SPqCtR57E9FOh5aBN2ZZ6GZsZWHqRcHwmOSCiuC
  4.1409 +rcyainQ8QgYkGRo7cKsbRTwAOhEhrADgxQLXm+rvGimdRVIgtK7wiR1S22EIE/M9m4bgXjC/mGKS
  4.1410 +eMhHjKBsbKlQkziCA5js2AWzhdSPHfQ4kPLrrDcRYLwpZ1Vx3tQD156U+zSh7byF3n0mfmECo8Z7
  4.1411 +feedGomatXjYXzfjQhq7zyRN0O2LHW4todMuwzy4NtQAsNpoAxJptPfVzNiOB/VDdfEEs0WFcUGJ
  4.1412 +0C+ae/FLfRfzXbsMcpqVX2w7KR9a0Q8XeerC3IVp8O1bNZ2UFRcF5rrlYIW65sqkxoJmPrzDFEYw
  4.1413 +hvEvDGP5fV6WCU174x9GOvx9+MNqfiXsrjNz8Gg1+EvpI35JqqVT3y8Q3CLT7qodOhoO9aJmvNqO
  4.1414 +hrl1p9aOklJsewPdGpPiDqPqNi9NdirwW51M3QtcpOS8tf1ZEySMjV+dqvwAPzBMl2eMohm/78zu
  4.1415 +nRSouf5APiGWGJ4/w1VEOQjOU6YdSbWvx/nHRulHo9znp5SraZbUvu5Layfz7HSgojCqPakMDMKd
  4.1416 +YC1LTcCZ8q4hMfV2Sp0yrl8RxuPAEY+GGmmXz/uE7dvdBbRWRxO1PGNxv1iZULL20qPaUsnpHWPs
  4.1417 +RTE4IHlOMHPTSyYIvkZG1gmuVc5y+CMtBOHni/rY473sqafdrrdrzia0mKrRUkujQqvSOESfWLA8
  4.1418 +42Xtm1aNI0GiKKfCI6qskipB6LKn3nlGHfHG/jwT+jyhPhvhtV5wap4qH754PqK0bA4bRCNMn+UU
  4.1419 ++Qk7iVqVus6IcRBlSZ5EfcBxKbrHR50vBUlKYfx4LitxePeL8ldWByIzSIV79ckGoQpalPEqBZUx
  4.1420 +9amH2Wao/vlMyl2NQrB/ayyOn552hSjzU8FEuVAIo7Y/5PyUilKdkvQAdPy4rglUHUceNG5bri5I
  4.1421 +olJueymaXl02HhuVYFt261GhXTCgLRITnhVFtbTWapMeyDVA3e30pn+6Q9tjvl0TmJ0G5q2SUQcI
  4.1422 +wD6WNXCQfvgCwncvtYDUd0jz6HqHgWizSa7l/KLx2+38VeOq1ZtGdl+FoYC/1Cu/zjOZJqyCazZ9
  4.1423 +9O9H/r9F+/lP+0v2T+T78u32rlx1tdzWsD7K/JgNAX/OSLaoVEl1JQLMUMd3ukaa4zpVLacsQyqb
  4.1424 +xvepQIa0y6/kqRpSpQwAErCl1VAmRQlHnEpVDgtIOLehN17/3FN+YY7kfcw+ZsuvT0UBaYDzWsBd
  4.1425 +MeKtFVjrksvCJMVT+cF6uM1ZOn5pKYYxQKIPw7nuV9qHUZ0+qFe+hLUayfNPA1Ev5eB01nyToCQS
  4.1426 +elIM/l1e/SkHL9zO55ppXyrr35tuVfGjPAc8+80LpKrLmFxIwUhzVrckGj5rG5KqPiHWLcb/KcnW
  4.1427 +EK0+A2hJ9rc4Vt1Tu14TbI37jxfOnODFvGbDlgwVqbDqRNKLEQ3JDImk/YihANdQB9m6RwqldZ61
  4.1428 +/erW6IHZ67sSvfddqVrveb9wRkfgda5Cbp87lM+MV8MWsSSfBbTfoiWvSeHveZItWwppl9biyoIp
  4.1429 +cbpP/g5s3rbWCqra11GkZVUua7GrjSqwrz7niUqgoyCKL1t1yq4+BniuLp2KHIKUN8rWS2n+NFil
  4.1430 +mnEVl+G76sJK85kU2VL5+fXvd9WfkDTA2iB5+VKW3+mUUJ+cLMVnkak/YM4Rys72Ij2qvu99nW29
  4.1431 +3qNLFTQnKv/VZztL5YoZKGFtAF1m6tYB5ZwJOBKvoA5V5wuEFs8KjwnG2bLUb/c5QCO4OWu2BHQ3
  4.1432 +Pc5lR6jM22w2Z7MlQExslIe1mANhe9Vu8VzUxLRHeKFE9ZwXn5pN18axZpecVqT5XE4hhUaJu3I2
  4.1433 +UygCDzDdtesFkHypxKZyCtGwVd8Ac/V7RhFJsb5KmR7oXjVUOsvWqpquXkNHoZO1StRk2TROqRDH
  4.1434 +N/WP5aj3GmZnC8OaF8u53mLEe7rkGnww8TM/imx5texL4wc0/ffPRVIBfBBj+Fe328DwT2v10eCz
  4.1435 +ip5qF1ihyhDQyPKiOOnkSMVImI57Pz1UF14Jvb7FxPZqPmabGsJhgKkGkuVqqHGNItqaGivW82c6
  4.1436 +hzvxwNR21GN49xKGQTUUbsYQgA02eheW5qVYrq4goqw2Wmj/ecNmLWhBwVT90sLW7D+5FH8fkOlL
  4.1437 +NCyf11OMfeHc97c+NNUc+w6tVbOqJYiXmunRh9G3Oul6eOiw+kriZc3tAUNP6tZ1SzYcIwZThI6Z
  4.1438 +Ko3e7MDywwGGmoMesj3OIc1A1l5NjLSLU3CB9vPqlTpteVjpNH0Wi0KntTAUjf9mqihLlZ9HXKXU
  4.1439 +vuYQLDplmAA/LTuzhg1n0m/czd2u8dZuZ2wxElqmZdqL/3pE+CsAXoOrmotpmacCtToxGrdNP8ik
  4.1440 +buyvGvpCHPLPGm91JOrvPOgJGMxRAXrT38DdUac+2ZI3RfWPYbPSm7z63c71MPgfDHT4eaP/Hk1t
  4.1441 +m+ls/59T8laZdYJ/U8pVNr9Ud225PQxndu1sa4XEh1WK/RE4pjNFPXk5Q9Uuv5MDOvW15jemsDrN
  4.1442 +5z9etUXzdYsoc4DgkyaiQh3/IgnRJF0Sev6CvMXyB7RT8/bbOebxPJw+5/X3bq6/mmKuFs2x5rHj
  4.1443 +p3aEKS/w/LN+aqgSoackrV7X58QQ+aSGu7NC5H4WF838o3qt9ly5E3txiO65L921+lOtWF66ai2k
  4.1444 +5UJNmouCLi7PumNm9e5Dc0QtW1J98ZhadmRXj4A1RX+Yqz/uig3+rYEVGB+aTrNuyNqNTJDvoVyu
  4.1445 +HrqXzRIWd9R5VEPFfF5PCjVJ9x2DCGCErNqJQX+faNveNZ9EVRetur/sT+c73THsdk3Wdy5pZKwN
  4.1446 +7ZY3TUvUOuDN2NgDqTANbqGnWQpSsP1y/jHrfx/oY7b88LdfH16tfp3r9mTVH2P02z0segGxQeT6
  4.1447 +G1mpIRQKfDG/LtIWEWtV8f8PGy3Y1K330l49YAzTjnyln9YPMbri0ebhZfMXz01OyKY96lTvOWAG
  4.1448 +M1o/breL3U4V7G636D4FSZVEqKlr+K2j6bD9+4P9gHdev4az6lLp0VevdrrlzubhJV7UGHGRqRbV
  4.1449 +178BYnMUkw==
  4.1450 +""".decode("base64").decode("zlib")
  4.1451 +
  4.1452 +##file distribute_setup.py
  4.1453 +DISTRIBUTE_SETUP_PY = """
  4.1454 +eJztG2tz2zbyu34FTh4PqYSi7TT3GM+pM2nj9DzNJZnYaT8kHhoiIYk1X+XDsvrrb3cBkCAJyc61
  4.1455 +dzM3c7qrIxGLxWLfuwCP/lTs6k2eTabT6Xd5Xld1yQsWxfBvvGxqweKsqnmS8DoGoMnliu3yhm15
  4.1456 +VrM6Z00lWCXqpqjzPKkAFkdLVvDwjq+FU8lBv9h57JemqgEgTJpIsHoTV5NVnCB6+AFIeCpg1VKE
  4.1457 +dV7u2DauNyyuPcaziPEoogm4IMLWecHylVxJ4z8/n0wYfFZlnhrUBzTO4rTIyxqpDTpqCb7/yJ2N
  4.1458 +dliKXxsgi3FWFSKMV3HI7kVZATOQhm6qh98BKsq3WZLzaJLGZZmXHstL4hLPGE9qUWYceKqBuh17
  4.1459 +tGgIUFHOqpwtd6xqiiLZxdl6gpvmRVHmRRnj9LxAYRA/bm+HO7i99SeTa2QX8TekhRGjYGUD3yvc
  4.1460 +SljGBW1PSZeoLNYlj0x5+qgUE8W8vNLfql37tY5Tob+vspTX4aYdEmmBFLS/eUk/Wwk1dYwqI0eT
  4.1461 +fD2Z1OXuvJNiFaP2yeFPVxcfg6vL64uJeAgFkH5Jzy+QxXJKC8EW7F2eCQObJrtZAgtDUVVSVSKx
  4.1462 +YoFU/iBMI/cZL9fVTE7BD/4EZC5s1xcPImxqvkyEN2PPaaiFK4FfZWag90PgqEvY2GLBTid7iT4C
  4.1463 +RQfmg2hAihFbgRQkQeyF/80fSuQR+7XJa1AmfNykIquB9StYPgNd7MDgEWIqwNyBmBTJdwDmmxdO
  4.1464 +t6QmCxEK3OasP6bwOPA/MG4YHw8bbHOmx9XUYccIOIJTMMMhtenPHQXEOviiVqxuhtLJK78qOFid
  4.1465 +C98+BD+/urz22IBp7Jkps9cXb159ensd/HTx8ery/TtYb3rq/8U/ezlthz59fIuPN3VdnJ+cFLsi
  4.1466 +9qWo/LxcnygnWJ1U4KhCcRKddH7pZDq5urj+9OH6/fu3V8GbVz9evB4sFJ6dTScm0Icffwgu3715
  4.1467 +j+PT6ZfJP0XNI17z+U/SHZ2zM/908g786LlhwpN29LiaXDVpysEq2AN8Jv/IUzEvgEL6PXnVAOWl
  4.1468 ++X0uUh4n8snbOBRZpUBfC+lACC8+AIJAgvt2NJlMSI2Vr3HBEyzh35m2AfEAMSck5ST3LodpsE4L
  4.1469 +cJGwZe1N/PQuwu/gqXEc3Ia/5WXmOhcdEtCB48rx1GQJmCdRsI0AEYh/LepwGykMrZcgKLDdDcxx
  4.1470 +zakExYkI6cL8vBBZu4sWJlD7UFvsTfbDJK8EhpfOINe5IhY33QaCFgD8idw6EFXweuP/AvCKMA8f
  4.1471 +JqBNBq2fT29m441ILN1Ax7B3+ZZt8/LO5JiGNqhUQsMwNMZx2Q6y161uOzPTnWR53XNgjo7YsJyj
  4.1472 +kDsDD9ItcAU6CqEf8G/BZbFtmcPXqCm1rpjJiW8sPMAiBEEL9LwsBRcNWs/4Mr8XetIqzgCPTRWk
  4.1473 +5sy0Ei+bGB6I9dqF/zytrPAlD5B1/9fp/wGdJhlSLMwYSNGC6LsWwlBshO0EIeXdcWqfjs9/xb9L
  4.1474 +9P2oNvRojr/gT2kgeqIayh3IqKa1qxRVk9R95YGlJLCyQc1x8QBLVzTcrVLyGFLUy/eUmrjO93mT
  4.1475 +RDSLOCVtZ71GW1FWEAHRKod1VTrstVltsOSV0BszHkci4Tu1KrJyqAYK3unC5Py4mhe748iH/yPv
  4.1476 +rIkEfI5ZRwUGdfUDIs4qBx2yPDy7mT2dPcosgOB2L0bGvWf/+2gdfPZwqdOrRxwOAVLOhuSDPxRl
  4.1477 +7Z56rJO/yn77dY+R5C911acDdEDp94JMQ8p7UGOoHS8GKdKAAwsjTbJyQ+5ggSrelBYmLM7+7IFw
  4.1478 +ghW/E4vrshGtd005mXjVQGG2peSZdJQvqzxBQ0VeTLolDE0DEPzXNbm35VUguSTQmzrF3ToAk6Ks
  4.1479 +raIkFvmb5lGTiAorpS/tbpyOK0PAsSfu/TBE01uvDyCVc8MrXtel2wMEQwkiI+hak3CcrThoz8Jp
  4.1480 +qF8BD0GUc+hqlxZiX1nTzpS59+/xFvuZ12OGr8p0d9qx5NvF9LlabWYha7iLPj6VNn+fZ6skDuv+
  4.1481 +0gK0RNYOIXkTdwb+ZCg4U6vGvMfpEOogI/G3JRS67ghiek2enbYVmT0Hozfjfrs4hoIFan0UNL+H
  4.1482 +dJ0qmS/ZdIwPWykhz5wa601l6oB5u8E2AfVXVFsAvpVNhtHFZx8SAeKx4tOtA87SvERSQ0zRNKGr
  4.1483 +uKxqD0wT0FinO4B4p10Om38y9uX4Fvgv2ZfM/b4pS1gl2UnE7LicAfKe/xc+VnGYOYxVWQotrt0X
  4.1484 +/TGRVBb7AA1kA5Mz7PvzwE/c4BSMzNTYye/2FbNfYw1PiiH7LMaq1202A6u+y+s3eZNFv9toHyXT
  4.1485 +RuIo1TnkroKwFLwWQ28V4ObIAtssCsPVgSj9e2MWfSyBS8Ur5YWhHn7dtfhac6W42jYSwfaSPKTS
  4.1486 +hdqcivFxLTt3GVTyMim8VbTfsmpDmdkS25H3PIl72LXlZU26FCVYNCdTbr0C4cL2HyW91DFp+5Cg
  4.1487 +BTRFsNseP24Z9jhc8BHhRq8uskiGTezRcuacODOf3Uqe3OKKvdwf/IsohU4h236XXkVEvtwjcbCd
  4.1488 +rvZAHdYwzyLqdRYcA/1SrNDdYFszrBuedB1X2l+NlVTtazH8RxKGXiwioTYlVMFLikIC29yq31wm
  4.1489 +WFZNDGu0xkoDxQvb3Hr9W4DqgK2fXnLsYxm2/g0doJK+bGqXvVwVBcmet1hk/sfvBbB0TwquQVV2
  4.1490 +WYaIDvalWquGtQ7yZol2do48f3Wfx6jVBVpu1JLTZTijkN4WL631kI+vph5uqe+yJVGKS+5o+Ih9
  4.1491 +FDw6odjKMMBAcgaksyWY3J2HHfYtKiFGQ+laQJPDvCzBXZD1DZDBbkmrtb3EeNZRC4LXKqw/2JTD
  4.1492 +BKEMQR94NMioJBuJaMksj023y+kISKUFiKwbG/lMJQlYy5JiAAG6RB/AA35LuINFTfiuc0oShr0k
  4.1493 +ZAlKxqoSBHddgfda5g/uqslC9GbKCdKwOU7tVY89e3a3nR3IimXzv6tP1HRtGK+1Z7mSzw8lzENY
  4.1494 +zJmhkLYly0jtfZzLVtKozW5+Cl5Vo4HhSj6uA4IeP28XeQKOFhYw7Z9X4LELlS5YJD0hsekmvOEA
  4.1495 +8OR8fjhvvwyV7miN6In+UW1Wy4zpPswgqwisSZ0d0lR6U2+VohNVAfoGF83AA3cBHiCru5D/M8U2
  4.1496 +Ht41BXmLlUysRSZ3BJFdByTyluDbAoVDewREPDO9BnBjDLvQS3ccOgIfh9N2mnmWntarPoTZLlW7
  4.1497 +7rShm/UBobEU8PUEyCYxNgTkDIhimc+ZmwBD2zq2YKncmuadPRNc2fwQ6fbEEAOsZ3oXY0T7JjxU
  4.1498 +1myzCk27uCHvDR4rVKM9SwSZ2OrIjE8hyjr++7ev/eMKj7TwdNTHP6PO7kdEJ4MbBpJc9hQliRqn
  4.1499 +avJibYs/Xduo2oB+2BKb5veQLINpBGaH3C0SHooNKLvQnepBGI8r7DWOwfrUf8ruIBD2mu+QeKk9
  4.1500 +GHP369cK646e/8F0VF8IMBrBdlKAanXa7Kt/XZzrmf2YZ9gxnGNxMHT3evGRt1yC9O9Mtqz65VHH
  4.1501 +ga5DSim8eWhurjtgwGSkBSAn1AKRCHkkmzc1Jr3oPbZ819mcrnOGCZvBHo9J1VfkDySq5huc6Jy5
  4.1502 +shwgO+jBSlfViyCjSdIfqhkes5xXqs624ujIt3fcAFPgQxflsT41VmU6AsxblojaqRgqfut8h/xs
  4.1503 +FU3xG3XNNVt43qD5p1r4eBMBvxrc0xgOyUPB9I7Dhn1mBTKodk1vM8Iyjuk2vQSnKhv3wFZNrOLE
  4.1504 +nja6c9Vd5ImMNoEz2EnfH+/zNUPvvA9O+2q+gnS6PSLG9RVTjACGIO2NlbZt3dpIx3ssVwADnoqB
  4.1505 +/09TICLIl7+43YGjr3vdBZSEUHfJyPZYl6Hn3CTdXzOl53JNckElLcXUY27YImzNHN1YGLsg4tTu
  4.1506 +nngEJqcilfvkUxNZEXYbVZHYsCJ1aFN1fhAW+NLTOXffVQFP0vYVTm9Aysj/aV6OHaDV80jwA35n
  4.1507 +6MO/R/nLSD6a1aVErYM8nBZZ3ScB7E+RJKvqNifazypDRj5McIZJyWAr9cbgaLcV9fixrfTIMDpl
  4.1508 +Q3k9vr/HTGzoaR4Bn/Xy+TbodTndkQolEIHCO1SlGH/Z8uu9Cioz4IsffpijCDGEgDjl969Q0HiU
  4.1509 +wh6Ms/tiwlPjquHbu9i6J9kH4tO7lm/9RwdZMXvEtB/l3H/FpgxW9MoOpS32ykMNav2Sfco2oo2i
  4.1510 +2Xeyj7k3nFlO5hRmatYGRSlW8YOrPX0XXNogR6FBHUpC/X1vnPcbe8Pf6kKdBvysv0CUjMSDETaf
  4.1511 +n53ftFkUDXr62p3ImlSUXF7IM3snCCpvrMp8az4vYa/yHoTcxDBBh00ADh/WLOsK28yoxAsMIxKP
  4.1512 +pTFT54WSDM0skrh2HVxn4cw+zwencwYLNPvMxRSu4RGRpApLQ0mF9cA1Ac2Utwi/lfyx95B65Faf
  4.1513 +CfK5hcqvpbSjEZjbVKJ06GihuxyrjgqxjWvt2NhWaWdbDENq5EhVh8p+FXI6UDTOHfX1SJvt7j0Y
  4.1514 +P9ShOmJb4YBFhUCCJcgb2S0opHGrJ8qFZEolRIrnDObx6LhLQj+3aC79UkHdO0I2jDdkxCFMTGHy
  4.1515 +tvIxa+uf6fsf5XkvJtvgFUtwRr3yxJ64D7SFYj5iWJAbVx5Xce56V4gR37BVaRwkvfpw+QcTPuuK
  4.1516 +wCFCUMi+Mpq3ucx3C8ySRBbmdtEcsUjUQt2aw+CNJ/FtBERNjYY5bHsMtxiS5+uhoT6b7zwYRY9c
  4.1517 +GrRbt0Msqyhe0KGC9IWokOQL4wcitijz+zgSkXz9IV4pePNFi8poPkTqwl3qdYcauuNoVhz9wGGj
  4.1518 +zC4FhQ0Y6g0JBkTyLMR2D3SsrfJGONCygfpjf43SS8PAKqUcK/O6ntqSZRO+yCIVNOjO2J5NZXN5
  4.1519 +m68TXo8OtO/9fTSrVPVkRRrgsHlYS1PFuPC5n6R9GZOFlMMJlCLR3Zd/os71uxFfkYPuTUIPNJ8H
  4.1520 +vOnPG7efTd1oj+7QrOl8Wbo/Ous1/H0mhqLtZ/+/V54Deum0MxNGwzzhTRZuuhSuezKMlB/VSG/P
  4.1521 +GNrYhmNrC99IkhBU8Os3WiRUERcs5eUdnuXnjNMBLO8mLJvWeNpU7/ybG0wXPjvz0LyRTdkZXrFJ
  4.1522 +xFy1AObigd5fgpx5nvIMYnfk3BghTmM8vWn7Adg0MxPMz/03Lm7Y83baROOg+znWl2la7hmXkiuR
  4.1523 +rGTjfDH1px5LBV4cqBYYU7qTGXWRmg6CFYQ8ZqRLACVwW7IWf4byipG+R6z3111oQJ+M73rl2wyr
  4.1524 +6jSP8K0w6f+x2U8AhSjTuKroNa3uyE4jiUEJqeEFMo8qn93iBpz2Ygi+ogVIV4IIGV2jBkIVB+Ar
  4.1525 +TFY7ctATy9SUJ0REiq/c0WUR4CeRTA1AjQd77EqLQWOXO7YWtcLlzvo3KFRCFubFzvwNhRhk/OpG
  4.1526 +oGSovE6uARTju2uDJgdAH27avECLZZQP6AGMzclq0lYfsBL5Q4goCqRXOath1f8e+KUjTViPHnWh
  4.1527 +peIrgVIVg2P9DtLnBVSgkavW6LsyTdeCuOXjn4OAeJ8M+zYvX/6NcpcwTkF8VDQBfad/PT01krFk
  4.1528 +5SvRa5xS+duc4qNAaxWsQu6bJJuGb/b02N+Z+8JjLw0OoY3hfFG6gOHMQzwvZtZyIUwLgvGxSSAB
  4.1529 +/e50asg2ROpKzHaAUlLv2o4eRojuxG6hFdDH435QX6TZQQKcmccUNnl1WDMIMje66AG4WgturRZV
  4.1530 +l8SBqdyQeQOlM8Z7RNI5oLWtoQXeZ9Do7JykHG6AuE7GCu9sDNjQ+eITAMMN7OwAoCoQTIv9N269
  4.1531 +ShXFyQlwP4Eq+GxcAdON4kF1bbunQMiCaLl2QQmnyrXgm2x44UnocJDymGrue4/tueTXBYLLQ6+7
  4.1532 +kgpc8GqnoLTzO3z9X8X44cttQFxM918weQqoIg8CJDUI1LuURHcbNc/Ob2aTfwH3muVf
  4.1533 +""".decode("base64").decode("zlib")
  4.1534 +
  4.1535 +##file activate.sh
  4.1536 +ACTIVATE_SH = """
  4.1537 +eJytVU1v4jAQPW9+xTT0ANVS1GsrDlRFAqmFqmG72m0rY5IJsRRslDiktNr/vuMQ8tFQpNU2B4I9
  4.1538 +H36eeW/SglkgYvBFiLBKYg0LhCRGD1KhA7BjlUQuwkLIHne12HCNNpz5kVrBgsfBmdWCrUrA5VIq
  4.1539 +DVEiQWjwRISuDreW5eE+CtodeLeAnhZEGKMGFXqAciMiJVcoNWx4JPgixDjzEj48QVeCfcqmtzfs
  4.1540 +cfww+zG4ZfeD2ciGF7gCHaDMPM1jtvuHXAsPfF2rSGeOxV4iDY5GUGb3xVEYv2aj6WQ0vRseAlMY
  4.1541 +G5DKsAawwnQUXt2LQOYlzZoYByqhonqoqfxZf4BLD97i4DukgXADCPgGgdOLTK5arYxZB1xnrc9T
  4.1542 +EQFcHoZEAa1gSQioo/TPV5FZrDlxJA+NzwF+Ek1UonOzFnKZp6k5mgLBqSkuuAGXS4whJb5xz/xs
  4.1543 +wXCHjiVerAk5eh9Kfz1wqOldtVv9dkbscfjgjKeTA8XPrtaNauX5rInOxaHuOReNtpFjo1/OxdFG
  4.1544 +5eY9hJ3L3jqcPJbATggXAemDLZX0MNZRYjSDH7C1wMHQh73DyYfTu8a0F9v+6D8W6XNnF1GEIXW/
  4.1545 +JrSKPOtnW1YFat9mrLJkzLbyIlTvYzV0RGXcaTBfVLx7jF2PJ2wyuBsydpm7VSVa4C4Zb6pFO2TR
  4.1546 +huypCEPwuQjNftUrNl6GsYZzuFrrLdC9iJjQ3omAPBbcI2lsU77tUD43kw1NPZhTrnZWzuQKLomx
  4.1547 +Rd4OXM1ByExVVkmoTwfBJ7Lt10Iq1Kgo23Bmd8Ib1KrGbsbO4Pp2yO4fpnf3s6MnZiwuiJuls1/L
  4.1548 +Pu4yUCvhpA+vZaJvWWDTr0yFYYyVnHMqCEq+QniuYX225xmnzRENjbXACF3wkCYNVZ1mBwxoR9Iw
  4.1549 +WAo3/36oSOTfgjwEEQKt15e9Xpqm52+oaXxszmnE9GLl65RH2OMmS6+u5acKxDmlPgj2eT5/gQOX
  4.1550 +LLK0j1y0Uwbmn438VZkVpqlfNKa/YET/53j+99G8H8tUhr9ZSXs2
  4.1551 +""".decode("base64").decode("zlib")
  4.1552 +
  4.1553 +##file activate.fish
  4.1554 +ACTIVATE_FISH = """
  4.1555 +eJydVm1v4jgQ/s6vmA1wBxUE7X2stJVYlVWR2lK13d6d9laRk0yIr8HmbIe0++tvnIQQB9pbXT5A
  4.1556 +Ys/LM55nZtyHx5RrSHiGsMm1gRAh1xhDwU0Kng8hFzMWGb5jBv2E69SDs0TJDdj3MxilxmzPZzP7
  4.1557 +pVPMMl+q9bjXh1eZQ8SEkAZULoAbiLnCyGSvvV6SC7IoBcS4Nw0wjcFbvJDcjiuTswzFDpiIQaHJ
  4.1558 +lQAjQUi1YRmUboC2uZJig8J4PaCnT5IaDcgsbm/CjinOwgx1KcUTMEhhTgV4g2B1fRk8Le8fv86v
  4.1559 +g7v545UHpZB9rKnp+gXsMhxLunIIpwVQxP/l9c/Hq9Xt1epm4R27bva6AJqN92G4YhbMG2i+LB+u
  4.1560 +grv71c3dY7B6WtzfLy9bePbp0taDTXSwJQJszUnnp0y57mvpPcrF7ZODyhswtd59+/jdgw+fwBNS
  4.1561 +xLSscksUPIDqwwNmCez3PpxGeyBYg6HE0YdcWBxcKczYzuVJi5Wu915vn5oWePCCoPUZBN5B7IgV
  4.1562 +MCi54ZDLG7TUZ0HweXkb3M5vFmSpFm/gthhBx0UrveoPpv9AJ9unIbQYdUoe21bKg2q48sPFGVwu
  4.1563 +H+afrxd1qvclaNlRFyh1EQ2sSccEuNAGWQwysfVpz1tPajUqbqJUnEcIJkWo6OXDaodK8ZiLdbmM
  4.1564 +L1wb+9H0D+pcyPSrX5u5kgWSygRYXCnJUi/KKcuU4cqsAyTKZBiissLc7NFwizvjxtieKBVCIdWz
  4.1565 +fzilzPaYyljZN0cGN1v7NnaIPNCGmVy3GKuJaQ6iVjE1Qfm+36hglErwmnAD8hu0dDy4uICBA8ZV
  4.1566 +pQr/q/+O0KFW2kjelu9Dgb9SDBsWV4F4x5CswgS0zBVlk5tDMP5bVtUGpslbm81Lu2sdKq7uNMGh
  4.1567 +MVQ4fy9xhogC1lS5guhISa0DlBWv0O8odT6/LP+4WZzDV6FzIkEqC0uolGZSZoMnlpxplmD2euaT
  4.1568 +O4hkTpPnbztDccey0bhjDaBIqaWQa0uwEtQEwtyU56i4fq54F9IE3ORR6mKriODM4XOYZwaVYLYz
  4.1569 +7SPbKkz4i7VkB6/Ot1upDE3znNqYKpM8raa0Bx8vfvntJ32UENsM4aI6gJL+jJwhxhh3jVIDOcpi
  4.1570 +m0r2hmEtS8XXXNBk71QCDXTBNhhPiHX2LtHkrVIlhoEshH/EZgdq53Eirqs5iFKMnkOmqZTtr3Xq
  4.1571 +djvPTWZT4S3NT5aVLgurMPUWI07BRVYqkQrmtCKohNY8qu9EdACoT6ki0a66XxVF4f9AQ3W38yO5
  4.1572 +mWmZmIIpnDFrbXakvKWeZhLwhvrbUH8fahhqD0YUcBDJjEBMQwiznE4y5QbHrbhHBOnUAYzb2tVN
  4.1573 +jJa65e+eE2Ya30E2GurxUP8ssA6e/wOnvo3V78d3vTcvMB3n7l3iX1JXWqk=
  4.1574 +""".decode("base64").decode("zlib")
  4.1575 +
  4.1576 +##file activate.csh
  4.1577 +ACTIVATE_CSH = """
  4.1578 +eJx9U11vmzAUffevOCVRu+UB9pws29Kl0iq1aVWllaZlcgxciiViItsQdb9+xiQp+dh4QOB7Pu49
  4.1579 +XHqY59IgkwVhVRmLmFAZSrGRNkdgykonhFiqSCRW1sJSmJg8wCDT5QrucRCyHn6WFRKhVGmhKwVp
  4.1580 +kUpNiS3emup3TY6XIn7DVNQyJUwlrgthJD6n/iCNv72uhCzCpFx9CRkThRQGKe08cWXJ9db/yh/u
  4.1581 +pvzl9mn+PLnjj5P5D1yM8QmXlzBkSdXwZ0H/BBc0mEo5FE5qI2jKhclHOOvy9HD/OO/6YO1mX9vx
  4.1582 +sY0H/tPIV0dtqel0V7iZvWyNg8XFcBA0ToEqVeqOdNUEQFvN41SumAv32VtJrakQNSmLWmgp4oJM
  4.1583 +yDoBHgoydtoEAs47r5wHHnUal5vbJ8oOI+9wI86vb2d8Nrm/4Xy4RZ8R85E4uTZPB5EZPnTaaAGu
  4.1584 +E59J8BE2J8XgrkbLeXMlVoQxznEYFYY8uFFdxsKQRx90Giwx9vSueHP1YNaUSFG4vTaErNSYuBOF
  4.1585 +lXiVyXa9Sy3JdClEyK1dD6Nos9mEf8iKlOpmqSNTZnYjNEWiUYn2pKNB3ttcLJ3HmYYXy6Un76f7
  4.1586 +r8rRsC1TpTJj7f19m5sUf/V3Ir+x/yjtLu8KjLX/CmN/AcVGUUo=
  4.1587 +""".decode("base64").decode("zlib")
  4.1588 +
  4.1589 +##file activate.bat
  4.1590 +ACTIVATE_BAT = """
  4.1591 +eJyFUkEKgzAQvAfyhz0YaL9QEWpRqlSjWGspFPZQTevFHOr/adQaU1GaUzI7Mzu7ZF89XhKkEJS8
  4.1592 +qxaKMMsvboQ+LxxE44VICSW1gEa2UFaibqoS0iyJ0xw2lIA6nX5AHCu1jpRsv5KRjknkac9VLVug
  4.1593 +sX9mtzxIeJDE/mg4OGp47qoLo3NHX2jsMB3AiDht5hryAUOEifoTdCXbSh7V0My2NMq/Xbh5MEjU
  4.1594 +ZT63gpgNT9lKOJ/CtHsvT99re3pX303kydn4HeyOeAg5cjf2EW1D6HOPkg9NGKhu
  4.1595 +""".decode("base64").decode("zlib")
  4.1596 +
  4.1597 +##file deactivate.bat
  4.1598 +DEACTIVATE_BAT = """
  4.1599 +eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q
  4.1600 +FlWqXJpcICVYpGzx2BAZ4uHv5+Hv6wq1BWINXBTdKriEKkI1DhW2QAfhttcxxANiFZCBbglQSJUL
  4.1601 +i2dASrm4rFz9XLgAwJNbyQ==
  4.1602 +""".decode("base64").decode("zlib")
  4.1603 +
  4.1604 +##file distutils-init.py
  4.1605 +DISTUTILS_INIT = """
  4.1606 +eJytV92L4zYQf9dfMU0ottuse/TeFkKh3MvC0Ydy0IdlMVpbTtR1JCMpm+T++s5Y/pBs53oPZ1hQ
  4.1607 +pPnSb34zo5WnVhsH2jLpV/Y2Li/cKKkOFoYN3Za6ErAdFtKC0g44vEvjzrwR6h1Oujo3YgdWw0VA
  4.1608 +yRWcLUo6cBpqqSpwRwHWVY18ZRB9W3jq3HDlfoIvqK7NG2gF7a297VANvZ3O1sGrQI/eDe5yB0ZY
  4.1609 +WQkLUpHxhVX09NDe3FGr31BL1lJUD9f8ln+FShpROm1ujOFS8ZOAPUKRt9wd836Hjqw7O9nYgvYD
  4.1610 +iX+1VOlMPPXQ5EVRy0YURbaDZDSQZEzWo7rS5kSLNHaQwX4RRLrQGe1nj92Fh1zltEhHDDZfEO0g
  4.1611 +O6MraHn5xg8IpYOfLfC2FdxYShLC64EES4A0uuROYhq49Zs368RpMvTHJmOiscKHUXRXKIpcKiuM
  4.1612 +Sz/sYHa7TkxcRYkkEhN8HZaxKCJXFFJJh+baW5JluRG8SjM20JHEA9qWWtXywBjbbvF2rjzC61k2
  4.1613 +VSGuDibTUGlhVeLgTekLHPEP73wQrrscUsUGrPCGjkTCC1JXXyw8EJWP3FSUZY8IiSCCRp97dnfO
  4.1614 +RUUx5a0RtbxSzLX/3XBXYxIpyQka/fh74pGrjQ5QzUt9OnFV5dMV+otOG5gQjctxozNTNtzaSSiN
  4.1615 +JHqu0FeJmsqRN/KrKHRLGbaQWtHUgRB9FDfu5giN4eZWIDqWCv8vrcTjrNZgRXQPzy+RmGjQpLRI
  4.1616 +EKz0UqQLlR28ciusM8jn7PtcLPZy2zbSDeyyos0iO+ybBgPyRvSk/CEFm8IndQebz8iXTRbbjhDP
  4.1617 +5xh7iJfBrKd/Nenjj6Jvgp2B+W7AnP102BXH5IZWPV3tI2MUOvXowpdS12IIXhLLP0lKyeuZrpEv
  4.1618 +pFhPqHg3JFTd1cceVp0EsPgGU0wFO2u4iyYRoFYfEm9kG/RZcUUBm87t9mFtx9iCtC9kx4Rt4R8a
  4.1619 +OdgzSt40vtyFecAZZ8BfCOhCrC8djMGPFaz2Vlt5TSZCk053+37wbLDLRXfZ+F45NtdVpVWdudSC
  4.1620 +xgODI8EsiLoTl5aO0lhoigX7GHZDHAY4LxoMIu1gXPYPksmFquxF4uRKZhEnKzXu82HESb+LlNQz
  4.1621 +Fh/RvFJVuhK+Ee5slBdj30FcRGdJ5rhKxtkyKxWcGoV/WOCYKqkNDYJ5fNQVx3g400tpJBS2FSU+
  4.1622 +Tco9ss8nZ08dtscGQfSby87b73fOw+4UgrEMNnY6uMzYvSDxPVPpsij6+l0/ZPfuH0Iz010giY34
  4.1623 +HpL0ZLyLJB4ukaQRU+GwptO7yIZCQE33B0K9iCqO6X+AR4n7wAeH68DPkJzpTsD3x+/cj9LIVHC2
  4.1624 +An1wmv7CzWHoqR02vb0VL73siP+3nkX0YbQ0l9f6WDyOm24cj3rxO2MMip6kpcu6VCefn/789PR3
  4.1625 +0v0fg21sFIp70rj9PCi8YDRDXFucym/43qN+iENh1Jy/dIIIqF3OIkDvBMsdx+huWv8Kz73vl8g5
  4.1626 +WQ3JOGqwu3lb4dfKKbvLigXDQsb8B/xt39Q=
  4.1627 +""".decode("base64").decode("zlib")
  4.1628 +
  4.1629 +##file distutils.cfg
  4.1630 +DISTUTILS_CFG = """
  4.1631 +eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
  4.1632 +xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
  4.1633 +9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
  4.1634 +""".decode("base64").decode("zlib")
  4.1635 +
  4.1636 +##file activate_this.py
  4.1637 +ACTIVATE_THIS = """
  4.1638 +eJyNUlGL2zAMfvevEBlHEujSsXsL9GGDvW1jD3sZpQQ3Ua7aJXawnbT595Ocpe0dO5ghseVP+vRJ
  4.1639 +VpIkn2cYPZknwAvWLXWYhRP5Sk4baKgOWRWNqtpdgTyH2Y5wpq5Tug406YAgKEzkwqg7NBPwR86a
  4.1640 +Hk0olPopaK0NHJHzYQPnE5rI0o8+yBUwiBfyQcT8mMPJGiAT0A0O+b8BY4MKJ7zPcSSzHaKrSpJE
  4.1641 +qeDmUgGvVbPCS41DgO+6xy/OWbfAThMn/OQ9ukDWRCSLiKzk1yrLjWapq6NnvHUoHXQ4bYPdrsVX
  4.1642 +4lQMc/q6ZW975nmSK+oH6wL42a9H65U6aha342Mh0UVDzrD87C1bH73s16R5zsStkBZDp0NrXQ+7
  4.1643 +HaRnMo8f06UBnljKoOtn/YT+LtdvSyaT/BtIv9KR60nF9f3qmuYKO4//T9ItJMsjPfgUHqKwCZ3n
  4.1644 +xu/Lx8M/UvCLTxW7VULHxB1PRRbrYfvWNY5S8it008jOjcleaMqVBDnUXcWULV2YK9JEQ92OfC96
  4.1645 +1Tv4ZicZZZ7GpuEpZbbeQ7DxquVx5hdqoyFSSmXwfC90f1Dc7hjFs/tK99I0fpkI8zSLy4tSy+sI
  4.1646 +3vMWehjQNJmE5VePlZbL61nzX3S93ZcfDqznnkb9AZ3GWJU=
  4.1647 +""".decode("base64").decode("zlib")
  4.1648 +
  4.1649 +if __name__ == '__main__':
  4.1650 +    main()
  4.1651 +
  4.1652 +## TODO:
  4.1653 +## Copy python.exe.manifest
  4.1654 +## Monkeypatch distutils.sysconfig