From 0e5b70d417ef5056007e84581e2843b97e254af8 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Wed, 7 Jun 2006 18:58:42 +0000 Subject: [PATCH] mv Mac/OSX/BuildScript one level up --- Mac/BuildScript/README.txt | 35 + Mac/BuildScript/build-installer.py | 1028 +++++++++++++++++ Mac/BuildScript/ncurses-5.5.patch | 36 + Mac/BuildScript/resources/ReadMe.txt | 31 + Mac/BuildScript/resources/Welcome.rtf | 15 + Mac/BuildScript/resources/background.jpg | Bin 0 -> 45421 bytes .../scripts/postflight.documentation | 12 + Mac/BuildScript/scripts/postflight.framework | 33 + .../scripts/postflight.patch-profile | 71 ++ 9 files changed, 1261 insertions(+) create mode 100644 Mac/BuildScript/README.txt create mode 100755 Mac/BuildScript/build-installer.py create mode 100644 Mac/BuildScript/ncurses-5.5.patch create mode 100644 Mac/BuildScript/resources/ReadMe.txt create mode 100644 Mac/BuildScript/resources/Welcome.rtf create mode 100644 Mac/BuildScript/resources/background.jpg create mode 100755 Mac/BuildScript/scripts/postflight.documentation create mode 100755 Mac/BuildScript/scripts/postflight.framework create mode 100755 Mac/BuildScript/scripts/postflight.patch-profile diff --git a/Mac/BuildScript/README.txt b/Mac/BuildScript/README.txt new file mode 100644 index 00000000000..c556de8329d --- /dev/null +++ b/Mac/BuildScript/README.txt @@ -0,0 +1,35 @@ +Building a MacPython distribution +================================= + +The ``build-install.py`` script creates MacPython distributions, including +sleepycat db4, sqlite3 and readline support. It builds a complete +framework-based Python out-of-tree, installs it in a funny place with +$DESTROOT, massages that installation to remove .pyc files and such, creates +an Installer package from the installation plus other files in ``resources`` +and ``scripts`` and placed that on a ``.dmg`` disk image. + +Here are the steps you ned to follow to build a MacPython installer: + +- Run ``./build-installer.py``. Optionally you can pass a number of arguments + to specify locations of various files. Please see the top of + ``build-installer.py`` for its usage. +- When done the script will tell you where the DMG image is. + +The script needs to be run on Mac OS X 10.4 with Xcode 2.2 or later and +the 10.4u SDK. + +When all is done, announcements can be posted to at least the following +places: +- pythonmac-sig@python.org +- python-dev@python.org +- python-announce@python.org +- archivist@info-mac.org +- adcnews@apple.com +- news@macnn.com +- http://www.macupdate.com +- http://guide.apple.com/usindex.lasso +- http://www.apple.com/downloads/macosx/submit +- http://www.versiontracker.com/ (userid Jack.Jansen@oratrix.com) +- http://www.macshareware.net (userid jackjansen) + +Also, check out Stephan Deibels http://pythonology.org/market contact list diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py new file mode 100755 index 00000000000..1305c0c47dd --- /dev/null +++ b/Mac/BuildScript/build-installer.py @@ -0,0 +1,1028 @@ +#!/usr/bin/python2.3 +""" +This script is used to build the "official unofficial" universal build on +Mac OS X. It requires Mac OS X 10.4, Xcode 2.2 and the 10.4u SDK to do its +work. + +Please ensure that this script keeps working with Python 2.3, to avoid +bootstrap issues (/usr/bin/python is Python 2.3 on OSX 10.4) + +Usage: see USAGE variable in the script. +""" +import platform, os, sys, getopt, textwrap, shutil, urllib2, stat, time, pwd + +INCLUDE_TIMESTAMP=1 +VERBOSE=1 + +from plistlib import Plist + +import MacOS +import Carbon.File +import Carbon.Icn +import Carbon.Res +from Carbon.Files import kCustomIconResource, fsRdWrPerm, kHasCustomIcon +from Carbon.Files import kFSCatInfoFinderInfo + +try: + from plistlib import writePlist +except ImportError: + # We're run using python2.3 + def writePlist(plist, path): + plist.write(path) + +def shellQuote(value): + """ + Return the string value in a form that can savely be inserted into + a shell command. + """ + return "'%s'"%(value.replace("'", "'\"'\"'")) + +def grepValue(fn, variable): + variable = variable + '=' + for ln in open(fn, 'r'): + if ln.startswith(variable): + value = ln[len(variable):].strip() + return value[1:-1] + +def getVersion(): + return grepValue(os.path.join(SRCDIR, 'configure'), 'PACKAGE_VERSION') + +def getFullVersion(): + fn = os.path.join(SRCDIR, 'Include', 'patchlevel.h') + for ln in open(fn): + if 'PY_VERSION' in ln: + return ln.split()[-1][1:-1] + + raise RuntimeError, "Cannot find full version??" + +# The directory we'll use to create the build, will be erased and recreated +WORKDIR="/tmp/_py" + +# The directory we'll use to store third-party sources, set this to something +# else if you don't want to re-fetch required libraries every time. +DEPSRC=os.path.join(WORKDIR, 'third-party') +DEPSRC=os.path.expanduser('~/Universal/other-sources') + +# Location of the preferred SDK +SDKPATH="/Developer/SDKs/MacOSX10.4u.sdk" +#SDKPATH="/" + +# Source directory (asume we're in Mac/BuildScript) +SRCDIR=os.path.dirname( + os.path.dirname( + os.path.dirname( + os.path.abspath(__file__ + )))) + +USAGE=textwrap.dedent("""\ + Usage: build_python [options] + + Options: + -? or -h: Show this message + -b DIR + --build-dir=DIR: Create build here (default: %(WORKDIR)r) + --third-party=DIR: Store third-party sources here (default: %(DEPSRC)r) + --sdk-path=DIR: Location of the SDK (default: %(SDKPATH)r) + --src-dir=DIR: Location of the Python sources (default: %(SRCDIR)r) +""")% globals() + + +# Instructions for building libraries that are necessary for building a +# batteries included python. +LIBRARY_RECIPES=[ + dict( + # Note that GNU readline is GPL'd software + name="GNU Readline 5.1.4", + url="http://ftp.gnu.org/pub/gnu/readline/readline-5.1.tar.gz" , + patchlevel='0', + patches=[ + # The readline maintainers don't do actual micro releases, but + # just ship a set of patches. + 'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-001', + 'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-002', + 'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-003', + 'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-004', + ] + ), + + dict( + name="SQLite 3.3.5", + url="http://www.sqlite.org/sqlite-3.3.5.tar.gz", + checksum='93f742986e8bc2dfa34792e16df017a6feccf3a2', + configure_pre=[ + '--enable-threadsafe', + '--enable-tempstore', + '--enable-shared=no', + '--enable-static=yes', + '--disable-tcl', + ] + ), + + dict( + name="NCurses 5.5", + url="http://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.5.tar.gz", + configure_pre=[ + "--without-cxx", + "--without-ada", + "--without-progs", + "--without-curses-h", + "--enable-shared", + "--with-shared", + "--datadir=/usr/share", + "--sysconfdir=/etc", + "--sharedstatedir=/usr/com", + "--with-terminfo-dirs=/usr/share/terminfo", + "--with-default-terminfo-dir=/usr/share/terminfo", + "--libdir=/Library/Frameworks/Python.framework/Versions/%s/lib"%(getVersion(),), + "--enable-termcap", + ], + patches=[ + "ncurses-5.5.patch", + ], + useLDFlags=False, + install='make && make install DESTDIR=%s && cd %s/usr/local/lib && ln -fs ../../../Library/Frameworks/Python.framework/Versions/%s/lib/lib* .'%( + shellQuote(os.path.join(WORKDIR, 'libraries')), + shellQuote(os.path.join(WORKDIR, 'libraries')), + getVersion(), + ), + ), + dict( + name="Sleepycat DB 4.4", + url="http://downloads.sleepycat.com/db-4.4.20.tar.gz", + #name="Sleepycat DB 4.3.29", + #url="http://downloads.sleepycat.com/db-4.3.29.tar.gz", + buildDir="build_unix", + configure="../dist/configure", + configure_pre=[ + '--includedir=/usr/local/include/db4', + ] + ), +] + + +# Instructions for building packages inside the .mpkg. +PKG_RECIPES=[ + dict( + name="PythonFramework", + long_name="Python Framework", + source="/Library/Frameworks/Python.framework", + readme="""\ + This package installs Python.framework, that is the python + interpreter and the standard library. This also includes Python + wrappers for lots of Mac OS X API's. + """, + postflight="scripts/postflight.framework", + ), + dict( + name="PythonApplications", + long_name="GUI Applications", + source="/Applications/MacPython %(VER)s", + readme="""\ + This package installs IDLE (an interactive Python IDLE), + Python Launcher and Build Applet (create application bundles + from python scripts). + + It also installs a number of examples and demos. + """, + required=False, + ), + dict( + name="PythonUnixTools", + long_name="UNIX command-line tools", + source="/usr/local/bin", + readme="""\ + This package installs the unix tools in /usr/local/bin for + compatibility with older releases of MacPython. This package + is not necessary to use MacPython. + """, + required=False, + ), + dict( + name="PythonDocumentation", + long_name="Python Documentation", + topdir="/Library/Frameworks/Python.framework/Versions/%(VER)s/Resources/English.lproj/Documentation", + source="/pydocs", + readme="""\ + This package installs the python documentation at a location + that is useable for pydoc and IDLE. If you have installed Xcode + it will also install a link to the documentation in + /Developer/Documentation/Python + """, + postflight="scripts/postflight.documentation", + required=False, + ), + dict( + name="PythonProfileChanges", + long_name="Shell profile updater", + readme="""\ + This packages updates your shell profile to make sure that + the MacPython tools are found by your shell in preference of + the system provided Python tools. + + If you don't install this package you'll have to add + "/Library/Frameworks/Python.framework/Versions/%(VER)s/bin" + to your PATH by hand. + """, + postflight="scripts/postflight.patch-profile", + topdir="/Library/Frameworks/Python.framework", + source="/empty-dir", + required=False, + ), + dict( + name="PythonSystemFixes", + long_name="Fix system Python", + readme="""\ + This package updates the system python installation on + Mac OS X 10.3 to ensure that you can build new python extensions + using that copy of python after installing this version of + python. + """ + postflight="../Tools/fixapplepython23.py", + topdir="/Library/Frameworks/Python.framework", + source="/empty-dir", + required=False, + ) +] + +def fatal(msg): + """ + A fatal error, bail out. + """ + sys.stderr.write('FATAL: ') + sys.stderr.write(msg) + sys.stderr.write('\n') + sys.exit(1) + +def fileContents(fn): + """ + Return the contents of the named file + """ + return open(fn, 'rb').read() + +def runCommand(commandline): + """ + Run a command and raise RuntimeError if it fails. Output is surpressed + unless the command fails. + """ + fd = os.popen(commandline, 'r') + data = fd.read() + xit = fd.close() + if xit != None: + sys.stdout.write(data) + raise RuntimeError, "command failed: %s"%(commandline,) + + if VERBOSE: + sys.stdout.write(data); sys.stdout.flush() + +def captureCommand(commandline): + fd = os.popen(commandline, 'r') + data = fd.read() + xit = fd.close() + if xit != None: + sys.stdout.write(data) + raise RuntimeError, "command failed: %s"%(commandline,) + + return data + +def checkEnvironment(): + """ + Check that we're running on a supported system. + """ + + if platform.system() != 'Darwin': + fatal("This script should be run on a Mac OS X 10.4 system") + + if platform.release() <= '8.': + fatal("This script should be run on a Mac OS X 10.4 system") + + if not os.path.exists(SDKPATH): + fatal("Please install the latest version of Xcode and the %s SDK"%( + os.path.basename(SDKPATH[:-4]))) + + + +def parseOptions(args = None): + """ + Parse arguments and update global settings. + """ + global WORKDIR, DEPSRC, SDKPATH, SRCDIR + + if args is None: + args = sys.argv[1:] + + try: + options, args = getopt.getopt(args, '?hb', + [ 'build-dir=', 'third-party=', 'sdk-path=' , 'src-dir=']) + except getopt.error, msg: + print msg + sys.exit(1) + + if args: + print "Additional arguments" + sys.exit(1) + + for k, v in options: + if k in ('-h', '-?'): + print USAGE + sys.exit(0) + + elif k in ('-d', '--build-dir'): + WORKDIR=v + + elif k in ('--third-party',): + DEPSRC=v + + elif k in ('--sdk-path',): + SDKPATH=v + + elif k in ('--src-dir',): + SRCDIR=v + + else: + raise NotImplementedError, k + + SRCDIR=os.path.abspath(SRCDIR) + WORKDIR=os.path.abspath(WORKDIR) + SDKPATH=os.path.abspath(SDKPATH) + DEPSRC=os.path.abspath(DEPSRC) + + print "Settings:" + print " * Source directory:", SRCDIR + print " * Build directory: ", WORKDIR + print " * SDK location: ", SDKPATH + print " * third-party source:", DEPSRC + print "" + + + + +def extractArchive(builddir, archiveName): + """ + Extract a source archive into 'builddir'. Returns the path of the + extracted archive. + + XXX: This function assumes that archives contain a toplevel directory + that is has the same name as the basename of the archive. This is + save enough for anything we use. + """ + curdir = os.getcwd() + try: + os.chdir(builddir) + if archiveName.endswith('.tar.gz'): + retval = os.path.basename(archiveName[:-7]) + if os.path.exists(retval): + shutil.rmtree(retval) + fp = os.popen("tar zxf %s 2>&1"%(shellQuote(archiveName),), 'r') + + elif archiveName.endswith('.tar.bz2'): + retval = os.path.basename(archiveName[:-8]) + if os.path.exists(retval): + shutil.rmtree(retval) + fp = os.popen("tar jxf %s 2>&1"%(shellQuote(archiveName),), 'r') + + elif archiveName.endswith('.tar'): + retval = os.path.basename(archiveName[:-4]) + if os.path.exists(retval): + shutil.rmtree(retval) + fp = os.popen("tar xf %s 2>&1"%(shellQuote(archiveName),), 'r') + + elif archiveName.endswith('.zip'): + retval = os.path.basename(archiveName[:-4]) + if os.path.exists(retval): + shutil.rmtree(retval) + fp = os.popen("unzip %s 2>&1"%(shellQuote(archiveName),), 'r') + + data = fp.read() + xit = fp.close() + if xit is not None: + sys.stdout.write(data) + raise RuntimeError, "Cannot extract %s"%(archiveName,) + + return os.path.join(builddir, retval) + + finally: + os.chdir(curdir) + +KNOWNSIZES = { + "http://ftp.gnu.org/pub/gnu/readline/readline-5.1.tar.gz": 7952742, + "http://downloads.sleepycat.com/db-4.4.20.tar.gz": 2030276, +} + +def downloadURL(url, fname): + """ + Download the contents of the url into the file. + """ + try: + size = os.path.getsize(fname) + except OSError: + pass + else: + if KNOWNSIZES.get(url) == size: + print "Using existing file for", url + return + fpIn = urllib2.urlopen(url) + fpOut = open(fname, 'wb') + block = fpIn.read(10240) + try: + while block: + fpOut.write(block) + block = fpIn.read(10240) + fpIn.close() + fpOut.close() + except: + try: + os.unlink(fname) + except: + pass + +def buildRecipe(recipe, basedir, archList): + """ + Build software using a recipe. This function does the + 'configure;make;make install' dance for C software, with a possibility + to customize this process, basically a poor-mans DarwinPorts. + """ + curdir = os.getcwd() + + name = recipe['name'] + url = recipe['url'] + configure = recipe.get('configure', './configure') + install = recipe.get('install', 'make && make install DESTDIR=%s'%( + shellQuote(basedir))) + + archiveName = os.path.split(url)[-1] + sourceArchive = os.path.join(DEPSRC, archiveName) + + if not os.path.exists(DEPSRC): + os.mkdir(DEPSRC) + + + if os.path.exists(sourceArchive): + print "Using local copy of %s"%(name,) + + else: + print "Downloading %s"%(name,) + downloadURL(url, sourceArchive) + print "Archive for %s stored as %s"%(name, sourceArchive) + + print "Extracting archive for %s"%(name,) + buildDir=os.path.join(WORKDIR, '_bld') + if not os.path.exists(buildDir): + os.mkdir(buildDir) + + workDir = extractArchive(buildDir, sourceArchive) + os.chdir(workDir) + if 'buildDir' in recipe: + os.chdir(recipe['buildDir']) + + + for fn in recipe.get('patches', ()): + if fn.startswith('http://'): + # Download the patch before applying it. + path = os.path.join(DEPSRC, os.path.basename(fn)) + downloadURL(fn, path) + fn = path + + fn = os.path.join(curdir, fn) + runCommand('patch -p%s < %s'%(recipe.get('patchlevel', 1), + shellQuote(fn),)) + + configure_args = [ + "--prefix=/usr/local", + "--enable-static", + "--disable-shared", + #"CPP=gcc -arch %s -E"%(' -arch '.join(archList,),), + ] + + if 'configure_pre' in recipe: + args = list(recipe['configure_pre']) + if '--disable-static' in args: + configure_args.remove('--enable-static') + if '--enable-shared' in args: + configure_args.remove('--disable-shared') + configure_args.extend(args) + + if recipe.get('useLDFlags', 1): + configure_args.extend([ + "CFLAGS=-arch %s -isysroot %s -I%s/usr/local/include"%( + ' -arch '.join(archList), + shellQuote(SDKPATH)[1:-1], + shellQuote(basedir)[1:-1],), + "LDFLAGS=-syslibroot,%s -L%s/usr/local/lib -arch %s"%( + shellQuote(SDKPATH)[1:-1], + shellQuote(basedir)[1:-1], + ' -arch '.join(archList)), + ]) + else: + configure_args.extend([ + "CFLAGS=-arch %s -isysroot %s -I%s/usr/local/include"%( + ' -arch '.join(archList), + shellQuote(SDKPATH)[1:-1], + shellQuote(basedir)[1:-1],), + ]) + + if 'configure_post' in recipe: + configure_args = configure_args = list(recipe['configure_post']) + + configure_args.insert(0, configure) + configure_args = [ shellQuote(a) for a in configure_args ] + + print "Running configure for %s"%(name,) + runCommand(' '.join(configure_args) + ' 2>&1') + + print "Running install for %s"%(name,) + runCommand('{ ' + install + ' ;} 2>&1') + + print "Done %s"%(name,) + print "" + + os.chdir(curdir) + +def buildLibraries(): + """ + Build our dependencies into $WORKDIR/libraries/usr/local + """ + print "" + print "Building required libraries" + print "" + universal = os.path.join(WORKDIR, 'libraries') + os.mkdir(universal) + os.makedirs(os.path.join(universal, 'usr', 'local', 'lib')) + os.makedirs(os.path.join(universal, 'usr', 'local', 'include')) + + for recipe in LIBRARY_RECIPES: + buildRecipe(recipe, universal, ('i386', 'ppc',)) + + + +def buildPythonDocs(): + # This stores the documentation as Resources/English.lproj/Docuentation + # inside the framwork. pydoc and IDLE will pick it up there. + print "Install python documentation" + rootDir = os.path.join(WORKDIR, '_root') + version = getVersion() + docdir = os.path.join(rootDir, 'pydocs') + + name = 'html-%s.tar.bz2'%(getFullVersion(),) + sourceArchive = os.path.join(DEPSRC, name) + if os.path.exists(sourceArchive): + print "Using local copy of %s"%(name,) + + else: + print "Downloading %s"%(name,) + downloadURL('http://www.python.org/ftp/python/doc/%s/%s'%( + getFullVersion(), name), sourceArchive) + print "Archive for %s stored as %s"%(name, sourceArchive) + + extractArchive(os.path.dirname(docdir), sourceArchive) + os.rename( + os.path.join( + os.path.dirname(docdir), 'Python-Docs-%s'%(getFullVersion(),)), + docdir) + + +def buildPython(): + print "Building a universal python" + + buildDir = os.path.join(WORKDIR, '_bld', 'python') + rootDir = os.path.join(WORKDIR, '_root') + + if os.path.exists(buildDir): + shutil.rmtree(buildDir) + if os.path.exists(rootDir): + shutil.rmtree(rootDir) + os.mkdir(buildDir) + os.mkdir(rootDir) + os.mkdir(os.path.join(rootDir, 'empty-dir')) + curdir = os.getcwd() + os.chdir(buildDir) + + # Not sure if this is still needed, the original build script + # claims that parts of the install assume python.exe exists. + os.symlink('python', os.path.join(buildDir, 'python.exe')) + + # Extract the version from the configure file, needed to calculate + # several paths. + version = getVersion() + + print "Running configure..." + runCommand("%s -C --enable-framework --enable-universalsdk=%s LDFLAGS='-g -L%s/libraries/usr/local/lib' OPT='-g -O3 -I%s/libraries/usr/local/include' 2>&1"%( + shellQuote(os.path.join(SRCDIR, 'configure')), + shellQuote(SDKPATH), shellQuote(WORKDIR)[1:-1], + shellQuote(WORKDIR)[1:-1])) + + print "Running make" + runCommand("make") + + print "Runing make frameworkinstall" + runCommand("make frameworkinstall DESTDIR=%s"%( + shellQuote(rootDir))) + + print "Runing make frameworkinstallextras" + runCommand("make frameworkinstallextras DESTDIR=%s"%( + shellQuote(rootDir))) + + print "Copy required shared libraries" + if os.path.exists(os.path.join(WORKDIR, 'libraries', 'Library')): + runCommand("mv %s/* %s"%( + shellQuote(os.path.join( + WORKDIR, 'libraries', 'Library', 'Frameworks', + 'Python.framework', 'Versions', getVersion(), + 'lib')), + shellQuote(os.path.join(WORKDIR, '_root', 'Library', 'Frameworks', + 'Python.framework', 'Versions', getVersion(), + 'lib')))) + + print "Fix file modes" + frmDir = os.path.join(rootDir, 'Library', 'Frameworks', 'Python.framework') + for dirpath, dirnames, filenames in os.walk(frmDir): + for dn in dirnames: + os.chmod(os.path.join(dirpath, dn), 0775) + + for fn in filenames: + if os.path.islink(fn): + continue + + # "chmod g+w $fn" + p = os.path.join(dirpath, fn) + st = os.stat(p) + os.chmod(p, stat.S_IMODE(st.st_mode) | stat.S_IXGRP) + + # We added some directories to the search path during the configure + # phase. Remove those because those directories won't be there on + # the end-users system. + path =os.path.join(rootDir, 'Library', 'Frameworks', 'Python.framework', + 'Versions', version, 'lib', 'python%s'%(version,), + 'config', 'Makefile') + fp = open(path, 'r') + data = fp.read() + fp.close() + + data = data.replace('-L%s/libraries/usr/local/lib'%(WORKDIR,), '') + data = data.replace('-I%s/libraries/usr/local/include'%(WORKDIR,), '') + fp = open(path, 'w') + fp.write(data) + fp.close() + + # Add symlinks in /usr/local/bin, using relative links + usr_local_bin = os.path.join(rootDir, 'usr', 'local', 'bin') + to_framework = os.path.join('..', '..', '..', 'Library', 'Frameworks', + 'Python.framework', 'Versions', version, 'bin') + if os.path.exists(usr_local_bin): + shutil.rmtree(usr_local_bin) + os.makedirs(usr_local_bin) + for fn in os.listdir( + os.path.join(frmDir, 'Versions', version, 'bin')): + os.symlink(os.path.join(to_framework, fn), + os.path.join(usr_local_bin, fn)) + + os.chdir(curdir) + + + +def patchFile(inPath, outPath): + data = fileContents(inPath) + data = data.replace('$FULL_VERSION', getFullVersion()) + data = data.replace('$VERSION', getVersion()) + data = data.replace('$MACOSX_DEPLOYMENT_TARGET', '10.3 or later') + data = data.replace('$ARCHITECTURES', "i386, ppc") + data = data.replace('$INSTALL_SIZE', installSize()) + fp = open(outPath, 'wb') + fp.write(data) + fp.close() + +def patchScript(inPath, outPath): + data = fileContents(inPath) + data = data.replace('@PYVER@', getVersion()) + fp = open(outPath, 'wb') + fp.write(data) + fp.close() + os.chmod(outPath, 0755) + + + +def packageFromRecipe(targetDir, recipe): + curdir = os.getcwd() + try: + pkgname = recipe['name'] + srcdir = recipe.get('source') + pkgroot = recipe.get('topdir', srcdir) + postflight = recipe.get('postflight') + readme = textwrap.dedent(recipe['readme']) + isRequired = recipe.get('required', True) + + print "- building package %s"%(pkgname,) + + # Substitute some variables + textvars = dict( + VER=getVersion(), + FULLVER=getFullVersion(), + ) + readme = readme % textvars + + if pkgroot is not None: + pkgroot = pkgroot % textvars + else: + pkgroot = '/' + + if srcdir is not None: + srcdir = os.path.join(WORKDIR, '_root', srcdir[1:]) + srcdir = srcdir % textvars + + if postflight is not None: + postflight = os.path.abspath(postflight) + + packageContents = os.path.join(targetDir, pkgname + '.pkg', 'Contents') + os.makedirs(packageContents) + + if srcdir is not None: + os.chdir(srcdir) + runCommand("pax -wf %s . 2>&1"%(shellQuote(os.path.join(packageContents, 'Archive.pax')),)) + runCommand("gzip -9 %s 2>&1"%(shellQuote(os.path.join(packageContents, 'Archive.pax')),)) + runCommand("mkbom . %s 2>&1"%(shellQuote(os.path.join(packageContents, 'Archive.bom')),)) + + fn = os.path.join(packageContents, 'PkgInfo') + fp = open(fn, 'w') + fp.write('pmkrpkg1') + fp.close() + + rsrcDir = os.path.join(packageContents, "Resources") + os.mkdir(rsrcDir) + fp = open(os.path.join(rsrcDir, 'ReadMe.txt'), 'w') + fp.write(readme) + fp.close() + + if postflight is not None: + patchScript(postflight, os.path.join(rsrcDir, 'postflight')) + + vers = getFullVersion() + major, minor = map(int, getVersion().split('.', 2)) + pl = Plist( + CFBundleGetInfoString="MacPython.%s %s"%(pkgname, vers,), + CFBundleIdentifier='org.python.MacPython.%s'%(pkgname,), + CFBundleName='MacPython.%s'%(pkgname,), + CFBundleShortVersionString=vers, + IFMajorVersion=major, + IFMinorVersion=minor, + IFPkgFormatVersion=0.10000000149011612, + IFPkgFlagAllowBackRev=False, + IFPkgFlagAuthorizationAction="RootAuthorization", + IFPkgFlagDefaultLocation=pkgroot, + IFPkgFlagFollowLinks=True, + IFPkgFlagInstallFat=True, + IFPkgFlagIsRequired=isRequired, + IFPkgFlagOverwritePermissions=False, + IFPkgFlagRelocatable=False, + IFPkgFlagRestartAction="NoRestart", + IFPkgFlagRootVolumeOnly=True, + IFPkgFlagUpdateInstalledLangauges=False, + ) + writePlist(pl, os.path.join(packageContents, 'Info.plist')) + + pl = Plist( + IFPkgDescriptionDescription=readme, + IFPkgDescriptionTitle=recipe.get('long_name', "MacPython.%s"%(pkgname,)), + IFPkgDescriptionVersion=vers, + ) + writePlist(pl, os.path.join(packageContents, 'Resources', 'Description.plist')) + + finally: + os.chdir(curdir) + + +def makeMpkgPlist(path): + + vers = getFullVersion() + major, minor = map(int, getVersion().split('.', 2)) + + pl = Plist( + CFBundleGetInfoString="MacPython %s"%(vers,), + CFBundleIdentifier='org.python.MacPython', + CFBundleName='MacPython', + CFBundleShortVersionString=vers, + IFMajorVersion=major, + IFMinorVersion=minor, + IFPkgFlagComponentDirectory="Contents/Packages", + IFPkgFlagPackageList=[ + dict( + IFPkgFlagPackageLocation='%s.pkg'%(item['name']), + IFPkgFlagPackageSelection='selected' + ) + for item in PKG_RECIPES + ], + IFPkgFormatVersion=0.10000000149011612, + IFPkgFlagBackgroundScaling="proportional", + IFPkgFlagBackgroundAlignment="left", + ) + + writePlist(pl, path) + + +def buildInstaller(): + + # Zap all compiled files + for dirpath, _, filenames in os.walk(os.path.join(WORKDIR, '_root')): + for fn in filenames: + if fn.endswith('.pyc') or fn.endswith('.pyo'): + os.unlink(os.path.join(dirpath, fn)) + + outdir = os.path.join(WORKDIR, 'installer') + if os.path.exists(outdir): + shutil.rmtree(outdir) + os.mkdir(outdir) + + pkgroot = os.path.join(outdir, 'MacPython.mpkg', 'Contents') + pkgcontents = os.path.join(pkgroot, 'Packages') + os.makedirs(pkgcontents) + for recipe in PKG_RECIPES: + packageFromRecipe(pkgcontents, recipe) + + rsrcDir = os.path.join(pkgroot, 'Resources') + + fn = os.path.join(pkgroot, 'PkgInfo') + fp = open(fn, 'w') + fp.write('pmkrpkg1') + fp.close() + + os.mkdir(rsrcDir) + + makeMpkgPlist(os.path.join(pkgroot, 'Info.plist')) + pl = Plist( + IFPkgDescriptionTitle="Universal MacPython", + IFPkgDescriptionVersion=getVersion(), + ) + + writePlist(pl, os.path.join(pkgroot, 'Resources', 'Description.plist')) + for fn in os.listdir('resources'): + if fn == '.svn': continue + if fn.endswith('.jpg'): + shutil.copy(os.path.join('resources', fn), os.path.join(rsrcDir, fn)) + else: + patchFile(os.path.join('resources', fn), os.path.join(rsrcDir, fn)) + + shutil.copy("../../../LICENSE", os.path.join(rsrcDir, 'License.txt')) + + +def installSize(clear=False, _saved=[]): + if clear: + del _saved[:] + if not _saved: + data = captureCommand("du -ks %s"%( + shellQuote(os.path.join(WORKDIR, '_root')))) + _saved.append("%d"%((0.5 + (int(data.split()[0]) / 1024.0)),)) + return _saved[0] + + +def buildDMG(): + """ + Create DMG containing the rootDir + """ + outdir = os.path.join(WORKDIR, 'diskimage') + if os.path.exists(outdir): + shutil.rmtree(outdir) + + imagepath = os.path.join(outdir, + 'python-%s-macosx'%(getFullVersion(),)) + if INCLUDE_TIMESTAMP: + imagepath = imagepath + '%04d-%02d-%02d'%(time.localtime()[:3]) + imagepath = imagepath + '.dmg' + + os.mkdir(outdir) + runCommand("hdiutil create -volname 'Univeral MacPython %s' -srcfolder %s %s"%( + getFullVersion(), + shellQuote(os.path.join(WORKDIR, 'installer')), + shellQuote(imagepath))) + + return imagepath + + +def setIcon(filePath, icnsPath): + """ + Set the custom icon for the specified file or directory. + + For a directory the icon data is written in a file named 'Icon\r' inside + the directory. For both files and directories write the icon as an 'icns' + resource. Furthermore set kHasCustomIcon in the finder flags for filePath. + """ + ref, isDirectory = Carbon.File.FSPathMakeRef(icnsPath) + icon = Carbon.Icn.ReadIconFile(ref) + del ref + + # + # Open the resource fork of the target, to add the icon later on. + # For directories we use the file 'Icon\r' inside the directory. + # + + ref, isDirectory = Carbon.File.FSPathMakeRef(filePath) + + if isDirectory: + tmpPath = os.path.join(filePath, "Icon\r") + if not os.path.exists(tmpPath): + fp = open(tmpPath, 'w') + fp.close() + + tmpRef, _ = Carbon.File.FSPathMakeRef(tmpPath) + spec = Carbon.File.FSSpec(tmpRef) + + else: + spec = Carbon.File.FSSpec(ref) + + try: + Carbon.Res.HCreateResFile(*spec.as_tuple()) + except MacOS.Error: + pass + + # Try to create the resource fork again, this will avoid problems + # when adding an icon to a directory. I have no idea why this helps, + # but without this adding the icon to a directory will fail sometimes. + try: + Carbon.Res.HCreateResFile(*spec.as_tuple()) + except MacOS.Error: + pass + + refNum = Carbon.Res.FSpOpenResFile(spec, fsRdWrPerm) + + Carbon.Res.UseResFile(refNum) + + # Check if there already is an icon, remove it if there is. + try: + h = Carbon.Res.Get1Resource('icns', kCustomIconResource) + except MacOS.Error: + pass + + else: + h.RemoveResource() + del h + + # Add the icon to the resource for of the target + res = Carbon.Res.Resource(icon) + res.AddResource('icns', kCustomIconResource, '') + res.WriteResource() + res.DetachResource() + Carbon.Res.CloseResFile(refNum) + + # And now set the kHasCustomIcon property for the target. Annoyingly, + # python doesn't seem to have bindings for the API that is needed for + # this. Cop out and call SetFile + os.system("/Developer/Tools/SetFile -a C %s"%( + shellQuote(filePath),)) + + if isDirectory: + os.system('/Developer/Tools/SetFile -a V %s'%( + shellQuote(tmpPath), + )) + +def main(): + # First parse options and check if we can perform our work + parseOptions() + checkEnvironment() + + os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.3' + + if os.path.exists(WORKDIR): + shutil.rmtree(WORKDIR) + os.mkdir(WORKDIR) + + # Then build third-party libraries such as sleepycat DB4. + buildLibraries() + + # Now build python itself + buildPython() + buildPythonDocs() + fn = os.path.join(WORKDIR, "_root", "Applications", + "MacPython %s"%(getVersion(),), "Update Shell Profile.command") + shutil.copy("scripts/postflight.patch-profile", fn) + os.chmod(fn, 0755) + + folder = os.path.join(WORKDIR, "_root", "Applications", "MacPython %s"%( + getVersion(),)) + os.chmod(folder, 0755) + setIcon(folder, "../Icons/Python Folder.icns") + + # Create the installer + buildInstaller() + + # And copy the readme into the directory containing the installer + patchFile('resources/ReadMe.txt', os.path.join(WORKDIR, 'installer', 'ReadMe.txt')) + + # Ditto for the license file. + shutil.copy('../../../LICENSE', os.path.join(WORKDIR, 'installer', 'License.txt')) + + fp = open(os.path.join(WORKDIR, 'installer', 'Build.txt'), 'w') + print >> fp, "# BUILD INFO" + print >> fp, "# Date:", time.ctime() + print >> fp, "# By:", pwd.getpwuid(os.getuid()).pw_gecos + fp.close() + + # Custom icon for the DMG, shown when the DMG is mounted. + shutil.copy("../Icons/Disk Image.icns", + os.path.join(WORKDIR, "installer", ".VolumeIcon.icns")) + os.system("/Developer/Tools/SetFile -a C %s"%( + os.path.join(WORKDIR, "installer", ".VolumeIcon.icns"))) + + + # And copy it to a DMG + buildDMG() + + +if __name__ == "__main__": + main() diff --git a/Mac/BuildScript/ncurses-5.5.patch b/Mac/BuildScript/ncurses-5.5.patch new file mode 100644 index 00000000000..0eab3d36668 --- /dev/null +++ b/Mac/BuildScript/ncurses-5.5.patch @@ -0,0 +1,36 @@ +diff -r -u ncurses-5.5-orig/test/Makefile.in ncurses-5.5/test/Makefile.in +--- ncurses-5.5-orig/test/Makefile.in 2006-03-24 12:47:40.000000000 +0100 ++++ ncurses-5.5/test/Makefile.in 2006-03-24 12:47:50.000000000 +0100 +@@ -75,7 +75,7 @@ + MATH_LIB = @MATH_LIB@ + + LD = @LD@ +-LINK = @LINK_TESTS@ $(LIBTOOL_LINK) $(CC) $(CFLAGS) ++LINK = @LINK_TESTS@ $(LIBTOOL_LINK) $(CC) + + usFLAGS = @LD_MODEL@ @LOCAL_LDFLAGS@ @LDFLAGS@ + +diff -ru ncurses-5.5-orig/ncurses/tinfo/read_entry.c ncurses-5.5/ncurses/tinfo/read_entry.c +--- ncurses-5.5-orig/ncurses/tinfo/read_entry.c 2004-01-11 02:57:05.000000000 +0100 ++++ ncurses-5.5/ncurses/tinfo/read_entry.c 2006-03-25 22:49:39.000000000 +0100 +@@ -474,7 +474,7 @@ + } + + /* truncate the terminal name to prevent buffer overflow */ +- (void) sprintf(ttn, "%c/%.*s", *tn, (int) sizeof(ttn) - 3, tn); ++ (void) sprintf(ttn, "%x/%.*s", *tn, (int) sizeof(ttn) - 3, tn); + + /* This is System V behavior, in conjunction with our requirements for + * writing terminfo entries. +diff -ru ncurses-5.5-orig/configure ncurses-5.5/configure +--- ncurses-5.5-orig/configure 2005-09-24 23:50:50.000000000 +0200 ++++ ncurses-5.5/configure 2006-03-26 22:24:59.000000000 +0200 +@@ -5027,7 +5027,7 @@ + darwin*) + EXTRA_CFLAGS="-no-cpp-precomp" + CC_SHARED_OPTS="-dynamic" +- MK_SHARED_LIB='$(CC) -dynamiclib -install_name $(DESTDIR)$(libdir)/`basename $@` -compatibility_version $(ABI_VERSION) -current_version $(ABI_VERSION) -o $@' ++ MK_SHARED_LIB='$(CC) $(CFLAGS) -dynamiclib -install_name $(DESTDIR)$(libdir)/`basename $@` -compatibility_version $(ABI_VERSION) -current_version $(ABI_VERSION) -o $@' + test "$cf_cv_shlib_version" = auto && cf_cv_shlib_version=abi + cf_cv_shlib_version_infix=yes + ;; diff --git a/Mac/BuildScript/resources/ReadMe.txt b/Mac/BuildScript/resources/ReadMe.txt new file mode 100644 index 00000000000..1a6e63764ff --- /dev/null +++ b/Mac/BuildScript/resources/ReadMe.txt @@ -0,0 +1,31 @@ +This package will install MacPython $FULL_VERSION for Mac OS X +$MACOSX_DEPLOYMENT_TARGET for the following +architecture(s): $ARCHITECTURES. + +Separate installers are available for older versions +of Mac OS X, see the homepage, below. + +Installation requires approximately $INSTALL_SIZE MB of disk +space, ignore the message that it will take zero bytes. + +You must install onto your current boot disk, even +though the installer does not enforce this, otherwise +things will not work. + +MacPython consists of the Python programming language +interpreter, plus a set of programs to allow easy +access to it for Mac users (an integrated development +environment, an applet builder), plus a set of pre-built +extension modules that open up specific Macintosh technologies +to Python programs (Carbon, AppleScript, Quicktime, more). + +The installer puts the applications in "MacPython $VERSION" +in your Applications folder, command-line tools in +/usr/local/bin and the underlying machinery in +$PYTHONFRAMEWORKINSTALLDIR. + +More information on MacPython can be found at +http://www.cwi.nl/~jack/macpython and +http://pythonmac.org/. More information on +Python in general can be found at +http://www.python.org. diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf new file mode 100644 index 00000000000..cb65f094097 --- /dev/null +++ b/Mac/BuildScript/resources/Welcome.rtf @@ -0,0 +1,15 @@ +{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf330 +{\fonttbl\f0\fswiss\fcharset77 Helvetica;\f1\fswiss\fcharset77 Helvetica-Bold;} +{\colortbl;\red255\green255\blue255;} +\paperw11900\paperh16840\margl1440\margr1440\vieww9920\viewh10660\viewkind0 +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural + +\f0\fs24 \cf0 This package will install +\f1\b MacPython $FULL_VERSION +\f0\b0 for +\f1\b Mac OS X $MACOSX_DEPLOYMENT_TARGET +\f0\b0 .\ +\ +MacPython consists of the Python programming language interpreter, plus a set of programs to allow easy access to it for Mac users (an integrated development environment, an applet builder), plus a set of pre-built extension modules that open up specific Macintosh technologies to Python programs (Carbon, AppleScript, Quicktime, more).\ +\ +See the ReadMe file for more information.} \ No newline at end of file diff --git a/Mac/BuildScript/resources/background.jpg b/Mac/BuildScript/resources/background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b3c76406cf4a264410e12d5af1c11380164f1e66 GIT binary patch literal 45421 zcmcG#RZt~O&@H-gcOTr{-Q73t?l8Cw?(Xi+;LhOgHu&J~HnbBR@AdU z4elQ0mlA0JX_iq}q^@c~H}_6gX{1`2s%fVxt6@r(O#@pIh!k1D0T#SkSX9{Wld$sC zCcL$6JEIaX#d=KOdg(_@qGUKk;7jzx@pj=}d;RTzzxRM&M&eJgbOKSq?_Ch~zrSi>D{|LL>- z|Bw2gDgN(y{eO>w0T};v92moy{jhR;9TqACkh~50)$bhFf1up=f$vWA;{vNr@CE@8M4FG_J zLb?t{STY140`5ubd(7HF*gl3w9UJ7Q7!4VsWJfyBPeC$w_M2v%M(Zh%a3qiU3dHg| zbsisoxF17aFmNfzJ`A1_;++ZfrZNkEpUn~@x-xxmGrtZLJa=0Z&FaGU8I!jATOlgp zl5@>4Mu@Xg>ie4`l*ile{az-}%Hs)*TMHb)bw0Ya*Z2Q{5d=pj0t~KJv^!XRgwCWH z3K0f=ck!nl=s9tBe%%+!1W*mm44`vwdqLlm8l#b4dGC_Bqol9$<2t{6oUo2YdIb{X zl)47}Y7>+vHvXN3H>r1=Yv?m}^Q?FAXKGf2HSx}s)DQg8VQ~YSC#TzMzB>lbsbtp` zCLdWKp+lPinM91FF(quhB+RC>=p=1>Iq#Y&iWL35h1hrPiBQ5Dw_M)n$8V* z8GF{5YkHG8y$;T}6y@V6Ql z_B0uv?eh^9cp(Xn#4V2}96V4W8gQdd*v(Fnc6v!-{8~K-V{P0b>Ry@QM{^9J20^Ab zR>Z0O6aYZc&h+}s{$*{*^*x6Fd0j6%ImTRY`?-L-4Xyh;qPK&%g3yyl&l&Xol5pk@ zKJaBGz2T2f(Ptcw>o96!iJ~C91b%1O1Ys{srS3DxIzczgl{|sqp`3e8hB?0Dv5(m0 zMFo&CiBYote&9gp*mBps#Tv&f%@WFZX=F9lyvM7799-MBANFVf}5a;8mtOQT=zGtJJySJ-#e9(%| z;~*RW7yQ6_C4X40o;OIT^B5^%$V%{qE?1z}pnsqsA_F{X z)3mH5DnXbu>bKjr?dce#gbs=|w4p?`>_Y0n?V5zw_FWQda;*S;X+B3g#M84C)79?Q zbsv=DX9&LYXGaVwY~AYM+IjrGA^n_JV#%mq1!KFyInmt~hl(djhq>nR zp=@tg_{3~7L~hwd3f#?~?32rC(Wg!J9gXWcx@cc^!slX?t$6OwtAc&;wjCJqxB`Fl z`kr52(<`;heS(%T_t&!AR-&uIO=`-@^`rAkhk(;WU2mwf6UkZk(Nmy)c zD}b7IA?vo3iKbZ_OB&jEt~v?8jwe_j*6r+s3J&Cjuh$AmckTP$gobgQy;1atMSMTilr|s!ZJbu=Wm_@c&B>1bXH~PM z0Kn;F`@OF~2bppKj&xT?sRLQ5^ASFlHbeAi82C`a6xujRVD2&~L%(dFC_2mrRkijz z6ud|lFAb9gd}(U*-2S(qNM0qG27DLSTlUm+eji1kwlmkyNZJl#vD!C@s^_H5!*m`6 zmH7g{ZC4>Ak4@Ka#LqW`0E&w=A=OKY0|x%=TSDD$SQGb^Sy= zh1`ZuK?utFJ8@+y^3ZMP__QlsVO;R>+9(CAg16+6;7>PMG$`LW*Mg8Y#e$(MR~!HU z)J) z)i0O(lP;;onu-MglPbUp5bv0ph!W?|uPAPmqy6 zm*MBJhe?BWV5rkv`y;%*&&Uyv_cQA8 z5CHz=kSs}6ijwBE8i1-FWg58H+$;c-l1lB8$Kc$rCPLZ4|8r^lQI*Iqw6#xGFdJQ! zohT@<6l#Ets7S@VBGY7+empVheDRyhlC*|!8<7rEzcaZaU7k-`N+EbT zRUb-tOPbB2`9@~1!cU#Xo_2X@A1lib^rpJLBHTUR zxEe0-{fm8ZbqN9Jy>iWu{JhK&hS|tzN_z`<#83hQTnTl>1boEwMHs#0dNg@t~+dcJePuX8mGJNieb?z8oBL z-0L9q#YZ0@5nEM&XX%pJ4=PGx7BF^t3zEpSD3@4&6uY?`sNe#@EI{L2!=G{c@erRk+=UKX;wcD=O)X3Ib6ZH~TqK+{j8Pbf5fs7>C>6i9y znV!QKjN>Z{GB&~#_`w4)<=^M$v)Nv-0+&lT-=)5Hi;GL*-GtAJ5YOEU9f1#8rO~e> zi~Z$-EhO6!h&c{TH*XWHX+v@88nZocb_m5=9i5982acFRL0*I|wHy@l#{oO_M>?YU z$TB%xBpg{KX_PHdhRWZw>Uv4wHPelp1dlfSmY>QtMZ{61;LaB+$c*lLO!yqS$39i2 zOxrRp61lPB-U_a+ZwF_U+H~FNY5$n%YS3o_1NXlQc&#R8|En$VaCYz<D)ag_?@a$xK$1LJ9adtxq9UTIYTvf;mZdr!+Z|FQv@~Y)-u+4Xo*W_;G~n)G3yu}B~dHd2jux{u2^tfb>uG}FVjP$c-x=CYHCpn{v( z+BON{6ABqf{5**10u6P%XarOf*M31h_J)GL9Y}wH0<5ZXs~a2iS|`31)bGXhpHmTs zx1W1j!U#JbpYQ4JMUXKe5WY7d#E|RZ20wPE#}wTvWrp`)#YR-X(#Z~)f*!dn{ujJ6}@qo zn9+p?4F{x2D2q)@Gpjasq{o8+b`B24v1YUzcE*n&1AVtMZDGwX=ofBkHO^g=uEV=$ z1+EI5{vA>hiX(Kt9`TP?;A0)*d4Yc>^%5lr7Kcf{KaRK)P0Pp+E54u|@qTRz4p91| zHM+J+{aZ!LnX)FYqJL#y492hD)IH!KFY;Z%Q?48UxwSO*+CyElc?up*C6|S}32wZ? ztLy8wy!KQuucT1Lk*-gnz<`Z})vw_5(`hqe14H9Hsg4w;A^i<#gIELz zY00!Ua<$Fm(D9(D-|d8!(6#Tpy1qW&!nNsXm>MfJNn_)$Nj;~=PGqu~h_@LtnX3Gc z=lj&L){_S%jM&Io3vJuPL1`p)-^0XX!TTwb-nSvCQP0gGYwSLgMhlLjb0+n(?| zmikP!+7c-g*{_tf8cs_nN=*)S^l~^7Mo~EMBg9YN>nM%q$9Dwa#rm<_l~l%_c8p+) z$eFBpDn|Db(vgdO-cVx27)mW=@+1|qmK<1?h$5WDvBa?Y?7V_}P9l0J?<`kTDn=rEaa>Q2!KV9p zEsx7Tns`F~@E6~3)W+a&(KyV)3y74n4N*1&7X6LG>EBi=u$_$y_E3yRYWEuUX&ICe z@G`W^wYaL`vh+Mu57?xKTb8{&4i@+rdz-xi|9e|FTe8}j#GQKWu|{t3<|zg5eEbna zIdyG6`G*`&xZXeVK`DU_`E%_+Qf@cadAOs=$_e!DWkZ-*mNbu@VsnhAK~PhwzKN7ik*?u)s3QjD9!{@=LOeHe+mzesiGJf5 zzg(SRa6FjEoceu*#zuYPO}I!x0aQ}3h*ZmOVQR-Ed`?wa$=8g|W_w|B--a&#xs+M# zLuD*G7wf0W%8k6XSPEw0HLi$CXftFy|A7(Go?xytE)GN0aTcXhzc0(L zlSvcQbh^ac^G4dP%K=r7n=IHV6UqT&uEg2hCOBu%acw`+Fo_*u*cQ@x?p+z77`VOcrczED=Y&!EJKcZloE&Y(VYh4a4>GuC0%H?N;rPtE0Z~!VsByPV4knM$Lv>t5P4;BWp*>#1G{Nup zgg9lcxcF_npn)Kl@RIl_sG5nMlRo_LEK3de3H`~=&Dwe)iSy+}3fR#RaDE&Q=e>O| zeVza?TFDdqlF;5eVSlc^|6q(^C6pM=a>+~8WZ8}hlfER7ce4HcHx=lC8N>vdTM1Y$ zcr*E2?(@N@>$byh3TnVL!}Fst7HhpK)6Gb}r(pa=f=8n!7iNS;9XJ*8Gpz!PygrMB zHHd~(s?dOu0jh8~A+<}9*jhF_b=G8NsCG)jR|XNXH5Q(Sho}GL{-mL;FQNn`+pnyY z6(hy%vF5+mmaaUehzfuuEog_p$h;pP1V+-H@)9IQ{^CVxzrAYmeAxgY?%Y8sy=4+V zTz?4n1wHM&0`gx%Q`(QV?`6!W8X->Zs3B*l+3231drs3t-0KH;aEhjuR`D3NxmB7l zK3rX(|G242=;LXC0ad|e5~rpS%uaJDE5n5z*=dg-D!+%19!1i~4xqSYk^C{Y;0nx+ zrt5TUd6$5BYTIRQTqHXZ01rn+h0R2XT|;F-iG5)(=3?Qpg5U}V8xqNc8tplGyeXlN zKS1hxGI^gBe&D*eU>3Gvd!YxdG4I+3xbO?z(`p&V1~+vfz(NGU2|%*Iu&`%BgeOiC z&%CpNE3m;=mNTCFe%BODZa?jiS(z0yX~0aYpAJWCub}uvBq!u?bAOi|c{wBkH{(LgoCW7PhWIk| z*rb2dx8IlO7bh`G4wU|;(XO~h!N`gKgvRO`@$Jj!p~iDt-yPAWo8?Jz;C*rZo1ib~ z^A3J9z@M1e_xORQnRU$msbGu;-f}7v1?)aC$N?L-Ndz{CB~-b990S@EF&Ck>u_w49 zRwh#1Yg6UYL&l*Y?ljJI@$j3}yUf9Flg-OFRsd>4|aFH(A`q&H!Iu5OTw zEs>=TjK(>9gd$CkP@e~(*AsST|9B&lb@+0gP$xX$B*^WfLk7=tTD&Ij?k{*ma+U6z_|S)slw!5^;cKcY#L_Gck}%WzIr?*Z@(y${e^rdNh;G65~+c0(_sS?{eH%${2_z#S+f9EOY|(W`5I_ihOiT1R&h6PZRNOt=;{myLHhaPrb_+N?N;JiZ(uFlfgx zlc9V|5w0!jK1(FzXvzq;_1|$y6|6lze0jQ8U*y|?=UtRALTsGQZwqXQ5cdq|X_1QD z$Td20Hu93pAR73Yi>rh8TA23RI`-A=Y%^P-A(q3(w{6p?m@b&rH6!DOSX9{Kd$1th z&vFD1c;&OwWZx))%zZiycoaBXEUKHC^?V~WDg~)W9L=>Kj+4+&ByElZlDcB#(x#&} zJ4}9a`rT$sGQc=qoCP$Va>8J=xN7R0Bt$7hMVupQ#|vBHdXF3emjt2r*H^98bX1=$ zFGzgGzui(K1ijP!MNtL-6ALVaMT|-k69a~3LUzSaGF>s-5~@9?`eGFzwdBHA5pV$z zbGvMzdD61S*(_y)MImX;Lu!YEQ+cl2WJQNJ@6GSuRk13$+@fs@X zzmu1J#>k{ZF$X`Cpf7EK6-{hk0Gi~*e3n{Q3|+Ngzk5HZ{Z8%$zCN4K9L;!nw=fHp zJ17rQgUMEBP%O(;5ssBrwb|h4FU$G)iLp zQVx%o+)M7kgK}sNpUTu zlvZbDuxVG!#R)EhbOKM8gHK4}FkuzVM;{r{;Z2)DbfAaiWj=Hhb=XyJj-^L{s*KN4 zzqXqG+CAA}b|xhBxW_N;kQ{m}%R0ADfBWzM&Uju3AN_#;`siU3kwV<5SUjy<&6#~0AN;IF zMD9*Ux_Ga^Gnv0!Uf@fuVqFFcNwC(pzjV~pWUQ{qnbQYRwO+1K)SHsS@ptl%ewi=-tjvC|&WWn)30 zK;y9>>u?g2^qF_imyzk6r=iaF!fgZbd}pAlG93LNTyC!Y0EU!&r8`2h6HL`LN0t5X zN2SUh75wrGjmwtFye)a0i?sK0XlZvU!xn)@MpmrXjf~I3afm-KeN$3Tq-Q>5D$f7& zeYj~XIV_kw05cE@vZ-G#7F|S^y0@~y#(2>osRKI$&q*U<^^#AYCxmAH?s}8uD^HJ1TGu8!Q7ZyI&U}6xKy4za8(U zRvbtR#G3iPP01lltEZ*`)8KyQ8t;j6bgHV7E5QBW*0A)2BzvJo$54zDD>ns3!gI+& zh3`+T>ovGc5D7cXRISO9vW*YZDL2}0XC{si)%ixzmFlN73in`|O|3aB^(##poku-9 zQvmW$Kuz2qlGwagWOB9}&DftG1)phszpQST13v6mgqM*s>tBODUklvLo)yt(cFh|% zTemVrGoxb9X>_Y%kPyZ%TR8URMC$|Ve3RomQ%C#*)#SDO6q7p*r6-sqt+~80cdh7W zy#K|X%p!4dR0=NRt1b2YeT_@tH2pT@qB9Mn7VYppac=#)DsP|BAVTn*`cDmZ&YA6I zYG;zbai~n{hQ_#oI^toYvNG78Wl0E&q3`Jw6m4@Y5K1ul3DCxx0JBE)XVHg>UWJW> zwgf!SQQY+6s$hgHpxa^e`(WRN!1rP2jRPBD>a1tY=0`zQLHA9u-c8;REs~7ElrT0L zw4?ZfT3sfHnl;~8lHJPZiZ4vRRG5G$6AYK|M^KBX3fHXUsA5ofMKpxjD6y6%b6P%2 zAHN4VWxiwrtqYgOO5E8uK@k012Brh41~P}TxOKYD)?S8-0!$^KZTeAA-QSF4j$XlE(>RqD&lI1% z|FJPb(EU2&E@x?26A&EV&^|smV{+<@Bz*G#caon6pKmS58PSjd-sr1616_{k>Cqk? zs&hoP!2sI$*O4HpSzR>46c3Bx8rQT3(uv{{0ZURod<}^oN7hQmbv@LY2MTAZLu^*c zIyirSKu2;U6*lwl^R~uQJ7TqH@PN_M6>9Uxj0g%X-NsYtv4RzH;6zt7p`}3=!h(;e zdH2F{-^g_WSyT-27%Z<0Cpm&zo+-!kb~bw%UmtR|WtsEtXI6mpAIHgM=%GcpnT;_s zJim=D(w*-OzRdvDV|J-+B#d0vh6W(UHFQ2565^U5B4qt2$1dfqO?S-!6RhK(`a z+I?+K?)u##E$fAHo=Kc+Z+NAvYGm&0XQ}Rsb|+-izS-n#ELK(MGUc*n+X$E{TT(2N zb^kkAGu`DS*2Vmal#Rp!Tc-&t!opc7B(=u{7JOtm3w%i@_qw9`mfVBIia7Q0MeXjD z#;PAQ)LHZ|D@oZw8jcYYd~=Rlzt*SkenSIN-_?8Cob$qZ>O0>5#4*!cdVT81vtqY>t5=HnDg5!|DNb^zE^D(;EsVCPpL~` z-!awj`73K}t6P(+7zF7zBIezij;$Ks@m&&=28MhGRB2G{p)oODOyEuzOiYcQ|GF4+vzHj{8yV#p{I&OlyTkCsU zpM3@8jbJ%$=;S}oFn=x=bbN6}LwFou@!{WoM;vj+pcwQu9R_$$j_gskF1 zYN@J^xDmnAH^~4{kyb-DQLTFHlUwJ3?nV}w&7AB{309rhUGvi1F-J4JC6E`)>0b=x z(17VMuC)H<*4Ri4|5sT;OkU5{I_bPu7)9l3-SX6oPST*7h(r0WMVo}08eK3|j*97# z>$SFBEQ&jApBXOgonNLJMP1wXA(XwxSoAtAfc~yN#rD+}wpJwp{G5maMA?|p^U?fluRA`eD?z8zz23H~^8o_(oNCI1B05|v7kHgOZ`@bbM=;wCV$=6qGqH1=`o)UC z)7ta1+L#H7={!HBJtb>m>fb+#w#%+<{{gnk!{%3L3QaajtkKnX3m{`VW`8ogzN{`P zhRRLy`%{szR^a58W2%NSdt0nH8c!KBgB+FX6AJd~&d!kF(`L+uLl0C}R~H{8bD?tm zoe+O5UK#z#J0=b%#KR4{MLfCQgX_$}!wf)ZfbZA>6bCE&6plA*mR?~=MzJl|vh2N- zFM-b0S~ohUHXBwFGVYe73ob2nc?Ts@RNo*kM}?j=N?6jKa0C+MY4>D*oDBfLbUleB zvfLyy@4WxP`TXjc8Cif)dd@L=tgZKTgUMHdy?SOF%nI%*zFoXhVE*{?vW9YmIOfy; z-J74Kj;A$l*6S?odEUw>fnLdu`z^C9=9mc4VQNe=RZnjJAH#PrDJsAp065()<}WlD zK*bYb%9f)bZIMq_gE{kqvo2twMhf_H7zr(;>St3V17X_QD^Mzcse5{sYLz4L#nZq2 zA=MA~IB!W|u`?o6>^oCn{>=V-rrf#f>{|*t!AN`f zojL@l<88lveM5e3x$a=`(VV+JADGGxCf?ZYU#RawGy-LD@1Cw0hWB$!yJ->GxO8)` zh4UoJB8dRma>i{c51RZ?yhW~X)Z-r^(LjYt; z5(=8=a##|I^dugTqdyhV)=x!BmrX70qyVj4+)n$A2R!YzeTJ(`0^9X%4K@A85?=Oj z8Xg7m3Y_q_!|}K?mY3^-YEyERN43Mu1XykJW4CIhj4g`eii|s4L;}jHB#l5RQxGEx zQ&$#&G#fZa>IOO)i5Yt<`xF-|fgd~lR?P+Q!hRYe_IC8QDv?0OFnnszP#{x z*v|WT!P=KU!1yo<+fA=W9p86H_AJU#JgdL;r~}~$oR*^O1wQdsc4LGN_;Pu=JLX?p zdNrT`^P&G9vSfjbRz)%X_v3mZ@)J9lfpW+kRHe%mO8it$+WUbrY<(DcyK_6O=E7Gm z(&}`@=HivpokiWX>r=!~Ih9%TE#KtLq{tyT zS{ki=eN{9%zR|rce%#O~{|KCRs&W?6VU`$4$@;;|zh56qa?5>qrX*7G;;>3w|piH|fyk zatWH(Y&B8fKmG7GYvYgkQMfSc`_cfvj6~2ow_9tGCI(NT;CK5OHq1;-*i2gHEZzb zB+x78621xR1F;)@U>Ln}`=54w2}g&F424PAa8AA_WuO1@+3&Br52s1nFMeZ#UQdLu z0$!}O$XQI#Hn?t60Zbxf)z%#+w%^!RK6+hP7T&0*-DTv9&x*L^7%R;OYgZ4XGqBPw z?zxwPW$Q-m<$>G5#81cM)#-?3=S!L0RHGX5nGX4lkIv?dE+YOSE^1WM|c z-a*Pewv~=U+nj6iho|$)96*J#@R*2a6NERo^CCDo&p6DxP-5KCXM(8@nDg}?KhoxQ zg6enk@dMxvT*`ltDcOT=J$m-~-dlu0jX0l!311qsj2!*gW0fU@1W&K)Lcr_6mp}AZ zTpCOKu)%w87V3xC>jDUh(5uu$Zu=Kd8{;t*(%qDg{NAsnQm6V(K|rtkzp^J1cutEo zJ?0F*FL(bo6~P6VJ*DY$QPOs}l&1s#cvV;*lU+Gp*rLb8v?Y(7D`UKq!CU^>TuBB4>qPIxC%mcXMFKVOaY5xpG$x4 z>eMFEEabTCKS9-W^rs@WQV)m94fAusP^#UqvU;!DW}-8Lcpb+w9}ZdeG-z9*`1D=| zYFTaW3`P)hc_*V6tk<$XsjMi0puJM%#&vuY|Dyfn))ug*44 zWf{FEQy2W@wRV_;ECHXP^zr-b1umSPT*i1>dc*X9J&CFX)e0vHj6qE*gJKTagCavf z?c!}`=Gpv7m)5IWQPC|eWh%LIt+`kONu05{l9dsaPKR-!%I8D>K4>&hPPhLn{o^6% znz!sHiU-~rO-7n- zR}DzgTFBrCZ{d*VCBGZ}4z)uD2|;4UxML1Uv3Juzy}Rj`abSD`0uK**JYBtL^#E@# zgP0vtS7`~6pf_*)s>JI%#ozI9e{}qob_s6`hJOz>>vgyEU)@Z4Qub6?syI`KHJ^OE zUKY5z%f0|a%^ccTu@BSuZ*v&AIbj&BIxmBnOgd%Ex}UU3s@7Q4m5i5ih&iaUXd}N7 zz-kZKf_X;%{-YbmWXR@}9XB^#QyGMebjfP%r+^$JF_>bkH0&i9_LwZe*V!RCb)Wx5nwW~2 zF3EW&dfnUK^uZb9xW-^LK0(3*u9kx0nW5>R|FzN6K<_50{gy&jkwdHRe`7b#uP$ z!kK`CL47h}}9m|#AHH6KqH zFWF$>akXx>RxfuNForc%iPo!SD9v+RIDJ6^vSI@qc`QiNOb_2}8v;-$@?aX|##9+} zU`csQ%)#dhx0o2)%H%vD2`Lq`_ZaB@oQ;s7jK=f0uVFYJ=L?6HL}Ee~X|+rq6Tg!J zzP#g(ST*DYV($njFmm-SXe+b8>qu)WqJ6QDZgc)_i}03|U6%&bo16!qR&TeWl;l`= zkT`m5xhTpWhqXxNQRq@n*)v?}*h#cW=O|nZ2~+5FyL%WirgxZXHfgOEa-Mi9h-mbI?1jwI za7LIzn+J_H*>*Dtj^f~GGRbyewVIp=>afJjyTLU=g9EFE1ZHi+?=`eT$(R&XBTYoz zhSe@&T#vwCKY4+gvS?z^IFl!lfVG91avNW^a4E^%QjlFJ3C$R}WQ|RsB%2t;-l_%n zZcx`w&Lr?lX3ks)Tf_gH)cP3fyW2MceO0Xy+n-dycB~(sEN&|>`^|>EG|3amHQH=4 zJw)>rOp6HY8r$(JtLTyz;yjP*7G=u$2+;LQa&IS=U_r!}b`(=4V!Wk3Hl3JABr>=< zZ${VFCZ(<)c|G==IY^+(z^drCE~IL!_S2-fjKh5=D7(2HHB?kIL4}GqoSM9B z07Rju=HciqDY4A%-j=`=65~Tg|W%Y}J@h z*EXultyg%7VRt5}LE}tffYyZk;Zq+N8C@PCBp$BKcW$t+TH3#Cgw_d+(%%C9zTb#f z6V@z8j(9+XzaYXyH4x~j7*e{qLH6^BE38Ck$5P2o-b#2TdYh(Q4By(n z44J@Yy^&a5Vj}PyCDWXqlR^=bVC5ht@Yvxg0b%Jgq-S}St~O>m^nNvTAeHHC=^dv{ zH8Y$SCe@_n%UU+p$gF@OlN79L?17N>J@_I}B2rTk3Wz5C1MN$41l%PDd*Ttl3SdoYe1W-t9g3K8 zIneUK5a|n2x@Sf$Si>UI;CWO*aYsJ*q`$6|n6xkna_?3cM38C6 zDc z!9P_%Zo?m?V`mRm~4}Ae9pq4{7 zg3?|Oz#-jre{5W>_-YJf^mmbwws}`<3EUKw02){MM7s8vYLm;t087;s z1I=F3g;vmZS>#wmbAz!Mmh4t(V{^n9;W`>S(N(E%KEon=Fi8K zcWsz_n4g~CTf7IepgtGb>b&8-EByq$s$6$QdMMqIt3W;Q&oYzbbft31>e%8@!)ILw zOMStrWRgaT)(GozG;{XZ>2W2Q@X~Cfl>4}7W;1+rHzk%Na~WEQB8$BP>l=xSks!qG z$batJyb@LN`7LcGIr3Yb#&;R+3oEH6iVKJ4g-8-eNBfj?Tt9dr-Fu~%Xr|b{wQ@CC z5^Ba_rEuDIDQ!~9Riagx|CE(JxrdShi-DxI9OM*bDFGu-pvxe&Dz>pSQ$Oyyh{hh% z_VbiulV|}W^ZGHgy_<*dWcGIBj5q{z6tw&!`!-YPa2K3xY19l*Wl1yhpOuWTTljlO zX_<>1*qp-(zc$V?0!zg-#t9%Gy7~Y~i$|RAF}7rjcE6AMJ@4Q6_KA1hT3XkQ>bl56 zr*2&P10oWP;$Mz6lkO4zpjJcE%}KaB?F)<*999=#CMKtf(v*f~lBG|g9k>LIxJ2Pf zm(a*KFUDohDY(m9N9nejL;mW4&ga|sIRO_vQr3m|mXbfND?<-!aJ7>+R4+)(qaInOunqk4Y8&z&R#fxZpFb-w?35ZqMio0LNN|xm;N+>d=BB_HwsoPo z*oD^|k|tmN{ur0oycqE?RZ;zzCJ>732PGxwqVfNths`5vNKeG|U;)?VhN z$@B%jUHaDKP49>mTqS=vc`wfClP&Y3Qd63eF-cRwv`7y=T-r$1{V1V%z@r+4o4KHk zv>sd`YqjVnY{>n&OrU=9ymK#Y-u!e)z}3bQt-ptpvOmMGNVR=rXuYTzXh!}>H$S;Idqk+4CZp`lOP*vlz!#3hI) zK9ZGFN1G9&gl1l@)%0FuT^AbytSgD1D{Gy%AbfZ6jhlY%Vr|lGF}bqj032M6^U73d z#wQ254M>(UiBvK)ZeJBcE>A0E(%n_-ql#73TG$K)!XOvW{IT7OZxEd9M) zPs;mYAa3?8@9P(syVsb?HSdAqY=u>pBALOSr>%ry>G=IWk3aVlAa4EpgTIS=RXIn2 zAe6q+(_s*Z=n>_yK|h}Fjl$tfSJ!{Y$}HZe3Jxe_!k%#M-j#tNresqI&RK_0`r}_< zbZ|y6Ces+74`&|wlSg(|WJ_7Kmg0tDN$Ulpjud6If{_`CoM|BGlE2u%1oI=pjd8Iz z5o-{sMz4(Hq{5nvMLo8v2Ga?Xx&I}ttUW7Dvg}l}rOCtzcR8Yn4I~P7$)ZEkFC09x zAG4y_p%ERe?2y4CqLT)r?F3(iWs(Hze4%T;W%V&hq<<`0_za9{mDI9wpW-8yF6WUj zzTLzYXa9~M!$kr{(#={~62P??JxmI}D69l5c?h^n)<&cqRI>jJjzIvyxF<%dv1Ghh z1o$WEIZ*z=Nc`2+6|!;FPN-$%g>{U7KfY^rV@pjC? z{h&vvk=ZR)>bMDST1R3Q9}Mq3dSKow1u*JOdzyy~TPq9R6|LAV^C}Oyb(Wig$NCb+ zH+g)($(HPK%EGb7+oq>W5&xn0TsINnvy!^hkO10%BCw>t&<}p<|A6f84|V1>rM@(# zcQC~b?^Y2riKamTEzi=oWGT`vRFmaJzi1!PWK2@Jdw7@#>TH-MC1W<~MD_zS7eI_;uY5elj5i+AmnTQr)V3H>nJaxedskG#ThQDY+yc196 z)T4vQB8vSmJ~B7J9%!qC+oslrb@-NJfA2MP^ID)Y7NbBDsTGt? zL2+BF&8w{?)E-DN35`8TnG6e!hDdPND7K_+;Xm^xW~De5d0@VC-Zy$41#23+y0$jZ zu8-Y0p!pY-oq`gQG6&3f=A>Xpz7~ek>#pzV;`X++dcO%!gIuR~cEv%7iHkURHN$kJ zzZrG;1p+%d!c2^*Q>&wmA@W$`6D#oIiT*vvosP$MI@Nb*W9trD(B~s_gKIkuVakmr ziAGG0>%PG5^tf1L01eq|+Y*`HY9UiDHRiz&Qn%26orYM(!+2#WIn`uJLRNx-=oj|b zX4rT&0kem&-|y;kzU5EWy_-#Z%NH0N08kH8&{3r(XR%_aQmo9kC2MfY52yKmtZgpI z!Lo988E}VhQCniL%@mNI)QpKxBT(pc8Sc(*x1V}f&3uz}(KE2|`S^3wk3{Inw6rvj^8A%A?fCE?Pe+;9=+d4od#g4z z8QvTvp5S~H$ZxF;fIwiD;s7Wn3g(}NCehtS5pk<)tfayn`nR9aa)}BIW}9eia@mwO~KI{YBaiW2N2pSj&i|;rM!dhVJn? z^>8V>l*QD~J=a{ewMM+g8YMVO%TzD&))i`Gg~{g-V_3fUf zqP?bT6+KXzIt*{wVUIozL<{(%Qw;Wg=wr{BbB_S?s3cm6S*^o@d!0(gBg8VVAfGHy zSAe72<^Kz4K$pJ>VP5zveUAsOe`6O0cIB6?9U_`;r=mJKLhLq{=J(K6SThlXs@F1; zl<^B0t7eA0OT2rVVwB%Ej)x}$UbXKZhfF*(+fMh; zq)6hX&k*v3BB|tp^Yh5ZkAezBFoZ!3$}%uQxgFcXUjB_)IccCnfidR`FX*M#B|t|2 z+_Oi=+eAp}$wKty9CP%5Cp1~~8sF_)Cycog_qC2|>5!+p?-#)3#10BWwBLd`Ix z|DHq5UNV@3(hXweB1p;D{5pc;c%)=@TnHYQ^_0$;D<;UTs-vkgr`e?5cHWwdh#SGC z6i%njn3$-pf+>8By*6^>F-qwX+%PD!Yr7kuGJ)EySj8|Olpw?qO8S20_P*F+KdC$7 zljWP{^arfWWw|)}+yDOW{b9Z?#M12~0R~=vO>mh_U^iN#9B~MhH2_>}Rtw^$n%U5lS!@A_ zfVZM_wIV{SX6zfo-q%`|Q<_oCl~iUG6PC6&srU3`T}d&hH;%Dx2@z)qlQWn+wvk7D zEK3iW_*Ot+BE%7O6|e)Qj>4Ul@MnCtviuul$Zzy}biZlhOmbOMK(%xR8JY zs}k4M{dS;hDJ5t-TkNu$K(%e_H8^dnx^{{DtP*ra3P8E4`^^-&vZ7+aN>m3dgCo6b zxmU094aY&1^FYaf#Bn90Lcw-0*2X28GKu|pM$TeWs;`B6--~k7oxKJozJMT}=!fk2 zqMCn^wet;ho5}O~`2ND=cmP_3iIgJvK$6*Vd9N zVvMoK3l7gOKHL16a~Z`5S}rn~T3iq~l+Q{OD9SOcUBwWL`1K|5bio0%%&H}oAkUiB z@;1Lm!!TfsOE8DxhG3;vAkN^!gcUh%9Z|Qlzirz|Dxa_j3cdNv}?HhNG$%RbjqHQW! z5TPj-&6lSRi&E)kRcjnwTZ6h8v~CV{7lu^Z&3;|G~-#^^V8Q~ z_qa31Gk3!!yUCe#ZB7t{+Jw+d2x6e)__CtAX}Lz3hzN_)S=-|vF0?|Dh%f|<%cZ`@ zp|sGYcqU27f>KPF(ZO?jsnuM1@+WZmfSy45LHTWr#?HHi6Iq3esu8gh6{sDV>@h>` zN{goDZHQuJgRDAxmokN@_1Z0`u}y5d*(WZX27|e(cnx%dW;qpjYUTrA!jV*+P1}}k z{fY|^xv2*hDJ>{&Ua|uyw*nZ%ZljPCY5yvqaU*nW025Ru&_M;m9CTAQ=IAFyMPsg_pu z+L?nIo@H(-aArAN1PvzmCPA1bBo! z>$-6nA0eRbSwz(ZfWVo5m@#8E*lkH~r_Y7!ywMOCGiD6-xWov|m<7f#1PmcRHj_O!t{}>c zA>@vZ-EVmvrg34K@LjZ`%J!sNU9Vg@wG1{={Ed>Dt_h|K3M;x4*G4zwnPhD@>!;uL zqksFu{s&_m5#tCt`?H^S^6-6E+f+Imp{zO{W=r0TTw_$erpVUe z2P9itPf&}hwOJ*FIJUvbLeWYcS|y+9P-{g`x>7-Wc@-3JG@BWWfP|j3F55A?2nOZX z=v2K;HbiyWyR_~s6v^QBV<>hQ{!M*I$WMWFOGpO%ONV8Ff5Bog}ch%N3~DQSyfgarWC>IO;oyK zI$>|3LVz&v;t@wMKdj{PGVv4a{SPML^){Yvxf>DcOpKlx)>d~im&r;M1qpH9KIG=D z9JkRHdearj)0VzwKzgO)(ju;zP8P=HY{x`$en`?X9|I^>mNi%jM(w0}aFeivw#98K zo8l-qwYl)i@tR3@X{ON7bjWCJGoU;^SAU%8+*jQDa4z$; zq@pVH^P4mR)o!9+ziisGpkl^C@8CK*|nmE5+&vLG6GUa4>uai!e=i$OBH939HlOb+ENs zshav&R(sB?-62VZL-V$fwl2o}lErnNQX%nWrKw$eK_i$En0}7c&bD%k zH9Ky-sfoF)LCW|`lg}_uewwBSDiaY#9%L>CWU1Vy42YU39Mxq3%#5vJ?`a))TwEB3 zW7ZikyF8Jsizrt}t_Qo%e26NU%Kk)hUyC!I67f{B+eGSmvE)lWqUI#6L^hhKYIgjM zWh%a9&d&a!kj_PGq`SV$C_ydBO3qOXw@{70JvhjkV#b@-Ip5%lO>IWtTZdw!8m-8# zfKM5iolJNqNo$ST*C84yZCoB7mg%5)C`ILSl9pPz?8;Ucd1a53O|8XgQVh6i=97Fj z1vy8Auf5dq_*<|3)~~6Sq3@x(F%FC@TTV?reYEYaG>`xUBxsO2?>D88!+bMa*a!Pw8Z7)v7!3I{u|WGOj{7ni!9v%_rNp zmsYz=K2yk+v%2Y2y_53FWGJU21$>gAfKJkF6XN)xSQZ=VS|J0oDBu2$fBSbne5qsd z@e!8lUW)-`z@coMum(*M!I9aStqwdIS1oV*-ZQja4){Q!D1oz5G!%;B7C$Ie`l#bQ)k5U70Z2459` zgDR9gSLJ0G-t$PD0-XXCFf?GY%_!@pTLR@#2{Zb#7QJbI@{MC9l!Y?*qWW|H`cJ>; z8^81=uX^PtJ@62bjz!d~qICgS>TWEiYEO};eJ#BuXT09}_lih4cv{^&H7APHshM)c zGJXWQsggAF5;z|q_xKISa0@zK(OlKaaN`pbPh~52P)iQCr&gb-l-0_*_;}^SmUUgF za?;CsF6UC9<+7tV;ddG*!*zc*Q5*XwSzFzka20i_9yE-UTxAm$Lw{)FMOeRI=Qh6UOznEIS z$M_uYFC=bO%9TxZnO|F)RNV^Io#*A$n z&yBbVXew@j?A!#+O~bYw)Y1@T9w}crrL>aCsitKjWHdFaB-9l=mcQ9@K%}-~<1-$o zg7lBma4sTi!DgDj)SJqh=K2~Qs40c9!WW4LB=JBit?F2_9uoo9C5w~t%0MSsmII_D ze>ebeoW{ z$`7b~mSvY5>LiHQ{p8kqYW#Z2XKefGB{~@hm+mK1I?*#80DCb!t&)_gT6QZ(i0TTG zX0w7Xqdebgt#YTKz+{VTOE*-3AiI>gR1(~B7on7RlL_oe*%aVQEo#RF{6S~WF}bX~ zw4qZ2G9s;_w=g_u4P?r?c9-W9+ER?x(>x7e(G*P{L?GCb)h*~XxMYUsslFaEuYB!L z*#M{q99dIt74kV*H!S^&!1RB;>4(4j?1Meccfa;afB(eRJdv^g~c7y=#>=2V9Zn-iPbbiV-?O^wBC?%*EF)$Y0c^DTWe zifNM7!PK%EhO0ARf@CpZ5+t8ClrBtev&w{Q&BvnKyX4TqmtwU3a4i|!dh&b{18gUy{;PP?OMq}lHDEqYLpO9N| zBc9ixvi#4+Hz){LxU66%;ilG3F(Gi=>cG>qTHA?QUjo5C0HMizkDdzVSJMnPRzkFC zCHpJ;vpUX!Uasa;a4EL&IJQ*Kmr0^*amuw-5x+^2M%8P; znaTiVC7{a!Jejb@UMf3HZ7$JyTH8urv#nyyC1sW0F~9;%#e9X6DzBv&@z=i>xpcOZ zL=a>8m6+s5e)IqOuHX7-j=TT<3t#+)C${eXbke1K?czSoeAsQ;Fx`&dvu2<`&Q{jF zzg2fb>p|R64&vk_6HdCZib)d7@4T@)%6UXc<5bU;e?AX!qXQ3sNW%sx@hY-<-L1R4 zo!zPX@T!GrE2I{9CU(x^d61p4hzenHhAbtWd72lLIJh zVwfET&yM7bJDml_^ZvlBnNag~POWI&MNleNS^iI24Nt54S+Aw?AEk{)_`|sZ5?q6Y zaCCmIXFLFKG0wLL(in4vG7D45OdH0dvdpjAM}ljuOeEE^!uy{zrN-pMdhk{ZOyxyx zvY5n%RlU7K?H2{&wcVuTx4xVe=$5k30?Y!%xAmc?EcO8Hlr%OqOS` zc;F3?-49mnSW~Y%zik73=crIOc1+gmkho24Zuf`x4ywDA%AW=GR<6USq%MU%b0d`_ zOj)*1_O2FDA@IbVF66gMxRtv!S(z)!M7E~pQgPmOOQvd`hNR<`k8M<@>$EOh?Lgas zDXKy+qB1B6UCF|zJG+}_>$XTHX?YtXS0$wj3F)08^fnRsy~Q%V`?Y`XSI$gPqf!Aa zIC%ePL8}g=D}Dx#m00D~^B2GM%CGzPS8U(>J+rV3{LDQZ40|pw>ZH~%#@vi z8AMp$2qsKMj4fBG`WRPYF%pt1HEO%qDR^}qj+GJwx?`Er%VU&R|H9vX-S12rODkl# zOKGH;BzNTVG}Vwt0hmndvIo1N)6s|s-uQ}d{oE59x4-U+L-(D8c8-`BVc5i>OrfgL3yY zgc;`B*Wt*i=VI%!&p?8 zOGTR9v?mP}RkASJQf#vPZ(`KndhASwA8V>4O?vE0X_S3YQYPH1AGEc&vt~!c4UIQm zTXp`18ln$Xr=l595+IG~mCKZV;5C2emu_4E9DnqD1i)yrx^?g)pQvm{oF}qe5`1L( z84;W}@um6$?P5i{XuR>~zWwo=!|9h@b?CMi1U}$wlN%6*Eo>aR8iy|X3~V3&R1BMs z1My6OV063<0T>~O%GV^2j7a1CNc%TcGd5qX8Y$_^*Xgj;3J0e@%lm0o2YQOeDHXfa zax9hXg^G$fQx~ib0o87#Wa+f#V)e-iJi#m?bqO8Y1!e+1Alov5W>mnJY6Pztp(Z(4 zxx`XSm^KY4YXQl$-AuK6q^91)dC<@HaVJ$WC$`nV+%hfVKsHr(JP~=H2>!vV|JG~Y zc!_!x&87&SxvP^Rp&^`WTODg!>#Ky&$5{5DosfUfWJV@e^^b7x-Y-ekTtqIB4*lk< zzv*8dnmzE6YYyLejo}=JfZ5g+*go-0Y#n_H=7+9Em>mX(tqdr-dy6DC4UTr=K0+iS z?%fPoo-Nxusw;p_aLGixNtbv(nx%?p6wm(sO=3gIsIy#kGOx%`k|UH$J3UJIeM?_F zvMA<<)d*eSa%Bn|nkiL6S^m#gf6r_G(MLs^PO?2O2%Khr?a0I$9&2qPv@&V>py(qX zp+1t8?1xrTmxg1T<^xhQ;pubvjaPl!i)Ot0jhn-Tzq~cvd*zjfmTa6$m>t6A;U{7H zvS(uJ=o2x_kArz$H;<(KVr@%x3fQI16OY%lhq&{By3)tCdAMEe-ouI3fqG*IDQ<6D>$^pLrt|g)WOJ|N{iMX1g}G{*v;9d;=<|bfcw`aG5Bmz^b;F3>tjjy22-USQ zvPOp^4aztkpl~y8NR(QxsdmJ~?Uizbr4S@Iz)1q(+^J$pi0U+$V&2^iYKcK{;{h?r z?F4-NFZ}J-{mz4@3_eA!oWL92GP`~Vi?3r^eA>XvCzn65xmx?4-I>$~M#x!r{&mNq zHuFd#9}PE@(uyu=^~N@F?te2Sj9Z%yKWxDikIi}K20-NS?A{YsZKJNk5y@onv8UnC ziBH3P<1!2z#}Q^nKw$<#0Bo;%=^I3V1^`j_+1vGpo6ijZ(*7Ng#XaSsR(zk#J10ru zda7@C9la=7?)sOx@{PY(14b@C5~Oht^tBVM>*V-@ogU<}?!_^adt;>o5MDUq15@nO6nTH@q!8Z)4c`ha0ntpR+wbedTp07gXwfPpp!? z7rfSiF=4U ze+I}>x7yO$?66wPQnNP5AGi(pOgmXN?*%uLSKeoF881pXH9cCyDb(AkmPck6b9ne3 zI2{OR%O@j7D2m&ZAi5viZ+L*L+3YD;0Wi5_nx%EH)#|i*RTtDf;&!FWSx)r|N=kfl zndLGES2d$In}=x5Kk|xS`n$jUEgxBGkPpP)e8=)94sSg0*RQ?o{^Jc0OXaaj`meka zkpMJcn4iEfKMCSlwGAo2n;M%~ThFp8B&2mrZ~>wusg7{CZJ*iYBEh_1eD)$SO@KzP z=FY2wkohxqpD6PN=7&y!Xu#&->%idku+Pk@F9C&f7mEuwlU`H%FmjnkSt2ir7<0AtrtA@}bCz|)vvU!uJ$#h_dXJ+~pk+L+=bxNCBoR-*2-8PfE_amhI)(TVh!%)7bH zN3qt^NgWEKT|CQGw;G-&k(dAK-~ZKb{b=5p-+ag7CypPw{oAiRwlhf6j;#ZV$=a@z zQ}WrymDoJ|L~Lx|01n#-!(oJBTi>IQNz_JOV6QiVXmBRV?PiMhJ&DcOMt#oFX{LM$ z6`PAfeaqK$=OjTeHk7(sx>NX@mZwq>E&YbcSO!Kd8f)8;v~$(SB(xket|vDD_7Hb( zgv7nFCAH-iU1^!?+FHhzSwq2^YN`$;%lgcz@;zowgk~z;Je8|Zv9(Qc!mj4H`m5jm zv$yrG7Sf&&j@wXZYb>SZg4C0MRy-jm#4%bjZ9Rj!#=UB){*rdxuSn9tPie^KMAi0z z$j?xrC{L-{SN!Z7Ui$jK@nB#hB>45W@i$(!ee27vIDT%cnA;=IDV5EoWn;w*!~6)g z4nG-NN1l$^=2aMG$H8G!?{my^M-uBxY*rYPGXyivW2qa2wlJP9!-iI4^ z$Z{0YT7soss$>l~`$)dKRXIFyhG6y^R=ZQk6qH&jB01T{x=!FDZD`_Q1D;JD{|pIN z$r_K@@)l0y=UlWQnAm*M+N?$VQ8JkxZf0%Pb#kV5841ea)FD)n+{G&PrGz>yU#GKv z_Kgn)ItsjR{qMVPzUIWuFDPwVmvPh;Dhv*rn9VQ4){!UU@bPD1ws{4ZH(YA%vIaQ- zFn~x;R2cytY9;^&xEL$xDy~zq^5K})Wo!Uts#D1&*m4a|WaPalI0-;=ARVBNKnheP z)qoPME}3?Jqt8FHP2LRGy&nX^s6Zp-0#P&OQ9tO2xOXcMck<^+b+M$ZnSo^@N9&j) zhk0beUm4mFo7U=q zCd9nA2+JQznxvMi8zk28D5hdwAvC2`bW}S_6%X1rhzKO}2TFS3l{$+aMgHiw{^76v zjR)h8U;mcj`pXXA{s$)y-+#P%|E$i5G0iZ{kK@qMPr>06&%u1_nzGN_uJD97d5KiO zr(_G-Ub4US*Tk0~|Ogg=A5`eP@NB6Gkzyr(?|GSX90Dh>^T{TE(#pJ=a zgPB^JfdU{?GcUe$T5JbhnGtp}^JY1on{}yVs!k*)BUKY9vN!)eH^%ri4+gxif6H+F z$)g{B|MvXsmQTV8ccp^H5N4QfUWH>PKL>}7ep*)D(&!F&&0wZ;6eY{sFIh$g^s%LK zjJJ@{JEW})!Pc_KaWDeS6x>J(0FeRqGkOX ziK|(Tm4+n|;G$H{85N5DfJ6WZknud07e53^dk!RNm2kIwn|h@Qqhr z_P$rlcu94Qa6QH?#Rms$Z9g8zuXrIgwysq$81*F3l8A=#v;6mCTPT(6ah#M)sh#(5 z_non!W*P)`0J3zShA()vAWjR_IvoHAB|EB(thibNYl+lkThekwWaXD-JhX%^cZN#| z+-vsPSy}0!<<)+D4JyKuw1;u`R>yA1nPJQ)y|7UbPs}ZKNQ=FTM5q-*m~=LVX-OJE|voblHVvpGz&bq-0~>4=MYKEXxKBx3$YP4D4sim6k*WsGxwcY%&Bxje)^y2ljPJY}|M?U<%Lt0*W zE(>nmv49X}+c-31aUgP_k(v^d-~lLV#*%6|CcLJ#x6l(&CT}L^-!)li z(7%jjKRczISqP0FsU?=}{mY;xwX@V*4QQ41@W5te8Tp?F?Xoe5#?q^t~|8B(nyC4#sCzN$qTRun{8}OF5q3PBSPd7E2C)Qst$&XNwGX+zd-=J%4 z8bdL&i%n@g4+_CD&OX$EM>{zu!v5K_c z({;$i+(d zAM0LaV9TY?Dla3ho3(U|opCNR2=>c!p}GOcWkOV1(ZwNAB?FL!ay%|e^E?uk?#$M8 z0J6}@@Pu^m0OH==Kw6aH%oPii;vt)1)+YD7573(aRWlX7Ub*b&(^3H*?MYGW>80pTaq)1>9=m^-=zp<8^J3kgbP z)`lHdu`2nIwneXiku-})8FW7Ujvx4~AH9@V=QrPx{`V`6-};&5)ONnnWgwP-*)Yd! zeiTQJKMjOM?c`89=0~nml`De;dlh7&wy1mzC70!-rWKyMB;%S4i1nl%CnvOht=Wc* zu0)P?ltZ)~E~DzYQ~5i>%(W_`ib+!?_|xcs))c(;HRJ(L29nFf3NfBJCZyDsOdx&F ztdxmJ<3)`7_aLQ%(z$8~U~b#kex1@KOR>qw%W6{YX0Bw-C5o^jQD~ie>Oh{@uxLzW zoI?CmwEo!_zWCKY-hoHo$T`yO0G=$9Qt8sQb#p;47eiX}cSJOC2=pGg2~|puhF~d~ zQmRG-esav($63}N%LHiN4TgVyslNH^-!fc(<*^U`PvpqJ3_fZo1wsg!!wAC+Tie%S zn9Y?a9*YhI4GHc1ev-u=vtnw#Px3AXq1WhYYGo1-wmHQjDRlk5Y=YXx* zDT?M$N;oOR^hE$O*J1MxeS>};iwcaON@|-PC;8gkxEpJy2ggIjmfz9EcWHS6%fC8P2xPKhve=lOeb+yJ^G~g0XL@Bkv~lhyH)cCCzZD~xlcJi`GZUBx47`QS zLyyywcfa-Qm8F&!sY&(AX_H3OIV91^?4fkr(6oq`6RszfjA1?KI6kIio{J(opfp0n zmu6gMsOoiPxsu7i{XP@BR$g-jT?E)DNxN4uJuRg~O_ck7Zg07!l+CIgHCQ zu$`f0W38ZBC|N|0HUOH$2J%XmX*#IW3^q5;2TkF=&b@BJN_)e?d@SY`d+oSovoO+f zD=$olZks3w*dI5~q61IOcxIGd1K`JmDqe^qMcW-)ZiyPzRmXL})2*Vhtq{|qizZX< zE)@-SXfzIoPJ!iy2^&+d$_M<^rE0s^zj=23HJ9J}RxOW+w%Qk(sk%V~8VeB)ERo`f zxY$7)cR|jq&3Cj3-i}f~|D>)Mlt*nU?B9v3&pD{h&3BQhqKCNo)2U2U_wCr~<>NuVIA5B~n~q z91kFIbQTs>b=+8txC<3wO5Cmv{0U9*geFGrvf31}5}EvT7Rr2HDO+g`G3~g{OfZXE zgCkA;wTQE~bl{nslt;qB-KW#mResfLQ)6>IFu5#JQ$??Hfg>j`TwPI9zb}*SHVWis zKa)w;B^$O2rB+{2Y;UOjA>_lq{ey4$!}jV|)8-S0?|4C8HOu87;vqPH7s4Lf;xy#&*j}Z@l|H4Dwa|>jz$(;oD~|fw zSUnk(xK0T`%nO=j1Yud;YhcW;!_3pcu7M^1MUV^-9OUPXT@dEA>n6UvF7D730K57a zL63p40-kO2h$CVg5mSV1Mr?;Y(Q2NYw1fSQG1p<89?DJv)`|e9n+L>aMB*mirRk`e zxK^6mXP`=D?NQXp3CB5^nWD3t{lb_0{Ev6wnS5fKH2xWhTxH_GW-ToHp}4xInoVcH zRHnmu;+ad%2Fy!>%Q>sN%Sm#HBI?nTK&1*vk(y<6w((R*T7|XXwGA)jx(dJb&c*+G zu^rvB*^oPHAs{fTHs_!$5X{8mLNg9U&61gD)`6raaD-rIB9V!X z%#F3&DJQgL4wiN3q`DA5yMWAUOTSFdD!FXi7epo}qrH*KmM|5svZnI;3>*iVwd}2C z3#ALE8JnBz&YH057$72uDI&()+AmIlR8>4>69Z90@QTypNHIW5D+1T*8NSjuUDfK8 z_07~+dywmtHtVd{dA^EFhSZC#<(lV}ALoI+%g#R1h~&}Q- zKvr*DCMnxHgX4S%q$G1yIy3Rg2u8Vh27v8Kp-Njx)t0~v-AS~sC8<;)rG0J!Ip(+e zEY2SRTN~%UqOK$%y^5jOqlRJ7=guI>91qjJmLzsrwpMgdWpFCX-eBr!$*WmJb|(k> z=#JDywu2x5Y32lWtQ{nplx3rW)uf}9QCW#)f0oVaRJu%+=lcGniTG3e##eJRT(&~e zDf#N&RB4FtuiE@Z1vB zmDZMa+Xd5}4Z9+FYA$BP_PK*&Z$<~6)r=<-%<^MaBo_+|KR)CDrjW8~1Ie)Q0+elw z*7Bs%#qvgy&UaYLs-z!kxyU5b!X#(Glds1~(`|-z;utZeH`m%un(o)(&9hgN%{oCa z1TI3s5C$+a0tX-o!VnM!uG7{QByhJ^bisUzEZYM$YjEB zy?jxyKW@IF1J9(Z1pqfLPu_Nz_VzAf=0*te)i0>Zl)#}QIkBU^<=UD*AiF8*Mfym0LoM|K^upJO0x08fjuI@IS0wt5-sN+V3PDn64TU*gtmMf})>dtH7) zoT%m#r5&%lU-?Y@m}PO8Y&TrhktJv2$fDs1~He^t6hV6P>a}xv5Ie&Mc9alUw=czczq2{QOm(lqXDIc zN)tEU&=9Yda7=VLjqQr7eppzuDBsww_eU-hE9p*Iyykd;V!0YzBE-$6AyS~v0#7aN zDdx{UIi~=sJK6}M>u&Vo5))Q!H|ra+yFB!39e7qUp1M10PVr?#^j+Th-At`nKhIK5 z>Cdw2H&5#_a;rUeiZUqGW>)Pc5Y;UZA~~}OEZJa5@;1=A0)>H;a`t0e5Lma=6g>}t zB%N(0>m8lCIqcp*MO9+mH_l3BeOF3RMN$NxV08 z^&w8#rM_e~_6HJ0)v;FMsOw@%jTVL6=m>H4jA5eEn<|P11p_YgZE!o&+)~B@Qe2I> zrdv5_vT4>p&1Evx*JzEcMa!@>cQ5c;Olh(Q(M_oPmBnCv+f?~XtgoJRg9$0;NNSww zyXs1QQ~p=tSO)&G7F6X2;xig@+8@7W2bc)mu!wVc!Ha+KpLF2Cnygz3hnvUC-?_;L z<3Sn*a%6B3NR=`w14k*fKng&fXl_llXx&QLl&{{b98abW>clT;*)?M|oGANjsBV8m z<|ByBAxPTcKb5hvjzk0wnMe+*Q09=!0yhp(*4Czkq}f64XT{3JU>$)eXl+2XD06$c z>w%k`Ka3k)5bF>L#xcK^)L6b&`%iWf1uB^ZH};^ucT}dyY2pw_)g_WZ5UzZNM+KRT z%#_AK8K$J-iQJARtnTab4i~;0Baw+-2kkgY`8#%NqU|-4X4jlYMkwgth0>L*6o9z4 zzqtu!VW_aql}YvZNv6;yLX5G14y~DP_bZX_-M!)uo`6Sg43CIsA;7V)|3~+x!_Tp+ zSOyZ&Zj}Qc1({%Fm}N!UPA3Oa1Yl(~ln5k{3a>Pq&`|;6yu&@|i4X+{y5ERHUhE!| zcDGV~Y*UQprb)X6V+d)JD05My>PO>tpjnPR*CYu+{e5Ff^&s_|(Pg6NXt;-1_E9;@ z>dAJFSaP0Z+cWe;X!se_JzYgwVE^OFi%?k$EXC};>T%qA3*-ht+5e>(2~G9rDB$FM zZdlQ0+PM*xD0rQW@p(lk>UG3QDmMe`;x}+m+xRvwBC2I8%CbZ=7NZI{V0~TrKN1F* zOB+9D&dwj4%)*qlGfR+Ub6i6n3!#7*b(^Sy+=K0sx9OhqizELE9e6&nsArSMHv;mU zWi>;+BRutC5a$O?q;QAqZ4JV1X5sxXx=up z?QUZlUQF*jn+3p;L%T2$Ib4{B*QM-_lcm4Gbd zGMWkMDu}C>@?37Uw<#GIadEk;-oI427qez1fQIUPNT?$Q#^Kl~f;8%x>Z{$Fvy)qF zC#BM$;wDhNqrF!#gxvb`x>=QM8{}l0h~H4!Z27E)*N&*N<43{QEIA5*2EAHoc0-!! zkcvhrltw@yxRpT8pXyjUVQ&5~fsu4_UXr>YU{#%H`_t{mJBvqdH|r4qJf3?X+%{hJ zPi9#DFHs9Q*QBW&o9` zu4F;p3~Jq?K$9ud3IE{BDQ2_2uoGKA6W)Tg-7cvTwOSx4r@~GXQ#YI^ks`CNwwgA% zER!W1;&z!e_IJ+rs_yc#jL!2XK9eY~wP@g|a5+3#m)veA#l(1miqm7sEF1{Ybe0Zv zN4RA_NhU4_%??kl>xtkjBpQb|RjaR9rBq%@n6o}g!6Ii-p?sYg?R*=PPmo!A6mN`F z#znIHBS2D?PUHdqs2q^0%UOUJ(a5YCV=&|51o!WqeEU=I$c~3yK6Bn@I^&*2PHiqiL_&dh!)9COJAEm3Ns; z;MYC$RLJ}~>CX+}L2BW#!q=FSBDqH-c2jgHq0?~7A?m;8vEw`Xe2#vDulN;X16s&>~4l4d&jcM3q9zn1d*;Ib)Ez1ZmP zC+3}J(H?Nfw;>&>HE*S+&F(=Jr5k)CCw5zo3|%1LX|LDM&mj&VGHN1`tN;W@;ykwPj4Ac^3(oqMpA} zOF40+o$7Rm^1;b$V9Aw_Vamr72~yIzG^B~}4TS`@GRvkIO1r!yAd+=KZgqt(m!w(g z<2E~(K1JUj(;K7fi#|`mOJ%{lV**M zJgVCjT;@{ztbKY@Fs&44XlyOnuP|~1VX;flRJdFytZWVn+QAXbLtZ;%91yrTC`d~A zn3IHr1thUrW7}>pC8sH0AZ<9X`tZ2|-dYF>+^!X;Eu^`1U%1E_tm{&k9-KEw|(>qgmrpKt#Ej zn$_q@<~SoN)BjWkbjymnLVOnms6H>1n){s)#7?19eQ%mo;AL}XwX0oOnOTg%+Re1B zbANS}B)6xgYIUgWGq=~BJZV>2>e?zN&cId5szI}rnPyg*l_cWQfy-iK&5#&Kaa3^P zss4LRNJ18>CtMM$S*tb4xXRw3ts%e>9B zXp)6h%i{osDj=2nQ$(vBA#!95>vf|g{yq065C?4bo&i&~r)h<|u8|Sjg>0UDHl-CV z;>@$Cy&sUSs@5AY*Vn3h;>b`0#uX^K37u0UhFo$BZHPJ(7Q!F9H{bh|{R zuQ4BRl2FKL`!5eD)2ihU!I?n0gE{F1hy-_Byz)a|_MJa>TL+#$cYB@izKch1y=L>` zTOWu=Ul`2)%2oJD0H%Z_tRR%Ca?}|@`HonX%1d)HvMLU9;*sisW|<8$l4Nz!s0TeU z0b{bypJW|frJ5WY5-m?9)htO%wRU&*WQn}TRNpbebd%*2tej0k(^@Y2oNAumAe5z0 z9Q1@I6*sbiQYb5fg-FY!IvANhp`o_9oxN*oMvkh)b&ucXGu&+8SwYff8r2^`t#-)u z#9NL>YU=8}xl49Z+Nze_n0U}SRH43Z9RelCgSAoy*Fp5;xNGD4!Bmr4wD;pLK5oH* z01xb5_7Xgb;$asMmc?)I>R-XpA-?3oIDRnEuptui2^;i;71wUHAx`ZUBprJYRU{h# zF;6H~TEnw|z?6p_b7{pGQ!FP?>AYBpLX!@|b6X*5zVp=SHUE=lYM3elB z+-6W}kNUNH*3GlSR|Db(f?cMYq#Qf9UAX2wU-})dd}jxqkAdT%iSE}viuYeQdfN?$ zcK*SA>Da$BgK*K|$E4u3y+u@9LAQX5ySuv+Jh;0%0U8Y++}$mBfW|#Q;}E2APl7e> zZo!@45bX7T|Fz!aP3{}qNv|68UZ?Dw+E)9M#(`k$vXHBk>0t#ioKx8+ndaj$ z)z}R#E-UR5p1D^7_*lKG1Ij+=gwiMuY53xQ)XzwgYA7IKGnQsH5Y2%`zy4B$U{maD-}RMc8OHLSK>;Ap$Ct^L#qLjFrPxqtf>SO2s01J!0?jCIK#@Bl4j?&7|$&&TmHk8@=4 za1CJZV`$ChF=KOo5mBV$fJBI2Y>}CeQ^*=@#kNmc2QjN|%uhdMn6duU^s$FSF<)Si z*bAe((esP>{XBOMB1z7_M>B_iMnUK%xwXSOAvfH-E+4Ygeaa5IONN?R&?KHfpX6Qa z19d4A)$}^`ZFMbWeytMD-Maz$erJT0FY^9o&s_VM(cohky)>?+p+J}Gjuxnv#+yQ} z$gF8$V2b?|d@RwGXDh(2k^Cb{qjQRi)ip^8SE;d6;8!G2SaLC`IGmIxsr~$y_xlr+ z8OrW*+JD32Jy#`i5l&{2ZQ6LTOy0YFUAHf8wdzNq4F^YmBrpuJl;oRKNmr!#h^({8 zT;)z8T&H@Dl5vj9dfZl+{pdgBM`)@3!EyA+Lfq_{8Zk>XkMqIJFH7De?_{jH$3Y%ail!m`PO(t`Gbm^ zf2{Z`KdXV^AF(0@mu1{)^~S=&fQh}C6luP^VtX!G_4-jH=+O!KcN@)i?{W-5DQY`(Pt! zEA-`l)4(jf&ODygY5x=V>dE4(p@1auS^N+xp7Nc@0$q#Am`P_raGRE zoX~WJE4xf3M2Ydqk-F|t8hz08fa0PKzxy#2@v4Kw_a+aFIlpeT+Xi0QpszlDQeGyq z9MJ0^QeJTtJ~<%;IX%kHI0=F|EBL#dup9PjCBRb+>A>+O8h3-Hy?Yq|aWv>cpN(nn z--`-k&PhfmhPTQZxuXW!$cgec1?|)bNjA}%GDTqAY}34)ww;dD!+fh6h9QyQr1|@;b3fG zDXgZO$H9-Cw>qU&jle)HX2h#J&R)2yBYg;?gp5P#3CXZDs{xVA^U~P#^JWd?X_((+ zay_=1KQj9f4F9g#&8huYS+VM%86nl~skj+1cz<1=Xz}K#bj*$TIWa#tO&v$E^&CIt zi&?vW2WN*zO#%7%4jH&OWwv^pQ3sKRRZI((!a+DY-+g42*ztGqouRr0#9Z}R0zs}n(BDVtPAxv4aD>zQS z_m>g1`3in*Scj#ykGzT67k>xOC;hN8vu7yvv4K5u2hy~^uJ20R3U6Jjat)MBK{T8)p8(nU@*~*UY zud*(XkW2lIR4pz%rLY?aG|!$<3(JC>r?0{nn6MizW|`QYAWFt6XSOLAyQ zDvUA0GN;%-7&7{Rs9_K}U&gsJhg?9(YR2fm&*@+y8~b9e`t+JAP@|2g)n;pMCaKp> z$qN=lr4~&JL0Sb@u%P1~N72nha>%s5VR*$If=gC)%YLS#`blHJ@X9{2hD&l0`sRzI z-}g(-TwKI_x|@^_NEGsEp$@F!2RO}teltWr;F=m`5rkP*pSq_NHrEO1>w5-Vsp$1# z7H2%_itcRIzVrN05<}q^DBG)*t`Xz~pfU~FDD&5}MF*iw5FvWJ#1sYMZ7i4-b#dG$ zxX?w!Z&st6f!MOuhjkAU#4b;X^SUhCSGLMbM@8bNjRMs^70-!567uA%d8IFJwe52o z%f;}Qtz|$PQ}*``@YT4$l1}6D*+C#E3}}f&xnaY_8v)d)Wj5WcG_8+J-7BA4dObXR zO)`IR5mVUt<6P0jke^$>p#u<{F~%Z*yVz2$K<(P{ydF8wl+%zD;SS}T-wY>|L-Fs9 zhE22qzTy?)+H~2lMY$8O<|l`10AD=e>0QItr!mtD@bDJ~{S}llH}tB*dtQI-_FgBLzwll5Td`2- zLra1D7?fjWOUkG$XkQVF%hd)wbDq6pNlRSrrOKMqg}?iM7F!xw`@XL{I*S9c{uWio zS3r4*T4kafTxAnjW&|hFwqez)&Av`tLD-apOUIG5AKpxQ@1TiwH47*B*%mCnSj>K7 zP<~dnu%T796UUo#HA|`4%C+9>n**C_BXnx=&!Lo+KdRMMNICz#>A79kScU(u_I<=t zt(ypz3Wwq6PqZ$R@wOMqgm-Rb@hEz6?*|d{7k&??z_K%)8g>==!4N`%w1^~KR(c18 zG_)g7I|3~oBsKy0=BgE(_5SxT^t9&fs$#p582j|X>sRg{iM~RclF0&r%!wyWn04Qf z2X&ZDuR9yXLIT}?oH)H`{T2JXYB(xnML0YwPM$hw+Gel= z;C_RDyj2TLp>7!%eNh9Rd`yko4{~6VRulG(1%_tpbawdctnwAaHu?UDkBpL2m8v%I zRsO`nT+?Ij&gnN1@pbm+4)AI|+$}dOsonl?PX%ZAEK5EVBt`FSIGfrmiY&Ws8dY#6 zT;D$iRHC6^;f3&OnP5RHy#sLQ5rL_2haJYLzfkk+t2pNAi#GY+_@O0FQ8kne;%|Ho z&G;af;Pk};MaAo&!Mu0;Vztw~s^#=3M%RXebSWh~gaKC6GO_oc!liI|PO4tGhCFp( z9zR-8H*I<*&)GR82DM>g(C((k^GPC^pv-7!^Pz#8gsr=OO ziK2EU8l|DFja^xK_=^%ftvra9ts)oLlrdK;N>OYAv9j|y5KrSdmK$sKQu9WcLGgdA zLzTYNEV%R15slj}@51hT1(;t`OHzvmh=~XnDk{VpaB1{F7Q?TNZYV1{3-fQHC6zkq z+B?YY)d!e3tUY#xy%(@g(#2OfxjZ=>yJ1BL-&xsAG}Dx0rJB})Cu9;@taPv$yu;L# z|Jl!#!cWQ0n;OHW@&DfXc)m*Xla4H-_BeS|VTx71?qq!WO8}zA));36J$NLgo}^>N$=qF%lMu-BK_`xZ0j z@~9J zIpcbYm?MW46WgS;gN7H(W$SN{Oxi|IF>#4E-HWuI8b;rDOd)r5bc~5wlEridcDW>@ zjDxN7i;Fl^tYRZ*c-5~U47{oZV{KPvFX!|oux1w4ht+QJ-bEt@WAw7N2& zp!(peGp0guR#om7RPL1o4MeSYyr52e3X?~2wedZBhYl1-?>tHW4L->)o-p`q!PF=( zgJ+mx*gR)r*bmlxo>Z8w$C>#H5uhWXgBHGcIOFi5m>1-3xIc&*$e3 zS!pO7%dJs)kf@Y&I$d9m?~XJJ5|mk0ZSNtI0jamPLOlqL6v-+Rv=!_yt-tW*thu5i zw)ffll!uwKteEnxSL4;VV7P&uRJ^Xx@{@23^ga~TyBCJBLBwyLUJmRF_tya8z8tPE zXhZDG!Rqi;WTWP6w1~I8Oy-)-$_f91?^hR9HvC54p z#TK?-d>3=FbLY&(51nJ@1kR@aC4EPVU{EjLX)8IXkTy(Z4LtnGs<{7<`V{RkIR&tE zLdD0$L3E<(~j5UA;R9vGCMJ$YwA@8*59AR?ycj2o6Z)%b$LXSL0oy^MTsE1>i`+g4wag zO|hfOHyk1qO6iesFus`1WTyxaHF3&PEnf7XeB&pY=F3YmN>qZBv_r4^)1Y^Zt0J@K zD4CrQ&r1$bYXoA+-9`~#N?L4+$f651xyik!grgb#g4%&s#m-!19+LNFT*hycylla> zet%&yiCtw~=b+#nKPlv)t7?ZYOPwC*ozkP!&cAZFO& zAI+LChTB2@`r;uFOnm`Fb^Fpammhnz8jf+9I<*V|$E`NtpaJxYV07=@s7DMZ1a4ow zq^%mNb@Ce0)DJUf`B$Ne(nXJW3!YY)hnjMNxtWrN&A?h<@Kvs+n5W7(tbGSK~i^4YAY>t52b& zY@D^{r)O34%6d3C6E5rRMEZ3z8K=s~LhXMo{-zE`#&ArKV9m=<=i>qlR@^3ig3{KU zcoEQuNLk31IT>-5nwnu`Mx+?WFr4mp_1Zw;aFxROSy+zC;`)ev&E2uhLfF4-B{883 zS0YT+XNg>+z?rr{yuc~^JQFK;8$rIqn@lwN8OXp-E|D-VKagRFd3dh%ZFDPcDyp14 zy^dZV3F45+2S8e=O)fv#%nhm8% zUQ{@xvkN53ZDI_BsE5hh{6L{&YES;Bp0>82>;^HRYx^ zRwD_=14?`1jL~Hup5PHTz8`}NX^lfOzh#W+p~X1?CSjz<16ShK1yF;xW}DVyDlI%* zo;>eAmXi*>J{vT4L04E)uga#gptUE-$4!sTf9=e~!G%5TgNm=o@KLYE#YsIQiFUz^ z2P27k2jiu{moT6Mq0$_1tOq49*qK-q-o)!i)S^2&Qtr6FeDj-y8vV{D;KKvg=WJ)o z*2Zv)R>T8<@u-pqK+$bqkEOG~@|G);6tgVBuvU(Pp6y>jvCxd?$_eSHN|6tTI#LbB zSK0meC>RQwi;X~g>Y^7D4AI*-mX3GH&Tf#xN>@7BU;=R13RCQ z69%ykz{0jSq%zr&ztv!eYqjliriwcvhQ~9Mio3yOI_WSsEJPNu&W&yWT=zFFJ6(jo zDTsyX2F6RnxTX?EXFA?sdmwH?&)m1i%l{|@2_o4>MZmSHb1-sWq2V5$b?R0i6^Syq zpu8sPY|sgzF~>`NNmbk4U-YhtK71fU@lLsG-`mFZ)0(AV%}i&JgN_g0aW=vV8<*CI zECuV6e89@}?)Em!*dQG3nT5bOHwL^A0&?Z(91g69))>p39Z^)b6)q0t?{-6yqc_iDSmXfN)FLVeFsApl7h%ba_olnzP|qfM>DzDO*m<; zP%fO+eEJJG)Qja$@VS#nq{fvI#;vnaAIMQaW6>vRAmoqM-5I)vbD{2fG&P)v;L1sN z(yim>-%(`i9j&c68t{=VLihYc%^auh%cU%11f>n&4kWHPNuj`o%iiI6m`Nf`cJ(91 zYBx|2D_O}<+CXsu;}!1hl8uy zVJnwfPx`xG1fQ$hXS9HyQ^N9EFuWsU_NkMkafjZZh-uJFrX!c2K`U>nbAAjlxq~tt z=>UTN6NL<1MfYljOZhavc=)LY5@lpEs|`2nf~}}mwWAQu2Gj!5s`&JItMebb`>pO9 z@wD5Q{oo?%_uH4Z%dJTC(EHNmuG6IklQa5ns-S&|19H!C+q~Q>j9eRzX7o&IPm?pN z%N_W;4xeuo@KdF%x+NI^&*ohm+x_i<$i*28(*+=hs<5$H1L{?~H3LW^EOT&vC@Vab zEdX#50%gsWmgoYUt*r1$*qy(3)s%~Fk#>4bo^Gq#J-+wjrXs|4FCzk(QN-d{?`kW99`bbw6yTTpj5AYM)!8l;$ zXy^k+5-1WXB|u68pfFSdH(5t$4cdztISj?>%?aDjXMV9TJ6eKJt-k(=l8=9Z0Ak%j z2`hyl1W&Pc+r5%a)}gKgrrUUvV?EhDie;=gTT2`NYbvNq5{n8=;d+*=$;<&;S&&u| zZb0ZYsQOEw1z2xEJe_uhf3Evp(4x-CCCaBPPEYFl&qj3J-`C6$Vn25n(#6qC9A-yr zJv9nJsZQIU!+Ux*EJbJ8K+rww@6{kX;S=XzD&jp~LxBb^e<6V8z-hU}MB0j_w{Vnw zE%iBNX-T^-v56)r+SP-|eBv?joi%o4Z_B&6m4jmm*ERG0T~<~g^+Aah9nRa;wlto} zAik_*5i4ZP(k!vk8cG0t3H09qzwHiVi0soyToX_{&tDEdJ-j1E&FHx%wZVaB6*HeuR-& zs)>@d!7Xm}DNTn?Ts{gAkxtvL(~DNl5=WKEHZ?`AU%Ja(XX(+XoH6cmD?x39Qs4-Q zZp)pe&r}hbaF73fmW9vRoaB!wtJ8n3LzB++u%<6s0O6kWM!dgB>uTTSIwQvkc7oBN z+02UCRg53Ci8L$b$e$;-Gtc)Sjz7Pj-xOPmfcj-ukEVwbQ0;JM7*3?CQgd@1kx_?bCf|uuJ1cBDm_SUqZ&Il1Ai(0VyguzBy%l1l=2SXLr z)HrNR(e(p0aBA;p?oDFy^-VP)BNmXYW0I`RWXAFz3k=9d1+;9=;46rO z#}ZbQ<+-HtT(K&cZ4LGQ4s>eJq0Gty)cFYNU(L?cMuQ3sqvvuSPnJ<4G8{_;$_65R zKpuhAtgsX}o~1mlquU6nJm^q`saSWDlPx?W2n&Zyx&+fxW!2HZa+ST(^f*T^?gQL7=kt2ZtrhB;=8)f2 zBnm~mRcT%DWFSEXhGybtYq7j1uVgH-@(vI;dJov(g!%YaVCWFYqFJG>Qp^?#f^*z=|rR>HZ(^`G2KJd;0(KrWRyFo z_37_Y{Hal4l27!MqX+B!mh%lY%QrrQf5L|{q z3<*41cL38F>nC{qR0In_E?dXEx~|NDi74@?^))vFR`~)`12?QiUOOB{x9ziDX&7)= z_T{Of2eeD%x9yA}9Je17-*8a4ltjuVBXhJG-=YaK+(e!b{BZo?!hh#lcNta?C!)N{csYO z76_R9(tEb3t%`HUBqQ?={kzx0#WN*{fhPVtftPRa=w%tK5NbpY9h3C0Gw)X+X!=Vf zJXJ1PH#-H?*TaRs-8E{IS4qXcYD!1tv1TIlyrMq6oJVZ=y2RN9o$2N#w!zx{;%vbfm6L_>3iL}$Mx4Z4obEkIR z!;A+XCSa5AGVrhf+v&p8$GUN$_Juy;h$NB$F6O&wt(J5Q9Eu6i!h$`L%YCr0Y$0Sw zN18Nvp{Y92CEbJLQjS<7=fPqkAcaQE!B}jsc$(Y6zH$sRN6H@14b7q0c(q~tqC==d zMr(tpe%jj}`0l#f6mtY7@xA=j9_SlVkk7$y7;){8VbA0(jy}FjZP)iqy7l*~nL}_y zsjJqDpD^MW8^wj+?gR3qb6?koBYIbU3!g%e*h~s@<((v3p3qI4Zk=Y;L`KD~?3X@QV8K|704zAK7tKw7J#^zN36bqqPa z;5UvUMi*lizC%1_8;_vFdvkv!3Fy@I@b)bX7!4h>{Z3y^fcx3=0A9K+{m-;D&a$N~ z{%ADYIlK5nyhPr4T}zh|k*cOQwRdkyDy02t)E{R+85ECGa;qgC?Q0gshdy&7%Ccq{(NB$Wd|nPt+_D1%hxT*i)303 zuI)2qv#(Eo9KBMhYv4i0CG&0{0!6CFtc17--iktSe4(c^{`fhQ7JGEzgMHgZz-iC0 zOH{MQNMS4|e2Kv69^+e@g)XgRyohvvXA*i^0b!kc04(#;BG=BKmNcp~Uoos4AI{W5 zz{g0mneU?Wn9V3^wyL8vxu*|cnM_Y^QfZ`BiyQal_A_Cj*I~&Q_h2~RzMIhggGOe{ zWg%3eD%&TSeGqr0eYe`JrMHFQCi-b3iRZ#-5fI^Nl8AXEJt+6K%}m;#K7~q5`!79MuJ<6`&@Wl6 z_jFBmYfrlnIR=V5mVML}%Zhrlm-K^zhXb@L+}RnL$A-hFo}0V2+)slQ-^rciiobt# z&L4RPf-H?wg;Vwx8M?$TYeFsv=N6qzIiDAp@&9mqZbCIaS<=JCZ<@hc{16+{U6+Qe zHDW`g&DkXsWjW$vqNUXjhaHV?Nk!w1{ru2JPOe!0`%Szr?m6TVIc2CIIajUse5nsF z0eLg>e5@#Zf07ak5+{VQ=8HarC72J9W9edv2z}Yh>V7>4dGUcNHNP}?q8}1&xM5L# zR+#y2-AtKeUlLDXcrmH`WXelbq}&Pud z?nf+(NZshq!_Q(x-^*d8t%^MwW(~l~L4t&R^;{enMGi-D%MSOKq8Ym0IbW81HKXV} zJKpxAYJ2~ewLAX&Mme<6#fd6Z@xG_%ep(;QYKY~w7k@|t-IUuebsb*&A2dI6JY5e+ zLTd}kMr{S2MZcfFFC}lra0Q6I(xP%?g$*r&y*KICgQilsguA^joWTG(Ej=u{eb@qULrSKSzyr)HWOx)e-#% zPPAOht^Y~Ye!Zd?MIqs~j^y1F5L=@WosTMn#{P)x-bj>ijfaaOEN)otF9X>xUj9yn z$NYwIUFv)}-!a1k)4L~ROG~~* z$(bZ=oFYlS_+wJ4X=NV{&swX>Ut6a?=ftBh5=j?>c=9U8vMZK$v)jVy9LPo4+P?v& z=yCBBm5k`1Xuo!;MCheO+F#k!y<~aAg^3m+1n&M+yFU>JB0Xc>B_B$^Vn(eHeSN~E zkv}WwBJ3i*fSEPqE$HtwW5z(CXi~`mUxmc`&0G=p9xuF(oI{lvq(bbFI(BWgmlXU< zb=V_p*N%G|%|4fhHF^Gza$q!x?kaQa1zuUeXG<5gx^75@P_j(B`o+1#HGfTJ1x81< zs0F1=T>`oy2QHx>!+x+KmYz~3;7)Btf}T}tC6o@8l{1_GcMeZUHE|cuy+cY37lkFnwTDAW<*8-3Ip!Q2?fs$eV%0Y>k~H(v|+z7!r}a~X$ihD2j1YI>HzzK zcMx4)uwN^oeI|kUfmSRQ(hY6iO+|maZ5mU*>uLtST&VJz^F~g?>|llo5QH7bC)(YZ zw#pV%IyaV{Vb+_8v0Go4g_Un0Ene#laxP4Hu8hb>eI7Tjz@<}taGl>cu6lfc!DY4K z_qte3QnE+bi4~%vfwBV?K<)FNL{NcnEaOc!C^^9=c)Xl9TdT{F9%{mC7H$pE5i5%s z%G?Ss8)IgFYfQm&!iB?h@onF&0FeYbrM41NelHwbZ-IgmS4)!nSE7<&o`jCCDysa- zF=&XzV)5$bp7!-%BSXFM%6pPU3D<+}a!QU}ua}aCrqpH*a`M|*!V%Edy9hm_tBH8e za5yc~MWal+&*N5~^P_{+U}IIaFk%U$(xuszqY}~OKFpsgZfVm+an~zch|OQe3;WI} ziTfcC6SKbTrg8bHBNr52i4E}<&K?ws@ThjttzdheY;`{mF^B%dG`Q%ydbDtgfQvP0 z{Y?&FH4#zzv4CmpF6ONE!-d=_b~od$!bP>Z`FC0LY2$|&mMq=eC+lx4Y{G>wi5=rA zW8=um^THex@re)NLYzwJTaX6}^9mt0&Y`BF8j@pOEzh7yn{=Nw85A3#^lTh_iR>uz zpzEi;zdu4i&~KO%>{L;(I)~A~aa={6OEg;FG!~9i&}uy#%-fORdyKEx)#(1=uYrJW z?T#W|RU0_TFR0}p&!1SG2rrL+Mp#ia&^fC@?Q+uBsxs=-Yj}bV!hpMOCBTV`ErK!U z>odLiz67>H=uhsxQiL3<+KLLrRi8i7(joL4Rtfj}+~> zTBtlNCPz7@g>>Zgtx@_a>js1HC|FxBwn9yQ#Uk*eA1`wQV-pWbIBbK zQU7Pw%Vp4M1zgNBN0jsYDx;5A>;Oy|x_>BpfnN4c`nPE~#9$MI(3&}17#NQ^4-UXf zC6L@tu=*9+dv;^~Ivb)Vab3!uC3%rJT<|LjO=Q2KS!dC(?MUZ})ckta{EAu7RpRQP z>+ja^pbP`0)DA4e#c3b1l#$eINi$ei7{WIN?8r3Kn=Vi1w7~@Z zZ-@8aS)DqX@Qr(~_#nw<`jA5FKa(Llnfc6E8#uGEswN2CGXrs{e_LELa8jpEcW_8* zzN5jK+v-ii-m&LPz)ODad}fck!pMGhIwIMQqY{IPuL{sWVf=01X6iL(au@0rV}LJ& zCN$(0Ha-MbEJjwmRlWu7=G4DeQlI*Uo`=4qjwKJcihD_$vi1RFX@*yWYv8up$8e)_6X6gaR49|7=YLth|4w-dT zQsEN4UN`9NrVfT)s)`Fgtf83xo=)46UxM_d{Dy#hD(Ls{OZKJT#)J6#U!vDi-Qj)o zWG5?n&2I*&#VaPl6bd^jg4Qz3)yK*ve#h&&W1!e9a0u@RB?c`RlcP)xX5!{ z7-W(RCEJE<-Lwf_Z46@#a*2neYfd83T?-IzpQX}gLTK_vPWxC^v_mZY_qprhQ3r$1 zk!P5Ot|Y9&9lJ`O4DvaYoD44Zp4(wS=CbjwP+x)QE#SQ+QXRRFioKtY$G;5|=i?xm zLHY7p?~^;+)W^-cv90IVHS+5g#kPG?=5HgoyverG{68J?F{_+oYF2Yb>a+!PdHIzU z0gyxmu^fXV5K;;VHV<-y_0 zh>|J)?*xp>y2MosnV){xk@x%W_io_|Vycz+B5yx-)7BPRS}ixxhDrx7Ju6v}8!hQr z14Yhxw5au79|guD@Ji0rNAF*z$eLT2%57*n)JiI@t8c23YvJYan#swSe!a8K+3p&` zt>@rl>*7a45`(TMQrE{Q$wS|si_6z3a!>y^DIs@j<3b+09BN?#K~EbSO5Tk@Dknfu zGd-cs$IzDV>76=&6i(nsQTzx%c}$WabxSja9Q(bj==D5g{y(v292jh};XWU_(IFO< z&0Uz-sD>+Un5oE!S;w~vLFAzfIbf^6o~IoxC06(l41jlRB!8&i5D7SvI3lG63}ME( zKt@nIp86I%8Tu+E$qV)Q9nX{w)3bGYbSNf6V*=3l_DpyMv z2DAz7!(6E%)Kl^QHvjLW{-<;Qzn}HLm-_Dz|2wY#3#tE3=YQw$fB&riz0`jf;lJzk le> "${HOME}/.cshrc" + echo "# Setting PATH for MacPython ${PYVER}" >> "${HOME}/.cshrc" + echo "# The orginal version is saved in .cshrc.pysave" >> "${HOME}/.cshrc" + echo "set path=(${PYTHON_ROOT}/bin "'$path'")" >> "${HOME}/.cshrc" + exit 0 + ;; +bash) + if [ -e "${HOME}/.profile" ]; then + PR="${HOME}/.profile" + else + PR="${HOME}/.bash_profile" + fi + ;; +*sh) + PR="${HOME}/.profile" + ;; +esac + +# Create backup copy before patching +if [ -f "${PR}" ]; then + cp -fp "${PR}" "${PR}.pysave" +fi +echo "" >> "${PR}" +echo "# Setting PATH for MacPython ${PYVER}" >> "${PR}" +echo "# The orginal version is saved in `basename ${PR}`.pysave" >> "${PR}" +echo 'PATH="'"${PYTHON_ROOT}/bin"':${PATH}"' >> "${PR}" +echo 'export PATH' >> "${PR}" +if [ `id -ur` = 0 ]; then + chown "${LOGNAME}" "${PR}" +fi +exit 0