execnet-1.0.9/0000755000000000000000000000000011760165371011661 5ustar rootrootexecnet-1.0.9/testing/0000755000000000000000000000000011760165371013336 5ustar rootrootexecnet-1.0.9/testing/test_multi.py0000644000000000000000000001211011473521746016077 0ustar rootroot""" tests for multi channels and gateway Groups """ import execnet import py from execnet.gateway_base import Channel from execnet import XSpec class TestMultiChannelAndGateway: def test_multichannel_container_basics(self): mch = execnet.MultiChannel([Channel(None, i) for i in range(3)]) assert len(mch) == 3 channels = list(mch) assert len(channels) == 3 # ordering for i in range(3): assert channels[i].id == i assert channels[i] == mch[i] assert channels[0] in mch assert channels[1] in mch assert channels[2] in mch def test_multichannel_receive_each(self): class pseudochannel: def receive(self): return 12 pc1 = pseudochannel() pc2 = pseudochannel() multichannel = execnet.MultiChannel([pc1, pc2]) l = multichannel.receive_each(withchannel=True) assert len(l) == 2 assert l == [(pc1, 12), (pc2, 12)] l = multichannel.receive_each(withchannel=False) assert l == [12,12] def test_multichannel_send_each(self): gm = execnet.Group(["popen"] * 2) mc = gm.remote_exec(""" import os channel.send(channel.receive() + 1) """) mc.send_each(41) l = mc.receive_each() assert l == [42,42] def test_multichannel_receive_queue_for_two_subprocesses(self): gm = execnet.Group(["popen"] * 2) mc = gm.remote_exec(""" import os channel.send(os.getpid()) """) queue = mc.make_receive_queue() ch, item = queue.get(timeout=10) ch2, item2 = queue.get(timeout=10) assert ch != ch2 assert ch.gateway != ch2.gateway assert item != item2 mc.waitclose() def test_multichannel_waitclose(self): l = [] class pseudochannel: def waitclose(self): l.append(0) multichannel = execnet.MultiChannel([pseudochannel(), pseudochannel()]) multichannel.waitclose() assert len(l) == 2 from execnet.multi import Group class TestGroup: def test_basic_group(self, monkeypatch): import atexit atexitlist = [] monkeypatch.setattr(atexit, 'register', atexitlist.append) group = Group() assert atexitlist == [group._cleanup_atexit] exitlist = [] joinlist = [] class PseudoGW: id = "9999" def exit(self): exitlist.append(self) group._unregister(self) def join(self): joinlist.append(self) gw = PseudoGW() group._register(gw) assert len(exitlist) == 0 assert len(joinlist) == 0 group._cleanup_atexit() assert len(exitlist) == 1 assert exitlist == [gw] assert len(joinlist) == 1 assert joinlist == [gw] group._cleanup_atexit() assert len(exitlist) == 1 assert len(joinlist) == 1 def test_group_default_spec(self): group = Group() group.defaultspec = "not-existing-type" py.test.raises(ValueError, group.makegateway) def test_group_PopenGateway(self): group = Group() gw = group.makegateway("popen") assert list(group) == [gw] assert group[0] == gw assert len(group) == 1 group._cleanup_atexit() assert not group._gateways def test_group_ordering_and_termination(self): group = Group() gw = group.makegateway("popen//id=3") gw = group.makegateway("popen//id=2") gw = group.makegateway("popen//id=5") gwlist = list(group) assert len(gwlist) == 3 idlist = [x.id for x in gwlist] assert idlist == list('325') print (group) group.terminate() print (group) assert not group assert repr(group) == "" def test_group_id_allocation(self): group = Group() specs = [XSpec("popen"), XSpec("popen//id=hello")] group.allocate_id(specs[0]) group.allocate_id(specs[1]) gw = group.makegateway(specs[1]) assert gw.id == "hello" gw = group.makegateway(specs[0]) assert gw.id == "gw0" #py.test.raises(ValueError, group.allocate_id, XSpec("popen//id=hello")) group.terminate() def test_gateway_and_id(self): group = Group() gw = group.makegateway("popen//id=hello") assert group["hello"] == gw py.test.raises((TypeError, AttributeError), "del group['hello']") py.test.raises((TypeError, AttributeError), "group['hello'] = 5") assert 'hello' in group assert gw in group assert len(group) == 1 gw.exit() assert 'hello' not in group py.test.raises(KeyError, "group['hello']") def test_default_group(self): oldlist = list(execnet.default_group) gw = execnet.makegateway("popen") newlist = list(execnet.default_group) assert len(newlist) == len(oldlist) + 1 assert gw in newlist assert gw not in oldlist execnet-1.0.9/testing/__init__.py0000644000000000000000000000000211473521746015442 0ustar rootroot# execnet-1.0.9/testing/test_rsync.py0000644000000000000000000001544111473521746016115 0ustar rootrootimport py from execnet import RSync import execnet def pytest_funcarg__gw1(request): return request.cached_setup( setup=lambda: execnet.makegateway("popen"), teardown=lambda val: val.exit(), scope="module" ) pytest_funcarg__gw2 = pytest_funcarg__gw1 def pytest_funcarg__dirs(request): t = request.getfuncargvalue('tmpdir') class dirs: source = t.join("source") dest1 = t.join("dest1") dest2 = t.join("dest2") return dirs class TestRSync: def test_notargets(self, dirs): rsync = RSync(dirs.source) py.test.raises(IOError, "rsync.send()") assert rsync.send(raises=False) is None def test_dirsync(self, dirs, gw1, gw2): dest = dirs.dest1 dest2 = dirs.dest2 source = dirs.source for s in ('content1', 'content2', 'content2-a-bit-longer'): source.ensure('subdir', 'file1').write(s) rsync = RSync(dirs.source) rsync.add_target(gw1, dest) rsync.add_target(gw2, dest2) rsync.send() assert dest.join('subdir').check(dir=1) assert dest.join('subdir', 'file1').check(file=1) assert dest.join('subdir', 'file1').read() == s assert dest2.join('subdir').check(dir=1) assert dest2.join('subdir', 'file1').check(file=1) assert dest2.join('subdir', 'file1').read() == s for x in dest, dest2: fn = x.join("subdir", "file1") fn.setmtime(0) source.join('subdir').remove('file1') rsync = RSync(source) rsync.add_target(gw2, dest2) rsync.add_target(gw1, dest) rsync.send() assert dest.join('subdir', 'file1').check(file=1) assert dest2.join('subdir', 'file1').check(file=1) rsync = RSync(source) rsync.add_target(gw1, dest, delete=True) rsync.add_target(gw2, dest2) rsync.send() assert not dest.join('subdir', 'file1').check() assert dest2.join('subdir', 'file1').check() def test_dirsync_twice(self, dirs, gw1, gw2): source = dirs.source source.ensure("hello") rsync = RSync(source) rsync.add_target(gw1, dirs.dest1) rsync.send() assert dirs.dest1.join('hello').check() py.test.raises(IOError, "rsync.send()") assert rsync.send(raises=False) is None rsync.add_target(gw1, dirs.dest2) rsync.send() assert dirs.dest2.join('hello').check() py.test.raises(IOError, "rsync.send()") assert rsync.send(raises=False) is None def test_rsync_default_reporting(self, capsys, dirs, gw1): source = dirs.source source.ensure("hello") rsync = RSync(source) rsync.add_target(gw1, dirs.dest1) rsync.send() out, err = capsys.readouterr() assert out.find("hello") != -1 def test_rsync_non_verbose(self, capsys, dirs, gw1): source = dirs.source source.ensure("hello") rsync = RSync(source, verbose=False) rsync.add_target(gw1, dirs.dest1) rsync.send() out, err = capsys.readouterr() assert not out assert not err @py.test.mark.skipif( "sys.platform == 'win32' or getattr(os, '_name', '') == 'nt'") def test_permissions(self, dirs, gw1, gw2): source = dirs.source dest = dirs.dest1 onedir = dirs.source.ensure("one", dir=1) onedir.chmod(448) onefile = dirs.source.ensure("file") onefile.chmod(504) onefile_mtime = onefile.stat().mtime rsync = RSync(source) rsync.add_target(gw1, dest) rsync.send() destdir = dirs.dest1.join(onedir.basename) destfile = dirs.dest1.join(onefile.basename) assert destfile.stat().mode & 511 == 504 mode = destdir.stat().mode assert mode & 511 == 448 # transfer again with changed permissions onedir.chmod(504) onefile.chmod(448) onefile.setmtime(onefile_mtime) rsync = RSync(source) rsync.add_target(gw1, dest) rsync.send() mode = destfile.stat().mode assert mode & 511 == 448, mode mode = destdir.stat().mode assert mode & 511 == 504 @py.test.mark.skipif("not hasattr(os, 'symlink')") def test_symlink_rsync(self, dirs, gw1): source = dirs.source dest = dirs.dest1 sourcefile = dirs.source.ensure("subdir", "existant") source.join("rellink").mksymlinkto(sourcefile, absolute=0) source.join('abslink').mksymlinkto(sourcefile) rsync = RSync(source) rsync.add_target(gw1, dest) rsync.send() expected = dest.join(sourcefile.relto(dirs.source)) assert dest.join('rellink').readlink() == "subdir/existant" assert dest.join('abslink').readlink() == expected @py.test.mark.skipif("not hasattr(os, 'symlink')") def test_symlink2_rsync(self, dirs, gw1): source = dirs.source dest = dirs.dest1 subdir = dirs.source.ensure("subdir", dir=1) sourcefile = subdir.ensure("somefile") subdir.join("link1").mksymlinkto(subdir.join("link2"), absolute=0) subdir.join("link2").mksymlinkto(sourcefile, absolute=1) subdir.join("link3").mksymlinkto(source.dirpath(), absolute=1) rsync = RSync(source) rsync.add_target(gw1, dest) rsync.send() expected = dest.join(sourcefile.relto(dirs.source)) destsub = dest.join("subdir") assert destsub.check() assert destsub.join('link1').readlink() == "link2" assert destsub.join('link2').readlink() == expected assert destsub.join('link3').readlink() == source.dirpath() def test_callback(self, dirs, gw1): dest = dirs.dest1 source = dirs.source source.ensure("existant").write("a" * 100) source.ensure("existant2").write("a" * 10) total = {} def callback(cmd, lgt, channel): total[(cmd, lgt)] = True rsync = RSync(source, callback=callback) #rsync = RSync() rsync.add_target(gw1, dest) rsync.send() assert total == {("list", 110):True, ("ack", 100):True, ("ack", 10):True} def test_file_disappearing(self, dirs, gw1): dest = dirs.dest1 source = dirs.source source.ensure("ex").write("a" * 100) source.ensure("ex2").write("a" * 100) class DRsync(RSync): def filter(self, x): assert x != source if x.endswith("ex2"): self.x = 1 source.join("ex2").remove() return True rsync = DRsync(source) rsync.add_target(gw1, dest) rsync.send() assert rsync.x == 1 assert len(dest.listdir()) == 1 assert len(source.listdir()) == 1 execnet-1.0.9/testing/test_gateway.py0000644000000000000000000003171311473521746016420 0ustar rootroot""" mostly functional tests of gateways. """ import os, sys, time import py import execnet from execnet import gateway_base, gateway from testing.test_serializer import _find_version TESTTIMEOUT = 10.0 # seconds needs_osdup = py.test.mark.skipif("not hasattr(os, 'dup')") def test_deprecation(recwarn, monkeypatch): execnet.PopenGateway() assert recwarn.pop(DeprecationWarning) monkeypatch.setattr(py.std.socket, 'socket', lambda *args: 0/0) py.test.raises(Exception, 'execnet.SocketGateway("localhost", 8811)') assert recwarn.pop(DeprecationWarning) monkeypatch.setattr(py.std.subprocess, 'Popen', lambda *args,**kwargs: 0/0) py.test.raises(Exception, 'execnet.SshGateway("not-existing")') assert recwarn.pop(DeprecationWarning) class TestBasicGateway: def test_correct_setup(self, gw): assert gw.hasreceiver() assert gw in gw._group assert gw.id in gw._group assert gw.spec def test_repr_doesnt_crash(self, gw): assert isinstance(repr(gw), str) def test_attribute__name__(self, gw): channel = gw.remote_exec("channel.send(__name__)") name = channel.receive() assert name == "__channelexec__" def test_gateway_status_simple(self, gw): status = gw.remote_status() assert not status.execqsize assert status.numexecuting == 0 def test_gateway_status_no_real_channel(self, gw): numchan = gw._channelfactory.channels() st = gw.remote_status() numchan2 = gw._channelfactory.channels() # note that on CPython this can not really # fail because refcounting leads to immediate # closure of temporary channels assert numchan2 == numchan def test_gateway_status_busy(self, gw): numchannels = gw.remote_status().numchannels ch1 = gw.remote_exec("channel.send(1); channel.receive()") ch2 = gw.remote_exec("channel.receive()") ch1.receive() status = gw.remote_status() assert status.numexecuting == 1 # number of active execution threads assert status.execqsize == 1 # one more queued assert status.numchannels == numchannels + 2 ch1.send(None) ch2.send(None) ch1.waitclose() ch2.waitclose() status = gw.remote_status() assert status.execqsize == 0 assert status.numexecuting == 0 # race condition assert status.numchannels <= numchannels + 1 def test_remote_exec_module(self, tmpdir, gw): p = tmpdir.join("remotetest.py") p.write("channel.send(1)") mod = type(os)("remotetest") mod.__file__ = str(p) channel = gw.remote_exec(mod) name = channel.receive() assert name == 1 p.write("channel.send(2)") channel = gw.remote_exec(mod) name = channel.receive() assert name == 2 def test_correct_setup_no_py(self, gw): channel = gw.remote_exec(""" import sys channel.send(list(sys.modules)) """) remotemodules = channel.receive() assert 'py' not in remotemodules, ( "py should not be imported on remote side") def test_remote_exec_waitclose(self, gw): channel = gw.remote_exec('pass') channel.waitclose(TESTTIMEOUT) def test_remote_exec_waitclose_2(self, gw): channel = gw.remote_exec('def gccycle(): pass') channel.waitclose(TESTTIMEOUT) def test_remote_exec_waitclose_noarg(self, gw): channel = gw.remote_exec('pass') channel.waitclose() def test_remote_exec_error_after_close(self, gw): channel = gw.remote_exec('pass') channel.waitclose(TESTTIMEOUT) py.test.raises(IOError, channel.send, 0) def test_remote_exec_no_explicit_close(self, gw): channel = gw.remote_exec('channel.close()') excinfo = py.test.raises(channel.RemoteError, "channel.waitclose(TESTTIMEOUT)") assert "explicit" in excinfo.value.formatted def test_remote_exec_channel_anonymous(self, gw): channel = gw.remote_exec(''' obj = channel.receive() channel.send(obj) ''') channel.send(42) result = channel.receive() assert result == 42 @needs_osdup def test_confusion_from_os_write_stdout(self, gw): channel = gw.remote_exec(""" import os os.write(1, 'confusion!'.encode('ascii')) channel.send(channel.receive() * 6) channel.send(channel.receive() * 6) """) channel.send(3) res = channel.receive() assert res == 18 channel.send(7) res = channel.receive() assert res == 42 @needs_osdup def test_confusion_from_os_write_stderr(self, gw): channel = gw.remote_exec(""" import os os.write(2, 'test'.encode('ascii')) channel.send(channel.receive() * 6) channel.send(channel.receive() * 6) """) channel.send(3) res = channel.receive() assert res == 18 channel.send(7) res = channel.receive() assert res == 42 def test__rinfo(self, gw): rinfo = gw._rinfo() assert rinfo.executable assert rinfo.cwd assert rinfo.version_info s = repr(rinfo) old = gw.remote_exec(""" import os.path cwd = os.getcwd() channel.send(os.path.basename(cwd)) os.chdir('..') """).receive() try: rinfo2 = gw._rinfo() assert rinfo2.cwd == rinfo.cwd rinfo3 = gw._rinfo(update=True) assert rinfo3.cwd != rinfo2.cwd finally: gw._cache_rinfo = rinfo gw.remote_exec("import os ; os.chdir(%r)" % old).waitclose() class TestPopenGateway: gwtype = 'popen' def test_chdir_separation(self, tmpdir): old = tmpdir.chdir() try: gw = execnet.makegateway('popen') finally: waschangedir = old.chdir() c = gw.remote_exec("import os ; channel.send(os.getcwd())") x = c.receive() assert x.lower() == str(waschangedir).lower() def test_remoteerror_readable_traceback(self, gw): e = py.test.raises(gateway_base.RemoteError, 'gw.remote_exec("x y").waitclose()') assert "gateway_base" in e.value.formatted def test_many_popen(self): num = 4 l = [] for i in range(num): l.append(execnet.makegateway('popen')) channels = [] for gw in l: channel = gw.remote_exec("""channel.send(42)""") channels.append(channel) ## try: ## while channels: ## channel = channels.pop() ## try: ## ret = channel.receive() ## assert ret == 42 ## finally: ## channel.gateway.exit() ## finally: ## for x in channels: ## x.gateway.exit() while channels: channel = channels.pop() ret = channel.receive() assert ret == 42 def test_rinfo_popen(self, gw): rinfo = gw._rinfo() assert rinfo.executable == py.std.sys.executable assert rinfo.cwd == py.std.os.getcwd() assert rinfo.version_info == py.std.sys.version_info def test_waitclose_on_remote_killed(self): gw = execnet.makegateway('popen') channel = gw.remote_exec(""" import os import time channel.send(os.getpid()) time.sleep(100) """) remotepid = channel.receive() py.process.kill(remotepid) py.test.raises(EOFError, "channel.waitclose(TESTTIMEOUT)") py.test.raises(IOError, channel.send, None) py.test.raises(EOFError, channel.receive) def test_receive_on_remote_sysexit(self, gw): channel = gw.remote_exec(""" raise SystemExit() """) py.test.raises(channel.RemoteError, channel.receive) def test_socket_gw_host_not_found(gw): py.test.raises(execnet.HostNotFound, 'execnet.makegateway("socket=qwepoipqwe:9000")' ) class TestSshPopenGateway: gwtype = "ssh" def test_sshconfig_config_parsing(self, monkeypatch): import subprocess l = [] monkeypatch.setattr(subprocess, 'Popen', lambda *args, **kwargs: l.append(args[0])) py.test.raises(AttributeError, """execnet.makegateway("ssh=xyz//ssh_config=qwe")""") assert len(l) == 1 popen_args = l[0] i = popen_args.index('-F') assert popen_args[i+1] == "qwe" def test_sshaddress(self, gw, specssh): assert gw.remoteaddress == specssh.ssh def test_host_not_found(self, gw): py.test.raises(execnet.HostNotFound, "execnet.makegateway('ssh=nowhere.codespeak.net')") class TestThreads: def test_threads(self): gw = execnet.makegateway('popen') gw.remote_init_threads(3) c1 = gw.remote_exec("channel.send(channel.receive())") c2 = gw.remote_exec("channel.send(channel.receive())") c2.send(1) res = c2.receive() assert res == 1 c1.send(42) res = c1.receive() assert res == 42 def test_threads_race_sending(self): # multiple threads sending data in parallel gw = execnet.makegateway("popen") num = 5 gw.remote_init_threads(num) print ("remote_init_threads(%d)" % num) channels = [] for x in range(num): ch = gw.remote_exec(""" for x in range(10): channel.send(''*1000) channel.receive() """) channels.append(ch) for ch in channels: for x in range(10): ch.receive(TESTTIMEOUT) ch.send(1) for ch in channels: ch.waitclose(TESTTIMEOUT) def test_status_with_threads(self): gw = execnet.makegateway('popen') gw.remote_init_threads(3) c1 = gw.remote_exec("channel.send(1) ; channel.receive()") c2 = gw.remote_exec("channel.send(2) ; channel.receive()") c1.receive() c2.receive() rstatus = gw.remote_status() assert rstatus.numexecuting == 2 + 1 assert rstatus.execqsize == 0 c1.send(1) c2.send(1) c1.waitclose() c2.waitclose() rstatus = gw.remote_status() assert rstatus.numexecuting == 0 + 1 assert rstatus.execqsize == 0 def test_threads_twice(self): gw = execnet.makegateway('popen') gw.remote_init_threads(3) py.test.raises(IOError, gw.remote_init_threads, 3) class TestTracing: def test_popen_filetracing(self, testdir, monkeypatch): tmpdir = testdir.tmpdir monkeypatch.setenv("TMP", tmpdir) monkeypatch.setenv("TEMP", tmpdir) # windows monkeypatch.setenv('EXECNET_DEBUG', "1") gw = execnet.makegateway("popen") pid = gw.remote_exec("import os ; channel.send(os.getpid())").receive() slavefile = tmpdir.join("execnet-debug-%s" % pid) assert slavefile.check() slave_line = "creating slavegateway" for line in slavefile.readlines(): if slave_line in line: break else: py.test.fail("did not find %r in tracefile" %(slave_line,)) gw.exit() def test_popen_stderr_tracing(self, capfd, monkeypatch): monkeypatch.setenv('EXECNET_DEBUG', "2") gw = execnet.makegateway("popen") pid = gw.remote_exec("import os ; channel.send(os.getpid())").receive() out, err = capfd.readouterr() slave_line = "[%s] creating slavegateway" % pid assert slave_line in err gw.exit() def test_no_tracing_by_default(self): assert gateway_base.trace == gateway_base.notrace, \ "trace does not to default to empty tracing" class TestStringCoerce: @py.test.mark.skipif('sys.version>="3.0"') def test_2to3(self): python = _find_version('3') gw = execnet.makegateway('popen//python=%s'%python) ch = gw.remote_exec('channel.send(channel.receive())') ch.send('a') res = ch.receive() assert isinstance(res, unicode) gw.reconfigure(py3str_as_py2str=True) ch = gw.remote_exec('channel.send(channel.receive())') ch.send('a') res = ch.receive() assert isinstance(res, str) gw.exit() @py.test.mark.skipif('sys.version<"3.0"') def test_3to2(self): python = _find_version('2') gw = execnet.makegateway('popen//python=%s'%python) ch = gw.remote_exec('channel.send(channel.receive())') ch.send(bytes('a', 'ascii')) res = ch.receive() assert isinstance(res, str) gw.reconfigure(py3str_as_py2str=True, py2str_as_py3str=False) ch = gw.remote_exec('channel.send(channel.receive())') ch.send('a') res = ch.receive() assert isinstance(res, bytes) gw.exit() execnet-1.0.9/testing/test_channel.py0000644000000000000000000002670411473521746016373 0ustar rootroot""" mostly functional tests of gateways. """ import os, sys, time import py import execnet from execnet import gateway_base, gateway needs_early_gc = py.test.mark.skipif("not hasattr(sys, 'getrefcount')") needs_osdup = py.test.mark.skipif("not hasattr(os, 'dup')") queue = py.builtin._tryimport('queue', 'Queue') TESTTIMEOUT = 10.0 # seconds class TestChannelBasicBehaviour: def test_serialize_error(self, gw): ch = gw.remote_exec("channel.send(ValueError(42))") excinfo = py.test.raises(ch.RemoteError, ch.receive) assert "can't serialize" in str(excinfo.value) def test_channel_close_and_then_receive_error(self, gw): channel = gw.remote_exec('raise ValueError') py.test.raises(channel.RemoteError, channel.receive) def test_channel_finish_and_then_EOFError(self, gw): channel = gw.remote_exec('channel.send(42)') x = channel.receive() assert x == 42 py.test.raises(EOFError, channel.receive) py.test.raises(EOFError, channel.receive) py.test.raises(EOFError, channel.receive) def test_waitclose_timeouterror(self, gw): channel = gw.remote_exec("channel.receive()") py.test.raises(channel.TimeoutError, channel.waitclose, 0.02) channel.send(1) channel.waitclose(timeout=TESTTIMEOUT) def test_channel_receive_timeout(self, gw): channel = gw.remote_exec('channel.send(channel.receive())') py.test.raises(channel.TimeoutError, "channel.receive(timeout=0.2)") channel.send(1) x = channel.receive(timeout=TESTTIMEOUT) def test_channel_receive_internal_timeout(self, gw, monkeypatch): channel = gw.remote_exec(""" import time time.sleep(0.5) channel.send(1) """) monkeypatch.setattr(channel.__class__, '_INTERNALWAKEUP', 0.2) x = channel.receive() def test_channel_close_and_then_receive_error_multiple(self, gw): channel = gw.remote_exec('channel.send(42) ; raise ValueError') x = channel.receive() assert x == 42 py.test.raises(channel.RemoteError, channel.receive) def test_channel__local_close(self, gw): channel = gw._channelfactory.new() gw._channelfactory._local_close(channel.id) channel.waitclose(0.1) def test_channel__local_close_error(self, gw): channel = gw._channelfactory.new() gw._channelfactory._local_close(channel.id, channel.RemoteError("error")) py.test.raises(channel.RemoteError, channel.waitclose, 0.01) def test_channel_error_reporting(self, gw): channel = gw.remote_exec('def foo():\n return foobar()\nfoo()\n') try: channel.receive() except channel.RemoteError: e = sys.exc_info()[1] assert str(e).startswith('Traceback (most recent call last):') assert str(e).find('NameError: global name \'foobar\' ' 'is not defined') > -1 else: py.test.fail('No exception raised') def test_channel_syntax_error(self, gw): # missing colon channel = gw.remote_exec('def foo()\n return 1\nfoo()\n') try: channel.receive() except channel.RemoteError: e = sys.exc_info()[1] assert str(e).startswith('Traceback (most recent call last):') assert str(e).find('SyntaxError') > -1 def test_channel_iter(self, gw): channel = gw.remote_exec(""" for x in range(3): channel.send(x) """) l = list(channel) assert l == [0, 1, 2] def test_channel_pass_in_structure(self, gw): channel = gw.remote_exec(''' ch1, ch2 = channel.receive() data = ch1.receive() ch2.send(data+1) ''') newchan1 = gw.newchannel() newchan2 = gw.newchannel() channel.send((newchan1, newchan2)) newchan1.send(1) data = newchan2.receive() assert data ==2 def test_channel_multipass(self, gw): channel = gw.remote_exec(''' channel.send(channel) xchan = channel.receive() assert xchan == channel ''') newchan = channel.receive() assert newchan == channel channel.send(newchan) channel.waitclose() def test_channel_passing_over_channel(self, gw): channel = gw.remote_exec(''' c = channel.gateway.newchannel() channel.send(c) c.send(42) ''') c = channel.receive() x = c.receive() assert x == 42 # check that the both sides previous channels are really gone channel.waitclose(TESTTIMEOUT) #assert c.id not in gw._channelfactory newchan = gw.remote_exec(''' assert %d not in channel.gateway._channelfactory._channels ''' % (channel.id)) newchan.waitclose(TESTTIMEOUT) assert channel.id not in gw._channelfactory._channels def test_channel_receiver_callback(self, gw): l = [] #channel = gw.newchannel(receiver=l.append) channel = gw.remote_exec(source=''' channel.send(42) channel.send(13) channel.send(channel.gateway.newchannel()) ''') channel.setcallback(callback=l.append) py.test.raises(IOError, channel.receive) channel.waitclose(TESTTIMEOUT) assert len(l) == 3 assert l[:2] == [42,13] assert isinstance(l[2], channel.__class__) def test_channel_callback_after_receive(self, gw): l = [] channel = gw.remote_exec(source=''' channel.send(42) channel.send(13) channel.send(channel.gateway.newchannel()) ''') x = channel.receive() assert x == 42 channel.setcallback(callback=l.append) py.test.raises(IOError, channel.receive) channel.waitclose(TESTTIMEOUT) assert len(l) == 2 assert l[0] == 13 assert isinstance(l[1], channel.__class__) def test_waiting_for_callbacks(self, gw): l = [] def callback(msg): import time; time.sleep(0.2) l.append(msg) channel = gw.remote_exec(source=''' channel.send(42) ''') channel.setcallback(callback) channel.waitclose(TESTTIMEOUT) assert l == [42] def test_channel_callback_stays_active(self, gw): self.check_channel_callback_stays_active(gw, earlyfree=True) def check_channel_callback_stays_active(self, gw, earlyfree=True): # with 'earlyfree==True', this tests the "sendonly" channel state. l = [] channel = gw.remote_exec(source=''' try: import thread except ImportError: import _thread as thread import time def producer(subchannel): for i in range(5): time.sleep(0.15) subchannel.send(i*100) channel2 = channel.receive() thread.start_new_thread(producer, (channel2,)) del channel2 ''') subchannel = gw.newchannel() subchannel.setcallback(l.append) channel.send(subchannel) if earlyfree: subchannel = None counter = 100 while len(l) < 5: if subchannel and subchannel.isclosed(): break counter -= 1 print(counter) if not counter: py.test.fail("timed out waiting for the answer[%d]" % len(l)) time.sleep(0.04) # busy-wait assert l == [0, 100, 200, 300, 400] return subchannel @needs_early_gc def test_channel_callback_remote_freed(self, gw): channel = self.check_channel_callback_stays_active(gw, earlyfree=False) # freed automatically at the end of producer() channel.waitclose(TESTTIMEOUT) def test_channel_endmarker_callback(self, gw): l = [] channel = gw.remote_exec(source=''' channel.send(42) channel.send(13) channel.send(channel.gateway.newchannel()) ''') channel.setcallback(l.append, 999) py.test.raises(IOError, channel.receive) channel.waitclose(TESTTIMEOUT) assert len(l) == 4 assert l[:2] == [42,13] assert isinstance(l[2], channel.__class__) assert l[3] == 999 def test_channel_endmarker_callback_error(self, gw): q = queue.Queue() channel = gw.remote_exec(source=''' raise ValueError() ''') channel.setcallback(q.put, endmarker=999) val = q.get(TESTTIMEOUT) assert val == 999 err = channel._getremoteerror() assert err assert str(err).find("ValueError") != -1 def test_channel_callback_error(self, gw): channel = gw.remote_exec(""" def f(item): raise ValueError(42) ch = channel.gateway.newchannel() ch.setcallback(f) channel.send(ch) channel.receive() assert ch.isclosed() """) subchan = channel.receive() subchan.send(1) excinfo = py.test.raises(subchan.RemoteError, "subchan.waitclose(TESTTIMEOUT)") assert "42" in excinfo.value.formatted channel.send(1) channel.waitclose() class TestChannelFile: def test_channel_file_write(self, gw): channel = gw.remote_exec(""" f = channel.makefile() f.write("hello world\\n") f.close() channel.send(42) """) first = channel.receive() assert first.strip() == 'hello world' second = channel.receive() assert second == 42 def test_channel_file_write_error(self, gw): channel = gw.remote_exec("pass") f = channel.makefile() assert not f.isatty() channel.waitclose(TESTTIMEOUT) py.test.raises(IOError, f.write, 'hello') def test_channel_file_proxyclose(self, gw): channel = gw.remote_exec(""" f = channel.makefile(proxyclose=True) f.write("hello world") f.close() channel.send(42) """) first = channel.receive() assert first.strip() == 'hello world' py.test.raises(channel.RemoteError, channel.receive) def test_channel_file_read(self, gw): channel = gw.remote_exec(""" f = channel.makefile(mode='r') s = f.read(2) channel.send(s) s = f.read(5) channel.send(s) """) channel.send("xyabcde") s1 = channel.receive() s2 = channel.receive() assert s1 == "xy" assert s2 == "abcde" def test_channel_file_read_empty(self, gw): channel = gw.remote_exec("pass") f = channel.makefile(mode="r") s = f.read(3) assert s == "" s = f.read(5) assert s == "" def test_channel_file_readline_remote(self, gw): channel = gw.remote_exec(""" channel.send('123\\n45') """) channel.waitclose(TESTTIMEOUT) f = channel.makefile(mode="r") s = f.readline() assert s == "123\n" s = f.readline() assert s == "45" def test_channel_makefile_incompatmode(self, gw): channel = gw.newchannel() py.test.raises(ValueError, 'channel.makefile("rw")') execnet-1.0.9/testing/test_basics.py0000644000000000000000000002221511473521746016220 0ustar rootroot import py import sys, os, subprocess, inspect import execnet from execnet import gateway_base, gateway from execnet.gateway_base import Message, Channel, ChannelFactory, serialize, \ Unserializer def test_errors_on_execnet(): assert hasattr(execnet, 'RemoteError') assert hasattr(execnet, 'TimeoutError') def test_subprocess_interaction(anypython): line = gateway.popen_bootstrapline compile(line, 'xyz', 'exec') args = [str(anypython), '-c', line] popen = subprocess.Popen(args, bufsize=0, universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) def send(line): popen.stdin.write(line) if sys.version_info > (3,0) or sys.platform.startswith("java"): popen.stdin.flush() def receive(): return popen.stdout.readline() try: source = py.code.Source(read_write_loop, "read_write_loop()") repr_source = repr(str(source)) + "\n" sendline = repr_source send(sendline) s = receive() assert s == "ok\n" send("hello\n") s = receive() assert s == "received: hello\n" send("world\n") s = receive() assert s == "received: world\n" send('\n') # terminate loop finally: popen.stdin.close() popen.stdout.close() popen.wait() def read_write_loop(): import os, sys sys.stdout.write("ok\n") sys.stdout.flush() while 1: try: line = sys.stdin.readline() if not line.strip(): break sys.stdout.write("received: %s" % line) sys.stdout.flush() except (IOError, EOFError): break def test_io_message(anypython, tmpdir): check = tmpdir.join("check.py") check.write(py.code.Source(gateway_base, """ try: from io import BytesIO except ImportError: from StringIO import StringIO as BytesIO import tempfile temp_out = BytesIO() temp_in = BytesIO() io = Popen2IO(temp_out, temp_in) unserializer = Unserializer(io) for i, handler in enumerate(Message._types): print ("checking %s %s" %(i, handler)) for data in "hello", "hello".encode('ascii'): msg1 = Message(i, i, data) serialize(io, (i, i, data)) x = io.outfile.getvalue() io.outfile.truncate(0) io.outfile.seek(0) io.infile.seek(0) io.infile.write(x) io.infile.seek(0) msg2 = Message(*unserializer.load()) assert msg1.channelid == msg2.channelid, (msg1, msg2) assert msg1.data == msg2.data assert msg1.msgcode == msg2.msgcode print ("all passed") """)) #out = py.process.cmdexec("%s %s" %(executable,check)) out = anypython.sysexec(check) print (out) assert "all passed" in out def test_popen_io(anypython, tmpdir): check = tmpdir.join("check.py") check.write(py.code.Source(gateway_base, """ do_exec("io = init_popen_io()", globals()) io.write("hello".encode('ascii')) s = io.read(1) assert s == "x".encode('ascii') """)) from subprocess import Popen, PIPE args = [str(anypython), str(check)] proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) proc.stdin.write("x".encode('ascii')) stdout, stderr = proc.communicate() print (stderr) ret = proc.wait() assert "hello".encode('ascii') in stdout def test_rinfo_source(anypython, tmpdir): check = tmpdir.join("check.py") check.write(py.code.Source(""" class Channel: def send(self, data): assert eval(repr(data), {}) == data channel = Channel() """, gateway.rinfo_source, """ print ('all passed') """)) out = anypython.sysexec(check) print (out) assert "all passed" in out def test_geterrortext(anypython, tmpdir): check = tmpdir.join("check.py") check.write(py.code.Source(gateway_base, """ class Arg: pass errortext = geterrortext((Arg, "1", 4)) assert "Arg" in errortext import sys try: raise ValueError("17") except ValueError: excinfo = sys.exc_info() s = geterrortext(excinfo) assert "17" in s print ("all passed") """)) out = anypython.sysexec(check) print (out) assert "all passed" in out @py.test.mark.skipif("not hasattr(os, 'dup')") def test_stdouterrin_setnull(): cap = py.io.StdCaptureFD() io = gateway_base.init_popen_io() import os os.write(1, "hello".encode('ascii')) if os.name == "nt": os.write(2, "world") os.read(0, 1) out, err = cap.reset() assert not out assert not err class PseudoChannel: def __init__(self): self._sent = [] self._closed = [] self.id = 1000 def send(self, obj): self._sent.append(obj) def close(self, errortext=None): self._closed.append(errortext) def test_exectask(): io = py.io.BytesIO() gw = gateway_base.SlaveGateway(io, id="something") ch = PseudoChannel() gw.executetask((ch, ("raise ValueError()", None, {}))) assert "ValueError" in str(ch._closed[0]) class TestMessage: def test_wire_protocol(self): for i, handler in enumerate(Message._types): one = py.io.BytesIO() data = '23'.encode('ascii') serialize(one, (i, 42, data)) two = py.io.BytesIO(one.getvalue()) msg = Message(*Unserializer(two, None).load()) assert msg.msgcode == i assert isinstance(msg, Message) assert msg.channelid == 42 assert msg.data == data assert isinstance(repr(msg), str) # == "" %(msg.__class__.__name__, ) class TestPureChannel: def setup_method(self, method): self.fac = ChannelFactory(None) def test_factory_create(self): chan1 = self.fac.new() assert chan1.id == 1 chan2 = self.fac.new() assert chan2.id == 3 def test_factory_getitem(self): chan1 = self.fac.new() assert self.fac._channels[chan1.id] == chan1 chan2 = self.fac.new() assert self.fac._channels[chan2.id] == chan2 def test_channel_timeouterror(self): channel = self.fac.new() py.test.raises(IOError, channel.waitclose, timeout=0.01) def test_channel_makefile_incompatmode(self): channel = self.fac.new() py.test.raises(ValueError, 'channel.makefile("rw")') class TestSourceOfFunction(object): def test_lambda_unsupported(self): py.test.raises(ValueError, gateway._source_of_function, lambda:1) def test_wrong_prototype_fails(self): def prototype(wrong): pass py.test.raises(ValueError, gateway._source_of_function, prototype) def test_function_without_known_source_fails(self): # this one wont be able to find the source mess = {} py.builtin.exec_('def fail(channel): pass', mess, mess) import inspect print(inspect.getsourcefile(mess['fail'])) py.test.raises(ValueError, gateway._source_of_function, mess['fail']) def test_function_with_closure_fails(self): mess = {} def closure(channel): print(mess) py.test.raises(ValueError, gateway._source_of_function, closure) def test_source_of_nested_function(self): def working(channel): pass send_source = gateway._source_of_function(working) expected = 'def working(channel):\n pass\n' assert send_source == expected class TestGlobalFinder(object): def setup_class(cls): py.test.importorskip('ast') def check(self, func): src = py.code.Source(func) code = py.code.Code(func) return gateway._find_non_builtin_globals(str(src), code.raw) def test_local(self): def f(a, b, c): d = 3 pass assert self.check(f) == [] def test_global(self): def f(a, b): c = 3 glob d = 4 assert self.check(f) == ['glob'] def test_builtin(self): def f(): len assert self.check(f) == [] def test_function_with_global_fails(self): def func(channel): test py.test.raises(ValueError, gateway._source_of_function, func) def test_remote_exec_function_with_kwargs(anypython): import sys def func(channel, data): channel.send(data) group = execnet.Group() gw = group.makegateway('popen//python=%s' % anypython) print ("local version_info %r" %(sys.version_info,)) print ("remote info: %s" % (gw._rinfo(),)) ch = gw.remote_exec(func, data=1) result = ch.receive() assert result == 1 def test_remote_exc_module_takes_no_kwargs(): gw = execnet.makegateway() py.test.raises(TypeError, gw.remote_exec, gateway_base, kwarg=1) def test_remote_exec_string_takes_no_kwargs(): gw = execnet.makegateway() py.test.raises(TypeError, gw.remote_exec, 'pass', kwarg=1) execnet-1.0.9/testing/test_serializer.py0000644000000000000000000002020011473521746017115 0ustar rootroot# -*- coding: utf-8 -*- import sys import os import tempfile import subprocess import py import execnet from execnet import gateway_base as serializer def _find_version(suffix=""): name = "python" + suffix executable = py.path.local.sysfind(name) if executable is None: if suffix == "2": for name in ('python2.6', 'python2.7'): executable = py.path.local.sysfind(name) if executable: return executable elif suffix == "3": for name in ('python3.1', 'python3.2'): executable = py.path.local.sysfind(name) if executable: return executable if sys.platform == "win32" and suffix == "3": for name in ('python31', 'python30'): executable = py.path.local(r"c:\\%s\python.exe" % (name,)) if executable.check(): return executable py.test.skip("can't find a %r executable" % (name,)) return executable def setup_module(mod): mod.TEMPDIR = py.path.local(tempfile.mkdtemp()) if sys.version_info > (3, 0): mod._py3_wrapper = PythonWrapper(py.path.local(sys.executable)) mod._py2_wrapper = PythonWrapper(_find_version("2")) else: mod._py3_wrapper = PythonWrapper(_find_version("3")) mod._py2_wrapper = PythonWrapper(py.path.local(sys.executable)) def teardown_module(mod): TEMPDIR.remove(True) pyimportdir = str(py.path.local(execnet.__file__).dirpath().dirpath()) class PythonWrapper(object): def __init__(self, executable): self.executable = executable def dump(self, obj_rep): script_file = TEMPDIR.join("dump.py") script_file.write(""" import sys sys.path.insert(0, %r) from execnet import gateway_base as serializer if sys.version_info > (3, 0): # Need binary output sys.stdout = sys.stdout.detach() saver = serializer.serialize(sys.stdout, %s) """ % (pyimportdir, obj_rep,)) popen = subprocess.Popen([str(self.executable), str(script_file)], stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE) stdout, stderr = popen.communicate() ret = popen.returncode if ret: raise py.process.cmdexec.Error(ret, ret, str(self.executable), stdout, stderr) return stdout def load(self, data, option_args="__class__"): script_file = TEMPDIR.join("load.py") script_file.write(r""" import sys sys.path.insert(0, %r) from execnet import gateway_base as serializer if sys.version_info > (3, 0): sys.stdin = sys.stdin.detach() loader = serializer.Unserializer(sys.stdin) loader.%s obj = loader.load() sys.stdout.write(type(obj).__name__ + "\n") sys.stdout.write(repr(obj))""" % (pyimportdir, option_args,)) popen = subprocess.Popen([str(self.executable), str(script_file)], stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE) stdout, stderr = popen.communicate(data) ret = popen.returncode if ret: raise py.process.cmdexec.Error(ret, ret, str(self.executable), stdout, stderr) return [s.decode("ascii") for s in stdout.splitlines()] def __repr__(self): return "" % (self.executable,) def pytest_funcarg__py2(request): return _py2_wrapper def pytest_funcarg__py3(request): return _py3_wrapper def pytest_funcarg__dump(request): py_dump = request.getfuncargvalue(request.param[0]) return py_dump.dump def pytest_funcarg__load(request): py_dump = request.getfuncargvalue(request.param[1]) return py_dump.load def pytest_generate_tests(metafunc): if 'dump' in metafunc.funcargnames and 'load' in metafunc.funcargnames: pys = 'py2', 'py3' for dump in pys: for load in pys: param = (dump, load) conversion = '%s to %s'%param if 'repr' not in metafunc.funcargnames: metafunc.addcall(id=conversion, param=param) else: for tp, repr in simple_tests.items(): metafunc.addcall( id='%s:%s'%(tp, conversion), param=param, funcargs={'tp_name':tp, 'repr':repr}, ) simple_tests = { # type: expected before/after repr 'int': '4', 'float':'3.25', 'list': '[1, 2, 3]', 'tuple': '(1, 2, 3)', 'dict': '{(1, 2, 3): 32}', } def test_simple(tp_name, repr, dump, load): p = dump(repr) tp , v = load(p) assert tp == tp_name assert v == repr def test_set(py2, py3): for dump in py2.dump, py3.dump: p = dump("set((1, 2, 3))") tp, v = py2.load(p) assert tp == "set" #assert v == "set([1, 2, 3])" # ordering prevents this assertion assert v.startswith("set([") and v.endswith("])") assert '1' in v and '2' in v and '3' in v tp, v = py3.load(p) assert tp == "set" #assert v == "{1, 2, 3}" # ordering prevents this assertion assert v.startswith("{") and v.endswith("}") assert '1' in v and '2' in v and '3' in v p = dump("set()") tp, v = py2.load(p) assert tp == "set" assert v == "set([])" tp, v = py3.load(p) assert tp == "set" assert v == "set()" def test_frozenset(py2, py3): for dump in py2.dump, py3.dump: p = dump("frozenset((1, 2, 3))") tp, v = py2.load(p) assert tp == "frozenset" assert v == "frozenset([1, 2, 3])" tp, v = py3.load(p) assert tp == "frozenset" assert v == "frozenset({1, 2, 3})" p = dump("frozenset()") tp, v = py2.load(p) assert tp == "frozenset" assert v == "frozenset([])" tp, v = py3.load(p) assert tp == "frozenset" assert v == "frozenset()" def test_long(py2, py3): really_big = "9223372036854775807324234" p = py2.dump(really_big) tp, v = py2.load(p) assert tp == "long" assert v == really_big + "L" tp, v = py3.load(p) assert tp == "int" assert v == really_big p = py3.dump(really_big) tp, v == py3.load(p) assert tp == "int" assert v == really_big tp, v = py2.load(p) assert tp == "long" assert v == really_big + "L" def test_small_long(py2, py3): p = py2.dump("123L") tp, s = py2.load(p) assert s == "123L" tp, s = py3.load(p) assert s == "123" def test_bytes(py2, py3): p = py3.dump("b'hi'") tp, v = py2.load(p) assert tp == "str" assert v == "'hi'" tp, v = py3.load(p) assert tp == "bytes" assert v == "b'hi'" def test_str(py2, py3): p = py2.dump("'xyz'") tp, s = py2.load(p) assert tp == "str" assert s == "'xyz'" tp, s = py3.load(p, "py2str_as_py3str=True") assert tp == "str" assert s == "'xyz'" tp, s = py3.load(p, "py2str_as_py3str=False") assert s == "b'xyz'" assert tp == "bytes" def test_unicode(py2, py3): p = py2.dump("u'hi'") tp, s = py2.load(p) assert tp == "unicode" assert s == "u'hi'" tp, s = py3.load(p) assert tp == "str" assert s == "'hi'" p = py3.dump("'hi'") tp, s = py3.load(p) assert tp == "str" assert s == "'hi'" tp, s = py2.load(p) assert tp == "unicode" # depends on unserialization defaults assert s == "u'hi'" def test_bool(py2, py3): p = py2.dump("True") tp, s = py2.load(p) assert tp == "bool" assert s == "True" tp, s = py3.load(p) assert s == "True" assert tp == "bool" p = py2.dump("False") tp, s = py2.load(p) assert s == "False" def test_none(py2, py3): p = py2.dump("None") tp, s = py2.load(p) assert s == "None" tp, s = py3.load(p) assert s == "None" def test_tuple_nested_with_empty_in_between(py2): p = py2.dump("(1, (), 3)") tp, s = py2.load(p) assert tp == 'tuple' assert s == "(1, (), 3)" execnet-1.0.9/testing/test_termination.py0000644000000000000000000000710311473521746017304 0ustar rootroot import sys, os import execnet import time import subprocess import py from execnet.threadpool import WorkerPool queue = py.builtin._tryimport('queue', 'Queue') from testing.test_gateway import TESTTIMEOUT execnetdir = py.path.local(execnet.__file__).dirpath().dirpath() def test_exit_blocked_slave_execution_gateway(anypython): group = execnet.Group() gateway = group.makegateway('popen//python=%s' % anypython) channel = gateway.remote_exec(""" import time time.sleep(10.0) """) def doit(): gateway.exit() return 17 pool = WorkerPool() reply = pool.dispatch(doit) x = reply.get(timeout=5.0) assert x == 17 def test_endmarker_delivery_on_remote_killterm(): gw = execnet.makegateway('popen') q = queue.Queue() channel = gw.remote_exec(source=''' import os, time channel.send(os.getpid()) time.sleep(100) ''') pid = channel.receive() py.process.kill(pid) channel.setcallback(q.put, endmarker=999) val = q.get(TESTTIMEOUT) assert val == 999 err = channel._getremoteerror() assert isinstance(err, EOFError) def test_termination_on_remote_channel_receive(monkeypatch): if not py.path.local.sysfind('ps'): py.test.skip("need 'ps' command to externally check process status") monkeypatch.setenv('EXECNET_DEBUG', '2') group = execnet.Group() gw = group.makegateway("popen") pid = gw.remote_exec("import os ; channel.send(os.getpid())").receive() gw.remote_exec("channel.receive()") group.terminate() command = ["ps", "-p", str(pid)] popen = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) out, err = popen.communicate() out = py.builtin._totext(out, 'utf8') assert str(pid) not in out, out def test_close_initiating_remote_no_error(testdir, anypython): if '2.4' in str(anypython): py.test.xfail("race/wait/interrupt_main/thread-loop issue with python2.4") p = testdir.makepyfile(""" import sys sys.path.insert(0, %r) import execnet gw = execnet.makegateway("popen") gw.remote_init_threads(num=3) ch1 = gw.remote_exec("channel.receive()") ch2 = gw.remote_exec("channel.receive()") ch3 = gw.remote_exec("channel.receive()") execnet.default_group.terminate() """ % str(execnetdir)) popen = subprocess.Popen([str(anypython), str(p)], stdout=subprocess.PIPE, stderr=subprocess.PIPE,) out, err = popen.communicate() print (out) print (err) err = err.decode('utf8') lines = [x for x in err.splitlines() if '*sys-package' not in x] assert not lines def test_terminate_implicit_does_trykill(testdir, anypython, capfd): p = testdir.makepyfile(""" import sys sys.path.insert(0, %r) import execnet group = execnet.Group() gw = group.makegateway("popen") ch = gw.remote_exec("import time ; channel.send(1) ; time.sleep(100)") ch.receive() # remote execution started sys.stdout.write("1\\n") sys.stdout.flush() sys.stdout.close() # use process at-exit group.terminate call """ % str(execnetdir)) popen = subprocess.Popen([str(anypython), str(p)], stdout=subprocess.PIPE) # sync with start-up line = popen.stdout.readline() reply = WorkerPool(1).dispatch(popen.communicate) reply.get(timeout=50) out, err = capfd.readouterr() lines = [x for x in err.splitlines() if '*sys-package' not in x] assert not lines or "Killed" in err execnet-1.0.9/testing/test_threadpool.py0000644000000000000000000000442011473521746017113 0ustar rootroot import py import sys from execnet.threadpool import queue, WorkerPool def test_some(): pool = WorkerPool() q = queue.Queue() num = 4 def f(i): q.put(i) while q.qsize(): py.std.time.sleep(0.01) for i in range(num): pool.dispatch(f, i) for i in range(num): q.get() assert len(pool._alive) == 4 pool.shutdown() # XXX I replaced the following join() with a time.sleep(1), which seems # to fix the test on Windows, and doesn't break it on Linux... Completely # unsure what the idea is, though, so it would be nice if someone with some # more understanding of what happens here would either fix this better, or # remove this comment... # pool.join(timeout=1.0) py.std.time.sleep(1) assert len(pool._alive) == 0 assert len(pool._ready) == 0 def test_get(): pool = WorkerPool() def f(): return 42 reply = pool.dispatch(f) result = reply.get() assert result == 42 def test_get_timeout(): pool = WorkerPool() def f(): py.std.time.sleep(0.2) return 42 reply = pool.dispatch(f) py.test.raises(IOError, "reply.get(timeout=0.01)") def test_get_excinfo(): pool = WorkerPool() def f(): raise ValueError("42") reply = pool.dispatch(f) excinfo = py.test.raises(ValueError, "reply.get(1.0)") py.test.raises(EOFError, "reply.get(1.0)") def test_maxthreads(): pool = WorkerPool(maxthreads=1) def f(): py.std.time.sleep(0.5) try: pool.dispatch(f) py.test.raises(IOError, pool.dispatch, f) finally: pool.shutdown() def test_join_timeout(): pool = WorkerPool() q = queue.Queue() def f(): q.get() reply = pool.dispatch(f) pool.shutdown() py.test.raises(IOError, pool.join, 0.01) q.put(None) reply.get(timeout=1.0) pool.join(timeout=0.1) @py.test.mark.skipif("not hasattr(os, 'dup')") def test_pool_clean_shutdown(): capture = py.io.StdCaptureFD() pool = WorkerPool() def f(): pass pool.dispatch(f) pool.dispatch(f) pool.shutdown() pool.join(timeout=1.0) assert not pool._alive assert not pool._ready out, err = capture.reset() print(out) sys.stderr.write(err + "\n") assert err == '' execnet-1.0.9/testing/runtest.py0000644000000000000000000047321511473521746015433 0ustar rootroot#! /usr/bin/env python sources = """ eNrsvduWI9mVGEbJl7FgSyNZlmRZlh1EuRQRXcioSzdnaIggV7O7eqZmyO5eXVUceiXT6EggMjOY yAhUBFCZOSS9/A1+9Iu+wN/hH/AX+Eu8b+d+IoCs5pCjtVxkJ4CIcz/77PvZ+3//h797973s7b/e 3u+qfldsN/vLuilu2ua6ut+Wu9XVu3/w5v/90+99bzqdJtbTurlMymYNj1bX+P1i36x2dduUm3p3 XyQJFJ9M6ptt2+2Stp8l/X0/mayri4T7WWL5srtcLq02s656t4eX+XySJNTEm6sq6ardvmuqdfLt t1bZb79NpIlk27Xv63XVJ7urqq+o6lW12VZdclPtrto1vGhhnOv64j5pz39drXYwnnXNw+1qqNh2 MMaiat7XXdvM5xNqA/9ZHRZ9tSt3uy6DJmZJU95Us+R9udnDR1fWPazB4k23r/Jo3XW18esergQd 1rvqJrspt1so6XQ62A3VeGg3MPPMmdG2q7ZVs158UW764b6Cakd0dt/Dl6uldJDhj5zX+9PNhnep XpW4NX1yW8Oj8yrZN+u2qZLbq6rBPU4ETKAnqojwpOEvuaibur8CcKl3fVLdVas9PgaIRFj69lsZ 4rffUtVt2cH4dwAqa/x7UzcADfVFUiZ/Xd2/7DoEjC75FLauPt/vKnpCFdXQsDns64IGBkv5FNeF BtICBNJEkquyT5o22QGwVrtCwTZ93tCyJAt7kTJeOpllUa7XMCc4V39bdRmXL3BFVCk8HdLOZNK0 OxgEtMeADk1NVpuy7+329emSQsl1VW3pPENrq7ZbJ+1FItD+FOHpKWz0U9m5ZHVVNpdVX+gp4KFe LmHVd8tl1lebCzm++A9/FktpC0Z1eha+wh74lW5OHTUsM0sOHDjTG04JZ1+q/YL9xnqAK2AXvv0W GoKvgAy+/ZYa+vbbWXJ+jz2W+81ON0N7am86gIBssGl5Xa9hT3cAYTXskV4M/Ndu1tA8TOkyxBi8 P+ZsQLsyGcKmUrXupaCZW3RgMLJs+rhTAGZG97ibJo9Nv3ke35Gibvqq22XPZok9SB6FUymO+nKz ZQrDBVs2sld0VKrYdl107Y3aMHuPeAl0I+5SwIkf2CTANu/rdt9v7mP7BXuAhWAR3Unm7uqbrXKf D+4MtaGLVoBJ3YrHbMUwCFnbw3vgUZjcOU5EFnhvgPK5mxgeIE0cYb2aHfzVGwOHhyq5K+icZXsm Vl/wtYDZZEOTgPen+O4MDg514cBWfPyHYcuFKJzXTDZLI3jYVwCcdVv1TarOsw8e0AbBSN1gGw+F C9XV8RDxHdZRgMGspwMHSLJ5GaP0/kugsxF4EM7oBoABanR1eb6pHJjQCLWg9fj2W2lQyCwtUw/0 BYhHV66A0sIuVOWajutq33XYcLQTajbRjSCOlKapru43Kde/bmvkEm9rIFL8Tg/C9OvsLDe+SHo4 Nx5XBZNQ/WCfBACw+RaX6Cy4aok/n+i6T6washvOXquTaUqN4Fd/7x4K/dYCh4dgZ6hZXwRnWzOW wTjVIOTTxjoeq8dDJ4bPHaxaLNgweKkACqoX8nsDg0KeRMSJTSsM4iga5+7SZV++r2QoaR49bqYA woJ0ezq3tkqeWScSQYamYk0YmTKfAcL54XNNggz/BAwpnIlVCYzkCiazv2EJRlelav2uXF1D2c+g GDIJsE8ljBsqwAGoASiF9FcXF8jJ7ZtN1fe6ift2D0ND4aerAuHtAtlePCjUEY7D2fcL5H09eo9H wKFaASaUYsS/RHmYcXbCLhWixwE6F6WnsH8uv4nzMXRteFoI56PTik5JMK607h31kdl4VTTti1KE YE4wsoeAuwFtBHQf+Cfv/uHbf769L5arFqWJQvH07/6Tty8QjPlxfV6jhI+S2h5gLcl25TWIZYRg XhSfFJ/kLPq/+0/f/lNsbNNempb+s7d/hS3Bs0sEwU+/fpVkKYjv6/2q6vqUUG0qhwF/w9cGwBqw +vu6BDHl/hakk1718J+//RPsod+t3/3Jm//wD773PcEPpGpgqef1bp2xkGN0CskNjBh1AtuTTfUe 9m17v7sC+UDNqHxf1hsiPnC0ysawkzOz7tQRTgHOz01CUmcHOKpcreD4GQnvSPloiWCwXAr2kXHY lYULlPoBdwocmrvTKE9BlzRKqOSxHXerartLXtFbwv7HSBmw0rDQc9iS/YaZalntxz2IGt5JVELp ZAJ1YCy4Dfnk3X/x9h8zfK2rAv+8+0dv/s9Sb9v2fmI2cIaEk6Bycr6vN7DWS6ASKELix2SCfzf1 OfyGFqVEsYSF4CayFAukcCCkYKoF4c+g4xAmbrtyixqjsmsBHSZfM0jgIJXKaFjeRSJ4i0WtLZEn PD6aMOyhPMxUcRcM4ClOj98N7y2VvaiBG0CeRFeATpbqaaw8gCcQkApIhVfFvDhJnoc1w16cHgSY XGiJwdOb+60CJQSe0l7bucir0snMJqrLZfVOr3MLx62zV5nhzCzfgovgD7uJpjrUBI4JC+gmTHWE whhZl5olFVCqlC0woYwYgHa3+25V0URtwrploCCGAlmZTabGb+9h7vM122J1Va2uMw+pP0p++ctf Akq7P68QVoAedGuA4019XRFxv63qbo0Yt1559WpWpgGH0axLLAPH6RRBYVVCT8V+uy53/P2MpKOf OPW3ioR44/YXdjsRRRtxV4Dr4ZTt7ol3miUobqi/U15G1LMgW2SgY2pBw8V+s+FlHd8ROXOveQdk b5ADwBljI2pzcNjcKW+U3Z5hHZC4Kcyl8B43YMpAo7OEcDi9gCPXrK2h4joFCBIrTVRtGZG1SOap s1QBF2H+Te25AfXclYCniEwNr+l3Xk+r3bRXnbfN5j66mI/0qTUFpalyhwpZYvWdvVCg5IzCWlU9 FaST3WU/OpfdfgtbrqVEKL8nkROBt4/NaWAWwMavebWvABxWe14PGAEdfxyGTQys0+JPSw4QiLw0 hNO5PIAmgNg2uzNFub5AXXVAuv7GpVylol0XWDq5ajdrMs8sCdX0xGJdLC837Tn8ojYAD9xe1asr wOUgpPQ9qd5XwPgARqmQGwU0sC6G2ZkZd+VzNR75I7JLBYuLZYT6aeKkykSIEpMyNXirrD0dq6BM 2WqTHsTILpWwzgTwWxWChQ9K9YWZXWGdWjheeDY9yheF2+k0jxIwr0lkGNxhyBpxbf3KRhj64ZH4 YmpaIQzBMIOaGgdDIBTIVhN9Tj76CKC1906YghXk4NdVquiLtbLqX4q1gdsHobTdstEwKdfrWr7S LmkVUD+JrGkvdqAedcKCvqV/aCOOxA04OOAB6769z/KgnBDAjGbqbxitCK+FC5QzXd9ev7tqtTxi AaHYhyzevx9bvL+7pbAYb57g+Hok1oIgU24sBQadBcg67csLWI2saZuTrlrtu75+jwaKpjrBw5Cj HgbRG8kGiH9ToUPReZvzWLcFtkzjkBGY0dU9CBL7amiA0ooQhwfRHqXIIhoEsrOt+6DhozJIUaR+ aA5sXPJUG2gIr21Mosbj8YuBPGEaLZCQNOssg3ozFzJO4dGZp2QW1l+pEMNWt0i0mFgy/wE0pV3B JrIld09Wr6/7+1UbkEQaj6J7b7pyVZ2Xq+uXaIsIZbcywZaAqLOtoiYqr+oYORzJW91cII1BtDgZ EeaooUBMVy9YHKKvHsXpWFhSCJ8Jtipb7M6XTCktLuLt5VWBehOiyy+KHyTr+gLgsk9ABBGLd9UQ G1B1yt7NNW8A9dV0Cgwt6AuYGrCme6hbnrd7tof17YZs4LMEJDSrBWBcUJYHMo8MLaKLAZJsz2CI LHfVhsaycOqeWAsjBM4InPYO4EkM1SMCDtMfuSCQPO7nj9c/RpHRb57lCmsIT57nR5D1h3C7Yq4w pNPRlismPpi3JuwB8f9jkHslZ5lzwjtsk/2Y4GszLN6yP0jOA/HYF8VITnaZeUY+h8fgcHaatulB 6Ja8kUjJllT3Vbcp74lVxianDrWq8fgBcxyDm2/MW55SWZOm3qw1Hm3FtpToaAIl0GcEcFF34zIs aOKic3uLwpD2IOmJ3MMvrCHMuM+RavQWZUUNXIquuNDjywskotvMxe53Fh5bOisgAqlZ/plgkiVO 3fP9sRQYaB9CZQOwwHdkQMmH7KWWrsisrXYDQ15AyD6pjRJoziNN7oIskrso7KgCDshp/BQXix+h svevWMJiltlSoInQdPI8AUpaIpawZGClEy3vshGcOEueuUfgoHSu4c2couKDUVKt1AGjAg2RT938 DkV2aT2ygJbiuVm75GFYybmcqdIhcuzQfpbB61ClDaf4LsKMBB0nTyzyBaJ8te+AM6tXpLXbtVug wv1W0IFWUyQwjMKqJauFPoZo+8dHwK0A66a4nX2P1oTkS1hw4zim6tLHEksuE1otQhOIQOzFdSsk AF2b9ja5rZJ1i84KtyWgF7HtIvY28JI7zGGNTBGvm7UKtMahkwu3cFqfFZ0ghgLK9agxydJ5Gjm1 vL61s6p6xF1VXsdJ3imBzhxqMysbKsD0fBzu/Kper6tm5EggClIeW4pcizoETTooHQHLoUkftFct lx6gA9P0XvS42Jwrg920AOKstSIEhYLXvo8rDwPYDskXSZPTYETTAMBtW0d/31d3EU27VyfaN7l1 2uxXv4twX8HILxqbgLDrZjjCCmG9iBxDqp7+5Cc/MdKZWBd8zOQokoNhKD4zQsk2PikzQsp5W3br V7hb3X67e+jCSZ9TGH0gT06T5AtUIz/ugCvFk/a4/1WT0F9kUS8ajyFVtmeSYM0u4MMj2S3REOpl kmXU54bbd3gdKe4zO4rp8iStDCVVS8TSL7Q1DKSSctvvN6jwIc9FFFuSq/ryCq0PaFc1TjtkFeWT ZHObddW7zrAvRbpyuf0hOW137p1+fFuTnyzjxMv6fdUo6+7Om0HgO6IM6bvzWZKCoNNUdzsf2ZEJ IgOUEkGCt1cIAyjdivdDSD61W0ZdgdxFm8oiLbYYLYnNLfBvISPygLI3Znqli4UJ5GM+ZrFKUMXA 4Wq/s3x1Fgw/DLvyw+JX5Akcmc1+XekKQ6KVAQDFC7LlFUFRqf6JeuqCLuI9vydv/zX7y96jT8J5 3bCXdcsSixora7ptzsp2riF8RDZ7JgxE+HEASDN27cl5daIZTgM6MDDtJ752R0ajLjdAnntcQeUc IJ2ouUVXwOErFMlm2WDHyq2yRxkg66qb9j3zJDfotkO0hx3hk3N0dycTyroqN05zZOtAcwXxiUpb SkgO1u2pnl4eVxbCYO6UaskFJVHx31moKXgvAqErJVrHLiMRUbGb6G1vai3YWwx3MjgdmQVydm3b BUy1RG4Am12b5onFhel/WEUVLaig3Xg+0L9AmdX1ndaYLAQGB6raMoNTPy4TYHvWzzyPKvCY8VH4 +86oq6LWBs+7BL2LNDa4rmzdF2sb+z1Qlky3zxQtL+zKWM1GqJa8B6/g+IFUl/WbGn4/y/1JSC/s DkPECFpEJ3R/8KQX1LgYeKFKaZIvmsWmvDlfl8ndnPb0rtC8Yv4QhITHZQV0tASgx7n1CR08/8QD O0M+rfrmCZ0+ZFmNRlLpcmd2V6+gTfcYSNczwlmilrN5WX3zhe5KGL1dCZNz4Uv0KtZGEa/HLcCi BOhUOdYT/uJ5Eh5zm3lFy8BmQlRF8LI6bcEuVIY5z1GP8b7Kx/TwBlplHxWnlLsi8Kor+ysC5RGe H0BmR6oBHoCv2OLN2VSlWS5ZKo0IGT/rekWcmz/X7CqPOfDT2J17CndVw5/+7vz05PmZrWYi+0YL aB3E2JGpEiBgGYXLCW08dTYLN7yrTJvOkNquvkSqKXedtsg3djX8Zm6RZ2LqstK+syDNXhHyEIEp /uZ3rsg5M+r4qkF/PrQgeZPCf4AboDbLr4Eilx972gKSiFF1swO2Fn1iSGsHfZoRl7sp4TGX80E6 RL4tfbUTuGfUdHoWaKw2IZK9cMcZvN+0K7Qkh3Zmx6UWnYuwJKzLJs4eQu8XhTJCXRRia1xW7/bl Zli7izp0mT5NUgaxfL6ALw+v9mKhRhqjNx4o1+46K0OSvanGLBpTJk3U/IhVuNkCK52lgzNCgjg4 7jQ61/Qn6AyIS2k8AV+qk/+quWjjLoE9eWQCiliiohCwmhJ/tMhjdhnvnNIWN+X7+rLUHKCHUdTZ WZKougOeHqXidFDK2W81j83qSp/BfpR8+dOCLYfKC0/0xV39Hg7d95Pk9f6cpixXXcm/zdUtOWtx Qt5jqsZNiV5l7ysxTZFGW3dU2OgPxhrXG+KLhbeU/oHz9de0xBYPAW2cPj+bGaX0pz0648OQSdUQ U0sZBbC6RqUaSW/6y5SxXSh4RQYTPwFWB71ufLw9nJT6UZDEIYq1kmaTpAOHTby1bZBx5z9PUs9c CUstg4OBue+QFROlhFwAMnRN1Qtr2Moa/A2cGj6yVGf8SlNeY0EwpN4RNQ/a/RywTB6DhHO+qZoF G/+SzBkaCH6iFTRDyB0vjBX6mqlz1d2T45ZccR4ktIY9INUhGx5cLop4q1Q1mIrysOqV7nCmVbum MeQcXX/KOFjP2D+OPNVWO0SQpg0RKj0x1O4FV7fq4cSWqlMt1GZ9GwEhKOLpC4nxZX0Ktn1eAefQ 0EWfGDPAmmza9363NvtQsDi71ENb6q0IgNG0rJFjgXe7SOLqg7f4oTXVDjaSDQkU3FTDOnve2Yqc QKurUw1kdo2zgLlDXY0Bva6zMBkDICzFYe21CzCNEVJagucYV+11pA44dmcdPPRGB+Ag1to/fXJQ 1FFX50afGNfCp1wi3INXuHy75TVkq2gUPzXC7OlRQuFv4DtqWn8mF8AyuzHUq8pQ89CfRBpx5ArL CwkmdssMBOMDtE/eb6rFdNM2l1OXoyjP6bqMKrg7Z0lgwUddglL0Y3gFiUVON0y8A6q0X9a2I51w bZt6qHP6ruzd6APqCT1uPZzQPMEJ/Zb28bdN+1tUnb23WBQu5ckvPL85Cn2VUtwmGQsYgdEiIaeC /YDkh+Yl7AE5uJQ7T73zyd7VutWY+UIhhGH0kk2iBJRQTfwVH5OBaqqf02dnRq8SFlbUhnj9G8QY X7AWr1q/ZKKaWYBmvipoo79xYJNPC9zUFwvk1JfQz/wGUCRS2koNA0/8QQNQ/GiT1OrKPMHBHDrW aCKcuWglD/VTcDxQ7rDHt29qJI9/b8Yo45FxKgdtf7cDmUJOO93kNO4f4vOhLPlfiEKJpYy/qBqU ndvOuu76iL2RfGsKXyXYtLfLm7K7rtB0MP0x18C2racvh525D6BCDZGM7o7Ffmyo003jhukfXiHG Dx4m4u2VzpAUy1fPAU+6RzFcvroFZPDwXr65JBG1Ko2yfojl2Ra0LupLdK3DzeKi7PNPdibPkyK8 t6VMlhF3L+IpuLuT5/nv33oZdfp0B4QnZsi/c6zzcABDg7BOzzP/OH0Ch45XIU9OmI/Xttzc41vo rFpuMXJ6bWBTjgTDXhGOo0vcWmf8ZnjH1pWARx53Z7BGqX2LtQtxKNyEXsieg/RSuxOHM1ROXwrK 3ZHLETg9C6xK8IZFJfiirz7bapoBr2HVqu0izA2pa8QyDdWuH5FCJk1IGMb8KfbBpMrmyJbOtipP M0TLS1J4Lk6YydNqkFlyUIi7UEiZw5UhClwn+63aXhIqiqgQ4160HvOLMp4r3lUPdBfIA0cCngwU f2Z3YL35UfJsPlTrySKx0MWQm49VJPTwqZWFipuMeG531UV9pzXdFkV5gt4OyfSIq+24ZKH4ZUyD SAX31XDX0yToSJwwpMgT46kUlNKAyj4WjiZmpRQ78WMviF1pQyyq4K246QtkPRXgAg/QUrEN0tdM 2lzwx4yAsNyIq2SATahN91i4qgu/2U9Mi/45iIGymt8U/veR/LRo3KX4sXaVo2yw2ZXWciOv7lQf MqwBebHot5t6l6W/alILaInjsdfb5lOeyOBOn8/duw4EB4i4uO/58PZbHTxJXFiwTDayehGNvz0+ b6Xiu0WI23Jbnol4FsHdliAXTiBE39fVPT5F943MV6Wr90WPd9/zAO2r8DVYJpylCl4jVz3C2BV2 FCQU3JZL8ULrl8s0fr6dXZjaFaCjH6lfP56G2tI4NmHYpIgplmcEByMoORQfeTgAbj+/Dzw9TAuk cMxybbSdiVET2iWdh4QLKJBQwYoNtLKu+8t9TbwxYZL3VYe+KA3xhyjYF3ElLghZEsXAI5uR8Ce6 NyQNiM2lcg7U4c+fKVcHS9szIME6/qOxf+TrNeM7SRwXc8ji427q45PnzxAiKQCEuJzpQQ7MZWxz teIau9HN/+pXpOml5oda1ffgh1+LQnJLZkP5kBXDQVflzUJJfIjEbrsauN1BFuZnfMBFIekefi2V LY3JWhg4l3dxJIsIWWIdIDyo+bYjWbh3555qx/Xu9vljzwHk75yNCff3kWHCA89w4zA/s5wanqGv 9a/Ja2+4S0dgPyGv+uF+jFP9CHtnZE9AlNmUSNeULomA2OtH0sGXas21QkvqeECz7YQd/9J37Bbq M8AlWTXlgpUSCbxN1bKcYj8UEx2wzxbrwJSZ/o5xNAG5HBjsTdX35SV5yJL/K2IE3g83lsUwgjct qKPApjLmKbT5CdDe1F1hFbeLwB9D+9C1JaPc8ahhvamAzgkWHlAo28CFamUZm7dQhAOkoQfurVPX 2l5hHKT/CJG3cBB7jtJ2zTSwzKymZ/ZkZcdjrPD8O3C0n4TsazA22w2Z/0pUYSMv622LxohTa2kp cNwxN2FIlbw4rxCvb6jZEA6EqDZbJKdCXiWgW+wiK4FYsw1keEeD5KJ/l1l33OqNfVTDd6DuVihJ q989hY5pw9KC+y5JrkuRD6cGBArXQPXNvsHYcjG7etCi6d3zXzKjIMJllXSUs8qe4OBjAL+uFGnP GTLfuGBUFnoXGbOvd/9H7OAZj0SoR25jGEQswSEm64ytX44SeEXaaZu9e0fs5C4ck24uAEVZzIW3 vDGXBrMw0+9///tw2pTLEzomU6i0rEdEKXrWf5ds255iA+TT4+7m4Pk15nqZwsz0rI0Vmvb5HJBt ZIgdACxkA3BkaRWiyaN2QAW1rhUzjokcHx+n55lp01yAIN/ucoNV54fMI73xWDXmCZfZApEMZAPc H/J6OX12Bujm44hiuMBb3usqS/e7i5MfpqGK8ShjiBcXYHfLeLFuCzWxvyHGNlMuWl4Qll27k3LZ zopWhM3elNtM9dsykw/EJhjndCq2enOr9Hhvj8e9MXCXu+Txsztzx1t7BQPtYcKEemEOu+mMKjPa VkftbdSuJlxci2Z6Vr0ep/E2mm4pq+ErMh0SMk4qdq143JHLSlTry7AXgqsNjfl8MF7BEFDP/Rv6 7rFzfodF1WEztnMvcq3YqNzI7eV6LW+cULWo7iPVV19tF9OTaWAZkta0fjmsZpsBLDgVb57b0dkO AbbSjbg96TgaalQe7b2FF1voeOsHIJW3JL9Kg87uGrQa2VkW2ypkZabLZNg+p6hIFCvHVsFQWOvX xLsqbciK/j5mljt6J7YtghrfN7RXXVNvf5jhdVRXxiJxLK5txs7iygW9ZThXWedQl6C2bjr1b5Pz LOgeqE/f74dgy9zLl/WcR+HELeMiA2IvIqDCtP0IWLGkA2Up4l/K7yAiIczDICCsd2x8qLGbFeiK W11Nj1IsGocLq/Nw0HxrBhbYkFn0xs9j4dBSufrimN/30Hb6umezODHRfS0rZruZTV+iQWMY7PgY n7ebtRjToZkF/OfWeDQEpUx2ginbuzI0c3k9hiUPTfv4KR8/XXsKMUX5I/tY6zMxS6asnhvoNzzd TheHjrMFKvOHtT8AYIe4TMVO4HVi/o8UotNfNcJqmS3Jx0JDxiZ7fHkZvIOfHM3JcbyK7bBn9Coe ylEaHSWRD0Ql8hwF6aXRIsm3YzHEo0SH1EWpUDpp97utBHasSoyQ6Pp9PZIYVmVjlbwpd3zZCIME JNW6RtedhAI4UahVkxapv1QChBqsBjacQH9JMURpp92Ldcn3F8nJcy/kM7UGf0/ntS0BCFBixKR+ Lpo5vcrOxfQZ1s6dHRY993F7yyA4Sj6O3IxjEI6NRlyoVO4Fx42anBC8QQtBI0L2QAoTollWRF+U 5Hc1jZrm/DD0YSOk5cIxwUZ6JpcB05FScPU5Wj4r8Z7GceCDF8mPcQUxAsxtvfb1aZ5TAtUavgNk 7wR3MGw8knWAuTzA7nfcMEz7T2CZgArANCPdjHflD9RrYHwkBxbCJhDwDwifMoPy7bmJxNxaXWlr aVYqB32hkXI3yk75QW6F+516RejL9etPdD+7VqLDpr1+aHxf8C6gqjgfD36syzk6AmtK9hU775pB 6t6307fFLMlct+Ld8YnFnhwoi+dXPfBeqcnKis2PmoMUfsjgpcr4qNW2GaObPFHKjQ+DCL64cRRQ 0AZL0OBjgeKo9beW8tSHgbNi26r7GrGtGF8qp2W1M6rJiXLvl2j7Rh9keYVZ8Z0tH07lFWCmH1Mh QTVUR7U6atCBIPhQ3k8Gl9Y3lAEzZefA0aJYjno7qvDRJdUM/LJmkpPJu8nbP8WjT4YVWOebtnn3 X775/CPKBjrB/7wMnyaVg8q2gPdzgfPh1ViuKdPPsm2WlGmoasjcnHLaIbyhCRjyGj/XNWVvQKYs nYxxkwPMo2uZgdYCtpoizX3Z7l7dbDfkhVutGTvY0QWqD6i2bnfRmlYoH1rP87InhtO5Blikzo21 neFSQoMYPPTrBn6guLpFCqQQvg8Pha43EcNjd4578gHzV/OKDn1wFYL+8QXP7mEN2UuCVWzjBIb2 OKoxLupWv2huKDvnSANffPlzLFKRH2xuh8kyy6pCqY2NwwmxZaKvueNZqoDbKmyHz0J7rOX1bUHR LHzf3rp5X5FKxdXSsVGeDlNgGIv6k0vhSyd3Z8T8fzhjiOVvdjr/+IwvC7W7AVczPf5APzc63IPD Pv14fpYP3Ps9agrGfNwHbCT1Oni52A+DGW16CgLq4y5ZMYa10hbh3ktkTMtHW7KVHVwXzHwXpqzB 8eZ2VgIQIJ4PsusZeVVCFXFsy5P/VbbpYCiBEAgPCgfnbbuRjqAf+kV9f7duZZMzE9Huy69efvlm ltgP3nz+6puIw4Dtc8nWqwjhG5yP9ta8HR42FIPzrPJAjkRoOLi0JFryzW46ZCg2xaJbPGxwCADf cYDWdVjFTXxZwWZ+QymXM20qk7bplEm5rwHWfwr0ILyA1V+VqKqsFfVih2YKuAU0G1gYjJ1iJfQx uRAVJwPrpL7ajMm6fn9UmiJW2SEXRoX4QC4p1gc1QZm7+NsjALWPrwcIq3fZQZNRFWmMyFjsfrD2 Ezy/77fVKktV1TQ/fcaaI0OTTUhB9cz15NFEF8bcrpZLO3r0vqvGRozvqX6i4hKikyMN+5hR282b kdtPnTDU1nN3BvabyCwUCxakaoAj3OsruzzuJKsbDBumAn8gQ3bUXCjSoJoCXzXXI4ef7oDx8no4 TuBwLQeqj9jS89FH17eefsuLbgDVAMjb7p6OjE6EJDFT6RmnVQ0DymH4PYmwiMV01oJiLOQTpxSr bjU4LVJYIzoT/phtvq1U2UNvgBYt0i4NZlSurTDbSZmc32NW+I7jeYN8iyXUvoRHI+KqkfwoyV7M PvYQlw6Gl+5RPHmbRuknlcChxrHeDYfNu6FIntV2U3JE7NS+GKE0wwAFTXbjpMsZCiiLivpybUf+ RWXlxo/hWqw2bV9l3vqSzkqlKOkWzw8usEplwQpeHR+C1xYleoqDqe7IX1UT2HXS6d7W7K4fhJao KKQOK9rJkBTL7rrq/BCEZGY3XkSwAmn3No26TUrh6FWUkMNw9yBsdCiThtkLXlTfATWyKQMbs2kF 8L3dyNZoL19hXqbcTUeC+qJ6db1R62oWJXeDOnpzO08Pw5fme5jjXC8xZWymHOup1wJHPEsuHg6D CAtKrw7Hv/IzwpA2i7zhdfoAKhYAiTw2sl4ey0ZoeLhXX/7i059lXCs0h01XZUO8LHbPoSYb6LtM +v25wZ2YmniHfU3zA3kbOyaHMsXh4Mm//PzlL+acpA8Y23oNcN/2/cm6el/zncXrsG1K3uO3bPVM S3yEO5YTH9HKrxOJUzHIZPDlVxGnbM8dzmEoVOojR2SlHLP4WqVUJLOb4pZn6KH5bo8XbTDSqdDH 2k8PhaQJr2drcjRTkQ05/4IdXIU6YTVHklH8xirwFWeOMFdhFBkLhV0mmSSnpVtEudu9VjRSBt2O 0zx7eX5JS3fhZqTTOepYhKfwhIovMC/J2zPg2DPOao/xzplroNHvGPwxkJEWLvNIMCNe+RKZZOpD TU4PjVgWRPBpsb1PZY0Rs8cQh1pz5epC8jzX41UlVvi2HgigrqUJL24gOjf+RqkOk3ny/HdRbkMx 65lELNVak+vbAd2QeI0fOBL63hhfltxwJBUTxJjhy482yRxTKl2kxdiMLY9sKT9L8FDNtHyT5wdS rT7uOBSqHjVsrCXdUNJVadrSDUBZeSpmeLUibhwXXYiiluqf6N6NFmpxodt6aNBUe2LKGJO6xEHz mlscWfSF07M9IU7uqlVrgZsusGE7tN6Tk9lt3Xz8YppwPkfWmfeoMidhQ8LGsVbKV0pBa5K4uGig tRUKodJ7bmsmfUoTq6RWfTjer7R8KhcYNOBanvQb3ioVKF/HvLJKTz6oZe3wawmo1pULPkrrqt8d e45K+xQh+lcMjIvYOMfGGg8URsA1IkyOj7BDIM6rK/LBCMkgiRrWOGkbqRKFG5SbJlA/vGMkl9VM AHA1FaxeHJf7QbCg6nRwYwEcQAiDqbnhelFaXihqj9aYjBY4dvMIyxIHIcMmuQ7rA6ED8F63t/0I VEXaxV5f2CNglIlPfGZ7QwvKUxwsJktBTUacHaQXel2QxjFTxzoPEo3E1YONczVR+8fTUcO1PUs+ Shp/TDL6yJ0tc41jE64O811qzjBI5QYfO1xc+EE5tP2dsbN0GRNJh/qxvhoLhwGnrG13JxyWXglx FDwU6EwP50gfKNtLmA7BZt8bvokZ3jjYK/2BF/eYVh+fGCTCSRM8RbLcF5JWXHFPtyzfCqX4CK93 yV0fKTg/cPuFtxgILpCU7NlMVXPohCyvN9pCHocXUKxI5XJc4/pBTynDZZmVEH2l5vaoahIE0pfb S8LZdhLVxm4pvlOy1MEdq7tZQt7Zf1tvlSUKoSyXsaufYWiRO6S/w3Ix9hfb6yBBFxW0RJVyvR5U r1rL11S3Tjp2WreUKqQcLV0xYkoBdZSSip6oX09s7a01xNXN9pghYogG4egzvPgMsPbkeV4clTMI ulApbzrmB3k75Gf+ASiFmlRMEd2FV3PDDJHGUVDtu2PMXC43u8E5jyY+khEnP3Jn8IE4kQYPbZnR mzG+BzZamdFBopOwQYDi5Ft9CTxXtbBMC96+UbYWjomPQ+wlCZetKNXpRC3RUZIDcMCyDNPhYnVM FkVJLqA5NNbBkusgJLvVlagoQ+aDtGZE1yseULWeqdj9kqaKEECG07injGRhLFcO/Zr7CZVXRw6V 3VpRida1G8wGUDmBpMnjAMa4rjhPSr8CahkfpjsC3gGJcKrNOhx/mvvEIAhUaE3iKY4IWwPcT+FQ XNyP8fSae1sIA/HeZDqY0U7qwDYcKrur0G/Fdj735DFLFoN1iqUvxC1fWB4A8NsjHqswEJMt4a0G kyJWdCNC3A+cdjWLb6c9oabQvwcmulymgy06WD84rebakLjg9jt0owlwDG/MfOwuAtSje2IcHn2r Yo75DIZtgWYlYwY1F8/5om4mgKqypcDPbJvnbmQgVsthB9hnqLvnu11UqGDEgCiBdhQxAq2cIAT+ iCweZ2/aToJ2h24wCTJQA4efMPDhdq0wcgCTBOCKu0MvK/eODkX0iMQ4VrCALw8Cg8QN6oNgEHG+ WlewM+sCYdReT6P0T2mDmJPpKsp2LESZdFkYFlHR77Jn6Bu0JSk6slg4yF/icarDOHYfAdFcxImM sN9CFbDJPC1k3AMNRqn4OEvPqBiHp+huTZZJOsmiB0R0e5JKP2lhUONHylwkhQ1m10V+4hVBvCeZ Z1bAOJYrO0ImsN7vzrzCuhR7Krwzhb/Ppf3CrJjiso7anVEtrRpSiLKmZLe4PicgDZUUwRRLNSbv r0Pw4YDsezRbsIaKGtIkEc9/maQfkcpx25EvhWbl7NDSWK0YHNi6rXpMmykDjI7P2XEZGEWG4pWA cVzi3HbOzsaZawNFNlDZg1MjpnsepP8h8XYRXu9QBm3b023EdqVC9asrNOhLQM3LcaFoSUn/vvmJ z2rIiHGtnyRqSPzVGT1pZ4QmKa9w+RlEHxbKxcZ3deQmk3f/FXuXWhei3/3jNy/+5HvfM26k8q2/ B9QnOrLJRHx/VSwtuiQ4kchd7Ehtrnh399xElmKBlFKBUUGTB+Q1dI6XRDI7+JftMyLZM5ClwCIc HIwTCtU3nHcNWYhemJweMxBKWYtekoKJHAQw744dTq+x2RHS4a6T9b5T9mrEOG7uEBVqQbDQ3YCv CeEqTEtSuXMr5L6nVPbCN3hx6u9mnM7xiD7sfXEbtkuJkRkeUOMfeR4KASPyCEjGvdhBGmCDSxqm RPO8rjjbPe2G2QbmaCVZgx9sgeyWuuffe47VFV6s1Sk1hnOe4GM5p0rLTFVTlVYDgXXfXDftbXOM 6Vl1I+c+7nYZmVE4q6GZeb3owUVjtP/o9HGP986muQLpWuyC+Rlm8lAUfpc8u3t89+MU3RWjvTHa UP0CzJhYEDoDCQWFuBvNe6nC6OXJj+XSXXmHJzXiwUHhLu5QC5TZJU8+zp8+fRG6hP7alHeLn9R5 POoy3tEDnJoWBflm96xmz09+PT+Lirh8p8GOGoEhP6mXxYtPnoXXG0pCQieEnmDlsSatvUqcfiHE js1RkhGVGvlCgpAr67C+E0HoD0h0p2N09JYvh5iHxVGIHYQkTJobQ5TObaqmkgLoY3jzDeY4gcPM AsEKRTIg7g2yPGLUsjCkqB4TCQep0u/RkadsosL0lF27l8QriPWeKgqhapSbeqflRLqbWXbr5EXx ZwkiSgfhPkLdX13dWpNRCTU5dbWQIk1KcvOY4IGXfaF2zXuLBGPgHbPJi+T5n7EqW4FEp/A4xxB5 90/e/kt1SatY6hs77Wb97k/f/N8vh0gqbOUWtn5C1Fwu0nSKnANXhM47JUaH3N5jy7BZE+c+WKF7 UpV+yrjTz2Kz1BkatpuSE7ZOJuiyubuCXbq8olhSAerVjDwA5V4JmRE2HpUOPg8PO+WmOJJwWsNI mfV+7JyFH6r3X8DGB56k+JANMlRImM5XF8lnQnsspgHLzpj5/QywVLLqKkq+R+b8u3uNCgle+dqR cRq4I0DX6X90o8SrUnWJGfkZIlg5TuzJco6OEMlHaigfYbXPbAMWh0pNuv2mErUWdgZn9H2LPidt c7HXyQNvmRFJ6Bgo3UwVG0/mzv4zipIqy8CrTdnTxCcibOlOFvNTK50ZEvtqd9Wuea4XdLLrxuoV cUa537XIVK0IoZDTGkDmHZ/lr+gkoftEyXiEspz1FYeS9XOnVR1CbEUN6E7wMAgM2muILKBZFtkv tX0EDsY3XzvKYXu8GITRAKShBuBbPRBZBWzLWnMA0krju3Arl0ssC81QONdeZZ6iltotYz0pdF3d QzleVRjzTy0NGSFE6ghatjpnb4cJOzGioRWQR31Rr9z9Tm6v2t4aCnqM0IL7uywnpmnZYqsboSC/ sMFqIGUHb2HBVlW17o0tBH1pxD5kAxOGc8dUHMqDZQaHjm5HMrkSy1fbXnNEfN3tRHxwPuMe9PAX SQZ0ekYXC2YJfGV9FAmF7GWj5EoU41BSliAt0kPbVAMt1hhwCBvUGcKahF7wdGbwXa2RpdbFoNT2 Wn4mBBGXDY5sX6+rTtvHycmXt1WdKtTycuqdzT2vcBS8lLm7IxYBwKtsmBaVTDIsjyUF6kRPdnTq LrzNnmEL7XuMM7hm9kKDIM/xdSURbpXfkfDz4hVKDkY37XqvYitPleMBNeQlIbVX2jFXNPg0Qwso DY1W2nGXXvvBAPC2KbNHQW2PcqgDTBX8V7oSFdC/dDHOgiqF9dJkh/wJNSesK+vVOIUWziKZRCKW lIGmGBbU8XDzOw+nkkb8ZaIr7ByN9iMbzQZ4HH1fADtd1YCh4cTf0zIxBkbSYbfSVXS+OJODVOdt SnuOXO8urwzXvuSl9ksGac/CrP/IHU6pbtbNboEUHqYJykU705im8sLBCxdW1L1Z6Xks+LsqCPO4 6Vp3R0KJRyq5gIAYCYEtGg1ehGeo8xkV/EzU5SoVKN464rqfFeqMnYUeFNjIoAmYX/tLaseQ8wEv lpXcGpTExMcwoOZpFp673I1o5M1tHnOisewzZsISKj2iSTdlEPFYNUzPq6u2XlVW5EgLUnwYCXzf ue6wUdWZrusChgKm1Cf94vO4MZhLqKsocbB6hILCObry46m7QaXXlhTOVDfq74KZ3ykDL62cHsgM 8PXx8SHTx332uMtTnfjTma6lCrCPJ3rK8LVbBzpWOiODWI3gAcIDfEBNUxBR8Ny3MBk+pfHb5ZY8 0GDDjlVxYp5CaZ0+jOJNgiC9Q04xI25ZixufsjQGZKCq2MYqMvYFCaW7rlT8sb5xZIlaytinl7ru VUQJZRnv3Ft6zo08cxvqvY5+41d4BHzJZnNCsSVxnUQ3RMluq56uSuGw+xGD492Wo3bsipe6UuZu pl++0FGbFkn6Ixzej9MYaWNUfajwqiUhVCRdaxSfwROdhy3DjnPEwfg4y+MYlNMpSe7uUMloS74P VTCyQkRkYs+bVTzzZBAerhW52AaL4BEaKGnoWr8szdlq4n3zQCjQqc4eAAQ/J24vYy8NfPB6d7PL Tu0dPcsPgQQMdXyTuZfjN1j29a5aLf8gG6sXvQGUaatPBrBkRNGS+ZtsMhZ+ibdRHLwjLVqEDJce yznYg6Osx4FAp5FIH5NdUaLa50pRgRZPeoConJUutjVr8H4brTz0jbbVzDpfKs/V73cvoggQeufR Hzn1/7inOk4inLmKWVhvNcqz5rGzDFmIoK0wBW7AiL/PCzRCDPs9Grq+1LPKeXBcLJrXQB8pv6kx vE2wpALt8N2iYw6zFD1qJoKPXdZEjafLnXLRSZIGROncZlTuhQ6L0G77Yc8VGk/KxCfmt/KI7Qur /U7yqaKDAunCDM/RTwZiE7gAZJO5+J3d0FmYZ+IvDT0NidKL6NoM7C3G+KP/TwdsYrjUpsYsWF8X 1zu9qTM7XSKF6FADvtxUFzvs0HrU1ZdXeDvINH1EPlGH9QjO5MFYo+afN7YFzZhb/rBWaDoLXhvF zUSMoyNI4mFG0jEOzTpVNCB1gD9t1sccXih27MFVIOAl1+DLfdtOn0JiyaJsWAjbEX5rCLLtEai7 Ez7sRi+qCgRZuz45eIKtwvkhV//IkUsztMOmbJzkqxv28PHGSZqnaqu+6o7Zqa+6/3+j/k42CZZl bI8mj1DB8bYp8Wa2sfYsFpPrqtqWG7xgRutM6v9eaYLhm3J/gvX+jZhmgPUFWIN/c4qOYyMV/JLO dLlXHIYKymX/m1cql2K/MwG42M5N0EQj/bTDW3kxqAohi3UIxrs2Al/2dBbma34E8ESI+0EIimyW 6VTHuEjji/ewf+OA+TDCZMb4YWQFv9jE6Q9PVCas5xWwVofXQFQup+GndeQ4HAf/n67XAv+ZzzM8 CWhsbh2I1/vzoYonoxV/vt8MVfxotOLn9fuhik/He2wH5/h4tOLX7W3VDQx1eKxxPMB79EdBBDTg KCLAN3lQdhAR0DTjLfEKhKUfglSsE3vwwEbRDg4+ncmEh9HI0e3RDKBBmYnV3h8TLxHTTPv03Zlm ntnfL/xmnRSjyvqs3Gww9vtRErCUdbUdGDjwkKrDsghZSyUeRthCnn5X5cXDqKI/ioUty/6R1SDi SxVBBo0T0Qp/RdHAMG/8vqQrRb+xD+NFk865LZ7+7yL75xTPUofXLkcC8LuXtUpWSP81h0WJ8LIq YAqAWxGNpljSKxzLERduTGtBJNYyWN/SPaXlIH6FSSo1ubUqj9eoo0NzIS6xWwOfnEq1M5pAnOtX 4x2Mbyr78WShBwG8+yyNqToCyaQcRtvx1TOdpY/7xeN+RkpIGeNMjSA/qnNuwWtgAO+b3FUlJ+71 A6HI4/gJ0a/zeK0HbivWS0c307Qc2VRrDT+SaNID2xZdNapjDT22gWq51gPrtT6wYOuBFVt/6JKh M9D4kq2PXrMPWjSqtD6wbHH9Yfa4z0PtIeNZW3OIVwwionQkY7iJQg2DzwfyhvOX07md4NVahjHa eEh7CPy0i5D+ri2pomaiNbNsIQw+qIOwdffEO8RU952eTGhPPcDsppjt6TeS7+VXze8I63TAa86S iEGPmaC/EAenI3ggKfqHsQJECTCVZmzKVBeGM24eOwgkRwnnfxAbfLCXMtMsVN87k88tW7pcX9Q+ c+h4YwfbVPzIjD2QOdA7uqXANlX9zr77pDcgS5WBxVurGdoE1vVqt1xO2X6XRhhRsWv6u6hqBns5 YsrDaejLZno7FVscxsd82G7/frfbH6sTap70nNb7PxIGIEXPN9VJrU+pitVIt221CwbpfpTRga5p HGV3oJLH+IDsOPhTBFnsnLBJ+CuKLB4lPcbnri/uk1RivHGcwFsKbcPfF+gpndp7kHGDZk2c5BhU C1ZT1U4Jxl0h3a9vSB4uvh/txi+OKc69R6fPfzA/eXFmzYxyAtsXFcs+0bP8kVXV8lpxsd6Og2od cuxRbSIP4Q9rMmpKsTrwZxyNeEuYMHrt5w+vLtBQXV82R0I1lDwGqr87CTxoM4ntIgA5fsAm+nQj 5nN1AuNXwKXDUJY0xxs7lBYukr0ARihnRTD5+4T6egup3rTrcTct6OLMLT/mmHWEUxa0EPPJipAV 20Hrj8wSCEB+XversjvKvitF//6CZACH6hY9bvsRE8Ryx8yOnG2h7Jj1k94HKwAP86BYgT3J/Nkl mGP+LC9kw1Tf3myp2yJwvtOZy6yHUZtuQskI62ZOCQn98+tqLLxq7MaLlxX73brd74rbrt5xLk/g B5AjIBEPgX1luT9X6sKjq5aYWOGXZbUpApZMWxlrQ6UNP+Zbk3jBg35nz/OggEob8wUVsGBNAJU8 mLHzFIFRrrQLmbKUa8yMum7AXDaqTyR4NPpEBx9EFYvjZ92ccynn3D2l58EN0tPndlhUD6oi+xwl u5bi0hevGQKqrlMQYG7dYj/Vep4oaBiAVoT5Rx/+D3jLT79+lTxNKCV5sm2Bienh4Yc3SNCoOVXN 0YvNqr9q95s1LaITy5IvgAUgIIAlbaSI+9PcgolHzHVNLymSOzYxncmXSSS+F49BAtvj3YWeQRrj Kufz48HeAUW5u2Zhoe8CY+o2kw9mDwJtCyD57vauK1cV8hEWdZUnBS0hANXKoD5rlwI35Gya+UA6 o/vIFMCths8SL2oRw4KYfhqG3qce2bMPb7lW6xoEGJZy8eb6LlnXaz5H0HyRJK/3l5co9bYN4MdI e3i9HYVowTjWxYTz6qLtKsUs4Ut0XQdifnLStDflZb3Kp7FzLHPlqxWSdfKmvwSUtMJNM5jVwW4r DmPhXyKSFxZA6VB4rxACVKMM0QKklFGD4ofszim57O7cLjAGnY9k9OYQckZ2RSNp+8+J4FPHhYaF U6XeM3q/XQc9F1rExFDXXa3ye97RzTX/qEP5yGmni7qT+BWsOz9AXhDuXPeigx1CG40KeiE50e5U qHNZgDu9d9+RFaCoK0x8rUGqDNiOYBpJQELlTp+dUfriJPnRj5QDqKLn+QCfgM1ItGHKwM07x2mE pjrpd4RP8NXJqG7C7EK22OwKdHN1PlJH3r9jufRud/r8zySCibr5BQ+F20JG7w/Md4yTixil+DtE 2T5bMJnUdCOZdoOCyeNlwLpZLiWk/CN1FdqEvbjIwgsfP9BvLyNvP9Zvr7JImKiUQqywHMa84RT6 SD7CtnBMPxC8J+8I22Z5+DC7EJ9/rAfI85lX5oKbu9R1McbOJ3aJGt8HbaMd8gIT+cHLZ+4rCzG8 ePLxk08AtjZtucMGGAJh26aEetx6d2peppQAtcwO4KJtt30q1bgEEK9ZgkEzn8+SF/E3PHi7KwwK dIotwrzPaA6fuGNJr6rNpk1P8T2BwJXTa3q5v2Z77BWtArx790/f/hOdkZduDLz7Z2/+nxtOyEu/ JTy3k+CusHP1Siy1GWkEMaok3oCu7uqdlb1XB3lRjeFzjiYNcNtTfgSB94HECVk0cwIzcyp1gonA BkXdCCvx6+RN9JKie6u77XFe4viSTPvdciopDfPRRMK4JqbmWFph926hXQvv/ls/TX/tbVMFKYiJ MaAViykSIjl2sylG7eM1zn3mbXtrtJkVsemLoZRNt2tUpGxv9/VaNMnwLbjbT42oq8A0ATsvHT1w M9NNuZAkH5xay30JvOh2JM8Qvdd5AFFPVIQBeH9vK3XZbY9cKSiJK3XZXeqVujy0UjwXa6XogQb1 r9u+vsP8LRkfp0LncplbSZJgJQU0MeLWjBvlGLXPgpRJZXNZ8Qb1V/XWzTRDAbsIMWMLhbN67rvk przHgB8S04VDypRJs785x031MlHQKxRfVWxjpN8U2tUfjx9set/1FHokHjMTAJH5WRxcvc7ww6z3 pXpLI4bXsrZjYZZ1yj6OBUVBf3EdN+XN+bpM7ubJnQQbxrRasLx5PKefWyh+SygORZjMA3eUo6vf AYGhg+dA0jE1JUS7qexn8LseOWJWDqn+/ua83dQryiMWDa07OBrV0cyJvmvncbvG1zqVUrtZezib Un/iGYAp3QNzdoUx17AOwq0KMcOQ5cRSHRqRjAYJjfRlLZYzMJi2MzbRkpXnfbsBuTDIechRuvz1 MuGH+IBJJH9SiUiEc3sWeYDIVH8uBA3OT0bNk2LZwl/8YfenSMIYbsIL6EBz4l0xPESfpE8p4G65 uS3vMVqZpJPAVv2ML0YUdGLJSHdH5IoZTSnT0F12KurngolnYVGvWS7K0qIA5iP/qAFOINOjhSf5 AzdB8gQOQf8fIQr24Jg5dq8MyEEgTv4KEX1tdCuCmctWhOI4UyYAe2uGRFIWieYw4Ahwm6cvHLkQ n+m+XWTu9K5Iddi7UES3e0V7Nd3G/rlZbwD0cDL54vVP+Yhw68zXIknUZJoyILiUWpHyn+FRIVLO zVhhOGXjMIkO8iSs/rgoVxTWUjaHo4jR/vOhM/kGrU3elFxfhwt2A1NK5BBarZ/XPUWTYQ6In3GK Pw8EORwrJoZRwZFzJ3NMmdxIU0gwlkscGIilvY65hSGhkdXVSdbEBVul2pMFU7+t/jm+D7L7kdyc YxlVJSQV1KToVjHT8liykMHmDSOv27YCdl+RTiuLOYd6GTt/9tVXXz+89c1A8wOTdpYRszHEEpyq tCjlrni9fPX681ffZKadLC84m7DTlMZZB9r65uVfHGyLEzKOtWY14FaNsTBsvzu4aP5If/blX2dA LKzx2QHgKM4ytmVrotTxeAWSYV1uMCarm/GYDunXnASWsZAVav5rK0WczmMnCF2lidGp6gzv+4oC CKrsEDo+vqpx23bXkulEcs1iCMbyumpMEyD+SPxrZ2yabq/KrsPofZrz4LDubn2Qy1tuBI0Hcp++ tLgBk1EJfYlQvXDvp/mgcH13JRTqORO9rlUkbzHPe3WbUZI+pNEl5WrCnLXFETlXWECPS0xWDZqY FchugfGVBlFKkEXLEvKDhESYilfDRZDdMx4pEENB+UY/rBZxatR5LBCrwvqsbu1M3hTCK1gOO1wu 8kys5s4PtU7TA1igtGl23knO26hSBowG02bB+xfI3Im8jaBPITG3FFeGFAIePE7HL7ZMyae2Oalu trt7id1OPJGms5YoH5qN3bxYaCg4FKzwquyvBqON4ctsgM1bLqt3g2mv+ufRNKP9i8RJUXJItcHN PC82eMPQQ3bc1ovgnZrnc0qH8sLFe4MDVqnTUI2rklP6SbRGE30dmYhLMlCrXDarxXOVa2dJNLQf SFtIubcpPRWlzzGoMKM7O+Y3xUZjFQAIc4WzxHY/SlUxS+Q3ZyGknmxkW1deTmNA7ZKGahBnsahl cheRiS5UGMQUFeLL1aIcJbNuWbSnc0Xc4Vj2ziFIcjDB6gpIYvbJJz+ULcDMIO1qh1j+2Z8/ezY5 TqMhtvH+ar+rN0V3gyvvCkXxS2zudju/jrnJM6yWuIHFPl4sHlspd5XGlmdESYKbNygkih1aI5gZ 4Rr0M1hMb9Y/mAKdu9o31xTc/wcvPnnxwx/GRcir6m5dX4qjHzbBqggO7Y8hlAM1asAARzliEb2w RYyWX1Lc3Ri/bUkYUZWZmhZZBvqr8vk0DpimHBULyQQ7Gy6XPDLAQ6qGCzT41EqmAbXM0uZh4rLM lRdmSVxiipO7z1sM+IzB7ZIrTAbYqm3FqFfYKabWVp3bubUvFCvbbqsmS7vzdMSXMZoelTDRHtu5 IH1cpsElH4p2BMXjS28Ru0LDU0QeoQL77RrzpkNj1nTqBmOteyrXYrVpKSGqiV4HvB8DO0ZZHtK0 wZax6hkTqorzOsGyy7EqZvOi3QAJRJTtJ6jvual7vLJVt3tugFPlzife7Mr50769qZ5ikae79mn5 lE4OWq7dgr/97Rj7QoGyg4X77Yn9z20AcFb0buhAG79VGr1jK+netvuuOrqiXdleAxuRAJ8bcruu 5s+ACC3MTM12pqcwc8Y1Yy8CbgSO8Pk9GiK8ayBTbks1pev6DU0d/ipVr1KKenwbEIPUri+FKMoM NBWtE8cJdQMYuF7rqPjsoMFeJ9e3YwRpi34217dFX+0kWHvmjsldq6OSAe2oyVOaw1kMfcdjgbMc 1PdHkGPyfuXE6YhkfNeRIh2wkvDY0oK92t1ThiPWs8Y7lrA0XMqESnfXiUACFog+88FSDDKphsPB kn21TWdJqF8GaI/IUVpucmYxfZzxcPrHmeoPvmJ78KG3sfchQ2V/P/+1xXqbw8AIFL8O5fbuq3f7 Cq8oAeI0hjyD/IokSfF56ieHZeU+NkC58DBnEDtNSa48/KqbIctG7+LjcrUCBCwWEBc5QxPvOQWE Cw9HIt6Ho93vjnQ/AOV+B4R7CN12lRf9gPZSmzkYKMWpzADuxLrejIU5v69c1EAgUG5oszRPLMma rh9z8GC5i+z45JOVHpVDsRgJfL0DDjefyvD8y+VmmsDps7NYJlvdhBzZwUZcI89pmp494Xaf4wXk /BiJQm0Se6dDVfvmcmxeGjfFUZuMLI6oh4ehPKJ0PsmOMkIiCh3KkFvHskQ6SNymiYJzze80jaPm weEdahJTmhnaflrPz4ZGrtfSoXDDvSqQGSSAcfBBunewUSiUf8BCDNN+Qo8xBsAdtsmFYBA9QbHw yCYhiZcd0cH2Ots9umPQhCiT0WaTpFgtRdnNUVOijALHvyFCwLboxXOdehUvjeHwyfkLQ+tTEUln QyRQLpQhPuFs3QMqZU8pgtxBiC5srZzR9CsCa6M2S826tYy7di3BcafsYWGcPvD5mT0WXlFUsWYp jB5Iva+bwbo1JStER5aMUvNxB/nJ81nC/8WdRBRXUPfQtKp1Wp8NMELWbHXRoYIyQV3wyfOBE+aG UaS4Nh1p86Xq3A99kVAUFvHYDkzqY7qSRwhrIP3uG+3OwY4DFWUV1KqqIsTgXrfp0wimM4V06K2n xJqFQ4RC8yHhV9FHfZsXGxjfkCcIZNvJyGvo0JOG+I4amjiOZRkDTVWM/SM1AWMFNGYt0i4dQAcN lcUUyqg08NxUsO5D/AegJU+hl3i2NJUQXm7v1ZuFcBZtt4uZ1bC8paxFvhIR0Qz9Tvr6nDWcmIla MpnxuDF3OuZrdIEW+BNdC/sbUcjaF3swzbt7g4BVGBtMCsu2JZ0yHEvnwxyYzQmN+CbREnmaQC9b 7FW9We+7jYIgogIhjYunkVeVB7K6C5HTpTzPVZ1e3iSWHyVQqGIa8TBTaY9x8/bNuuo295SujPT2 bDwczuJO1mTKfmk8tnb1zVh/lC2MNUZCabGCTkWIR+1Qh9SFrZnd3gs8K0cfTEQFgBg1TWBxpr8o 8lCFwu7QciuXZmYJ+aXKrxM8UYyi9tstgfGQLQEXcfE8NCJIr5bBIQIK2itKSmtGo4jzUzJuLPH9 BdfxMmhs70nnWK2d1RrTcLABaJVt82FzrOtheZQTZ+eIwpbXjODcO3EpC0Nwk1tZdXvnLYtUjZct YIUJc+dATDDttCz5QX/R5wP0hhq1PRPvtIdllseEB6vhKEjEtuhuRv0caG4IePQw3RlbVj0EIBcO /ONKiFLrca3T8kDfU0kT4XqySZ/WkNb7m60yVWJ6v/O6CZw7t/Xq2uCluoEx0djQ4QFxiT0wT2V/ O6qyHzWYca8FDlDGdkHDe7g+/eba0N6PIjKCqNT/nb6IhXkgNfFFUAdGgVNIITvs+to6tMjLkj64 PTQi3pJtHhCSrRk632Hmoa/LXakYm1ufsaGCVMRsUOBOm56ThhabiKZws50k6v78flf1GTaZH6PR NU4NmHy07xOqPz1gWwy7xWtwQ70+fJy0kLgq7FBApR6gaJCqdoe7Vo9wRpd6LrVCtGpWLYqV2aAN 68aJ5RnG45BL6+4wj4XzJaMdAK3ApYzTv6qhaNQ8cfyBuAiXOSx+6ioWUvTFQylgDywf8QB4doyP I6eNpyMdj7Gr3Qxf/vLV6zcxSQwv5yJTva5J0Ups11NoUDDB2s7gurtCKvNUgLqItIaKgk0J56pW /mnExSAKiQHwgTnHY6hEvXKEyhyjBuGi7LRWsqR/IoiNUDk7IibZuU5srLI3G6U3rlJe4BTu273o bfBqi29PJG0kXU5OfStko9lNzlvcrXTyXds5ZVhBMopuPY0FtBfRWGgGKg6UEXuTxcnE69iY6RDD sVWEMc31AY4Nz5IkIg7AuKXfGFG2Fx6d78lHOYXXqpXZiOc+3XF05C9bhj1qIJvfy0g240Ppq50R eGYs/MTEaCgXEXrY6UMJzUwoiTpSO6mSG3VLmZUXOjdQjFuc9tw51sHO0LVBvFHxseXyahxPJeQU qgIp3gPaTk3P+oboukJ5FLHnkLSuew7jBh9iD/dYNdBZ4MPD6cQe1miGKkBuOYwgpTH1qy9/8enP fh+9STxFhI3c9GtdFow4glsXAy3/uJb9VC2v5hZTkPreya6pf7MOb/UcdW9txCXL9O7cYduwWmxQ 4rc03rdX9epKGSd7SiFv39LqiyHJ30xC6eOcjmNHszxGEVGuiEF8sAqidFUQh3LgcpI4SYPr6Mit JvpdpAVbU8OmXeyp6tUdcTXqrw+M2utte7+9vtTLB/jvmoIcx1CXJYpghRTFwdV1eVlpIwbm9Cad kY3OXMrFzRfkOS8/XPd5bEM3gFsz8cy/AuT7LdDVdS+Q1O/Qr13DU9noK+LF9j5QPt5eAZUzxkPE cfe7q7Y5YQ81jDLhclXfmEgxpK5OZNHoxgB5aCE6xjA3yL8M8AlSxYsCj1MVPlfpR8iUmXUY2qGv OKRK6Crvrl1ULnF44QP6Brz9uK+GpJu6NyuTSbNa+XRsxj13VMQtpdYuIfdBIx26nKvXj1t42EQU 7uZGjvOO8SaKcogs+6g3njc8r2dzzuH0Ij0Fec0+f66KWWxGmYt/kWVPvi/xG+DN6bMzL8e3RMyS LsStQxWfAl4PIpSx4auheLLPoIBDotCd1hgxRi+yb/EQcPJG9yo7mzDg2JPalOyPLlA3u+oSpJta kTKQ20l6rXpqpe1PlGGWmvAEH+8aOwyDeJaDN9bDq4k8RfdmYjRcEU3kcZfc7HvCAGWjJkEBe6id /MNut8cVoyPUmrxl1f10V6Q/ppYo5Dwbkb5fqPde04aZyG8CvT6WsugF35UknMytoYBH6FZF6PH3 UfpRuG3m0gTHo4noT4DfoQhMar9iwVJ7Nkk8ISJATp030Ky8pPtRsJfb/e4pdguD3W9pg+CMcJl+ FJAsWToKP4bD/PKrl1++8VTb6uACpyuHltdsOnM1HQPEJFy8+SSOQ5nQaOKfR+iLkolxVoM0xoGC sQuUHraT9o0gG6rAoIjrNq7qGB8WO3zJ6VlE64+ObrZxt7rbLdJUXWg/YhCqBXaZ8320Btxjenaq xG/okUQO9IrSDTjRc/vbdhvx3lZbCq0UU2NhPOrOxSPkrRWf1q9A0p8Js3RTXleIbMUSW/0+d9dV 6Y3NiOFwyN8uuDkgFb2dBzZi3a6Wy/QsgGPHTuZsBED/dNCYhR0/Sm6Bq6OLAnSe0Zdmd0UuOj2+ usHUWkM+RlSZ7mDSVm1Rvae2AYNC71o42qtrkuqodX/eZHddUOBldYM7gifxxenJJ/Mz7CtLYU4r ygmyvW9j7rtOu1R37nvMkVVJ3loR1P8njNKGktexzf7PZ5goBfm6gWGbxnW0g2oLdZwNiivc3U39 /sFNHZz6i7NJTGXGB1wFg5DygxYHKh27wq+BVVqQZOKTOLyN6PtGL9YbunQqHT7QXZxA9aqkW3or YGXam0SPfN2isNNX+3UrwtHA7R4n3CrH/0ZOSa1BFAVowI7euLSZU3+CvIvHRwiwjCUYM5Dvyzts j06BMRQrYMAYU20O70Bcfx6BAKNNvO9xnJYe/T3q0beoqF22210/pBjAONMc0ZG8ALGRPcW1wTA4 GJqCHVaUQWzmXVeqJIxqih2n4jFO0YIRT3FroXSM7JOysAG/oLn3unlPDJS6YSAxbc1YeoyfF+em aPj9/ly3y7favmbPpq9fff3S9o9+jwBRbnFPKSPYe4v71Wt2mvL68L0E9zGwZPTYaRj7xmekHj/V 8IKIjfxuqCNvXyynRuwLiS02zgHFVhTFZ9+g7rdyL/6qArdlvfOMYBHLIjcehFmg3Y+aBvVoDhoH SUrZIVJ9Fiod4kOB+UWQo5l4dDjw7pjhOIyzsnitbtYIiwWj2a6iMIg7W5J5SA5Gd6dm4X1seu8c TnLvpigUjCZZsupGtGalE4Xhot03a1tjJkp4PheucG75Yn396Zu/dL2TSaAmqYhHYPPr7u7ttGij jiWcaHHZI5qlroj0rJwr0bGh7Fzl2apsRNtFM5iJRqzX8Xqd0mhgmAN2qAktwOadl+jxhy2owBgY xIYMlRy6JzZ/jDqNse2wCpZf3V9C4UEZzPXhjSiotgySJgJn3F3voNlMm8U+7KIye9pqwgnDrpr3 ddc2pymqcNMzdb3j36dROSNNWW/RSEuU8alwHw4QQ9pklaYudkdhONIO7Q/5lpNDrB7y6//l9ZuX P//mq6/epGdDwXaGOZDopbVxLwi1fKddVQCZyNLHr2ls38DYHqcza6SiUxvHCKyFpXAX3PRZbFHK NbI6KXHYgIDoEzA6fZ6XuxRYKfIPhGI3bVf95Jg78SNgAKfdgME8vk88pAzGlE/imqUBSCDP8vUa WQUoxC0NLHVwYO5yI4VSBD5W/2CORGox2swgUB174LzygvHmB1G9MPVSPtvm86Oow6AqeRQJjHp/ fPrZZy9fj9zPsY+AHZxejh5SHXR1RjHsptpdoVKWn+bufcOrFsPtdxTAZj5sPb3zDvFffvXzl9bx HT22Xt0p1v38m1e/eDlF9shvlUHZnxsMLxO/RmvU3gytNzLLRwrjPyJSWG4kfJnW+mFMEARvPywb HwW3DYlht4TXW8QW3pp5di9uJwVuuEJ+FMijsUg5y5MJLw3FOPBHCb/2/R6dprRLj+04GPektM6c ErCkRWSb8Dv5HHEz9jS8RbRfuV6I+JQ5GXyHXjJjPMzXFg/jhMwEfr3qr8i+e8TSoMUOZE61Du2+ I65tgKZLcguZuMOo8pAHHA7kJQWRKpw9zmOQGFeT6/WWtaILyAtkNKV9FWhJ3nsLL0/tNS+vqyVH 5YU+5JQCjeqqi/puAYIX2U5OUndDZpRFffHxGGMLcHK9RHM0SwHP//zFD589y+ck4e9u22Rd3vex bQV55N3edjRgv1IVOviSdgl176UT3MxVWJV39c3+BvgztO2iQCi10c7T9/sb5jf5gpoWEMsLbJin XoRZqKsthUvrrMFxTB97eBsy2+PYMhgEPDzBii6tVJwvR3YZvmzy4fDkxMGjBAW4x1nkwgh5L2MB WksVnnm/49i+xINk7LVHXLkYv3iNcmfAxBw3KuBZVH8KDZ07eRSlnQcEVzRpRrLz5hRv06k2zgbD Khof3BFeb+K6K+53vCIKkmRlBNhIm0A5XdTFKCcpIw7IZOIo+x204ttGOBgLMipzH3ShrwRv406G WELZe3UjKGai5ja8rY8aCKDgqFXFGRTmIOAfM6zpMXmPWItPkASoN45wo1u7Z1BWE2PnVV5IyvXd Sa9Pnue/L5fWuPuqpgLi4h5pqGa8c1OVDbmwAYKhG2h7pj/lJQiQsZXWgLCQ9Zw/QC1noIjrTo7i D9nrwYbNPfrdIg2/5qtUMhlnu9gLz8NSSblzYJxXixI92HO0kL47PXwjGm/cbHG4oJF4osTN/ZYC s3PoQgzlG0jDKumwahQkHuveS8wmoEo692MIrrC3o2736ybkysFAZUS5AONLXrelqhU7pI/YJANH +zrLk77e7SWHM90SUB5HerE5s1EMtDm+G1agBZWgere1oHUGdGkGULjk9Yy1VPfXFO2jqoiXuqrg XDosFPzXo7BedgD4X1CQxdu4Dt8flYI1cS+iOWZ1AQfothKqHGlIe4SSprijS5xNDcydlWaLW8yL gUvUCopQi0g7NkZajidFGh4kFOERYX0foG/gJCrQ9iVe+OiyCEjlzsmGTa3Iv9JiTiYeAzP/Y5AU VrjDsx8tFFOUnNBwBkRfCn5KXMQwkjhKjN9h1MvNhXK5lguag6UxDqbe1OPqiDDv8LqoyTjvs92L k91zjF45jBOHcDhtaH9dbx1Gk+3k2Fq1Pk7AHwY3BXJ87Z7OHp80ZPSAsPX63HEM76ZN0s1F+vAt EJ9YOiAcInJs6CDcn7dlt6YMW91+uzsQNGOkrTnhDhg62cXJh8ZZl1nyNxxOgH6hEXxcETLxmBzK dmFVClYBg9KLV4Gtf3j7+uU36ZmN4qCl/d0swSjGm+O0HXEWari/Lz9FTQr2FYv2eVAfarWcCgOc mvXou1UiFtM9aUUMIeRI293qdA5/VBSak5RMVvAJf1XTw8uIjuwNXWFdO/neZdRfvY4M2kGmsRaF BchgWLMk2m4mDc+8OPA5wpX7SEJTfPxiMgw0SrZVHGUgdvuCuv9eZdy1L0vrwc8lC5gEboS2ONIn DPWqRBd9ONOXSNbJRkaFL3DbaHP80JHOel3IJlKujGMurB6KMUmA8B3DTMZ9eWmowpsdEVSSs39Y 94uCYjRWfYWQMszafseWLUf8rIKUvFTm9NkZWn8226uSs9nJQ07Sl8YvX1GAgIntjcU+Xzp2yXQ5 xbBLeSzuMme+krw32DVS63zy7r9++68wCRuKt+WuWFdbtBETPX/3z9/+HyZdGxTatJfFstzWt2XX ZNPnxXPobUqZEamuqod3cACro8BEuaVQo9KsOQfPOXGMEnqzmFKCOLyv/L7aLKbQ9Pb6EpN66aaM 0UGeTN79N2//FAdct4VyqHn3L97+W1RZ1A16RAJBRYHmqtpskVtFbcS7f/n2n+mMdrrWv3pLio59 wxHsSA4RJSyMhCv+t2//xRaPx67YbvaXdVOI7uvdv37z21eUEQ9d9OtVgmUSeRlkxpt8xDHkUP+7 2QDtVnchoFIPLwFxXF5idhbxhUC/ZP2aMmKYfdDf8K36Ran27nsGSH61LNfrllK7cjJKZf7WucPo YaFyo2TTy6qpunKDewpcI/muIo/WV3rA1Jq6mszJvqxe0pM7NDKdnCCLelF3/Q5+llR1Me13GIYZ 1WTTmboUxgEvAm0hnsHFVDcyDQrgznIBCfyOmhe8EobFOd42BS+hjMC0iMVUrO2RQZ8A84lFYbCA Zsv3ZbeYwtEIu3WmArPgaMp1s5vOZMzSkjXDZ2ODZ80ijxrZX0nc2ePgOWB1oRLcDW6awBNumgEt Z4ecuUoZlLJSM7SBTcIpWRWsFeFJkKwmBRhWZ+KKyGBMYtiNt/ZmONOTE47OPTVgwgbfqbUVfBfA 65nrsZiy3ksMSX2wshtY+vqE4kZV67wYW47mAgbKN17VhNUjaxtJu21ytqqxUaHYomzakhy8Lxhz 3Ke9k6/DRM1E4ergHq+r8/0ltlZfWt1NCeMoLQCVuVRnlgvvu3IcGlAdi2K8nrx64E99aMrOzCkR WMSwYqKF04gBt9CULUylvU+VgClkC53dMtnYBf14Be0v8M8s+Uwgs1vob2ZgX6B99gvSAX2uxrHQ 3yzdjD0MtWpVxt9kMEA4dpwUDB9SGCf6wiphWOJz9Bu6VzSf3+L2Uaz0zMJkFlWXUrwXhSAONIg4 C7O6wTgtFeXsdQelLgUzwVHvCiroLq5cMlmaA5IJmVIcojk5C0XBCvOQylhhhpSWzZQApF+jR4zw HVd4EcJuiWaKT73uCqqF2XPl03rljTozTRd6t1ThJcfhplZkJRZu7zPuYkF/w6aAr1my/shaJPN1 Yb46Sb1RTe8sNYA2feIubNp26y00OQU7iyLbbyHZ4DYmdaL0Mjh+vojj7xKvpcVrwk976QtviIA3 di1Uz7AgrYsXYII7YOUi0IVt7JqIKqUFcwrW5NccXzNJ0KD2WSXhsc+f0vu44TekovJNMcdO4V16 RT6QiootNb2h60DbaEPOT1hzCcgGEuBmv65gx5zO5IxLwzrHuSltbYnVMAYgRs+mU99nxbjEmCbO nBVUujm7ORdpyGQ1AlapfFgfOreT3cntwY7cjVGhyMZAwG1WRAvlwTAtVu97WDxbwfFIrh0g4mNk ZVE3QvooxlISlX5/zppiNqzGwkeqy6AGrJfw5qKPuAdJJiaUl7Ayt6GuzIQWzVBCjCQcMqpeWevP o0u4kJV0zz4nX8eTRJnZ6Ug5uJqOJBfj3O2TyeQR2Ur4/qC5O3Zzg0QcF3Py8pev3iy/+muAuWf8 /c3L129ef/Hpq5+9/JzIBT189eWbl9988/brN/TwhfXwy09/Bm+++gYef8yPv/zqL7+CJig3ukqN LVTEyY6NCevJ4uJmAbSOeqCX88NIAIgCh6+uHEo1wwU4huLlkt3TydE+FV/cPuVsNbDIHw8m1naQ hb7t41Hr2EsR6WCxSxC+jFLd5AEHlpiXZkrOD8ibsheZF+WQmF+RN3CnnLcGE8I7V4SXwVj09zOb ANG8xF+PrCYAs7fVVVfZtx/tM09G9EgKcG8ccVyOF0QcRO7UyYM+FSkB6slQrdMu4Q93APyskCUi N1AWupQrqEqowgWBo5DoOBg89/Qslm/MWfQneBQ827RwVPaGG4StRLXAiKgqiujr9fPjhSowEGDJ 2WwUqLakhGBR7/Fay3h0+XbkrprVaS5cqL3RvEykHYnvhe3LI5EYvdOJz9G1e0sHTEn81K97Mo8C YkRjaBvZIwkVpOUxu+5eDCsLo4dz3YbseayWzevI2VWHgn4swvs7kZrDPPNx9YcYQa+2Ns2QfPG2 h5lG9NauTeM4mwiUQhrD6jMkL8VLqgdjeMW0JwC5yDSupZOlRt+ZNLyQz0g7ISRY1Gkydl/pwwft wgqgFBAHlpWqnD14sIpq+shBGkKLkXUXn526X0JTsRsm9xggCi9tiBZ6qoBinqzKPVqhXm/3nEDI NPT9XzVTy5BrX/mzhhzFUfNjZmlxEZNDUCCwywJS5rVuwHqWmG4WXrdGMM8nh475vhk+6HaUGNO6 YmMM7Zz/HnkFQHlsiUFnVvqe2SvlhlLj3TA8Kzr/uyz+ukLIhhLA7AfJKUZd/00IBqtr4698p6mB 4igKw77ycBbWhGYRHLZQ0rIl+3oZJhna2q0SWTsKgItezTXA+FKvDncyVrHQsRXJA87sGMYupxSo uEi8bfAtjFM0nc+nVpzhJenNsA6Wtp3N9QvdGCeRGPEi1mPgG/IcWJwEFYc9t2Sdem078a2ujIVZ Yh5RpI+7p/dP/3Y+xzaf84exD9JpJjKLcc5Q8KKIpKbufH4/nw/V9rxESRkXdRE9L5VZxYLKPEz7 AswYLqRc7cDFtgtRfAZsindA5VqxLlrEktKOx5zwqGA2JYsM1qWLXPPkMbJNLIpZKjx9QC3Am/hi 4vcXqpy66Ck+CCgvCrAeOSpq77G+xWYrdikNR3CiTb5biSbM3blTUOseDkt2QN0+D7ChrvwkUalp zib2vYFaxcVBkS4O7yDoUbR5CZxjpZamMXixe3n3sXDBiMUg9SvkKgHp3RmUReXwANFLTgN/JxUp XBF8ngUt0OepnYBCRbk4vSvoTOoOuAq1qu/aZ/nUvsqxsdMum3DdAZoSWJUK81jIcjXsGLRZq2Ml v4nExuQy0s0kdE7DKAM4jafT+G0sO+KStv5yvRnWyt1Vs2ImRYPkGVQqMTts8Dm/1wBUr+PgI+kC 8D4ZbXdvbmsi+qrXLgCZnTSbCGUsTEO76eRUMSFL0qcUjZkjl/hBpfjpHOOZ6BKqYXtZVFg9VA9y ZFwcMI09Ow2J1RnrA3qbrvgqal/sFqW2l9BBJUrx6HhkFjokokPYDrv8qIOsuzlyagMpo3AaSl1J tS+rhlXthE6ijtdftpThYigYRQSprkoKYcKDEkyf4IRnYZxv6t0WcPX0JASUwF44MTneqsCg+s8q S00MxMOKt4P/7usKyPjdWPviO6WAdBIN5uMgQHtj4127uUgYm3s84Sujl4x41wzHjeMZYZPHOZmH ydOjw9G2OxeOiGbUEXMPC/MaeBeNE0WMl3mriJPTADlPKd24KKzG2lFRrtRKT0mzVTBrBkiWPPp7 XrIpg1oY621boMdXtf6ABddQZnod9nuMwdv43WS+uLMOtDkfPIRRh0+ZsRDoxUJ7IylGwAl/NLwo wzKRjeTuDuC0Y1dveM20VW7on+S90AGdgB+ZiyZXmVNeqYORJ6uyr77jfE855syTP+bED2H/g1fp fRxdrYcbGUQRcrb5Y9HFQqC55EjGGwmx8JA+LJZJ6GOU6f4wFB0OBG3W2I3iPsiOG2KxCNoOccJ/ 9Lj6AK7Fk9PvzxXtPITN3INmtpNbyB+GhR8EQqzHUvCotZ/SJTHcCLFrNlQIhy3xTiirDCU4Vy+Y 9SfOeyK8vCiwrEwH3uVxVPD7njt2yHcrrmR9oc2VbcNqBZSvYWVrlADoEpPE0PRjYIrqx3QkOhK6 Fa4i0FkRW4qJreK46FUmxiHVGjLKqFyzOW6jLduSyzG1gfIEf0XfWyisb2NqIJDXwIjNnXQK24Jn rqIDKPEQPfF4R3SwZXuNyBx+IaoMblui+WyvL1mPsQ1iXnKsy+it30NBKXioYeYSJyiEixJMMGAU /U1VAiJ3kbkSJ1FUGiPb5k3ZFy0FkkD4X8Jx+Lpr7+4HFbXeSePYmHh+FwaZcTWxHJqabjQdER3F tXrqh7ZkCuC67nuEAM8uO+CzEpjslHpAtsZ85mVgJd/8crNZqiO5xFJ9Fkk2QltFqnATCtRqHWep GpFi1hCYhYrG7DODL7acJYprWxlPgjgD4YjVNQN0d9t2LUi+u3vb1R3fXmDyEE8GVjw0tNzV1XtE So/pyiG1wPHT+CRI2i2ckj+bwPH8RfEM/V33HG/LIVGP2Y3CvX8+NYYB9mJg82s0W67aX5f02Rur TodahgudlU6j73XlulKIl3glPhSElDYbKtir+4+WFwCQBglepykuki8ZOkdBVPceZ8kr0jOUFMgD sQ1wlsQWUnaCweNFyy3uLOziKSYA9UMbADwl+aM5oHWJxkDcrU4CSoFbTV4CJ/wCw6qReCd2e9b1 T2NWIMB262uDgde43xY5mIhNh/dh1NyT6OD2yjTtN2jvzRWpfTk4OCVibi+KEX8O29+/M9BF3c2S 1LxOOU5ZPjgrzrgq0Q8xWhn5AvYq1HS1fiqN4VUGOFjeqJS+NRwDvwn6p1q1OHNqhJ1F7EHKVQPK /UZv9JxEhd/xWnKsTc6AaqOQKb8QvdxndDrCQvRcynyxb8zSusXUK1WyjvaIj6UEnpxICXw8zQ+n y6gvXGrg+HTCupJLNiyrn9bT1rv+CBAWYMTHz+5+jFjQzR4C33All8swoIrdMXRF2c1lA1FLy0PN D/q6qQH83jpX0Y8SpjmM6wA2KvLRJ7xkL2z1TmMkuo0equosmYRKzAhrHnM9KpqQBXkAasd6hDzg ryYxLxwlvXMN+qVN7ibtG78VnGRNrqkGJ2ddy6JsOaoVu/pV2V8N5mjBl1mmBzmzx+RlfNpvw6R2 vbULO2Dm1u1tM15qeVPdtGgPJSZCDKkABNz7hRw9q3p1p16jI9SyultOMfSaPDM6TfaH8jirmVXd x0uYpVgqDUYosaN5dhXxeJlUIiOl+v7c+v7izOlDubm7U40Dnjt0XXYsJRTiObVqWSzDkx4/hdk9 7BHkqaj1ssr1OXRDgYLLOuZIM7Tw0ko+0nkfnTqqSvvxRM/GIDiS9Ait7hhyCJgln0HoMeWBZJua eSFmy45irhB7SSJlexHwV45BCv0EyTRyNhm9soo+FhtbWa/1mio7jgWReIcesIV6FysSRhOxLHWq 4jFRSNSCuetLCoABDBJYUQmDWGZa14bMQ1FeNE74OZXba+Fmf+AFVC+V1d3C5/LKb85tUr4V8Xw1 KsqXna9m34CwUa6q8xJEYkkZrH6Hy6BfWW0QuRfYX+ps3eL7hSb8+03gO6ITVDoXOy72mw314AdB xhamm7a5nI7QaOVtpsdoLILuLIOCVq4OVjmzW4kqB/uJc8RML5SAEo4XJWzFTcLgxyxGZHkktE+9 +4kzZ5xJ3M8kviK7c66CsjiMqttNY0GZqYQqcAT46xruksoee9POEO+i5Et+KgejMMMgbkm/JF5t 7nzM28MN0a7TX6HQNqBhCgkP8Dy/trbLLN4H0aQRD9WhUpGqTFwcFc/cvUil/I12V3uSJDpy+Njc J0h2ACIsGXTq+P9Ll6wn8RWUalxlI7dwg7uZMyv9mY7jD3BVXgpGNvmc4lZ1Qx2wBUUg9Gwztrrz HUhFKcI07yRAWRTBFTadMJdiIdi9Ule6q7WYrEsAZThwO1tWUDrr8/ullbLc4xycaJUc6t5xl2Bt K9NRhHc6XC7BwklAX+Y+GGIFZNH0NgeHUYoX40Y2hVi5sJ050YCmixCDiUnCPwxhxeWDfNpxN1qa hA1feYAO4ZCouuTHH022DNwIFCpEqRt3Hg1wvIfdBfXkHgM8ApTkIo3KF7wMi+HKWWOImVPKFacu 3W92dK0fWWjrWGT5cCpEl+1Ol1rET2eOsiH/EBIYcLlKFZBHvZUsNYJr4bDpk/5erPbss7aIKvWU iGfVtSpHwkzZnTRuL3JTju/0YZSHe8eniznwaG259JaPcAWM9r54bZCwMYMNaq95th+mYNOKGte4 4S9gvwcoy6xxSeIWHd4i8wzrs0iGcTUoezz5gN5Idl4tCAavs3of1nSqltXlEmbLOS224HwubLyV w3YZBalLitEshOLpaaUIf47hCHZkFRnKZu14HshVpCz97BevMZLFcl12K7yAlP4Gvlz9Ls0PkqdN 6PCl7mtaq6njqfVo+ovkzuyM95dyrc6i5wcLHsp+ZqFYKD5LMux9xpmm86Fga8rjq/MzeI17lWxU yP6Y/Lexl09mNbSVRvtYDF8UXti3hW3uzJ1V6NhlAUrUaBZZf8oC5G0COXn4QHdEUxTG1GspVND1 kcR5/l7iVnodPiKW75bC9daYCLvGAONCftzgmy6weh4/fRSY7tQp2cQBQKygd5Z+jLc4U49iCaaC 2q53MNU2OHUoUYIGvrs8spSbUXWEu81RqLTpcsygbyBk4WB/nm7Yk7or8fCO3Jvd0d7kti7wcL7Q UNoBizDNiuR4J+bQyrfOtx0A3i5BtFKqKo4FRkYIfb+Boq0ALom22BfGuCoQ5UgVwluqO9FxXYWF OlU6PYzN9N+9/UdI7knUePdv3ryaUDymiUhA8LhpTTZWZT3Dab36Co0xbU+cWF9MKMSSRFLq7+FY YTglqq8WUuQdDp+HUoDNoB6RU3v6uC9I046urUlU266uPx+WI4/V0x+qR+kID1abJuIarnNXcbJ4 NB0fzmH0iCRuU+Ogq1l+MMk4Hubp6eP+TF0IefjEPnhOoTQxmSxv64aABRpDExgVeTFnAJIMqtzm x7GHz/9cP6Uo1fz0hd3Am89ffSOP/+zPo89/oJ9S+o4ZBfBUmSDPMQtD95PJ7xxo/nmJiUYCO/Wm /Nt6c4/6nvfkxqNlfOcEVSDT6KScyddfvX71Szkw+tJLiUGJLtAwiZ7ynLGNiqSSxhbEnuTTzQY4 2dWVUWBYDO65jNY7da5agoMtLviT03RQLy9WYk38ze8mx3uLVE1rmSKoId+pY7UxnvmX6OEDZaiv DCrnA4pxycC16WNZHdy8KFaDImc37ViCFEdctKZ+CvWOzJMCYxBDDQMRYVS6gIs+HRWuwfRtc920 t81LLPB4jccOn/vu/1SRFgijo2WMJTNpH8g4R88cOGK/SQ0WTOepisyaDhxInVB1Tjdmdh2Vpl34 XeSqb7A2PF0ab2xB9TsrxbiVc0MEPaCLnPvQ9qjxco6jfrXUJJSUU6xWYj0ZUCl9VRlZLGBiNsCz nW8qP0KGFkuv4GhSoAzHHXcINLDnzB+jDxm0RsfePvePZABOs4T0MyBlnCecAn7A+CRmXqWHkFqC KIaymTpPY8sSurRTg/CGOihcVDXovR7aoGV8dpDgfCRgf/IlgL3BTL6ftHo5kO607FgmBbCQDmfI t8CbyxbVa+yyoILdhtcyhhEVfj3GrDTo0z/ctk0NT+nLcAqO8WRrvIIRPR89x2w4wFU95jT2COKG E0qYkB8EEw5GVdkUhKliPnn33/uBP1flFk5T9e7fvvm//g0H/uQXouSQgHtIDmFTTjgcKCVlfCpJ JrkByvFera7Kpu5ZUz359lt4BWfk228JN9DPizX8Miiju9zjYQNeNR4NtP39hP4cjOx5IrP3I3oe jpHIelAdLnN11dYrrMZf+sVpeoHKzBTmjx9w6s/8kIp6Pe0VxFbnfPHwIrlYJ5mMI/8ttPRbIGLD k+mDuKSUlWs64+xci2nTmviXPO8gzCPph1d7FpP08iy4X9oK7HGPJwNdvGcJf9cRobadxWdQgRRt V/jC8cTy8CO+h6LQdi9uY4Gsob2XoYSwHW2zI8tzk/xtvc1OpzAWdKCE8UzPvJGZIIZYxScn264w XWfTz3jWawR0vrHn91l0QJehzzyfHBFpcTwsk/T2c36e5eg+x4+kaOp2EgkkId2UW6hhwri5/aGx mx5kYfOWXZvaQP08AuILKTl3bvHNsBR2Ey1bbNstSsgWQYQ3eDGhomRNypn0M7tp8ulB/wbFgvgO O0amxuj9h4qEHrtOiX7fb9W1z4hMOyUxXBkpnd0Z0Iz7Ht3ekvjcOl4DUbnN/PoXVj5vlf7sjQo+ Stpp6w50dSvF67ZY77k94qw5l+9i+vbNFyc/tK4HXzhBwG2XLWjKGyFCeHNZDykvuNc31d3u1VeZ lwNR5q3urdJiuAdROZ6DyHuxnsaV2NTB691atuCLzzPg1AeCK+NpX8ja26ubk8Ij+mYSF4BJ+WkN D9DuceM7fnR6ZYPRmTdHjg5QenRw+nxlo8pYYjlMxrBsumdxKEKSmCORvXS3W+XDtELRKFtRgH7t 8KA+chECyzcSomVH5hLl6fzWljp4cYci4JRbX2pqyAE0Y0a9g6yd7goBehjUtceQIn2ok0vh8KYU nhJE0yL5Nd0uii8LwaN/FvntxMOSMiu6TqcCHbhX8HSrmuOVrbTCrHKlwNDpEfCaYhenTHN9AYca 4FeSLxeD+YswsFrtb/Yb1GxKiZYvDpCdPqYMcCaXBQDpvh7GQJ6JeKkhPs0PHRK5B8U9Ac+1wRwP 99aZobsDQ0FTaKl1WVvVwGQ1RkFIYaGm6pIa0+tCwYF94spt3I0p1ssp/zxj2m6Dhb/ajswE1F3T 7jFsI2wA0m/blZeJsbthdOvTMyDTYNYVcrjvAVyWyt0pyz9oWz3Y1+X8IT9kR9xFH7Ze6rNAayfc iJ9YbTM6MkpTWd2MtJ1Zxw6viT1J9PcxVbBd67lV6/lZ9CIWv43twChKsGPHek14bJiCk3Dfxch0 jw88xOZhJ1MGnUGkfnxIE89mZzcTwNTStDV0KnUR3u3woWdW1wy2FKHwwXr4harIcbEj7lCk8CRr PwvfKYsTIIxGFDrhgJSp0Qwgj9WSd8WS70Jbxzl2QD0GMroM3uWL2BpHPOYjTQ0ePC3geDXmIxOM bhpKONn4slB6nfpvq8OHWrcaxKGNXRbn1VkuyTZJFxqXM+MReAxlN3HqPBcZeBL44gyT2xHdLGJM Z4SFpM3IDmQp0piLI7O6dMHy74wqIEIr+HYwsq+5PRJwROGUmX3iSPJDDVqa8we155QKz814p84F l+84Ed0YQ24cztyo/6NQ5qcpiFzB+3sHVxxswYsg8cGwFokxO+Re+hCuJT6FIRBBFDKGOZgi4q+H 8VnHbcbougepGZijjge7OLANQW00J+Cv26uqIcFLgfd0ADKUTDKJiyxxDoW23Vp1WajlkikvjPXd 3iSsm06V0rVPKGJuT9d8OIwuqdN1RF2SEUkdoPxSbpLyfVlvSA3f71d4ZYH92t/XZVImStNOyeZk pfJvv7XlAQ7eaVzMv/02g4Kkf8CS5DXHTrxK99lAk1d4k490Er1rnpYlUKoZnnnmq0TywfW5WB+1 PHQ5eF31q67e0uWo57Q2L7wVUmPFO8LexHj0PL/erCJVw8VDUXN8+YokecWXv/cN7M7mXrHiW5Ba KYLpuq16YRTfY2ttj9o4aCAjcf6vSJzPxU1036v65K2vGA1KQF3ud+1NyUfqnnKiuqvusbWW6sCO KkD6DayMkiqstO6jqap1n/DopvkD9vGLz3NPHyolhwMSczGqE4Ql1lpRu5RRn9napWjkf7sVW/Q0 1TT/Fd5t9lCtMgDF8KzqQumuo6yc0kxZCggNRCNuX6ZtA3KWSZ60tFHVssVavvsf0JhHKQPV5SY6 Ot27//HNX6XsNTb5S/bbVzY39nPBYnQsWh1dQYLGwIFTnmMTz3fMMs9NKAXoEmosV2gA67VxGn1c 4STps4HYlwr/f8y9y3YcV5YoJntgr5vLva591133Try8QslmRQQZCAIg9Si0kiWKAlV0UyQXAbYk Q+hkIjMARCEzIxmRSQBVLY/9Mf4Ff4ZnnntkTzzx0Pt1nnEikaCkbqu7iIyIc/Z57bPP3vvsh5Be 52AXgAzCeNi1YWt7AFHDPaeKniaOPXuVUnJSzoo5xclXUpK0RgOGrXM6ni+nGdCHlQRSIIOGQUTv Af/Hy2myk0np/PD5q6ff/fD85cH/lPV/3t7e7t/7UhIuFWgwmF2WExW+FODlqzmG+0mi/jn81+cz Nkqjo73dY3vfSeWIavd0OKOhWpQhfVADcObOqYqnsTfm3mZ+t8bwwPe3vRM9e/LixTdPnv6jtTLc FvA0iUm7S6qQ+OmrF2+/f4kG5l9ui07LVQGxyx7SUcnLGzk9BnJ+jWaXJ9XZCi2Ai2XcRM1oXp5e o21nubQ3MXfkq+jRtifjSQe/3LZnWWbXnVSWOVszjblrsJ8rapgUeUM4f0aLgukodHFaXfJNKHR8 SJFgkmVxhUdOM85oB4kzxLy4xGja7I8XnU5XzfnAjpqALt9lyM/wlGM8GI6Alx8aQQsk+KPvH3Vi pmYc8kWlHrFFvGUM1qDDEX1r1Xf27qd672ragBlWl8trW/Eg3QIWim0Pj+Kfr3ZOju42szi6C9Ll RCwJJpT9qRkfp1F0v22SgVDarxnW9ixOBYeevDx4jiIrgywwBg8QZ3M88pR7vbs/AEBzSeNsjbZF adYME6rtyAi8wOOYhj4QQZCnmSY/sSMC43uyOIfptZVqbYWpQHatfqA6peTFS8UEZ2Uvevbqzf53 b169ffnt8Ic/Pz/cz9rmqhL5Paj3Sx7uZKkD5c3+t1nI6BU21KQDxK4H4rs3+/svQx05q4ti3gHk YQjIv7Q6die6LjAJZgeURx6Ub168DUwJ5gKbdgR9TB5+FoDR7gg6EK/qxbQLyuc3QJFJuhONr0dd c/KFB6NzhYHDX3Z15I+bAqHdFATyi1HAAPuERoaCiGxMiYTGb8CR0BCZPakO4fzLwK6GWUpggx/+ pAseHH47fPX28PXbw+Gfn7z89sU+tLy1s+N8p5wm9uddJ6qGkFhDTd1unMOmp+30XbEElvfP9Jj4 cNft024ITs8tyXg6IRLWcJ2ncPxV04KSwTCsNL807gU9f8ISU/8P0fbV9um2AX2gweHVvAYicDmU ReocNJK/BQnl5mB0D0InfQuqPu3wCPTK0TsVhY8d+oeTajgb1RerBbkxuenmFP9+SllQYybUcDy0 SLcb/AY/+yzL4f6b76Em0GGQomYncbsG5TW3z0QWNxrkC5L4LyBOSssAeqg8kOP5Mtby0qHwFz8Q Y+7apQ8tWk5pYE+mwDQOHm5jnJHJAMgyU8sBUFcheQOgkeHLGyRmA6B9QpEGQMKIrAyACjFtGAAt Cdf9htp9BO2+gXYfQbvfUbuPoN2fuN1HDzvrQruPoN3X3O4jaPcptvsI2v2B2n3U1S7SBHRnnCIr O4DGTuDwvhgAhHL+oaiXgy904CXkyXT+9UjZSWgLwk6PVcONqTpio2GsZNohL8JcmY4NwXC6MqWp rg0UG+dZytxsnmrqqRA3rCIKGfJ620ENKu4w31XfpXe5enYNTDygwyHr+Hyg0k9CbTJN4vJ6YtUP T/Nr9aHVvJJxCTD+8bx2V9PpWu7dKQ3DYDKCvHSQslgqA2HylV+5YuhdxNBssgPeM0T5Dflhw/62 XLnhu50rgMZk9x0t4ltMf+CyEXtxcRm+RxSfSPEzEGLVlf0gZEYk88O2EBwMM21dl19ccpDvNmBo Ul1Iun3gCh0xENRK8jwwA44r6cQPU5MFv8bnoxrKlUtNKjSaybM3l0ghNCIGyYSNpy7i9mx/VrR4 H00RxLJi5SG+owxMIAmPmghtZ/GvckmyapMyUsI4zielRHEcLUFynicIIo2+GkTtdjG8MQ61+6KU 7HIuR/NltBvdj3bvIUDYLdMUnvA3Ve+AzvXLvMjJrUvXl2lO773cGIj6rwXArhNt2dC2ot0OIFQr 6a6WRg8eRInblIuoL6NfCQCnkNCBPkb3opeu1zKu+gA9KiP6f7b/hzqCmnSWTdexoWbd1kxYx0p5 swpjsWGEOmrGkXTWsyMtIR2pgKY05XI1Yk0kO9xiPOyqmrFjLkY1WtYjDR3wmQJok67LhYZRSsvx agqlUCNUaA9k3gakujGApuVFEfWHUR/h2ZsQiBdFLWkWo7HeFKwqxKmUDhTI453q7WnvJrPf7tuD NybiztTutefyvp5Mo9ZxDzIsRm0IKTKEjLlsIWUhQtVOL+2piMyJm5mTPJTw0b7mPaEbHWR0koDv q4pzYM5fPDP9Q6YFWB1iapBtczVLsGg6v2uBwjZRtTvMk5X6msm6+FAWl3wrwzGkMC4tSEBAhc/K cSuKg2ZjlN4MOFbUZJI7GBpcfRU9pG/2ZGeoWBx3hvpsGKqsSpt/Iu7MX0BibdMNrGGtSEJN0Lr1 Lfdtn/rQYeeqI6yS5nOLvYziu00sMYkx5ip7STapdl0KuBebgH5zjcADvIb1cJhmQtbcxwzrG+r3 tND1A+r1RH4VwcuVwywP99vuIFt2d8JY3A7zb60z+JW6A3NvRe5EwxNkvz09wvaz7VZ5UfaYaqHd fnFJNlExynMdkYE3Uvqsg10XHwH6jZUH1tlDusfAs94eLOrx1sMluf32gEkheIu4NMG+PXn6j0DS fCXR9vYXaXuCb6cu+lc5QT6C1Hv90yPfu/V4Lb1WmEKhWeoaCnW///O8r09poUZaPna0PwFtBQFh q4Nu/cSGMrQFCwpZT2HmAQNlBkIVKeDuTFJUzQH9ueHAavUloYZMH3gJgxfleAF92rqj4VIuOUcl RIvk98I3zBSmS6575Cs0wd9F16Qug8jOJpJcteKqTFxmJZLYOuV0SzFtaaZb2xX/G/Au3aaLCQzp RiJ+q/jb/cguvoM8LOoK1J2YhKFEwpb7tYm82LV3O2oT+WpVB2oaOY0/6qheq9Q2/o2AXfkLv4Q+ B1SJL13wmBwAvS8bykzMDeD19NqZhIlEV1kOnAlAaGrbVd1Z3QlWDcytBcOf2931MKwZtoD4M/xo PZA6MA3+PH+x7Zfw5/nLYCP+bDNS//nVm0M03KEdko+H5C9sx1F99erNt4l8PiBbCLQDM1sbCHcx nTTopn6UxD/CEUkwO0JnJPFPusSx1czB909evIDZenq4eVsvitPljc0dVosby7xBYfTGUt9Uy2U1 C/b+6auXB69e7A8PniLODL95++zZ/htYlmevNh/N5PKg/CuyLjTjnb2YXD5d1U1Vv66aUtJxrK9g 8Y5xpilj/sO6Ok3NxBEHqxdmTZe+H12Vs9WMKznDsIJzO3zxBRRtG1LJZKE5yXSaXxT1vJg+3M3b NQV5w2c/zKe59+kA2VHV6W2AE7fOU3gLDa1Z+fSmPpgmDsZIPL5ZnZ4WNTX3c+A6MlNwTq7r4jQh m+N2yll46wrKbbOpj5JWZLzhabEE74OVRBumkAd0NrOF0ARjolHyiEtULpOekzAZuJbRorFAKFm9 mBND9DM6r64aMuaIitliec1aFjjGJ2WzmI6u89As5Lyh8p8y5/HHaCva6fXeR2//PVraYcImTNYE Db3/9PD//neffKJt4jLUAeiYn3JTBfP4AxdP2q+6+cBZc5ZJhEDsuxMoiVUlDbn7NWd+JiGdDbyt QKI4MfzjFuHd9u5OnHhk3CsL6P2dTPcpvSnGma2nx96ztZ7KgEV3q6JFkUmAV+OLafGhmOL1oDJi tFniO2yRhefVrGqW02vYZK+fwzlKyMSJ+nbzRw9k2Zp8cR03zP5im6kAAUzl4A5XS0KAejbSgQHd AJWmS77i5bTmaFOoDMK9RM/JjsF3qgUFdqxbGDxxB1w1Px2OOTkaiTdzelXi5Ydukm6rt3a8bARU 23O2rDyo7bjZ69sZYDvB2EHU5w5dngaAuIZ/g8VO6mJ0sclFqMxOy7aKm7hvz6S9AGrcJ4rXCzfh 9JYh8cZCJXwCKz4uIkFH2AIp7gGFlBpPJXgGopKPsOYn7hGNuzqpDGN/sOpOGNfp4kli5wSvb9Ry mttjQNsFZpBDdKQrWt26rYMm2gA1VHC0enRJUp0uzbhSw/4yBMSd0JbGEe+MSTRzt4OFY374LXOD 6EI6m1YnI47MhKCGaCth6RSdQeysWW8Dh/sGGCKvwrB0KWvQsgyx0mzGeBUhUDwHY5UcTL4emTrH azqpq/W/Yv3I435oeQUoG7IMaR/jBb1tV+pGwj+dT+VKnfY7kEwnQjjWmU9Bgp+wcUsf6OS4n6In Tet91Q8YAki/1M+jva2dY1dv7cL5e0Q3zoB2I7AcTimQ24ok1rXQXwdJecj+CIMuyCxijqbhDISl oZ8hM6ght9pGVBvVZx/8tDiCq25qzVCks2J2UkwmmNQWPcDg8Id/4eABHlwcRVQLeH4W0cnqLLrz 5cM/7ny2s65bsRpO7Ls/tZfcq8pzwq4rwVDsUtSQNFYwBZiZNoPSE+cTpDn6qMUfw+IK4/6Vy0Re ozH8sjir6uuBgMtaCD7AOwopT120pAlucKC+8mNmsRgYVwmA+51RdCNvgMtldXbi5tMcDlVhBQSw Jov+JmEXgWC/77/tIR94NZueFfP3dw6P/wd2sxB8O6VkiHPKO6Juhoq6RIcNfIZq9O58CT8aJeM1 vZNrdguKmhLTcaj0wqwuRHeMZJxG5xW0WUcXdXGBrIc8jpbRrKhhElZXUbHKo93t7T/acX9NLDXy 4kBHFXHRsK+roseDKHmYbVss6SppAoyb+cxXRclV2LvmisyGpFDbckjAXeVWmXZQIkSCq7RnNndn v1RvRFUsj4C78qun405h6ii86f2+gHOI/I5QSnJY8Q0z7+7tUOrdeBjfOvWuaFexuu7QTUFHdEFR IuAtpcnUoqna6AzPe61pH8oL67hEAxApZfEQbO5oGf1ImVuPjXont0Z/+6WlUEbBoBxfXPNJ6AfY lKpHMewUyr94rBKruhEa6X5RYq+agUqk5CzNDKiPjFwrxpujs8QKRc8vn5Drna3J75DiOtIhS3+F GK0WE6CGiYpe2iURdodi5YQZ0NNWogw3Hir7mPO60G8ah4mbarVstuQa8U1tOZAbMD67mCCL3Efe wRpMr0U1xGWdq+52J5o4IHoo19L/BEIYJipR8fAVgDT/gF+8FK46jAhb4U03yHyqTv5wIPIW5K/u 1rhLhExHdyd09S1oaZKV9szOHYToT6zfAU8jiJVFgMMccTu29nC8F5lwlLGN8/AFUUB9sPcYfJKo ZL+YROVwACFyw/9skn/L1UEoXYuSRaQaJgWMOD2tW6ZV0u+nZqWAe7rCQwuDbE+B3eETc64mSkaB LxM9e8qo2poVzPDLI9XIaebFliutOVa22Edwhu2kxm3H8ArxKBudnNTZaFxX8+tZNppM4BBvMgxw XCyzEQi32Ul2Mqmyk/IsI5PmzHBr8QlwWxfvV9WyyE6qyXUGkICWLqt5hj6hqPoYYzquOsOILxku CPwztSHAI4X/hPczNH7OJpNsAjzB5HSeTcoa/vchm8DjMitmGbGhdm1WI0NHT6s5/lPPMpLM8NX5 Tna+m50/zM4fZeefZeefZ+fFaJLhRNsgyqykKlk5O8vK+WK1zDD3+sXJJJuOTqAn0+IMcWFaZjR6 pKHI51kgZqNFNhvV71dFkcEYVhlGVs04oACMdl7BtMwr7vy84g7a9ecVO4VnsmGgTrXguK+ZpCpe ZMC3Zu+zJpOiVnVAQqzVzEDEywB95ugIWl4U+KeCnlK6rKxZncD/FhnZnNrVl7Ryy0mG+iJa8OVp VS0zYIiXNGNssress+UyW2WraXY1WzhIMIINif/wItBkntcZqpkmxVW2GMGbrBlBpQ+jmuuleQOM NEh7WZySA9mxkDS5EsEeb3wu+TIXYnkWXbMxcDi4EP6HiUKvjDQ2RClsK04DlvD2WYuQU82C1aPL Vnj+v6wajPx8Ul2x8d54NFe3XJyWndg55cvP5n3TaXTCu7ecU6KsScQJRKbXKvl8tVoCbto5Obyp AMjQFV+7ym+Ze4QfquPBw6iVaAB6sKoxOkP0gYug5pkuwNU48mhNj6ikJr7bGWq9zYNFU730SsYI Qd32++7ymK3NYcnoPXWymNAXEFoRESYgqUpq91M1HCscIedvoS6RK/DETmDKbakuc6LTUBHO6uLF v2L/CT1EttpXD9A5ehKdPtJrVE4At2oOdnPAZJT70ItYj/p/TEhYUJBBLBA3vHse4FZs6IBxg9Mz u0l5FDVH0K3yovbdoDg070cAZsOcBRThWKWIKIkbxSQqdeUzy+323BBaCogVPtyNwmNx5jactYHr bqO8DUwGb5ZQoAU1SRjK3tTrBWAltLBmzRmmSkjubOY7lmUOfglZ7LCzQKJYHyxmOwogsQqBdiEL xUjdNMXBihJWDthDfO94WMhWDO7PI6lw7Kg4Kc2LLsVNmT4ggyceIaOzYBfw/doutDAcaugUWM5O PnLUfRKlAc+yAI47QBwbSn/I2EF3yPBGaUAF3Zco+miBkQYb4N7TdkpjTaWUpx8z/ngGk8mXNBUS 33jl0dYrug+8axzBkXzPA5t6EncowIjuwv2BTVe7GoSWvrrb3G0eQ3MgaUgHMyPb8cU9TVsasJqT tVI+NVgsnCat1V13cfxMZA7wdnQ8bwQP1ADUBK+bmK3wxLRJDkIS8Vbg3g9NS9BcF9acE4IBF96x 7MGVeCALodpu5Y0JZ3X2wTw2U2JA6dmxdrQ1ltDGvqOVjYVV1HEfpszCKOHQvsldDYkqkGP+RmsN p92eY6pKZ3JAkrR1Z3SjfvYhHYCtuSmRfCgRo07rSE0CYSD2nbfBDZKmidrj9JOnF5+bbgXg7jH5 Dg99DSDl9rAolA0m5GdnbkXiYchxUwhe+1rFGlYc3W0G/btNPzY6CO9so245p5ueqRA22emcta0M 4U+zKtltmZgVAIB6eIdtap0b1AzK1bw9c3puX+VtcLkiXTo6XnuxC9AF1Y+u7sd7MD33QbphMYfE A90hJewEZ/UIabukTsa5xS0Kr/4B6D2jkG7JNl1yyIme2na2bJRyEo5Dgt51JyCwfMDc0RMgddRH YeGKpiuPsuGPndblAPu9muaAJJYqSQlDIQkJ2uUYbZxx0dKuRJZ6pR0nOz6pSb1A0jXLw6gYACGZ NAWkVyApOg5yqTGrJUiyjm3RWbxGeYpu0Z1RhEqfSJQ+0UmkpPfoZFJFJ+UZMMYRqmw4Ls3kFK2P IioQ6GFcRjC4iDoZXZxMItKbRO8jjHk0W0Ssn4hIP4GuaXQZgi5sIViss8A1Q21wpHQS0XIZrSLU H6jhA9qmx7+K6NGNB/NWv4Locdmg52wgErNCeFJ0W+imFN7eKJyGb7cnlW+18JiKK+aKt9lhHYC4 ltaEiKfyhklFuLDOxKj+A3KEdGkPf/wB1Yr/EKcZPnyl3071u8f63Rm98yH9QX8HJJRK/bivXy6q plXNUyigH2NxOqwL1BXVaMw0W6DhCQD6F3XwWuPJL4proL72qTQU/ZKSZGcos3fcQjCQIyqSc9an bYcUS+gCpe9hFZJ3yoHssCWzSz7Z5Ydi7imd3ONNwJj7xUQBDsf601OSwx6VCys1SNOpXk8vsWAG xvj7+7f/2U3YxSmPp9XZ+7uHD/8bTtkluWFnIEcjVcOggpyyi5TnZNRGMRXIKVZyJuccV9K6KBaL ORUrTrlHkKPf8Fcl4tJ9xqDu+kFlGmNQjZPZysnSpWsE83RhPiu7AZ2jCw0HOjN5RToNF9pCIOGX 2dvSs8dA0f1TZ79an+jJjMzPX6K/iLnhoi4+oHhTATOLmGRqVoA0UzQPQT1HEyVXE+QueoZBlnJ+ HhEVajmm2nSw2LwkVJGoGthkouFABbTb3sF0HBx4gMyKLR2ASp1iD+4N/X5RnelmBX7qV+tIetUC umGOK7sT6qTRIx/aeOLkGtMfbCoir3Lpeis1Eob4bPVz/fhWcz1Cf2RkFlKOh4huiRWsG4hDiUm7 KOIwcpL0QrpxJoY6R/TyaPs4p8AX7MgkucQj/Y3f6I/10gkeR2IbUjTUKlKVnT0r5gZmgFIQSd9p QTPB9UwCc/7V8i7nhttnOo1ECW/xXuDOINDl9XK0CzKP18VGcMs+8JrXTTuGpkrswslwbBCUALh9 jHMZJ0dxqDFXD+J0wGWKzLSr+bXjXakwMmccm19YB7MBb/Ip9DeoH0aXPmt65ZmNa6KhfhHlAvoA 9PHaoxeuWyGayg+BwtXXOipNsxSLMcrbTBebkUoOaEcwpuMm6ZsoGHYFBSaV2E52P1NHRUG9g/VR TTATjG9bV1uqSWmQIy0EwBv1LgyuWi2Bt1E8IIdZv3FwqvtulkSqGSOilZNQmgtdK8gyWzAZlr91 jcLJWpUb1qMzpjxAcELK84PDnmnlj9DI86q6yBUYKj6kWNgw/lUj4x8IHIu+kgEXQDuyNB5kuD5h MeTK23aq7xyFV+DmZkSOMaqG8mM3lDh26wjEUIR6q5bFJ9q1TkeAQpNf0WP5ioG9F7cDRBLSuB41 5/msaBo4qdLWPtforNDxJnyQtCHrccFE5u+auPUTZCFC/1l/gzNB7jbcueoEedD/qFkMKKw/ZgbJ Lng+mnJ+b50dwieHvLPlg7WUN29x3t7xpzE5qiQKNggVf/CzAE+qMT6+jw8fKJGC15f4TMntEEmp hn1r2OZVgqVgHlsOHt4hVCjXFmRA+KPy4X5DyV/xX3SSf1GxqfGvkjek8x0SRX9rS0ayJWOw8uC6 GXSXwBBYIoSX3pEFCKCMZmZQJz6dRkDuojZsllWkrPp8Yx/R1L+rg1bf+lj4Xr68WnoyUCvJr1lG PNJJdkYZBIoiQmqIe5EFMTwG6povGnHGIvI2YQzkmyEnGS4vGmbStfgOoAXEJVEAPdieMIn9UP5I WGfSICWtqQyqir/lQt9TIbdLPU1dqeHxeTG+SE7nNCWDrtZ40G2FhLSDHqLtwRvGDdAcKJ0UTuxN 0M3E4b6dysZgk/umnevHFGFOQD+2fQEbcQU09tzLSsVSVPyabSNk81MGiMeGXJo4VWl333KrpaUJ kiHz8RxzFKkcFoJK+XMjLQXmJoBjNxtzRvej/h5e3tK6oyrX4fBZ12j1qWVcS14KfM3CTQ9slDIB KxvbJ9NVvOKBZ1IeBvMCycscVfPGA1E8GwQdc+jmIfx9xuC8PSCFpC0+SAhkOwF9cTUi74OBVymX Dy2ms10Sf3e5n1Bf1XPY4YqKyNN91R/zYsdL4EisjDUktApvm+vyDnU2h3/WaNcX5c6SRS1GiWV1 oA/k0+YtwSsyNHvKn73b7zf7r1+9ORy+/fb5s2ftmvbX1syprdrhp0PJQ1igGdeDbU/Njh4/o6vE mtOMXmyrQaJr83aacvizP7VWxDPO8smA7t9RucfwAgE8qYCSevt3tx9OlExX3t/hfqQBi6S2Zyd3 6P5ALUHOpn3DSUnSJ+U6YHQJhx3w8PSsAv7Mnnp1Q4QmHcE8lz7dDlFkl1/faO++nRdX6J9ZTPbp 6tPNryZXouJMr/wzdUnyqXf2M2zVMTn0BMfQSdUccqQI0bq80R8Fz6Z+wP/hy3UOBkw6WRrOov6R TNlx3zsy9HlrdcQ6LURubeVZJ2kjw3OvvSkJVRCkd6vMXLrKk5gJhwcy7RTw4EMRyv5NHjPDaj4k Ll9SgXwo6pOqKXDLumMRHuVWI9EOo1bfgHNiJtvOjXfTiAFQEnBFzW4cw/vk7X9yxQmQ9JbFSTl/ nx7+r/+O5YlmdTIrl5E6iNAuFo8QyRRo+9yjwewoUiDQpuVDORa7zHC4hVU95fnAgxwFu/PlcrH3 4AHByBfVuKryqj5jae9qNq0X6CFFhYEPeMBvHvDn5ry6tD/iM3z6NdKI4nc04p85TP/QuetQ444t Jh4WomhLADFJALG6AlEVO2888Hgc9MfnFcwmpiSiH83gKGbMQFtuEF3iY19caDD4KZf5F5RtiBzB Gr3GeW2vU+dVSSttqaXX17mZZgsd9XtdfsFWMnndDRQcoIYlOCgdvioiKk3VVn5YYOOj+ppitMWX 92M7D6W5ynFV/bC8/CKJ1fry8hZ17GR6UEbZyzofAo/s2mYT610UQyfAZcBpTMFxingBH9qjVFHp KOCnPSjTE5oIaX+zKxjLy9PcvNit2tdOwV41RXGRbNucMtEA597MrYGMTpKuh7ru+sYuaCmaq6vr Uiyn6SFJ83lx+RoLJ312wu1nVvdSO9cYAQTKw/EihK2BZzTKucwUdGuUOv+IMh+1tg61sIUXVMAg oVnpXbuJ3w4fcVJk+ZXx1VFM3YmPdfoxmQsn7YacF0wqp+VJfgDbvahfU1EcNX9JeSM2DirpKP3N ajYbke7Z7aDBLP9L3rHLMTUVk6R+K2ygnicfmGpEETyydK0xpceysVX0XhdYrYYh4/sDvL8+kEhD 3pFFaBMdMBXsu/p7fxyT4mR15mvxg82SSN3nycVjTmLxmBm3bU4bWhNaPgerHTkek7eSUYDXHk0D x5OQ+dkkpjAHTMFkq46eFP2SCwy/Qk+ojiwLshGnZ5IdqvHHxFXg9hCFMaIIMxPnIgYhU556Ogkr /4aTiEVnAyE/Gl9Y9JUUfhhT2D4KgNEPucVEE00RwVPvtknRHWu9goTHq3d7miPU3kalu020tfVY 0EjiOBhCA8zcvbf/0WXmGHXf3z/8f/74yScdcQWqRil6qSac+rXW874mMN8znTL1SVfgsgozWsYh MVCJQ96yyDoUtQrxKf1wS6Y9+3aeIJnDUrl4s85RuMfXxK8ZDy5+liwdQLCA+yGhV+WaaZgV7fQp Q72BJI6ABcEYorDrg1Fch6M5GhNWK8SpV0QavhMF9gqYu5m2jMmEqRy4zrMSTRerhFyphqZ53Ab6 wSu1EjUK/fUyqJTaScvcXmg4pTalq3zJVVvWm9Ktex9NC5tlh5G8VTuRJixj+MlkXmmrRfzZml58 qdUPVMKxfWb23I4HoFINk4IdZn10CmTAXzoK8kG8vs6NwkvQGiHz98push2cxUJJKmqsBUSUsHGi 1cMOpEDFz7bT2RLzSFFvizlgcD1aqqDN3O800HHTbZqDdr9dNzAbHMacAtLHKh561TKL49HaS+mg 0z14IkaXbDk9az0ojKH9oAgNf4tMsBUyOWZ63h6zble8BizkJoIhhrBeoAXyYJNWKSu49fv7a14q ph2ej7veoM5+vR8deR08DqPYWuQSCrEXCPROGX+4lIU1kQKdt/SwJGiIE7VREahh5jYy6rEzRqad cHDSh9LJxOlysI7IzqYSz1aiwIUNLE1F+jOkdPVHHD7GODXh22N/rYGvWzq4x4E2WgSNCgv6cCHL Ac45Y2wXmUyZOs8dACb8R9DTWnlPq9YsSK3xY7vaoNhaoc7rkjChE0oSOqQs7xP3g41UAxtia8tQ tpf2+aR3D/9YTw8o+MPNNEGYccriwejmkIRKdTeM3EmgJZ+cqL4NtU5XrRN5Y6zgtKnbicxvNaR/ rV4y7xvo5NAJ7q+2Q2CELVMPU6Lt14x8iDb3zTl2NG7zJhhmEj6ghR3a6GzFnGQR3oAEUTYSvC7s n9wOnUTFx6jQoyYVQmKuU+C/J/22b+jCYgkDKJu7PJBiTUJor7gPzb7IVvUOjPBCv7bVi8GrT+u7 xTV5+0rTsDWN5EEuVobLLKKr2EYSjfpBodMK43VcfxKNh8WinFbKDZnfLZ0eKw7T7jmznU5YMXyx 1xLD8LZGkuz1schehFe6Vq5lqneMmZmwaLA+fGtC352IZ05AIbWEKH2QQr4VAwK9CMTfiYz8ObcV pRNAxQFRcrabIRsg1Oda+RuW1eWonlCmAYKvDW2UKQ291MHhpNEuHKnmLHGJRIJAx6vlpAwTezJP 3sVC0GgTiBcxVPCQAZKfXgnVbwI1qyYhKKYbos/iB6/UbPKZFbfCyt63xCGW2lbB49RoCeprPAcw rG00iih0KUz4GPZ/pA3+p1V1gesB3A6H05SV8WLKYr4IGRKIfod4sthRWFfNajSdXnO00Ek0PClO 0XLI3SwiOtKOJHcSs7pkNRXNRtd0ijkSp9AQFxQ67aGjCgiN5+wngJUw9FABvWhGp5gE7hpjd2Ag D1Ri2MglQYPH55Q/rVFJzbRsC78KvGDgMdHNFgwKZrKzLwQMa5FevblugKWhOUYPkx+KiGK74HJQ tjeAdOZlmD6pqiUGskNTvSjPc3sdjcp3VUvAAPcyPLUPTbTZ3Noy6BS7YhBShHo0PysS1MoQ0vhq 9sVyR6z/8PNReZwGpNYdOwswPKdd59cOnl4t0dcqo/sRPY7KcCki3BxIheyliNxx5+7vHGcYBDCg w9K30IHuIrUb9DtOz1ZTCOAI+4kDvb+zJ03upB0iu7OzFzeIjUQX6zPFnaNMJI0ft+QddekABdHL RQ9JMjDDa3uc/a2t0BAxqFA59wxfhC605zg4VOgKVxBzsXSPMy9ysGrKcUg7IRDspIPMHiElPlaH IGwPRRuE8CfcXhoIMgu7PoY9O20qK/0hWu2hi38TQkun73gM7HRggpGbuAb6pmDcALYz7MIfaeVq gwacGQmM+iq9AXvahgmidN3Ooj6QxRoICxI4orBEl/7UdxRAfovGoKzDD5793wEkH3zFJHBIV7Xl RUiUKlrvGz8WT/UQZuDThpGDxIhxjVttizGesVOsui+mwaD61jOBmSzEgC2H5ST/pTQ4AM9aCDoE NT/lqoGtqIiETzdCWCuFcaPTID8d2K9Q8KD+wXm1rBL+0kXgAEdukWHNZmbULBB56KsvaKWadhF4 u7oyL0W/knV74qK4FqbI1IQDfrUsgAT6c++SA8xjCfz2GQUfPqlWS4Of02o08RkBr7PYsJPyWfFf 6/cvLb+Tp5l3h2o6sYeSpjfTAt3uEfTo2JuLzurda2jmZ4UyIFJoTAuD+1gma2018g6Kkv4PT968 3KMJkrkUWzZneL3g7Bztba+j75NFKMVdgBLgXCA8K+TLSYHbF3O2fCj2otGHqpygex9wOSIwSBx+ PBuA+7ITp5yeooE/8JEnwHtOgWlshNAR+sC4FteaPySOMHLa1vFyaYDWDUGNl4i2tgn77osbM8xx p4IGsJUwZnTHw3sog05M7Zbei81XnSbduhu0T/S6e1XcduVtjo67tWNoQL7DnM5dCm2ei5VmQXmC 0UM7YMKGN6Mt1obpvTosEi8ggrdHjbOgRuVWxLAAMUuz8OZsjdnJ0O5LiEf2iw2Pu8WFco51urW4 lg/ttJCqRucBOYRdtKrRnm9WfSgmQ+AZeEETtwkooyzGQ/t2/eg4EH+72y17PVooPm/90uFjGM9b Ka8puENDQglWarGfJ3E/XK07HKjNdqijWc5g6QklkFAuw/Kum0gLnuH8yDmE7XcWp87JuQO/gzS0 apYys60SZgtaKlCrgkSfqCahe02l+wjF9lbf3Cbt5qipTmyDP1Y8EWcrof0OGhIJoTmSorxnOvcL 8TxKazWbvJLrmJbe6ryaot6Jr+GVxA+rYkUTy9eomkLRydcFO78pHrcOtG36HN2tH+tcVApultoq ufKsPTCTylMZtbHZDut7ssixIGBU5tAU6LraWAz8q/WaeW2EisaFKrhhp/bWbtQ/nu7shVRBvoLK 0jSjOYRZ2rRLJSz6ZjfwC+l6+/RnL7q7qKuz6EhW/zg6otwyVQ2TXbee8jw/7me+eYuyefAv8U3B 1B7oyJt/dfng3RY5ZQZeHSAzjp1JgjyapxhxybPYj7AGVylJ3Q2sinogECn07Z9jhIdfrPX24Xin LG9if7eQ6RReWowmlnwpVt53a8R+96VrAdbqk9ILDFv8uLRvUz9jb6EvfsIJPnA1o1gER1HBwLuA NYdcDKmKFspmukYw2OKyu7z6Ra3jpYoeAfBSyqGRp0FJ9WK0bzE106lW6zpSqLJgck9xdrCwd5bA pxhzRlsSWAFtmtmsEd5QaaJOPbtrx6327rc6G2BeZbg+LRUYZsIY23TaQXexz0JrEFMVpqMqWEHg FLSd/rkRnfanz5X71OKA8gaaBTTKfW/XeCfLnQjD5ZMrAbkCRZMVxWTS2xuhRMmdsmlWxR8fpr5j oEbkBvF4tRAcjg+Wk6cM+Nm3MZIV643RJ0PbVggHsjAU1j1J10TPDUkC3lpalxttI+9TtEicBoDA HGRRUZMSc7TAcEOFzUsyZ+CtEtsjQ00VyHi1TEMljMUy/Erb3i0O/ShusqCBwY1PJXwP/EjY3uKo Dx1eLXJ4gya2y+oKC/az4/bdLAPwgr8Wl7ZJBhchW9b+aDLBT/1Q+GuOaYOfA5EEUMW+h+y6aKbl xG/OpxjHi7zFpHLrhEHRSNIrJZvRZhr9sqqmDfvuLyq8udywcjH/sGFJvT6hbgd2XqCYC3lSeZYN itWwt7QzH773Ujn/UNSBhYv5S8NJi1shUfirF4KQAPEX5c/n6zJn1x/EgZPJ/FClwRp21cDGqNJX 0YeQIRyL2QLvLfJQLG8HKb3KqFoX71clRkrhelt3m0zpWPSbGI/6XqeWTOZKW7rqvKzyAdnG6tSZ x46czFwiC8xJuplp3B0tM5h7RMBfMcMRc11mynOr0stqWXA2By6HFjzz6TWqtOQytcIUnAu506AY Bcyg5L5qwucw0JcJ+ogRDNtT2Nct0ZjszjeUUK1CJb9q+qnd/X6LsV63o2xzBidEsbuJhlTAisNs kbKhY9hmjNWYbFoHc+pb4rTJGr5R8rKSX8jif3w5SXwmUjrB9mUKB1hkReFGZRkgK/gMRXs/I4Wt 8YE2lFSUpDlDSey6qK93rmZ0cY9eqFNAC1lBbY4lgllTpCv5+1u9D1i5GkDuvbP6EMyngNOvCmxw EaaLzi7wgm2TGOJd/cpno4tiOF/NTjAmFwppCQbsKq8GsdCVOKAmsaC1psheRv1Rr9TswkIGpRQD Tkg60LIS8xfGQQwfgxWUoCbRm7S2Qq7TbXnDCdOj6bUvaIoFZmPB+0VcV9UVDPYzvhguy1kBvBRL 9MH7RtKvWSkiurXUzuWjjtRCokgmphfzopiQagPIZgPHSmFLzsQbmnSwjZM8RyADnUUVj77bfO3f soipUZQsz4trItNUl52e2dqyiFrBRtjShGw+sNol/qI78jRs4dFijkkdDs3gNAcktM2uC9bqkGVm nRQUACiYHRVFQJVnNw1oYANB8qXvZHYiwwiKxlZ4ACmXuY2nofsDhj1Qv3RWpv6DvlcdZIoAnTIQ ZMh8r6l7EDYssQLwU7mWhDl1MJ4wtaoxENdtcF37VNGWRikMGQJl+0ZxvXjy5AapuCob5ZfTiU9Q 1CI7Br6PMiZI9U136d7dSgC1AMiG1xnW0BI0Xrhby9hozyArSH31wvfzKG4xszFlSRHQaAAHu3+1 4JtC3Max6P3ilqEXfJ2bcmxR5xixiQXMyj1esTBtqITTdHEGL3lXLjlgxDpDhoy6iXHNoZY2p8cH kVZ6oft6yx4DO6WVA5ZKVdnibUaNDGa2VSLewbNxEoMARXMwUjnkGjkZhqzOpcZ4zbbZPeHejjxj uWMdCdYChNNpw3U9nRbKOMsdwRWl555PVgsyVk0WTt9am+lqfVoPFFl0XLDrXD/mz+el6PSvgpyW cDWxjEFqNZy/rOkwEOfJ18WPFJBj20eQTVZpBexxiomYYXaUT2KHfaK8l5za57hNdqyLGd/orD2B uBu0pVmQnQlCax9QCAhv4aRECFbI2rLXe5+9jVyPUDysJqMpLCWyPWgi+n7r8P/6rz755M6n0YNV Uz84KecPivkHSWTd6zXVqh7TZTvusa8PXr1983T/4Gs7VCCG85CfOAmfP1JPf52WJ+p3ibynREwp x8vnbIVV3xgEV9r3dVGmW/LL0FZc86Hcx4kCeTWddpNYDH0sBUzeAAbaufVDle/H2hI/vj0gm6Gx gtWOOobiiPBs5tK3Su8BI6HL9hyDaIwl0igHX45acwiv1iSAUUevjOVIwfVsxprh4uKsFQR67dHZ Cdqey45mKOCzFVeCbto5YUFjL3mM4UfiNBB0x1zG2onlTU0zOfpl6sPRjCX7dT8Qx2711lqwdkW6 J+KUyz5O8Sj3AjF9oB4iMdWyVsJcM1dDHHAyrjJTgy9b2x541nW0B0qOryEvTDiduhUuWNYvV8eg Q7skNVT7/FgDwEaAVr9r3O4lkgqVDxgmfzicjcr5cNjXZysOT+nDKPLN40GUPMy2rSHQVPVxsPa8 Af1P9yLn0Qkuphzhy/GFFZSkRZJykOcww0R/1IzLso/h2lh/Ep1c29m9TEWGmCNiNAlSz3xSIFJj kuKEaSu9mRQEIVHEMVXhMG25WXo5fk1AUVD0OnzT4HFTURTusTP6j+kuK4zs/lqxg0ir6xwKqlxP 3WVgPKWhHYdd1RRApHnHLfj1/svDNz99LYYOMiz6SiMD0oTqsvc5hr2SwLZDVkQClsyLy/cPDv/3 HQp71XtWKi+fWTEpMUlHgTzsku0PJBUHsVisyMQoHAVrUJfndbU6O49UOo4nB4d5j9xPmvNqNZ1E IvFFpu1qOsHIs5Rbgjw48l7HGTvC4AtdUXo1PLX8Q+XOdQUtziXo3TfcryeqMJHmHu0pnG3kC7Ca Y5X/l9GHUZ9v2lob66so2c2iz7JIpRy/Ex0URSSxvE5WZ03+F+InMJbXA7rX23n0xy84VhT0rEZs SvrfVNX01QJvkb4p5/zj7XxUX/PPF6PZyWSEv56f7l/RK0Savq/l6b8AifIpoCGW+A5zN4yWVS01 fsIU2vgDC4woCm//KQadakHBsIH49eVqRqFjlvSkRQN6tzphz1kqB6Qo3Bf8erhaTFVomWGznC15 xM/EG+nb4pR6gvyR/H5DtI5GWaCHELXeNOXZvN3Kk9WZ+hT1XyM3gD+eVdTlH5B15Wmjx5JSq/Tf oBzcBnVYX3OUQuo1Rtaie0tpHdCFIBFumV/PAAfboPZh79EakIcW/oJFoC69hmHSMqNTAK8GW0Cq GUKcGHIaFTwglonOTYUWBKxasJMZMhJZ03uryrQeqZ0kCvYlbZk68ZIRywnkphXWPeBWW4AQ/uaA TPd7hqBv2C9LHzWnGOZQPsfy6W06FYSC5Y0TrISsTfzYl0CziJiI8M5iExFROBXoHghp4bogLBah GvT7raQXo1WjmDcVMdO/QbUgUIhZ/SQxa3R35JwBJq3mZKxEnCn8paP+ZqtPnAS5SaNq3KpKFQ4n GEaGeq5gwylGUNO2JaBUkYSs2tJQOGWZWTfeJQcAdgdtJ1cwKg4Vu1P+6ph71tha6530E3NuqGCT QORQCQzYAH9HaF++heHSceP02/dyJIJwaC3rwFRGegBiUrJlKILPo+hgdXaGF4Mo6ofgiduEOlsR hSXcJDtpsmk7f4QeIVJsbc2rLX6VqkiG0OOkOj3lsF9DyQ6Cy2ILgSjD1UQLfCaVX5v4rc/wOcFl oBhW9LSTOgGKDHIF2zWaIX+h9gQJbNwNHN6JCe2s3wkmikW+KkBbRSEJYgBQQI5EYeWWkmjBFjAn 2Yp/rxMIHu4GCrb4RA4xvH2MVk/96KuvVPxgvgKxlW72kI1juBWZl9KgkYC1p6C4o9w+tpKlt2aG otNdLR12xuV99hQu9Z2ML9Qq/jna+XzP0THhSyAn1YK5C5A9Fjq/HxKKb8rlqzoC1P4XORfl5Y8V vf1n9+0TIJXw9g/W2xcH5+XpEt9+9ZX1+o1+/fix9frJhADct14Bc4KvtqxX36OnGLy7Z737tvyA rx5Yr55Nq6pW7+0PIBDju7vWq/33+GYwsF69rJb89lP77Qsei/Nmn17Zpb7joTlvqNRju9Tr6pKG YY/jeYOvysZ5BV3ht4i89pc5vZ67vea3bMjX7/3S662Q+WwtrQDFcned5tAUgz79z877t2ol3Ldq yeAttqV0Y/4hwi3aOVnlmNWF8ESVlHPooj0tRjOkhyDQRxSs8MyLeLg+BhpTKe/UVXSQ/toKAk6M xgeZiuY1cZVTcJBOMZwgHyaXmIpkHi/ZAX4UNYtiXOJ1DbrBo/DEXbTpzjq2xz2d9/UpweW86wXr IpL1RC2/gg5/H8olOLCmIkdJEKTloLePZom67p4U7+TXtsmg1RZa2EtOuuBFlSPZcTk3nPk6js+d QAlifYSFjjeZPmDdUcLupxsaS8rsQZXhbzx9lv40c6+FA9YEBMc9ARI0LSK8nE/QWpuCLBL36yQ4 1SpGSzlNirZi0Eek6Le5aV1FCve/soR0tYlp+R73GZTVIG2tISK2YY/rDlMd3oZYIJeIUx6Y721N susdw/nAZ8pzJz+pJtcB02DZ6SwKuMBfjmYdesIAgprbXJuCuJpD1iGU7MU4F/6Mb8U9XRSxBrXo qkjFo+6sODgIvOir3Op5OcnS3hqstpn7IDJTGzeQg/W4fIepHwZLb5oVDgwtCQD7gu24+nTFiOHH 4K2CGqRPCtZQC28lRTWiXR5mC5tjLE6XomrP8bfzwdUy0Rt3vXmd8YPrhFktAGuApRpWdGn513KR UAvVouEekB/1iHgtP+gh1XMapjehhqWJ1IscMmyuZyfVlDOsan7uqFoYyfx4Da3mfIcm5aE/D7qB bK2z8roxeZZfGuuHdCri4T6khYFuWK/q8ux8SZ0yXbiRqvv4/zHnYhZ5HRtYuLD5LLTGMrBW9tcd Hp1zq/PeYRs3xc7cBO/Xoqe5t6lx/i1RkxzrGOmdzU/vQtco9MFaaLsbTptpO4tf4LrdRfG6aD6C kLA+V5kYwkNlUxLgSkhvYmmbuEyO1ADZkVd1UEps2vZatG9JXS/tiM/PXte29Q8ipg8CppMx03Lu OvRRgAc8wptwSJxaeDZwDH1UaMg/9NwlKScYAY3IPcnLdj8pblra/4g1E4W7iiWHT25KQ0w0R+nT RTY6ol95mFjKhPr0kF+GVkAB89bBHbnqBRG2dgNrj3errk09C9JMp+k6K6LNyB3+GLhD3JQv2IBE 3WLz4RWK2nvlvPIP8Q3Paqqauyc20WK3Pr/qBkDf7YwKoQOXi4Yxycd9deamHYfu7U7c1ojS3scf tq2T9mO4zN/5dG2drPYC/pvgK97CKZYTftqyyWo+dhcX37hYhlVyfO34Ygy7Tw16/pu9pli7H+0R 8F96fvy/wKEj4c+o6aDLhttpfBHaIPA+bdWUU8Hun+Yv5wkQeI+RmzdHqpo4vg09/t8ZjDrHVJ10 Xded0sFVxtm4KK4vq3qiZ0SeP3ZWpHruxU7+fedHGh1aYmUzuCuAVY9C6+XOqgcG6qq2s3SzmQ5D cA45RzdPM47q7V+Bhw6MjWYcC/d/CzTs35M5vu08ORVvmJ6Ly187OaHkTR1Tc3E5aX6jqfn4udlg cnBA/K1EbxIYRBb1dRRFB27njc3dJlHncJtUuw20POWc5njkNxy92IRuj0yrf8eD9t49d9y/8jS8 E71C30VKVCft2nOJhn8YFJKMwrXxEPlPkE8KHqVNNLJDiIGwk/e6nVL0scgC1Uvlk/Fzi0ugCOA0 cyCJSNOEbtbRutehhbAatBZKXJ2wi2n/N9M6YO+qanozY0TNDz5OV2AacZVvziRTkXZdIyL1MR/Y 3+4imuOvX/oBFcpiQ13/WiEIalGi6cDV56Y8WGvVg5pce2y1CnmhdawkrZr3Shfbb+9nq+9aXSk/ fu1mtrKQfoxqVgDwsnscqrb9Uq7U8NwOo29tBiyQj5dXvPleVKNJ2t1dVxVOsL2J8wQcfhfkKLFd j3Fq0excDocQbAIQ6oJHi+muQR0yqs6/kuBDcrYzCb8hoW7NltnIOe9lmrrwxr2FgtO/GftVYDZb yDsRJbtWFyv4EW9LyIx0NNcRnLrvWJQ1nbcWmEtSDM3jLPrbL6F9b7GzvxG2YLd1yovfE2n8hsj9 wPYCsb/7GL0pld/07Pg9TwKhdXRFqQhd09RLxzCm8bQt9CZIirBq7kbiInMcF4JjmkPEF0ZPf6OB GB23WZYWEOB6BQQarO/11hWWnPX2q6Odz/a2djtVTmIhJOSuNQctWylrTjaJKkpEKWyY/ZtfdITw wOpuABnKs7lBBniwZpcOGhcd+FUHPkDtGw6nPM8J7425WMdMi+ClWNuARlefvMkaeoqWZvNqYPct 53fddcbVdFidnjbF0q1n3lvdLC6HXEg6KxMqFQH1gaY2yg3Y7c1N/ejuT6gnAVMP3bfjtZQ4aOzR 9hVrG3m06a+NHb+zqtFuqvd+++2/R0cJ8iNpPmDWzPc7h//tH9ndQ/zCAOtLiaLcrE7Ey4G9mtlV kXwcMb4NHZ8YGqaej6Y95Z8cA+BYco0oR+ZROSPbrMuqvoiQQEVQKNrJHxJhOy/Pzou6h/a2M1TC ck4AlV4muixA/KNKxaielkUdSaca10MEo6FRQk8MYoFkve0joh2XKOKQBOQxDiTsui1eQzCcah7+ Bp2/HKM/EfwIlcspAvhqWU5VDSRrk3HVLJ9QNM+n+D2LnqBlGv3u9b7d/+btdwNhu9kU7uDD/ClP Koa1SHRjOXzAN9+MtIE2esmrHlpmZBwyA+1w68YKJJosKkD4E0qSMsPUktZKi40nlEBru7KwM4YO p01dfFBpbUJjSmajK8mYO9jZ/TJV1eaVVdEM2ym+vb2dRfCiwQB9k2bw+Xa+bVseDXGnwoaaNpks IMCU1ECjVdutFbciXrBw7Careuo6GmpphYFiAZ99+aDC58NPV/W0MqH18bfPzOiPzbJ2gkybxST/ 6JPRZHw+qv3A3TaEGl3IFkn8IPas/QW0lHO/cdftXnOAJO6202PbJ/fG8LYqlBHBH0RbO0GxLmYa k9yt0xhOMru3N4e6MZWzSAAkNoRM98AJwQhbE0gFvFVXKTMg2/cCWZaQPJOB/ZyIkZAvQCVSHkbA IkfV5TzCjMVIpABiSZTQjrRgT0OHg6cVLAH7RrEIrT6tSwgicRDirTo2gz2O7lO0m0CExZsbc+eJ Pv92s2RPDEWUwRUEJgZXDuAftwI8xMDj9zViDItmPFoUCUbsZvck/KWTXxrQKhqZOwE6uIsPlVxQ J4hJqS0DnpZXKpwH6WmK6KRg35pLDOGGlpAVfKwvKUIeer2YLUS+nMinKdXt1CEpRMq9ECnoHZIQ 92CSLzAcKwvUyqRSQfowm2B53KSJX1SWGmq4a+rUUSu70ZJG8QidlGM3c9WMUn1rWgWTxpOVoH0F fG3tBKIsnfEyEN79QRTD/9035SmOFXyqWgGg3VgjPDZEaMcgVV6Hhttiz3iKVSQ+B6LHhmEoDLdY HvDfX++UJBOTAC9Y1zmGZUjiZ+gPtk8xf+IUc8Fs7URVvZa7bVXHzPejybWEDlJg0u74jgigqvP9 /R+fHxx6GX5NLNSbkGtRwQb7CNTKTBiwRbkoJL4UpyHBvEzz///iHA3Zxzh+GZoDNXNNHqxo0aJw uHiHENqHnQ2FeKnhpJiSV3c48ZMc8GZ6yGu5c/B4I+KYjHNHbL4t1w0iMWI+hfku2zzcmhkyCY/r uCMi3JzKghxB4ZeIvTepp7Bu7p+0+FKp1pM+udHWb/tZGpKTnExRWE+08s1qwcmvSLKeiXW7F5CT /SzthEdwXhA+j5bmEgoErdlieS0J09RR8fGsgdldsWpLnWRJ7xZ61CD6ZFG6QXTBdX3ZqtHc56N6 BFOQrembjT8q9I8kZeDAUYHcDBYmIdZANeDxq/pa5FTW7KpIQPQOz+li4kb4K2ljXFv5zqzr52Bo LX3tJp2XwLv8yo5UJwkSp2n0VfQohKGGKD9/+U9PXsiI+yhbK1oGsntpZ/glXxaBCkz3o+41JKbE n70N1x/EJB3KaRDHaQcwiXIAW6g8vUZKPiuW55iIJWExb4apM0/Q9ZmGgak4Uyv0Jgar3GSRx3BQ wIHyh/Bq86LKQmKEWCdtCJw38aw5i7Vljk5lCjJwUywZSeCUKZfQ+wbDH3ck8KQyQ4AFy8/dlDjP DYaR79NwMBPV4hp48xMcs0SUtFaPRyKSmrdKoVIWCx9TA9BSvDWLM6s7ftBe72iwgOmYWq2DzhQy 2xDTZ8nysG6Ow93H8L6E+Q6N1KfzlIGLRotBNgkIrxMRVnSy4RlHwLlH6dUFi2o7hlGpQNrdB314 XykYfSXAcZrYcjZbLUcnOiSFFUrc5aKZAOJgtmZE/sw/QAgT6P0NqskW4Us9Ysg9TNMbFpOL2Qtp MogV1o21vWB9/jLpwE2fnpI2meJZb7pwUcfKSRzrX7FuQg9/zaphbiK9altbwHaOC3f11q8cru1v tnz0MrALOws764tDkSkB2jfYkf0o+Zc22pBclhJKI8NSW2Q0QVtO63lZs98ZNZXS6vc22LY2v/Ov vNT1zNmeamcGVu+262Tih19ZmbWWVSDTKpcgrzbxXTNUVUukVFFFQcJZIiEOFQSYfLUiYydWTJRN FjB5koCrJkxjO+WQEwu0CkYElv53q2SSAN4HLpA6ygv4LD2+HX54Ki8VqxR1fKj3ooDuNyODrANr nhIQ/Ezi6TRrH4DcWT9Q/EbciUQzIy37iBVVW8KT0LSzgB4lsD9VntqRl4actmOaR89Po+tqxe7g p9fwvsW0xCpQfewHqZ1bUWkpi++Y856fFM62pvUPYsm/DeWWw2UNN8RJdm2Oi/mgbdfympIXyflI qeETyXTpx/VXEV3DQUnbrkldntNmyC9f7b88NEzG+UiMF0GqIL6XLss+7TuCwRVy71wlGFPbTkAd TgbMvdBZha3eHH77/E1yxakLzboc8NsQz39lkQphtlXnJB2iVU+H3R3o0p4ElEU76dH2sWUpMVtI PnU3dP3FxAuc3844xFVVygXVoJV0wVfzDOjSQN25hfi1DsG1LxtZ9LIuKeNmO27P3bLSYzccbkfN K69Yl6q6k9Y5WsvO88xavWAGJtVn4THa1JFQQYl7Bacebkl9Thq2hZtDNxww076piaVS7IejNuEu j/a2do5RDYOXYJj5q6RTEoRVtA9w08AtdHqCDZvG8nHaiglUY1xUwu7453ng+9FVzndyqaFCHPNn Z++4FZrKaDRfQ5MYFg+D98k8Sagfk+EWdcneCFzt2XMMOwjNr8aUSExdqm/BeD6UmH2vFfDEiMYS H9lldRybEvZuKN7TpSIFZR7iJEHhofps1TjRATsUNjvkma06KE5iOXfAt8kfEZcBQOxMO4x1e+vJ sbDPBilafe+eWpWGAtEci29Rv80hKtfV+JkumO2ZxbbQhnhS1P7Z0uVAHsTJaUOy/oc4aLa9wbXE ZlcTMuf29cK8mm8R04IYUor9gDrJ1UVDR2jyzqXIuImAPffUa55uNyhIGgbP+/3bw6aQYcDVHBmr h+s4/XTwe7b7do6sELJoqGj9/VqbVpeIitIq02rmT6b4aXKblp88fbp/sL5lvwrp3wNlbyKwASp0 5KIukpVpQ6kQFNHdC+E2l+nI/owbe0CE1FjaJFwj7coXjZVy9ncC3IzzeC+Sy4Gd/DPcmpMVhgaG D0gzmm7dkD0+dXWdGOhML9PuOcmbdsptKwCKKvab3QhtJt/b9wjGWAhZ96omyph02HDIVdJtTb4V ud34csO50uru1sd1xuqOiWDPR48KLlZOxWIJly+U64QyGZnjZlzNkRajyZOy2QIYGDEaZEpzYQbv yG23lflE12ro2qtT/LPMoAAWyd7eCYZNDMQsLn/28ntM6IQxPstpJ+sgU97NOMh9hl2NrjY8kmQx EAOnDVvS8DgIhx2JODQGbK4LjGkNn2MUu+M2YbgjMph1B9iV/qxNmkn4cm/XEZ2IVzQyrom/m1g7 3WeNHM3Jaen5WWmwVvZefselge0/9jUlgADEGFM5RsB2jl381rPzL5xpteMHcnddCv7iM9AsVEWC qH1SgbDtJ0xzEoCpDF0vqrN9ilWu8I0UFkbrnPd0S0hnEMXpAbl9bYOViDaFFGWVldQH9xNDQElF 6k9HzbKz7p/3n3wLVTBpEg8Da6HaIDOalUCfyUT1Yl5dSiYzRKcmGp+P5me4y+zd1b5VTqM7SG8x 6lVDBpu1zEFBBhLWoqiZGETOrOAScGgU7H6fnSPlu1MbZ2EQWfPRURO+9tyMBbrlgSoqVnAMs7VH 8QucHpQmZS0x1sXoRnlPjNx1gxqzDG7Kwkg9tUw0iK0PHCfGNHk1m5KRySDqvM4GpI62tqAgB9BQ uoENqX0iQ8jsfmWRe6XtZhyBpvIJ/BXFxKycl/BoaT6KgpO/4msJsSzjsHeoOBN4QRhgNIUgpxwN Ce9QBJvTtnh6DqcS4B78i5E0m7ZGTAHJMeAfJvzAFdYv91/sfw9s5/Dlq2/3u8JgKR7GiLlq1yQK ThoS7Mnb4s72zu7DR599/sWXf9zg1+df9O4AjN3dzz5naOeLCwV45/PPAMc/RLuPop0v9j77TEf3 zBfXUOvHH3+MmkW1XPKlyXcrmPEsOvinl2iMnm9jHlY4fNFeGgWg0bQ8m1OeT1ILNnJhPCk+/fRT 6sLOw53d6C/V+Xx+bU3Izue7X0Tfj66j7c+inUd7D3fZtQQTQXD8NuqLGHm77KdKHkDpzLb/FLN0 IjnDZuUEIzOWDbupTUq+6EGqenleoAUKFYNJZS+zshFomNoRI1o3gGe0A86L6QJ4Y1YkTxvjdYXx hMXfwaxV/M/RveRPr78CxH/88+R+Gt3HJ9xPVf04v/8nfLH9Jy7TlH8tqFD6p8jVU8f0HQ0BHv98 eT+6//Pkb7u/RPePfp7sHSuYSEUf5/fSv4/TrvCsxJ3b4VXp5MA5wcQ+JV6IkFhAG4+3e6PyMOR5 bvp0Z0hrtQNrRf/9ZTVTn7aj/3E1hcWNdj7b2/0SFh9o/vkD40OCrI9ib/Ts5fQ6caUHGO4ItzZ+ ys/qarVAB8GkdQfFOlUsfcScSfvihAodoRYM2ZcH8V5I98dwrPKoNmsXZC6IbhTiNcTaKUvdMrNH 32C7kMINWZEp2rwl28S/xa9jL2o96VAxHBTao6MtLI8VrxmOvdnA43rI2KXnhB9jj6dBZNNF8CE+ Fk5PweeXJM1su3Vn6CXC6i0g4fjACTlnZYOZ9YbXxagWIIizrV5KdQvWvQhdGOA/23y+eK8xl2zE umz+xHEUJ4/K6TfAjN0ZfsR/QGDu0D5H5kKSbDQfCUqn0O6aJ3xtJAbk+0bz0fT6rxylnmaHCBn7 2EZYEQgZ7VMgXn3ZpXCY9+RGiyTqarVcrEAYqgoMDcpBI/AbNhkhA8UEOZbWGeVGs5PyrFqJKZDi w5RTzwjEjcmIzW0xx8Ql3mRA9fyM1jARwW1Jt0jyDUCLliKVZAhzEqWpHp74VJOryB7IovjuSawV bpPR9c3lJ1BefC+JYR1EThGgdDRuwORzIO97wC2slkU7twKQi/5en7QiAOUG20iD0wTb7+OU8oXE d3+KnTsdbJ/5lRXdFm3b2RsM9D2nQmbKhxv5897d76Gdh3ufHbd6hSuFPTAsk/GtTLBQxquS4VRn TntZtJ3R/7nut6r+YwbuzhM1uwUsbu9XtaUMrATpiGSczRITZExYAPTlIk6pMwfgAjGhlQHQ+P3g Z5vVQy6OFkJl4IrfHj7b+tL3HBqNlQM1ATgrlibCQ8wf47QThDa/FihA9p+ETiU0niLncKe3bmOq zBaWWdOm3a4DtyPcti5jDp61zeN5hEYf73ff/ncmP5YsxvuHb3NytKNMTigMLjhZ5wMsxsHgmSN7 8vo5kZ73jzDNlpN+8qJcLID8vf/s8P+4z36Xo8kHlCknkfrGuUu5Ec5Qq+g3eqehONkgGVCp+3q9 H9h6GiVoaoUsCTDX9WxUX3ggCDg62JX4CNySarWHRkAgDF1hYok++c/D6IrJ1rLaUjlLVAdHDJRy cY8+VOUE84yQ02i57HHKGwKzhR1AW4QCzSCoOKZQYUmS9lQ5Z2YWMwegU+lqCfwnsCEjtuA8wXRq KG7rJDBYl5+sj00xK7ewAnYBhB+Yk0OMmV2gfTkG9vY6DjO1aijJGE7FnMbJdjt6ZvLe81NVHFuD GvMJnKUYi0gXalhHQDGLgA86GaGm7aRAfrAH4Gj6r5FaEhiY3ZimJYb+fXMdqQ6/e7dVXzXv3ilV BuaPwataupCg7HC4njR7yMEXV8t61GtWIDCQ1Kev+dAlF0fa0CTxAuB08+yP2N5VbnBlZPAZ+pLn 0RArlqd7vZ61yHJOK9zpbW3+X6/3Z0yazrJKcTVCLQctBc6JtRIKtkoCj40Xkx6lSsC+V6g7ek17 4aEJFl/Ue3t8GHytkk8j3JwHkfQ7Ex/2jVxBMplq3r6uAymh1/uWky67fWyAoHMuZ27IIALKWpQc bySSpTLjeveOonBwfBBKUbwYjYv03TvYTocS1p1e9VDTOyoZpSKoB2MAlMCVfPeuwp/amZoTWlPf eu/ecSJg+C6Orgx3SkIJ3/M0hD9o84y5x8l7u0fzSqPj+iuhXJKTPD/LgT27YGvQ9XON2lLJXayT escT4H465xom2J/up2x5MkImr16OV0vCFdo6Pq2KtBzdG6lU2dG0+FBM2z2+LOcPdyuMODaIOhFF JfujCx2qEfeFD/xaA9gQbXrUQxL06IrYpb29TffOk0Zs2mHLY+ZHEiM1GqotpKj8pEJN4giQ4fK8 gsmgM2LLHBE8O++GgBrtTdlz6SM3SIb8hkowm6Ld/tWEqVnmz4dQ8nXVlFcYx9S6jePzj0jhJosw aC1CeOa9G3zWBRCNRIREUkKbFfWbQEaYdgtgPQC3Np8Z796ZDsOm0sjGsNGibgGyAB8XxWh87i4x nRqCtsASSGALOcx388+xP6MTtMNVi1e8X5UfkENcApaumqJnkRfTOMy6nPw3E77wVHYv1L/yJD+n 4/dUrm6ZaZrS4QsTex3NUDWPh0Wfx9Q3s9Aw1fJOpWiLWZ9ZMSLiCUQBpg4N8JQbkD6te9wEXReo 2mpZ5eSR03D9TtqjLZifL2fTOw3wjsAkyZ7k2lecZK5HSO8fdMAF3LunmCscNxa+d+82h6tLLH4S TELf5SVhMLWPJwZyX2RVLNpCMVUF3OtxD/RBojoSRi8CuCEJpMAfhj2EqUXcwOAe8woNt8YFJ0NS H5nHkSO/FGYrj57Pm2UxmvjMEBIpqkr3SaXSjfb6/ozyvcBqrt5PNb/VB6xlegy9PaDbQSG3jHFD vTfpkgf2ABaHdb8Wnthwo71JseAUdyG6GJjD34I1Oaw4QcNKH+F0lb8k7ro4G2EI4qVh5YtJf12H AGSGsOT2jsBrI2QOJlOOS7w/GzWGTTtHp3+asyvFmE/gnFqLP9IUwRn0Z9fyE8l8OaMo6DDJDI8V RQi/1IPEY4qozcewo86GEVNrWGGcRyAvU7RQZn7ZYu2RkLDaCAX3noMUpsOIV2z1gdP1Iwbo2RIp hkbRk1G4YyC5Mor2+QxWk7Z27eVimqyKh8xw+UZmas4F1VZzdneFTeEweTjjPX3kE00VbZ4aMKM1 COHXvd+CIp1WyIZa8EUv6fFvPTplvTWnv+7C6+mqxhhjp7H4CoYPRwWMLumrAjhgWPR379QLoI2y +uihyJm0J9Crmm59SxFVp0R/4GBirk6tqhwr1F4U/eTQCuZPafJouKd4sYyX3yc1CmuoyoyYYZ6J zeaIwh+BWEb5soUy3H6EpIKS2oP+dv4Qx4z8jArgZOgtDIq2FzEatNORneGFADn23bvhUBGoIUog Sk2SO/uUhvp7b1PiTXGqhPoEti32w9q1m2xT0mP8m29SXsB1e9QObrW45rypzJwORxMx1UpIL680 7yR4qEuNGuUxepP0hc2SM4Ze5gZGvIV6AlZNOEZPrNob9BtAuGK4rFeYRhuT2Q/6qgK9IIMKPkGc +rjPqajoIDC5u8TdvCa3ENEPMSStEP0e3u6zNK3UyAGlKIaHaVmYk9aPAscMqID7Qe7H5jqJ49d4 e1XUSyPfAd+H5rtr4jMgWB3cP1e27jnb8pBFl9VjDJHcDp8k4PAjV+ZWJVzWcF7N/1rUFV4HaRCW bThafRddEZkYkotyeH/3t7hq4j3EvmY5yTFWWgysiHlDkdNixkF4a0bKr34JqmC5sUDuB8v3X1Tn 7TjSyoABdSPIxt0MUUOlKpS0t+401DQGbax8aVu0BYPukmXgZEhaG38SOPkgIHzYPLR9gRpsYV2v u7JuhefUCcH6URPVdnnqHsiatk32bdeHDMvGWaRYS4XBxj+EAuBqAuKZQ9qbTvDCcgVzqrrA7WzR 3jbBTyb34jKJ+WSJ7Z1rEXIsHvTROh819lBxguO002eh399gflVZfZjtRX0VssZZQCvOY885FYDQ 0l86vjiQlk7w7UXmZuKpzqIxMGioO3wmR1prEfiGD/YEHfsDl0ILsJjFp1innFblc6FYdhx1+xDU 5bylE3sh2oC0IVk26Gidjy9RdKCZHYvhQExxXng2nNlaXFOyBtTUJvzbmrEABKsMw+lqxZ1zQz6M ftScnjZqWiP0xmyjpX4ZmFYbc3UxRvMV4njAHTIgNxy9fHX45u3LY0I/B463OiHcw3t5FtWT4ZCU OTjBmJWc18lKbfTbYKVA4SwNxdWYhGqQiE1IDesD2uraER/tgec68mrasSqKvgnGmfXpJB+qQMgi vWfnZrE6/jEdbgfh3xjtTIBuZ71yieXVcjFYaN7nSPYcZnPpMx1lkuUMgKMCz5qzFhzFgQ9Y17co Jv2Q4T4UdaaKFEVolopPfRsnNhnEZuuZ3nY+aeE22Jr21ISOgJtnpevwcGqK4mejpeve4WtMw2Ao AgJZNxt0u2+TYhpuvBdY6d4dmiO+RVPKP30RCuz6GWY4N9pAhwbRyyHJGrCyK/QDxzeG3rh9hk+B bhMbRt9k/oPuJFq5lsFP+ocQwQ3WJHC4ZAcY1EoymB/pn9dPDg763jRYl8J6KhRNeMB3/vY8qLJD uSRO/MoyIUsyrvG+2UR1iX7B+JqC01pWl8qtEydSzYRSoUfyqEZmG2s6oHGNmJdj2Wk79YpyH3MK gjREa7Gk/+fnLw/3SLGEMSIiFmA5npPcjFvpQu94Xt72nTlew6w4Rn3TT9tVXK5YKHbPcf9l/CV7 Cpge0kR3zBdufCyCVOuq79nInFeXQ5nC1kJpz2AHrTSsH4OweN5vAwtX8fRZCNjt+4WwmoMQLMGP 9cDQGN1154NJHS4vMbhA0h/gFqE7YlEMWivad4NCrHEOFIiEUWyvS7tnkwHLxrkMbByEyRjB+B8o YTBeUWg9aJ9GcJBMSgYeIh+Lih0oF2TrVU7a/pU6C9qzJ89fcGQDjPtNkQDNcK82Gu/VRkO68sd0 tWZQV7celegABzecJe0J+NHMAIU+9/PHEaEm7qUXSoxgAEUskC0xdwmWd2fyhm0nM8mlbppJIZ1m JvlFeCb9b7/jTOLhpFO9Mzq5U2GrT3ylicP1KwFaFWLui6rbgrSwXOYjqrJ+aZu9KltLv/gRNn5s G6j+Y3HtmafeUWH9r01snjsUsTl6/Bjv65rlBNjwLEr6BHMLb0v2ors1IhTCT7u7y+1Dp6+E00pa KiQdiIVn8BQ1HRMilk0iJFMmZGIGT4qzD+Kl3+JT2CFowCXyaTU/wzDulHZnXI8aE30dFh+LkZcP e77yb0m6IU8S88sYCgAxXormBTN1ZnAWpjozOLbJo5u6pySVpM8N9npCqrXGZpJ1EG9KYspF0wzj /kJdx6h2au28m86Vm5gdxbcMXKYklvcxDU/hbmuu7xiGBnAaGBJT0ednXF6mzXP07xomihiTTF/F btVsuTmr0IAHTzvLYU0DwFlTKOPxNJbMSevBhoKDMLo5vqf0yTMC0SOhU3lIp7LVcXUu99OW1/58 BaLWacPIptBMCBKedYHWHBrtJEo6kMWI+h2qXYvS4Y+jP+4d30DjD/7x+evo6O7kmJwTATSRuiDw ZM1YYPrff/72P7jGv/OqKd5/cfjf/x0Z/uLTFnpbgbR1Uk7L5bWY7+6x2R5ytXh1guXUrMKUN9Fc brSUsYWy51oUdUmpP6bKDpiSNKu7VwEntriwesti3oNCMTbAb5vltQrGrDQNvd5b2vve5dzyeqFv xKQoIlopVhvVqQU27vVQOqbwZhz3Ds2oJACGHiG3LbaqaOTLxikN3tWQBwkbNF+g7c50SiJAdara jhv4vBjRNJZkE32gIj0z9OeTspp1GeD1evfkyo9sK4tRPUH7Bn09/YCupR5I/Ay+q75Ht4hoSyUH C9sMQH22umkUzAcanmXIdC+6LovpZItt6sygYcSlXD9CGWUctaKIixiQBoeCF740SliauQ5oHZU0 wugBoEOzKjaxNez1tgjiFk/9pBpLR+pCLqlJ/wawSbnBqhS8p6wxOsH0Gq/66Jr1tLzCIEQNgEBH HczykzPwSJDcNjEtUXofV2fz8q/FRFtjYIgSdn2SAZCnywhvmldnZ9Avmt/FtMAAyYA0PvJtof33 sjgp5wPAeMa4phBTWb6JwE3w9s0LNvRW9cjsdrwk1+15Mc3QqPREDKLI6VIiTaG9Eft1mxtZ+SWO AD2LjfiVmlGNWkZHhXyIsvin0wlnVukdgX1SVRxVJFBN9X6v16GFuknlqAC07ACnBW67ZnUCa7Nc LQtJB8VAxbbB1vNHdjgRpZjdpSs3aHw4pE02HCbT0exkMtpz7wiQ6W6rFdM0MzrBtAVcD5Hb2FXP vYDSCNeAolNYKvw7vOG2852dfAcpTmPtYSKufXKpatg5nrGXbVvE/+yOYtTFdE3rr044cDzpUC4x ekFzrmMAqA+99lXmxgry6uQv6hoBftprrxhveE0Xvnj+DMfVkNyH+BDzb7JO5xJLShDwCOrCgvHT cHgMv7HPw6EvVp3aKQnzxfU4dE4T9NN521X1jkRO2HbfUnnZc7gV2NsZO4BjIl9P66t+32snvOPs UHlwDkLKOjeG6uk8Nae+OyMb38q1ljbpXFtXx+9VzDlKWxs1vmOnpMq/+z4r5go/uOq6S04ojAIa bgb4SeMIXXYSOWONHEwPlMwZx6RCb/0tPZbvGsVzKdTB5bUblqB169vHgs6gAllN6Rx0wKs9ZQD7 hJHylTuOCQydDV9qie+vsulxiRBt9NoMjimEaIrhuAnXNiAjN82AasqfhJu6b+o5cpRCOAeluxGP BJs7gbacGh3NqZsJu3NOPWdu8fAeykTJkZHIo95b7hzrr5ttSncUunJoud2iVMCyghIu1XAOuoDH GXBBezafC4LGDdnPo0fbFCR0JY7w8V5olTu7E8NAOPLEaG6BakpxaSjP5lUtmbaMNRa33Y42Stvv /Zdv/yOlUpRAhxfldIq/3//x8H/5Lz/5pMV/SeLHHtpa+g4QffJGIGNwPR8N4RRMCEZZjDlgwXwZ 7wWcqcVtHKWdxlYiPacPnh6JEphU2NtkUU7aZn9+2qn+ctRcYPHowbPowevn30Z3J6RWKydKRele vK1t4PWbV0/3Dw6Gh/tvvn/+8snhfqQcmLU1HjApU1Sg8XhymJoJMEnAlQLj+3A3fwUS8GvuY3dk /FYzYt4DWF56dlEdzRyyDmZZqLa4XxmmsNqk/tMpbNI/Ux2pmvbMPHXOUcWIRLMb7Xwme8kriO69 tCKyVsinlRMTP9WC3Hu/h9lUaWNrD+F/OHz3X7BXr5IvHggFIZ9g5PBW85It9pX9KHq/oHxDng3A NbO3IwhQeKUlkUuknapm52A0+zVJPhEYW9/DHkjGafTnanoGW/If6+KimBrWFPB+d3v70dbu9s42 STKWoS9G+NjNt+H/JsWHnW0Q2YdDkk4oHLuYBSK/OJsgyxMf91TKU3ao5Y0CFLImdwopxroD2iaI dvwyNy95DYBvGpXQB6UJZLpycA3i3Gz/qlwmqiIWQ7uT91/5mhWUud8PDv/P/0STz4JzOQYyg2Jd 2cxc11OOfIheHciSs6O1dtLjxQ6b3WpvTd1VJlt/ixF2vEeWSZq6J+kvv7nR7tC22r2wrHUdU11t pSvKfctIN4ZVRJfCD6N60P/H/Z9+ePXm2/0fX7/pG1BstUtuk5bCiMKccegbjjmoAtSjQhu2CsUZ jlyTg6j/ZG59R2G7oYj4GD0X53GrKWDY5DSLqlmcfA/APvvYATWnjEIcSSd6XRfjYlKQ0XnNJuhR vBXjqTQvzjAseQuQJjt2h7jiHlUk3ZIJJcdD5X99WMjgoeBLsYLlEjlKlEs5ihxbMDOwwtANl0eT gx33nATRJh04/ZvJ9YHghcyvmHDKzQKvvbq0sS9UrOJBOynGeGARyfTFmONCdauqCjDU3+s7RtVW VYdFdjtpAyJxTjYJblxOmSnXAYCdheiW3Iv0aqqyftKUOJyo3Rbt4YtycXItbxOpmtnFvCPStKrU vVJpffhQ6X1nHWMRrWapLaa480SRVdXsm161rr3Oq+oiF8wxxRhbBuaFpa/HL0d7x6Txln7LTcmm k2VFbcSV1ub6XZteOV4aiZmUPeRGo9nYB8RluyF5NkNbbQKq7imZs1VP7mrILVMrFJ7ViArlY5v4 VYK7R3sSXWsrdiwu/fDafGuGFXb2jn1ZKUFw/8yEAxpXM06XX/Y40jRoEES7qyeGzHqUeInrkoXG 3AVywA0sEo7Mq30VVgsMZUXA9LWvFbwVAQzoj60TkH6p8nJLefPw9sw95ZR3NHyS2e/ntiKIVu1S 7fmwHRkugwJz+RFpO3gQhuo5s228TvTZbfbCsxFH4sVe7lHJvXdY9FulCVSRF5poi1LPoEYfWCCO RkX+5MYT8t07cV9ecgAZEhXbPka28LG4Nq88p2+QyigIRNTtwe1LIdD9nmwqCSiC7qyxAhU7Q8TY hGp0VKWai4ex04gVe0Knime+TkQu7bLjOetIuN6jbT5yhv1QuCodpodDVgUTRDjrIUWsVdWfzKo+ sZzrT5WboQmSw/dAKvQBCCFR9AOanYrzvxAlnkLJmtI1cYZ1wtAwPPV7dXG69w46X5eF5O9CUt8g 3tD5pzbBu8gdgBWBlvEL2G0dyYZj7CEwvN0DNLPRCTFmx4/A8PLJ9/te/GOJSOs260DZDUGhSd8Z sFYeoCBXN8Px/RV65MLqqdjUeKFH8XOsqAojR8WOdzDOwtgj+po607st7psTKOBTFvImw2ZsxzE3 OuKl5Kz62y9ebC1JZXVs7wc0wGh7g010yEaJ+Udhq7yMHBjnkELBxao/cWsb9L9ykeUu/v9jVCmw +sdJRjzk26eN8lyVp5HYLenwC1ib7nBVfqo9tXAF74zlOcc/otsaNwm3zqsOwgy3/EA1DMW3FlOQ DCIVP6kzjwl61rbcxHDxYarwQyA4ONpH0PAogDEhoVI5YkXUC8m0xHSP8LN/0LRK4wVug8WDJgu3 KR6uYoKRxGu815Atxwq5Kd5Ztu11Mc3odnMNfJnY3InlcjTlqMfHndXWO8TZ9j7tlOQbwQh0Ktyj bijsWGapS3ninZ3ve3f4S8Ygglmeg02pIyLxWtGEI7OJS7rGxW9Nl22X0tstjOtrJ0zjRh2yvDfz 4mqpVjYP1xKq1cpbsMb90IbsArX6p7rs99byJ7S5g+faFQNJ3feiJJLbGetQ7WD+9Imc33SwZBGv bYvE3tljEo8RlxS30+24bNWifDWsQtRpAnErZ5KbnPb63HLzD55RTlpFgNrKPIinErZSXzuA0WX+ rAu2Phj5x82noHOGUXYrOL6w6uBuLUAGfJoFkriZiMfdu8hWw0yrM7rxFwH1t/eVdK4R5FBS92Z4 XY6eh0P7RsFlc1t1bVcluRMqZwQmzjTgVCxiVJDIQfs6+Sl+ag/me7qtNEI0C5MskOWIUeNz0r12 3UFj+cy07B0lEofIjIJkTB6FdcCFyCzeU3HtzqQz7d5wjbWnmtIH4yC5eDc9xO9EY9NbnCsM1KvW IWK7EQWEesESYTYZ4ONzlKMQEMUOJ4hp7/3jt//Z1YHjveW4LhfL9386vP9fB+7JFuX4Ylqop79O yxP1G9mSzx+J/XE5nwyX1YLupROLIaZgHNcNpxmdW3EDcjcAK6Ww9xPOSkU7id4JFMKyDxyqRv4f J2tSrygDYOi9ERJfgPS0WtgSIu/2izPKjK2Gk0V1VS3ZXtNK4KuiPVN/OYFoeoS8oiqtXqai7pE+ xLmklj1SDWCW2qOrfLGqC517xkrQAkCOTddgloezEUXhsedZwUKerr0WPSUQ7Db12LUHX1xTaudy rkHkmPNkmcT3gEmy+UdoHIcrs8Nk08wRw3HFD2ztCCoc08ri9xwjySSOUbYqKDoitKtBJaEepPxV 1uwcG5+xMp+sZotGlcii3dQu81dCCQFHUdmz6I9OCcZgiRuMWRmhOfzkFMI/OUopGFp41IzLMnb6 j9/9vi9G44vRWdHQLCnCJt10p1/5w1HBPUtkprJ6WwfW3Q0X3TVrPaUWJBVVMeTNnpCJPqIz99Od 3PYwdDnGtRmFQ3D3qrLmSk1ySEbzGOnrZDQFEoxpQ6d4z4KIJecYxfaG1zZm8Fv4F50PUK5L4q8P Xr1983T/4Os4i8wShQruvzx88xMW4/QhPSf4QdH7VZdrk+JkdcZq9o6oOP2tLU1S+1nggs0Ercgs LQReu9n19GUbzmTrlk2UR2ZitWEqA0AjZNa8S7ZkWif/UonvR+kaNXHukHRHzA2S8V42vdQ2IfqV pQNR9X3Ec7N76NPmH9r3t5rbcO9x3VhD0RHwArHmCOJj89UKBGoPyMVa/SVtF2ZnhcT/Lri03Xv/ NcbpNhYnsJ0vigmetO+fHH79d598ohM6PaMvyPtFkmkV409fjq6VLbsVp5WCYjEoZU+gdV+4lBhg btmoXtCiYJiaCfqlckg/dDtSaRAwSGEx5VAQ8LspgXhPGzHNLsXhGfMeUAlKdFPw7Y2kYCZbCYpK BrVH88KPL6WtaWxDZpWyCLbP+WiqxCYzCwnLSYJu+z8+Pzw4fHL49mC4/+PT/deHz1+9hIV62CUV wVSxUCRJxYTN54d5OS6GdCQNtl3GkxVFzZoE8s6tjNIshSp06u+ga6xUuVlkCso7brIQnQV783zY VPHN/uE/PXlh6qlk2HFNu9gP6H9w+O2rt4eB4oxVgeL7b96EiwPmxda+W5Sopax4a7gZ/ODTHrl+ qMzCNq477TGQheWNSPwzV6b0VN11h/Q9MUhh6zL5m0japoRt21aXZ+cYgvQSza0pMDxsWLLUNDs2 ozClfP1vSllA4CimEMnPX3Eg1RkBPSclllPsAt0WMDodew/ijl7ACboklTZxaUA4iBpRcF9L2jcV BpH5YRY3x1xmSXxpr6Wuk59OV42dy/l04gHLybjcy8GoS33aSusGKz5ZLXYTVQTzu/sNI5EaROaH Qa1AZwmQXaO7R1gKerS7pkfklrnrUHTYFqeqF7x9uBf9yxPLHc1QKp3ApCW2K22ARqi2pAedwc8O Wrqe5sG0z9hJ1UdAvuSepbO4d2+tqk1GKCea0GXhnvlbGsoaHcgPrX0jgBJRqEMdTua5m6VTLzev F7esnUWuxmgp5Gesb80xDSp0PqxPTy9YO0abP69L0p3QJzVJ/jdYLn61E3i367wb4qGamA5b5OZy VC6hsyXsNCY5+KKoB1ALf7lmh2Ru2BAvxEc0zAWXTxRNxMgXThw/q3QLG6GRH54/O3j+3csnL/a/ TeyyaWiRFWfA1PsHNNuEym49EFp3dr/cQAfbAmfmx4XoWsQzQ7hPDmSAXs845AAXdScnQyPBzLOn D/4Xi+gN2IHuT/KEqabXGfM4A7AyghEzxU4uZqH+EG1ffXHaDgmnQSDvRcliqfper3uT24Qork/i janEUAQ5frIlq7XbxgBYsz8oMR3Tj2k1mij6MTRCWacxBdd2EkQHDyuvv8Ezwi9Dp31dzKoPhccS Caf8hrz5ErMQmaxAJl1TXHQmDdqsggW4I4KmYoYkV2sgo5EqwbAS51Z1UgTifQbGJJy0jMXhogOM 8i3G6rXqYLx58BPpKfynHz0v5KMsN/9wP9q8hdewdcb33n/z9u9QwIJBsRj6/unh//Yf2Fj3BMjD fGuCbsNie8DCOilVoIK4p1KG3byXPE2jNxUm3Hx9OpqDfHc+KycwetfmeWsr+v75YTSFY3mO6U7a 1s797XwXbZ13+66p8/N5+VRbO7/GjpBWEQ2eVbYu9S7x46+FMnc5vuGz5sxaH109v7GSO7UqkRb8 8VInKrc2z4eNrwYbVFhhIDars81yzVUMpecVD/hEt5zZbd3fyTR0jdQHbOH6Q42McX0jcqsQICHj C/6mtRc3hPPlhOvzojoN23PYEUVFHWIVlxC+oj9uByslGzdH7YO9wsxVAze4bKAZL0wwgVKV5a+B 3Q5qSqZUeE2gJw0DYqxtUSU5ONLNHh9BJcceBdmQELVSeeFC8PyhHFmZMa35d/u38eTrOB++VpXz 1yfSCyo44OpeM+RY7+EEG1l7w3Sgw6cuMIzgRzSDvZ5O2ytk4kbs5i2DZ6of39bey+jfTDcS6D+I +DAvi/nYuRYhTiCoxEB5h1gLDdE97oWHOA2yDy0GYVldANHUNkmcjtrlCVqp5dEDN6RFUUjDn1rx uZC86RXlueYEVHSHgd3Ya1tZj1UUgfBVoJy1yHImqo14XumK5zAHcFDASsHHiceJOeM5crp23Car lg1jd3/sPs/dWVkT4dofAIi8U87gooDdreO7ZjsExC+nKTWWY3eRull9Pa55B6CP6jyBpJ7zam/c 7SO1BIQfNj9HTZnc0O1jlqUP69i2TjLnjDVAGecZKGH+3to07IZgOhyxjeUqGl0xX81Ii047is2h KQBNQrF5PVomZnu8fa3tqCPXqRF4Alc0Ly5lpjpwVV2ls/OYUJbu+3U3x3vSsXdpqkJdkXIe2t3U nc79hKWx5i1QkM1W1EJ55pPtdXSupDedBGYJiMj7k4BRRsr5arR+Fm6xIDIL6+LFB+fBJEQSSmv3 LDAlkopYho72p+EyYntDPwVf8ffR1m4g4hLe8as6683mPmoMne1hx8LtSJfju83P87tNjDZGuoZ9 S9mNDjRa9HmK7kd8Q52m7fi2WMOnM7SZDQHTW9rWXo+rGVpiNT07gIUcSOJTEd+hLM15jbff9jLd iU6mo/kFx7nytRn4MsimGWS2vbq9fSzBOsWAPz6KCXvplUpUfxx3mG9AmR2cr1YjLt3iDSI9xfGV jeOBuVaHYrMU7mQNYkeTbQ2ojzGs5Rq/I6hYdxpty6ArlAh7bWfXdhh7FezxBq1tspEID0DSi9PQ amG3csEr6V7eRrMgkev0xWEE4yEKqLAM5xwyPg+tJV6HcyMZJXEqpqmPtVCtk8RaWArF7kc7IXnQ P/02kAxbC2/iVmLpZB3zY6nkuiJZ2rYs3Jt1ImTYG4etH9dyqrwBVPNhlxxPB2C1eLMAGpT7rN6w 9Ke1EB0i4GY9UGl39ayM6rO2YA0vW3PSe/8tBgCQJOGMee/3D//f7JNPyDUerTwxLNpwqFy5zpR3 WeiKXWIWZSz4lH8trKt5zteF0RAUKDbYPIRXvfHieoh2PiXHduBfvZ5GNeWbPxJPMe7cyHjtv75+ +mz46uWLn4ZPDg7RtgD/Dp+9ePJdryvchS6h1ehDZhTYs1XpgWhOXAkZNX7A28xmqyW5j4idNVqO S9JpqsT5U0/r0Rmee+ZGYFE1TYlZtjHB2qSYLznpuOtaqqZjXGFEnFr3MSCd3yOjvKDji8avRkix Z1lAppxWQppYdUkl2jBIRATOK80vW2XJkG9E+MAGg8HsHvglkMcD3gY62jaQxYKZLE+6Hg7+zl3W QR/LLYjJEiS9QgxvbwB8dKVYlf7P837qmkkeb9CYbSBLfjVk9bfJcIQH+HkeDkrF3Qqfo+xrqyHu rXOz0aWQGVKH3Fp/mEAupuBAAox4WIq3h65Dpcn8KXQdTIo0sMLkmb4eooKQ6JdpIHi0uGtYZazN WLzXW5HcwjY4K+19OeBaXvdvMKlv7wcC0pUiTDUr2Z5S3Wq3h/HGelu3G+xEPV+mN4yb9bjdK8+x EgDjioU6zcURfic0PjrNn8NKXvF53pcUiw1en2C6RKbIEtIRofbTzg7SiKkmDJl7QdjGP6uFs/rT Yt55+zBV+sw20lgtCCfGbQCaWXDmxaWcJQN1EqXtj5rCW9NL4PYAWitDia5musP72huDFUSB9B/c DznraCKXNQcWdc3XUHoqRnQSWkJbxDeHk9yGb12qqsHjQZfpiTODZaJF5aKvqKC+ufYG3UGmuOp9 O6AUw0RYj+VzACZ87iR9WHXLhti9WPZKcXCLjRbLX6kFsBw1sATKUuykgDOnoIg4o1M04MBfQhPj KI7uRY/CSzqK0EFXJYJtL65rGcvNsGgcU0NxdElMKbpYYX80A+MvLVc1U8LPZmIImvlMj+lmG0Af w1HCQwYph3JhOMkzzDwfr9k63C15vB+pv9w9jzZ3byQ5SyS552+9DCPKGY4dY9Amsw6bV/PbLWYi wqtxS4JyJBN7f7Np7Z4YJHfLERwiZnpaKiJrWoRc6yoSf0AJOpQu3QmDSeMniKvZCeDT/8feuy45 kiXpYTSZzNYMNBMlSuLS9CsayWIAXUDUpWfJWWyjmz3V1TPFrb6wq2q7qaxcNBKIzIwpAIFCAHmZ 3ZlX0C/ph37oAfQMehuZ3kN+PfcAkH0ZUkb1zlYiIs7xc/fjx4/75z2WmyVM8OP+EWxH4ymaQjfT 1aVqGpIemO66TbaUKRxubs9h/hnJn9LgZj3l1mJo5GrpWC5I9aV7NuUlQUG5vSSAhW7f1OluOCFT a8b1JIQqBDOAf7ZbAUXEb7C/XpW7DUjF1QyNxRuK5J4kMb3jKLlARoiYnE02GkaByXqPs4/1YgqY u2H+/dSR3d3kJQsacMAKot7uOrrTk+xJwaDctLiIw+tK066zhxacKHhiq9cGM5GPYHgUW7rR+MiL bCsHHHeWIP4fYQBGer3WHVpNEALY4Oz9rpq9y66m8M+2lpXt8gg1wK/Iqn6a8aLHCqEC/rJOVqCA tYMqmsd4oQVz9fb2Fra02JLLsAg4X2RilqY0+vss2/6eIdEoDPlh1WbQvz1TclIZ2Xt1B/Oah36Q fX1dbi4W9Y08Wt1hCtSXlXplJ6j6U2d2IA9onRsGBQj3OX/I0XjETNiHKdnU7c+QayROXCZ5UTWk W0cVQ681NoTI9co+Ou1fXA51vqhn70ojRSS09bCc4332FnZEPHLag64zn5nI6My2ikrRzA6eNb3v BbNJotXYPJ02RSZ2t03Wz4auatOc5+RAdnHRlFFUXm8DjoVbpcH7K5Pw4T9eXMhrc+VFIDCXO8Tb nOpOzNCWkpBitHvzwsD0rerV0IrKRZa9srh83H3M2CmUwNQ/ntY3FEcvKo5gfc5RB7VGTBpYLefw fQnMIqwERzGfNs1uyR4F56wcwOVAEP/MOvbsHMDwz0uKZkFR/kT3t0FaHJt8cafArYZgEPiF2VeT ldtZsV5/+qPkFRarvQnAH3Qa9I+R4JxFJ5fnqmMIIs8mQOakqjAnDJGB3fvQxDXA8nP1fzjXROOd 7uzYsF+Uq2RqGGoOkvC+7PGAbHRCpqEkeXOwgux2pAy5dwv7w7TBqEE5ovzm+yxpI3LipkiBXjqe 8Y80N8hveKMoJwozgnvNoKN8/faOOtGGcaaHyMM05iU2MNAF+E1yM6XuL87r6Wb+ApW0m13opEAi S5jH2EwewHfbe/XEqG9HGkG+XXV5E08qI0znsD+bRG6QO6AlSERjngWDOOzBYno5tjcChVDaTPBD nHwO+/CkWoFwUG3HIINMIOvFJnEj5iwtITlnZbpitKF7jYaeEA7sr4wVxRWb4q3HtrqoZtV04QSr IG46h6W+mN5F/FBm1iM66Cg6icoGFNB0k1Gt06tUZFpTGDm1ezEX5EtfrLPx2fMOFCqmd9rNC2wS jm1BIAv43HuCRni2wkEojIG5cjQUigu+A6IIElzBgfc1YTcmKAndjx/Mh5gZAzIgtok4u3kXGAkT NY2WEib1lTSJPk3E39DeZi96FFMo9NUnZAYBDU7aGKX1zSlam8wlZ/onRdjwpeSqEwGqnVXNKNKL vQ4T7mPXJS/JAa29iB05InLoNCJTBBJOKEZM/zQ6c2zKIeLawFFvtRUmmJVIq+HTEXJ2B25a9mwf JqW5TBx1RuWt2FpHNzrwhTfneCCUlo1d2f3QJMeO/Pvg5BJlcNtAoQCmeO2mTuBzOqaIbbjpX58k SAjUdU7H0qULD6wW2E9k0nqObRMTicxCNL8TibblrdDBX4kzMSXbr0zH6ZL9a3vp2XpHMKvj+w/S BKHwH1xzpXRA1gGsUF8FnG9oX/PJOPsoLpdlyPXdR3nTEhKnnxGn5HBFUwlLkqBDIdeydbn+6PFT 1MzXaCU7maCiAn1hObIXC9F7iGx5q5H1N6S4bU3tutxeoG8sCGzRKZcmIYKjmZvtXneyvkN6etZd N+VuXkuUnW58dyeQNNoREq3onOBKTnWOnoVmmkFuN84RpsP0y7imhdNHIcsVSji4FAS04FCgbg16 TwaOBUwzaFlCdl51Tjon2Xp3vqhmFEqAgiDPdg42JqToOCLJJOJ+CamEpnYzDkMDpWWSQAZxLvTV /MCqzISTU6i1zfTGlUAczHqKlleRxo1PfrCDoSMSR3plUYOCjzQZgo1sXOEMoVMhqa/9ZasBiaPl lOkVibFNNuVsBwsMwygajDcnfRNhVbPBRGCp6tzdaWdjugIYRagQ0NCHqp3luH24onBXgAyfRrFs j9zIGn9geALdT7pp7AnRVSLRfmpmQa+lcCuJml8BoI1BrtleNMyoKSJXIuDKjAGy1CP5GSL1GGAz 2aeRNYQRfIGtLBbnrPCzqsaVIKC5TCEZMKyzl4+4UcQcQ41GXDcuOAJHFBwMpVeP0VAwVR8rq1W9 NxlY0zbUszXGlCap33vxdYvtnyHi1STe5eJ0fhrT2hljlzm3KyYrfQpDqCnIoxcllbkZR8qLGVjQ 3sQ04a/COU35wbCluk26yzUdgdVR3gbeAp2U43zaMDatYQmvgkg3pZa5/lWQbYqHLaYrXjtMr0dM gyKbJQ75p0sH0gLfnXkLyO/D7YYRxKKVEXXXC6siC6aZIdJ92/3N7vLyTuVbEV844gf62+zWlxu6 2MaIjWRegBp4LvCtsFmJ9+dyVaLPlhlu7yizks+mJ7ifjBLE02C5B+Uq1EGOIq8NHJyEjY9reF3e rmHlb6fnTQhNoCkWoZWsSngJKAkVeVFFS1eGQ9KN9+8Ndm8oPQ7aOoZXsZ1F1WxdfTLIw4ENGXYp eo4RxpSRDnpucO0jOo6NMilBcI5jUwJUyqRy5LlEEeEozulapALCc1LMVaxU9D9gGeRlmkwwGwZz jAE9oanAoeF/vYZt9id9+F3a3xPjwlb9ARejQGexU1tPy4kVF0Qu+8RMghSoA40/7HnP+dqlWiE8 FLwDmWm+j56ObD+9TaiV4ynnGWZPztpnuGNHbSa5Nf4f8YRrNdZPFHsqJ9kzaNjnsn5je35pgXG6 wD7sRFdNlb1okuEpE73NgsPndLBRjqHXXRzxF1dBfZHIZDTx6izZq4qycF7L8b5/VAua0+rM47e9 kOFao+DiNf4IL+sMtP1J9tmcBVy5+4CTWzXHFjYlVPB5cUn6PwoXrpH8bqYN73piX2SqKIZ7ckPl TaAzH/dR3nfef/EGA59Nputq/e7y/W9f1/8tR0PjFyPq3k29kFiCGqBbo2oRALLuIAJUGMZBW1cF J8BgaPT8iIlz6LMrhgF4RzAAFO/srzMPC8AN4exDne01sg7RA54UT7q82aA5MRTfEzTNgbQLPsHO g2i3Y4Jt7TvHJcxSTRcwnHJakraypsj2DTupVk5YMmLvi/mSAjy6J1UpXRi2A0zpBoKkjIRDzwCP YaxoxwX6ggFeSKKF1U8okHJLMD+1BPAoe6HZTWRhW47pMxd9lAjYL0iDsxTO6z1E9dwd0TQfPJL6 dg9FbF6CnrxGaqdhZ6xZjFuT1YAWxRnO9pQ0r2eJgvitV2t6xf2t0KFIq+9MARsvQhJIICieHZ+t K56/6ZmJSBvrDcyv27H5zrNVJNjE5MpQFVLPZd7TGgFRsQevWLjH/G4kUg6BO0abe0o8mdi0Vowe ZE4X9F0MbqUXySyigOr4WDZWK0UcBWH6hIATdsjAtd4msFoNLV0yirFy6/E7AUIRLwfb0ZZftMMB cE9zf6Dc7Y0EdwcNQworYEIek8SA4kgkDojJrW2gLQg79Rbx1KCzEbkATiPTGWLtYbeHpJbTNZEK /flpJKW2lMA+ZuK04wE1QktG0fZsnNwIIROSFIzPkNqf2bChC5IB3vR2B35HOKABCWdeHkK32xEd rRNXxe0kt8vS9QpCKTsjiasx0Yhmdy53IvmDpnjQ5AKm4rcilhVgXwuXspBqm0AJl2ZnGUtmZDNM +qg+46THOhs0PCe0A8XTYpRwtBBOID4Z7NLwONEJsoQ1Heta8BdqxWEIu92UYCrU1TO1yFtQ2k0l nIn8UF+3giKMx5aX7/O35CSmS9LM8h6g8u7qNIgIKZIHoy0sIpRU3ax47Nv2bspr7ogkybgLfYbl 6Lw2WX2vy6gIkSLa6OckD+UBcQGn9v05k/f8+cdm5VAspIbvIIPF183kqnERe2z7FFLZvb5G4M9g Afk384vpHyrUONdLOLOV4uhr3B3hbyrmGTZwt3q3qm9WhWdAJMxRS01zR3tdygDS40gpmdgQzAWV TLZAY6mU3CQcnCom1U+Y3eBC+JCp9Ht7bE+imR2UeWpl3oN+sWgeyPUOtfhEOL0xpk6MePdwN8i8 pAYJ9rrkkHpQ36btlvAy4rL9+8a9S5m2CC7J0awmxeyZyhHohPNysW8kDo6GnloZ+3dq72OGeiKr tjsJb53N6935ohximRgzLsDbbQFYcKIPkgiqq8QD6yPxOeSNJ7gi0Ux4sZB7pNUWdQNy1SRiLRv7 0eFint2gBaPSwwmGGh4r48Nrwvv1rjeN+E7iL/1yBDF8gRZ5mpUdq7SynmkYpmz1ZA94blNHyCch DpZKkveALTAzQdhfy7522C0vUmi4Hu2V3OOZfh6LieT2rqfv+p33v3vz3/mBUdbz8/cvXj/usCqC LhkRzP8aQZjPd5eXJvI6ji5HX88+py/lpuj40cAdfcEvGtp7CJWOjca8GAST7WZnI33vmhKyOHEJ yBYuosBRB9gAH5vr9oY0fS5Nx2ifbMESxhtoD4MOPAWqBV/ykST+5vPf9PqFef/HIBo2Qqgh5LgX taC6iIMVSPv6UYxkHuTldDXF4UJnjgbBdb+Zn79YXdfvSkSsyCFrRU+5ASk01bN6mW/IviCDdwzv DTUtJQoldBUs6UUGhKwmhkJ1utGcyR9Qm5ryCeRKUAkmnZ2FMHgwn9cco/4OUcZn0zX0LHokeXZy 6ZvdfnExwTtQLxq0c5gVFoBvo1hLFYPktfMRqAn0sUaxSvY9lMMv0IMU613Kl8BUg9BKGR6UqRbN rkGBT3LF1yXKxDgSVw4ECJ4+AYtEkbDoM0rGziOeBB5y0e5bwushiFiP0d3wTVpVFxI2fvHdhjCb w3R0xRe/hcna636CJrL+UPdefD00Y5rhoilRh3/Rd7pIrjFxpsEkdhdPTy7XeQnBlIaGuKHLzJQu ZOTxT0fW2gbtA+EvUGOe5L8mKPzo7bacbuYgd+IXLs9bv5oMGT+I6MAZe21VMUKnwqjq+rSaEiHa cFxxD2Fb3nmbNJskiSVqdjGtFjB34Hx4SdYkW/VMcRQYREPnLrPaYnvO8LLjrLuqu2FdEg0U/0Sa idhpA5QtUPHPgUMDQBVYS/i+ULT1KKio+xUxc12YAwmbgvHULTh7/740cDKdw2T6zfz8P+yqtHO5 s9euWVqyLSpKAu4ufYT+7i32OCElQZ4iHbXbiGVrZ9xu1GGCmSwO0/S8vkalt5STCT9AmxxdLJ37 rM14XXprkhYTcsque+BbF9t6KxR725uWvOjaQosX5ra7aGucJXifsex5wzGRH6dPzxJ4YGtZTk5u HSBYb9amAR7YIkfXTk/Yg6tJZguBCZ5J3qlB+iDbxr7cs3cwgXlJI40imSsygtwDyUdI4rc9dT5H UuRaFMuAfNdbSXwbSHdanSGq18WE7GYYG6U7mZghuqrmcJSFnid5pi1u7nD8pJP27aK2codCLYmh 8lOBtrpb82QEIRC/WA0LXfD+37/5C1mF7//2zf/tgvbg8UG1sXR0REM2c2L0Y7ez7XB7IKSOPc7Z IgbCgyJtfC5U8jPDrzudE45oiN7iaB1IAbM05Ajen+EqyzFpkzu3Sh06famGuoDqvn+JkZBc6fn3 O/h4u1y8//L1//OXjNi9qFlorjnithy70AI1+/dvIPXw+y9fZhy1eUD1QvcmkrB/t5s3DA6GEwBt cOYkgl5u+KwHUjLqjoos+80Uw00TaCpdlikgUL3Mvq1hDbyc3izKu6IliBEanv4kAV0ZQcZcH3XP 6ShhIKprD+WpIGEom8O3IPgX6jb8uGAt8cSyIFAYlTUEghlvW1w9DiljQoVpjLB99WVdZ2uVnTQt 1W5I4XSg1kABGXkmmlUMuYMcjO9nYLrY5nCUqzCwWfp8IP1pY5rJXi7v9Qwhj9GJYYLljbOX9SXM 056kGgS0nA7oH3nkcMj7zdit2hviyOeKg55PeDJ5d7PwymX1C7cx++u3W5kacs14E5HmH4KvhrWO k2sgQxjhY/FnNOLgXwG6NY/7WHKHUbE4Em8ToukSPC+Fmxd1H0pAa3p8HETpolAimkz8LaJUk/mO +YuLQ01tRdRsrMZsavB+eUW5ODJymcgfCgzeSq/saCDVHFkOnHqDAkkrSslBdnjc7f8xIos4WBLx sAscGGUM101Alorc3XV7/a7tKWct8Y1gQwikUUQL7vzgPGfyOo7tTuq+e0NtEtOe0y1EYW5peKlN QtioYMYVZQNSHIcZJSgsB78E1aQUduFBM+4+aLqoYKcDA5nx0IHUQADO9Tquf9Yyj8y9xNvVxzqq qPVHFxWj5acy+170MARA92ZBOMvjEj5+pBk+6Tq0+DOkVElqCTvghwGwnASKI6yK3qnfSYg+yK4a jDiIac/6B2oDpUALxQDSr8oEF1LbzHZXmuc3xpPYWxySOUjid11cupzK9lZgfzknHLaioct4WoCL enWJ90G4bDZGTkRrpc2UDcJajymYPX1S4QBcZvQiKTP/WHkQTOIG+OqYKQ8pzvOc5aA1h922sKqL u+6jT1IQ80rM6/WEn65fq/xj6U9bCSpX3nY/edB8/EgePkm4nAYdmKiX8NPEZDg00hJJ/D/xiB/u MKknCpvHdFtrl6V7xfsq2xF1Zlt3yUT4z6W7oknudJd84+6Sh5+zu7w1EfZXaZD7f1wvRS1lv0Z/ HbFqzJsWlOzPNSl++mT4ZTmeQYuOuU7LfHB6S2txmlMF87P+8Yyvq3V59En3Z5hTgXIPSvB0e1HH IyYoN4I3y9a68m4bDgrBlwoBZrDRzbR8pWtEFPNQhdRtiW3irYiwrHb7ETevMul9NZWua2+rzlYl 0ta92BZPa9qmL1VJlgUj0tKjcwK9dvEs+PZqTIf8Av/ZZ0IgmqBDGs108Elflqc77ubMLzkbcn2i 5gvnPDizOIxD6+zaP3XCMQl34R83PcLNqW2E1V/TZc7l7Yx44qid7ZmjAgdd8AVgzX9A5PUhFl15 3xxKxl2uZpeB47ta2+4nuZ8b/wn3A+OKSu+jLHZrcA4CeHjhUBEtVxo0UVpvNJhhIfLLhBJOyHva n+b3uCvxgwbuuaNw/J5Dp/OPQ59ze9yXXOSe3RQ2+pTRF+Q3OWJnQYJqdTnOd9uL4a/3guFY2sdT s50n/VavU93mp8KXGKeRo+oEGYfpcbBMarckNarqHPT45MrPnaBJEjI3//hTVPgYo7knxeOubVOX 2tT91D0vhPmpZKxZ1p6IJ3t3Twpei3DeriCVQo7wy9Y8er0W5OL2tuZCBhJmEabSmofaaPNof7en r7C9D4qPLkh7EA5xa76staM5HpPPd9rH5JEZlBRBDa4WLlzVL0+a3RKOkHeydvU1c1wfDvuGArX7 34vJ9samCD9SFSd0dzVEvZIF78B5iPXzgjtKnWGnff/Vm7/kyAbL9XRbzEtYHHB8QNTa91+/+d+s uh29fSAbefzcTDerHjnGQFHkhkqZNSO0fr0pMQrYfEAXAnhDOZ9u0GXsfANdoAujEIUzXd5QTO1x l118QPYz1AwH0jed99+8+adYadFfvv8Pr//3f8EmP3JhIm7aUNwogwwVy7FsbTGH6kFJ9ZogQXfb atF0OturqlFzrx2e7LkaxfqOnR2nf7gbogEYkmh255K06SA52oZKvMl4TWY25CQ0RCMlaCK2NjuH 4m4yNJOuLirIhQt3+AmbhC6nZAaC4HWICiphjqYECzpdEfq4dZvqOFRRc7Sy4Gbbq4L9ovzwqFhB ItKQi9Svhk8fP3mcCJKaPy0ew/9B1/wq77CDFLTdBJQQvyv5UagnlLU/JU+Gf8glQT7SPH90fVHY P0rc18ScEnEjFgtvipje5bmBSte8AA49H8H/y7EjzI8IVARhs6rzBrE+ZVTY2Y52fKJCP0f0L1Bi I7P13bySzxO89MA9cUQvpTB1cYYk67uRay89wJhLMHlvsOq8DKrzalFt78SXtKRYGTnzAkpOpkYE +ncnqiTyCOtIs67q+h1elNWCErge0sKI1hBfZm5q6oRx9g+GNxhzdX0xwoZJypF+tIe3fLacE0RI Kn0hH0eayMn3rloscmdX9/LhR/w9olROri9q1KJ9sVtJgV6uC/qIMAEjJx3n/qMMF88rv8kyH3Ol J06I+top3hh5515K+9ovzEQx9suzoYOdppu0IyeysM3jRBhO5XE++1WQ+6+DA4z3X4nRba5XN7M8 HCVkF/Rl9Op69d2zZwwt+w28DvLuNs4Ye3nhC2ZuyUp3/Mli6cvoJf4bZgJyn+3g1Z660ne/g07U j1TgDWBlPkJhdSibIK7cz7550XFQR/Z0phaLKZOrhSFSkuklNNBIcXm8ttEnN1ucT9I4uRAWJfeP bzYXVZFSuOsLDcfyfTk4hZPFGBy9AMaXp7L4KZysr1XnmLeVZlM42Rx8mLytM9w0flZBu8hbSnRS OPlgGs2uJoIF0uSJfEEKJ+9uFeUO8kYpnNyTzwjsQj28c6/kqX4bBalcApuSDqkgVG0n9WKepwmE qVoo5GGnJSkEudcb2tw25Z7cXrJwieIMIF8xxmWaz9nXGQ1LtM8opTwcwfAkZWqNmtCreSK9/ejk 2JS4p5fzPFWC+eiyRrqpDGa9ZpCPTvLp6i5e+pocP7pp/W01SOvvpo0Zz1Q1/GEEoe4P6Be/TfWK /ejkQMscs/TzIIf/0cn1W0XseH5bbcNc/kd3khE6T0uHykd3OaND1KQluXz0pzD52iTH13x0M2w3 dyz95okM9qM760A+muQtY8Ef3QJsIKs8LsD56FWqxjNQyzqQj276qjlHITPdav3oZ9hTgHx002PM oyUeKVO9ZD8GWVDAw6NAnspiPgaZXJYfZQq5vcfnwwwpJo3jc+Hs69Hg0UdXDoCViMjVyQzmY8gG CcFlyBZQZDil9q5VfVAsUZGxTrG8+W59EYglJn0h1vYjTeRu4DCiL75OiRhOPknkcgacOWG+MJsm cqWTz5/xx3xPPpvIlZ+28zhrmNNJlMz6xef54ayQyOsg1/I49zOrHobUL5tRkNbj/001IbaUqH1A xUnryz1WlXRTzUlMbqGQSOvuGdMLtHDf5Kmx048jkyqcws0Sz9sE6FhOV6hfenS1XS4yK207Bm8H ZjSVCikhb2pSI91ganpZ6Ls7VtPLMLmXHr+7m/70Zm9y/O4k/0q1MHk6uf3u8hW668hby5Dvficv av+8eWLscNHitwebH5xVZyCTSKgphF5DoQae4edKAmZX00xvYvtHDAMUkRoD1fflifQFfoBqjUwi 97wrlUxmxMJMAl+e0cbkyUxuAk96kHhCeUth5nuwq+zNdJnIRGfW1KQxzQoPta8///rN67w9gyTw szz/9tv9WTCBm+WugQ/7snCCcDV7OitVvGU9q8FVfFBMdmBBy6EAUya3qHpGSrBUelI8S4KRJnTy 1ustGW7nbXk1wcikdHKr4rg1tyYYmZTunNydi34qT+e2CUZOWtPT/f77b9HUPtXW96/e/C/30rFL vnup2JPqdSVktOvyovP+9Zt/bmIdm9Pd+zev/69/+k/+SRzMGKv9GxZ7/BMsU1bwTZW5Cj9Rp+Oe GsV5DOUk8q4c2PgsiGBLcWYEOVKPqqSe5+xVgwEI1uKuO2GvhEl5u15MV7Qv9ZzfFqPrNar+OXHD cGkmES+Sr/DbYnFHeuZyeV7O0V3JgCdivZmLw1Bc1Td4WJQQX1MBvt5ebcrS4rA1o+zt6h8G8M8f iX+/Xf1JLg840M32piaq2EJ0jZIViHShQOTtTh2bAXl9KLQqH6/V79pLaPCQytvpck3LvLiummo7 eYZ2GxjunZ6M13av35d6LRASGUemslTIggXfOWUQ9jfp5DEkG6PkYZg2QecsEZQO8/EdGfvz4bY2 ry4uAiBm2Hwnik7pDhzee+R5P4rseyKDYAeGYiHUiCnNMwd6nPv7Tx0Pst2UdPpYojLRlQ8jC+qn J6Mz7yp9wdFOG/R16eX/kJOvnv/yj6mXf4ogUDyMwP4B4F6yqkbbivwtBph6mC0UGkswISSSgJiG 08rHNj52nmerrfMqwvKMm4r+S0FrYzRLoYz1S5ic4B0Idj2w02MsVDA534flsUeb6axy1RMUi36c SuoSR8nQr0rmcT+BrmFwabKH2MvA+PMPe9bjbfgEQ1RoBEzsscCyKuqzP4Z9JnwslTDR5DgKtGlG /ImbcMpOd9AH1Ala0T0TrK1Kf8r3dxH0jeMMGPaJUrUpxjokCr1jIkUoKIkBXPM2i15yn2l3aAmt 8ZPZi2QmD9oMXhyB400X69ZCF3PBGktieO8BpY7Bqf28e8vtfnx6vkHUUAMGdZY9aNBb7MHj2zk6 R/SSTpVSVxtrZpBVc9OCfTzpwsGhpnuFXghBfwTCjAHWvijSQQW9RBTIikG3nRBYRQp+2XY3XfgW z7/6+vlXr/dUIBktAjH0QUTAO/npoqmzejbbbbI5O/Y7KnPanga8L4aRV1XYnrjxmBA+CLbK7seb 3eqTbhGxVL4H2TfgTuk2cMBAAhCQaSCHY0vCm2kA53h++5aC7MPS02IHR9sYch0ZMyMR6yT7JOt9 NMg0ukS0LPkwwiCsKj6KbODfdGAC/BOOBSNLXkMvoC6OQTzvPuo6Prhi5yDC7sRIu0hN5FtDEo0K goLTrYK+ejrI/g1t/rQcQHbZooDpMtXu76FiXYWKbasHBl08UA+nNc5bf25QXTvv/+7Nv/QdflEB ydfP7797/bv/kV1+4fxyXc1LY/SAjWKXScz6qFxdV5t6tRQIZbwaZ9+yNHyOeC2bRtAN7eCnourk BKTCxeet3q/SgtDzVdB0OjFYjiJMrO/IDEV7gOJ/aAP4pEAnqxZIn+4QnXy7wyES7Q72QflwikRN YAXf0E+1U6VKqG8pz26sSzus0NppNu/UplQe/cb69JJXZmTOb/x/cXy7LfhC5XSzYNMo9Ugm4lmP ZP/hlMXv/h4fZXJbmYXmEodhkJx8R2IhMTCLximYmgtIndtk7QX8GVGQBq1wTat6Ob2sZveqq+Q5 sp4Md+KuZmYIcIJa1Zlx88lmO4JKLbL2zqV1cq+qUo4jK6pWhozxgFPWGFNbvK1gyfhe34yOQIgK bcBQ4qUti9FBQmfRw4nEIszN4EYW82pDCM6OWTCw42YLoy8mkz0+/mMoUrEc1EX/oFHoVQ2P/qB5 uwIRyuuKHpkhGnuwQbaOkSUfd8yxwG8SduIBkKt5HXvG28ZAjyON6IMpmPo6TCZRVg6Aq2xvpIfU +1x4sOrXNoUoWIh032Ry0FiiJ7RPzbpj5I4gcw8F6rfp+sm7FPKXDu44f8gislGTSEK0KCm+9CmP 9xkIGzNdyyEp8vMqZheXuBlv61u0XOQ1PuqGlez4UMHEfStCpZhoTUedIJ5BF34+GD75qyYT81qb N8ao4YAJ8HSxWyzoWuZMSjWVyP4m6LUTv9tcVvUTuy/iet3UqMX9ofkmtSizfv4+2Tt5oMvcIUHR lJL0cuB8KKxyPF5gk5lETOeKwacdSi1NLsy9ly8xAKrKCPhUsaJvU77fVZtyriaamggyIqhC0AFO DYStyQaLRNGtCfcY2RbZ8QmEftwxbUXUDae6XNV4d5nlcBQGqRF21D4ZAAKLok9zPXdYb01LZdPc 4dX5hgre1sPzckivMBc0ZwbMvio5PCBIOtuh2ERLs1x/LjIrh5WNcPo+2wgCxkQ8jfh+RjpZD3vL btb+fLF+9jsMmqlYgsMHDdtvDznsZMh0hdFbxuvz4eDUma7qEXUSuEQZz5GLAsWvAmxlRC2wWCU+ KydT6acieQu+QQKhXCYK/g/T7FEW4jqDhfb0cTPyFhohKDOZft9Ds+fQHQghNP4x/0E+4CYVBiDQ akroUFxkaLjc/GjS7vRj2hPFMinnPelD7R2NOlBur+o5dzitBsJWkSSUgurkhMiAXqZXgv+uQ4Pv iol+cfqcXmnMBbcQTavoEmyrU9XOnoomEzLC2LZv8EK/F6qkkuolJaYiiuJZLKdrjIM1YPwHz03S z4DhR2U7g8Mv1MlGy2ZULuk53yFzIK8R4ou/o26RkAf7ERI1hRplnP4wFEDVkFxYzbCTegEytkg6 GHnHy0Q6ETyvw7BQ545SoY0VP4frN6B7QXSHWGCWvB05jDu/e1HvYKIKwDYVM+q2QfJLz1EA8XZd R6I7uG6d4CQFryaiScFGwC9pRD9Jz8lhSNJT2Cu55+5HaN5O6kS0YPux2JTL+rrsBST8CpE7wpiH JIH8jO+DZuGrGHZYQE721o0XgzsL2lVTMqK6qSPou6ftAeb4ADWYg6zf30tgtt3RcUWB0pSXsnQL 73WcDtAxaibqMSNsCLlkVgMXO9AVrm1uKSs1J93//HBxNJ80JjjkDGYu+48IrPx2doVShS6JqPFe ZMuIluC16+pkDkyw/+welBvGnUA//4a+/B1vLEbV333QjN6u3G3NMDmDFIxDohijSSIWSdMi/8rG JfAn1yYHw+5yvJs2BqZBsCQwRNcX97oRXCcHpHGUfpIBL2thmCcTBUHTtYMfpCxZVU7IRkqRCPpI mfrOFR+C2M0pHrfmrhoeR05L2/UTrO1jt1mk77fZR2caZNhuezZIp917nb11uq4UXhwETie1rm7+ nuqSbsC1hf6pZDlzg1thREx574k3kkdCi5op7HSqJITJxTPLyl+QxkZTsHXWAKNEDDsIHnsfBoOC 73gQKCOM6fvvQ2xFxJgjg4//+PruLyRS2m5bo15kRmcOkMj5ih8HZ7NboZ6HjeSBPXU1O8KGCR4g OaMeCVqOwbX5hIHwtrSlywuMOMfry44WbitaYK7s2MGljII0nUCi83oOjYBVc13iFivVfQ3/PJuK 7OFd/lQNJsI52jS7c1rFPLJijhKR8OLm/W15d15PN/MXqG/a7LzgrUFY18xwgUQUPX9HJ+EFC04C SyDepVZGeBIaray2Y9OXhh95aQ0WKCcrnmES59pS3od4ZFLsqUvrhaL9Ijwco7j1zzxE8t06pEON NUkU5zmdajLfLZd36JhPYIEg+MXteRGiFmu79MPhpnGgNmt75A32S/royJyKFsK5cNVpVcjkkm+m oML2/rLfFv3GjYAQRARTeGUOrusiqRc0L2MxkREV9CZXbb57QiQVe1OPbtqdX4jVjj+dqLMibd7C wbGD2mHYj6BXby1SAdLBaodEgs+yvWM3jnNgOnk0gU0Nw8HWD4fin3FhfGYZo5ERFDvmaTYgvL8J beZRFLTdGuZAWAuZ8fbO3i0jhAuSHdSTmjFCLoyvYN9zNVJIMDwJ3A7k97bC2NfmoS30UaGtz1fl jSJ1h5Yg7pg4yXoJ0DauFldF5oADOCAwPOG08GP4uG2SHrLdFeSR4+oB/qIV9g3+rPeHWUP9KAsC 3r9Zu21oY08/pRCk+TnSxJ35f2boADGLfX/6+i8Y6rhzPm2qmTG0Vnu6KdnFnitE8TRT2+tHaoac NXD4W2L00u+//56Ci5EBAxsNfPbNi1EGB/e78zJDl49qy77daIuLmof13acOtAnbfb+kT2lLDbxM GYuVKNsND5LpSA13TEJRkY79GBGYC4vq4Q3losYDyk29Wcy7fhLJnEiVbhLVXn5jeJotHjrGRVH0 05U7vhlBOzyhSG6bma99ydepB8Fw1XJelC0Bdo9+habpz07KaILWlLMZUnShln0+VvMYSi6GKWO2 ttE4fdCcZagw7XVHQs6rsIeGOmm2iXhx3k7BhfUV9EZbYC201Ijf71A8aLk25DgBzMohJ4abKzhe AdEVdKJccTcm0BJMEKtAQYAH6+KQi2QyEApbtLahY2yDv5dke7qdY/QPRz2GF34DvuUYZOV2VmRv GjKjhdZgKCqQv8/vsm/uvrkbPimeWENU+iFTBiM6yS80CSLYifomW0ADN9ls14AwX/3B+r9ojz81 fCIAJG6bb/ILcUHKjcQJxaj3/lFKdxmbLyeL2HBzcWYqg63pCzGg7Ye75r6pDeV6tUvHCfCTjPUm eeK9T5dq8vhpD8Y41On/sbAKnZUGEthbDBPrFuNQNjHE0iH9SNeWq9w4um8YNzP5TVg7EVWDKsFK Y6HGG5g4fJvSi8RE/eA2jTV7LVaRuFZJbwzLTI1NBH0Een9Tw+JChb9O417T9wMUwUZpGuUNW3Fp fXWijnf1SUihNRoRfuXcyrp9UqoNV4b0t/z+S6pCC3tvY+dta1X9gPaxyogGMMv1nXMB0LhEUJ0F vw9WpJgtQHgJsS7jZHJFwUS9insjYPlMMAFUBWSGOTM6QZwIbNpjWEcnsOmsmHdfVKu5xM1DiNVd tSWFqCEJLPZmunhH4a9Ez3RJphU+OSBwTsE88Jfen9rh3ho/ibiu0xQj4iB9EoGpdwFrAZOSBQ2h 8BDHECbVd3vFOzVW7A+wggmIpsymHwfZ40E2fNI/wkJ473Q5Naipo+rsnuEVowuV/RMTJftcGpwb S5+Jfvfl/Zb5MzC9H8wkiolph4bUgvTSGUQ/xBlqj9DDpvoDMx7cphpfJ2PORLZ4kF0ObXWw36M9 C2+h0b4XWOwnNlTDY/ZsqobsJNotiSxpz1L1pyr2U/sIRowUJTgkx5sNYY5T0YGTLQtmJ0HPkPTj 5JoRiGKg1tu02iIeT+fmTbtHUyFOI24aqdBsYTOSEnsX2sV2yijz8RhpXbCBKKwNF9U7bqQpNrgZ cRj2F5XbiAMM06y2M76up5esMg2XQ2/ZXDpiLbIfNZu0nWElUHcPZUE065Fpg2BW5Hb7jIzR0LQd S3soN7hJyQkq7O1xPblDcNdq6ypNUiwOZDX0Zf9ydq5Wem7SjreH+qr4NAGbuNM56Zxkz9TBGZ5k n6fhjg4deNw0cwIdOTnEIs2mHk2nvhwgzCgkhHF3jxf3FZ3/F3biWwYmaZx1fsGnDbIBd5fPBd1Z l6s8FLsFD/WiVWyzs/CA0IZd4LJXSz+YZSBq8jxrU15NBJD1YrFrrpJaKyZL33v2Lg5NLvePDIWD w35gOCCqF0P5Ue69YyMOFAOBUm8xUKXIOdO7cj7hcEqSLDvfXVxQVLdxaCsgWjAiikd3+pHoRQ1O jaMpj+FgmkIgnfkdIkH79UsqIaEGNHH7QRwbehnIoktGNvNaQeAA05xcJm+sJ92FB7w7sT2KNP58 EzPYWZhalwrs9g/0x4+a3MbjxQ7Q4TmNLWbNU7AR+JPZTmHh6sj4A0YPr9oZfcY+/fcrBIOfHr2b 8OpkHIDDJeCINZQ2m0/LZb2yCpHEqoStrd6gppT9fQLYaf2YVBc4Wan/X37928mLr774OgwvZVLp z59/Rlp8bDwS8J+eVzzJndSr0KEo2yJQS41Hg+7zL59/+9vss5fPv32dPfv2xesMRjP77rNvv3rx 1W+zr75+/eLZ8wzblX3+/DdvfttVOXQkGKQbMh7rYuu7MHnpRXxrqqoAHsUBJxtYywu3AfK1712c toXkpuu/92/f/DO5tlYDt/dnr//XLjsGkWGLgNjOxHuCfaoYx5StIAYS+ViM5kGM2pRoYqxRABHc TZIWomQ7yYY/139A6wVHEVRd3M9JfG9kbGiKE74cjzsM8yviBus2l1Pg0peL+pwBBYzRULXq6NlX LtoeSbeacsgVH1YQA8Q2BhKhvMBQkKL/Nja6mRonI5AA2lbfsRPVHMi8uMju6h2cxVdULXX4QgNt PLHJzUcjNZpuyXhco2ZydMepBAZR1AEc85k4QMLBBNH5N4JzS2RG8DT6QexeYBnOrqarqln+4Kha E24hVOOeZ0br6eNtl1c66KV6SRk9MRJRPYZCMM+JCh9DU2UWpGAwTvVkcHWEuxqQI6UwizLzeabO EkM22fDs0XWAEKdnSqOpnfXDD+JhYYvBO5IffijCjoIEtFD9PrK1kTky1dVJV+iEl28V2IjFCN2D roZsLhtXKB0FkUtmm5B+0TaGsWsP7TpcMWIf5QbNa3SIMH1guD9j+6zX9uSlAVT5qo3d4QgqRKKu IyHjNyPNErsaCfJcrRZ1vU7OAPx4aAK0RHl0mja9oHuB1IhfTa9LWLcUvpOWpD1soNCGaNZiXU6e hyYqKrsd8DUG5yeLiHl6EbWGonQqKcyD+bdgSQNrwXASxClCmmH/9fzYFkeMrFDIMHfW005SXwZv PKLBSo3Jz7t3ODGw1Jz9l9k9pGsmtsBEV0oimc2mZjBQ2xqeqY+tdlaDnrtdGBdzeGJrSvS/ri7u 2FNBA5bSUzzahpmwyk2B9kF0QlpO/GD2kOhVKwqD2S+iGQZyy4RjnDhdY3+2rzM7cNMmYwo4hUP6 7Eajzey58WAd2rKrYO/wDllei78zuY7yjEanQTysMgKR6WAi4u/UKGIvtrIqcH3zEqZYBI5jDgmZ FDmXddRsaIkLVKUucUgw6z3ZqCOHeKJF30kviBVN1AtO336Fh0yoIykT/elHfpjZZ6s72kkwdCrR MYBAxPT8PZj2OSjyhx/Qp30qFShclhxW9di20THxP79mdSySH29K/txJtIQDCVkDQ/fgJu/4LqUx dMgjOLGscO3pvMffDq0bDDdNNyr0GZeVXa8xNT/glRfqyq+ZrsO9dZuXzCfKea+FvdCQWPZhM+CV kmgOY7po6momhNQ11ZHKZqfulCBpwV6KJTeoRAF/hj3qGwa79+Vv8hYs57/0ruWZEbPkd2CVTTOO q+BMij0LLeCdAfobYZdNZ1fO3SR2goRtcQmUKX7ANM3KPadIL3NUUDinIcZa4wjsDnVeqcy26Ug0 r0mdRDXhZe6kjhh0quMOsbL72Wy7jI1sUWitPHKWIl3ESaQEOZNi1GGp8kCHpdhTceIGB6uNk5JD AfLvgNfQwWK3gm10cWfGUCeyL71YUodKVSSCCVnFo1nr1DH7x2INVkFPUenQsxZBirYbPjZCMaKD 9qv0C+goxL/ESMO/3PJ1RR9knrSdcHBG3Mxcs9vAaItxJeMAmkQiIblpEhVPwz3GHNf4mswAVmo+ si19hKPwSI1ArahbrWaL3VxlIsZsxsljMRUZIEUu95kZ2222JkQmAS5rMHQQ7BjweXEntgwjWTvn db0op6sRi36kM4aJsKEoTCzOeYfOxrnCFLVXtPbDfjk0lcOu7uE4VTAcC6NhuWiQ2Tl924AECEdE 6dcNaZ9kGgO59rFie97EArVnQ5BmEkE+KcsPP7RTtqlShwWJyskhjrCWP/yAafcRNIbBaaJ8DEhW dh9V5GoiGvCiwAypXWy0vhuRAn30g+/YA5RgLZPjwrdE6AfhrsYryu5xMRHjOoGtz1SBd6gwxOvE SCw/tE422657TLc2ec5oBrZoX8n8ikir+pZkX5h/V9AAWn+8WdKU1KU8zNDi9wb3TgMSQ94Y9Y1b HTPOE8rfrmBwVReSSMVNX7EXUDzUH0Fy7Bc3/m4YztOpUWUs8AMa4mxY/BLabq/9fx4pMAhxGvaG DIyqI0j/17cK63gthpFNo5im7kHlqhbXN/KR8wf85+5b54jG5r1GjywX/upw+Ev1NBdDJq+CkGwU MfUaNoTyAubjprq82kYKcRcx14dIbjJxfyUtDTcEUm9kVGVD/JbJGEEd9kGRKx3KAw4teFORul84 JVrsEYn6QuyVNDSiPBmxHi1y+QxnMHvPdxi70b4gQh9Wqw+t8ZPmFszlAgGaaSsBzoKiJZKwNoKk eMUsHF0It2lEjIRim0V1ub1a3LFFIWEt81VGY7i2Q4IPDFAJDuLpqFx/qTlXrS4WuxLEZ0+e6Xm3 a0GI0f4vNhP3IMJ426SMEfeWwOnh7gwHOspKDixynuc627ZFVwhSKIn0xAjirUkKZnY+RLn1st7c EQLmZrsot1txqL0uN+c1zFKyB8Xi/VLbCjy0WUSxXVuiumJV8T5I415BswW0Chej6Qqh4lQua+kT 3IrJQSeQhqQ/eiwhDjKOnzaA4yryYZIajRzpjAUuADzbdVwjXAe4DRcFHZa566g7FCwRuxctEtDZ RnySjaEJ14IrMaLjc6a3Iavd8hwGp1acU/xFAoaFYrCEbPVH5ng7B5GCAMXlDvoKsRvm9RbXtvj+ QHcjW4uEJL8P/ww6GwXb/2U3ZikFThol7hUT9daRv/E0EcGO70wxiWgJWFoVck7HtRSQ7MCfuQc5 hKsRMPliLMIa/IXVXxEukSJdRBev0ImoLxYgUbl8vaxRctbM8doW+rtVVIJHOCbq5khceUg/sRgL J2YUKNJKVtOlHCM8pvVO/O6ZKDreI0FcRWmCmj4z6WOahMPVs7w7sICyxBhbjJYsEXn/92/+e/Tl DGLVvp+8LgRigRwB1ROwbgZu4AobqsPBT6Bd1X5RRvINmp4Nsm9efPNcQDG4qB78jZfVDoO64o0C h/kCxsbnXTIChhw5K94aXESEpSX1Fyh/sp6WAornnLNefcGAJfiSNR543uCbQb5ilkOGsSMxqhGW mNTKY7rKMCx87gSJwGUM7FW1K5QZx1/jlFGnOEUVihJB+gbbWaKIndcSfMEUib/QtASkmRrVLo+0 h0QiNPZrl+VWbvg1KRwdVODDDWjAxZICVkqBc0KDHtZvXn8x/HXuB5Gw8ZFtNQsaTBw5FBPKBUNk +wakUD/EkoONXQXRRCK26Bu7lGF+DMTdMHzPVljol4idS2ZsMmuhU7E/2NxZsb8DVOnTx2fZx9lH o+wEdVnru4/wyga9uoOeHPDnp9gznVZnFDW61k7G/mnr/ZPs96wzXsJez/aa1ygtdALvlDbDsj3l iUmkeYtmqjyKJjdaUY61kT3qPe23RO6wHMfFg7pc6ZA3qEMHbSYP02GR0Bm5dY1hUzo2AgZ8DnBI smD99jjVINO/NA11VnhoNvBSbTZDIhbQfn8ABFPYXcO630SRtsIGJ8UPiRAY25pe4B/BR6cgHmTz 6CeEOqDjxTIwsOZhgn/91zwLqEOOc17uBj02yh7MMwLwZdwfpyUDU6GBqQN6HUjY+oCV0r0FvSMz 8BwBiP3dh8ck73iPUPugRh2zKIMPPvB9ooC8JRdjF2EeqYEszJ6/MgfWMUf6jU0/f2BcBDHRfD99 ff4vvXBPtsIaDpcw5vmnloVAIs76J1AKSQJ9/h6Ps6Vvmht/zoafaCY8EFCw2IyQkQTKtpaNRzJY Z8Rv9RQaZk869XneDkyKIMu0RgiFl8QB0tSFm7bXb7drd4gjXgUsiQTt0PXLINvB2cp0Uj9b4jU9 ayKEbjdyATa10vbbzuXOYq4SJzNOGx2Hc0dMpXyfss6H12TB/T7+tCmXLF4ghg+5HbzvR0VAHeLl HPgy+plW5e02laFSS3JTbujQVmWfZI8T+IPZMAwWpKiuShKqflqdpcNduM2s2pw/kVhi4F9t6/WL rcbPDPoG+uxyezW5wqDGh7rIabRdsahRG+O/e9YpfO3RRDj33BJR7r4VNFr6FnkH3rY6uno4hfKO kUidqi0QoQn+3Vc1vkq6f9VwGbZXz4KihnW21eNI3oL108rnhGlOZss17Wpr9Gkt+aprR8L8GlVg 6o8MS9txsSXCpn24Pa/HxmVVfslSHT92mg+EpUAvag1jNLT706NrKORKumJonYR073aQ3fXT+Jt6 X2pb3rsFIRUyxEGPkhFi7lfOPvoE8YV+i72Sr2b7INnIL7YZEUQeZ6rsC4Nleyjdg37nw79RbVAF bmesOzSar5X4osAJ0ZN0e8PBcUqPvMyTMKG89tPunSWKPaddh93Ymzj9irbkZwmIMrtyMHyjiSpP /NN90bKS+Pxdbs3JO8gFchmKKxhRsd5dXnVQjchmHSA26m+nFl6QekjjPbfUIcxj01u6Xhh7SOM9 t9DlXddLGSGUqiaBbKCs2InjRHElabfAUzB6m0qUSWAyeN2L79Z101ToTyKGTIT4TL5PdEjUYK+L kr04nokt2dPirzK0cKVRrW+gHPliiMhZtCk8dylFUfTaFAiw1kIj73Q42hkC5kcAjgP0TIPNEUkM si/LZb25E4HVI9/vtEZdcoJJoaCc9brkcT1hnzGYxX9D7ydj/FfEJplmGl/KBLmul4xCcYPKKz9I LvvJcMsniAwmlx7kE2oPKNsag8kypqUeJMexc5zjNExJz1EpFjBDg0ZXzEs+wMYH3ATYANGLcRIE RE7gXMM1jPhwthFVQ/Xp3cZnLKegW622m5FafzAfVs8HNhQ8twsfX9AhoM5uFwYUEARrzENAwwwA 5lHEhOiTdS+a3ckE80wm3SRNg7x7D3qYJ0UPpyMZLF9AOnQOa2TbX9SzJjFlKEl6Bz/neJ9hED4v DWcfU9riYsLeaD6wOBZsU1B0nSbQ6CzoaxD1ErMl6yUEqWgrwK3VERkb3t2cO0eZSGdlgwSuYT+b zt3gCXh5tgjSQ7LZovY2vVlNYA/LNblPa7g8LJoYAt6SrVBdDly12gaB84hx9Ga1DBCPjTOGBkbD R/6U6aBnQVqRXXVXRadcu68LJ5roERzY57SxjIm4DfMUq8lK8CD7YBihuHDrz44inZLn4dj8/BGr nlbvvde8VP5nWPfVkhb+f/plH03XI/hA/z4q1HZ6bCMLJOMa8/bHKJ4MIpfA/pKwN7Sc+Z4Eb2Y+ eid7ponIWQSoErh4cyc+LwKkwVu63OCCQi0B5uAvFLSWUjudQLALGAvWIwmvW0lyFpckpnYZA03w HP86ROj20M1F3wmrw6qlPVE5UbYgPFrs/lPcUW/79ljKuc76+/U81Yow6N3DoRc5IPPj0U63E7bw DMIAmFLjmopgoDnjw4wLn1Cug9gNPrTCbYC/41THP047+WBMgs1uwoxQdh672enDsTOUpLyWCTqZ mEB5V9WchVGvx2QjhTLTWxbtncfspUhhzMlbtlPeGltLkg3SpxNsurq/thIxBMIKYCc99Tpc+3qv KP3YvVbYlDRvezPMDPN1kG3PnUE62NcBiA5RyJ1cXtgRXiKQxtkcRZ6H8T1Un711kbtVJ1dH52RL Fx1BlOpGqNKrMDvePwu8B1C44y2+9yH59Mf3xtbkrNnNUOXPfvsmCqH4jZhpLr1K1DoH0M3bNqjJ hMkbLG1ejPwvDNG8nnmDI1vVC8qU2KfEGkDWDTzRnBIhzIzbh2o00Hl//uYvfRtnE/z2/ez1//Qv zB1Ee3CDe8aO7TqxY9vDpw5X9ZBrkrdGcE0GyNSAn5zZCZtqQsyS2CWOOJH9ZRTEmGKRHuF6fkIm lhNOxDFozAW/uD/4EZaNTdf5nRBoCUC8raFRW8KwIJ9Xtju5AeGU3c/FGEeIsLqOwAOu1PVeow6S umKKbrPMxDVK9kn2OY7JC204DFfH2bkknJqJ+2J7t28Q7RJpOOSqw6ZgP15NpuewuU+WVYPGvLah 3jGBA17Wi7n57MOOq1Be+D2aonBerdDcxgmTThC2Ys7rIs8cIO5SaClWzyFSZi9tI+yGbpoYoy2p MkVCa7c+TiFPQraxtUoea6Fjp+Qxlx8FhYLZNUFzYg33JNVJRobStHvVxCA9/ilncUzT990+jgZA jj/SY8fhJzgXh9ru3Jss7t3eUQObmnEHqx3NsY57ON9LMkjgtX7/IhnFkETCwqz4p6cZr5UHY68I dBEWTybj+KPXNUQYyEZAXOuLiw+6e0NqZd2shxnQs5PRF4XhDr/+tE9RiE8QupzMk5zjM2ITUbqP rKq37XTdchUU6gMPGfQfMuQX35qK8cqN6T3biJOaEk2rUDvaPKJfq3mjAgLSnVj2U9VFM70oiTdw kcvpbVP9oRx/9FhMT7AKLTnoW5xFbZbhmPWgyeh/OSJ2mrLZV8FSlrMAzC25lMYLk+nyfD7NbkeB pqC3INsuxkoVhW0jKpC2PHYENAPhMbVnwM99U6d9KeGr1N51r3Au4PwIRxfQcowTlo/HeXQkE2UJ dhPvYvIixarjEifz6uJiYijo5Anu3agY7WavKPPyyOJktk7K9xOP3v6Ct0GZ2x9V3OEmkpbHLYpe 3LsnhQWtSfFRrNn6nekO9nMbD88uSYUr40GxuXFM6F6kPYbVqBPL17ovmCukF1bQjpt5mvc8HkRA MiTJjShgbNkYICUQzHKvuTmIf9MKDpfqxwac8xykWLT9V1fyK/KBJ4n4zsD0F/08NJncGHth78NZ p+NKfE7dI50dLTYVG2Gz3YpzMCIAXJYokpKJ0Hy6nQ4c91zdzI2mE8/TJYj6Ii84Rfb72SfZrx9/ +OtRa2d+Tj1CgbStk8S2rtXRBHjWBsHO4NiWS3wuvVIVhnmWPXSpyj7Rsq7NpvCtPSmGHl4ETAy5 obHbGwSHQiodi6hAZrTNu2oNzZ7O1YgezrXsCTa7miK8W7lpJLKGiqcV+kthkDo8CLwry7UtSRQz vs1t0FUSJxp+PkZbUjRfQoAvRIjDFqLSjdpIM+gP5abO2NylkwBeh/IIfJ2XJA2frCv/ggS/n1Zn 2Qdjpg2/g2sSEyhTrIF+9dQhQGZAj6OFbSUG2nbJ+eF22zpFXkFXE/ow7Im2D/M2RpLrqDgDQXEU Ly5wP3WMjqjbxtLIkXMJT91omjw6c6c5c8fx2Om00T58e0ofQ4FToUO3a4dh38aBSBN9HPbzgb4N +/fhj+hg7uXUfE93c9jVo2Hw0e9v8zmsJ5qPFyiQrHuo3G6J7AojQH6GJIHSBoJVWlTnxQp/0Hgw ZCiZo/fusyNFlfYI9c9c9pRgSYf2/lH7sv+l1m80Fz7bZhzzFOYC9tcIYfMh+4NNfiD4bq8aaHkD U1r/rJ1d2NX0SXIxRXV7iZNIfCwaxvMiKI5BuM2y7g/m/WZKKUYiSydE91Nb8tlAassqYlO7j4+r 3bc0i3/G6nEfmnqY6iUck08Q6PanyV8n95C9UvN5e+xUpmo6/CAbch770eMH8BlT6aQxuZMjoWEh 8+emc4krEUYxlgX1HLn3Wris0CpVOFdAuYV6ME7kOdr3Kkg1v3cNub2HqhjQvncdE/zp/fzN/+Dr jrfL9bzavC9f/x//NTmAqQcSkFnXGzymunh7iALtIv2gB9aO8KHL2ynivIxGbmBC46HX42Lc6196 wYKkBMPry+2XPnY6RZFNfkB7fgSqovuBH0ZZUTyC/9Grq+1y0fFD12GhGBH3GAUwXWSsmh3qT5cU QY4C7UC9xk+CCzUvNJtePkRddMfwhmgpFgXoEchJVnRMGdHHbK2o3kWY4S2rmHdonOHzU3bMFutY zJtzD+YW0czYv7M0alz4bYTKdwgMtildCGNoAxw/dqsKtilvqBU6zCeBg0+qajZ+u7B4NBZfWdGi CDXX8W32IthIEKHJdF2x3uqTJ8UTvBqm9lHT4pbFhvuik2sZRZxy7LDBc94mI+NHffDmiok0zpXo bXADb2It07R9/B00G+lYBPBBGLZWCGgHRG3O4GjN7tyhKx4cqKmx5QojVaBHhowwcZsUsQyJBYto Il4spq7+eUTiNUjLi4kFJSvwk5tGto8NyGu781739O13ZziIaAtiwzzcOsRkwJbvaLD4Ao0d28u5 Y0AknXyLhksLrCgc099fhCHC1c/i/eWb/+qk8/4KmZt1bjVfqzc9QmMHfjpcwMRF2IDzoXo6Gg9p cpD9fViGQg28f/f693/NPrIvHFyuCJNBhwpvImm8aX0bf1U6WNKYXNb1XG20SJit63fEG9iD6nq6 qepdEwJz7Qlfbpx2f9JdX9wiHFD3gYCjxl2Gh1u0Xwhe5yAQDYdyvncuBWf1buXe83n3gJLcuS58 PJCbwGqFKwRvuilNtb2jq76W4jeuJsW7jyTaWBa3Cs81jVMe3+QiIB6MAdSWP1taXJnmqr4R0Y4R hUSrS7omWMEW3fT8jo5OTda76JMKBPozaHu31/RR0bDGj73b/oWk633fR+V/OS/au3nB3Yz14Sv0 1nbbe1hsvM3QfjXrtlVNKVaZudmHJsntLLVSI8LtqeyQu/zYoWkfFaCYGJQIjG+46e+pzPY8d0gS 4nw8LdP1255LclPBfFGvLvMo+/ZuXeIkqqsZpuYfzfhUkmc5Aa/gj1WN/+IZk55gY7gu87OIILfU jIEYnVEwmx7SfEQEHyGdR6t672AgjyJC+f5W+xPH5Nozb7wLfFI5zgSnyJs8EhWsIskSUlBtj5Dc OFobbiTcGEWFq1euUatCygCbe2a/fytvlWLiZu0EfcW3sJiv0JZdvQWooxlbqAGxDSWt6SUeAbeZ k1Oi217h8Z1gFL/4PKNNp+j4bvB290yb0BkLWDxXznfrnFX1xkmSQ/ayqR5MnWPCKa7Kmwu0/6ub Yo5RydkfnAn0+rGe5YTnVhcRMygvbuv4NxVs8e/QiqAl3KK5wdzv4WQ6Bip4MSc7ZypuIF8KnOWD 7Em/5Va9mGxrMmGmm0SvQ5258Fp2uGAiaCFMXAim4zj0lBp0f4hflPd/wp24VN8dTB0D/MD7b9DW 6IUZ0E5L7xgzbw0zx3WHpeRX0bwms03es+CJzEXsfbo1IBGebU7ImjZ5ty+Wtt3Pn3/z7fNnn71+ /vlIODaFoS+neGmd6YYhkSCKgD1jS8f+KjKgAK2V0MM2nL+3coWtiSTEUHfQTdyCafqx/hIdZT9l fGESQ8/Jzt5tM8QwvfwQE8fX9KSmcgnesnxwHMHbrjOYLIi0jh3LOmYAnZe+6htfkZIylUAZNKYh /5qVU6WUb6lbXczV8Tyz9et9gM5M3QsWn0bOVcCWuUC36FodoCSWgUqlbuLUPAipxF90fRdDSn6D cdc/gK94TA6Gzma96MatRzSHWY0nJU43CN4XO41qyQ5zIYNrRbtQxkPLKDAj1uj1GBhI50uMa9Fw 3Gc/026Dp3fa3uyh03elJDvztBExW6C3b40ccm57Y+wttLnfofaIQwz2oxoh1jqDq4Xuv+ID7q6O FEu0ei1g2/heuhCyOL1Gkx66JJclmo+y/JakPJ5a+Nzkf6SAwph2QPkjrYYsr7Bqtg6kKZtwg8QG TKM9Co7dxvOJwy7n1n8wTvRJAp0g7DP+4Q+VfnOGvThHU5KSz+yCupyIGLi9KVBADXin5PuxFFl9 qEQeZt2s2++0pnJ9kbg7WSOEWG0X1a0J04cPAz7pjbvdpFMIseeozz4YS+7R0R2Q7Hkmsq/JnMJb YFTf0b5MlMJpzuGKDJ92Ar2pgj2FEAvJDvmJ3WCtGOyImbIZtxFbA4fwd7u1Uxe6JGTvTfwZzIig HYn5Qu8D6mE9mnJtsD7Wg2xbbYWhJmt0ZMFMVMklS0/i1XFFfNS68MZUzEoohQo9GPMyMUZOT3df fPX6+bdfYcTGb7/+9pMMwy76fSoM7ElUxRgJUNaXi9bnTR3vfEenRn7lV3HZ4PbU/eblm9+++MrB ChRfIMUb9OfXSfb999+zbTaHKUKkriu6UMnmDJPP2PoGixtV2Z34Fo017Tu0aNnu4MReLu4Eah/P fruNAtqhGXdr9svp5nzhp4dOuCH4tnAI9g4PwgBGHc9YgbJZJRAD2/ucwQNh0rztRGuzbXAkpgAX AweR1bzXVccBZIjDJwdm2OmD5kyGzq9t3DInCg43z42F40spGF9blA293OaDjfn0rF8AJ8SbNM4e FdMKb86FenJne6ldytPlAuXqTrJGJUbxDLikA1ENeFoxW2HAP4qNicyzalh54YDAX5VOpicNA9Fy EAQBJZQYSQigH8RiTkwB0doGUq1wXmJoWmsaZhVSPtS3/bZZ4e/JzIa73X0oH05mXz7yxVHpO6a2 ZwQE4r9lsDfkosmvnZeNEWFiJ4G2o8t443oSQrdYcZ/cHLGY5sAso1z+DItQthyMZ3xE2qOAN63V WpFPTwEzTDhFJWNGHzFDAuCvDe52Oc7zPHn+bhlYyFYY+GZq3TFwOoE4FGZMotw4xs3Yb2pnHRPn r7xfw8jh4xFV4sNidGb19jsl+Q85TM1ylY/w0uyPaZ0BdUxwSm0htsGzyQFS0fG4hdYd3t/fpMi1 c4SGh78wy/JDfEqzhx87a1K8hAfKilaRCjSYJvvS75lnrdJeQuG7vz2JqcubJno+Y59hxuIS9s6b KRyP5/1DE/9QD4SFJaS+o08NyWh4LaxVRrlFj+PrVtom+f334vswHSpZ+E73eTdhaN+mVzpQP1UY /rw1fJXY6ILIJHyCceOTBCXgmaQ7xhthL4wKywrw+rxezAMcEJ4/bkEUTdmoePCJ/nFWxTVGDCWb /W4hYAHLKdl2DGKg39FHZ87dhRwI1ovplmIUPmiy4VBDADI+QA9JaIKBFuaTQM0pZuR+GkpGiTRe TCZag0n/OMmIoBKOlbEVsyLOAIwBVsK2PK9WCuERn4e07rhQka+yXzGin/roasnzg8uqjxBjvPgW YydxQCmBqOaeRy9gNLZoAIlpD5xCmfeEMzkZBjdQS5CJ3YBEXQyqDuUaBDSvrwP1TvKgwhGgkcU9 MIfN6uETQ73futhM2B4+pmvMnkE2mZDpFEPdeGABznsZyXZVhSsdkyJIC8D29h4PMqjj0yQeKVsw TBjJPqWS0RTIbvGIm1TbxFPlYMyPsY+a7Nd6PM6eplRHMgEVL9/C64fwy1Jp57jYkoIYcS8etwSE v9GxOED+tmpRnSbLclkToBBlKFjBzKA0ONmEZbrwES2NC2a06HCMTJUuOWCOkqkg99jNtLkqljAz p5dlK8f/oMuHcHeIuhEgXRdnGCSLdml3YtgrJ2tHkHQ54zoifhNPlp5O82OErriJSUK2w31hVG5H JBKqbKDpCDFJJTtFFzBaYJ/QKK1D78JG9fFQd6hW0SpUiPuHWr+kfsII/Dg6mj9Ay9vbgPtR9pwX qEP3IHzy94cu1LDf15KCwoPTqCQVEd0HWnwzetDjPH1EDerJUDp3r05770P2KFoS3ef4KgJV0tbz h+4+iFMhc7qqdUafdSPQUUz0QAy6en2+KQmQwJjD4+7urAhUJ4w6rUcWLTE8tqQXDutNzBEvBbXC Cfc0V8HrXWG0y+rdTwMYMmQCrU1pw3rRUynaVfn85F5QZEljnJYi+qejv3p8ljKw2VeC2xkylCcK zEm7m5p0ezKIpLPIyuH+Huw2YvQWSIWWo6tRnLe6c7kJNReafG9MrpRCD2/FV3W3VeKyp44vPnvx 8s23z191Y2gMVMV5RZxqyWdJTYtpDBSOE6PFmsJTWXgTaVOu++3H80hgjdUqqY3L7tKmxHAtHlMu 9dgk3LUDs4sDe2IgD8ZXfDl9SQ1s6pLg3mNNl0xHjjTXJDHQP6Yvk/olNN9o08ec6Ba/Zzi5OZqQ 7M2B8cK3dn0bWYyQARHqX7ujw9SnW9bVoiL/ePKq2D2yBHMptqeQo6fi8dOQpfNgFgo7m8x3m6lF HQrUChhJN6mEsGEDQG4mIzfmGEbvzXqYzB4dunJZ6p9iCRjcnZAF0uvFzsCYUEyiMEXc3/hWFT7w 24HiocsY41sXlBwTA45sIjBQjdDiBJIp4mVQMUiestqEMrU23QdzOeWioyKk7xPcfr8fXrRbfEfK 3+/4t66wAOqNe6GUXPsP6LT6oHiKhwdgJHMumVS24Zj3PbVTNG+Ca8KAhTmXgf4QHsGgoEfoFseZ H2gG/2CDdY3xCstVz2VZTsln/UGKZQrAZdA+MfJKWDRzlV989fnzr17jQGSeVJc2/cJ4XPex/EKL yt02bbp1yKj5kOWWMb41iTn0rLU+tVRkodKCMG2sMWIc5nBsQqLDuepJ3AIeWvOQP7N1hVXbtNpW tGjPXZ2tmr9vwtbaHrFJkl38UJgFz56kdg3vx4WKc+HeXiJ9/QV1/87+jKlUgIa92kjpqQ2bt7Mg 0x5dSLusxgxtt6ou7rLeTclx3mRdkoz+Lapm0Paj3yaXxNW3B4F4sti+7X7wwQeo2oY/qC+IttaT VHqOCIpZUgZ0AlXTctvgL0fn6XQ0NJyNJ0//7EcpZ1VPNEld5nhGUaSO6lpKmZ5Xuv627MqJSaqt wkd4RnNZDsq3T1Bl/5gtkgm4hzHQ5FKgd+2yVNxdY355LXif7k1GDIilR7oHTUH/G9L/cMSvXVyk nkFHHjhuGDF4N063azH7Nxp3SWbgkBdtwRYidLHYpP7O1eXfJhbfXVUu5tndniM9p7jtdN4v3vw3 5M6JyqPmenUze798/c//T3bBhOfhMwnjiU6x88w4ZRpIpmn2ancu/Zt9V2/Qu/JZvb7LvkGKOEdf Xa++eyZk8GUmIUIy0k/QPlskI6IOyCAMGRcaVcH8n083CadMGy9VYo9zaxS4HuNYImjIyU8L9Pts OrvC8wR6HjXMNJuKvIY35XVFrcduwvdDLB7D/fYuxZ0AWrvEVjeL+oZDnFDYUr7DxYo6nQqy3EmH mR45RC23Q8Qd+Gn1F3FmBo2QmYChT3GeWdNyuQuUJ6gOqTPMC8zAT0IMBaLnK7OSEuLPbrOgGFE8 kDDBl5GBJiTBsAGbRWgpfs1h/PzXhgx8NL+PDr6IY4OXSH8DLD1zAi5SNbXYQVBS323uM9t/HA2n pNfUrRJsGXFemhnGBSzn7izhOUFOf6iTuSqrjZk5DaISXKBHDoelxcJRzKNJgrQpHwFlESKAg8ts Jp84RG/qOvAzV2Lj7CkiXYmgz/7FCmJAvtEYtpUs2uDx3QomKsF8TGmycyEtcm44ptTqQGicLeA8 e3Tq9W7bPoUSkUdwuiSF5dhwyk6hZIZwhumdubfl4dq481wHYsccmthjToozLHF7Qp/SUzqdNl4V of8a4kRifboDznIAASveGLhpY7u4e6lFnIqlCJ2gYg0RCUQlqSCnkKVhamkGHs/PZuCdMcbp6A/I jxiPgg0okP/2zLj006i+UN7H0Qg9tLwBVlSLlkoayjOPPN+Wy3JeYSyw59vN6q51aFw0Ga3dwI58 53Da4ZOQ5+nrjuFEzNMNM+sx5izs9LCRrmXDnJedzmcvX3793fPPJ89+99m3r/BsOMmGj96+Hf+r 4k8PH3Szk+l87mKVTTESGG7C6J1POi/cJsu5IvkbSxFUhd1Uq4+eih7MLweNKkZdv/DJ775+hSft IGWW/7tRLtBJMG2gBUYwLDfj07MUJrD0CiQ4fXzmynYvEKQr0Phfi3OVH+a218W+Gr7PCHOBrkIc i5rIWRGJ5IVgOV7LMRVe9E9HT888UxxdPNeRYHwtrSyb2XRdTjjOVw+hqbSNjDyLgie9VYnYURKY /v8A6kP970C/hvlxCS3QoD3/V+hV9fbtv8o9wBBGcGTQqqty9m4ClCfn0/mE/KeIxgCjY9Y3pbwb e4PnCMMzPck7zVHXxqJqpovVbhmq+BAUrFr5ITOIjlfkgTxhLFA/DihtWdg0aBU3yrIKkOuu1u/6 dHZ+v8MgdmQMTtjUgoAJiwL2sM2aHIcvd9W8zm6KT1WM2tbI3iqWe1RzMXr0qGucrnHsMB3p8dHV zlEaX9V4OID8ciMMv3RaPco9t22MyY6uEtgO6mxojIBkCETWql4NqSA45rEi0u3TXnJ0ufx4hfZ9 6yo8uyXzS80DEv1k3GF7zOp1tfKkstzQ/T1xNwJQO5n8tP9UyIOzCh5RMNRijw8OhT47cTHwMZDa qX8ldyjQ28gYEp3oUe5fm0I7WmRWUWVujFcgy8soi5eb7V1PcvvhMbqYiORBPHLAGY4Od65dYoug 7MT8mCqIVgDC22NQW/5yPWRQob6HOpWqulPy1bS5apXR8WPPzelUelXeiGyA3nRBtRnVif0qGBBG z6TaEdQJ2Weot7rODdiVLyas5hX6wyBwEEaYULm3iHDGLmpkNdgLUXwkrsGdgRaiZUpry4lfLUt5 u13DuscVVcBse4SbNGGuPaIwRSHSaJb9Y8v57h8dfJ9qY+CjjvnvH5UCHvDvm5PLBU5X3ju3oeC2 0p1GJrgkImdN0KhbZg080GJ1rUIxBiVLx+9u6BKGRtme6vyU0x1xTk2Kj5oWf9vE0pkD0zkDr7Hk sOpefJ7fISBRcCvRVSomm0cDSARX+fpJQoNFomzu5pdEyG5zIJXMk2aoGuFLMJTYQERY67ubfT4a 63PuPdffy6uT302BKRl1WZAba069Gd2ZYXL1ooHfrgyPYlTKKG3LMhcBWfsr6N3Nqe3dM2Sk55LK 3lH6FZOxywc6F/ptKTFq3ECjsfsOQX6xUdRT5XVsmaTlNA8o6hn8Mf3Y8NDsGZl2akHWZFRVO4PF SB1+BnwWlQQWdIvvS0X1wAw2y4ET5gy+5sR7NC47qPzCnXWKm+F0Q1B8lkUWpFNhsoihqDh7AZtm EQtkGywXuG+50Up4k7nwGS4G3UAfVE5zFzDyFIu+J4P+2dnzj2XOP5U172XM7HjnXJHrrbm7b4tI Gi8HNxYYDoTKroNwLQv2If5JQsDgKZ2SwGLXVZoy1zJaCa2Lc21+Oho+OesnXEoMZbNs95JmYkjr iAstJcm4gJwv1kFIUBdq/oZcfJHdpXQVFVY0dPk1Y5PYruxznt/DYGofqdMRwlSbJxf+PTVe3mbR hq9je7d1L4nHCzeSgwSjfWZ/w3nrNAF1el0O70A6UgoZxnumXz2DLdO4wm/53ijHa4ySnha+EQiO zoBqy4qijQmb1jDK6XK6hX8Tgjd5+ZF4jT1C8bSpKKQUtq9nte1jrhE9qBtN+KHvnSFWZWtjpCrq pWqI2Oy0CEWcT0R/NccQlMPpUNUz9yYNDrbK5n3RYSMybr3EE7ffSN0XsBZEhzk+G5HgXtXk3M+U e4USfBpMV8OVRnFMnfOO3T0kDCvd4fVO4Ul4mGGIxAjFPyaIx6r81DsIwUEXRBVM2XGA5lyrcCMW pzhdP7rh8CVdHTAm6YbqrddWKUtTPD1lryQ6wkoj6AkWsx5V/Sioim7GFddCkiuIkvoVwnur1NmV 7rMQN1kL5WiTftFaS7dwIpiCPcaUjrFT9YcyVa4T/QSTGHBaBFkKOoVuRVuPyxyTskAittQlabz3 F0vXNHz0FTme3P+cihwsdGlt9U6y5mq6ocCIizVCd17Vc5eNsSJSrWKW83jhB7pKTCORdE5EbVgt 5svpLUxHt2UnwayCFNVyt7S3XKxvwHYRhSbruayKlqh8sTqJE67XtY646tJPXHFkwNefxpABZwRI FRP8xh3k1NAShAr2aEmRw5FAS0/MgfPE2wmu3R6A+c5Xydq2ff3gXDoPTV9wcB2j2fCay2qiSHt0 wuwlxTOMFqnv2bVngtO5KtEoI0OzmexmuniHeJ0olZhLR4IQ1M2KbwsNBeDQsBKeBD1oNPMnPjf1 +pXa5k2Xfj/OtMYyUdkyzvy2WpbKIE9IDYZVsK69ZGrl8eJrsfEIFP+Fa+5xkr5TO2m7jzzxZQlT BqI0L/hwi7FM0UQG+/pGRzvzRpuNUmijaZ1dYreIitdy06gSU5+dlYqzEKHXA8Zy0JMCpw31o/CN dzgLRAjPUx4V67uCbKKK/R4V3rq7qTfvGvfald3H3I/H1ttWWLL3+vtr+dXXz7963VpNP5x4u+Do 3i94rUBm/PN1OoWI/+nt8WpY3kJHNT+1jj+lUum5QNs/IqlPpuvNhHZFvpvVVVmZO/RNeGZKnZNi lZhdjVSOLDgtpGMNBDa2JDz6CNI/ZJmL2z1dVSPrdauJ1sz/cfhgOXwwf/3gd6MHX44eqOeFilGY bfmOMll6xgblG5BVXkKvfI5xBCk+pL2UmGb4FlgF38CiTHxRwhEBzgskQsFeiZH4Xl2v1KRLbc5g r1xM/1At7nQLSZjysAj6rrxzY4SzQoPUs17iU7Rio73EGrxp1rPA2tHhzO7ZArZHtGw1JNEIfhSJ j1J4KnHHt7vftQBheoIozV4VRj0iTkubuLABk2kTXXnV35InYNmzBosH72U1evDLZ5PPXr4cP5PI R/o6p5t7jEu2AvEPL/p2q3ckGyFMOWzQTb24Lu0pEoWCmbGfpFfvdzWj8zYNzJDOi5cvn//2s5fm 0j//MPvH7G32KBtlH2efZJ9mb7fZ21X29vbxOf4zy95uclXgZLDS0G4dQTbIItQjJlbz7isQxJb1 ddnjHP3Oi1ffvfjq86+/eyVGm67JgHRNB6HtJnTNO5lXzTuyhkHN3BqZ6ib/ezhqDf9w9nb09m3/ 09O/H509xAtsSPKi715Xs8esBfWqFovyklw5vAqeihajWavo4MpS0FZTY+femklp23I39pCcIIM2 FHSQ7zXrQzegOQ0kKjAlsDhGxoJlj74ecOof9aUoFzq4WftX6g5aMCtnGSGaQr872aQVhyqk/Wbs QDC6GUaKg4pSsF0CX+0b1r29mmxrcZvuMUeZzufTLTtdcGnREO0fAspPU5m+ouAVAOBR1vxB8+8k AHCzHpi0fQs3TIQSuX73/LPPNZ/HqhuJaAOraoKGp9GsstCiqYbTvssEcRE6UC1AEOPr0ds9M431 P+OW6RRCuAYIs9bC4+1bNPF45E9TolFwrJIn/RZX9PzRg0b61E+fIH44KiA1V6pNUdp8mv3RWX/f lZSplUsnFXVgT0LRuKUmkW20nUjqcB1OpmRp3lSSnN50Iklu9OiRT7zvGCZ8toPJw/ehzrYvfADW HimU8GbTjf1KZgnWQHvPDr9rSrnsRE8Qxqsi49MJEqUlisdcWOUYteK6dBetNecVImiXIj/D7Z5p 07Lgn4FLlCkS3aLMQ+giYaoBqZwnR2syfVfCyY2dvCJhdieV9Cpt522XzZ66ed8LD38zt5IC131v lg0F7XYuStAMEQuK9IcmjN1wqJUZd0H4pKlAWQY+mAPXZh8draGlw3kCQhZH0HT1PqqreohJhpQ6 T1NyhmM/qdXQSZpH0hNIFKzA3JTb/tFG3h/LSjHzb/ygyYqi+MSae+tE76NZ5O3kfKGRuBxJ4m3z Ye/t/GGf/r562M96xYe4wdrl6Pk07DEWWscWQSCjXZQcom6GKoZHvuauJnPMG/algAW+rtwAby84 JLFo5bKmWlaLKQWt44BYEjOQAi40hRH+/HSONpTaYC5xseQZhV3xrcjZcolFNf8OAM0yZotmkN3M sDABZCaekXB5jE06IG+/xReGKQIbWjSxly9/tBosFBMhYeuZktP7l9Ez4c5CiyR0L1XVYuKItyqc 6V4Bb1NWkMdZvElVBbhGO6YfHKZMA6K4AFJZP7lwWY+/RrcZ1pzAWJ3BgjmfT7PbEd0u3dpi+4Eh mtiQ4Sdzzr1OU7pltQEsTuIt48d9vqvw6Kk2zLdl23Op5uoTnM4ZG/A3yiCoKvRRAd8OWuhVFx6C HAaWgVSaPX3aFBcbR+2e8L9j3S0plPHniVgV9vSNKJs9qyb03dxs3bVjaA3ceDATvEflUWnxv0NX nB9nafjdM3JV9cbmR94UGP3kbqmQ78A1guuPdTV7h8cWicC4wnibOLqKddN232GGuiDySNi54rle JcbaUcWr05baehot/HfPhhS80b80bB9woafLVArWQfYmODk/tu545LXXe7DpM+qiazyZnWQDO65H b6J6gewsbCcrSlbIMlpEK/UwZVG03SnHNT5whwfzFYH05haP36HJdk4N6FY03GzkApb+MBxUs+3R RTMedB2hDN95JiJRA/stSwVrQeXzBbZTx6B+4QU3LqzTHLdalvYh0VlY8VMuQxYQeXl7wYvpzthS VHh1P8jEwshbKgV6VL254tqNozvNRXUrrouMYVVm58CaES3/Br3S0AKCmOcNblukq3RCr204hJOj 9WL8KxboFv12TKikihkBOMakB/vy+atXn/32+avYcOWqXkjUtXJ1XW1AGEtq8cgmwKQ5he9oB5g/ iwkaoIXQAyTkn3TQQ9/mxV3SmQhrlrYsiSuCae9hmjIvFyGRTqxzT95kBX5fonSDTBNmVKeBVRLe VG5Q712iDr9AG4pNbJLFqTgmAR1p6VxwUe9W8zwZm8CKPsHlQM+Hq1SfhLgAvq5Q6rC6ExHvwjyI ijmd390zb5envdiam5jAGnShf7hlz79/8SrVMkoXGWfuXNuDm4rUhAnnONyd+DNK92x28ebbl/5O xAtfmWfO6TE0A9A6c3gXSbu1638pEj3IGyGPJf2DpM/I+RrlAagDLXqVqr1qKHfzD8WQK7lTONfY rouwf8OaEQjBdcoKDifMfieolFEU/Rf4lJEtVf6k+ChlcozVRM810vB094Pbt9LdQ/bBnGHHr4+4 d3S3MwzPK6grbLyVSkSCQcssmWGw1GBz263niuTLkyInvdZe3RBOFM7nHmvveDMzc9a4W2Q9Gtfh JxmS7vszSCIlnlLsYcxzFmohWhUQmNUgLUUaiG5rN+zQshszhyGJLMwP2vgMKD7sOL/Jg6ZTWmMJ RJIqrxDkRTAxsRduZon1akVVLs4ryJWTxaThoD0d7uY23jkJsHLwV7l2v4FSYGPmiNJSAy5bzv+O nZlzJCCQfkgfSY4gRDiGWb6ZhtF7YZKCmA7atsMxMXBN4ARuKQns8Nbs9Hn5zrcSiI7ENjSX2+PJ oGXY9260mClLbkOUg9TynTehrGeDO8N5zqvWlGYKLARoAVqxqwX7NHI/IjMMHl5ahHnourTyAtYA N5xBNXANnqP3lJ0bNKpJQ8i1jhDJch/6EieOkfRvrLLRL8L8yjlHNE5w1HUxnc+juHV8YPI9K4iV kRsP2p8MsnBENVfLlDBzbp2YcHsn01pDNXTdd361TZWtWvqd2tyk16nIFv86vWBl1pAlLDU8tFDd a53qDlg0yVtC/NBRJqfEeX+/2Ss2D5ufODujs3i925ACUNSbsWxCJUHK3OEWco2qm81s/GTAc3b8 JGJwmFJWCooE7mQGGa4s0PNvlkMt8Nag8hdYdbmqNwI7BEwWcTjocXEzvWvYHrunx5/6wpdRVpB2 cUfhzNCLvlxOV9tq1mJFLIoaqMmATu54kmIQLqo+bknwjSu5uOumVfXBIgo2Wz7Cka3yHJEWpMN7 09XdEhr5KXDn3+8aLdLnnp7OkAZSb7L7+3A1LhbThFhHAxVc02FC5xKAkuT91EzgcmFFf0iZXBEV RAeZEhgDoNyGawhFC+JwqOymFIXHwFqc+infg0ahYdSKfsD+6VxS35uceI2wryacwlppOhXKjqkR zQnppfvUDMbvXWodIjzIlL5mCJ232OE062P8dMaSaWCRQkmeuLWzptJGIEIKeT9yy5FJGmFjnGTA pgkLA8E62PKRT0Z8Ro2Aqenbc/2GkIWnvxq5p5Tdqq2JuxU3Uk1CF3fUamrzwXYx2XTLMDK663wI GUZ5/5duKOLmrHbrtEKSOd7qjlrX8AmsdSAZUqq5IhO3czQKv0UBhPS7i7sPPvigXSfDBzDu8hCS OxS/GsdQXCKvyUmS5P9m/JgZ+WNyISLIx8YTwxxpVeEUaZK+4kAVou41atfYtv1E3fZghM4xQAZw 8uE5dCO58NGbq+1ycYKe8bOr4UfDBggOf1V8VDxxaLj/PX36+An/ePLXT/Xl73dLgs5otn4XB/Fh uYWHrnoIs5V3AhgOOqNK5/Wz7v4Lpm69MuVwcMbsrtzuDd538qR4qnAvzcjWEhVhwyHvhUPzNjQv dRLn/pF8FooeMy9NCll+xmV6+17eCSbtvC4bDaP3DrkV+ng01qpB/tot/UQ4UaL/T6JGpFrsaSd4 4gaaCX5J+Xf7mugkdMhGSwzYPiaRaCzDa+D6t8tFRjfuXD3m/6Ix7iXnhJQ1YPHCNKefwI/1GR/d uvwovWGi3n/+GtNUqmsTyyb77tkry3r6BTJGVtoih+UbkX3rw6P1/Zcv70VODfINDfeYfnHhKE4S 2jTj9oZJw6M53+VfTvGOzzoGoOqrJ+fG0NtajALIOwgLa5FJUzo5UbClY4W4+qPucJMZBVV///6K rTIapX3aTrLJ2AtPQr5e2EHoYSfmCyDlw2iSnUWwXHvaXQOyeKgo4KcfMaBNOKCKU308ExUM/uZ3 GqXRgF4kLaBhLL3wjoTAvCRRcPenek6UuRk5vwmAzqoBHEO0GGmAH2ArWmV/ADnG1mxgyw8Rd5Zk AiPmMGJFaDImQ0Muj0GZkFjLHA2FPLdQsGWbG8PXxZf1sCVFt7xdMwQ4m7jRlSd3Rj88oVwPxLNr gg5FbEnYROcYHEedyr1qtSVNqeYUrOrYpxcy8WSdYJfxlApNiIoPn9H7bWl9ojI2KirELPnzr19/ 9vJl3znZYAZhEcvmcpzncuyNjjhUIikCFLeNXNncfVRSNQkxsMoud8DZM7oIpKOrkQvnqHo95/C1 iKr86QefdgJuL6UPl4iZ29UDynBRX7I1aHOZsosb9GPk6Vm8mzyEArLhV3nnaPYfbaZ4K0ZWJHTn Tjep0bXY35Z3ie2M5Fdf6I9XiUZG04GXxeIBqzvTBSfV0hqy+q6sjedbK44EadUQHmM8x1Zk7+y/ QAe4yBOQygktgVDxA0Kie7iJ+g81fHPWFuVUQKD6UdVX4PUQHOClebk2DY/76K3Ep9Z139yb771D nVsFxPFOyZdRV7X3kBNH2tb70tQ7tfoJNgK9ZPGUCN03rRa4hiTurF9PmIvt9YSP5bb8aVUFGj9T VY1btZzQ2rbeJbBLOuNeBI7WOCHNG3Y6Kjov6GSAsgSbEJMO2pFzjM+SkgXBnhGUSXO1I6gD+gLE AnVn4siR6CESFYbfpvWXaOwxMSyTvMGxTqYfmr2CYltxQVm64SMGhbjLvF21pDm9Ve2DgxaO306f jM7OUk3wvMJsTIbGU1XBGWn/4GICa+2BhoerSxWszGysgsGco5NRx9FYRhrp1BCx6OTp+qh0b4yS vd2SM9+7R///4HH/xYHH0dVQELTPsY0NLi9xctC02BfzrzX7gYtSk27PpWgIhtJ6lfj/UViUI8bA 3k05jf8ZupaMmYyHC9sWP2np1VWGHrK4V+5mW7yyZfn6mkBSryu8THF8a5KWnloG3yQZGbRQcaUf Gytc1EdYwMkxyuN9mDVv87M+QndznN2XqjILa0L1jdwe08D7Fh3mzq3d2mu/xdeAS2rBeXJq0ZUK 0P2bYdhoIbGpF92fu3TfQMsepF793VfZk+IjcsmQMaJI7XO0lUNFDZzk6dBLQZpgtRIUBhye8Owb 0JNp+PgDvNipoWfPIR259g6y8x3h8sO836G/b62FVVpsQAtFJ6pEURSRSRTnMGIGWiDlKds3O/HU 3E8mAA+8uYE0Fw758ZZwbp9zGf2Uqby4rBtnm56mDdr7jCzzNjBJpueIeQxcC/EDMSYJ1Li+aWgt 4xCwyw12EFmAwfE3MlM4EjbbdVrBNa6RiH3Odv8p2G3r3lE3e7h3j+xStKKxuomYWg2COgW6kvCs LO4HneggC+/sHaOgaXCdQeYQO8Gm3mz3qjab8v2uXM0InQg5SePANApRjnWhAPcVmhljWAxU9fHV vmr/bFQNrhaqcehosgpdrmZXdTUr2zcxx3UC2kJn1NDxtVpQpDZy9Priqy/x0A9rAl6H0fc4WJUx yQHRButEm8lLHIJvHDQSD3kDBh45u+NEHFqSYE4DIIiTEpWHzsUCH5yiCIZ2460iLwgdSC68H6sC jt91YyUhNYeg57IeWQJDJ0J94A+8Thn+0IRQ4L/IMADmFp1SKRnPtdjahuaEDVe3LlW2YvO8Td66 /WNa1C0ijzZyFRsnYt6kXZyhb5HaAuu8Q7iqaecUNxemT8L7+KqdFpSfBJRHyuyN/EhcOI4kio76 4cfiLxZleNbx8DwGp0qL34Mf0wsY5iA0re7fB7fnzyIrJcWkvP/BuFU4aauvR/x++/GPKCkWeI7E OWL7k0t7zzUhqwlrRT6BpY12XFDdcziXRDaAyWuel/Xlc4nyIqA1Af5Zx5Sk4cXoQYDqRflur8mM v2y1MXdjUjfN74U+CvOyYTICnkgzAgUXEkjUGZpaM3CoIPSgAbDoWua+ekssxRyLrz5tMBQUDATD hja4jXQDyBLV2vUg0M4YZ17HkGE1cuMu2aqL7Tx/93JjR4wzp0tacpaO/TxfG2rBY00poHBMcpyl HEDga70OQpCmFEAmGV46NiORc0yhZn55kVVweCSfDha1Y3hNrXCKZGclIHDtOy85+zvh7ZyDWIgy iRH17ajBPihltTiTWVq47a4GcjQY6KGBfZjWuK181HMq9LDFOCX9H3mXwTIUOwK9ic8MGsC9qGnP D9zuHJjGDu5HrMXtjC+X3BbfoxVHVDJLxJUgkQO7GsfLBBIsvqFNHX330iHgacTGboYX3zxvTQuj emTaq3KxYKQN890Rgfx5MuaKo+5vCQInqh57YWK+/DHOvxiF83bbM4TuyHJaGBuI5DXKzq67I8it 1bxeDp7fQp/RrohHA4qrCOPR2+vGV+J2KQQK8g98xTYTXHxkb2LLOAQ7tJJrAeXNB+7lWf69NEHC gOdiHGTej8gymDaBZ4gxWRDS5FcgvyUQB5RIsYLvGAwUuZl5+fzl8y9BJJl89fXnz5Ng4c5Fs+4M Pc3dP6jA/i8Fe/bYIDGByO2fUVyIYxvMW814mCB67vOt1Tjr5ar5zwc5WU3jrTUG5V5UM7wJzHcr 2aTxQe2U8ngZ53ylR8nwMmhiCSMR3PpX9JMMnybT62m1QPStFKlqhWoMJIc5EPJxWTV014zPYrKe M3jBO/4l1+7z2Ju13xqkXMEk1CSJzi/2gTavTTJ8eYCfcVQIT6aNrIF+xIAUxGP4RycdNYBS6uiF BxkXkYHvnU9de9rpYuF4SpGugqW24FpobgOf3qd8haIXjDWOy/Lu5hRfnsVcAcnqqfwyqnq/xef3 FLOgkuaJ51E+x1D2obsTNDC4xyjwXeyjslDoZ1RgsOqxmeG1LAi7onVEkafMG/WKeArn2CkKtefl 9qaELdSAP6lP5YnARl7BYeUao43ikZq0aByqjW57mUbF2fUeGUsiFekq3yokdcm+gud8UQffmxrD 1wBL3dQIiD/qWYscY70XgPo8RPubfxz26derh/S3ePgp/P2Hp4M/KsaPThbH0A9W63RARn0/arlE dzfKi4w9M9puYyEg8+TpsBtJA8egRloZrYcdZmE4vPawdv7+iOZZMAZYA/eGepSy+8LEqjyOp2gU aY+GT6JiigyEA89BE8gKIfIQoYt33Mbx8+no12d8o3366yCuxImc32b1Yrf0TetnjwezJ4PZ08Hs o8HsV4PZXw1u/81g9m9RrscSfDIYVOnDXG/aQ5t+lBG5+pS1O6CgaD12SyFUmmarL/F3oJxG3MXH SDv/9PsXCfXxxUoaKh3P8+hJm3IBaKHC/tOWMBeGJ9uZwXdrF3DUmJ434yf9tDLATK9CtikVVkLo IO9CRmrz/T1qYzWJrbpsJ3VwQ2hb0Y67RFpJh0Ssm0w0Wvf0+7T6xS83BrK7h7VpX23+nNVa4qz7 0wc5YXv+iur8Kk9Mb4lwUm9NfPdyLvabm3JWVteoFIXpLot29jioydJhSYXDgMUyjhfFcRakWO9/ SzX9sKV3ab0gyWRYoJ9zHQQy2qGp0cr99PyAa9xX3IXW3KN9mkGPhbOparNVbg05gWFol/wslZPd xvEvyfvZJ63qRBYdyEuR7s7R3Rn263lNZqRFUaBry9V03eBF5s10hV9bCDVb3t+XpMXblu5NKvku SktgHxlg6OFNdXm1baGFyrZqS2oz1utt6/VwAfLIwrrNoL2gOEveVLOyhVKvxlsrKE7zDTJ9A2fS zRL6JzPnBHLF6bdQsq6kVCMQp+giWSJtNoE/z/3G8iR7V5Zo6ncXegOkDbRDzHOx1NbNuX+UDjgS PAa8TFvMru+7OE9EGSpJRR3aSe+MXyb4Rio/nkxxH8EAjXO8PWbbcs9xmMPVyYjqcRqnc2yr7jAO PfPtYxj/b3Xv1txGkqUJ1sPOC2xmH9Z21mz3KQoaDSKUIEQqq7qqMYWsUSuVU9pOZcqU1HR1M2kQ CARJtEAAQgAi2dU5e/kV+0P3eW393NyP3wKgsqpnpspSBBAefj1+/Pi5fEefI8+JQX+JX77oFcO2 ypFOD635615rXXxZPbS2F+21yX350Or+S3t1+sJ7aJW/bK/S3agPrfBte4Vy395bHUJ2H+elZk/8 EntAa6XJjfgzz3EY90l2E6k+eqqNtn5KAB+Chq3gEgixe4QwauP2KM4g6skz7Mm3tDl+jV/+tr1b pAhp60+7ePGAwz8NRwo1O562h3RC/UiakyS1JSm+EOhOEme8EyCGB8o+1Lj7sv+2F4e/ocxmb9KY Z36ynU8JwLZ0Tyy4ro64kw+8Zf78t3I69HpQU68oTdOCXmcdurbkFIngDtuK4HsmRWOv78nbOtE9 XK1tUGPfQ15prs0Vi8SNIYoR6lU8dZwM4FwO+2i4QqEDy1zuFvQceju/1Ah+1zWhK91O0CEZxRMM D7IXHSOQ6ehCEEJWuopZPVlYvxU0tGKWCOi8mQ68oGDqiG1xRI8xnAvkLFWJi7SF/TPZaPGJo5Un IBCacSgxShuUnES1WtY2c33jaU+alXSwuDRtoDJlDv3/y2tPxERSPNxGMltNMyYSoMaDDST73RIi oQ8CcHRg2w7c6DEa2vQJbEIvOYryb+5PJ1eQ+dJeVXzQb34xFz4bsBEqDPlOoY3nktASvfhDSw5u HTCN1AtUTGX7hYV6EQwUipdcQdAawvwGYUvY3Xrhv5No7XZ6RGXNdevYn2WkZiExqTBoGsr04sND vzoCO4F15UgcUlnhmX2y0nfbh+t3kjcMFGaC7trb4WF93aP/yet+9PjS2p/DND+fofU5eC7EKvMX WLaMSujzu+rMS3+J3h4kaudVWJywMb2NEvwivZPIllcwbq56YE7CdE5naLV3HNvPrCTW+3380Mpe qYcIezgKcy2nBXjWkwsP2q78I8RNGcaw72dXVDDmVSIKcz1pcdAOWYodtgrxpPRano/p3NFNpA4f LJtpCHDPbF3DrFoY8yIhdLItbKZFWfyHrb7VPJwvTF/RAQCP07SBLrngUTf2DBlqwYX7sbVbB/Uf exT0vPPw7d5JqFTUvgJ3ZGvuhj2XVreUCaP5fPbjAxUw0Slq+iFGWbDdxo2wbDn0jPlxMe/wVTb7 uKToO6ig8xZINQ3cRtiRX+AnjA1y09hXUxpO+RYTD4ql2HHbvjf8Knqp9fKKcdr7BBcsFLNb/S7b vEsabd9OePX5moT/7i7ZWrdGXAD+hMEqhvhmixoTvDYsTgpuCTgz3qxQ4325CgKWZWmavWxf1xwv mqsoMXdKEnblUsfHxpN3N+0Cb4Jl6/eRbKzfjeUh1fDnmmjCEM4Ph8weYcBF3l/1suQaqs9QQv05 FSRhUNQw59rDwVIa/QqcwIYhbNm7t98OJaAYkkc25qr+YbCst4Ch9hSCoTCweLsx3PDpbN5s1W9+ TW+B8ubIut+9e/X1sLicHc9+c3H57Gh2efFXR8dfnhwf/Xb25cnRxW/q6WX91381mcwm3vtsCCue nfxa47HBCVf87dwM1p0O6vEP5pCZ7Rb1kFUd6tG34J/2go+Q57hvzWDXH3JFTBeg9ePjXIGvDcmZ EsfHXx6Z0Tz7jfk4/NWXw5NfFV8cm9eK8jVoaszv35vDDIpp/+E3hI8wrxuq9B1S8EzqOzFTVJz8 avir3wx/9VuvPvP7d6tPXF+bn5L4ckiU35/fm8OlPPU9F3rDHjguhGVNIfOvNS5aaJgCNnuw0aRW /Js08M4kVcInTwDLgBYigPzsrAepeQ7EgCFtiWcj+y4TX9ENlN2hoqVfZF9lFXzsN0epnaHPIKvB t9655Nfm0FrUAiLeMUhZXsmUDx6Yik0hK67nUvB64K/mBdSThIXRyVTny0XHVE8p1AOPUJawEC8B 9DeJxSHYhdnY62Xw7nm2Zr4S5CqHkmN7XPsV86vnuapR9M5VfMMZnikT9e0UDmr0kvXbwDrOE+A4 /Lqq60lhdjn87zOSWo3HgFZC2c+wnP1F58tWvfQzZjtX3sbUZzY7ZpQD/bLh41Mj+b87feG8d0Gd O4FL/WdwP4IXE4eQHvjhHfF/hflvyP9VRXn2xdE5fho8MQzCS74du43E9mx+gVzMAoixXDZvauaf IMIlslk/AusV1MBSmy2JIOwAWNT38j0rKC0zeQ/PDF6kM4NDVMRyNtkg/Vzd+NnBJeFlCsjmdgqi RnuWOjoq2sts6jvfn7KrjrLVsuih9+SwW0Wk5cP8cNTu0VcatsZB/Fhic3g4DgcnPtKAJO44/zo0 4o5DirTHWlTmpflSziyMsSmPVbADAeAxifq+D2l/pf3OFIwldYRuhUmvCma+jui0rK0crGERWzRw 0JB4s6vYBzUJnAULgISOzz0kY3NBDdXnXFswVcnz2LZso3b5hyg7nS1pqP0GvHiuJ59qyg0ksFGG ln6pYLFhRc9oEuDE94COxG5ja/W2C77aoZ3hjDEE/3F27nKw4y8Ra8VfrVxemFcHMzApYUVisfGf 43pvQKNsuiUlncmm4+LsOVPXWcJydB5seegFy/wSMpKV9W0oyTAnA9hQlZwaz7e+LNYYMxgEzNhK WiNl4FU/TAZ/aY+R8V78DskPVLh0WKevgn7UAL2tonnyejpUiCdau2muMk3Z8q7+vMKNTvfm6mGd yuuFE/Um1Iu5QaEsknHaw4P8+DdHz/761Bzkx78enpwMfv3Xv/2rL3/zD8kX+MB6+MAoqQspRUgq maw3Y08mOXhAGOLfRhIcFxRwwyj0Ik3h2F6WvEMNWETq6wNIPdthYaJwTacQMayuqg5NB9n73bcS 6wbuD0aeYN+Hxw3qoszfr+LQSeEUfb2j+m7NIIjq4/Ld/2juCOP5ajCdrAEf6ePq9P/74he/YGa3 ajr8qbm3H9f38glAJ0EH3OlYLkZ2+pVwSzJ+v/q+w9ezV/izuqFheSkVvQXB2GAH57sW2sKL3xXl l30BuyNOemoY8KvvS3kvAEvQeZ3QDJ+8NCu0EPJBgQhMQH0Ypsw/EzB+UwEuHmaOleBLuBG/O/3m 6Le9wIVXejuI+tdxHINGZhpzc5Kb67+539ZNy1TTVHGpz5+rB8wTCVOwiViWIlCDC9MFEqxZfqKK Dp+ezhrkOUMYIh4eDwGv3Mw2KCvos5ErzZdn9KXebHo/ybH7zdcviNadUMs/FGamt6unOK8TBglZ NexZDIRuWMfUiEvmxk5Cbe7gpvwdlzPziXYI+ywtV7ccmyYjSEIlNCBESR2Fa5R9hSC2GUOO/PDc GhZ8gmk+FxzZNSiKV0Dd0o0wRw4lnQJ0xIndzINT/lBWhNljbj0EohKAORUQeUwgKkl/KboayyhG dkBaAnf9cmAE9pVfjorjAK8HqtH9xAF/A53t3V58ESiepPJRMdvRiAAMjLflqIubMlD3XA6mi1Xj RV3jKGxN/CkEsTELdsmpSmec2sMOPch2Ruueysu0WszME2UNMt8cpaDgLHWeB/eY2xT4C9wHNMYu /RCcMZGSzQzhErTVpR5a5Ln0/Q+HxHV34e1ZsHWQ25rtPzfbI/a5Bs9tTIg2xYwQNAZyqvt9N877 5ujLEAuSj82pxEsVUBCvEqIBzOpPy92CgY/Mj9+P3379/Xff/n0VTohZ02clbOfj6BHRy+UsMi5c TxrvPKDVTRlAmuxye0M87xdfr5bbt/Vk9o3hUK+W5t6sw0JiMVN6rqdjAP8sV2XVLzJU+hfsv+6I znVotn468Q/WRsCLkDWn2K1FM9NYsEu7O0vKE4b+g5kkAHpCmLSz82AXN70RIgqM2ZU3701df9C6 iYOn+IHTy7WkgTaFffk5L1ebq/SR7zJdTsSHlkF2Vpv5FWB702HjNndy2pFlr/O8u2rlRokVowot KVfRQXgpeOa+22USjpzLC+MnBYM6MRBijM7vi93lZQ3TgCmPJiAKXdEJrg4W5ZEcxQjj2a3IFDNI Qvw1NLhAxA/Qpl06axC0DsejfT4TgRXlE0M2tlM9gcp0hzw9IxiJAO7ISAX2TUJz6/GIeloiRD3T 7XVNgH1Ll/UKOoUMfwaPEWuNHMQm2/mFOiH1aBHZqWkQdLUowWJMLcIDnkYBmHDbkF/dIrCtSCQ0 qzXvRyE2j3yQ1V9aIumo08uqSoJDzPVouD+XMzlWm1XVJ79wCFy2Ef2BucUPgJIHrgm1qKqiu81X I3254VJCWfnkLao1a4vrXnTN+RrIN3bFTWnE9wrGBIf/DM9GHBcRv6J7R+b9AjfMJecq7MQn0CXN Smt91cPGyb18CQXr2TeBSFfFK8Qiv36Bz4es0m0M6cEnN6raYSjtYQEzOv7kP7ajGNka0imGTUf8 dVY3K/Msd7Eyj2BiL/6RWuLjKZ4D8g8NqowhML30GAkRAlsD53LobnIimNPic3+glO/GwdcD8pu+ b9I1utcjJbgtESCSKD6u1oxlZLtsAboGU4C+lA/sypIqm2mD734xXYAAWk4hyONyt5weDOMNIbzo ptGHdIEVQ5zewnUsSoEFnAGAn0D9g3GidLaiSeQpgiCmoIBnO9zB0CtkxABwuNtGuPQoQDu0S1vc ppp9SgPxXcsQ45puw14/uNE5hrJG7Xn3PgD5NfPWdqxTlgXoUh4gPHlYy7wCUa4GMGkJ4BNvBTp2 LkakAmEnHPjJS6cgeVuihYUsLcCpSavwlMG6CAKPtfo4YTNBcJ40LC3F2XxDkQ9rDyW++B6FIT8L yCF1Tx2KMptTNwOubvoDxx/OA19gSf+HArcRplj90ElMbxePjyBzDlYityz+TpLTbJhI8CYloONl lAHOvew7G0hneXfg51+Ooub5UbJ5GoKUSDTvvVymMpcR8bjL865BLW4+gZlEXTXLybq5huBQIgtD izf1jRGYjQwmAnBAGKY5pmlS2k5m9EtZHbaUqf5j75nH/bCdMZv75uuSPykR9RQCragkgvgglLZw AeS/+Ms3X5/g5H/z9bOO5hc3E0DnXi7J0fe7d99+yyooeOUYshTPMHerTq8BY+T0pry15suK1FWQ /ZSj6I/7J/1n4RVDZXMCN0PUJBSYOWuxQMIw4qHsyIEnHqbd6VgjB5B+9OkG0qiyWK+SAYxD1R19 FZ1eJCYwPKQAIDZlldAalYcqcuAw0gcgvhwQo+mjBank1s965kflFqMzb9kioCtVnlSOEl0R0KCe qwg5SDQbFcKfVTGZqbikPPEddkxXD4EXJpQ5GKpV5ZbHKVVrsIRBNBktonxIghMntVyR1JRKKuY0 hl5oYXAKIJvp4Q5LKVZcJatABMhPDC2wm5gTNzH8t9UnxE3bvimKCJ3pSBYb0iWG2tLPmVpDeZEN QmQnJLi2eWvvyUIthWnmsKXQ0LB5627L+ufXjnaeW7tn/4JrhxtcZgzgqD977Xx9M/CtkE1FYhDw qBR+ufndqrHzbwPZpd626b1b34aBp96GOYhU6ADhmctiioB6dPDYGGurJoODv0ic/FkGb3WifTQH hUeMTqkdigakzWm2q7XrTiRvOGpO0Wlmkn0Fu9pXORkw3IaBtJJZDb8ZRYw5WU83A8X3NpMguIBp AOnF1cBSpEw3wVHupDBvYTQdWREvL1BaQZIzQkrKGbmB2MUNaGoRg+UK0GXZI7toiurpTtbtthsC MiiWl9ps5QomuQgZ2kJ9eHA1TAnt9CKELCA08nF1YLU2FtjL/edQMkMh+fNFZHdN/GdepO58eYTi /33XE5opHQpe9PCCjQ6X5tJI9cDgA+l4ULwCVPvFvVYNg/G2iVv9Z3wD48RQzUmeguI4667lK8Bc xmxLC4CWKkBBVnztJO2iBEgrfXtgbPrJtvos0dpJ0VrIbpGhF4x57YYYl2CBlUro49mWMHPhSsyX nYQoQe7AWizDzKZV6lrL7iaBPG+vvPukl4zUQsMIJT0LNXSgoEK1pHtob8WdhCxt/v28q0jLMS/z EtRk11IdDdFr0cy5BVasPnotukPYVS8Ua4fPCWPqf0PHryWp6MhNnYHxlPLW2XMgJ1UyCUulJZ/o ZG7pjXeRXMwiwTk6t5MamlxvWhZ6pHf+Qw7lfynh7i96/BMRiBJv/3b09yF4EmODZZWWqHPHrxO5 8+STUtJZSmprGGXAtoZRWg8ajnR5dH5H+96e8tYqbWZ6d0HHPeikAHZocU9mTqIwIwxQ0rl6hiZL VjILebh4EbJSmsUDVHYgmvWqaeaQzw400mgBEV1Vh5XnAHdEtgAytZvTuK7N8U8yiKsaotPnV7sN BMlCJ1a7q2u6HwoWJQEjrG7QagxRnYWZwgZ0ZfNG8sGDGLOZNAAHNaG9AsFOkPoWbL9gxLmPT3qU zVRy0yqM3nn1vcWom6AxjGQZnDsKYHDJDmX8NjhmMuOYDvjo/dboH424YQYAcVL0m0MTI4tv6Ewb KdVNmxh/ZybnB1nVdVPvZitiEJAAcrmS6qquc9idw1F8n3HXdcmX0IpkXUhUSbonK9d/64fElmT6 odNirgbRpRksxX16ue1pR05dX++7d9/2EvbZoNRT8/0p/NDrfFy/+5/X4Ce6HawXO8PjBoZulvXm 48fTf/X8F78ASpiuFgvU94IVZLck6mLwLzAhUfplCFrfbDnJt/MfxjwlHSQJ8D4GK+Zgin4OVOK0 3twAY31brzcc84a9GWNQCKDLS1wrT7mDhkAfhrrp8dchLXvj9Ca95sN83bPMY1jAd/WYumBkXyw2 LPR3VexyMl/oWuC7enznPR8Wd8Hz+m6+1a/Dd3r8U6fzqPOIB1zQ9BfXq9UHQzCEQHez+oS6dZ6T BsDXV0vK0ARzfzm/g2nF91e34ChlPjV6GoVz1CV9El9q/GIus2ZS1wTSOyp+gC+ArYa+MaoSbheY RAPJF/BbH0fSaHw/7waJhQbUEJi/XFNaloXh4smgiw/gV7XXwJ8Ifhpwf8bberKZmQGP0XAojY34 b+WntFr7R1FLRWMIjyGINb/GPpP3yPwJTyTquJsLzOzA5w9EILyyKYITFyeIPADnSPjLwVWXDTkp giUBFHbhRYleMa3Qh/ihBJLZz34Rqh/u3U0cviyNsiUDPhIlmBMbtjy2CSh1iI88jD1xJNmoeTwY S+lD/HFUy/jyXK8TzT4cAje29ZEP0azeR4A8+X52fF65yTw7OUfPCPf42bnyKdPTh8Z8bAlzbOLP ZVAW1wGLMJMEUoCpmpV+7+ykY+Fg5v3JgpXDSwKRTnkIiYTT7yRhvY0N88a/681quzId1ouoWk8u dcd21F8YrtJsHFKgBtMzklqYbPvRerkS8ks/mLURrJeaN0aPYxGCOuAPSZ8XlNoQJZlEUYyI0zc+ YjbgMDA2DJYJj4t2kYV18R1pAw89UMKZj+cdx3MG5PymNwadj6yeyrQAP3MDXgt7XhM2FrzKHhJY QydFCTggTQZMy+HhMFibWiabmqc3VRW60IQ18cMy/Yr0+pAOWEZd302m20Q/MmeCnHfkFPLC/HlF KeW98ybZkinbx4vAyM1v5SJPFwvA7PQTwC+3GyOxXEymH5iIpMjAPRhMd9vS/LzYzWokb5CL1vdG PlXJ9NKvjlQDA4560xxweQXeRWHTZj9TxhO4UxkJXnnx6X3CQ0S2/JaoS2oMlo+YMYoaDMSKvzgh gL4P8BIFmmi7cdREDoNDGl4AySlUMDySGdnWV6sNyJPXkEYYbzQ2V+DR7WozS7kPdvE4h5Zf4j9v 337/tuv7zXHbIPStw8alFn4IVUACme4Pf/vqzZuXX7dnu6RX0bUG3WtI2nvlJbamiU3vapi+iD+J dxO8IfsIGLJ6h5aWBSvHshU7CcQpqQcwCFQPRlQlNDUiDyoJpF1dUUpoXGDIFIpsq+B4D55QYoCB qJc4N7hFJ2DZrNAeA1MzlRv30A6co9+7QWvd4gssSQPhGRJThpupvq3D64dlHovJzcVsMqQalCzC 3ILWwLoc0ks6AM2s4CuHCl1MLlD3RyuGO9dBdgwpVsrM7EtxxoZX2VN6IIIVn9xWsZiQNMmxUc0T 14/VX7qzTY4gt1U5dAytBqCk4Nks1kbWV/Fg5MGJFOEmOY/tY3M9omdglQD3uViZDrxagupst962 eWnTOynDrp0aw2Tx7ulNo+dlkwnMtSqtkNdjIyLxd62v/LCgtLaNuKIKG0aFV1sIj6uM5kYQJ0o1 X/2Ib3d/JyRG1PcYUut+5d4jLmIBCTky1Kwc8/jIFxbSjNKd3Bl3qmHqlOEbA31PWWDlmbn+uVpD S4YUGqiG/QyjsafybjsAHREL+nxI8WJy1MFIQCnueb8Wd+ZuDlrL6YoUKV0qyWc6nT2HvEYl+TU+ GQ55Tw4RiTtp577EeB8infPeQw5iN+CH+h7ORgQHB9yNs/Kuf1I5TBbkelLovAoYipYjNIRPWvqx g7VTm6Iay6T8dY1Ds7n+fnrvxtY6aZvXJ0lkoC1Xw7FCgGxSw2tUD1i1grKBaz3fsqxwrmm66CGf gU7uNrUR/GScewi+bXQij/rncWwwDLuiexJ3w3YFkaNsKBCEl5mjAs4kOSL2NtQ+ZiuBNltmSuGt sfB+oFuwf9OEZ3ItbrlRCqX3ZUr7hWNS3sGteuO4pfISMD/Op6xpJ6GKo5dKzBK/Ax4Eu4wmC4Od ebZwrWzCB3Oi3iPz2W9lP0AT0A/R+/aM1hMFCHtx/k+I1SvqDGytSOmZtBJKVwPaEhApSJEyX84w sbARHhBbkmlINYBJnA9RY+lGMPcF1WG6i8qVMHfyxEweiyy4i1vVYJi4A/OWSnnMvWGb8BqfUPxp c9+AOZAWwBxHS8OrZqsbbNfQNoeDqAkQ65FUM93uJgunuTIDmDjtenGEic8gNxqYgGZziKMCWxEq 04Oq3FSAPFcPrgaIq11QAAR5T5vRzaEEYx64Cm9WgL05OEAT6M0BCtlHX7HNUmGEqckHWdceQZJY lmu4mWzMiQcZRJrVdI6GK4pX4TlYfuJ2g56pI00+OnWXJhHUigvhc9pbEXf5gOpbhtp37HsQOXsw 8+VP3jyIfD4pmL25CJ9U5xVnjCSnhFjeQ/aB6azNVMJf4SI9sAswbR0ukx+KQ9P9neN/AMQnoiXP gPlIImYscguT0sKnmkXFX2N9Q8RoM+cej8hdUfKoWiwbDvevgpbJEI2P95RcyvnramM1hXyBSdy/ ApU4F7Q1DMbgJsZf/XDVlnuPu/OE953915y0ctt1KNJwWwbvykQqbjcjHU/HDVK5e42VtmLcbZil xPIgS4CHipWR+PgXlOFsvzH1TvpCF6rg3GJnhB/DceDU6P4MwQ+1WyKr2wb3i3WxnxlVA9d+ewvr pl3ObIMvqEHZwKqa7KTYEp5ehepRoh8LN8JKWMgJCUILM3w75oVy2hev6oi9ZGSsdPO22ehSEzU/ fLBRrtWo12qxi0+ng88bXw/DH8xRdhbhEDP10wc6RP6j3HftTIqYkDlSSjWWfkGRO+qn6gFnk7es ReJYik+i8PiJiFc7IuTJ46a5ajlLzNND1SieCsOrpwIyklB78Vd2lnlPX4MIUtcTiEclIz7fOFDa 3K2fwgEJH/Haofw2IImJsAvlUhYNOByraQTNECGFkM3F3Bw2DUG42uoms5l9JppI+d6HTijbj4zI 8KQJQMG4kuIfReHN/NZAM3/+TdCl+pRRDj2vTRf8uq4nWx1XCJIVwGJRRHa9xDzF2gpUVunoZwZG FS6qxtUboz1sPFYwVZIF1/Z0qeY0O50Ds5oM5lHym30z/ZUYBG1JvX/WqzWaE6yBLVhL6cJI9QBB YsOwRTsLIJhLr2iTy9KpZmHIrue82vESe7QSjRe6YQeK+CoBHK4rG8A9oTdoUFMVFvFUvi3Dy3We +huM1M5FTJB+H4Vy7cL4mK0haYxzYw1JqbHXkDR1Oa6kyTqgCppe91Yq+CWirAdQjL+YPATrYKzG muguWX1pUYIVEQU98SZQtBBta+KGpIUPHE5CP59a+mAPiJ08Rz7IsEl9hnwcQkxWrKSwHBkyJgHm 3srqIo7oHh/BN1iVEsRcz1e7ZnHvVz/Q/GpZ17N6Nnacn6RG6+KCzZbVgQThz7uZ7qj6syFkXXGF qvNYoLwwMsWHh63MowJTUiGmoJkfQO2P9FXgz8mIRQBkZDGc1U7zt8gwFwplSgI/54U1hDhNhWKY W8bFbg6ASyDuY8vlE/PqQL9YpboQz1owacPzdHCGYdniFLJaVPvDTqE35O+RjH+2V6P0m3ocUcbS NBooODGOfs7/zPughSi+J9nN9pD8Tq/rxRrOEJxL8EFlDZuRC0RsCl8sw/sfbMewELOQpmh2F1SN 3CUbp2/RqixWd3EmXzTmoqiFzrGOLlkCbfaqeY0UyYHtfHcLEx8rGGmROBMWT7FzHGzhNHUlXRjQ eURKJOyPj90MgfTNADySJtR8gvvOeMymyzFA86Ant/THCrl08y7DBeGukkfstaH7eXMNCrLiyw+Q l/xy8gF9ZBdGNpT8wrwXG34Rcg9sZiRGImo9N6XMGpi5kf35N0Zyf7qcT+sN95gUpNjpnlTdsxiz eC/P9RqDPIgRkd4VMHwA3m2+ZdSelXjwovtLWVnS2NPuH/98Dd89rGXb1DesY6CexA1f3NsmyDe7 wO3lpv2IpABYgJt5g6kbBm1bw4xg0+dEgxCOsXerUM8GiR1m/nNvRUoS3ktsMAzvzNIBesj2AZmb +baMlHitUwOuw8jF5jc39QwU4WBLvtpMbsjDGrXiyFXE96thRKI1kWqzu7mZbO4H+5hKl7Mh8j2+ u5+lRANJzGQFfN5MA8SGMVNmswP7HMIgSndxhknAIcPg0Sy0WUF4DSVBj5tEO8x2M7+6qgHlRRGp nY/r+Yxo1SIiUQTIS2m504EWnfrPFIVn1D/Q+JU4P119rTa/Eq0iAhacLWgUonTqchU1/LyZXAH4 8ncrSCs2B4THXbODICKOz8HQGwjRwfzxvOZg+0CVJMSIoh0E9uOsNkS0qcUCYn65qD0vA4zfLQxj wgMHEv7M6UBczA0TlC2Ek7qYbMHFCO76TBMgK9TL6RxC14ofaukQOYJCA/QeRiEAOc5q08oiOK8O mHXh47zLzOT7uleINKAiNP/IfKL5F2ZVL8g8CmvBsEuL+6P2VXktq/KAXjM3dZ2GRr1OUwnqM3FM 2kd+v++ks0EXrSlYwNkawA7/gEYyczxhI5z4jvVthCv24OmXc0FUoXfRQP6oR0KM2UhGxMdsuRwI Hipo6O4GihRDqxjOcwF5E59a4Dk8YZjna4Y/cLazV5dmV8Dw39wbZrEsng1+jXa0i9Unw88BFhrA pmjjmAuurRrg0TzZC6HJJ0uz4Jvh0NX/1VdfEV3wCP+h3qy+nlOyFFT7KfY3GAzgz8nTY/f+9xvG pl6KMW57uypwT6lWwMpqJufs+FxUSRCjx7FIxXM53rBB8dMgcD3snHOSA8e6+kbMppurHea1dBmw qELUUMnpo2Y13R1B8s13RxGpMihjKCJhALNAJd1upqt1HXaqrUOcckzpL2BdIBfVr71feJFsAoF+ odyoii+KnjlZFqtev7gb3VV73uyqF7rVYftHW6BgBiOt81ts5gXRW7xdBBXVB+LktQjBOKeIjDoq PEhGycjs3qZiXmqVyw15tsL9C3Ax8Xt54oXBgBYMfh5cjgmNbGAW7d5zFJ9y6tUyBGLkDOZd3rrU HC66eCP6VeedPKeEUysGyR8wbSIOqbI5yIJUVO4ODWQ55vFLg1eL1cUEIDpNy0HiRrwZzOazZe/U nMhmw9rSoJeQvhbNCuQSJGNK/vb7hKc5MhsAYYacNqt7lGnMkWw4RCe6MQc0kLw9tVlkAxBdw+GY KHQWsWhmHZTm2cnwPAWn+WfrIDoRgfHRbCpCbj3rPm5GRAkqsxt1YIDGhbLyMxYEqhWoDvwYzBb9 oDqMknbvcVM+3jxuqp65RopfNjku9+Qa2SNX5qpf0PH0ofIEvuBmgmLF16++Lr77/rR4+/zVDy+7 rbha0JERVSxcbZTY6yLt+0zBmmZyQnhcUyCBRwVQUA1+y1340ZCuc1AuMWY6achxb7EnuZne+tYU TvtaJgHmEwoGkLLtaJ9s16rZVslFUoSs+eBKwEH/edbXW+eyOrQsEUJ6iarkzLqL0nYdTd+8Ed2S 7yK+NWdYv8g10+kQVw6uMf6M6Jx5FMlcmrs8bB3A4VkyAnkGuJ5eq2fsEYY4jWjfguiE+RXAwo/H AmI+RhgBKzeIBAsaaJtqpuea7BVHlOL0FhYS5UPtmsEMhx3A+FrFVxDx4rMqAu9Il8PEDrOHoFef wNPc8HTEboLMEs39cju5IwCm2EnHvI0qKZoCs2y2OtIv0L9nhg3NVlPDhc49r50oAROfZ254Krck R75TOiRpprLRNW7K4p3A63TDpgBTDlikCmIxT5BX2kXqaSOaL5y4hkL5hJ6ALsAW4ayd3UE3dXTZ F8CMoCq2zUpPlaWKf1IVF7/jinJzyGT5eIM0qUnxMTphfNzNwRQ+byTZVHp726XlLuid4cdOwkR3 Oh837/5tgJFQT82Jt/zYnP67f40gCeaF6WozK+BXgGkBskPwsMJquBrRDYOKmsg3TrOGiT9WfrAm x+2BuhRbLWGgdaOUSjZR699x82+xN2ZFZLHprrberD4Z3ov5VMwmZC0Nn1dPivfv0fjKkXbEI96/ H1r0tAk6xWILhVU00O2AXhnYiiCFy6bEt/GjdQqWCfK2cC49wrP+b7SemqbIqwE5z2JGsZBgz5Kn HB7ZnA1VOlV51szhTsIBlD02rytTvQUJH3MtYW71RCtwlNqOqA2LSzXw3CC8qpnvmbU1NYTrVwo1 JmqBVwby1aNaeHIYloYZ+9oUxjze6GA6LIJffuIcKf6vZRtMfqghkLtjOwQ8a/jgqPmaGzO0wBPi c3yefeYGeMdotrOBRxgKGNEsCzwaW/W3Y5deTQC1psv1HAiM93uZzw5g0Qf9sYU9SM8Cl9rTvaBX n92ZuA/x3A7CefO+Z8pzsSQ0RGsigCgJwEP7sr8/fMFfDMMLr/fa4TJrSq1SdiFx+ZzzSG9MjdM6 QdJwPOEuCqP1t+52QVxgxm/kndJIWuqrIGkEMsIzTgITMG91qPBnMWskVfiPpToMBKOPgWMit4J+ N/Qx8I3DxjkP9XIVP+RHMuKQ/w33uqUdwgtUi83W915D/f/16pbLlwdP5eg4BSQMDciuC1YvlkUO X7bqUEDwxWzcPpp0Mt30CP1M50rataq2uBuPjAy3Rn3us8FffW4now6F6Jt+De7U512vnmX4gv+2 Lu88eVZr8eJZNCNexMCTx5ThkKMNhoHRgktbfasetbFz4uFuyMR3zUHzX7+4BWVKvdzdgGDK6X6C TDpWjrdXyNuBmznT11RyVnVrRxKFwc2rw/kcH+fH/QKYG4yB8r6b3pKgjblzXHdpGh9ZOWpTX5mf Nx6M2qOcTPfIk7BWRnqV1wcsViaKjcf8UcqOx7a0AmiDH1L6EOg1CXGGOSh0OZKuIkw3n8mE5JSg 0c7H7bt/A0Af4xu40hoB9+Pu3W+c+I/4H8S+wBkao68WJb4Am2E8rgamADwy4/n4KcRsoy338fb0 f5gTZhvbVDb1AuOqAvcoRmmLbh/mtgBah2QiaGjuYBw3/63pbpseHQ4hNUJPejVSLykXSkw8LhfV q81qt5Zs5Agpib+UXfG7ZgM5nLWVe2Og6usdHQkoSi9ijROcr1G32a42tdkgu7rbR62w+cksrLyI P+IFIpODAkzi9Eox+TSZo31IWbPE0mO2D+lewDMAV7Xrw65MbxAXcQw2Ih/MDb1NEceGxjXQ/VOE rn6VCkLNwvGB9wYmKHNfUHh8r5G5mt9ei8D6AhiU+QH/mu+v+DpqfpKPCinvG54U81Q+mnf+U70E brjamJ/tZ/UWkM/CLuOw0F9/+il9k6bvNAfxdVoZxnliJbaX1FOIBoqKpdXNDXhioCRj5t7xdCvN 0cWNavH6sr6H3tBtynAFSNZILuMQ7w6PNCgSnRtesQGZ7mp9NYWKLWWNVD0D038vNbF7Mp439/N6 Yc4teTO87Opayyf61cDqEHnMyjL4fZFfWxp5ImWCLcAReZiuk+JIwCdxKWsHluARBgOb2aE7wfpC flnvNuaEa5yUCvNwQZi9DSwscA4AialAO2WeGCGOf0esI/r9x47LKnMN5x91QAfHwbRQTEsTxKdt MTjfcOtu2hJDVXkAa+t7GTTEJJL4UiaScQCOlJqQEc9LQHKJuhLTyN15nSjQUh+sbUjJ1quVcgTo RIiE/Z8haQck1aQzRLrsb44D2ng7c5bD7gaeMzXbc46WzrB9HYCGYhQV4OkLQhvRrqtCGg11QnHW ICFSEPmkCqo8JGBUQSBB7sfxlfCx0u+Q6pRlda0da8WeUlNiGrR+J2oq2FqgO4TGtTywo9iHAFRs cotJKfEN8+v4cjExe/3fF18+M8KZrdGedS0okKY8m36dewx5akLqWkNtU8mkSpKfWS8A6QZVKuW3 xRB522STxunlS+abezP01/M7c4xG4DfmB83+UAi8ipMFZq9hWtIea6Z7AAJmkMpAcn/aIBnTD+xe rlHdHHZcshz2KUS/SiaixwbwebTUAmgDM9DH6sQO0lWJJEj25BOSJS3beS/chgeQjurz0ncyJ6Q8 phjLR2k8pSpT2LAvFBYZuH+7Mt+Ipdn8Ewixx79R8sMk+DoPABk6CsxzAt2lmAwLZcBXRy8CjAI1 Ru4OEYZQ4PcBJMTbeLkH1xOGjQxyt6BEvaTXEnc+a7tZomuEyFBVymcf3Jl3fjYW1tXAywNPWZNr gI6ARPUSvQOuGe6chJMtJk9p1fw5Gx59eR4VAPW/Wr9hUkmBOePUig6zplucW9HCOBS3/ZEnLS/S o3gdEa5rwL4RWCi2lbs0zYMzcKQ46wab4rIhNUe4MxKpVBV3kbc6D2AvXsI1xVs063hU3N3dFYt6 C+6oK+KnRb2dCgwceJVN0IQ3w7zOKeAvOv9w1ONJlOXepTWWEp0w/rGxmkN14Nh58vITpydF4dfT JfAyml6LnSNNWTZrG6q0fVjQDaCUYkBxKurGh4Thgu74eSHnMh1C7jzqs2Ql0uTghcKccFoJX/po y4mM+1NJuD2oXVkQsEefW9cp1eUqYzyLYJofFd/9zQACNSafVvNZsTFy0upG2D15sq/r+oN4Go7H gCQzHqPpUvD/qZ4S3LwkE8fi3pTYknrdYtq8uX9zjxFVcCJA7C9c23+vDHvzKbFd77QRaY0a7vWL P/1U+XwZ7g1TwGxaio4EKWCzshW4gJeA2LFJYSpcz0Da0opNhDT5009tqb3MS9AFrDK4aXHiLxTr uIy4Yw1TDFeyhEG7aVaaPEGkq2fw/nmoJgzqB2eeXxr+OO6mW6ArAFki5AKhZNPMKcB3gthF6KDO p6HmMHNvQtEa9/bM/DlPlgFAvG2UeWwxALVO+aG+H7FDK0YFW/w14U3V2fDZeSphmewuO0Nuj2au M5QyJ3+JxFrCsGRiMyNX+ci2MPLTvaevV/leSXhZyGvcrelH3RnZX/OGtNvxBYnOGTAHJR46f9C/ e/72u5yo7PJ2hCjI1heYD2d1bdJDhF/9xq0FSs4HkmFLFqG8I9awAIj+jMriRbTSxSi9OhTGaEL8 CFWBKsJLIwVqZXYgfc0fS+5kn5VY5L/GCRn89V80I9Tgs7BMf1xHrmpEl7K5Gmw1A01lfP2qCRna iU6ozGzIrM1feC7hHFnfB3jUqrHBGtVj/FLfDnIkH6oQPlIeUJx2kxSfRLfoX6zx1GpjvlihIU3g mq3NNLsLwR9+3Jw9bs7BQEJtSR2D+ayKNGUSZqK7N+LKvG7GVjypdyQfqCnYvJYIBCtt9CfViyHM /U+ZFIrSqXweRVER+VLLN5hSJ5RzNKhK602QxDBAyAIoQqSAHtxTe3wXZB89aFIIVTGn4FksjYAk QuoD+LSpMdGigICAtanACDbfEyASxclfUOHXmF1AbZf1soFU8PeUvMAnbpbRf0BfxISAfhiSl+9+ gJ3QeDZliPzebO/Nru5iaGu3inqjR0GejK/Z0zLVwyj6++zk/KBeRVTbZTMRIjaKc+fwx2U3V9J5 prILIDrriwHJ5cBM11EUj5vkg9vr+fRa9IwY+wLbF6tnKEjsoSGX2wnl6mJKf2A7f3j13ekQI5om xW45/7irC1FII4e5X+02qj0aahNXVDwu6kGkQY+DOOykYZ1UXbdvvUednwfxcmKzHEkFPzZzc8Pj UGDwLK1SfqguNyRiC7Tnf2ZRG4tyxeHl8JE5uwGKFJyEVwCuiSHffZsKCZ9QV4PoDfJW3hoJB5zI BGx0sgAbWx8j+teb1cUEE7KJeQd3RhGm7X4EudnMcsN1mdRAFHgo1Ee6rkh74m4GsDjms7sd6BFX Ri7OOXAERW0F1QF5yNM1VDGaymGLZLFX/iuv0+BfdKGCUe9Zq6D05y1XWInDKEMBODxHD1MSZC7j vHHPXlk9HwgZ3bLq+oLQ+Z59TSRG3fSzQXtbHAv0Qhyn+aX3ftLA09aI/RWye9+gVRdlA/t7latG LdDeXWGXpWWUfpnUQINasmPNtuY/8EbsP6pa6tPjpgYsATyIvB4gwDkVvmZBy/rWXrpTfjit9g5d PVynBICDxdRQm6YM+jfwnfNZ1xSaCLb7FYIsfWN9McwVy5rdnMtx+05AP7B6A3HBEuCNzcwbPsq5 dt9woLiQkXvQD9+t0TCltJdDE8v2Wox/fnlpvtdJ6/nVWmXtCWpReFX1MqZSw7atYgLkNKpfX5bd OMarDY9f7Q/ciC5SJ8Flglf3sBu/9EMYhqYEC8z1FyIGd2YcTA8uP1ZEEu0L4L0oU3PgCqTf3c8F dfHUGozXm92ytl6LrE+w3/PCDSh64S5Z+emtff+py91igXW1hjS/AON3+sQnAwC6hVrrAr5DD/Cj euqvl8735dJ9QdYw5eah3h6pzzHMr6pNVReLI8tMmjGv3Sqp6j20iX3N6KRo5DMYOj4flgiNzwlb QpFNCMUssEIMyMwXZYDkCzKUpcGlvyE3pbfs5vXtavVhtw7BJWJbE+LmyI7TSmBfDwNZkPsFOOMq ibXBQHp8liE+9iVGpzTPnRhfSpsD4NEAIB/WZeUZecys9aqc+t6q08wcqLEjnm4w4nhkZ8P5F5KN 04fUjk/8neGrpXfOky6oyoNrB6mVYF3xXy81u8LJDiiBUraHcFJs9qaHDmu2i4Yp+nGHERUIICAh U920hushPVc8yuZO724v8GlXMh+hfocrZETi7jddLSYl1ukw3GPnka+YDXq+MpVSXC1ihoQynRSC FET8MQiZdu8KRjh9e2C0ic9vNX/NozJvb7XIf0uYzD5Qo2wkbzDBucUvdkkB9IW3n1pqU2OVONgf lyHuuld5qgENGJ0fiq3mcTN8PHMw2W5pw0n84qSy9wXnjhZsw8+6P2RNxSglOT8u1M+iadTlYoGf LyiO9r6AXDvqdcgZ8qEmSe6plcHAuWe13i0mG3HI1Ubl+ZJMyBf3fDnAewH5gj7pgmBDsICIso0O wJQnh3JtV0lVWip1aquBITb/Mhe/S0SEoDydEAxJ6U/AGMq4hKBE4PN9l0wCoGBXBL6oVKnHYs2u Df/BSDd2HjZVLS38ES0jRYa42zJ2ror7gJbonEFXLClnj2dgRynmB2hW7Du9x00P30o5O7VbwGmo /xkYrRurWLhIo9oINSyPWJuLVbphsydFeEFqs55b20tgpKLqMHsrhU6KeQdXqs1urAmAgehD82xg DMfFKjFDCBvFk/dBLKdReSkWc8s7JnPfNC8hIJIGzAUleHR0qIWkd9IuRACBs//y45lKvU0i/Qmr Uk4veltxElfCpX0F/hXm+3i2u7m5t1gqhuf6iomQZQYM8pVz9MfQaaeQeMXg3pu6WYM6HiNHPIT/ jkaDdmBeEwFV83ekzhpqEbEMUWPmibbkoZ4JkmQepEX6yOZl/BJLitY2yYWZcGnSlFlS6hI/+gj1 1hMCrfwnHdVdDKzb1D02fOsW3McQxpypwzOyiCPD/ogJhW3uDLJd4ZTOw7l0MmIFQHOUk+VTbQMn 2hIMM5gcmaRzF2onG7lQDGv+tb8ZklInjz8TQh7KaJy6QFi4bDdesxaTm27m8iAiMB7HWFK3gT8c qkNXQ1Oj4OlBdyiaHaK4vBM0F+9ElbNhPqH/1drn8Crm5SoTvDXN9sDR0LyMaTnt67QWPoAW15Ho eVi9fN/vdc2M0TpXuwbZVRegJWYlOKsa1o7rURsWTVD+Hm8HF6+jkyTbJZff+fnBvt6Bm3dip7W5 DCARqK2gbnqchz6hseOYE5T9lFd7i7ou5V/lYrlcoBO7lOwxpCS5WojTHiuxbMBbqGhQ0W9l0IHx uP5oWTpiMR3gbFxaEgHtDr5F3zQEerylaEPKC/S19Q0iA/cKf299B/etvABfcqU1wYEGEJmamGtM Fa0vYfXRWxnb+0OdsP0AFbdSyzq7UiKasO7SzoB+3VDLdTaBEjwsfc2/C7LgmKDYww6+hlrfnhy/ EcyU+dUPeoK3f6ng5ui9Yd4Jr8PSK1MzZaezLkkaE97cja5qEsbH09XGXLnue03xabJxibakAocQ ERiBy0xgEzZWifiJmjHDF+u7uCKrurevoVB2Ahz9WJYG4oS1de/SxbkiC5EivSwyXeLNsX3NLQQe JJL4b3ejmob0EvLVrpcqEpGLzN2ZG/3wSL1w3tlT+JxxnjVrChYSODE8BzegRsCCEFOycCG1KCuw h5zTumqO63usSfStFyFcVpayxBmRYl3YGZEDhQxpcerVe7OM9xgz0/HdGZcUA08XfnAHZ0gsXa2X /dDMMzUSws4tmfDYDTS4H7wOvDEBI67NjsXty03SlPUFE7iL7W3UmgIDK9X24HahsGtYYq2oTKcz NnUQDkZ8b4KE9j+YPZXXRvJa9gvI74bCSah0VEJhFG9MBzhMvJJlIRoYxVCRFm0HE3KXCKxOTj0s bx0PzLQLyVTxbfggPeT8dYmsqjDO4BDDtwHq8Pe9qu8P2mrtxBW4dSaJi+hLHDoE0yf2CE5lIOHQ +BG/GkALiTt04EgZCtVecGi4esKys6dA0CHxl35AV8iBN5XSbj7j00IEdginrLzMdlPJouVIkqfN LLAjICZR9UuY8A4z1C3rW5uZo00aLWa7TYjYrQA+MAWwyiVtZN9BnGJ4aDprOz20MBRy2dDpnDGV OabcRfWq1u0IWLgvLWdam8+GLi26xeagdDsz0/b8cs4pp9e7DaSTgDwFry4Rhd0PqVkte1uQnNfg IrYs3s9n7ykVVL28conAbbaAwPZEQIS07irHlptfzBp4UWNnFWA9DgJXcmiLSN4LgHssAGvFbubi cgK66nuVxzqYts1qd0VZC96/l6MKq3//3rmyYqoG0vYYAarkoCgzgCDIaGNW38wGITySCuj9e1lf UyElijDLWbmUh14VTyC3EdQSXvaewCpknkFd/hmwqS/rDWqc0PpvphWNVaTJByTdZcPhtZynbIMI +75yDxyyzeRiVifI4HW5VVkvLud3W/CvhlcxN5ohcAt042tIDKeb2/xzZL4Hr+ELULZ72yKR1dEe IAqyVOkx3REEO8U/JWdtEMZapWy4BFaNoPOAFlrPuomqckcRHmE2WxhxMvX6jPMV61gDrnPpeNy+ Ps52oNWFpDTmRQL+1hXaegCcsoyfYKdEJJDzr0wd4FVgqGTxzsmHz60IeKlQBVSuBA4CzFzd4Q4K 5Dm/w0zSASKMK6NVxgQwjL1SdtMybedHbQImVgAWRo5ASpS14qj0KHcmR/AvbjbdIw9SJaUncE/h hqAVbb2qTaJR8C76pbAjqaAe3WQytIdjdGVnWR+xBDhMmLOACsLaPBPG6qn7mNqI5cNs6xWMcxXn 9El4DxHKYtAfPk4ofa5l5r5OyNNDBbg7mS6Iri7VBXnmtW37RclvVfKSgpFzzRasZ8Nh8WxwnGRt uV5Kc7mupkNp0LGSZKtbzJGQOEmd2Vanbmrry75rkHZNy3TXSICpvtI+LuG4MYcLqX4+o+N+8N5B XQ/i+uaXXEkatcUG+WWGl3OghTFavGd/mDAiDHJ56PIE+ur5DbRZekJ8laMahtdK9DKLr2WmaTWd 40nOKZ3Q+uXzzVbyUXeR3NZvLG5IolsYedPcN8BiMeBf70BL7TCVduKcf+dhXeQs7o79xzpb5XGU vwUFq6CoS4pkrVKeAn7sHxWEhkeE0y8SUVuxHStpuvLdXuRgnS8zvXPdJnv0Mn825CBzEkXPuM5z 5Q/Bz8iJip8D5KC92MG9gpKyCcAufgkvbXT9UOnbJgWorhYRu3Znhq3gFEjGOSSbm8blbgFzAJcd ut9IrBnO6kSOhKfUnHPdXYLkmGrM3J6Cuwu9ai57xXB9P0R2OHzvA0liXrrX5p+vBfvjfSqIRiRz UI7ZO+v79152u++ev35ZDgaD6v37tKAdex5QB/t+lrw//v0/ZMEVkl4arMCZ+NU88RGKklQj5+AZ dQRfFOrheXfcbTK9rmdjZ9ThCBQXlsGqAMyeNOra8Lv6bruZAB5AoFNRiEQTmxvR3HPQ35MTnOGM v3+PDZlL3b+3L79/L62an0nmhh+xbbhOmjv2+/fSMlwHa/KDq+lir1UJXlXRnZjjZJsVYbs3u4sG 2PNyay/UqiLp5y3mvjAXSCQbznVGAwvv19L20DVt3qvnn+hOG+W5dvV41eBDoPTl6sjqNlx2OkkX PMm+TymvJIEaXWLBxRPOA7pYQ03v3/fNN1paM06VZFomoGmwmGQOdhkTKHvCYn5ZT++ni1rOmUx/ ZOmGBcp4sN3mkN4HwuakLvMYainVIcHUV7VuQC/2T7wkekTZSOXJC4Pn6YbFUCBnk8xtPflg7lq/ V043pgT0cFSUoazed6Ei2F2CucCOu+1S+VUFOASqG3mLpllENPObQmfSn/PQcve39X3CZkevptJn B9URmFp4sllXxFZHDQ05vCkzjhOzepEdQiqUojTdqTIHppdPwn4SlkUrEIozMDrtXOadptZNLYAQ At72FtRGNZ5l0d0d2JoNg7biVCdCR9DXLzpDUW3SYIbGuFa+KTqKWNFhNVmiwTT/Biket3g5AMXV 9nbVCUBNuei8bmxcGYaN+2e/rdjChLt6+BorWS7fvw9m03AN6TDWXkO+VxypNnPPViqvnVlQCaa1 KVFjjqJ5wB6MsVCMOmy3eBbunGCn7/Ippxz9PBLjkiHroNpFTpbcEKylGHkKjLSZFSoh9A3xZWDF 0ReoULMyYyb8Hn2VBF2CD0xziO02oPpU6mjmvy3DTc0LyjwL1EBdUqbXqD+8bE5R0tIEYsF72UFI exIy6TZNC9eVJ6oMNZlXCVXJ77AgMgeYLFF+kExvaAgpqFjPKUodNSS9IbvzcYsw2ylg9sqG7rZs loQ+DnFjXS0sAx5Uh6dNGLQahINWWOhIN+N5wsbis2QI58OAFOdUNfs1w+d+5dvB3CEi0SL83T8C wMxlHzkeiWmuZZ+Qrt9jopoA5s11bR1dk45Zew41t5LaMaptDDFlmHVgFWxWbtkbFeC1GHhw8c8j 1QVucsR/PaeuPUZnX52OhxWbmUOS07XGXCZ3tjtQ+wgyiZOJu7s8Md00dB0U+zTZNAz3lIet0/Fp AYPOyEzaHdHZS9Rb51mcOHVs2YHmMeJskTSKaEsUoN75yYhAKttVpgdA37BSBOXjSBpG2Gojx0Tf r/MLU+mPyyA1ARmFHzdAJS73qy1TpesAKaYngB0utUJxtkUrwvb6vIc9hIwIoLjATHjdTgI3SBtb KBu7JOoJExjQWnBeCq3JYC4o+SleWAN5J7CXj9QzLy0Cimvk+6zA3Sn4x+xK0wsuPuCUvVXH5w7q NcMiLu7ns5LrtA5l5uBKpcagmra39GC+GkiU3t9t5i7WNWmE4eYTFphP9eYCQFnEYUNFEvIj1o34 WzfatC0bnkMEreXb29BpPMrEpg6ialu3d7i1W9497/y8DR5t7jNvuH7W40xdNBXcaaZUyWycAfRU s9nSQcr7bVZ0wRekkt/rM40lQ7d53dPjla22xtSE3ceN2dPMEzg502raj6tNe+rHFUYxWTpIURXt F1ebul4GpkR3/cF853xt4+ysYKvvdlMDNo8zfVOhmaZQPhrzM8I+98+MV9HjBjm76QUrn+yyw9Tj pPdbUEolElS8HB1BOF8vogj26/Vz/+BkLCOOpNxlMfuG843tSES3wDVrg5HvR4tJAgLYA7Mol4CQ vtiuSq9ftiPhY+1PaINZy8ulnKtfnFSdj3fv/lfKUwTQVINZvR43u4v1ZgWpWz7ev/t/Ojr3khmj kc4m6zkmRuyeDE7g0EOPYHzdvaqiuvt43oHm2lw3IAfMxQa8pSRfbrffMc+mHxa1ufONuqby9QdI RKTqsi7E7rfOx3969z9Bx3HqUcNjBN3Fxz+d/qt/Q5mdyHJAhihGpzffIYnG9npTT2ZHzeSyZh0Z pjkFEYANAp3O88WieAHPKL0CCXwQIbKBVZtBAEkfUzHM6o3ARBu2Cqm7UAfX4ZyxqFGmBLd0mOw2 dFdgPzGYlu3c13fWZIGl3FN4Ym/nNzaBFH6eNNAZ+CjOIH8zaeZT7HGcrCFMgzi5g57O62Z08uy3 Ua5D+xSV+fLFL4SoIsvdDUIubEv1zpF65+lvQxsC+ACRP8IBucawdJycDLYLzTQNB+Y7E+gCFZyh 5k8BouzCt/sF/hA7kcAgwdmo2d7W4ONcpoZzxtpMrMO1Y8lBNQOCm1noKMdCpAYA3WU4goMUSgD7 TI1kInU9laQQs+qikHRL53BY+k6nyP6gTvoV5PZTsBY714ysV7jm+CtBY4QAON4qpuCIoBCaLYSO US1IrxX0nn+HXuKVgbeJuytFTm6q3FejcIcFSIFF/Qn2x2QK+RGRI6xoUL2G++AvNoiJIFuWNHIq Qhsie+7B+e3m0F05ca+x4HkeN0Po3EFMOsd3qCEe+ewhBhSEN74qjmPqhH6pASCCPDR8NsSXztPy ACAZFK9Pi2a+3RHvRi5aEzeXyIS6uAoBEQPgjYUiLn+XWv4KtDldNdvnmNWMOK1jupV2v8Oyp4Y5 P6XCR1Nz6UQWnzpunL4Zuk5zQG7JZEwDN1RzvO7Qw5PGR9lyoVTHDyfc3RxR1rW6OVpdHk2OqIon eGocbVdHuMWOTB1Hap+Qob0WD1SrETecFxAld9Nr7hZ7pwKV1l5EgDu61FEA56y5ii7Qco/xe9N6 Bp7C8uI34CrqzUVxuajv5hdzI1Pem8MbXY4mS9TlB9Z1u7Tcm2IClmwYph+2/YgOTK1EA3EEyO3G DI88xHlW5jee7vMA5oiXMbpPwNtqg5AhjN/QqG7LWbI887C/w3muZy+YYl4iXZrKYMMamQXaq2zi 43Tpfec/LnMfJpVWNTr4iGjCbEf4jMlTmLetA9TJ8tlNoTN2hW3wW19EFaUPctcT6ZtNukRQSDIj z81F8aplc6JUSJSKTKpBpk8/OLoFWgLaW61ASe4T1F6BCr+TEcp8Px4cR1GsrpNRdL6rqorEMq6T xDL+cqhY5J+5sVQByF14iBgZ4W49N7ejMmXM9oXc2MNEDnz/uT6fH7a/8ruIhoMzqfaI3VdggfKn LdcdRTcP2j44Tci0oMWQvg/ZQn4NbmLcEoRIq22cY2vlC95IH//53f8SZb813+rNx59O/90p3ZKs 7hHuKRApAlcMDAC45LABSl2GukojhqDNg3npBLg03VLiFLnNfWNYjM2Lu6kzuXNx6HjJuVxiYKDc c/hr50EqS8m7K0nypFuA8z32qsIAWHn+h9Xqw9t6Mbn/Wfl01/fmbuul0PUy6C5X5gBeLczBvDyC W6sfutqSRXe5wvdWS3irNY0uptAtu7N5M119Ql878x5okN88P/1D4WJijDxEF04KrYELPCXNHXD3 q3Q6WM4HG2SCZQJ8g8+eb1yiWJfJiZ9k95Rfod0qLpRV8Kj09QWQBTiXuBij4CdViS5hKqFl5hcQ l2C8vqmSpUnNOqavkH2disO/QL4hdxbXW89a5dVHNjlXYbR/dWk7cUBiM4gGGbYjzqDuqYkB+Hqo Mu2J4paKBac9p1gSaAyuKlMIjOA9+KmXCjkQbeVeo5vNCWErDsIY4AY8O+Pun8fGOjczxeNN+eTJ 402lTHU0KTNLgHrhszPp+UjEygD91Oqk+XtgxcxFSsryNoEKJKQ1R8tEa20gVLZUvyjBr6NfICBV CEVli0G/7BffKCE/A6XYIknXaFvSc1Sxwwty5sAK0Oy/iJPAYDSR2qNQVUbBL27AbC2RTlR783ft y6/VsJe36qRsLM6xMvlQw6oSyy+pI4HiWo1B1ZNCfXYTZVeCPDx48ye0H577zqa+gtRSm1LeCLYi px+yh5qmkfXNKFFlP4pNnN+NJPRLOwCEXCxKFYgRqzwRMWGQWNQkRctgkLvlvmGqamMdYbBiLKfT ukXgPvR7bF+iyDtDbPbDh1t7/GYRMiBuj1sK962ASLEdFIkSuhbQJcZ1mVrNViuPMUeAx28v2TAU NA9hdBPbg9a+V36aH7gQg6uIuU5PJ/BFZXBBr3ozu4v7Ynu/1rmFCZMTQ2Y2Kwi7Xa53WxdlCGp/ HQL9qHgCXXn65MmHW5yHGdAmp6YB6fNq/slcvqhW3YwRcjD6SCkXTVctDgnoRsDQ0g0MWUAGZICr msclzlnV5E1UPkkNvHDM7EvwP3cSldzcRs7jslI8Am6fj1MPBIqQnxDmYYRLqNOqNWGe7LnOUtEg VHACIbDh47lho13VSbmWJEJOMKsXZXUMdl5rykTk0tNFkzEMxnll03a/2PkK5oMhJHFbkU+HaZFc r5K2737ENMyV01+ITC4zO+xECjMGT2PpJz17HlwlwlC2oFCKpUpgllkXoDhs6w1Hg5Mde7dlVlQb jlpGCgbA/ibyU6a2+4aQ1yCOvTypBpfjQHq8vYYQsKQmm9Egr2uEIOciKDseJyC4l7O+negAwRWn /Gw+PE8f7mruR0TbaVKj2Sm7EGrz+vnpiz90+wqxMptBszbHVYmj6Ks56nOzkpq0JcEyN/viDy9f /O3Lt9IyphrDaqt+0T36qtvWjbwt3BvY9+1ttDbB2I8teUBBT2eWqfiiODlwK/udi+e9C0rmZK/a mMBzFD/NPVkYAcbLIAuA7j3etDCBgBE4ylJig6FQBVUS+O8x0HAbpVZt3CFLodbax306z2XjhOct PqnBbEzpcuTcUKoqOlXSI10EoMhN4J7HtwCwei0AFa44MZcPvojGzA1cuNLqBNA4wPGd1id8a56+ gKcZZQQ8fw0qIhQRMxVwgXQN8G02D9/e3qz5AQAP36xPg1K6CVe209nUd+PVbmsGVKM07yST8sfZ F1VR/nj7RdUV7Ka3u+XbujGyWItOZIvw+g44nj/N2Icg1paQpmQbpAriKkBFzx8jWHkpIB/9AmaA oCUf6Rktpa4qKgvo/n5ZqTYoKwMBwHv+qPYiyFU8n03qniFeSJxsXlLBSLeirdhjRXAPNSHzVGCR NIfTaFcTET5hs8BLSfcweS8TieQjMESX290NcBW8SLdXhJWdmaLn7HdhXq3aUk7MRAHiyPjnq+C8 xy8E20o0YOLCLYGoURDp1qstijPucpGuvqNApNymxox5ArNCsZZgqLxZw1YNMugBVLZ5EneMko5u a8NXurx1VVN8IZR3LDhKdDXEwwCpb7K8MvLR8XGYjCB0m2DWQmyFuze4+QCcBVulkJl5oFVgRwoj lOHFaPDy5R9f/XAa15w8v/1jGa96kPMdo6UowlQCvJrdBfAwV1Rugl8jnBG4DEoqgsrhRZk7y2Sm 72owx6SovydBFaC4QdM842oiRyI7I/RBTUjAK5wPb6RW4wyyTCBxgek11AnwvJPFLVw58YcDFLic 54G+PiSUwG03DiHgWE4aZN9XqGDtKQa3dhcub4iBp6yT19EXjsqU66o1s9NiZjqSjFflZzJranXB +Le16VbJTIrqAcSJAloAsAP0V8NxJjyeb0h/h9cQ6DHXJRq8mGmbAglfEY0ybUogtCfltk2izlr3 SdQzXC69wAgJ6KU+Vy3RpKrDiUs6BSME9ogohYAsBKHCEk/qJdMGQMbLADAweh8Ue/m34Wkos/nv O3sGQCNqTO8Num+iLhOGZa0mHkAmFRoEVhbN6AehmSb3PjLdqDZ/CDZADcqpKzMSarB/wOtkpFlM RM+JoO7DdgZFzgW6RvT1ldRI2z6rDknTpSmAXbZwA9BTS/tBIGgIp0nwBhhAwmEmN5M1kC81VoHJ uxumU7Zpk0c+m8sfbM7jyykgS6mmz93wtVdh3gi33dmBiV25Ar4VrA8OCRk/ZE0szSyOzH9VehIa BO4iBeAP+CP7gVSDBbuV+40NbiEgpOQI33qJ/tbd3fby6LdduCHfXnSjhCswtGy+FRr3OibOrUJI SVHGEyINUYNm07rLqzE5+fUbIU4CM2lt0hXa+nrTyyvJAjviV/wa5RQ/tNr1PVYsr6Ur5UJU5UPn oAdI1a2zsL3b/qz6zfv5Bvj05Q3B1kJIvhcgkyA0LqVtTKD+TjAZpCL5Tu4IdzsP6Rxwkas2mUeU i6q0m5wPwh2ja76ei4T4papY32crsds4JbmtWdw2Uj1fNsxCdiMVwdo7SJeSLlKwdnFd/LDSvTFp WmsSR5dl49SgIYw5Ux1aEoOWHmHUWJPrjjw3dQymfigddakh01GoZ+ZYuPnS1hBGJcOLA8MMUIus h8T9k4jXKhHQbV5V7kVLuMeOg4E9CTbKI4taLLCHeH0GoDIqqsafKQgLH5QlmUJ0S4HIFK6fHJbx Eg8YNXJsLyXhoPFduNROveQWOow9ZGuPGHQXBFhTdKlCryWJmdc1NRCqltmeq8/iodElnDD0fLgD bA1sbQixS6i0DPyDXVDJZZstVmOR60ZtoHPhQa8miIY2imvEJcGn8Xzy70H0M5OSeUiD96bW0BR7 FQWk5ViGOheCyVuIkKSrMBLO2fo8yb9cT8oni5YenmTInSHQsUmfZK3MgcKaDwLxoJGkh7BWWyIY hCpktknjRGS7dZpSjPScuGW8WF3Ro25SXcuvidKWvyYkbPjZ44Oqb60zWHaPmm6/gIHiL48o58Yt KKu/+Rpcyj9Mrur9zCPmHOsHMY9HSeST2WrseFP4Cr+hE9Yw9RlJYS7MZ3RwS2brZdvK3WWw2JhS ITaRVsCfLdK9BWbcAEogiSTg24ypSMporCbFHxwZHdljQ8KWD7DipBvGmJlhCxaNGfCbpt7NVm/y DaorXbrLjfiT1LM8ckJ2xNYZJWzbChl4U/e11wrYM94vyiUk9v6w6F9WY5QmgZBeqjxDA87TPTpC zWN9sx5hgLIn/Jn/EPGzJ2V6KhJIZgWbCbdmcgq4T94kWOT/CFF03jC+o6iQMHEk6pjEFWVTH3He Uh7sIIXSlp3QMzXWc60osFMqKiV2d3YKmlCpFCl32R1n6xTN2U2KxQcyxaRM4Mm9+UB6aZ45MJbu bi7qOGkt1ZFaC70e7YBAUXdtP5JU7FI/h4T8QEHxIRw5r5pdTG4uZpNhZ+/GTfPhvcRrhTocspVo QJxCwKuutSR2QxMxy/FaNmzKSNoUdgg4JmIeltqHOQOwh5nEx7q5JSKYJzTrOcOQqnL445KgCKRy K/lGg2380VZe9h0F5QwpfLBu81sk7mihzF4xzqiCc79NVYk/y7QYyCsgaTPoaeH2GMXNfgDcjz+1 K7aGRaAn4g4L+oCzy+kLupLnQIng6eakOwkNoXpNLrygsXvUrVozwmTuToSB88TNhrJTQYSGWw68 Mstl2eVR+rnSCeZy0s4RtQh/Ri4iXQmZhvFvvdmQyiU+5BzWPig6wKPRBvKHmlZhS80Hszrd5apQ OAAMC6bDgD4B42oG5sN8Y1Y98CI3P5/13vz96R++/w4iIHpgN+0OWX1qlgkOdAKfPQuSyW9KUyu4 P9zOygrQNZef4GupazPjMCek4iUfbs96pmCPwsE/uTVAT5iia37r9r0nDj3chzcYvMHJDqZ55M/2 yJt0754rrJoryCnA8KYhZTSoVVsN/AueqGae7ipke5h/mx+503V9ktLydmkcaiHXz3LlzAB1OXYp guvofHnVVZTYJdSLUbcfYgQpARm6sz4Z4OT6Ot9L6MH6WerRcgV8BkNLg9Ar3BJ29yaX7PLELtfl syDf7mLV1OPLmeFyqPpbTLag1ECv4Nv58stn3UjPjm0Mbie+9+bJAKvSPz2LfiIPDjN4AL8wM6hH SM8Mfc9qYJUzcO6oyEsUnSn0lkLnDjNRiWromarG/JCpBiESdjfrMT1gz5bL9SFWdO38gS9m7g5O O8JkA4X7iFw/ulwn7ezvlnPo+Uu0DySgCywNsrcV4I/T5jby6ePGms1XEE5p6gAaBevv5VondFcD p+1sVp/IJVkG9ziXgRkN97J1JSrFZQi9hfqaZI8MEfssYn1/MV9aSEdzFm5JOgjFu8sdJUXXiA/4 LqHw2zflxp/kNMhopKYAy0NVFnQmPki8sz5C5/ID5UITHlYb4vWA0h0T+KpWUxEv9NhwGa5Gex7j Pcq+ns4NS69XLWmq/YOPMwVAyibTFDq6xBGEfsPh8kJec29K+xDZAYYCuk34dgt6EkyZh9x433Ch MrKUpTINYJNidmPbJDi50O/IPaoqSyxA7oReCXhOMoKAclSXAkWJpCD/TFIBMcHFsf6H2DDzeFP9 B5x9EmrGaCCxF+iqbZ2x8jj5RWLxxlNrdLgxgtvMu3PhL7n1MfPMJbITrGxOep67R9OuazDslDMK PknodP2NBbLwWO6vY7ANSVyRreuo6x+IH+p6zckANqsVuM+MtGtGpGrseeqMnlmPtdM8epeyO86n ESvCTB1AHGYCwOyPFzcUamKK9r2p4oVVvXI1jga9ftQj5ct057rnuTn5mrI70s554fpJzZ7rw7on EY2IuLiHOdNh0GUe1JX1VSbQ9eR2OfZIgEDXMBC+nm7HcM6AwBMgHvy8negzxZgDYp4DzGnGEmGx pu4cYYdJi9StfLdAUrvEZs8uv6tTy5G+KXn02dmyIJUsHVsQQEWchAcIeQmhwr7tiExjmhPiIECk jGbZ/xoulLul7VseHrJSXxHfW21oymVKDGd4NviVmpnF6gpTACXFdujDwJfwp9dzdMnhCvXQuKoR /xURXEu/+PaAx0DQCWpQkTIHSltcPy3T7k/jbkoN6A3rHtJJC4lf1xkhUdwAX313+vLtd8+/BUnh yNT12yOqmDgtmNoQH48pQBQ1RZmTZuerAWDWYWgHDKbvAuyVdrwFt2LTRGHNQfA3lpFaY9evVlyM IPZeh6J6blyKz7lwaonGbynldPAEd35YLIPeTp5rmbwViE6tISDZyuStoLI9sXsqk41kW1Vx7cL9 m0ISZqNdGMIklwVyPcSDzabSSo2WIjmEsT/yoTws5Ie1C8b+jd5QRlnro4RasH1eTJLRTJ7dMYhz cAwG3T3Xzj5mLugd7socyqwnm+2o2/35HYuyC/F7t9cACTxbbWHHStAdnEDYIbNIehkSkYSmGj06 mU3qbkgYOtRfRod5Ve0XjHtYD0BDty/k0JSLvB4X+9JDBbFEiiocNT4mZG1NMYjCtVj80vCxqEOl 7X3fd3bkOKKvipN9vSLdto8LptbI6xlpvVtDd918QuBSJnJJbQEAeIeMut4e6D2I1HqJPQCksY9E KnJIXA8IZD7uVz1zTkFNxjHdJnaTcfTSXXSVA1vKxeBA8pJ6FvjbG6FhHf5I3Tt4S7S4NMRgl2ZG qB9JYzM8RqBVSPcADCUDAEFVJDcMyfpcFw8vcdulB/troLlI6LTw9+T7oiPGPvalqT6/on0HzITl FktoDfaa1tji5HurrJktKT/4kXV8hH6Mjm1P4CP1ZXTstThZSJ/hs+03fLEkkWg/NHAJnY3Yg0Wq jQpa4nMl+aeoqLTvStIv1SG4tN7BSjGbw3Mib/u2gq9IVZHFuvAzucTNRQAcVlqTcMmMfBb2gITO +Uoh599tX32vQTRorsYSks7aSKIC/PwszPRIk4tGeypArm5UgZnvkly5FpBcnXW3J4OU7DyxAhGm NaPwROT+6exM47EpNa0hSPt6PqvR7AZKrgBIzhu5u4NW6akZiIiuo9b9Ek1df9BPaUiE+6ah0cN9 qIMj6Z1qwIBnWiP+zFtdfiErgBdh4CNvriWH/i81uqXEvSTCl2yAgXs/ULy1UoKvuqDHKe8ippBR aKCVkbfX57+Uq5o+iK134Me2WtEbyqiQLL0O481kOVvd5MZqG7L6AX/1siaLZzHChubHSaMGiEpQ h+FadyANckdBO4SRqe3YBySnzoaFoAPgO9WfGZoDOxjCchjevt5tEf4EI2jTU/1z59juPTeHZyqX xdJwEpo+P1pFMRhPQtnLUvat6XKFg8P5x7MO3Re8IgShQR1PpOxwPWZWmUDQCAhD3mmnhfpuMmVx efhZ5GBlGqFBafcgUuSXDmlaXoHJmm/dK9LeA3ucw9Lga5G/ZPthN7j8IQNJUoRHT5lhQ8ziIcN2 dGxzKknhA3ay+AgHZNT5+F/e/WuNmPnx/zj9f5/+4hdpkM8A2nN9rxE35dIsIYedjsh3kI6Es0GM x3JqDrrV2fDZOYCanvWega/Fce+8X5RdPAkWC4oAX29WF4v6xjA1wuh9jF6EjNvbl5hxs1F366vN ZIZpl3qoZPNbrQhjArCxxk47b26PXfbQEcjRLecXKshEI97069lFMZ2szXlSFxBlQFnQJ5sPJJTC ndT0sMvRzjer5Yf6fo1op0aSg2QaIOVu6wtA3qsXa250CSqHiWCeQCgKWx+hrn+Edu5uFpD/hNTQ Ftap8+r1m+/fnr55+/KbV38EbbQguVl9IQ7xNYmfexV7ENkb+V6pTInWSVeBHHh5zFJB2+aevk09 iMDrHEaeRa+LHASTwjNwRdPz+KAVjMNgwTPZ0n1fZ4QRC+zXNlWRByQZKQ8tMlYqOkyF9srrPXFh 6+XTOQWZkfTmOTo5P2Dfcz3zWc6x2cfz9KbaHykb7sTEHNILb3ZrxE/5Y/dDFIfPeknHuwbr461M JwFZFlF1UrPvH+TRO2eSszPomMX48R3n+3Z/TmYzJHbD7f/U866IvSG+/VPiaiihClR+rCaI3x3p tRqFy8wnX9r+rzexnCphBQkLt/eaC2bMUBgegrmLs31ruHfk7k1LHNFo/a4JVEJQKBG/TIAF4ULn YQsY/ltIoAXzKSYcDQSuRpTZcQlTaxvRH07kkawLV+jU2xlQT2uihmkwRbJOzf76yx4QIzPw29Ta j11BzH3WAlqqkv6lb7xqdbmgNqiaA3x+eTOHOLmrtFlIOycZLs67OygUm7N5esB5uym4AZBNAiOS qzHZeDqHsB1zGbs0pRa4NWGPx/biaT2wX57naUz1B/XEHMbM3qeT5Wo5N9x0TAc0knp2rHGjXNO5 WMKev3mFVH6xWm0bI0mj0EbP3GlfLz9ZWkGDajBm0jKxa41ySwbPYS4dhpIQs8jnu3fZ5Plw7/V7 EQvVWjsjOzbmvrqBzqZQZUT6oSmREXXf/P3pyx9Ox2++ffefXn33QzeFf9EqCdlmEVgAnTTGmGFh vQJJL0plEFIH3RQ+XI0lDXtjE+5tcTDmjTHVFZLKKyyXp1vCjzL7y7DkSQHStsalhTkhQ0TUkNhH Tk56CTjVHBGCWS6iw8NljCyakxWzTQMg2KagpYMwNT4nAoZil8oLM2QYEZ9YVuvtSd/88ww6/k+G aZFvM+IXn0SonICEZl5Aa8vRunuQQA2Vp/oWgFDIVwoB0J5wi0ZFbvnFjAz9gn+gG08vsfsQ2Da7 +yIFF5gWg1qbXrFaLu4NOcLcz4rtfLEoTgbHg+OLk34Rp9fs3kIcOAkfqB+jss/wXmq6E5hH/YUN R4gL7P84EDCk1Ca2E0xlg/pSK8EFGULbw8+GOQ+hmLqeVAaybIhtY4qmTd1Oywtl2gHtVfNUusre 8+IGD2NpwcOUPMIXFNVzkkZA262jp9r4BbXqY1496D6SZ6oAtzXicfAwuPJUqr6L1WQze7U0VLYx HDyxEYJ3gqx+PnawKTKmzNxnwUU0jgniYEuQilJ3Xb9tq3oMSKbue+LV4CX20YfJzNeolBJy0emK PdHKaeJUIJPYL+oBZN2u9t6G7PbFLRKtQXZ3wnZTvkm5m17mpjSb24D5tmsnOhisJ1MIOP3TTxWo y5QmB5IBz6epG5456Y1IbdfPlGrFnEuDnR1yKaYcOt04ma+5JSO+P1+PB2NBn6Sff6oe1pQNiEs2 xf33m/pJK4NoQizyG03JsO1eaQpks30r2uaUU5lAedrlwoSx4ZSk6XOYPLKVq5K3M+D+N4PXSJGn 5nNCzLZTrCDyWHgakGe26ETM00PeHDzg1RvM3QDrOvYViv7iR9NzozM0pEgbNyvnl9uvSpMovwYy dGFsmlpsQ2RAwR7GXkvXEo0ytp+M1Cr5A/dFomRRU4+b3c3NxOaEk5/Jn8ZP84oxbsHzwXh766V5 DJ/zfqMNOkCDGf0Ua12Bt7ojDTntMJvWvAvPmd3im2qIs5XKzCU+KSo/F5IEH7gxE3FFOEHzKAAQ BpmDpBmcWrcIryF3NOZ54Ff7mv8Ix+Foirr0exwG0XPEbVI/mmOcgRYrCCJuhTEJIn1Huga/ozos ONNVP2h5HDTvNFv7+xXHII8yoCx7HGbsCMz8zS/vx7Uc/hZ5bwrCiE6IeDcFixr6kuMzdkHblJIS D6OkjCh3vbol4P8AhGFT2/goPSaw7Zmb/gLxektuZsR/Y72rC1KcLO/LTeQGqq3M4LMhFWnvkoRw a6MFOQLLOqO/fPv2+7dfmZ0F4ViP04jW6u3Lxa65LgOPQEWd8JFYFsv7KUw8iWlJwuJZE5GngGtz pXUQN0nLTTJm1HrDWowPPvtlAGnc5efm6fzCbOdMLGh0UU9k9FACh6/DBTZCc5eDKYxYzihgUbYG mf0z+nBexRIMNTKiPxAGuwHHWYgbJcLWnIs6ntOwUT9VwrcBJMoW1DCxpcPvCmhX2yTjFEyexfKL wgZSelYodynj+aQv6k4mZzA9oFPYFepE5MHVj3mI47GusrNPx3TQlWdOvlZmfjHOVNUPepKjk7Z7 lljn/BEkiZwVTHrGnS48b/ezNZ/9ZnieUp6pqen6WTjpLoQEQaKm/Nsbj2erKdgtD9bUPeTyqGeT bBqJeUzf8h4hN8cwitVmfoWGfHtU9JFs4Rn4gs4xoxWx8iLMHt5ONmJlt7vXpR/mLVZMJI3IdlXc QLH1ohaXAonJaJ7yph+05h4WWSS1r5NGeyf4oOaXvwbSBefoGnG1ocEdak9Z71Xj5qn6th88HVja DoNjH88Ys9KMxnyGDlJg1ILxR6QDhu7sTzKMKkZjt+tgTj2ZpxHhspfUal8PWh12whGDrpLblm42 ULtQosKRVySADnQcWeG40A9R9jgnbdCT0gLbxv7wLcrMcP2ct3mTvCWGKzpsSzWxUY6V2h6Wfd+L QKUOebYlnotM5j47dUpTcUmZ9VT6MdRslNHLWSmBaj3jSs5lZYKfU4JC2lwlGk/uFOjFx2Pc7ygV 5PJRprsREjbvzA4lWuexAvPgkdoAIkoPOG+EsVAhxML3CzB1qToIAGI5VfoF+Io8nobQI1AsPvob S/rpWulMn9xOCb9InHhB9KYfVbHUQc2lzFtjGfKZtDBUD83MYDjEeecAYU4Z0XS62MXkvjXW0WbU TBifD8zYCgz4gYla+fqsS4UP1wBNq0IpD8ztSi9bs7qUktFpRVdgpNezQWWHuf4Kz0kkUjaVJtxk 96Z/baqsBi0UiKLOBYtk84Ci+JJhd5FFyBSmeABMGwN52+2MF483fU5JlnUKNecatasz/sb82D9Z rcWF3+ypx2ZH0rkf1XE9Zc86OAzrjZdBWosN6nOV1Vbpl6+ncTlZzqSPK8vppSjLimV9i8Pvppyz ANURattnm5vNVcgi1PiYCb8lLRzRhKbhyklwbq5aOcEGeEViItOBQ6YsBzzjZ7+IzqL955KsrCDk hlOI+CNt9r30NsTaBeojRtF3IqQ/LuA9A09DEJjCb4ACE4q0lPAaDjuS7G6mKWWbDt/mW/GfYwzu im1dhP4FBhWGyfuOu+iYi3d3SO4EVmfDh66gpOQoFlWJXIdJWkA04xCK9WqxugC/5iivOacjidU3 IryaCxuk7wKHgI4cYWGGdJfJxTvWrSoxBbpMvgmdNCawODf6eawJYNYXjeu7+dZeLh4C7ixwD42p OnHzz19UY+0bat2GonUr6wFngNamfq+fX3aiobYsv1aVuGqEi7kBlKFRFO+k8AS1aWR1KXZQnsLN P60o1RpcQD/+n+/+ra8B2ECOq9X04/91+r/9x1/8AsowLn/xtv7h1EzDcju542TIKG6Cz8MWXB8A xQIw7Anl11x6B2ZHPIUsHAjP1gw6UJuLI/DjDcCx38vo6OwBniXgarPaITAR/ghSJv5SdqF7AGmC 3TQjwIzVFFFASWupNkGOwbcGrpHe0VsISDg62m0WWL7nadsmKGWPus12tanHW7NAXci83WxHXXmh a1Nx0x3dex8iALAoAqFUMmuGVj80LqgK+76t7Yxl+wq9ZKAUSHGiO9dFqWpi5Cnzgzn7lN0TjH6j rjmko74L6ooaw6/de9R5QWpBew9mXeSIbxyJ1JSf3yNTelpf1cuDZ1ZeOGBmsShEU9ScfnJ1WVxv bxZuIjVtcWw8utQwJKuhJ0Mv7pqFqFewEma4ZReoGIgLSFrfBNab1T8S1A54TtKX0gdrRSA2KrXP IRCW/5uwSyP605daRvy3smA4XrtUMarU8T1kAjAWgERoSraLhWhxwCI3lMSRXmPUH/ndT/Eyv7Qv DHDRQzn9jZ0WVQHt97Ia8NPUDLyxQ8HVcKg1MjEW4BoXcAA/5oNcLhs9kXYGtQi3M9ytlOpJZVQN bDVUwcivZySd86O/7ZD5k/a6ooQmmfB9bx6gKz8gj4Vkg8TV6HvXts9yEJODbj2wEHxruMsLWJ96 83pi/jHrCd+Q6fjVBS9+TeFHED6OdyEGEEu/cE6EOKuNhG4el6h5W496Py7FL2RRT8yRAN4ocAwe Ub5pCc+UzPWN4CO0QIEK0on5VeJ/I7hw33ZjW0VAErCMFUf2s80rFkCXqN5Cdwv0O8Pvv9NPg/hk b5D0oZOrMobxsEOf9+3oXTrqMAp870RQqOwc9Ey9XosnkyoHH8/08M47nk5vTTxBYsfdzlT0Gu7P V5BbJrs/WQY/YHe6JqI9ar1hP3t/kucDinwtGCvCBMge0iVBiESLroepaD1c47S7zZbYpaAqNp+W t9NSVa+zfLniLjuZPnqS2G4g+Gzni6abiaeDsOwPm9XCAxYGN215cYD/ip/2D/fmpZvXddPoBC/p 8IQxnf/QDZopPe8gqI3hQKa4cYTUDJKghUs1YNzs4Dz9fN9GfzTDwIp0i2GZZsPZqSgkqBdIAwRa wvNNRn+AecnNfsFdBy0IgZDAbNQSTjorLAh2FIXnFiggoUeUb3f+qU4sZm+ynvf6lsxWi0+1fVgd WAW56OdredR55GYLvO8vzZliGN31fHnXK7rbFYAN1V2+FFw2rnhrs6Zovs0MjZLw34A0JpRq22g8 PGru1dg+5pz25q6GFwS4e9C9AJ1itsiJgMUtV/2Meo+LjVeXlw1gM1+Yu5ARoDGnI1zSav5j7qCA XBXGC8mx766WUR8H3IRhVictpbjjYDDp3UzuZobEr3tDMECaiwxc/c0XNy2Dy8Xkqt+OndW7ns/M GR6/91MnWsvGLaab3B730qxo1N8cR1rfX+FKlKndYB+Gu6HYGupbcogJFzqCW/9TyKcHFt6nhjqO 3Gyt738WMWWCW7jlAdyQJ1vTsGWdfzDM7hv59WCjOV1SqNI/J9H+OSk4TcXEDcOeayL9qUUOeVSc XtdWxXUZzRtKpS+/ef7u21PQd+u5LZcrlEXqJpFR51HxfDYjz4ijr1y95jCdb+j+CheiezA/zCEl 0f1qZ3MT7QJPg//8/O2r59+d/gBjibXfRY9WoDG7J9e/V999++q7lz+c/v23L3+QFeNe+wv3Uyem NXu4MIEBTmDTydOkBWeYX10vzH/bFvJd1HeKdOGsxl/GF/djIj24CnwLP3X+uyTXpGWYpPa7msNd /CGXtvcAtZxA5sB97CwV6eofAZgitUFKniOgKk4iebdFsEMwItaTGWgsJkvnutLaXbscZZWgRGCN UNdkczHfbiaGvGn+yU1cAy3OG8IeTeVj4J0yksXDg132wBn/OPhQ3xvObeboHK5JvEVj/S5CoIKu VoixhPsh3Sh4fdHz4w4UvrbxKst3kPgHm8lt2euxr/BMXhz1QNDsCejdQcwJ3PDLs9KMph+efYSs Z57AlUzGf65kk0TFlngglOmkDwmdTqq2F1In/p6jluQ1sI7DDERV+jcJT67yrl+0j1B2D7VCRqi8 qiEoZaHzKIl47j/tRNAL5qKLYmlkwkXKh6fr+172ZIE4TVBt+l34Aqt8CpqGuwGt8uFAONCuNh1D SELPUF0aUBQaQv0sINB0DfetSXuHYaRwPMAmXt8b2ptC9steBVZfnMyYaglidsyGQCiUMlerUuQJ 1yt7AKGa8oOLa1XfzoY4VFvHeYJHMIzO+sMV4vIndiyuuO4TxyqbObNmoXx3TDHa3f7tTUU9oK9I ah6QFtNDxrzK1zuzKKzWzOM5ZVm+3wUvxAarzmM9HehAHBu0nwveD1ls9h56PcZAoiQhsm2LoSHJ 4fvHzfshOPIiNfLWLnr762ScY1wfCsIhctUL16+yLJcLpzfk44Z2I1SaqY7i+4Qx8GVz2Dlsnz7F fcpv5Xdl7xBxws3I4ZvYscDeU6Zr6iVtiae0JSLXvQwlm00He46cpSjPSMyzLhpukUtTq9yRKsfj koVFSZ9jdW0kR1POVNdreR06+7hxK4KR04rKpDMJ/8YFGVuWM15vM50gTBB9L9Lb3BKgWRJ1HBwC cKjeTLy0j9xpQp7yDuIHeUIH9UZSAVACsnlXq4CUAo1BukiPBn1EO0QchmFdMqMUHNZ2FiqGhaq8 fGoJoppf2obb3U9tqbBSeRDVu7DGNZghsK31Wqu1H8EygO8u69vSvD/qpYSAoPdM/ZiO4oRcJO2j G8qkBYh03g/Z7GMK6sWaFzHJ7RpEghleRkDCd9ZOynLLlkmd6NA7j+19mq4MyxowB+BFiCSaibZd 22X2qNo/S6ktpp69+mwnrnI0OwjekMWVYD9r7RVt1ioonoga45YZvqIe8xtyNxjJHcEjfldxlkBd y66000ORgdL7LYhNIlcylGcGxVdffaVYYHs8rZrewXpn1nHS1L7fFFARyTIp/0ixATmzmoSHKcOa 87PfCEa7NglFURa2RdgEXNIes/ZpgvrjvHtdAUHsMjzoYYAn+UG7SBCCXT/ExzMr46n+gufVuAzw iFvlBOkCAqtL2+fmFF3drMEIbc5Rjk+mRCufrR1o9zgKJob8i3DlrKsRep/bKe3mRVE97V3z/ycU eJE3iKbZVB5sNYfpkCpv4/Z8unE+tyOFV73wMDfEjxdvJlw8yEkAmuet25jMWAaMh8Lx3/XmYtXA caD5SQrHP7LvoDfV4wb8vgRxHpxiVpd7k1N4DFf1Vdv8Eow0UnyD6eXjbr6tjZDRbO8HhjFdgFvO trhdbT40hTnp7owMhtlGCSFJBwIJD2bWRDn7fLzlGvyrgMvoyen9yJnU4mxrpiQHHaSSBuoqN4fI Z94LuhfkLWAOiMVEQMPrdR/brxK59yzIuu8DEZ6bL+jvaqMOz3aPDQctZ051kJRJbisrD59OP4my bDhtCq2DWl7xYQLToUSNcaY3I+QXYFNcsJOdM07YJFppYTBy84pRzJerlN+BpRHO9ZrwMthz5oSn DJyjSfTTXNn3vYw0NjOCNkRF9N4Pew+AhbavJd5a2MHgSYtFPc2d5yaCGW5+OSqepRtKnn98al0C 5tfCcPvktKlgTnPLHT6GbKQlviV682SPsIQ3f9fb7XpIl6n0wyY3uRIqliWlbpU/CO7n9WJW4K6D 7Vd63hl4tWk9fylJPI+X2KVQqOTGY4UlbJCR9KhKo5nHA7+tL8z1ZJgbenbdWqDGQauH7ZDO7VGv ys3qHCgmp9HD5nFgS6nxbDg//4yzOKgl1xsuJlSI0kWJDk/yxN3K+ar1X2HdveXGu6URynjNmc27 Rn+OCxL59tu2Ilck20rSC8k6kfqGbnapj0NubTtwDZHPe69e+vpm3yqf2KaqrGMTZaiEBKaBIsFm NNYSiq3w7Nk5ZGIXz0FBcHHPwT6GLoCyE9N79/TV65ffvzsdv3v77fdvXn7H7a8W6hbVrMw5jb5C bAnm/c780S/VRKXCFuLYhOjCkLjYmDIU+AV+zd0+baAqfAs6Ysa7mF88G4hbd1DyEmLRF3GDrWMw 8+FFKpRBW2ZseKPoh534w+npG3xSHRrSML+02m+I8GdLEtIGej3/6vikX/zq+MtqaMSSyW57vdrM /4m8qyUqDk1uF+g00gKKS+KyOsQo3L86JHU2Cd5RkAEFODzGGAc8IjnTZov8rYhyILdxoc4vzEhr ThhQeBwmyY8YmEIcxozo3Vxjcr0LgAEAnVCn7VhInkr/OPk0oVQAw0RCuUfmvgOJ6SmU4X//gTys cmfKZDk1i2WPkPkX2l4j4od/vPgrYCtg51F8AWdO8mErWp83qAobFXBciFLPKVbxXS4D54sp5dR3 oPurKPFNJ7MfYToZZN/sRtsoKT9NZeKBjpqzrbTE+mP1PAHTo5SVNB5dGZgGsKqpLK35ZVO3UmmW PPfkLWynzcoOmdZFHUtkEBlBggoKtV7ylc5saMinsTzRGFNSmj4Iwou9UvWOIASm6EHo2aS+rm86 MUHQh/gVd0uHFBiQ2qeL0jvYDeC4oPf8Ul9KKTNFiTJTQy1zUKmiFZ0e9rl+/vulNqpHlOMqkFwr 7pcqnciJZyaraTvwxgNVubYennfcpyue/Ii8mkePm3YKY7qSucvTV0eDO1KomzmNMAjZ7L5Vj0TD VTOYQ5l7VWZAJezdkDjoVQkgmjpQxiwJ/tZxo80UNVyV0YpWy0+QrQ48odF5uKTl6fMyjVlS2d4v 6ua6rrecr8LM0QoS6Y3sFnCRccxPcWPT0yMsXs9s0BjlzLVpeefLtRlluIkMnwfH9KNAB0VP8YJ/ C9wClPgLiJ1E1/7ldLGbGXIuzRogXMS92px2FKQfKM2bhufswG8Gdz6XFdwY34kR8vjYFLa7iwUk FFRdc9Aatr2ea7BXDFXz/VQRnOrekAwFroBNpwVVnKgH9c1FPRurJobFsXpMXuBjWSh4Wz67Uo96 15MFdu64D/51IMGo2DF8Ol7Un+oFlHlGT37io9l6y5kJbIBwIf3wrWGMxfCI9omiIXByaug0YLtr ibn0XAlmF5CaHrL9jHSNsZj5yDydXkP+eanWfCZg4KhKdcj7C5cmdgw+3aB1nf2c9vnQcTh+M16Z zbSZG/obaaSZSEq1fefBSugce+ObE5t60rbLuDCmW77bopFM6BY2fFf5x9NtgmulLokfAP3GZ7KS F6zc4wA4bK+80AqNhUkFQO7havHct8o3ZW6UAkkj4yNTMRBirjL1FpeU3Lu4GdQrIknRLhtMm8aN jH8KJRfFI0ZcRrh5QojzStv8eM4iJjKDdEgEB1lY6o3ZSGQmC1ix9eS0U6/4sOImjk78eq0NFq9O vduLXsWR1aZFnmukldsNiP4I9VD4JuVHIEh7RIKrPjpBDT/k9qpnoxMrrcPUQiSHWwK6E7nHam0H s93NukSASTwc4cCT1GJYy1dF+WW/ONaqBTOhZWNkR6uD9o86eR5ue1kHuLpv6rsThC+11qZNb/Dk dxer2f1X5eBJ9bun+HHwpAcSzeD1u29PX4FPcfHP8PXr70+ff/ttBbU8S9Qym38qUF0y6spZ1+Va zaN9lXY4xeh8jQQwvjbkAoAjyKw0O9htL3+bOHLhRBXiW13iVxjL0XZyZZmDmQpFmGHVLj7QDJDS pd+d9GGwQ1+wxLHfmdv1ZDO9Lk11EfYI5fjr5GUy6gkWG1CE+YkXkm+e28xr5BAJdwY8rdFJzcW9 UghyTgHlBIYom68TJUaqmAPFYIacjA6TEyUKoeKY4TAWq7USj60xL/z4f+8G/z/kU6aF """ import sys import base64 import zlib import imp class DictImporter(object): def __init__(self, sources): self.sources = sources def find_module(self, fullname, path=None): if fullname in self.sources: return self if fullname+'.__init__' in self.sources: return self return None def load_module(self, fullname): # print "load_module:", fullname from types import ModuleType try: s = self.sources[fullname] is_pkg = False except KeyError: s = self.sources[fullname+'.__init__'] is_pkg = True co = compile(s, fullname, 'exec') module = sys.modules.setdefault(fullname, ModuleType(fullname)) module.__file__ = "%s/%s" % (__file__, fullname) module.__loader__ = self if is_pkg: module.__path__ = [fullname] do_exec(co, module.__dict__) return sys.modules[fullname] def get_source(self, name): res = self.sources.get(name) if res is None: res = self.sources.get(name+'.__init__') return res if __name__ == "__main__": if sys.version_info >= (3,0): exec("def do_exec(co, loc): exec(co, loc)\n") import pickle sources = sources.encode("ascii") # ensure bytes sources = pickle.loads(zlib.decompress(base64.decodebytes(sources))) else: import cPickle as pickle exec("def do_exec(co, loc): exec co in loc\n") sources = pickle.loads(zlib.decompress(base64.decodestring(sources))) importer = DictImporter(sources) sys.meta_path.append(importer) entry = "import py; raise SystemExit(py.test.cmdline.main())" do_exec(entry, locals()) execnet-1.0.9/testing/test_xspec.py0000644000000000000000000001501011473521746016071 0ustar rootrootimport pytest, py import execnet XSpec = execnet.XSpec class TestXSpec: def test_norm_attributes(self): spec = XSpec("socket=192.168.102.2:8888//python=c:/this/python2.5//chdir=d:\hello") assert spec.socket == "192.168.102.2:8888" assert spec.python == "c:/this/python2.5" assert spec.chdir == "d:\hello" assert spec.nice is None assert not hasattr(spec, '_xyz') py.test.raises(AttributeError, "spec._hello") spec = XSpec("socket=192.168.102.2:8888//python=python2.5//nice=3") assert spec.socket == "192.168.102.2:8888" assert spec.python == "python2.5" assert spec.chdir is None assert spec.nice == "3" spec = XSpec("ssh=user@host//chdir=/hello/this//python=/usr/bin/python2.5") assert spec.ssh == "user@host" assert spec.python == "/usr/bin/python2.5" assert spec.chdir == "/hello/this" spec = XSpec("popen") assert spec.popen == True def test_env(self): xspec = XSpec("popen//env:NAME=value1") assert xspec.env['NAME'] == "value1" def test__samefilesystem(self): assert XSpec("popen")._samefilesystem() assert XSpec("popen//python=123")._samefilesystem() assert not XSpec("popen//chdir=hello")._samefilesystem() def test__spec_spec(self): for x in ("popen", "popen//python=this"): assert XSpec(x)._spec == x def test_samekeyword_twice_raises(self): py.test.raises(ValueError, "XSpec('popen//popen')") py.test.raises(ValueError, "XSpec('popen//popen=123')") def test_unknown_keys_allowed(self): xspec = XSpec("hello=3") assert xspec.hello == '3' def test_repr_and_string(self): for x in ("popen", "popen//python=this"): assert repr(XSpec(x)).find("popen") != -1 assert str(XSpec(x)) == x def test_hash_equality(self): assert XSpec("popen") == XSpec("popen") assert hash(XSpec("popen")) == hash(XSpec("popen")) assert XSpec("popen//python=123") != XSpec("popen") assert hash(XSpec("socket=hello:8080")) != hash(XSpec("popen")) class TestMakegateway: def test_no_type(self): py.test.raises(ValueError, "execnet.makegateway('hello')") def test_popen_default(self): gw = execnet.makegateway("") assert gw.spec.popen assert gw.spec.python == None rinfo = gw._rinfo() #assert rinfo.executable == py.std.sys.executable assert rinfo.cwd == py.std.os.getcwd() assert rinfo.version_info == py.std.sys.version_info @pytest.mark.skipif("not hasattr(os, 'nice')") def test_popen_nice(self): gw = execnet.makegateway("popen") def getnice(channel): import os if hasattr(os, 'nice'): channel.send(os.nice(0)) else: channel.send(None) remotenice = gw.remote_exec(getnice).receive() gw.exit() if remotenice is not None: gw = execnet.makegateway("popen//nice=5") remotenice2 = gw.remote_exec(getnice).receive() assert remotenice2 == remotenice + 5 def test_popen_env(self): gw = execnet.makegateway("popen//env:NAME123=123") ch = gw.remote_exec(""" import os channel.send(os.environ['NAME123']) """) value = ch.receive() assert value == "123" def test_popen_explicit(self): gw = execnet.makegateway("popen//python=%s" % py.std.sys.executable) assert gw.spec.python == py.std.sys.executable rinfo = gw._rinfo() assert rinfo.executable == py.std.sys.executable assert rinfo.cwd == py.std.os.getcwd() assert rinfo.version_info == py.std.sys.version_info def test_popen_cpython25(self): for trypath in ('python2.5', r'C:\Python25\python.exe'): cpython25 = py.path.local.sysfind(trypath) if cpython25 is not None: cpython25 = cpython25.realpath() break else: py.test.skip("cpython2.5 not found") gw = execnet.makegateway("popen//python=%s" % cpython25) rinfo = gw._rinfo() if py.std.sys.platform != "darwin": # it's confusing there assert rinfo.executable == cpython25 assert rinfo.cwd == py.std.os.getcwd() assert rinfo.version_info[:2] == (2,5) def test_popen_cpython26(self): for trypath in ('python2.6', r'C:\Python26\python.exe'): cpython26 = py.path.local.sysfind(trypath) if cpython26 is not None: break else: py.test.skip("cpython2.6 not found") gw = execnet.makegateway("popen//python=%s" % cpython26) rinfo = gw._rinfo() #assert rinfo.executable == cpython26 assert rinfo.cwd == py.std.os.getcwd() assert rinfo.version_info[:2] == (2,6) def test_popen_chdir_absolute(self, testdir): gw = execnet.makegateway("popen//chdir=%s" % testdir.tmpdir) rinfo = gw._rinfo() assert rinfo.cwd == str(testdir.tmpdir.realpath()) def test_popen_chdir_newsub(self, testdir): testdir.chdir() gw = execnet.makegateway("popen//chdir=hello") rinfo = gw._rinfo() assert rinfo.cwd.lower() == str(testdir.tmpdir.join("hello").realpath()).lower() def test_ssh(self, specssh): sshhost = specssh.ssh gw = execnet.makegateway("ssh=%s//id=ssh1" % sshhost) rinfo = gw._rinfo() assert gw.id == 'ssh1' gw2 = execnet.SshGateway(sshhost) rinfo2 = gw2._rinfo() assert rinfo.executable == rinfo2.executable assert rinfo.cwd == rinfo2.cwd assert rinfo.version_info == rinfo2.version_info def test_socket(self, specsocket): gw = execnet.makegateway("socket=%s//id=sock1" % specsocket.socket) rinfo = gw._rinfo() assert rinfo.executable assert rinfo.cwd assert rinfo.version_info assert gw.id == "sock1" # we cannot instantiate a second gateway #gw2 = execnet.SocketGateway(*specsocket.socket.split(":")) #rinfo2 = gw2._rinfo() #assert rinfo.executable == rinfo2.executable #assert rinfo.cwd == rinfo2.cwd #assert rinfo.version_info == rinfo2.version_info def test_socket_installvia(self): group = execnet.Group() group.makegateway("popen//id=p1") gw = group.makegateway("socket//installvia=p1//id=s1") assert gw.id == "s1" assert gw.remote_status() group.terminate() execnet-1.0.9/execnet/0000755000000000000000000000000011760165371013314 5ustar rootrootexecnet-1.0.9/execnet/script/0000755000000000000000000000000011760165371014620 5ustar rootrootexecnet-1.0.9/execnet/script/shell.py0000755000000000000000000000477511473521746016324 0ustar rootroot#! /usr/bin/env python """ a remote python shell for injection into startserver.py """ import sys, os, socket, select try: clientsock except NameError: print("client side starting") import sys host, port = sys.argv[1].split(':') port = int(port) myself = open(os.path.abspath(sys.argv[0]), 'rU').read() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port)) sock.sendall(repr(myself)+'\n') print("send boot string") inputlist = [ sock, sys.stdin ] try: while 1: r,w,e = select.select(inputlist, [], []) if sys.stdin in r: line = raw_input() sock.sendall(line + '\n') if sock in r: line = sock.recv(4096) sys.stdout.write(line) sys.stdout.flush() except: import traceback print(traceback.print_exc()) sys.exit(1) print("server side starting") # server side # from traceback import print_exc from threading import Thread class promptagent(Thread): def __init__(self, clientsock): Thread.__init__(self) self.clientsock = clientsock def run(self): print("Entering thread prompt loop") clientfile = self.clientsock.makefile('w') filein = self.clientsock.makefile('r') loc = self.clientsock.getsockname() while 1: try: clientfile.write('%s %s >>> ' % loc) clientfile.flush() line = filein.readline() if len(line)==0: raise EOFError("nothing") #print >>sys.stderr,"got line: " + line if line.strip(): oldout, olderr = sys.stdout, sys.stderr sys.stdout, sys.stderr = clientfile, clientfile try: try: exec(compile(line + '\n','', 'single')) except: print_exc() finally: sys.stdout=oldout sys.stderr=olderr clientfile.flush() except EOFError: e = sys.exc_info()[1] sys.stderr.write("connection close, prompt thread returns") break #print >>sys.stdout, "".join(apply(format_exception,sys.exc_info())) self.clientsock.close() prompter = promptagent(clientsock) prompter.start() print("promptagent - thread started") execnet-1.0.9/execnet/script/xx.py0000644000000000000000000000024411473521746015634 0ustar rootrootimport rlcompleter2 rlcompleter2.setup() import register, sys try: hostport = sys.argv[1] except: hostport = ':8888' gw = register.ServerGateway(hostport) execnet-1.0.9/execnet/script/__init__.py0000644000000000000000000000000211473521746016724 0ustar rootroot# execnet-1.0.9/execnet/script/quitserver.py0000644000000000000000000000044111473521746017405 0ustar rootroot""" send a "quit" signal to a remote server """ import sys import socket hostport = sys.argv[1] host, port = hostport.split(':') hostport = (host, int(port)) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(hostport) sock.sendall('"raise KeyboardInterrupt"\n') execnet-1.0.9/execnet/script/loop_socketserver.py0000644000000000000000000000063511473521746020751 0ustar rootroot import os, sys import subprocess if __name__ == '__main__': directory = os.path.dirname(os.path.abspath(sys.argv[0])) script = os.path.join(directory, 'socketserver.py') while 1: cmdlist = ["python", script] cmdlist.extend(sys.argv[1:]) text = "starting subcommand: " + " ".join(cmdlist) print(text) process = subprocess.Popen(cmdlist) process.wait() execnet-1.0.9/execnet/script/socketserverservice.py0000644000000000000000000000646511473521746021310 0ustar rootroot""" A windows service wrapper for the py.execnet socketserver. To use, run: python socketserverservice.py register net start ExecNetSocketServer """ import sys import os import time import win32serviceutil import win32service import win32event import win32evtlogutil import servicemanager import threading import socketserver appname = 'ExecNetSocketServer' class SocketServerService(win32serviceutil.ServiceFramework): _svc_name_ = appname _svc_display_name_ = "%s" % appname _svc_deps_ = ["EventLog"] def __init__(self, args): # The exe-file has messages for the Event Log Viewer. # Register the exe-file as event source. # # Probably it would be better if this is done at installation time, # so that it also could be removed if the service is uninstalled. # Unfortunately it cannot be done in the 'if __name__ == "__main__"' # block below, because the 'frozen' exe-file does not run this code. # win32evtlogutil.AddSourceToRegistry(self._svc_display_name_, servicemanager.__file__, "Application") win32serviceutil.ServiceFramework.__init__(self, args) self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) self.WAIT_TIME = 1000 # in milliseconds def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) win32event.SetEvent(self.hWaitStop) def SvcDoRun(self): # Redirect stdout and stderr to prevent "IOError: [Errno 9] # Bad file descriptor". Windows services don't have functional # output streams. sys.stdout = sys.stderr = open('nul', 'w') # Write a 'started' event to the event log... win32evtlogutil.ReportEvent(self._svc_display_name_, servicemanager.PYS_SERVICE_STARTED, 0, # category servicemanager.EVENTLOG_INFORMATION_TYPE, (self._svc_name_, '')) print("Begin: %s" % (self._svc_display_name_)) hostport = ':8888' print('Starting py.execnet SocketServer on %s' % hostport) serversock = socketserver.bind_and_listen(hostport) thread = threading.Thread(target=socketserver.startserver, args=(serversock,), kwargs={'loop':True}) thread.setDaemon(True) thread.start() # wait to be stopped or self.WAIT_TIME to pass while True: result = win32event.WaitForSingleObject(self.hWaitStop, self.WAIT_TIME) if result == win32event.WAIT_OBJECT_0: break # write a 'stopped' event to the event log. win32evtlogutil.ReportEvent(self._svc_display_name_, servicemanager.PYS_SERVICE_STOPPED, 0, # category servicemanager.EVENTLOG_INFORMATION_TYPE, (self._svc_name_, '')) print("End: %s" % appname) if __name__ == '__main__': # Note that this code will not be run in the 'frozen' exe-file!!! win32serviceutil.HandleCommandLine(SocketServerService) execnet-1.0.9/execnet/script/socketserver.py0000755000000000000000000000572111473521746017724 0ustar rootroot#! /usr/bin/env python """ start socket based minimal readline exec server """ # this part of the program only executes on the server side # progname = 'socket_readline_exec_server-1.2' import sys, socket, os try: import fcntl except ImportError: fcntl = None debug = 0 if debug: # and not os.isatty(sys.stdin.fileno()): f = open('/tmp/execnet-socket-pyout.log', 'w') old = sys.stdout, sys.stderr sys.stdout = sys.stderr = f def print_(*args): print(" ".join(str(arg) for arg in args)) if sys.version_info > (3, 0): exec("""def exec_(source, locs): exec(source, locs)""") else: exec("""def exec_(source, locs): exec source in locs""") def exec_from_one_connection(serversock): print_(progname, 'Entering Accept loop', serversock.getsockname()) clientsock,address = serversock.accept() print_(progname, 'got new connection from %s %s' % address) clientfile = clientsock.makefile('rb') print_("reading line") # rstrip so that we can use \r\n for telnet testing source = clientfile.readline().rstrip() clientfile.close() g = {'clientsock' : clientsock, 'address' : address} source = eval(source) if source: co = compile(source+'\n', source, 'exec') print_(progname, 'compiled source, executing') try: exec_(co, g) finally: print_(progname, 'finished executing code') # background thread might hold a reference to this (!?) #clientsock.close() def bind_and_listen(hostport): if isinstance(hostport, str): host, port = hostport.split(':') hostport = (host, int(port)) serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # set close-on-exec if hasattr(fcntl, 'FD_CLOEXEC'): old = fcntl.fcntl(serversock.fileno(), fcntl.F_GETFD) fcntl.fcntl(serversock.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC) # allow the address to be re-used in a reasonable amount of time if os.name == 'posix' and sys.platform != 'cygwin': serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) serversock.bind(hostport) serversock.listen(5) return serversock def startserver(serversock, loop=False): try: while 1: try: exec_from_one_connection(serversock) except (KeyboardInterrupt, SystemExit): raise except: if debug: import traceback traceback.print_exc() else: excinfo = sys.exc_info() print_("got exception", excinfo[1]) if not loop: break finally: print_("leaving socketserver execloop") serversock.shutdown(2) if __name__ == '__main__': import sys if len(sys.argv)>1: hostport = sys.argv[1] else: hostport = ':8888' serversock = bind_and_listen(hostport) startserver(serversock, loop=False) execnet-1.0.9/execnet/rsync.py0000644000000000000000000001573011473521746015035 0ustar rootroot""" 1:N rsync implemenation on top of execnet. (c) 2006-2009, Armin Rigo, Holger Krekel, Maciej Fijalkowski """ import os, stat try: from hashlib import md5 except ImportError: from md5 import md5 try: from queue import Queue except ImportError: from Queue import Queue import execnet.rsync_remote class RSync(object): """ This class allows to send a directory structure (recursively) to one or multiple remote filesystems. There is limited support for symlinks, which means that symlinks pointing to the sourcetree will be send "as is" while external symlinks will be just copied (regardless of existance of such a path on remote side). """ def __init__(self, sourcedir, callback=None, verbose=True): self._sourcedir = str(sourcedir) self._verbose = verbose assert callback is None or hasattr(callback, '__call__') self._callback = callback self._channels = {} self._receivequeue = Queue() self._links = [] def filter(self, path): return True def _end_of_channel(self, channel): if channel in self._channels: # too early! we must have got an error channel.waitclose() # or else we raise one raise IOError('connection unexpectedly closed: %s ' % ( channel.gateway,)) def _process_link(self, channel): for link in self._links: channel.send(link) # completion marker, this host is done channel.send(42) def _done(self, channel): """ Call all callbacks """ finishedcallback = self._channels.pop(channel) if finishedcallback: finishedcallback() channel.waitclose() def _list_done(self, channel): # sum up all to send if self._callback: s = sum([self._paths[i] for i in self._to_send[channel]]) self._callback("list", s, channel) def _send_item(self, channel, data): """ Send one item """ modified_rel_path, checksum = data modifiedpath = os.path.join(self._sourcedir, *modified_rel_path) try: f = open(modifiedpath, 'rb') data = f.read() except IOError: data = None # provide info to progress callback function modified_rel_path = "/".join(modified_rel_path) if data is not None: self._paths[modified_rel_path] = len(data) else: self._paths[modified_rel_path] = 0 if channel not in self._to_send: self._to_send[channel] = [] self._to_send[channel].append(modified_rel_path) #print "sending", modified_rel_path, data and len(data) or 0, checksum if data is not None: f.close() if checksum is not None and checksum == md5(data).digest(): data = None # not really modified else: self._report_send_file(channel.gateway, modified_rel_path) channel.send(data) def _report_send_file(self, gateway, modified_rel_path): if self._verbose: print("%s <= %s" %(gateway, modified_rel_path)) def send(self, raises=True): """ Sends a sourcedir to all added targets. Flag indicates whether to raise an error or return in case of lack of targets """ if not self._channels: if raises: raise IOError("no targets available, maybe you " "are trying call send() twice?") return # normalize a trailing '/' away self._sourcedir = os.path.dirname(os.path.join(self._sourcedir, 'x')) # send directory structure and file timestamps/sizes self._send_directory_structure(self._sourcedir) # paths and to_send are only used for doing # progress-related callbacks self._paths = {} self._to_send = {} # send modified file to clients while self._channels: channel, req = self._receivequeue.get() if req is None: self._end_of_channel(channel) else: command, data = req if command == "links": self._process_link(channel) elif command == "done": self._done(channel) elif command == "ack": if self._callback: self._callback("ack", self._paths[data], channel) elif command == "list_done": self._list_done(channel) elif command == "send": self._send_item(channel, data) del data else: assert "Unknown command %s" % command def add_target(self, gateway, destdir, finishedcallback=None, **options): """ Adds a remote target specified via a gateway and a remote destination directory. """ for name in options: assert name in ('delete',) def itemcallback(req): self._receivequeue.put((channel, req)) channel = gateway.remote_exec(execnet.rsync_remote) channel.setcallback(itemcallback, endmarker = None) channel.send((str(destdir), options)) self._channels[channel] = finishedcallback def _broadcast(self, msg): for channel in self._channels: channel.send(msg) def _send_link(self, linktype, basename, linkpoint): self._links.append((linktype, basename, linkpoint)) def _send_directory(self, path): # dir: send a list of entries names = [] subpaths = [] for name in os.listdir(path): p = os.path.join(path, name) if self.filter(p): names.append(name) subpaths.append(p) mode = os.lstat(path).st_mode self._broadcast([mode] + names) for p in subpaths: self._send_directory_structure(p) def _send_link_structure(self, path): linkpoint = os.readlink(path) basename = path[len(self._sourcedir) + 1:] if linkpoint.startswith(self._sourcedir): self._send_link("linkbase", basename, linkpoint[len(self._sourcedir) + 1:]) else: # relative or absolute link, just send it self._send_link("link", basename, linkpoint) self._broadcast(None) def _send_directory_structure(self, path): try: st = os.lstat(path) except OSError: self._broadcast((None, 0, 0)) return if stat.S_ISREG(st.st_mode): # regular file: send a mode/timestamp/size pair self._broadcast((st.st_mode, st.st_mtime, st.st_size)) elif stat.S_ISDIR(st.st_mode): self._send_directory(path) elif stat.S_ISLNK(st.st_mode): self._send_link_structure(path) else: raise ValueError("cannot sync %r" % (path,)) execnet-1.0.9/execnet/apipkg.py0000644000000000000000000000663011473521746015151 0ustar rootroot""" apipkg: control the exported namespace of a python package. see http://pypi.python.org/pypi/apipkg (c) holger krekel, 2009 - MIT license """ import sys from types import ModuleType __version__ = "1.0b6" def initpkg(pkgname, exportdefs): """ initialize given package from the export definitions. """ mod = ApiModule(pkgname, exportdefs, implprefix=pkgname) oldmod = sys.modules[pkgname] mod.__file__ = getattr(oldmod, '__file__', None) mod.__version__ = getattr(oldmod, '__version__', '0') for name in ('__path__', '__loader__'): if hasattr(oldmod, name): setattr(mod, name, getattr(oldmod, name)) sys.modules[pkgname] = mod def importobj(modpath, attrname): module = __import__(modpath, None, None, ['__doc__']) return getattr(module, attrname) class ApiModule(ModuleType): def __init__(self, name, importspec, implprefix=None): self.__name__ = name self.__all__ = [x for x in importspec if x != '__onfirstaccess__'] self.__map__ = {} self.__implprefix__ = implprefix or name for name, importspec in importspec.items(): if isinstance(importspec, dict): subname = '%s.%s'%(self.__name__, name) apimod = ApiModule(subname, importspec, implprefix) sys.modules[subname] = apimod setattr(self, name, apimod) else: modpath, attrname = importspec.split(':') if modpath[0] == '.': modpath = implprefix + modpath if name == '__doc__': self.__doc__ = importobj(modpath, attrname) else: self.__map__[name] = (modpath, attrname) def __repr__(self): l = [] if hasattr(self, '__version__'): l.append("version=" + repr(self.__version__)) if hasattr(self, '__file__'): l.append('from ' + repr(self.__file__)) if l: return '' % (self.__name__, " ".join(l)) return '' % (self.__name__,) def __makeattr(self, name): """lazily compute value for name or raise AttributeError if unknown.""" target = None if '__onfirstaccess__' in self.__map__: target = self.__map__.pop('__onfirstaccess__') importobj(*target)() try: modpath, attrname = self.__map__[name] except KeyError: if target is not None and name != '__onfirstaccess__': # retry, onfirstaccess might have set attrs return getattr(self, name) raise AttributeError(name) else: result = importobj(modpath, attrname) setattr(self, name, result) try: del self.__map__[name] except KeyError: pass # in a recursive-import situation a double-del can happen return result __getattr__ = __makeattr def __dict__(self): # force all the content of the module to be loaded when __dict__ is read dictdescr = ModuleType.__dict__['__dict__'] dict = dictdescr.__get__(self) if dict is not None: hasattr(self, 'some') for name in self.__all__: try: self.__makeattr(name) except AttributeError: pass return dict __dict__ = property(__dict__) execnet-1.0.9/execnet/gateway_socket.py0000644000000000000000000000626311473521746016711 0ustar rootrootimport socket from execnet.gateway import Gateway, HostNotFound import os, sys, inspect try: bytes except NameError: bytes = str class SocketIO: error = (socket.error, EOFError) def __init__(self, sock): self.sock = sock try: sock.setsockopt(socket.SOL_IP, socket.IP_TOS, 0x10)# IPTOS_LOWDELAY sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) except (AttributeError, socket.error): sys.stderr.write("WARNING: cannot set socketoption") def read(self, numbytes): "Read exactly 'bytes' bytes from the socket." buf = bytes() while len(buf) < numbytes: t = self.sock.recv(numbytes - len(buf)) if not t: raise EOFError buf += t return buf def write(self, data): self.sock.sendall(data) def close_read(self): try: self.sock.shutdown(0) except socket.error: pass def close_write(self): try: self.sock.shutdown(1) except socket.error: pass class SocketGateway(Gateway): """ This Gateway provides interaction with a remote process by connecting to a specified socket. On the remote side you need to manually start a small script (py/execnet/script/socketserver.py) that accepts SocketGateway connections. """ _remotesetup = "import socket\n%s\nio = SocketIO(clientsock)" % inspect.getsource(SocketIO) def __init__(self, host, port, id): """ instantiate a gateway to a process accessed via a host/port specified socket. """ self.host = host = str(host) self.port = port = int(port) self.remoteaddress = '%s:%d' % (self.host, self.port) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.connect((host, port)) except socket.gaierror: raise HostNotFound(str(sys.exc_info()[1])) io = SocketIO(sock) super(SocketGateway, self).__init__(io=io, id=id) def new_remote(cls, gateway, id, hostport=None): """ return a new (connected) socket gateway, instantiated through the given 'gateway'. """ if hostport is None: host, port = ('localhost', 0) else: host, port = hostport mydir = os.path.dirname(__file__) socketserver = os.path.join(mydir, 'script', 'socketserver.py') socketserverbootstrap = "\n".join([ open(socketserver, 'r').read(), """if 1: import socket sock = bind_and_listen((%r, %r)) port = sock.getsockname() channel.send(port) startserver(sock) """ % (host, port)]) # execute the above socketserverbootstrap on the other side channel = gateway.remote_exec(socketserverbootstrap) (realhost, realport) = channel.receive() #self._trace("new_remote received" # "port=%r, hostname = %r" %(realport, hostname)) if not realhost or realhost=="0.0.0.0": realhost = "localhost" return cls(realhost, realport, id=id) new_remote = classmethod(new_remote) execnet-1.0.9/execnet/threadpool.py0000644000000000000000000001325211473521746016035 0ustar rootroot""" dispatching execution to threads (c) 2009, holger krekel """ import threading import time import sys # py2/py3 compatibility try: import queue except ImportError: import Queue as queue if sys.version_info >= (3,0): exec ("def reraise(cls, val, tb): raise val") else: exec ("def reraise(cls, val, tb): raise cls, val, tb") ERRORMARKER = object() class Reply(object): """ reply instances provide access to the result of a function execution that got dispatched through WorkerPool.dispatch() """ _excinfo = None def __init__(self, task): self.task = task self._queue = queue.Queue() def _set(self, result): self._queue.put(result) def _setexcinfo(self, excinfo): self._excinfo = excinfo self._queue.put(ERRORMARKER) def get(self, timeout=None): """ get the result object from an asynchronous function execution. if the function execution raised an exception, then calling get() will reraise that exception including its traceback. """ if self._queue is None: raise EOFError("reply has already been delivered") try: result = self._queue.get(timeout=timeout) except queue.Empty: raise IOError("timeout waiting for %r" %(self.task, )) if result is ERRORMARKER: self._queue = None excinfo = self._excinfo reraise(excinfo[0], excinfo[1], excinfo[2]) return result class WorkerThread(threading.Thread): def __init__(self, pool): threading.Thread.__init__(self) self._queue = queue.Queue() self._pool = pool self.setDaemon(1) def _run_once(self): reply = self._queue.get() if reply is SystemExit: return False assert self not in self._pool._ready task = reply.task try: func, args, kwargs = task result = func(*args, **kwargs) except (SystemExit, KeyboardInterrupt): return False except: reply._setexcinfo(sys.exc_info()) else: reply._set(result) # at this point, reply, task and all other local variables go away return True def run(self): try: while self._run_once(): self._pool._ready[self] = True finally: del self._pool._alive[self] try: del self._pool._ready[self] except KeyError: pass def send(self, task): reply = Reply(task) self._queue.put(reply) return reply def stop(self): self._queue.put(SystemExit) class WorkerPool(object): """ A WorkerPool allows to dispatch function executions to threads. Each Worker Thread is reused for multiple function executions. The dispatching operation takes care to create and dispatch to existing threads. You need to call shutdown() to signal the WorkerThreads to terminate and join() in order to wait until all worker threads have terminated. """ _shuttingdown = False def __init__(self, maxthreads=None): """ init WorkerPool instance which may create up to `maxthreads` worker threads. """ self.maxthreads = maxthreads self._ready = {} self._alive = {} def dispatch(self, func, *args, **kwargs): """ return Reply object for the asynchronous dispatch of the given func(*args, **kwargs) in a separate worker thread. """ if self._shuttingdown: raise IOError("WorkerPool is already shutting down") try: thread, _ = self._ready.popitem() except KeyError: # pop from empty list if self.maxthreads and len(self._alive) >= self.maxthreads: raise IOError("can't create more than %d threads." % (self.maxthreads,)) thread = self._newthread() return thread.send((func, args, kwargs)) def _newthread(self): thread = WorkerThread(self) self._alive[thread] = True thread.start() return thread def shutdown(self): """ signal all worker threads to terminate. call join() to wait until all threads termination. """ if not self._shuttingdown: self._shuttingdown = True for t in list(self._alive): t.stop() def join(self, timeout=None): """ wait until all worker threads have terminated. """ current = threading.currentThread() deadline = delta = None if timeout is not None: deadline = time.time() + timeout for thread in list(self._alive): if deadline: delta = deadline - time.time() if delta <= 0: raise IOError("timeout while joining threads") thread.join(timeout=delta) if thread.isAlive(): raise IOError("timeout while joining threads") if __name__ == '__channelexec__': maxthreads = channel.receive() execpool = WorkerPool(maxthreads=maxthreads) gw = channel.gateway channel.send("ok") gw._trace("instantiated thread work pool maxthreads=%s" %(maxthreads,)) while 1: gw._trace("waiting for new exec task") task = gw._execqueue.get() if task is None: gw._trace("thread-dispatcher got None, exiting") execpool.shutdown() execpool.join() raise gw._StopExecLoop gw._trace("dispatching exec task to thread pool") execpool.dispatch(gw.executetask, task) execnet-1.0.9/execnet/__init__.py0000644000000000000000000000141511473521746015431 0ustar rootroot""" execnet: pure python lib for connecting to local and remote Python Interpreters. (c) 2010, Holger Krekel and others """ __version__ = '1.0.9' import execnet.apipkg execnet.apipkg.initpkg(__name__, { 'PopenGateway': '.deprecated:PopenGateway', 'SocketGateway': '.deprecated:SocketGateway', 'SshGateway': '.deprecated:SshGateway', 'makegateway': '.multi:makegateway', 'HostNotFound': '.gateway:HostNotFound', 'RemoteError': '.gateway_base:RemoteError', 'TimeoutError': '.gateway_base:TimeoutError', 'XSpec': '.xspec:XSpec', 'Group': '.multi:Group', 'MultiChannel': '.multi:MultiChannel', 'RSync': '.rsync:RSync', 'default_group': '.multi:default_group', }) execnet-1.0.9/execnet/deprecated.py0000644000000000000000000000302211473521746015766 0ustar rootroot""" some deprecated calls (c) 2008-2009, Holger Krekel and others """ import execnet def PopenGateway(python=None): """ instantiate a gateway to a subprocess started with the given 'python' executable. """ APIWARN("1.0.0b4", "use makegateway('popen')") spec = execnet.XSpec("popen") spec.python = python return execnet.default_group.makegateway(spec) def SocketGateway(host, port): """ This Gateway provides interaction with a remote process by connecting to a specified socket. On the remote side you need to manually start a small script (py/execnet/script/socketserver.py) that accepts SocketGateway connections or use the experimental new_remote() method on existing gateways. """ APIWARN("1.0.0b4", "use makegateway('socket=host:port')") spec = execnet.XSpec("socket=%s:%s" %(host, port)) return execnet.default_group.makegateway(spec) def SshGateway(sshaddress, remotepython=None, ssh_config=None): """ instantiate a remote ssh process with the given 'sshaddress' and remotepython version. you may specify an ssh_config file. """ APIWARN("1.0.0b4", "use makegateway('ssh=host')") spec = execnet.XSpec("ssh=%s" % sshaddress) spec.python = remotepython spec.ssh_config = ssh_config return execnet.default_group.makegateway(spec) def APIWARN(version, msg, stacklevel=3): import warnings Warn = DeprecationWarning("(since version %s) %s" %(version, msg)) warnings.warn(Warn, stacklevel=stacklevel) execnet-1.0.9/execnet/multi.py0000644000000000000000000002157711473521746015037 0ustar rootroot""" Managing Gateway Groups and interactions with multiple channels. (c) 2008-2009, Holger Krekel and others """ import os, sys, atexit import execnet from execnet import XSpec from execnet import gateway from execnet.gateway_base import queue, reraise, trace, TimeoutError NO_ENDMARKER_WANTED = object() class Group: """ Gateway Groups. """ defaultspec = "popen" def __init__(self, xspecs=()): """ initialize group and make gateways as specified. """ # Gateways may evolve to become GC-collectable self._gateways = [] self._autoidcounter = 0 self._gateways_to_join = [] for xspec in xspecs: self.makegateway(xspec) atexit.register(self._cleanup_atexit) def __repr__(self): idgateways = [gw.id for gw in self] return "" %(idgateways) def __getitem__(self, key): if isinstance(key, int): return self._gateways[key] for gw in self._gateways: if gw == key or gw.id == key: return gw raise KeyError(key) def __contains__(self, key): try: self[key] return True except KeyError: return False def __len__(self): return len(self._gateways) def __iter__(self): return iter(list(self._gateways)) def makegateway(self, spec=None): """create and configure a gateway to a Python interpreter. The ``spec`` string encodes the target gateway type and configuration information. The general format is:: key1=value1//key2=value2//... If you leave out the ``=value`` part a True value is assumed. Valid types: ``popen``, ``ssh=hostname``, ``socket=host:port``. Valid configuration:: id= specifies the gateway id python= specifies which python interpreter to execute chdir= specifies to which directory to change nice= specifies process priority of new process env:NAME=value specifies a remote environment variable setting. If no spec is given, self.defaultspec is used. """ if not spec: spec = self.defaultspec if not isinstance(spec, XSpec): spec = XSpec(spec) self.allocate_id(spec) if spec.popen: gw = gateway.PopenGateway(python=spec.python, id=spec.id) elif spec.ssh: gw = gateway.SshGateway(spec.ssh, remotepython=spec.python, ssh_config=spec.ssh_config, id=spec.id) elif spec.socket: assert not spec.python, ( "socket: specifying python executables not yet supported") from execnet.gateway_socket import SocketGateway gateway_id = spec.installvia if gateway_id: viagw = self[gateway_id] gw = SocketGateway.new_remote(viagw, id=spec.id) else: host, port = spec.socket.split(":") gw = SocketGateway(host, port, id=spec.id) else: raise ValueError("no gateway type found for %r" % (spec._spec,)) gw.spec = spec self._register(gw) if spec.chdir or spec.nice or spec.env: channel = gw.remote_exec(""" import os path, nice, env = channel.receive() if path: if not os.path.exists(path): os.mkdir(path) os.chdir(path) if nice and hasattr(os, 'nice'): os.nice(nice) if env: for name, value in env.items(): os.environ[name] = value """) nice = spec.nice and int(spec.nice) or 0 channel.send((spec.chdir, nice, spec.env)) channel.waitclose() return gw def allocate_id(self, spec): """ allocate id for the given xspec object. """ if spec.id is None: id = "gw" + str(self._autoidcounter) self._autoidcounter += 1 if id in self: raise ValueError("already have gateway with id %r" %(id,)) spec.id = id def _register(self, gateway): assert not hasattr(gateway, '_group') assert gateway.id assert id not in self self._gateways.append(gateway) gateway._group = self def _unregister(self, gateway): self._gateways.remove(gateway) self._gateways_to_join.append(gateway) def _cleanup_atexit(self): trace("=== atexit cleanup %r ===" %(self,)) self.terminate(timeout=1.0) def terminate(self, timeout=None): """ trigger exit of member gateways and wait for termination of member gateways and associated subprocesses. After waiting timeout seconds try to to kill local sub processes of popen- and ssh-gateways. Timeout defaults to None meaning open-ended waiting and no kill attempts. """ for gw in self: gw.exit() def join_receiver_and_wait_for_subprocesses(): for gw in self._gateways_to_join: gw.join() while self._gateways_to_join: gw = self._gateways_to_join[0] if hasattr(gw, '_popen'): gw._popen.wait() del self._gateways_to_join[0] from execnet.threadpool import WorkerPool pool = WorkerPool(1) reply = pool.dispatch(join_receiver_and_wait_for_subprocesses) try: reply.get(timeout=timeout) except IOError: trace("Gateways did not come down after timeout: %r" %(self._gateways_to_join)) while self._gateways_to_join: gw = self._gateways_to_join.pop(0) popen = getattr(gw, '_popen', None) if popen: killpopen(popen) def remote_exec(self, source): """ remote_exec source on all member gateways and return MultiChannel connecting to all sub processes. """ channels = [] for gw in self: channels.append(gw.remote_exec(source)) return MultiChannel(channels) class MultiChannel: def __init__(self, channels): self._channels = channels def __len__(self): return len(self._channels) def __iter__(self): return iter(self._channels) def __getitem__(self, key): return self._channels[key] def __contains__(self, chan): return chan in self._channels def send_each(self, item): for ch in self._channels: ch.send(item) def receive_each(self, withchannel=False): assert not hasattr(self, '_queue') l = [] for ch in self._channels: obj = ch.receive() if withchannel: l.append((ch, obj)) else: l.append(obj) return l def make_receive_queue(self, endmarker=NO_ENDMARKER_WANTED): try: return self._queue except AttributeError: self._queue = queue.Queue() for ch in self._channels: def putreceived(obj, channel=ch): self._queue.put((channel, obj)) if endmarker is NO_ENDMARKER_WANTED: ch.setcallback(putreceived) else: ch.setcallback(putreceived, endmarker=endmarker) return self._queue def waitclose(self): first = None for ch in self._channels: try: ch.waitclose() except ch.RemoteError: if first is None: first = sys.exc_info() if first: reraise(*first) def killpopen(popen): try: if hasattr(popen, 'kill'): popen.kill() else: killpid(popen.pid) except EnvironmentError: sys.stderr.write("ERROR killing: %s\n" %(sys.exc_info()[1])) sys.stderr.flush() def killpid(pid): if hasattr(os, 'kill'): os.kill(pid, 15) elif sys.platform == "win32" or getattr(os, '_name', None) == 'nt': try: import ctypes except ImportError: import subprocess # T: treekill, F: Force cmd = ("taskkill /T /F /PID %d" %(pid)).split() ret = subprocess.call(cmd) if ret != 0: raise EnvironmentError("taskkill returned %r" %(ret,)) else: PROCESS_TERMINATE = 1 handle = ctypes.windll.kernel32.OpenProcess( PROCESS_TERMINATE, False, pid) ctypes.windll.kernel32.TerminateProcess(handle, -1) ctypes.windll.kernel32.CloseHandle(handle) else: raise EnvironmentError("no method to kill %s" %(pid,)) default_group = Group() makegateway = default_group.makegateway execnet-1.0.9/execnet/rsync_remote.py0000644000000000000000000000701511473521746016405 0ustar rootroot""" (c) 2006-2009, Armin Rigo, Holger Krekel, Maciej Fijalkowski """ def serve_rsync(channel): import os, stat, shutil try: from hashlib import md5 except ImportError: from md5 import md5 destdir, options = channel.receive() modifiedfiles = [] def remove(path): assert path.startswith(destdir) try: os.unlink(path) except OSError: # assume it's a dir shutil.rmtree(path) def receive_directory_structure(path, relcomponents): try: st = os.lstat(path) except OSError: st = None msg = channel.receive() if isinstance(msg, list): if st and not stat.S_ISDIR(st.st_mode): os.unlink(path) st = None if not st: os.makedirs(path) mode = msg.pop(0) if mode: os.chmod(path, mode) entrynames = {} for entryname in msg: destpath = os.path.join(path, entryname) receive_directory_structure(destpath, relcomponents + [entryname]) entrynames[entryname] = True if options.get('delete'): for othername in os.listdir(path): if othername not in entrynames: otherpath = os.path.join(path, othername) remove(otherpath) elif msg is not None: assert isinstance(msg, tuple) checksum = None if st: if stat.S_ISREG(st.st_mode): msg_mode, msg_mtime, msg_size = msg if msg_size != st.st_size: pass elif msg_mtime != st.st_mtime: f = open(path, 'rb') checksum = md5(f.read()).digest() f.close() elif msg_mode and msg_mode != st.st_mode: os.chmod(path, msg_mode) return else: return # already fine else: remove(path) channel.send(("send", (relcomponents, checksum))) modifiedfiles.append((path, msg)) receive_directory_structure(destdir, []) STRICT_CHECK = False # seems most useful this way for py.test channel.send(("list_done", None)) for path, (mode, time, size) in modifiedfiles: data = channel.receive() channel.send(("ack", path[len(destdir) + 1:])) if data is not None: if STRICT_CHECK and len(data) != size: raise IOError('file modified during rsync: %r' % (path,)) f = open(path, 'wb') f.write(data) f.close() try: if mode: os.chmod(path, mode) os.utime(path, (time, time)) except OSError: pass del data channel.send(("links", None)) msg = channel.receive() while msg != 42: # we get symlink _type, relpath, linkpoint = msg path = os.path.join(destdir, relpath) try: remove(path) except OSError: pass if _type == "linkbase": src = os.path.join(destdir, linkpoint) else: assert _type == "link", _type src = linkpoint os.symlink(src, path) msg = channel.receive() channel.send(("done", None)) if __name__ == '__channelexec__': serve_rsync(channel) execnet-1.0.9/execnet/xspec.py0000644000000000000000000000334011473521746015013 0ustar rootroot""" (c) 2008-2009, holger krekel """ import execnet class XSpec: """ Execution Specification: key1=value1//key2=value2 ... * keys need to be unique within the specification scope * neither key nor value are allowed to contain "//" * keys are not allowed to contain "=" * keys are not allowed to start with underscore * if no "=value" is given, assume a boolean True value """ # XXX allow customization, for only allow specific key names popen = ssh = socket = python = chdir = nice = None def __init__(self, string): self._spec = string self.env = {} for keyvalue in string.split("//"): i = keyvalue.find("=") if i == -1: key, value = keyvalue, True else: key, value = keyvalue[:i], keyvalue[i+1:] if key[0] == "_": raise AttributeError("%r not a valid XSpec key" % key) if key in self.__dict__: raise ValueError("duplicate key: %r in %r" %(key, string)) if key.startswith("env:"): self.env[key[4:]] = value else: setattr(self, key, value) def __getattr__(self, name): if name[0] == "_": raise AttributeError(name) return None def __repr__(self): return "" %(self._spec,) def __str__(self): return self._spec def __hash__(self): return hash(self._spec) def __eq__(self, other): return self._spec == getattr(other, '_spec', None) def __ne__(self, other): return self._spec != getattr(other, '_spec', None) def _samefilesystem(self): return bool(self.popen and not self.chdir) execnet-1.0.9/execnet/gateway_base.py0000644000000000000000000010735611473521746016340 0ustar rootroot""" base execnet gateway code send to the other side for bootstrapping. NOTE: aims to be compatible to Python 2.3-3.1, Jython and IronPython (C) 2004-2009 Holger Krekel, Armin Rigo, Benjamin Peterson, and others """ import sys, os, weakref import threading, traceback, struct try: import queue except ImportError: import Queue as queue ISPY3 = sys.version_info >= (3, 0) if ISPY3: exec("def do_exec(co, loc): exec(co, loc)\n" "def reraise(cls, val, tb): raise val\n") unicode = str _long_type = int from _thread import interrupt_main else: exec("def do_exec(co, loc): exec co in loc\n" "def reraise(cls, val, tb): raise cls, val, tb\n") bytes = str _long_type = long try: from thread import interrupt_main except ImportError: interrupt_main = None sysex = (KeyboardInterrupt, SystemExit) DEBUG = os.environ.get('EXECNET_DEBUG') pid = os.getpid() if DEBUG == '2': def trace(*msg): try: line = " ".join(map(str, msg)) sys.stderr.write("[%s] %s\n" % (pid, line)) sys.stderr.flush() except Exception: pass # nothing we can do, likely interpreter-shutdown elif DEBUG: import tempfile, os.path fn = os.path.join(tempfile.gettempdir(), 'execnet-debug-%d' % pid) debugfile = open(fn, 'w') def trace(*msg): try: line = " ".join(map(str, msg)) debugfile.write(line + "\n") debugfile.flush() except Exception: try: v = exc_info()[1] sys.stderr.write( "[%s] exception during tracing: %r\n" % (pid, v)) except Exception: pass # nothing we can do, likely interpreter-shutdown else: notrace = trace = lambda *msg: None class Popen2IO: error = (IOError, OSError, EOFError) def __init__(self, outfile, infile): # we need raw byte streams self.outfile, self.infile = outfile, infile if sys.platform == "win32": import msvcrt try: msvcrt.setmode(infile.fileno(), os.O_BINARY) msvcrt.setmode(outfile.fileno(), os.O_BINARY) except (AttributeError, IOError): pass self._read = getattr(infile, "buffer", infile).read self._write = getattr(outfile, "buffer", outfile).write def read(self, numbytes): """Read exactly 'numbytes' bytes from the pipe. """ # a file in non-blocking mode may return less bytes, so we loop buf = bytes() while len(buf) < numbytes: data = self._read(numbytes) if not data: raise EOFError("expected %d bytes, got %d" %(numbytes, len(buf))) buf += data return buf def write(self, data): """write out all data bytes. """ assert isinstance(data, bytes) self._write(data) self.outfile.flush() def close_read(self): self.infile.close() def close_write(self): self.outfile.close() class Message: """ encapsulates Messages and their wire protocol. """ _types = [] def __init__(self, msgcode, channelid=0, data=''): self.msgcode = msgcode self.channelid = channelid self.data = data def received(self, gateway): self._types[self.msgcode](self, gateway) def __repr__(self): name = self._types[self.msgcode].__name__.upper() r = repr(self.data) if len(r) > 50: return "" %(name, self.channelid, len(r)) else: return "" %(name, self.channelid, self.data) def _setupmessages(): def status(message, gateway): # we use the channelid to send back information # but don't instantiate a channel object active_channels = gateway._channelfactory.channels() numexec = 0 for ch in active_channels: if getattr(ch, '_executing', False): numexec += 1 d = {'execqsize': gateway._execqueue.qsize(), 'numchannels': len(active_channels), 'numexecuting': numexec } gateway._send(Message.CHANNEL_DATA, message.channelid, d) def channel_exec(message, gateway): channel = gateway._channelfactory.new(message.channelid) gateway._local_schedulexec(channel=channel, sourcetask=message.data) def channel_data(message, gateway): gateway._channelfactory._local_receive(message.channelid, message.data) def channel_close(message, gateway): gateway._channelfactory._local_close(message.channelid) def channel_close_error(message, gateway): remote_error = RemoteError(message.data) gateway._channelfactory._local_close(message.channelid, remote_error) def channel_last_message(message, gateway): gateway._channelfactory._local_close(message.channelid, sendonly=True) def gateway_terminate(message, gateway): gateway._terminate_execution() raise SystemExit(0) def reconfigure(message, gateway): py2str_as_py3str, py3str_as_py2str = message.data gateway._unserializer.py2str_as_py3str = py2str_as_py3str gateway._unserializer.py3str_as_py2str = py3str_as_py2str types = [ status, reconfigure, gateway_terminate, channel_exec, channel_data, channel_close, channel_close_error, channel_last_message, ] for i, handler in enumerate(types): Message._types.append(handler) setattr(Message, handler.__name__.upper(), i) _setupmessages() def geterrortext(excinfo, format_exception=traceback.format_exception, sysex=sysex): try: l = format_exception(*excinfo) errortext = "".join(l) except sysex: raise except: errortext = '%s: %s' % (excinfo[0].__name__, excinfo[1]) return errortext class RemoteError(Exception): """ Exception containing a stringified error from the other side. """ def __init__(self, formatted): self.formatted = formatted Exception.__init__(self) def __str__(self): return self.formatted def __repr__(self): return "%s: %s" %(self.__class__.__name__, self.formatted) def warn(self): if self.formatted != INTERRUPT_TEXT: # XXX do this better sys.stderr.write("Warning: unhandled %r\n" % (self,)) class TimeoutError(IOError): """ Exception indicating that a timeout was reached. """ NO_ENDMARKER_WANTED = object() class Channel(object): """Communication channel between two Python Interpreter execution points.""" RemoteError = RemoteError TimeoutError = TimeoutError _INTERNALWAKEUP = 1000 _executing = False def __init__(self, gateway, id): assert isinstance(id, int) self.gateway = gateway self.id = id self._items = queue.Queue() self._closed = False self._receiveclosed = threading.Event() self._remoteerrors = [] def _trace(self, *msg): self.gateway._trace(self.id, *msg) def setcallback(self, callback, endmarker=NO_ENDMARKER_WANTED): """ set a callback function for receiving items. All already queued items will immediately trigger the callback. Afterwards the callback will execute in the receiver thread for each received data item and calls to ``receive()`` will raise an error. If an endmarker is specified the callback will eventually be called with the endmarker when the channel closes. """ _callbacks = self.gateway._channelfactory._callbacks _receivelock = self.gateway._receivelock _receivelock.acquire() try: if self._items is None: raise IOError("%r has callback already registered" %(self,)) items = self._items self._items = None while 1: try: olditem = items.get(block=False) except queue.Empty: if not (self._closed or self._receiveclosed.isSet()): _callbacks[self.id] = (callback, endmarker) break else: if olditem is ENDMARKER: items.put(olditem) # for other receivers if endmarker is not NO_ENDMARKER_WANTED: callback(endmarker) break else: callback(olditem) finally: _receivelock.release() def __repr__(self): flag = self.isclosed() and "closed" or "open" return "" % (self.id, flag) def __del__(self): if self.gateway is None: # can be None in tests return self._trace("channel.__del__") # no multithreading issues here, because we have the last ref to 'self' if self._closed: # state transition "closed" --> "deleted" for error in self._remoteerrors: error.warn() elif self._receiveclosed.isSet(): # state transition "sendonly" --> "deleted" # the remote channel is already in "deleted" state, nothing to do pass else: # state transition "opened" --> "deleted" if self._items is None: # has_callback msgcode = Message.CHANNEL_LAST_MESSAGE else: msgcode = Message.CHANNEL_CLOSE try: self.gateway._send(msgcode, self.id) except (IOError, ValueError): # ignore problems with sending pass def _getremoteerror(self): try: return self._remoteerrors.pop(0) except IndexError: try: return self.gateway._error except AttributeError: pass return None # # public API for channel objects # def isclosed(self): """ return True if the channel is closed. A closed channel may still hold items. """ return self._closed def makefile(self, mode='w', proxyclose=False): """ return a file-like object. mode can be 'w' or 'r' for writeable/readable files. if proxyclose is true file.close() will also close the channel. """ if mode == "w": return ChannelFileWrite(channel=self, proxyclose=proxyclose) elif mode == "r": return ChannelFileRead(channel=self, proxyclose=proxyclose) raise ValueError("mode %r not availabe" %(mode,)) def close(self, error=None): """ close down this channel with an optional error message. Note that closing of a channel tied to remote_exec happens automatically at the end of execution and cannot be done explicitely. """ if self._executing: raise IOError("cannot explicitly close channel within remote_exec") if self._closed: self.gateway._trace(self, "ignoring redundant call to close()") if not self._closed: # state transition "opened/sendonly" --> "closed" # threads warning: the channel might be closed under our feet, # but it's never damaging to send too many CHANNEL_CLOSE messages # however, if the other side triggered a close already, we # do not send back a closed message. if not self._receiveclosed.isSet(): put = self.gateway._send if error is not None: put(Message.CHANNEL_CLOSE_ERROR, self.id, error) else: put(Message.CHANNEL_CLOSE, self.id) self._trace("sent channel close message") if isinstance(error, RemoteError): self._remoteerrors.append(error) self._closed = True # --> "closed" self._receiveclosed.set() queue = self._items if queue is not None: queue.put(ENDMARKER) self.gateway._channelfactory._no_longer_opened(self.id) def waitclose(self, timeout=None): """ wait until this channel is closed (or the remote side otherwise signalled that no more data was being sent). The channel may still hold receiveable items, but not receive any more after waitclose() has returned. Exceptions from executing code on the other side are reraised as local channel.RemoteErrors. EOFError is raised if the reading-connection was prematurely closed, which often indicates a dying process. self.TimeoutError is raised after the specified number of seconds (default is None, i.e. wait indefinitely). """ self._receiveclosed.wait(timeout=timeout) # wait for non-"opened" state if not self._receiveclosed.isSet(): raise self.TimeoutError("Timeout after %r seconds" % timeout) error = self._getremoteerror() if error: raise error def send(self, item): """sends the given item to the other side of the channel, possibly blocking if the sender queue is full. The item must be a simple python type and will be copied to the other side by value. IOError is raised if the write pipe was prematurely closed. """ if self.isclosed(): raise IOError("cannot send to %r" %(self,)) self.gateway._send(Message.CHANNEL_DATA, self.id, item) def receive(self, timeout=-1): """receive a data item that was sent from the other side. timeout: -1 [default] blocked waiting, but wake up periodically to let CTRL-C through. A positive number indicates the number of seconds after which a channel.TimeoutError exception will be raised if no item was received. Note that exceptions from the remotely executing code will be reraised as channel.RemoteError exceptions containing a textual representation of the remote traceback. """ itemqueue = self._items if itemqueue is None: raise IOError("cannot receive(), channel has receiver callback") if timeout < 0: internal_timeout = self._INTERNALWAKEUP else: internal_timeout = timeout while 1: try: x = itemqueue.get(timeout=internal_timeout) break except queue.Empty: if timeout < 0: continue raise self.TimeoutError("no item after %r seconds" %(timeout)) if x is ENDMARKER: itemqueue.put(x) # for other receivers raise self._getremoteerror() or EOFError() else: return x def __iter__(self): return self def next(self): try: return self.receive() except EOFError: raise StopIteration __next__ = next ENDMARKER = object() INTERRUPT_TEXT = "keyboard-interrupted" class ChannelFactory(object): def __init__(self, gateway, startcount=1): self._channels = weakref.WeakValueDictionary() self._callbacks = {} self._writelock = threading.Lock() self.gateway = gateway self.count = startcount self.finished = False self._list = list # needed during interp-shutdown def new(self, id=None): """ create a new Channel with 'id' (or create new id if None). """ self._writelock.acquire() try: if self.finished: raise IOError("connexion already closed: %s" % (self.gateway,)) if id is None: id = self.count self.count += 2 try: channel = self._channels[id] except KeyError: channel = self._channels[id] = Channel(self.gateway, id) return channel finally: self._writelock.release() def channels(self): return self._list(self._channels.values()) # # internal methods, called from the receiver thread # def _no_longer_opened(self, id): try: del self._channels[id] except KeyError: pass try: callback, endmarker = self._callbacks.pop(id) except KeyError: pass else: if endmarker is not NO_ENDMARKER_WANTED: callback(endmarker) def _local_close(self, id, remoteerror=None, sendonly=False): channel = self._channels.get(id) if channel is None: # channel already in "deleted" state if remoteerror: remoteerror.warn() self._no_longer_opened(id) else: # state transition to "closed" state if remoteerror: channel._remoteerrors.append(remoteerror) queue = channel._items if queue is not None: queue.put(ENDMARKER) self._no_longer_opened(id) if not sendonly: # otherwise #--> "sendonly" channel._closed = True # --> "closed" channel._receiveclosed.set() def _local_receive(self, id, data): # executes in receiver thread try: callback, endmarker = self._callbacks[id] except KeyError: channel = self._channels.get(id) queue = channel and channel._items if queue is None: pass # drop data else: queue.put(data) else: try: callback(data) # even if channel may be already closed except KeyboardInterrupt: raise except: excinfo = sys.exc_info() self.gateway._trace("exception during callback: %s" % excinfo[1]) errortext = self.gateway._geterrortext(excinfo) self.gateway._send(Message.CHANNEL_CLOSE_ERROR, id, errortext) self._local_close(id, errortext) def _finished_receiving(self): self._writelock.acquire() try: self.finished = True finally: self._writelock.release() for id in self._list(self._channels): self._local_close(id, sendonly=True) for id in self._list(self._callbacks): self._no_longer_opened(id) class ChannelFile(object): def __init__(self, channel, proxyclose=True): self.channel = channel self._proxyclose = proxyclose def isatty(self): return False def close(self): if self._proxyclose: self.channel.close() def __repr__(self): state = self.channel.isclosed() and 'closed' or 'open' return '' %(self.channel.id, state) class ChannelFileWrite(ChannelFile): def write(self, out): self.channel.send(out) def flush(self): pass class ChannelFileRead(ChannelFile): def __init__(self, channel, proxyclose=True): super(ChannelFileRead, self).__init__(channel, proxyclose) self._buffer = "" def read(self, n): while len(self._buffer) < n: try: self._buffer += self.channel.receive() except EOFError: self.close() break ret = self._buffer[:n] self._buffer = self._buffer[n:] return ret def readline(self): i = self._buffer.find("\n") if i != -1: return self.read(i+1) line = self.read(len(self._buffer)+1) while line and line[-1] != "\n": c = self.read(1) if not c: break line += c return line class BaseGateway(object): exc_info = sys.exc_info _sysex = sysex id = "" class _StopExecLoop(Exception): pass def __init__(self, io, id, _startcount=2): self._io = io self.id = id self._channelfactory = ChannelFactory(self, _startcount) self._unserializer = Unserializer(self._io, self._channelfactory) self._receivelock = threading.RLock() # globals may be NONE at process-termination self._trace = trace self._geterrortext = geterrortext def _trace(self, *msg): self._trace(self.id, *msg) def _initreceive(self): self._receiverthread = threading.Thread(name="receiver", target=self._thread_receiver) self._receiverthread.setDaemon(1) self._receiverthread.start() def _thread_receiver(self): self._trace("RECEIVERTHREAD: starting to run") eof = False try: try: while 1: msg = Message(*self._unserializer.load()) self._trace("received", msg) _receivelock = self._receivelock _receivelock.acquire() try: msg.received(self) del msg finally: _receivelock.release() except self._sysex: self._trace("RECEIVERTHREAD: doing io.close_read()") self._io.close_read() except EOFError: self._trace("RECEIVERTHREAD: got EOFError") self._trace("RECEIVERTHREAD: traceback was: ", self._geterrortext(self.exc_info())) self._error = self.exc_info()[1] eof = True except: self._trace("RECEIVERTHREAD", self._geterrortext(self.exc_info())) finally: try: self._trace('RECEIVERTHREAD', 'entering finalization') if eof: self._terminate_execution() self._channelfactory._finished_receiving() self._trace('RECEIVERTHREAD', 'leaving finalization') except: pass # XXX be silent at interp-shutdown def _terminate_execution(self): pass def _send(self, msgcode, channelid=0, data=''): serialize(self._io, (msgcode, channelid, data)) self._trace('sent', Message(msgcode, channelid, data)) def _local_schedulexec(self, channel, sourcetask): channel.close("execution disallowed") # _____________________________________________________________________ # # High Level Interface # _____________________________________________________________________ # def newchannel(self): """ return a new independent channel. """ return self._channelfactory.new() def join(self, timeout=None): """ Wait for receiverthread to terminate. """ current = threading.currentThread() if self._receiverthread.isAlive(): self._trace("joining receiver thread") self._receiverthread.join(timeout) else: self._trace("gateway.join() called while receiverthread " "already finished") class SlaveGateway(BaseGateway): def _local_schedulexec(self, channel, sourcetask): self._execqueue.put((channel, sourcetask)) def _terminate_execution(self): # called from receiverthread self._trace("putting None to execqueue") self._execqueue.put(None) if interrupt_main: self._trace("calling interrupt_main()") interrupt_main() self._execfinished.wait(10.0) if not self._execfinished.isSet(): self._trace("execution did not finish in 10 secs, calling os._exit()") os._exit(1) def serve(self, joining=True): try: try: self._execqueue = queue.Queue() self._execfinished = threading.Event() self._initreceive() while 1: item = self._execqueue.get() if item is None: break try: self.executetask(item) except self._StopExecLoop: break finally: self._execfinished.set() self._trace("io.close_write()") self._io.close_write() self._trace("slavegateway.serve finished") if joining: self.join() except KeyboardInterrupt: # in the slave we can't really do anything sensible self._trace("swallowing keyboardinterrupt in main-thread") def executetask(self, item): try: channel, (source, call_name, kwargs) = item if not ISPY3 and kwargs: # some python2 versions do not accept unicode keyword params # note: Unserializer generally turns py2-str to py3-str objects newkwargs = {} for name, value in kwargs.items(): if isinstance(name, unicode): name = name.encode('ascii') newkwargs[name] = value kwargs = newkwargs loc = {'channel' : channel, '__name__': '__channelexec__'} self._trace("execution starts[%s]: %s" % (channel.id, repr(source)[:50])) channel._executing = True try: co = compile(source+'\n', '', 'exec') do_exec(co, loc) if call_name: self._trace('calling %s(**%60r)' % (call_name, kwargs)) function = loc[call_name] function(channel, **kwargs) finally: channel._executing = False self._trace("execution finished") except self._StopExecLoop: channel.close() raise except KeyboardInterrupt: channel.close(INTERRUPT_TEXT) raise except: excinfo = self.exc_info() self._trace("got exception: %s" % (excinfo[1],)) errortext = self._geterrortext(excinfo) channel.close(errortext) else: channel.close() # # Cross-Python pickling code, tested from test_serializer.py # class SerializeError(Exception): pass class SerializationError(SerializeError): """Error while serializing an object.""" class UnserializationError(SerializeError): """Error while unserializing an object.""" if ISPY3: def bchr(n): return bytes([n]) else: bchr = chr FOUR_BYTE_INT_MAX = 2147483647 FLOAT_FORMAT = "!d" FLOAT_FORMAT_SIZE = struct.calcsize(FLOAT_FORMAT) class _Stop(Exception): pass class Unserializer(object): num2func = {} # is filled after this class definition py2str_as_py3str = True # True py3str_as_py2str = False # false means py2 will get unicode def __init__(self, stream, channelfactory=None): self.stream = stream self.channelfactory = channelfactory def load(self): self.stack = [] try: while True: opcode = self.stream.read(1) if not opcode: raise EOFError try: loader = self.num2func[opcode] except KeyError: raise UnserializationError("unkown opcode %r - " "wire protocol corruption?" % (opcode,)) loader(self) except _Stop: if len(self.stack) != 1: raise UnserializationError("internal unserialization error") return self.stack.pop(0) else: raise UnserializationError("didn't get STOP") def load_none(self): self.stack.append(None) def load_true(self): self.stack.append(True) def load_false(self): self.stack.append(False) def load_int(self): i = self._read_int4() self.stack.append(i) def load_longint(self): s = self._read_byte_string() self.stack.append(int(s)) if ISPY3: load_long = load_int load_longlong = load_longint else: def load_long(self): i = self._read_int4() self.stack.append(long(i)) def load_longlong(self): l = self._read_byte_string() self.stack.append(long(l)) def load_float(self): binary = self.stream.read(FLOAT_FORMAT_SIZE) self.stack.append(struct.unpack(FLOAT_FORMAT, binary)[0]) def _read_int4(self): return struct.unpack("!i", self.stream.read(4))[0] def _read_byte_string(self): length = self._read_int4() as_bytes = self.stream.read(length) return as_bytes def load_py3string(self): as_bytes = self._read_byte_string() if not ISPY3 and self.py3str_as_py2str: # XXX Should we try to decode into latin-1? self.stack.append(as_bytes) else: self.stack.append(as_bytes.decode("utf-8")) def load_py2string(self): as_bytes = self._read_byte_string() if ISPY3 and self.py2str_as_py3str: s = as_bytes.decode("latin-1") else: s = as_bytes self.stack.append(s) def load_bytes(self): s = self._read_byte_string() self.stack.append(s) def load_unicode(self): self.stack.append(self._read_byte_string().decode("utf-8")) def load_newlist(self): length = self._read_int4() self.stack.append([None] * length) def load_setitem(self): if len(self.stack) < 3: raise UnserializationError("not enough items for setitem") value = self.stack.pop() key = self.stack.pop() self.stack[-1][key] = value def load_newdict(self): self.stack.append({}) def _load_collection(self, type_): length = self._read_int4() if length: res = type_(self.stack[-length:]) del self.stack[-length:] self.stack.append(res) else: self.stack.append(type_()) def load_buildtuple(self): self._load_collection(tuple) def load_set(self): self._load_collection(set) def load_frozenset(self): self._load_collection(frozenset) def load_stop(self): raise _Stop def load_channel(self): id = self._read_int4() newchannel = self.channelfactory.new(id) self.stack.append(newchannel) # automatically build opcodes and byte-encoding class opcode: """ container for name -> num mappings. """ def _buildopcodes(): l = [] for name, func in Unserializer.__dict__.items(): if name.startswith("load_"): opname = name[5:].upper() l.append((opname, func)) l.sort() for i,(opname, func) in enumerate(l): assert i < 26, "xxx" i = bchr(64+i) Unserializer.num2func[i] = func setattr(opcode, opname, i) _buildopcodes() def serialize(io, obj): _Serializer(io).save(obj) class _Serializer(object): _dispatch = {} def __init__(self, stream): self._stream = stream self._streamlist = [] def _write(self, data): self._streamlist.append(data) def save(self, obj): # calling here is not re-entrant but multiple instances # may write to the same stream because of the common platform # atomic-write guaruantee (concurrent writes each happen atomicly) self._save(obj) self._write(opcode.STOP) s = type(self._streamlist[0])().join(self._streamlist) # atomic write self._stream.write(s) def _save(self, obj): tp = type(obj) try: dispatch = self._dispatch[tp] except KeyError: methodname = 'save_' + tp.__name__ meth = getattr(self.__class__, methodname, None) if meth is None: raise SerializationError("can't serialize %s" % (tp,)) dispatch = self._dispatch[tp] = meth dispatch(self, obj) def save_NoneType(self, non): self._write(opcode.NONE) def save_bool(self, boolean): if boolean: self._write(opcode.TRUE) else: self._write(opcode.FALSE) def save_bytes(self, bytes_): self._write(opcode.BYTES) self._write_byte_sequence(bytes_) if ISPY3: def save_str(self, s): self._write(opcode.PY3STRING) self._write_unicode_string(s) else: def save_str(self, s): self._write(opcode.PY2STRING) self._write_byte_sequence(s) def save_unicode(self, s): self._write(opcode.UNICODE) self._write_unicode_string(s) def _write_unicode_string(self, s): try: as_bytes = s.encode("utf-8") except UnicodeEncodeError: raise SerializationError("strings must be utf-8 encodable") self._write_byte_sequence(as_bytes) def _write_byte_sequence(self, bytes_): self._write_int4(len(bytes_), "string is too long") self._write(bytes_) def _save_integral(self, i, short_op, long_op): if i <= FOUR_BYTE_INT_MAX: self._write(short_op) self._write_int4(i) else: self._write(long_op) self._write_byte_sequence(str(i).rstrip("L").encode("ascii")) def save_int(self, i): self._save_integral(i, opcode.INT, opcode.LONGINT) def save_long(self, l): self._save_integral(l, opcode.LONG, opcode.LONGLONG) def save_float(self, flt): self._write(opcode.FLOAT) self._write(struct.pack(FLOAT_FORMAT, flt)) def _write_int4(self, i, error="int must be less than %i" % (FOUR_BYTE_INT_MAX,)): if i > FOUR_BYTE_INT_MAX: raise SerializationError(error) self._write(struct.pack("!i", i)) def save_list(self, L): self._write(opcode.NEWLIST) self._write_int4(len(L), "list is too long") for i, item in enumerate(L): self._write_setitem(i, item) def _write_setitem(self, key, value): self._save(key) self._save(value) self._write(opcode.SETITEM) def save_dict(self, d): self._write(opcode.NEWDICT) for key, value in d.items(): self._write_setitem(key, value) def save_tuple(self, tup): for item in tup: self._save(item) self._write(opcode.BUILDTUPLE) self._write_int4(len(tup), "tuple is too long") def _write_set(self, s, op): for item in s: self._save(item) self._write(op) self._write_int4(len(s), "set is too long") def save_set(self, s): self._write_set(s, opcode.SET) def save_frozenset(self, s): self._write_set(s, opcode.FROZENSET) def save_Channel(self, channel): self._write(opcode.CHANNEL) self._write_int4(channel.id) def init_popen_io(): if not hasattr(os, 'dup'): # jython io = Popen2IO(sys.stdout, sys.stdin) import tempfile sys.stdin = tempfile.TemporaryFile('r') sys.stdout = tempfile.TemporaryFile('w') else: try: devnull = os.devnull except AttributeError: if os.name == 'nt': devnull = 'NUL' else: devnull = '/dev/null' # stdin stdin = os.fdopen(os.dup(0), 'r', 1) fd = os.open(devnull, os.O_RDONLY) os.dup2(fd, 0) os.close(fd) # stdout stdout = os.fdopen(os.dup(1), 'w', 1) fd = os.open(devnull, os.O_WRONLY) os.dup2(fd, 1) # stderr for win32 if os.name == 'nt': sys.stderr = os.fdopen(os.dup(2), 'w', 1) os.dup2(fd, 2) os.close(fd) io = Popen2IO(stdout, stdin) sys.stdin = os.fdopen(0, 'r', 1) sys.stdout = os.fdopen(1, 'w', 1) return io def serve(io, id): trace("creating slavegateway on %r" %(io,)) SlaveGateway(io=io, id=id, _startcount=2).serve() execnet-1.0.9/execnet/gateway.py0000644000000000000000000002450211473521746015335 0ustar rootroot""" gateway code for initiating popen, socket and ssh connections. (c) 2004-2009, Holger Krekel and others """ import sys, os, inspect, types, linecache import textwrap import execnet from execnet.gateway_base import Message, Popen2IO from execnet import gateway_base importdir = os.path.dirname(os.path.dirname(execnet.__file__)) class Gateway(gateway_base.BaseGateway): """ Gateway to a local or remote Python Intepreter. """ def __init__(self, io, id): super(Gateway, self).__init__(io=io, id=id, _startcount=1) self._remote_bootstrap_gateway(io) self._initreceive() def __repr__(self): """ return string representing gateway type and status. """ try: r = (self.hasreceiver() and 'receive-live' or 'not-receiving') i = len(self._channelfactory.channels()) except AttributeError: r = "uninitialized" i = "no" return "<%s id=%r %s, %s active channels>" %( self.__class__.__name__, self.id, r, i) def exit(self): """ trigger gateway exit. Defer waiting for finishing of receiver-thread and subprocess activity to when group.terminate() is called. """ self._trace("gateway.exit() called") if self not in self._group: self._trace("gateway already unregistered with group") return self._group._unregister(self) self._trace("--> sending GATEWAY_TERMINATE") try: self._send(Message.GATEWAY_TERMINATE) self._io.close_write() except IOError: v = sys.exc_info()[1] self._trace("io-error: could not send termination sequence") self._trace(" exception: %r" % v) def reconfigure(self, py2str_as_py3str=True, py3str_as_py2str=False): """ set the string coercion for this gateway the default is to try to convert py2 str as py3 str, but not to try and convert py3 str to py2 str """ self._unserializer.py2str_as_py3str = py2str_as_py3str self._unserializer.py3str_as_py2str = py3str_as_py2str self._send(Message.RECONFIGURE, data=(py2str_as_py3str, py3str_as_py2str)) def _remote_bootstrap_gateway(self, io): """ send gateway bootstrap code to a remote Python interpreter endpoint, which reads from io for a string to execute. """ sendexec(io, inspect.getsource(gateway_base), self._remotesetup, "io.write('1'.encode('ascii'))", "serve(io, id='%s-slave')" % self.id, ) s = io.read(1) assert s == "1".encode('ascii') def _rinfo(self, update=False): """ return some sys/env information from remote. """ if update or not hasattr(self, '_cache_rinfo'): ch = self.remote_exec(rinfo_source) self._cache_rinfo = RInfo(ch.receive()) return self._cache_rinfo def hasreceiver(self): """ return True if gateway is able to receive data. """ return self._receiverthread.isAlive() # approxmimation def remote_status(self): """ return information object about remote execution status. """ channel = self.newchannel() self._send(Message.STATUS, channel.id) statusdict = channel.receive() # the other side didn't actually instantiate a channel # so we just delete the internal id/channel mapping self._channelfactory._local_close(channel.id) return RemoteStatus(statusdict) def remote_exec(self, source, **kwargs): """ return channel object and connect it to a remote execution thread where the given ``source`` executes. * ``source`` is a string: execute source string remotely with a ``channel`` put into the global namespace. * ``source`` is a pure function: serialize source and call function with ``**kwargs``, adding a ``channel`` object to the keyword arguments. * ``source`` is a pure module: execute source of module with a ``channel`` in its global namespace In all cases the binding ``__name__='__channelexec__'`` will be available in the global namespace of the remotely executing code. """ call_name = None if isinstance(source, types.ModuleType): linecache.updatecache(inspect.getsourcefile(source)) source = inspect.getsource(source) elif isinstance(source, types.FunctionType): call_name = source.__name__ source = _source_of_function(source) else: source = textwrap.dedent(str(source)) if call_name is None and kwargs: raise TypeError("can't pass kwargs to non-function remote_exec") channel = self.newchannel() self._send(Message.CHANNEL_EXEC, channel.id, (source, call_name, kwargs)) return channel def remote_init_threads(self, num=None): """ start up to 'num' threads for subsequent remote_exec() invocations to allow concurrent execution. """ if hasattr(self, '_remotechannelthread'): raise IOError("remote threads already running") from execnet import threadpool source = inspect.getsource(threadpool) self._remotechannelthread = self.remote_exec(source) self._remotechannelthread.send(num) status = self._remotechannelthread.receive() assert status == "ok", status class RInfo: def __init__(self, kwargs): self.__dict__.update(kwargs) def __repr__(self): info = ", ".join(["%s=%s" % item for item in self.__dict__.items()]) return "" % info RemoteStatus = RInfo rinfo_source = """ import sys, os channel.send(dict( executable = sys.executable, version_info = sys.version_info[:5], platform = sys.platform, cwd = os.getcwd(), pid = os.getpid(), )) """ def _find_non_builtin_globals(source, codeobj): try: import ast except ImportError: return None try: import __builtin__ except ImportError: import builtins as __builtin__ vars = dict.fromkeys(codeobj.co_varnames) all = [] for node in ast.walk(ast.parse(source)): if (isinstance(node, ast.Name) and node.id not in vars and node.id not in __builtin__.__dict__): all.append(node.id) return all def _source_of_function(function): if function.__name__ == '': raise ValueError("can't evaluate lambda functions'") #XXX: we dont check before remote instanciation # if arguments are used propperly args, varargs, keywords, defaults = inspect.getargspec(function) if args[0] != 'channel': raise ValueError('expected first function argument to be `channel`') if sys.version_info < (3,0): closure = function.func_closure codeobj = function.func_code else: closure = function.__closure__ codeobj = function.__code__ if closure is not None: raise ValueError("functions with closures can't be passed") try: source = inspect.getsource(function) except IOError: raise ValueError("can't find source file for %s" % function) source = textwrap.dedent(source) # just for inner functions used_globals = _find_non_builtin_globals(source, codeobj) if used_globals: raise ValueError( "the use of non-builtin globals isn't supported", used_globals, ) return source class PopenCmdGateway(Gateway): _remotesetup = "io = init_popen_io()" def __init__(self, args, id): from subprocess import Popen, PIPE self._popen = p = Popen(args, stdin=PIPE, stdout=PIPE) io = Popen2IO(p.stdin, p.stdout) super(PopenCmdGateway, self).__init__(io=io, id=id) # fix for jython 2.5.1 if p.pid is None: p.pid = self.remote_exec( "import os; channel.send(os.getpid())").receive() popen_bootstrapline = "import sys;exec(eval(sys.stdin.readline()))" class PopenGateway(PopenCmdGateway): """ This Gateway provides interaction with a newly started python subprocess. """ def __init__(self, id, python=None): """ instantiate a gateway to a subprocess started with the given 'python' executable. """ if not python: python = sys.executable args = [str(python), '-u', '-c', popen_bootstrapline] super(PopenGateway, self).__init__(args, id=id) def _remote_bootstrap_gateway(self, io): sendexec(io, "import sys", "sys.stdout.write('1')", "sys.stdout.flush()", popen_bootstrapline) sendexec(io, "import sys ; sys.path.insert(0, %r)" % importdir, "from execnet.gateway_base import serve, init_popen_io", "serve(init_popen_io(), id='%s-slave')" % self.id, ) s = io.read(1) assert s == "1".encode('ascii') def sendexec(io, *sources): source = "\n".join(sources) io.write((repr(source)+ "\n").encode('ascii')) class HostNotFound(Exception): pass class SshGateway(PopenCmdGateway): """ This Gateway provides interaction with a remote Python process, established via the 'ssh' command line binary. The remote side needs to have a Python interpreter executable. """ def __init__(self, sshaddress, id, remotepython=None, ssh_config=None): """ instantiate a remote ssh process with the given 'sshaddress' and remotepython version. you may specify an ssh_config file. """ self.remoteaddress = sshaddress if remotepython is None: remotepython = "python" args = ['ssh', '-C' ] if ssh_config is not None: args.extend(['-F', str(ssh_config)]) remotecmd = '%s -c "%s"' %(remotepython, popen_bootstrapline) args.extend([sshaddress, remotecmd]) super(SshGateway, self).__init__(args, id=id) def _remote_bootstrap_gateway(self, io): try: super(SshGateway, self)._remote_bootstrap_gateway(io) except EOFError: ret = self._popen.wait() if ret == 255: raise HostNotFound(self.remoteaddress) execnet-1.0.9/doc/0000755000000000000000000000000011760165371012426 5ustar rootrootexecnet-1.0.9/doc/example/0000755000000000000000000000000011760165371014061 5ustar rootrootexecnet-1.0.9/doc/example/servefiles.py0000644000000000000000000000032411473521746016604 0ustar rootroot # content of servefiles.py def servefiles(channel): for fn in channel: f = open(fn, 'rb') channel.send(f.read()) f.close() if __name__ == "__channelexec__": servefiles(channel) execnet-1.0.9/doc/example/hybridpython.txt0000644000000000000000000000701511473521746017353 0ustar rootrootConnecting different Python interpreters ========================================== Connect to Python2/Numpy from Python3 ---------------------------------------- Here we run a Python3 interpreter to connect to a Python2.6 interpreter that has numpy installed. We send items to be added to an array and receive back the remote "repr" of the array:: import execnet gw = execnet.makegateway("popen//python=python2.6") channel = gw.remote_exec(""" import numpy array = numpy.array([1,2,3]) while 1: x = channel.receive() if x is None: break array = numpy.append(array, x) channel.send(repr(array)) """) for x in range(10): channel.send(x) channel.send(None) print (channel.receive()) will print on the CPython3.1 side:: array([1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) A more refined real-life example of python3/python2 interaction is the anyvc_ project which uses version-control bindings in a Python2 subprocess in order to offer Python3-based library functionality. .. _anyvc: http://bitbucket.org/RonnyPfannschmidt/anyvc/overview/ Reconfiguring the string coercion between python2 and python3 ------------------------------------------------------------- Sometimes the default configuration of string coercion (2str to 3str, 3str to 2unicode) is inconvient, thus it can be reconfigured via `gw.reconfigure`. >>> import execnet >>> execnet.makegateway("popen//python=python3.1") >>> gw=execnet.makegateway("popen//python=python3.1") >>> gw.remote_exec("channel.send('hello')").receive() u'hello' >>> gw.reconfigure(py3str_as_py2str=True) >>> gw.remote_exec("channel.send('hello')").receive() 'hello' >>> ch = gw.remote_exec("channel.send(isinstance(channel.receive(), bytes)") >>> ch.send('a') >>> ch.receive() False >>> gw.reconfigure(py2str_as_py3str=False) >>> ch = gw.remote_exec("channel.send(isinstance(channel.receive(), bytes)") >>> ch.send('a') >>> ch.receive() True Work with Java objects from CPython ---------------------------------------- Use your CPython interpreter to connect to a `Jython 2.5.1`_ interpreter and work with Java types:: import execnet gw = execnet.makegateway("popen//python=jython") channel = gw.remote_exec(""" from java.util import Vector v = Vector() v.add('aaa') v.add('bbb') for val in v: channel.send(val) """) for item in channel: print (item) will print on the CPython side:: aaa bbb .. _`Jython 2.5.1`: http://www.jython.org Work with C# objects from CPython ---------------------------------------- (Experimental) use your CPython interpreter to connect to a IronPython_ interpreter which can work with C# classes. Here is an example for instantiating a CLR Array instance and sending back its representation:: import execnet gw = execnet.makegateway("popen//python=ipy") channel = gw.remote_exec(""" import clr clr.AddReference("System") from System import Array array = Array[float]([1,2]) channel.send(str(array)) """) print (channel.receive()) using Mono 2.0 and IronPython-1.1 this will print on the CPython side:: System.Double[](1.0, 2.0) .. note:: Using IronPython needs more testing, likely newer versions will work better. please feedback if you have information. .. _IronPython: http://ironpython.net execnet-1.0.9/doc/example/test_ssh_fileserver.txt0000644000000000000000000000107611473521746020713 0ustar rootroot Receive file contents from remote SSH account ----------------------------------------------------- Here is some small server code that you can use to retrieve contents of remote files: .. include:: servefiles.py :literal: And here is some code to use it to retrieve remote contents:: import execnet import servefiles gw = execnet.makegateway("ssh=codespeak.net") channel = gw.remote_exec(servefiles) for fn in ('/etc/passwd', '/etc/group'): channel.send(fn) content = channel.receive() print(fn) print(content) execnet-1.0.9/doc/example/redirect_remote_output.py0000644000000000000000000000121211473521746021226 0ustar rootroot""" redirect output from remote to a local function showcasing features of the channel object: - sending a channel over a channel - adapting a channel to a file object - setting a callback for receiving channel data """ import py gw = execnet.makegateway() outchan = gw.remote_exec(""" import sys outchan = channel.gateway.newchannel() sys.stdout = outchan.makefile("w") channel.send(outchan) """).receive() # note: callbacks execute in receiver thread! def write(data): print "received:", repr(data) outchan.setcallback(write) gw.remote_exec(""" print 'hello world' print 'remote execution ends' """).waitclose() execnet-1.0.9/doc/example/popen_read_multiple.py0000644000000000000000000000165011473521746020467 0ustar rootroot""" example reading results from possibly blocking code running in sub processes. """ import execnet NUM_PROCESSES = 5 channels = [] for i in range(NUM_PROCESSES): gw = execnet.makegateway() # or use SSH or socket gateways channel = gw.remote_exec(""" import time secs = channel.receive() time.sleep(secs) channel.send("waited %d secs" % secs) """) channels.append(channel) print "*** instantiated subprocess", gw mc = execnet.MultiChannel(channels) queue = mc.make_receive_queue() print "***", "verifying that timeout on receiving results from blocked subprocesses works" try: queue.get(timeout=1.0) except Exception: pass print "*** sending subprocesses some data to have them unblock" mc.send_each(1) print "*** receiving results asynchronously" for i in range(NUM_PROCESSES): channel, result = queue.get(timeout=2.0) print "result", channel.gateway, result execnet-1.0.9/doc/example/test_group.txt0000644000000000000000000000662511473521746017031 0ustar rootrootManaging multiple gateways and clusters ================================================== Usings Groups for managing multiple gateways ------------------------------------------------------ Use ``execnet.Group`` to manage membership and lifetime of of multiple gateways:: >>> import execnet >>> group = execnet.Group(['popen'] * 2) >>> len(group) 2 >>> group >>> list(group) [, ] >>> 'gw0' in group and 'gw1' in group True >>> group['gw0'] == group[0] True >>> group['gw1'] == group[1] True >>> group.terminate() # exit all member gateways >>> group Assigning Gateway IDs ------------------------------------------------------ All gateways are created as part of a group and receive a per-group unique ``id`` after successful initialization. Pass an ``id=MYNAME`` part to ``group.makegateway``. Example:: >>> import execnet >>> group = execnet.Group() >>> gw = group.makegateway("popen//id=sub1") >>> assert gw.id == "sub1" >>> group['sub1'] Getting (auto) IDs before instantiation ------------------------------------------------------ Sometimes it's useful to know the gateway ID ahead of instantiating it:: >>> import execnet >>> group = execnet.Group() >>> spec = execnet.XSpec("popen") >>> group.allocate_id(spec) >>> allocated_id = spec.id >>> gw = group.makegateway(spec) >>> assert gw.id == allocated_id execnet.makegateway uses execnet.default_group ------------------------------------------------------ Each time you create a gateway with ``execnet.makegateway()`` you actually use the ``execnet.default_group``:: >>> import execnet >>> gw = execnet.makegateway() >>> gw in execnet.default_group True >>> execnet.default_group.defaultspec # used for empty makegateway() calls 'popen' Robust Termination of ssh/popen processes ----------------------------------------------- Use ``group.terminate(timeout)`` if you want to terminate member gateways and ensure that no local sub processes remain you can specify a ``timeout`` after which an attempt at killing the related process is made:: >>> import execnet >>> group = execnet.Group() >>> gw = group.makegateway("popen//id=sleeper") >>> ch = gw.remote_exec("import time ; time.sleep(2.0)") >>> group >>> group.terminate(timeout=1.0) >>> group execnet aims to provide totally robust termination so if you have left-over processes or other termination issues please :doc:`report them <../support>`. thanks! Using Groups to manage a certain type of gateway ------------------------------------------------------ Set ``group.defaultspec`` to determine the default gateway specification used by ``group.makegateway()``: >>> import execnet >>> group = execnet.Group() >>> group.defaultspec = "ssh=localhost//chdir=mytmp//nice=20" >>> gw = group.makegateway() >>> ch = gw.remote_exec(""" ... import os.path ... basename = os.path.basename(os.getcwd()) ... channel.send(basename) ... """) >>> ch.receive() 'mytmp' This way a Group object becomes kind of a Gateway factory where the factory-caller does not need to know the setup. execnet-1.0.9/doc/example/test_multi.txt0000644000000000000000000000473011473521746017022 0ustar rootrootadvanced (multi) channel communication ===================================================== MultiChannel: container for multiple channels ------------------------------------------------------ Use ``execnet.MultiChannel`` to work with multiple channels:: >>> import execnet >>> ch1 = execnet.makegateway().remote_exec("channel.send(1)") >>> ch2 = execnet.makegateway().remote_exec("channel.send(2)") >>> mch = execnet.MultiChannel([ch1, ch2]) >>> len(mch) 2 >>> mch[0] is ch1 and mch[1] is ch2 True >>> ch1 in mch and ch2 in mch True >>> sum(mch.receive_each()) 3 receive results from sub processes with a Queue ----------------------------------------------------- Use ``MultiChannel.make_receive_queue()`` to get a queue from which to obtain results:: >>> ch1 = execnet.makegateway().remote_exec("channel.send(1)") >>> ch2 = execnet.makegateway().remote_exec("channel.send(2)") >>> mch = execnet.MultiChannel([ch1, ch2]) >>> queue = mch.make_receive_queue() >>> chan1, res1 = queue.get() >>> chan2, res2 = queue.get(timeout=3) >>> res1 + res2 3 Working asynchronously/event-based with channels --------------------------------------------------- Use channel callbacks if you want to process incoming data immediately and without blocking execution:: >>> import execnet >>> gw = execnet.makegateway() >>> ch = gw.remote_exec("channel.receive() ; channel.send(42)") >>> l = [] >>> ch.setcallback(l.append) >>> ch.send(1) >>> ch.waitclose() >>> assert l == [42] Note that the callback function will be executed in the receiver thread and should not block or run for too long. robustly receive results and termination notification ----------------------------------------------------- Use ``MultiChannel.make_receive_queue(endmarker)`` to specify an object to be put to the queue when the remote side of a channel is closed. The endmarker will also be put to the Queue if the gateway is blocked in execution and is terminated/killed:: >>> group = execnet.Group(['popen'] * 3) # create three gateways >>> mch = group.remote_exec("channel.send(channel.receive()+1)") >>> queue = mch.make_receive_queue(endmarker=42) >>> mch[0].send(1) >>> chan1, res1 = queue.get() >>> res1 2 >>> group.terminate(timeout=1) # kill processes waiting on receive >>> for i in range(3): ... chan1, res1 = queue.get() ... assert res1 == 42 >>> group execnet-1.0.9/doc/example/conftest.py0000644000000000000000000000057011473521746016265 0ustar rootroot import py, sys # make execnet and example code importable cand = py.path.local(__file__).dirpath().dirpath().dirpath() if cand.join("execnet", "__init__.py").check(): if str(cand) not in sys.path: sys.path.insert(0, str(cand)) cand = py.path.local(__file__).dirpath() if str(cand) not in sys.path: sys.path.insert(0, str(cand)) pytest_plugins = ['doctest'] execnet-1.0.9/doc/example/test_debug.txt0000644000000000000000000000370211473521746016754 0ustar rootroot Debugging execnet / Wire messages =============================================================== By setting the environment variable ``EXECNET_DEBUG`` you can configure the execnet tracing mechanism: :EXECNET_DEBUG=1: write per-process trace-files to ``${TEMPROOT}/execnet-debug-PID`` :EXECNET_DEBUG=2: perform tracing to stderr (popen-gateway slaves will send this to their instantiator) Here is a simple example to see what goes on with a simple execution:: EXECNET_DEBUG=2 # or "set EXECNET_DEBUG=2" on windows python -c 'import execnet ; execnet.makegateway().remote_exec("42")' which will show PID-prefixed trace entries:: [2326] gw0 starting to receive [2326] gw0 sent [2327] creating slavegateway on [2327] gw0-slave starting to receive [2327] gw0-slave received [2327] gw0-slave execution starts[1]: '42' [2327] gw0-slave execution finished [2327] gw0-slave sent [2327] gw0-slave 1 sent channel close message [2326] gw0 received [2326] gw0 1 channel.__del__ [2326] === atexit cleanup === [2326] gw0 gateway.exit() called [2326] gw0 --> sending GATEWAY_TERMINATE [2326] gw0 sent [2326] gw0 joining receiver thread [2327] gw0-slave received [2327] gw0-slave putting None to execqueue [2327] gw0-slave io.close_read() [2327] gw0-slave leaving [2327] gw0-slave 1 channel.__del__ [2327] gw0-slave io.close_write() [2327] gw0-slave slavegateway.serve finished [2327] gw0-slave gateway.join() called while receiverthread already finished [2326] gw0 leaving execnet-1.0.9/doc/example/svn-sync-repo.py0000644000000000000000000000705011473521746017163 0ustar rootroot#!/usr/bin/env python """ small utility for hot-syncing a svn repository through ssh. uses execnet. """ import py, execnet import sys, os def usage(): arg0 = sys.argv[0] print "%s [user@]remote-host:/repo/location localrepo [ssh-config-file]" % (arg0,) def main(args): remote = args[0] localrepo = py.path.local(args[1]) if not localrepo.check(dir=1): raise SystemExit("localrepo %s does not exist" %(localrepo,)) if len(args) ==3: configfile = args[2] else: configfile = None remote_host, path = remote.split(':', 1) print "ssh-connecting to", remote_host gw = getgateway(remote_host, configfile) local_rev = get_svn_youngest(localrepo) # local protocol # 1. client sends rev/repo -> server # 2. server checks for newer revisions and sends dumps # 3. client receives dumps, updates local repo # 4. client goes back to step 1 c = gw.remote_exec(""" import py import os remote_rev, repopath = channel.receive() while 1: rev = py.process.cmdexec('svnlook youngest "%s"' % repopath) rev = int(rev) if rev > remote_rev: revrange = (remote_rev+1, rev) dumpchannel = channel.gateway.newchannel() channel.send(revrange) channel.send(dumpchannel) f = os.popen( "svnadmin dump -q --incremental -r %s:%s %s" % (revrange[0], revrange[1], repopath), 'r') try: maxcount = dumpchannel.receive() count = maxcount while 1: s = f.read(8192) if not s: raise EOFError dumpchannel.send(s) count = count - 1 if count <= 0: ack = dumpchannel.receive() count = maxcount except EOFError: dumpchannel.close() remote_rev = rev else: # using svn-hook instead would be nice here py.std.time.sleep(30) """) c.send((local_rev, path)) print "checking revisions from %d in %s" %(local_rev, remote) while 1: revstart, revend = c.receive() dumpchannel = c.receive() print "receiving revisions", revstart, "-", revend, "replaying..." svn_load(localrepo, dumpchannel) print "current revision", revend def svn_load(repo, dumpchannel, maxcount=100): # every maxcount we will send an ACK to the other # side in order to synchronise and avoid our side # growing buffers (execnet does not control # RAM usage or receive queue sizes) dumpchannel.send(maxcount) f = os.popen("svnadmin load -q %s" %(repo, ), "w") count = maxcount for x in dumpchannel: sys.stdout.write(".") sys.stdout.flush() f.write(x) count = count - 1 if count <= 0: dumpchannel.send(maxcount) count = maxcount print >>sys.stdout f.close() def get_svn_youngest(repo): rev = py.process.cmdexec('svnlook youngest "%s"' % repo) return int(rev) def getgateway(host, configfile=None): xspec = "ssh=%s" % host if configfile is not None: xspec += "//ssh_config=%s" % configfile return execnet.makegateway(xspec) if __name__ == '__main__': if len(sys.argv) < 3: usage() raise SystemExit(1) main(sys.argv[1:]) execnet-1.0.9/doc/example/funcmultiplier.py0000644000000000000000000000052511473521746017502 0ustar rootroot import execnet def multiplier(channel, factor): while not channel.isclosed(): param = channel.receive() channel.send(param * factor) gw = execnet.makegateway() channel = gw.remote_exec(multiplier, factor=10) for i in range(5): channel.send(i) result = channel.receive() assert result == i * 10 gw.exit() execnet-1.0.9/doc/example/test_info.txt0000644000000000000000000001424211473521746016622 0ustar rootrootbasic local and remote communication ========================================= Execute source code in subprocess, communicate through a channel ------------------------------------------------------------------- You can instantiate a subprocess gateway, execute code in it and bidirectionally send messages:: >>> import execnet >>> gw = execnet.makegateway() >>> channel = gw.remote_exec("channel.send(channel.receive()+1)") >>> channel.send(1) >>> channel.receive() 2 The initiating and the remote execution happen concurrently. ``channel.receive()`` operations return when input is available. ``channel.send(data)`` operations return when the message could be delivered to the IO system. The initiating and the "other" process work use a `share-nothing model`_ and ``channel.send|receive`` are means to pass basic data messages between two processes. .. _`share-nothing model`: http://en.wikipedia.org/wiki/Shared_nothing_architecture remote-exec a function (avoiding inlined source part I) ------------------------------------------------------------------- You can send and remote execute parametrized pure functions like this: .. include:: funcmultiplier.py :literal: The ``multiplier`` function executes remotely and establishes a loop multipliying incoming data with a constant factor passed in via keyword arguments to ``remote_exec``. Notes: * unfortunately, you can not type this example interactively because ``inspect.getsource(func)`` fails for interactively defined functions. * on Python2.6 and onwards you will get an explicit error if you try to execute non-pure functions, i.e. functions that access any global state (which will not be available remotely as we have a share-nothing model between the nodes). remote-exec a module (avoiding inlined source part II) -------------------------------------------------------------- You can pass a module object to ``remote_exec`` in which case its source code will be sent. No dependencies will be transferred so the module must be self-contained or only use modules that are installed on the "other" side. Module code can detect if it is running in a remote_exec situation by checking for the special ``__name__`` attribute. .. include:: remote1.py :literal: You can now remote-execute the module like this:: >>> import execnet, remote1 >>> gw = execnet.makegateway() >>> ch = gw.remote_exec(remote1) >>> print (ch.receive()) initialization complete which will print the 'initialization complete' string. Compare current working directories ---------------------------------------- A local subprocess gateway has the same working directory as the instantiatior:: >>> import execnet, os >>> gw = execnet.makegateway() >>> ch = gw.remote_exec("import os; channel.send(os.getcwd())") >>> res = ch.receive() >>> assert res == os.getcwd() "ssh" gateways default to the login home directory. Get information from remote ssh account -------------------------------------------- Use simple execution to obtain information from remote environments:: >>> import execnet, os >>> gw = execnet.makegateway("ssh=codespeak.net") >>> channel = gw.remote_exec(""" ... import sys, os ... channel.send((sys.platform, sys.version_info, os.getpid())) ... """) >>> platform, version_info, remote_pid = channel.receive() >>> platform 'linux2' >>> version_info (2, 4, 2, 'final', 0) Use a callback instead of receive() and wait for completion ------------------------------------------------------------- Set a channel callback to immediately react on incoming data:: >>> import execnet >>> gw = execnet.makegateway() >>> channel = gw.remote_exec("for i in range(10): channel.send(i)") >>> l = [] >>> channel.setcallback(l.append, endmarker=None) >>> channel.waitclose() # waits for closing, i.e. remote exec finish >>> l [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, None] Note that the callback function will execute in the receiver thread so it should not block on IO or long to execute. Sending channels over channels ------------------------------------------------------ You can create and transfer a channel over an existing channel and use it to transfer information:: >>> import execnet >>> gw = execnet.makegateway() >>> channel = gw.remote_exec(""" ... ch1, ch2 = channel.receive() ... ch2.send("world") ... ch1.send("hello") ... """) >>> c1 = gw.newchannel() # create new channel >>> c2 = gw.newchannel() # create another channel >>> channel.send((c1, c2)) # send them over >>> c1.receive() 'hello' >>> c2.receive() 'world' a simple command loop pattern -------------------------------------------------------------- If you want the remote side to serve a number of synchronous function calls into your module you can setup a serving loop and write a local protocol. .. include:: remotecmd.py :literal: Then on the local side you can do:: >>> import execnet, remotecmd >>> gw = execnet.makegateway() >>> ch = gw.remote_exec(remotecmd) >>> ch.send('simple(10)') # execute func-call remotely >>> ch.receive() 11 Our remotecmd module starts up remote serving through the ``for item in channel`` loop which will terminate when the channel closes. It evaluates all incoming requests in the global name space and sends back the results. Instantiate gateways through sockets ----------------------------------------------------- .. _`socketserver.py`: http://bitbucket.org/hpk42/execnet/raw/80baab4140de/execnet/script/socketserver.py In cases where you do not have SSH-access to a machine you need to download a small version-independent standalone `socketserver.py`_ script to provide a remote bootstrapping-point. You do not need to install the execnet package remotely. Simply run the script like this:: python socketserver.py :8888 # bind to all IPs, port 8888 You can then instruct execnet on your local machine to bootstrap itself into the remote socket endpoint:: import execnet gw = execnet.SocketGateway("TARGET-IP:8888") That's it, you can now use the gateway object just like a popen- or ssh-based one. .. include:: test_ssh_fileserver.txt execnet-1.0.9/doc/example/test_funcmultiplier.py0000644000000000000000000000006011473521746020533 0ustar rootroot def test_function(): import funcmultiplier execnet-1.0.9/doc/example/remote1.py0000644000000000000000000000016011473521746016007 0ustar rootroot# content of a module remote1.py if __name__ == '__channelexec__': channel.send('initialization complete') execnet-1.0.9/doc/example/sysinfo.py0000644000000000000000000001114211473521746016127 0ustar rootroot""" sysinfo.py [host1] [host2] [options] obtain system info from remote machine. (c) Holger Krekel, GPLv2 or 3 """ import py import sys import execnet parser = py.std.optparse.OptionParser(usage=__doc__) parser.add_option("-f", "--sshconfig", action="store", dest="ssh_config", default=None, help="use given ssh config file, and add info all contained hosts for getting info") parser.add_option("-i", "--ignore", action="store", dest="ignores", default=None, help="ignore hosts (useful if the list of hostnames come from a file list)") def parsehosts(path): path = py.path.local(path) l = [] rex = py.std.re.compile(r'Host\s*(\S+)') for line in path.readlines(): m = rex.match(line) if m is not None: sshname, = m.groups() l.append(sshname) return l class RemoteInfo: def __init__(self, gateway): self.gw = gateway self._cache = {} def exreceive(self, execstring): if execstring not in self._cache: channel = self.gw.remote_exec(execstring) self._cache[execstring] = channel.receive() return self._cache[execstring] def getmodattr(self, modpath): module = modpath.split(".")[0] return self.exreceive(""" import %s channel.send(%s) """ %(module, modpath)) def islinux(self): return self.getmodattr('sys.platform').find("linux") != -1 def getfqdn(self): return self.exreceive(""" import socket channel.send(socket.getfqdn()) """) def getmemswap(self): if self.islinux(): return self.exreceive(""" import commands, re out = commands.getoutput("free") mem = re.search(r"Mem:\s+(\S*)", out).group(1) swap = re.search(r"Swap:\s+(\S*)", out).group(1) channel.send((mem, swap)) """) def getcpuinfo(self): if self.islinux(): return self.exreceive(""" # a hyperthreaded cpu core only counts as 1, although it # is present as 2 in /proc/cpuinfo. Counting it as 2 is # misleading because it is *by far* not as efficient as # two independent cores. cpus = {} cpuinfo = {} f = open("/proc/cpuinfo") lines = f.readlines() f.close() for line in lines + ['']: if line.strip(): key, value = line.split(":", 1) cpuinfo[key.strip()] = value.strip() else: corekey = (cpuinfo.get("physical id"), cpuinfo.get("core id")) cpus[corekey] = 1 numcpus = len(cpus) model = cpuinfo.get("model name") channel.send((numcpus, model)) """) def debug(*args): print >>sys.stderr, " ".join(map(str, args)) def error(*args): debug("ERROR", args[0] + ":", *args[1:]) def getinfo(sshname, ssh_config=None, loginfo=sys.stdout): import execnet spec = "ssh=%s" % sshname if ssh_config: spec += "ssh_config=%s" % ssh_config debug("connecting to", repr(spec)) try: gw = execnet.makegateway(spec) except IOError: error("could not get sshgatway", sshname) else: ri = RemoteInfo(gw) #print "%s info:" % sshname prefix = sshname.upper() + " " print >>loginfo, prefix, "fqdn:", ri.getfqdn() for attr in ( "sys.platform", "sys.version_info", ): loginfo.write("%s %s: " %(prefix, attr,)) loginfo.flush() value = ri.getmodattr(attr) loginfo.write(str(value)) loginfo.write("\n") loginfo.flush() memswap = ri.getmemswap() if memswap: mem,swap = memswap print >>loginfo, prefix, "Memory:", mem, "Swap:", swap cpuinfo = ri.getcpuinfo() if cpuinfo: numcpu, model = cpuinfo print >>loginfo, prefix, "number of cpus:", numcpu print >>loginfo, prefix, "cpu model", model return ri if __name__ == '__main__': options, args = parser.parse_args() hosts = list(args) ssh_config = options.ssh_config if ssh_config: hosts.extend(parsehosts(ssh_config)) ignores = options.ignores or () if ignores: ignores = ignores.split(",") for host in hosts: if host not in ignores: getinfo(host, ssh_config=ssh_config) execnet-1.0.9/doc/example/py3topy2.py0000644000000000000000000000057011473521746016151 0ustar rootroot import execnet gw = execnet.PopenGateway("python2.6") channel = gw.remote_exec(""" import numpy array = numpy.array([1,2,3]) while 1: x = channel.receive() if x is None: break array = numpy.append(array, x) channel.send(repr(array)) """) for x in range(10): channel.send(x) channel.send(None) print (channel.receive()) execnet-1.0.9/doc/example/remotecmd.py0000644000000000000000000000033411473521746016415 0ustar rootrootimport os # contents of: remotecmd.py def simple(arg): return arg + 1 def listdir(path): return os.listdir(path) if __name__ == '__channelexec__': for item in channel: channel.send(eval(item)) execnet-1.0.9/doc/_templates/0000755000000000000000000000000011760165371014563 5ustar rootrootexecnet-1.0.9/doc/_templates/layout.html0000644000000000000000000000240011473521746016765 0ustar rootroot{% extends "!layout.html" %} {% block rootrellink %} {% endblock %} {% block header %}

execnet: rapid multi-Python deployment

home |  install |  examples |  basic API |  support 
{% endblock %} {% block footer %} {{ super() }} {% endblock %} execnet-1.0.9/doc/_templates/indexsidebar.html0000644000000000000000000000144511473521746020121 0ustar rootroot

Download

{% if version.endswith('(hg)') %}

This documentation is for version {{ version }}, which is not released yet.

You can use it from the Mercurial repo or look for released versions in the Python Package Index.

{% else %}

Current: {{ version }} [Changes]

Get execnet from the Python Package Index, or install it with:

easy_install -U execnet
{% endif %}

Questions? Suggestions?

Join execnet-dev mailing list

come to #pylib on FreeNode

execnet-1.0.9/doc/_static/0000755000000000000000000000000011760165371014054 5ustar rootrootexecnet-1.0.9/doc/_static/basic1.png0000644000000000000000000005707311473521746015743 0ustar rootroot‰PNG  IHDRöÉÍÍÆ?iCCPICC Profilex­XwP”;×ÏvzïÍ¥H“…•^¤.Ò{/*u)Rwi‚€‚¢‚€4AfÃ"‚ ¢" W)""z‘"Š¢(½ˆ oô¾ßÌ7w¾¾Ì<“_NNIr’œœNŸˆˆP$ ,<’ê`j„ws÷ÀãÞFÀ ?€÷ñ£EÚÙYA–)KAïzI ëú¦#³Q¡A 'p бïv¢ã˜ÈˆHÈDÇ~A>þ'@¬@ur A| b¶À-ÜDǾ[ø GûÒeÀr…û‡€›‚XÏŸLóƒÝt»þþ4¿0ˆO€T £@ý ]Ö/‚ e9>CL ¯ ¬añ„¶U;¡ŽúÿÒhíÔ ¶ð_šÌ8¸–ø_Ú¼ÃæZ!øzh*Ê›ê,F`†76æ¥áØrXÏÞØøY±±±^ j€¡~QÔèM^8DÿW{kο%PÐ9ÐÁˆ£(!ôìNÜF¦,{X§Ø)+\©<ܼgù¥j„T…Ew‰µáMÅ;$ͤK›È´ÊiÉ×*ÈÎ*±ãv~T±U­WÔˆÑì×VÒ9ºë­ž‚~¬ÁC#&’ñéÝݦÌf$óx‹–ï­9mômCìòìï;|tbv&º8ºF¹å»ßöðœß˹OÉËÒ;È'Õ·ÔïŽy*$¬¾ß:„–^M¹ñüÀ0uš¶Å-#«|P'Žo‘`{È>Ñ1Éñ°}²uŠiªÁ£„4|:×1Ô±¹ã#ÏNÜ>Yv*=3<Ëñ´F¶PöZÎpîý3çòâóÝ Ô 9 §Š:Ï–Ç•8ž“/E–¾)»qþh¹G…b%²r êru›‹ø‹s—Ú.Ÿ¹âW£ruµïZùuÊ ÝZæÚÁº 7iõ·Xn 6TÝŽhÔiÂ5õÝ9×آܲv·ó^ö}VÉÖon?L|dÚÆÞöúqY{`‡bÇbçÝ')OÍþbûëå³Âç{»Ä»>v_î íUê{ÑÐóRóåjË«„]ë¯ï&¼Ñyóómóß±CCKïn ÓF”GfGëÆ¼W~??Þð!ö£îrâé§œÏ{&e&¿´-˜ ýFú.ò}yz`¦q¶x.e>dÁuq÷’Ú²ìŠÈîU–ŸØ5°ös}õ×êÆô¿'rŠù† fgre~ÅjÉö„C³‘›Às™O˜?WA(Ix^”,ö o.Þ )%•µ}EÆ[¶C~ÇŽ …IE¥sÄye•ÕquEHÍF­Eå]¡ºåz/ ІD#R’qåîv“qÓ s! eKS+OëP›Û“vEöêï9u8w»¼vq›pÿî±à¹º±ëÅâÍå#à+ê'á/CVPTÒÖßO 1 5³ ·¡ØFذ£ÚÒl"­¢Ì¢côcµߖÀsˆáÐÏÄoIÇ»“ï¥Ô¤I=–æ’®Lú8Ëñ¹Œ×'šO–ž:œé“etZ<dçÜÍ-:•gŸ¯P€--¼S”sv±Q‰`É̹ÎÒse´óæåbå O+K«¨Õ¦D.Ì\l¿Tt9üŠQ _Í׫®¹÷WíD]ËÍÓõä[Ú  o77žn ¸£ÛÌÝü¥åÁÝ‚{”û¦­ÛZWô=¼ú(­Íç±n»`ûRGçÍ'9O©9>S{.ð|­k¬»³çzoþ‹¤¾à—Ný¯D^3¿þ98õfämßßCÍïj‡/Œ”ŒæŽe¼Oý@ù0±ç“ýg“Ií/ _Ŧئ־}þÞ7Ýî«èÏ81Xð¶~èïÞ±½ãu\Ÿ“¿¬|‹ŸÁÍ•-ª,÷­Æ¯+Óý¿ûè1«@A6n0V:p’†:Wø`µcÀI g*²á ­‹àwü€q ˜'’@ èsà‚A<È  ô€O€B¨!D&â:¢1‹äEj!½G‘×(€R@¹¡ÒP ¨h>´:]‡þ„øb²1ϱŒX3l:ö Žg‹;ƒbb 0´022º1^f\c²gºÄŒ`ödndác‰fyêËZÅÆÂÃ6ÎîÀÞÆ¡ÎQÃ)ÁYÌÅÇ•ËÍw1O1¯o Ÿß#~{þ1š N°DHU¨K8H#R%j,:!–±¸mŸ,N+‘!©#9-U½}¯4¿t¿L®¬“œ ÜˆüåQ Æ>”âc¥2bâNoxû)©Š¨±¨õyÍ9­Eퟻ°ºiLZ|%˘¾3;» ²”¸Òõsûú±Mÿ£`>À ð€Œ€+ €ãàh&áŽH…>Ar"w#ãõÈo(yT0ê ê;ZžóN /†ŒiIJbÉØVœ(.÷žÁœ¡žQœ1‡ Ë”Äô“9žyƒ%•žj-¶>ö.Ž&N.n®Nî$ž]<ë¼øNð» È ¬ Õ g‹ÐDÝÅŒ¶ð"âlH‰UÉ©™í3Òs2K²ëò¸< ’UE3%/bìÎ3Ê7U^ª.ª k4Ã´Š´;uVtwèyëô±,Œ3vw™r™¹›WZL[é[gÛLØéÙ9¬8y8·ºÊºåy`<ãöÌí£@ßEú®ûgÖ[îÿšN¤¼9NÓŒœŠ®ŠÝ'?t¨,‰œ¬²täaZæ±= 'ÖOõdU@¯™å‰æÏ¶Ÿ=[^jxž§|¢²±:ý¢óeñ+_¯Ö_©Õ¨[¨¿ÖàÓÈÞÔÔìÙ²|ïT«ðƒŠGâm…í /žÊÿ÷ìQºÛ '²÷ü‹Î¾É~ä+þ™×ÄAµ7jo‰Ë ½cz·0<4Ò:Z>–øÞ}œøûáõÇKQŸŒ>3~î›ÌÿâñUäëÐTÉ7·ï¼ß{¦ÍάÌÞ€/ùç ‰‹;G—N/.ϯTÿpZE¯Öÿô^c[k^÷ÿÅö«aÃîÿ­|i3§`"QB)T¼ &<ÿ¯%,4 æd›æM€%8ÒÜ Ö<ðë  š8ÀæJàC¸¯-¬¹à«VšLÛíøk›˜C e‘vtYˆ=ₜ`|lS÷ûXØýƇÃCm¬ æƒôL²ñnˆé²UÔ(gˆ¥ ¾B±¤ÛexîüÇÖZ´ãþ%cKÈ#/Il\Éf‹)¬ Ã3ãÏK(ü¨0b>…-*ðá>ºÙG§Ò@$¤EXH …í@†=[òQN†T*0œT[„ßþ·ðaÓÚ¿sеS¼‚S¨a7¢ )µ]‚ˆ5ÄIâ´·¥Ïò‹d8Ú?š¶¬ûþi£¥ÑÊh5´¼ÕõÐZc» Às¯‰6Dë£u`ŸV÷TãÔ?ZIÿ¬Å;&›c ü£ñ·uØœgôæ„€ 8Ÿ0úxÿѶru¸Ú ýVâEGDɇéõÿ,‘äØHz›D‰8H  ŠÄÂ?d<‰I¦*àÍÃýðÊD¢ï?qRДýpv pHYs  šœ IDATxí] \TEÛ?(ÈEAà M-´\K+IÓ\0“L—·¼”B‰&ù ZAXÚ–„]+_  {ÒÐr)Ã.€iVX.%¤ ð)¤  ‹²‹»ºßÿœa˲À.ì²gøý–9sæòÌ3ÏüÏ3ÏÜìT*Cåååå€-r —-VŠÖ‰r€r€r€r€å…x*”””6Ë ñ6Û´´b”””â© PPPØ,(ÄÛlÓÒŠQPPPˆ§2@9@9@9`³ o³MK+F9@9@9@!žÊååå€Ír€B¼Í6-­ååå…x*”””6Ë ñ6Û´´b”””öÝdÖ7ZÝÌœ&¿Á9`gg§É­GÍW¶í×êVZ¶]÷³vZ¢®õhOºñ0"dšR* 7ˆ™r =ð’M<øÕò´—ÐÂùÎuýúuR¾sñ¨&­‚N9Ç+NäYE§Ë’og¸hŠü>B¤«“hH9`(xùîÕ«ñ~‘ÿÖÐl-<>éGüïµk×@0Iw#~ ¯%¯› ŽLà!~âéРÅó2Q#Â~yùƒd‘ßnV’&¿‘9 )Ên<öîÝò #r‘˜6Ã+T Ý ¿¤‘.Fz÷’ýA}ɯÍTœV„p€—|"öø…ƒØÃAðË <ïé˜uC<8œ»»{ǹӷ”ÆåÀ¥K—8iïl!úøÕSÐK†érp4ǯR©D/ëß¿¿éŠ£9[ ¤R)xÈ?¡YOÉ×â‰Ê@ð’§P(PU%¬EDl€NÈtSS“ƒƒ/uwøõ”uËçêG{™å·TSÈK>)—èò}$߈'ÊÔ àûÕ«WÑÙz¸ž´8ÊÆÆFGGÇ>}úp`Èþ°ãXN·æ s¡FDÂ/º:š Ô‹V¡û€0@6€éÖ5;Î\_ˆG.(€èÐßQž\.ï8k3¼m¨”ëËLM|ÄC¹ÉdúГqNˆ§Gk—š^³}‘·v(÷¬¬Ü-ŸûNììá 'öÏN*¬‹à¡3nå§¾ Å$ý\ÐNžt!C“ÈËs–>ôåkü Mj)ña‘$!„:£ AyK¡¯{thêïТ0dë^–¥>µ7>8º@+FLvÉÆ9þZäQS~N}»\½°N5¦ÉÖ™AÇ âð hIrÊ¿½<5 è8/£¼-ÏY÷|áØíëgëõÑ3J‘ígˆ² ~¡âE¾ýÍoô…xDçQžXiLª_tJ·îŽO:P±êÞ2L(ë¾y?zîÚðOW>¾bœÎf’ægˆ¥÷®‹E2.­»‹³îœ»Êå騢%µÍEƒ€¶/b¯ø'C\k¿ÆØ÷\~/^$†³³3‰ï9 LYª†J¡¡sÁß1j1]Žn #Ì«Ote0±&¯ùcãÒ)‰s_ “í§K ДG/FànÔÞ¸ c/Ç I“Ó±…ÏYñOx¯Ãz>ÀœÈä †zøÕ—w§_ ®¾¾¾ººº¬¬ì÷ß?pàÊè4mOFJR@Rr‘´¥Ðº†¥dƇF$åÊš_(ò’#Dq[DÍ\ŠÏ.!i#’’ãEHÁDñEu ½ª03” cCSòÊH`™8)4>=Oœ,ä^…&ˆ5Jm.¦Aò_$ÚTT§RIÅ ñéâ̤.#aJ^…JQ‘¤A›FQ‘™üaL²¸†+¿"7)4!ó€8á)¿ü•‘’™#dÉFˆK¹J%+IHgÇ ™Ð”"HËòâEÍqÒ9šeebR ¡0ÕEaq²HÀ:QDRaá t&dæf&„2L¨&#ÙRzÄ]¹råË/¿ŒŒŒ ¾ë®» d€4s̵á° [À°Œ»ºÜ,’ÈŸH³•  e¢CåFˆBÓ kšsf¥K´ö½-šòæ$ˆ³“X!ƒ¬$åªå_š—Ãõ Fš –+]ò¯M·4äSÎÎÕþé¯\tqnsÿŤ”qbÞªO±õ×ÑÊÄ,/ØNšT‚TºúfÛ~§]'#=ƒŽC‡Ÿú+«óÁÅ$gg§°PÀajݧÊt÷…мôP¶˜¤Ì …ÕïZÕÆ¨ £  ŠõñãÇ¡dCՆ µ[Ÿ®¡FˆÇ˜±¶¶¶²²ò¯¿þúé§Ÿ¾þúklÔŠt73Ó¡ˆ8¢_mT*Iµ yU(ƒˆlº_ïàœ(¥$mhJ!!¢ˆÅ½˜2E+§Â$6ëj’±"%,Dr™ ¼*V}ÖtšÏ*L‚„2Nª¥EÉH›Ìbj U¹ìw%“UXW–ÍJ$™ô¥dŽòf‘RÓ£¨³.¨íÄ ãÅ\bY6ÛAãÙëêØ¢9åHQ&% A&aÃ’š+«ªÉE>™àƒ”ÌD°žr.Öݜ۽{74”ž*ÙÊ»À4½½{÷êÓçùjÑjî/BÑø1bÈV;'*‘BÌJb Ä©E~X”då_-®5Dþ!¬ô¨u§j°òIäJ‡üó´À£ ñº;W ú °ºS7wLI:›mŠÁ¬GݧÚë ª(Q‚p£½¾ÙºßiÖÅÈ~Pûí·ßþòË/P¯¡d×ÕÕAáÖâõ6è ÎA†` ‚Ã0AfYÿ½=À… °ðÞ%Ï.;ü!tíÎßÖÎþùó8  pŒ+#ol`iSËŒÖG“ÊpfÊSçëOåCƒ}›«è==$” Ï?Õ°ÂAÒøéÈ„u®CÔ¤9bÛRF¸dæpŽß®#`£;ÀüÙBÀÙÊÓû(õ­3žL“£cݾMx”œnÌ$z`¢š<Ìo¦ÇÞoúJ!³±æ Ãô•2LÈ!gA•UŸ@ÒÂÔuëXS©#sýNp‰]ÿ¤`×¹*dLCEV¼cúoÙ ¦N+è™K 3˜AF ¡ã<ØÐpçÏŸâ‰'Î;—ð¯ý«J´±"ÜÜÜãÜ_|ûî»ïîØ±cÀ€úWsØÈa£]ô—˜±c‡M ‹˜3Bzï짘¸ð½Ô›|&{´'ü¦A-? +õ˘ #ˆÍމȿìÂ?xqÀHRºýð ˜÷p¹Ò!ÿíR©»sÉÔ$À gq£c`ÀÌp“Ѥpµô©†íõtt–3íõÍžlwQ÷»v+c”À[¼øz”¡Ï˜€òè *©Ç"ÏMŽÓv¶ÈoN²(1zoñëÃöBd“ç@dÛ:®ù[‚s;ÕìZ|h\x¼#b¬ŽÕÙÆ­M>Ü…óu9©r&% ›Ô „‚Õu:Uƒ(Äqä´Ìçr]eݩෛLVG=Ý–””Ðä~Aünå$U3‡0\礄÷{šqAèÞ·U<“=@+™3gÎ’%KÖ®]«çò“Ñbõã‚/å¸qãÄb1ôz=ªÄ"ݺ6¶]ùèä?ŠùÚÜÃKúÏ€¶þøØ6¹³ý}ÔâÙ,ÿ¬ nñRK*£Ô½°Z—ü·Î_¯Î¥Ÿ‹|<ÕTºö÷Ò,F£Oµ—‰ÞIßdzBÙ%¨‹_à0~5ëѱ_]ùŽc©ßj¡¼:زþ7AMåáPƒ4(”‰ž»fÕ91ÃdssªºÝI jDå½ö. “QÉCª¼(/߇a®Ì>N—<¬zÇA´šô7aÚ‡'R¹oujåÈÁ®-C ’„OüD^ãÒš~{ŒÜBÞZ¿ˆ´né® ÿ«9ÔIý¥r`œÝ<‘:&öõõ3ÈjÒÚm«7öékÜõ-äêôaºFd¨œ°ªéŒ@ å>“¯¾úªŸŸP~ÿþý>ø >9°Ý…WUZø†¤ˆÖFÅ-+”0‚¤‡†ó¨Í>I´ -±5|’ßNÖzsÃÀ†Ò}F-ÞQ0tnõdàƒa,þñhý8n%tí¯{¡üÌgZ^§}ë]ºû¦tw+:Tx‚ì„õÏ«—>Qyd×ôô%ѧSDZ÷{vq†D¶C9» d˜SG~*­Õ­m(ìýÃ(™´:ëpm}íÁmñáLèSÓ9ù5½Œšµs*Ol(®®¯.Î œ˜XɯŒâ¾l‰èŒ’µAërŠëkK7/9Ì|áÈÖ¤¸>øL(#.5¿º¾öpÖºQsã å}Ù>ÊŽs ví8X?p2X±)xiÖárä“9-<1ñª»ŽŽÞ:g£=ß@¤øn4žª3Z´hÑo¿ý6wî\²æMÜî^´´bŒš±XÀHÄLhÜìæm%jùi§»0®£¦Å`CÀŠœâJV>—M¤FÍ¥•s{…Õ$ÀÑ+òËk«ìZ:e-Œ«3Ôë§IÅíýÚí Š&7Fòã·GʇuØ7Û«ŽqÃ5±WÓßi)­>hƶðdz믴ÍÞ3—ÅDlŠX6³£íGÌŒ¤%Fºù.Ù\vM½£ƒš!Ž,Þ¹80cVe¤—‡/ Hä2%ˆ·,òg½XS¬1êc·ãÜ ¨´^r†{FƒÕšÙRfO‰ˆã¸È¡yU ø«)ÑÌa­Hi…‹É,Šd'XËO¼ÿ‚-âòQTPZG“¹3v<˜ÀDlbøçQukv}|ü iX— .Yä*7tP³û¿˜2}óÍ7÷ÜsO÷s£9´åÀøñã1<“øáN\ÛFbCX!gÅS—ö-1QbaøCÍ9hÊOˆNù·žX–{~D°HÝNœ—3ÃWݧ4Ji–x]AQïufÞUŠ$A#|¸¢Dâ’x?F«Oy¬ÐݘAwއ±J4^R(=ª³oÂB£ÙïZׯRžô:/ ;Œýd»ÖÕ`‡!v `%dßK©Št”fEŽZx¢Pš?•íf'oh`œ]tÈ¡:ÃÔWWÖÉ”ön>~Þ)[ÞwË׊y}å9©ƒ‹›·®ƒäGBœÇcϞС•Uu.žƒ½]Û¥[^_}Nʸ¸yz{8µÐ§”7Èøê*k««OOoW(-‘Màƒü€Þ|óMsN®Ê«÷}’ñkM“£Ï¨ÇÌÁl¼²¶øÀi¯Àq-sÚݯzMqá¹wñé)ζ¡+)ããã±Â²_¿® Q¿y¬g´ S¶}AKZÉO›"›äÕ•Uè.žƒý4E¯½Ø†…·" n(NuäJd{F6TŸkdúù¶TD»TÝYµ*­ã¾©¡1Ÿa‚Û³g§§'ŽÅ2Ù¾}ûº¸¸à¤&l†êôô½ 5Æ$ÖLy)kd¥nX¶0Mðš&¾ƒ'×Nðq<|ý†n |×&ÀɶT_øŽ¨ÜØR*U0ö®ˆÖ¾³Ù‚h6§ÖRm¯Y]{o.Já;¨úøã‡jN|¯?æ<8î3jìX§Ò-#ÜÆæ×*e'÷¬Ü{äÑü"âÓ¿aç6›ÃB° ïÕGö¥nx)Z¤ÄÎj%@­ä§½ŒHwѽöbÞŠ}XÚ¨`œ8AoUíRugÕª´Žû¦v†–ò|£@¼ìì¯ £â „ñ1“-…÷] ÃÁeÃŒ€9`«tù­[·nÓ¦Mæ£^¹kÅxIRáÑÔØ9³g¯Ø˜/Éœó[Q%ãà.Ùµ12ÚÒØÍù• ¯úð¶±x´ Y¹­RÉÈK³ÂÂV®dƒš#”f­[¹š ˯dçrj‘„M¸!§}œ†9µcé±êƒÕ`8Ønh‰~M‰ŠK%å=ݼ,ØÐ ,">g¹lîF03+n,C™™}ÃÿüóÏch¹aÃóq¢!u¬Û¥ti¬zÎPÂèwŠK2î¨Í1¥©Fµ<ÝΓ9P{¿bÃPÇ¢ºg¶» ¢3%Uj·ŽbjTkΦ ¢ÆÕ¬¾˜2-Hö¾jå;Ÿ8qÉ~¡óAÏ”ÉüwÏÿjʶµí@×S,Àby,Æxçwzª@ZŽñ9ÅjŒÏVš£Ñ9€õÚO>ù¤Ñ³íV†˜e²fÅ%AÌ+³ý}‡ß,dvlðx¶BrB’µu'Ö„°|…\`ÁßáSB¸Há`í8oï‰s—0‰?Ÿ(ý•a®V>Tr9@À”Ÿ7§‰F“!`8Ø®Bý7nCÍ Õ¨–YÙ£GbÞ^¿-9¦­AñÉ:¾€Ã‰ïÁ£—'·áK‰é/FY¾v¨`eú«7 BBrn Ä˹›ŠDàÒ“îö3§ÆÓgË…ÊÊã•ÿø-K™:¨G7päèþñ&â?þÐýš†Ú:(ÄÛz [Lý²³³,X`nr\gmŒÏ˜½¯›Y˜úÒ]k™”Ù#µ©’ŸÏgD;·¯_4{ä© ‰¿”V;^˳ï¸qŒÄù±ÈÈ‘óšvn9†)q‹qPäwíÚe1äPBz”â{”Ý7ra8½».ÍÎßÀµyÉ®Á#Ü`ßô57>[ÉnÐÆø c¼…W8,è•W^¡¸ou-«ÁtºU.Ñ8s "‡ ÃÞÛV:ãþóŸcÇŽ!ÔÌÊÒü}¥õäØýÚƒùź mUEÝÊšâƒÅ5ºßõx(1‘DZ@Gšû|p9npÃ]q¸Nhýúõ¸ ´Çé¢ö(Ä÷—mµ À:tCÄÔ©Sa“|@I$•¸ßtÓM?þø#NÂ"!ÐßÏœ9cÙ¬P~œ}œ[OY”2egU— ëòsEŸ²”Ê‚ídð4{öìÌÌL4f+`ìµtéR¨óšÔo3 o3MÙsdàp+\ÈçããóôÓOÃÎWSSóé§Ÿ/@ŽÁšà*a*É“5zôhèŒü£ =õGÖ…Â162•;{ö,¬«GŽÉÏÏÇN°¡½$4ÜÆ8À%Ú+V¬Àù㘯¾åõšÕ„R‘€ñX¯NüØ` KNÛp£‡”àJõPÜ1Í^S.H–Ôäa_R'«ÈKÂ]í% iŠígWÕ•% ˜ø¼YY:ÈΖT•å%ÓŒ»É¸6]S”TXFò×)¤yH#Ê”)Êpò~Œ¸DZS(ÄÏ%'P†¸D&«ÀûÐÌ’†Ÿ“¦¾ösU^ îwÆ5ð2 rNª©ÉÅêâ’:iERe–5_Ånthexë­·å5wîÜIty ¼¦OŸŽSÁѦ/¿ü2¾ÓšÑ¨ßB8±Ä¢IÜñ"‘HN:…f¡ÜX×dî”B:Ý îQ§›|Îa«…êj,i`¤=ñPWÛ¦A ì6 œaÛöíØ±c(ÀSŸaàà5’ÉX“øÀÕé++~á÷G"àzIÅáý ãƒkŒjeÊ&/aÞÚ9¾ÌìeÂQ‡N.©Ë$΃Õ>)‚èKÐóK¾Íˆ˜»ÝžùˆüaìïÚ {‘ÇÕÃߺêȈÏÔ–œOc’¤³ÙMS»ËJ¤½*g3Ì’«û÷3>3’òKŒ?Ë߉aBIø1y$³g«(s'S ­ˆ;dž¹Ú|Žæ…ymYfŒ0ír×]wif6oÞ< ÃâÅ‹ñ‹SáÐ4ååå8ªläÈ‘Ø û /rÍ$Ôo¥ †+m8’Ù9b‡ÁªÇ°°°sçνøâ‹°Æ`èöÒK/a«¤N|'Á2£ßÉ[\ãß„¤sYŸóvÉuLiFÀ¨¡a¿;. ³‡ÇT6-KYs k‡q#G461G‡KÕܘ¥I՟æÆkØ@®•Ò$Œ .º8~üŸ&ÿ”ìÙ%‡w’ÄÕg ‹ Yåð¾²ÉoÙš©ƒšssÄ„JÄßæ‹×2QùKÍqŽ ®óöDr<ÙüùóÉ$90}Ë–-'Nœ@£ã[½_kMžP¿µr S=¨¡F.YuØaöîÝ=jÔ(̼é´Ãt¿‚çÏŸ‚`M÷³ê ‡ÜAÂ:D`Í+¡bÖn“ÇÆ¯+1¡Y]²PtÖ•ª(Y(H*ªÊÅ…£ Ux–…²†š£1Œ¨ˆ5¢ð1eéäÁ1ê “QºTZ(`\@,6Éþ ÃK.gä(L…¦KŠXCMs|`l;0×”¤ÀœÃÅB΂ G"™ÌÕ`8ØnP 0à ù!C†`=77× ´F‰¬ ¦XÔÏ穹¯ÂÃùŠêCºl¨Ñ˘N!ÞÐ&±Šøšëa0AŠþŒµ1ÐÝn:ú“““aí1]þȹ®H -›ýI)¬²Æs~<Æd—h·J’,&á[hW»÷Äÿ„f+XyˆWIËÄqÎ ²KÍŠ¢t`;ë1Ùx.7/B!xˆŸÍA<ÌúˆŸÇ~Að Ç7gCRq&ü«Áð®€ýkcÆŒ¹óÎ;1C‹Ç®åÓ…TàjRYxÍo’¡¤‚!]†xzF ÛKo(; 1¯÷ÝwX€¾å{€.ÀŸ””dÚ»ýpqmÌÙÓW}Z œ©·wõèà ÇúÚZYÐþU¸0×Èkëeì4ê ,öbO…î…$|S6Ô×+í=<:Ê1{ì›nßÝÚ,¸Hí…u«V­ÂòJ\jj9yíµ×^}õUS—ÒÃùü dïZ¡HÛå3jô*jvÄÙÀõÜ]㯠¤jllÜ¿?°Ûú´iÓ²›e¯iiiéƒ>q``  ðÖ2«€¶Æ<Ê?ü€PF¡Ã;LÌb>&** =ì‰5J¶7N&æ‚x:Ýj³2•ëaÞ|óM )´õ·Þz »“>ù䬸ڱcVS˜ßÁn€Ž/ÇD_QQ‘Ír߬?üðÃXÖl,|Gm°9ö³Ï>ÃIDuuuXx Ç"³Ö’®(ÄëÅ&+Š„IÒÓÓqù`}áÂ…ÿüónL…æ^PP€¦è¨X¹höêLž<(b¶mÛfvblŒœRöBŸ2eŠÑ«Æ/¼tÑ…7±Ws®Ø „ÝŒ¬6+v3›v’Mºl~j'KócÀEöø˜Ÿ5°Ã K ;¶§=Ä9ØO±(BÅâþÃVƒAÖóᤔµkׂ«G¢µ„¾–°uëVNç7ù°Ò  liþè£{ì1à>ü3fÌ0V‰Öpœ‘Áu5×yΦµÅwÇüd0 {*…T ý»Z`[²c_¤ó:Ö­[‚ž®gk`=hb±nݺ=SÑhm9ðÅ_àK [¬pX(Ù6‚Á|/ IDAT‰B0K‡½²Ð' ±±±Xnooß]ÅÑBº˜‰8Ö…lÁ nµÉ¦2o¥`xÁ 2qŠž }¬‡Á]]KHhøúë¯q˜-¾LØC©`rk „Y 8Väûï¿ã7ÀF|&yäȧY(‡Xb>aáMDDDwÞ˜·‹™…{ †Pˆï˜EÆ|Ûóò‡ƒ^y; LíÖì–l‡éDZÈ/--íСC8ÖK*q² ŽÇ‚É•V4.éBÅõO ! qøÌã÷äÉ“ÐÜýõ×I“&Ra0Ñ?ÓÅÄ:€>//¯; oz¾‹™Ž!|Îݱ>QˆçÙØžž‘?(e8·‹˜×±Œ·ÃÀcÛx‡ï[ma£ÁáìXz¢i-¾ Ø@0tÃ7_¾[n¹åÑG Ò<6ÒBj@N¼ÉÊÊ‚§_zâMwÐÐB8ЖŒîà…ø¶ü4aHwšªS²  X‡‘ ó:ö%Y¯¦Ó*뜢áˆDf ¼ƒëÝ»7¾yx¥>–:qØGJv¢Èår,…Â÷Þ2iî˜*|›q!;޾c>ƒ³ŽãÛöÛîàÒvÙPÓ݉Ûn•ž©–†ìKJLL„šÖ3XQ)Ø‚ ˆÇÅ#p8›ÎÆ ‡…ßqN,ªfÕŸ.~á ùÌ™3çá;~á f0? UoEhu¤Rˆ7O“A/;zô(QØ ‰ëÙmÞÓMvcO å ÄÛ€ñ *<ðàýc¨š × ,[¶ ;§°ävüâ4ãÍ›7CpuL{gavSTº’\Y{ð럽ïÄßÛøÀh›ëâ»ÂekNsá¬ÿãoØi[X–ùõ0°Ã`/8†`ÔÓ–W:CÀ(M”'æà  @!xrRðc;Û€xÒŽ¨ ¶ãÁ‘…7111ø’᪉u–Xv9kÖ,¾ÅÍf‹—\.-,¬ó÷öà‰1–Ç\ëâÿ±2G¬.ØL!¦0 è5‰‡ãº¢°ãš$²†Úa4Y¤¿ßÝÝ <æ‰Å†7Ç량eÆ$*<¬4ßÉ”Æ(–Im—©ÂÉ p0Bâ ’ :N³Àq 3gÎ$!X6Öåü»•ÐÙeÃ8µº; [ùYBb…xS¸Ú64/œ ðÁ@X¡‹áL>,! v˜a‡ÁÙŠPØa‘´óÚVÁZB\]]±jž(òåys¼µT¡=: ÄC·Å+ Pl`h¢³²XÈÏã;‰€ŽƒKH°j–·ÔëL¨w`ý¾Í/G§!¾("yíëã¼qhC~êÚ•Q›$ # MHLzq‚/9"´>gC¦Ìü ^‚eÏim#.‰Y½l¶ Œ7|a&ôØ(Ä›rÀ¥ÕXž å½¢¢bŠW˜à ìß¿?`ýßÿþ7À¤•Š>v0ÄC‹'Š<1Ê ‰9¾kZN*@¡R˜°A åPh,JþûßÿB€ $£<¢ûck.4úî$ÏYé)ÚÄ„&eŠ|þœ->á(Í_rhõÁ‰&ù7lEd¨ÉŸì­ÌY9U´I"ŠIšSyÔÂ(íÈ_½aüÐ8 “œ9Vž-ÚôW¶,uù&týpÑ!а‡É°úâ¸ÉRëÖí]]íØ@Á-^¼¡E)'õtà¬2J9‰L¸^8_wk~ÆY˜”$l °d´l·Ý,—h‹pñ¼üûï¿y? 5Àzv»ýÙ³P¾(¾óœ1®h=ÀGðÝ– žÌ¯ßIíPS8ã2ðÉ­æRó‰Õ9+‹Žæÿ û¾ä·“õd5dCé> ã¦þ”þ_Ãl?V=—WHÄ Ã]EÖ€IÙ´7N …Ê}«S+GîÖŒZw¬OÝi5Ë…xëp¡sâW8èõÝiš¶c@É%X¯él`ñ oŸ!õ"Õ´zuÜ :ßvgfÒuÌ \”°Â_òúXů˜(e„)÷Ü3-F8ylûª) “;k”« >%üVIòƒ.富 'ôŒšµ˜‰<±A²e©×…ƒqQ™ “X}»c}Ò· ]ñ,â:àÒÕ`7x ¯=gíœÁòU³özuþîÍLú­­È»04H$È`‹Dä~¸ÀÕÞ5±,÷üˆàæ@Fœ—ÃÍO,Ÿ!š+€úÎDBF\àè`oï;»â@Êì)QqGh^U‚Ÿƒ%G¤îK§Ú\ºIC)(,ƒN~©*ÙëÕuŒƒ³‡·Á8§á3¶«dI•U2¥½ç`?µYÞiøì= iuUãâéëÝbŠñ›yT6¯òœÔÁÅÍG‰eÔÏ0*Ìg{ôò®œâÊÊ#»–±®ùü€ õµ¥›—±®( ¸Fq±)Ị+kËó£5\L\ÅÕõÕÅ9aCƒ+»})M{$ÓpÊÊ ဓ·¯¯·64;ùúaWb ¾7Ójïêë秉ïÍáNXúì«I+h®Uv–¬ÅÓW…‰&£°j˜kfÒ¤Lëžõ©ë¤Y2Ä3tÀÕõ†¥))¬–æš™´Z†uD¸ECQˆ×ݬ4”r€rÀ\0×ÌdK}••›ÃB6ä”#äòŸ;‚‚ƒ²þÄ~W«tâ­²Ù(Ñ””¦ä€4?C¼¯¢Eô»gÙ‰’ÿ¾ËZ'ón$ˆ7Ҁ˔‚Eó¦ Ð͆òüÕ!8æal`ä¶|V¿®Ü·9$$,5Ÿ\Õ³!2$l]){À˜²8gsÎ;6$rÃáêæ3Ç'×F"¸ÈÍGjÞ³:lõ®RR¤¼r_d`ä¾òãæ°»] ¢x¥¬ùýãÿ^Ãå[{dC$K¨X¹9§–3Þ”çl[½-?gsàXöEغ ¿¹¬O¶ñ64àÒ-ø4”rÀæ8ÐvfR^¾ËmDP¢xpJvæL·´ð «÷UûM>Pœ´ìˆœ©Íß$ŠKcîŽÞ¤† DѧÆÅ-‘¦Å ~âp=xÄž\‹« p+Hvz¼8-züüO€ÅÿìÍØ[ÍjëpŠ •iiÇëìn-âD~žÎò³GÓ‹ÏËyq¸Ïx’œ›°)Zäž…ÿù)#1lèí왲çqž<âÆOgñÎuˆûo1?= ñ60à2WÛýôÓO@Ï”””åË—ãÖoÀ=Î&´4×ÐЀ[Èqi-¾Co½õÅ)ƒ¤— àw\ùüóÏ?ôÐC?üðƒAÉm6²²î΢¸Éd¸}§®îŸºÛ’’æ¸_`Íã ¹Õž¾Î- T5^$‘뜓æß3@×ɵNZFŒÏæ——ã;â®>¾ eá@⤌ eË%ª~Ûü¿­õI+‚‰µêh¢RølmdÀõá‡4èÑG…Í×ͤž¯¿þúé§Ÿ† ÿðÛ´ nfŽ+,ÆsnÁ‚‰‰‰>ø`aa!Tûnf{ƒ$Çà …Ï6©ï¦M›ž}öÙ¤îšÕÔ>/ÞÞǪ±[È[ëÀ*ݵáÕ#‡:1òÒ¬ñQbF(d ¦„§Öí‰tuóDV1±¯¯Ÿ®vÛê}Ôð¯urm¡?s‹‡ŸsU•Í^ÎÐÂßÂ:y@ÄDýX¡ŒÃQW[ƒð.–æÄºÿµ±>éŽfôÐÖâmdÀ5iÒ¤W_}÷Offfö€9âÏ?ÿœ9sæW_}eáø®)¸^er›ö•+W4_Q¿NÀ8ƒpßáÇUï‡ÒÙ¶ÛÌLº>øL(#«gêkg­57®PÞ×IYž0j!ÄJ¾Í/IG„¨—²Jíý&' ™MÁK³—ã0ÚÔÈi቉WÝ]už\;š3®H¢v©,?¸ Ñ63ÖÙe Ü:òS)»ê¦Ù Â0¡Ï¥–ÖÖWÙ´Öÿ`öþn‹v=«Åk ¸d0a1 ;àjb\ÞNí¸fa¸Èì€Ë]÷€ µà>»jVë1àš¯Ñ2üÐJ¯ =zô‘#G¾ùæ(ª¯¼òJ\\\xx8n˜S—oÌÿçÏŸ3fLNN΄ ìô‘u9—–-[öÉ'ŸXå=@-L'Nœ8~ü8ùýñÇ1¿û›fÑ0|i>Þ°~ÿ[Äå ¢¨ ´(–‚˜Ì±Š·…’ò’XµzQRòžŒè…/-Þ³bwÑÙÇÇ/ `5t¸qÉ"`¹«Ž«B×yÉ™; çŽg#Ç$%äÇ­us°gìGÌŒ¤%Fºù.Ù\*\Ç,’dÌ¥&¢hç2†9ãè¦1c˘ØztÑõ,ÄÛÄ€‹ç4tj¸Ÿþyýúõ¯½öÚªU«0¬îׯÁ(ž%K–¬^½zÖ¬YFÉ­ç3ùè£p“íŽ;žx≞/ÝBJÄííšh?îh9räm·Ý†ßÙ³gÏŸ?Μ9šã†?˜æÿúë/ÍÀÕï:{ÍÙòêsRÆÅÍÓ›»ÑÃ{ÑvÕ¢íj†ø®Ø£ZÑü0n}¾beuU#®ùðôvUks:O®õ³ _\]§tvõðpµgb×}$¿gµx†±Õl)è'OžDÇ1b¦F_xá…›o¾™t×.ÿ&$$À d"P—©24aPP>~@g(ª†¦µäøeô7biVN<Àî¡C‡Ýü¾ûî[¸p!”thpúÌÌc7fiié‹/¾ˆO†>/^´d˜ˆ6sÍLš¨:æÍ¶eú¾:®_¿i†º„ù|= ¼ .Ì;Ûj.ÐŒ&¯o5àÒ|ÕÆ¯¬m3àââÈk[ßÍÈ"_~À¥‘‘MvÀ¥„=Î µZ®V¯Ûh¯R|ŠþùçÝwßÅÚÁýë_/½ôz8ÿÊ  +RNŸ>»A -02y°â·ß~ëmà<¾^^^ýû÷wssƒM Ú1¾à.¶îNΦ…œÿßÿýŸšWVVâ+NМ7¹à*¸Þ½{wšaÛÐÈ zf§a‚G/«¯¯/**‚™®ã^Ö6+bè7: i¡ÅCO‚仺ºöíÛ’™HZ§’oìpòðÕûŠ{o_?]•×uUòm{}Ã8¹rç­s±wõös%˪Z¿èöæXŽžùÞ{ïMœ8Q(Â%í†fŒF ±|GÅÁ(¼ø\ 2ÄP>ô|||¤y­œÀ:ìBÞÞÞ<šC¿¦ãP,5)y›#(X¶!&å•…g~ƒ¬‹·ðV0&y°¥®]»{XÒÒÒ°ävUýäÉ“õ/ö\¬;Ô?¾%Ç„ºÏÕîÝ»cbb,ŠN FµÐ˜-‰×ÊCCCá‡svÖw´+ˆ}ÂûöíÃ`#ÜÝݘ³%ge¶™IS2Å\Ö'óhñ¦ä¤eå °X¹råsÏ=÷¿ÿý + â*aÃVUŒÂ>øà-ºÉÌö´iӴ­÷h…‰ 3B<¬mÑ6À7QÏñ"~X,„Ïd×ÖÛ$''Cc°ªLMF›uñ¦.Жó§ß­ «Ù3Ï<³xñâ]»v½üòËXV ÇL@ë+ñØè¿}ûvxxj0uÅ_3„e¥ž»ï¾û?þèⱬ¥¼¼œØXx:¬Û<šãÛ‰®@öô IÝ)SîÝɦ½a9@!¾çš#Ðdárss±”X}ñÅK—.Åržã…õü£ x|||05jts<¦(± ¶r^C‡«ÊpÑÍÁdl¿¸cøo½lÄ*B<¦¬Q›4Ú`/æ´»0keÍj.ë…x3ˆG0çòòòyä²›K•>ýôSÌ’oÞ¼™ˆÇI^†W~p×îýGšý&Ï£sšÚÐ,ܸq¨Wwf\Ýt` YøZ@·=sæ –µ`Ý=€ïÎ;ïÄ*&x°¬¥Ó•ƬXæ!Á!@b±øŽ;îèÁbMXÆv{÷îÅdöB£ôsÍLš°’ c.ë…x“6kG™Ãƒõü†uH6ÖYbNk$ƒ@(è¸ñ`‚hÓ°äÌЛÏ  ¥Kö,£M²8ÄaÍ:År”’ö[?cÉ×ã?Ž©Ì$wZ8ÀÛXˆI`¾å–[°”8Žåö8IÂßßL³U@oË%T[©§NjùgÒµ%žÁn>`:À«!Ø3…ƒTÑšæš™äɳ%iWÛ§Œ[,ƒÃZçsåßÿ}p†²°ó€¨¡µßmšY¥Ú³bÁœ+Ö«jŒ>^\õvÕW‡°Ž Yy°úâ®CÅŒX¾­QÞ¶ávcÃrJë™úƒ¸Ž¸[ J³7T"aå®°¬úVÉåõGR#wq'3á‹’z%à`øÆ' ‹A±; ú8ŸûqαÁ?0dÁjij¨ütløÄrà§žz G > àwÞÁL6ŽâÈb˜bL½l‘'Òr<ØN…Ó¤ÁË!É J0MÇ’bÌ6a£/¾ß7nÄΉx  #WƒŠ¾#S-Þ<ŽeÎ8Å `;lµµµØç‚ÙW v´b$Ž Xƒì­§Þ%HJgw(J%'.ÞK–Üb¯dж.ß;ñ}Åžû¬sXžvxù:f“(ûe‘<m@8SR'sþ}óÐQ+JÿqÇIêcG~VP .©uøU|ê¶åÇ·Fh&?ºtdAÚëGßž3ÁáØ¦M§^Y‹S˜ pXZŽo ±@CÇü3®:¡•Óùc=FüPî Èú‹ ƒ59AÄëAØŠ+°q ¿„~L0`¹Á±cǬ±:zÒlà \Ï\;fZ-žUmÑuÎW=b@ ݲe Žüå—_°-j;ö7ë1sˆEr†B<㤾žLY±1<cX–{c¿+Ì/ú¦¤ñÚçF„˜–ÀÇ»´ÚeYoð¥ÇbœÃƒíßß~û-&Ìq‡ O"l•Ä\ɇO{(i-áZÕé™GÓB|ÏÔÁ&KÐõ¯šÿÌLxÐæ}“cg Çe’û£ 7Fv2I/Û¾h8“)ºpÇJ û6S§;JJq‡\ S8Äóý‰OÏñ»{ª$hŠ$&oûxo&#*#4ûC'Y®Vr†ñô„(8@Ä ë ^±ƒ1 ¬4ØéŠo?™UÖ¿‚4f{ÀT3®‰D ÁÀÝ^4Ë ÇŽb(ìXšššŠ«ÓÈÙœ–CžQbZC1«'«C´xJô¬8<‚ƺm¨›#tU0®÷'‹Â¹°E¸ÝæsëaA€(uðÓ[âóƒØÈžò_…ÜãÎd#ÎØ/d"Dw;µMŽ *\Ç/ÆÍ¡ËÆh¥A]ñP9±P&xl3 v4j‡ÀJ° ë¶æ$v‡)ÌóxœÀŠi'R<æ]pÂÌ5ÝYGkžšXO©T‹·Ð¶Â䌡 iý&GªOcÖç®yð÷ ¬Ø# «gï;p²—o‘Û»:ËWD('{ûõG/ÖÖÛ³q‰x¬8ª"ìˆÌoöLÖNŽ÷²ºLBb¡V¤„é ›¼ ¸Y(Ó­™,Ì]c±<Ö~¿±¹bòü(Ä›œÅ]+»B°ýÕÒ1†±ÇrÆ.˜hÀ„ßÿÝVéZ›4Œ!“8‡Å©&-¨ÓÌùýÛ±±±Tï”]F@!Þè,5N†ƒ ÂPŒj“ä ëý-€‚€)6À2†3mÌXaœîiyjŠùa†¢)Ä›éz‰ã\p‡†ž‘-<vua+/jdátÚy¸ûPÿ­¦¨;æ¨eÆŒÕ?O ñúóª§cb¥3ÖH`BOl‚ò pº/5Ä›€µ4KÊŽ8@!¾#î˜÷ÎlÁrr`^2ŒR:ŒtyœQ8i–L®+››”¶BÇ,œ°¾B)Ä[t›±  Q,šÊΈÌv»à–«Î"Ò÷ÊÓù[¢Ö}~êb£e-ôPnYYâ-«=´¨Á±º8“+11Q+ÜŠñ}ÂF|«èj ÓµšJÙ$kR(•W/K¥Ð¶QÐuåÕÆË—±êŠL®$'E©”òFyÓÕ«M—/]jh”_½výZSc#ö£5\‘_Sƒ·êšBvYŠ@„6)®qY5IÏüü}^¹´®‘DÓ‘yGuS)šäÈ´È›,-*¶\™\AÊT)¯ÊA>G%;^ $!„-sˆ"—rD]‘55WGýŽþï˜â;æùß~üñÇ~ø!î4?)]¢à¦›nÂZÉ'Ÿ|²K©i"½8Puð£UI‘•üèí·½ÿí±K—¥¿ýQä¬GžôÄ3ÿùò·Š+W¯+ϾõÂæ­¾)9lÊ“/¤Ü÷Ʋ°Û†úÝ'záëcµM×Yì=Y¸’™ŠIDAT{åìQ#†4Q”¸ã`mCÓé‚´Ö|w¡0ãß/}ðKµ´©©¡mæíS©jºô÷îMq³n4ùáçÞØv´ú¢Rú÷+Ÿý÷ëŸT\¸¬b®UîÏXµ4z˾â™üŸÒýoF,¼íÖaLzóg?ohÂg@ÙTõÝGñ£nyÓMƒDO¿š[\ÕÄ‘Ú/˜¾! oé’€;wîÄ€8_ÞÒimC®ò‰FóNÚ6Qh€8p¹úhÎæUO=»®ñÎG}ö/ÎZùŸÒáS—,_ܯ03,à™¯ÿ¬¹t±2ûû/¯Š;æ3í…¨±‡3^zhÚœM‡ÆÄ/»|,CôJVEÝås?¥L“åöôÛ™ë§W¤­|ù“B©½¯à§>.ÆŒâîÒëh¦ŽÌñyÐéTÊ3)ó¦­JÚ6:úµçÂïÉÿ8~|ÌÇǃ'ÞÝðý–åïì9z¶úðk‹×dÿípï°ëgö<´è/]b“6Í»£èÝç\½ã·úÆK_¯›´ø?N|mkÚÚS…é¢È­Çk/·S N*nè@zF4?nÃÁ ?üpVVÎX·й8q‹Vaƒå x1S·¿;¬Nÿ.F4ÎõzéâÇ>ùÔ–ôç§rw }häì{|yà¯û&+;FôZvʲi^N§k>û~ë¤ù.ëÝoÒÕÏæ¼rUYŸûÞ;WGG䥾0n [Èîùø»e_ÅFÌ•U=êùÈyÃ*¿¶»mæ·{9öeÏ©Örgf½ýGÃóY?.z`d?»ICû=øÌ—Í~"<ùÙ÷‹—>ÿÂ?~¼rÇ»ï=w—wŸüM«dÒYâ¢Wïóó° ¢¿òÓž»ëôòm²q+>Ýý°·kŸ|?÷{eìö®}ì´J£:8@!^S,0ù/¿ü7'@©‹‹Ã…¥Øetb+cqq16²B¿çž{pmjŠRkC$52ÌÔqwù9öé}ùï’<åUçã¹½WÜÇ¡·Š¹tT¡ò¿pEÉ7î qt´gì}îíý÷½_gG ä}†öþƹ—¬ú§Ãʉ‘ýú:÷fYã91p¶ÓgǪêåCä8ÝL… *;ʼ-?ëªÏbKÄ®ÏÒ¥?÷·wîsñç­8¦æd\awkŒøí”)Ï|™ß´ø¿›Dc9÷¾|î¤Jyíè®”Íú;ÙõaNç^e^i¸X£§'Ý{«³û 2}õ/¿_sìÛÇâ{[vë ¡¯‹+vÿý÷ãÔmp¿ëßÿkÈõE,ö¹àóƒåžûöí»óÎ;q4¼E‘gãİ·­0ŒÀÏ®¢^uåºüš¼—JåºòÙåî†õíÃá‹9V²Ý”]¤uõÓ¼’Ep†éݱ;§Rª¹R©²ïÝ Ê?ïÚÍ\·É·7£²c웚äWe2ÅU™[ÀªU÷\½óV>½˜¦&åU¯s½˜^ÌUv=¦²¡úÈõkÃׯ+íz5ß$x(Äw ‹z3Öq+œEQE‰±(8õópîÓkÞKâÞçÓ¯·¢©ê³·¶ªûØõÒ@j÷îãêä°¿òÜEÙÕýTІß‰¯ßqó'6éõkv×®šy/lÜ»û…ãBÆÜâlwM~ü»·?==d€›òäæGV•Þ2iœ"3æå€1Ÿ=à9r’“Ãù‰Ï-_6jp¬¡ù3'E\í7ȹ¦¯S}® lúöRU~½îÈ?þûýÖ‡G¤†ͨ¨ûÛ«‰>RPX<씜ºm?øž5BÏïc_Ýöå¡¿}òÒS/¾¿ù¢Ý5¦×ÙY5\—C°Ã­Çø2úíôÉßÇ >]·ûjÐ#øös¶SöW•åý|ô‱¯ty›Œoú¸ç€“O½°yß/ÇJ~ùr¥pÉæ¥—›~L]ÿ\þì§Ÿ|þÅ®[‡T-}uë±s×ÆÍ›ç)yûµ>ÿ­ä½¼âÍÎ+ûÝ6y¹§WfèYû~>rh÷šgÓ壦÷îK 5m˜­;€jñºùBC)¬ˆ½ú ps·ëÛ‡(ên 7í>¯zü•¢õr˜mì–%ïyzÂmŽÿœpswwíÓ!¨Z7×f¯>>n79ÛõfO½¹ñLýÊÍÑ;Þh²³ëø\òOOðìkͬǀ7×Dœvgμ»/´ÉÜÙs­Œ/½ì}„û2ß^¾ 6rÆGWYÒ¬óãî°?2)õàÇ“OÖ¯ÿèÏß^*Z•–þÝŒ7æÅ¥¾|9"ñ•‡6bjÁîöÐÄ÷Vpu‰Ú÷¿‹ÓŸz3üÑËlèÜ-Iónõ„fO^°Óç8´NJÁ–ÆFl§Àî )®ÅŒØ¯¨Or½¡‘(:ã°);;×~âb[ÌââŒ-£ë?. ´}U˜–Ää zÙ•+W°e ½ ëMÑËpou—z™²®æÜ•k}Üܽܜ{µ§»ëd¹´¦ª¾QÁ¸ô¿y€{oµyGÙtY®rìëèÀeÕ:ókÒ’£Ç¯ÀÊߪ¥²Ï@Áh¿¾½™&iUí¥^Žý<½ÜÉ`BgÁ\`“´¦öÒ5Ç~î^îνԥ3LS]ÍÅëv}ܼÜût–Cûy[ëH>Nñóôô„äã4ï¾}ûBòa¶Å\W§’OµxkmuJ7å@‡°÷ôìÙaŒö^ºù vkóÎÞ±_¿–ÀÖ™_;ÿí'éÇå e+ˆ¿rÅý‘×WßäÒßÙÎÑmðÍm³lÉNÓçèæ£+®£§Ï@ÍhÔ¯'(ÄëÉ(r€r 8Þ½ùƒvÞÑ`3s€N·š¹hñ”””¦ã…xÓñ–æL9@9@9`fPˆ7sÐâ)((Lǽ ó¹m]§3¹¦#šæ|ÃrR×Vb i[/TΪF«Ð}´ÒiΆ _ ¾N9K#˜‚Dðx94EfϵC5I)Ä›½9,„~}$ ý©2âù~Eº=~D.Ó˜Æât!“ÆÊÙò!Õ! uDeá,0JƒÙ9@P—H>~õ§ÇàE“¼äa¿ б±>¦?ãhL³pRG€Ï )7 ©].}ŠïeäfÚ˺ÌL›IÈK¾¡Â`ÄÉ#ÂɃûì³Ïpÿ¶áa?6¾ÊårlÏÃ>X솵ÎÒŠ˜…3È4dÌÉÉ ù°ÛYÝÝÝ9¹sÊ#œ¡ân–ºT(©ùŒ‘Êâ’t18t1ÒËÐŰ–ö2ƒk-‘Ñô¤Ý!ù{8ˆ=/ùD€Øë/ùúB<É”€¾‡ã çƒCÚÀ>¼Â†ZòH…ÏZäÉbé$’‰‚svv† ãòFŽ+€ø”'bi±µ0”0R‚ï¨#º:ꋊCsB/Ã[°!¤—uéTC)¢ñ{”¤‰!heH>Qn öpxda—;«b ¿äëñ$;¾xP€òˆð|'!<"‹TøzT.l±0„ Iƒ|ó(OD¯àxAGdઃބ_âHÝI/#:º7I/Cíe6Ðèm«€Ö‡ló_w?ÑoÐôÂ³Ê b¤ÕGòõ‚xBÉ ×A1Z„Ã+‚NáC„®-é4„r@˜ƒLCØàÊC©‡GyÄÑGÄõ/Ôì1IuСHŹÆÚdŽ@Ô‡”- âÍÞ^F' MÚOP±ç‡°$ßý‹ÖâQ0ÿy‚CÂŽóšÁwN!^ÿ 1ur€@<v@y ;zø9ùo¶ÈC2uæ`¤{»QAt"T~â‘Çw¢EQˆ·Æöí”f´5ÄŽ9d­ÇK>éˆÙi†ˆ /Ä#*räQžhx$Í‚(K8ª_èÃz§aãåw‚õxDÀ[=¥¼ƒ‚,í*‡Ú¡¦ßñˆúB…"Fyô/‚ï´—YZÛ…47¤šÅxNø,€ž@<ÂNÏâô…x䈲!U(€ÈBX*z÷†ÀA³À/Áw*|zrŸFk¬«U È¿¼C!pˆÖ^&VŽê á$ij5ä =œô2ñxK{™Õµ¯>£¹Vµ#ú ùU‡€ò@ê ñ|Ž|¿"ÂÇ‹ïˆ Ô§l‡r =ðB $ˆ;þ'@¬@ur A| b¶À-ÜDǾ[ø GûÒeÀr…û‡€›‚XÏŸLóƒÝt»þþ4¿0ˆO€T £@ý ]Ö/‚ e9>CL ¯ ¬añ„¶U;¡ŽúÿÒhíÔ ¶ð_šÌ8¸–ø_Ú¼ÃæZ!øzh*Ê›ê,F`†76æ¥áØrXÏÞØøY±±±^ j€¡~QÔèM^8DÿW{kο%PÐ9ÐÁˆ£(!ôìNÜF¦,{X§Ø)+\©<ܼgù¥j„T…Ew‰µáMÅ;$ͤK›È´ÊiÉ×*ÈÎ*±ãv~T±U­WÔˆÑì×VÒ9ºë­ž‚~¬ÁC#&’ñéÝݦÌf$óx‹–ï­9mômCìòìï;|tbv&º8ºF¹å»ßöðœß˹OÉËÒ;È'Õ·ÔïŽy*$¬¾ß:„–^M¹ñüÀ0uš¶Å-#«|P'Žo‘`{È>Ñ1Éñ°}²uŠiªÁ£„4|:×1Ô±¹ã#ÏNÜ>Yv*=3<Ëñ´F¶PöZÎpîý3çòâóÝ Ô 9 §Š:Ï–Ç•8ž“/E–¾)»qþh¹G…b%²r êru›‹ø‹s—Ú.Ÿ¹âW£ruµïZùuÊ ÝZæÚÁº 7iõ·Xn 6TÝŽhÔiÂ5õÝ9×آܲv·ó^ö}VÉÖon?L|dÚÆÞöúqY{`‡bÇbçÝ')OÍþbûëå³Âç{»Ä»>v_î íUê{ÑÐóRóåjË«„]ë¯ï&¼Ñyóómóß±CCKïn ÓF”GfGëÆ¼W~??Þð!ö£îrâé§œÏ{&e&¿´-˜ ýFú.ò}yz`¦q¶x.e>dÁuq÷’Ú²ìŠÈîU–ŸØ5°ös}õ×êÆô¿'rŠù† fgre~ÅjÉö„C³‘›Às™O˜?WA(Ix^”,ö o.Þ )%•µ}EÆ[¶C~ÇŽ …IE¥sÄye•ÕquEHÍF­Eå]¡ºåz/ ІD#R’qåîv“qÓ s! eKS+OëP›Û“vEöêï9u8w»¼vq›pÿî±à¹º±ëÅâÍå#à+ê'á/CVPTÒÖßO 1 5³ ·¡ØFذ£ÚÒl"­¢Ì¢côcµߖÀsˆáÐÏÄoIÇ»“ï¥Ô¤I=–æ’®Lú8Ëñ¹Œ×'šO–ž:œé“etZ<dçÜÍ-:•gŸ¯P€--¼S”sv±Q‰`É̹ÎÒse´óæåbå O+K«¨Õ¦D.Ì\l¿Tt9üŠQ _Í׫®¹÷WíD]ËÍÓõä[Ú  o77žn ¸£ÛÌÝü¥åÁÝ‚{”û¦­ÛZWô=¼ú(­Íç±n»`ûRGçÍ'9O©9>S{.ð|­k¬»³çzoþ‹¤¾à—Ný¯D^3¿þ98õfämßßCÍïj‡/Œ”ŒæŽe¼Oý@ù0±ç“ýg“Ií/ _Ŧئ־}þÞ7Ýî«èÏ81Xð¶~èïÞ±½ãu\Ÿ“¿¬|‹ŸÁÍ•-ª,÷­Æ¯+Óý¿ûè1«@A6n0V:p’†:Wø`µcÀI g*²á ­‹àwü€q ˜'’@ èsà‚A<È  ô€O€B¨!D&â:¢1‹äEj!½G‘×(€R@¹¡ÒP ¨h>´:]‡þ„øb²1ϱŒX3l:ö Žg‹;ƒbb 0´022º1^f\c²gºÄŒ`ödndác‰fyêËZÅÆÂÃ6ÎîÀÞÆ¡ÎQÃ)ÁYÌÅÇ•ËÍw1O1¯o Ÿß#~{þ1š N°DHU¨K8H#R%j,:!–±¸mŸ,N+‘!©#9-U½}¯4¿t¿L®¬“œ ÜˆüåQ Æ>”âc¥2bâNoxû)©Š¨±¨õyÍ9­Eퟻ°ºiLZ|%˘¾3;» ²”¸Òõsûú±Mÿ£`>À ð€Œ€+ €ãàh&áŽH…>Ar"w#ãõÈo(yT0ê ê;ZžóN /†ŒiIJbÉØVœ(.÷žÁœ¡žQœ1‡ Ë”Äô“9žyƒ%•žj-¶>ö.Ž&N.n®Nî$ž]<ë¼øNð» È ¬ Õ g‹ÐDÝÅŒ¶ð"âlH‰UÉ©™í3Òs2K²ëò¸< ’UE3%/bìÎ3Ê7U^ª.ª k4Ã´Š´;uVtwèyëô±,Œ3vw™r™¹›WZL[é[gÛLØéÙ9¬8y8·ºÊºåy`<ãöÌí£@ßEú®ûgÖ[îÿšN¤¼9NÓŒœŠ®ŠÝ'?t¨,‰œ¬²täaZæ±= 'ÖOõdU@¯™å‰æÏ¶Ÿ=[^jxž§|¢²±:ý¢óeñ+_¯Ö_©Õ¨[¨¿ÖàÓÈÞÔÔìÙ²|ïT«ðƒŠGâm…í /žÊÿ÷ìQºÛ '²÷ü‹Î¾É~ä+þ™×ÄAµ7jo‰Ë ½cz·0<4Ò:Z>–øÞ}œøûáõÇKQŸŒ>3~î›ÌÿâñUäëÐTÉ7·ï¼ß{¦ÍάÌÞ€/ùç ‰‹;G—N/.ϯTÿpZE¯Öÿô^c[k^÷ÿÅö«aÃîÿ­|i3§`"QB)T¼ &<ÿ¯%,4 æd›æM€%8ÒÜ Ö<ðë  š8ÀæJàC¸¯-¬¹à«VšLÛíøk›˜C e‘vtYˆ=ₜ`|lS÷ûXØýƇÃCm¬ æƒôL²ñnˆé²UÔ(gˆ¥ ¾B±¤ÛexîüÇÖZ´ãþ%cKÈ#/Il\Éf‹)¬ Ã3ãÏK(ü¨0b>…-*ðá>ºÙG§Ò@$¤EXH …í@†=[òQN†T*0œT[„ßþ·ðaÓÚ¿sеS¼‚S¨a7¢ )µ]‚ˆ5ÄIâ´·¥Ïò‹d8Ú?š¶¬ûþi£¥ÑÊh5´¼ÕõÐZc» Às¯‰6Dë£u`ŸV÷TãÔ?ZIÿ¬Å;&›c ü£ñ·uØœgôæ„€ 8Ÿ0úxÿѶru¸Ú ýVâEGDɇéõÿ,‘äØHz›D‰8H  ŠÄÂ?d<‰I¦*àÍÃýðÊD¢ï?qRДýpv pHYs  šœ IDATxí]|SÕ?Mš¶é.t·PVÙ›2 ²E†ˆ²ÔÇS|*®çÄ ˆë¡OÀÊPDx ‘ ²Ë†Rh¡{ï6ëýon›¦iš¦i’¦é9¿þÒsÏ=ó»÷¿ï|ç;ßá(•JB¥¥€y(À5Oµ´VJJ†`ô= 0#(ÀÌH\Z5¥}(ÌH 03—VM)@FßJ3R€̌ĥUS P€Ñw€RÀŒ 3#qiÕ”`ô 0#øf¬›V­‹åååiiiééé2™Œ£ ^^^ÞÞÞvvvºJд6L 03><ØyÞ¹sçÌ™3gÏžMJJ¨¤R©¿¿PPÀ… øÍÊÊÊÎÎ.**êÕ«×Úˆ[fì­Ú"`ž±Ej/€/aÂ>ß× /^¼øÌ3Ï888`†Ö³gOƒ¡I­Kë”\[«W×®]sðññ4h^ÙüüüÖê‰áíâsðÍ7ß`böÞ{ïUWW^æ´Ú‘ˆ¸ÿþ€€ÈW`Mšß5ˆ[Ë—/ïÛ·/”ìööö'Nœ€Ú}ñâÅîîîšÙ¬3ÎårÁÄnܸ3`À(?¬³Ÿí´W±54ti=à}ûö_-]º´[·nXÃÅÌêøñã …Âzkt°b›Æ?ü3F£+¡MH«˜ƒa²~ùòeØÁB ¦º׺{÷®fmb±ï"ôÝÓ§O‡@h3†O=õTNN”棧&%i\LV£«º}ûöÓO?%&£kh² ?-*…Â&KµÝ ?þø#äÛ¯¿þºíÁ6zÞjs0L͵Þx³^zzzjÕ{v­[º„æóÂ… ?ýôôŸ0Õ·¥¡µ­±´À`¿·råJKRê»ï¾ÓjîË/¿ÔJ±±Ë°°0õCú…ú~ïÞ½66º¶2œÖ4]0G°$&Mš=–e!+b;4°u²dZ¥-¬Ý}ðÁ°E~饗-ZƒÆVéF{n´uÖ*¢ Ž°±xk•>´J£Ø8})ôŠ`ePå·JÚm£FZ'äææâe…^.!!Ú?<9Èú,¡¿Â¶¨þýûkn¬À®^è üql@\½zuaa!2#‚-ˆ0WS{{‘¿<²f ¥¥¥üñšB‚ƒƒÇŒH]êuL9`Ö€²Xl§Âά½ª3´óˆ££#l)wìØ/Ë’%KÞ|óM›ÑšZù“5†ƒmß¾ýwÞ¹wï´Àóçχý+žÜÖ­[Ù¡bo¦»i)ÝÂìË„Ãl B…/ñÛ©S'ÍÊÙ œ4i&ªã08TÇiD' ƒÀÞ2::âl>ð‰„›FÈ,åu¤‰Í¢€iÆ.ãBŠkVÛff•ËØD¬™†N¸¤zgMš47Aà­·Þ:vì”øìW š$L –™Í­æ×IÓŒ}‚ð‚å)̾àsÜÂòîøñã<U”쀌åY¯ë꧈eb¬ ÿðØOCDiò`*AìÛÅê3Öµ±f T¿øâ‹Ô™{“¤3$úuëàw‹ÑpG‡¥<2¬é7,x1ãÆCÛž“*clÞ½C‰gþsnã#]ƾ0pnf5…††àa‰¶aªþP:=lUÀ 9ÄòîÌ™35q\Á©-TyPE`›ð£> $Àò8a1 !ÜÈ`?`ƒâà~ȉõ4¤«›F('Ù•hØÔÁ4Û"ñ€ïAñ‡JìÜ ùqæ…è+"âu¢ŒÅ¼ºNÑI,úübhˆG ÛE8ùÐʉ‡µøÀS;<èdJ½U•\z5;îç{SK2{vèìbÏhžhФ€1.¡Ì zÒ¬Hd àYØ‚^—èÝfQ ¡ yôÏ ÖN|÷³³?ª¦YC'· u~82ˆY¤AM#EDuy#˜ƒQË@ieÙ ¦–dMùm±«PüPçÑü"C\ý=D®%UeÄß|cw|aòŒí/~bC/ï.Ö9„Vé•Ù«¥Ý»wÃÂð‰'žh•ÒFMB.ž¡Ïö›Ý×§Û¤ð‘~âšuÎì6¡¬ºbçCy•E«/nY÷àGšwÛyÜŒƒ}Ó¥K—0õ‚ ä_ÿúõÚצ_5¨1ÖN|¯±!DÀp7¿Ò,ƵkýéÆ &¹P²796V%…m#PT4v(V“•Ð m‚åÒší³£è¬þ3`P Ö¯D÷ìqtߣ©¶Eª1±÷ìî“lkd-‘ Í-m––·! KJY½âÛQÏtpdÖBiPSÀ¦.l\¤´²:&>ë~VQQ™¤°¬²°TRT.ò¸ÎŽ{7±ÀYdß©£ûÀ.…v­Ð=ãÕžKK>ãÈÀOõžÞžé sì}ƒã3 ÿó¿KW³á?—%Î&Sý¢cêx]нoþ¸^óÇöáñ(›Õùì¬%ñûËÛøÞÊÑ/Ûñ쬥OVÓ˽»îf/øòÏË÷sp$Õ²ïþˆyù›ýr…€ì4KëP &ãæ{§ôš6ØŸžm«ãX`ë^—)”|÷ñQ]—ÍŠ 6è»s·Ó~ú늎ŽÓ$ë Àê˜-®ÝCÿaݱº^X`R™üF2£Ùéÿ”¾cû¯\0‚ÇåB§n’æ±<î¤l½¹of·ñaîÌ–vRÀBË+©dC/—+R±H(4Ì)*Ï/©hØušÒêø-ö@µBº gã½Vï’µuÀB“Hk<ÑïI¼x7«¸¼ê›ýWÊ$ŒË CBIEÝ~[CòÓ<–¡¬}‡ô±Lsm±ƒxˆ hýë»#(" m˜‰…i1™7§wç`G] 5ú- 0¶#\>¶sãtÚel¾ìéÝ™íòÞ»ÇΦ]u°³êß':ØvÎ[ká±ÀœE‚‡ÃÓ5Ö»T®C˜‚MÙuæN GB‹[˜§R.¡EoGæ\¨¥Ç¿Zö÷·êL¹qêÇžuÛgÕ·Ú[ÄŒ«¬–•UÕBŠÌÖÜU®-6 0i1QÔª:¸NÄŽnžmÍwU®_ËŽCø\L¥¾¾ø3â\Â:ÔÍÞe×à ÷¼õ¿Y_ó¹f|ÁZsü·múñ–Um>wôzzVqQB¯ÃJ£Ö†0c¨7ýÏXOòöÔÕ&ð%^Ÿ9p #3M23 *‹SJ2ÑŒ¤’ŠÓ‹«ÿEŒ|þáÏ"r<éÂôí/Ü/LíìbæŽX{õ&ØÕ¤¼—~iìÈÙò›¤*‹}¬–Ä6Ù1.‡»4jñ¹´k2 žßÊ3뾺°R¢B©ˆôݤÔÜÌ&‡oø L°˜{yrƒì䛆“Vï]…Þnb’™ •^wYr•xÕœ¯Y—Hcf¦À¨à‡ÿqýÕß÷'œÌ.Ï÷ûŒèÿxä”èAF· å$Ê‚õÀFWFŠ%ìM/Íþü·®·F“,-_§ìfé!Y‡GY9‘$7¼U“R•Úè-zÜ€‘þ^=ôÉç7n~he w¬äUÎßýFVy^G÷ SVø8´ßã“ȪÒK²]|Ù iE’ÒÇw½†zć÷GüËF–š_®Òšøyz8‹^˜6”d¬ÓW¹„ÌÄdoVu|{NK?¦Õré™´+EU¥ÎÇ*Y½#ˆëOYuù‡'×bCš£èø¼Íì~O‘0!O S9ún¬¸ÒMÆÁT3q‡{‡ù¼77ÚEqäíÔWueš¾»ôž( WJK«Ó‹«ÁݼˆŒ«à”'﬒W»ÅvÅ.‡×¬–¡ÙÙ`ø5PA‚å¸ÿ^ü ¼G P¯ ð8¸–TÎ(«±TP()›À𠃹Rî$pPÏߘ# H¿[„"ÁXKÐjZX-ã»àfïì[ß¡*r¢,<Ò±ŽV‘M¦”ÁŸq³ÌSL0•› ­Îk_ŽëôïGú‹E<"I!òBf-š @TÛ(J“IÅ!r÷ ‘$ÕË * ý#/% )áR‡Ú„1íõÍ‚_.äü'«‚1ATŽ›0TlçëÈqÇ*I¤Û"žrO‰4µLšžYQYqñBöª×i#ý–»Û‡×–2迈o¿õÖ¾•§¿‡·àW/|yðB¶XvYlDr+ ÃÜàÄjþž7àT· Õèÿà ¬wï~tmg÷`63ÝæöÛïä'â% w übìë8¿‚½‹ß?N}zvý•¬Û@‘“çøÐ(ÌÙ::{〇ål'õrtÿhä _œÛp6ý*PÚ×·Ûª±oöôŽPW¢?b2€ù{:Æ¥ëóê hMLr·”DYÍXK1pjêW÷Ù»v(º ¡“ÑydŠªƒ©Ï]Ëÿ­Á[Ô§›Û£Áâ1®Â0ß-§<ßÉA”W"ÓýÍÞ,“fåVÞ¼S´óVáÖ*yÑí¢miåg ÝÖÑq°áàr8°¹‘"ûN¼4h+4b’v:q!1¨cOL´RŠ3YkqðºÄ¢´~=C\;ªç]蘦 rBaÊ‹—ìïj>>{çËà~ˆC›¯õW·ÃÀòÀc߃ÑqzÈÛù÷ÁýÆü¼P¦¬ÙÐx4éü’¿V» ¥ Æ+Cµjð¨YÅ×Jg/GõðŸ>$„¤¼K ÷%3$SQ°)k£u5 ÀñŒ7Yt ¸Î¾qzˆÏ뾎ý.äõrpïáÝ)¯¼-çdçâüÀ„Àµó;Ÿ Gb©4u_òS•²š ª×‘ ‘UB½:0ŒârflRQ:›iÏÝ£lŒ¨“{Ð~ãdÇH#ƒ\[´kçÌÿ x¹²ÆK¾ßQ}7O]yð±u=¼:![Fiî½BF%ì½pp9ÐeÏlyø³KOï€ç}¤Ã0å£Sß >]Y‹Gì•®”JþN½©~ Tÿ›øöÔ¸RgÅä ñâªR6Eíï|I¨2_ÔgY°yd*ûÄY0³‰þš `a>ΡÞb­2–„Pô™)¸%¢3ÕM«Õ¤€BY½/ùɤR’ØÂø°(¬_iæ/ªJÜ“47WrS3qè?¤,2äeÅ„jL£ã:Ÿ~e;îÁCZìäTÝUð@¶{èVº‡ä©F{«%¿&:1'Š™GZ6pˆßB˶خ[+•¦mKxpçýYq…;ʤ™š ÆØÉ ”)e§¥.Ù|wx|ñn5½x-îû€Ë|…±ÄÒÃê[z"ð>áŒë—[$¤ çô®ãœT“%ÍRX\Ö¼Ôg?Vl0ÿg3cÏ(Œ?Dz˜zjhÖ-“©éÑê”þA'neœº]ÓãfõÃÈÌnÑÄj8Œ$žqÅdÊʸ¢ßñçd熋 ØïÅç‚wÉ*eùÅÕi…U÷ ª ÍÒž…»<â<†ÏËxMÇï u«³¬ÇÞÂYµP-ÄæÝûõÖ>¨!ÅM‹¨WŠLVyn³æHÃGˆ9”VWüz§ãöì±áÚNv_ö¤ð&ô&bJ€"?>pÓñ;ø«®u„¨“‚¦ItŸH‚_5MU´–æS Lš?ÃËÉT.U`ÞÁ!|%‘åUÆ6,˲D53DÈrÆ`.‡ú÷îíÓE]Ü.@p+&óÖÈÍs!Ú}=þ’] ƒÓ+vΆü¬îžIQ3„º,¾øßG>/Ûòì3®d3jqöö°gØúYÓ~ÄÕ9v2Æê!Ùžº‘ª#f[ŽiˆŒ-æP0ËbÙ’š/1–ª°ÍlMÌ/Xç}8bŒfÄŸˆœŠ£É.gÅbé ËY]TKUX;®”U¾µ{^`Wµ¸ÿLçü}Ô5¼2xá¼È‡®çܶa*¥¥&z— š54”µEÄ4oÓÔ•Ø`Ê®¨+Ñ1 Àô7©ûnÖ:Õ2 (²7øu@¦›nm-U¦”€q¡×Bž3Sþ ƒ­:¿‰5¡Š^ò¤æ°p>-ì ‘2.tX¸{æ-6àâ‹?ÍôÀZ ø8Ðyú&ָƄè6GÆLLs2V¦ÕŠf‹Å­`u¦Û ø*ûŒò Âhá Á+Ë󢄂dÈPß­ønŸnlzfiÎï·ÂÐ;¦‘òl¿ÇØô6ôk•sD¼fŠ;$s#QJÚ5iWõP ­üLquÒß™²yÂ\&ª3c^´jÜ›}}º=24ÄÍ_~¿(íÅ¿Và.M¡“hŒÕ¨ó[aÄRcÔ¸†ˆ ¯¾3qêɸ È?Àã\ܰFh.ËSàTæ{êFý‡…:OP_"Â?úÎÒLA|X@ß<‘_Yôd¯é£U+ÎZ¬ÿÒR³ó$<7"+hš"0iãÔöŠÃØ¡1ÞM¤9Úü£¦oÖ²n¬ï_»±[m"½öU¶@g]¢IþަÛQHHúÒa6©¸K 0ùa ECÛ§@S´‡}W?Ç]\gxš†·ýÖæ9‹ùÊ/Ök_çEáaRx¨F—(îKüžÒ™‹&ZÐë¶4 ö~MsÞÕÒêÚHy  Öbo²ë$w+1dk¨3ñy‚¸èV¡¶òÚH7afØò‘ð¸Â–WÒæj° ÀXÚ@u¿²+¤ä»µªd"/©¥lh<‰°#ú(Ö¦Óÿ­Lñ¸[Ò a‡ö¸«ˆ£iÝ _U¥X?Áýu»üÈO:K•,­ÎØvoJvåeã´ç¹=º#Xm\ñ6]ʬ¿¥ã·s!N݉(È„è’Éä‹?Ù|åNrKûFË«( øÍ ÛÝÅu¦ô€‡œ™a{Ú'º@.+˜­©"2…âôµ©¬ÆPSÙéý¦)à,ð‡g¨Yaûœ'ó9u–¸•„¸ïãÐÿÿUw>àÕX6›O·øÌæ)jÓ w™„¿ÜÊ[iå§aô„}_•²<™¬`÷{½„<a°·¨7\qø:ô‡á¼MÓ£éÁÙ2ÀZzÙ4ýÛd/Qwüõñ\Ô&{oÙN°ÜÂÒ«wS\œD½:*“ Uד³òbïg¸89ôìäï$bLœŠJ+²ò‹»ר;ç””KªBü¼Ø‘^ŽKêÛ%ñªjé­{ée’ªÈp7qÝB¤B¡ˆKʺ•”ìã9 [r—U\»›ê$ö÷ØÕ !1#7.)3Ø×ÈV·­ 4P ´êÞNÃ[ßúú†='ƒü¼¼ÝÿwürˆŸç·oÌ;ŠPÃÚíG×í:1v`÷âòʤŒ¼¯^™\}·óø•»)¿.ª¥²©¯|9¬W§/–0–ѥ啮߳ëó ŠËþ±|£ØÑ^ì`¿tíÎoßšß5„ñ‹p/-çƒu»Ór u íäÏLAuñâ¿ ë—’%àó~xçI'Æ›÷^óû‘)Ãû¾p+æ6Uo€$4X G57Œzf厣1l©œ‚âÁ ?úí¯ó¸ø~׃/­ª–J/ÆÞGzZvÒÏß¼7äÉeýç}P^)Áå_çn~¼ñDþ³åÏÅ+7³?ÙôDz÷²ñÑÏ~úéæý2³Ó› 3^_ýÓþÓˆ#ñÑ·¾9tþ&âÀg¯Ç–î;u•̓K´xæz<{I)Z‹Fj¹*wªø>x¹9Gù\¸uñG.ûz¨EÁ C#S² .ÞJìäîâÆ‚<§¯Å?óÈ(H}§®ÜÅå©«w‡÷ê„Èù[‰ÝÃ:B¼LÍ.èàsîF°ÏÇÃ…Ç«Ùæ á0>%;Ä×39+?#¯¸k°Ïù›LÓ§¯'ðxÜ1kö‰ì™|TDd(HC«RÀQ«Ã@Ô37x$ê»]U“®ôü"87ݯëáó±óŒ:s-~Íëó€ŠCçoyùvÒ[ „ —˜!vfæÖÑ»S`…¤ÊÁ^[uåN ¬âþøûàÄ6äíî‚Ù)À[s*¨îXÜÕ'èIDAT®_¿þúë¯'$$ôíÛ÷ûï¿wqaž ­¬¸´B$d”®b‡´ì:ÿé*´¸91k&à-ÛÆÜHHåp¹ÜÜãã {1› òõ´ØÉärÀfXÏN ¦4±`Ân7y;CS?WËÊ”…© d5‘˜˜˜`/3d¶ÄÄÄmÛ¶¥¤¤جëX#EDÍçu#!-ªWg¤ôî—œ)—×,ïÞ¸ŸÞÕ=”ái»…¸8Ú/ÿñ(•@8º_„L¦ødóa½ùÊÆ€nàNšÕêŒG1ªÈkñ©Zw‡õ OË)Ê+ªç?ØàZÍÐË–Q ªªjÈÆzèÂ/^ÿóæÍkY­V]ÚH€í=yú‰ìüâÏ~þ35§pÌÀ®åüÉÜ„«? K%¨æw½4gÂ`_OÆI?ŸÏÙ·Ëí¤Ì(¢ ÄØ=êoÈðÒœñgo&@nDÙ;ÉY?î9%©b\£hÌÇæŒ¼åϳ˜‰Ie2Ìý~;ty"Ãü;z¹~µõ´”™yE[œu‹ äÔ*N/[—ÅÅÅvvu+:è 0vã3¿°Õ`¤ˆìçyõnòW¿‚Vý“͹9;þüÁ¢Ï~:0ëíµŽáøA=4E¾ Cz`ý ‹f,)'ëÕÁMèãÁ^B†\®œ~ðìU¿ôtOÞ‹Õ£t öór­çÿpÉcc‘ÝcvA º1gÜ Ô¯{{!XâÌ7Öx{¸ôëôǪ—Xõ=[?ýµ ˆÅõ%Û%Ÿ:?jÖÐIÓöÁkúèg?yö‘èYcévÓ>‹vQÛ«¯¾ºzõjÈŠêÑîÙ³gÊ”)êK‹)"Úèp,FO?ýtèСhÎÕÕU$}òÉ'6Œ. ÓHÑbσ6dc€ä 6ôìÙ388ØÝ9ÛΆƒ1‹îÛE$dVri h.îܹs÷îÝ'žx‚Ï7æÝkns­žß˜9X«wšv íRs0(?þøã¶;„fõÜŠæ`Xyçw¼½½íííýüü²³³›5šÙú) •J7mÚôôÓO[WMÕC+bÓ“&M:vì«_º€±ŒŒ àÍTC¥õ´:víÚÖê=±X¬…ƒÅÅÅýùçŸjí-¬±Æÿþûï[Œ´! P`ݺuÿøÇ?,Ðõ4a-»ÿ¾–B âÄÍ›Úçg[áhOšKäääK—.=òÈ#Í-ئó[ À:uê$‘Ô;HSánÝj¶Ÿ´iÓγX¿~ýܹs…Bí¶M+Ò">ùä“[·nea†Õ04°5Æ5¶ýHlrtù:Ôµ+c¶Ú~‚µp0Pü‡~X´h‘££#VHzõêEÑeKoáþýû±'¥½¡ OЊ8û>ýòË/{÷î+³¥×‹ŽåᇆIÔSOµ»s<¬ˆƒ±o!ôT5oc€ÌÊÊ:~üøìÙ³ml\† Çê–››KfÈ“kCy`y8kÖ,ÿm¨Ï¦êªÕ S¯   S ÖÓꀖ¿žy†qÚ׃Õ,>>*ûvø$luÈððð€[ þqQ€é§½ÛR ¬Y³æ¹çžki-m¶¼ui1ëÞ½{NNN›¥'íx= Ào|H¥¥¥Á€»Þvsa] ›…ÂÃÃÛ ñm ß}÷Ý‚ Ú-ºð€­Èš½¡0[Â\II üŠ^»vÍ–ÕܱXÀàíµK—.̓Eó—ž'•qºë JÂï©ÈêrqÈQʉBÁÁ^1‰ˆÈ™8Ù¼Grˆ’Kt{oTà´-ÂiŽX¥”¥¬©åLœzŽÓô£e÷¾ýöÛÉ“'Û°SQCÈc]KJJš8q¢!ýnµ%7ö2·êx#ÐRFHÆê¦{—òÁ\O?ºìÀ‡ˆ˜qHh×¢ýû÷""Â8Ÿ$_¾ÿñ%AºÀA¥È¨y)°tܳZ:E) °#r]_6 °—=ù9™ÜŠ#ÝÁr°€œ™wIá~â6©¦"ö_Þv’]Ð4û ~”8aÀìv;vì8wî8·Ùk; X—5=ö–Ã/ ,===­”†7'“„ýM,é‚åùwò9u‹ÇxíäJYÌ‘¿$»·ÌL-÷Ì»¤½VF¢æ’§¨ø›L,äÒVj\ÊÉå¡$õB]BúPJÄ'Ãb, ®X±â믿>sæLHHHÃŽ´çëâ`8ìž`b³lÙ²6üT$phÿ@/6_c¦N¿7szÊ3{¤Vb†ÖPÀ³W’BâîÕ7ž¬Ò“‹DÌçÉ„â“$S/ºØlÓ-€®Í›7¿ýöÛéééÖn…ÃÒIJ¿ê/¢e›m¼µçŸ;Ì!i4ž¥-Ü©†a’î5nà‡_qyX!6ÐÂúË ˆ´~q\¦~U ;Iû/i´UA°/;Ò”Ž±~#ͽ ËK—.}ï½÷`2OÑ¥“zV0xóÅ&"œEêÔ)=¶DÇ ³Fôá¹è˜BIpr{%4õ˜€iʈ§o%• Ìð+bIÚ®zwu%x>±Óy‰ØK‰.&&K#åÑŸ¾{÷n쎽páÂåË—qšžþÌíö®u‰ˆìc€½óçÏìþÍ7ß|ñŵΥ·…Gå FM®Ž¿,K£ÑŒï¥ŠÒ#†Ä̯IèW$õKÆjQÏ·µbGL@£¦PÕFGGÃh,>¼ X2œÈ0äýõ×_a±a~üøñT«¡ý5®õ<%\8ðôéÓ'Nœ€‡)To•L£lMå$àÕ†wØ,ãõIQHÄg̘I°‡³ð‹Ý\EEEàQ¥¥¥8ªŸ9¨á]cùòåƒ BJc•Ót- X/ÀØŽâ[ ·•˜'@hܳgÏâÅ‹ccc±IÎë{÷î þþþ¸ÄËa’3á•qøðáeee8}¯vXロE²z—þt©ëåÔº+«%°ôå`uY#ð8$ o<> †lOVŠî[•`°¯pÍÍ8ÆÉP3§’?Ø} äÀ~ðqqQÄ53Óx³(`íc9{ÀÊðrÀ7ÔV˜H`e‹RSSY‡Ûuà‚v:l@ÜÉÉ / œqɦÀËlCÙÞ¬´_Ä%>äxÍ4hªV pˆB@`àc ñPäð×d(-T¤§T'Þg±©™{ `üäE–¥µ‰l>ÀSWÖ$ðmuBƘ©oe-Y²¤Ýº.TÓÁ‘¶0͑ÚF„Ç{LÔa‘0ÃÔ³p6`û&+ä@ÎA(//Ç%¸â3 ÎÕÕü¢ ˆ»êjñ"âÌÌ=Ô)DõŸˆüIÞc²»ùÒ{qÒŒdR‘,îN8£qS£Qk¥\®àÝ»-½xBš¤ÚÈÌÔVª¹$ž~U¢£N€Õåm$ô"ú7rI†  ÍÄö¤(|q}ôQŠ.=kÉ­¶0£ê:ª‚λ !so&úìd¿˜òa꥙dÐLadA¸£qœ¤L)ùßæÊ+טÛpIÞ"¼DÄNWL–d¤ZBäõת”eE)71Vþ×ö²ƒ‡˜E0MK*\)IŽ’$²(Â0NX¿g ótŽ/h%7¼üí·ß xÃåB̾ڳcІÄ1mЬ¹D|¨’`;¢. ™S}‰fb¨êR°dÄ÷$c±½ 7½’Cnpˆ ‡ô0ºà¯IšF wQœ³]üâ–®Ò²¥•ðxÃqtRHªd·/U9,ÏÐVo &`·ÊˆÀ•7¨\·|XוFbÁ‹õ³/u±…ª ¾¤3Q L'51ÇÃw§tƒ¹!ƒ@ À¡›¨˜ÌàEUR”K²&JO_(ßöá‘Ûd½ù’Ž$,ë%WÈ*žÄ‘‘ÊŠIÂN-íS Ü´ižj¹¾nCu“TsÈB˜4ÜÁÿ4)6­Ì`*­ `_b(ÿ]{Mÿ[(Àê=Ìë0ÚdN kΜ9¸­()æÞ:¯¸{Mž–(½zNröŠ$‡ì"dÚLòìL̸x’ƒå‡c™ÅÅ ¦Ìià%JÕƒ:ˆ… Ð…›3OU’xg»·_ûÿ‡ü\¯g†\„,!›pdÈ`ÛH벦·B¢)«*8'÷WïÙ\yîOišT^ȸ©HJIäDÒ{—tˆRÄ„¬Ý ÈÕCá°@IWp¢ÿùä[kדòäï~Db0cØ—D%R€BmK桬 js*Ê䎖íÙ+M!0ÏU{ňÚ5RÁëÆsV^Ý (0]|)ä“OʈS÷ðç>ZÁt¾Aƒg¸­MtNóvøÛ]šô°’8XB‘v_™‘U!cü®¡ô“òHf‰Ý}3”Ü …_xm~À:ªÌã’ÏK9÷ý½¿ú~£‹G‡šj—’äí k¸X¦ÕØ—‹€ø>«•L/­ú—-­¡‡­Ü鋇‹)äH¡'¬]d¶ã«R²BF„’]¤È‘Ñ"ÆWVª¹äbyGÂ/èößß¶GZW‰¨+ Y Û"±.Sm,ðbg­[TkûØ>ÿÓ9XÏ]!­<°þÛ#ë׸ÜJFªý ‹€®žCÖ–‘’!då{Ž +÷ºÊ/Éòë±8MÆÃ BÀ4ÜoT`½KNvWsc„Â!S'¼ñÅ—î~Ú]©J&§;‘R½31†}Ù‘a`ÚÔ³Žk 0ƒžCIAÑÞï?¿¾é‡ž‰9}¸ /.É‘“dg2n6á÷PÞšž¿ú{E¶j†¦d”õu®TÕË8Dª`,{K”$]An+ìîÛ òÃúEÎX´hÄC³íDÜt·SS4ÕΉƺ>F"~ÑN§×ÖA:3è98»»>þƲ¾c¦ì_öÈoÇ2¢*H„= !姈}Õ@YÒe sQ•‚¤+I¼„ÄÚÛIy¬{cA,år ø<%—[Êç‰<½‚Böë3lìä>QQ„žØxà0»Ãš†äi¢ zÛ\ ke»Ôõ£Þ'7eü‹œN$¤¤ã=âxï@‰””+Ir¹jG’…Ä!„ô1ÈÁ«ŸR!lj*½½ØÞÑÃÑYìíãܵ‹‡/—¯WuªöÕ¥4ŒAL¤ÁJ)@ÖÌéñ4ˆüï(Ù„”äœä€Š<"ö#ÁäÙdx$LœCÜ©Z¯™´µÅì`Í|ª°Å¨"B'2{:™M®Å“¼"p"ž.¤KÌU‡òÂà¾RkÖÌVhv[¡˜QOª9±“þp£u!ä8ˆiH„->þ¨ÈfQm²X « f-(O‹Ú>š³>jûÔ #¤01(ÀLLPë®Î¤u ­õŽŠˆmí‰éé/6­•—)<é “¦% .±þ­TW |¸\ “J=µÑ[¦ ˜)¨h%uäe‘Sû¤±1ðÃÇšÂÖìêܬ¿âîûù°—wÝ&nÍ<4n P€™ƒª­TganõÙÕ‡¶+¡É¬‡/Æx2®¬—; –ÖwÒJ=m?ÍR€Ùг–KùéUID‰½Õõæ^…JRám»-,I 0KRÛìmq8ž3e+Q€¬•O›m kÏ™Ž²•(@ÖJ„o•f©†Ãâd§³8ÉÍÚ v}ê @—.˜=jÍDb½ÏÙ6Õf’ˤ’ŠR™k~èq˜ŠÑ§Åš‰Fí¡Z °f>eûâÒ•ñ\£'À…½©|<Ù¹af¸±€ó“øîìMyiÑÇuj |¡X)ötáóêëï«–¦›ˆÔéM3 YM÷Qº%±Úº”DàGøš§ŠÕÞiîÿŠÛÌÁçœÆ›ÃbŽDÔWåfÞ¸|YÂøƒÓ S*D‘ƒ‡Ú „Ú·éµÙ(@f6ÒÒŠ)šúS Q P ´ˆË-ª–¦ `(@FßJ3R€̌ĥUS P€Ñw€RÀŒ 3#qiÕ”`ô 0#(ÀÌH\Z5¥}(ÌHÿˆ3kÂÓö-IEND®B`‚execnet-1.0.9/doc/_static/codespeak.png0000644000000000000000000002373211473521746016532 0ustar rootroot‰PNG  IHDRšrë1\gAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÀPLTE¦Y[ËÌÌWµñÍ`  M šÏï°²´ å!ÿüüЉkklFuÏggº>=ãââ¢ðÖÖ…ÝIGM]¸*FÑŽŽš¼ÓuÃôòò=¦ëª•è­­£xÂðÀßó刈îççJr—á!šé"‰Î6/4•˜œ÷õõx¦Ç¤v|a3?.T~XZ]îî¦×××ñùúS\t°ëÁÁ™<>Þëòu ||~ûøø¿¿¿þûû™ÿÿÿôŽqæ& IDATxÚbP••€ EÏ €ìì„4íì쀀—GH²òƒ:»º(«.«£=PŒ‰‰ €ÌUlímí¸Á˜Û^Hpòƒ€ PÚÒ–OÚÞVÈÈÞVKÐV› €tlõmÅØÎÖ¨ÇZ”Cƒ €@é©Rb f³ãä V>;!;;y!Yq;);^;;.^€bIK1Ù‰phÙÛZYÙÛÛ“PÌŽÍííˆA@ÜNMˆ•™ÙÞ^ÙžŸ™YΞÇÞ €Ô™€fs1ØÛ3Ë3Û3Û+1‹2ÛÐ"&;& Ï™×DÐ^”™™—Ù €€vƒÌb`cˆÁ˜ìQ@1H°ƒCÍLšiKH(0Ȭv"B ³²†§@1ð0Éh qé)ðÅl…€–Ñ ;k{[c[nn}[[`ˆØÚ ƒ-P·- Ÿ­²½Œ­®­ µ=+@Åí­mylem5mYmYEõˆAÆNd¼Ø`Ô°Øñƒ®(Ä€úMAVJÙ©™²ƒ8HšÅNÔˆ›ÑÞžQ8ÄÀËf§ ¤†ð ГÄ  `! f0‡™YÀ^ØÞ €Ô였¡ `o¯%`£Ê’á ;.;Q{Q[KMf{y{.{A~€bZ MHè@1€Â ĵׇ[@ ˆ¶ãӃƲˆŸXª«‰Cýa§ÆÅ @`uv––v"Væ@= É$Å"¥gÇhË-Å%."jggÂL“Ä Ág)Ê!m-ÍT®od­ÅhÇ¢Ëk`ÍÈhkÏ¢Â+h­ed)$bÇ @@ó m¹šäí¸m©…ÛVØÆ˜:mm¹Õ¸måM ];^€ª +ˆëëªÙÚÃQËV( %LªæÜÀx:XÅŽ €@î3Ƙ­=Ðiö@š[LÛ+ƒ µƧ­œ¼/@ÕYÊsŠˆó‰H#ÁNêGNV;I\vêvÚRv¼T'I,v†lvì@µ2,*l¬v2\\vB,–l¢6ÖZ†T§VeÎÉjÂÇÊ¥Áƒ–A‘Ä " `5q{,@€D; È0aÇÁÌ RɬÁ* Ê¬ÁÃËleh%$aL#̆´WD’œ6±1«Sˆ<33›†¡=3—>³Ì- q!Q{{Q.!!!6fPjµcfjoÄjÉk¯¡@ æ\¢&BÀ@Ó€9H^‹+ˆABB›]¹d‚I vM0KI‚ €@¹0²@Š IÂR•§$+,U±Øƒ$#€«%«8<ñYYÌ”ä³c ˆ2;PƲcPPcaQ³³ä¶Uçâ“”S¬Ä ££ £LÃ@O²Ù‰Èª‹KALã¶Å20ÙÉ‹(0é—¯ –– ÐKCike!NKkn[qN]`Ú5дÓee !;Mn[{`Ò±³”ѶF¦FÀÅ L†–Ö¶f À*Ä @ vºÜ¶À@–4·Ó´åf³*Ú'oÇakËdJ¨:ÀbDŠ €ìT€4hˆ“/ °t1±µe•4ª´µTJ³°°t–D,ú¢¦ doÇ ´ÌÖ–OJ×ÖV, bÇ ÆÊ @  |bË ”U7·µeÔ7°µe !–@w1°jÚ²Š°(ÜÀyAQÈN”9Œ¡ ¤À9 èPn‰ |Ä  s;M6hðC u(Œ’,,,fìØEXÄ¥8ù„`ñ&à«&Î&Äg'ÂÆ @À’‡G„ \ ‚ê'y;!& 2yP&0á’g3 ;N5h|‹-gµ3—bÆš80ƒ‰³Ú±É°rY Ú20x¡ÙPÍ\DÞŽKÓÈHˈÃ\hòê  `Ž«æT5...QAlYÌ €˜„@I‚X^ÊsiaQÁ "ˆOœ" ÚL¢X ÄÎæRÀLÅeÈ ÎVü ÌYÌJZК €d@)^$ü\Œ@eÊÀü ̤À œMÓP”¬L €D˜,!Á˜ƒ¥BJöÌ\ö¶Ì<öÂüÌ@=ÒB†Ä Ä'b' 9.PAÎ,o/À,Ìêl\úÊÂÌVÌ‚ÌÌFöªï¬€†±ó1Ú3ë Ú K++iPåk/$¨ Tb̬,¨LLDDAÍNËžCƒè!pð°½`§!m/*¤oè@ vò,D WUf(C‹*Ĭß9åå‘”Ù3[c@1XñB\HK|¤ÊââS³´Cò *•‰ MÔN_ÄÒNX2ˆ#˰J©ËKª‹[Ä4,œ¢`´~•æ) ÀŰš`B•ääcbå ¸iÀ\Š2y&>X¥¯¦"-áäd µµMÀE#¨jbT‘‘a2ÊÄÂnÁ¤Ù on.oÎiig.#..ÎÇ¢Ædj'$%Åf'¤Ã.Ã)%ÎÅÆ l@W[2 !{.°9lPÿhC ;V^€¶ÈD¤XDDÄuEõa¬¯wª%H@ØVâSÓòu\QˆiÜjLº0¼¼Ú2R|â,"|||¼Ä ÌÚ¢<ܶ`ÀÍm*˜u­”¹!"ÜÖŒÀ´&Å+ær€|*oÇÒ ªwÅŒ 0M¨iÝ@ p3ç…*±ÓÕÒövúÊЊ[\ƒËëò€i!9°™öævú -ÀìÆ bp3Ø™²c €@¦éÂê?>5=hàˆ¨hòH‚á6´…¨`Ð[¬¡ÒÂÍ(ª¯/Ê+ –3‘beå i¢0µæìLÀpÓÑ;£B&`Ýæ`5&N> °Eò–Ê`7"€¡Œ8ÐmN! ¶ÊvVR\ú‚ÒÊF6R6 AS Á>„ª`cѳÒ ˜²€Tp«‚ÒŸž¨¥¤ 0"õ€¦$½ý#­, Ò¤Làð‘V¶é¥[h,ÙBƒ¬EÚÆQ‹››ÛÔÞá´ä  iàÊU^Κè`[Uvhê’eWn3h j¼˜ qjZ ƒòµ€H‡½µ*¸lWaá  izà´Ç.#"¢&Ã$#ÂkÈnŠÈ8B°ú D9Y`M!Cv&!]`Ú“—·ãã  i¬Àâˆh2°FÖäâ 9C‹€ŠK!p;[ŒS R<Ìšàl´IH°ò¨¹'b© ‚’¿Ám,`–œ_eÔøØ Mvq;u`v’f}`Á£/d'*ÎÊÆÅ¥oe¥ÏÅ @@Ó„D€cC2ËTŒ0(@2£9¨}ÌDV\ Zˆ×ÐÆˆ‘‘ÑÆJ” ˜{’ú>.#€‚˜jå¨AeÙu¡Ù ÔŽÀhÕI‰0(H‰£‹ë©{ôlŒ3 XfŠ€iMhI-¬¼à7°äääcC÷¨äac ¸iv,à"ÞàRg1WgÃ0 XÆZú}ÀfR 0IJV6F€B˜ÆÊ Ê ’ð‚Ó”S f°¹Ž¦¤69ˆgªeõ‹ “L¯'X%#@!L×Næ2"*:æ`}À‚ d°<¨fRguN˜iœ|â\\â,j2Ð †„#@1˜@l7—×= ÀŽÏTFF@@¾¼$“šŸ8¸ùÆÊe 3 ܸb «?HÚgc 5&vuu` ,$$Ãn•sq±‚j `»DJ\\JèpŸZÀ¼£'¬z…t8Õ˜˜¬ØˆA˜ß¥€ÙTÜøÓC­®>H@CHÈR Ø¥¶cÊë[BM“Q‡ŠUX)ý-.ÂÂÇ'Î@ ’Râ¬êR¢šFZÖÖZÊŒ<Ð:ÝŠQ( -ÈaJ,Y-õml8 5YÙø8á@`ÓÌÁaj­ iЃš¥¶p¯G¢^0«@S¯!` SXã‚Êp…¬lµ¼Ž´ƒ#n™šjÀZÄ4†… ¸Fbc  iÀl‹Ã<VËí¹jmQ`³Ÿ…â^s5Ðð<(Ô pÝêÖ‰lÀR €äÕ°Rh@ú?àpQ‰šª1IÁ RlR¦À6°Òã—7v,\À®…(¯••#@ÝfÊ t>rA±L|\á SQVpKÑ Øhõ“4ÄA-`È©l›kèk“¡ ¡@MÓö³PÒ¸¾gç„D†$X»¨¾•(¸SÅêf1jòj€úYlàž—¬(  iÀ^J¢öó„ì$=GP²–çâµ1224v”9lŒ”aÅ–°Û§Ï«i„ÔÕ PÎEéÑš+ó0’YÔ- 1`ûÖw[RKZ …@ Ót9‘ ‰Ô”÷:54 Ã›öøLD°dš%Âm² Àà6nÔ€%©†•!£ Á¶®3b8 €˜d@õ<}‹³‚û€¬\ú†ZDµœ…‘ìÄ &¢&s0Ý{ªÀƆ• ‘JefÄX,@1è±£” Þ=‘QPàáö(¥í‰Ìðê €ä… 4¬@M5PûMŠOÃÂÞÚšhÓà*XZÊÀ†´å¨ùfÇÆeé’ÚÂZ^Âvö @@€_UjÜÄì¨qÁR-ŒÅÊÅê7²qÙ@ ðø3¨›kîU²²»‡à.°€¥2$:ÌìˆÑaFî:3³‰ÙXC»´\ú¢ÌÀ„ìré[ñX9¢<†šúÀ>¦…=?¤Û$Ǭ/ @ jRð‚ž¿¸8ìAÐð€uÜ9@sSlà®+°ÇjMÌòÜüv ¥JÌl¼öÄ Î)är/'ÜiúöÀî¦*Ü4fM`ç×è2} c…VK  ©ÖrJ n¾‘°3ê›uƒ(°ôf—ѵS€D¨ƒ¾†¦-¨êdfÔ²±Ò ]J6À¾;³¦ £ 58r¹x€ÞgfRfp—䀙&Ä"¢. îæÆ¸¬´@aÊ žŒ”f´*Ò×´â5´úŒš›@¡Œ6PáàµÑ2Å®=@AZjœàZWHXz³1‚-€åÌ€Õ:8¹BclD…ÀS@»„䀽} ûL@ƒ fJü ã ìb°ádRmvBl iNi^ .6ðl°RDtëmmô5Ø ƒ"l\ú@{¹y€m ]}+[^`º °iÀ: <æê>±Bà Œ8ÀCšÀÄ‚4c£¬D5ظx ¡ R™C“” mE:@L3ädAªX1&oé µà602ÂZÐ4s&qVD MæÈS¼ÌBDv4 ØßQ7’‡ô†Ùx00˜9ˆ3 €Ø4@µ>x8Dv\˜#‹ÌVÄ™@ ¼hKn ¯IœiÄÀÏ æ&ú*À*TÆ' t™T*²b’Q11$lÙ->1==}s,*yeddL@ÆÚ°3™ŠÛ(ƒ€°t«¥¥®ž©©©ž††%!µæì @“!Þ9 €0´è4 ¨­À¢“mhŒUSDWG† [¤¡LLØYòrA¼¹,‡$»‚‚6¯9¦V°Ã,!ÚAN ,N³唂Ö6< õèò¦œœjœ|\BH©QÇPd§ˆé³BT0Zsƒ½PVFرçca‘R6Yy-‘}!¯ ì”ÃÍ9 €L0fg ìî€#‹‡‰SJJŠh0yjkó˜€&g)›Sfò:@'1©•9Ž°Ó T N`.`+°—¬Àiá8+&ä¤ r@1Èó6Ø MC°Ç´ ™DX@^+¹{\ ûøÀ7=`¨å8ØÙ™Ô¤X¤¤€ <4vH¡é.[À爠ùMÔ……œ9“šˆ©¾Ž,°ØiÄÀk š cb’Õ¥À^$ÐËz,¦,z–¬æÚêÈyP¾dLWÝÔTEL[ÌT3Ÿ§:¢Èa&~KKV;´PSW1AÊ @ï‚3ˆ¾¹9ƒ!°lºSJ]äu5uq^F€b`æX`dM:L؇6ï8l@€ÃP“‡Wu¤—4‘Ì£iVÁÁU,r€½c]!°ª‰¤@š‘\äèé ZÃÅÁRÖ0¦=h¦UÈRn °ŸÂ ÂPÓ¬eÁ…ƒ¸p9 € …‡•¾#l„Ç^Y•Ÿ_B1¤ ž·çµ‘† iòóK#ËÚ é™Àno-,¬eäL°Ó@ƒ½P[ìÁ‰SC¡Åäv`Ã[Wì4€‚:Í4ïÉdˆK‚ÚV¶ÖÒÂf: ðd£È©äaÁ@s%ìXõ9`‹ìÍ ãMƈ”–ÔV…™ÁÍÍ#Å)5D Y0÷k@œ@§ ‰òÂl™ ]K,} y$öŠRz ‚4Ó`¨ 3VKÞÒÊËörð1#¸½‚,,|¼0gسë±êI‰˜‚ò˜ L›[2Àסqš<°a3B¥b°Óun€N±ä[¬)n€Žº ÜX{CT3ÌmØ´y¹‘aÉSak-mFkjÁÍà•ò 2ä4€;MÈRÃiB :š* ‚4¡ "j©© 3ÀŠ ”Ó€ ‡ §qÀƒ][[X %D*9 f$£!r( 攵¼(Gõ éˈ +Ë2€Æ¿ÕA -]!y B7l¿˜Œº)¢­¤Ãn‰°[2ÞRJD î6sCPZѤ­©# ÊÌÀ onΊ½¯ªŽñô«LÁm@,}sP“][ÅØ,`‘…šÀÃêRq±²°Ûk 5P_Ò…È] R Ø‚5ìÀ%¿š)¼#ƒÖw”Á.-]d@­@4o[Ç 7€&A- =N=h#—À¾ž%¨½@´&^ ¤ jk‚\ÅY«js³°@›²¸ºÀ"R|¬ØûV @ Ó¤ ý Xë[^RÒÛdƒõKA]Ap¨G@…@&,øY…ä%AŽÍÏÀñ 6>+Ž-°a ö³¹,¨k!cŠÜOv“@^Eêqk"PjÒcEt 嵡]Z` IAç‘@N H„‚RP…d¥7²«["ºw ÐÞ€(°{nÂÁZ§ ªX‘ƒ´ÂJƒ…SMÅâ°2`ÁÊ ì.A{*2¾¤b×Í¢¼Œ5P§×Dö\¸ SXw]H‡´ê>Of"à L”Rºvhýc ð2PcÔögcÓS—‚¬ò °7jou€ÜÂÆ^E§ÉÁÈìMò+€‚¤5=Ná —áŠ6x/ž˜V¤ÀÝ Ø„ÐÍ\ÛÁ´††xõ$À6ka­U-Úƒt÷Ø€)Yâ,^P‡>€ek` @§±²€s%ŽÄn§ i«€b„ Ô8€'?yC&>..Q}¨Õà¾ÐÛ< :ˆÈVwZÖðVKÑÆ‡W´sа*œ- XmÀ*€p…™9(f¸ N•-œbÚÀ®¼•¹¹¬‚)°}¢oe£Œn²­µ––5®5…¶ÒÀ ÖˆØÑúÃ× @Áº-À&Ž1)yHÊâ‚ä%P‚Œ@âOܽ³§ ˜Ó,Õ8Yø°„¨_-žï…d8p„ 4% NC@wqSêafA,ólÄ   îî[ª«I±X ¡Å#¤ÍGÓ ØçCyl ¤­©#†0@1Ȩ‹@ê(#°Í®´ô€U»9¨Ù`® MòÔNT¶ÌB¢˜ïÄ`¢Ë%Î"‚Q˜C«S`E]]®À Y 4WM‹$ÏÏ,¤aˆ®¨ôJ˜ *?p \®‰séÊñC‡Ò•0[YÛ¤±²ª°Y¦$',§ªª*g¦l‹Y¦›†&†^€7%Ñ7{€‘1+LfšÐi>!;ffy+äkØ ¼*­g CvpyŠ:® ,¿0F—¹DyŒÀ³]À$,íyŒPfd@ÛzØØÀslŒ]7©1HÕ¥^ÎÌÌYs.* P2†è¶äEš—j•5² p»mí%/'F³š•M”G4‡È*j(ˆQl€æ ¹ô9Œ9¬tA“ÌFJw‰Zq0‹iiAFÐþB+#-Ð𜭖‘¦<Èq² Äƪ÷(H+›¨¡5@ u+äÑfsm5Œ¦)+›#·½1?Ô04 " M‹¥… Æt+,ÓØšñÝaÇ%м†2/ŒJ%f!héa v—(‡=@1¨˜ÚÀ—Œ¼ne¡NW]ÆË¶™Ã2/*ŒrJà—ÒÉTpúEX˜ö•  ßÀ0M›)!§A6 £€%›.PJ”`¸€^y €€ÙØž9: ÌjØ\fõ¯µ‘¦¾«8!«BC…d—¹™4(fÑhñx‘ £4,»€›p\–ÐÅë`Yò¨‚ t?#¤ èø+hA<¸ïì ¨¡­=¤ÁËE3U9eF`cOÃÒ€fÖ¶¨YÑŽ ºd˜ÞAu-°i$ö4T@k@‰U”ƒžg@k!˜Ía‰ €`"!Q)p#ØãD 3svv`y¦i‰?a,EÁåhu;°mÉi+Á0 ‹x M åƒzŠ´äÒà1Ò‚†Ø%à™[3 6M°6 °j€‚÷ÞA£¨Àޤs]ß v'°¤ååЂUv`Ïé OÀÉ‚s³®¡´–² 2¸¦ÅÈ fy~Uh²”{KÓØ^œÖ€:}^P••ÞFÆöÜZ¶Œ¼ ] ¯ÒÀ‚ ´*¢g¬6e9$ 3…À„ ­EŒx-A“*˜É $d‰ZjÚ rX‰j°Ú a)mAIÖ0€}¡cl80 ¬Rmíá4hÇ 4¿î}òg” 6 a…€4°KÁcÅ«*3‘€((ÜŠ&x¡®ÌÈ¡ T *`Yí +E€ÑjTÁ/ èCפ2‚ÚáZŒ áx[{€‚9ÍÜ´HM°l€Ùš²Õ’6€`ÃM £xÜ6š@/éój2*kqc1M£z ¨Ó@&q )XG½"°2"Ðv—¬VÔlÄiš êâ\B¬,œRºXœÆÆEÐiö ‡¥=H ÓÀ={И‡%‹¸Å«))©Åš¾&Áà0–eÆÞŒ&ƒŽ¾A`EDhØrè²Q°ÓJ×›Sfd´¦¢Ó ®¼EœâHêIEND®B`‚execnet-1.0.9/doc/_static/execnet.png0000644000000000000000000010761611473521746016233 0ustar rootroot‰PNG  IHDRr¹¸¾º?iCCPICC Profilex­XwP”;×ÏvzïÍ¥H“…•^¤.Ò{/*u)Rwi‚€‚¢‚€4AfÃ"‚ ¢" W)""z‘"Š¢(½ˆ oô¾ßÌ7w¾¾Ì<“_NNIr’œœNŸˆˆP$ ,<’ê`j„ws÷ÀãÞFÀ ?€÷ñ£EÚÙYA–)KAïzI ëú¦#³Q¡A 'p бïv¢ã˜ÈˆHÈDÇ~A>þ'@¬@ur A| b¶À-ÜDǾ[ø GûÒeÀr…û‡€›‚XÏŸLóƒÝt»þþ4¿0ˆO€T £@ý ]Ö/‚ e9>CL ¯ ¬añ„¶U;¡ŽúÿÒhíÔ ¶ð_šÌ8¸–ø_Ú¼ÃæZ!øzh*Ê›ê,F`†76æ¥áØrXÏÞØøY±±±^ j€¡~QÔèM^8DÿW{kο%PÐ9ÐÁˆ£(!ôìNÜF¦,{X§Ø)+\©<ܼgù¥j„T…Ew‰µáMÅ;$ͤK›È´ÊiÉ×*ÈÎ*±ãv~T±U­WÔˆÑì×VÒ9ºë­ž‚~¬ÁC#&’ñéÝݦÌf$óx‹–ï­9mômCìòìï;|tbv&º8ºF¹å»ßöðœß˹OÉËÒ;È'Õ·ÔïŽy*$¬¾ß:„–^M¹ñüÀ0uš¶Å-#«|P'Žo‘`{È>Ñ1Éñ°}²uŠiªÁ£„4|:×1Ô±¹ã#ÏNÜ>Yv*=3<Ëñ´F¶PöZÎpîý3çòâóÝ Ô 9 §Š:Ï–Ç•8ž“/E–¾)»qþh¹G…b%²r êru›‹ø‹s—Ú.Ÿ¹âW£ruµïZùuÊ ÝZæÚÁº 7iõ·Xn 6TÝŽhÔiÂ5õÝ9×آܲv·ó^ö}VÉÖon?L|dÚÆÞöúqY{`‡bÇbçÝ')OÍþbûëå³Âç{»Ä»>v_î íUê{ÑÐóRóåjË«„]ë¯ï&¼Ñyóómóß±CCKïn ÓF”GfGëÆ¼W~??Þð!ö£îrâé§œÏ{&e&¿´-˜ ýFú.ò}yz`¦q¶x.e>dÁuq÷’Ú²ìŠÈîU–ŸØ5°ös}õ×êÆô¿'rŠù† fgre~ÅjÉö„C³‘›Às™O˜?WA(Ix^”,ö o.Þ )%•µ}EÆ[¶C~ÇŽ …IE¥sÄye•ÕquEHÍF­Eå]¡ºåz/ ІD#R’qåîv“qÓ s! eKS+OëP›Û“vEöêï9u8w»¼vq›pÿî±à¹º±ëÅâÍå#à+ê'á/CVPTÒÖßO 1 5³ ·¡ØFذ£ÚÒl"­¢Ì¢côcµߖÀsˆáÐÏÄoIÇ»“ï¥Ô¤I=–æ’®Lú8Ëñ¹Œ×'šO–ž:œé“etZ<dçÜÍ-:•gŸ¯P€--¼S”sv±Q‰`É̹ÎÒse´óæåbå O+K«¨Õ¦D.Ì\l¿Tt9üŠQ _Í׫®¹÷WíD]ËÍÓõä[Ú  o77žn ¸£ÛÌÝü¥åÁÝ‚{”û¦­ÛZWô=¼ú(­Íç±n»`ûRGçÍ'9O©9>S{.ð|­k¬»³çzoþ‹¤¾à—Ný¯D^3¿þ98õfämßßCÍïj‡/Œ”ŒæŽe¼Oý@ù0±ç“ýg“Ií/ _Ŧئ־}þÞ7Ýî«èÏ81Xð¶~èïÞ±½ãu\Ÿ“¿¬|‹ŸÁÍ•-ª,÷­Æ¯+Óý¿ûè1«@A6n0V:p’†:Wø`µcÀI g*²á ­‹àwü€q ˜'’@ èsà‚A<È  ô€O€B¨!D&â:¢1‹äEj!½G‘×(€R@¹¡ÒP ¨h>´:]‡þ„øb²1ϱŒX3l:ö Žg‹;ƒbb 0´022º1^f\c²gºÄŒ`ödndác‰fyêËZÅÆÂÃ6ÎîÀÞÆ¡ÎQÃ)ÁYÌÅÇ•ËÍw1O1¯o Ÿß#~{þ1š N°DHU¨K8H#R%j,:!–±¸mŸ,N+‘!©#9-U½}¯4¿t¿L®¬“œ ÜˆüåQ Æ>”âc¥2bâNoxû)©Š¨±¨õyÍ9­Eퟻ°ºiLZ|%˘¾3;» ²”¸Òõsûú±Mÿ£`>À ð€Œ€+ €ãàh&áŽH…>Ar"w#ãõÈo(yT0ê ê;ZžóN /†ŒiIJbÉØVœ(.÷žÁœ¡žQœ1‡ Ë”Äô“9žyƒ%•žj-¶>ö.Ž&N.n®Nî$ž]<ë¼øNð» È ¬ Õ g‹ÐDÝÅŒ¶ð"âlH‰UÉ©™í3Òs2K²ëò¸< ’UE3%/bìÎ3Ê7U^ª.ª k4Ã´Š´;uVtwèyëô±,Œ3vw™r™¹›WZL[é[gÛLØéÙ9¬8y8·ºÊºåy`<ãöÌí£@ßEú®ûgÖ[îÿšN¤¼9NÓŒœŠ®ŠÝ'?t¨,‰œ¬²täaZæ±= 'ÖOõdU@¯™å‰æÏ¶Ÿ=[^jxž§|¢²±:ý¢óeñ+_¯Ö_©Õ¨[¨¿ÖàÓÈÞÔÔìÙ²|ïT«ðƒŠGâm…í /žÊÿ÷ìQºÛ '²÷ü‹Î¾É~ä+þ™×ÄAµ7jo‰Ë ½cz·0<4Ò:Z>–øÞ}œøûáõÇKQŸŒ>3~î›ÌÿâñUäëÐTÉ7·ï¼ß{¦ÍάÌÞ€/ùç ‰‹;G—N/.ϯTÿpZE¯Öÿô^c[k^÷ÿÅö«aÃîÿ­|i3§`"QB)T¼ &<ÿ¯%,4 æd›æM€%8ÒÜ Ö<ðë  š8ÀæJàC¸¯-¬¹à«VšLÛíøk›˜C e‘vtYˆ=ₜ`|lS÷ûXØýƇÃCm¬ æƒôL²ñnˆé²UÔ(gˆ¥ ¾B±¤ÛexîüÇÖZ´ãþ%cKÈ#/Il\Éf‹)¬ Ã3ãÏK(ü¨0b>…-*ðá>ºÙG§Ò@$¤EXH …í@†=[òQN†T*0œT[„ßþ·ðaÓÚ¿sеS¼‚S¨a7¢ )µ]‚ˆ5ÄIâ´·¥Ïò‹d8Ú?š¶¬ûþi£¥ÑÊh5´¼ÕõÐZc» Às¯‰6Dë£u`ŸV÷TãÔ?ZIÿ¬Å;&›c ü£ñ·uØœgôæ„€ 8Ÿ0úxÿѶru¸Ú ýVâEGDɇéõÿ,‘äØHz›D‰8H  ŠÄÂ?d<‰I¦*àÍÃýðÊD¢ï?qRДýpv pHYs  šœ IDATxì}|Õµ÷™í½ïJZõ.Y’U,˽7À6Æ@$$ôž—^x!¼$ï%/„—F $š ÆÆ¸WYrQï½lï}§|gv¥µ$ËØÆ´ä›û[˳3wΜûßÝsî=íb à ®qppppL#€Opÿspppp°pŠûppppÌB€S ³ààÞpppppŠûppppÌB€S ³ààÞpppppŠûppppÌB€S ³ààÞpppppŠûppppÌB€S ³ààÞppppð®A|x„fhš¤’=1„âó¸'á …Œ@La„4P<<2Ž\w$jSz½ò½Y$òN= CLŒÇsÊu$Â$!¯*ƧR„á ÄR*‰ó„$ƒÅH:D2d,JÆ"2Œ#FHÓ2š¾5Ká¸]®õó¤â¨/#èÆžÏ@NªÕ1¡¬Ç1Kñ …Àq„½ëx¾Srt88þmÀ®Xcä÷Ù|>ÜjG §q„u º»^×–VMjŠtr¢nòÂò³{ÍýˆÇ£qgoYi#ž†| x¹ž ¨œ¦1èˆãÔ4AFNtf÷&<ÖÜx¤ùÔá¨4ÓÌØÕLîiDò0fxr´AÞ±ØË¯üx¬¯0I+?¥©;×h<{B|ꥡhéPy†ÁdâÃÕ•¹žïWV 1·—rX|—‰$Ñ@‰IФcèüYËàÙ…;÷g®±lÀ–6=]?ÜtéËðòS\¿´Q‘Ïœ;¾À5³ìy{Âj¢eÓÝ~¬x÷#®!P$`Ì«í©¸áà‰VÙ‘g³G»¼ EÅæW,—yøeO "í48rcNyq‹¹ÌŒ9ÆWßz¼tóYÒ~¦•l!&;ó¬ýÆÀX±Ï¡eÂ:„ XÂ….KxîœD z/¬ ÿþT…£§æ†¿­0¤£ˆKk8×8D¾~ðÏo ‰­MÏ Ì\‚Ü{w++†äB¤ùœ 1‰@+ JDRQoaß^^ÈѸâ«m;lÊ ×Á‡6Òó¯tÆ[?»;–£êï/s ó:àÒž@ÿUIVOþÚÞó'Š<£bšÄqáÀÍÛKeÇQfm«b(œs¸zÛè „2‡ÏzÓWR¦²Ók>‡kc}Y [û\ñæ¿)ûfºúMa碈ßÀ„’štURx_=ð Ð(;ÆN“ùeGø7]U\Ùѱƒ¢ ¯¬kÜö´!ÆMS pC€C€Cà}@à*Ãå¹Î_ëfDÝ>q–lúËY•Á–¹òÕeŒ"b]9ÙâòR‰ïZ³å]}ߣK#Äü«ö‘po¨í4’¯ë‘©ÝRÛW·ìõìuþçU£§j£>ëÇZ !>B ýûŠn škGõµ6 Š:Å´(îÝ_éŸ,…tˆ6€1ÐðèK‡v•ÜЈ'^½1¼üš¢.ÔÿfZûkuÞža¯\+IÊœÛù*Ñäºqp¼Ó\—bf’¢¤j"wŽwv• Ëóæº×ò7ÔMö)Á›0›cÆ`:¾ê#çGÃôù×+6~Â@4»ËÔ;°í;‡&âJböb }D}7ÝÙ2¢Ï½´ÊÙ_ÆÐɨ·-g>fývÄÊ%b"jt6 K1*(½šî=Bwײˆ³6R&XiÜžà•ŒÖºz6à–HÝŠCw~»+Š· ®=¦þý›lõtà N/Af²Çspp¼—\¯bHñ b:7æ[ßþ⟊w E¶E–3ÌÖ’Ñè k¯sƒZ©ÄT*$—G|L,õâÒxV´Ô3Á·;D.+a]Ù) p@I%Šêê5Û·š4j l/¹´@d5ïuŒ„µ&¿!ßYRÙ§I÷HÓ}˜”¤i¾¥ß8x6g #c¸E;9„o`ÙK‡«¬=Ñà?oEç÷šº_¿ÉÙ_A‡ßú®Képg888Þ=®¬ è*R^P]÷›‘ÜÜ©0½0a!ÎZœÄò¶Û?FPLÚÚÄd¸b†‘ ®²jc†HM>RcaÒåö.¼ÍÊÇâgöÕ%ŒHIëMŠ+0ÎÀíüŒ¬˜V6˜ò4øëÒ˜ý¹G„x2!Æh÷ψÀîJn׌]Èè9¯¡)–±!–*ea^nzZL5šÇ‹º{-ÂS_¢·„È^«Gp+T"B«,¹M_àK›l¯ì9¢iÕwÉIh΋ø#…‹Œ8-9²ÎÑW4C+$AH=š;àààx_¸²bˆA®ÁÕ±¢ÔÀ²ÉóGÃ6$Ñzù"BU€bQk¯[ñrÞFW_ r¬`]»Š/ÆCXÀ/‹øÀÀú·ùáŽÌúAÇ) ÀÜ#HSP–FÎIŽ–ÇýÀ1,&¦¤9tÓ™¨Ü|wVž³°¾]™”jRC4Æ8ƒ_À÷x½»ÄYhÀˆéóÔÆZEzwIèÑm£g¥ ( ¶Á_ƒg ògŽǘ!mþËùæþ ÝÚ‚†.¨&ûäîI`)Ã2×TäÍ(êK[Ô·¬\W5il|qù¹ý9a'›¡— <ó/-ó\撘Ŏ÷ì­±wÔS&×888>P\Y1ì)]YfµàÑà¥b„ÈP$j"hhAŸ´_'eŒ‚Nº&gߤZß|Ó'»Æj?Ž"_öZîòa™€G‘ÒxD(“ñ) Œž Ì:’Ý}Æà…:ZNkÌÝÌýhðD±½'‡¡’qPð\&+,«î*^Ò[áÔäL’ª^oœìEÞä±H'Û>·:èפŸ€9ŒÀ$’€.c„¯t(Ì‹°ó% ²ìƒ geùyÎ`–moé¦Ï¾”>t:Ó;P©#aû0ðP80¬“šmé -y‹& —µ.5;ùÙÛÎÿ%ÛgÁg§•>¶…5ƒ3ÙÞ–;Ù¹)äQ°ëŽ)%ð⇇‡ÀûŽÀ•Ã+5;ñ¡>óX‹4èM…0œÏÈeŸÇçó)±l5$HW ‰I’ ˆ±¸Á(wØ DðSºÄWPÖ”»huí–œ‡²•‘–Ë#|)’Dõ™H­/@nºg ÄíÜà×Òx˜ ,Ý#±ñ#ÏhiÄ#‡ÅO@èu¤Lã«_5´bû eYc”O¹rÄ‘Ã"èܧ˜ìä…'Ó]ýòx,#F_2%§íI·XÈÁc<Ój4ÿ‡9b!4pÂÐóú"÷xeÜW•‘BÐ@ÑhIÔ×åuôú‡;=#6ðc¬:Wu›ÁÞb¾)%a¹5%÷ a®ÌrŠâ¡8Æã§Ë!%šfÂa(0W-ÍÏw–C€C€Cà]DàÊŠ¡#}±ë–û—Ÿ}nMÇ~q$€8f*UUÛe2L®´¥—;¥—/ŒQ¤0Öx†Í„'¦0 +Šéòý<–Œðí_¹¾Ç-D-éÚ½8äJ<L< ñÆ„„O(íQgûÒʆŠ‚FD-;RšT2Òy(8p9ئ2DRZÄcò*loÌ®”¥íq ȃç}ñuH•…B•ó즾C:šˆoP-©ixRF3¡PÈr8/AÞô†E²±SÛœýõT4™<yÎ Í“”M¬}*RëŸlõû^Ç"ƒ ¥+ß[}wžsp‰­—fX7¼X ¤ÔtšëcÒç;–mëA“iZ­S" ÒX4N1cãEÝg‘Çw9§µÉyã:ppp¼ó\Y1¤õžTU>¿åþPýª2G?O ,\4¦* ã~†è /€ú>[L(Gò\$ A' ÐH—ÓcÌÒðÅb‡1µ6ʯ ;ДYD4ˆW2ŠQ÷ßX·­-ˆãbš© {ô‰‘ÂUU؇ÅÁc¡@åãÁ:]Q®eíÍ…Ù-ãnúx£ §Q>Þ$€ÚŠnŒ™ëùëqŸ#ÏÚ­Œ€FÒL””àà²N#‚áZ„© œjârÒ vyh@®7瘲ƒ.+ñA $A¸@µ$cŠjPH4ÔúTn“M(fT¹{+·Ÿ}Jö#‰$”Jc©^=¢Í!-„ {JvþÕDäb/O:­J¢ÒàÒ†~mïIë¾W4Ü.\ãààx¸²b¸ïÜ~›±Õ‘»ó5ùú×Ô«QÔúÜPWá Z1´£ÑãüæGóbv›Ò€ e<½—hù"üŽâÊ.šô£l°³>h/bhp€<¡ŸjbpYCÖqØ 'af /¶ >­B¡_ÈÓXŽÓÊ>Õ6DLr°Ï1ÖdîŒÚGÒmCYw1†Ô°1+Eyªvp( sÛ ¡ Ñ`yÙ2³ÅH”½Ë>þjI­¤íTuÛ¾BÇ0þ¾l (%¯Xdç 0XÝÖ¤â|Y<]ØB/Ì eZ],³´·zÕ "p"NExAœb4a,A†Z‹"[¢Ü'd $®FËÄö™ø¤€â888Þ®¬n´Y‡²ŸETÒóýx“Ú5`/Þˆ Ö xL0z„ßýB–8\[\&Ì0JÄbµV# ”2kãØ*ŠXçõz¼“æ,º ¡Î5:õzTnâÔðàè¢!'o‹B•?7 Ëʼ=–Ëü"±H!—1¯Ä )+(™´hÅ}2Ó`ŸÒåÑxÝùöÞ=ñ¿îÇcÙ§÷­üŽÜï_;|TõaUÈ&Djra??G¥×iT !_%ê¬>¸ t¦-f‚®NÔzM-XqŒˆ‘ß{ظVŠVþkÅXFÆì"K"öÒ£EE<£QgÒIÄ’"±PT0†b4žâÕè*ж(s»p{ë²Á^¾¥U¶ðBÎÌÙ[y³]VF­Ê3)ý4x«Šø…eY)p¸ƒì6[–¨ÔH UƸÆ!ðFàÊŠ!xãN^ÎRû1t”õíÏwv-ñ:Ÿ©\âSKE™–—2ŒÌâÅ[ ËJŠrrÔjµJ­·4¨vŸÖ«JÇ):Å÷Æñ¾!oc#Ú·œ³3’C(n1føŠKô%Õ%¥…9zƒB©‹E²²-'ã±XÈïq:†»ûgš|oîã ló óZþú¼67\°éŸ›>ð£-]ûÛ$Jw}iÁ‚úú…Eùzƒ^.•oðôp4æòùl#cíÈ:ºd 9„ªÎÒ ð0ŒÐLtª÷>‘‡ W·nk3ßµëA¹sÜ–oV——äT”—å礥«µZ±H,à°©ÜGÁÀ¡À`4êq¹.gõ¨³YÓk;.iÓ‘A¨¹”«œ‰Sÿ î a8²ÚÕ# µ¶ÃÍq¨³Çµ+ÀXøÙ;Q7úÚwÉ»?{åßÝ¿Õà¹Áü«!på/è£uz¦ÓBì}Ü0t¬Þ5²Ž (DÒÓ5=î¶Ü‰çjò´5‹ê—-_žeV+ä<^BvƒJ€’ÑÉMf’‰ Ò9ñ¸oÁ‚ᆺñŠrÏÿ¦úzak¸b ‘'EÒóÙâúšµ õ ”•äæÉ5jP(!jS=ÙöÆ´2Ï_R2º¸¾¯¦ÆûÐ/ÈžÞ•îá¶Þç.h‹h}ÉkÕw¨œ½¾Òœ†u«×¬X^R\¨–Ë1 5½ûÑéFC8;+³ ¯ý| O  ç1î/ðØnšhn‰œîqtXÜÛèüê³Å˜®¤ª¢¡aIEY‰É`ŠDµ2Mœe’̓FÙæ ’"k¼ÞµÅ–’ï# ;Ú’ÅS«G[^v·†Œ‹=¦¬to‚¢ ‚ˆ!O"Œ•¥Àµ&ÇÑÑ7ÙÁ<øýá»?›ÿï2,nÿž\Y1Ø»?ëØ.½¥e­ßR•ð 8 º%Âòÿ/ÏRlÚ´©aIƒÙd"’²l! “â>%ôòðƒøV Ÿ¯ÉLFC—\>ù½ïÄÇÇ“ëÐ .‚ßZX&^TuãæMË×ëõzèÏ¢4S¤’ŸÂ´JÀãi5•Ri2§÷ x“ÿós¬§ggë‰ñì³6U6Na£¥E«—Woß´¡¨¨¤þµ$?ɵ†‰‚ü¬LZEÆã2ÐÉ!$”ø«Aô*DÖ„\çûÞÜM‘v×É#µtñŠuëÖä+¤R0C±á/”O DáoœÇǤbVÉ$Xå<µF 람´Œ­ÚñãŸDº;ÀÉΙ£Å“»æ‚©´·ÿx9…Ì>Ðx­l ¸?ÿ@„v²)ÓGÿ£â†ðoŠÀ•¿£÷œR9Ö¯»Á. >aYã%æÃOhùÛnÞ±jÙµRÉÊĤ°†­Öà8¢|¾E ùqÜGÏPímd(ìVh¼‹—.,É•ƒù+Ù¢o B«RVnXßíò üç(«CwÈJÑ1mÕ8­4 Úì"ã]m)%›Äà]}ּį“ÔÇü_OKÒy{D®s×Ã6w/‡À{€À•Ã&»ËvCì'˜¿ÁvΈ¤}ž.Ú´å†5+–*45/Nª?¸s vt8bÑt¹Ü¿fµjÉŠ4…x†·™]U ê³÷qž<ÆÐÔˆDë©©¼cãú5«Wi•|Q+xIæB[ÛÀ‰“«úzT"®®Ö¯XNèõlŸdKärÁ­;l]‘_ütÁÈ…7-§*T°!U,(c× ©Îp h¯@ <:ÅõyV&¡Ó±ÌÃkf·)êˆa'{½âÞO©?wŸtÃÌùÃ(øü·lïzú ÕÈHæøá‚åeåå dRé,qat(äxêÙ¡gŸu5¶‹r Ù[o”Ýy§²¬TÀŸ &föÕzFǃN&7·zae–Ù|Q+·jëùn3mÑnüº´¹Â;,fÂÅû^9å±á?ü~ÝÊ•$Æ%Œ‹¢T*UÎm;BÍgbk®e˜ïí… ¾a!pfÝÖïtƒgZ&PëYôÍϡɱ¹ÔW­C?üo”‘ͨµ³fà ¾öI4؇d³—Rø+•Ï ß¦“èÇÿ1‹ZÀò ˜Çž›á,Roi¸}b >‚~üí¹ü§›Ñg¾‚Ö݈>¾õv {>íÿÙ3•ÄÍ‘0úÌÒɧ[ìéÝ¢±ô­Ï¡³§§Ï!$WDŸzIT¹ˆ‘Êf±}±Gâûø60LêNPE \áöd#I"u<óÐGoœõžy•;æx/˜WÎbà¢w8¡†$"mܵpá&Ó,‹ã´×;ðÓŸwíy&½ÉiÌMµý/ÿìÁt±eÓ’!¡>† e~§©ó¬À>MZÆZZAµÀLœW”¿¸a‘Édbíõ ’À‡}äýO9u‡s J`‚Ù'Îü÷¯5iúEþ°¬X©ÎðPŠÊ,/%oÚ>øèª‚ýåëuZëNõâ<žóÕ=§¿ýWÈÉòÙçýU—¼£«ü§攕ðçL Šrf—úÌ[Z†e-_» œâ‰Ôi&q<#›ŸzJ0dÀ²Vî_Ð#oûGŽw<ë§ìϽh+(ÌÌÍ!R:Œa èwá7¸ÿ§a·SM:å¶_îM^¡&Œ³…ð¬âí½Iñ@/ºu²L«˜ z*bÕúá7ѺZtëÌwFgd^TLzý•yž¹ëïÁÏ—eóëŸA}s;tw`–Êœ‘ÎÛf Idk_7ºq) À¶ã—4P?üûJ¶çŸuÍR ‘)ïô}"Pu{.”ß'ºy-zà̧¾Ê~Y.mo{-¬‚%(מÎ)ÂãcæÛ7\ú¶ÏS/SZãEèæéÄâxO¸²b˜ÃÆh$’¦–çåå `r%Õ"xøHÛŸ‡S3¿ÚðC»ÝÒ…~ðѳ1oôiŠ ¢®ú×_\ؼ[糃Ì~\WW”ËKDJˆ³ævâ¹N§{Ô³)d+åóáW›Ì:(ÄC'¥ÕÕ‹jk§œÞI6† õ+–O<¦P+2Œz™dzªžì@T0ØõËÿsDÜ09L `8ôæ»ËôZ£^Ï• X¯7²w â Š–hõå¥%f£1‰;5t‚è±­m½•Ý»mÕ¢ UÛãxø#ÍÏjƒà;a¼Íç5]Æô4±X|qh[g2)ÊŠxíç¤Y­ì<Ò|Æ{ÇÃù&tCç|>kKÉÌBKV²göîFP}#9{}þ|ïn뙽Z;%aÅ™Í~Âã£S·Ã`«)«LøðèôØÃ¬Y&Ù¤RvÍa¤!}æçÞ6I²§Ž¢k§ÿi´H uN t<,H©æ÷é@§¤;”O„!€Xý‘lI­0“˜ËB°mB?ø¾i•]8‹ùä]o{ÿlÖÒ$I þv_¢P“—^}>üÑÏO/Õ›;àxϸ6Å2#nT§§™ôZ-»<ž©hÚwüÈÂ9Að«À ÕÓ>Ü3ª)è ÌKúÊ7öÕ~ºgh8û·*ç0 ¥)ôÚâ¼\^Ç å”bÀ±É<3FDzÖÇÙ{(«XÈ‚ aòZ—!+ÔÖSV\¢PÏ6gZÊ0Ëd ƒÞh4™xs,Ç`G²ØÂ=Ã)Îù:­Ms«LN»OÞÙ­Q«§üÉ©O‚ dc]æ]Ü“æúBs¶Y$“ÍòF0$Fñ­·„žèñ l¾¼Œ¹Öie¨8R« ~d3ˆ ž5E“a `IœžË8§Ð¨ÖöÂx1,'Õç8p»Ð–Ö òª5ÄyV$¶µ|û¿Pº}3f;ø}Æ|É÷ë¿(À|Í`B§ûØÈXO$;ÀÉò5¬…Ï“m_þÛçkŸbÅbú#Ÿˆ}ÿç"ÇnÃ:Ý®‡ aµ [ÖNñÏãÑiô¿à­ßŠø Ÿ‘u}õ>ÔtùØð…yšZ‹Î °ÊcäŒL·ŒLôàÿ¢Í· à“"Ñ¿†þòG6÷Úw¾èzæõd5–éÞ]Ï6nEçÙo4,a/C›…% Uae–<™zLòíº-œVHA¼ŸÌãoÅ È—("Äj£J¡J$)Ù:u(›c†L˜: w%m.õÈgêÛ·ÏÓÙå곕¬m¬øhŸÔ(;ôól•ÈuZD<5fóFÈaO˜V˜^[óù&ÉÇ(D“A4ÆH˜ž…‡¶ù}rDÅ`à IDAT•2)ø¦ïBŒLÏ-PfdËÁë;Ó0•è‹EÂl,›çLLÑwµ7ÜÜ[?ŒžÃûkj«…àH)§Ä- }¶OêqÅ«Jµ*5‚sf’Y¨@i7Ô¾©"Ó‡yà>Áx‘Ê[cqèD«ÄÂ삌&ÆÑk/°gºÚ!Àbn»ž!Ü~7ºùv Hï¹Ð„¶,a‰«ÔÖ“Ýé0§š©A“}€®q|¸†o"H‹a$ÃÁg„¤³a+$ Ø sýKA¨ÔÚ Ë—…-Jlþ̪ÂDr&Äp©Bõ<æ0 D½@.U6tfÔÅš‡‘«WHGæ<ú’']à °´üñ¡)h0:îü´a¦:KëÝóo åS'^|6ð•M¯)ç`UÓ8C7|ó 8|þ‹Ð†Zö2T^¿a»ÿ—šZFLQIüw ø}èi€ÁèzùØüÑNŸþ :¸ÜÃ>ôßL.=~ø1:¥RWøó)Å0>&™šÞO_»Î!Рɖ–9užAÀЇkd®A1$V1Ú>.àOK‘™#Kl6óƒxtv¶ÝvOaåA\9¶k×½Ç7 T…bå]/b»^Zxs{Åçc!ߦ`—D$HHÒÀ@ mk{åø¹sqL¨Œya{s ŸÒbA‰EѪpfÚ©IåÔ½°ùÌã§ ¢6Ô½˜{•šPš^üÈýT$ž®•aš–ÞÝ}‚è~SJ SÕPlcÖj AteñŸàóD¬{a¶ôµDQŠÒAø¼¦nÁB<> "°Å£D4ÊêŠéº ‰…¸HL-]ݾî®~d †wK¼£rú²{‚Nßz ÿÛ­­Y$êg õÌÛ’ ÉKßÏQ ptCÓªƒ…Å8Yù¥OM‘­°z}àŸG+@ëdÀaŸz ¬9ÿüüüHöxòE´´˜µ ©5~ Ÿ¥ÕR$ô¢eó|áµ­GBH·œù=¼Î!Ì~úÔ;¿/o;ï5î$‡Ày~'—c ‚)u(Raé y7$æÅ³:‚¬“‚¹F‹çVµ~é[ç³–ÛƒgÅÑÈT¾AÃHI*ÏÒ+ öúTÕ½ewå8þ…ñ)›Ó4 šVˆÅÛŠâ I˜ &³IŽGQÔ‚c|°,Ì^.ÀÍŒÇ' ùÀ5 ”âñ¶Q—ŸÖ#¿”u;¶3RãhÏ0é…DÝ”™hMž€Iy¼Ñl•=XáÌÐ à·°;¼oг ¬ü‡kQ ×gL¤WS„ `ôL¹cLLS£iB£ Aér}Þ[¾ò´7=ØÚ!<¾È5˜Aƒp›IzŠ·õ?8]SíµWT¯MϾS'ç=˜O˜Û/¹ú°yݰ=uñZm½ïé×ÔßÏ>ºNNM‘ Ô,Ò¸©S3 Måd7rÙ‘¬KoÕ|rõ<ö.9¤Í\öëÂ[ñÂ]ãø#p ŠF“±´q{( [ÎmPƒHQ]Ã"P&ëüÞÏ~é7æÑ˯ãçþ&öW¦K<ËW„IšQ®€ -ô6 ¤[UxT½ùs‘;÷ðfĪҴX£*X¿Ú¶çZ"—~À ìAIŒŠ•ŒZ!M®3fšH&08¢½!§Ëаrzfc0#ŸÉs5·vDiäHCî¶µ–se{_N¶R® ø3'Œ‰[™@föè²Í±QŒ/ Ç.¡ ‘N~ËÿÇ5ØÊš“ dòáŒü?/ýr {ECçþ¿ù¤!âa¯à|”f ¯¿å4^zN–wÚÃÄúl¨»±f²egÔ .Õù¥r’è5þuÏÈ>ƒ(Q+0/1ðž˜fÇÍéö“‡.Æ8Á¥e+ùÁÀeÃÿ¯“ÈA»ú›+(–Ö”ïäêÉ^çæ}МYǼ}¸“ï/צ€WqÀq8c`<™•áù«W)W®uïÛI\Á¬Ò]Út¨ ?þG£«ÝiZ³´¡rq=C`A0àõÑ^Evû:þÔDùH0‰†e`ðNµ„¸WmÚ ûU®µ¯OÈ\P9 ë½Ï]PP›•©œãs(äÛ˜Œ“þ¿ÛÉbšéDÒ2™ì{« ~ÖüÄ`k‹Û¼¥-ÉïÔÅó2r²2%0ù„îLMCQC†Ü×ÖÝ© dzÏÛüÁ|Š"f;Á3²2QÝïD7™r€Ù­b¼?·yw?a8­¨Í“¿±8FBžU¼íÎS…›öZUá– ä "Lˆ”½Êˆ‚‚¾Y˜ê2’.;>ÄÔ6`ðõÖ â8·ì¸ì¤ò ’1N€(4P3¿ü©L¥¥ï¼bð/* ëd@C¦ó‚y;ÓÞ­ÿ¯só²%“_ؼ¸“ï;צàןŽBñ–Vw(v÷$)ÏÌXð½o5õÙ&‡NoÞÞí¡–½roǽÆTUÞ°rÙÆ5«AìÆ ^'óE#4¦Ó…¿A¡î#]2ÆYW eÌ C’¢œŧ?iÿ¿_',Â8øšñŸß©0ò.XPV&‡b3A„ºº_yƒ&ãòáÐðh ÊÙ%£/§ºÁ–<äֵ˭žùÇ?÷z½ª;[MùRC|Mý¢¢ÒBÁ%!IˆàZíöìñºý­âÈærsUY‰2U¬ È’¤@*-ûЭ–¦“áÁ!†™ÚŸ _7ŽžÝk»uiîò¬Þ!Œ§Óàë6·êŠ›ºÌD`¬…½1C Ò—¾°ú»þ#¿ß9zTÀîcôδ‚}ùÛáœâëÚ ¯-+M~6tI9ë¼éídý þ G?ñeÁ¥ºá:X¹.…ƒìÂéXÝŠ“†Ô•éÈfÄÊ¥œ½ÓW®ëÿë¼φ½Hæ=Ïäøà pmŠø†x Éé“–Þþ4ŽwÉäZ_]•óÀwGþñ¢W$7÷ïeø¹eÅéYæÕë×VW,ƒoJŠÂ¬\ŽT椉¿¥ãÏ+Û^ŒYù–šÂ´Œ 6o.ÕÞdßq{˜"ÏízÝ66è'‰˜FMV”.[¹¼¤´„H–¨KöWs hûóSÖ˜,9Z×dô|‹óF1dS§&„bqÉGïºK§34··P-†ôHe骵+Vdf$ ]Ìî ïLÖò¦¿E|>>N„s‘³¾Êl̲J$…ÿvÞ6öÊËN‹… Ã|¾ÃdªÎ“å–eÒü8 ÚŠ¤âñЉSzR1à`ºNà>C™æÍ¨uÔÜýÆú¯©öÇמÀip·¼u·¡f,lXB÷3ôØó’9a_ì…éÝ ¼Ð:ý2µ S$,:g}ƒ’=á‹éè0Û™ù#˜I„;æxo¸fÅSErlØþü ö‚4v–Õª‰D¥[·R…¦¶–Uã“”±@Ÿ¶277·jA9š’R02pØø“-öž—Ÿ—·½°ÑÒ^7ý³1mAEf~îŒr{lEŠ ½^rï§°††–öNa($‘ˆ”™ Æ‹2TlöðúÞöǹ çÁA88²óf(Ôʦ¹¥~—v‚ãYé&å‡oM[RïpÚERY¦ÙlÔiy`­Hu›y,ðɰ5âw…ÿÏC•o LMS6{†ŠÊ¾ô…hqñÀÁƒ–±ñ8ISJ…¾bÁÒúúºš*T „½…`¡8É”Ýa{ý»o(m=êxÌçë²wüC¢±7ÜûÜúojw}³÷²;ÌuÌ`èêÁ¯PQ‡Î%|Å{^Ñ8@×,Åç>JPœŠëMŒ '~‡NA¿y‚Z¶~–Ì­y ë2gùûÅtzõúð èÐ^†@„CñÏ|“§T]üL®“HO[ºÞËŽÊHüîgñ{¾ÄÓgù€’YcßûÚ›p­ÿåѰ…JlŒqu]±×uá2ôeC½±üÒ‹ €7$¢ž6tìZ·™^¹)‰÷ep§9Þe®Y1$ù±?ýLI‘êÎ;İz‡6Cž‚nX´ ¼$;+èó?Y r*ì*!Õ Ê&Øù ßÏÿø7á™—7X:71lÎYl÷‹K+>õ ØcŠ&TÒÉdËkª+ 㡠ƨÕJ‘XÌn¶–|.HQð99ÚþÃûÝ‘D}ƒD ÝÕ:xèpNi‰Šx³Ÿn‰D•\…óâL ЇҚ–Å‹S:qÒ~>Ý3ñ¿FÁÖç`ÝqûDà‰Ç=WT8³ŽüŽ í7 Šò‡‡F¢á¨B¥(ÉÉ̓ý‹4ȽÙzÖ7 ­À> \߇Ž>÷œøÞ{UéiP)6õ80¬eÀΦ «kó (ŠÆÅ"ØC¶b;€€Ft `}uÏį+ö²Ò–5ð‚qÕšå‡ÕxÄ…ëʌΞèêA¶98QR£Huãó¡ø;ægJ‘å8® âþûïëÆ~õ^Ÿ üxR2Žc›mßaÁð `SL¶ž}bFÌRKŠì]x — Ø lƒŒãǬÔgŸ9yæÑÇÖôÞÉAp‚LJÁXÐ}ùeL&eeóÄ"h¦bŠRš I< 8Ç[=}ªûÕûïìßMÍÓÉ^Q¯ÛÛÑ#]T'Óêx¢Ù»2@ NÓ”×óøáóžâ I÷JuT3j˜‘Â¥ä OGçðž=ñDødR‚Xûý¦¼\>„E%™œ,øHÀ•"•Cù¾D2œk2Í@Àm|xÄò¿m¾ÿ‡!¬ ¦ä¾H$ŽmÝùÆ÷÷0”3ÓxÑø©4%Q±tIqqÉÜZOÓO¹úÿëX5pö4«›’öz.j:….œš‰)°æC’—Zû퓼oŸÒ¡ÿù­©23Ÿ‹2¹yÁÚ¥ìú¶¶ì×s?j8_Y¬[žX &î|Û $Ÿ›_„Vo@oîa”œûƒÉexð"ó IÁ¦¨ÖúÞhå—MKøÄÍXòÛÿI’™õ·¬,X»Œå𹿢#o̺”xƒ‡*]œK\çR€ÒI’-ê ¡Í|‰ ˜| ‹¨—iÞ—¬ŸÜ‡ÀÕ®@%Й3YU°³rø ÆãG¾÷Ýܦ³¹Û·ÊKʘìLˆã$ŠÂ!N@SB2¥°1HP€$¯Ïævw©²wîµEÿütCßþ›é©µBjn 4!Úÿ̾ï?~R·ãf]a¡¸¨€'Ò@—ÝG‡ýÙÃ')È5ó;ì§DÏtFžûísyÇW“\N‘J~´ÀvðÜ™ÎÿøVàž._&Rª›)j êp(n×ÖnÿÇsû[†Âuߎ;/(å!TGÅDtR2`¶ˆùý $¶Íh€šå±G;{úÌ·ß*ƒììL`’â±6 žœEƒÒòñŇy½¢žN[g—ïÙ¿õ=›aÚ EÔ¦­û?ôVmt"Àâ*3úòЕJ;Ìàåʇ[oEnD?ù[FÔ¬©’|Zñ‘[¶ñ>ñ9”[rQšÑ/~M ]JñÏX²5<>Ij& !á¤)U%٪¼PzzšT*Í€a£ñ¨Ðb÷÷u‡ŸþÈ/þ|ôÆ-;ÿÜ}t(Ì$2s\@0/§PÝP‡ F£@H1ÌX8,êéž8tÔN†Oª³ŸþèS±‰ã(0üÍ OmîâËÄPç £™hï°%`ƒJP3‰Ã1¨ˆ–UËuÒÜlu^ŽÛh &[ÛƒÇPÃÕní¤•ÂÁŽ[þö€¹¿ £ÈÔ’+É›`íGîýÉÓÎÌ๭슌/Fï_¡õáKŸÛ¾m[êõk lÈëš²°+TH®d ßïY»Nà«ê´²ÕR“é.0¿V¨g•¢{rCHqÎ@‚Ÿ°Hò^"ÅwÀ!0/W5=Eõ$¾‡rPzƒ½bÝÂÓ!Ø4e¶(ƒ8|¯°¿o8½ô{]4 Eî£/zÜk[›·öV01!XRd¦ýù«A4r¦Æ7 ñL!œ€ù8üÚ©X –ÎT@$¯y]-xW ?;_vfdÁGheÖ~Å—G{òî$…$YžXÒ²áÃÏÆ²ƒÖšèÄö‹*”¿Žá«¢ˆtqŒs¨%ßòaÿ‰4PVZ¼|2¿Â®ÉSZû«^úí#§¾Ø±÷a`tÁÇ|ÛNÚÌíoŠÈX4V±­¿éíbßh ùÜh²9½÷Õ5.ç‹RS€dkŠpC€C€CàýBàªL_Á¢±c`ÿ_ë?†YGL• @xŒƒˆ{B­Žl¿ë;~ð‚U€Îù‘/šð »ÛºÕÝ‹B½úz”¯A4ŽÆ=ˆP¡ÚmGV-ÉʈªÓ:xi=ZðÄÏ>”I²…ô.׿ÈJx ñI‚ɉHþ"$ÓGañA_í,{)Œ®ÔzÜUsk,aì‰álý¢¹+Óçy*-^Y×·ý®¶Òõ¤¬ËŠ»‘syEVSUåĹêXàKç_þ_}é„áîý÷Ôõ5—“¶d)–´–mˆùÅÈCA1ÙTï«d¢Ç÷Q¾I‘:}“ÓÏäþçààx׸*Å\€È^1Þò¼·7*¯j“`Ò Ä"U¦ë?ü·ÒÛ·FÅ…¢$‚ØÎ°¹pK›ÀÑɃ@¡<”^ÃK‘*ñ 4Pá1¢øØ°íÇFv Fšþ±5e·¹Ê?à\Øóæñôeð Ò‘Îñdf\rJ>‡NRÎμgà•<fö<±´‘GÄ€yŒ–é˜ÙšæÒÛ‘\3ò݇N—­Ûç’E.øQ÷!|°Yàè"Ü}‚¸§ àÆØ]è3PüÆ ÿøkÙ– HßNsS„(ÐCko~-oUh JtPÈÕfï^BÅÍ}eðèk¿E™f²:g,Ü[w«U 0ÏGk=?ŠCÆÔ¨›-š„p±¤ý»?øGî­]§=ÈÐ#u#[1Ù"˜8“åê)÷{ÒØ<$´ÇÒèÕ-ˆ¨óâêLÄa¶nžs@SGÜùW5 e$tORþ^ý€—Œž9°Pê‚NÍ‚€Ë"aÀ<Õ Ú‰„ ÄᎠbly»”|‡Î`Ï "le®4ãTT“Ü„ÄzœMcÝËР3hÁ”- Îe2˧¾úZÑæ3ÝXl¨ï> Øov´§y]YL¸±éIp;Üc7†‚„R„<~»L„ØœxâpV IjQ<„¢^dï+÷{åPE#áÆÏ@¤±¼pC€C€Cà}AàjÈ)°®Ä!ë”r !‹cxhÛ‡WÞÞÕìCàf{ âmÏ‹FOe…mµ>ëªÄ¤>™éTïîr ŸÊûäiQB$"ù.ë&˜™ÐIšR ^n¾Ìú¦§ù s36‰µ5ZvûhéÖÀð eÔÇš“`²/•bB½´~2§`@©ˆÑ‚[`P°f§îe‡Ë5÷kP FœÒ,@·1€ÓHzÎ_9ÜK"W„Ķuðÿc=·Ø7¹‚8Aü; ‹ëª‰ú½Q?È>ð«E&’¢F E#0™‚ŽÆ±dbJ §À€,eB*£ l7Xh`w¶D7ÀêÞWweÔ“ÙËä-»eà„‡“™Å¶7·-ÚÒÇÈN»Ã”LJ²åëû:ï²ö$÷K˜º9ER’M¹¤!› Åg‚%nªzmñÇOdú&S…›’’òÑ¢›¶?µü¾x¬¿Ñ’kËô…µ§0ˆ‡ƒ…AAKö =ëF?Sä¶(8Bq¥¾ƒ'Š´ ž øX“ÆÙc¥)ðÖ¨ ð~+¶MPáþppp¼ç\­bÃK‹DƒÀ7ŒA`)ä$·Üþ©¿`ÙhÌÉfL¹°Æß/>ywÌÂì3 f6•Ò ²æÔ°†€·0µŸ9)ƪêF?òÅ“‡Z—¿ö1>k# H‚cÂ\`ÛvËë¡4Ý+,n&%,B[OKÒÞð“×·=~ø§++ÒÎmùìï}¦ØÁ}üó{¥Žn(mÑa±k2ÎР.m,V®eSC“Dëß%¾Þ@é-õŸz^©X}à· üVq<',óГÞpÓá|¯±O;±K<|‚á‹¢éµû—Ü·Û½Kù§^©è9fºq¨·‘0U.«{UPîèæ5Ràt`qØOm¯h aA%$S}xBÑäŸ~ û†ˆ8 ‘(nð&*%.ÃNÒLÛ-è~uÓÀ Hu¼ É" IDAT83r8Ô]Í®=Q²þÄ ÿY›ýìŠcÏ—y&øq¸Å|Vâà.bàd¡³_HSÇ0ÜŽãgc!Ép³I§Ôd檴¨ Áh’ÐØØ¹ÑI›×]~ç°™B‹;àààxw¸ZÅöp¶Ø~À…r–Ê76*ÿÎd#gQq4y^9qò˾ ˆMÚâßšå9Š]Óknx6kKì¥W¥ÇÿTés€<ý —H…úÜÖïüÏó’óçF™Éú–Ùû¤©ý“j¦’ô-'ÏïT!yß…òÛ»o‡ÇVÌÃ5H@ÀN¢‰EŒ›5x1àBŸµnà ºîúÂ^Æ= ïÛ«ô¹â^Жr2„0(Ñbˆºœ|—% ögV ´©Àn¬swù`ó&ʯDÌ&‡ßáhé=r¬ë _öÊæ…[šï\¿õø£+ºêƒÎºþövÛCv2®øN󈙚¯ÓåM¦4}zº6ËËÎ1ÁvÓ¨¶Ç›°t¶wœ8~B¡TÅSÅìÞLî*‡‡‡À;ŽÀÕ*˜›ƒÜ—Y{9q”SóˆG …£(dG£§¶:F³!ÛìÚ¹%A,\tècßlk³a'ŸÞ1ÞœÃLUAÆåÊÐÖ]¸õ¾ßs¢/!N?c?}³g¨öM<(9ýçIeîmí\¸…j:Žvã+8 œ÷ä¢;„ü@úðñ쾂¡Ý°µNˆ0¬œëI2áUÆpÄôçÿ ü‡~NôVFmB ~\fÆ%’b•’Oð(؃«ä 6èÛyï_ãeñãÿ›c9·‚fµ»“ŽBåÿøWÞ\Ï®^DyNzæ±tÿÄ>K bÀu J> ‰·ÞóÒÍßyåUbÿ£ Ï¡q¨ì-ð äЇ-?dÎãóy<>!VÉÁ}ÝåóììƒêyP$Š`˜«GüüJ!–ÊÅÆŒ ÜæLƒAk4”ru(€Z©rR HF†GaR?iu8ݪý6Oņ$ã¢D=!ͬD‘¬¾ýûÜ}ú ðb¿,Td2¸@.óiÕÆtcAAQUUeeUEa~.T%‡’´sP‚­åÒÄbNGÑ4ì6Á)†9øpo98Þ®A1€è_ÒyühùÉXÖRÖá Õ#¨>Vá0%L:×Ê1H>×λ^(Ü;ÚNŒ4.z¥ˆa=ÚLÛ×øä‚Û;úcô™c‚æ?ïœ8·ˆ¡“nmx ¬3Ø)­YÿôŠŸ~üQáñÇ3$¸º´(7Û, Às µ¡'¡LJR£ms´jUFzZ0:|èXOoŸÏ烪xu|B©PÊäRµZkÎÎ,,ÌÏÉÎV)•2©D$•²u¼a¤3Z ìíw ôŒNCa¨( EÅ’Àcp"s UJYnºÚ 3¦¥ådg•æçåä¨5jàjɹ‡°›Å,c×ÜëÜ{wkP ²‹PdIÇ_›³õŽaBîX.¬ŒúÁpÞ…km¼¼²£k>Ù6†Ñ]Ç ­h6Ï"ÙÚDô¾¾9`ÑCØå\´½gˆ¢í>¡B2C릯ìòÆ—Êå&“©2[QWçöxÂ1Øy øý¯7%Aoª• ³Ù¬ÓjA!½…¦¹êÇr988Þ#®M1ÀŒ\к@³M~ r@ãg Q,åàv¾ìû’29•^`ûðÇ_Î];Ú…Î?Ÿåè,LXl¨ãöÏ¿Í!‡'k >. {(µñ¸UǨ`Ï\ t˜¶:S@δ0gÆi9 ë­\¹lùŠå°Â%œçháµ(ƒyH$N^°i¢AÁm’ÝÌ| €J\Ô7P[üêKÒáþrpp¼\›bFajm FmñH‰²kÑ Xr„bæ®{ή¹ç:;v°;ö˜|âÌm¾IM»`¯[þLÕŽX›u¾Á8>yºÎCX\ä)!kŒO†„"Q”ÇÓ 8p‹JW-^²hŲ¥¥ÅEbùÔ¶\ï#š  æ:”ÁIRcã˜^+Ôh®Ro½CàÍ!À!À!peÅ@òx¬+7áË·¤@›¶öÆŒ"¹Ù„΀ïአlë¤BÙ¸ÕR·¾)õc yü%Á¹ ÖÆmž‰Ò„ ìKuËlAÓ¶KÚµ«b´i}Ü ;e†å«çûØëëg\cÞ?þ®-=­þÞ{ÒÒÒ!õ}ä‡{4‡‡‡À[#peÅðð=å,oÔïÿGúÑW˃V†&u±Ñr²$ZHòÊzË'<^hÃöÆÏ=x$¦io!‹–?x`ãäù‰ýA“ZøðÖ.kH¨ö£ œƒ9 }t©ÔJ­vaMUmuÍòKó d ¤ƒ}×—‚Áˆ„| ÝÙxô˜~ÓƒÁÈÅ&]Šw†C€CàƒƒÀ•C‡ì/B7¯B‹oþF󮼞s&Ä #GÞщ˯``b6ï8ùõßÿy¡>/‚B§gù]ÿ¼ÉÒ±•,v¡/hqÿtý䀨—qÃ…#¦´’üœ¢ŠŠõuË—/ËÌÌ"þ5ãû±Œt†àoÆ>6:>6F.¬â¬I‰ÏœûÃ!À!ðEàÊŠIä ! ©k±e ÚáEa?rñ$MW§˜wp ñ!‡àèm_ùsºíl¹=*‚lm²õm‚’NC€g"gü}ëný‡nqüÍß›­6‰"œ—³¸rÁª•«–54åç¤)ñ¯ÚÂ2ù ;HC¥©ÀäÄ$¤Rÿ«Ž„ã›C€Càÿ®¬ˆ¨rO¢¸ 9IvÊχLëyvõãÎÞ’Ëä<'Œè˜ïöþNP‚:](™Òd¯!•~±(¨‘<\ìôð<4'ãX¼™‰ÉÐè9ŠG£<(QqÓ¦ +—.Ñ›Íÿê‘<"£ê\È‚ÇHgMØøÿã Æ’C€Cà_++†úÓ¶ ‡IU° ¥× ØÔD|ІFN¸z2ÙmóúR㺌ƒ?ŽÆ¡™È”·„UÝúíµ͆½î!¬ çe»†k,§ÓÂÞ} ÉaŠE1¨´ªrë¶V®X¡Ñjÿõ½„cžP(TËi…‚â»t£ KîáNppp¼\Y1|¼û@ÇàP£ÏßDàqs5ÀrAãÄØñU!×¼*!9œá­·ýM±uް¡®ÞqäÄ=£8ÆCbå8e€Š2{R¥9¡®@iäQ£¡CXØ-—Jk—-Y¶zZȧà ¶Âºƒ@ÏkŠõ|{ie‰úH £€¼hV¥Á N&ÁÛk +âñF›ÇÖG ü1Lpoé™™z÷‡‡‡ÀûƒÀ•CµÓfðYW ôJàÂ_`ÿ˜¨ ·c]¯®ïY{ùb8Ž©Û††¼vº´^À›ÿ¤·µ‚žô8-fwºÇ<³Êd.*Hciª`ÆNéb¶‚ºº*±Lðì3£mmT4ʺ! Á~—‘iý:´e_,¾"TL4ŠD0‡¯VCS ’œß²nK‚Ûd8ÇN7!›ƒ¦)©FMþ¿ö¾>ªbkülËfS6½÷^ „B( B ‚Š@¤ˆ"úDy(øTàÿ”OÑ÷h¢ˆ‚X(T‚HoAIH!½—Mv³½ýÏ-[SE?ÞcOö—;wî´{fî93§Ì¨=ݵuõ‰Ý—Yv¶OO+?Ú«"ø±¥+Q†;Ú YG„9ž9a¯ÑJ”*™BAjVz`©ŠxD‚Zhhö&¸[VvÔâÌ‹®,ECéožÎroÁ€ÿ½¸7cP1˜Äy †WÒpu[Pt̯1w2ˆMö5ÂÒ—¡¾šÍÖ¨‘oyäåhórJ?Ûè6íÛW9$ ão±§ÑtÔÔ0eÖÿ{»mi!S­Bv…,àdíQ‚ ‹Â0Š“°ñøTžC™x‚3±ôù¹–8Þ@í>f4cÊ$»„nÑ¡“8 |}pEk{[‹BŠ•tBÐÆ Ù>>ÐÍ v“³§hYü=v•D‰ý¡c ¥ûi®€ å½qgïª@Kœ ü`àÞŒ¡#*Ü:.ææŒ¥ûäAÉÉßÿ|SQy¶s—ï´5eêÁ>ÏA¡šJ•çêŠÐVÓ45E|1i.Ý Ž]hT8nQ­`¨X!¸ Œ_˜Œ3¶NZÇ£Zõ]ÓWÍŒhmEãžîƒpÇvõ«Jº ‚Á°e0p¥¾ ç࿞|ù™{zºå,­Tʯßh^º\›}^@O½"`Üf2š œÏsQ£¡…кk´/iV‹M=‚Å2YíL†‚Á¨`X³y<_5ÃUÑ®Q¹k4Åü¢|á¿7³Þø;oáBFx(åËfïîÖÁbûàòH­VÊä„£óÚE£QÝ)¯ý Y­á¯|×-"œ8¶AÇZL‘wwª 4J ÓR 1Ο2ŠÄ –?cc¹³`À‚'÷f 'ÞÝ€;À}SɃ W™·¾C®0™œÈw‡1“ya¢6.Ô×CQ–ýAL­ºÌ‚ŒDPÅwö‹Žÿ—èͯYÏÚó½}zó ü3®+v5l^¡Þ„(¡ö&ÜÅ#ùt^Þçé„Ä%.Èèæáƒ*8ò@"L¶ˆ§™–,øó1poÆð?¢`(îƒ]q!¦úò0’Ž#iC9Og‡D¶88ô¼½4*AÜ uWÆv4¡ÿZwŒ Aj[‰Šû°ÐЃØÛ 9®x–4´¾‘Ï×åÜö„õ¶w xë¡ÂgËú€Xð§÷7Š|ˆàùÿ…߆´]&ŒárÜí€IOƒŽ7=D–¬ X0ðH1`D*º+·^j@‰=§y’R¤áZ£Z˜£RiHéŠ1o@*‚Aøð2µ ´Š ùŽSãœ#b|€Z„làr¼}ûÆÅ{yJ]]‰ý´ÇjžS«<œœF''‡…1q_&ô£¾×ªìºzµV‹š|«ýc_|a^hhÊÚÆ=7&µbÇîÈ?»Êdþ¹®²µµ¿T†ë0¾wp 6lÆSécF'{ûx#"Z‹´›ÔK+D}ÚÛåJBc|µÀLöòŒŒŠ´³#|™)@*êçëÛ·¯X©ÿ°ŸÒ! Ôf.Š s ~Ï‘O¹1€#W+ñXkcÆ€ŽÐ×nˆžEZ_\ÚÿaXIÜݱ(G‡žÔºª{¾dëžg€O÷]]ùdé×#žaÿ`á&xÿm"§a³CìxVî "ý„ôŸÉjÏÁ”­Êƒ-%0=„x ô˜¡°øÙX3#-¸ùOÂ@÷ÔBÿ1 é=Çâ_þWÄÐ4«*ß;E®gOñÚﺒÒ=o@€[ʼnú ÄuP•%;v¿\Àjç£ï´/,$¸OD”ƒ½=Ò¾`^{ö5çÖšñÇŽ4D„‰_˜kN˜út–ËëI´-­ÈΔq8Ö\‚Ä#†;Å)•E³Ÿ.g¨B³~N(½…qÈj~øÞÉ5rĈE//5<]((f€ªoM}½¢¾žyáRóþƒ-98+G€ñ-ß9 _ß¾Ñ}P8„%€þ *•Z*c ZQÀλÅÌ¿ÎR)©‡˜èÊ… ®%¥ƒƒìý|\òYܦ¶C¬_1hÑ êôù’·ÛïælbZ×ùÌš2ûlmíž1\ù…jL¯×1Ó1Æ—éä]:,‚ÍaÅË´¸É8Mï×·Ãß¶@@™Ch¤Ì .ÆnžkO‘O“¡ÏƒrY-¿Šs“v¡ï šá†FBˆa5d’ ·7"øä-¨ë¼Þ-ÞZJ¡ ‹Ë#ЬÅÙÍã7OB9"Á¸1¸Z·ƒ¨¸G¼ 4®Á,Ü’oÀ õ¨é“…‡á½/áo› %à?ïåïÍ8eW”[ÐðÁÖ§ÝkÔ÷Ž<èoÃï$øhæåoÕ ”Q€4]̲=<™P›g[~f¼¼ÕȨ[îDH´ÁJèîÊDŸ\vŒN.]±¬lÍÇíõ^Ÿý¯è—cÒù³œS’!*šeÃ#ÜܺáÜŽ†n2®R*d¤mº¶¶vþBvÑm×ÁCƤ?㪠·@mó°vˆî³(cfj ŽDª¬®a …¢²»¬3ä9×›oܲR´[‘'}Í`îqtu ›úTúàÁ­ðŒ ™\ÝÒ¢.-•Ÿ9Ëλ eUJ¹¬ãÎ-†R¯€€UT”Š„uµUªèHfH€/›cßÚ‡âYÓ Ñ(åò¶äo¬€ÖÊLl²u`øú=5=}ƳÓýñü·îÖÛø&8C’-L?Ï_íD7iqÓK)Pƒš€1±Ý$í]táQb?3hl&#Dpšâ IsàEV‡^…%™f5nýÒáãO!%Äs_!Q1¬'4³çC|7¬+&.†@".@‘àè®Íϰi«á“•àöç·6f\L$æˆ6Ø2öt ~‹nŸ‚ó8DS åõÇ¢=÷Õˆ{3†yw¾ûQ(KlTn‘Z~xF£;𜲇¯,Q[m¼¼é .¨ÿ0tX)Çš* úòÈÖú0r Ñ]ƒòá4¹ÎÁ>0 (¾_wwWjŽìáàŸ1ó ßá›/¾äßÈ]Và²â=,_Ý1{†ýØ1œ°p¶ ¯³Ag{3Zôà"„$ÜJœÿkµŠ†FçÚ &n~ùBàå ”¡GÅ‹ s¼[ù¹•5¾¡ªQ1îˆ4ñ"Æ€Ÿ˜Öe®ÔË=>aȳÏNKIIáÛÙ© ï4îþšû]¦¢¦X¬QãÊ à“›ã{á­ªö18u|G.Û ‰Æ÷“r­øb©¤Y ‘H…E%[·2÷îaJÄßãg×ðÐY3Ÿ›6uŠ[Ý ç£^­—ÿw©é,‘|’H”C]4´ân~™ CȉLþQº¼–Ûp0’6Aä½EOMpêúi%bã€;ù<öØ6¯ë”½‰ö:¤!É®,ŠÍ¤C†H$pp‘»*ffÂ×50îÁ–º!½ôë²Aè8ÒÀT ×eÊ¿,’ ï@É/‡´82&|·8›FQÖ*ÈÚ/CNÖþT@ÌÄÐÄâ`xRCKÙŸŠå?·ð{Ó€YÅ7bÊ+.ƒú{§*§Yÿ9ƒ@áŒî¾ÍAãJ®|©QáÎH¸¹lvþ³ Aæµç¡þÚ(#}DŒ:F6â©»›[t߈Ȉ0T,ë“ùº¹MzvªcHÐé#¿~xâDŸÂÛq*EX~®Ó{¹¬÷Þm<ÔyîæÄñ|WàY Ò¬³µ¤„¡Ñ YÇJÏ^´ýåñäIl>Ÿí ï¸ÍÖj\I†MBN†"ï‘„"]T_%Â[l­ wŒ€“ «»¶ö2\Ü#Æ\8/·XUž/Ôªë€q„Á̱²kµâªXLOü£½9–t¡@9U®‹[J\ÿȰPÜg›®¶²r«oRÞ¾ÝöñÇšíûxíÕ6 A©Öa¾³ÿÀÏÏœ8~œ£“ËÃK(4–Ý ®épá3d¬^Æ'ÉPr’PüßK&‹…+äù½…º\¦W”Qûø#`!ÒÂΠ‚Â°ñ7˜¼®/!l Ø*˜JJ2vÁ›ÓÉlÖ°U d`ÔÛ‹»wŒ ìNU!øD‰ß1äXÞŠæU{`ú|"ò“/`ÜJP ±¬¯ ­8„©Dƒ("ã96€¿Ý ƒ§c 8ýè t‹e¾ ˆJáà/PÕN$Oœ ):Êh–]P 'ÏAA¸£÷g;ô £†‚½ñW(B•(­ˆö„Å€ªëŠ4ÆáÈîØ0÷C#çCÒ«ðéËtRQl_ë‘eæÁŒÕpõC“"p2 ®W‘<è3ÒRÁɨIM…p§Pâ73›$€‚"hƒ‚!-µÃbQËvmAîÜFà†ÀÐQcÄÑ{߃œfÂó e½5yp¹Àf¼aBøú{¨¬ð‚ù¯@Ž{cÀü'¯@2Ì)©¯ TB °ñ‡˜¸|Îå‚L á0ý9ð6.C¹´‘L·¶2†”aȨÿ»iµZé²I©¢Æ*Qãrç°v†ì]3£'†ÝÊD’ŠÐ1vRaàPÈBÕ5¶¬øöLˤ8Ra È‘ÓÇ`?ÿ>Q}\ÝÝÌ"Ý96..ÞËûR §ÏîÍ/`ý‘“ªöÓhÿ¸TõÇ%å{^A©#˜³žã user¹j• ß+õÁ_s5ü}IÞßßuôvÔ <´lV]KH\‰©=¶¡ àclÃŽËÆ7À}-Ôv6ík‡íìåîçãØ¿o,`çìŒFIÍßìi[ö–µ@P Œ «<{¾«³‡Ÿ”¯·—§‡ÒŠ+Û²‹Ñ^+m°ÃâûM›650(=X.®Z"4°¿ÜŽÍ|‰’?À|¡ÌnÊÄÉS¦ ŠÅau§#n™]K]QªZø‰šÐ¡ð¥ ÛL¡éê°v:l>EÞåÜ´Nbw¼É$;G…„ìÅ;€~Ks Ï6ýxzæ ¢Z8ýtøÃÌ¢œ@ª›ÒKð“¦Ç†¤y°æ'X™ y§@°ŽÂ”Ù&el–¸lPÑIDAT,™!·¦¼m_¨„ë [ ’\:~þ|Hs’\‹ßÀ§`qšIêfy,7ŠÞ¼ŠÀän]¦Ÿˆ`Ç[´ÊÝ(-ܘ 3‡Ðq…G`¼ik ‰Wë¹ï_¿‡ˆöÚ§|÷ÉÌöðÖ7ä ¯n„ªupì5ÝBJ»—Áò†ô¡90“bB*Ø>6Sƒ`Å&Xk:È]_¬üºJOŒцq¢/#éؼ¼IúTÒëÔg7|nÚËx{Qi°Ð«½ sÌW5ëqÅõ|»Ü()ƒYQæiôU¬!I'¤«<ëöúJíÉ$’œ_o"Ó¥Ç!a{kÝŸ¿hÓ7îAÔ{÷”|Ưß )iÀ{7¿û€k+OX\{°õ¼îÜÀ`zâ<·óϼvºÅÊ/±k²S›î:Ôßd¹À`±´hôÃ`Š5¶'˜Ê+–ƒwl¿˜øýíì 4U²j‰Duí†æëol›š’^ZÐçï‹ËŠK.^¹úó›Ùå^wŠm•âa¢Fõl÷Ϙ¨žÈžýœ´]h-!÷Û¨'ög8cGÔ–;“-T*Üa0~b2û³XóU*[ îÚ„.lÐìëÊŒìàäÈd1"lmlx\gg— ?ßßÀ€gg.µ;“FÓrè§¶·—[ ™ ÆçöÎrwÏ‘á‰#’úÅõ÷Gõ2·pè°õ&x†òVxLldt¥©æp­x,6úñ5€¶˜Á8Å´÷`*æ¨îZÍ7d_i“ŠÞìG!D¢º³ WdF›¡€›wøùAÕ% %ä ¢“or•-CL–ÂäPÃ'ñõ¦ž¸Š/P¬LC,Ö¸ ˆî5á8ṳ̀HO,¤åöV ¡¯–ªÝ+ˆ¸úõ#h(ß’’ :ð¤%0؇x” Ó’á Åð¦}ŒX¾Žx¤‡ª={_"2æ¥uk_‹%Çñ`3YBÖ"82&ë§½2ïÄb–í‚;È=›ÉUÚ’(=+H.èiéEÒª± aœ/¬_EÜ2'> Ôôec@8—G3†OÆÂzÝëc“b‚–,züL_5Ûi†}áS8hÔ}˜xé Š~#bs Äð=ÂE¿Ðï¾$=Îvüð\žÍú –”Á’bxæËç]£Ø{¯Ýyö+á­ÛÐoÞhàÿ KYð÷–Àá|—:~Ç;Þÿòdø[{YA±1Q±¯,~ãÄÉÓĦIzHvîl8´–ɺÍ`¬arßœ3ÿâåËx¾L&+/¯8~æìGÛ¶¿²èµ)©Oy.¶²ÚËb•†¤6„¬ŸðŠØ0€ÅOrrŸÈwɱɶƶ‰ã8Dxø :bñ+K¿è;ä.‹ƒ«ê‡ÎŒŸTõ› ¥Y lC'9¥J¡oŽ> ÏÍ«òòÂÄï1¬ƒ]¼Æ¥NصkwqQ±J.W‰%_ìj‰A§èk„5±.9°mñëÕÕ¨öÀBÔE³2^wôdíáå?™.ª€ Ÿ‘·4r¤†Ñ›e2,´û—й–f&Õ!aÀºp|¦O©ï>i‡ z&#ŠBÄÿ&Ø6”þ˜…î½b0cl¸ˆ…6üc .c >CÏMx!*Úös·áp£Êo±›®'P/DÂù;‹k­~zþá¹ÿï7•cóÝV¸ðƒ‡D?0uô¨ýb¸¶(ð'¡½]õîJùÎíxh`§“ï9G›p$•h/‹: .7 À‰ýû5O+ª®¾q-·øÆõ_î”ÞÎ/ÓZÕ‡”#)H‹#IlT\R¢×ý¥¥b©Z-÷³wŒíÙ¿Ü­ÑÃÿà£[×B• ¬;ôèϼk·TK_³›ÁsàŠ&Öëªù R(îlü̶­í"¹º¸Ä&\0'cTò;&SuýFÑÆMœÌCÖRém`lbñ혲·5ê0µÚi÷÷‚ÈH·3¬ÀÍ­åÅ>ß½©uxPàè”ááa7sr/øÉ€ü|¥Ì÷ààìZ·â=/?o6îÕú ‚ëÔ´%¶õÂÅïX2ܤÊk_Áøùº˜Xظj— ôêžx€¤Q¦60ÉD.ü®m'$9zHÓaÇ|XINâö5BŠnõ+O цd8}ûxõ=d&†Ôè‘~8n¸"]u‹è9ã² ë›;`}‘cõW°{uß 2 /“³u¼‰'*oXBÎÐg¾¿7K,Ör8ZÒ^ÇÆÚ:ÀÃÃÏÝ-9ºOÓ”É%W®ÔìøÒád-ꜣ jʸø—þöª§‡«T,‘ˤL­ÖÊÆÆÁÁkcƒÊ O÷³v6?oþ·û©ß‡K¥ÞZ-³¡\ðö[Íû¾óLj”¨ŠŠfÛÛqÑ:–ÉR²XÍßÏýéO*˜ho?|ÎóÉ 57o·ïØ!ü~Ÿ5®rpUİ;aÇuŽŒt?^ÕÐçòÙ8aCÃß^í8yJüâ‹Îâ"úD¿±ðE-ïmÏsˆ5r•÷˜”“N×2úÌi…\¶sk¹PÈþŸ5LOÒ#çþRB·;Û0ˆ;—p×5$ -0 7¿5á Ó` Iµ—áœ\£rb±ù]eÀáù0…¢éýS™ã骊%(QÿòV›Ÿ&ˆ·ïÃùí0]Ÿ':«+è×µ£a­iTwSâ*Úi¬H&ü'²æCás™Â’=ÄÃeÿ2G‘ž*Q„J²:Ó²Íïü‘à~ F$ˆÞ(,c‰yE˜Ì,$!Äeë-Zš„‘T Ãåè¡_"¡.z4 ƒë§è’Fš‰áŒ*¸Se$ #ã_fô˜ Î[E÷és…­yR³{ê%ž5‘P©flƒÏqH êKÞdÜWêÙ§ƒQ^5q ˆ(Õá°*zq;¶‹6Ì¿jö+_‡Ž¿qâ&ëØç¬ºk1íU!òö6®Ÿƒ«³ßÞX笉m™4µþÀ<™Ì´qëϦJÛ¥«àÀ!EP€çݶvLk+•-K$ÔŠD –Ù· "®^ª(k5M8 !¡ò@!î`pX|dŽŽ_ U #†%²Ù¬ƒCª²Ž¹WÝ W*ƒÔjþ«ümÙÜ|ž‡“k¿5ÏF,‰näØ*ˆÆ9njYaÀŽÏaëÖÆSgÒ¶»WŒ_™6U^‘±QO?ýÌÄ!5Õu·v¸tÍŒ‰¤~È´IM± ŽäYi*Mkëíꉋ‹ÓÒ×ãúó–¾Y}·‰]vËK£Pÿ°7{ìèÑÏ>ÍHE4‡`‚îÇåæ©:2 ƒŒÈjM—ï 3Sÿò3V ¨o][)ɬß8µ…ÖôÓÅ“¡ñ OÜÆf@’]̨sºÞ-þÐôÿa øæ¸ð ¶Vår™„«°DAˆ\PkŠë´ˆôÃ~. m“»VÂtv%:§u;SÑ;wAÉ…¸;Ç‚$ŽÜƒïg…¼½U(—+¬mlõ¨ä¹¹6.yí‡æ¦Ž‹WmE¸É¡Å†¶  §xÀl”R¹ à*gÇ8÷õÀél;r8+¢½!R«¸ó{~øí´ÿ­ë‡ÈÂÃúÖÕ ž2â×UoÿècÆÛ—Ô ÷ì?âF°Ãm÷B­j€Û$‚Òé±k …âµ:®€Ñ§àà5˜O$¸´Î”+2¡ö6(= “ÖaÜ•ïèJ6Áω[„DGx…œäÆ~?dÀR ˜6ØM0Ý=Màü÷ {jöÂ*’Zá3d3Ç7Èj&3®@ö“¥ŒIF7»tæªFqæAœr®I†•ø²³a^¤n¹`$0Ïð¨î•ôŠáØ©®N¹Ào‰„>Æ4ëQUmTNÓEÚå".†Iòˆg(c9ÿ!i­a”’’‡%šS‡Sp½É°Î£r´ÖÐ9½=é@//ü2!_dØÌQŸY<{3œ¹?Ò´q¡« ü]œ‰bÌ%Kzá’Ù£û¸Õ-Œî#ËcÔ¼ë{Ó$¤˜Í+$„6ÀF¸\­¥Ð\„ì¡€gSÀsÏPI`ß%¨*‚úR—¦œ¢Æa¤Õ¸š$ލd­¯«wtðq'!$ï4ŒèÓ‡³jŵ[·J‹Ëjëê›Zš¯47Û¶µ£|I#lGY;'2Æ XÌF{Ç•,ã°y"Akck jttwue0BB‚B‚§¦ŽÎ/*ºœ§àNÉoy×;ê›[­$Ží-}µœ¿FçF°H/î­¿ ë±³j±±Q{zùùÌ?näÈØ¸~ö¸p¥Þ…ÁHˆuÿÿýrD¼¿ƒ ÕÓÓÓÝݽ‹ÃætííÕU7LQx²¶Ë ±°f¼0f|Jo¸EêÐ0-J ¨Ù“*ÐÈâ&J 9„2öÂG¤RDpaSÈ€sŸ1Í-ºxÒCÂΓŠëH”-ÑNWˆîù¹Dâ §à)_¨¿ÿM7iÙÑ jE ¬¡k)+?BèìmP8ëZ`¸ÚÇÃÇé°<“ŽY±NÇŠ Iˆ ëÖCä*pVBM1ÚN,›Ö^ÊéeÙ; {Ṛ̂¸ŒÈ\QM"p#éÚ«'às’.Ït'¼žBp1Y|½BçÙ ÏÄPu‚¨ ª„D¸²ÌP,¢º–$1†bé F™ˆN†ôH "jÔÀ©a9Ée1áš]´žc›4¦8Ö˜Oö»rÏÁ–•E2«9憕U!4v®ƒ~ž(€å³iöŸ´Í`®Šh•mB)S‰ŠÆjøÑlÜHšè‹qã,7¾ ÓÛ`Ã2ZúWx2tž +HŸÑûAÏ=¨}ÄJ9Ù‰¾›NF߯Ðj'dØse°æ%²*¨-Ÿ¿†•ëÈjc¡$—`„x†W95ØÊ ¼ ¢ÜÈyÂrÂG`t”ÉŒ²™Fü¾‰ðL,ˆáßà“ùä<  {mŠMÿWÿý…:ZÓ6\ò«¬*Á•5‡%ôÜE_>ÿé¥kmPÕ lÔåÙü¾ìýæRœ1 7èy"ù¦ËÁøËLŸùê‡ï[$­t©:]•J™R© v9E†cÞf.‡Ã³µUïü²ùõ×ÔR)€ÏÁ‘óÁ»‹–¼†Ž ʺw„«‰šÚÛ«ë뛚Z«*«+«Ê››šp›Uôd9jÔ >Ñή®„‹Cï>²ñhºjÃågPÿÉ€; …‘rãÚü’áuNÒ&Œ/Í‚Dݤo?ø¶=Gíx»³&‡¹| ïï§ xMV†1fµ,Ë„·¦POàævH]D‡)UI!‰˜Ê,Zöm[vb-Õ¡SS—t8¼†x›Äßù;¼¨ãdÆñI»àÀ<ãó°¡ÍÉ€4¨»yÛ¾ç»jYµW¨ñ Ñ$áÜ4á }XHó¶“ÃLjLböïp# !m´ŒMû©4W´à­sðÖç¢|ôô·t@cxôúÃüy¿8Vè:#N®™:†·Ä<À4Û)mÌc@šiêÎo!߮ä ¦óh¾ÞUZ"Nï_†§HÍì6qN‚d‰†Æ˜ö DŒ÷1yý-åÐçáNÁE<Æw;Œ¤†%Iší+`| QüdLWÌ?§Ok½O22áÓ)°{ªa’AT‘ßæ%hÝ€3â.a!Tl7¤ì2Éÿm$Òùûǧ½~élœÞŒ ²¶~R ‘ô“…^ˆ¤]Ü!lÎÔÆ€»¥â¯Ç²^ž™ÆÂ¡­²¬¬CÜñ`Œw7²uvÆú-chï$–I$b4|•Úòxnnn÷«`’íï±ùò¡} ìÓRå"?Xø*Lm¾† Iƒ-Èd„­'‰wl#3P£úÍ&/ü™nÛ ‡-y¦F‡ú„æ@Ï0ÚkÄãRUº]1þÎî! œtYÒ>‚-7É¢{b¸úDÂÆ¡8ˆ=µhE'ÞOt´¬«ô3?‡fXk¬„O†Ås`æD!)¸.i J³lÌÉ«Þã/e9\ ëÞ1¸ÔQ¹36Á?^ÕyØ’Î\Æ¥¢ :ò’åÇ7I¥¿1KFÅc×§¥Á´ ˆ7e´)+áâ(Xý½>Ðs4xa>LJéÔpå#ÈúìXG³,yñ ˜klŽÉ†¨ØNI}û0|ÕaÀ)ì[OR%ÃÎM&§wa¨›Ä9*¾Ÿ1a÷àƒ ¥÷Ç\É„˜P·D„b+°Ç…°õjÔú@Ÿ9^Z3žÖíÌÁ†¦^‡8 ðŒ6Ø8á-êóŒ ”u$\< ‹Æ›4) ýøžƒ1ä¦,D+ÜߊŽe_|ÿ¾f0l{{Hîþ &ó»YÐVþ̾…ÏB+®*ôË‚ÞW (Aƒ8%uÞª£’’pÈÒ÷þ‘´¡¡zP²Mu¡•V›p,mÂË›6„ãq½a<½¯æ?%¥ Ðù-/y|â0² ¾× È@ 'cZÞ}ŽÝÏÃÉpXµ¬“—¿ NþgÛ™¾t. 7«¹Mb4jƒàhƒ s‡ّB蟑Lô°\ÐׂÈ °­{‹}Þî‚&h’Ù„ºÂd£¤îòüÉñ‚Z²I@9“{M¢'éºýµ°9hõðt³Ô«É ²†$ø8\]À›d½Ô“Îÿï«;gï25 (©#8ø|ZØÕeʈD1 Nƒ°d´44ÓN=@iMïî]m‚3ôL€ï~‚²ãéªV1æê¨︊¾ Š[¿"ÅG#"=oÀ0úêã[®ƒ•;n;ŠË…G\ΌɚÏJÑ?g¢ööúÆÆ0T’?"ÆóèZú—”Ä7ÓbokE"h<óé1ÛÜo`n— Ø‚kð^â‡÷2éC%]&¹ú$méi¹ ¯ù^0­|È€“àï±'oÀ_@ï*Ƚ ô‘±ªVkð'%–=´zt¿=xÏ©l{ðïÝL¨—'Ãó!ÿ´²ëy”á{3ÜA¡V_áx,uiþÅJ¸ôõìÖ2´)PVþXî;ô§6 X}Ûµ¨#¬w½}»“ófRÞ`$o šŽ«ÌȰáÙ¹¸ÚÛ›˜$=ä›!Ë‘<=­vÛ}-8ÌÜKkkK+Õ°X¢fxÈÆX²?.Á±ï `Vpö#ºQ·³á¦ ÄuRÈwôýwüm¡‹‹…tFÕ“ƒsÌЄ®^v54¬ì*ÞgŒî”É!ö,=hÜ!MøÞ+†»¡™Ri³¸C}þgûã™I³+GsÔÑME‘s­Ì;o‹¨äG ÓʉÍ,`°òQž¤EÇg- …f1¯29WŽZ§0"¬›´2ÖÆÉ9",ØÕÕùrD™×*øÅ¹g J³ŽœÆ¯+ÊÚÚ„ÎÎô@ N-µÞ>ln¯…Ùf%wëîðÆëW•Êö–V¿+³s»Ïhyò߉{˜kYö –ü˱oQ’D*--)©®¯e˜)‘®­+nDH°¯ïÃzruÕ ¹DråÚöaH` þ8=Ÿ ÓU –8 ,°`à‰ÅÀ½Ã‹Ë‹[0`Á€O&ô6¥Oæë[ÞÚ‚ ,°`ÀÆ`Ž˽ X0ð„cÀžð`y} ,°`ÀÆ`Ž˽ X0ð„cÀžð`y} ,°`ÀÆ`Ž˽ X0ð„cÀžð`y} ,°`ÀÆ`Ž˽ X0ð„cÀžð`y} ,°`ÀÿèÕ‚ÚîllIEND®B`‚execnet-1.0.9/doc/Makefile0000644000000000000000000000617611473521746014103 0ustar rootroot# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* install: clean html rsync -avz $(BUILDDIR)/html/ code:www-execnet/ html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/execnet.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/execnet.qhc" latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." execnet-1.0.9/doc/conf.py0000644000000000000000000001434411473521746013736 0ustar rootroot# -*- coding: utf-8 -*- # # execnet documentation build configuration file, created by # sphinx-quickstart on Wed Sep 30 21:16:59 2009. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.append(os.path.dirname(os.path.dirname(__file__))) # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.txt' # The encoding of source files. #source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = 'execnet' copyright = '2009, holger krekel and others' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. import execnet version = "1.0.8" # The full version, including alpha/beta/rc tags. release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. html_theme = 'sphinxdoc' #html_index = 'index.html' html_sidebars = {'index': 'indexsidebar.html', } # 'basics': 'indexsidebar.html', #} #html_additional_pages = {'index': 'index.html'} # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = "codespeak.png" # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # If false, no module index is generated. html_use_modindex = False # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = False # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'execnetdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'execnet.tex', 'execnet Documentation', 'holger krekel and others', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True execnet-1.0.9/doc/changelog.txt0000644000000000000000000000013611473521746015121 0ustar rootroot:tocdepth: 2 .. _changes: execnet CHANGELOG ******************** .. include:: ../CHANGELOG execnet-1.0.9/doc/index.txt0000644000000000000000000000555111473521746014307 0ustar rootroot .. image:: _static/pythonring.png :align: right Python_ is a mature dynamic language whose interpreters can interact with all major computing platforms today. **execnet** provides a `share-nothing model`_ with `channel-send/receive`_ communication for distributing execution across many Python interpreters across version, platform and network barriers. It has a minimal and fast API targetting the following uses: * distribute tasks to (many) local or remote CPUs * write and deploy hybrid multi-process applications * write scripts to administer multiple environments .. _`channel-send/receive`: http://en.wikipedia.org/wiki/Channel_(programming) .. _`share-nothing model`: http://en.wikipedia.org/wiki/Shared_nothing_architecture .. _Python: http://www.python.org Features ------------------ * automatic bootstrapping: no manual remote installation. * safe and simple serialization of python builtin types (no pickle) for sending/receiving structured data messages. * flexible communication: synchronous send/receive as well as callback/queue mechanisms supported * easy creation, handling and termination of multiple processes * well tested interactions between CPython 2.4-2.7, CPython3.1, Jython 2.5.1 and PyPy 1.1 interpreters. * fully interoperable between Windows and Unix-ish systems. * many tested :doc:`examples` Known uses ------------------- * `py.test`_ uses it for its `distributed testing`_ mechanism. * Jacob Perkins uses it for his `Distributed NTLK with execnet`_ project to launch computation processes through ssh. He also compares `disco and execnet`_ in a subsequent post. * Ronny Pfannschmidt uses it for his `anyvc`_ VCS-abstraction project to bridge the Python2/Python3 version gap. * sysadmins and developers are using it for ad-hoc custom scripting .. _`py.test`: http://pytest.org .. _`distributed testing`: http://codespeak.net/py/dist/test/dist.html .. _`Distributed NTLK with execnet`: http://streamhacker.com/2009/11/29/distributed-nltk-execnet/ .. _`disco and execnet`: http://streamhacker.com/2009/12/14/execnet-disco-distributed-nltk/ .. _`anyvc`: http://bitbucket.org/RonnyPfannschmidt/anyvc/ Project status -------------------------- The current 1.0 series aims at :doc:`basic API ` stabilization, improved tracing and robust termination. The 1.1 series will target setting up permanent networks and offering unix-shell-like capabilities to spawn processes and applications. execnet was conceived and is `actively developed`_ by `Holger Krekel`_. The package is licensed under the GPL Version 2 or later, at your choice. Armin Rigo and Benjamin Peterson have done major contributions which are MIT-licensed. .. _`basic API`: basics.html .. _`actively developed`: http://bitbucket.org/hpk42/execnet/changesets .. _`Holger Krekel`: http://twitter.com/hpk42 .. toctree:: :hidden: support implnotes install rel-1.0.0 execnet-1.0.9/doc/install.txt0000644000000000000000000000245011473521746014641 0ustar rootrootInfo in a nutshell ==================== **Pythons**: 2.4, 2.5, 2.6, 2.7, 3.0, 3.1.x, Jython-2.5.1, PyPy-1.2 **Operating systems**: Linux, Windows, OSX, Unix **Requirements**: plain distutils, setuptools_ or Distribute_ **Installers**: easy_install_ and pip_ or distutils **Distribution names**: * PyPI name: ``execnet`` * redhat fedora: ``python-execnet`` * debian: ``python-execnet`` * gentoo: ``dev-python/execnet`` **hg repository**: https://bitbucket.org/hpk42/execnet Installation ==================== Install a public `pypi release`_ via `easy_install`_ or pip_:: easy_install -U execnet or pip install execnet or hg clone https://hpk42@bitbucket.org/hpk42/execnet/ python setup.py install # or 'develop' or add checkout path to PYTHONPATH Next checkout the basic api and examples: .. toctree:: :maxdepth: 1 examples basics changelog .. _`easy_install`: http://peak.telecommunity.com/DevCenter/EasyInstall .. _pip: http://pypi.python.org/pypi/pip .. _`bitbucket repository`: http://bitbucket.org/hpk42/execnet/ .. _`execnet mercurial repository`: http://bitbucket.org/hpk42/execnet/ .. _`pypi release`: http://pypi.python.org/pypi/execnet .. _setuptools: http://pypi.python.org/pypi/setuptools .. _distribute: http://pypi.python.org/pypi/distribute execnet-1.0.9/doc/__init__.py0000644000000000000000000000000211473521746014532 0ustar rootroot# execnet-1.0.9/doc/examples.txt0000644000000000000000000000113111473521746015004 0ustar rootroot============================================================================== examples ============================================================================== .. _`execnet-dev`: http://codespeak.net/mailman/listinfo/execnet-dev .. _`execnet-commit`: http://codespeak.net/mailman/listinfo/execnet-commit Note: all examples with `>>>` prompts are automatically tested. .. toctree:: :maxdepth: 2 example/test_info.txt example/test_group.txt example/test_multi.txt example/hybridpython.txt example/test_debug.txt .. toctree:: :hidden: example/test_ssh_fileserver.txt execnet-1.0.9/doc/implnotes.txt0000644000000000000000000000233111473521746015203 0ustar rootroot gateway_base.py ---------------------- the code of this module is sent to the "other side" as a means of bootstrapping a Gateway object capable of receiving and executing code, and routing data through channels. Gateways operate on InputOutput objects offering a write and a read(n) method. Once bootstrapped a higher level protocol based on Messages is used. Messages are serialized to and from InputOutput objects. The details of this protocol are locally defined in this module. There is no need for standardizing or versioning the protocol. After bootstrapping the BaseGateway opens a receiver thread which accepts encoded messages and triggers actions to interpret them. Sending of channel data items happens directly through write operations to InputOutput objects so there is no separate thread. Code execution messages are put into an execqueue from which they will be taken for execution. gateway.serve() will take and execute such items, one by one. This means that by incoming default execution is single-threaded. The receiver thread terminates if the remote side sends a gateway termination message or if the IO-connection drops. It puts an end symbol into the execqueue so that serve() can cleanly finish as well. execnet-1.0.9/doc/support.txt0000644000000000000000000000145711473521746014715 0ustar rootrootContact and Support channels ------------------------------ If you have interest, questions, issues or suggestions you are welcome to: * join `execnet-dev`_ for general discussions * join `execnet-commit`_ to be notified of changes * clone the `bitbucket repository`_ and submit patches * hang out on the irc.freenode.net #pylib channel * follow the `tetamap blog`_ or `Holger's twitter presence`_. * contact merlinux_ if you want to buy teaching or other support. .. _`Holger's twitter presence`: http://twitter.com/hpk42 .. _merlinux: http://merlinux.eu .. _`tetamap blog`: http://tetamap.wordpress.com .. _`execnet-dev`: http://codespeak.net/mailman/listinfo/execnet-dev .. _`execnet-commit`: http://codespeak.net/mailman/listinfo/execnet-commit .. _`bitbucket repository`: http://bitbucket.org/hpk42/execnet execnet-1.0.9/doc/check_sphinx.py0000644000000000000000000000073411473521746015455 0ustar rootrootimport py import subprocess def test_linkcheck(tmpdir): doctrees = tmpdir.join("doctrees") htmldir = tmpdir.join("html") subprocess.check_call( ["sphinx-build", "-W", "-blinkcheck", "-d", str(doctrees), ".", str(htmldir)]) def test_build_docs(tmpdir): doctrees = tmpdir.join("doctrees") htmldir = tmpdir.join("html") subprocess.check_call([ "sphinx-build", "-W", "-bhtml", "-d", str(doctrees), ".", str(htmldir)]) execnet-1.0.9/doc/rel-1.0.0.txt0000644000000000000000000000114711473521746014411 0ustar rootrootHi all, execnet enables zero-install ad-hoc instantiation of local or remote Python processes. It establishes channels for basic data communication. Data Serialization is independent from Pickle and is tested between Python2.4, 2.5, 2.6, 3.1 and Jython interpreters. execnet-1.0.0 (compared to 1.0.0b3) has bug fixes, new tested examples and introduces execnet.Group for managing a dynamic bunch of hosts. See the improved docs http://codespeak.net/execnet/ and below the changelog. I am set to improve and develop execnet further and thus am very interested in feedback and suggestions. cheers, holger execnet-1.0.9/doc/basics.txt0000644000000000000000000001230511473521746014437 0ustar rootroot============================================================================== API in a nutshell ============================================================================== execnet ad-hoc instantiates local and remote Python interpreters. Each interpreter is accessible through a **Gateway** which manages code and data communication. **Channels** allow to exchange data between the local and the remote end. **Groups** help to manage creation and termination of sub interpreters. .. image:: _static/basic1.png Gateways: bootstrapping Python interpreters =================================================== .. currentmodule:: execnet All Gateways are instantiated via a call to ``makegateway()`` passing it a gateway specification or URL. .. _xspec: .. autofunction:: execnet.makegateway(spec) Here is an example which instantiates a simple Python subprocess:: >>> gateway = execnet.makegateway() gateways allow to `remote execute code`_ and `exchange data`_ bidirectionally. examples for valid gateway specifications ------------------------------------------- * ``ssh=wyvern//python=python2.4//chdir=mycache`` specifies a Python2.4 interpreter on the host ``wyvern``. The remote process will have ``mycache`` as its current working directory. * ``popen//python=2.5//nice=20`` specification of a python2.5 subprocess; running with the lowest CPU priority ("nice" level). By default current dir will be the current dir of the instantiator. * ``popen//env:NAME=value`` specifies a subprocess that uses the same interpreter as the one it is initiated from and additionally remotely sets an environment variable ``NAME`` to ``value``. * ``socket=192.168.1.4:8888`` specifies a Python Socket server process that listens on 192.168.1.4:8888`` .. _`remote execute code`: remote_exec: execute source code remotely =================================================== .. currentmodule:: execnet.gateway All gateways offer a simple method to execute source code in the connected interpreter: .. automethod:: Gateway.remote_exec(source) It is allowed to pass a module object as source code in which case it's source code will be obtained and get sent for remote execution. ``remote_exec`` returns a channel object whose symmetric counterpart channel is available to the remotely executing source. .. method:: Gateway.reconfigure([py2str_as_py3str=True, py3str_as_py2str=False]) reconfigures the string-coercion behaviour of the gateway .. _`Channel`: .. _`channel-api`: .. _`exchange data`: Channels: exchanging data with remote code ======================================================= .. currentmodule:: execnet.gateway_base A channel object allows to send and receive data between two asynchronously running programs. .. automethod:: Channel.send(item) .. automethod:: Channel.receive(timeout) .. automethod:: Channel.setcallback(callback, endmarker=_NOENDMARKER) .. automethod:: Channel.makefile(mode, proxyclose=False) .. automethod:: Channel.close(error) .. automethod:: Channel.waitclose(timeout) .. autoattribute:: Channel.RemoteError .. autoattribute:: Channel.TimeoutError .. _Group: Grouped Gateways and robust termination =============================================== .. currentmodule:: execnet.multi All created gateway instances are part of a group. If you call ``execnet.makegateway`` it actually is forwarded to the ``execnet.default_group``. Group objects are container objects (see :doc:`group examples `) and manage the final termination procedure: .. automethod:: Group.terminate(timeout=None) This method is implicitely called for each gateway group at process-exit, using a small timeout. This is fine for interactive sessions or random scripts which you rather like to error out than hang. If you start many processes then you often want to call ``group.terminate()`` yourself and specify a larger or not timeout. remote_status: get low-level execution info =================================================== .. currentmodule:: execnet.gateway All gateways offer a simple method to obtain some status information from the remote side. .. automethod:: Gateway.remote_status(source) Calling this method tells you e.g. how many execution tasks are queued, how many are executing and how many channels are active. Note that ``remote_status()`` works even if the other side is busy executing code and can thus be used to query status in a non-blocking manner. rsync: synchronise filesystem with remote =============================================================== .. currentmodule:: execnet ``execnet`` implements a simple efficient rsyncing protocol. Here is a basic example for using RSync:: rsync = execnet.RSync('/tmp/source') gw = execnet.makegateway() rsync.add_target(gw, '/tmp/dest') rsync.send() And here is API info about the RSync class. .. autoclass:: RSync :members: add_target,send Debugging execnet =============================================================== By setting the environment variable ``EXECNET_DEBUG`` you can configure a tracing mechanism: :EXECNET_DEBUG=1: write per-process trace-files to ``execnet-debug-PID`` :EXECNET_DEUBG=2: perform tracing to stderr (popen-gateway slaves will send this to their instantiator) execnet-1.0.9/execnet.egg-info/0000755000000000000000000000000011760165371015006 5ustar rootrootexecnet-1.0.9/execnet.egg-info/PKG-INFO0000644000000000000000000000401111473521746016102 0ustar rootrootMetadata-Version: 1.0 Name: execnet Version: 1.0.9 Summary: execnet: rapid multi-Python deployment Home-page: http://codespeak.net/execnet Author: holger krekel and others Author-email: holger at merlinux.eu License: GPL V2 or later Description: execnet: rapid multi-Python deployment ======================================================== .. _execnet: http://codespeak.net/execnet execnet_ provides carefully tested means to ad-hoc interact with Python interpreters across version, platform and network barriers. It provides a minimal and fast API targetting the following uses: * distribute tasks to local or remote CPUs * write and deploy hybrid multi-process applications * write scripts to administer a bunch of exec environments Features ------------------ * zero-install bootstrapping: no remote installation required! * flexible communication: send/receive as well as callback/queue mechanisms supported * simple serialization of python builtin types (no pickling) * grouped creation and robust termination of processes * well tested between CPython 2.4-3.1, Jython 2.5.1 and PyPy 1.1 interpreters. * fully interoperable between Windows and Unix-ish systems. Platform: unix Platform: linux Platform: osx Platform: cygwin Platform: win32 Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Operating System :: POSIX Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: MacOS :: MacOS X Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: System :: Distributed Computing Classifier: Topic :: System :: Networking Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 execnet-1.0.9/execnet.egg-info/SOURCES.txt0000644000000000000000000000326011473521746016676 0ustar rootrootCHANGELOG LICENSE MANIFEST.in README.txt conftest.py setup.py doc/Makefile doc/__init__.py doc/basics.txt doc/changelog.txt doc/check_sphinx.py doc/conf.py doc/examples.txt doc/implnotes.txt doc/index.txt doc/install.txt doc/rel-1.0.0.txt doc/support.txt doc/_static/basic1.png doc/_static/codespeak.png doc/_static/execnet.png doc/_static/pythonring.png doc/_templates/indexsidebar.html doc/_templates/layout.html doc/example/conftest.py doc/example/funcmultiplier.py doc/example/hybridpython.txt doc/example/popen_read_multiple.py doc/example/py3topy2.py doc/example/redirect_remote_output.py doc/example/remote1.py doc/example/remotecmd.py doc/example/servefiles.py doc/example/svn-sync-repo.py doc/example/sysinfo.py doc/example/test_debug.txt doc/example/test_funcmultiplier.py doc/example/test_group.txt doc/example/test_info.txt doc/example/test_multi.txt doc/example/test_ssh_fileserver.txt execnet/__init__.py execnet/apipkg.py execnet/deprecated.py execnet/gateway.py execnet/gateway_base.py execnet/gateway_socket.py execnet/multi.py execnet/rsync.py execnet/rsync_remote.py execnet/threadpool.py execnet/xspec.py execnet.egg-info/PKG-INFO execnet.egg-info/SOURCES.txt execnet.egg-info/dependency_links.txt execnet.egg-info/top_level.txt execnet/script/__init__.py execnet/script/loop_socketserver.py execnet/script/quitserver.py execnet/script/shell.py execnet/script/socketserver.py execnet/script/socketserverservice.py execnet/script/xx.py testing/__init__.py testing/runtest.py testing/test_basics.py testing/test_channel.py testing/test_gateway.py testing/test_multi.py testing/test_rsync.py testing/test_serializer.py testing/test_termination.py testing/test_threadpool.py testing/test_xspec.pyexecnet-1.0.9/execnet.egg-info/dependency_links.txt0000644000000000000000000000000111473521746021057 0ustar rootroot execnet-1.0.9/execnet.egg-info/top_level.txt0000644000000000000000000000001011473521746017532 0ustar rootrootexecnet execnet-1.0.9/setup.py0000644000000000000000000000467311473521746013410 0ustar rootroot""" execnet: rapid multi-Python deployment ======================================================== .. _execnet: http://codespeak.net/execnet execnet_ provides carefully tested means to ad-hoc interact with Python interpreters across version, platform and network barriers. It provides a minimal and fast API targetting the following uses: * distribute tasks to local or remote CPUs * write and deploy hybrid multi-process applications * write scripts to administer a bunch of exec environments Features ------------------ * zero-install bootstrapping: no remote installation required! * flexible communication: send/receive as well as callback/queue mechanisms supported * simple serialization of python builtin types (no pickling) * grouped creation and robust termination of processes * well tested between CPython 2.4-3.1, Jython 2.5.1 and PyPy 1.1 interpreters. * fully interoperable between Windows and Unix-ish systems. """ try: from setuptools import setup, Command except ImportError: from distutils.core import setup, Command def main(): setup( name='execnet', description='execnet: rapid multi-Python deployment', long_description = __doc__, version='1.0.9', url='http://codespeak.net/execnet', license='GPL V2 or later', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], author='holger krekel and others', author_email='holger at merlinux.eu', cmdclass = {'test': PyTest}, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU General Public License (GPL)', 'Operating System :: POSIX', 'Operating System :: Microsoft :: Windows', 'Operating System :: MacOS :: MacOS X', 'Topic :: Software Development :: Libraries', 'Topic :: System :: Distributed Computing', 'Topic :: System :: Networking', 'Programming Language :: Python', 'Programming Language :: Python :: 3'], packages=['execnet', 'execnet.script'], ) class PyTest(Command): user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): import sys,subprocess errno = subprocess.call([sys.executable, 'testing/runtest.py']) raise SystemExit(errno) if __name__ == '__main__': main()execnet-1.0.9/setup.cfg0000644000000000000000000000007311473521746013505 0ustar rootroot[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 execnet-1.0.9/CHANGELOG0000644000000000000000000001621511473521746013103 0ustar rootroot1.0.9 -------------------------------- - add gw.reconfigure() to configure per gateway options. Currently supported: py2str_as_py3str and py3str_as_py2str to configure string deserialization - channel.makefile() objects now have a isatty() returning False - group.allocate_id(spec) allows to early-determine an (automatic) id - internal refactorings and cleanups (thanks Ronny Pfannschmidt): - refactor message types into received handler functions - refactor b(chr(opcode)) to bchr(opcode) - reorder Message ctor args, rename msgtype to msgcode - refactor gateway.send to take message's init args instead of a message - inline and remove Message.writeto/readfrom - refactor collection loading to avoid the indirection over tuple - remove the unused NamedThreadPool 1.0.8 -------------------------------- - new ``gateway.remote_exec(func, **kwargs)`` style fo executing a pure function with parameters. The function on the remote side also needs to accept a ``channel`` which allows it to communicate back and forth. Thanks to Ronny Pfannschmidt for implementing it with special kudos to Maciej Fijalkowski for writing a "pure-function" checker so that on Python2.6 onwards non-pure functions will be rejected. - enhance rsyncing to also sync permissions (stat().st_mode) of directories and files. (should also resolve http://bitbucket.org/hpk42/py-trunk/issue/68/) - fix rsyncing of symlinks, thanks to Charles Solar (should also resolve http://bitbucket.org/hpk42/py-trunk/issue/70/) - update internal usage of apipkg to 1.0b6 - remote_exec(module) now makes sure that the linecache is updated before reading and sending the source. thanks Ronny, Matt. - removed all trailing whitespace from source files 1.0.7 -------------------------------- - try to avoid a random KeyboardInterrupt Error when threads are ending. - extend xspec syntax to allow for one or multiple "env:NAME=value" environment variable settings which will be set on the remote side. (thanks Jakub Gustak) 1.0.6 -------------------------------- - fix jython/windows interactions - fix waitclose/callback-with-endmarker race condition - fix race condition where multiple threads sending data over channels would crash the serializer and process 1.0.5 -------------------------------- - more care during receiver-thread finalization during interp-shutdown, should get rid of annoying and meaningless exceptions - fix glitch in ssh-fileserver example - experimentally add "setup.py test" support - will run py.test 1.0.4 -------------------------------- - try to deal more cleanly with interpreter shutdown setting globals to None. this avoids (hopefully) some bogus tracebacks at process exit. 1.0.3 -------------------------------- - refine termination some more: CTRL-C and gateway.exit will now try harder to interrupt remote execution. this helps to avoid left-over ssh-processes. - fix read-on-non-blocking-files issue probably related to jython only: the low-level read on subprocess pipes may be non-blocking, returning less bytes than requested - so we now loop. - Windows/python2.4: fix bug that killing subprocesses would fail - make RemoteError and TimeoutError available directly on execnet namespace - fix some doc and test issues (thanks thm and ronny), add ssh_fileserver example - update internal copy of apipkg - always skip remote tests if no ssh specs given 1.0.2 -------------------------------- - generalize channel-over-channel sending: you can now have channels anywhere in a data structure (i.e. as an item of a container type). Add according examples. - automatically close a channel when a remote callback raises an exception, makes communication more robust because until now failing callbacks rendered the receiverthread unuseable leaving the remote side in-accessible. - internally split socket gateways, speeds up popen-gateways by 10% (now at <50 milliseconds per-gateway on a 1.5 GHZ machine) - fix bug in channel.receive() that would wrongly raise a TimeoutError after 1000 seconds (thanks Ronny Pfannschmidt) 1.0.1 -------------------------------- - revamp and better structure documentation - new method: gateway.hasreceiver() returns True if the gateway is still receive-active. remote_status now only carries information about remote execution status. - new: execnet.MultiChannel provides basic iteration/contain interface - new: execnet.Group can be indexed by integer - new: group.makegateway() uses group.default_spec if no spec is given and the execnet.default_group uses ``popen`` as a default spec. - have popen-gateways use imports instead of source-strings, also improves debugging/tracebacks, as a side effect popen-gateway startup can be substantially faster (>30%) - refine internal gateway exit/termination procedure and introduce group.terminate(timeout) which will attempt to kill all subprocesses that did not terminate within time. - EOFError on channel.receive/waitclose if the other side unexpectedly went away. When a gateway exits it now internally sends an explicit termination message instead of abruptly closing. - introduce a timeout parameter to channel.receive() and default to periodically internally wake up to let KeyboardInterrupts pass through. - EXECNET_DEBUG=2 will cause tracing to go to stderr, which with popen slave gateways will relay back tracing to the instantiator process. 1.0.0 -------------------------------- * introduce execnet.Group for managing gateway creation and termination. Introduce execnet.default_group through which all "global" calls are routed. cleanup gateway termination. All Gateways get an id through which they can be retrieved from a group object. * deprecate execnet.XYZGateway in favour of direct makegateway() calls. * refine socketserver-examples, experimentally introduce a way to indirectly setup a socket server ("installvia") through a gateway url. * refine and automatically test documentation examples 1.0.0b3 -------------------------------- * fix EXECNET_DEBUG to work with win32 * add support for serializing longs, sets and frozensets (thanks Benjamin Peterson) * introduce remote_status() method which on the low level gives information about the remote side of a gateway * disallow explicit close in remote_exec situation * perform some more detailed tracing with EXECNET_DEBUG 1.0.0b2 -------------------------------- * make internal protocols more robust against serialization failures * fix a seralization bug with nested tuples containing empty tuples (thanks to ronny for discovering it) * setting the environment variable EXECNET_DEBUG will generate per process trace-files for debugging 1.0.0b1 ---------------------------- * added new examples for NumPy, Jython, IronPython * improved documentation * include apipkg.py for lazy-importing * integrated new serializer code from Benjamin Peterson * improved support for Jython-2.5.1 1.0.0alpha2 ---------------------------- * improve documentation, new website * use sphinx for documentation, added boilerplate files and setup.py * fixes for standalone usage, adding boilerplate files * imported py/execnet and made it work standalone execnet-1.0.9/PKG-INFO0000644000000000000000000000401111473521746012755 0ustar rootrootMetadata-Version: 1.0 Name: execnet Version: 1.0.9 Summary: execnet: rapid multi-Python deployment Home-page: http://codespeak.net/execnet Author: holger krekel and others Author-email: holger at merlinux.eu License: GPL V2 or later Description: execnet: rapid multi-Python deployment ======================================================== .. _execnet: http://codespeak.net/execnet execnet_ provides carefully tested means to ad-hoc interact with Python interpreters across version, platform and network barriers. It provides a minimal and fast API targetting the following uses: * distribute tasks to local or remote CPUs * write and deploy hybrid multi-process applications * write scripts to administer a bunch of exec environments Features ------------------ * zero-install bootstrapping: no remote installation required! * flexible communication: send/receive as well as callback/queue mechanisms supported * simple serialization of python builtin types (no pickling) * grouped creation and robust termination of processes * well tested between CPython 2.4-3.1, Jython 2.5.1 and PyPy 1.1 interpreters. * fully interoperable between Windows and Unix-ish systems. Platform: unix Platform: linux Platform: osx Platform: cygwin Platform: win32 Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Operating System :: POSIX Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: MacOS :: MacOS X Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: System :: Distributed Computing Classifier: Topic :: System :: Networking Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 execnet-1.0.9/conftest.py0000644000000000000000000001173311473521746014070 0ustar rootrootimport execnet import py import os, sys import subprocess collect_ignore = ['build', 'doc/_build'] rsyncdirs = ['conftest.py', 'execnet', 'testing', 'doc'] winpymap = { 'python2.7': r'C:\Python27\python.exe', 'python2.6': r'C:\Python26\python.exe', 'python2.5': r'C:\Python25\python.exe', 'python2.4': r'C:\Python24\python.exe', 'python3.1': r'C:\Python31\python.exe', } def pytest_runtest_setup(item, __multicall__): if item.fspath.purebasename in ('test_group', 'test_info'): getspecssh(item.config) # will skip if no gx given res = __multicall__.execute() if 'pypy-c' in item.keywords and not item.config.option.pypy: py.test.skip("pypy-c tests skipped, use --pypy to run them.") return res pytest_plugins = ['pytester', 'doctest'] # configuration information for tests def pytest_addoption(parser): group = parser.getgroup("execnet", "execnet testing options") group.addoption('--gx', action="append", dest="gspecs", default=None, help=("add a global test environment, XSpec-syntax. ")) group.addoption('--gwscope', action="store", dest="scope", default="session", type="choice", choices=["session", "function"], help=("set gateway setup scope, default: session.")) group.addoption('--pypy', action="store_true", dest="pypy", help=("run some tests also against pypy-c")) def pytest_report_header(config): lines = [] lines.append("gateway test setup scope: %s" % config.getvalue("scope")) lines.append("execnet: %s -- %s" %(execnet.__file__, execnet.__version__)) return lines def pytest_funcarg__specssh(request): return getspecssh(request.config) def pytest_funcarg__specsocket(request): return getsocketspec(request.config) def getgspecs(config=None): if config is None: config = py.test.config return [execnet.XSpec(spec) for spec in config.getvalueorskip("gspecs")] def getspecssh(config=None): xspecs = getgspecs(config) for spec in xspecs: if spec.ssh: if not py.path.local.sysfind("ssh"): py.test.skip("command not found: ssh") return spec py.test.skip("need '--gx ssh=...'") def getsocketspec(config=None): xspecs = getgspecs(config) for spec in xspecs: if spec.socket: return spec py.test.skip("need '--gx socket=...'") def pytest_generate_tests(metafunc): if 'gw' in metafunc.funcargnames: assert 'anypython' not in metafunc.funcargnames, "need combine?" if hasattr(metafunc.function, 'gwtypes'): gwtypes = metafunc.function.gwtypes elif hasattr(metafunc.cls, 'gwtype'): gwtypes = [metafunc.cls.gwtype] else: gwtypes = ['popen', 'socket', 'ssh'] for gwtype in gwtypes: metafunc.addcall(id=gwtype, param=gwtype) elif 'anypython' in metafunc.funcargnames: for name in ('python3.1', 'python2.4', 'python2.5', 'python2.6', 'python2.7', 'pypy-c', 'jython'): metafunc.addcall(id=name, param=name) def getexecutable(name, cache={}): try: return cache[name] except KeyError: executable = py.path.local.sysfind(name) if executable: if name == "jython": popen = subprocess.Popen([str(executable), "--version"], universal_newlines=True, stderr=subprocess.PIPE) out, err = popen.communicate() if not err or "2.5" not in err: executable = None cache[name] = executable return executable def pytest_funcarg__anypython(request): name = request.param executable = getexecutable(name) if executable is None: if sys.platform == "win32": executable = winpymap.get(name, None) if executable: executable = py.path.local(executable) if executable.check(): return executable py.test.skip("no %s found" % (name,)) return executable def pytest_funcarg__gw(request): scope = request.config.option.scope group = request.cached_setup( setup=execnet.Group, teardown=lambda group: group.terminate(timeout=1), extrakey="testgroup", scope=scope, ) try: return group[request.param] except KeyError: if request.param == "popen": gw = group.makegateway("popen//id=popen") elif request.param == "socket": pname = 'sproxy1' if pname not in group: proxygw = group.makegateway("popen//id=%s" % pname) #assert group['proxygw'].remote_status().receiving gw = group.makegateway("socket//id=socket//installvia=%s" % pname) gw.proxygw = proxygw assert pname in group elif request.param == "ssh": sshhost = request.getfuncargvalue('specssh').ssh gw = group.makegateway("ssh=%s//id=ssh" %(sshhost,)) return gw execnet-1.0.9/MANIFEST.in0000644000000000000000000000042011473521746013416 0ustar rootrootinclude CHANGELOG include conftest.py include README.txt include setup.py include LICENSE graft doc graft testing prune doc/_build exclude *.orig exclude *.rej recursive-exclude execnet *.pyc *$py.class recursive-exclude testing *.pyc *$py.class prune .svn prune .hg execnet-1.0.9/README.txt0000644000000000000000000000034311473521746013362 0ustar rootrootWelcome to execnet and elastic distributed computing! Rapidly deploy tools and code to local or remote Python interpreters. See doc/ for more info, examples and contact info. have fun, holger krekel, holger at merlinux eu execnet-1.0.9/LICENSE0000644000000000000000000000106211473521746012670 0ustar rootrootThe execnet package is released under the provisions of the Gnu Public License (GPL), version 2 or later. See http://www.fsf.org/licensing/licenses/ for more information. This package contains some code and contributions from Armin Rigo, Benjamin Peterson, Carl Friedrich Bolz, Maciej Fijalkowski, Ronny Pfannschmidt and others which are useable under the MIT license. If you have questions and/or want to use parts of the code under a different license than the GPL please contact me. holger krekel, November 2009, holger at merlinux eu