[Distutils] Beta of wininst with uninstaller

Thomas Heller thomas.heller@ion-tof.com
Wed Feb 21 14:43:02 2001


This is a multi-part message in MIME format.

------=_NextPart_000_001D_01C09C46.A9DB76F0
Content-Type: text/plain;
	charset="Windows-1252"
Content-Transfer-Encoding: 7bit

Hi.

I've implemented an uninstaller for the bdist_wininst command,
the new version is attached to this message for beta testing.
Don't bother to read the code, the changes are all in the C-code,
which is not included here (but I will post a patch to
sourceforge for this).

If you want to test it, simply replace your existing
distutils/command/bdist_wininst.py file with the attached one.

--> Let me know of any problems. <--

What follows are details about the implementation
and the design decisions I made:

The installer, at install time, creates two additional
files in the c:\python20 directory used for uninstalling
(let me take distutils-1.0.1 as an example):
RemoveDistutils.exe (about 16 kB, which is the actual
uninstaller), and Distutils.log (which is a text file,
and contains information logged by the installer).
Here are the first few lines of Distutils.log:

  *** Installation started 2001/02/21 20:27 ***
  Source: C:\sf\distutils\dist\Distutils-1.0.1.win32.exe
  020 Reg DB Key: [Software\Microsoft\Windows\CurrentVersion\Uninstall]Distutils-py2.0
  040 Reg DB Value: [Software\Microsoft\Windows\CurrentVersion\Uninstall]DisplayName=Python 2.0 Distutils-1.0.2pre
  040 Reg DB Value: [Software\Microsoft\Windows\CurrentVersion\Uninstall]UninstallString=C:\Python20\RemoveDistutils.exe -u
C:\Python20\Distutils.log
  100 Made Dir: C:\Python20\distutils
  200 File Copy: C:\Python20\distutils\archive_util.py
  200 File Copy: C:\Python20\distutils\bcppcompiler.py
  200 File Copy: C:\Python20\distutils\ccompiler.py
  200 File Copy: C:\Python20\distutils\cmd.py
  100 Made Dir: C:\Python20\distutils\command
  200 File Copy: C:\Python20\distutils\command\bdist.py
  200 File Copy: C:\Python20\distutils\command\bdist_dumb.py
  200 File Copy: C:\Python20\distutils\command\bdist_rpm.py

The format is pretty self-explaining, the 3-digit numbers in the first
columns simply define an order for removing files, directories
and registry entries.

Uninstaller information is written to the registry,
so that the 'Add/Remove Programs' control panel
applet can show (and remove) the program.

It appears as 'Python 2.0 Distutils-1.0.1'.

The uninstaller reads the logfile,
sorts the lines according to the 3-digit numbers,
and reverts all these actions starting at the highest
codes: Files are removed before directories, registry
values are removed before registry keys.

Observation: The uninstaller _only_ removes items
the installer has created, so, if you did have
distutils installed (in the c:\python20\distutils directory)
before installing the new version), the 'Made Dir:' entries
would not have been written to the logfile because the directories
have already been present, and the uninstaller would not remove
these directories, even if they would be empty.
The 'File Copy:' entries in this case would have been 'File Overwrite:'
instead, although the uninstaller would remove these files,
because it cannot restore the previously overwritten files.

There is one exception: Usually the installer tries to compile
the .py files to .pyc and .pyo. Even if this fails, or is disabled
in the installer, 'File Copy: xxx.pyc' and 'File Copy: xxx.pyo'
entries are written to the logfile, so that they are removed as well.

What do you think?

Thomas


------=_NextPart_000_001D_01C09C46.A9DB76F0
Content-Type: text/plain;
	name="bdist_wininst.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="bdist_wininst.py"

"""distutils.command.bdist_wininst

Implements the Distutils 'bdist_wininst' command: create a windows installer
exe-program."""

# created 2000/06/02, Thomas Heller

__revision__ = "$Id: bdist_wininst.py,v 1.19 2001/02/19 09:20:30 theller Exp $"

import sys, os, string
from distutils.core import Command
from distutils.util import get_platform
from distutils.dir_util import create_tree, remove_tree
from distutils.errors import *

class bdist_wininst (Command):

    description = "create an executable installer for MS Windows"

    user_options = [('bdist-dir=', 'd',
                     "temporary directory for creating the distribution"),
                    ('keep-temp', 'k',
                     "keep the pseudo-installation tree around after " +
                     "creating the distribution archive"),
                    ('target-version=', 'v',
                     "require a specific python version" +
                     " on the target system"),
                    ('no-target-compile', 'c',
                     "do not compile .py to .pyc on the target system"),
                    ('no-target-optimize', 'o',
                     "do not compile .py to .pyo (optimized)"
                     "on the target system"),
                    ('dist-dir=', 'd',
                     "directory to put final built distributions in"),
                    ('bitmap=', 'b',
                     "bitmap to use for the installer instead of python-powered logo"),
                    ('title=', 't',
                     "title to display on the installer background instead of default"),
                   ]

    boolean_options = ['keep-temp']

    def initialize_options (self):
        self.bdist_dir = None
        self.keep_temp = 0
        self.no_target_compile = 0
        self.no_target_optimize = 0
        self.target_version = None
        self.dist_dir = None
        self.bitmap = None
        self.title = None

    # initialize_options()


    def finalize_options (self):
        if self.bdist_dir is None:
            bdist_base = self.get_finalized_command('bdist').bdist_base
            self.bdist_dir = os.path.join(bdist_base, 'wininst')
        if not self.target_version:
            self.target_version = ""
        if self.distribution.has_ext_modules():
            short_version = sys.version[:3]
            if self.target_version and self.target_version != short_version:
                raise DistutilsOptionError, \
                      "target version can only be" + short_version
            self.target_version = short_version

        self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))

    # finalize_options()


    def run (self):
        if (sys.platform != "win32" and
            (self.distribution.has_ext_modules() or
             self.distribution.has_c_libraries())):
            raise DistutilsPlatformError \
                  ("distribution contains extensions and/or C libraries; "
                   "must be compiled on a Windows 32 platform")

        self.run_command('build')

        install = self.reinitialize_command('install')
        install.root = self.bdist_dir
        if os.name != 'nt':
            # Must force install to use the 'nt' scheme; we set the
            # prefix too just because it looks silly to put stuff
            # in (eg.) ".../usr/Scripts", "usr/Include", etc.
            install.prefix = "Python"
            install.select_scheme('nt')

        install_lib = self.reinitialize_command('install_lib')
        # we do not want to include pyc or pyo files
        install_lib.compile = 0
        install_lib.optimize = 0

        install_lib.ensure_finalized()

        self.announce("installing to %s" % self.bdist_dir)
        install.ensure_finalized()
        install.run()

        # And make an archive relative to the root of the
        # pseudo-installation tree.
        fullname = self.distribution.get_fullname()
        archive_basename = os.path.join(self.bdist_dir,
                                        "%s.win32" % fullname)

        # Our archive MUST be relative to sys.prefix, which is the
        # same as install_purelib in the 'nt' scheme.
        root_dir = os.path.normpath(install.install_purelib)

        # Sanity check: Make sure everything is included
        for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'):
            attrname = 'install_' + key
            install_x = getattr(install, attrname)
            # (Use normpath so that we can string.find to look for
            # subdirectories)
            install_x = os.path.normpath(install_x)
            if string.find(install_x, root_dir) != 0:
                raise DistutilsInternalError \
                      ("'%s' not included in install_lib" % key)
        arcname = self.make_archive(archive_basename, "zip",
                                    root_dir=root_dir)
        self.create_exe(arcname, fullname, self.bitmap)

        if not self.keep_temp:
            remove_tree(self.bdist_dir, self.verbose, self.dry_run)

    # run()

    def get_inidata (self):
        # Return data describing the installation.

        lines = []
        metadata = self.distribution.metadata

        # Write the [metadata] section.  Values are written with
        # repr()[1:-1], so they do not contain unprintable characters, and
        # are not surrounded by quote chars.
        lines.append("[metadata]")

        # 'info' will be displayed in the installer's dialog box,
        # describing the items to be installed.
        info = (metadata.long_description or '') + '\n'

        for name in dir(metadata):
            if (name != 'long_description'):
                data = getattr(metadata, name)
                if data:
                   info = info + ("\n    %s: %s" % \
                                  (string.capitalize(name), data))
                   lines.append("%s=%s" % (name, repr(data)[1:-1]))

        # The [setup] section contains entries controlling
        # the installer runtime.
        lines.append("\n[Setup]")
        lines.append("info=%s" % repr(info)[1:-1])
        lines.append("target_compile=%d" % (not self.no_target_compile))
        lines.append("target_optimize=%d" % (not self.no_target_optimize))
        if self.target_version:
            lines.append("target_version=%s" % self.target_version)

        title = self.title or self.distribution.get_fullname()
        lines.append("title=%s" % repr(title)[1:-1])
        import time
        import distutils
        build_info = "Build %s with distutils-%s" % \
                     (time.ctime(time.time()), distutils.__version__)
        lines.append("build_info=%s" % build_info)
        return string.join(lines, "\n")

    # get_inidata()

    def create_exe (self, arcname, fullname, bitmap=None):
        import struct

        self.mkpath(self.dist_dir)

        cfgdata = self.get_inidata()

        if self.target_version:
            # if we create an installer for a specific python version,
            # it's better to include this in the name
            installer_name = os.path.join(self.dist_dir,
                                          "%s.win32-py%s.exe" %
                                           (fullname, self.target_version))
        else:
            installer_name = os.path.join(self.dist_dir,
                                          "%s.win32.exe" % fullname)
        self.announce("creating %s" % installer_name)

        if bitmap:
            bitmapdata = open(bitmap, "rb").read()
            bitmaplen = len(bitmapdata)
        else:
            bitmaplen = 0

        file = open(installer_name, "wb")
        file.write(self.get_exe_bytes())
        if bitmap:
            file.write(bitmapdata)
            
        file.write(cfgdata)
        header = struct.pack("<iii",
                             0x1234567A,       # tag
                             len(cfgdata),     # length
                             bitmaplen,        # number of bytes in bitmap
                             )
        file.write(header)
        file.write(open(arcname, "rb").read())

    # create_exe()

    def get_exe_bytes (self):
        import base64
        return base64.decodestring(EXEDATA)

