From f3192eb78917d4aea931d3ca9db008c09cf4cf16 Mon Sep 17 00:00:00 2001 From: Alexander Afanasyev Date: Mon, 19 Dec 2016 17:11:20 -0800 Subject: [PATCH] build+ci: Upgrade build scripts, enable coverage and sanitizer flags Change-Id: I825ea4fdf4f40c4af06b5667af432f1c0eab368d --- .jenkins | 11 +- .jenkins.d/00-deps.sh | 20 ++ .jenkins.d/10-ndn-cxx.sh | 60 +++--- .jenkins.d/20-build.sh | 60 ++++-- .jenkins.d/30-test.sh | 44 +++- .jenkins.d/util.sh | 18 ++ .travis.yml | 31 ++- .waf-tools/boost.py | 292 ++++++++++++++++++++------- .waf-tools/coverage.py | 22 ++ .waf-tools/default-compiler-flags.py | 167 ++++++++++++--- .waf-tools/doxygen.py | 2 +- .waf-tools/pch.py | 5 + .waf-tools/sanitizers.py | 22 ++ src/logger.hpp | 16 +- tests/boost-multi-log-formatter.hpp | 214 ++++++++++++++++++++ tests/main.cpp | 115 ++++++++++- tests/wscript | 20 +- waf | 17 +- wscript | 19 +- 19 files changed, 939 insertions(+), 216 deletions(-) create mode 100755 .jenkins.d/00-deps.sh create mode 100644 .jenkins.d/util.sh create mode 100644 .waf-tools/coverage.py create mode 100644 .waf-tools/sanitizers.py create mode 100644 tests/boost-multi-log-formatter.hpp diff --git a/.jenkins b/.jenkins index b933b31..674d751 100755 --- a/.jenkins +++ b/.jenkins @@ -1,9 +1,10 @@ #!/usr/bin/env bash set -e -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) -for i in `find "$DIR/.jenkins.d" -type f -perm +111 | sort`; do - echo "Run: $i" - $i -done \ No newline at end of file +for file in "$DIR"/.jenkins.d/*; do + [[ -f $file && -x $file ]] || continue + echo "Run: $file" + "$file" +done diff --git a/.jenkins.d/00-deps.sh b/.jenkins.d/00-deps.sh new file mode 100755 index 0000000..41b93f0 --- /dev/null +++ b/.jenkins.d/00-deps.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -e + +JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +source "$JDIR"/util.sh + +set -x + +if has OSX $NODE_LABELS; then + brew update + brew upgrade + brew install boost pkg-config cryptopp openssl + brew cleanup +fi + +if has Ubuntu $NODE_LABELS; then + sudo apt-get -qq update + sudo apt-get -qq install build-essential pkg-config libboost-all-dev \ + libcrypto++-dev libsqlite3-dev libssl-dev +fi diff --git a/.jenkins.d/10-ndn-cxx.sh b/.jenkins.d/10-ndn-cxx.sh index fa278ac..e5f7585 100755 --- a/.jenkins.d/10-ndn-cxx.sh +++ b/.jenkins.d/10-ndn-cxx.sh @@ -1,39 +1,43 @@ #!/usr/bin/env bash -set -x set -e -cd /tmp -BUILD="no" -if [ ! -d ndn-cxx ]; then - git clone --depth 1 git://github.com/named-data/ndn-cxx - cd ndn-cxx - BUILD="yes" +JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +source "$JDIR"/util.sh + +set -x + +pushd "${CACHE_DIR:-/tmp}" >/dev/null + +INSTALLED_VERSION=$((cd ndn-cxx && git rev-parse HEAD) 2>/dev/null || echo NONE) + +sudo rm -Rf ndn-cxx-latest + +git clone --depth 1 git://github.com/named-data/ndn-cxx ndn-cxx-latest + +LATEST_VERSION=$((cd ndn-cxx-latest && git rev-parse HEAD) 2>/dev/null || echo UNKNOWN) + +if [[ $INSTALLED_VERSION != $LATEST_VERSION ]]; then + sudo rm -Rf ndn-cxx + mv ndn-cxx-latest ndn-cxx else - cd ndn-cxx - INSTALLED_VERSION=`git rev-parse HEAD || echo NONE` - sudo rm -Rf latest-version - git clone --depth 1 git://github.com/named-data/ndn-cxx latest-version - cd latest-version - LATEST_VERSION=`git rev-parse HEAD || echo UNKNOWN` - cd .. - rm -Rf latest-version - if [ "$INSTALLED_VERSION" != "$LATEST_VERSION" ]; then - cd .. - sudo rm -Rf ndn-cxx - git clone --depth 1 git://github.com/named-data/ndn-cxx - cd ndn-cxx - BUILD="yes" - fi + sudo rm -Rf ndn-cxx-latest fi sudo rm -Rf /usr/local/include/ndn-cxx sudo rm -f /usr/local/lib/libndn-cxx* sudo rm -f /usr/local/lib/pkgconfig/libndn-cxx* -if [ "$BUILD" = "yes" ]; then - sudo ./waf distclean -j1 --color=yes -fi +pushd ndn-cxx >/dev/null -./waf configure -j1 --color=yes --enable-shared --disable-static --without-osx-keychain -./waf -j1 --color=yes -sudo ./waf install -j1 --color=yes +./waf -j1 --color=yes configure --enable-shared --disable-static --without-osx-keychain +./waf -j1 --color=yes build +sudo ./waf -j1 --color=yes install + +popd >/dev/null +popd >/dev/null + +if has Linux $NODE_LABELS; then + sudo ldconfig +elif has FreeBSD $NODE_LABELS; then + sudo ldconfig -a +fi diff --git a/.jenkins.d/20-build.sh b/.jenkins.d/20-build.sh index 8220c31..e281a7d 100755 --- a/.jenkins.d/20-build.sh +++ b/.jenkins.d/20-build.sh @@ -1,32 +1,50 @@ #!/usr/bin/env bash -set -x set -e -sudo rm -Rf /usr/local/include/ChronoSync -sudo rm -f /usr/local/lib/libChronoSync* -sudo rm -f /usr/local/lib/pkgconfig/ChronoSync* +JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +source "$JDIR"/util.sh + +set -x + +git submodule init +git submodule sync +git submodule update # Cleanup sudo ./waf -j1 --color=yes distclean -# Configure/build in debug mode -./waf -j1 --color=yes configure --with-tests --debug +if [[ "$JOB_NAME" != *"limited-build" ]]; then + # Configure/build in optimized mode with tests + ./waf -j1 --color=yes configure --with-tests + ./waf -j1 --color=yes build + + # Cleanup + sudo ./waf -j1 --color=yes distclean + + # Configure/build in optimized mode without tests + ./waf -j1 --color=yes configure + ./waf -j1 --color=yes build + + # Cleanup + sudo ./waf -j1 --color=yes distclean +fi + +# Configure/build in debug mode with tests and without precompiled headers +if [[ "$JOB_NAME" == *"code-coverage" ]]; then + COVERAGE="--with-coverage" +elif ! has OSX-10.9 $NODE_LABELS && ! has OSX-10.11 $NODE_LABELS; then + ASAN="--with-sanitizer=address" +fi +./waf -j1 --color=yes configure --debug --with-tests --without-pch $COVERAGE $ASAN ./waf -j1 --color=yes build -# Cleanup -sudo ./waf -j1 --color=yes distclean - -# Configure/build in optimized mode without tests -./waf -j1 --color=yes configure -./waf -j1 --color=yes build - -# Cleanup -sudo ./waf -j1 --color=yes distclean - -# Configure/build in optimized mode with tests -./waf -j1 --color=yes configure --with-tests -./waf -j1 --color=yes build +# (tests will be run against debug version) # Install -sudo ./waf install -j1 --color=yes -sudo ldconfig || true +sudo ./waf -j1 --color=yes install + +if has Linux $NODE_LABELS; then + sudo ldconfig +elif has FreeBSD $NODE_LABELS; then + sudo ldconfig -a +fi diff --git a/.jenkins.d/30-test.sh b/.jenkins.d/30-test.sh index 7e6610e..9f7ec40 100755 --- a/.jenkins.d/30-test.sh +++ b/.jenkins.d/30-test.sh @@ -1,8 +1,44 @@ #!/usr/bin/env bash -set -x set -e -# Prepare environment -sudo rm -Rf ~/.ndn +JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +source "$JDIR"/util.sh -./build/unit-tests -l test_suite +set -x + +# Prepare environment +rm -Rf ~/.ndn + +if has OSX $NODE_LABELS; then + security unlock-keychain -p named-data +fi + +ndnsec-keygen "/tmp/jenkins/$NODE_NAME" | ndnsec-install-cert - + +BOOST_VERSION=$(python -c "import sys; sys.path.append('build/c4che'); import _cache; print(_cache.BOOST_VERSION_NUMBER);") + +ut_log_args() { + if (( BOOST_VERSION >= 106200 )); then + echo --logger=HRF,test_suite,stdout:XML,all,build/xunit-${1:-report}.xml + else + if [[ -n $XUNIT ]]; then + echo --log_level=all $( (( BOOST_VERSION >= 106000 )) && echo -- ) \ + --log_format2=XML --log_sink2=build/xunit-${1:-report}.xml + else + echo --log_level=test_suite + fi + fi +} + +ASAN_OPTIONS="color=always" +ASAN_OPTIONS+=":detect_leaks=false" +ASAN_OPTIONS+=":detect_stack_use_after_return=true" +ASAN_OPTIONS+=":check_initialization_order=true" +ASAN_OPTIONS+=":strict_init_order=true" +ASAN_OPTIONS+=":detect_invalid_pointer_pairs=1" +ASAN_OPTIONS+=":detect_container_overflow=false" +ASAN_OPTIONS+=":strict_string_checks=true" +ASAN_OPTIONS+=":strip_path_prefix=${PWD}/" +export ASAN_OPTIONS + +./build/unit-tests $(ut_log_args ChronoSync) diff --git a/.jenkins.d/util.sh b/.jenkins.d/util.sh new file mode 100644 index 0000000..a89bc27 --- /dev/null +++ b/.jenkins.d/util.sh @@ -0,0 +1,18 @@ +has() { + local saved_xtrace + [[ $- == *x* ]] && saved_xtrace=-x || saved_xtrace=+x + set +x + + local p=$1 + shift + local i ret=1 + for i in "$@"; do + if [[ "${i}" == "${p}" ]]; then + ret=0 + break + fi + done + + set ${saved_xtrace} + return ${ret} +} diff --git a/.travis.yml b/.travis.yml index 63e80e5..508b081 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,28 @@ -# For Ubuntu platform only -language: cpp -os: - - linux -compiler: - - gcc +sudo: required +language: generic +env: + global: + - JOB_NAME=limited-build +matrix: + include: + - os: linux + dist: trusty + env: + - CXX=g++ + - NODE_LABELS="Linux Ubuntu Ubuntu-14.04" + - os: linux + dist: trusty + env: + - CXX=clang++ + - NODE_LABELS="Linux Ubuntu Ubuntu-14.04" + - os: osx + osx_image: xcode8.2 + env: + - CXX=clang++ + - NODE_LABELS="OSX OSX-10.12" notifications: email: on_success: always on_failure: always -before_install: - - travis_retry sudo apt-get update - - travis_retry sudo apt-get install -qq libssl-dev libprotobuf-dev protobuf-compiler libboost1.48-all-dev libcrypto++-dev libsqlite3-dev script: - ./.jenkins diff --git a/.waf-tools/boost.py b/.waf-tools/boost.py index 305945a..9b9395e 100644 --- a/.waf-tools/boost.py +++ b/.waf-tools/boost.py @@ -30,15 +30,15 @@ When using this tool, the wscript will look like: Options are generated, in order to specify the location of boost includes/libraries. The `check_boost` configuration function allows to specify the used boost libraries. -It can also provide default arguments to the --boost-static and --boost-mt command-line arguments. +It can also provide default arguments to the --boost-mt command-line arguments. Everything will be packaged together in a BOOST component that you can use. When using MSVC, a lot of compilation flags need to match your BOOST build configuration: - you may have to add /EHsc to your CXXFLAGS or define boost::throw_exception if BOOST_NO_EXCEPTIONS is defined. Errors: C4530 - boost libraries will try to be smart and use the (pretty but often not useful) auto-linking feature of MSVC - So before calling `conf.check_boost` you might want to disabling by adding: - conf.env.DEFINES_BOOST += ['BOOST_ALL_NO_LIB'] + So before calling `conf.check_boost` you might want to disabling by adding + conf.env.DEFINES_BOOST += ['BOOST_ALL_NO_LIB'] Errors: - boost might also be compiled with /MT, which links the runtime statically. If you have problems with redefined symbols, @@ -52,24 +52,55 @@ import sys import re from waflib import Utils, Logs, Errors from waflib.Configure import conf +from waflib.TaskGen import feature, after_method -BOOST_LIBS = ['/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib', '/usr/lib/x86_64-linux-gnu', '/usr/lib/i386-linux-gnu', '/usr/local/ndn/lib'] -BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include', '/usr/local/ndn/include'] +BOOST_LIBS = ['/usr/lib/x86_64-linux-gnu', '/usr/lib/i386-linux-gnu', + '/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib'] +BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include'] BOOST_VERSION_FILE = 'boost/version.hpp' BOOST_VERSION_CODE = ''' #include #include int main() { std::cout << BOOST_LIB_VERSION << ":" << BOOST_VERSION << std::endl; } ''' -BOOST_SYSTEM_CODE = ''' + +BOOST_ERROR_CODE = ''' #include int main() { boost::system::error_code c; } ''' + +PTHREAD_CODE = ''' +#include +static void* f(void*) { return 0; } +int main() { + pthread_t th; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_create(&th, &attr, &f, 0); + pthread_join(th, 0); + pthread_cleanup_push(0, 0); + pthread_cleanup_pop(0); + pthread_attr_destroy(&attr); +} +''' + BOOST_THREAD_CODE = ''' #include int main() { boost::thread t; } ''' +BOOST_LOG_CODE = ''' +#include +#include +#include +int main() { + using namespace boost::log; + add_common_attributes(); + add_console_log(std::clog, keywords::format = "%Message%"); + BOOST_LOG_TRIVIAL(debug) << "log is working" << std::endl; +} +''' + # toolsets from {boost_dir}/tools/build/v2/tools/common.jam PLATFORM = Utils.unversioned_sys_platform() detect_intel = lambda env: (PLATFORM == 'win32') and 'iw' or 'il' @@ -101,34 +132,37 @@ BOOST_TOOLSETS = { def options(opt): opt = opt.add_option_group('Boost Options') - opt.add_option('--boost-includes', type='string', default='', dest='boost_includes', - help='''path to the directory where the boost includes are, e.g., /path/to/boost_1_55_0/stage/include''') + help='''path to the directory where the boost includes are, + e.g., /path/to/boost_1_55_0/stage/include''') opt.add_option('--boost-libs', type='string', default='', dest='boost_libs', - help='''path to the directory where the boost libs are, e.g., /path/to/boost_1_55_0/stage/lib''') - opt.add_option('--boost-static', action='store_true', - default=False, dest='boost_static', - help='link with static boost libraries (.lib/.a)') + help='''path to the directory where the boost libs are, + e.g., path/to/boost_1_55_0/stage/lib''') opt.add_option('--boost-mt', action='store_true', default=False, dest='boost_mt', help='select multi-threaded libraries') opt.add_option('--boost-abi', type='string', default='', dest='boost_abi', - help='''select libraries with tags (dgsyp, d for debug), see doc Boost, Getting Started, chapter 6.1''') + help='''select libraries with tags (gd for debug, static is automatically added), + see doc Boost, Getting Started, chapter 6.1''') opt.add_option('--boost-linkage_autodetect', action="store_true", dest='boost_linkage_autodetect', help="auto-detect boost linkage options (don't get used to it / might break other stuff)") opt.add_option('--boost-toolset', type='string', default='', dest='boost_toolset', - help='force a toolset e.g. msvc, vc90, gcc, mingw, mgw45 (default: auto)') + help='force a toolset e.g. msvc, vc90, \ + gcc, mingw, mgw45 (default: auto)') py_version = '%d%d' % (sys.version_info[0], sys.version_info[1]) opt.add_option('--boost-python', type='string', default=py_version, dest='boost_python', - help='select the lib python with this version (default: %s)' % py_version) + help='select the lib python with this version \ + (default: %s)' % py_version) @conf def __boost_get_version_file(self, d): + if not d: + return None dnode = self.root.find_dir(d) if dnode: return dnode.find_node(BOOST_VERSION_FILE) @@ -141,18 +175,15 @@ def boost_get_version(self, d): if node: try: txt = node.read() - except (OSError, IOError): + except EnvironmentError: Logs.error("Could not read the file %r" % node.abspath()) else: re_but1 = re.compile('^#define\\s+BOOST_LIB_VERSION\\s+"(.+)"', re.M) m1 = re_but1.search(txt) - re_but2 = re.compile('^#define\\s+BOOST_VERSION\\s+(\\d+)', re.M) m2 = re_but2.search(txt) - if m1 and m2: return (m1.group(1), m2.group(1)) - return self.check_cxx(fragment=BOOST_VERSION_CODE, includes=[d], execute=True, define_ret=True).split(":") @conf @@ -160,7 +191,7 @@ def boost_get_includes(self, *k, **kw): includes = k and k[0] or kw.get('includes', None) if includes and self.__boost_get_version_file(includes): return includes - for d in Utils.to_list(self.environ.get('INCLUDE', '')) + BOOST_INCLUDES: + for d in self.environ.get('INCLUDE', '').split(';') + BOOST_INCLUDES: if self.__boost_get_version_file(d): return d if includes: @@ -195,7 +226,9 @@ def __boost_get_libs_path(self, *k, **kw): path = self.root.find_dir(libs) files = path.ant_glob('*boost_*') if not libs or not files: - for d in Utils.to_list(self.environ.get('LIB', [])) + BOOST_LIBS: + for d in self.environ.get('LIB', '').split(';') + BOOST_LIBS: + if not d: + continue path = self.root.find_dir(d) if path: files = path.ant_glob('*boost_*') @@ -226,15 +259,10 @@ def boost_get_libs(self, *k, **kw): according to the parameters ''' path, files = self.__boost_get_libs_path(**kw) - t = [] - if kw.get('mt', False): - t.append('mt') - if kw.get('abi', None): - t.append(kw['abi']) - tags = t and '(-%s)+' % '-'.join(t) or '' + files = sorted(files, key=lambda f: (len(f.name), f.name), reverse=True) toolset = self.boost_get_toolset(kw.get('toolset', '')) - toolset_pat = '(-%s[0-9]{0,3})+' % toolset - version = '(-%s)+' % self.env.BOOST_VERSION + toolset_pat = '(-%s[0-9]{0,3})' % toolset + version = '-%s' % self.env.BOOST_VERSION def find_lib(re_lib, files): for file in files: @@ -248,28 +276,110 @@ def boost_get_libs(self, *k, **kw): name = name[3:] return name[:name.rfind('.')] - libs = [] - for lib in Utils.to_list(k and k[0] or kw.get('lib', None)): - py = (lib == 'python') and '(-py%s)+' % kw['python'] or '' - # Trying libraries, from most strict match to least one - for pattern in ['boost_%s%s%s%s%s' % (lib, toolset_pat, tags, py, version), - 'boost_%s%s%s%s' % (lib, tags, py, version), - 'boost_%s%s%s' % (lib, tags, version), - # Give up trying to find the right version - 'boost_%s%s%s%s' % (lib, toolset_pat, tags, py), - 'boost_%s%s%s' % (lib, tags, py), - 'boost_%s%s' % (lib, tags)]: - self.to_log('Trying pattern %s' % pattern) - file = find_lib(re.compile(pattern), files) - if file: - libs.append(format_lib_name(file.name)) - break - else: - self.end_msg('lib %s not found in %s' % (lib, path.abspath())) - self.fatal('The configuration failed') + def match_libs(lib_names, is_static): + libs = [] + lib_names = Utils.to_list(lib_names) + if not lib_names: + return libs + t = [] + if kw.get('mt', False): + t.append('-mt') + if kw.get('abi', None): + t.append('%s%s' % (is_static and '-s' or '-', kw['abi'])) + elif is_static: + t.append('-s') + tags_pat = t and ''.join(t) or '' + ext = is_static and self.env.cxxstlib_PATTERN or self.env.cxxshlib_PATTERN + ext = ext.partition('%s')[2] # remove '%s' or 'lib%s' from PATTERN - return path.abspath(), libs + for lib in lib_names: + if lib == 'python': + # for instance, with python='27', + # accepts '-py27', '-py2', '27' and '2' + # but will reject '-py3', '-py26', '26' and '3' + tags = '({0})?((-py{2})|(-py{1}(?=[^0-9]))|({2})|({1}(?=[^0-9]))|(?=[^0-9])(?!-py))'.format(tags_pat, kw['python'][0], kw['python']) + else: + tags = tags_pat + # Trying libraries, from most strict match to least one + for pattern in ['boost_%s%s%s%s%s$' % (lib, toolset_pat, tags, version, ext), + 'boost_%s%s%s%s$' % (lib, tags, version, ext), + # Give up trying to find the right version + 'boost_%s%s%s%s$' % (lib, toolset_pat, tags, ext), + 'boost_%s%s%s$' % (lib, tags, ext), + 'boost_%s%s$' % (lib, ext), + 'boost_%s' % lib]: + self.to_log('Trying pattern %s' % pattern) + file = find_lib(re.compile(pattern), files) + if file: + libs.append(format_lib_name(file.name)) + break + else: + self.end_msg('lib %s not found in %s' % (lib, path.abspath())) + self.fatal('The configuration failed') + return libs + return path.abspath(), match_libs(kw.get('lib', None), False), match_libs(kw.get('stlib', None), True) + +@conf +def _check_pthread_flag(self, *k, **kw): + ''' + Computes which flags should be added to CXXFLAGS and LINKFLAGS to compile in multi-threading mode + + Yes, we *need* to put the -pthread thing in CPPFLAGS because with GCC3, + boost/thread.hpp will trigger a #error if -pthread isn't used: + boost/config/requires_threads.hpp:47:5: #error "Compiler threading support + is not turned on. Please set the correct command line options for + threading: -pthread (Linux), -pthreads (Solaris) or -mthreads (Mingw32)" + + Based on _BOOST_PTHREAD_FLAG(): https://github.com/tsuna/boost.m4/blob/master/build-aux/boost.m4 + ''' + + var = kw.get('uselib_store', 'BOOST') + + self.start_msg('Checking the flags needed to use pthreads') + + # The ordering *is* (sometimes) important. Some notes on the + # individual items follow: + # (none): in case threads are in libc; should be tried before -Kthread and + # other compiler flags to prevent continual compiler warnings + # -lpthreads: AIX (must check this before -lpthread) + # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # -llthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + # -pthread: GNU Linux/GCC (kernel threads), BSD/GCC (userland threads) + # -pthreads: Solaris/GCC + # -mthreads: MinGW32/GCC, Lynx/GCC + # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it + # doesn't hurt to check since this sometimes defines pthreads too; + # also defines -D_REENTRANT) + # ... -mt is also the pthreads flag for HP/aCC + # -lpthread: GNU Linux, etc. + # --thread-safe: KAI C++ + if Utils.unversioned_sys_platform() == "sunos": + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthreads/-mt/ + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + boost_pthread_flags = ["-pthreads", "-lpthread", "-mt", "-pthread"] + else: + boost_pthread_flags = ["", "-lpthreads", "-Kthread", "-kthread", "-llthread", "-pthread", + "-pthreads", "-mthreads", "-lpthread", "--thread-safe", "-mt"] + + for boost_pthread_flag in boost_pthread_flags: + try: + self.env.stash() + self.env['CXXFLAGS_%s' % var] += [boost_pthread_flag] + self.env['LINKFLAGS_%s' % var] += [boost_pthread_flag] + self.check_cxx(code=PTHREAD_CODE, msg=None, use=var, execute=False) + + self.end_msg(boost_pthread_flag) + return + except self.errors.ConfigurationError: + self.env.revert() + self.end_msg('None') @conf def check_boost(self, *k, **kw): @@ -282,7 +392,10 @@ def check_boost(self, *k, **kw): if not self.env['CXX']: self.fatal('load a c++ compiler first, conf.load("compiler_cxx")') - params = {'lib': k and k[0] or kw.get('lib', None)} + params = { + 'lib': k and k[0] or kw.get('lib', None), + 'stlib': kw.get('stlib', None) + } for key, value in self.options.__dict__.items(): if not key.startswith('boost_'): continue @@ -297,42 +410,53 @@ def check_boost(self, *k, **kw): self.env.BOOST_VERSION = versions[0] self.env.BOOST_VERSION_NUMBER = int(versions[1]) self.end_msg("%d.%d.%d" % (int(versions[1]) / 100000, - int(versions[1]) / 100 % 1000, - int(versions[1]) % 100)) + int(versions[1]) / 100 % 1000, + int(versions[1]) % 100)) if Logs.verbose: Logs.pprint('CYAN', ' path : %s' % self.env['INCLUDES_%s' % var]) - if not params['lib']: + if not params['lib'] and not params['stlib']: return + if 'static' in kw or 'static' in params: + Logs.warn('boost: static parameter is deprecated, use stlib instead.') self.start_msg('Checking boost libs') - suffix = params.get('static', None) and 'ST' or '' - path, libs = self.boost_get_libs(**params) - self.env['%sLIBPATH_%s' % (suffix, var)] = [path] - self.env['%sLIB_%s' % (suffix, var)] = libs + path, libs, stlibs = self.boost_get_libs(**params) + self.env['LIBPATH_%s' % var] = [path] + self.env['STLIBPATH_%s' % var] = [path] + self.env['LIB_%s' % var] = libs + self.env['STLIB_%s' % var] = stlibs self.end_msg('ok') if Logs.verbose: Logs.pprint('CYAN', ' path : %s' % path) - Logs.pprint('CYAN', ' libs : %s' % libs) + Logs.pprint('CYAN', ' shared libs : %s' % libs) + Logs.pprint('CYAN', ' static libs : %s' % stlibs) + def has_shlib(lib): + return params['lib'] and lib in params['lib'] + def has_stlib(lib): + return params['stlib'] and lib in params['stlib'] + def has_lib(lib): + return has_shlib(lib) or has_stlib(lib) + if has_lib('thread'): + # not inside try_link to make check visible in the output + self._check_pthread_flag(k, kw) def try_link(): - if 'system' in params['lib']: - self.check_cxx( - fragment=BOOST_SYSTEM_CODE, - use=var, - execute=False, - ) - if 'thread' in params['lib']: - self.check_cxx( - fragment=BOOST_THREAD_CODE, - use=var, - execute=False, - ) + if has_lib('system'): + self.check_cxx(fragment=BOOST_ERROR_CODE, use=var, execute=False) + if has_lib('thread'): + self.check_cxx(fragment=BOOST_THREAD_CODE, use=var, execute=False) + if has_lib('log'): + if not has_lib('thread'): + self.env['DEFINES_%s' % var] += ['BOOST_LOG_NO_THREADS'] + if has_shlib('log'): + self.env['DEFINES_%s' % var] += ['BOOST_LOG_DYN_LINK'] + self.check_cxx(fragment=BOOST_LOG_CODE, use=var, execute=False) if params.get('linkage_autodetect', False): self.start_msg("Attempting to detect boost linkage flags") toolset = self.boost_get_toolset(kw.get('toolset', '')) - if toolset in ['vc']: + if toolset in ('vc',): # disable auto-linking feature, causing error LNK1181 # because the code wants to be linked against self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB'] @@ -356,14 +480,14 @@ def check_boost(self, *k, **kw): try: try_link() self.end_msg("ok: winning cxxflags combination: %s" % (self.env["CXXFLAGS_%s" % var])) - e = None + exc = None break - except Errors.ConfigurationError as exc: + except Errors.ConfigurationError as e: self.env.revert() - e = exc + exc = e - if e is not None: - self.end_msg("Could not auto-detect boost linking flags combination, you may report it to boost.py author", ex=e) + if exc is not None: + self.end_msg("Could not auto-detect boost linking flags combination, you may report it to boost.py author", ex=exc) self.fatal('The configuration failed') else: self.end_msg("Boost linkage flags auto-detection not implemented (needed ?) for this toolchain") @@ -376,3 +500,19 @@ def check_boost(self, *k, **kw): self.end_msg("Could not link against boost libraries using supplied options") self.fatal('The configuration failed') self.end_msg('ok') + + +@feature('cxx') +@after_method('apply_link') +def install_boost(self): + if install_boost.done or not Utils.is_win32 or not self.bld.cmd.startswith('install'): + return + install_boost.done = True + inst_to = getattr(self, 'install_path', '${BINDIR}') + for lib in self.env.LIB_BOOST: + try: + file = self.bld.find_file(self.env.cxxshlib_PATTERN % lib, self.env.LIBPATH_BOOST) + self.bld.install_files(inst_to, self.bld.root.find_node(file)) + except: + continue +install_boost.done = False diff --git a/.waf-tools/coverage.py b/.waf-tools/coverage.py new file mode 100644 index 0000000..ce92883 --- /dev/null +++ b/.waf-tools/coverage.py @@ -0,0 +1,22 @@ +# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +from waflib import TaskGen, Logs + +def options(opt): + opt.add_option('--with-coverage', action='store_true', default=False, dest='with_coverage', + help='''Set compiler flags for gcc to enable code coverage information''') + +def configure(conf): + if conf.options.with_coverage: + if not conf.options.debug: + conf.fatal("Code coverage flags require debug mode compilation (add --debug)") + conf.check_cxx(cxxflags=['-fprofile-arcs', '-ftest-coverage', '-fPIC'], + linkflags=['-fprofile-arcs'], uselib_store='GCOV', mandatory=True) + +@TaskGen.feature('cxx','cc') +@TaskGen.after('process_source') +def add_coverage(self): + if getattr(self, 'use', ''): + self.use += ' GCOV' + else: + self.use = 'GCOV' diff --git a/.waf-tools/default-compiler-flags.py b/.waf-tools/default-compiler-flags.py index 225833a..2999e8f 100644 --- a/.waf-tools/default-compiler-flags.py +++ b/.waf-tools/default-compiler-flags.py @@ -1,53 +1,57 @@ # -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -# -# Copyright (c) 2014, Regents of the University of California -# -# GPL 3.0 license, see the COPYING.md file for more information -from waflib import Logs, Configure +from waflib import Logs, Configure, Utils def options(opt): opt.add_option('--debug', '--with-debug', action='store_true', default=False, dest='debug', - help='''Compile in debugging mode without all optimizations (-O0)''') + help='''Compile in debugging mode without optimizations (-O0 or -Og)''') def configure(conf): - areCustomCxxflagsPresent = (len(conf.env.CXXFLAGS) > 0) - defaultFlags = ['-std=c++0x', '-std=c++11', - '-stdlib=libc++', # clang on OSX < 10.9 by default uses gcc's - # libstdc++, which is not C++11 compatible - '-Wall', '-Wno-long-long', '-Wno-nested-anon-types'] + cxx = conf.env['CXX_NAME'] # CXX_NAME represents generic name of the compiler + if cxx == 'gcc': + flags = GccFlags() + elif cxx == 'clang': + flags = ClangFlags() + else: + flags = CompilerFlags() + Logs.warn('The code has not yet been tested with %s compiler' % cxx) + areCustomCxxflagsPresent = (len(conf.env.CXXFLAGS) > 0) + + # General flags are always applied (e.g., selecting C++11 mode) + generalFlags = flags.getGeneralFlags(conf) + conf.add_supported_cxxflags(generalFlags['CXXFLAGS']) + conf.add_supported_linkflags(generalFlags['LINKFLAGS']) + conf.env.DEFINES += generalFlags['DEFINES'] + + # Debug or optimized CXXFLAGS and LINKFLAGS are applied only if the + # corresponding environment variables are not set. + # DEFINES are always applied. if conf.options.debug: - conf.define('_DEBUG', 1) - defaultFlags += ['-O0', - '-Og', # gcc >= 4.8 - '-g3', - '-fcolor-diagnostics', # clang - '-fdiagnostics-color', # gcc >= 4.9 - '-Wno-error=maybe-uninitialized', # Bug #1560 - '-Wno-unneeded-internal-declaration', - ] + extraFlags = flags.getDebugFlags(conf) if areCustomCxxflagsPresent: - missingFlags = [x for x in defaultFlags if x not in conf.env.CXXFLAGS] + missingFlags = [x for x in extraFlags['CXXFLAGS'] if x not in conf.env.CXXFLAGS] if len(missingFlags) > 0: Logs.warn("Selected debug mode, but CXXFLAGS is set to a custom value '%s'" % " ".join(conf.env.CXXFLAGS)) Logs.warn("Default flags '%s' are not activated" % " ".join(missingFlags)) - else: - conf.add_supported_cxxflags(defaultFlags) else: - defaultFlags += ['-O2', '-g'] - if not areCustomCxxflagsPresent: - conf.add_supported_cxxflags(defaultFlags) + extraFlags = flags.getOptimizedFlags(conf) - # clang on OSX < 10.9 by default uses gcc's libstdc++, which is not C++11 compatible - conf.add_supported_linkflags(['-stdlib=libc++']) + if not areCustomCxxflagsPresent: + conf.add_supported_cxxflags(extraFlags['CXXFLAGS']) + conf.add_supported_linkflags(extraFlags['LINKFLAGS']) + + conf.env.DEFINES += extraFlags['DEFINES'] @Configure.conf def add_supported_cxxflags(self, cxxflags): """ Check which cxxflags are supported by compiler and add them to env.CXXFLAGS variable """ + if len(cxxflags) == 0: + return + self.start_msg('Checking supported CXXFLAGS') supportedFlags = [] @@ -56,13 +60,16 @@ def add_supported_cxxflags(self, cxxflags): supportedFlags += [flag] self.end_msg(' '.join(supportedFlags)) - self.env.CXXFLAGS = supportedFlags + self.env.CXXFLAGS + self.env.prepend_value('CXXFLAGS', supportedFlags) @Configure.conf def add_supported_linkflags(self, linkflags): """ Check which linkflags are supported by compiler and add them to env.LINKFLAGS variable """ + if len(linkflags) == 0: + return + self.start_msg('Checking supported LINKFLAGS') supportedFlags = [] @@ -71,4 +78,104 @@ def add_supported_linkflags(self, linkflags): supportedFlags += [flag] self.end_msg(' '.join(supportedFlags)) - self.env.LINKFLAGS = supportedFlags + self.env.LINKFLAGS + self.env.prepend_value('LINKFLAGS', supportedFlags) + + +class CompilerFlags(object): + def getGeneralFlags(self, conf): + """Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are always needed""" + return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': []} + + def getDebugFlags(self, conf): + """Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are needed only in debug mode""" + return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': ['_DEBUG']} + + def getOptimizedFlags(self, conf): + """Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are needed only in optimized mode""" + return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': ['NDEBUG']} + +class GccBasicFlags(CompilerFlags): + """ + This class defines basic flags that work for both gcc and clang compilers + """ + def getDebugFlags(self, conf): + flags = super(GccBasicFlags, self).getDebugFlags(conf) + flags['CXXFLAGS'] += ['-O0', + '-g3', + '-pedantic', + '-Wall', + '-Wextra', + '-Werror', + '-Wno-unused-parameter', + '-Wno-error=maybe-uninitialized', # Bug #1615 + '-Wno-error=deprecated-declarations', # Bug #3795 + ] + return flags + + def getOptimizedFlags(self, conf): + flags = super(GccBasicFlags, self).getOptimizedFlags(conf) + flags['CXXFLAGS'] += ['-O2', + '-g', + '-pedantic', + '-Wall', + '-Wextra', + '-Wno-unused-parameter', + ] + return flags + +class GccFlags(GccBasicFlags): + def getGeneralFlags(self, conf): + flags = super(GccFlags, self).getGeneralFlags(conf) + version = tuple(int(i) for i in conf.env['CC_VERSION']) + if version < (4, 8, 2): + conf.fatal('The version of gcc you are using (%s) is too old.\n' % + '.'.join(conf.env['CC_VERSION']) + + 'The minimum supported gcc version is 4.8.2.') + else: + flags['CXXFLAGS'] += ['-std=c++11'] + return flags + + def getDebugFlags(self, conf): + flags = super(GccFlags, self).getDebugFlags(conf) + version = tuple(int(i) for i in conf.env['CC_VERSION']) + if version < (5, 1, 0): + flags['CXXFLAGS'] += ['-Wno-missing-field-initializers'] + flags['CXXFLAGS'] += ['-Og', # gcc >= 4.8 + '-fdiagnostics-color', # gcc >= 4.9 + ] + return flags + + def getOptimizedFlags(self, conf): + flags = super(GccFlags, self).getOptimizedFlags(conf) + version = tuple(int(i) for i in conf.env['CC_VERSION']) + if version < (5, 1, 0): + flags['CXXFLAGS'] += ['-Wno-missing-field-initializers'] + flags['CXXFLAGS'] += ['-fdiagnostics-color'] # gcc >= 4.9 + return flags + +class ClangFlags(GccBasicFlags): + def getGeneralFlags(self, conf): + flags = super(ClangFlags, self).getGeneralFlags(conf) + flags['CXXFLAGS'] += ['-std=c++11'] + if Utils.unversioned_sys_platform() == 'darwin': + flags['CXXFLAGS'] += ['-stdlib=libc++'] + flags['LINKFLAGS'] += ['-stdlib=libc++'] + return flags + + def getDebugFlags(self, conf): + flags = super(ClangFlags, self).getDebugFlags(conf) + flags['CXXFLAGS'] += ['-fcolor-diagnostics', + '-Wno-unused-local-typedef', # Bugs #2657 and #3209 + '-Wno-error=unneeded-internal-declaration', # Bug #1588 + '-Wno-error=deprecated-register', + '-Wno-error=keyword-macro', # Bug #3235 + '-Wno-error=infinite-recursion', # Bug #3358 + ] + return flags + + def getOptimizedFlags(self, conf): + flags = super(ClangFlags, self).getOptimizedFlags(conf) + flags['CXXFLAGS'] += ['-fcolor-diagnostics', + '-Wno-unused-local-typedef', # Bugs #2657 and #3209 + ] + return flags diff --git a/.waf-tools/doxygen.py b/.waf-tools/doxygen.py index ac8c70b..6d8066b 100644 --- a/.waf-tools/doxygen.py +++ b/.waf-tools/doxygen.py @@ -85,7 +85,7 @@ class doxygen(Task.Task): # Override with any parameters passed to the task generator if getattr(self.generator, 'pars', None): - for k, v in self.generator.pars.iteritems(): + for k, v in self.generator.pars.items(): self.pars[k] = v self.doxy_inputs = getattr(self, 'doxy_inputs', []) diff --git a/.waf-tools/pch.py b/.waf-tools/pch.py index 08cc5de..3df299f 100644 --- a/.waf-tools/pch.py +++ b/.waf-tools/pch.py @@ -67,6 +67,11 @@ def options(opt): def configure(conf): if (conf.options.with_pch and conf.env['COMPILER_CXX'] in PCH_COMPILER_OPTIONS.keys()): + if Utils.unversioned_sys_platform() == "darwin" and conf.env['CXX_NAME'] == 'clang': + version = tuple(int(i) for i in conf.env['CC_VERSION']) + if version < (6, 1, 0): + # Issue #2804 + return conf.env.WITH_PCH = True flags = PCH_COMPILER_OPTIONS[conf.env['COMPILER_CXX']] conf.env.CXXPCH_F = flags[0] diff --git a/.waf-tools/sanitizers.py b/.waf-tools/sanitizers.py new file mode 100644 index 0000000..a8fe55d --- /dev/null +++ b/.waf-tools/sanitizers.py @@ -0,0 +1,22 @@ +# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def options(opt): + opt.add_option('--with-sanitizer', action='store', default='', dest='sanitizers', + help='Comma-separated list of compiler sanitizers to enable [default=none]') + +def configure(conf): + for san in conf.options.sanitizers.split(','): + if not san: + continue + + sanflag = '-fsanitize=%s' % san + conf.start_msg('Checking if compiler supports %s' % sanflag) + + if conf.check_cxx(cxxflags=['-Werror', sanflag, '-fno-omit-frame-pointer'], + linkflags=[sanflag], mandatory=False): + conf.end_msg('yes') + conf.env.append_unique('CXXFLAGS', [sanflag, '-fno-omit-frame-pointer']) + conf.env.append_unique('LINKFLAGS', [sanflag]) + else: + conf.end_msg('no', color='RED') + conf.fatal('%s sanitizer is not supported by the current compiler' % san) diff --git a/src/logger.hpp b/src/logger.hpp index 2ac782a..7e46ea5 100644 --- a/src/logger.hpp +++ b/src/logger.hpp @@ -1,6 +1,6 @@ /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */ /* - * Copyright (c) 2012-2014 University of California, Los Angeles + * Copyright (c) 2012-2017 University of California, Los Angeles * * This file is part of ChronoSync, synchronization library for distributed realtime * applications for NDN. @@ -48,12 +48,12 @@ #else // HAVE_LOG4CXX -#define INIT_LOGGER(name) -#define _LOG_FUNCTION(x) -#define _LOG_FUNCTION_NOARGS -#define _LOG_TRACE(x) -#define INIT_LOGGERS(x) -#define _LOG_ERROR(x) +#define INIT_LOGGER(name) struct chronosync__allow_trailing_semicolon +#define _LOG_FUNCTION(x) struct chronosync__allow_trailing_semicolon +#define _LOG_FUNCTION_NOARGS struct chronosync__allow_trailing_semicolon +#define _LOG_TRACE(x) struct chronosync__allow_trailing_semicolon +#define INIT_LOGGERS(x) struct chronosync__allow_trailing_semicolon +#define _LOG_ERROR(x) struct chronosync__allow_trailing_semicolon #ifdef _DEBUG @@ -67,7 +67,7 @@ #else // _DEBUG -#define _LOG_DEBUG(x) +#define _LOG_DEBUG(x) struct chronosync__allow_trailing_semicolon #endif // _DEBUG diff --git a/tests/boost-multi-log-formatter.hpp b/tests/boost-multi-log-formatter.hpp new file mode 100644 index 0000000..ae37416 --- /dev/null +++ b/tests/boost-multi-log-formatter.hpp @@ -0,0 +1,214 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2015 Regents of the University of California. + * + * Based on work by Martin Ba (http://stackoverflow.com/a/26718189) + * + * This file is distributed under the Boost Software License, Version 1.0. + * (See http://www.boost.org/LICENSE_1_0.txt) + */ + +#ifndef NDN_TESTS_BOOST_MULTI_LOG_FORMATTER_HPP +#define NDN_TESTS_BOOST_MULTI_LOG_FORMATTER_HPP + +#include + +#if BOOST_VERSION >= 105900 +#include +#else +#include +#endif // BOOST_VERSION >= 105900 + +#include +#include +#include + +namespace boost { +namespace unit_test { +namespace output { + +/** + * @brief Log formatter for Boost.Test that outputs the logging to multiple formatters + * + * The log formatter is designed to output to one or multiple formatters at the same time. For + * example, one HRF formatter can output to the standard output, while XML formatter output to + * the file. + * + * Usage: + * + * // Call in init_unit_test_suite: (this will override the --log_format parameter) + * auto formatter = new boost::unit_test::output::multi_log_formatter; // same as already configured logger + * + * // Prepare and add additional logger(s) + * formatter.add(std::make_shared(), + * std::make_shared("out.xml")); + * + * boost::unit_test::unit_test_log.set_formatter(formatter); + * + * @note Calling `boost::unit_test::unit_test_log.set_stream(...)` will change the stream for + * the original logger. + */ +class multi_log_formatter : public unit_test_log_formatter +{ +public: + /** + * @brief Create instance of the logger, based on the configured logger instance + */ + multi_log_formatter() + { + auto format = +#if BOOST_VERSION > 105900 + runtime_config::get(runtime_config::LOG_FORMAT); +#else + runtime_config::log_format(); +#endif // BOOST_VERSION > 105900 + + switch (format) { + default: +#if BOOST_VERSION >= 105900 + case OF_CLF: +#else + case CLF: +#endif // BOOST_VERSION >= 105900 + m_loggers.push_back({std::make_shared(), nullptr}); + break; +#if BOOST_VERSION >= 105900 + case OF_XML: +#else + case XML: +#endif // BOOST_VERSION >= 105900 + m_loggers.push_back({std::make_shared(), nullptr}); + break; + } + } + + void + add(std::shared_ptr formatter, std::shared_ptr os) + { + m_loggers.push_back({formatter, os}); + } + + // Formatter interface + void + log_start(std::ostream& os, counter_t test_cases_amount) + { + for (auto& l : m_loggers) + l.logger->log_start(l.os == nullptr ? os : *l.os, test_cases_amount); + } + + void + log_finish(std::ostream& os) + { + for (auto& l : m_loggers) + l.logger->log_finish(l.os == nullptr ? os : *l.os); + } + + void + log_build_info(std::ostream& os) + { + for (auto& l : m_loggers) + l.logger->log_build_info(l.os == nullptr ? os : *l.os); + } + + void + test_unit_start(std::ostream& os, const test_unit& tu) + { + for (auto& l : m_loggers) + l.logger->test_unit_start(l.os == nullptr ? os : *l.os, tu); + } + + void + test_unit_finish(std::ostream& os, const test_unit& tu, unsigned long elapsed) + { + for (auto& l : m_loggers) + l.logger->test_unit_finish(l.os == nullptr ? os : *l.os, tu, elapsed); + } + + void + test_unit_skipped(std::ostream& os, const test_unit& tu) + { + for (auto& l : m_loggers) + l.logger->test_unit_skipped(l.os == nullptr ? os : *l.os, tu); + } + +#if BOOST_VERSION >= 105900 + void + log_exception_start(std::ostream& os, const log_checkpoint_data& lcd, const execution_exception& ex) + { + for (auto& l : m_loggers) + l.logger->log_exception_start(l.os == nullptr ? os : *l.os, lcd, ex); + } + + void + log_exception_finish(std::ostream& os) + { + for (auto& l : m_loggers) + l.logger->log_exception_finish(l.os == nullptr ? os : *l.os); + } +#else + void + log_exception(std::ostream& os, const log_checkpoint_data& lcd, const execution_exception& ex) + { + for (auto& l : m_loggers) + l.logger->log_exception(l.os == nullptr ? os : *l.os, lcd, ex); + } +#endif // BOOST_VERSION >= 105900 + + void + log_entry_start(std::ostream& os, const log_entry_data& entry_data, log_entry_types let) + { + for (auto& l : m_loggers) + l.logger->log_entry_start(l.os == nullptr ? os : *l.os, entry_data, let); + } + + void + log_entry_value(std::ostream& os, const_string value) + { + for (auto& l : m_loggers) + l.logger->log_entry_value(l.os == nullptr ? os : *l.os, value); + } + + void + log_entry_finish(std::ostream& os) + { + for (auto& l : m_loggers) + l.logger->log_entry_finish(l.os == nullptr ? os : *l.os); + } + +#if BOOST_VERSION >= 105900 + void + entry_context_start(std::ostream& os, log_level level) + { + for (auto& l : m_loggers) + l.logger->entry_context_start(l.os == nullptr ? os : *l.os, level); + } + + void + log_entry_context(std::ostream& os, const_string value) + { + for (auto& l : m_loggers) + l.logger->log_entry_context(l.os == nullptr ? os : *l.os, value); + } + + void + entry_context_finish(std::ostream& os) + { + for (auto& l : m_loggers) + l.logger->entry_context_finish(l.os == nullptr ? os : *l.os); + } +#endif // BOOST_VERSION >= 105900 + +private: + struct LoggerInfo + { + std::shared_ptr logger; + std::shared_ptr os; + }; + std::vector m_loggers; +}; + +} // namespace output +} // namespace unit_test +} // namespace boost + +#endif // NDN_TESTS_BOOST_MULTI_LOG_FORMATTER_HPP diff --git a/tests/main.cpp b/tests/main.cpp index 6185729..b37eb19 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -1,23 +1,116 @@ -/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */ -/* - * Copyright (c) 2012-2014 University of California, Los Angeles +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2014-2017, Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. * * This file is part of ChronoSync, synchronization library for distributed realtime - * applications for NDN. + * applications for NDN, originally developed as part of NFD (Named Data Networking + * Forwarding Daemon). See AUTHORS.md for complete list of NFD authors and contributors. * - * ChronoSync is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. + * NFD is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. * - * ChronoSync is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with - * ChronoSync, e.g., in COPYING.md file. If not, see . + * NFD, e.g., in COPYING.md file. If not, see . */ -#define BOOST_TEST_MAIN 1 -#define BOOST_TEST_DYN_LINK 1 +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_ALTERNATIVE_INIT_API +#include + +#if BOOST_VERSION >= 106200 +// Boost.Test v3.3 (Boost 1.62) natively supports multi-logger output #include "boost-test.hpp" +#else +#define BOOST_TEST_NO_MAIN +#include "boost-test.hpp" + +#include "boost-multi-log-formatter.hpp" + +#include +#include +#include + +#include +#include + +static bool +init_tests() +{ + init_unit_test(); + + namespace po = boost::program_options; + namespace ut = boost::unit_test; + + po::options_description extraOptions; + std::string logger; + std::string outputFile = "-"; + extraOptions.add_options() + ("log_format2", po::value(&logger), "Type of second log formatter: HRF or XML") + ("log_sink2", po::value(&outputFile)->default_value(outputFile), "Second log sink, - for stdout") + ; + po::variables_map vm; + try { + po::store(po::command_line_parser(ut::framework::master_test_suite().argc, + ut::framework::master_test_suite().argv) + .options(extraOptions) + .run(), + vm); + po::notify(vm); + } + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << "\n" + << extraOptions << std::endl; + return false; + } + + if (vm.count("log_format2") == 0) { + // second logger is not configured + return true; + } + + std::shared_ptr formatter; + if (logger == "XML") { + formatter = std::make_shared(); + } + else if (logger == "HRF") { + formatter = std::make_shared(); + } + else { + std::cerr << "ERROR: only HRF or XML log formatter can be specified" << std::endl; + return false; + } + + std::shared_ptr output; + if (outputFile == "-") { + output = std::shared_ptr(&std::cout, std::bind([]{})); + } + else { + output = std::make_shared(outputFile.c_str()); + } + + auto multiFormatter = new ut::output::multi_log_formatter; + multiFormatter->add(formatter, output); + ut::unit_test_log.set_formatter(multiFormatter); + + return true; +} + +int +main(int argc, char* argv[]) +{ + return ::boost::unit_test::unit_test_main(&init_tests, argc, argv); +} + +#endif // BOOST_VERSION >= 106200 diff --git a/tests/wscript b/tests/wscript index 384dbba..b157a32 100644 --- a/tests/wscript +++ b/tests/wscript @@ -8,8 +8,9 @@ def build(bld): target='tests-main', name='tests-main', features='cxx', - source=bld.path.ant_glob(['main.cpp']), + source='main.cpp', use='ChronoSync', + defines=['BOOST_TEST_MODULE=ChronoSync'] ) unit_test = bld.program( @@ -21,11 +22,12 @@ def build(bld): install_path=None, ) - integrated_test = bld.program( - target="../integrated-tests", - source=bld.path.ant_glob(['integrated-tests/**/*.cpp']), - features=['cxx', 'cxxprogram'], - use='ChronoSync tests-main', - includes=['.'], - install_path=None, - ) + # TODO: Re-enable when there integration tests are implemented + # integrated_test = bld.program( + # target="../integrated-tests", + # source=bld.path.ant_glob(['integrated-tests/**/*.cpp']), + # features=['cxx', 'cxxprogram'], + # use='ChronoSync tests-main', + # includes=['.'], + # install_path=None, + # ) diff --git a/waf b/waf index ef9df38..fa68e1a 100755 --- a/waf +++ b/waf @@ -1,7 +1,7 @@ #!/usr/bin/env python # encoding: ISO8859-1 -# Thomas Nagy, 2005-2014 - +# Thomas Nagy, 2005-2016 +# """ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -32,12 +32,13 @@ POSSIBILITY OF SUCH DAMAGE. import os, sys, inspect -VERSION="1.8.2" -REVISION="a01aa13963437a19e5d8748cf2afd71b" +VERSION="1.9.7" +REVISION="c00f221443fc5d8f60edfcad309d0601" +GIT="4095f1403a11e4138d720e650b435411e757ed70" INSTALL='' -C1='#/' -C2='#.' -C3='#)' +C1='#.' +C2='#)' +C3='#%' cwd = os.getcwd() join = os.path.join @@ -164,5 +165,5 @@ if __name__ == '__main__': Scripting.waf_entry_point(cwd, VERSION, wafdir) #==> -#BZh91AY&SYLt"@x#)!2Xa\x#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)/=[{{Zm˳]9yo3ZݻS5Kmמ4L՗s_^/^&.m}+e#):z{Ug:vi>{׍>jWlƆ}wpY>mv,u#)#)#.#)#)y#)l#(MœY`'F]g\#.BI#)Cvf(R]OcATQZI#.7mmwi{g} oJyv;6juBn7n}s]{I^>4ݣ]wv]˞6]w0zO{oۃtӀPP wfir#/uF=\x{D[ӛmowbn#/6^ɫɽuW_{>2}WQ׻=o_}zj[}h}.[wul6w9{[NOrٵﶪ6nPOӕ,}x>& C5[l{@i#.:}s{>vNs[qmnwi7'X}A\) o}bTń))%ڳ6Nwi[2BT+g! Ӈvw4=.ssoY齴(Hvv*ݬs{ww;_N_zfnN;SӪ^2v{KQm\#z݃%4B#) #)#)ɣ@#)&L&O(PMSi)'5M=!hz#)#)#)#)#) #)"b2#jTSҙizFS #)#)#)Iꔒ j~T=6#)#)#)#)#)=@#)#)#)#)M#)M`M&OLQiP#)#)#)& #@&4 SOhԏezқP#)#)#)#)#)|WtI?wV5sZom%)) Z$#){V@X?eB?80L㩇.$5d 3doAR :]XA#)/_ ݄sEM̺q8+I0z|-8]Yt>q/eBJJqQa[;u8@!x!4(Da*"CJ́J@"* I#)iD(E(#UH! 8•#/AԠ)U%P`JC3LHȅͣfh)2R-je,P4$&QDJllJ̠ L)AhI)i$%5$`"FT,liblPRJ)H6-SU$X$j64,f%M1TTI5̍HhԄlf(dZ)Jlb`LM6(`)L  f*d %@KdI)%%6)2AQ)I j 1l,L(%iD,LTlMe44Tf*iM$@jK#.Dl&**"#/ɐl`MIE$dBD̈ I31),b$"HJa I4bL,0l#M"J3AIR,K$٦Q5,RY+$I"3c,*#/Y1YCd24IKZlc $jL2RFʕL QdA%()FHiH4 5Z34&aJBIEEI2I(J,4`",E#.6k1RXJl21 #.MR,ؤ,bJ$TbSL h&M)&al2d*#)k$h,%!K&QiLei)T٬mLdJHэLhHaQ2@KѴjR1EbKI ,!Y#)Z4 eFi#.U-m(ɩk%H)&14HLMͱ(ЩFhK_ѲVK(Mb֊ŢBfTDlTƥb(lX4Ild15EMdleEbdjZYjF Y4DTe*MZM+6VRRm1BbiQ%QDefUfjV*J66 %CDB*#.5 Ԇ!5E QH&5(ڕFdhƤ,jLڵVa"eMdIaI3jҦkJdJJJMlR#.lfd-ZF@`iHQD1m0)RD2ғMh4…eDXcBi)lƉ Cbř!RRX md,!#/Rɍ QFĔdh42S1i̓FM lP)DE")d,͢ō4"4H`)eHJFS`lB$fҩ#.l,V((I$I4%)3H5lme6V*16)4ԓ,ɢ[R2e-%%$K1(D#.ed LDԐhFMEF6VL2L%&h#)6)"`-4TY3#.%,lhѰѨF#/DEd* c ()5JQ5cXfhBiIDY2j,Q+%4%4IR*JRV"%+e%i*,mf)li&lIaB"ŋLC4`LL"(0Kf"j6تHBc@FjiX#)bL"MZPQiMRIQ[f+%#/l(#4cfI 4`ͱhإ6Jhɨ6-FXkId4*Z)*ҲE(LYRVM%dՊM3(mEIFF54fX*eEFZ#.&VLS*DUѶŢhڡMkjDH6cQdTElII"!jMb̵L|>~iy{\Ef;i6N#SW d]j$LLYEpT|#.)T\AȟgQl+=i8nT-QUuI Dn#/5_Ͼ!kF>I2hDLYb"< #.n]u^?v;q0?NX;QLC6Tf5F2$_Bjckbأ¢5UwCkJTe0٤J52*(ĴhP5WJFk1Q$Qb-Fiw.u@(lٹI4"C0+1jAğ6.Z1x#.-W4=v#/*6PPt+sLPш}[i<;:N!V&CSMlJ=i+kqe7gH \ZpPD(aB1t]Ɗ&DUCBWyChJ;sѧ (*H#(k=?#/\n28o}up#@k^{Phmأ21ޖH4|:EZ9`ZR  7n\w]uEA귞w/H(䕚%[5ND~uKꢱ+LyS5eB6JY*%x I+1ϳ iu%ɅVQUkr#/Er2?f_ C<ᎲB8zR5NơƗd>5~ĝqC.}Po!P`rwC: AW0d;עX0M/RPX%1F*'Mhf҃絗S+߿Zě#.KH!c$4&27221ae/)Q촽Fv8Y[iҔcB'!.m+3,s]HeJ]<0=w71)$LŢ`# Rzr}_?[By ' -%$"K^3aT;LqV1^75&}U4B?->36T s #!sld?B<(u=Rx6WIFY_nhyϳwk'~jKOWY/(yHl4cxf|%>[mg neDH/V6$EXyc`.9=}T̝LR֗Gp\dFz}yp2f({O8k|zm!i#.4Y4Ps]#/k0U¶&#/jb<}LyȠ\\;m3FSjB׉92|p8Kj˝wŖIGAAHPsF?c :ߔ(&#.&s!檟MFTM϶*u!;>xIj޺v2xd&C찳#.$7zֳ9Z#/;LGg&B6[)i"zsl"8gl={rH<#=#8mDDm#.}:Rn`PMh:um~#/ck=c ,s5TV3#3ұ*(&zQqdUALjϣݤ`Սv=&} 1wd[&\2/1߶#/u#bGTSzPC#)Uo5񃅽\v%PGQب%9׆ĴMb$6(i!7 OZ6ݍx4#/5M?~$#T.}T'r8Ax@Pswbm  ( B#0[M&0]C G՘F>53Qy#/vTTڍceld/gbavbYᙄA#/pym,r2 TĵVm?Xf4T#.})qSA}ZQZY|'F>Jz5z[R *]>=kXh²V- ͻ#Ѐtͩ6hu->o̽Z{E^m%mx(6Hk@\K+uKZ֓@qFZHא مK 9z{Т#/M'cxgcB Agƃ'Yw^(#.C#.Pk#.,$]歱;4閞^jٿZr0luΥt57̞L =uWEUKݶxۇ_) #/B8rOx$uRGK:L 0IN֫KwYkSs`u"Iȃ6lmeQDvzz}_UWfh3 s}=ɴEhlD 3FCc|bhǥUL*ak[3]uv`҆ Urn!L^(4h`tsR>{e;Ϊ`1TjE=A!tVpqW*SiW\HU{ÏJg_3)$J*Arbp EѸLH y'~{c;umDM;TuFꉵy xcnM=4]d#)m<&Bmv6z9mAv^rjQC MYP4?uwRV7\W^lfo #)ܫ_fW1!-8Hg25|btx;9?3a4$u^0x>hlgi-]7՜x{H@|)_.4 '?2k?=N~96h 4 ES]5 Ϟ.= }Z 3;b~[}>P4?E[c&9;Q#{iqn,.񐀕'#/D0#/j{WzaIj-;x40j4-DZp[~yE9ztv+VrH,.F4om4#. Mq]s,Ccumg#U,z鮝ck\.L!#~˜#.mK楽cv]Au&#)Mou5)hX#)bE#uLeD" moCMKk!S0}ef%s;A(Q^y=oj'aask܈m'4jX΍o)#/f3#/-Ƥq 14Z6'N^q%D!,wP%`8oQƆd=$vQ`>\#. b^Y;Ic8㚰#.BԺ;f̰D 2T!3Zy0ԅ'g^|bvCZ)63ԒWt3qK.`ME?:L+s8lLhZ],ԚTq ~ѻb+#.zF-ڟo x`M4?%4aB<ԗS=,߷6w]b{oN Mc:be#.p(k4j 49/;DZ $:pR)2ӓRI98h#\z UbT_?~=ӽtccH*ۂ #J)VkqZױ;${tCuIg ܷ 8st1̛5u|=dEr{^ r{o!T_U7( T\ɤԆnޗL05WFv9nTXtk_~ۜ=|8CCCJB(ڤx`L>:mIm($]Jy.a<+#.;-%$qC#/QRrIEl"Qa#o"1$kEb=cc٪Z<#/hn`ɐ#/wCYqyӎFKn9J:ج'Oc \CL릉7{d$Qߏ#/y4QfvT[㿮5q}yfHz.M$t#/wfq3ظ":1Qmhj|o6eh:YИ)жqL oZc'0'c % ?1 QU MCKE UL/ZM3S?vAz#/(#/00k[x$S65S%i9'#.f 2Cj]!Z{cl樺Z#Vl@J㫳Sʢׅz*2cv+l$"g^v|`\;7˷g몽ۅ#/Tk#y~ZG«C¹WNYݏyfȓ:n9_ǐ3 f ƑFF6164XDVB=³zn+F% Un]p1L52ZTI`(5"$%a|ˢX>DpL/1PL78=:ڑsA qO㤇; s1C8e 13wAHj*?<#.U6dQ73Xj cH?L<1cknؽUR!2 `_<5p:ف姼!ЯI ?R1 F/ R8d[Dp}zPyKL(4e*2ך%aF‹rV&c E{O^tivv#.{fPl"~2 cH dFZ7b0Z#.#/$ȘM̋" SW,*+)IĞl>מffW,מW=[Uvƿ#sDOGbъq7"8_f#9.N=d>?PɎm3 7-k5tM#/Y5ߦ}A8^͐&: NTxXrCaaԱo#)R0z⹂|rԙQQLgC+v0J#Ċ L{Q)[Ɇ%k0_}}ՐwJ*IU h“d %89< ֧:;>8I0mI)x|S21B55#//Q1#)jy!(LdG uY=3F L#.3'go|'h)t:Kk*RDԕR~G2^%j c;4q+옶Y~Q%euc4鴶=*ΨhNa ( smm$UѶ孄2lmEYdi(bP%]~\s>Yӌ(@GIv1cjun);~!S|Uqffff#.:|J4SP}-yq's f/-•t1=fF'4LucZ6|?.=:;қd݇Ўnsw˚͊pjorfr#;PuAG+5:ػ#/fYq QN9Uu:;rIް#/G_x<ȬB68/DL%,y&Si{bWj>&1Yg4۳?@dД;͇#/ z;{h.c#)𼿦\gQpaWu[p4HZ?Çm:#.=Mܽ |G܋-l*^մGmed 2ӑ_Crqy+#.k˕hBSNXZ"IcL~XoOZD!dj'j瞪cҋP'o(ކZF@RF(K #?O#/C2__ff#/Z0; a+Kv8Ϻ,[e9s~_Wzb,*kkARY>s&$TbT]bi-*6S. A@8@Ԛ?%`]=d~U`W\'Ia-X'Cg}nh(Qfo~45lMyw a5H,KvmPH򄒷nWuF#,-x=ee V6FЦsBvbC]"x؅w#.0(7n?6us:Q]G6(m8&jqеbb%3mDDL~"R#.PQa(yJe ߰x"R;͑m!LSc˱pO%3T}Ig=V?[:$?qAC휍k\ &1J)$8BØUJӷ7=Ў$ؿ^\H2* f71zxl&?Vc%Β(T'م?wOa]Y9fm!¡AzlP)=:Qchi]u{Cxs]GD%䋹X^:~J[_;ɜк}z5JrS>" 2o-%3A n"n?aWYDUB>},ìUc~!9-Qm??U|q'ye#/h7hrԱI#*aʂGgTj^3>f~].KأL>{64#)%3#/N2EQ5|&~lTDsS;VZltjl9ޮY*8,]+dWz">T"NV_**5L,v!c6x><|>hiɔʪc:!yo}>;yw}#.߯5`M5z*ۣ#؏gynӨn5߆Jʖ+φiU ~1L#.;LZݩȗ)bC~2|ۻǛ/Z5;8rSx? \⮯N>~cYz4i|2row|=:M+vT^M;z_T-DzM Vv³sul<7I>ز1.˟ǖ*ѲVG+U׻~ދ>ܷʈ٫3A>]3]%Uxt築^`޻)uⴳF퉟UCiYWetmMCٷEP>)4Y)K#.:o[UkN|jZX/[=^~#\sÛ7{o[ʢK(z+V/T;t"NKk4?LFz7N=F0^l)9yٿѝő٧=$]\Y9[l a*4\~<||^{~UVN? r>ߗӑ|?Z`W=*e5՗f#.o/`moM<~_mOeN.GQU2naF /uɮs#.@wݣv;Wj>S,#.ˣnzuJ|ݘHĿA#.7og_'t_mk0F͢K}E9"7?71EYD;"k%a|@ɛUuu|?z>ݾAp<+O/Ȯηݣn[>Ե!toguGQ}\g)zNM7ccok=g<85\m|6٫gVkՆt+m;ywi<*/hHvGk_^v;@ySGlQ+?d; BYӰaݚ7"?x9o`ϟծmd)mtE*^amltxו5hvYՖ}=X;Nnv:<3V?mی}՚0&gv.ju-/o]X\$Ճºz !nOUMغ岖[Vx%ΪzïEg_89_8l4(;y؟;sE[!R53F&fNE{I==z7{Y_/f~{C}{BuJmV+Xh*y%JL؊v{,}k|1?$`L//a]s#u!O*D<>b1PaX#ia4(*I&cPbaDQSR&0arZNK2-`l44b,ȶYE,Y +tԺFIJxͅx⚙Q3EFdD? S&Ӭ_oY޳!%9guS$4]'Qq8n]E QE"YCSC_$t/=個pX`8h$HGJnldcf*Ց#.45vF( $8Ǧ |8aoYiտ+tSyOٕ驪yصu*&u}gb_?9\OiSroի>U_jw=ڗ}#/{Em&HVK֥1ky=ߧ=^Z]Hk] '_)0ڕ.0`}?/ǧ*-ԍߺ.RyI+\Ayфo<~/GZDR]olM^޿_U{7nnfY"v9 e|AVacM)IM9Ac° &,m+G#.੉.#hx4F#)iB#lLH0r %b sIډ.w5 Y9##/ )Z%`ȥMĈ¥bilxVZҝ}1u%{RopmV#.#)u12(8CGtqF$wX>#.#/9QB!Ҁ0!DmiJG\UvJh )"12#.e"#."N*Fȇlbl8$XX0ai&PN٧`4* H!SHbڢfH(LUV$(:#)hK+R#/(qN;pGq6%M3ME^n1a߀})sGh^a/?}ү-ϻO0#.ԴoWqxnr'^>6]n93 Tƛj#.HGbj%+bSJrT&5TûD =V|=?TmN&aHBh%#/ߊh&4Π4L1 XjgLclm&fĺb5MXDI<ӕcV+rLĎI]AT`+Q`|E7Nٴ\ qyU@Q۽`#/R:࿑3H-VbL{Dm,6@A_#)cjvZ8 `8 騞DVJ,#.6;RFE #.S54.mZ1"qc/8LQ-#/IN.1yJKTX-dJV(ZJ#/ <-[s#.>%f #.p6LӊΘ!ќˮ3{{s#.V&t-*u"!AC$O,cH1=:ה]޻4&3G"9_"%HOv-1}Npg3/ZVSB2#9M,OyJZq\YDaNmksбk<2C@ZV<:=<465Hk)^W#.u*q |bL(:?\0#.Ֆ7Rz6篫Bc5%&ܸo.2tػ+J(}ڵT9ݪm(^l},$Aֻa-xk185BD{rcDsqRk*krwdBR\ګ==CLGײXe0O3U1Ct{/2}I4ڒ7K%gW|K Yu6psik#)H9r)&a4:8#E(*=KU]uIwC:P^j~8^]ڶjl q#.#."tm#.C#/Yu#eY8`Mq)m^|ׄ"WJP2pZ=$ɴa*K; '=D;.i(7vx0N<$td<%|8;y^=ϒ8/s[uR$%A]&bdrlVG sR -#/[ck8gc rŸ?Tz:<Gޟw<(]VJI^,z<HtfjJ7̓݃TS=M;3on~7{9sɦ 4+i%!NFý[)Ḣv }†iWҗ6!ݏ-9ULP!r<,$ԂXc4ei 8hR\T~pUތp͍&0v QfޛdrL=)se2mt:p7\.9mk'C|6* %_-b#+Ȫd4[}ʲwG |tZGTy$Qs ɚEvM_zw!2"] g~$yJJ8rPGf{dV''=Oӷ헖FZ6&ǝR3YOq#.ń&^Q'}utd M\Qj)N$S-d fLXs5ЛyA~D;T>k5:7QiMY/8^o}ސ[]u>3 mtW!N#.~#.Sa)GEu?4sfoY={ĉF0MқWSbG3{MSTׄ]ʎl#.G$p?匟=8Ne/|TϜ"YhqzU*J;s$S364Mfh#.f)7#O3u֎Cpv6Q/6q$H|&z*#,-.X%fn)ނ#NTH8G5jD'.J}HukdT?| Qy#/S2[#.K?_|uԉ|HkQǓKcxnu,/yl~8CؘHYfi_7 5dNjn^S#/ŷv"#)Q-T^l)MZ+ᆋB2RiS9MMɘ>{pK&ß1I:«}5]سR]~ɕbJ+ON){tx<شplvH1}{65XU',n%}ik2[VZSt[s=qDG ً^i`jEg"̈́JI#\5%Q]G]sT?k~㊗9$GγfKQ]~`yƒ|UƐDSG**wsGf{C:U-pZQN1 7eB#/M ysg7k$[-IK8ffyo/2qNTK"-g<.92׍kۧgZ2]=%/O2*n?5]Ƚ*K7nk ܮ/aAΏoϒ"Wm:[?_kXYEuï'Ux6>xP:og{r=NrL#}#.]͖ssnB%Usxe&y }Kƿַcެ^Vm.)d-TTFLa|yn5xN]]1ſ1'g 8<\λf>Owgkay`~:{spHi#/37EY4-jcʳI]5-:|c},>zxD:hv] w?ZQW=:yj=};z}R5gHI4]WmM欫98LJ<ű2dsgn[n1**sܬw}ɤԯD_[A383= 㷧ֳwt\[pG*nUz* phhj5j-˯#/^Ԥ<(_tE\o9d|NMtK|'#/kvcOt?ܪ"Wg\յ@pWehZbtd#/}gJֵQ[4G}#/$dtٜ1HRc".iގEdm**$x>|r]og#.x#.o}wy-ʭO#5D-X|Ua-ITiz "*<Uw]dZ']#.+,4>?wNaNzFޤ$Ƹ_m{1C g]=OF?|TEwt,Pz XX;,j1TR d`Hg3XGw*ê\© 􍢗y{I lt/7eƻ\I;r[w)JVmwwMe1Z퀻Y;'TcOCֻ ˎ|f]3]Щr!N3^%8PS#.fIyipZĘXc2[Ƭdij˂2ⳟ#.eѮ<=|!z}x9;u_u۳-}9m!eYC#. [D|%+^TXKSKúlfSBT7H<ʙ݌K~Hl\~Q:EF?#/1yGؒM&DL,SD\@s=ܩl<ԛ)&q~pK&מ(a_OO|V\bEW]^6vx;Lp7qFγޢL@ _mtn(jvOPv:TXVHBJ!%a#.RAZ޴ׄz-,MA2I47 lFۢgyf?@ef}s^.əC-)\W$kl,Ԇo[<+<,#/i5˔gξ%uFKyUȜc{="WEyo~k<>=2t{oӚ,FCˌߦTi,CU_#.ԫ|eN^A5k4fvmf4:ұ=ֽuHOo`:btQ2ONVts:M>WROeA'Z]ߍuQJQ.bD5T>~n`|sKѬ|'FæNkB=>NQj+=$ C KHY:(=~'^3Js[$u ѕ}S6'ȖUEDYKuN}0ovSV%Cr?ĸp^"1ˮzrek]tfЛK &a:11k5k%BOrSѵ4J@J:E@@}ѲՏOڑKNjk+}iYKKrSٷľ2aȥNqq Ktvz4'to~V֏|Ll|Df%Ϋ~`n_BN#*9z\$^IC)ԁu򬬉n["=yZivd$rǜ7 0#/-tfl/6@NR]!BxMΗk DO鱼&<s:lR#)ڍomŨtS"un).$^}4O-UwR/VL]Y7t?nnvPCc%SmM&kX!)$mgYw.QQZYpo>>n.z5zq L~uV 6<^G.BWT;ӭ]Vawb\}9PYDž<0fsHR/]Dc؋:K|*Xl8ULڑNٖ۬d`'{߄xTz'yMESؠbpȘ*zř<:yM:q\ҊfW U8RwmbJHd.9IAk'=?F{9k421}W4{g5Ϸv&޴~eE:Fy>+~m#1t<ڞ#.W*T!12=h[U$5u/'H3!hH?*#/&jF09@5RXng3@"i#/:fߩOub RTIQ÷f5q |Fh-*4R&څKAٳg`_A1f>=&TU'65A? <"*\GOMp\O74_¦_hNErd=D>ٻȭ>T|C_',vXe#.yZY'EභsYTlaO9U>Yǿ1pq A6BESx>[gcH'Ub"mYnñԤ!;M#/?@fJ'rJǗ<*}h4y]\͛2eV x!8.:]H4gU']y7Uv:V`5gQ0}9kM:·N#)sWMlurע})m}n_9A5 CuiCtl3ke˨̛iŮ< ,XGqVLL2zgB߸fm5e"($s*8wn#)ƚ{M7)]ݙKRU}'L(nmhg.tpWFd*{34ƺʢVO*0J0 m2b2M##.ݺC>fAm:8'lLbQ;v;9O}(O9`8C%6@г-dXj;VD5uBjcN*#.rD es1C&bhؙ͝oh~\(v[y f`ςwuLCfRe `B˴'g­,]WQp #/o%*7#.(4"r1Mx}BLUtXa'9AP]=xCMs0#)˟wi^$chBkfnͽZeNN0ʼBP҂P])Pݚ7bdIi5:K!kƱdvJ1AFpMms|$3$9A9$yXݖæikl<~S$p5ýaut#/k2=Sa{0͔7ݜ{uCכ?'ؒNƨ8TrRlpaLl{{az؊A漕r3;ݩ6#/]\1mGe5 $ɲ篾,݇[!*9lf*5i-Zh$6Nft-[`RQEPf^4R_q~b%:ٍZ(ٱtƗֳuUn^1נZ-AN55L48f]:Jzkkv8[oƉ.%B#kTӟ~Ӝ5g^[8:ltrdwf9F#/ۚNHz.$45p*#.]VZbog&t^<|x#.SJeE1JI.9lp#.i,2CQ4;F|uV'y81O{"Dχۛo[p-`{:*:@e3-'&H9&}\!QR'|?w\Px!9cS{^}4v:SoӢ`xSvޮЭȚ~a&bvcɈ|]Ct̂OZNԖ~=~gfBscWdkJ!1eXLU!. (52ïgjlA*T"jx#."V5Y/Cy]WĔL.#.Pt!T5ʞvá"7881`sqSﶲ)z?=*Ho8 Tyh7iq9g.E9&vɲ=*.94h$&b4|ILq=fx\c>bG'!6#)9}Hi#.j#|@#):ԉY#2BiX9|l]ba! @䉱(Xat P\%v؋Bº#.q ;*9.ȂV$VOʯf 6Xe}9CBOR\S/@Zs5ZK{Baa2y&!g7'0hzGeqNyKRlr-<+LjWPʣcj*߂0(x,WG[6H9T36{\=9r%vbdS`*E)3Dֱm#./#/Q&3+Um+=3*/V3o;t7ay‡`lu#/8!sE;M13X.6N#."ޅCvNᚩe'.~57t/?<q#[ܵr$[q`_`yNO(_qV{'Fqnk>) FDɭ0^ڹk]84laQY`I$;F0YEJF()ET,Y93k5wr_Lv>NWn/d.L8;D J+Ug#h#.s=*B@;)xrBn8[ijm ^1#.:Pv: m5@"ނVal: U#.akk3t7hsHZ3tBRڷ&}:Bb2a11Tv *L+sZ"Uxy݈&w{8Jx4y8>8r0P#/(KTrbU(P]L$aKYlbHBַ1e">&$ORw`A#.haӷte*6jik37yyB:0XwL9.>9[\ףӉmG-PPL@4rzIq/;)c\Hq GϢAWȥH,]CpŢ&6<ʰaI5H[DփYSwIB:Ђm-0xt##)M`9#/@,BR*rA `N(_QVػgid2A!I3{bl=#AD'v920{믅* ň!J#.0 צa!=`bՃM۰pxCCUU=a%@@fPï9*V<٘~Ok0qZdR |"`Ύ\y콇&31 զӠ23^H`ftsf0j,/X.QS(z'wFP5]l[=wsBZRc)R],^c xmR…L&mYakXxq#:64χ-hG T_J#)$с)=|w;z:|gV0:q}Wtoi5@K-H]{bG HIuQꔳ+ѣ4#. ӥŽΞ+Csч5v=[aR.0?q8CNOyܶ)ݍ$̋6A,C~#/\@ @B8Tvi>{x]FHMy":#Hᄐ甄&ؙ\ӳF%@$I@R"N{1!Υ8A:9 +b"s#)1$R!f&2D=%7y,GCMPv*a{XSp>=ոf<><)ڊ$IPa6 q i&Bͭp}|^K)[SyUX,>:wQs"Z.|;jqJ mI1{p8B(%w+ثKf(&w)A6Wg3ԸHJ"zc'Kmm6Lc̞>(Ցb1]JҨ7M!m~vpo44qCM6Kv/w V3<~kj;8-ol r_`EܝSCt4>?P=I_FM!5HvZ&)lʫK]!2l E0ݟF0q>v}mgnlxk#.*̌uaﱚJJb--,Z4m31ҁ&ty5O9[ײiةL̲:%$fy:!C;5*%#.v bcpm-dR6cn[YzS3bu#)b@A<8w@S#)b5h!gԧ*W?zGRVco,h}](lQ_k2pIkL_wk\f,L4_>8k"r0 ͽ(f_b_SJHBP#/gW;'dk}WuE'l|MA3$0U M(l6#)~K`%N؝puvlO#/aYNgbg×KA?':Ă!3swsYMx"HcvngI&B?FA1%ddPFS?%6 HW{w~$ǬLjL8dӊqYW02>wn6GNy[q]eZO Zk1f~ud9vFެzC6ەq8y-3V-׿V&A30GbF-wEsOXۉu$!i} rwr6L0u\|1?xmHly "؜ ]Uƭ+W/? O?VNmcsǤo#/񆬔R44 4XLD%k0ɝu¦1<0qk0fsyx@;8AJ#.q+61 'S^c3#)ojdNrtL{Xo).@v#..ݯB*3'T~|RyF3>f\C5>vCk`xSǹww'JUW#.}=:VKz?[]5߳[XJ TsS;?^K)*~-OΗ|~,>DZNA439ۊ?k#.=|cgA\_T7qz%eW"C1*{*Vzzgճ=^u+粯a"x$oG9Fɪvv#.{gG\.rX¿Y^WnRLS?'FOK!o&>h:`l?xɆ- ˌ?aIM;ӕ#/ȑ"HW}]uu>[4׬+ʍdȘ\7,1׮{M($ߣ73_=2_u`}+5d1C6IQ0?~L>+7 84u)DKa^牜 l\ !#=۳-O2]-ޫ#)oL1NEN rc{|bVsR"T`0љ~0}fgn1/R=\o@oqӬ.L+/_U_4aN 1w`K_Xzuu\77MB~.#٧@$۾($y47٧eqX1Jf6&͙?3o3KӮ壎Zh&#/bc_wɽ3 *(㩾8*ds_7@:Y#$}TqKQ{,歂%f%L&+9~[>+_OƔ3V4?r:ryz,fzuLz}ۈ> OdD-t.eG;LHHBvU/)Ne`TFҏnXV[#ש܇DcJ=4uu8rr;[̟ slÃѮڢt$?!sNy30N'^RX^81?Ezdp#.T_Oҷ.Luή+ 4RGǣm3?ܚGχÛ@3;Gv#/ @և}9ֶ/SzܞYf9#qͫiUJ DhtX<T|\kݒԶ:̘9k|+noq aaljm4/d"U#TBvM=5kh?Gjƛ $6hݫ(R5E`Va~(i*mP)a]$QY3} *mNENЩTB!H(m:Ʒ .ڟA5gO1ajQ\`Wfkp'ܥ ]".T.$[#fB,ђӱ3ָkpNdXw)*$A~TQ[zQRH:5C#)SDQ[ !Kϋgu-7rE>:5cД;FFa+VЂ2ΨHv _8@@ˑ!˚WXt]OCw gDᚤ?ny mlGZ/smXt*G+v)}_ENՙ#/5j:TnVQط#1|.;lѾbPww᪐)]^枽8HTzzg>u61T*#/ 񨬥yJlHC6B T1XC,F(k?&~y* d< QBkXݬ1؆oP.n{] s5p;g,]|~ 6E$#.3x>Z{n9胤Of`3uK`Ӎ/͜>[xHh ZpYW4ۆJ2mtD\3]:fE #+Me>{뚺q&Vm}9eӽizB^Nu./8vG^yJ Q?{=!߽7ʄvOxȍ"&{z:x^α쟐YρN]5ҌﭱeuXDM5Ҕq"WV2>E5hy&.3-Szg,GI:WjRx'<#ӀsUE{eQ&o2G:LHFi5ZZgѮr#.h9{|Opk[jiW0uJӫMYD2`x+TcL~5ڔ\G=&*k+bH*J [qNdeB3=}o\aS잎lV+jڪU_Q%SjwjŮ, 3?N|WN?Dn\n%Դɉ̙F0UrO͆8kQmņNb+XYpIĀÚ٩IocP#/Kn޸q/tV;QώmbqΒmN;$Q`(s0F$݊)z+3öHo۠n35#ӕUhΒŒQggʵȾT1 c[J7lχэjV]=0b*k5EXZ[;7b+O/45%Fhg+uLY"4zOEUJv>uw 9&)àx;S;8k#)_Pyi楗ipm ݇IJaelL-#/ܲ}"DɵmX~7-z{Ixw])b.yM0.+7}TW FaR V+…>mM;!VX;qs#.,ia:UL~}S]Vi *s)t`urG-j4\m}T_j&s!3"FD&K!W m`᥅MxYJNewQWB? g;ڧEtt48\)6eQZMW#.u6J;%-5!&Lorv#/&o2XE: gF>l<[cSuJR6PǷ8qGR@dNϞpQ7ws*ϡۨq_c}ɈNTo,ANF$7DxQPvJbTªN6 n[U:ʻ⺜/ul2o."EThV!!p#uܻi٪~&H956"~AMײBYKY8oϚgt9_FTTrL c1sH~/RP; ͞;dg%+.7I]o]= — |kÙS٣AV<4˞1ߎ ,5qN}jnMe צ[16=0MRftYd*bK7~o>?!c:'$Dµ^uA# nBry:9~~wdI J0+ꢪ+=.)|}N>pqaq[NpI~)H\6t>8}o*ןal==߹&-b2'vkC `$?BHhia#/O#.C<ªh*[Ϡy⟇}aM1UZvT"d<@ 7C1Ѽg-vny۴莤j9 #)s 0$ cXv}&qL#.A["L>!<Ě9c)aI::#/+z'iAfٰKL^ͽţ'ddnˢu2QV0RRHEoKT1,.d${ZBͱ7MxzYμk;tvb) C%eLVY}iue’u.L̒C{Wsۉ@ٟCGAW7ذn|JmY4"*Tnӗ:"CLi9CMo#.!TQ#OwaImm0!ΤLŸ־u۱v~ǵpN{q0ȜC ꛆ;[#.2\uztON6tEg7n$was>Mw6NŻK2mY 3ŋ;xCTQ@'93RMBȠscy)M+'Q'\`T0GnP#.rFq:b"j}ZVXH=+jbEdPjЄM,#.;Ȗ?xS~3 loRoP7~#/vB*KO4##F}$8#a?HIcBx;34#.Tq&3$d S @"sSr'.x>^>]%ޢb+wwq#/n`l#.8֭oP=K2[v,2hB{&}6,#.!B?(28@@W"MܲK495i6uwsWZOz=qWFV|Rc&MqR2erhm2nfhj)YD"+-8R|J7T\vʘeBj1k6Pq~$|6CH#)_@iӏDvl_3cw[PYϨHO8*t:HIrA6 I'g6cw'l O0$|}^5C???.9EZ+WqWy8pS\q]uwt#.K)ô"&,`ڈ(ENҦ.%#5{onäL1eXoztLbl@~qrCs P!p}T̨D7ܿ#JIC!m@}qd|U*ucMv B0rd_x|`!*\q&4%!㿨2NEG\ˑs7)Ň !I$萅.H#)}B#.Ih~cX}7y#.֘>A$q%KIܰCy#.٪T6#?,Cp ?}]{.20Ǥ#.K${5">'c`CtM'Kŋ[g Aư"aIea!AooG?Gr{L5Agޚ aG]w>3!"zIt{#)}C|A 2ձ͛`1sT 4\3'_-잦͎Ah<#/(b/NFB= {_ߣ·<ϻ;#)8g>1#$>/|}?!࡙?D=T~Pp=/7ZUYfi&;C|2og0~G?UgoP~c_N]#/9vTOC5[T#)1#) q#)nanr𕥼gx}.599gtAmE詃#)p`XL3TéyN53W}gj1Od$#.! ]Hj3;qk:M$XF%n@#"NckLq4TN9#.QC+=== fzAEQ1!q#&9#.gtS׼9O7e `No=7(ϫ=,`DiV.VU]ms]Иn/n@q*Fl3v*#)Adzy`xN9z|}mΫ!#)b3&k?O0%S[O]X, 8٩Ly/WiOSP8M0^ޖ7 "3噚MD?1wk`͉a5cu_:ΥO=EM#.DP+xc:OA<[H̬B4XXAɷF:_{nQ f4 &sbl<#ȏV3C M1l1#.f1Aris8PDfvAA1 4&a,WZ|F.=CHcvqql/2Z8d+l JyDGiBN!A8?(<D'Ebhj8 LEdfc/yWk;rםګј*fՀ62Li#)M:}]~ɖ(#.H$;۰ PdCh~cEZV=ճk:Cu0R$ #)UOl#.$1Cs"3m~F\U6դfŇd T\^!=c<];7aYHn#/#.Kk`jm#)Eܘ#.WX奖ƒ{3i :[$؉\y٭@)\8FäDYh5THBǐژql^uApiIVat#.A#.a$#$Z6Ey joFO3!u ne0(K*QA nP2'w#.Ɓ릁3C'!LC"$?0(oIv&"/SӭL@dpe=aQ˻ba=OPg}4I"\L9ě} Rk{6BU0O`oh(؛?~va#3:y]UQ0;pN@,8?<(o?<=nkDa% a#2J%jJi˥P - A=?xa=c=G#Gޏx#/*b'Ӵ7v=õ61^C8;Ǐg'hBGbA]IGBh6RMK#.ϰț1:mLͤ5(VHP,!0rC$p[PY#.rzjZGZVp#/b^;HltwDeQxwA! tE5s ~xuNmY̝?l}p"M\ CSvk%eQ:/z2A^-Q<#)v[]z&C{_G{ԫzxT/׎StW= r2{^_mwj>F=og3Q[ݿԨfzn,Wغ?W Ձ#)~۟^z&V|SPg4_~H)}&_U=rk/8}S-[v@&)Z1קSkȿs@,cd\T@Bәnt~ͰǏ#.L#3.b~髙=cHh<ϠE1?$=Gl hd 3 #.#)P/?8\E:}Wޔ#/x?鼲|z&d=5BC3~ ĿEo<}AQ!e%;&`NȂ{ h4E}_#ֶE&6([շܽWzAWi;'p>j^r!AaL7-ciTY8"97.W=SsOˏMlp|0I˕WbV!h={(QHa_o֎s fꓳU}p2nX8D~D@PDGZ#)]Bek6#)/<k99=Lgnz:F>wEU،~4$Fvb킬MӵdD τ4g 4o[MlOo#))0]5C+Pf#.NfEPm8'V&%&bEa)e3jөp&c&'ПW[#[*jqd6'9y_γ1$ ғcE<*@0~>4~8C'nyвE2=mh8m[Ihy~M#)_#~e?Z[}QTG>%ۣIN>1鳆Ah4E"I0 Q8-b^Ů 5`pG55 1>gRe0!#)qaaַRNSj{=jiޏRg@Uʞ?#/iCJa0!3,&ab#.f Q@hњd)_$7sLQ0JjD^JĤh+1TiPdAF1RS4й 54j3#.܄+$-zxى%)A~~nvt =J1+~k;k#.08$0܄2I1#.(Z9&T4rqUDM|(;7;/G8~6%-@8"p7Q&{l%Lf񛾙|ÄdkN[ׇ|͘.2#fwG\KضA\cS䥒O𖀝+hf!ncj_-9>S6#RN`,6Y)jK`g,O(j+'BB͝&m+[0tnFZj?.&gy2i)ћm#.h ,82+L~!9Џ˛_ o8K櫣L#)E9[1ּI>Y#80_Īk᤾QonR>{>,̷)}y?`xH5Y2鮈ItgRm]]$iJ `e*ن{_/8kRe o/Go3Z5LwƱwI2[ie;#.72R$S=N4kefz!Aҭ ?%5"IM2Wc=5ZѪlI!6J6a1Vr%N/yyS^Yq/!0;dCept9sRG1ygX55;\8/$fZE7'mͦm6oi;Str#/ +;C&sy`XUcdo~ aք;Y)z\! %!\1S_1ے4P֖'&R?c&62\W^^i8i`h1lH(Q}?pïxǠ9HǺؑ٨<5CJ 'ꁘk0j:^@KAR@j`,bUOdf; $Yу|Յ-qMA!_QN5SfX:?;i0F#uAR#)#.@ ZTrh ^1E3q2#)#.\.is.a`56̆a%( E]n;6JM+י;%\}^֍_/noo:Oݪu_]l}MJ 3hczrWc8dҋiuj#.RFdA fPJPIHU!#/eV3YK̝J0`Nea1>?eTUYj֏ya23HtQߣX D;GgaguT%&};-@P6LXtY bՉ/^)#/y4>B6 8Fr#.54bq%MȚ a~YMsx!QY;w&ǼL3{s#)"I?q8i#.?OI{$qϯie()+۫mq+pA1h=H`xMg)þё&Is:X?$D0IC#.!̴ɴ#^LV#.[6x<Ux#.*M#/qSndk1@^ [_#/wq7Iۖ%vPv>(tiM:t:3&7v;V<$qH\]G)gMDbuL6")8غ0u"q]NCb1B5kmxľ밨} fl`!j#)cww}Z,qmf5b#/LE[}9;dCdڪ_.{9:nӀ^7L4ijrW/O6oć{R &T ƹiPH;ĆpM/z#gz"T$5ѓPw+##/1hJh}P»s}r"lh@Ⅱ!31 0Էs2P^m#.P=SFzsI&J9MtbP^#/$9^ѐ1/غK2 D2C j)ܙ} t`wS0mc2:KEJFbhnS^Zv'/N8j 99>}m%J#.܏qεiSnS-.H K=OdԛԧJ%vcv#bfF|%#..f\y.ffeXc->yS=#/@n2!1X !T^ o#/dWLJxS{]:,F `XY8qX~*up"lDΰL.:jeb*Ya2ALt[cgLK34AP;o#/U3Dm2q(.Ι .b[Vga#.!FjFlf X-괵K#/΅)϶UFTXmRN&wC.Ŀ PN**,gRq &$Ue F#.!cLK9 bc1! =.{7~OX4OoqX9l4|K3' 6ܛ m#)IzcitvQy/%]ؘF4s#/eOtՎD=!48(ҔEtT+g qꂒuك)ZFRg?AEPXN=Xt"#/`U30h/&NWLr,d#.qCCiC'xCi1AQ֊.f,9PF2c`g-b*}#/,YHɹ#)MtN85u)2Ɯ>^Ʋb͉g`)ϰGx#тc1@5Ɛ2dLQ+"h@:lrMV2x$Xm™MR,ft𸦭DM{,k>o@v+rSIr`dSp7i1;j];[1Ɨ;?XԙfZgPd#)>FÂ9Kb'c[owr`5yơ(:_ШR<8Fdm{UUV?qˀe#:tgʁy3D]v$bN'V1նxy-ڜxpi2.1=PZooAAap%WEo4;S3,@q5->|#/*JvIB Uk6ƌ?qBhȰ*#/hoҷ3X*D2@lkWe## }+xfOd1ZZ 󱵉yu#)ũL8Wxچgvmܭ I"8|| #/&&"2 (I&in!ԞQ23븠ن]+J@r<_,A( L?/!#.Y"0wEosnHc0D ->W')]_{by1|iaIj MRln9pKpFjQ?k5[D~R쳷8;CTj]{4O6e#)pQO.#)xk_,<4⾗ף6’'ڇ+H{,A;8C_#."V|ʘE@S 'bA #)󪀹-E#)Lˇrҥ$KZ_y[1^Z"]i8gcD$nFH䞅O&X sd3h /?5 $x ,cQׯh<*#)L{Ye7#)7Bs۲H@$C #)#.ìDߔAAXGx*p`Owz/;`K\DmDP)²P51#.A؀#)Nʏz"4MozskwW+y;Jb>33"8#)#. k#1pؒ[#.%ۏ8zy={zӋ,9 xYȷMD>&L0j̯vJ^Hy~?wA2Ow`wy- NXbhQԏ 鸣@TXd(Nүw_s#/D#Kŀ׹OKi.k#.43xpݴ̝$8D{`^@Jm61KTdTMlU#.#/m5e*X#/#/eXE$D~rWu~H>FiC桂$rѭ?#:hFaFoGR[5-6ȕˀuE^$#.$257ЛkbzfeX0xp8Xjhi)䛺\_pz~@IWj!"(SXv3Λ0sZ"Tpb !d aGGa0 ! F c!7]fhfUg5#)$AL%*{!2JT5'N}m¥㧁CEaB^jxStl"l7gg0Pdr 36?3B}o>_fH?ztBig\C+DHf"$yۄL+ dxNH#/jHa1(dڢn{]_3Yo62)BEr?hZ;xm 2>ꇟ~zQ`u™(g5 -$ú_Jp.g46fvkФf@zXj(N ^N]_`qTYui"wi;K#.~JOI#.#/vAa[H.6k'3V#/|>/ds%8B`HoL'~%cxL晢Z(iO9''M0j`fr)%8)Hu5+S/1QY#.o =ra#g#.nQLi:?("Z<0ć"V!|wASX:q@ctLpN K0Z =*p 7x;x?pU- C/i#/ݝ 8."d۹없W냦+"Prdxh#/iWe7rKɳ&B#PrAߞޙ${\q2q<ԡ0ZDd& ;*^5J:s֜<_F7B 6wSMW~K5[v%oC:gk#,av⬛VaA#.2 5MWmש;ZlBy\$#)f٢܀+魫=p@WPd$p׿+$g6L`Y GT8?oO3,;4n[`=/s'KtF(,^!~݋hkSMZ.BGT8HSfFf$#/@V:L17$K8L5:&&$;+`e}bjJPV}t+{6!" 01z#.|s{+71C0Qy0!ɱ? O c#.fhh;m.#. WI]U5R2SRHƽ ӟn|uGI.#KM1^96guJQ7%`ty4d3r6 K_n׳3-aٷQzCt`V0ZIAide)65tdRd,C3tNfzSSĚA(g7=x}^R)E/pË@n']_*ahc CF!nŒ~b~I_8RnSB 3| [Fq'M-:*^wħ߹$2*Y*rn)yqw&61YUИB׼a;#)!Sw!ICa"P>my]B.A#/#p˻*}x)^ǟ5+٥y?b Wyfy%ydL6k#)md0n`H}5㬵xQWHT o Fq# H1R;#.4u0HL7R|g(z|zy& R8qW&|@9w.p.Nr#GFqۊ7 ۾13Ϫ{CpC^*8V#)VyRh)6pEƒ4ji4+l ]Rb! :#/,;5rnP@ۚ(NIB< d e+gƋ3tF{S)|B>4_q6'v8Q||QΡiva-}FNJC&`F,gzd@ةT11zPI0vzjétQEvH[ap=4,F(&g"V<'6h KAHչ6Vd6p9@vPd?NdބNes(UIKHJJ jyO2~nba_<ӨlDWhTpg&)F""(]ݨb`&(~4`pS#.Q͂(,{3 Px9F\"qcJqS\%`DhT#/=bQ2ޖyESdq[n1:y狞Di% #)$M,TfrO`0p uZt4ĸ0@ uV|'|WA%q&õ#o¬Oo](Ldȥ7GJsqm!ݹ1&>{|0-'Qڼ Lg#.kǛf_rpܢj{ g4k,G7{="@h~K:|9:#/uQaBI!1?i[G^mqzbcr׮'iGwņ_T{[ѹu &l63„׿8]͐hGU<6^&>5śiyzKCnx#.Ok2`a&P/`|ngKC3Naj{v\y%٠I7"m^Fe5uvvZO;ǥz-`@sN#HKO)ẠNMn2R7;v@ \slLfe3E,~{sp3i.v0ч[E`[o2#.`0@=C+!LZ,g`zp<y_3bh#.~wiSj/M3ra%&P4lƎFNݹ-#)'0cgi75ܛi3lz#hjt'n:#.)'Cl_#.\@oBL#/ݥ(:OpBV6h0| ֤2;XMbhlɓUG{Vzk#R¡^_f\5/2LBҖ.KR)Lf{f,3Dt.IzM!8y/[,33 L,8Pru/NXΣ92L3H])j.7?۲'81G^|ʾ}\Rd+n!y()Ú p>$fl!bޟN8|8:gW!/>7Sx)ns/x.>4tI&a:Ĉqf7b#LT8,WSyv:pB{'%:=/۾O>`n[;r]n}#(Nv3xHay HK*2cV1h(|cauL%dnEp;efXo4d ddQ2v%Mhٓ4ukDJ6FPw1fomYah3Zà n-@+Dnul[ 6Bl4NiiaD`=qRvٗ#ڋ|ɔBJkD6Bn[LQ$Թ8Xj0]#.IL-1FL"&ޜD% tM8bqLϑg1y!Ѷխy0&Am :\B :tf6#.@`#wVHwξok#/, Ȅ/(wǿb_N:K`d)h"6$4D#C]NŞx\;y[dyiJv!; څq[t&#.dCQ#2:t61Hp{7:r䴆"Merb74!#.Q`,])TD:9GLmҽ{^A_aNKuĝFX`ID+RS5:Qg (&f9 zM43#. MF(LZa:I3dpjЮVBw8cP#.恩26Ƒ)$s߾<6 /\]CÜ)Xа:$gTXix`DY(o"?>?#)Tm}WU3Z22#/6ْnR 0A(w'a%3?#. DQg.iEх{a\QFO>8:85r9O+Gv{"ʁ1nlr N.8Sv!vv]6M {ؿi`eV$<5B(ts1uY 0j`Ͱt4%AbJg]x8`lC0D ;DB`"#.^6O7qRTc×Q jn}>8)bMJ?_@$ $:5DdI64vg7DmS) \J=]?{ بuvi[#ބOy$윅6_D'\ >Ia&IPaj7C?O$gay !+'9ZRV P| 7fMvd6 c.ؔFz# T:3',Al)>>?o)48/0-u&3}}y%)+lm+FTR3Q&6fWP"{蝟YLJCQיO@N!#.E„"bs#)МΙȒ.BPsONIDn.ʑ8wb‚ J0΀ x#.B#);`œ@c^F!4@h0l`osL(I^Wժ_:} Łv=G3?\}0ᢙ#/^yCg 9GD#)Hkă4Co"3 ̃uB"%@ xIb#/Z5?1HsqN++ LhAUbW* 9g]8c}Ij)%|V)L>SjMF#.<4`CLeN^ӊAAp1IMW07өiD)zz9LSNyG#/6#.0a!#FdCD^ejQ09G#.#.n@t~np$OO?DM+4x{#.`0Ģ֜0x>v"*U4${@ĉ3AC|PTt02 #/drp@f /"aG&m<Ӧ t]]޴?@?ʣ*ȐJs<(TÆ{yA Om*8{4,*GdSXڌi,%I7msDe(JbBB,JedQFILjISj(֥$ $ mT1jbU4ڊةdMn䊣I6AkXdU5V+my^Y-,&XV{FU8P뫧ѥT+vTuI*MqM!*mOn"i.S]~.>@6XTyV}vj-gJrI%a6Mn#f~gOZ f+8ao#.4D#(##.&(IHiZ#Ғ7h{1OL##))7G{c#N@tL!(#)P*aۀ.:Πv &@5ilJm%%է M!* +$#)ȦTLQ-&ВPR3e3,B%TjMIRm`kJiE d)FKR#eVFJ"i#.JX*+eTPe)3fMj*d*jSVmK2jY %\P)IHTS!#)QCK P`#)dBI:6CI_T7[oOga~#.qr7]t#.3mbk6mQ:"y;:wpIJg#){b?ǻ۷nG'T=GmH=ۨh%~/kg^8b͵ UЩn@!֎Y!ۛ46u4H/1P%Fal;”5*{@<[6!Ff`-lpF0OU43G@(2.x.3AAM ĩ(wvڏ+y4Ծt~#.S#S#.0z{]k@!b{N6r6Q]bt4I}XpV_|!F{8k@I,Bv96>fwCI2Gc#.FEٝ"o8\8BK#)2@=:#.J-p*U0ʱq#)3o#._qd=&#LGs!9$F2;ƈl=Li jM]q⇗_#)ޒKC)>d{nx$v,3AX)kab9hQo}zqW5W| Qu]0иXZꆖ8]#/#.kಶe}ͅߋkpB8mS2"p V#*LïPhjCih0|=1X!*ITMΔى8~ /zź#QМ!2Xbmt&U8`YGfXު**"^0n.gCO|.GV,¡T2`ƒW:G@Qudi.Zѓ9+*ZӫzÜE,7D+^u\)hvG:SKCR,ju #.N;&}H,,depL:o,RɚYT^ک4=̋LҀĩ4=i*&qEuTf(Dg6ӭR=j,aa;:MGJ$g/MEw^TDtreʾ10gFì]*wpSzqZAM@Jʣ[ l`/f-N>!1 s/(&s `1Y#))#.(dLq7IIPKb!L8dIofaۉjʪְC`qA+yf(Z iM 01%pT#/H] bi:N4R{#}|NPd] }Yܩqt;{yx^w%Ҙ>8f豅?,#.1NץAč{Ӿ* ڃUkXٶXR.m;5{KkSbĕ^K\{RA!_\#)mDh70;=Yo#)G%l(d5]">hBDVz#)#qZ\B,!n'>fĜBdDC=Rm #)(#/#.yQHmv~"S2k.G9@Gq>$0) #/H#/BAP <Lt 8Fj.xa{^$,nj C_ݷi_Qv T$ѣX]Im:7T#.r]F(_/ʦHaRg$7W6V}LJ84 W#/JU?R<\ *-HYsScjzkR?tM_<"V3M3bII݅~mna|LV"6#pvv/  J >Fީ r`Tg[1nTkiAy/`4;;!|rfo:>u%@b#)ȑ@ ZR0pG%(R82#)m!@P& BU[O^!kZѮR rxM -cP,#/Lj=pu7{1a/x1v's|x=A{#/2EM+c?u)ds0#.|+)=5MNJ!iB՗DY) n$D`ءÊ&:Jd<yܽxD2Ra`2)M4[x c M-R4C' Jr @ tmI pX.CQ0e #:;gYG=^*#)s @/RO DGa2ZY65ڢd+[nEX1,p !!\WRtB@04z7c Qh.g`#bnc_fE/jz:bk0 \3#.A"Rvl9#) A 9|uZ/:ρ^=?'C!bGkYX-yBJ!"h#{5cZ͙mcb(SF8HG]Ѣ#/I66ړ#.G,vP B",ø[FF#mH߳AHe!O@r`w!-n@;臥CJ.%Aev4P%s0DivC\ö8scl:;VLC_J@7wGfU=10'wGeE)k{iґ}IG'Kjt1.(:AU 6{$F3d;ste oLPØPCG4 )(ٚZ6if5ie}oWyB7GGc6b_maʡ1.y xuRkeG{ ,TIA:Hxҙˡ*΃\k5#.2<{> >P#ˆ}_=| c}ɥ_oYNB9!&̆I׉$Fnu,6n˾Sд%"H?DIVTf@NܕkETYШe4a ęw{~[p;qLi#.&aաVhioT⪈Tge}Ia8it-d13 YX_+Jz5ݼg"؋HP&DڥZZj5#݉4%EK?DsmMQE0$"Fh%FQQ6+FhikHk-6k[JϜ@I&÷u"Nh<#) L(E1G%hB#/@S q$8آ)$!;#/^ҿ_^PR0,"5qن>߿b_N<лu: ]xUWt#!#)~Pا֝N?%a`C$2\PB6P~;Hi{/Yv]8PQEzut'S& 2{\&#.?1ēҐ97}s/5+eT]8bO a4#uщ, մe$C\[度I#)$ mxqҏͧNS9k]:YS!^ummj)[h"#c!Ϗlq~\~[A((&bA&I!QdV8*scCA:iw9xaѣB,PQJTlZ2&*e4Mo,fRQuy(S[i ]=d0P,i01CL#fpa-5u#)%ۏj`ƐOBA Z$4CE` $țr<:IWJ&q™5ns#zjƁJ)ʜeGC[lXͲN AIH4fCEӵ%zB&:M,by#.;#)<{z= շ@jN#/BS{fQKG,Gs2C;n'~qqv#)a2i ,^\UTc_>_@]HP,.;#.d\E#/ٜ0"UJQQ!=Mh#/c0=Hy=]]"}cFF0 ?]~;SŀM7?($@)wGGpQI n~,oC$>wp*OGVhBV 1T@Ж8X#/#.Ejmm؄b!"#%\#@**eQ3ytm&/i *!vGx$rH f>zX4BL.pwm?𪜌Nf]8f\St>A#)/" 6%}D@PLȥ#)A(z>J뭧vX5h+E!|rmd H{'UmMmQIə8HA(0QmZI8Y6M6m.z #)D,T!yOI͸B1BEFKS$L~ir߃LΛ<陚)S5'4qM#gz8COda|40;ף "'|YC%[WK #)0rHg-n͐6`yzP߆E9ӜpDc݌6BdQ7 l#&\_{JjjggԚ1CI,",լ4#.+F?*sNd բ=O& +#)>I!{P[_>#/m3پN2X,{-hZ:)JZSh*:uvD84'w7#cgD#)ȅ~KNT7euRH*rԖ$@q#/$#. 'br`*!$a Y$q6OCPն33IwydIfh&n0'wu*6V!gvQb(XYlJTVjCs0fT#)"e[u[7JRrMuX@LҪB#/;nc;xsCO RaÄb6#HQ@MR@Ϧ&FHlϘc4$glM3<ۣR5u%"0I2J'rG}MdSjAp}VbE,4#.Uq0`LpC 4lE}/ӹb8+>瞓d :JIsgKvZƝ|Ai&`.fa~}v]?x}%sI mwS"Y׮рN&c&,$[.FDw~-k蘱Z&|5Qdt@C$ b1#.D2 VË?i{@#.Y5+o`PgSP5S睙VJ;*"`ZOݝqA,|i9:3D5 V@Oi& `+zHy3d(ghc"Ӟ5QawLT:CBBF*,529#!6#< *[}qX_vG\ouYҷV›jfzˏ%ȭ2gёraB;)=YˏbB\Z{0t/HnIP}͉a N,m1#/Hi#.ne]=m-|iq=\ geouIj}[I?]_A*"7}/; u;bwCJUJVZP#/DE5ds.n kt<_Y9#)aQWsŁ%t#/apPxYQ7C #/#.Մ6.3 w?l9#TW#)1UHLc~%"SWmQo۵% 4d>'_#)k{J>l#/IܑP7S"4剒:<ҿ5 9hIǍFb API8?w&6DDvT,k>^hWyIfW(c*"b]ӣ5!^y.$Hi0v)#/w7ie|6:9uųٱkiD8Βbi6VЛam4۬#/D`SZ4 m#.bqYju66hY3HLReEubX) c֨j&(fgrM.o lA7&D2h]f89 }0HFŐl^۰K'[#)/#/h&)@a/QA tκY4weдKia&VGV8@h3$Tpm:#.MbԖKe$&6Pf[6)j10JZ^ǩu$F4CP1F#.P-Fd+S|` t%0d c 9̴00tmGW#.!4 A*ReN@258SoCLP#. 4lQ-+13q]f 4g}PSpZkC&æ,TDQ*T(S$r1jKk#.wJ3gA[Ua#.Cbes#/&4eDkC7ᤌbh1؄44ZJpŲL'$~мoZ!NAJK|jB]0 -1)Jd!#/V%hO0EFXAĨVo޷HBtQYV!cg(L.س Zo/G$|XAb R_ّ0@C]H mkPNnQiHǯ }.c m*pѓ鼧Mg{w`_-# z qE}ēϬ'-c1b1VH61 c PBի2=$ad:[| .0XfKy/S뜍1rJ2]؈n[~奙(ctwaIe0Cv9W\(6~벑,NDj;fu,/jh%!V=/6PdK%˺Mp*~DݘljL"wʆnɄɼCV?@#.&#/y2o:;66%KA$E~1#/(P#.D/ 4| 4AAC%#)abw#/#/#)4_'a__Lт(} ^:}#)'}3L\Hb2KIh8J#.#)@;A6ihѨq ӾۉCn*Hl#U 0DM*@r(*UTBaPvV=cU@b#.36FjQ XD1Ȓ@aERDEj`O"$5Q`#)&pQ 91x>1 I4~q%'fD?y#{ FMBRs b,Iǎr#. yz;#)CT}Fbd#.m&bi ᭸O݌vM3 ܊ץɡ@s30wMv#.?rt]s;ǂ$lr4gՕ}04~ X#TR[r@ a`PhfBz]G*&31ST?=V{6Dy\Om]]ܪ8QlM 60[K#I#.kEQMQhL 4d`hc&EZ@"iP &$ -06쫰chv9. 3c fְ o(:TA'"Zh FHvtmuT(vtHlG BI TA!>PZH9 Z21I9P+\'8w#)SS^<U Xi$-|`TS&\H䐌c#@66daU1FLW alӀifU'gR|m:%Z-޶#Ƿ0ڲR66nRɌm#/9a1#)HՒ& wPxv" ةHA#)#)0pQ%#)4M h_-_kHc8/8oC"JHJ /BB]BXNh\=۸^mOd樮~%44j@C7јӍ(z^5!]ITdW 1҉A>fr֬8~qn5O5-aFy+#ID 2yM$ĚH1&Іf0pySBۿ)0[KbcʪG9(^Ȩwr1D#.{VgBY^eSx7KNm(LͥD4b.qQla@l$gh3\_3=i=IwED$P B+>[5c1 `FGiiC`a$ #.MlA@2=qY;WkkgMQQCZO]iUVQUF-_:fj܍U6ȘF㹚#.R΃as%~#.{v9:,HZC++Ԝ^vaJ#T{d;>D)@)D_YP{;i9?h`ōhdɍaz;ڤ6Aʦ#)Tw +Ǵ#o%q;Ew:>W4ۚaΘ9lyxM?m%]XOzuɒO#)Or)#.6tJ˙_CI#.w9q3#.oeoponZMz #.@5$k;g#/RCeʤUn(BG2#髬Jc>8 j:q0Oz}O⇓!=>ܦ z-UT3#-$iIB)RJ4Ɉf̙bYPJe@IUT^ޗP~)*@iHH;u&c6zDԉ\q8msQL#.sZ#)cM{AΠ;,+*qcYyxZ c39NMM#/beЭТibC0Â9P#.E#.g(F$f|!܈w!8IbpEk"դ$ uMPڍrVh+U8Xd#!K F@zomMajNZT{ $z!\FmdT5uCt22WF4<ݡT6u֬QED`27nѢ.r0$yJl#/FpaIƨE\҃[3Dbp08\mA_/@'BKHoRڭ,ʤ#.T,`eՐ][xD@2Y2LLcH` mV$&B}#ot7ǓFg #nVF:^12"D+WJH}Xk#.#ÛXL#/lJcLX0#`g Y042[`F fc0EQ֚dǃ|@,=3#.J4lF*'<^5FiEmX8׹&0<]4n#-8RE!gR f% #)\@cB(m*!EK#)Äj@w9' ,42mfB LHB0ƫ59a(T(BZ!&Z&!N?TP?Z|`(yy/OwלZTz ߁a@7o3F ɻ;].Zz!* `2fXRaL9i+9hD?3{ .<>:k*h#bSf?yܑ"sQ.!ʠB*,7Nζ ێY!B<\Py3`u'Ql_#.Prk9X,$njnpltB8SaǛUK`oy5\]OĴ CcA#.%#KZuhL_B(=&EBv :2F u/0ax(af#.&ֿS$xeS`=Wi3Z}ߌS=#}KRV0޶=0cղae泀#/keE1'=d d!(ŐT4mk =31#|~"THXWꇑ#.]ʨ+z&ݹ?˫lO#)Wppj T > 畒V)occT8TJUS p5TG>7K?GWYrҪ"pbMA@-#/a )Q6xo'&Λ)RRBsl#/UAM4k2WSX`T[FAK:܀wvhkQIxZ,oʼmXV@#/jR@) #.k!a(F- 3cD a#.z4Tv"}#)sN_X{Æ#)i #)x)%u#)F6q&N.NgӞ=mC)܉(@I LdF7W4dB8 BS 6 `.! 87%(U#/qT2!BD&4XP'y=rBxQ"B<؟CO?nM>A3#.#/ <' |x^3oJx7aBx_PqeDP<5RfEe6R"4M#.)ʵm IZV@hX6#MR VLb#er$O#/\P(cda#!+DI1ct!E #)l5Dbjij#/34E0m;d*@B̨0Ѓ#.#/`:wt#c0"a# P5gCW\*>\|>ӗg#.>QUwJ e\i,(fc>G(B`3eMeK(A:Hu1ƃC5xRbH-*1 յ:̇S)EffBF@LG$iAi\p3cBS;c 3)OcZjk ("kff#)m#.#.@}`w>]?/($;7H3㊾'q#/6=tD^qPzig;AgDvH#o[t \J-A#.4.|o<\!59v4E&#/އ'|Y*;C 'Ri֠a)(a_Gh˹;u3Dbஔ߱쉦#/Ϝ;8-58;Ffnӄ%OTd{x̧?sZ4@q;hDdS M^滸8OsJt7;Q kҼ#.v1Z-΃oKܵ:!/˖w߹ 1)a^ RrhG ËFD$}$R@;f#)fKt03['uLR=Ҋzm ':X]f#/rA(P. 2kn><;0bJv&|ЅaY~Β\[2ΌJ_~n eSLr1=IX(wTu1𢢲T^&wMHFQdTOX;w՜vր`jn<]/qs%뗸}00cFIIتBM`N<NtNfp9HunJC%¼j혶pwl)8g4acEar#CI/4Gth7k8'Z3-tyM#.wƒpw#G/{I<$WryqӋhuz& sg>bP@ [[ς'Y" uF>B$]CDB۰tr{rXպaK.  79zkJ[i 嶄ɔvX^Mb xlhDD"#)#)gc hѓiUsfvaap#/,M 7#)А8pGd @0{l{YZ$;>3C 6NӳGC֘oI'|҆\"zA֟>}ŅޖwDSl䤐JLr\pCävMd~8[lU K/c<.%tS\;z;aQ󜤖.5o`#/$#)tR៌!pSZyvv ۽E5݂I4m92#.F5 OW+#4b-K6 Mv]VU`):l֓=ijLl;8[,DB桰Vp8݃X1ʸOP%݃RzI P{B՚z=bv6e*N.E[cXEfa##.$_Q[0^Oqyh^2j SY48i=%dZV|q?gNB:ZQJ0IIcC8N#/p@H=WiV0v{<=zS:d`VR$e;1F@,'ʷ`zxPIĝ'n Q,K|`i9N6CsmÛD6ʼnMЋ 礸hkWۉÎC)*2AЁi#.0S_2f w3 ,0J67hf  #.3΄q%+vpY0\y(aHd&Dm03V0x5P#.44U1iN(boMh56ǥ4@>fimƨڵЏ@Ei>**38z37W:mcgT2_Zbu#/F;eC !Ȭ0)(E\d7~vFp5c-.RSHaa,^Tb4܄2a0llY2|Ъ;4T(Ic#.p cP)Kύ&R#/8H#"WʠF ˍ=Hx0 dCʄv=HW Mlh$0j)ĈU9Fc&]ucWc;̕ζ֣ŴHJ8ir(#.Xb3% ef=dfW+ q,F#x9|͡82,u5:ě77LMXjBYw-֮g^`*uvftV'TaH# Nia#)j#.A1ę#f#.0RFT.&%:5q%٭!2T1@+\ФIR7vmo#.)6RCc;#/ #)ȴ8%S)TTT* ic#/6Qeyh܈F .JCi50um#.7I -9 hrH4v3k?90q9:a؆@f,y#.Qp&3A.7f]Hqt2JQK#F65 aBhmFLD#.$匢nҫ28t"'GF[ եiGʪ@̂ el˛L!XE)iU߼\ R[Zr7EUA0Y#/ m~aR'~"S#12󹇀/X{q?A'z*5;k.b1ݟȠEUTd$=ޢ%}Ɓ9?kekeӜfq3 @6ޠA"pm!7'! qnqa7[x ~Bv|b"[o cFUoq+F*."5A[;^3I{؞D4pRB k2MT?9q$~jny_2xS?zd#/e'i2Q eB N@#)>)ϳ-J~{,9ԘT٤h(!BL*0(C-,0DIRbLQJSIYJE1PRRQJhiRH2URLLH#Mzi69k/7j2pжсX35ulr˱Qx9'gEԏĘu'-4حR~M|x< B-`?z}M։c/8+Q |ĈҔ %w k#/L#VL֝!b4c#.Ę٤#/&"#'U)py7.5"#pY1#.sˣE`L啜FQіr#fq,bnde 0lY.x#.#AU>8.B}=׾WM#.OncXK_d0h'e{RcH1B$&FE`EwqkNʲqa &XCm N( ѷLPf 48;jb.V@{zeԍCh7D٢bv:D 3)IQ4;&ScuRk$IUS";C ')A}|͜#:c<=oZKV}T;nL$O9w4!回/ܾ(=09pO~U6Y7bӅWPsV+G@#`Y)8^mQJ-ռ1?/]t5*vˌ>pӘ1tGyob=/POZ8>駆3>7%tlzT\0\b+0 gjÇ-D_|v}P~ [/bH4<,=#.ʛ}w浞~{3z)HI ^o*oUbX5{. c\J#/wdCO}Xo#C?9n;(Q00c04= (Ȋ o?H/mRF_C/6&\#)|N)^5( ">1l#)E(cD$+LG$`E#.B<ŎI!h%UO=.+[gL.U]B7AT&X6ZsQn ؼ``\[kU*Ҧ\)T,qQÏ'NW-41! 6 N2 "DlSKJhaR$EF9ȸd\rz6^tٖBB܊4BBiAG>(įHn40Hgf]@g^pAf!!RĹZqӡDnD>NHFa#)]X:e*uEaǞML{#.)\z=72'[2ecK@:6#)cMB2!=]v`뇶"aic&TP 3iCR#);9stBHaeb|ErEbӱe;.Q0J$32kLAz#.ilӔ͔C6 ݄X܏MנA[٘gD؊6@%j%+xV(rUTF5MnH?_<cלt!2u"e1V^钺6)g(XW#.FNk\L`j"=枮uV*6aSKxQtInCE?b1 &iӘSˉjM`Wˉx鰲+f@!ҙ8F,;,YB8Mt'plr6:!4,T73&9kgȗkYfhP:( :@Glէ<醶m.#T OôXIK+qr-?$ Cf#gM6vb)(B#)S-(0tf$tC)xyA^g.PQ#.4,VO3\:1 \Zg;0SC3&3TQUBIp 伱j%͔\u;0e"il3dP5~>Fo<4#)L&N|f,EC9j2>Fdѭkh+," ٬Abwj>yn%[ޔ5"0{OCITbh"l\D!N~Kf5šވsEbv-Z 9h,Ȱ|('F02bB0"JMNK߁ÛX^Y7CfG4}@DSX:l0\_Ȧt`,H}0j̚Ԗ"$6qMܹ}#.%А$9.poJG+b’#.qV=J1XoJ0_bN&l}iF"PyhEAFH"PԚlA^-µ&m#.(.9u =+Ԏ ! Зsn%Ha1731bETcQd/U!2#.)^R]ZOCb*Hlik3 Là%ڌBhC4uԉ##.9uTUSSx`0G1 Mc'fIRЍv$f錼lRSgcǂ9gc :*i64:)A" 1|}ovH1o_ Z4Wtw{T#$芦@+JkuP}yk_LĹ_LmtE1rJo)glRl#.inx&S4R=mL3m[CfY?#XAʡ$_N'ٚ͆4% '1g:\?W; ]Jc@,TiZѥaݐ=#.(,h柹+1T-ZʄZa5_nK!^Uq,0}a;]l3fcI =/@ЫÇy woIvߋ<}RB B9>p`P9GhĖ8(1B d}p)&cF,–E%R!n bhb)545.1F!!K(G#)J d: ,c"#)`a6>#.hK(4]mʨ+6#.ˉw78R$a#n;eɃ631wij"W8,Tp RKs1U!ey΅N.~I8L`0]Bx:FBuhs)Dl{i*ic8xyg8tN'=SBd~x\"HHmLhT% c5 hٵ#_unI\gM6Sk-\.2Yfҗrֹk2HaM@#)al6 d`1#.Axrf;`fAA0l﯏}/&i}#.pYtHcrm ?1(qbwAMX΢(4W!߈-- xJhKwήxC.[I6`RS,7XqtN&6\7ΛREYnɹd~3xz0U@#)G\pAlj ;LƥF7ef CRUIP%!OĥAgPl{DDǹkԖz<@Hk(&#)?#/i=^urӳ&*k֧3X b{HP qTRzC;0 u0BN8Hr j#/}^zzLLBxzxl= 8V)R\auP֐@fR=1hw7ע,L!)}q.#ѷ#)ۺj}d=h"Chk?L(5?fd{A>:<b'hl$@X4uBBF$V5Ȋ#/T;\U!wRF]kmie1(jX#.@<ѓhڊdcs]ILbSc!ƒ@f'"Gz9s$@!L9m w!2 f GYZEeOyA#.$J&DRjfBzbƓm4_^y@T 9~GnCF t!#)cTx aț5k6*HHZ ,P!/jC^" ye?ɵ\Ŷ-F\z+7ٍHC( #x^#)6wŶfH9 Iɧ} #/у> [ bF0AĝMϸBrd\zӌX|8h0q(}f8d/1LNILXRM\.MU*Ѳ5Ŝp 미E7U:C#.1RG׃8ᬼ$l -['ocB՛B>/HEÃ\m/5K#/37,>Hf-  7r`{G+#/jdM5%ƬdڣY;[-^&ŠVOޠn8b pd14FghJ(hTR&lY9]}.3߅U9o[lQ~|H߀@#/:Pɪ=2Wn`G#.*!L`4CGgPFFk=#/"< #)ܵƑ2Q9CE,*:NXn@tT/HMHGxIs#@Ĺ3cAZMc1#)|#.rԐ#/(( +So5Dѥ5;#.&։2Js3 M:hqfeWs*7s)`!uf#.=uzyݗ4RX!$Y\s d9ʐεm!C{>^:F껆< =|O8c :µ'B"Snòvv89h ;XGDZ-ŸJ38qPU]zqf$-U#(4~%',L'bI~0m/ܱǢF+ e\^GܙtwKДqF/SJ L݇R;N_<#.C ߷Xx=;z(?c"X0f\k#.p#)JG@^'"%2PpM<.#.Ey:B)clWr<ձ/$a#X&w{:|ncWlꪄ2z?2P?}f 1~rT#$ y,mr4⏯=6Ǟ%‘(v!o#)=Yѥ$ImLEx7Cc s֭;diEtjwlFo 3 9%.wCB#.N6k!!׆OxQO3d! wd͇.A6#.P;p-!#.VX7!J!x8+ZaH%m7Jw#O$i$#.f=mI |Zzpcm̒v3$V:5^@ W?/onG?~oǯ/'/OeWu0NGt?y㻦L$e}7#)tN=;3#/ّnߕר7/kLfv̧#)c_5<< M*,ɀH xL7Aƒ@?Úp_G]熸+LpgR#)L*5lkzY(lgbt1"wpZeX h=0&5I7j=:2t#E/5zaG7'?՗fG݆YD.^x1k##pWی!Qf]d݀8Ϙ\LGKן{RW_=h'b:vv4Q0Qd_iwpYQFɵӯ.ci0z}4ߥd5Lcu|m5O;OVʘg]ƈf~W!z֭5[3^N#.*cAy9Hsb*QHYX .0]qdc"d:,ڋC"moGӇ;Vӣ9,)$=ܼm^ZoUx&Q!@Z#.!ۚNembCsa&H..UAN61GTxJ |*s#/Aowpm#z(|'A8Tlsmov&j B6 dJ?C"ϧo5kݛqEcx[rs%,I"eJ%S8 j5pC9v8N`Ib-bY㗄hTKY!k0"B7GBYțJU3D!{`&VW7-Y;)UEz"_`aH#/) +#BZh91AY&SY{4@$#)#%E(a\>w#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%GtC-T#)}w'mfݺ{tybZطvǵ:wo,˾ݳݞ╩:$[۵ =#)EoSt#)6Y7}뺣=O$7}|:nͷ0;.iՀ#%#%;#%l#%@OAC ٗ0ܬ 65MSAs;h#%kم+h%`#%DwkYI(#%=`$Ppr oqo[7N]sJl8ZO >ibvy;n^޽W{|iz>w{#.ov#%Uz׭kZsvt{be=7nID$`#%#%H*iBAJ[˨;&5*>>k.ƏO EֽusC徰v#)t w"q;zrǦtS}qŽx;/8{9]imm˫w{ZmkW9W+A=W^衶>[Sʾ9vkIUݏf$yݮHsO{/'ܶZgK{=#%y}Ju(#%#=-jέCNg'wE;׏{)׻w{39#%#%#.7*_yvlv{#)#kw:$}Fݺ!}ožo%VXvճJޗ24dd3sN6o:ϸ|v[ݗu}uצݬ[V#.6Э>ݜevh7L&.yw.wbM]crm{Óbǎսwu3m׮V: 1:T#%Сs.o^thƗl^e h>Sڶ #%k>o8B]{{oi9wsyݹ#.wUssvgjUIsjDSm{if.gpsw|x>}w'E)^2[gNhn^TݾXּswwkxzD#%#%&b2 L&F)OT4y@ z=OPJh &d"4M McD1#%#%#%#%#%$"DѐSaFL%GSQ#)\ܨFwnIkϞyyݰniU"ŕu G#)FqeBRE-L`Ule-KK(,_WxC1<N+9)+Y%v ;A;`5Gh a}Iڞ',G4ZGg{i( X#)4]ƍ̔[$$X#.w `Z#%UjO0ݤSJ" %%4ѯ {,Q˕jp)5L%QF,h444d{l 71Vn-TR;\&2NBIf)%",,BZ5jłEy84z`qY4@_좙NzX*8#) qN-?$Ybњ8hiVR|os_ˌdzcGmħWrtdI[£mCXu@B#)P賝51eET *#.8@XFDLhp<@1&lצiuL%4;b}غ֌MH#)vZCf8o[ٮ-.+Z7FX,S@DbDcAc :Y]v1ѣ4Uqis XcX1\t+)qM F5sIX_*ŃF(W{uL_UE,Ds_>umtr9e)")X)%0yߓ{yєcY6|^kcvV0ny&o,5AhFx#%Ʀ*`pր6?uCJ "1Ҷdʁµm4sܼ3ªoH)`yA5~{^?vBI$sBIhJ4B#)!d ~Q vME`T kΠ0:w´y"=:Di󥦢Zҷ?6h|,-U#)kAE:ǎ-?^:q,>jOO,ח7y6//DQKq Q:@#.<8\6RUBU@H$Rk9}zk[pTU!uP._{=}vm~Jsw3U ~ fϋn<1@nIŶ]8eiX5T,@|1SK\ 3c [agIO|ٸhlR}I0М.%V'.*f~GA_iX,8{`rd뢑6.*EYRp)h}Snpq G¨2y$A).Ivt/ae7vcϬo㣟!# K0N2&5'/f-K͍׺#S8t2I2-)p"ѭcOYy٩2!eǘ\w*9.8 x \AM*NyzyYֶ0 TTeS-JAmpyO ;9Btz#)Ssch嶇,9XıM-'MwQy5K*ߋ'u]*!k߆=V)"g_1WHr"UcRgCTn#jI)Hv|;cꪨrc XfJL3: ny,H#(ɏ>0U'==_#ȏ2FUl;[KTY f\^A齀qfkk84,g7v#;%W.7-JvN&zTjsxv ֬tJ{U0WكҎdXLؕUWE`JG!9:j^ jD[3SZ-T|D~oi/KJxhnueZQp_~uDvLl7J5P;S"VC7]%1ULIKP8<&ԟkp!;n)t.{>h2nMu!g9RLH)]k[Ub>>\72߄F0/#.X qu@>Xמ9|Uw#]/q.!Uk11NƧyyw* Y\* "^3ʝySTq(njUqP3s:}Y 4gIzV#v٭ 8r]w3H,Dgyd/\.`=+x[Z$c& ҹ#)CdWZw324soیT> #)mnZ]dw+(Ai۽)Xդ4Sqe;a3d#.V &!:%F}Xiix)˺!65nD8M@\ԓvઌ>Y]YݯsqPYgżԆCYpNJ>glTMRAKM( X1%d>#):._/qi;#.TSg#)G۳#.i=#)]/ivج.l⼎Xi.bDݐ9:Ft]ٚn,JNy` ihf uq߭96`{hRPD@]:ӌhq#.$vmVe~R)sa:9ؘQBBRX#)@K$RF/:#)^}s#%'{GCz-wÎN p<(d1wQѮ(k|3iU|Hm3߯4@ ֗#H^4$ڧ4`T:$9k,"SIK{9qt"<à#)2r#)W4Nݙ>r5 @}{>S#q}&ʢF#.uv?^G ʳP +d>}KiouC;+$5#)n8m!#%#)e#%7pFUQZyh& -MzPjUUBG;[uF<́=˱D9NLߍ]_7I#%t~VfET(uiCzIA`akڛ;V&g*zesֽoH1˰Mdܭ8[#t?mio%:TjzbՔ\'w1{eR0,zXـ3~y(gjռ}Ϣ^g59<KU#%37*4-KcN(68Vn-w.9B)LYQ~npy!BIL,#.Ee0Y0C՞8tBR R(;*V- 7>発lthl2:Ao#)J=%~;ڪ(7*i١A?Pla d1Wu*8P)" V&BVcx44#)ވ{m㘡kTó:g\jd|:4&o;N#.Yvg ܕ眍[W;Mdy-Yy^>go`;~"8oS'LT12s4!sucܣ,fj^FS`b7&f (T*T8^c#. 04VRHLB6 e  sG1pE#)JV,IjWܯ>zې2(J 愖4#)d@% "^H%U\VwYt>fw #Ƿ_`+dl0DNYT#[c(RAZȌM$-DQh1AHL]ї?I>׮4B>kzc\n9*eWS|]yeݡ?[[1N&v>w{Șp\pZKn2TRZ#)%Ƶ_Fᵓn%.TR0гU2pD>3?*ر͟1[HG`$iWcf(EE^{SNy'f}c Rxhd#.%L2ϴ^޺\~ ?}Sn*iYxXYčCbt1d0gYơ=#)ٰnPK_9a$aTe!:)u(WԌvRocmӑ'LiceJHZ1/GԻˀ?).,F043.rʴ66R#!U\ÈC#)N'=1tᓱ*x0r'~Sa0mpc{9a#@uV1?I%KViް qMZ@U:ɬ 7D]iyS&H X*%VlkriF І!d%b#)$J,٩:.w#.#)5anzk4]]#P2C)=g#%'؀#% Ay n7Ѽ!|89a.^3 5)l35qPh4#.u~w(3P+(?E"CA;6%䆿ݏɰg>HdObb`Mw;#.bdfʴK^j[\e*Wf)YU+CT(RwB'|>xV԰)X{~rt6 ".jt;f_W7%*e<,l<~W^Őka1fA{D8 \I#xV-.yX~D}fK.}nRW_W0[c?WĀAdîo2hJ5r,'-=#.9#bXg]v7;cmTNs:U*ɇm샖^'T oΩ!h#.Ƙ& _ϑFoZRJi6#%פY5GM!v#.ߝ'gs;M jas]\N2]nGu낐WH.DK#.|U{paۆo(rF;&3"RG6D9O_ZyF"57`am;sZ(@ciZzt1<둣8nܠyh"qRQaؠ>G0,[rVYhTП̣5~#.b0!0! k\ P=F!2?OaaԘ1XLF PU#).~tWYНNt{_>[l~#.%zlb,H#)E3z?ojJ#%AJ@7AHK`DQT}`?X6v?z&: He\p%(dr G 2:t_L>̺o'BC%,\45D 'HO՘|+ǧW}p/z?o|NŇUԜGa3@_׮a*ᆲ~-VݙSuWVAד ײ]8#\l8d+2@)w'`jL~'z(5U=aEE"'6[o?~9b=WaO'g#):0?+6%lް6W1!aZs!p,/5/krkgv;Z2r_g|WɯN@W_ngJY#.;وMt9xap}/7~]Ww,#%8Q|}ߐ!_[ywT~rm6 oEqGb%<8#.sOQiG $#.+1K6.m G'7ӳ_\.~o/0~ށn)_irj!tfԽh:07r޿D?~@n([m?@<4j@~ݏzIc{?j_>Ǎ3|%{a[l1LeJCG·WyVg>/Vt!A^> Zto`YGKSɠB3z 4(4qxkp_' x_܎|W.W~d}vS4QwPvL)\21u.nD4IJ=9cad#%Br5ITמ\F"3J q6`Q5..Xd'#fc].FF͛=|վ GZ"#kR:7K+cŽ5m]D3$up`3|_ۻ-~9k_.#%:IrSWQCS)('9L9#.{>n ;)ms8$|(Z*c)#. oZXU]WC9LH$ʇ#.DV>M&AJ"B(Ҋ02묔c'PΏ]؜aiM,v藽CZ/\XB/THa/|V?c-&1.#ŀujO|uBʾl=i#)~lb S~_O8yp1 @tEqqr/1IFg)Avs~}\fKPsޚPg__as.uTK2YԣGX%iG#)!=yx HB%#|'#)$[ɸspDG%Hh^d&%gtuӰɝw7c;jHu0UMb.U@sio^wV,q&EJ#qnp\6Aiх1`d"R#L1΄x 0d`II{vGU(٤q6 1E#Pmlpr4R4uBqfwd1eLݨ L9RAQfD֘o+#%hfڢFRPC!YJ(KLVVDu*hwȃqƷ&9$8`f#%p.3m>vh.AH/VCN5XreɚJS1AjiB- `Tydh Dc^}m"Ii1N"sUX~8g@ SҦ6;U16C,-c"NM$$1۾,|3y ГZ#)Ki^>Qc+U]ʨ;Dk"w]rr~Kl@A͠#eFҔ[žqlֺW*#kq#.##.:27#).wqFQu<EdbY+z}6 9wMWKUbCL8fVRYOc5uF:.c#^ liZ\n,X-9yȨÄf9&D!.15]µ `˜l`y&e6^f/r}1Y6#l.8Xv Ix|bhL?;cݑVv^x×8Lh4J"NeΉ"2~3/rWm$3wCrDZ"7VsPZ`.#)C*/ȑv|h])\@ġe󇜟-KEp:^ٙ&x9SK#.Qߛ?͜W|M2a2dx%2uFDwpGJ:h'z/Uriu/疚Ko#.*i [3#%ٔi0QnzAڐ7"p#) XZ8xR< "#\9_#)ZjBtk'^9DK#%G#7{_ {nŸ; k8M^ɀ;}.Hus]9 Aۢ&ٺx`3OdR,#/r iU1K L*k%ǻ'Ϯ9&"_'6՜g}'%3P}&I#.Jzy6Q=ΛװAAOA,7tuQ3ڋE%w*=n[^OOBzN9>GHqt>#K>BQ72I8xLjo<3Z˲(q=y5LU͊;6膇pt$60dǧ5rOKǡf=-e "M<3CT8lUOOLttANiG׊V<(ߍ==#.e[UA\G_7ݒe܆;#ADi@'.s>2d=XnY5L!vͨ)JkC9%߂iy}XZaփq~[ݷ^:+Њ!m޹#)aM/,FevG u_!S99~ùv#.utw?16|f+M=uK`0ՕDT}Ƈ, pginkN{šM/GyT:zu@fK۬9;$`Ek#M~sF| qeu`U(+Q#׻05lS A*/p|6=}8h'JxxZ$a#.%Zv{W>yΜ:sɚ F͕4}*uV68շ?5;GŎ0+J9}ʂT͘6FmG޶s&J/OX{Qc'ONK:"Էӥ#)E;v#!x]^vg t :cYǥZNwϒC^!uqŗ.HmV3/8юazb4o}MT:s8P,4#T8#)m}^\n{wϷ;5c,LcW.gV#XrsŋT0Ԑ0G^"YzylWx~褅4mo-^yRʊ+NtY% Ć3#)\dd34*t msĸaKF1}nN9a*Y,f<wpڪ,5*&UF϶!ԊUe",ˠD>JTx*bK5kFmDM`Cf|%hx`}7NNoEO#QG ;Nk6ꔽ̨]&+{ǻ5%_qw߄})8(8;f@ Et@E] 7G|VO5)uzmwaWU>oK{ȖkJ?6gsOZeyWR|o9?us9pL9+'=:DEsޘ< PVlRPxi.6.SqCsޖ8ja &\bm03n]| <}F'W,rݫgm]s_ \'PRv0O|]>+e^G<.okXDq"Qzpj0D꺹Q6T~[ͽODnl9:<>ۂkۏ+paJJNҫZL .S1$B1Gɽ:ZLrX׋M`DJUo벋R.~vgy4Te/ʖ <:ԏ-ҫb88X8]IgN+/w,]fn1BB&W8hMJ4ŰGEG锠} P7#.o٪LiKQmդrfG,&d YsI-mUk 47rmcEIG%W0DD1W{ΓqzR ;XǣIOy #.]1D_./_#.@AR,R*k #.E;J\xW+ 8@ @N?_VI7FZy9sV#';[n6"sW/$f`<T6emJ;I+]H^agc"%Pʲ.{FS(fb7|$re5H]| u?6Nm6TO-4Qnnk`!yU [﹀pqнb)[ToaX=yk#.i#3l2qtiBqQ)̱4~KuVuQ3U#.xh7EU%͐~=PABдYdg16q*TsEs^I^Q k+NL;pBbT`w^4/Svz}+1"mJf7²hB#.skt%-.u2ɍqdd|#cf#)m9FӜ|#.+IUdeD=/e_"}n.{.}1M\93Wwʾ<>&5{EMy>^p:.QwzeMӔxqѶ/iEty/i֛ן)'LȘpw;]`LPq~;$oZ ufP"Pt0R0.`,]a{{-6uhH+v?D#%yNNh^[b4gOpl]A p—.B#.N}>/JZ+UK`؋cζAJ]ҝXvu[k_#) )}l|ʎZP5'rGTi33~~|DފjHQ8:ϸ\زVVQ%={i0B͹qJiQ$ӣ_D!mX`Qf2s!e7*FLnW/lx]WNW|%,@>RGO7B3P픡l,ff鸓,(q̰|el./; rP$oZW訔Rl," Eg0`p1"Z@ OFRp˅̹i!}Ӝd$P!76u(n}yإLk*vգ2?0ٰ}VU *:ndF>p>#)!`Q1b6s C#:lZKԌCBIQ\r=J(x9/=tJh(oSIo#%i?'X \B¢ں6-j%]6T>#%۹k? >#'SZuL3=#%5$9\88#.0M{Y0Ul(;WhX2`q$OhuD1AMzoCG wD*}z<.Zk#.̷"hvߝ~>s<7MiYeS#69P.#.\4'pGhNU 뙘EeW`E@^i@|lÖ7%<CmAgE\k~>4;nhA睡#%;[^XjN7ޮ{X})# S8[e ma@;UROQR#.؊njfQF<ڦ9[:U0.;xۢğ8GU'3db^)@kZ!e@;T[R`msG%56Pp#cXPgw#)!ƙ "DmSpygFal.&访XlCǢIis-qߦ J)龗Ѹon7($rϏlCˤW_~uܣUARw*5_Be{A-0{Ong}ۮ33 #%|~ #.o~2) T1rk[aሊ\UO0( 2Fj\[[,~5Zfr (DK-g((1<6bXePqWxxrQ{wV}+m+P8yxr(̸FmU-uX^qZF/Z|Ybn))D #.|2#. om54n#)c2ג캜Ȩvb;!/=t_}v!F} xL7ƼpT8zה'Tx4m#[OtK 7;તj62*k3YO55z&D|W!^Bj7e&i /7%oPq&@b[0!gNT)IQ%2#.jv<&y%EJ#)fGJ<#Cv-T0<]T{r? Ʒ2;5#%ހc-0(l^żׁD0apIfsIA>eX8f#)NaJ-$ZlaM>~=9L5[7=6gg_Ijcw;#)3#NmY֬@#.^gX=O$Υ* )gw'DMP0s<1sZ: қ]/b5*݅(J/S;jgyaUúGH/~${tzPOO^DX v!if-&{z߰gl[S=ᙀ=|V.8yzup(MX/#.[kR fU$@r#.x/xU õÔl}Lt;r6'¼ȉz%UP{<1u0p`쒧yFTÏor#):jgf߲/ߙoa!Ń_ 軘䇔m|xG-gCN#)%`UwDc%@(!!ݹ"k(9Y((J#)%!#)20Д{ȳ_|0{/Fr>Q}C3Ԭ;]-00;;}/nt.C( 1pEJ$ abc:"86(qȲ"ZSLlpn}#%\ 0[)`?\sp4KRE:.R:nPY#LU \)@@Qv !\pH*a`ZnAPC8m?;;?T{Ϗ0z!wHJb by͗:k6?#%,>+0sɇ:]!^Dƿy41O=<_lYi\g m҃^'$]">$0e]Ibn%y6.yMR#.ImhSɯqi-N0%%ZjP^5ȑ}+n_T>dtH4x$ Ú\!w)! >;:$,Z}ɹ>QҾwC޴tĵ=73N=dTEAs j[;j2lx7O#ӰBT]M2!)e&I$eT’¡IscJg}N\;PDPK+a05'#%cTj ED!E wȱh-_2Fvvd?.4N=u@#.QZŅj*2,a7\3*gczt۾ג1~SKZ=Y$a8G?64&Ȭ}Sa]{-WKv^9=̧T[7'O6#%D&HLʓUN}ߨz>=G}zH|;Uf嬇y٘>NFɆ<:3]=.wCA"HFMpnF*#)İ`] 4U^.vlcM-U#.zlQM4Br>vbX|#.!z{qNYU )HɽYWT#){g7ۚ@U%U+*} H),p@iAFL`iKM:~##)%c Տ":܏o^FT4+E'0/fpZ P)PGY0M2 شfzөf粻#.=_'Uv;=/ !k٨{>o}ōvJ.=;V%| cΌ DT_I#%Lq#%MoME.;|ٞ!}5`~Һy9 z!V@U7?/BNUIbZ**wIAZ R¤=gXQ ٗY|9"@tf:2deE^^@_pJ%\BH?wfDJ$*Jڒ{AτvcpR̆Bf}Q* ?Ó#.BOJHi/lF IKgk8ڨ?_+ o_kx #ޠb$XF]mw.uBsC_¸(!!d$mű=tGU)n1IOLsJY0!#)(rvl_ W`X[wx;!i"GaqׯO'Ya4I "$XrXxҪWbI8bq3#.98Y6oݯ{\;~ҠdDÙ9y2ty:zv(z,DlT#)c0e][]j޷ۧf/@`sBMFNƨkF82+$r`ݾJ#Ҹ>)+O[TQ7uwLhc:z`ztr:#0bH'0;#)>4 y:4yEQ<$Cdҡ#%pX8DE6j2#9ViT>E^ַEO6d#)!+gd+kZL'﹄nj21/F (UP"dQ{U*Ú8 ֞2%^oyʎҮhה\RN=ʆB" ~>8[w>z_ Z3V"rD UdչX ')I3,"cIءm`l]]KbY'ܹp\i mPW*"-RhzEޞOIcx܁C2? q$MlB}-;U(<<6JVC("*ܞu >3 U_~ b׬"R?3Jﶲz_#.uNT:Ew֡w#ε󘔢ʻ]~R15̴a1t8=iǒHzt[DUSWwGENnJ G[mkڞgDr`QDcgu1Y3:ȺbZ^NmIg;q4}eP{<|oD{6xW],,@eޫXbbGj{~|#.+QCޤfzGh)p+@)E"3%kMO韒`>ǝr>uQPҴg25sC.˹C[pLKN(1$:]@No*#WJġ+AFEP'#9lS>>ݨM|hٿ>86wQ3(w^k?LuY1bmi\omvt\Ep'Pe) ɋúwKXͻr|?g+"1aVzkɛ{ߜzm2V[X³"~?cȠ9QGcRG-4A%z#.3:#%#%ugCL+h^@i8QpVQIu5j4AM Ae'쏺j_Ň6@OHmvZC*H2_Pa2R.ȩ QJpY(Mgop}ɘڎhΡ<Ǚ2F>;x"-?[# _<44YrPFQBrU A%϶_߶+✬qV!^AR/W\Qiw)fGJy$[yS1%s [#)1P][fEV??7F4gV,o!ޣ2yY!ikoq.g>u2#.ԱY_XSɗ}jI}Y. M2&?e. dҶ #.H6Դ#e^ԗ,mCdGۺ3lO:υ%%06r|9M{u(|x!3xE(O"|#N!6 uI\:ð#.v7U2#.{TXzTvC,f>?Gp2ϳ('O(*gAvwt{:a0POn-mS W5aJ1p=m; ڜbKF4);8LBzJ^燾߇&SGWm zc!\ ,8{'D_⯋xJbqUʐUl9"jgUWvLe\{=RpOV^B,* r:2"zRk[zPH5B#%ZH/j#.IE|eմz($$%|(#%/%*I+@#.a׼c%QaKF\갊}2#%Ԉf{=RY:F̊g(^k_\*,*EV+W#*OgS[<_ ̪fL#.SqQCF{PA#%XJB]a `=,- B#%oPt#%a^05}BLM^;׵h #+znȲ,7tK@Ra린ꪴb~#)n7Kޭø:.A$4po|q[(4(I#%cZaL•|o򪮟ZXHzIޙEro-s];aEßV,5@2WA"h$avGm~m^ís$~s}g>n\㤤Ø`eE:*t#.fJ~}r.=!>؄MtZeH@jTIبc !|R᫻A@fװ@AGf\ Hb/d9ˉaBH.c՝/P>Cv,A"O!5,HznSwIN&W8Bm. ,>t޼1,s,Iu#%}8Vzq"=a?_ۮqvYqZw/ r.࡜g%s3mʄ"BAUVc4|5e[QH G0#%-PP)sNl;8XǎD/miUD5yhٳ=ⴜL:5HfE :8`x* A؂-w?]HrVFBJa8=@6ǥִ;?lV]%Ζv8x <#F68\jRMem7ιGUf+U*3THٵNqlJt?Yr6=}0R[8oy0, fG!ts86fp 0ĈD<≙>?eDzdf5E[;C-,ue&Db4yQ贷K9Wc#)#) M'\ך3iʁtF_yiG\mpy$u z3FusO7d#.҄gU'7%Az]Sqɹ$̓fzc7<8|߶u/1euU !Xh -(3cpr.Z#)>(!/6bN#)]g!'9L%)*]nt H~bh~:!#)|< ``bA==/d wPY7J  5L澐rq,da>_E%z2!}\y *(!9Tu#.ζ֝ItYamqt{'>dv<'!Շzvmݜa$|S|tFr#.t6/C0|4\cRŰ\&ҵOp /A-2Y.XyR$#ps]K`"^EO>X.eigt`jU#.َQMO\#.#)JUwĦ&X]3jh$>A3GL)0 FEڞc5UT.%#%(8N5qG֠3^ފRrJjQ-]pA'kxc"?`刯ekw:]M#)~+Ȗ/1ŶAB̨7A0z`5{UX(\ 9M͸CπCf#%b&3#.#.nxƳќj!Uzh@.vc GiXnu,d8V{#W4uȆk} :A=# jN,P20g x/u8 +?]$N+tdBEZ7#rՠ|h)x{L\L\2|y6zѶ*$ǯ l#)iM/ z r.s0yًXmz#%zuѵ]"TQO.#fj9,#)X=e\{^^EIvh5fuŴ^[zq!7#L⸢H'_4d<7j!`򴩼X!]9T')@8\pEp^n5ϓ0I6k.v rbv~8cm{i_[Bd#%#%-{NF@"Q qhSjtmׇʺG\2b5, r+űdC6҉+JXMYV&fuNQ4.צt)D3@(IZdd(+}!hW5,#)Ƌѿ,N!#.Ml\q`!r I#)Ji<ڥX@ud`z+BH(#)ǓEО#),5hGީ#.nSǧԻk*Hot5߯|ֺz)t ݣW>/8d[rAhΠ$OYg}]\‰UjFXt;D6ƙфNvclG?G}>~.YPxsF#%>Or`gv >iNU%x-+,8݂,/bak=*Dd?uL#. Oa>o#)oeT*p)~zH?~ϸ?_MD#.ȁ` #%| 9QTpB:+:E#)EfH #%?AVls?~/_UnuXmٶɡl~`8<:6#.$5-;O8^fo6H%#.|=P: ŋHgcc#%/)ruH06}ao_s4C.Q_@Rq:,l/r|I#)!c>x(Rd'3'8 T G_f#.mLO9P+7jrH@} f6(O <3rL$o4UK]'`"9p#%RpD##Z?_;eŶlZG˟n[*=\Mݡ LR`TwܲDORRO2_\s= L Ӽ |_nTݩFib#).37U#}WXT{N"D8lM9(b0ĨeH~=GbK񦫅@.I@OBt@ܻ=-5-IөToð{OD԰ PPpר.pҔ`!d`E9+xr$sV5GQlCDj#ahp$OW#)TB'޲G̨KȨ`Rnx]BQ@Ac0c_/}?#%#.s#b9/]_eFHeZr,3X`w%6Q"A;ia[@RHpi2tvݣr+ !) 4^*r#%$#."J>^WxR}tU|mšåRpR,E&Vh*@0tMA8x]6AsS};gߤ22_@F4ͣy0)bjo%'i=.?Cp~)L0iPIT%@K [{NJ"hGlmK'G1cZ]S09i5H1vI,XtI!b]_ۿ,a>;b:}Q^a]n.2#.tzPura(ne-Me^cIJ/#%sx?zvW#DK^ޒJM}턣-Z`dsԬ^Iq;YGe#%>mk~@(:-,XC{2$N"ئBˑKdS=V3v Bio#)jE"F$.rwH#%],"@!#.L"!e_O(jD"U$%2+ǡMfTۓnqVJ "O^4h*Zϵ,#)K!nV)')S[U^2[%܍YHSM&ư$ Mʔk!"L#%Fu½!0MD)?5.`c2$Fo!b2y]L2$#"[=߫voGڅ>YAkZS?>k~ǜkoƺ{Y7LF2((]uUtfq̪5 AztBM4UUЇeCD.d妐N$L#)LTk.d`RȅwUoDP4$VMJQ8oue5i3nF?-eoʂH! #%} @&8Pi0ڏNQ,çÝDO>^wȑ"JV#..M"nʸ"{C)KBEgw>}jݸ6%Z7>˘&$"B_>Zy{\O<еZFk"Uޮ`$AM&I6kɡd.I$bI:Jk;tL̼BHi:v6U7);|ObpyE$S_BϦ\ <^Dԇd66#%r &tέiI"0ӡR(4™EeQ!^۳܁S_txB|^ѲT7h#%c**Or ?[T\bD#-MO@-P^*ՉLٰ#)7V*ٻR(8P=gE&'sл4/xbo1p="BQCF{dB vCzI $wwX2#%=,6#%恛Gɂ>rgv#.zLHA#%'~,~z[nׂ@B#.U#)B{kIx5%H#.YQ}zqfHE` +Sl>=acq_>A#)UNQu1ڟqCpcةEJHl{a2Z5w><{lx"XVY#%1u?$ø#.#.B)bA59KuaتM].qC8=nkcR21 :(rxC^OkUP9~eGmc'Bt*XP ~#y.=JdYHz0I=O1#)BXDsl#)#%Y"')'t1h~0:z~wA=Tϟj-[[jx2C؆73^u!rv'hw^K)]'xa߆B MEaUc;ddk46hsNp)4Er:Mqģh]^-)%YV"R>RQɹ A.&T҂pᱬ*蘑)Q8kPLJO_!#TJ^{&ynFټQlma;fD_<[a2;i"Oh8}G~ wbB QN}@c E#)w9#).x"O5Q.{A|π{ǰ`bFAhiJ5Zdѳ_%?6wGQ3x#.j\4ĸ\q#.-#)CO) ` ``ةn2)m,{^䮳޶W[o#Jj"9CQ#)ȄHԵxz!fF'ovg~F $dR+#)j#%s5iO SiL!Gƍ%tAh0"ۃ7ؼ-kq/:~_E>d#cDeokڷ#4A#)n2SˮxKH w<~?+ܛGt.gz=#.#.#)p E#%'X2Oi5q 05^*~`iPBST1@#.AVQbC={@g0ޥo8:$o,k*.~Z[4f؟}4RM 6uI*0#%mJ:kVq⎧,u[j2pD5-븏26ipU3+X{ D~ʮ-5RQE`?_R<`Sٽ|~i#)ckU*?&ϬZiiaL0ԅa9(,HX?^#)۫Z02d tBAyE!`CYtq#9c˟Q!J@pPт|=#%uz=a!7Vh:1B#AO=|P(?,W!\iNF5}B0; PRQܞ`da١gc}G۝M}ڱ$*!_7HS~gS8:є"%A)Uh='?^6I?ӁWCA=f(`E&Q̷ Lk8z1׻e A A @\æï;cP9UR `AlwflHG%rO1>p>\8l5mi#%hA*D#%tVKS`~*r _FNA9׮7B-M @w^x99`1S#%0%r;ǡ@@`Oڨ_"|~HV|UB9r T^hw})FN'tu}lG߄㤤#.%|~[^ERD҂v1"m0$&B'9D(wblNv_ޝq8F~zwj:&TIxOʨ2a]\7kF>n ÿ9o4^đWiƹų.ARa$*XD#IH^⃬ǖR'8,:ryazgQJ_3ﶌwx_T=lo t9Av/ѴO)_(#.%EAǦ,cMX,9BOm >疌g3<+4 f`9ngӿNp~Sz#)٦#%5 -/B݅#)Qt`|CeG,jg$H| @s,J>puf5129n!" "?#%]QzX^Oǰ /@h*<f_h*_Sqf6O1Sqp-&Vp'`3}wQZ< jbMxQzK!42j`$c ["#.itS`۬+$BCkšfg{#)2MBX{o|sTg-s95^ -/~_h%@#DsOZ5kU Xl$of UĊ #)SE%$jA,QHCE8yJ굇z,Љ .@]Uڝ|{#%5i_wO;: MyQǷQPQyD*#.Wю8?O){-:ue"#֭TQlllbnI"kIDŮwr#)%Zn~;Wڛ`XD4n8VڣI+׫']Ҿ;̥ηCQ$Fi/Iv+˗uBSA ]O/ͅ?%'z4JM[#.k΀srYaq?AP#%P|> ?#%T!=U\0:>zW'D0[`rC`ZH2Žwؕr03"`<`8އԣut/`j%/:+y!?Nh84C4d53yκf['ݰK-dʰxɑ#%Fijj +B-PNZJYVTO ?|g#)IS[1׈0?#%1FhpHUXfZ)݊8pjխ1W0c-AS"%z#)r±OabSa ?љ`$fWVk^6|j:QzbP_{_/ Ldg*]6~A@ n"PBdfZ{:Q[9?y D@^9vog#%{N#) :,#)͹q*봵LdM/'9i':6,,ؐ^;PuGz;aXn{lT^#%AsF!q)I% 9 YWc<({Ixrb 2BP^j&|1eՕCy,ْ+)^5BI_v`#.uchsmj),.\M2>nCpp m:qpeܘr 7~(=x#)NclRvrXCh] SW@Xoe.&Q=uGfe(t]Az0'[JwYe&k$' 5۔PV;7!x<9DAH #ut_9ɄMW^$c̨v#%yaKE#)j/sx>#m?7ك#)z[1$q #%xA}ZFJ"׻#. dEmʡU5$>GGxw O퍶Næ#.^؋Up llh~ahs盙#%Gŀ(7R"#)l8?k=]]^ձGG[Oaz<#.@%?$d(D:߽|=܂pj22ZuY="AdPp䮬"NZpih>V&Rؽ4#.#%QQkZHwJs/^M&D#)p :6,$*WI0#%liU:}xDnpPVF뜷\93XSΠխ44{9^#)dc2m|i#%<mظ"@:-0Tx=ݍ,Ǚ<KO{0cGTlﺻ3g`݇h!L<,MJ!T<'߾ݗD^Ӧ6뉹nJ-єc_[#fZ Vl̘)yznP92E ~ZC~`wRw37 u]v㇉^6ɶok%wVM<VMaJCL4)0Q5ekZJݼxR#"oU"hm6G$r Hth12`f8B%GEBC/!Ž,ð"2y=τ;ͥzV   HcZ2^QX~('+7h̜/:Rms"&LZWegn!N9%|#.񪪰qKۥծIӉEۛ]##%D;a['@7NϷl]U#.hb-vÁ̚DŠ K(J̫Qz4xil\89E)-YMǷ7Prη3867pȅ٢Siz7N4-(ˆjzm#)ji-67?#3ܽܡpNΈv^#S N%܅wU4js23r%'!o=2:wHC]XDD2D;O sצ-K0dzz)ExO37:W#-c9fDo2 \ g9;#) K]&)e!ڹ@1sX,x_#)l8V9;Wa.o =$8xĚjyJ#.u@ 腣s/rfECc4e,%Hͼ|yӧAI޽ sosCLP潘C#.<1CA󸙆\G@0q(*W ;!ZkQuM#%ojn@pSY51&ǫ$X[)%)X8(C=e]% Uq,Lhᰟa&Ff6nt(, d!̀iuo5&U)[O#4/nщ Ҙ.kTȜ@B@a ,<3() 5c#)K.䱱5"QcbwylnULd('jhZNefzvÖmzS0J"LJyfdUfd̒UٞIxKjٞ qaCPPY `07,ŧߤՕn9/Q1wá lruTF¬`C)#.h >uqNkt4#3'a3=FChYCS8G+}95GASANݐn`h%Q;>=’1bȔI.jI|]dQjFj \Bř$%N>7KMguTKe!M6f#J#. zN‚Ŀ#%:N::&MUB`칗WoiH;^*zM6zZD|hktKL OIzKgznpkklNzxDٶlb6Q6l8,SdB!Q6M#)8CM$dؒo;КZO#@M[Yr2Ń\MXOiHMN#.42N&fNwM!2gΠcBM$rHFp3JJ,PFЀr0Br0xbšNERd]s3:;88p ,H(D ylq뀺3CRC/gPJ=pDgd yŮ5wxW†"`DRP$d#<;x; xy`#.E!SN6|{L6چs6>95YR&#.vEK#.۾ /Y$ Nܧg,FK ȹIMVɌFx3#%ϒnMwmܤ``l J™q{zNS.>#%%Nn_~L#%X$D 5LěK&wr 䃄͊&HM|-nm#RKcGF XT.2s#),mtW4#nF//s~T)Ol`M덄Cݹ+.DEP҄=͚5qʴ6J~mdO|s341  c׺#)*&%mĨ G@PIQ#0LnO#%wZ#.)WQ٘@bڛA7 ϼ̓Fj?a9>lJ/"An}Q_)_g~4Owq ь;1q^ӹ?>--/y\Lr[xZJAO-1xo R`fvҝ#.!Fz#.SPX T#% 5zչۭz?CeaO2i4[<>$(I$"*?Nͮ4Y$;VjٔtvX$5}%;}vnEiϕ~ZzTLLU1!S9C#%#.KP`~?űYr<]~(%/{s`=Q1pwXCb$K(j#%#)(nT#%;r׺^W$&p*;Y#.;+13,l`[%M #) }$$lMF*X3WJT#)F 9#.Łv(@2ϙJ5%.Nb>*vk,FC8qd"f @{dQzz}!*N\(=1Xv7d_J* -9  e 2cS%&d ysM7V5䛄bZFUUy~A:td8 tbe4b`EWdE#.H( a ^#%Ȁ "#- Ih*4Dc@=_[`'(AKT,B՛8Wue RALH(#) f#%p2$O\M{"^E=kr{7.f$w.W5ys}s_8 u)S &#)H+BdY!/-_ߎ|YK#%$OAþt>KkEEsKHtBZ{,x給,e0jPd@)`]͈U t-#.{CF+dM1snCUQ{SLZ31~[<YTjey_9o<^\{\HS#.cʹ 6d2k )&H#.!(aCKhg6’`,._\Ǣ֛wRZ<#)$PPo?9Ҟ~&l Bl4ۡ=g݆eZn$IӶnC\E{^ݧ^|;pdqOl|rT^UakZ}spS^[oΠߝtMZN@('%}WQJU(9(iO*L{ۊ#%YHXE9Q7ƋUH}R#)څ{#%dDH"22"H#.A h;>601b}nacs X#) 3Z`7:V]Pö**ɋ)ӊh+WpIC%h1a,744dZ֕ |L̘ )W9ӱn;D]z(:]ٯ*鸚jVqR<LD@WcKsQ#.SX.{)(" :3!ѐ" lsTi)͹W-vieQQE))Ed'3-cEasL#%XAd!mckj>fM4kWAa<$C}xtv) 僬#)Hz}G~_-ZyA/D̿^(bA/")ٕЄB`TB!#. Ng ar*% ?!5}9YE>f\`@b&Izx9ta tm<%^Ih6VeiPJ=sW 2!f :j UDCd8{3^NֺvW_f!ZHDKJ)d?"0_8UQ*F $yy~VEC ;@ aN9PX핰B0뚾8xȋ@B+&P @#%E& WQe_x٢}DIuz:<3(bEHv:a)]RRӆ7V,7 xl1ܗ̦,pW g֜jՃDVmTlⱫɘخJ4O ~;ְ:<=vjxv<}BiuJ@(t y鵥G^=ݦ,(ɻY}E׿<{c*[#)8H9xg^M\9>;1lj>u|o}HYJEc#)*v3)v9s~wVM<0(4|>u1T&CqY1CSVW=XGLP 5My( j 9Ai#.#%!.Hu^kE(JÝvߣ T#Dvc`a+8`lN95uZ8o=&B,0A0G#5[:Owd_]MۯF3`=/hۛ&H]HM:̻7#)ڷW]Mz\tI<, νls#Pv ȋUR#C ij4Rn!RK*O]b{}-OAEhpɓ"!u0+d9]k0cv)10RiMDW}sd b(]Q:|4o6(_7zsA4C9P+CIYpO'RšLJM9*+,_K9F@Z 2)OFDD :=xb8@c8`b@"[]klvNYhM+]suA#.刬mBZvʂ!BSIIq+4XtE`dsna$FLUEu~-o7T*2G:bɞPnio"${+W"iԅ Fz(=HQU^wMN-)#.2B9 d>ctԮ>"ɊQT꠰v %yJvÚH!EkB%+EʑծVh#)4􉙐Alх\ 8ɯ*"6Iul4D9e#"ӑ!Q4"D#%*,K>&%sJL59Cq-F"H5E@%0#.B  I6͆R1#.D#[Ǖqk"\.v:.KdE1M.*r4Nre;MQѣ Z܎)"F"YۓVePmTLFB<"<6HȾW434ˉ[,T$74* Jc[B:z#.e.d%#)uMɭ#%IP&$U`Xz=h{x=MϬ\z^0ErlJc:I8PlQPUJ<H$+ `SJ{xx ,raqN9mbT F^Ȼ/0" ``LQLx)`w~1>Q,`st̸TlD32cm"31a .#)B$#%lRTBRV #%!Z`qˑ!^C(Fe@y`'я0n4ĸɤnP8]0b30}6%$#%NdU#%`G[զ,ϡd`S7 !>qα޾qm^2Ydf r$/ Y#%{}O%}'0YqYD$<wD2畘fmjBUMi?F= Tq׽0aMiUS8&FUD H҄`+wjzy潖j6T@!czµ,A )RV64b;^m+\sNz[ppK#.܍#./[)DYg-m 3~@$/ou8Ƅ166Bp㉺vVnKWkynBdLL`|m.* YG!#.(4#)-(lt̲l2j 7؉#)Tdd,MD,TaE4ll+GC"d!c+#) )Y5C-RB Q!_7 #)3ez1#[e^ڂg#.>ƵЙq}g=Qy]+؅S)!`J'9 Df%1!fP pmcfÍLQUoZ>TXc#y4 uP8݇c0 wQ!؅8Mn&73|BKoS-"sdG'] 2I,l9 bP-6XK(Oݲ{|~0܋|sc`]'5}fv,9nIwC#)2#g'j r,>$4!{n:z#./Bpq1^)?Y̝h4[NKE HXQvE @Lg#){#%80#),"@1&H\lHV0*#%"60wh[}+`#% ht*kiJ oaCI #)n8E%$iV6#.3f3~7v_#.mcHmyYɺg=M<7s7=coT8Mx k̸[|O$(&Cd(},bVH%2e,ڙfILblZL?LZC-4C%6%#.Mi۔2kI$S6B123 B*bRgull"dFS15),&&a JPP*ho޼ 1ݎ*D|Abm@F:=~Ӷ~zD;8BѪF_b"3ң,d0u8[@gpmLXXPEafڅMBB>yc6ape#),MksVvb`bҟ\y;0^zYi//*7ҫt@aV1$+ݷı1mF+%bF)6f$a#.-TQLfM>֜sWUbF))W"Z.XvK(?"7zu2uysO~tIĄ0MHBP6rVu/h_Z~~nT2ڢXBP5']w`ªGͅA[;UU١RWQc c g-S"Rs#v"wT3&nIۧDWN0#TUBrˇgd$OuWֱ:p"O:21GjFC${3ٚPXy$czijޫY]f9/:E\2lmY!ѣQEMKÊְƩTl[rL›Zh4]ՅXqL umnoLuW]#%aݦ 31u!Zb˽k1t&fcZ6c5lԫi:88q~^хƌcWmFg*2#%M 9V NPkCuN0p\%b ZݝidToc =pj)RSݘ"*Vd+#)10io0;Wm̾Axɏ37<î2Pqj7 8{Ob :K+1xݓCʑvvQRXeu)SEd6QX9sszPwڈxtqe9^ȥ^uQSaH $n#.m=Uٽzk8 [A;-1#=n$%%iȝQoX8$׉˱TU#.*uvޱ0;otpi34gvhW<'/JRg #dDž+F(i?C3B6I7;-s vnŴ3:I=!^tkJ&qdָ2L/_H!ѥCHTr9~:j\^h/Ym(*.$w #.S\m}vcl4us0nXTȍ;o[d'{UDl!QϱQs*p`Y8(wCtQ4$JBUg귒\;^7)pNUJI=2UmsVߎ0eoM X٫ NuXqf]`V2[Ȉy-2D=t{52aU͏Z7A7dt1oyRBUIMa p*?a֢xt| r%3Z*n6nT^ @0c\N}],2o"թG/?]eynj Kj|BKV7\y>x_Դ$Q2&iRT6H@ђ "?ax1<4VOPKtܸ!.*GPC>pe n6,"11XZ V@v B;#۶@@Ǽyi;k-a.@9AvBbC'-(U#.!ݮ'*Va`AE3Pk&Yn欴XLap0~g);!ѳ؂09E$aD^#) e`8\[F(Ds6{+,.<4IX`č(3ż\CdMNErս Oي c#.!KC,QF1uu02PY0UD@J&Pl`&`1!b AK7BfFho?@AEl .^U o{rqHP0zVA@\AR~p -]vO;.?@zdCVzSBQoi¨UAb #%ZѵƵժ;eI$HBo`9!dxxiJpe1.GO*PK;Y,,կhuNh2ÕbW"ɽ43i2jdteJtY#.MD .ƥ:ҔDm` E/g͸=5‘Ar[S2bI%:S C*#POok4N)(6DM̗CR#ED]4c:ڝo:ku^Tsi?r"#.M⼉xnRS)#)3:LJ:jΓo|6ަ\$3fL916\d%adž9\4(wMoNO3IQ yXX=(X.F XnNf/޶nEXQ #% +b=Yz9rq\2X2E,HbD"4R*8ŌLfK 7G84mjK:f;Iιwu#.^Q5SMۭ]#)wqIם҉-x#.fەD$RDYR$ppRm]FVvFqoRj0Mu$J]H^%؆fPJ+#%I#)S;^S!2Qs̈́,S@#%dBZGfbKH>5֦S"q0#D4W dwfWrQÞQCzZKʨd"#%@\q'T?_<EP+ ip؉%w?[d6B]{P.+!͆A@K LcGA%?*wX׉KLѷ_#%H @/wȅq=g"lSQE#%~FO1/ı"hYPUHB1AC$YD_,DI$޵j%dɦhf*LiJV3Z_6Cf$QmSEqF+O[Wn1&eLjiZV ъo-U $X5I"m_+-3TR<3I-6(̩#)-m[c<[iuurJmS+՚ uFLKm xLTD? 6|fƒC7 ~.P#%#:exh$Lct'\N&ۧ_t[ģ-dj=I-r|1j 嶵miifimJj}]~_mVDmfoDAdMHY#.הQUcXյ[ 55DΛ PbE>MnjJj6b32Z6Һ0jRZVe2M4TZܡ#KQLR)D(m5&hfb0+edK#BR6TJڊMFDiHP#.II$%U65DdHڊX[&ekRdƓJ0@bB(!U"kMi#)%Z6kT[Im-_-^lf-U\(YAZ6=npcoQ0J"}~8#)#%V0 SHLߌh;r6d5;J#)kJpr7RB;"`axluG #)~>;u݋f͵ 5T߁J7iC"+9EQ8Ps$E@Y xEF$P,۝4,0)M{t#%N#%+O q>jӁWA Ϟ<ɒu([w@>͸̧ކq}sbLIR*v-XJ;LC,A-wx9׸C|w#%S>޼}vD.&;0(R`-i`'38m@3RiP:٨UrCF~UG6з)Ѿk5>Cf>:b_%A#.rd~t&fҪB]#%ƪj=0D+i#)l!A ƇHo:OY=)*`1>>H*Ld)G EIT4ô-nZtѷA#)o~9鷽]'R#.톸I>A7@#%P?>۰|]L`#.IE#.e" ]ǟ׫#J󢮚<џi 0IJQnYh@үCAP̒f(nd/Tn|Nj!aEZ9dd6"1VWJdq) IL&4P7 PІ0C Dٲ*TF#.ެ_{ja% #e*%rsqzʼS?vıO &Qq= 4؍I Ղ ir' &հ5FRn,1FAbEd47 9F @ӭO|O0]ZX#)¡T2`tYGU቞wbE T%I #.'ʊ Ъ"lGVr cg1QIjAxSmgLB`0B"l[BSID2&1ڐiaxsFYDZZEb ٠R ," # #֋#.Mb/:[OZQ5{D1GHCg1p8۟ёØÒbG Q3a5V #%tr}4R#%Eyե>S{$:osrtRbf]v^h|4ԉ<#%#%c2#E(!o,٬C;@uq5rIM#%(NK)"TŌ%&.kw}lŧ 1>bF4ƬZmYwR?N΋侫:^5|X_=ϧS{#(Sv}w(Dݧ\$(μ]\ul G:}<ת_:4jȸoԙ~koUbQffMEʆw]4[nDXZkoWٵ7k%kMiz}{HL'kг)cK ]$2iDZq16HzJ/a`Z@.8Rbaf(Zݏ#)#+7,#`6Mꒊb'0 .ɯJ)l5T~J-U=oal 1* aP2AsMuT"W]iV6ŧm[u8?^ld 6&qd\r=#)`b(aKx6lRA%$DXd~.>E箓P`[C'W׆#.Q@J?@7v\M6}v3g"jh$QuI#%'U@@LP4tτlfܠ{Bu3D0K1nz{ByQ9kǚ"#U㇑AM&^-ES?(c^:1ʏ}a׷P,D# Ăns5)STSb9>~MaK q!$#.u%R5P#., TT2Gj6, dEp;/ȦX-k_{LU!.C(#HQw: &'Y9EK5#)Jnl{BXK,#.ĻAڻ'Xz(%i_~tHqǯ~"TXANJh#^B%?HoR)4oo,cHQT*gP ^J%,%Vd`GK卉[v5CLKvIk1UC41%щ~DXVNH4PO@jHD,B)"#>oٕ;+dٌ*m&Kc#).V۩Xm7kdҦwMeU⵭#%F*$XGΟ1 Lਥ!z8HtW4XzL3<4"#.$hQ*"NtX%Ƭ<~6Js=)؜9ABy#.yhkz)#%#)Y#%(UE{3F=) ?z$ H@(h#.%Ad n/g+2q=c6kr#%J7LLBuS#jm#)RZR/[#.p9{ѣGLҕÓ#%zUO"'Ppd/#hnueU6 fQwhy%d.L(s+6@SV'EkCPUGęP4ur0I??=_SAObw\p"trYX0Pm,('ˡtP a4 t%rθwƅB,he&#)$QjE漏' /#)ӟ#T}/y ,T^SQ׵  0BRP)hY,L Roh,PЉ(DpM*C2P17gWyGbUD)Vԡ#%qoL8Zfx6pW#%dVX$<dEP2To6ئo߃!͒sB#.#..T$, aqM#,$.0${݂BяP>6T=q"!U#.El[*TMoK e`1fֶ66]ɎjqIH`DqM,\`bݛN,69`3ږ׌۶0EGH#.#)#)@bi\QG" mK CS#%>)A4?==tEo;k{9/uEP+S"BLDeֈ2@jnHbh{бl9 jɛ 7#%ce#3 6&'0N4$%,J~F0Nu8{r'BƫզL{3 ` Xڠf/Uȷlj#* fqZ EV(#.[AhnKm 0*E2#.{շ:~ExM{({;?~X+P Vy;'69P.*HB(&v%3 rQeI!QˏeYўD>bi B/wb}* ,vޫ҄%r(x󵮵mT12:0n4TH*F2PY!eƁײ\DkI6QEUD1 `6}diB&ѓ=ۻz+\.,j!#05Td^\l"ǭo_#)w˚glt́2ti&YJZ,#.@a#)+\cy wão 6Hٓ#)bv46hK|=.J!e#%@QZ#)uǼ͐!%RH n#%T48)c*%箌yÑMMǭi'D]:S%sa$DSMjed5Jj"+okImAj@B!tPh ~L9B}!E͜T#)ǪjT=@E7tl:Lxȧ5⎅aԉK:7,ygmk| ѩ«_ȶ #)IൾkqIl ߣeCC_^86]ՓC|iҗY0 %=$F*1᮸(]h7GCkQ'd38ZaV:hZ$fȕu[=96c7;Q篂Z'Hy[U13ꗾ<Kb<%8.a#%4*"XX2KdRdT-URTiRP!>O2K7f_`!̏cm #WRU`H0n;T#%HF('0C 2 hw4 gL>|xiyU}J(%UakjV= /b{H'f0lnǢ<CӣM6*,H)XֺDgXy4BKUE#%CF<1D:B2_߭$e44u #3Wm=|E"@&ܤ Nd#%#.ݵur[[M+iۭ]IK3VVWU\^.IjdM`Ȩ('+2}#)5E1m8-"lc|2j }~V[wpprڡoͩS 7 J1" #Fm&ÖV!۪՝ HƟ!;h=qTpm׬^bc~RΝaLYXzJ=oMzGb #)@!cF_}#. ;/=5|U&U TRڡIg]$&qZ$„DR5hr#%3$X8 CL}+d]Zȯ_|gq~_ ί5CJ@߆ 5 ,aL|@:髡#)  !4ƈ2IĢ=BsQ USF_-#%6(*AxRWߝO,?fï6qAN d3]idb1zh{+qQ@a4bg(Ȑ "STv[-m(M"'@,"r6g#%ó ͹#p>!G]w" Fjq0h` eH` AAr$lEbU8^^ MxbFH!(`)kE3ww9nP+IP7cWYuݛ}TMg>:/|d8k#%vL]WEuĸ+1K uS )>|&M{kczU ҕaI>JR-!lMH\pnXo=)doowIٜ+=;iqcg0#)E}i+A4O<"y}&\|>@hV"mmFճhQ Kq 6@"hl}*J9$R6ͯ,o] mͶJѱV5y.]ۙ xڊu466#.h%eSzZkIk]^yBKdT-V*Tcu2)3݄|Md[I" ,*,)-ayI.!B 6Xf'U§%_^LD-'ߦ5mM־TF[JSTTSeY)4TmX2XʍcLh#jfK#%"#%D.DJ@{9>"U!DI0}=w~oW\X; rh4C#)u1zJ 1Zߕ֒Z/ƹy)b[Vmt@SaT8l8~X`|z&#.vJުHHns'k.aVJjMKZҤ4zmUVOռI  {o #%i2Gpl˷hBD#%0`^;.c):֙8#.m)6׍y2@Z 5PhPhkpKj,1#.[qA$V̓W6{;؟ mvl/.%#.b$p+i;X#2f#)&Z6Z6F!$c0lmA#.HBBŀӰwI#%"ڛ=-%( 91x|^1=#)M1Da% o_)P) Ş$VT|xFN,.'f&c-{rٚD8YCEE&  `C+ !yOVǸ X}QP8Bj?ת3t~AFq9L04ڊCc#%#)/9|(~[-]g>nAG%r6҇GSD1 jIm#.h8Is|{uD}SLpP#)ī#)4y7#%Hg8is@Mp11#)j#. bRh- " T"\Z Q/9㧄z(o6Oɸ|̈́o /RB9m7 @ .s"HUTPDF#)CPkv;)(BLs{;#)qRj*1B":?UFҽx2W#.QwlJre)&4MV))60x#)6g]َt.Wwn\[ǒ4nܻ̱Ͷ[\ҫhKN)4%gwItٝ+)Stlm9j$dD!hv6K=0  _h>vCY 6r9#%v؅v!A:؉`w@"oNx{Sp#)BzJWgYye)>(?9΃օGbUcY#)Zfi}Vi@ZT-Aw患g97L B 2 $a>,{4uE%juԲcwZnJ7Zh~#// 9F.I1tɒMfBPAX#)(z$V뵻imOuշjݒ#%Az\(OzVu#.7bH``{OX#)<@;Q]Ffͫ4ڥQ[JGh0A@AM9URԋ-2fچڠ=#%g3H#.#.eE VeZ3#.!r9Ϊ4ԇD#%tܡLI4Gl9{uD/H8!Oc7_nؽl.pS' L"@EW9o"+VlE!}0t/yxi*Oa4!vK15$Kd!D r l)li <%O9x殒Uʽu6j#%&c̗Z%0Q#.!R[ŚxնOaٙG$Z"gF 'ʦ \a#%eI#%ՒCZBhTZ56]HFإ0(L#%K]5lV{m딐 hv`l71`paٳbj ѿ;njN0>f#)U@D@sD5H@ZtqP?>ȂH#%d* *`U"A#.9{`B(|3HH3$ulry[6iČQi #%r:瞨C$'79ODM~߮^;UhaA=+tk}mmq63kR"<]rK&8(BIj5GL쐊ơihQV vUY86p*ʫm^1_w={@fxA>xo#)fgXxPOO:|~J ;AD##AY#%$)"CLV>R";*P9*>`ijSL:.):x bRI "Oj'"0D#%MMo#)r4[WTck%AWtSn@`ϡBQ7gsI9vIxl;4`s%f)}'2e #)T#p܈&tǧBunӌKwh!CFH(?.4ja)/ ˩AJ\2 &bD|]#.6lQ/#)bC$/iγ-)>. sS|ǖ}ӖIavG*scI{"iHϲ昦>Qڶ) jp?#Bz{oǴ7LA(]9qν\xK\@Y&#bds8ɔLFSZ>w$hd0}d}m:<2)6M/<<i/W'tokZ Y;r-^δF4ϻY]Hx6M_ګǢ&`!3&lxIHr Q#)+46 ص:AR^Q$2D1#*S(Kz`=DP6 w#%HUn0,˓GG{LZ\dDP*#.)F^<\FI л:GМ%#)DiT6n>D?0@#)A}EU;BT$vQ))#)bf;73ldz޳;M˶7]@q#)I#.I&.P6(FM֮ZM%\u/d3fj)c^?Y曳#.--kJ~z[/W٢?B{xj5o'jz8ש۬q#"l!J|mTg!UQA'If̘FQO_37Gܴ\d@>$4t>>:w6 t}\9t.Z! 2p;s)~5#)1PX&_ zŠsuNyb=ݞfEP ݏ'0O'Hyг5ς] "*u$= !nBA DB^p]@>$z+><C_FLj{Q'T+60116#%z[z;>IǶn0_;I)Sյmh;kbb:@퀠$;^ЭxupQƏ#)g pkيIa&P`#.H#."uXb9nPηx[c=uj:F7WN#)N+ҐqZ#fee/XALh"@JF LW͎}w* U 9Ȑ#%, w4{)p'8 4t##.#.CLK9=aL7 EKd]P4rc¬dZKoCu[fY+T{!;{7|%b?Vbo& :eۥTjmEVVM„#)]L`#AMFzpUB $|-?>ֆ4{3 #._ųhW?̄XcrG2%e%1ܞc*#)ͻt dvιm=[v s>j3_^ $NF}⎒1>Ab:O^J4HC`"uH:ajB1ֲx1R#䈍q=Ѿ##.4ur˵RQbilٱbmjPE;5Y#)#.0؇bcٟt<~w-F_?۽?k/2Bq q Fr3ƫk$ SJRim#%F"@k-64J8 I*6!gn7~:UrnjNc#P2F7vRQ4J+52TJVٖA6ь0ExlB.r)#.{AMj!67j֙W*U˥;= ^t*VJ$ d#%#)AfZ0Y"[DcFQh44hxR0q+ F#.Gph@;Tdf#)%IƨȆ\ fPj!B d&h"h &( <=Mt,e7Pڭ,!9^446||yڍz湩zkv.+Uv}01ẘR9xbmモ8&SAR4ʳQDM02Mhl"Dņn,finaB%FhAet0&@ry*%|C#).Nİ]b"UM}3#)J]#%cfѨ Ch[!$C5P"r*#Qvx5`Mn#*"#%$lM34DA#Ii Q%BT bJ"#%E14DH MT:$j)(me3%Dq5±Kr+%ڋmͦl&\ݶ0!K)`w~.gT4@;DӀ+]1QL Hgz8~ U2sU#%E$T"F#(P**lrs$OUJJp;+"M O00,PL S ;ŝlha Xv$@O6g;b(uutou҇wG֥wuǝJ3s0lG](77bYJY@: #)we`9w:(ҝs Ǔl->3mAK5\S>5\KK1gE&olE$HFFDa7p{ =ͶWE : R@s$IPex(a)!&ak_#%mBa8}Qzk'}ʃ^^4ki#OF?YKeu~kbVrI٧Y{ؐɟ&,^oѡrhHM#.4@i3Ž#)$ v|SfwW`oMj3M=eDT*(;+Fם#%,'-T|2NlvXTeEE#%ET$i-;iJULJ4sCn.U L0X̲) $%-٭9ߤNGPMq4~X`! dUL#)24L%7"QIsmMh[5U^6r+C/P3#)6} h)xy\f].ͧUT'_ap-.;Pl&#%H+"*$"J(Y$r-K#.v׏E d@a A@itX<W2-P %☂yQKʕ2`F'1wFA#.P@]1AK6b$ZϤ+qMV瓶':X\L(RԏuZkp^LVvT/XFsq/ 7Ȧdpp//?{}9wi=lvuhq#.CznCpڇav#)g_* ~bUL tLFqVӰZdgftRӶ$LI$賀|5UY'àE7, K196b1Fq/+6kSb0+GK@Fl!Zq?1;x3ܭXS+:Lhb9;ַC}hO2IYͯc͹ |;TpU- +r!t,YyQٚǤ.ڏ7J6҈nԫlJ]l[NW6C'JFo3GDe=W򕿗WPoc7^f%v؍豋x9 7Vۦ6)0{zl(#%?Co'Ez')9W=$%CC[ Gqm]#%ds-MVw풢0CZ3oQ$թ`ˉK`VZ觇~%@wiVkQ-29ysthRJuqd:hM]qn<(n͒eL%m,v-_m8/`nKG}`3}737R㍰dD3ИbJ=~#)X)bR ՉiP1OAusJ#.E'%n8*eҹY%%0 'MNL@^ #.2#%>t|(E#.UQ6z]6GfỵAц  ,H]BE2,ҭ&+jF(R3aAX *A΄oc &ݲi7MƑ҇#%0$xC6{Eu}F~j+D:z#)؊dRŴAdz۾'iLr/xU,> 1հRbHj#)YydFPhzpHp6il^#.1@\v#/Y`f 9][j)g>9&XHR#)e!dQb8|ԎeWdDbv HyJbfo@%qA5MҭI*lLc!%Z3ǃhZ8QƛMJZ3x#uAH &a#%Ywn1MY[5p#.1Wގ֚:YMiMkZ ܘwG /'[+|2b#)!"#.7"*9UbKZ P3k z1!9N+: #ͅ@e C*DcifL"2#%#%`2D6YTޮe|3Jɒ$nj8LU:@v{Kz}͊DnK8axm6&ijlNChc]x]g-[&rtC%c!nJB2#)n%48LLayգo[o&K,޼YOZ65#.G:C[5F#.cw#)L8DwaxJ^ߥaQi:06Ӓ?)/EFu7y6D!%y``r2”+MuiF3BS*c9銍KAUV54XeҀ>*XУԋ]Z)E߼#)4#)9e84s[uޖ̥05.hpfX#Lw tC!]N#)iKl M)嶇ӒkB"0]C1OtR4#H[&`.@7u3Wf_p*N>TMD "6C̥90nkWO(M9&t%)-ru\ M0+;BqB/6={%x0ȣMWi dUFG^B{}% a]M6?'*-S+I'#.#.sU#)OXl@[d27y~;#)}+ 3y|Y ĬWiśAJ3>~3{{p1$FN#tUNygl{νIGS r ')4UfMQ(Aod24i'1wPzT-#)$@0/$j2!KuS)kF֮j ER #);D;yɫ{:ƗQb#j4‚b((el&Ս%bM͕4fT,I((CH4S4l#)*f!S<#.' Q5A:aMUl~!i,$&#)4m]lXumA$h9^$uԐ!ra1-nfJAHl2>^3_H$"un6篥 3KQ1%>[]BMo C\`^ԁҍ>|"FhՊZs S`M<Y5ȔF6GZͤ[ )543HT`#%AJ})p.@2Cќ)#.DD#.$w05ex0/dZs2c|\]5peRb"5Zc̵)B'šl`#Q^eSkW6S(ftff0Xҡcc#.8ddVKty?f!`}p~n8ЕPٝ"B2pq&.YM`˚à;DΉמ m ج%- sg@-j&~_۷IYȬ6l\"E(B9s [4Z!U7IAOI,#)9"BYiaqma|p49$q($(u0'IF Llh,RhJiF>}Mw+ӀcЋw]Hj8' \h=U$$@2/iIaӎ3<2l]C8|ZTa1S5OLاb_sc/%&l=r8;RٯF)NrbDDAU/?8/mRb_cku44 q^0f{~np3B\ޞ238gZB c&0n'$uNmg0g!Og0Rƚ]^ {AWImoȫ1 :97Vu8y3listr6c.R$l#.kȸ|YJxN~1w QC#L06#)F( #)WKޘ#.5ٴ)_-)Nr$9QMvѽ08HzQ4 e0e2XvҊ5rL L댈5H0.q#%5M԰͟K7 ژfHf1.ӟCs2u,aiɽt<!'HTFSS %213T#ÞH؃f+GXoFlIP\oF1.JfHK"ASA'G"DR$[#.V(C @iH! 36 #%b U~_Ӝqnro"ݠHT(BdSuR㻣r@*WٿQ9[q5W;_LL!]:Lݔ7rSv%[3e25[.I!MLc;:ލ WnR*F:\LZـ2!(JXΟ Q.-خPqJrF'VTmȥȽ0$(vCmE Z-嬺KWL.7'삄]]^~ZL*0@I&zuxnѼ0ɑԖń$MHN4#^¹mE!n0mMNw^.gd;Ab+CVYu4LG=yԁ$3%J,A< >K5촉;)q=zHUI@Xeىd̓❷1]04qs:`qc*7\^Ɔ,$anI\D)7[L6V}E[@D$M5)b`(p0\5H+aB"0oRV44lh1#%b7Q!'7GSYVK'x018QL+<6i٨}]N&DuRPl]-Yxȍ.?-\e\ØG2#)fiB! #% (nUcر* KE0Fu4EК'la@HhDXD@D* Ă~T#%CU{oP#)+LiJg/Zb y$r̋@_b9tÆn#@7F{#R$=td'~&;IdWכ{k˻k$2%MNo7usǾu,! d !D4M4$bC@3VޝnFOr69SFF #%2 Ѷxt=O'cvhӰZC#.tDxpN㈲p4F'L#! w3323TVhD,dĉfiByr N'#)̂XsW\vT6oLh$'EAHr#)=|=Ш>YXmNzkDrFu Ѩrd.0)2f[MO3&ܣ&Xn X<DuH#.{#Q/UҒ"l$n:ѕmȱqMR1X頤~l3|#)(ɝ+!gxsQ_!J4@PEڴ5Q%[T"8Ɣ.D 7U#.Y"#)##P+` =8ƊH\1#%B}Ɔs-,h5k_]{榅V#)雰p# " H" 죾Yi6#6j {mΧPd#%Ƀ%CHbR$ %¤"TvDۉ9i% !a 1#.#. $AEH#.҆`9+ԠG=O#{,0!&9[a#)Na$0Q6|bV64X<PQK$ @#)Xn"/杠$VM~ZبN6LI|-3}-ˇHh;ֺvEB(x LH]}n8~kT1 $9J%oUi6zXdJPXƻ4܈Ab-#.H[uklz.VtCT>,^ʞ 09M4AjUm4%!rKl|rO:۱##)][{zVmh+,ԒjA[[0JQZQVV#.X*@`2Nsч')&hЮvqfn<a#..+٫~#)`! " 6$ny)ٗҦ΁S.#%qI!۷|Ζ-ِy =$4jxMǮ^T w1g"jfAOqLqAq|色WS*4&M5pu0new#.k`f8Ci1eƅΥ$61cJI2YԢe4FHK]@l -K"m;| #^|#.5GF[#.k#%Xrp/>hvEՑӢ0!">O ,{#.YRuT?`!:2|#)i/J՞bzA0"0!#%*;p7{iOwB]< bH ID Thko 8HHZ#)w[1u:gHP6WTYj#)z;20 y}o$[pQh87}s oihhc#.qOMdALP)Gj`aӿJ5L̞uTVIwk,4ATWN{痽g#)RlbWu+1ڊn[6mER0"*l{NE|fzCh} )T=!"Ȭ1F#.KG1:@!$S+E2[6m_Qih6Tm%FҔڿCU>4&X|U#.P32Bx %X,E#+llcQ6(ڐƱfb٤<ړVEDBpPK'QIޯxA4#)xj2*h Z v,urSS D{!>5EW#.|QgHb&7(h}6'#)EvD-Y`~L}6DP䞰*"H/P( !)ABS(DMRjөί1eKkL#%?H+ Byʴ}@ORzy^5@{<FypbܵF#8P$rCͤHȔ9JՋmqq`vLn;vްm&_ #)󱉒i],{A>%wT0"FF)(*#mSh߶ּDQm%2gEYR@$!<ĹE#)0U#@#xM=FRO;W^h;.)#%_ީZ֋j1Z RQ6V-jik Qo~wom*IN~~}HR)N4Ɍ hiYJ)92Md݅pq֬m%I#CCD`6Q$ZY 2ڷ-lMsaRѻkkkmMoUrT[fnʮks-^]kRTȔ󺷚kή8%N#.U)Qmab-4MIUV;[x[(ʲK^MYc5e]&憃&28HbH- f 3{2IC6K!)|4h-Rڻh\>3)Pa1T.^L¸P"պ*?˨s< %ǭW#%'IvN$z0z++co'g#%[Qly7\H[^9DfBxYcS{[#.`SS9c }^Ff̅: QG)ȼ.#)Lo_jt##..2/ff6".Ȱe$GFd ZCJt͞[CHbyq --Q4HǏ5vf9zHZ[!KPM;F !]ñm.2PkEZyM@nu'p`@~.Jg Mæ2AiT5s#%[L̃mG/2uw>DP.H#c-%jf~}8#%f.Pؗ#%N+RA/P;nh|x2va&tQq_jIb8i 2ȩI1Iсdf,?{U{hv+VmA(t,qw҂kă#t[#)BãM ZѬm)x {˔loa!"0CT/m622\ BCܔiuj#%ݖyĚ=f7ͣȈb\\,uH\S>U>K+k!#%/v+qAx"@Hl7JSxD%s =o> ^9h{\ɊYU?g/~o_?ٳ>)Tnw~__?7v>/}q{A#%Bq\$D5?L`Q#)!=Us0)޿?wv$$Ͽ$6 J#! 6B Me̢i 6,M ?۷Zc--U$qWbA|3?0<#%j=?Цwk|??ObxRܲ<#)4d`h<&XAׇɪrI@{?g>2֘;Xl?``ڕ5$CS#^ݭ1h$qƆH a4jU;7{3ZqHvq7um +J>#)vSfZM3Z2iB ED k 3/~fw$`mX);%v]Ws3PEATiq<׉n6,  2Bi#)NJJX,1xwܰd#%Pc$A4$7J.2$ =^wIA_i;Mb1@'4n[hC!#%HJ$jĨ5QjS+lZԦE##f۶mv~sA@S3 ?Ȉ+~uRU)^1߿%|=Sl#%OC<*,XJ9a~a&n$Y#%GRGGOu/v+p? #%Z;%(TX0$a*#)$"! 2@ u}~܎_:Ԅws;{T#)>Υ%:O|QI#%"?; A@X"(E-?#.R?#.-5]ِ%A*Oߝ9*y9S2x |>N gA,M/-80aw<}9@L(w{%^k +#)fgp }_ KHyFѧ&:F?(rE8P{ #<== diff --git a/wscript b/wscript index 087173d..8a484b0 100644 --- a/wscript +++ b/wscript @@ -3,13 +3,13 @@ from waflib import Logs, Utils, Context import os -VERSION = '0.2' +VERSION = '0.3.0' APPNAME = 'ChronoSync' def options(opt): opt.load(['compiler_c', 'compiler_cxx', 'gnu_dirs']) - opt.load(['boost', 'doxygen', 'sphinx_build', 'default-compiler-flags', - 'pch'], + opt.load(['default-compiler-flags', 'boost', 'doxygen', 'sphinx_build', + 'sanitizers', 'coverage', 'pch'], tooldir=['.waf-tools']) syncopt = opt.add_option_group ("ChronoSync Options") @@ -22,8 +22,9 @@ def options(opt): help='''build unit tests''') def configure(conf): - conf.load(['compiler_c', 'compiler_cxx', 'gnu_dirs', 'boost', 'pch', - 'doxygen', 'sphinx_build', 'default-compiler-flags']) + conf.load(['compiler_c', 'compiler_cxx', 'gnu_dirs', + 'default-compiler-flags', 'boost', 'pch', 'sanitizers', 'coverage', + 'doxygen', 'sphinx_build']) conf.check_cfg(package='libndn-cxx', args=['--cflags', '--libs'], uselib_store='NDN_CXX', mandatory=True) @@ -40,12 +41,18 @@ def configure(conf): conf.check_cfg(package='liblog4cxx', args=['--cflags', '--libs'], uselib_store='LOG4CXX', mandatory=True) + # If there happens to be a static library, waf will put the corresponding -L flags + # before dynamic library flags. This can result in compilation failure when the + # system has a different version of the ChronoSync library installed. + conf.env['STLIBPATH'] = ['.'] + conf.env['STLIBPATH'] + conf.write_config_header('config.hpp') def build(bld): libsync = bld( target="ChronoSync", - # vnum = "1.0.0", + vnum = VERSION, + cnum = VERSION, features=['cxx', 'cxxshlib'], source = bld.path.ant_glob(['src/**/*.cpp', 'src/**/*.proto']), use = 'BOOST NDN_CXX LOG4CXX',