# class bdist_wininst

if __name__ == '__main__':
    # recreate EXEDATA from wininst.exe by rewriting this file
    import re, base64
    moddata = open("bdist_wininst.py", "r").read()
    exedata = open("../../misc/wininst.exe", "rb").read()
    print "wininst.exe length is %d bytes" % len(exedata)
    print "wininst.exe encoded length is %d bytes" % len(base64.encodestring(exedata))
    exp = re.compile('EXE'+'DATA = """\\\\(\n.*)*\n"""', re.M)
    data = exp.sub('EXE' + 'DATA = """\\\\\n%s"""' %
                    base64.encodestring(exedata), moddata)
    open("bdist_wininst.py", "w").write(data)
    print "bdist_wininst.py recreated"

EXEDATA = """\
TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAA4AAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1v
ZGUuDQ0KJAAAAAAAAABwrraMNM/Y3zTP2N80z9jfT9PU3zXP2N+309bfNs/Y39zQ3N82z9jfVtDL
3zzP2N80z9nfTM/Y3zTP2N85z9jf3NDS3znP2N+Myd7fNc/Y31JpY2g0z9jfAAAAAAAAAABQRQAA
TAEDAKgRlDoAAAAAAAAAAOAADwELAQYAAEAAAAAQAAAAoAAAsOsAAACwAAAA8AAAAABAAAAQAAAA
AgAABAAAAAAAAAAEAAAAAAAAAAAAAQAABAAAAAAAAAIAAAAAABAAABAAAAAAEAAAEAAAAAAAABAA
AAAAAAAAAAAAADDxAABsAQAAAPAAADABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAFVQWDAAAAAAAKAAAAAQAAAAAAAAAAQAAAAAAAAAAAAAAAAAAIAAAOBV
UFgxAAAAAABAAAAAsAAAAD4AAAAEAAAAAAAAAAAAAAAAAABAAADgLnJzcmMAAAAAEAAAAPAAAAAE
AAAAQgAAAAAAAAAAAAAAAAAAQAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAkSW5mbzogVGhpcyBmaWxlIGlz
IHBhY2tlZCB3aXRoIHRoZSBVUFggZXhlY3V0YWJsZSBwYWNrZXIgaHR0cDovL3VweC50c3gub3Jn
ICQKACRJZDogVVBYIDEuMDEgQ29weXJpZ2h0IChDKSAxOTk2LTIwMDAgdGhlIFVQWCBUZWFtLiBB
bGwgUmlnaHRzIFJlc2VydmVkLiAkCgBVUFghDAkCCnGHXtSCpPGjIcgAAKg7AAAAsAAAJgEAy//b
//9TVVaLdCQUhfZXdH2LbCQci3wMgD4AdHBqXFb/5vZv/xU0YUAAi/BZHVl0X4AmAFcRuGD9v/n+
2IP7/3Unag+0hcB1E4XtdA9XaBBw/d/+vw1qBf/Vg8QM6wdXagEJWVn2wxB1HGi3ABOyna0ALbAp
Dcb3/3/7BlxGdYssWF9eXVvDVYvsg+wMU1ZXiz3ALe/uf3cz9rs5wDl1CHUHx0UIAQxWaIBMsf9v
bxFWVlMFDP/Xg/j/iUX8D4WIY26+vZmkEQN1GyEg/3UQ6Bf/b7s31wBopw+EA0HrsR9QdAmPbduz
UI/rL1wgGOpTDGoCrM2W7f9VIPDALmcQZronYy91JS67aFTH6Xbf891TAes7B1kO8yR0Cq3QHvkT
A41F9G4GAgx7n4UYQsx9/BIDvO7NNEjINBR1CQvElgbTfTN/DlZqBFYQqBD7GlyExHyJfg9hOIKz
3drmPOsmpSsCUyq8+b5tW1OnCCWLBDvGdRcnEMKGNuEoco4KM8BsC+3/5FvJOIN9EAhTi10IaUOS
druwffI4k8jdUOjISCJFsnzb3AwvUMgIFEBqAcz+c7ftGF4G2CVoqFEq8VCJXdS/sHDrLR4bfRw7
dGn/dChQaO72+b6QmBlLBB/sjnQTGnOd+5YNfIsEyYr2IR8byFn3Hnw6Lh9kQ+2w0VoDxUUSPsgP
3ea+U5ccGY1e8NQUxtHd8GHOgewY4YtNENAM/3/D30RUC/qNRAvquCtIDCvKg+kWA9GBOFBLBeP/
3fYGiU307mUsg2UMAGaDeAoAD45OHdv//+0GPfSLVRCLRBoqjTQajTwIA/uBPjEBY7lttgIuNoE/
CwMEKou23Zq/D79OIIPCLokwA9ME8BHNW7f7Vh4DygUcAxHRCE8cicG/3LYvVxoD0BP0jRoe7I2F
6P7dsxEalGI0C2iw81BmC7Z82y4QH97Qzb1t742EBQ02+EZHGlAbJexkZvcDtXXwHkRhSwRoV9y9
1AYoRsq8BecPXHRG4WDdd0xmi0YMUAQOQfd2TlB2hZIJ6S0AjbtrOPe6Hie0Pht2FFENbTTbb+xL
AfodGDkqFO5Nd2wbGBNAUItyv0AKUEJf69zGagZVFLQS/xoVOcbh5HYGjLR51ppw/3934ev3USQE
RBGKCITJdAuA+S91A8YAXLlbOeNAde+HQDR0F4BHapYmtiwIYV8FWa+xN1oRJsBXUBS8lr/ZCo7Y
jOIMxGoKmVn3+e/bbPkzyWjocFEAHmi8AgANo1kyDUVAP0hQMt1sTW3XGiEUFTi+wI3Rlo6wBFYv
WVBCDwHg5Lq7OR0wGP/TaDbk97UDawdgIwoBFdOpZ850rxhfPJ+ewO3eWjP08fbCEADauAA1W923
BgA9POFOO5SBd4f7sQkQQIWsDKd9CFch27CrfQYzoVihPH90FJdociKmcw+8aAEEAGnsVQaQ6fjw
v1Aqf8cEJGCf/QDwPfQzuc/CGtg11AUgGrv9uzRN6ANB1mggjhZo/QzeRjYH4KAABF+sXusnda3d
m+GBeAg49XUZS35wa+Z7zx3RdFzQKdU+24b7gz1QpwpCCFh1OTHoGrStRimcMdKNv72hHUCLUAqN
SA72UVLL0r1n4VFWRkSjMCwMSMMJzZRe/BDe8MIWITaYw9co1qy3rkvti/gFkPyLgvQRK9CXSreN
K2ZSD/grbVdSmWyB1vErwtH4jPAV9McNRyMywoWgeXUob91BCOWD6E7ehN0BM3woPOLiTi3CfInD
nWNhSIUKKSgcvv4d/MuFVmanl/gBwegQSHR56UPSELkJEZYQ0+jG3O6LLahJaDAePGhJgPcMHxqz
1aQJGoUbLu7MPzIWM+1VVWiLFdM7xcIFHJQWXzlIVa40OLjZhhRad0GmO7wgiTyDEgAG7UGwiCWW
uTgbnrLCQygovoiMcWjvObbHCPIVFQzAM5mC3GJ2CkCeu3ZDAovla6sYaJltbRD7Db0+UFU11lVW
kMmWWimKIWwTn4XJWOhZ8lRVRtndHGSJaLBoSKEEcHH7bYxbHBVUshDNAnUf/zUeLWbG2gUfYKkj
7N10k9gtUOsQaN7FDqPhto/rRcQgxDg9jPAv2TP/V1craJ1WtgsbJkczdQQv6wLwV3KRMMbvVuOI
YWicZL28gZrRcm8Xvpz4UzPbmhkADFNo3JLaGMfae/waGGAXBzD5TbQbQQpyUwDYU1CNRZjHyLK5
mjlwJ/gcxGucpe/13crsRqvZ0axhRe3RO8MvtV7awF44GP2NTZi3dWZ78dVyjDacU1CL9Gwu7Uj/
tHHW4xDrpC3aZKwBrNfaaUnzbOgp+P6II202O1ti7Mcgqu1ttmTGNezw/U4AvTGzbBbwDAgQH7C7
ZpsbDOhZN+homnQPrAvY9xj88oQbBy9WcKBSEkYSiyUwCasXZH6SaeDoGbiUXi3xAguua5qbPY5j
amXuAoEIs8sEAOsDcsiC3M4ctmjsENROEHNhWYcrGYxhHc8BNSXkkE7r2c4WkwMCkyBoWERyfMlW
AlJ0bDHocfcNPYtACD0x7HQpPYAWQuBZTdMDSTXgTyMwU/u+VYk9RKFio+7DZoC4vxFchQ0ZrHH2
FhQu3xygXev72BQQtVm7illkplNpofAcUY+OFB1AoYPB9yCeBaThAslHvdt0Uz45NZw2o1RsdBJo
FO72F+E3wiIMN1ketJ8ZblYY8hNo+HFPGgVJzcDEEyjOA6k/aXODAISMV3UBDOBoOHR4J7RzD5Q1
0CL+7ROTwZSH+IVVBYPI/+tmU4Fr5JoJmBKbMzqbo/eUFAfiCQikGdkZtgr0cvTki93twRCYaKB5
iTB7MHyOWyTTVl6k46MxOrE1fxL0KhnwlkvlXltfxVABoaqLrVZwCwZDGhAv+L/QUZAGtARB6/YP
t8HB4BDxWOJQPv3iuy79aJiNElPEHb19VlWNX+uSEEEUvVGF9rkL/4GbkYuEJOb32BvAg+AYwKu7
kIFjl0U2/wWNluuSsZUrc0kPKAq5DoN7lCR0L5KJBCYTdpttB3QqNGhMLCwCZkMbpwOHDehnjwS3
bIgsbYt2bwO4twSUdYSLUlSBxP2lhXdSHgDU0Fvs78UDmxAA/CgMB22ZS26saI4IkXeEAcv2GdkG
6QCbdHsCXiGAk25uD4X+oUSf4ZmhFT5PDbhzDtVOXtsvHIaX3lbizp26s0ljptYuV9DdbNeSEKg5
DzeTi6THyo5DrPcPZRlqMEknlGYbERq0Sl8j2NOk0HOK0Iacsb5yZyDgQSYu4YH3A5jk2EdomB9c
BftzJ3U2H2g865Z9yITd+A35WYfrG1eEBhu5TovDxg0I5hyBh2GTeBuJBsIY7WNpWYlGBAMiXnwr
lVpaJlYd8QqhOb7wdDWCTQhQUbwFgxDOQmURI4yYK9ak6wh4cD2XMwmxXesGiB0o0Ok+VzudK/Am
ElY0SOEtcDYjajnQuWk25A5nQDGFGqGAXmETLx5ydEmrFb/Qdgk3dEMEAddqI2iUdNgGM02Y/DfW
GAb9fysVMDQGBw+VwUmD4QJBi8GjHTDw/kLrx8cFB7Hdmd7Sruxdw2oM4DxonNDTk0DoBl4dQPMc
JVw9TQfIMyalcw3NRgDk1mwfCsQnM2emsAm4IuvbQDkBGirrHAxnO9BBv65LfCfBIp8N+eS4dQ2D
Q7OdtEmEo9Ot9r1Ph/CAHWxoD9MF3GBuYYuELTgFY8PsEOkpePoXTcwdqz1GLIVoeDARY3OxMHhI
L0Q/RDEy8FCotMAVeIdNFiwZFWQ1MZvFwMj5YTzxlmb/JFi5wRQ7K2zCYPxQXlxQADt7YliMXABd
GxNEyrY2YyRAXwv2rYaEifABdRw9jAEaCTsowjMYhAmhmSCPGFYNOxmwaBhAiRKW7xiFDHVq/BQv
dsmz2BRp7HRXYh4IGwjO3HSw2HQEZnNJVHw8MbLNoDjOzWDs3mE2sup0QDX+A3sfwBb8dKUcQL6o
F6orO7IBVqZWolAmCwx5Xgx7J4fRg1Y8NfxsBUIyshE8xPResZbxETZEXOw7Xei7JLRedOrKWWcZ
UHJAKJQkLBHK4nVlroNUQm6JA4Sz9HoQFwKYFo/ZBHRIHCFd1XS3S7zdVGoLWRGNfcQs86sG9Il9
aOlGBaurAHDADKsy8baNGpATjBu/AAgXRKE1N1nAMIkvLyxsJWgsCxzcHCStbdAOxBvFFQcGM8H2
wcxrJ9Yf8CsrGbsznRJsIOIWQBn0JSdPLm15GvgzbOfJbpQjn4mOXG0OunOMNHyYwQWUfrtlMywF
rIx/kCCbdbQ0uG3ZAryoD6T+gygg9BjB2WhcLhE2sGMwFp9Ao0x4NeTiVyxYwzlgWCVe/fTSvRxq
ULuAiXo33Om+bHbMBE7XVTvw6CwVKy1M4mKzpU53oFwfDWwneMsjRosgUO2VBpsVAb0PpekOnZlU
E6O4GDA94EMpsmoKaffcErJHIF1gnxij4sDPzAyiF5dQo5U7H69sYRQN9pbUN22rzcU391vXUBN4
wWCcbIEH7LGA4fEspmnD8N7+PwvTVU+A+Vx1RIpIAUAIMHzo/4ZY3gQzfhZu63J12cYGDUbrSzhY
ttMFCvT2OFFf4UkHqIg8CmIfiGvQv7kGUh+tiA5GQOuncoWrTXBSdgS4VQgoq/ZvhAhMAupXK0EQ
AjXY4qa4IoE5zY00EJPDF2b7hlg+elY0Egu3mvzffmiMr5hOCIWdDYvWK1YEK9GJFWNbcRedK0YI
JbtX/i4m8W8MBFOJASt+BMsU4Fm6QEF0d7L8U5htOllaYFIzM9sWAGcjXVGUdjtcGzYpPlXIM3cx
agJRNHBvBzvDSAx0Lhe3mbEIVraN1MLCLdHq69J0Re2kASbQnCEoemo8GlO0fH5Wlo6PXAHYA9yG
FEDW5OBgAUw7VwB/h/yJBhycehXgc3My75FMF5RMW9i70LRotgZsIvi/JeRmxfnY6t4X9cQepAIc
iYAlTNjvBQY5BuSYdlZejkqxQa87dhECwllzLWMECy1WMmv0iI6e3Aq3CgmBdqboBvBhqnkWiMRg
Ar4rpAQZgYeCXG2AjqQzI5vbfqD9HHd8EUAETgYYhINZrF7jTNsRMTuSOXitmBANEWBv9pYK5OAQ
RR1wBJ6DPgd/akQG5oG+JaheVlOJInOga26sM9SeThxQt1mhHZK37kQqU2bYznALTdidCEOPeIO7
CR4l8TjWag9X3HS2F7UKTw2gvkaMLLac7OgI1ofwzuYsE2Q1I1NXhk9DIjRqW4v10v2yUdjC20pD
al1TDfgVoPTL/zyAJwBH/T+yResY3wOA7X8InAhYHFN7GtJNnlsIBGAIaV2UHDIUPS1LOlZyCNSU
LXADQ/rqCAPW/CbogrIC9KAK/qkdXYgJtEx4WT2Ld5akTK5ICUKxHoyx1jM0HvIbCAmj6W76WTvH
ufh1Fh8YV8YL7lgwDx0hJ7JszWZBov938BH2AIdaJGKJEBEWuuQC4I9qKDxYA2NsTPRk1bvX6uwh
uifvQNc4TiUhZjegKAAXJ701fmtl2wSOQTtNRgl8FoN1tq7BIxKD6Fa0LE0H5kphWk0Mk7nqAs1w
E5LoKi3FqGscD6QzMImk6QU7icw5EdSvqZlr03UQgMQSFjAVpGrMvhYvBh4sve8jv7gewSyMxI7f
GPwKVDonIzaRwjBXeISxGyHYsQAwizjV77RXg0UKhwSvGHXGbp2FC++EcOt/JaBGHhlCbPTrWYiB
jB1AdNoadDuwf4UzlhmY6yGJYCIX2p8JBxoCWYOwLE34szswbO4tHzP/cAh2yCE0lYtfQDI8biAP
chBAaCRNgouCwBh0jr0aqZ9QugUMH1nDVr78i6/3FblWM7hoRcCJN8RLHadZo1RGAlt0YhgdeObv
zEKEmXggwDgBfhXFz/VtHyQMMA1iGmzBCd1t0QUIFQJemVGiwKyKBphYIWJR5woIgHRZVY424oN8
K4eg9KrSUYgVZVAHWOXNRASAIF21lhs5BFioYdjC1zC0Qgg/DGwQqswABTPSO9u/wcLCVhaLzTvK
dCyJUBQCCP0W/y8Yi3EM994b9lKD5iSJMYtAHNRetbsgFFG9JExwwgz7Ti10uOkIkACoX8IBfZz2
dDqLRm5rluh+M6okLD0UDZtbdkshUD8ybAgeGijrSrfBUFFbJA3H+ABUWq9DAJ9VCLtqaza694oB
DaY6wR7bdxsM5w+DfCQYOArc1TuMfQmxO/d1Cj9fYWRNb619IIl+GDoTYCDwQxB+duWt8Sg5fiRW
DiQQRIFqGG0GwBV0hEMnifhtkq6GPvxMJYl4FItW1btSXxfPiXoMvLT32cdAX/f27TJ4+Qh8WQQP
f1QfuBHT/xe29uCJShBS11E32hvSUPfSgeLAQgPgfmxlUjwkzBl42QH4X0FPVjl6FHUPI26bdY9v
DiycC1YbybBkhCdfuPppEC5UeZ5xU1UQDAQEtt3tUHYK+QOhPgAI8OKXKGyLVCOIg/oEv/uH9u+7
xZXDS70FweP7iVwZiR7+1bcIyA0Ph8RnJI0QNBkE2kazFbY9iEkeiQ0b39qGckGLLwWLDooRHASj
0W98NRYQBIPhD0INLvOCc38WdBXHAA1V3WwY0Hjj9t0NheuiIotQEMHpKMEIXQYmB3Z2GCS8yjfP
19ogLhcFvQQRSDPJrb3tCo5mCEB2i14cC3k32h63Bom9HwMTiVdDBL33v8HB4GnB9/WF0nQhxwNW
lJ88XczR3V+kaPbBIGFncxslgWMpByZ+lByxHNiE2iV8V1oqmHKkdf3ho+xVIdgCVfNgLLetbcXs
ApIiAU9pAqW61GZzoDONSBLH5lykUh4SRFQM+S/5ZlsL2Aw54wgtAnMvmDNj5O3hSu25xlvcweEY
SAvkSZqjlmw0CcQzKIy1G4NIQokGOhwUAftbV5CBSDfiEAPKiUg5kovkkgq+CGZLLhkLhDZlDjfm
PzlINBI2YDZDhOvlM1lACMiB6Yykrvgh22gCdQmLx9uDc27ZwginZ3JqY53JLLSkFlBHbsclhAfY
AQM5FkhPJcBwuDeKCp1TvA6QI2c+VgIEDkMIk0nSIIkhJYywKLMhH2u2Cwl4TjDzBrj4NCwj2Ttp
LHzNZgXDcAAlybcVlmoA/QxDAcXcki0p/QY4WXat+gtHMDUDtDLuWTbNsi0zaLQ1MaJZNsum1xEy
S+wz+A8kgZdbf9NXAodbA78FejyJQ3Rob62JngQPBAV1Dr7WgSXe60coUndXynUjG9j1BnUNPldR
6jwMKGDbbrzH8gFGNAIwDjjAZ2tB7lEIIHQOrbUmDAFw0B9gsnyOhm3Aw39SbWoadK4RqmRjINHC
QYOHT/brzAY4WlzETyiWSXwMBQ64Gl/Zl0jMShd6VyiMkO7YErnHw3JAKVAonc5BcygfnytRkLAG
zh4uojbw1o1qAnID2B6JXiwSQ2K2vDjIBFD94mUvqgCD7FI4U9ZAK9FvOOD7KUOyora1xmsSSC5L
/9eW+FbBEDBWO8jDVAoVAdeWf0RzBSvBSOsFLAcejHDwuXwDg/gJGQyFLEADMNFvfhiD/QNzPP/t
9g3Xk5YNxuRIig/HFHV//99MlIvRi83T4oPFCGML8kcxifzbe9c4iS9yzusEN6+D4AeLyNHo031r
C7UBZB5LGHeRY1T/9ixwg+0DGQHNHAfB7gPT7iuiDja96T+zJb5BSN1toe3HUo2whI0NMFEOOF7X
8IlSzkMcJFwhNPgl3m4pW1EPLFIQ3l+B7gMQNBwUia6172bGnjNcWHEGYXhDDiwUA/jWxVt3/VgU
ziBzLKn6+tkCDeegBj9MLE/2uhncc3xAJwDy1Iu70iW25M6CgeEHcuoQvf23wDPRr6I47YvBO8X6
BIlsww7SrVxLJgGLiQPponPbEkzSF7wqxxzwXTtsBYWdFnwaRDvWdSOu8Vvcv4t7KC10GYvXO7EV
bLtQ+HMHK8JIV2Qr8nOJNeELXXd1Z7RMQUgEU4lTNCj3xdbaDgdHMGrWo9qGt1lMOjErykn/SywH
I9/tOQQ+VXUgYvfWNrn5IPJOi87Ci8ikwzDhzl6wCwXQvcFCyXadwjvBBcFLFFrTPhREMCSBAnj8
BffzpYvKLY3hAyvQ86Tao21vd1wlRANSDUtdFUNnunbwKwwWiXgcKZFqcyl2aP1DGAkgjzGEByqW
DnM4MsZVcjIOktJic3QfJf8/JcggmB9joW/Zhx0G1tA84Agagpu7gfqgBRPyBb4FM9A32H0fRo2E
CAKHd2ycpZsDSCj5UGEMnHjj+Y0FDkgOx0NuNPY2TfAE6wiucVMuNLrRkggRCoNiLXNoqeR3nlky
vjQGjkgLkwMsCE6x/dh0iYv8AGKmSwzFBJG5QmuwYQgIA4Zq3g+7h2dymDC4E6HIcyE8Cu+1yTTH
MWk1oEvb6eY3IHLfcBokb0OhwdJWyVNRUjRX6mzanPHjUFE8LGyb2bWG8IUh+wjmBT58hYVPZdA0
4h/i7SwYNzUCXQ+De348+nbSWTvoczPjSjsF7r229uv6+UqY9vRYc0No+Qf6Lvl38HfpzYvJKIy5
FCPG5lTBAa0GzbWN5jR2tFVrbbe7EJc0cxvJK+rRDEWEO1zDghKKcUCkNyuA4wv9biMSuc10AzPy
g+gSzSV3icdZKyT4Cx8tkIf9wAs76XM7meAERyMH1h8wnenJ7NHvzrV8d1WLDI2pI869VmuvJg4U
YtSQZYRT4xvXFRzh3q2fzowKHgPQOyqHqXWUWMq90yo5EOkXcxdqmfCCkxUN2u2lwjcdivzrAgCo
DEFImYGE9vCP/HX1d4leenTby8SChZgVQCQmUTZjpg9QQI3fCSwkUX8N1zoSUjw2Oz9RQgVsFDAA
uWvPFDDPGohlCQdABk2Ps+wPQYwkHxVM+2hyJyQKGQglNM89Dbg2dz2fPCA7hsD2Kxx5UKROhFds
C1meBAQGKUi1sMADD3Neazwwt7rYopfYBNArnTgDmoMXX1ZM6M5NnfoatO7nUVxJaObZGrF7QHRW
4sXZlV22VAAdkCg84CdNPg0j4lBwZhixKcy+VgJpIRiJ0gDmkmxgLAChna3XNg7PiyZompba1txr
u+mVTFF3hdoXsHbIJYGQoTMGG4c27DDD4FFcYf2bNd5MyzMYTHk/VVHsh9+e8uTXav0r0cMD6lBO
e7IrGUtMjTGLaTmwuYZlUdArAWaS6hLIdosvFVJROkNb9q3NhTJqx0EYLINLcz/W2kZASEhRiXkE
RkQOHGEIGBFLIOgE12gTs6zyhKfYG4RZhBVSyMbg4j0SVMrE6MTnMwDOOUEEkxncS1SKZPcD7oNR
mBII7k/RWLjCgqElRROfz56FEAgfavxQlHneISUNkAiMz0AKJBQrjhgom72Rnf11BlulwRbZw09R
qDojQrKO1yJolBR8KmOELZ67DlzWtZFS3VAGG8hmEDXP7HjaK2QS3P6B/Z0LwRBfJEwJB2whEOwY
UoTsEcoCPgk7SskbKVxIUFK8Xu/ZpgcMQKZmlhO6O+dBUFZTdEtToc29R9F0N6F76CA3UuVvHy6J
VgR/UCvVi24I45BvJdtufT5mCO+RMQ4YMUMui8dMrUGrhVZVxWNDS/RSSJNWmTsISIeQnZigCQwh
TJcNGJFfTQgyU0+w/hT2GmtFQ0gqQ+Vyu/H/1DUUzTYDQDdrOFwul8saOQE6UDz3QF5BbJpls6I4
Nla4OT3gkmIGG+8MB1gCGqIMe1cYwpWiAEdYaY1yAZ7di1hGKBhwgPN7DRgIV2OqscAO6U+3BtyI
Qbvv3XUK7L2LrXjCDNNc+dsPhu/F7x3fEVWB+7AVmcNyBbgIK9iiFX/cgg+Moa3owe3bd1GI32EQ
ihaDxhusVvEDOeSQs/kI8vP05JBDDvX295BDDjn4+fpDDjnk+/z9G2znkP7/A028ZHWGqASfWRUW
dyv1thJGE0h19LENufHybbtvY/fxTL8IizX39+uLgdi6W/WHEzFdF1t/j0lweF8LwQiflYVQNsEI
UG5J1lBLAxmgLXRIBJJqdLzDDx8coTe7Qo3dhSKKT6NFiFB6I/COEFoMiEgRdQAA4TDgDg9IGMPf
FH8MLbziIHbOA0YJGgsmkvBWyNoWNhdtbgzBDDTBfj5NE67FvBDCRixAgT7YB4kzTTq08Stu3/4G
bOhLTz0dgRY6HBqdzhAKH4yctQqSbChGeixgK1fLiX47jCkr1LZaWiJ7rfmFiQZuLWipZdxVv5RW
UjFgw44iTRFPVRB3Smb31ER86sijfhy4getM10idKA1ArtFAxhrmozBdIP6vcqV0E0n32RvJE4PB
fe4XW+9NYTSdZmMQFUu1En0StkUeVm+NskVY+HNEQFwEXTwXK7oOte0w3AvwigCyjs/T4NDt59yX
AMcIC8g2eeAsQT/7zkZ3CixyvK6F+CMgCRhbqghWyEkYgTXCo18U0+i4bsHxFlz6RSv4QIoBxRaL
SWOm2SKPlQgGr6hWorvQEHTV4A+ui68FbZN0sSIfAkCvRXPQVtTDqP/jJx+Qzg05B4LaQmDvfeYa
r0jcedAfyTcs59gIvosE7X0zJ0y5TQQDyM6tmelaa5Gw1HID12iuFbXTjvVFySHBYMxlXpYDJCxh
FERkGA5IwwxEBIXwUoQg3CxlDI0MwYhBMgTIA9gCDGAghxwMBQYcClBvfgNr1LsBxxXVdQPCKzdo
z5maQNYf7SMhaHiFlrFaAWB9qsTzhZcsLY51IalBabM+MDvBEVQtYXtwUikM+wjrDzbi1BF/Z4YU
UmSkSZSFcmI8DSRDZgxtYiE32MldY2EiXo9C3BLZYp7bAZDu75MwQvMJiEr/EUFIO1B47iFyCDYH
TgzBwOboZklhzyg3sAIFNqQA494n46PgTQqICkJIRIArwsC99s+jWwaeFIsrCuLHQx9rBgocK80T
FxGq6U4SIfQUw0oJN0DgmzAYEHpAYlBukB+BZWr9K81TVlCyTV1hSfiR67SYVh5koYqJAz7g7/1Q
g/8HdhU/PIPvCOgM75WRTIlMN1BWHQpLtouy6hs75oJis04gOittBn8p0248+VMr/YtrZNEIK/Tv
iQtb/otkIuESQQF6kUxkO/6QtG2W262+cUUDTEbQjkfL5XK5BwRIIkn3Sm9LLfKVATDf+QwPPbII
IFFTbCDodGwRRBN2ELHqZpBn2Nt1CaGr+vHRW1l1HLJWVVkCbqCujbpT6yBSVeiJSldgARP03ERb
bZmi0/43GsWJ2r9bU1LHRxhci4pXRfz2LjRdXkwe+3QGg33MRU235QwfOL7CMJ6wWFgpz4Hs8IJd
5f6ijCT0Bvy0JE23QL9n7VfPRANITDRN0zRQVFhcYNM0TdNkaGxwdEEm4E14fImsJIK3XyixMgHv
flyERI1EA0NK6i7QpYm67TkIdR9xGBL0X/mBlG7AiSmJKooXYwsvjxqcF7kRhQ301I2YO0M5KD02
6AbwQYPABCZ283b5fTcen81zBppiug8rtMWN/o94OS51CEqD7gQ71QU7+uPfZtulLHYlVPq+UYk7
0+avYPf2f3MSjVyMRCszeCVTwwTREXLy3AwR2m+Vo4UcDETUC3QrjQMr8bpAeRB83clmEaIDzuWI
LAub+1sb9kqHM9sDTBxISeWMGIFwvxwXde/dtItrZKCvtM3/HBWaiO1wjIQcPSgFjBQeb8cNiVx4
QokREnvdEd80HAhDO9lyxVeL3/c0Gxm7QowUNZSJIT3TUOBdA3EkHtM5Q/Rhx1UAEsQ0PuK3HTwP
j4ECMzRlwEORKIcNuQqbW+C9O0mF0uwrPiD9O+Rge29ND44HYBQ41hcsuVksLfhsuuiZ6P84A98r
00UDzzvX8CYCOuqWGtccIEnL0Uz/T7iNfQE7x3Yng8//9xos4DYsLcduGEEErn3a3S0svsVt4B8H
K8cScu3bsWUjFyS/O+eLsXxs5KgvA/iB/4jY7++nD2cmICsswi+NlITYcaDGYDaJ67mEXZ+6P3Q4
Q4hMoLSELGhi+0XWy4gFMb3G1cKvl9eLSvzvi/XTwXQ3Fr5DK/CJFDt0n+sJShgrNrz3KODwBo//
WrY3HKGMborQCRwq04g9MQ288emLCAyRf3IHxg7Aviu6jeufNykMk/FzFIH+2V34j8kb0oPioPZg
iHHrINw3VF0gFDPmAooUMQzxbu0quYDCSzQxIfBFy22xBPYOhyQmtjayR7rivLQ7FRYN1cJzHrfF
mDB3doZj/Ik5jTzVpHEEhh1y5lcmRujVFHqNwjERbv8FgYXCdAgz0NHoB3X4WISGQ2tKDihgjBzQ
PhhtjQUxJE8j+st+lPuuOl8Yg+gET4gmK98njnXBOTMII3XcderwxBgVyEogK/h4mBrSwhxSkEDb
eHX668GaHk6RG3f1DdNC1zv1dBeRLAF0WGshS037AQwMi4ALCiQPPNBKCF+jYTgAaeCxaBJkGIcT
eGcLX2Y0VfU4SQNkGDRS0+QuAG/YaABjwIBiBFAvgR0VVVJwhfa3EPxioDuDOPvGDGhnsrNMKEg4
e40usp0WTPgEVh63fg/sqFJRS3UkJ4M6FgiBATAAv/1qdxM/HVlO4C2r5E9RkA9bsgiMHvt1H3hk
Q+Ds4yP8dMhiQz4CyC8jwM6AwUukQpglMJiERSMvLpAkD98NMPyAd4Fo3hOhNAq7m3IXnIkCEJTH
ATgRxwJxOuDhOIpAyFHtDGoAG7Bja9d7wNt+nNp2/cF3dgMVLBEU0PVGe+876FjokYatwzcyIPcI
6iCF2kr8VhQrxQPV5jBWllSIX4I4cA6LSzxVBT1uAm42QzwSzYv3pKk+YlKmWcqmO8e/cgPFF0ss
A/2iCnV+0bmtakFEKA2RdVvYnW4fczTqmivunxCEkOXkCldHV9RYBzlWRzB8zfdaiy1e+IR7guSM
nHpRsIphWr5SXTAoVIlRcjUYvXjBEl4fzBduNw5Z+YtpnFEgO3EwY0smCjfhZe5RQZeJ+occOXMJ
K/VOdM7lXrVUSTHNgTYvaboJtA4cLCCD6kRzifg8IotJQRIltjoRi6XIGmFvsbf7CAvWRx1y4lii
VzAjymoj/gbIihzOjTTOLIRXgHeOdTJOAdPqBGcCtK4AxzkEvtsH+MEjawydYF4ENgN/ADmwyzhV
dMeD4w8rvgJdsMM0MU4Nq8skE8nWI6QPD5myJc0gNJwxpmyEHAUBlM+FPQBvO8NzK1kYg9rPAc35
59WH10Em5WyJr5dyBzxZTs3RGrX6z3DB7sdCAVeU9UjXlOAbXAi8SSgRO/dyF4MP9u+L90WKDkaI
Tf8Gg+sC6wG+HWtE6ydxLB8733YTZ39rBYsdHABFRk919hgoku3MYBBLnusZv4Gen9sGBBlwRUmB
YfUjdkQScjoOcjNtnaN2+UTYtZwQSQRtjstCE/gr8z6s8BHgF+qyrTvzD4LcJwLNzbZH2HQt2cVl
BXrs7cHrHtlzAt44K/kzMTbG6o0UzZrCxBz63kFcghZTRgjqz4k+K6ySKxRnVg1W6QB74dRzYiB0
VlfYbFakz1rbXhtAXhB6cj8QSjUZ+Wb+9YigW9vOaAMrQVhAizEdvJfYQTl3X4lBZ5r9RnHTO2af
/yU4kjzHRrYFPEAL3GBMW3GA3szMUT0JC3Ic+30Lh+kLLQSFARdz7E0lbl2YxAyL4WDPUEZhntvD
zD1QYVzQfZcd/Gr/aHBkUxBaZKGhUCnYekt0JQcYaMvoFtR4iWXovqpqAkE3QC09TYMNXFFsZ3Od
BmAU9F8HdNrNDZjx2WENlDGivyOh/BoAo2Tk5la++0n9OR1wGHUMaP5ZTgBhzzZQfxjoaAzxCHAn
4qEC1RW9kD9AlK1Qs93cjAwJnFADkKDyNUQL1QhaBDIA1HcBGE6hDHswtr/7CxKAPiJ1OkYIigY6
w3QEPA3ytu0B+RIEIHby1NBOpKq2uGuspvZF0DMRon/eXjTU6w4rIHbY6/VqClhZxVLRlZpwNixV
regdOt6nHByB3vDsVAmJTYjL3FmUoBdcCi7/dYiBRCNjI2MoBRQQmV17Yw8DBCwvShIkpKIUxd5l
n3s2n/hg7AUPAACKygZVFUjTPCf//xAREtM0TTcIAwcJBgpN0zRNBQsEDAMNIE3TNQI/DgEP9v/2
/yBpbmZsYXRlIDEuATMgQ29weXJpZ2h0D83+v/s5OTUtBDggTWFyayBBZGxlciBL995771djb3uD
f3vTfe+9d2tfpxOzF03TNE0bHyMrMzs0TdM0Q1Njc4MhPE3To8PjASVDMmQXAQMCAyRDMiQEBWTL
TjMAcF9HfW8Jsy9/9/MZ0zRN0z8hMUFhgU2z607BQIEDAQIDBDRN0zQGCAwQGIU1TdMgMEBg58KR
jWzXxwanhAlJWKuvswwyyLcDCwwNa6ohgs66f84DG1WVQYAG/CcIKkNyZWF0ZURp/5/4v2N0b3J5
ICglcymoTWFwVmlld09mRndvFuxpbGUVKxAdcGluM2CWsmcXEBKCuf/2RW5kIBl0dXJucyAlZFMX
YD9YwhQTSW5pdDIYzQI8YE7fXG/fdv/2ZnR3YRxcTWljcm9zDVxXN2Rvd3Mv/9/aXEMvF250VmVy
c2lvblxVbnN0YWu33/5sbABUaW1lSFJvbWFuC2hpCjEFu21tekKQd6VsICTdbm+tZxY0IHlvRCBj
KXB1rvBvv4dyLiBDbGVrIE5leHQgERfWCm1rXS51tBwZS27rtvdjZWwVHGkdaBVTsdYeYLBwWy7r
eRYyI1u7tcABLmRhD1AgAva6YKDZLvXTu7mDzSAGQ28RlVxJoN1Wtj1QYRQAQ7UoZtgamqGzXZgy
Z9x0OUMiW7gpU6Pft6/hofqzZqdzxC6rby5Z5AhrABtjibsQ3rIcFCFigV4bwqFuDFa0pYXDBdeL
qE1JZl92B0f3CjosrnZVTAhva9tjaBJnMwR5KoO2W7iwQHNadHZzLCrCENqxb0JhBJ2Je1vCAHeD
919PcDuh2xptbRGUTGcPUi3mCtt2X1MQcMBTK1QjDc+1NkYIbCMLx1CP2fYbWmdyYW1OAmVDkyYc
/r1pIQ9Mb2FkBN+be7cRGgDfJWNvWNB0AWt4dBpfRSU7Cx+2TbMuBxpyJzAnpzEwQ1NbiDAUZBJ2
OiWT22ACP3AAMhdFawx2iEUYRd9b2sbJXB8bT3YGd8PWnJs1qiDZ6RYnUDgkGx4ZTdqvsIe3PwAb
cz8KCvzbP7zQBvhZRVNTQUxXQVkJb79jD2EuLApwLU5PLE5Fjv2p7FZFUitDQU5DRUxcU0s23CgY
50sHZHXreS5DHNrAl/f6x5uCkCTJsBRSZRpbc7htZlRiKS1Tsr9C5xIMbLXbd2IAI9KtFT4AMDQz
EIlEQjth2xq2SXUxWxldAj1yinCjPQBEqRFhefHJ5iZNK59ZOzK3TYc9S2V5OQordWwgbm977VgL
7mP1IGsdSxu3bFJhLbPdI88IHWctnCFT4GOzSxilNioAF+oK9993bXJKd1kvJW0vgEg6JU0gJzaw
Qzyn/+w/CtsWUmpuymhATTJcWCthlyfO+LWt9hZkFV4AbvYAJpt164lnFl92aw9vBWNYkE8P1DM1
sLzrYnVpX8VvBwUi8BXeQ8oaABw7tZTgBzMCMUkwaxxjeSQAfgkr1GYl7Hgv3Yus0XXA3e8JYUwr
ncGww+FjDUNvz3iKHI9mhSAiTyIgZ6vBNWxHb8pweQxkNh3JHp4WFzoVPwCBgNE+LmIOe96Mb+t4
dWNjvmaPIR9k1CDRNde0CQxkNTDeGN1pEnJ4ZCNyvccyt9ITShGsZSvpS84XAo2BNbsAEy6r4vZg
ax/pZZqOcm1mR6C1I3xkc3UIg1uXBG3sZVkKdP9QXmjgcD5huiBmcsIYa2HyG2OzEGsEx2iaAHuV
nmsodvUgRB95lzC17y8FV0rnHG1iIcEdaETEJL/saK17SxZjgOZjZWXNYXg8NGOH/C91NgePh3JC
IIURCmtmXVv2PxcR93IZ4zAa+Bd2jmQMc49esdvW/mtod27MaS5bcjzi18tkL2IYWmsOIsuqFab2
oP048aNvbyd8GHvg+GCRZDJXWImW7G150W9scz8WQhesFZxGFIUv5wL32LJfGHR5cONANIIGnOx7
NU3XNW/gB9ADxLCg0OTe7Bcb47GSYug+JcnsbU9mZvFlRsF9E85jcxEzYx0MjobSbWQ3LVjW1IYh
m1JtL2wJR3a1G24L5C1ghbZ+WcMDGjbbHAkJL94daaBlBOMFYPwBXdOcHVAABxBUcx9SsEFONh8A
cDBAkEGabsAfUApgFiwaZCCgiD/IIIMMgEDgIIMMNgYfWBgggzTdkH9TO3ggTTPIONBREYMMMsho
KLAIDDLIIIhI8DPYIIMEVAcUMshgTVXjfyt0yCCDDDTIDSCDDDJkJKiDDDLIBIRE6GSwySafXB8c
ZJCmGZhUU3xsEAYZPNifF/+QQQYZbCy4QQYZZAyMTAYZZJD4A1ISGWSQQaMjcmSQQQYyxAuQQQYZ
YiKkQQYZZAKCQgYZZJDkB1oaGWSQQZRDemSQQQY61BOQQQYZaiq0QQYZZAqKSgYZZJD0BVYWBhmk
acAAM3YZZJBBNswPZJBBBmYmrJBBBhkGhkZBBhlk7AleBhlkkB6cY34bZJBBPtwbH2yQQQZuLrwP
kEEGGw4fjk4ZhCFp/P9R/xEGGZIGg/9xMQYZkkHCYSEZZJBBogGBGZJBBkHiWRmSQQYZknkZkkEG
OdJpZJBBBimyCZJBBhmJSfLZ9AYZVRUX/wIBGWSQC3U1yhlkkCFlJapkkEEGBYVFZJAhGepdHWSQ
IRmafT1kkCEZ2m0tkEEGGboNjZAhGWRN+lOQIRlkE8NzkCEZZDPGY0EGGWQjpgMhGWSQg0PmIRlk
kFsbliEZZJB7O9ZBGmSwax8rtv+DPGaQC4tL9oQMMiRXFySDDDJ3N84ggwwyZyeugwwyyAeHR+6D
DDIkXx+egwwyJH8/3oMMNiRvHy++ZLDJZg+fjx9PkqGSGP7/wSgZSoah4YaSoWSR0bEZKhlK8cmS
oWQoqekoGUqGmdmhkqFkufkZSoaSxaXlkqFkKJXVKhlKhrX1oWQoGc2tGUqGku2d3ZKhZCi9/UqG
kqHDo6FkKBnjkxlKhpLTs/NkKBkqy6tKhpKh65uhZCgZ27uGkqGS+8enZCgZSueXSoaSode3KBkq
GffPhpKhZK/vn2QoGUrfv7yTvqH/fwWfVwfnnqZ77w8RWxDfD02zPE0FWQRVQV3c0509QD8DD1gC
r9O5p+kPIVwgnw8JT9MsT1oIVoHAYDLIIGd/AoEZJ4ecHBgHBmFyyMkhYAQDh5wccjEwDQxMiCUn
wa+IC3RTTiBkeSxpY1S6UMtWMnJl1a2w/00Ec3Vic2NyaWJlZCdiISGWS3YegRLYyEcjQRQvCXF0
ec0UsoERrhcen7MsZW/ZKD1jHzRN86UDAQMHD/M0TdMfP3//AU3TNE0DBw8fP3/kKXgUbfUBEDYg
qAMgkEUBgqY5CChuLCWfIL7LBF2gCS6Xy20AAOcA3gDWAL3lcrlcAIQAQgA5ADFULpfLACkAGAAQ
AAhkZ7cSmDOlYz/uAOEIyhY3717YgblZBgAF/xfrEjYbETcP/gZWFjA3CAUX2ZtM9g837wYA85Ut
Sxc3/7a/zZxrtwampggMDgv7wN6FF6YGN/tSW0r2xu7++lJBQloFWVJaC1sXJw/svdjvCxEGN/Yg
uV0onialgBWvBRQQRnYb0FjGF/7uJm4+sPcFBjf6QEr7UTHAvq7dUTFaBQBaC1oX1xZ2bFoFEEpv
YLr/uq01dQVUFW4UBWV1hqZsLNbcEBY3FwsdFm+5t+eGEdldA0dARgE72Vi3BRHNWG/6C/lAb2Du
dSO6FV15AdzM4N4AEuhGCx3kQT7Ab0ExWEhSWPaZa+4QBYUNC0r6Ud9GPvlTFGVkECUQFqamZGDd
zP11FZUXCwoAb5sddhhDdUgLFxrZN2QxBTFvg3mCKQKzFabP37BCMAtZFwUUOeMxZN/7CiNaDXPM
3AMLOhdxRkjYBUJXT3r+4Q7rhpMIvwu2BVJHyJafb/D8cr1hL8n+DQMGkhZ2mATJbxHJZi9YBwUD
d80I2XsL9zf5yRb2hgcF5w/Nhl1I7+5JB3uzhPAF9lcP+zfO3nsLudkHBfpkb5YQxw8hb5u9FiP5
agcFA2wZwzgVQ5tv7LJgA1VvRwVOKVvGm2+BSzYznfIBa2l1Ylxg7hbnbxETs0nDmuxabwVvtqwh
5EdRMQBbb9jrJWl1bwNvyrYxRvNZAltvW2AP0xeb3832CmDfcibfDW8Jm/AFSfz5PQMIieRkb1r6
tzbZe7wJ+2mH9t9rG6RA61LXEb/SylLGLzfx1ok6Y4cVAFWkla2MnzfxIDl3xvNaCwwP6bSSCG9m
61tI7SULDPcLLxms7P434gmIshhhC4dFDQMaAdGE6DPal8BICT0Bsv0tRUtR03T3cOq6g0XIAU0T
IANhW1H3Oj1zCSFyeWYWqBdGNlB9FbN+AVGCWV//gnWf26JbaCUxVwd6rmu6zT81ZA13bAEgB27s
zH1RdBkPJS1vFWu6zW0FeQeFcgljbY9d132udSl5LhNDL2kZa2Y213ULThV4Gyl0L77nPnduC111
G1FHQ/Yl68bBYxFsKzlpO0O27A1oK/+3LnLTPWHsBAiw7yl4AP3hsl02gRwCAw5QBj92eESbU6ND
DwMw3YW1fQACQ6NMCW9mZyMUnwWv+0KEJ2wDY/+UcDh0T3kDO5l1EybdYRlpN39zEvUT1jk6YIAI
gVDDwRsJS9Rtfe8T7+w7mSeeAEJ2g0lnD8G6KUQJcp2/eQd5IWRtgwMBoWQASYmQkf6DB+MgYwSr
YoEUwpKmZ257pyG5j/dJbRtJm+kue4tNcj92BXfFPjcZ9WNVJWdbEpaM9Al5Y2bvde89JOd0D0MN
LKTnLotT0UItCZWQFiCNbWFmwzysS4BPs0P34ZrrbX0NbAdfl1R1I11y82dzATNZFUP2o1AVMSuG
G3kac4nsU4PKOLJFYzpfCAFIJgNXjdGMcEavaWhldWQIrNPVdPl3DQNkrdspZ4JXElgl4Y2hG+OB
42R3dRdjeaHa5wZmDTV5jdJggQACAMHlRFXEAFRQKnZVLDhH8Wl23kGxFY4GbzVJbnRBbALQyhYw
GRVuK+BUdUYTHEDLTDERpTYobu8NUmVzdRZUaHNkYlfA3w1Mb2NhbEZMAUTbz96LhTczTW9kdRFI
mwQ05GFuZMU73bpgD1NlColvAnR5Kt4LqBJikhGwgRmORo4lC+hU+8q2rfubJR9TaXqGRhNtQ02j
4u/tP2FnLpxMaWKGNwvWnq5tDDdqxbCY+0FkZHIukIpsNrBHZLSTEmgEoO1MG3SIARVnIyErVlO6
UsVN6XVwSSkQU4YH2Moyv0F0g4EQ9NpidRv5mAg3N7BnG5xvc1gYgl4sXBYIy35uM4MYRCcMVG8W
Cbvbtmx8cgtuOlVubVhDI04QNBlW7I2K2WdkvEV4QRBiYG5C0hAO1trZo/AQUQjAD4u9NywxmjAM
mgPWTpgcT3CDXUWzzRoVUg6G3hdaMk4kAStBeVNL2ATDaGWTyBMytoCepuswVKFPtv0mFDZoDENv
hXINw5PhOEJrPptPYmpzh3CaBExvCY5JmPsMhUL1GjVsJCo0279dU1BpZEJydXNodvXcTbuG4VP7
ImZwOXQN122xZhARaHhfCbRr7+Z2S19jY7ZsZgsVgtyjomNfJF9BD7bRxt4JX2Ztnl+0XHAd2oY7
wmjTcjMRp2puC1YC2hFmQTsObtbaY2XZ/WU9XdFcYbBtP18hvYZz2+5UmjxjbUduCBH3uHNb1XQ2
ClhjcCgNG5u5MW9puQVKXzmCyQWsYwt02EYBPTO4EwEIcXONijdr/vflpT2ei21SeQedF2NA2CKM
B24YtG4aWinWWCtmKUYf5hfMlRk5WB1tcD7nDkAhB83GdgxBr8tAbGcBG3uczV9MY2wQZho5zoYF
Lg5mMAKuWJqQaGxFE+hxGuSQUWHUhgMo9gFkREMVYLm+dxhS+Q4VTWv3eJabFgtUQm/AH2W1x/Zs
Z0mvbTMgcWCuoO1Uct1z7RICctuk4MB109BlheaLGT8tQlj7NlNXjmmNRUYJdTX3K0N5c1woFGPb
WLbQOVA5azXQZpWsgos1wB0J8+hOyQZTmw4Qd9IsGUEZ7zyJksF1IBPk3JYv1gloif9JC/aGtWgl
/uVWap5Usi9VcGROcVBFMOitWEz7qBGUEyRFuf/gAA8BCwEGHCMMOivqfFinYASyWPReCwNqBzaB
JlsX0GEMZfUGdhAHBgUCaZ7lfGSMsBLwCtsFp/gBHi50QjbYzmsHIEqQUJgdIWj3G0UucoxMDs1l
S5hTAwJALvZOs3smPGgxcAcn3ittU8BPcz4M611b2ffzJ5BPKQ1nAADQPnvGA0gAAAD/AAAAAAAA
AABgvgCwQACNvgBg//9Xg83/6xCQkJCQkJCKBkaIB0cB23UHix6D7vwR23LtuAEAAAAB23UHix6D
7vwR2xHAAdtz73UJix6D7vwR23PkMcmD6ANyDcHgCIoGRoPw/3R0icUB23UHix6D7vwR2xHJAdt1
B4seg+78EdsRyXUgQQHbdQeLHoPu/BHbEckB23PvdQmLHoPu/BHbc+SDwQKB/QDz//+D0QGNFC+D
/fx2D4oCQogHR0l19+lj////kIsCg8IEiQeDxwSD6QR38QHP6Uz///9eife5pAAAAIoHRyzoPAF3
94A/AXXyiweKXwRmwegIwcAQhsQp+IDr6AHwiQeDxwWJ2OLZjb4AwAAAiwcJwHQ8i18EjYQwMOEA
AAHzUIPHCP+WvOEAAJWKB0cIwHTciflXSPKuVf+WwOEAAAnAdAeJA4PDBOvh/5bE4QAAYel4a///
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAIAAAAgAACABQAAAGAAAIAA
AAAAAAAAAAAAAAAAAAEAbgAAADgAAIAAAAAAAAAAAAAAAAAAAAEAAAAAAFAAAAAwsQAACAoAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAEAGsAAACQAACAbAAAALgAAIBtAAAA4AAAgG4AAAAIAQCAAAAA
AAAAAAAAAAAAAAABAAkEAACoAAAAOLsAAKABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAJBAAA
0AAAANi8AABiAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEACQQAAPgAAABAvgAAWgIAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAABAAkEAAAgAQAAoMAAAFwBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPTx
AAC88QAAAAAAAAAAAAAAAAAAAfIAAMzxAAAAAAAAAAAAAAAAAAAO8gAA1PEAAAAAAAAAAAAAAAAA
ABvyAADc8QAAAAAAAAAAAAAAAAAAJfIAAOTxAAAAAAAAAAAAAAAAAAAw8gAA7PEAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAOvIAAEjyAABY8gAAAAAAAGbyAAAAAAAAdPIAAAAAAACE8gAAAAAAAI7yAAAA
AAAAlPIAAAAAAABLRVJORUwzMi5ETEwAQURWQVBJMzIuZGxsAENPTUNUTDMyLmRsbABHREkzMi5k
bGwATVNWQ1JULmRsbABVU0VSMzIuZGxsAABMb2FkTGlicmFyeUEAAEdldFByb2NBZGRyZXNzAABF
eGl0UHJvY2VzcwAAAFJlZ0Nsb3NlS2V5AAAAUHJvcGVydHlTaGVldEEAAFRleHRPdXRBAABleGl0
AABHZXREQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
"""

# --- EOF ---

------=_NextPart_000_001D_01C09C46.A9DB76F0--